修改样式
This commit is contained in:
@@ -1,19 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
appMerchantOrderDetailPost,
|
||||
appCollectCollectPost,
|
||||
type MerchantOrderVo,
|
||||
appUserCardSelectDefaultPost, appMerchantOrderPayOrderPost, appMerchantOrderCancelOrderPost
|
||||
appUserCardSelectDefaultPost,
|
||||
appMerchantOrderPayOrderPost,
|
||||
appMerchantOrderCancelOrderPost,
|
||||
appMerchantOrderZipPayVoucherPost,
|
||||
} from "@/service";
|
||||
import { debounce } from 'throttle-debounce'
|
||||
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 Collection from "@/components/collection/index.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 {CollectionType, OrderStatus, EventEnum, OrderCancelStatus} from "@/constant/enums";
|
||||
import {OrderStatus, EventEnum, OrderCancelStatus} from "@/constant/enums";
|
||||
import {formatTimestampWithMonthName, formatTimestampShort, navGoogleMap, callPhone} from "@/utils/utils";
|
||||
import useEventEmit from "@/hooks/useEventEmit";
|
||||
const configStore = useConfigStore();
|
||||
@@ -115,6 +116,39 @@ const orderStatus = computed(() => {
|
||||
return ''
|
||||
})
|
||||
|
||||
// ====== 为设计稿准备的数据结构(商品缩略卡/总件数/总价等)======
|
||||
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 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
|
||||
@@ -133,29 +167,6 @@ const callPhoneFn = (phone: string) => {
|
||||
callPhone(phone)
|
||||
}
|
||||
|
||||
// 收藏店铺
|
||||
function handleCollectionClick() {
|
||||
debouncedEmit(orderDetail.value?.merchantVo?.id, CollectionType.STORE, ()=> {
|
||||
if (orderDetail.value?.merchantVo) {
|
||||
orderDetail.value.merchantVo.isCollect = !orderDetail.value.merchantVo.isCollect
|
||||
}
|
||||
})
|
||||
}
|
||||
// 防抖处理函数
|
||||
const debouncedEmit = debounce(1300, (id: any, type: CollectionType, callback: ()=> void) => {
|
||||
// 收藏接口
|
||||
appCollectCollectPost({
|
||||
body: {
|
||||
targetId: id,
|
||||
targetType: type
|
||||
}
|
||||
}).then(res=> {
|
||||
callback()
|
||||
})
|
||||
}, {
|
||||
atBegin: true, // 立即触发
|
||||
})
|
||||
|
||||
// 支付参数
|
||||
const payMethodOptions = ref({
|
||||
orderId: '',
|
||||
@@ -227,21 +238,72 @@ function openQrCode() {
|
||||
function navigateTo(url: string) {
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
// 已支付上传凭证(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: 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
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<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"
|
||||
v-if="!loading"
|
||||
>
|
||||
<view class="order-detail-page">
|
||||
<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">
|
||||
@@ -289,7 +351,10 @@ function navigateTo(url: string) {
|
||||
</view>
|
||||
</view>
|
||||
<!-- 订单进度 -->
|
||||
<view v-if="orderDetail?.refundStatus !== OrderCancelStatus.APPLIED || orderDetail?.refundStatus !== OrderCancelStatus.APPROVED" class="mb-52rpx px-30rpx">
|
||||
<view
|
||||
v-if="orderDetail?.refundStatus !== OrderCancelStatus.APPLIED && orderDetail?.refundStatus !== OrderCancelStatus.APPROVED"
|
||||
class="mb-52rpx px-30rpx"
|
||||
>
|
||||
<OrderProgress
|
||||
:steps="orderSteps"
|
||||
:current-status="orderStatus"
|
||||
@@ -350,58 +415,77 @@ function navigateTo(url: string) {
|
||||
</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">
|
||||
<template v-for="item in orderDetail?.deliveryPhotos?.split(',')">
|
||||
<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" />
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="w-full h-16rpx bg-#F6F6F6"></view>
|
||||
</view>
|
||||
|
||||
<!-- 商品列表 -->
|
||||
<view class="px-30rpx py-36rpx">
|
||||
<!-- 商家信息 -->
|
||||
<view @click="navigateTo('/pages-store/pages/store/index?id=' + orderDetail?.merchantVo?.id)" class="flex-center-sb h-80rpx mb-36rpx">
|
||||
<view class="flex items-center">
|
||||
<image
|
||||
:src="orderDetail?.merchantVo?.logo"
|
||||
mode="aspectFill"
|
||||
class="w-80rpx h-80rpx rounded-full bg-#F2F2F2 mr-24rpx shrink-0"
|
||||
/>
|
||||
<text class="text-30rpx lh-30rpx text-#333 font-500">{{ orderDetail?.merchantVo?.merchantName }}</text>
|
||||
<image
|
||||
src="@img/chef/142.png"
|
||||
class="w-32rpx h-32rpx shrink-0 ml-10rpx"
|
||||
></image>
|
||||
</view>
|
||||
<collection :is-collected="orderDetail?.merchantVo?.isCollect" @collectionChange="handleCollectionClick" />
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="item in orderDetail?.merchantOrderDishVoList"
|
||||
:key="item.id"
|
||||
class="flex items-start mb-32rpx last:mb-0"
|
||||
>
|
||||
<!-- 商品图片 -->
|
||||
<view class="w-136rpx h-136rpx rounded-16rpx overflow-hidden mr-20rpx shrink-0">
|
||||
<image
|
||||
:src="item.merchantDishVo?.dishImage?.split(',')[0]"
|
||||
mode="aspectFill"
|
||||
class="w-full h-full bg-#F2F2F2"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 商品信息 -->
|
||||
<view class="flex-1">
|
||||
<text class="text-30rpx lh-30rpx text-#333 font-500 block mb-20rpx">{{ item.merchantDishVo?.dishName }}</text>
|
||||
<view class="flex-center-sb text-24rpx lh-24rpx text-#7D7D7D mb-24rpx">
|
||||
<text class="line-clamp-1">{{ item.merchantSideDishVo?.sideDishName }} {{ item.merchantSideDishItemVo?.name }}</text>
|
||||
<!-- 数量 -->
|
||||
<view class="shrink-0 text-28rpx lh-28rpx text-#333 text-right font-500">
|
||||
X {{ item.count }}
|
||||
<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>
|
||||
<text class="text-30rpx lh-30rpx text-#333 font-500">{{ `$${item.merchantDishVo?.discountPrice}` }}</text>
|
||||
|
||||
<!-- 商品缩略卡横向滚动 -->
|
||||
<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-1">{{ dishTitle(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<view class="goods-price-right">
|
||||
<text class="goods-price">${{ orderTotalPrice }}</text>
|
||||
<text class="goods-count">
|
||||
{{ t('pages.order.totalItemCount', { count: orderTotalItemCount }) }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -409,7 +493,7 @@ function navigateTo(url: string) {
|
||||
<!-- 分隔线 -->
|
||||
<view class="w-full h-16rpx bg-#F6F6F6"></view>
|
||||
|
||||
<view v-if="orderDetail?.receiveMethod === 1" class="pt-36rpx">
|
||||
<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>
|
||||
|
||||
<!-- 收货地址 -->
|
||||
@@ -441,7 +525,6 @@ function navigateTo(url: string) {
|
||||
{{ orderDetail?.deliveryMethod }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 联系电话 -->
|
||||
<view
|
||||
class="flex items-center py-36rpx px-30rpx"
|
||||
>
|
||||
@@ -457,7 +540,7 @@ function navigateTo(url: string) {
|
||||
</view>
|
||||
<!-- 分隔线 -->
|
||||
|
||||
<view v-else class="px-30rpx pt-36rpx">
|
||||
<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">
|
||||
@@ -486,7 +569,7 @@ function navigateTo(url: string) {
|
||||
|
||||
<view class="w-full h-16rpx bg-#F6F6F6"></view>
|
||||
|
||||
<view class="border-bottom px-30rpx py-36rpx text-36rpx lh-36rpx text-#333 ">
|
||||
<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">
|
||||
@@ -501,11 +584,10 @@ function navigateTo(url: string) {
|
||||
</view>
|
||||
</view>
|
||||
<!-- 下单时间 mb-40rpx根据支付状态显示 -->
|
||||
<view class="flex-center-sb text-30rpx lh-30rpx" :class="[orderStatus !== OrderStatus.PENDING_PAYMENT ? '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">
|
||||
@@ -516,14 +598,9 @@ function navigateTo(url: string) {
|
||||
mode="aspectFill"
|
||||
class="w-44rpx h-44rpx shrink-0 mr-10rpx"
|
||||
/>
|
||||
<text>{{ orderDetail?.payMethod === 1 ? t('pages-user.choosePaymethod.creditCard') : t('pages-user.choosePaymethod.wallet') }}</text>
|
||||
<text>{{ payMethodText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 支付时间 -->
|
||||
<view class="flex-center-sb text-30rpx lh-30rpx">
|
||||
<text>{{ t('pages-user.member.payTime') }}</text>
|
||||
<text>{{ formatTimestampWithMonthName(orderDetail?.payTime) }}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
@@ -607,11 +684,20 @@ function navigateTo(url: string) {
|
||||
</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 @click="goPay" custom-class="!h-108rpx !bg-14181B !text-36rpx !lh-108rpx !text-#fff !rounded-16rpx" block>
|
||||
<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-52rpx text-36rpx lh-36rpx text-#333 font-500">
|
||||
<view @click="openCancelOrder" class="text-center mt-22rpx text-28rpx lh-28rpx text-#333 font-500">
|
||||
{{ t('common.cancel') }}
|
||||
</view>
|
||||
</template>
|
||||
@@ -678,13 +764,111 @@ function navigateTo(url: string) {
|
||||
<!-- 支付订单 -->
|
||||
<password-container @success="payPawSuccess" ref="passwordInputRef" />
|
||||
<!-- 核销订单 -->
|
||||
<use-code ref="useCodeRef" />
|
||||
<use-code ref="useCodeRef" />
|
||||
<!-- 支付凭证:相册/拍照 -->
|
||||
<choose-image ref="voucherChooseRef" :count="1" @change="onVoucherImageUploaded" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<style>
|
||||
page {
|
||||
background-color: #fff;
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user