This commit is contained in:
2026-06-18 00:10:27 +08:00
parent fbf40a1575
commit 41099f4190
9 changed files with 328 additions and 68 deletions
@@ -106,6 +106,9 @@ function chooseImage(type: 'album' | 'camera') {
console.log(results) console.log(results)
emits('change', results) emits('change', results)
}) })
.catch(() => {
uni.showToast({ icon: 'none', title: t('common.prompt.up-failed') })
})
.finally(() => { .finally(() => {
uni.hideLoading() uni.hideLoading()
}) })
@@ -138,6 +141,9 @@ function chooseImage(type: 'album' | 'camera') {
.then((results) => { .then((results) => {
emits('change', results) emits('change', results)
}) })
.catch(() => {
uni.showToast({ icon: 'none', title: t('common.prompt.up-failed') })
})
.finally(() => { .finally(() => {
uni.hideLoading() uni.hideLoading()
}) })
+8 -1
View File
@@ -554,6 +554,7 @@
"cancellationReasonDesc": "30 minutes without processing automatically agreed by the system.", "cancellationReasonDesc": "30 minutes without processing automatically agreed by the system.",
"cancellationTime": "Cancellation time", "cancellationTime": "Cancellation time",
"cancellationTitle": "Merchant processing in progress", "cancellationTitle": "Merchant processing in progress",
"cancelSuccess": "Order cancelled successfully",
"cancelled": "Cancelled", "cancelled": "Cancelled",
"deliveryAddress": "Delivery address", "deliveryAddress": "Delivery address",
"deliveryDate": "Delivery date", "deliveryDate": "Delivery date",
@@ -591,9 +592,15 @@
"useCode": "Use code", "useCode": "Use code",
"writeOff": "Meal Code", "writeOff": "Meal Code",
"uploadPaidVoucher": "I've paid — upload proof", "uploadPaidVoucher": "I've paid — upload proof",
"voucherSubmitSuccess": "Proof submitted", "voucherSubmitSuccess": "Proof submitted — pending review",
"voucherSubmitFailed": "Submit failed, please try again", "voucherSubmitFailed": "Submit failed, please try again",
"voucherUploadFailed": "Upload 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." "pleaseBindCreditCard": "No bank card linked. Please add a card before paying."
}, },
"energyMeal": { "energyMeal": {
+8 -1
View File
@@ -554,6 +554,7 @@
"cancellationReasonDesc": "30分钟不处理,系统自动同意", "cancellationReasonDesc": "30分钟不处理,系统自动同意",
"cancellationTime": "取消时间", "cancellationTime": "取消时间",
"cancellationTitle": "商户处理中", "cancellationTitle": "商户处理中",
"cancelSuccess": "取消订单成功",
"cancelled": "已取消", "cancelled": "已取消",
"deliveryAddress": "配送地址", "deliveryAddress": "配送地址",
"deliveryDate": "配送日期", "deliveryDate": "配送日期",
@@ -591,9 +592,15 @@
"useCode": "核销码", "useCode": "核销码",
"writeOff": "核销", "writeOff": "核销",
"uploadPaidVoucher": "我已支付,上传凭证", "uploadPaidVoucher": "我已支付,上传凭证",
"voucherSubmitSuccess": "凭证已提交", "voucherSubmitSuccess": "凭证已提交,待审核",
"voucherSubmitFailed": "提交失败,请重试", "voucherSubmitFailed": "提交失败,请重试",
"voucherUploadFailed": "上传失败,请重试", "voucherUploadFailed": "上传失败,请重试",
"payMethodZip": "ZIP 凭证支付",
"zipPayHint": "请扫码完成转账后,上传支付凭证截图",
"zipPayAmountLabel": "应付金额",
"zipPayAmountInvalid": "支付金额无效,请返回结算页重新确认",
"zipPayAmountChanged": "支付组金额已变化,请重新上传凭证",
"zipPayPendingReview": "该配送日期已有 ZIP 支付待审核,请等待审核",
"pleaseBindCreditCard": "未绑定银行卡,请先绑定后再支付" "pleaseBindCreditCard": "未绑定银行卡,请先绑定后再支付"
}, },
"energyMeal": { "energyMeal": {
+126 -30
View File
@@ -21,7 +21,8 @@ import {
appMerchantOrderCalculatePriceCartBatchPost, appMerchantOrderCalculatePriceCartBatchPost,
appMerchantCartListMerchantPost, appMerchantCartListMerchantPost,
appMerchantOrderPayOrderBatchPost, appMerchantOrderPayOrderBatchPost,
appMerchantOrderZipPayVoucherPost appMerchantOrderZipPayVoucherPost,
appMerchantOrderZipPayVoucherBatchPost
} from "@/service"; } from "@/service";
import useEventEmit from "@/hooks/useEventEmit"; import useEventEmit from "@/hooks/useEventEmit";
import {EventEnum} from "@/constant/enums"; import {EventEnum} from "@/constant/enums";
@@ -46,8 +47,13 @@ import {
pickCheckoutPaidAmount, pickCheckoutPaidAmount,
pickCheckoutTax, pickCheckoutTax,
pickCheckoutTip, pickCheckoutTip,
pickZipPaymentAmount,
resolveRequestErrorMessage,
isZipAmountChangedError,
isZipPendingReviewError,
resolveTipAmount, resolveTipAmount,
stringifyCartIds, stringifyCartIds,
stringifyOrderIds,
} from "./utils/checkout-order"; } from "./utils/checkout-order";
defineOptions({ defineOptions({
@@ -471,11 +477,45 @@ const payMethodOptions = ref({
const payMethodPopupVisible = ref(false) const payMethodPopupVisible = ref(false)
const payMethodSelected = ref(1) const payMethodSelected = ref(1)
const zellePopupVisible = ref(false) const zellePopupVisible = ref(false)
const zelleOrderIdForVoucher = ref('') const zipVoucherOrderIds = ref<string[]>([])
/** 创单后提交 ZIP 凭证使用的应付金额快照(不再依赖购物车算价) */
const zipVoucherPaymentAmountSnapshot = ref(0)
const voucherChooseRef = ref<InstanceType<typeof ChooseImage>>() const voucherChooseRef = ref<InstanceType<typeof ChooseImage>>()
const voucherSubmitting = ref(false) const voucherSubmitting = ref(false)
const zellePayPath = Config.zellePayPath; 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<string | number | null | undefined>) {
zipVoucherOrderIds.value = stringifyOrderIds(ids)
}
function openZipVoucherPopup(ids: Array<string | number | null | undefined>) {
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() { function openPayMethodPopup() {
payMethodSelected.value = Number(payMethodOptions.value.payMethod || 1) payMethodSelected.value = Number(payMethodOptions.value.payMethod || 1)
payMethodPopupVisible.value = true payMethodPopupVisible.value = true
@@ -486,7 +526,7 @@ function confirmPayMethodForSettle() {
handleGoSettle() handleGoSettle()
} }
function openUploadVoucher() { function openUploadVoucher() {
if (!zelleOrderIdForVoucher.value) { if (!zipVoucherOrderIds.value.length) {
uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' }) uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' })
return return
} }
@@ -494,37 +534,91 @@ function openUploadVoucher() {
} }
function normalizeVoucherUrl(payload: unknown): string { function normalizeVoucherUrl(payload: unknown): string {
if (Array.isArray(payload)) { if (Array.isArray(payload)) {
const first = payload[0] return normalizeVoucherUrl(payload[0])
return typeof first === 'string' ? first : ''
} }
return typeof payload === 'string' ? payload : '' if (typeof payload === 'string') {
return payload.trim()
}
if (payload && typeof payload === 'object') {
const obj = payload as Record<string, unknown>
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) { async function onVoucherImageUploaded(urls: unknown) {
const zipPayVoucher = normalizeVoucherUrl(urls) const zipPayVoucher = normalizeVoucherUrl(urls)
if (!zipPayVoucher || !zelleOrderIdForVoucher.value) { if (!zipPayVoucher) {
uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' }) uni.showToast({ title: t('pages-store.order.voucherUploadFailed'), icon: 'none' })
return 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 if (voucherSubmitting.value) return
voucherSubmitting.value = true voucherSubmitting.value = true
try { try {
await appMerchantOrderZipPayVoucherPost({ await submitZipPayVoucher(zipPayVoucher)
body: {
orderId: zelleOrderIdForVoucher.value,
zipPayVoucher,
}
})
uni.showToast({ title: t('pages-store.order.voucherSubmitSuccess'), icon: 'none' }) uni.showToast({ title: t('pages-store.order.voucherSubmitSuccess'), icon: 'none' })
zellePopupVisible.value = false zellePopupVisible.value = false
const firstOrderId = zipVoucherOrderIds.value[0]
setTimeout(() => { setTimeout(() => {
if (zelleOrderIdForVoucher.value) { if (!firstOrderId) return
const query = zipVoucherOrderIds.value.length > 1
? `id=${firstOrderId}&orderIds=${zipVoucherOrderIds.value.join(',')}&paymentAmount=${zipVoucherPaymentAmountSnapshot.value}`
: `id=${firstOrderId}`
uni.reLaunch({ uni.reLaunch({
url: `/pages-store/pages/order/index?id=${zelleOrderIdForVoucher.value}` url: `/pages-store/pages/order/index?${query}`,
}) })
}
}, 500) }, 500)
} catch { } catch (err) {
uni.showToast({ title: t('pages-store.order.voucherSubmitFailed'), icon: 'none' }) 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 { } finally {
voucherSubmitting.value = false voucherSubmitting.value = false
} }
@@ -1024,8 +1118,7 @@ function handleGoSettle() {
if(payMethodOptions.value.payMethod === 2) { if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput() passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) { } else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = resOrderIds.value?.[0] ? String(resOrderIds.value[0]) : '' openZipVoucherPopup(resOrderIds.value)
zellePopupVisible.value = true
} else { } else {
appMerchantOrderPayOrderBatch() appMerchantOrderPayOrderBatch()
} }
@@ -1040,8 +1133,7 @@ function handleGoSettle() {
if(payMethodOptions.value.payMethod === 2) { if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput() passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) { } else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = resOrderIds.value?.[0] ? String(resOrderIds.value[0]) : '' openZipVoucherPopup(resOrderIds.value)
zellePopupVisible.value = true
} else { } else {
appMerchantOrderPayOrderBatch() appMerchantOrderPayOrderBatch()
} }
@@ -1068,8 +1160,7 @@ function handleGoSettle() {
if(payMethodOptions.value.payMethod === 2) { if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput() passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) { } else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = String(resOrderId.value || '') openZipVoucherPopup([resOrderId.value])
zellePopupVisible.value = true
} else { } else {
appMerchantOrderPayOrder() appMerchantOrderPayOrder()
} }
@@ -1079,8 +1170,7 @@ function handleGoSettle() {
if(payMethodOptions.value.payMethod === 2) { if(payMethodOptions.value.payMethod === 2) {
passwordInputRef.value?.showPasswordInput() passwordInputRef.value?.showPasswordInput()
} else if (payMethodOptions.value.payMethod === 3) { } else if (payMethodOptions.value.payMethod === 3) {
zelleOrderIdForVoucher.value = String(resOrderId.value || '') openZipVoucherPopup([resOrderId.value])
zellePopupVisible.value = true
} else { } else {
appMerchantOrderPayOrder() appMerchantOrderPayOrder()
} }
@@ -2121,8 +2211,8 @@ function handleClose(merchantId?: string) {
<view class="checkout-paymethod-dot-inner"></view> <view class="checkout-paymethod-dot-inner"></view>
</view> </view>
<view class="checkout-paymethod-text-wrap"> <view class="checkout-paymethod-text-wrap">
<view class="checkout-paymethod-name">Zelle</view> <view class="checkout-paymethod-name">{{ t('pages-store.order.payMethodZip') }}</view>
<view class="checkout-paymethod-desc">Scan QR and upload voucher</view> <view class="checkout-paymethod-desc">{{ t('pages-store.order.zipPayHint') }}</view>
</view> </view>
</view> </view>
</view> </view>
@@ -2135,10 +2225,16 @@ function handleClose(merchantId?: string) {
</wd-popup> </wd-popup>
<wd-popup v-model="zellePopupVisible" custom-style="background: transparent;" @close="zellePopupVisible = false"> <wd-popup v-model="zellePopupVisible" custom-style="background: transparent;" @close="zellePopupVisible = false">
<view class="w-620rpx rounded-24rpx bg-white p-28rpx"> <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> <view class="text-32rpx lh-32rpx text-#333 font-600 text-center mb-16rpx">ZIP</view>
<view class="text-26rpx lh-36rpx text-#666 text-center mb-20rpx">
{{ t('pages-store.order.zipPayAmountLabel') }} ${{ zipVoucherPaymentAmountText }}
</view>
<view class="text-24rpx lh-34rpx text-#999 text-center mb-20rpx">
{{ t('pages-store.order.zipPayHint') }}
</view>
<image v-if="zellePayPath" :src="zellePayPath" mode="aspectFit" class="w-100% h-520rpx rounded-16rpx bg-#F7F7F7" /> <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"> <view v-else class="h-220rpx rounded-16rpx bg-#F7F7F7 center text-#999 text-24rpx">
zellePayPath is empty QR
</view> </view>
<wd-button <wd-button
:loading="voucherSubmitting" :loading="voucherSubmitting"
@@ -6,7 +6,7 @@ const emit = defineEmits(['confirm']);
const show = ref(false); const show = ref(false);
const sortOptions = [ const sortOptions = computed(() => [
{ {
label: t('pages-store.store.cancelOrder.informationError'), label: t('pages-store.store.cancelOrder.informationError'),
value: 'time' value: 'time'
@@ -23,26 +23,29 @@ const sortOptions = [
label: t('pages-store.store.cancelOrder.dontWant'), label: t('pages-store.store.cancelOrder.dontWant'),
value: 'comment' value: 'comment'
} }
]; ]);
const currentSort = ref(0); const currentSort = ref(0);
function handleClick(index: number) { function handleClick(index: number) {
// show.value = false;
currentSort.value = index; currentSort.value = index;
} }
function confirmCancel() { function confirmCancel() {
console.log('取消订单', sortOptions[currentSort.value].label) emit('confirm', sortOptions.value[currentSort.value].label);
emit('confirm', sortOptions[currentSort.value].label);
} }
function onOpen() { function onOpen() {
currentSort.value = 0;
show.value = true; show.value = true;
} }
function handleClose() { function onClose() {
show.value = false; show.value = false;
} }
function handleClose() {
onClose();
}
defineExpose({ defineExpose({
onOpen, onOpen,
onClose,
}); });
</script> </script>
@@ -59,7 +62,7 @@ defineExpose({
class="w-28rpx h-28rpx absolute top-30rpx right-30rpx" class="w-28rpx h-28rpx absolute top-30rpx right-30rpx"
mode="aspectFit" mode="aspectFit"
/> />
<view class="text-36rpx lh-36rpx text-#333 font-bold text-center mb-68rpx">{{ t('common.cancel') }}</view> <view class="text-36rpx lh-36rpx text-#333 font-bold text-center mb-68rpx">{{ t('pages.order.cancelOrder') }}</view>
<template v-for="(item, index) in sortOptions"> <template v-for="(item, index) in sortOptions">
<view @click="handleClick(index)" class="flex items-center mb-42rpx last:mb-0"> <view @click="handleClick(index)" class="flex items-center mb-42rpx last:mb-0">
<view class="w-48rpx h-48rpx shrink-0 mr-20rpx"> <view class="w-48rpx h-48rpx shrink-0 mr-20rpx">
+80 -20
View File
@@ -6,8 +6,15 @@ import {
appMerchantOrderPayOrderPost, appMerchantOrderPayOrderPost,
appMerchantOrderCancelOrderPost, appMerchantOrderCancelOrderPost,
appMerchantOrderZipPayVoucherPost, appMerchantOrderZipPayVoucherPost,
appMerchantOrderZipPayVoucherBatchPost,
} from "@/service"; } from "@/service";
import ChooseImage from '@/components/choose-image/choose-image.vue' import ChooseImage from '@/components/choose-image/choose-image.vue'
import {
resolveRequestErrorMessage,
isZipAmountChangedError,
isZipPendingReviewError,
stringifyOrderIds,
} from '@/pages-store/pages/order/utils/checkout-order'
const { t } = useI18n(); const { t } = useI18n();
import OrderProgress from './components/order-progress.vue' import OrderProgress from './components/order-progress.vue'
import OrderDetailSkeleton from './components/order-detail-skeleton.vue' import OrderDetailSkeleton from './components/order-detail-skeleton.vue'
@@ -38,15 +45,15 @@ const openCancelOrder = () => {
cancelOrderRef.value?.onOpen(); cancelOrderRef.value?.onOpen();
}; };
function confirmCancel(reason: string) { function confirmCancel(reason: string) {
console.log('取消订单', reason)
appMerchantOrderCancelOrderPost({ appMerchantOrderCancelOrderPost({
body: { body: {
orderId: orderDetail.value.id, orderId: orderDetail.value.id,
cancelReason: reason, cancelReason: reason,
} }
}).then(res=> { }).then(res=> {
cancelOrderRef.value?.onClose()
uni.showToast({ uni.showToast({
title: '取消订单成功', title: t('pages-store.order.cancelSuccess'),
icon: 'none', icon: 'none',
}) })
setTimeout(() => { setTimeout(() => {
@@ -74,13 +81,23 @@ const orderStepsCancel = ref([
// 页面加载状态 // 页面加载状态
const loading = ref(true); const loading = ref(true);
const orderId = ref('') const orderId = ref('')
const zipVoucherOrderIds = ref<string[]>([])
const zipVoucherPaymentAmount = ref(0)
onLoad((options: any)=> { onLoad((options: any)=> {
if(options.id) { if(options.id) {
orderId.value = options.id; orderId.value = options.id;
// appMerchantOrderDetail()
// 查询用户默认信用卡
appUserCardSelectDefault()
} }
if (options?.orderIds) {
zipVoucherOrderIds.value = stringifyOrderIds(String(options.orderIds).split(','))
}
if (options?.paymentAmount != null && options?.paymentAmount !== '') {
const amount = Number(options.paymentAmount)
if (Number.isFinite(amount) && amount > 0) {
zipVoucherPaymentAmount.value = amount
}
}
appUserCardSelectDefault()
}) })
onShow(()=> { onShow(()=> {
@@ -92,13 +109,19 @@ onShow(()=> {
const orderDetail = ref<MerchantOrderVo>() const orderDetail = ref<MerchantOrderVo>()
function appMerchantOrderDetail() { function appMerchantOrderDetail() {
loading.value = true; loading.value = true;
appMerchantOrderDetailPost({ return appMerchantOrderDetailPost({
params: { params: {
orderId: orderId.value, orderId: orderId.value,
} }
}).then((res: any)=> { }).then((res: any)=> {
console.log('订单详情', res) console.log('订单详情', res)
orderDetail.value = res.data orderDetail.value = res.data
if (!zipVoucherOrderIds.value.length && orderDetail.value?.id) {
zipVoucherOrderIds.value = stringifyOrderIds([orderDetail.value.id])
}
if (zipVoucherPaymentAmount.value <= 0 && orderDetail.value?.paidAmount != null) {
zipVoucherPaymentAmount.value = Number(orderDetail.value.paidAmount) || 0
}
// 是自取订单还是配送订单 1-派送 2-自取 // 是自取订单还是配送订单 1-派送 2-自取
if(orderDetail.value) { if(orderDetail.value) {
if(+orderDetail.value.receiveMethod === 2) { if(+orderDetail.value.receiveMethod === 2) {
@@ -165,10 +188,11 @@ function dishTitle(dishItem: any) {
} }
const payMethodText = computed(() => { const payMethodText = computed(() => {
// 1-信用卡 2-余额(wallet const method = orderDetail.value?.payMethod
return orderDetail.value?.payMethod === 1 if (method === 1) return t('pages-user.choosePaymethod.creditCard')
? t('pages-user.choosePaymethod.creditCard') if (method === 2) return t('pages-user.choosePaymethod.wallet')
: t('pages-user.choosePaymethod.wallet') if (method === 3) return t('pages-store.order.payMethodZip')
return '--'
}) })
// 复制订单号 // 复制订单号
@@ -337,6 +361,37 @@ function normalizeVoucherUrl(payload: unknown): string {
return typeof payload === 'string' ? payload : '' return typeof payload === 'string' ? payload : ''
} }
async function submitZipPayVoucher(zipPayVoucher: string) {
const orderIds = zipVoucherOrderIds.value.length
? zipVoucherOrderIds.value
: stringifyOrderIds([orderDetail.value?.id])
const paymentAmount = zipVoucherPaymentAmount.value > 0
? zipVoucherPaymentAmount.value
: Number(orderDetail.value?.paidAmount ?? 0)
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) { async function onVoucherImageUploaded(urls: unknown) {
const zipPayVoucher = normalizeVoucherUrl(urls) const zipPayVoucher = normalizeVoucherUrl(urls)
if (!zipPayVoucher) { if (!zipPayVoucher) {
@@ -351,22 +406,27 @@ async function onVoucherImageUploaded(urls: unknown) {
if (voucherSubmitting.value) return if (voucherSubmitting.value) return
voucherSubmitting.value = true voucherSubmitting.value = true
try { try {
await appMerchantOrderZipPayVoucherPost({ await submitZipPayVoucher(zipPayVoucher)
body: {
orderId: id,
zipPayVoucher,
},
options: { hideErrorToast: true },
})
uni.showToast({ title: t('pages-store.order.voucherSubmitSuccess'), icon: 'none' }) uni.showToast({ title: t('pages-store.order.voucherSubmitSuccess'), icon: 'none' })
setTimeout(() => { setTimeout(() => {
appMerchantOrderDetail() appMerchantOrderDetail()
}, 500) }, 500)
} catch (err) {
const message = resolveRequestErrorMessage(err, t('pages-store.order.voucherSubmitFailed'))
if (isZipAmountChangedError(message)) {
await appMerchantOrderDetail()
if (zipVoucherPaymentAmount.value <= 0) {
zipVoucherPaymentAmount.value = Number(orderDetail.value?.paidAmount ?? 0)
} }
catch { uni.showToast({ title: t('pages-store.order.zipPayAmountChanged'), icon: 'none' })
uni.showToast({ title: t('pages-store.order.voucherSubmitFailed'), icon: 'none' }) return
} }
finally { if (isZipPendingReviewError(message)) {
uni.showToast({ title: t('pages-store.order.zipPayPendingReview'), icon: 'none' })
return
}
uni.showToast({ title: message, icon: 'none' })
} finally {
voucherSubmitting.value = false voucherSubmitting.value = false
} }
} }
@@ -182,3 +182,28 @@ export function pickCheckoutTax(price: Record<string, any> | null | undefined, i
} }
return Number(price.tax ?? 0) || 0 return Number(price.tax ?? 0) || 0
} }
export function stringifyOrderIds(ids: Array<string | number | null | undefined>): string[] {
return ids.map((id) => String(id ?? '').trim()).filter(Boolean)
}
/** ZIP 凭证提交应付总额(支付组维度) */
export function pickZipPaymentAmount(
price: Record<string, any> | null | undefined,
isBatch: boolean,
): number {
return pickCheckoutPaidAmount(price, isBatch)
}
export function resolveRequestErrorMessage(err: unknown, fallback: string): string {
const e = err as { msg?: string; message?: string; data?: { msg?: string } }
return String(e?.msg || e?.data?.msg || e?.message || fallback).trim() || fallback
}
export function isZipPendingReviewError(message: string): boolean {
return /ZIP.*待审核|待审核.*ZIP/i.test(message)
}
export function isZipAmountChangedError(message: string): boolean {
return /支付组金额已变化|金额已变化.*凭证/i.test(message)
}
@@ -1,8 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import { import {
appMerchantOrderOrderListPost, appMerchantOrderOrderListPost,
appMerchantOrderCancelOrderPost,
type MerchantOrderVo type MerchantOrderVo
} from "@/service"; } from "@/service";
import CancelOrder from '@/pages-store/pages/order/components/cancel-order.vue'
import {callPhone} from "@/utils/utils"; import {callPhone} from "@/utils/utils";
import {OrderCancelStatus, OrderStatus} from "@/constant/enums"; import {OrderCancelStatus, OrderStatus} from "@/constant/enums";
import {useUserStore} from "@/store"; import {useUserStore} from "@/store";
@@ -141,9 +143,32 @@ function handleClick(item: MerchantOrderVo) {
}) })
} }
const cancelOrderRef = ref<InstanceType<typeof CancelOrder>>()
const pendingCancelOrder = ref<MerchantOrderVo | null>(null)
function handleCancelClick(item: MerchantOrderVo) { function handleCancelClick(item: MerchantOrderVo) {
uni.navigateTo({ pendingCancelOrder.value = item
url: '/pages-store/pages/order/index?id=' + item.id cancelOrderRef.value?.onOpen()
}
function confirmCancel(reason: string) {
const order = pendingCancelOrder.value
if (!order?.id) return
appMerchantOrderCancelOrderPost({
body: {
orderId: order.id,
cancelReason: reason,
},
}).then(() => {
cancelOrderRef.value?.onClose()
pendingCancelOrder.value = null
uni.showToast({
title: t('pages-store.order.cancelSuccess'),
icon: 'none',
})
setTimeout(() => {
paging.value?.refresh()
}, 500)
}) })
} }
@@ -295,6 +320,7 @@ defineExpose({
</view> </view>
</view> </view>
</z-paging> </z-paging>
<cancel-order ref="cancelOrderRef" @confirm="confirmCancel" />
</view> </view>
</template> </template>
+33 -3
View File
@@ -500,13 +500,19 @@ export async function appMerchantOrderPayOrderBatchPost({
}); });
} }
/** 提交 Zip 支付凭证 POST /app/merchantOrder/zipPayVoucher */ /** 提交 Zip 支付凭证 POST /app/merchantOrder/zipPayVoucher(单订单兼容) */
export interface ZipPayVoucherBo {
orderId: string | number
zipPayVoucher: string
paymentAmount?: number
}
export async function appMerchantOrderZipPayVoucherPost({ export async function appMerchantOrderZipPayVoucherPost({
body, body,
options, options,
}: { }: {
body: { orderId: number; zipPayVoucher: string }; body: ZipPayVoucherBo
options?: CustomRequestOptions; options?: CustomRequestOptions
}) { }) {
return request<API.R>('/app/merchantOrder/zipPayVoucher', { return request<API.R>('/app/merchantOrder/zipPayVoucher', {
method: 'POST', method: 'POST',
@@ -518,6 +524,30 @@ export async function appMerchantOrderZipPayVoucherPost({
}); });
} }
/** 批量提交 Zip 支付凭证 POST /app/merchantOrder/zipPayVoucherBatch */
export interface ZipPayVoucherBatchBo {
orderIds: Array<string | number>
zipPayVoucher: string
paymentAmount: number
}
export async function appMerchantOrderZipPayVoucherBatchPost({
body,
options,
}: {
body: ZipPayVoucherBatchBo
options?: CustomRequestOptions
}) {
return request<API.R>('/app/merchantOrder/zipPayVoucherBatch', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}
/** /**
* PayOrderBatchBo - 批量订单支付参数 * PayOrderBatchBo - 批量订单支付参数
*/ */