Files
cheflinkuser/src/pages-store/pages/order/index.vue
T
2026-06-17 23:29:04 +08:00

1016 lines
34 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import {
appMerchantOrderDetailPost,
type MerchantOrderVo,
appUserCardSelectDefaultPost,
appMerchantOrderPayOrderPost,
appMerchantOrderCancelOrderPost,
appMerchantOrderZipPayVoucherPost,
} from "@/service";
import ChooseImage from '@/components/choose-image/choose-image.vue'
const { t } = useI18n();
import OrderProgress from './components/order-progress.vue'
import OrderDetailSkeleton from './components/order-detail-skeleton.vue'
import PriceDetail from "@/pages-store/pages/order/components/price-detail.vue";
import CancelOrder from "@/pages-store/pages/order/components/cancel-order.vue";
import {useConfigStore} from "@/store";
import {OrderStatus, EventEnum, OrderCancelStatus} from "@/constant/enums";
import {formatTimestampWithMonthName, formatTimestampShort, navGoogleMap, callPhone} from "@/utils/utils";
import dayjs from 'dayjs'
import useEventEmit from "@/hooks/useEventEmit";
const configStore = useConfigStore();
// 价格明细
const priceDetailRef = ref<InstanceType<typeof PriceDetail>>();
// 打开价格明细
const openPriceDetail = () => {
priceDetailRef.value?.onOpen({
tip: orderDetail.value.tip,
tax: orderDetail.value.tax,
deliveryFee: orderDetail.value.deliveryFee,
}, 0);
};
// 取消订单
const cancelOrderRef = ref<InstanceType<typeof CancelOrder>>();
// 打开取消订单
const openCancelOrder = () => {
cancelOrderRef.value?.onOpen();
};
function confirmCancel(reason: string) {
console.log('取消订单', reason)
appMerchantOrderCancelOrderPost({
body: {
orderId: orderDetail.value.id,
cancelReason: reason,
}
}).then(res=> {
uni.showToast({
title: '取消订单成功',
icon: 'none',
})
setTimeout(() => {
appMerchantOrderDetail()
}, 500)
})
}
// 订单步骤数据(配送订单)
const orderSteps = ref([
{ label: t('pages-store.order.orderStatus.ordered'), value: OrderStatus.PENDING_PAYMENT }, // 代付款
{ label: t('pages-store.order.orderStatus.paid'), value: OrderStatus.HAS_PENDING_PAYMENT }, // 已付款
{ label: t('pages-store.order.orderStatus.received'), value: OrderStatus.MERCHANT_ACCEPTED },// 商家已接单
{ label: t('pages-store.order.orderStatus.delivering'), value: OrderStatus.DELIVERING }, // 配送中
{ label: t('pages-store.order.orderStatus.delivered'), value: OrderStatus.COMPLETED }// 已送达
])
// 订单步骤数据(自取订单)
const orderStepsCancel = ref([
{ label: t('pages-store.order.orderStatus.ordered'), value: OrderStatus.PENDING_PAYMENT }, // 代付款
{ label: t('pages-store.order.orderStatus.ready'), value: OrderStatus.MERCHANT_ACCEPTED }, // 商家接单
{ label: t('pages-store.order.orderStatus.completed'), value: OrderStatus.COMPLETED },// 已核销
])
// 页面加载状态
const loading = ref(true);
const orderId = ref('')
onLoad((options: any)=> {
if(options.id) {
orderId.value = options.id;
// appMerchantOrderDetail()
// 查询用户默认信用卡
appUserCardSelectDefault()
}
})
onShow(()=> {
nextTick(()=> {
appMerchantOrderDetail()
})
})
const orderDetail = ref<MerchantOrderVo>()
function appMerchantOrderDetail() {
loading.value = true;
appMerchantOrderDetailPost({
params: {
orderId: orderId.value,
}
}).then((res: any)=> {
console.log('订单详情', res)
orderDetail.value = res.data
// 是自取订单还是配送订单 1-派送 2-自取
if(orderDetail.value) {
if(+orderDetail.value.receiveMethod === 2) {
orderSteps.value = orderStepsCancel.value
}
}
}).finally(() => {
loading.value = false;
})
}
// 订单状态
const orderStatus = computed(() => {
if(orderDetail.value) {
return orderDetail.value.orderStatus
}
return ''
})
/** 税费及其他费用:按订单维度展示,非承载订单 deliveryFee/tip 为 0 */
const taxesAndOtherFeesTotal = computed(() => {
const d = orderDetail.value
return (
(Number(d?.tax) || 0) +
(Number(d?.tip) || 0) +
(Number(d?.deliveryFee) || 0)
).toFixed(2)
})
const orderDeliveryDateLabel = computed(() => {
const date = String((orderDetail.value as any)?.deliveryDate ?? '').trim()
if (!date) return ''
const d = dayjs(date)
return d.isValid() ? d.format('MM/DD/YYYY') : date
})
// ====== 为设计稿准备的数据结构(商品缩略卡/总件数/总价等)======
const orderDishList = computed(() => {
const list = orderDetail.value?.merchantOrderDishVoList as unknown as Array<any> | null | undefined
if (!Array.isArray(list)) return []
return list
})
const orderTotalItemCount = computed(() => {
return orderDishList.value.reduce((sum, item) => sum + (Number(item?.count) || 0), 0)
})
const orderTotalItemCountText = computed(() => {
return `${t('pages.order.totalItemCountPrefix')}${orderTotalItemCount.value}${t('pages.order.totalItemCountSuffix')}`
})
const orderTotalPrice = computed(() => {
const n = orderDetail.value?.paidAmount ?? orderDetail.value?.actualPrice ?? 0
return Number(n).toFixed(2)
})
function dishCover(dishItem: any) {
const img = dishItem?.merchantDishVo?.dishImage
if (!img || typeof img !== 'string') return ''
return img.split(',')[0] || ''
}
function dishTitle(dishItem: any) {
return dishItem?.merchantDishVo?.dishName ?? ''
}
const payMethodText = computed(() => {
// 1-信用卡 2-余额(wallet
return orderDetail.value?.payMethod === 1
? t('pages-user.choosePaymethod.creditCard')
: t('pages-user.choosePaymethod.wallet')
})
// 复制订单号
const copyOrderNumber = (text: string) => {
if(!text) return
uni.setClipboardData({
data: text,
success: () => {
uni.showToast({
title: t('toast.orderNumberCopied'),
icon: 'none'
})
}
})
}
// 拨打电话
const callPhoneFn = (phone: string) => {
callPhone(phone)
}
// 支付参数
const payMethodOptions = ref({
orderId: '',
cardId: '',
cardNumber: '',
payMethod: 1, // 支付方式 1信用卡 2余额
payPassword: '',
})
// 支付密码输入框 ref
const passwordInputRef = ref()
useEventEmit(EventEnum.CHOOSE_PAYMENT_METHOD, (data) => {
if(data) {
if(data.payMethod === 1) {
payMethodOptions.value.cardId = data.cardId
payMethodOptions.value.cardNumber = data.cardNumber
payMethodOptions.value.payMethod = 1
} else {
payMethodOptions.value.payMethod = 2
}
}
})
function appUserCardSelectDefault() {
appUserCardSelectDefaultPost({}).then(res=> {
console.log('查询用户默认信用卡', res)
payMethodOptions.value.cardId = res.data?.cardId || ''
payMethodOptions.value.cardNumber = res.data?.cardNumber || ''
})
}
// 立即支付订单
function goPay() {
// 如果是余额支付,弹出支付密码弹窗
if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput()
return
}
// 信用卡支付:必须已绑定卡(与 appMerchantOrderPayOrder 入参一致,避免 cardId/cardNumber 为空仍请求)
if (payMethodOptions.value.payMethod === 1) {
const cardId = String(payMethodOptions.value.cardId || '').trim()
if (!cardId) {
uni.showToast({
title: t('pages-store.order.pleaseBindCreditCard'),
icon: 'none',
})
return
}
}
appMerchantOrderPayOrder()
}
function payPawSuccess(password: string) {
payMethodOptions.value.payPassword = password
appMerchantOrderPayOrder()
}
function appMerchantOrderPayOrder() {
appMerchantOrderPayOrderPost({
body: {
...payMethodOptions.value,
orderId: orderDetail.value.id,
}
}).then(res=> {
console.log('支付结果', res)
uni.showToast({
title: '支付成功',
icon: 'none'
})
setTimeout(()=> {
appMerchantOrderDetail()
}, 500)
})
}
function navGoogleMapFn() {
navGoogleMap(orderDetail.value?.merchantVo?.latitude + ',' + orderDetail.value?.merchantVo?.longitude)
}
const useCodeRef = ref()
function openQrCode() {
useCodeRef.value?.init(orderDetail.value?.orderNo || '')
}
function navigateTo(url: string) {
uni.navigateTo({ url })
}
/** 订单详情顶栏:与设计稿一致的 MM/DD HH:mm */
function formatOrderNavScheduleTime(timestamp?: number | string | null) {
if (timestamp == null || timestamp === '') return ''
const n = Number(timestamp)
if (!Number.isFinite(n)) return ''
return dayjs(n).format('MM/DD HH:mm')
}
function handleOrderDetailBack() {
const pages = getCurrentPages?.() || []
if (pages.length <= 1) {
uni.switchTab({ url: '/pages/home/index' })
return
}
uni.navigateBack()
}
/** 顶栏居中展示「预计送达 / 下单时间」:非取消、非退款申请中、非商家拒绝 */
const showOrderNavTimeBlock = computed(() => {
if (!orderDetail.value) return false
if (orderStatus.value === OrderStatus.CANCELLED) return false
if (orderDetail.value.refundStatus === OrderCancelStatus.APPLIED) return false
if (orderStatus.value === OrderStatus.MERCHANT_REJECTED) return false
return true
})
const orderNavPrimaryLine = computed(() => {
const d = orderDetail.value
if (!d) return ''
const isDelivery = +(d.receiveMethod ?? 0) === 1
const label = isDelivery
? t('pages-store.order.estimatedDeliveryTime')
: t('pages-store.order.upTime')
const timePart = formatOrderNavScheduleTime(d.endScheduledTime) || '--'
const suffix = isDelivery ? t('pages-store.order.beforeDeadline') : ''
return `${label} : ${timePart}${suffix}`
})
const orderNavSecondaryLine = computed(() => {
const d = orderDetail.value
if (!d) return ''
const ct = d.createTime
const timeStr =
formatOrderNavScheduleTime(ct) ||
(ct != null && ct !== '' ? formatTimestampShort(Number(ct)) : '')
return `${t('pages-store.order.orderTime')}: ${timeStr || '--'}`
})
// 已支付上传凭证(Zip 等线下支付)
const voucherChooseRef = ref<InstanceType<typeof ChooseImage>>()
const voucherSubmitting = ref(false)
function openUploadVoucher() {
voucherChooseRef.value?.init()
}
function normalizeVoucherUrl(payload: unknown): string {
if (Array.isArray(payload)) {
const first = payload[0]
return typeof first === 'string' ? first : ''
}
return typeof payload === 'string' ? payload : ''
}
async function onVoucherImageUploaded(urls: unknown) {
const zipPayVoucher = normalizeVoucherUrl(urls)
if (!zipPayVoucher) {
uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' })
return
}
const id = orderDetail.value?.id
if (id == null || String(id).trim() === '') {
uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' })
return
}
if (voucherSubmitting.value) return
voucherSubmitting.value = true
try {
await appMerchantOrderZipPayVoucherPost({
body: {
orderId: id,
zipPayVoucher,
},
options: { hideErrorToast: true },
})
uni.showToast({ title: t('pages-store.order.voucherSubmitSuccess'), icon: 'none' })
setTimeout(() => {
appMerchantOrderDetail()
}, 500)
}
catch {
uni.showToast({ title: t('pages-store.order.voucherSubmitFailed'), icon: 'none' })
}
finally {
voucherSubmitting.value = false
}
}
</script>
<template>
<view class="order-detail-page">
<wd-navbar
safeAreaInsetTop
fixed
placeholder
:bordered="false"
custom-class="order-detail-navbar !bg-white"
@click-left="handleOrderDetailBack"
>
<template #left>
<view class="shrink-0">
<view class="order-detail-navbar-circle center">
<view class="i-carbon:chevron-left text-44rpx text-#111"></view>
</view>
</view>
</template>
<template #title>
<view v-if="!loading && orderDetail && showOrderNavTimeBlock" class="order-detail-nav-times">
<text class="order-detail-nav-primary">{{ orderNavPrimaryLine }}</text>
<text class="order-detail-nav-secondary">{{ orderNavSecondaryLine }}</text>
</view>
</template>
</wd-navbar>
<view
class="animate-in fade-in animate-ease-out animate-duration-300"
v-show="loading"
>
<!-- 骨架屏 -->
<OrderDetailSkeleton />
</view>
<view
class="animate-in fade-in animate-ease-in animate-duration-300 bg-white"
v-if="!loading"
>
<!-- 已取消-成功取消 -->
<template v-if="orderStatus === OrderStatus.CANCELLED">
<view class="px-30rpx pt-20rpx pb-50rpx">
<view class="text-40rpx lh-36rpx text-#333 font-500">{{ t('pages-store.order.cancelled') }}</view>
<view class="text-28rpx lh-28rpx text-#7D7D7D mt-26rpx">
{{ t('pages-store.order.cancellationTime') }}: {{ formatTimestampShort(orderDetail?.cancelTime) }}
</view>
</view>
</template>
<!-- 已取消-等待商家同意 -->
<template v-else-if="orderDetail?.refundStatus === OrderCancelStatus.APPLIED">
<view class="px-30rpx pt-20rpx pb-50rpx">
<view class="text-40rpx lh-36rpx text-#333 font-500">{{ t('pages-store.order.cancellationTitle') }}</view>
<view class="text-28rpx lh-28rpx text-#7D7D7D mt-26rpx">
{{ t('pages-store.order.cancellationReasonDesc') }}
</view>
<view class="text-28rpx lh-28rpx text-#7D7D7D mt-26rpx">{{ t('pages-store.order.cancellationReason') }}{{ orderDetail?.cancelReason }}</view>
</view>
</template>
<!-- 商家拒绝订单 -->
<template v-else-if="orderStatus === OrderStatus.MERCHANT_REJECTED">
<view class="px-30rpx pt-8rpx pb-40rpx">
<view class="text-40rpx lh-36rpx text-#333 font-500">{{ t('pages-store.order.orderStatus.merchantRejected') }}</view>
<view class="text-28rpx lh-28rpx text-#7D7D7D mt-26rpx">{{ t('pages-store.order.orderStatus.merchantRejectedDesc') }}</view>
</view>
</template>
<template v-else>
<!-- 顶栏已展示预计送达/下单时间此处仅保留提示类副文案 -->
<view class="px-30rpx pt-8rpx pb-24rpx" v-if="orderStatus === OrderStatus.PENDING_PAYMENT || orderDetail?.refundStatus === OrderCancelStatus.REJECTED">
<view class="text-28rpx lh-36rpx text-#7D7D7D" v-if="orderStatus === OrderStatus.PENDING_PAYMENT">
{{ t('pages-store.order.autoCancellation') }}
</view>
<view class="text-28rpx lh-36rpx text-#7D7D7D mt-16rpx" v-if="orderDetail?.refundStatus === OrderCancelStatus.REJECTED">
{{ t('pages-store.order.rejectReason') }}{{ orderDetail?.rejectReason }}
</view>
</view>
<!-- 订单进度紧接顶栏时间信息 -->
<view
v-if="orderDetail?.refundStatus !== OrderCancelStatus.APPLIED && orderDetail?.refundStatus !== OrderCancelStatus.APPROVED"
class="order-detail-progress-wrap mb-52rpx px-30rpx"
>
<OrderProgress
:steps="orderSteps"
:current-status="orderStatus"
/>
</view>
<!-- 自取订单展示核销码按钮-->
<view class="px-30rpx pb-52rpx" v-if="orderDetail?.receiveMethod === 2 && orderStatus === OrderStatus.MERCHANT_ACCEPTED">
<wd-button block
custom-class="w-full !h-98rpx !text-30rpx !lh-42rpx !font-bold !rounded-20rpx !bg-#14181B"
@click="openQrCode">
{{ t('pages-store.order.writeOff') }}
</wd-button>
</view>
<!-- 自取订单展示核销码按钮-->
<!-- <OrderProgress-->
<!-- :steps="orderSteps"-->
<!-- :current-status="1"-->
<!-- />-->
</template>
<!-- 分隔线 -->
<view class="w-full h-16rpx bg-#F6F6F6"></view>
<!-- 配送员信息 -->
<view v-if="
orderDetail?.receiveMethod === 1 && (
orderStatus === OrderStatus.DELIVERING ||
orderStatus === OrderStatus.COMPLETED)
" class="pt-36rpx">
<view class="text-36rpx lh-36rpx text-#333 font-500 pl-30rpx">{{ t('pages-store.view-reviews.deliveryDriver') }}</view>
<view @click="callPhoneFn(orderDetail?.deliveryPhone)" class="flex-center-sb py-36rpx px-30rpx">
<view class="flex items-center">
<image
:src="orderDetail?.deliveryAvatar"
mode="aspectFill"
class="w-80rpx h-80rpx rounded-full shrink-0"
/>
<view class="ml-24rpx">
<text class="text-30rpx lh-30rpx font-500 text-#333 block mb-6rpx">
{{ orderDetail?.deliveryFirstName }} {{ orderDetail?.deliverySurname }}
</text>
<text class="text-24rpx lh-24rpx text-#7D7D7D">{{ t('pages-store.order.acceptanceTime') }}: {{ formatTimestampWithMonthName(orderDetail?.startDeliveryTime) }}
</text>
</view>
</view>
<image
src="@img/chef/153.png"
mode="aspectFill"
class="w-66rpx h-66rpx shrink-0"
/>
</view>
<!-- 送达信息-已送达 -->
<view v-if="orderStatus === OrderStatus.COMPLETED" class="px-30rpx pb-36rpx">
<view class="text-30rpx lh-30rpx text-#333">
<text class="mr-30rpx">{{ t('pages-store.order.deliveryTime') }}</text>
<text>{{ formatTimestampWithMonthName(orderDetail?.deliveryTime) }}</text>
</view>
<view class="text-30rpx lh-30rpx text-#333 mb-24rpx mt-36rpx">{{ t('pages-store.order.deliveryPhotos') }}</view>
<view class="flex items-center gap-20rpx">
<view
v-for="(item, idx) in orderDetail?.deliveryPhotos?.split(',')"
:key="`${idx}-${item}`"
>
<wd-img width="158rpx" height="158rpx" radius="16rpx" mode="aspectFill" :src="item" :enable-preview="true" />
</view>
</view>
</view>
<view class="w-full h-16rpx bg-#F6F6F6"></view>
</view>
<!-- 商品列表 -->
<view class="goods-section px-30rpx py-24rpx">
<view class="goods-layout">
<view class="goods-left">
<!-- 门店行:图标 + 店铺名 + 右箭头 -->
<view
@click="navigateTo('/pages-store/pages/store/index?id=' + orderDetail?.merchantVo?.id)"
class="store-row-detail flex-center-sb mb-20rpx"
>
<view class="flex items-center min-w-0">
<image
src="@img/chef/126.png"
class="w-40rpx h-40rpx shrink-0 mr-16rpx"
mode="aspectFit"
/>
<text class="text-30rpx lh-36rpx text-#333 font-500 line-clamp-1">
{{ orderDetail?.merchantVo?.merchantName }}
</text>
</view>
<image
src="@img/chef/142.png"
class="w-28rpx h-28rpx shrink-0"
mode="aspectFit"
/>
</view>
<!-- 商品缩略卡横向滚动 -->
<scroll-view
scroll-x
class="goods-scroll"
:show-scrollbar="false"
:enable-flex="true"
>
<view class="goods-track">
<view
v-for="(item, di) in orderDishList"
:key="item.id ?? di"
class="goods-cell"
>
<view class="goods-img-wrap">
<image
:src="dishCover(item)"
mode="aspectFill"
class="goods-img"
/>
<view v-if="Number(item?.count) > 1" class="goods-qty">
x{{ item?.count }}
</view>
</view>
<text class="goods-caption line-clamp-2">{{ dishTitle(item) }}</text>
</view>
</view>
</scroll-view>
</view>
<view class="goods-price-right">
<text class="goods-price">${{ orderTotalPrice }}</text>
<text class="goods-count">
{{ orderTotalItemCountText }}
</text>
</view>
</view>
</view>
<!-- 分隔线 -->
<view class="w-full h-16rpx bg-#F6F6F6"></view>
<view v-if="orderDetail?.receiveMethod === 1" class="pt-36rpx bg-white">
<view class="text-36rpx lh-36rpx text-#333 font-500 pl-30rpx mb-4rpx">{{ t('pages-store.order.deliveryAddress') }}</view>
<view
v-if="orderDeliveryDateLabel"
class="text-28rpx lh-28rpx text-#6D6D6D pl-30rpx mb-16rpx"
>
{{ t('pages-store.order.deliveryDate') }}: {{ orderDeliveryDateLabel }}
</view>
<!-- 收货地址 -->
<view class="flex items-center border-bottom py-36rpx px-30rpx">
<image
src="@img/chef/145.png"
mode="aspectFill"
class="w-44rpx h-44rpx relative z-1 shrink-0"
/>
<!-- 地址信息 -->
<view class="ml-28rpx">
<text
class="text-32rpx lh-32rpx text-#333 block mb-8rpx line-clamp-1"
>{{ orderDetail?.merchantOrderUserAddressVo?.formattedAddress }}</text
>
<text class="text-28rpx lh-28rpx text-#6D6D6D">{{ orderDetail?.merchantOrderUserAddressVo?.displayName }}</text>
</view>
</view>
<!-- 配送偏好 -->
<view
class="flex items-center border-bottom py-36rpx px-30rpx"
>
<image
src="@img/chef/1333.png"
mode="aspectFill"
class="w-44rpx h-44rpx relative z-1"
/>
<view class="ml-28rpx text-32rpx lh-32rpx text-#333">
{{ orderDetail?.deliveryMethod }}
</view>
</view>
<view
class="flex items-center py-36rpx px-30rpx"
>
<image
src="@img/chef/1334.png"
mode="aspectFill"
class="w-44rpx h-44rpx relative z-1"
/>
<view class="ml-28rpx text-32rpx lh-32rpx text-#333">
{{ orderDetail?.areaCode }} {{ orderDetail?.phone }}
</view>
</view>
</view>
<!-- 分隔线 -->
<view v-else class="px-30rpx pt-36rpx bg-white">
<view class="text-36rpx lh-36rpx text-#333 font-bold">{{ t('pickupAddress') }}</view>
<view class="flex-center-sb py-40rpx">
<view class="flex items-center">
<image
src="@img/chef/145.png"
mode="aspectFill"
class="w-44rpx h-44rpx shrink-0 mr-28rpx"
/>
<view>
<view class="text-30rpx lh-30rpx text-#333 mb-18rpx line-clamp-1">{{ orderDetail?.merchantVo?.merchantAddress }}</view>
<view class="text-28rpx lh-28rpx text-#6D6D6D">{{ orderDetail?.merchantVo?.merchantName }}</view>
</view>
</view>
<view @click="navGoogleMapFn" class="w-66rpx h-66rpx ml-20rpx center shrink-0 rounded-50% border-#333 border-solid border-1px">
<image
src="@img/chef/127.png"
mode="aspectFill"
class="w-62rpx h-62rpx"
/>
</view>
</view>
</view>
<view class="w-full h-16rpx bg-#F6F6F6"></view>
<view class="bg-white border-bottom px-30rpx py-36rpx text-36rpx lh-36rpx text-#333 ">
<view class="font-500 text-36rpx lh-36rpx mb-40rpx">{{ t('pages-store.order.orderInfo') }}</view>
<!-- 订单编号 -->
<view @click="copyOrderNumber(orderDetail?.orderNo)" class="flex-center-sb text-30rpx lh-30rpx mb-40rpx">
<text>{{ t('pages-store.order.orderNumber') }}</text>
<view class="flex items-center">
{{ orderDetail?.orderNo }}
<image
src="@img/chef/1340.png"
mode="aspectFill"
class="w-20rpx h-20rpx shrink-0 ml-10rpx"
/>
</view>
</view>
<!-- 下单时间 mb-40rpx根据支付状态显示 -->
<view class="flex-center-sb text-30rpx lh-30rpx mb-40rpx">
<text>{{ t('pages-store.order.orderTime') }}</text>
<text>{{ formatTimestampWithMonthName(orderDetail?.createTime) }}</text>
</view>
<template v-if="orderStatus !== OrderStatus.PENDING_PAYMENT">
<!-- 支付方式 -->
<view class="flex-center-sb text-30rpx lh-30rpx mb-40rpx">
<text>{{ t('pages-user.member.paymentMethod') }}</text>
<view class="flex items-center">
<image
src="@img/chef/138.png"
mode="aspectFill"
class="w-44rpx h-44rpx shrink-0 mr-10rpx"
/>
<text>{{ payMethodText }}</text>
</view>
</view>
</template>
</view>
<!-- 费用明细 -->
<view
:class="[ orderStatus === OrderStatus.PENDING_PAYMENT ? '' : 'pb-68rpx' ]"
class="px-30rpx pt-32rpx text-32rpx lh-32rpx text-#333">
<view class="flex-center-sb mb-40rpx">
<text>{{ t('pages-store.order.subtotal') }}</text>
<text>${{ orderDetail?.actualPrice }}</text>
</view>
<view class="flex-center-sb mb-40rpx">
<view @click="openPriceDetail" class="flex items-center">
<text>{{ t('pages-store.order.taxesAndOtherFees') }}</text>
<image
src="@img/chef/1336.png"
class="w-28rpx h-28rpx shrink-0 ml-10rpx mt-4rpx"
mode="aspectFit"
/>
</view>
<view>
<text>${{ taxesAndOtherFeesTotal }}</text>
</view>
</view>
<view class="flex-center-sb">
<text>{{ t('pages-store.order.total') }}</text>
<text>${{ orderDetail.paidAmount }}</text>
</view>
</view>
<!-- 订单支付 -->
<view
v-if="orderStatus === OrderStatus.PENDING_PAYMENT"
@click="navigateTo('/pages-user/pages/choose-paymethod/index')"
class="flex-center-sb text-32rpx lh-32rpx font-500 text-#333 py-36rpx px-30rpx pb-68rpx"
>
<view class="flex items-center">
<image
src="@img/chef/138.png"
class="w-44rpx h-44rpx mr-28rpx shrink-0"
mode="aspectFit"
/>
<text class="">
<template v-if="payMethodOptions.payMethod === 1">{{ t('pages-user.choosePaymethod.creditCard') }}</template>
<template v-else>{{ t('pages-user.choosePaymethod.wallet') }}</template>
</text>
</view>
<view class="flex items-center">
<view class="mr-12px">
<template v-if="payMethodOptions.payMethod === 1">
<!--判断用户是否有信用卡-->
<text v-if="!payMethodOptions.cardId">{{ t("pages-user.member.creditCard") }}</text>
<text v-else>{{ payMethodOptions.cardNumber }}</text>
</template>
<template v-else-if="payMethodOptions.payMethod === 2">
<text>{{ t('pages-user.choosePaymethod.wallet') }}</text>
</template>
</view>
<image
src="@img/chef/142.png"
class="w-32rpx h-32rpx shrink-0"
mode="aspectFit"
/>
</view>
</view>
<!-- 操作按钮 -->
<view class="px-30rpx pb-30rpx">
<!--申请取消订单中.已同意取消订单-->
<template v-if="+orderDetail.refundStatus === OrderCancelStatus.APPLIED || +orderDetail.refundStatus === OrderCancelStatus.APPROVED">
<template v-if="+orderDetail.refundStatus === OrderCancelStatus.APPLIED">
<wd-button custom-class="!h-108rpx !bg-transparent !text-36rpx !font-500 !lh-108rpx !text-#333 !rounded-16rpx !border-#666666 !border-solid !border-1rpx" block>
{{ t('pages-store.order.orderStatus.pending') }}
</wd-button>
</template>
<template v-if="+orderDetail.refundStatus === OrderCancelStatus.APPROVED">
<wd-button custom-class="!h-108rpx !bg-transparent !text-36rpx !font-500 !lh-108rpx !text-#333 !rounded-16rpx !border-#666666 !border-solid !border-1rpx" block>
{{ t('pages-store.order.orderStatus.agree') }}
</wd-button>
</template>
</template>
<template v-else>
<template v-if="orderStatus === OrderStatus.PENDING_PAYMENT">
<!-- 上传支付凭证 -->
<wd-button
:loading="voucherSubmitting"
:disabled="voucherSubmitting"
@click="openUploadVoucher"
custom-class="!h-108rpx !bg-transparent !text-32rpx !font-500 !lh-108rpx !text-#333 !rounded-46rpx !border-#666666 !border-solid !border-1rpx"
block
>
{{ t('pages-store.order.uploadPaidVoucher') }}
</wd-button>
<wd-button @click="goPay" custom-class="!h-108rpx !bg-14181B !text-32rpx !lh-108rpx !text-#fff !rounded-46rpx !mt-22rpx" block>
{{ t('common.goPay') }}
</wd-button>
<view @click="openCancelOrder" class="text-center mt-22rpx text-28rpx lh-28rpx text-#333 font-500">
{{ t('common.cancel') }}
</view>
</template>
<!-- 配送订单 -->
<template v-if="orderDetail?.receiveMethod === 1">
<!-- 待接单/已接单/配送中 -->
<template v-if="
orderStatus === OrderStatus.HAS_PENDING_PAYMENT ||
orderStatus === OrderStatus.MERCHANT_ACCEPTED ||
orderStatus === OrderStatus.DELIVERING
">
<!-- 已经被拒绝过不能在申请了 -->
<wd-button v-if="orderDetail?.refundStatus !== OrderCancelStatus.REJECTED" @click="openCancelOrder" custom-class="!h-108rpx !bg-transparent !text-36rpx !font-500 !lh-108rpx !text-#333 !rounded-16rpx !border-#666666 !border-solid !border-1rpx" block>
{{ t('common.cancel') }}
</wd-button>
</template>
<!--已完成,评价-->
<template v-else-if="orderStatus === OrderStatus.COMPLETED">
<template v-if="orderDetail?.dishReviewVoList.length > 0">
<wd-button @click="navigateTo('/pages-store/pages/order/view-reviews?id=' + orderDetail.id)" custom-class="!h-108rpx !bg-transparent !text-36rpx !font-500 !lh-108rpx !text-#333 !rounded-16rpx !border-#666666 !border-solid !border-1rpx" block>
{{ t('pages-store.view-reviews.viewTitle') }}
</wd-button>
</template>
<template v-else>
<wd-button @click="navigateTo('/pages-store/pages/order/evaluate?id=' + orderDetail.id)" custom-class="!h-108rpx !bg-14181B !text-36rpx !lh-108rpx !text-#fff !rounded-16rpx" block>
{{ t('common.evaluate') }}
</wd-button>
</template>
</template>
</template>
<template v-else>
<template v-if="
orderStatus === OrderStatus.HAS_PENDING_PAYMENT || orderStatus === OrderStatus.MERCHANT_ACCEPTED
">
<!-- 已经被拒绝过不能在申请了 -->
<wd-button v-if="orderDetail?.refundStatus !== OrderCancelStatus.REJECTED" @click="openCancelOrder" custom-class="!h-108rpx !bg-transparent !text-36rpx !font-500 !lh-108rpx !text-#333 !rounded-16rpx !border-#666666 !border-solid !border-1rpx" block>
{{ t('common.cancel') }}
</wd-button>
</template>
<template v-if="orderStatus === OrderStatus.COMPLETED">
<template v-if="orderDetail?.dishReviewVoList.length > 0">
<wd-button @click="navigateTo('/pages-store/pages/order/view-reviews?id=' + orderDetail.id)" custom-class="!h-108rpx !bg-transparent !text-36rpx !font-500 !lh-108rpx !text-#333 !rounded-16rpx !border-#666666 !border-solid !border-1rpx" block>
{{ t('pages-store.view-reviews.viewTitle') }}
</wd-button>
</template>
<template v-else>
<wd-button @click="navigateTo('/pages-store/pages/order/evaluate?id=' + orderDetail.id)" custom-class="!h-108rpx !bg-14181B !text-36rpx !lh-108rpx !text-#fff !rounded-16rpx" block>
{{ t('common.evaluate') }}
</wd-button>
</template>
</template>
</template>
</template>
<!--申请取消订单中-->
<view :style="[configStore.iosSafeBottomPlaceholder]"></view>
</view>
<!-- 价格明细 -->
<price-detail ref="priceDetailRef" />
<!-- 取消订单 -->
<cancel-order @confirm="confirmCancel" ref="cancelOrderRef" />
<!-- 支付订单 -->
<password-container @success="payPawSuccess" ref="passwordInputRef" />
<!-- 核销订单 -->
<use-code ref="useCodeRef" />
<!-- 支付凭证:相册/拍照,上传后回调真实 URL -->
<choose-image ref="voucherChooseRef" :count="1" @change="onVoucherImageUploaded" />
</view>
</view>
</template>
<style>
page {
background-color: #F6F6F6;
}
</style>
<style scoped>
/* 订单详情:商品缩略卡横向滚动(对齐设计稿) */
.goods-section {
background: #fff;
}
.goods-layout {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
.goods-left {
flex: 1;
min-width: 0;
}
.store-row-detail {
align-items: center;
}
.goods-price-right {
flex-shrink: 0;
text-align: right;
padding-left: 24rpx;
padding-bottom: 10rpx;
}
.goods-price {
display: block;
font-size: 32rpx;
line-height: 40rpx;
font-weight: 700;
color: #14181B;
}
.goods-count {
display: block;
margin-top: 8rpx;
font-size: 24rpx;
line-height: 30rpx;
color: #7D7D7D;
font-weight: 500;
}
.goods-scroll {
width: 100%;
}
.goods-track {
display: flex;
flex-direction: row;
gap: 16rpx;
padding-right: 8rpx;
}
.goods-cell {
width: 128rpx;
flex-shrink: 0;
}
.goods-img-wrap {
position: relative;
width: 128rpx;
height: 128rpx;
border-radius: 16rpx;
overflow: hidden;
background: #F2F2F2;
}
.goods-img {
width: 100%;
height: 100%;
}
.goods-qty {
position: absolute;
right: 6rpx;
bottom: 6rpx;
min-width: 36rpx;
padding: 4rpx 10rpx;
background: rgba(20, 24, 27, 0.85);
color: #fff;
font-size: 20rpx;
line-height: 24rpx;
border-radius: 8rpx;
text-align: center;
}
.goods-caption {
display: block;
margin-top: 10rpx;
font-size: 22rpx;
line-height: 28rpx;
color: #333;
}
.order-detail-navbar-circle {
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background-color: #fff;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
}
.order-detail-nav-times {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 0 8rpx;
max-width: 480rpx;
}
.order-detail-nav-primary {
font-size: 28rpx;
line-height: 36rpx;
font-weight: 600;
color: #14181b;
text-align: center;
}
.order-detail-nav-secondary {
margin-top: 6rpx;
font-size: 24rpx;
line-height: 30rpx;
color: #7d7d7d;
text-align: center;
}
.order-detail-progress-wrap {
padding-top: 8rpx;
}
:deep(.order-detail-navbar.wd-navbar .wd-navbar__title) {
max-width: 520rpx;
overflow: visible;
white-space: normal;
}
</style>