diff --git a/env/.env.development b/env/.env.development index b5a93a5..764ee04 100644 --- a/env/.env.development +++ b/env/.env.development @@ -5,6 +5,6 @@ VITE_DELETE_CONSOLE=false #本地环境 VITE_SERVER_BASEURL=https://howhowfresh.com/prod-api -#VITE_SERVER_BASEURL=http://192.168.5.200:8080 +#VITE_SERVER_BASEURL=http://192.168.5.4:8080 #VITE_SERVER_BASEURL=http://192.168.0.148:8888 #VITE_SERVER_BASEURL=http://liuyao.nat100.top/meiguowaimai \ No newline at end of file diff --git a/src/components/choose-image/choose-image.vue b/src/components/choose-image/choose-image.vue index bbaecd5..516a268 100644 --- a/src/components/choose-image/choose-image.vue +++ b/src/components/choose-image/choose-image.vue @@ -1,6 +1,5 @@ + + :deep(.uni-picker-view-indicator) { + height: 94rpx !important; + } + + \ No newline at end of file diff --git a/src/pages-store/pages/dishes/index.vue b/src/pages-store/pages/dishes/index.vue index 6edb327..4249e61 100644 --- a/src/pages-store/pages/dishes/index.vue +++ b/src/pages-store/pages/dishes/index.vue @@ -51,11 +51,16 @@ function navigateTo(url: string) { \ No newline at end of file diff --git a/src/pages-store/pages/home-store/index.vue b/src/pages-store/pages/home-store/index.vue index ec7640f..cd424ef 100644 --- a/src/pages-store/pages/home-store/index.vue +++ b/src/pages-store/pages/home-store/index.vue @@ -1,25 +1,24 @@ \ No newline at end of file +.home-store-header { + background: #fff; +} + +.home-store-filter-strip { + background: #f2f3f5; + padding-bottom: 8rpx; +} + +.home-store-filters { + display: block; + padding: 16rpx 0 20rpx; +} + +.home-store-list { + padding: 16rpx 24rpx 40rpx; + box-sizing: border-box; +} + +.merchant-card { + display: flex; + flex-direction: row; + align-items: center; + background: #fff; + border-radius: 24rpx; + padding: 24rpx; + margin-bottom: 20rpx; + box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06); +} + +.merchant-card__imgs { + display: flex; + flex-direction: column; + gap: 12rpx; + width: 152rpx; + flex-shrink: 0; +} + +.merchant-card__img-slot { + width: 152rpx; + height: 96rpx; + flex-shrink: 0; + overflow: hidden; + background: #e8eaed; +} + +/* 仅外侧圆角;靠两张图之间的分割一侧为直角 */ +.merchant-card__img-slot--first { + border-radius: 12rpx 12rpx 0 0; +} + +.merchant-card__img-slot--last { + border-radius: 0 0 12rpx 12rpx; +} + +.merchant-card__img { + width: 100%; + height: 100%; + display: block; + background: #e8eaed; +} + +.merchant-card__img--empty { + flex-shrink: 0; + width: 100%; + height: 100%; +} + +.merchant-card__body { + flex: 1; + min-width: 0; + padding: 0 20rpx 0 8rpx; + display: flex; + flex-direction: column; + align-items: flex-start; +} + +.merchant-card__name { + font-size: 30rpx; + font-weight: 600; + color: #14181b; + line-height: 1.35; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.merchant-card__cate { + margin-top: 8rpx; + font-size: 26rpx; + color: #333; + line-height: 1.3; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.merchant-card__rating { + margin-top: 12rpx; + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: wrap; + gap: 4rpx; +} + +.merchant-card__star { + font-size: 22rpx; + line-height: 1; + color: #e0e0e0; + letter-spacing: -2rpx; +} + +.merchant-card__star--on { + color: #14181b; +} + +.merchant-card__score { + margin-left: 10rpx; + font-size: 26rpx; + font-weight: 600; + color: #14181b; +} + +.merchant-card__tag { + margin-top: 10rpx; + font-size: 24rpx; + font-weight: 500; + color: #b8860b; + line-height: 1.3; +} + +.merchant-card__go { + width: 56rpx; + height: 56rpx; + border-radius: 50%; + background: #14181b; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.merchant-card__go-icon { + font-size: 28rpx; + color: #fff; + margin-left: 2rpx; +} + + + diff --git a/src/pages-store/pages/list/index.vue b/src/pages-store/pages/list/index.vue index d640b66..8758a27 100644 --- a/src/pages-store/pages/list/index.vue +++ b/src/pages-store/pages/list/index.vue @@ -1,61 +1,751 @@ \ No newline at end of file +.cat-header-row { + display: flex; + align-items: center; + gap: 16rpx; + padding: 12rpx 24rpx 20rpx; +} + +.cat-icon-btn { + width: 72rpx; + height: 72rpx; + border-radius: 50%; + background: #fff; + box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.cat-icon-btn--cart { + position: relative; +} + +.cat-cart-badge { + position: absolute; + top: 2rpx; + right: 2rpx; + min-width: 28rpx; + height: 28rpx; + padding: 0 6rpx; + font-size: 18rpx; + line-height: 28rpx; + font-weight: 600; + color: #fff; + text-align: center; + background: #e23636; + border-radius: 999rpx; +} + +.cat-search { + flex: 1; + min-width: 0; + height: 72rpx; + border-radius: 36rpx; + background: #fff; + box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.06); + display: flex; + align-items: center; + padding: 0 28rpx; +} + +.cat-search-icon { + width: 28rpx; + height: 28rpx; + flex-shrink: 0; +} + +.cat-search-placeholder { + margin-left: 16rpx; + font-size: 28rpx; + font-weight: 500; + color: #999; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.cat-scroll-x { + width: 100%; + white-space: nowrap; +} + +.cat-recipe-track { + display: inline-flex; + flex-direction: row; + padding: 8rpx 24rpx 16rpx; + gap: 36rpx; +} + +.cat-recipe-item { + display: inline-flex; + flex-direction: column; + align-items: center; + width: 120rpx; + flex-shrink: 0; +} + +.cat-recipe-ring { + width: 102rpx; + height: 102rpx; + border-radius: 50%; + padding: 0; + background: #fff; + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.07); + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; +} + +.cat-recipe-ring--on { + border: 4rpx solid #14181b; +} + +.cat-recipe-img { + width: 94rpx; + height: 94rpx; + border-radius: 50%; +} + +.cat-recipe-label { + margin-top: 12rpx; + font-size: 22rpx; + line-height: 1.2; + color: #333; + text-align: center; + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-weight: 500; +} + +.cat-recipe-label--on { + color: #14181b; + font-weight: 600; +} + +.cat-waterfall { + min-height: 200rpx; +} + +.cat-dish-card { + background: #fff; + border-radius: 24rpx; + overflow: hidden; + box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06); +} + +.cat-dish-collect { + position: absolute; + z-index: 2; + top: 12rpx; + right: 12rpx; + width: 56rpx; + height: 56rpx; + display: flex; + align-items: center; + justify-content: center; +} + +.cat-dish-collect-icon { + width: 44rpx; + height: 44rpx; + filter: drop-shadow(0 2rpx 6rpx rgba(0, 0, 0, 0.18)); +} + +.cat-dish-soldout { + position: absolute; + z-index: 2; + left: 16rpx; + top: 16rpx; + padding: 0 14rpx; + height: 48rpx; + border-radius: 24rpx; + background: rgba(20, 24, 27, 0.75); + color: #fff; + font-size: 24rpx; + font-weight: 500; + display: flex; + align-items: center; + justify-content: center; +} + +.cat-dish-body { + padding: 20rpx 20rpx 22rpx; +} + +.cat-dish-price { + color: #e02e24; + font-size: 32rpx; + font-weight: 600; + line-height: 1.2; +} + +.cat-dish-original { + margin-left: 10rpx; + color: #b3b3b3; + font-size: 22rpx; + text-decoration: line-through; + vertical-align: baseline; +} + +.cat-dish-sales { + color: #999; + font-size: 24rpx; + line-height: 1.35; + max-width: 48%; + text-align: right; +} + +.cat-dish-title { + color: #1a1a1a; + font-size: 28rpx; + font-weight: 500; + line-height: 1.45; +} + +.cat-dish-member { + display: inline-flex; + align-items: center; + max-width: calc(100% - 88rpx); +} + +.cat-dish-member-inner { + display: inline-block; + padding: 6rpx 18rpx; + border-radius: 999rpx; + background: linear-gradient(180deg, #fff5eb 0%, #ffe8d6 100%); + color: #c45c1a; + font-size: 24rpx; + font-weight: 500; + line-height: 1.35; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 100%; +} + +.cat-dish-add { + width: 56rpx; + height: 56rpx; + border-radius: 50%; + background: #14181b; + box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.12); +} + +.cat-dish-add--busy { + opacity: 0.45; + pointer-events: none; +} + +.cat-dish-promo { + padding: 12rpx 16rpx; + border-radius: 12rpx; + background: #fff0f0; +} + +.cat-dish-promo-text { + color: #e02e24; + font-size: 22rpx; + font-weight: 500; + line-height: 1.4; +} + +.dish-new-ribbon { + position: absolute; + top: 0; + left: 0; + width: 184rpx; + height: 184rpx; + overflow: hidden; + z-index: 5; + pointer-events: none; + + &__text { + position: absolute; + top: 26rpx; + left: -66rpx; + width: 240rpx; + text-align: center; + font-size: 22rpx; + font-weight: 700; + color: #fff; + letter-spacing: 2rpx; + line-height: 44rpx; + background: #E23636; + transform: rotate(-45deg); + } +} + diff --git a/src/pages-store/pages/order/checkout.vue b/src/pages-store/pages/order/checkout.vue index 1a38c94..414c7ec 100644 --- a/src/pages-store/pages/order/checkout.vue +++ b/src/pages-store/pages/order/checkout.vue @@ -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"; @@ -28,6 +30,21 @@ const { t } = useI18n(); const configStore = useConfigStore(); const userStore = useUserStore(); +function fillI18nParams(template: string, params: Record) { + 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 appDisplayName = computed(() => { + const name = String((Config as any)?.appName ?? "").trim(); + return name || "CHEFLINK"; +}); + // 送达偏好 const visitMethodRef = ref(); // value 与 visit-method 组件保持一致:0-亲自送达 1-放门口 @@ -177,8 +194,8 @@ function handleClickSegmented(index: number) { // 折叠面板 const collapseValue = ref([""]); -// 单个订单的小费 -const selectedTipIndex = ref(0); +// 单个订单的小费(与设计稿一致:默认 $2) +const selectedTipIndex = ref(2); const diyTipValue = ref('') // 批量订单:每个店铺的小费索引映射 merchantId -> tipIndex const merchantTipIndexMap = ref>({}) @@ -186,18 +203,9 @@ const merchantTipIndexMap = ref>({}) const merchantDiyTipValueMap = ref>({}) const tipOptions = ref([ - { - label: "$3", - value: 3, - }, - { - label: "$5", - value: 5, - }, - { - label: "$10", - value: 10, - }, + { label: "$ 2", value: 2 }, + { label: "$ 3", value: 3 }, + { label: "$ 4", value: 4 }, ]); // 单个订单的小费选择 @@ -262,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>() +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) { @@ -443,7 +527,13 @@ async function getBatchCartInfo() { const results = await Promise.all(merchantPromises); cartDataList.value = results.filter(item => item !== null); console.log('批量模式-最终购物车数据', cartDataList.value); - + cartDataList.value.forEach((m: any) => { + const id = String(m.id); + if (merchantTipIndexMap.value[id] === undefined) { + merchantTipIndexMap.value[id] = 2; + } + }); + // 批量模式:查询菜品会员折扣价 + 计算价格(严格串行) if(cartIds.length > 0) { await appMerchantCartCalculateSavings() @@ -637,18 +727,7 @@ async function getAddressList() { addressesList.value = res.rows if(addressesList.value.length > 0) { currentAddressId.value = addressesList.value[0].id - - let data = addressesList.value[0] - - // 回显送达偏好(deliveryType: 1-亲自送达 2-放门口) - if(+data.deliveryType === 1) { - visitMethod.value.label = t('components.visit.leaveItToMePersonally') - visitMethod.value.value = 0 - } - if(+data.deliveryType === 2) { - visitMethod.value.label = t('components.visit.putItAtTheDoor') - visitMethod.value.value = 1 - } + // 结算页配送偏好默认「放门口」,不按地址簿 deliveryType 回显 } } @@ -663,16 +742,7 @@ function chooseAddress() { console.log('获取被打开页面传送到当前页面的数据', data) // 将新选择的地址id存储到selectedAddressId中 selectedAddressId.value = data.data - - // 回显送达偏好(deliveryType: 1-亲自送达 2-放门口) - if(+data.deliveryType === 1) { - visitMethod.value.label = t('components.visit.leaveItToMePersonally') - visitMethod.value.value = 0 - } - if(+data.deliveryType === 2) { - visitMethod.value.label = t('components.visit.putItAtTheDoor') - visitMethod.value.value = 1 - } + // 配送偏好默认「放门口」,切换地址时保持用户在本页已选或默认值,不回写地址簿 // 重新计算价格 void appMerchantOrderCalculatePriceCart() @@ -799,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() } @@ -807,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() } @@ -860,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() } @@ -868,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() } @@ -1085,6 +1167,197 @@ function navigateToCoupon(merchantId?: string) { }, }) } +const isUserMemberCheckout = computed(() => { + const vo = userStore.userInfo.userMembershipVo; + if (!vo) return false; + const exp = vo.expireTime; + if (exp) return dayjs().isBefore(dayjs(Number(exp))); + return false; +}); + +const cartTotalPieceCount = computed(() => { + if (orderType.value === 'batch') { + let n = 0; + cartDataList.value.forEach((m: any) => { + (m.merchantCartVoList || []).forEach((item: any) => { + n += Number(item.count) || 0; + }); + }); + return n || batchCartIds.value.length; + } + return cartDataList.value.reduce( + (sum, item: any) => sum + (Number(item.count) || 0), + 0, + ); +}); + +const serviceFeeAmount = computed(() => { + const p: any = priceData.value; + if (!p) return 0; + const original = + Number(p.actualAmount ?? p.totalActualAmount ?? 0) || 0; + const ratio = Number(p.merchantVo?.platformServiceFeeRatio) || 0; + return Math.round(original * ratio * 100) / 100; +}); + +const deliveryPillText = computed(() => { + const raw = + deliveryMethod.value === 0 + ? userSelectedDeliveryTimeDate.value + : userSelectedSelfPickupTimeDate.value; + if (!raw) return t('pages-store.checkout.chooseTime'); + const str = String(raw); + const m = str.match(/^(\d{2})-(\d{2})/); + if (m) { + const y = dayjs().year(); + const d = dayjs(`${y}-${m[1]}-${m[2]}`); + if (d.isValid()) { + const w = d.format('dddd'); + return `${w}, ${m[1]}/${m[2]} >`; + } + } + return `${str} >`; +}); + +function safeToNumber(val: unknown, fallback = 0) { + const n = Number(val); + return Number.isFinite(n) ? n : fallback; +} + +function safeMoneyStr(val: unknown, fallback = 0) { + return safeToNumber(val, fallback).toFixed(2); +} + +const displayDeliveryFeeStr = computed(() => { + const p: any = priceData.value; + if (!p) return '0.00'; + if (orderType.value === 'batch') { + return safeMoneyStr(p.totalDeliveryFee, 0); + } + return safeMoneyStr(p.deliveryFee, 0); +}); + +const displayGoodsAmountStr = computed(() => { + const p: any = priceData.value; + if (!p) return '0.00'; + if (orderType.value === 'batch') { + return safeMoneyStr(p.totalActualAmount, 0); + } + return safeMoneyStr(p.actualAmount, 0); +}); + +const displayTaxStr = computed(() => { + const p: any = priceData.value; + if (!p) return '0.00'; + if (orderType.value === 'batch') { + return safeMoneyStr(p.totalTax, 0); + } + return safeMoneyStr(p.tax, 0); +}); + +const displayTipStr = computed(() => { + const p: any = priceData.value; + if (!p) return '0.00'; + if (orderType.value === 'batch') { + return safeMoneyStr(p.totalTip, 0); + } + return safeMoneyStr(p.tip, 0); +}); + +const displayPaidStr = computed(() => { + const p: any = priceData.value; + if (!p) return '0.00'; + if (orderType.value === 'batch') { + return safeMoneyStr(p.totalPaidAmount, 0); + } + return safeMoneyStr(p.paidAmount, 0); +}); + +const scheduledServiceEndLabel = computed(() => { + const slot = (diyTime.value as any)?.timeSlot; + if (slot && String(slot).includes(' - ')) { + return String(slot).split(' - ')[1]?.trim() || ''; + } + return ''; +}); + +const localDeliverySubtitleText = computed(() => + fillI18nParams(t('pages-store.checkout.localDeliverySubtitle'), { name: appDisplayName.value }) +); + +const itemsGoodsTotalWithPriceText = computed(() => + fillI18nParams(t('pages-store.checkout.itemsGoodsTotalWithPrice'), { + count: cartTotalPieceCount.value, + amount: displayGoodsAmountStr.value, + }) +); + +const scheduledDeliveryWindowText = computed(() => + fillI18nParams(t('pages-store.checkout.scheduledDeliveryWindow'), { + time: scheduledServiceEndLabel.value, + }) +); + +const deliverBeforeText = computed(() => + fillI18nParams(t('pages-store.checkout.deliverBefore'), { + time: deliveryMethod.value === 0 + ? String(userSelectedDeliveryTimeDate.value ?? '') + : String(userSelectedSelfPickupTimeDate.value ?? ''), + }) +); + +const memberThanksText = computed(() => + fillI18nParams(t('pages-store.checkout.memberThanks'), { name: appDisplayName.value }) +); + +const subtotalWithPiecesText = computed(() => + fillI18nParams(t('pages-store.checkout.subtotalWithPieces'), { + count: cartTotalPieceCount.value, + }) +); + +const subtotalOneLineText = computed(() => + fillI18nParams(t('pages-store.checkout.subtotalOneLine'), { + amount: displayPaidStr.value, + }) +); + +const showAppointmentEntry = computed(() => { + if (deliveryMethod.value === 0) { + return storeIsDeliveryService.value || orderType.value === 'batch'; + } + return storeIsSelfPickup.value || orderType.value === 'batch'; +}); + +/** 商家标价配送费(用于划线价,实际运费可能因活动/距离更低) */ +const listDeliveryFeeAmount = computed(() => { + const p: any = priceData.value; + const raw = p?.merchantVo?.deliveryFee; + if (raw === undefined || raw === null || raw === '') return null; + const n = Number(raw); + return Number.isFinite(n) ? n : null; +}); + +const actualDeliveryFeeNum = computed(() => { + const p: any = priceData.value; + if (!p) return 0; + if (orderType.value === 'batch') { + return Number(p.totalDeliveryFee ?? 0); + } + return Number(p.deliveryFee ?? 0); +}); + +const showListDeliveryStrike = computed(() => { + const list = listDeliveryFeeAmount.value; + if (list == null) return false; + return list > actualDeliveryFeeNum.value + 0.005; +}); + +const listDeliveryFeeStr = computed(() => { + const list = listDeliveryFeeAmount.value; + return list != null ? list.toFixed(2) : ''; +}); + function handleClose(merchantId?: string) { if(orderType.value === 'batch' && merchantId) { // 批量模式:清除对应店铺的优惠券 @@ -1099,7 +1372,12 @@ function handleClose(merchantId?: string) {