1016 lines
34 KiB
Vue
1016 lines
34 KiB
Vue
<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> |