From 22fed3b163a5ac7e24bdb7617bda6996d2fd2ed0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Fri, 17 Jul 2026 00:38:57 +0800 Subject: [PATCH] =?UTF-8?q?feat(store):=20=E6=96=B0=E5=A2=9E=E7=BA=BF?= =?UTF-8?q?=E4=B8=8B=E4=BB=98=E6=AC=BE=E7=A1=AE=E8=AE=A4=E6=94=B6=E6=AC=BE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=B9=B6=E6=94=B9=E4=B8=BA=E5=85=B3=E9=97=AD?= =?UTF-8?q?=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增接口 confirmOfflinePayment 支持门店确认线下付款收款 - 修改订单操作类型,增加“确认收款”按钮供线下付款未付款订单使用 - 确认收款弹窗新增备注输入框和支付凭证上传(必填,单张) - 调整提交逻辑,确认收款操作调用新接口,并校验凭证上传 - 订单列表页“删除订单”改为“关闭订单”,调用更新接口逻辑关闭订单 - 修改订单详情页金额明细渲染逻辑,修复0时错误显示问题 --- .workbuddy/memory/2026-07-17.md | 31 +++++++ src/api/shop/shopOrder/index.ts | 20 +++++ src/api/shop/shopOrder/model/index.ts | 2 + src/pages/order/detail.tsx | 2 +- src/pages/store/orders/index.tsx | 120 +++++++++++++++++--------- 5 files changed, 132 insertions(+), 43 deletions(-) create mode 100644 .workbuddy/memory/2026-07-17.md diff --git a/.workbuddy/memory/2026-07-17.md b/.workbuddy/memory/2026-07-17.md new file mode 100644 index 0000000..b1f54c4 --- /dev/null +++ b/.workbuddy/memory/2026-07-17.md @@ -0,0 +1,31 @@ +# 2026-07-17 工作日志 + +## 门店订单管理页改造(src/pages/store/orders/index.tsx) + +### 1. 删除订单改为关闭订单 +- 原"删除订单"按钮调用 `removeShopOrder`(物理删除),改为"关闭订单"调用 `updateShopOrder({ orderId, orderStatus: 2 })`(逻辑关闭) +- 确认弹窗文案从"删除后无法恢复"改为"关闭后无法恢复" +- 移除 `removeShopOrder` 导入,新增 `confirmOfflinePayment` 导入 + +### 2. 待付款订单加确认收款按钮 +- **背景**:线下付款(payType=9)且未付款的订单,门店需要"确认收款"功能,与后台管理(guilixu-admin)对齐 +- **后端接口**:`PUT /shop/shop-order/confirm-offline-payment/{id}?remarks=xxx&paymentVoucher=xxx` + - 后端 `ShopOrderController.confirmOfflinePayment()` → `ShopOrderServiceImpl.confirmOfflinePayment()` + - 校验:payType必须为9(线下付款)、orderStatus不能为2(已关闭)、不能重复确认 + - 确认后设置 payStatus=true、payTime=now(),可选保存 remarks(merchantRemarks) 和 paymentVoucher +- **前端API**:在 `src/api/shop/shopOrder/index.ts` 新增 `confirmOfflinePayment(id, remarks?, paymentVoucher?)` 函数 + - 注意:Taro 的 `request.put` 不支持 `params` 参数,需手动拼接 query string +- **ShopOrder Model**:新增 `paymentVoucher?: string` 字段 +- **页面改动**: + - OpType 从 `'pay'|'complete'|'editPrice'` 改为 `'confirmPay'|'complete'|'editPrice'` + - `getOrderActions` 新增条件:`!payStatus && payType===9 && orderStatus===0` → 显示"确认收款"按钮 + - 弹窗新增备注 Textarea(仅 confirmPay 显示),凭证图片限制1张(confirmPay),必填校验 + - `submitOperation` 新增 confirmPay 分支,调用 `confirmOfflinePayment` API + - 新增 `payRemarks` state + +### 3. 订单详情页金额明细0隐藏(src/pages/order/detail.tsx) +- **Bug**:React 经典陷阱 `{order.reducePrice && Number(order.reducePrice) > 0 && (...)}`,当 reducePrice 为数字 0 时,`0 && ...` 短路求值为 0,React 渲染文本"0" +- **修复**:改为 `{Number(order.reducePrice || 0) > 0 && (...)}`,始终返回 boolean + +### 验证 +- `npx taro build --type weapp` 构建成功 diff --git a/src/api/shop/shopOrder/index.ts b/src/api/shop/shopOrder/index.ts index f01a76d..fdfd34e 100644 --- a/src/api/shop/shopOrder/index.ts +++ b/src/api/shop/shopOrder/index.ts @@ -194,3 +194,23 @@ export async function refundShopOrder(data: ShopOrder) { } return Promise.reject(new Error(res.message)); } + +/** + * 确认线下付款收款 + * 商家确认已收到线下付款(微信转账/银行汇款等),确认后订单进入待发货状态 + */ +export async function confirmOfflinePayment( + id: number, + remarks?: string, + paymentVoucher?: string +) { + const params: string[] = [] + if (remarks) params.push(`remarks=${encodeURIComponent(remarks)}`) + if (paymentVoucher) params.push(`paymentVoucher=${encodeURIComponent(paymentVoucher)}`) + const url = '/shop/shop-order/confirm-offline-payment/' + id + (params.length ? '?' + params.join('&') : '') + const res = await request.put>(url, null) + if (res.code === 0) { + return res.message; + } + return Promise.reject(new Error(res.message)); +} diff --git a/src/api/shop/shopOrder/model/index.ts b/src/api/shop/shopOrder/model/index.ts index 549c358..811680c 100644 --- a/src/api/shop/shopOrder/model/index.ts +++ b/src/api/shop/shopOrder/model/index.ts @@ -183,6 +183,8 @@ export interface ShopOrder { buyerRemarks?: string; // 商户备注(门店修改金额原因等) merchantRemarks?: string; + // 线下付款支付凭证(图片URL) + paymentVoucher?: string; // 排序号 sortNumber?: number; // 是否删除, 0否, 1是 diff --git a/src/pages/order/detail.tsx b/src/pages/order/detail.tsx index 33b9f27..9c015c8 100644 --- a/src/pages/order/detail.tsx +++ b/src/pages/order/detail.tsx @@ -349,7 +349,7 @@ const OrderDetailPage: React.FC = () => { 商品总额 ¥{order.totalPrice || '0.00'} - {order.reducePrice && Number(order.reducePrice) > 0 && ( + {Number(order.reducePrice || 0) > 0 && ( 优惠 -¥{order.reducePrice} diff --git a/src/pages/store/orders/index.tsx b/src/pages/store/orders/index.tsx index 0b5a292..0ace14d 100644 --- a/src/pages/store/orders/index.tsx +++ b/src/pages/store/orders/index.tsx @@ -1,7 +1,7 @@ import React, {useState, useEffect, useCallback, useRef} from 'react' import {View, Text, Image, ScrollView, Input, Textarea} from '@tarojs/components' import Taro, {useDidShow} from '@tarojs/taro' -import {pageShopOrder, updateShopOrder, removeShopOrder} from '@/api/shop/shopOrder' +import {pageShopOrder, updateShopOrder, confirmOfflinePayment} from '@/api/shop/shopOrder' import type {ShopOrder, ShopOrderParam} from '@/api/shop/shopOrder/model' import {TenantId} from '@/config/app' import {useNewOrderDetector} from '@/hooks/useNewOrderDetector' @@ -26,16 +26,16 @@ const TABS: { key: TabKey; label: string; params: Partial[] }[] ] // ─── 操作类型 ───────────────────────────────────────────────────── -type OpType = 'pay' | 'complete' | 'editPrice' +type OpType = 'confirmPay' | 'complete' | 'editPrice' const OP_LABEL: Record = { - pay: '已收款', + confirmPay: '收款', complete: '已完成', editPrice: '金额', } const OP_DESC: Record = { - pay: '变更支付状态为已付款', + confirmPay: '确认已收到线下付款,订单将进入待发货状态', complete: '同时变更支付状态为已付款、收货状态为已收货、订单状态为已完成', editPrice: '修改订单实付金额', } @@ -125,8 +125,11 @@ function getOrderActions(order: ShopOrder): { label: string; type: OpType }[] { const actions: { label: string; type: OpType }[] = [] // 修改金额(门店权限) actions.push({label: '修改金额', type: 'editPrice'}) - // 货到付款:未付款 / 已付款 都直接"确认完成", - // 确认完成会同时设置 payStatus=true,无需单独的"确认收款"按钮 + // 线下付款·待确认收款:显示"确认收款"按钮 + if (!order.payStatus && order.payType === 9 && order.orderStatus === 0) { + actions.push({label: '确认收款', type: 'confirmPay'}) + } + // 确认完成 if (order.orderStatus !== 1 && order.orderStatus !== 2) { actions.push({label: '确认完成', type: 'complete'}) } @@ -148,6 +151,7 @@ export default function StoreOrdersPage() { const [currentOrder, setCurrentOrder] = useState(null) const [opType, setOpType] = useState('pay') const [proofImages, setProofImages] = useState([]) + const [payRemarks, setPayRemarks] = useState('') const [submitting, setSubmitting] = useState(false) // 修改金额弹窗状态 @@ -266,6 +270,7 @@ export default function StoreOrdersPage() { setCurrentOrder(order) setOpType(type) setProofImages([]) + setPayRemarks('') setShowModal(true) } @@ -274,6 +279,7 @@ export default function StoreOrdersPage() { setShowModal(false) setCurrentOrder(null) setProofImages([]) + setPayRemarks('') } /** 打开修改金额弹窗 */ @@ -329,7 +335,7 @@ export default function StoreOrdersPage() { /** 选择并上传凭证图片 */ const chooseProofImage = async () => { - const maxCount = 3 + const maxCount = opType === 'confirmPay' ? 1 : 3 const remaining = maxCount - proofImages.length if (remaining <= 0) return @@ -375,31 +381,37 @@ export default function StoreOrdersPage() { return } + // 确认收款必须上传支付凭证 + if (opType === 'confirmPay' && proofImages.length === 0) { + Taro.showToast({title: '请上传支付凭证', icon: 'none'}) + return + } + setSubmitting(true) try { - const updateData: any = {orderId: currentOrder.orderId} + if (opType === 'confirmPay') { + // 确认线下收款:调用专用接口 + await confirmOfflinePayment( + currentOrder.orderId!, + payRemarks.trim() || undefined, + proofImages[0] + ) + } else { + const updateData: any = {orderId: currentOrder.orderId} - if (opType === 'pay') { - // 确认收款:变更支付状态为已付款 - updateData.payStatus = true - updateData.payTime = formatDateTime(new Date()) - } else if (opType === 'complete') { - // 确认完成:用户已收到货 - updateData.payStatus = true - updateData.payTime = formatDateTime(new Date()) - updateData.deliveryStatus = 20 // 发货状态 → 已收货 - updateData.deliveryTime = formatDateTime(new Date()) // 收货时间 - updateData.orderStatus = 1 // 订单状态 → 已完成 - updateData.sendEndImg = JSON.stringify(proofImages) // 配送员送达拍照(JSON数组) + if (opType === 'complete') { + // 确认完成:用户已收到货 + updateData.payStatus = true + updateData.payTime = formatDateTime(new Date()) + updateData.deliveryStatus = 20 // 发货状态 → 已收货 + updateData.deliveryTime = formatDateTime(new Date()) // 收货时间 + updateData.orderStatus = 1 // 订单状态 → 已完成 + updateData.sendEndImg = JSON.stringify(proofImages) // 配送员送达拍照(JSON数组) + } + + await updateShopOrder(updateData) } - // 收款操作如有凭证也追加到备注 - if (opType === 'pay' && proofImages.length > 0) { - const proofText = `【门店收款凭证】:${JSON.stringify(proofImages)}` - updateData.comments = (currentOrder.comments || '') + `\n${proofText}` - } - - await updateShopOrder(updateData) Taro.showToast({title: '操作成功', icon: 'success'}) closeModal() loadOrders(activeTab, 1) // 刷新列表 @@ -410,23 +422,23 @@ export default function StoreOrdersPage() { } } - /** 删除订单 */ - const handleDelete = (order: ShopOrder) => { + /** 关闭订单 */ + const handleCloseOrder = (order: ShopOrder) => { Taro.showModal({ title: '提示', - content: `确定要删除订单 ${order.orderNo} 吗?删除后无法恢复。`, + content: `确定要关闭订单 ${order.orderNo} 吗?关闭后无法恢复。`, confirmColor: '#ee0a24', success: async (res) => { if (!res.confirm) return try { - Taro.showLoading({title: '删除中...'}) - await removeShopOrder(order.orderId) + Taro.showLoading({title: '关闭中...'}) + await updateShopOrder({orderId: order.orderId, orderStatus: 2} as ShopOrder) Taro.hideLoading() - Taro.showToast({title: '删除成功', icon: 'success'}) + Taro.showToast({title: '关闭成功', icon: 'success'}) loadOrders(activeTab, 1) } catch (e: any) { Taro.hideLoading() - Taro.showToast({title: e.message || '删除失败', icon: 'none'}) + Taro.showToast({title: e.message || '关闭失败', icon: 'none'}) } }, }) @@ -435,7 +447,7 @@ export default function StoreOrdersPage() { /** 渲染单个订单卡片 */ const renderOrderCard = (order: ShopOrder) => { const actions = getOrderActions(order) - const canDelete = isOrderActionable(order) // 仅未完成、未关闭的订单可删除 + const canDelete = isOrderActionable(order) // 仅未完成、未关闭的订单可关闭 const orderGoods = (order as any).orderGoods || [] return ( @@ -522,13 +534,13 @@ export default function StoreOrdersPage() { {/* 操作按钮 */} - {/* 删除按钮:仅未完成/未关闭的订单显示 */} + {/* 关闭按钮:仅未完成/未关闭的订单显示 */} {canDelete ? ( handleDelete(order)} + onClick={() => handleCloseOrder(order)} > - 删除订单 + 关闭订单 ) : ( @@ -541,6 +553,8 @@ export default function StoreOrdersPage() { className={`px-4 py-2 rounded-lg ${ act.type === 'complete' ? 'bg-green-500' + : act.type === 'confirmPay' + ? 'bg-blue-500' : act.type === 'editPrice' ? 'bg-orange-500' : 'border border-blue-500' @@ -548,7 +562,7 @@ export default function StoreOrdersPage() { onClick={() => act.type === 'editPrice' ? openEditPriceModal(order) : openModal(order, act.type)} > {act.label} ))} @@ -652,9 +666,13 @@ export default function StoreOrdersPage() { {/* 凭证上传 */} - 上传凭证照片{opType === 'complete' ? '(必填,配送货物到达后拍照上传,最多3张)' : '(选填,最多3张)'} + {opType === 'confirmPay' + ? '上传支付凭证(必填,如微信转账截图)' + : opType === 'complete' + ? '上传凭证照片(必填,配送货物到达后拍照上传,最多3张)' + : '上传凭证照片(选填,最多3张)'} - + {proofImages.map((url, idx) => ( @@ -666,7 +684,7 @@ export default function StoreOrdersPage() { ))} - {proofImages.length < 3 && ( + {proofImages.length < (opType === 'confirmPay' ? 1 : 3) && ( + {/* 备注(仅确认收款时显示) */} + {opType === 'confirmPay' && ( + + 备注(选填) +