- 后端移除确认收款时订单状态限制,已发货订单确认收款后自动完成订单 - 管理后台订单列表和操作按钮区分线下付款未付款不同发货状态 - 离线付款弹窗新增发货状态字段及提示文案动态展示 - 订单详情支付状态标签区分已发货待收款状态,更新步骤条显示逻辑 - 小程序端订单状态文本和操作按钮支持线下付款先发货后结款场景
14 KiB
14 KiB
2026-07-17 工作日志
订单发货功能改进(shopOrder / deliveryModal)
分析了订单发货弹窗(src/views/shop/shopOrder/components/deliveryModal.vue)三种配送方式,按用户确认的改进方案实施了前端改动:
改动文件
deliveryModal.vue(核心)- 新增「发货门店」下拉(复用
listShopStore),选中后自动回填:快递配送→发货人=门店名/电话=门店电话/地址=门店地址;商家送货→地址=门店地址。 - 商家送货(
deliveryType===2)新增「配送店员」二级联动下拉(复用listShopStoreUser({storeId})),选中店员自动回填发货人=店员名/联系方式=店员电话。 - 校验:发货门店必填(
deliveryType!==1);配送店员必填(仅deliveryType===2)。 - 提交时附带
sendStoreId/deliveryUserId。
- 新增「发货门店」下拉(复用
api/shop/shopOrder/model/index.ts:新增sendStoreId、deliveryUserId字段(为后端落库铺路)。orderInfo.vue:发货信息卡片增加「发货门店」「配送店员」展示(可选链,后端返回storeName/deliveryUserName后自动生效,否则显示「未填写」)。
关键结论 / 待后端配合
- 门店、店员 list API 已存在,前端改动零后端依赖即可落地交互。
- 后端缺口(需补充):
shop_order表需新增send_store_id、delivery_user_id字段存储门店/店员关联;否则下拉选了也存不进去。 - 登录用户
User模型无storeId,无法默认锁定当前门店,门店下拉需用户手动选择。 - 原「发货地址模板」需求因无现成后端接口,改用「门店作为发货地址模板」方案满足(复用门店 name/phone/address)。
配送方式排序调整
- 修改
deliveryModal.vue配送方式 radio 按钮顺序:快递配送→商家送货→无需发货(原:快递配送→无需发货→商家送货),仅调换模板中 radio 排列顺序,value 值不变。
后端 Java 改动(guilixu-java,分两轮)
第一轮:shop_order 主表
ShopOrder.java实体加持久化字段sendStoreId、deliveryUserId(→send_store_id/delivery_user_id),及虚拟展示字段sendStoreName/deliveryUserName(exist=false)。ShopOrderMapper.xml的selectSql加LEFT JOIN shop_store f/LEFT JOIN shop_store_user g并 SELECTf.name as sendStoreName, g.name as deliveryUserName,让订单详情联带回门店/店员名称。- 前端
orderInfo.vue展示路径从form.shopOrderDelivery.xxx改为form.sendStoreName/form.deliveryUserName(名称落在订单主对象上)。 - SQL:
ALTER TABLE shop_order ADD send_store_id INT, delivery_user_id INT;
第二轮:shop_order_delivery 发货单表(用户要求"也写进发货记录表")
ShopOrderDelivery.java实体加持久化字段sendStoreId、deliveryUserId。ShopOrderController.update()的发货写入分支(无需物流分支 deliveryMethod=20、实物快递分支 deliveryMethod=30、以及补录运单号分支)新建ShopOrderDelivery时都setSendStoreId/setDeliveryUserId(值取自shopOrder对象,兜底取shopOrderNow)。- 说明:前端发货只调
PUT /shop/shop-order,该接口内部new ShopOrderDelivery()并 save 落shop_order_delivery;主表靠updateById(shopOrder)自动落库,发货单表需显式 set 字段。 - SQL:
ALTER TABLE shop_order_delivery ADD send_store_id INT, delivery_user_id INT; - 验证:
vue-tsc前端零报错;Java 用./mvnw -o compile后台验证中。
Taro 商家端 storeId=0 排查(guilixu-taro,跨项目)
- 用户反馈 orders 页请求
/shop/shop-store-user?storeId=0。排查结论:guilixu-taro/src/pages/store/orders/index.tsx未调用shop-store-user;全项目listShopStoreUser仅定义、无调用方。该请求非当前源码发出,应为线上旧版 H5 构建。- 当前门店 storeId 的真实来源:
getMyClerk()(GET /shop/shop-store-user/my)返回的ShopStoreUser对象,其.storeId字段(shop_dealer.id)才是门店 id。注意user.tsx:103用storeInfo(=getMyClerk 结果)判断"是否显示门店中心",所以那里就能拿到storeId = storeInfo.storeId。 - 易错点:
ShopStoreUser有id(店员自身主键)和storeId(门店 id)两个字段,二者不同。误用storeInfo.id当门店 id 是 bug。booking/index.tsx:186的storeId: storeInfo!.id || 0中storeInfo恰为ShopStore类型故.id碰巧正确,但|| 0兜底在未加载时仍会变 0。 - 根因模式:项目无全局门店/店员上下文,
storeInfo是各页面局部 useState(user/booking/center 各一份)。需在 storeId 就绪前发请求 +|| 0兜底 →storeId=0。 - 已实施全局
useClerk(用户确认后开工):- 新增
src/contexts/ClerkContext.tsx:ClerkProvider+useClerkContext。登录态(useUserContext().isLoggedIn)变化即拉取/清空getMyClerk();对外暴露clerk(ShopStoreUser|null)、storeId(=clerk?.storeId)、loading、refreshClerk、clearClerk。 - 新增
src/hooks/useClerk.ts:镜像useUser的"优先 Context、未包裹则降级本地"范式,文件头注释写明用法与storeId>0守卫约定。 src/app.tsx:在UserProvider内挂载<ClerkProvider>(使其能响应登录/登出)。- 重构
src/pages/user/user.tsx与src/pages/store/center/index.tsx:移除各自的局部storeInfo/getMyClerk调用,改为const { clerk: storeInfo, refreshClerk } = useClerk()。 - 补全
src/api/shop/shopStoreUser/model/index.ts的ShopStoreUser模型:getMyClerk(/my) 联表返回的name/phone/avatar/storeName补入(原模型缺失,旧代码靠useState<any>掩盖)。
- 新增
- 验证:裸
tsc --noEmit --types webpack-env全量检查——新建/改动的ClerkContext.tsx/useClerk.ts/app.tsx/user.tsx/center/index.tsx及模型 零新增报错;center页仅剩 4 个既有报错(75 的finally、82 的applyStatus、89 的total、106 的Option,均在未改动的loadBadgeCounts/subscribe原函数里,属项目原有类型问题 / 裸 tsc 的 lib 配置 artifact)。注意裸tsc默认会因 tsconfigtypes:["@tarojs/taro"]+typeRoots报TS2688,需用--types webpack-env覆盖才能跑真实业务检查。 - 未动:
booking/index.tsx的storeInfo是用户所选门店(ShopStore,来自getShopStore(id)/选择),与店员所属门店是两回事,不在本次范围(其storeId: storeInfo!.id || 0属不同接口的兜底问题)。orders 页现可随时从useClerk().storeId取当前门店 id。
Taro 商家端 orders 页「选择发货人员」发货功能(guilixu-taro)
- 用户截图显示线上旧版 orders 页有「选择发货人员」弹窗且请求
?storeId=0显示"暂无可选择的店员"。当前源码orders/index.tsx原本没有该功能(只有确认收款/确认完成),确认是旧构建。 - 在
src/pages/store/orders/index.tsx新增「确认发货」功能:- 引入
useClerk()取storeId(杜绝 storeId=0)、listShopStoreUser、ShopStoreUser类型。 OpType增加'deliver';getOrderActions中「待发货」订单(payStatus && deliveryStatus===10)显示"确认发货"按钮。openModal('deliver')时调loadClerkList():storeId>0才listShopStoreUser({storeId}),否则 toast 提示门店未就绪、不发请求。- 弹窗内新增店员单选列表(selectedClerk),deliver 模式隐藏凭证上传区。
- 提交发货:
deliveryType=2(商家送货)、deliveryStatus=20(待收货)、deliveryTime、sendName/sendPhone(店员)、sendStoreId=storeId、deliveryUserId=店员id→PUT /shop/shop-order。 - 后端已在上一轮把
sendStoreId/deliveryUserId落shop_order+shop_order_delivery,此处字段对齐。
- 引入
- 验证:
tsc --noEmit --types webpack-env总报错仍 387(零新增);orders 页仅剩 2 个既有报错(165fetchLatestOrders返回类型、169count隐式 any,均在未改的useNewOrderDetector调用块)。
⚠️ 重大纠正:正确项目是 xinlong-shop-taro,不是 guilixu-taro
- 用户最终明确:商家端发货/门店相关功能在
/Users/gxwebsoft/VUE/xinlong-shop-taro,前面整段记的guilixu-taro改动全改错项目了。 - 已在 guilixu-taro 还原(git 仓库):
git checkout --还原 5 个跟踪文件(model/index.ts、app.tsx、center/index.tsx、orders/index.tsx、user.tsx);rm删除 2 个新建文件(contexts/ClerkContext.tsx、hooks/useClerk.ts)。未动的pages/index/index.scss是仓库原有未提交改动,保留。 - xinlong-shop-taro 才是真项目,且早已内置发货功能:
orders/index.tsx已有OpType='ship'的「发货」+saveShopOrderDelivery+listShopStoreUser+ 发货弹窗;user.tsx已有getMyClerk()取storeInfo(含.storeId)用于"门店中心"判断。 - 真正的
storeId=0bug 根因:xinlong-shop-taro/src/pages/store/orders/index.tsx:465的openShipModal调listShopStoreUser()没传 storeId(默认 0),即用户最初报的?storeId=0。 - 已修(xinlong-shop-taro):
openShipModal内先getMyClerk()取storeId,listShopStoreUser({storeId})拉本门店店员;并默认选中userId === 当前登录人 userId的店员(setSelectedClerkId(match.id))。tsc --noEmit --types webpack-env该文件零新增报错(仅 162/208/212 三个项目既有错误,均在我未改动区域)。 - 教训:跨项目时先用 glob/find 在多个候选项目里确认"哪个项目有该功能源码",再动手;不要凭域名/习惯默认锁定一个项目。本次因
guilixu-taro与xinlong-shop-taro命名相近、且前者恰有getMyClerk等同名 API 而误判。
发货弹窗文案优化(deliveryModal.vue)
- 用户反馈"快递配送时发货人/联系人选门店是否不合理",分析结论:业务逻辑正确(发货人=寄件方=门店),问题在文案未区分"寄件方"与"承运方"。
- 改动
src/views/shop/shopOrder/components/deliveryModal.vue:- 「发货门店」标签动态化:快递配送→「发货门店」,商家送货→「配送门店」(placeholder 同步动态)。
- 「发货人」标签动态化:快递配送→「寄件人」,商家送货→「发货人」(联系方式标签同理)。
- 提示文案动态化:快递配送说明"寄件人即为发货门店",商家送货说明"回填配送店员信息"。
- 快递配送时在寄件人字段下方加小字说明"寄件人信息将同步至快递面单"。
- 验证规则的 reject 文案同步动态化。
- 不涉及数据结构/接口变更,纯前端文案优化。
修复小程序订单详情页配送方式判断逻辑(xinlong-shop-taro)⚠️ 注意正确项目
- 正确项目:
/Users/gxwebsoft/VUE/xinlong-shop-taro(非 guilixu-taro) - 文件:
src/pages/order/detail.tsx - 问题:原代码
isExpress = order.deliveryType === 0 || undefined,无法区分 deliveryType=2(商家送货) - 修复:
- 新增
DELIVERY_TYPE_MAP:0=快递配送, 1=自提, 2=商家送货 - 修正
isExpress判断:deliveryType === 0 || 2 || undefined→ 快递/商家送货都显示收货人信息 - 收货信息卡片:商家送货显示🛵图标+配送门店名,快递配送显示📦图标
- 订单信息区新增「配送方式」字段展示(使用 DELIVERY_TYPE_MAP)
- 新增
- deliveryType 值范围来自管理后台 deliveryModal.vue:0=快递配送, 1=无需发货(自提), 2=商家送货
- ⚠️ 初次改错了项目(guilixu-taro),已用 git checkout 还原,正确改动在 xinlong-shop-taro
方案A:线下付款先发货后结款(三端同步改动)
后端(guilixu-java)
ShopOrderServiceImpl.confirmOfflinePayment():移除.eq(ShopOrder::getOrderStatus, 0)约束,允许已发货订单确认收款。新增逻辑:若deliveryStatus=20(已发货),确认收款后自动setOrderStatus=1完成订单。ShopOrderController.confirmOfflinePayment():更新@Operation描述和成功消息(不再固定写"进入待发货状态")。ShopOrderService.java:更新 Javadoc 描述。- 注意:Controller 的
PUT /shop/shop-order(update)接口发货时不校验 payStatus,仅判断deliveryStatus 10→20,所以未付款的线下订单可以直接通过 update 接口发货(前端改 deliveryStatus 即可)。
管理后台(guilixu-admin)
src/views/shop/shopOrder/index.vue:线下付款未付款订单(payType=9, payStatus=0, orderStatus=0)分两种情况:deliveryStatus=10:同时显示「确认收款」+「发货」+「关闭」deliveryStatus=20:仅显示「确认收款」(先发货后结款,已发货状态)
src/views/shop/shopOrder/components/OfflinePaymentModal.vue:- 新增
deliveryStatus表单字段 +alertMessage计算属性:已发货时提示"确认后订单将自动完成",未发货时提示"进入待发货状态"。 - 成功消息动态化:
deliveryStatus===20 ? '已自动完成' : '已进入待发货状态'
- 新增
src/views/shop/shopOrder/components/orderInfo.vue:- 支付状态标签:
payType=9 && payStatus=0 && deliveryStatus=20→ 蓝色「已发货待收款」 loadSteps()步骤条:线下付款未付款但已发货时,步骤条显示「下单→待收款→已发货」而非停留在「下单」
- 支付状态标签:
小程序端(xinlong-shop-taro)
src/pages/store/orders/index.tsx:getStatusText():新增「已发货待收款」状态(payType===9 && !payStatus && deliveryStatus===20)getOrderActions():发货按钮条件放宽——线下付款未付款(payType===9)也能显示发货按钮(支持先发货后结款)OP_DESC:确认收款描述移除"订单将进入待发货状态"(已不是唯一路径)