- deliveryModal.vue 中发货门店、发货人标签及提示文案,根据快递配送与商家送货动态显示 - 快递配送场景下新增寄件人信息同步至快递面单的小字说明和验证文案动态调整 - 修正小程序订单详情页 deliveryType 判断,新增 DELIVERY_TYPE_MAP 支持快递及商家送货标识 - 订单详情页收货信息卡片图标和配送门店名称根据实际配送方式动态显示 - 订单信息区新增配送方式字段,清晰展示快递配送、自提及商家送货三种状态
96 lines
12 KiB
Markdown
96 lines
12 KiB
Markdown
# 2026-07-17 工作日志
|
||
|
||
## 订单发货功能改进(shopOrder / deliveryModal)
|
||
|
||
分析了订单发货弹窗(`src/views/shop/shopOrder/components/deliveryModal.vue`)三种配送方式,按用户确认的改进方案实施了前端改动:
|
||
|
||
### 改动文件
|
||
1. `deliveryModal.vue`(核心)
|
||
- 新增「发货门店」下拉(复用 `listShopStore`),选中后自动回填:快递配送→发货人=门店名/电话=门店电话/地址=门店地址;商家送货→地址=门店地址。
|
||
- 商家送货(`deliveryType===2`)新增「配送店员」二级联动下拉(复用 `listShopStoreUser({storeId})`),选中店员自动回填发货人=店员名/联系方式=店员电话。
|
||
- 校验:发货门店必填(`deliveryType!==1`);配送店员必填(仅 `deliveryType===2`)。
|
||
- 提交时附带 `sendStoreId` / `deliveryUserId`。
|
||
2. `api/shop/shopOrder/model/index.ts`:新增 `sendStoreId`、`deliveryUserId` 字段(为后端落库铺路)。
|
||
3. `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` 并 SELECT `f.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` 默认会因 tsconfig `types:["@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 个既有报错(165 `fetchLatestOrders` 返回类型、169 `count` 隐式 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=0` bug 根因**:`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 文案同步动态化。
|
||
- 不涉及数据结构/接口变更,纯前端文案优化。
|
||
|
||
## 修复小程序订单详情页配送方式判断逻辑(guilixu-taro)
|
||
|
||
- 文件:`src/pages/order/detail.tsx`
|
||
- 问题:原代码 `isExpress = order.deliveryType === 0 || undefined`,无法区分 deliveryType=2(商家送货)
|
||
- 修复:
|
||
1. 新增 `DELIVERY_TYPE_MAP`:`0=快递配送, 1=自提, 2=商家送货`
|
||
2. 修正 `isExpress` 判断:`deliveryType === 0 || 2 || undefined` → 快递/商家送货都显示收货人信息
|
||
3. 收货信息卡片:商家送货显示🛵图标+配送门店名,快递配送显示📦图标
|
||
4. 订单信息区新增「配送方式」字段展示(使用 DELIVERY_TYPE_MAP)
|
||
- deliveryType 值范围来自管理后台 deliveryModal.vue:0=快递配送, 1=无需发货(自提), 2=商家送货
|