This commit is contained in:
2026-04-14 15:02:00 +08:00
parent ec9282a64f
commit d2077f5844
23 changed files with 1551 additions and 428 deletions
+185 -51
View File
@@ -16,6 +16,7 @@ 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();
@@ -239,28 +240,107 @@ 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 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 : ''
}
// 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
}
// 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: Number(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
// }
// }
const FIXED_VOUCHER_URL = 'https://www.howhowfresh.com/prod-api/resource/oss/download/2037827804362121218'
async function openUploadVoucher() {
const id = orderDetail.value?.id
if (id == null || String(id).trim() === '') {
uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' })
@@ -271,8 +351,8 @@ async function onVoucherImageUploaded(urls: unknown) {
try {
await appMerchantOrderZipPayVoucherPost({
body: {
orderId: Number(id),
zipPayVoucher,
orderId: id,
zipPayVoucher: FIXED_VOUCHER_URL,
},
options: { hideErrorToast: true },
})
@@ -292,7 +372,28 @@ async function onVoucherImageUploaded(urls: unknown) {
<template>
<view class="order-detail-page">
<navbar />
<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"
@@ -324,36 +425,26 @@ async function onVoucherImageUploaded(urls: unknown) {
</view>
</template>
<!-- 商家拒绝订单 -->
<template v-if="orderStatus === OrderStatus.MERCHANT_REJECTED">
<view class="px-30rpx pt-20rpx pb-50rpx">
<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-20rpx pb-50rpx">
<view class="text-40rpx lh-36rpx text-#333 font-500">
<template v-if="orderDetail?.receiveMethod === 1">
{{ t('pages-store.order.estimatedDeliveryTime') }}
</template>
<template v-else>{{ t('pages-store.order.upTime') }}</template>
:
<!-- 订单预计送达时间-->
{{ formatTimestampShort(orderDetail?.endScheduledTime) }}
<!-- 顶栏已展示预计送达/下单时间此处仅保留提示类副文案 -->
<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-28rpx text-#7D7D7D mt-26rpx">
<view>{{ t('pages-store.order.orderTime') }}: {{ formatTimestampShort(orderDetail?.createTime) }}</view>
<!-- 订单30分钟自动取消--待支付 -->
<view v-if="orderStatus === OrderStatus.PENDING_PAYMENT">{{ t('pages-store.order.autoCancellation') }}</view>
</view>
<view class="text-28rpx lh-28rpx text-#7D7D7D mt-26rpx" v-if="orderDetail?.refundStatus === OrderCancelStatus.REJECTED">
<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="mb-52rpx px-30rpx"
class="order-detail-progress-wrap mb-52rpx px-30rpx"
>
<OrderProgress
:steps="orderSteps"
@@ -475,7 +566,7 @@ async function onVoucherImageUploaded(urls: unknown) {
x{{ item?.count }}
</view>
</view>
<text class="goods-caption line-clamp-1">{{ dishTitle(item) }}</text>
<text class="goods-caption line-clamp-2">{{ dishTitle(item) }}</text>
</view>
</view>
</scroll-view>
@@ -683,17 +774,17 @@ async function onVoucherImageUploaded(urls: unknown) {
</template>
</template>
<template v-else>
<!-- 待支付 -->
<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>
<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>
@@ -765,8 +856,8 @@ async function onVoucherImageUploaded(urls: unknown) {
<password-container @success="payPawSuccess" ref="passwordInputRef" />
<!-- 核销订单 -->
<use-code ref="useCodeRef" />
<!-- 支付凭证:相册/拍照 -->
<choose-image ref="voucherChooseRef" :count="1" @change="onVoucherImageUploaded" />
<!-- 支付凭证:相册/拍照(暂时不使用文件上传,改用固定URL -->
<choose-image ref="voucherChooseRef" :count="1" />
</view>
</view>
</template>
@@ -871,4 +962,47 @@ page {
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>