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 @@
-
+
+
@@ -79,6 +159,56 @@ defineOptions({
+
+ :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) {
-
+
+
+ NEW
+
+
+
{{ item.dishName }}
@@ -65,5 +70,36 @@ 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 @@
-
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ {{ item.merchantName }}
+ {{ merchantCategoryLine(item) }}
+
+ ★
+ {{
+ ratingText(item.rating)
+ }}
+
+ {{ t("pages.home.brandTag") }}
+
+
+
+
+
+
\ 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 @@
-
+
+
+
+
+
+
+
+
+
+
+ {{ cat.categoryName }}
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+ NEW
+
+
+
+
+
+ {{ t("common.prompt.soldOut") }}
+
+
+
+
+
+ US${{ item.discountPrice }}
+ US${{ item.originalPrice }}
+
+ {{ t("pages-store.store.sales") }}:
+ {{ formatSalesCount(item.salesCount) }}
+
+ {{
+ item.dishName
+ }}
+
+
+ {{ t("pages-store.store.members") }}: US${{
+ item.memberPrice
+ }}
+
+
+
+
+
+
+
+ {{
+ getDishPromoLabel(item)
+ }}
+
+
+
+
+
+
+
+
+
+
\ 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) {
-
+
+
-
-
- {{ t("pages-store.checkout.title") }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ addressInfo.formattedAddress }}
-
- {{
- addressInfo.displayName
- }}
-
- {{ t('pages-store.checkout.addAddress') }}
-
-
-
-
-
-
-
-
- {{ visitMethod.label }}
-
-
-
-
-
-
-
-
-
- {{ contact.areaCode }} {{ formData.phone }}
-
-
-
-
-
-
-
-
-
-
- {{ storeDetail?.merchantName }}
- {{ storeDetail?.merchantAddress }}
-
-
-
-
-
-
- {{ t("pages-store.checkout.distance") }}
-
-
- {{ storeDistance }} {{ t('common.mile') }}
+
+
+
+ {{ t('pages-store.checkout.deliveryInfo') }}
+
+
+
+
+
+ {{ addressInfo.formattedAddress }}
+ {{ addressInfo.displayName }}
- {{ t('pages-store.checkout.enableLocationForDistance') }}
-
+ {{ t('pages-store.checkout.fillAddressHint') }}
+
+
-
-
-
-
-
-
-
-
-
- {{ t("pages-store.checkout.deliveryTime") }}
-
-
- {{ t('pages-store.checkout.pickupTime') }}
-
-
-
-
-
-
-
-
-
- {{ showDeliveryTime }}
-
-
- {{ userSelectedDeliveryTimeDate }}
-
-
-
-
-
-
- {{ showDeliveryTime }}
-
-
- {{ userSelectedSelfPickupTimeDate }}
-
-
-
-
-
-
-
-
-
-
- {{ t("pages-store.checkout.appointmentDelivery") }}
-
-
-
- {{ t("pages-store.checkout.chooseTime") }}
-
-
- {{ userSelectedDeliveryTimeDate }}
-
-
+
-
-
-
-
-
-
-
-
- {{ t('pages-store.checkout.appointmentPickup') }}
-
-
-
- {{ t("pages-store.checkout.chooseTime") }}
-
-
- {{ userSelectedSelfPickupTimeDate }}
-
-
+
+
+
+ {{ storeDetail?.merchantName }}
+ {{ storeDetail?.merchantAddress }}
+
+
-
-
+
+
-
-
-
-
-
- {{ t("pages-store.checkout.orderInfoSummary") }}
-
-
-
-
-
-
-
-
- {{ storeDetail?.merchantName }}
- {{ cartDataList.length }} {{ t('pages-user.cart.items') }}
-
-
-
+
+ {{ t('pages-store.checkout.confirmOrder') }}
+
+
+
+
+
+
-
-
+
+ {{
+ deliveryMethod === 0 ? t('pages-store.checkout.localDelivery') : t('pages-store.checkout.pickupTitle')
+ }}
+ {{
+ deliveryMethod === 0
+ ? localDeliverySubtitleText
+ : t('pages-store.checkout.pickupSubtitle')
+ }}
+
+
+
-
+ {{ deliveryPillText }}
+
+
+
+ {{ itemsGoodsTotalWithPriceText }}
+
+
+ {{ t('pages-store.checkout.shippingFee') }}
+ ${{ listDeliveryFeeStr }}
+
+ ${{ displayDeliveryFeeStr }}
+
+
+
+
+
+
+
+
+
+
+ {{ t('pages-store.checkout.scheduledDeliveryTitle') }}
+ {{
+ scheduledDeliveryWindowText
+ }}
+ {{
+ t('pages-store.checkout.scheduledDeliveryHint')
+ }}
+
+
+ {{ t('pages-store.checkout.scheduledDeliveryAddon') }}
+
+
+
+
+
+ {{ t('pages-store.checkout.scheduledDeliveryStandardTitle') }}
+ {{ t('pages-store.checkout.scheduledDeliveryStandardDesc') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ x{{ cItem.count }}
+
+
+
+
+
+
+
{{ index + 1 }}
-
- {{ index + 1 }}
+
+ {{ item.merchantDishVo?.dishName }}
+
-
{{ dish.merchantSideDishItemVo?.name }}
+${{ dish.merchantSideDishItemVo?.price }}
-
+
- ${{ item.merchantDishVo?.discountPrice }}
+ ${{ item.merchantDishVo?.discountPrice }}
-
-
-
+
+
+
+
+ {{ deliverBeforeText }}
+
+
-
- {{ t("pages-store.checkout.orderInfoSummary") }}
-
+
+ {{ t('pages-store.checkout.confirmOrder') }}
+
+
+
+ {{ deliveryPillText }}
+
+
+
+ {{ cartTotalPieceCount }} {{ t('pages-user.cart.items') }} · ${{ displayGoodsAmountStr }}
+
+
+ {{ t('pages-store.checkout.shippingFee') }}
+ ${{ listDeliveryFeeStr }}
+
+ ${{ displayDeliveryFeeStr }}
+
+
+
+
+
-
+
-
+
-
+
{{ dish?.merchantSideDishItemVo?.name || '' }}
+${{ dish?.merchantSideDishItemVo?.price }}
-
+
@@ -1484,7 +1685,7 @@ function handleClose(merchantId?: string) {
-
+