修复bug

This commit is contained in:
2026-04-14 17:45:41 +08:00
parent d2077f5844
commit a89610c245
12 changed files with 454 additions and 125 deletions
+2
View File
@@ -23,6 +23,8 @@ const Config = {
shareLink: "https://www.howhowfresh.com/h5/",
shareImage: "https://hanguomcn.oss-ap-northeast-2.aliyuncs.com/images/20250901105756_1756695476183_56ac07ac.png",
shareDesc: "分享专属二维码邀请新用户注册即邀请成功。一起来注册体验点餐功能。",
// Zelle 支付二维码图片地址
zellePayPath: "https://www.howhowfresh.com/minio/ruoyi/2026/04/14/ef120c97e50c419da2263a59d6679229.png",
// 登录端口
userPort: 1,
// 手机区号数组
+1
View File
@@ -666,6 +666,7 @@
"coupon": {
"all-merchants": "Applicable to all merchants",
"expiry-date": "Expiry date: ",
"merchant-only": "Only available at {name}",
"merchant-specific": "For specific merchant use",
"no-coupons": "You currently do not have any coupons",
"redeem-now": "Redeem now",
+1
View File
@@ -666,6 +666,7 @@
"coupon": {
"all-merchants": "适用于所有商户使用",
"expiry-date": "到期日:",
"merchant-only": "仅{name}可用",
"merchant-specific": "指定商户使用",
"no-coupons": "您目前没有任何优惠券",
"redeem-now": "立即兑换",
+2 -2
View File
@@ -2,8 +2,8 @@
"name" : "CHEFLINK delivery",
"appid" : "__UNI__06509BE",
"description" : "",
"versionName" : "3.0.6",
"versionCode" : 306,
"versionName" : "3.1.0",
"versionCode" : 310,
"transformPx" : false,
/* 5+App */
"app-plus" : {
+291 -23
View File
@@ -2,6 +2,7 @@
import { useConfigStore, useUserStore } from "@/store";
import { dayjs } from "@/plugin/index";
import Config from '@/config/index'
import ChooseImage from '@/components/choose-image/choose-image.vue'
import CheckoutSkeleton from "./components/checkout-skeleton.vue";
import ChangePhone from "./components/change-phone.vue";
import PriceDetail from "./components/price-detail.vue";
@@ -19,7 +20,8 @@ import {
appMerchantOrderCreateOrderCartBatchPost,
appMerchantOrderCalculatePriceCartBatchPost,
appMerchantCartListMerchantPost,
appMerchantOrderPayOrderBatchPost
appMerchantOrderPayOrderBatchPost,
appMerchantOrderZipPayVoucherPost
} from "@/service";
import useEventEmit from "@/hooks/useEventEmit";
import {EventEnum} from "@/constant/enums";
@@ -268,14 +270,90 @@ const openPriceDetail = () => {
function navigateTo(url: string) {
uni.navigateTo({ url })
}
function chooseCardForCheckout() {
payMethodSelected.value = 1
uni.navigateTo({
url: '/pages-user/pages/select-credit-card/index',
events: {
selectedCard: function(data: any) {
if (data) {
payMethodOptions.value.cardId = data.cardId || ''
payMethodOptions.value.cardNumber = data.cardNumber || ''
}
},
},
})
}
// 支付参数
const payMethodOptions = ref({
orderId: '',
cardId: '',
cardNumber: '',
payMethod: 1, // 支付方式 1信用卡 2余额
payPassword: '',
})
const payMethodPopupVisible = ref(false)
const payMethodSelected = ref(1)
const zellePopupVisible = ref(false)
const zelleOrderIdForVoucher = ref('')
const voucherChooseRef = ref<InstanceType<typeof ChooseImage>>()
const voucherSubmitting = ref(false)
const zellePayPath = Config.zellePayPath;
function openPayMethodPopup() {
payMethodSelected.value = Number(payMethodOptions.value.payMethod || 1)
payMethodPopupVisible.value = true
}
function confirmPayMethodForSettle() {
payMethodOptions.value.payMethod = Number(payMethodSelected.value || 1)
payMethodPopupVisible.value = false
handleGoSettle()
}
function openUploadVoucher() {
if (!zelleOrderIdForVoucher.value) {
uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' })
return
}
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 || !zelleOrderIdForVoucher.value) {
uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' })
return
}
if (voucherSubmitting.value) return
voucherSubmitting.value = true
try {
await appMerchantOrderZipPayVoucherPost({
body: {
orderId: zelleOrderIdForVoucher.value,
zipPayVoucher,
}
})
uni.showToast({ title: t('pages-store.order.voucherSubmitSuccess'), icon: 'none' })
zellePopupVisible.value = false
setTimeout(() => {
if (zelleOrderIdForVoucher.value) {
uni.reLaunch({
url: `/pages-store/pages/order/index?id=${zelleOrderIdForVoucher.value}`
})
}
}, 500)
} catch {
uni.showToast({ title: t('pages-store.order.voucherSubmitFailed'), icon: 'none' })
} finally {
voucherSubmitting.value = false
}
}
useEventEmit(EventEnum.CHOOSE_PAYMENT_METHOD, (data) => {
if(data) {
if(data.payMethod === 1) {
@@ -791,6 +869,9 @@ function handleGoSettle() {
// 如果是余额支付,弹出支付密码弹窗
if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = resOrderIds.value?.[0] ? String(resOrderIds.value[0]) : ''
zellePopupVisible.value = true
} else {
appMerchantOrderPayOrderBatch()
}
@@ -799,6 +880,9 @@ function handleGoSettle() {
// 如果是余额支付,弹出支付密码弹窗
if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = resOrderIds.value?.[0] ? String(resOrderIds.value[0]) : ''
zellePopupVisible.value = true
} else {
appMerchantOrderPayOrderBatch()
}
@@ -852,6 +936,9 @@ function handleGoSettle() {
// 如果是余额支付,弹出支付密码弹窗
if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = String(resOrderId.value || '')
zellePopupVisible.value = true
} else {
appMerchantOrderPayOrder()
}
@@ -860,6 +947,9 @@ function handleGoSettle() {
// 如果是余额支付,弹出支付密码弹窗
if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = String(resOrderId.value || '')
zellePopupVisible.value = true
} else {
appMerchantOrderPayOrder()
}
@@ -1345,27 +1435,6 @@ function handleClose(merchantId?: string) {
</view>
</view>
<!-- 支付方式 -->
<view class="checkout-block">
<view class="checkout-section-label">{{ t('pages-store.checkout.payMethodSection') }}</view>
<view
@click="navigateTo('/pages-user/pages/choose-paymethod/index')"
class="checkout-card checkout-gutter checkout-pay-row"
>
<view class="flex-1 min-w-0 pr-16rpx">
<template v-if="payMethodOptions.payMethod === 1">
<text class="checkout-card-primary block">{{ t('pages-user.choosePaymethod.creditCard') }}</text>
<text v-if="payMethodOptions.cardId" class="checkout-card-secondary block mt-10rpx">{{ payMethodOptions.cardNumber }}</text>
<text v-else class="checkout-card-secondary block mt-10rpx">{{ t("pages-user.member.creditCard") }}</text>
</template>
<template v-else>
<text class="checkout-card-primary block">{{ t('pages-user.choosePaymethod.wallet') }}</text>
</template>
</view>
<image src="@img/chef/142.png" class="checkout-chevron" mode="aspectFit" />
</view>
</view>
<!-- 确认订单单店 -->
<view v-if="orderType === 'normal' && cartDataList.length > 0" class="checkout-block">
<view class="checkout-section-label">{{ t('pages-store.checkout.confirmOrder') }}</view>
@@ -1875,7 +1944,7 @@ function handleClose(merchantId?: string) {
<text class="checkout-bottom-bar-one-line">{{ subtotalOneLineText }}</text>
</view>
<wd-button
@click="handleGoSettle"
@click="openPayMethodPopup"
custom-class="checkout-pay-btn"
>{{ t('pages-store.checkout.pay') }}
</wd-button>
@@ -1891,6 +1960,89 @@ function handleClose(merchantId?: string) {
<!-- 价格明细 -->
<price-detail ref="priceDetailRef" />
<password-container @success="payPawSuccess" ref="passwordInputRef" />
<choose-image ref="voucherChooseRef" :count="1" @change="onVoucherImageUploaded" />
<wd-popup v-model="payMethodPopupVisible" position="bottom" @close="payMethodPopupVisible = false">
<view class="checkout-paymethod-popup">
<view class="checkout-paymethod-popup-title">{{ t('pages-store.checkout.payMethodSection') }}</view>
<view
class="checkout-paymethod-option"
:class="{ 'is-active': payMethodSelected === 1 }"
@click="payMethodSelected = 1"
>
<view class="checkout-paymethod-option-left">
<view class="checkout-paymethod-dot">
<view class="checkout-paymethod-dot-inner"></view>
</view>
<view class="checkout-paymethod-text-wrap">
<view class="checkout-paymethod-name">{{ t('pages-user.choosePaymethod.creditCard') }}</view>
<view class="checkout-paymethod-desc">{{ payMethodOptions.cardId ? payMethodOptions.cardNumber : t('pages-user.member.creditCard') }}</view>
</view>
</view>
<view
class="checkout-paymethod-replace-btn"
@click.stop="chooseCardForCheckout"
>
{{ payMethodOptions.cardId ? t('pages-user.choosePaymethod.replace') : t('pages-user.member.creditCard') }}
</view>
</view>
<view
class="checkout-paymethod-option"
:class="{ 'is-active': payMethodSelected === 2 }"
@click="payMethodSelected = 2"
>
<view class="checkout-paymethod-option-left">
<view class="checkout-paymethod-dot">
<view class="checkout-paymethod-dot-inner"></view>
</view>
<view class="checkout-paymethod-text-wrap">
<view class="checkout-paymethod-name">{{ t('pages-user.choosePaymethod.wallet') }}</view>
<view class="checkout-paymethod-desc">Balance</view>
</view>
</view>
</view>
<view
class="checkout-paymethod-option"
:class="{ 'is-active': payMethodSelected === 3 }"
@click="payMethodSelected = 3"
>
<view class="checkout-paymethod-option-left">
<view class="checkout-paymethod-dot">
<view class="checkout-paymethod-dot-inner"></view>
</view>
<view class="checkout-paymethod-text-wrap">
<view class="checkout-paymethod-name">Zelle</view>
<view class="checkout-paymethod-desc">Scan QR and upload voucher</view>
</view>
</view>
</view>
<wd-button @click="confirmPayMethodForSettle" custom-class="checkout-paymethod-confirm-btn" block>
{{ t('common.confirm') }}
</wd-button>
<view :style="[configStore.iosSafeBottomPlaceholder]"></view>
</view>
</wd-popup>
<wd-popup v-model="zellePopupVisible" custom-style="background: transparent;" @close="zellePopupVisible = false">
<view class="w-620rpx rounded-24rpx bg-white p-28rpx">
<view class="text-32rpx lh-32rpx text-#333 font-600 text-center mb-24rpx">Zelle</view>
<image v-if="zellePayPath" :src="zellePayPath" mode="aspectFit" class="w-100% h-520rpx rounded-16rpx bg-#F7F7F7" />
<view v-else class="h-220rpx rounded-16rpx bg-#F7F7F7 center text-#999 text-24rpx">
zellePayPath is empty
</view>
<wd-button
:loading="voucherSubmitting"
:disabled="voucherSubmitting"
@click="openUploadVoucher"
custom-class="!h-92rpx !rounded-40rpx !text-30rpx !mt-26rpx !bg-#14181B"
block
>
{{ t('pages-store.order.uploadPaidVoucher') }}
</wd-button>
</view>
</wd-popup>
</view>
</view>
</template>
@@ -2075,6 +2227,122 @@ $checkout-gutter: 32rpx;
box-sizing: border-box;
}
.checkout-paymethod-popup {
padding: 36rpx 30rpx 20rpx;
background: #fff;
border-radius: 28rpx 28rpx 0 0;
}
.checkout-paymethod-popup-title {
font-size: 34rpx;
line-height: 1.3;
font-weight: 700;
color: #14181b;
text-align: center;
margin-bottom: 30rpx;
}
.checkout-paymethod-option {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 128rpx;
padding: 0 24rpx;
border: 2rpx solid #ececec;
border-radius: 22rpx;
background: #fff;
margin-bottom: 18rpx;
transition: all .2s ease;
}
.checkout-paymethod-option.is-active {
border-color: #14181b;
background: #f7f8fa;
box-shadow: 0 6rpx 20rpx rgba(20, 24, 27, 0.08);
}
.checkout-paymethod-option-left {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
}
.checkout-paymethod-dot {
width: 34rpx;
height: 34rpx;
border-radius: 50%;
border: 2rpx solid #d0d0d0;
display: flex;
align-items: center;
justify-content: center;
margin-right: 18rpx;
flex-shrink: 0;
}
.checkout-paymethod-dot-inner {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background: transparent;
}
.checkout-paymethod-option.is-active .checkout-paymethod-dot {
border-color: #14181b;
}
.checkout-paymethod-option.is-active .checkout-paymethod-dot-inner {
background: #14181b;
}
.checkout-paymethod-text-wrap {
min-width: 0;
display: flex;
flex-direction: column;
gap: 8rpx;
}
.checkout-paymethod-name {
font-size: 30rpx;
line-height: 1.25;
font-weight: 600;
color: #1f1f1f;
}
.checkout-paymethod-desc {
font-size: 24rpx;
line-height: 1.3;
color: #8b8b8b;
}
.checkout-paymethod-replace-btn {
margin-left: 16rpx;
height: 50rpx;
padding: 0 20rpx;
border-radius: 25rpx;
background: #ffffff;
border: 1rpx solid #e6e6e6;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #333333;
flex-shrink: 0;
}
.checkout-paymethod-option:last-of-type {
margin-bottom: 0;
}
.checkout-paymethod-confirm-btn {
margin-top: 28rpx !important;
height: 96rpx !important;
border-radius: 46rpx !important;
font-size: 30rpx !important;
font-weight: 600 !important;
background: #14181b !important;
}
.checkout-confirm-head {
display: flex;
flex-direction: row;
+36 -51
View File
@@ -20,6 +20,16 @@ import dayjs from 'dayjs'
import useEventEmit from "@/hooks/useEventEmit";
const configStore = useConfigStore();
function fillI18nParams(template: string, params: Record<string, string | number>) {
let text = template
Object.keys(params).forEach((key) => {
const value = String(params[key] ?? '')
text = text.replace(new RegExp(`\\{${key}\\}`, 'g'), value)
text = text.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), value)
})
return text
}
// 价格明细
const priceDetailRef = ref<InstanceType<typeof PriceDetail>>();
// 打开价格明细
@@ -128,6 +138,12 @@ const orderTotalItemCount = computed(() => {
return orderDishList.value.reduce((sum, item) => sum + (Number(item?.count) || 0), 0)
})
const orderTotalItemCountText = computed(() => {
return fillI18nParams(t('pages.order.totalItemCount'), {
count: orderTotalItemCount.value,
})
})
const orderTotalPrice = computed(() => {
const n = orderDetail.value?.paidAmount ?? orderDetail.value?.actualPrice ?? 0
return Number(n).toFixed(2)
@@ -292,55 +308,24 @@ const orderNavSecondaryLine = computed(() => {
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
// }
// 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() {
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' })
@@ -352,7 +337,7 @@ async function openUploadVoucher() {
await appMerchantOrderZipPayVoucherPost({
body: {
orderId: id,
zipPayVoucher: FIXED_VOUCHER_URL,
zipPayVoucher,
},
options: { hideErrorToast: true },
})
@@ -575,7 +560,7 @@ async function openUploadVoucher() {
<view class="goods-price-right">
<text class="goods-price">${{ orderTotalPrice }}</text>
<text class="goods-count">
{{ t('pages.order.totalItemCount', { count: orderTotalItemCount }) }}
{{ orderTotalItemCountText }}
</text>
</view>
</view>
@@ -856,8 +841,8 @@ async function openUploadVoucher() {
<password-container @success="payPawSuccess" ref="passwordInputRef" />
<!-- 核销订单 -->
<use-code ref="useCodeRef" />
<!-- 支付凭证:相册/拍照(暂时不使用文件上传,改用固定URL -->
<choose-image ref="voucherChooseRef" :count="1" />
<!-- 支付凭证:相册/拍照,上传后回调真实 URL -->
<choose-image ref="voucherChooseRef" :count="1" @change="onVoucherImageUploaded" />
</view>
</view>
</template>
+15 -6
View File
@@ -386,6 +386,15 @@ const specPopupDisplayPrice = computed(() => {
return centStringToPriceText(baseCent);
});
const detailDisplayPrice = computed(() => {
const dish = dishDetailData.value as any;
const firstSpecPrice = dish?.merchantSideDishVoList?.[0]?.merchantSideDishItemVoList?.[0]?.price;
if (firstSpecPrice != null && String(firstSpecPrice) !== "") {
return firstSpecPrice;
}
return dish?.actualSalePrice;
});
function openSpecPopup() {
const sideList = dishDetailData.value?.merchantSideDishVoList ?? [];
for (const item of sideList) {
@@ -765,7 +774,7 @@ function getStoreDetail() {
<view class="price-current">
<text class="price-current__sym">$</text>
<text class="price-current__num">{{
dishDetailData?.discountPrice
detailDisplayPrice
}}</text>
</view>
<text
@@ -836,12 +845,12 @@ function getStoreDetail() {
}}</view>
<text class="section-product-name">{{ dishDetailData?.dishName }}</text>
<view class="spec-grid">
<view class="spec-cell">
<!-- <view class="spec-cell">
<text class="spec-cell__val">{{ specFromWords(0) }}</text>
<text class="spec-cell__lbl">{{
t("pages-store.store.dishDetail.origin")
}}</text>
</view>
</view> -->
<view class="spec-cell">
<text class="spec-cell__val">{{ specUnitDisplay }}</text>
<text class="spec-cell__lbl">{{
@@ -856,12 +865,12 @@ function getStoreDetail() {
t("pages-store.store.dishDetail.category")
}}</text>
</view>
<view class="spec-cell">
<!-- <view class="spec-cell">
<text class="spec-cell__val">{{ specFromWords(1) }}</text>
<text class="spec-cell__lbl">{{
t("pages-store.store.dishDetail.allergen")
}}</text>
</view>
</view> -->
</view>
<!-- 产品简介 -->
@@ -1335,7 +1344,7 @@ function getStoreDetail() {
.spec-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(2, 1fr);
gap: 0;
border: 1rpx solid #e8e8e8;
border-radius: 16rpx;
+10 -4
View File
@@ -556,14 +556,20 @@ function feeLine(
return { show: true, orig, cur };
}
onMounted(() => {
loading.value = true;
getCartList();
});
// onMounted(() => {
// loading.value = true;
// getCartList();
// });
onShow(() => {
if (userStore.isLogin) {
userStore.getAppointmentTime();
// 从结算页返回时强制刷新购物车,避免已结算商品残留
loading.value = true;
getCartList();
} else {
dataList.value = [];
loading.value = false;
}
});
+21 -1
View File
@@ -42,6 +42,26 @@ function formatCouponDetail(item: any) {
return t('pages-store.store.discount')
}
function fillI18nParams(template: string, params: Record<string, string | number>) {
let text = template
Object.keys(params).forEach((key) => {
const value = String(params[key] ?? '')
text = text.replace(new RegExp(`\\{${key}\\}`, 'g'), value)
text = text.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), value)
})
return text
}
function formatCouponMerchantText(item: any) {
const name = String(item?.merchantVo?.merchantName || '').trim()
if (name) {
return fillI18nParams(t('pages-user.coupon.merchant-only'), { name })
}
return item?.snapshotMerchantId
? t('pages-user.coupon.merchant-specific')
: t('pages-user.coupon.all-merchants')
}
function getList(pageNum: number, pageSize: number) {
return appCouponUserCouponListPost({
params: {
@@ -150,7 +170,7 @@ function handleSubmit() {
{{ item.snapshotNameZh }}
</view>
<view class="text-24rpx lh-32rpx text-#999 my-18rpx">
{{ item.snapshotMerchantId ? t('pages-user.coupon.merchant-specific') : t('pages-user.coupon.all-merchants') }}
{{ formatCouponMerchantText(item) }}
</view>
<view class="text-24rpx lh-32rpx text-#999 my-18rpx">
{{ dayjs(Number(item.snapshotValidEnd)).format('YYYY-MM-DD HH:mm') }}{{ isEnLocale() ? ' expires' : '到期' }}
@@ -48,6 +48,13 @@ function getDishPromoLabel(item: Record<string, unknown>): string {
return typeof raw === 'string' && raw.trim() ? raw.trim() : ''
}
function getFeaturedDishDisplayPrice(item: Record<string, any>) {
const firstSpecPrice = item?.merchantSideDishVoList?.[0]?.merchantSideDishItemVoList?.[0]?.price
if (firstSpecPrice != null && String(firstSpecPrice) !== '') return firstSpecPrice
if (item?.actualSalePrice != null && String(item.actualSalePrice) !== '') return item.actualSalePrice
return item?.discountPrice ?? 0
}
function navigateTo(url: string) {
if(userStore.checkLogin()) {
uni.navigateTo({
@@ -445,7 +452,7 @@ const debouncedEmit = debounce(1300, (isCollected: boolean, id: string, type: Co
<view class="featured-dish-body">
<view class="featured-dish-meta flex items-start justify-between gap-12rpx mb-14rpx">
<view class="min-w-0 flex-1">
<text class="featured-dish-price">US${{ item?.discountPrice }}</text>
<text class="featured-dish-price">US${{ getFeaturedDishDisplayPrice(item) }}</text>
<!-- <text
v-if="Number(item?.originalPrice) > Number(item?.discountPrice)"
class="featured-dish-original"
@@ -42,6 +42,16 @@ const {paging, dataList, loading, queryList, firstLoaded} = usePage<MerchantOrde
}
})
function fillI18nParams(template: string, params: Record<string, string | number>) {
let text = template
Object.keys(params).forEach((key) => {
const value = String(params[key] ?? '')
text = text.replace(new RegExp(`\\{${key}\\}`, 'g'), value)
text = text.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), value)
})
return text
}
function normalizeTimestamp(input: unknown): number | null {
if (input == null || input === '') return null
@@ -71,7 +81,14 @@ function formatOrderCardTime(item: MerchantOrderVo) {
}
function formatOrderPrice(item: MerchantOrderVo) {
return (item.paidAmount ?? item.actualPrice ?? 0).toFixed(2)
const raw = item?.paidAmount ?? item?.actualPrice ?? 0
if (raw == null || raw === '') return '0.00'
if (typeof raw === 'number') return raw.toFixed(2)
const str = String(raw).trim()
if (!str) return '0.00'
if (!str.includes('.')) return `${str}.00`
const [intPart, decimalPart = ''] = str.split('.')
return `${intPart}.${(decimalPart + '00').slice(0, 2)}`
}
function getOrderDishes(item: MerchantOrderVo): Array<Record<string, any>> {
@@ -94,6 +111,42 @@ function getTotalDishCount(item: MerchantOrderVo) {
return getOrderDishes(item).reduce((s, d) => s + (d.count || 0), 0)
}
function getTotalDishCountText(item: MerchantOrderVo) {
return fillI18nParams(t('pages.order.totalItemCount'), {
count: getTotalDishCount(item),
})
}
function isSameCode(value: unknown, code: unknown) {
return String(value ?? '') === String(code ?? '')
}
function isRefundApplied(item: MerchantOrderVo) {
return isSameCode(item.refundStatus, OrderCancelStatus.APPLIED)
}
function isRefundApproved(item: MerchantOrderVo) {
return isSameCode(item.refundStatus, OrderCancelStatus.APPROVED)
}
function isRefundRejected(item: MerchantOrderVo) {
return isSameCode(item.refundStatus, OrderCancelStatus.REJECTED)
}
function getOrderStatusText(item: MerchantOrderVo) {
if (isRefundApplied(item)) return t('pages-store.order.orderStatus.refund')
if (isRefundApproved(item)) return t('pages-store.order.orderStatus.agreeRefund')
if (isRefundRejected(item)) return t('pages-store.order.orderStatus.rejectRefund')
if (isSameCode(item.orderStatus, OrderStatus.CANCELLED)) return t('pages-store.order.orderStatus.cancelled')
if (isSameCode(item.orderStatus, OrderStatus.PENDING_PAYMENT)) return t('pages-store.order.orderStatus.pendingPayment')
if (isSameCode(item.orderStatus, OrderStatus.HAS_PENDING_PAYMENT)) return t('pages-store.order.orderStatus.hasPendingPayment')
if (isSameCode(item.orderStatus, OrderStatus.MERCHANT_ACCEPTED)) return t('pages-store.order.orderStatus.received')
if (isSameCode(item.receiveMethod, 1) && isSameCode(item.orderStatus, OrderStatus.DELIVERING)) return t('pages-store.order.orderStatus.delivering')
if (isSameCode(item.orderStatus, OrderStatus.COMPLETED)) return t('pages-store.order.orderStatus.delivered')
if (isSameCode(item.orderStatus, OrderStatus.MERCHANT_REJECTED)) return t('pages-store.store.orderStatus.rejected')
return '--'
}
function handleClick(item: MerchantOrderVo) {
uni.navigateTo({
url: '/pages-store/pages/order/index?id=' + item.id
@@ -171,43 +224,18 @@ defineExpose({
>
<view class="flex-center-sb items-start gap-16rpx">
<text class="order-time">{{ formatOrderCardTime(item) }}</text>
<text class="order-status shrink-0">
<template v-if="
item.refundStatus === OrderCancelStatus.APPLIED ||
item.refundStatus === OrderCancelStatus.APPROVED ||
item.refundStatus === OrderCancelStatus.REJECTED
">
<template v-if="item.refundStatus === OrderCancelStatus.APPLIED">
{{ t('pages-store.order.orderStatus.refund') }}
</template>
<template v-else-if="item.refundStatus === OrderCancelStatus.APPROVED">
{{ t('pages-store.order.orderStatus.agreeRefund') }}
</template>
<template v-else-if="item.refundStatus === OrderCancelStatus.REJECTED">
{{ t('pages-store.order.orderStatus.rejectRefund') }}
</template>
</template>
<template v-else>
<template v-if="item.orderStatus === OrderStatus.CANCELLED">{{ t('pages-store.order.orderStatus.cancelled') }}</template>
<template v-if="item.orderStatus === OrderStatus.PENDING_PAYMENT">{{ t('pages-store.order.orderStatus.pendingPayment') }}</template>
<template v-if="item.orderStatus === OrderStatus.HAS_PENDING_PAYMENT">{{ t('pages-store.order.orderStatus.hasPendingPayment') }}</template>
<template v-if="item.orderStatus === OrderStatus.MERCHANT_ACCEPTED">{{ t('pages-store.order.orderStatus.received') }}</template>
<template v-if="item.receiveMethod === 1 && item.orderStatus === OrderStatus.DELIVERING">{{ t('pages-store.order.orderStatus.delivering') }}</template>
<template v-if="item.orderStatus === OrderStatus.COMPLETED">{{ t('pages-store.order.orderStatus.delivered') }}</template>
<template v-if="item.orderStatus === OrderStatus.MERCHANT_REJECTED">
<text class="text-#FF6106">{{ t('pages-store.store.orderStatus.rejected') }}</text>
</template>
</template>
<text class="order-status shrink-0" :class="{ 'text-#FF6106': isSameCode(item.orderStatus, OrderStatus.MERCHANT_REJECTED) }">
{{ getOrderStatusText(item) }}
</text>
</view>
<view class="store-row">
<image src="@img/chef/126.png" class="store-icon" mode="aspectFit"></image>
<text class="store-name line-clamp-1">{{ item.merchantVo?.merchantName }}</text>
<view v-if="item.receiveMethod === 1" class="recv-tag recv-tag--del">
<view v-if="isSameCode(item.receiveMethod, 1)" class="recv-tag recv-tag--del">
{{ t('pages.order.DEL') }}
</view>
<view v-if="item.receiveMethod === 2" class="recv-tag recv-tag--pu">
<view v-if="isSameCode(item.receiveMethod, 2)" class="recv-tag recv-tag--pu">
{{ t('pages.order.PU') }}
</view>
</view>
@@ -237,38 +265,38 @@ defineExpose({
</scroll-view>
<view class="price-block shrink-0">
<text class="price-num">${{ formatOrderPrice(item) }}</text>
<text class="price-meta">{{ t('pages.order.totalItemCount', { count: getTotalDishCount(item) }) }}</text>
<text class="price-meta">{{ getTotalDishCountText(item) }}</text>
</view>
</view>
<view class="action-row" @click.stop>
<view class="action-left">
<image
v-if="item.receiveMethod === 2 && item.orderStatus === OrderStatus.MERCHANT_ACCEPTED"
v-if="isSameCode(item.receiveMethod, 2) && isSameCode(item.orderStatus, OrderStatus.MERCHANT_ACCEPTED)"
src="@img/chef/127.png"
class="action-icon"
/>
<image
v-if="item.orderStatus >= OrderStatus.MERCHANT_ACCEPTED && item.receiveMethod === 1"
v-if="!isSameCode(item.orderStatus, OrderStatus.PENDING_PAYMENT) && !isSameCode(item.orderStatus, OrderStatus.CANCELLED) && isSameCode(item.receiveMethod, 1)"
src="@img/chef/128.png"
class="action-icon"
@click="callPhone(item.merchantVo?.phone)"
/>
</view>
<view class="action-btns">
<template v-if="item.refundStatus !== OrderCancelStatus.APPLIED && item.refundStatus !== OrderCancelStatus.APPROVED">
<template v-if="!isRefundApplied(item) && !isRefundApproved(item)">
<view
v-if="item.orderStatus !== OrderStatus.CANCELLED && item.orderStatus !== OrderStatus.COMPLETED && item.orderStatus !== OrderStatus.MERCHANT_REJECTED"
v-if="!isSameCode(item.orderStatus, OrderStatus.CANCELLED) && !isSameCode(item.orderStatus, OrderStatus.COMPLETED) && !isSameCode(item.orderStatus, OrderStatus.MERCHANT_REJECTED)"
class="btn-outline"
@click="handleCancelClick(item)"
>{{ t('pages.order.cancelOrder') }}</view>
<view
v-if="item.receiveMethod === 2 && item.orderStatus === OrderStatus.MERCHANT_ACCEPTED"
v-if="isSameCode(item.receiveMethod, 2) && isSameCode(item.orderStatus, OrderStatus.MERCHANT_ACCEPTED)"
class="btn-primary"
@click="handleClick(item)"
>{{ t('pages-store.order.writeOff') }}</view>
<view
v-if="item.orderStatus === OrderStatus.COMPLETED && item?.dishReviewVoList?.length === 0"
v-if="isSameCode(item.orderStatus, OrderStatus.COMPLETED) && item?.dishReviewVoList?.length === 0"
class="btn-primary"
@click="handleClick(item)"
>{{ t('common.evaluate') }}</view>
+2
View File
@@ -2898,6 +2898,8 @@
'merchantVo'?: MerchantVo;
/** 份数 */
'copies'?: number;
'actualSalePrice'?: number;
}