diff --git a/src/components/choose-image/choose-image.vue b/src/components/choose-image/choose-image.vue index 516a268..4137b28 100644 --- a/src/components/choose-image/choose-image.vue +++ b/src/components/choose-image/choose-image.vue @@ -106,6 +106,9 @@ function chooseImage(type: 'album' | 'camera') { console.log(results) emits('change', results) }) + .catch(() => { + uni.showToast({ icon: 'none', title: t('common.prompt.up-failed') }) + }) .finally(() => { uni.hideLoading() }) @@ -138,6 +141,9 @@ function chooseImage(type: 'album' | 'camera') { .then((results) => { emits('change', results) }) + .catch(() => { + uni.showToast({ icon: 'none', title: t('common.prompt.up-failed') }) + }) .finally(() => { uni.hideLoading() }) diff --git a/src/locale/en.json b/src/locale/en.json index 13b241d..aa5289d 100644 --- a/src/locale/en.json +++ b/src/locale/en.json @@ -554,6 +554,7 @@ "cancellationReasonDesc": "30 minutes without processing automatically agreed by the system.", "cancellationTime": "Cancellation time", "cancellationTitle": "Merchant processing in progress", + "cancelSuccess": "Order cancelled successfully", "cancelled": "Cancelled", "deliveryAddress": "Delivery address", "deliveryDate": "Delivery date", @@ -591,9 +592,15 @@ "useCode": "Use code", "writeOff": "Meal Code", "uploadPaidVoucher": "I've paid — upload proof", - "voucherSubmitSuccess": "Proof submitted", + "voucherSubmitSuccess": "Proof submitted — pending review", "voucherSubmitFailed": "Submit failed, please try again", "voucherUploadFailed": "Upload failed, please try again", + "payMethodZip": "ZIP voucher payment", + "zipPayHint": "Scan the QR code to pay, then upload your payment proof", + "zipPayAmountLabel": "Amount due", + "zipPayAmountInvalid": "Invalid payment amount. Please return to checkout.", + "zipPayAmountChanged": "Payment group amount changed. Please upload proof again.", + "zipPayPendingReview": "A ZIP payment for this delivery date is pending review.", "pleaseBindCreditCard": "No bank card linked. Please add a card before paying." }, "energyMeal": { diff --git a/src/locale/zh-Hans.json b/src/locale/zh-Hans.json index 60040c5..36030f9 100644 --- a/src/locale/zh-Hans.json +++ b/src/locale/zh-Hans.json @@ -554,6 +554,7 @@ "cancellationReasonDesc": "30分钟不处理,系统自动同意", "cancellationTime": "取消时间", "cancellationTitle": "商户处理中", + "cancelSuccess": "取消订单成功", "cancelled": "已取消", "deliveryAddress": "配送地址", "deliveryDate": "配送日期", @@ -591,9 +592,15 @@ "useCode": "核销码", "writeOff": "核销", "uploadPaidVoucher": "我已支付,上传凭证", - "voucherSubmitSuccess": "凭证已提交", + "voucherSubmitSuccess": "凭证已提交,待审核", "voucherSubmitFailed": "提交失败,请重试", "voucherUploadFailed": "上传失败,请重试", + "payMethodZip": "ZIP 凭证支付", + "zipPayHint": "请扫码完成转账后,上传支付凭证截图", + "zipPayAmountLabel": "应付金额", + "zipPayAmountInvalid": "支付金额无效,请返回结算页重新确认", + "zipPayAmountChanged": "支付组金额已变化,请重新上传凭证", + "zipPayPendingReview": "该配送日期已有 ZIP 支付待审核,请等待审核", "pleaseBindCreditCard": "未绑定银行卡,请先绑定后再支付" }, "energyMeal": { diff --git a/src/pages-store/pages/order/checkout.vue b/src/pages-store/pages/order/checkout.vue index 84cf9a8..836fe8b 100644 --- a/src/pages-store/pages/order/checkout.vue +++ b/src/pages-store/pages/order/checkout.vue @@ -21,7 +21,8 @@ import { appMerchantOrderCalculatePriceCartBatchPost, appMerchantCartListMerchantPost, appMerchantOrderPayOrderBatchPost, - appMerchantOrderZipPayVoucherPost + appMerchantOrderZipPayVoucherPost, + appMerchantOrderZipPayVoucherBatchPost } from "@/service"; import useEventEmit from "@/hooks/useEventEmit"; import {EventEnum} from "@/constant/enums"; @@ -46,8 +47,13 @@ import { pickCheckoutPaidAmount, pickCheckoutTax, pickCheckoutTip, + pickZipPaymentAmount, + resolveRequestErrorMessage, + isZipAmountChangedError, + isZipPendingReviewError, resolveTipAmount, stringifyCartIds, + stringifyOrderIds, } from "./utils/checkout-order"; defineOptions({ @@ -471,11 +477,45 @@ const payMethodOptions = ref({ const payMethodPopupVisible = ref(false) const payMethodSelected = ref(1) const zellePopupVisible = ref(false) -const zelleOrderIdForVoucher = ref('') +const zipVoucherOrderIds = ref([]) +/** 创单后提交 ZIP 凭证使用的应付金额快照(不再依赖购物车算价) */ +const zipVoucherPaymentAmountSnapshot = ref(0) const voucherChooseRef = ref>() const voucherSubmitting = ref(false) const zellePayPath = Config.zellePayPath; +const zipVoucherPaymentAmount = computed(() => + pickZipPaymentAmount(priceData.value as any, orderType.value === 'batch'), +) + +const zipVoucherPaymentAmountText = computed(() => + (zipVoucherPaymentAmountSnapshot.value || zipVoucherPaymentAmount.value).toFixed(2), +) + +function snapshotZipPaymentAmount() { + const amount = pickZipPaymentAmount(priceData.value as any, orderType.value === 'batch') + zipVoucherPaymentAmountSnapshot.value = amount + return amount +} + +function setZipVoucherOrderIds(ids: Array) { + zipVoucherOrderIds.value = stringifyOrderIds(ids) +} + +function openZipVoucherPopup(ids: Array) { + setZipVoucherOrderIds(ids) + const amount = snapshotZipPaymentAmount() + if (!zipVoucherOrderIds.value.length) { + uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' }) + return + } + if (amount <= 0) { + uni.showToast({ title: t('pages-store.order.zipPayAmountInvalid'), icon: 'none' }) + return + } + zellePopupVisible.value = true +} + function openPayMethodPopup() { payMethodSelected.value = Number(payMethodOptions.value.payMethod || 1) payMethodPopupVisible.value = true @@ -486,7 +526,7 @@ function confirmPayMethodForSettle() { handleGoSettle() } function openUploadVoucher() { - if (!zelleOrderIdForVoucher.value) { + if (!zipVoucherOrderIds.value.length) { uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' }) return } @@ -494,37 +534,91 @@ function openUploadVoucher() { } function normalizeVoucherUrl(payload: unknown): string { if (Array.isArray(payload)) { - const first = payload[0] - return typeof first === 'string' ? first : '' + return normalizeVoucherUrl(payload[0]) } - return typeof payload === 'string' ? payload : '' + if (typeof payload === 'string') { + return payload.trim() + } + if (payload && typeof payload === 'object') { + const obj = payload as Record + for (const key of ['url', 'fullUrl', 'fileUrl', 'link']) { + const val = obj[key] + if (typeof val === 'string' && val.trim()) { + return val.trim() + } + } + } + return '' } + +async function submitZipPayVoucher(zipPayVoucher: string) { + const orderIds = zipVoucherOrderIds.value + const paymentAmount = zipVoucherPaymentAmountSnapshot.value + if (!orderIds.length || paymentAmount <= 0) { + throw new Error(t('pages-store.order.zipPayAmountInvalid')) + } + if (orderIds.length > 1) { + await appMerchantOrderZipPayVoucherBatchPost({ + body: { + orderIds, + zipPayVoucher, + paymentAmount, + }, + options: { hideErrorToast: true }, + }) + return + } + await appMerchantOrderZipPayVoucherPost({ + body: { + orderId: orderIds[0], + zipPayVoucher, + paymentAmount, + }, + options: { hideErrorToast: true }, + }) +} + async function onVoucherImageUploaded(urls: unknown) { const zipPayVoucher = normalizeVoucherUrl(urls) - if (!zipPayVoucher || !zelleOrderIdForVoucher.value) { + if (!zipPayVoucher) { uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' }) return } + if (!zipVoucherOrderIds.value.length) { + uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' }) + return + } + if (zipVoucherPaymentAmountSnapshot.value <= 0) { + uni.showToast({ title: t('pages-store.order.zipPayAmountInvalid'), icon: 'none' }) + return + } if (voucherSubmitting.value) return voucherSubmitting.value = true try { - await appMerchantOrderZipPayVoucherPost({ - body: { - orderId: zelleOrderIdForVoucher.value, - zipPayVoucher, - } - }) + await submitZipPayVoucher(zipPayVoucher) uni.showToast({ title: t('pages-store.order.voucherSubmitSuccess'), icon: 'none' }) zellePopupVisible.value = false + const firstOrderId = zipVoucherOrderIds.value[0] setTimeout(() => { - if (zelleOrderIdForVoucher.value) { - uni.reLaunch({ - url: `/pages-store/pages/order/index?id=${zelleOrderIdForVoucher.value}` - }) - } + if (!firstOrderId) return + const query = zipVoucherOrderIds.value.length > 1 + ? `id=${firstOrderId}&orderIds=${zipVoucherOrderIds.value.join(',')}&paymentAmount=${zipVoucherPaymentAmountSnapshot.value}` + : `id=${firstOrderId}` + uni.reLaunch({ + url: `/pages-store/pages/order/index?${query}`, + }) }, 500) - } catch { - uni.showToast({ title: t('pages-store.order.voucherSubmitFailed'), icon: 'none' }) + } catch (err) { + const message = resolveRequestErrorMessage(err, t('pages-store.order.voucherSubmitFailed')) + if (isZipAmountChangedError(message)) { + uni.showToast({ title: t('pages-store.order.zipPayAmountChanged'), icon: 'none' }) + return + } + if (isZipPendingReviewError(message)) { + uni.showToast({ title: t('pages-store.order.zipPayPendingReview'), icon: 'none' }) + return + } + uni.showToast({ title: message, icon: 'none' }) } finally { voucherSubmitting.value = false } @@ -1024,8 +1118,7 @@ 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 + openZipVoucherPopup(resOrderIds.value) } else { appMerchantOrderPayOrderBatch() } @@ -1040,8 +1133,7 @@ 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 + openZipVoucherPopup(resOrderIds.value) } else { appMerchantOrderPayOrderBatch() } @@ -1068,8 +1160,7 @@ function handleGoSettle() { if(payMethodOptions.value.payMethod === 2) { passwordInputRef.value?.showPasswordInput() } else if (payMethodOptions.value.payMethod === 3) { - zelleOrderIdForVoucher.value = String(resOrderId.value || '') - zellePopupVisible.value = true + openZipVoucherPopup([resOrderId.value]) } else { appMerchantOrderPayOrder() } @@ -1079,8 +1170,7 @@ function handleGoSettle() { if(payMethodOptions.value.payMethod === 2) { passwordInputRef.value?.showPasswordInput() } else if (payMethodOptions.value.payMethod === 3) { - zelleOrderIdForVoucher.value = String(resOrderId.value || '') - zellePopupVisible.value = true + openZipVoucherPopup([resOrderId.value]) } else { appMerchantOrderPayOrder() } @@ -2121,8 +2211,8 @@ function handleClose(merchantId?: string) { - Zelle - Scan QR and upload voucher + {{ t('pages-store.order.payMethodZip') }} + {{ t('pages-store.order.zipPayHint') }} @@ -2135,10 +2225,16 @@ function handleClose(merchantId?: string) { - Zelle + ZIP + + {{ t('pages-store.order.zipPayAmountLabel') }} ${{ zipVoucherPaymentAmountText }} + + + {{ t('pages-store.order.zipPayHint') }} + - zellePayPath is empty + QR [ { label: t('pages-store.store.cancelOrder.informationError'), value: 'time' @@ -23,26 +23,29 @@ const sortOptions = [ label: t('pages-store.store.cancelOrder.dontWant'), value: 'comment' } -]; +]); const currentSort = ref(0); function handleClick(index: number) { - // show.value = false; currentSort.value = index; } function confirmCancel() { - console.log('取消订单', sortOptions[currentSort.value].label) - emit('confirm', sortOptions[currentSort.value].label); + emit('confirm', sortOptions.value[currentSort.value].label); } function onOpen() { + currentSort.value = 0; show.value = true; } -function handleClose() { +function onClose() { show.value = false; } +function handleClose() { + onClose(); +} defineExpose({ onOpen, + onClose, }); @@ -59,7 +62,7 @@ defineExpose({ class="w-28rpx h-28rpx absolute top-30rpx right-30rpx" mode="aspectFit" /> - {{ t('common.cancel') }} + {{ t('pages.order.cancelOrder') }}