This commit is contained in:
2026-06-18 00:14:47 +08:00
parent f87f1cda0d
commit 2da4f39d73
23 changed files with 568 additions and 189 deletions
+1 -1
View File
@@ -6,6 +6,6 @@ VITE_DELETE_CONSOLE=false
#本地环境
#VITE_SERVER_BASEURL=http://liuyao.nat100.top/meiguowaimai
#VITE_SERVER_BASEURL=http://192.168.5.11:8080
VITE_SERVER_BASEURL=https://howhowfresh.com/prod-api
VITE_SERVER_BASEURL=https://www.hhcheflink.com/prod-api
#VITE_SERVER_BASEURL=http://192.168.1.8:8811
#VITE_SERVER_BASEURL=http://mifengchuantou.natapp1.cc/meiguowaimai
+1 -1
View File
@@ -5,6 +5,6 @@ VITE_DELETE_CONSOLE=true
#正式环境
VITE_SERVER_BASEURL=https://howhowfresh.com/prod-api
VITE_SERVER_BASEURL=https://www.hhcheflink.com/prod-api
#VITE_SERVER_BASEURL=http://liuyao.nat100.top/meiguowaimai
+16 -9
View File
@@ -1,6 +1,7 @@
<script lang="ts" setup>
import {OrderStatus} from "@/constant/enums";
import {formatTimestampWithMonthName, thumbnailImg} from "@/utils/utils";
import {getMerchantReceiveAmount, toOrderIdString} from "@/utils/merchantOrder";
const {t} = useI18n()
const props = defineProps({
@@ -16,7 +17,7 @@ function navigateTo(url: string) {
</script>
<template>
<view @click="navigateTo('/pages-user/pages/order/index?id=' + item.id)">
<view @click="navigateTo('/pages-user/pages/order/index?id=' + toOrderIdString(item.id))">
<view class="flex-center-sb">
<view class="flex items-center">
<image
@@ -35,8 +36,8 @@ function navigateTo(url: string) {
class="bg-#FF6106 rounded-6rpx h-32rpx text-#fff text-22rpx center px-10rpx ml-20rpx">
{{ t('pages.order.DEL') }}
</view>
<!-- 自取已隐藏 -->
<view v-if="false"
<!-- 自取 -->
<view v-if="+item.receiveMethod === 2"
class="bg-#00A76D rounded-6rpx h-32rpx text-#fff text-22rpx center px-10rpx ml-20rpx">
{{ t('pages.order.PU') }}
</view>
@@ -44,9 +45,11 @@ function navigateTo(url: string) {
<view class="text-30rpx lh-30rpx font-500 text-#00A76D">
<template v-if="+item.orderStatus === OrderStatus.CANCELLED">{{ t('pages.order.cancel') }}</template>
<template v-if="+item.orderStatus === OrderStatus.REFUNDED">{{ t('pages.order.refund') }}</template>
<template v-if="+item.orderStatus === OrderStatus.PENDING_PAYMENT">{{ t('pages-user.order.status.unpaid') }}</template>
<template v-if="+item.orderStatus === OrderStatus.HAS_PENDING_PAYMENT">{{ t('pages.order.CONF') }}</template>
<template v-if="+item.orderStatus === OrderStatus.MERCHANT_ACCEPTED">{{ t('pages.order.ACPT') }}</template>
<template v-if="+item.orderStatus === OrderStatus.DELIVERING">{{ t('pages.order.OTW') }}</template>
<template v-if="+item.orderStatus === OrderStatus.MERCHANT_REJECTED">{{ t('pages-user.order.status.merchantRejected') }}</template>
<text class="!text-#333">
<template v-if="+item.orderStatus === OrderStatus.COMPLETED">{{ t('pages.order.DCOMP') }}</template>
</text>
@@ -72,8 +75,9 @@ function navigateTo(url: string) {
</scroll-view>
<view
class="absolute top--1rpx right--2rpx w-196rpx h-180rpx bg-#F6F6F6 flex flex-col items-center justify-center">
<text class="text-34rpx lh-34rpx font-500 text-#333">${{ item.paidAmount }}</text>
<view class="text-24rpx lh-24rpx mt-24rpx text-#7D7D7D">
<text class="text-34rpx lh-34rpx font-500 text-#00A76D">${{ getMerchantReceiveAmount(item) }}</text>
<view class="text-22rpx lh-22rpx mt-8rpx text-#999">{{ t('pages-user.order.merchantReceiveAmount') }}</view>
<view class="text-24rpx lh-24rpx mt-16rpx text-#7D7D7D">
{{ t('common.itemNum') }}
{{ item.merchantOrderDishVoList.length }}
{{ t('common.item') }}
@@ -103,14 +107,17 @@ function navigateTo(url: string) {
>{{ t('pages-user.order.delivered') }}
</wd-button>
<!-- 自取已隐藏自取订单 未接单/已接单按钮 -->
<!-- 自取待接单 -->
<wd-button
v-if="false"
v-if="+item.receiveMethod === 2 && +item.orderStatus === OrderStatus.HAS_PENDING_PAYMENT"
class="!h-56rpx !rounded-56rpx !text-28rpx text-#fff"
>{{ t('pages-user.order.receiving') }}
</wd-button>
<view v-if="false"
@click.stop="navigateTo('/pages-user/pages/scan-code/index')">
<!-- 自取已接单待核销 -->
<view
v-if="+item.receiveMethod === 2 && +item.orderStatus === OrderStatus.MERCHANT_ACCEPTED"
@click.stop="navigateTo('/pages-user/pages/scan-code/index')"
>
<wd-button class="!h-56rpx !rounded-56rpx !text-28rpx text-#fff">
{{ t('pages-user.order.writeOff') }}
</wd-button>
+10
View File
@@ -144,6 +144,16 @@ export enum OrderCancelStatus {
REJECTED = 3,
}
/** 支付状态 */
export enum PayStatus {
/** 支付中 */
PAYING = 1,
/** 支付成功 */
SUCCESS = 2,
/** 支付失败 */
FAILED = 3,
}
/** 消息类型 */
export enum MessageTypeEnum {
/** 有人评论了你 */
+25
View File
@@ -386,6 +386,10 @@
"userCancelled": "Cancelled by user"
},
"contactPhone": "Contact phone",
"contactNamePlaceholder": "Contact name",
"contactPhonePlaceholder": "Contact phone",
"search": "Search",
"reset": "Reset",
"peopleCount": "People count",
"perCapitaPrice": "Price per person",
"estimatedTotal": "Estimated total",
@@ -484,10 +488,13 @@
"cancelOrder": "User has applied to cancel the order",
"checkout": {
"priceDetail": {
"deliveryFee": "Delivery fee",
"desc": "These fees are only due to factors such as the number of shopping carts, and are used to pay for expenses related to your order, including platform services and delivery services.",
"memberDiscount": "Member discount",
"platformFeeNote": "Delivery fee and tip go to the platform and are not included in merchant receive amount.",
"serviceFees": "Service fees and other expenses",
"taxation": "Taxation",
"tip": "Tip",
"title": "What content is included"
}
},
@@ -522,7 +529,15 @@
"receiving": "Receiving",
"refundReason": "Reason for refund",
"refuseReason": "Reason for rejection",
"rejectOrderReason": "Reason for rejecting order",
"refuseRefund": "You have rejected the user's refund application",
"merchantReceiveAmount": "Merchant receive",
"customerPaidAmount": "Customer paid",
"platformServiceFee": "Platform fees (delivery/tip)",
"deliveryOrderInfo": "Delivery order info",
"deliveryDate": "Delivery date",
"groupDeliveryFee": "Group delivery fee",
"groupTip": "Group tip",
"reject": "Rejected",
"remark": "Remark:",
"reply": "Reply:",
@@ -544,6 +559,12 @@
"orderIdRequired": "Please enter order ID"
}
},
"payStatus": {
"title": "Payment status",
"paying": "Paying",
"success": "Paid",
"failed": "Payment failed"
},
"status": {
"completed": "Completed",
"completedDesc": "Order completed",
@@ -554,11 +575,13 @@
"merchantRejected": "Rejected",
"merchantRejectedDesc": "The merchant has rejected the order",
"pendingPayment": "Pending Order",
"unpaid": "Unpaid",
"waitingForOrder": "Waiting for order..."
},
"toast": {
"receiveSuccess": "Order successfully accepted",
"refuseReasonRequired": "Please enter a reason for rejection",
"rejectOrderReasonRequired": "Please enter a reason for rejecting the order",
"refuseSuccess": "Order successfully rejected"
},
"total": "Total",
@@ -722,8 +745,10 @@
"order": "History"
},
"toast": {
"agreeSuccess": "Order cancellation agreed",
"commentSuccess": "Comment successful",
"deleteSuccess": "Delete successfully",
"orderNumberCopied": "Order number copied",
"orderWriteOffSuccess": "Order verification successfully",
"pleasePhone": "Please pay attention to answering the phone.",
"pleaseSelectStore": "select a store",
+25
View File
@@ -386,6 +386,10 @@
"userCancelled": "用户取消"
},
"contactPhone": "联系电话",
"contactNamePlaceholder": "联系人姓名",
"contactPhonePlaceholder": "联系电话",
"search": "搜索",
"reset": "重置",
"peopleCount": "团餐人数",
"perCapitaPrice": "人均单价",
"estimatedTotal": "预计总价",
@@ -484,10 +488,13 @@
"cancelOrder": "用户已申请取消订单",
"checkout": {
"priceDetail": {
"deliveryFee": "配送费",
"desc": "这些费用仅基于购物车数量等因素,并用于支付与您的订单相关的费用,包括平台服务和配送服务。",
"memberDiscount": "会员折扣",
"platformFeeNote": "配送费和小费归平台,不计入商家到账金额。",
"serviceFees": "服务费及其他费用",
"taxation": "税收",
"tip": "小费",
"title": "包含哪些内容"
}
},
@@ -521,7 +528,15 @@
"receiving": "接单",
"refundReason": "退款原因",
"refuseReason": "拒绝原因",
"rejectOrderReason": "拒绝接单原因",
"refuseRefund": "您已拒绝用户的退款申请",
"merchantReceiveAmount": "商家到账",
"customerPaidAmount": "顾客实付",
"platformServiceFee": "平台服务费(配送费/小费)",
"deliveryOrderInfo": "配送单信息",
"deliveryDate": "配送日期",
"groupDeliveryFee": "配送单配送费",
"groupTip": "配送单小费",
"reject": "已拒绝",
"remark": "备注:",
"reply": "回复:",
@@ -543,6 +558,12 @@
"orderIdRequired": "请输入订单ID"
}
},
"payStatus": {
"title": "支付状态",
"paying": "支付中",
"success": "支付成功",
"failed": "支付失败"
},
"status": {
"completed": "已完成",
"completedDesc": "订单已完成",
@@ -551,6 +572,7 @@
"merchantAccepted": "已接单",
"merchantAcceptedDesc": "商家已接单",
"pendingPayment": "待接单",
"unpaid": "待付款",
"waitingForOrder": "等待接单中...",
"merchantRejected": "已拒绝",
"merchantRejectedDesc": "商家已拒绝接单"
@@ -558,6 +580,7 @@
"toast": {
"receiveSuccess": "接单成功",
"refuseReasonRequired": "请输入拒绝原因",
"rejectOrderReasonRequired": "请输入拒绝接单原因",
"refuseSuccess": "拒绝成功"
},
"total": "共",
@@ -722,8 +745,10 @@
"order": "订单"
},
"toast": {
"agreeSuccess": "已同意取消订单",
"commentSuccess": "评论成功",
"deleteSuccess": "删除成功",
"orderNumberCopied": "订单号已复制",
"orderWriteOffSuccess": "订单核销成功",
"pleasePhone": "请注意接听电话。",
"pleaseSelectStore": "请选择店铺",
+2 -2
View File
@@ -2,8 +2,8 @@
"name" : "CHEFLINK Merchant",
"appid" : "__UNI__BB8E3C9",
"description" : "美国外卖商户端",
"versionName" : "3.0.2",
"versionCode" : 302,
"versionName" : "3.0.3",
"versionCode" : 303,
"transformPx" : false,
/* 5+App */
"app-plus" : {
@@ -44,14 +44,37 @@ function statusClass(status?: number) {
return 'text-#666 bg-#F6F6F6'
}
const {paging, dataList, loading, queryList} = usePage<GroupMealReservationVo>((pageNum, pageSize) => {
const contactNameKeyword = ref('')
const contactPhoneKeyword = ref('')
function buildGroupMealQueryBody() {
const tab = tabsList.value[currentTab.value]
const body: Record<string, unknown> = {}
if (tab?.status != null) body.status = tab.status
const name = contactNameKeyword.value.trim()
const phone = contactPhoneKeyword.value.trim()
if (name) body.contactName = name
if (phone) body.contactPhone = phone
return body
}
const {paging, dataList, loading, queryList} = usePage<GroupMealReservationVo>((pageNum, pageSize) => {
return appGroupMealReservationMerchantListPost({
params: {pageNum, pageSize},
body: tab?.status != null ? {status: tab.status} : {},
body: buildGroupMealQueryBody(),
})
})
function handleSearch() {
paging.value?.reload()
}
function handleResetSearch() {
contactNameKeyword.value = ''
contactPhoneKeyword.value = ''
paging.value?.reload()
}
function tabsChange(e: { index: number }) {
currentTab.value = e.index
paging.value?.reload()
@@ -80,6 +103,32 @@ onShow(() => {
<z-paging ref="paging" v-model="dataList" :auto="false" @query="queryList">
<template #top>
<navbar :title="t('navbar-group-meal-reservation')"/>
<view class="bg-white px-30rpx py-20rpx">
<view class="flex items-center gap-20rpx mb-16rpx">
<input
v-model="contactNameKeyword"
:placeholder="t('pages-user.groupMealReservation.contactNamePlaceholder')"
class="flex-1 h-72rpx px-24rpx bg-#F6F6F6 rounded-12rpx text-28rpx text-#333"
confirm-type="search"
@confirm="handleSearch"
/>
<input
v-model="contactPhoneKeyword"
:placeholder="t('pages-user.groupMealReservation.contactPhonePlaceholder')"
class="flex-1 h-72rpx px-24rpx bg-#F6F6F6 rounded-12rpx text-28rpx text-#333"
confirm-type="search"
@confirm="handleSearch"
/>
</view>
<view class="flex items-center gap-20rpx">
<view class="flex-1 center h-72rpx rounded-12rpx bg-#14181B text-28rpx text-white" @click="handleSearch">
{{ t('pages-user.groupMealReservation.search') }}
</view>
<view class="flex-1 center h-72rpx rounded-12rpx bg-#F6F6F6 text-28rpx text-#333" @click="handleResetSearch">
{{ t('pages-user.groupMealReservation.reset') }}
</view>
</view>
</view>
<wd-tabs v-model="currentTab" :lineWidth="67" animated color="#14181B" inactiveColor="#666666" sticky
@change="tabsChange">
<wd-tab v-for="(item, index) in tabsList" :key="index" :title="item.title"/>
@@ -6,12 +6,11 @@ const {t} = useI18n()
const {paging, dataList, loading, queryList, firstLoaded} = usePage((pageNum, pageSize) => {
return appMerchantOrderDishListPost({
params: {pageNum, pageSize},
body: {
pageNum,
pageSize,
createBeginTime: dayjs().startOf('day').valueOf(),
createEndTime: dayjs().endOf('day').valueOf(),
}
},
})
})
</script>
@@ -1,16 +1,15 @@
<script lang="ts" setup>
import {useConfigStore} from "@/store";
import {formatOrderAmount, getPlatformServiceFee} from "@/utils/merchantOrder";
const {t} = useI18n();
const configStore = useConfigStore();
// 用户会员状态是否已开通
const show = ref(false);
const priceData = ref({})
const priceData = ref<Record<string, any>>({})
function onOpen(data: any, num: number) {
function onOpen(data: Record<string, any>) {
priceData.value = data
show.value = true;
}
@@ -19,6 +18,8 @@ function handleClose() {
show.value = false;
}
const platformFee = computed(() => getPlatformServiceFee(priceData.value))
defineExpose({
onOpen,
});
@@ -32,24 +33,31 @@ defineExpose({
>
<view>
<view class="center h-102rpx bg-#F7F7F7 text-40rpx lh-40rpx font-bold text-#333">
{{ t('pages-user.order.checkout.priceDetail.title') }}?
{{ t('pages-user.order.checkout.priceDetail.title') }}
</view>
<view class="border-bottom text-32rpx lh-32rpx font-500 text-#333 py-36rpx px-30rpx">
<view class="flex-center-sb mb-20rpx">
<view>{{ t('pages-user.order.checkout.priceDetail.serviceFees') }}</view>
<view>${{
(Number(priceData?.tip) + Number(priceData?.deliveryFee)).toFixed(2)
}}
</view>
<view>{{ t('pages-user.order.checkout.priceDetail.taxation') }}</view>
<view>${{ formatOrderAmount(priceData?.tax) }}</view>
</view>
<view v-if="priceData?.deliveryFeeCharged !== false && Number(priceData?.deliveryFee) > 0"
class="flex-center-sb mb-20rpx">
<view>{{ t('pages-user.order.checkout.priceDetail.deliveryFee') }}</view>
<view>${{ formatOrderAmount(priceData?.deliveryFee) }}</view>
</view>
<view v-if="priceData?.tipCharged !== false && Number(priceData?.tip) > 0"
class="flex-center-sb mb-20rpx">
<view>{{ t('pages-user.order.checkout.priceDetail.tip') }}</view>
<view>${{ formatOrderAmount(priceData?.tip) }}</view>
</view>
<view v-if="Number(platformFee) > 0" class="flex-center-sb mb-20rpx text-26rpx text-#999">
<view>{{ t('pages-user.order.platformServiceFee') }}</view>
<view>${{ platformFee }}</view>
</view>
<view class="text-24rpx lh-28rpx text-#9E9E9E">
{{ t('pages-user.order.checkout.priceDetail.desc') }}
{{ t('pages-user.order.checkout.priceDetail.platformFeeNote') }}
</view>
</view>
<view class="flex-center-sb border-bottom h-104rpx text-32rpx lh-32rpx font-500 text-#333 px-30rpx">
<view>{{ t('pages-user.order.checkout.priceDetail.taxation') }}</view>
<view>${{ Number(priceData?.tax) }}</view>
</view>
<view class="px-30rpx pt-40rpx">
<wd-button
block
@@ -66,4 +74,4 @@ defineExpose({
<style lang="scss" scoped>
</style>
</style>
@@ -0,0 +1,90 @@
<script lang="ts" setup>
import {appMerchantOrderRejectOrderPost} from '@/service'
import {useConfigStore} from '@/store'
const {t} = useI18n()
const emit = defineEmits(['close'])
const configStore = useConfigStore()
const show = ref(false)
const formData = reactive({
reason: '',
orderId: '',
})
function onOpen(orderId: string) {
formData.orderId = orderId
formData.reason = ''
show.value = true
}
function handleClose() {
show.value = false
}
function handleSubmit() {
if (!formData.reason.trim()) {
uni.showToast({
title: t('pages-user.order.toast.rejectOrderReasonRequired'),
icon: 'none',
})
return
}
appMerchantOrderRejectOrderPost({
body: {
orderId: formData.orderId,
reason: formData.reason.trim(),
},
}).then(() => {
uni.showToast({
title: t('toast.rejectSuccess'),
icon: 'none',
})
emit('close')
handleClose()
})
}
defineExpose({
onOpen,
})
</script>
<template>
<wd-popup v-model="show" custom-style="border-radius:32rpx 32rpx 0 0;" position="bottom" @close="handleClose">
<view class="px-30rpx pt-40rpx relative">
<view class="text-34rpx text-#333 font-bold text-center mb-37rpx">
{{ t('pages-user.order.rejectOrderReason') }}
</view>
<image
class="w-28rpx h-28rpx absolute top-40rpx right-30rpx"
src="@img/chef/100404.png"
@click="handleClose"
/>
<view class="min-h-234rpx box-border bg-#F7F7F7 rounded-14rpx overflow-hidden px-18rpx py-10rpx mb-36rpx">
<wd-textarea
v-model="formData.reason"
:maxlength="100"
:placeholder="t('pages-user.order.toast.rejectOrderReasonRequired')"
auto-height
custom-class="!bg-#F7F7F7"
custom-textarea-container-class="!bg-#F7F7F7"
no-border
/>
</view>
<wd-button
block
custom-class="!h-98rpx !text-30rpx !font-bold !rounded-16rpx !bg-#14181B"
@click="handleSubmit"
>
{{ t('common.submit') }}
</wd-button>
<view :style="[configStore.iosSafeBottomPlaceholder]"/>
</view>
</wd-popup>
</template>
+84 -70
View File
@@ -4,23 +4,29 @@ import {
appMerchantOrderAgreeRefundPost,
appMerchantOrderDetailPost,
appMerchantOrderReceiveOrderPost,
type MerchantOrderVo,
} from "@/service";
import RefusePopup from "./components/refuse-popup/refuse-popup.vue";
import RejectOrderPopup from "./components/reject-order-popup/reject-order-popup.vue";
import {OrderCancelStatus, OrderStatus} from "@/constant/enums";
import {callPhone, formatDateTimeRange, formatTimestampWithMonthName, navGoogleMap} from "@/utils/utils";
import {
formatOrderAmount,
getMerchantReceiveAmount,
getPlatformServiceFee,
payStatusLabel,
toOrderIdString,
type MerchantOrderDetailVo,
} from "@/utils/merchantOrder";
import {requireMerchantToken} from "@/utils/merchantToken";
import PriceDetail from "./components/price-detail/price-detail.vue";
import startDelivery from "./components/start-delivery/start-delivery.vue";
import OrderSkeleton from "./components/order-skeleton.vue";
import {useMessage} from "wot-design-uni";
import {rejectUserOrderApi} from "@/pages-user/service";
const message = useMessage();
const {t} = useI18n();
const configStore = useConfigStore()
const userStore = useUserStore()
const refusePopup = ref()
const rejectOrderPopup = ref()
const collapseValue = ref(false)
// 拨打电话
@@ -87,7 +93,7 @@ onShow(() => {
}
})
const orderDetail = ref<MerchantOrderVo>()
const orderDetail = ref<MerchantOrderDetailVo>()
const loading = ref(false)
function appMerchantOrderDetail() {
@@ -136,10 +142,12 @@ const priceDetailRef = ref(null)
// 打开价格明细
const openPriceDetail = () => {
priceDetailRef.value?.onOpen({
tip: orderDetail.value.tip,
tax: orderDetail.value.tax,
deliveryFee: orderDetail.value.deliveryFee
}, 0);
tip: orderDetail.value?.tip,
tax: orderDetail.value?.tax,
deliveryFee: orderDetail.value?.deliveryFee,
deliveryFeeCharged: orderDetail.value?.deliveryFeeCharged,
tipCharged: orderDetail.value?.tipCharged,
});
};
// 接单
@@ -165,23 +173,16 @@ function startReceiving() {
const startDeliveryRef = ref(null)
function startDeliveryFun() {
startDeliveryRef.value?.onOpen(orderDetail.value.id)
startDeliveryRef.value?.onOpen(toOrderIdString(orderDetail.value?.id))
}
// 点击已送达
function deliveredOrder() {
navigateTo('/pages-user/pages/order/delivered-order?id=' + orderDetail.value.id)
navigateTo('/pages-user/pages/order/delivered-order?id=' + toOrderIdString(orderDetail.value?.id))
}
// 核销订单
function writeOff() {
if (!userStore.currentMerchantToken) {
uni.showToast({
title: t('toast.pleaseSelectStore'),
icon: 'none',
})
return
}
if (!requireMerchantToken(userStore)) return
navigateTo('/pages-user/pages/scan-code/index')
}
@@ -190,39 +191,8 @@ function submitDelivery() {
}
// 拒绝开始订单, 直接拒绝用户的订单
function rejectStartOrder() {
message
.confirm({
title: t("common.prompt.system-prompt"),
msg: `${t("common.prompt.system-prompt-reject")}`,
confirmButtonText: t("common.yes"),
cancelButtonText: t("common.no"),
cancelButtonProps: {
customClass:
"!h-88rpx !w-258rpx !min-w-auto !text-30rpx !lh-42rpx !font-bold !border-#666666 !rounded-20rpx",
},
confirmButtonProps: {
customClass:
"!h-88rpx !w-258rpx !min-w-auto !text-30rpx !lh-42rpx !font-bold !bg-primary !rounded-20rpx",
},
})
.then(async () => {
rejectUserOrderApi({
orderId: orderId.value,
}).then(res => {
uni.showToast({
title: t('toast.rejectSuccess'),
icon: 'none'
})
setTimeout(() => {
// 获取订单详情
appMerchantOrderDetail()
}, 500)
})
})
.catch(() => {
});
rejectOrderPopup.value?.onOpen(orderId.value)
}
</script>
@@ -397,8 +367,8 @@ function rejectStartOrder() {
</view>
</template>
<!-- 自取已隐藏自取订单信息卡片 -->
<template v-if="false">
<!-- 自取订单信息卡片 -->
<template v-if="orderDetail?.receiveMethod === 2">
<view class="bg-white rounded-16rpx p-24rpx mb-20rpx flex-center-sb">
<view class="flex items-center text-28rpx text-#333">
<text>{{ t('pages-user.order.pickUp') }}:</text>
@@ -466,24 +436,61 @@ function rejectStartOrder() {
<!-- 订单总计 -->
<view class="mt-32rpx border-t-1rpx">
<view class="flex justify-between mb-16rpx text-30rpx text-#333333 font-normal">
<text class="">{{ t('pages.order.subtotal') }}</text>
<text class="">${{ orderDetail?.actualPrice }}</text>
<text>{{ t('pages.order.subtotal') }}</text>
<text>${{ formatOrderAmount(orderDetail?.actualPrice) }}</text>
</view>
<view class="flex justify-between mb-16rpx text-30rpx text-#333333 font-normal">
<view class="flex items-center">
<text class="">{{ t('pages.order.taxesAndFees') }}</text>
<image class="w-28rpx h-28rpx shrink-0 ml-10rpx" src="@img/chef/207.png" @click="openPriceDetail"></image>
</view>
<view class="flex items-center gap-16rpx">
<text class="">${{
(Number(orderDetail?.tax) + Number(orderDetail?.tip) + Number(orderDetail?.deliveryFee)).toFixed(2)
}}
</text>
<text>{{ t('pages.order.taxesAndFees') }}</text>
<image class="w-28rpx h-28rpx shrink-0 ml-10rpx" src="@img/chef/207.png" @click="openPriceDetail"/>
</view>
<text>${{ formatOrderAmount(orderDetail?.tax) }}</text>
</view>
<view class="flex justify-between text-30rpx text-#333333 font-normal">
<text class="">{{ t('pages.order.total') }}</text>
<text class="">${{ orderDetail?.paidAmount }}</text>
<view
v-if="Number(getPlatformServiceFee(orderDetail)) > 0"
class="flex justify-between mb-16rpx text-26rpx text-#999 font-normal"
>
<text>{{ t('pages-user.order.platformServiceFee') }}</text>
<text>${{ getPlatformServiceFee(orderDetail) }}</text>
</view>
<view class="flex justify-between mb-16rpx text-30rpx text-#333333 font-normal">
<text>{{ t('pages-user.order.customerPaidAmount') }}</text>
<text>${{ formatOrderAmount(orderDetail?.paidAmount) }}</text>
</view>
<view class="flex justify-between text-30rpx text-#333333 font-500">
<text>{{ t('pages-user.order.merchantReceiveAmount') }}</text>
<text class="text-#00A76D">${{ getMerchantReceiveAmount(orderDetail) }}</text>
</view>
</view>
</view>
<!-- 配送单信息 -->
<view
v-if="orderDetail?.merchantDeliveryOrderVo || orderDetail?.merchantDeliveryOrderId"
class="bg-white rounded-16rpx pt-32rpx mb-30rpx text-28rpx text-#333333 font-normal"
>
<view class="flex items-center mb-30rpx">
<view class="bg-#FF7112 w-10rpx h-30rpx mr-14rpx"/>
<text>{{ t('pages-user.order.deliveryOrderInfo') }}</text>
</view>
<view class="px-24rpx pb-24rpx">
<view v-if="orderDetail?.deliveryDate" class="flex-center-sb h-72rpx border-bottom">
<text class="text-#666">{{ t('pages-user.order.deliveryDate') }}</text>
<text>{{ orderDetail.deliveryDate }}</text>
</view>
<view
v-if="orderDetail?.merchantDeliveryOrderVo?.groupDeliveryFee != null"
class="flex-center-sb h-72rpx border-bottom"
>
<text class="text-#666">{{ t('pages-user.order.groupDeliveryFee') }}</text>
<text>${{ formatOrderAmount(orderDetail.merchantDeliveryOrderVo.groupDeliveryFee) }}</text>
</view>
<view
v-if="orderDetail?.merchantDeliveryOrderVo?.groupTip != null"
class="flex-center-sb h-72rpx"
>
<text class="text-#666">{{ t('pages-user.order.groupTip') }}</text>
<text>${{ formatOrderAmount(orderDetail.merchantDeliveryOrderVo.groupTip) }}</text>
</view>
</view>
</view>
@@ -522,7 +529,7 @@ function rejectStartOrder() {
</text>
</view>
<view class="flex-center-sb h-88rpx">
<view class="flex-center-sb h-88rpx border-bottom">
<text class="text-28rpx text-#333333 font-normal">{{ t('pages-user.order.payMethod') }}</text>
<text class="text-28rpx text-#333333 font-normal">
{{
@@ -530,6 +537,11 @@ function rejectStartOrder() {
}}
</text>
</view>
<view v-if="orderDetail?.payStatus != null" class="flex-center-sb h-88rpx">
<text class="text-28rpx text-#333333 font-normal">{{ t('pages-user.order.payStatus.title') }}</text>
<text class="text-28rpx text-#333333 font-normal">{{ payStatusLabel(orderDetail?.payStatus, t) }}</text>
</view>
</view>
</view>
</view>
@@ -637,8 +649,8 @@ function rejectStartOrder() {
</view>
</template>
</template>
<!-- 自取已隐藏自取订单底部操作按钮 -->
<template v-if="false">
<!-- 自取订单底部操作按钮 -->
<template v-if="orderDetail?.receiveMethod === 2">
<template v-if="orderStatus === OrderStatus.HAS_PENDING_PAYMENT">
<view class="">
<view :style="[configStore.iosSafeBottomPlaceholder]" class="h-118rpx"></view>
@@ -675,6 +687,8 @@ function rejectStartOrder() {
</template>
</template>
</template>
<!-- 拒绝接单 -->
<reject-order-popup ref="rejectOrderPopup" @close="appMerchantOrderDetail"/>
<!-- 拒绝取消订单 -->
<refuse-popup ref="refusePopup" @close="appMerchantOrderDetail"/>
<!-- 价格详情 -->
-5
View File
@@ -4,11 +4,6 @@ import {http} from '@/utils/http'
// 获取州列表
export const getStateListApi = () => http.post<Record<string, any>>('/app/continent/list')
// 拒绝用户订单
export const rejectUserOrderApi = (data: {
orderId: string
}) => http.post<Record<string, any>>('/app/merchantOrder/rejectOrder', data)
// 获取字典列表信息
export const getDictFineList = (data: Record<string, any>) =>
http.post<Dict[]>('/app/dict/findList', data);
@@ -5,6 +5,7 @@ import {appMerchantIndexDataGet, appMerchantOrderDishListPost, appMerchantOrderO
import {OrderStatus} from "@/constant/enums";
import dayjs from "dayjs";
import Config from "@/config";
import {requireMerchantToken} from "@/utils/merchantToken";
const configStore = useConfigStore()
const userStore = useUserStore()
@@ -12,26 +13,15 @@ const emits = defineEmits(['changeStore'])
const {t} = useI18n()
const MERCHANT_TOKEN_REQUIRED_PATHS = [
'/pages-user/pages/scan-code/index',
'/pages-user/pages/group-meal-reservation/index',
]
function navigateTo(url: string) {
if (userStore.checkLogin()) {
if (url === '/pages-user/pages/scan-code/index' && !userStore.currentMerchantToken) {
uni.showToast({
title: t('toast.pleaseSelectStore'),
icon: 'none',
})
return
}
if (url === '/pages-user/pages/group-meal-reservation/index' && !userStore.currentMerchantToken) {
uni.showToast({
title: t('toast.pleaseSelectStore'),
icon: 'none',
})
return
}
uni.navigateTo({
url,
})
}
if (!userStore.checkLogin()) return
if (MERCHANT_TOKEN_REQUIRED_PATHS.includes(url) && !requireMerchantToken(userStore)) return
uni.navigateTo({url})
}
const orderTabsList = ref([
@@ -186,12 +176,11 @@ const reservationList = ref([])
function getReservationList() {
appMerchantOrderDishListPost({
params: {pageNum: 1, pageSize: 10},
body: {
pageNum: 1,
pageSize: 10,
createBeginTime: dayjs().startOf('day').valueOf(),
createEndTime: dayjs().endOf('day').valueOf(),
}
},
}).then(res => {
reservationList.value = res.rows
})
@@ -124,14 +124,15 @@ defineExpose({
>{{ t('pages-user.order.delivered') }}
</wd-button>
<!-- 自取已隐藏 -->
<!-- 自取待接单 -->
<wd-button
v-if="false"
v-if="+item.receiveMethod === 2 && +item.orderStatus === OrderStatus.HAS_PENDING_PAYMENT"
class="!h-56rpx !rounded-56rpx !text-28rpx text-#fff"
>{{ t('pages-user.order.receiving') }}
</wd-button>
<!-- 自取已接单待核销 -->
<wd-button
v-if="false"
v-if="+item.receiveMethod === 2 && +item.orderStatus === OrderStatus.MERCHANT_ACCEPTED"
class="!h-56rpx !rounded-56rpx !text-28rpx text-#fff"
@click.stop="navigateTo('/pages-user/pages/scan-code/index')">
{{ t('pages-user.order.writeOff') }}
+7 -27
View File
@@ -11,7 +11,7 @@ import store from "./components/tabbar-home/components/store.vue";
import Config from "@/config";
import {useMessage} from "wot-design-uni";
import type UseCode from "@/components/use-code/use-code.vue";
import {appMerchantSwitchMerchantIdGet, appMessageUnreadCountPost} from "@/service";
import {appMessageUnreadCountPost} from "@/service";
import {getDictFineList} from "@/pages-user/service";
import {appUpdate} from "@/utils/update";
@@ -94,23 +94,13 @@ function changeStore() {
}
// 确认切换店铺了
function confirmChangeStore(data) {
async function confirmChangeStore(data: { value: string }) {
console.log('切换店铺了', data)
if (userStore.currenMerchantInfo && data.value === userStore.currenMerchantInfo?.id) return
appMerchantSwitchMerchantIdGet({
params: {
merchantId: data.value
}
}).then(res => {
if (res.data) {
userStore.currentMerchantToken = res.data
userStore.getSwitchableMerchantInfo()
handleTabbarChange({value: activeIndex.value})
}
// 查询商户首页数据
// tabbarHomeRef.value?.initData()
})
const ok = await userStore.switchMerchant(String(data.value))
if (ok) {
handleTabbarChange({value: activeIndex.value})
}
}
function handleTabbarChange({value}: { value: string }) {
@@ -230,17 +220,7 @@ onShow(() => {
getUnreadMessageCount()
userStore.getFirstShopSettled()
userStore.getSwitchableMerchants(() => {
// 自动切换店铺
setTimeout(() => {
console.log('开始自动切换店铺')
if (!userStore.currentMerchantToken && userStore.merchants.length > 0) {
console.log('自动切换店铺', userStore.merchants[0].id)
console.log('自动切换店铺', userStore.merchants[0].merchantName)
confirmChangeStore({
value: userStore.merchants[0].id
})
}
}, 10)
userStore.ensureMerchantTokenOnLogin()
})
userStore.getSwitchableMerchantInfo()
}
+4 -4
View File
@@ -3,9 +3,9 @@ import request from '@/http/vue-query';
import type { CustomRequestOptions } from '@/http/types';
export type GroupMealReservationVo = {
id?: number;
merchantId?: number;
userId?: number;
id?: string;
merchantId?: string;
userId?: string;
peopleCount?: number;
perCapitaPrice?: number;
scene?: string;
@@ -41,7 +41,7 @@ export type GroupMealReservationQueryBo = {
};
export type GroupMealReservationStatusBo = {
id: number;
id: string;
status: 2 | 3 | 4 | 5;
handleRemark?: string;
};
+25 -2
View File
@@ -5,6 +5,24 @@ import type { CustomRequestOptions } from '@/http/types';
import * as API from './types';
/** 商家拒绝接单 POST /app/merchantOrder/rejectOrder */
export async function appMerchantOrderRejectOrderPost({
body,
options,
}: {
body: { orderId: string; reason: string };
options?: CustomRequestOptions;
}) {
return request<API.R>('/app/merchantOrder/rejectOrder', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** 商家同意退款 POST /app/merchantOrder/agreeRefund */
export async function appMerchantOrderAgreeRefundPost({
params,
@@ -208,10 +226,12 @@ export async function appMerchantOrderDetailPost({
/** 菜品列表(根据预约时间查询) POST /app/merchantOrder/dishList */
export async function appMerchantOrderDishListPost({
params,
body,
options,
}: {
body: API.TimeSearchBo;
params: { pageNum: number; pageSize: number };
body?: API.TimeSearchBo;
options?: CustomRequestOptions;
}) {
return request<API.TableDataInfoMerchantDishVo>(
@@ -221,7 +241,10 @@ export async function appMerchantOrderDishListPost({
headers: {
'Content-Type': 'application/json',
},
data: body,
params: {
...params,
},
data: body || {},
...(options || {}),
}
);
+22 -7
View File
@@ -277,7 +277,7 @@ export type AppMerchantMenuRemovePostBody = number[];
export type AppMerchantOrderAgreeRefundPostParams =
{
'orderId'?: number;
'orderId'?: string;
}
@@ -289,7 +289,7 @@ export type AppMerchantOrderCanUseCouponListmerchantIdGetParams =
export type AppMerchantOrderDetailPostParams =
{
'orderId'?: number;
'orderId'?: string;
}
@@ -308,7 +308,7 @@ export type AppMerchantOrderOrderListPostParams =
export type AppMerchantOrderReceiveOrderPostParams =
{
'orderId'?: number;
'orderId'?: string;
}
@@ -747,7 +747,7 @@ export type AppVersionVo =
export type ArrivedOrderBo =
{
/** 订单id */
'orderId'?: number;
'orderId'?: string;
/** 送达图片 */
'deliveryPhotos'?: string;
}
@@ -1640,7 +1640,7 @@ export type DeleteCartBo =
export type DeliverOrderBo =
{
/** 订单id */
'orderId'?: number;
'orderId'?: string;
/** 配送员手机号 */
'deliveryPhone'?: string;
/** 配送员头像 */
@@ -3338,7 +3338,7 @@ export type MerchantOrderVo =
/** 请求参数 */
'params'?: MapObject;
/** 主键ID */
'id'?: number;
'id'?: string | number;
/** 用户ID */
'userId'?: number;
/** 商家ID */
@@ -3363,6 +3363,21 @@ export type MerchantOrderVo =
'tipDiscount'?: number;
/** 配送费 */
'deliveryFee'?: number;
/** 当前订单是否承载顾客配送费支付 */
'deliveryFeeCharged'?: boolean;
/** 当前订单是否承载顾客小费支付 */
'tipCharged'?: boolean;
/** 关联配送单 ID */
'merchantDeliveryOrderId'?: string;
/** 配送日期 yyyy-MM-dd */
'deliveryDate'?: string;
/** 配送单信息 */
'merchantDeliveryOrderVo'?: {
'id'?: string;
'deliveryDate'?: string;
'groupDeliveryFee'?: number;
'groupTip'?: number;
};
/** 是否支付周配送费(1-是 2-否) */
'weeklyDeliveryFee'?: number;
/** 周配送费 */
@@ -4246,7 +4261,7 @@ export type RecommendMerchantBo =
export type RejectRefundBo =
{
/** 订单id */
'orderId'?: number;
'orderId'?: string;
/** 拒绝原因 */
'rejectReason'?: string;
}
+22 -4
View File
@@ -8,6 +8,7 @@ import {
appUserGetLoginUserGet
} from '@/service'
import Config from '@/config'
import {extractMerchantTokenFromSwitchRes} from '@/utils/merchantToken'
export const useUserStore = defineStore(
'user',
@@ -128,14 +129,30 @@ export const useUserStore = defineStore(
// 切换商户 /app/merchant/switch/{merchantId}
const switchMerchant = async (merchantId: string) => {
if (!isLogin.value) return
if (!isLogin.value) return false
try {
const res = await appMerchantSwitchMerchantIdGet({
merchantId,
options: {}
params: {merchantId},
})
console.log('切换商户', res)
const token = extractMerchantTokenFromSwitchRes(res)
if (!token) return false
currentMerchantToken.value = token
await getSwitchableMerchantInfo()
return true
} catch (e) {
return false
}
}
/** 登录后若无 merchantToken,自动切换到第一个店铺 */
const ensureMerchantTokenOnLogin = async () => {
if (!isLogin.value || currentMerchantToken.value) return
if (!merchants.value.length) {
await getSwitchableMerchants()
}
const first = merchants.value[0] as { id?: string | number } | undefined
if (first?.id) {
await switchMerchant(String(first.id))
}
}
@@ -168,6 +185,7 @@ export const useUserStore = defineStore(
getSwitchableMerchants,
getSwitchableMerchantInfo,
switchMerchant,
ensureMerchantTokenOnLogin,
getFirstShopSettled,
}
},
+24 -11
View File
@@ -2,21 +2,17 @@ import type {CustomRequestOptions} from '@/interceptor/request'
import {useConfigStore, useUserStore} from '@/store'
import Config from '@/config'
import {i18n} from "@/locale";
import {isMerchantTokenMissingMessage, refreshMerchantToken} from '@/utils/merchantToken'
type IRes<T> = T extends ArrayBuffer ? ArrayBuffer : IResData<T>
type HttpOptions = CustomRequestOptions & { _merchantTokenRetried?: boolean }
export const http = <T>(options: CustomRequestOptions) => {
console.log(options, 'options')
// 1. 返回 Promise 对象
function requestOnce<T>(options: HttpOptions): Promise<IRes<T>> {
return new Promise<IRes<T>>((resolve, reject) => {
uni.request({
...options,
dataType: 'json',
// 响应成功
success(res) {
console.log(res, '111111')
const ErrorMessage = {
401: i18n.global.t('common.prompt.authentication-failed-please-log-in'),
700: i18n.global.t('common.prompt.login-expired-please-log-in-again'),
@@ -29,7 +25,8 @@ export const http = <T>(options: CustomRequestOptions) => {
// @ts-ignore
configStore.serverTime = +data.systemTime
}
if (data instanceof ArrayBuffer || data.code === 200) {
const jeecgSuccess = (data as any).code === 0 && (data as any).success === true
if (data instanceof ArrayBuffer || data.code === 200 || jeecgSuccess) {
resolve(data)
} else if (data.code === 401 || data.code === 700) {
uni.showToast({
@@ -43,16 +40,30 @@ export const http = <T>(options: CustomRequestOptions) => {
} else if (data.code === 711) {
reject(data)
} else {
// 其他错误 -> 根据后端错误信息轻提示
const errMsg = (res.data as IResData<T>).msg || (res.data as any).message || ''
if (isMerchantTokenMissingMessage(errMsg) && !options._merchantTokenRetried) {
refreshMerchantToken(userStore).then((ok) => {
if (ok) {
http<T>({...options, _merchantTokenRetried: true}).then(resolve).catch(reject)
} else {
!options.hideErrorToast &&
uni.showToast({
icon: 'none',
title: errMsg || i18n.global.t('toast.pleaseSelectStore'),
})
reject(data)
}
})
return
}
!options.hideErrorToast &&
uni.showToast({
icon: 'none',
title: (res.data as IResData<T>).msg || i18n.global.t('common.prompt.request-incorrect'),
title: errMsg || i18n.global.t('common.prompt.request-incorrect'),
})
reject(data)
}
},
// 响应失败
fail(err) {
uni.showToast({
icon: 'none',
@@ -64,6 +75,8 @@ export const http = <T>(options: CustomRequestOptions) => {
})
}
export const http = <T>(options: HttpOptions) => requestOnce<T>(options)
/**
* GET 请求
* @param url 后台地址
+62
View File
@@ -0,0 +1,62 @@
import type {MerchantOrderVo} from '@/service'
/** 配送单信息(按文档扩展) */
export type MerchantDeliveryOrderVo = {
id?: string
deliveryDate?: string
groupDeliveryFee?: number
groupTip?: number
}
/** 商家端订单详情扩展字段 */
export type MerchantOrderDetailVo = MerchantOrderVo & {
id?: string | number
deliveryFeeCharged?: boolean
tipCharged?: boolean
merchantDeliveryOrderId?: string
deliveryDate?: string
merchantDeliveryOrderVo?: MerchantDeliveryOrderVo
}
export function formatOrderAmount(value?: number | string | null) {
if (value == null || value === '') return '0.00'
const num = Number(value)
if (Number.isNaN(num)) return '0.00'
return num.toFixed(2)
}
/** 商家到账金额,优先 merchantReceiveAmount */
export function getMerchantReceiveAmount(order?: Pick<MerchantOrderDetailVo, 'merchantReceiveAmount' | 'actualPrice'>) {
if (order?.merchantReceiveAmount != null) {
return formatOrderAmount(order.merchantReceiveAmount)
}
return formatOrderAmount(order?.actualPrice)
}
/** 平台费用(配送费+小费,归平台) */
export function getPlatformServiceFee(order?: Pick<MerchantOrderDetailVo, 'tip' | 'deliveryFee' | 'deliveryFeeCharged' | 'tipCharged'>) {
if (!order) return '0.00'
let total = 0
if (order.deliveryFeeCharged !== false) {
total += Number(order.deliveryFee) || 0
}
if (order.tipCharged !== false) {
total += Number(order.tip) || 0
}
return total.toFixed(2)
}
export function toOrderIdString(id?: string | number | null) {
if (id == null || id === '') return ''
return String(id)
}
export function payStatusLabel(status?: number, t?: (key: string) => string) {
if (status == null || !t) return '-'
const map: Record<number, string> = {
1: t('pages-user.order.payStatus.paying'),
2: t('pages-user.order.payStatus.success'),
3: t('pages-user.order.payStatus.failed'),
}
return map[status] || String(status)
}
+56
View File
@@ -0,0 +1,56 @@
import type {useUserStore} from '@/store'
import {i18n} from '@/locale'
type UserStore = ReturnType<typeof useUserStore>
/** 切换店铺接口:文档约定 msg 返回 merchantToken,兼容 data */
export function extractMerchantTokenFromSwitchRes(res: { data?: unknown; msg?: string }) {
const msg = typeof res.msg === 'string' ? res.msg.trim() : ''
if (msg && msg !== '操作成功' && msg.length > 10 && !/^[\u4e00-\u9fa5]+$/.test(msg)) {
return msg
}
if (typeof res.data === 'string' && res.data.trim()) {
return res.data.trim()
}
return ''
}
export function isMerchantTokenMissingMessage(message?: string) {
if (!message) return false
return message.includes('商户端请先切换店铺') || message.includes('请先切换店铺')
}
/** 登录后或 token 失效时,自动切换到第一个可用店铺 */
export async function ensureMerchantToken(userStore: UserStore) {
if (!userStore.isLogin) return false
if (userStore.currentMerchantToken) return true
if (!userStore.merchants?.length) {
await userStore.getSwitchableMerchants()
}
const first = userStore.merchants?.[0]
if (!first?.id) return false
return userStore.switchMerchant(String(first.id))
}
/** 切换指定店铺并保存 merchantToken */
export async function switchToMerchant(userStore: UserStore, merchantId: string) {
if (!userStore.isLogin || !merchantId) return false
return userStore.switchMerchant(merchantId)
}
export async function refreshMerchantToken(userStore: UserStore) {
userStore.currentMerchantToken = ''
return ensureMerchantToken(userStore)
}
/** 商家端接口调用前检查 merchantToken */
export function requireMerchantToken(userStore: UserStore): boolean {
if (userStore.currentMerchantToken) return true
uni.showToast({
icon: 'none',
title: i18n.global.t('toast.pleaseSelectStore'),
})
return false
}