feat(wle): 钉钉推送明细按仓聚集,并给每个仓保底 1 条 #79

Merged
yanhui merged 1 commits from codex/yanhui-wle-group-by-warehouse-20261022 into main 2026-10-22 14:04:50 +08:00
Collaborator

目的与范围

业务要求:钉钉群推送的异常明细「按照仓库来,相同仓库排序在一起」,方便各仓在群里只看自己那一段。

本次只改推送正文的组装,不动查询、不动页面列表:

  1. 明细按仓聚集(bucketRowsByWarehouse / groupRowsByWarehouse)
    • 组间:按该仓异常包裹数降序,与消息上方「按仓(异常包裹)」块顺序一致;数量相同按首次出现顺序
    • 组内:保持服务层原顺序(已按 pendingHours 降序,压得最久的排最前),不重新排序
    • 仓名缺失的行统一归到「未知仓」一组,不会被拆成散行
  2. 取前 N 条改为按仓配额(pickDetailRows)
    • 真数据验证时发现:140 条异常里山东青岗集仓占大头,直接 slice(0, 40) 会让 40 条明细全是同一个仓、其余 6 个仓一条都看不到
    • 规则:仓数 ≥ 额度 → 每仓 1 条(砍掉异常最少的仓);否则每仓先保底 1 条,剩余额度按各仓剩余条数比例分(最大余数法,总数正好等于额度)
  3. 明细仍是 4 段「仓|快递单号|快递|异常类型」,编号全局连续,不带发货时间 / 待处理时长

同步与兼容性

  • 无接口变更、无配置项变更、无库表变更,前端无需改动
  • 分支基于 e9923d7;期间 main 前进 2 个提交(#78 缺货补货监控),改动文件零重叠(那 2 个提交只动 binReplenish* 与 BinReplenishMonitor)

验证

单测 19/19 通过,新增 4 条:

  • 同仓相邻 + 组间按异常数降序 + 组内保持原序 + 编号全局连续
  • 仓名缺失归到「未知仓」一组
  • 大仓不能吃满额度、每仓至少 1 条
  • 额度少于仓数时每仓只取 1 条(含额度 0 / 超额度的边界)

本地真数据干跑(POST /notify/run {dryRun:true},140 条异常 / 列 40 条 / 4219 字节):

1~31. 简尚-山东青岗集仓
32~33. 简尚-崔桥工厂仓
34~35. 简尚-河南洛宁仓
36~37. 简尚-睢宁仓
38. 简尚-山东品牌仓
39. 简尚-新苏北仓
40. 简尚-崔桥工厂品牌仓
  • 连续段数 7 = 去重仓数 7 → 同仓完全相邻,无任何仓被拆散
  • 明细段数集合 [4] → 仍是 4 段,没有把时间/时长带回来
  • backend/scripts/check-syntax.js:194 文件通过

风险与回退

  • 风险:明细额度改为按仓分配后,异常最多的仓拿到的条数会比原来少(本次青岗集 31/40,原来独占 40/40)。这是「让每个仓都能看到自己的单」的代价,额度本身(默认 30、上限 50)仍由页面配置。
  • 回退:git revert 本提交即可,纯函数改动,无数据/状态影响。
## 目的与范围 业务要求:钉钉群推送的异常明细「**按照仓库来,相同仓库排序在一起**」,方便各仓在群里只看自己那一段。 本次只改推送正文的组装,不动查询、不动页面列表: 1. **明细按仓聚集**(`bucketRowsByWarehouse` / `groupRowsByWarehouse`) - 组间:按该仓异常包裹数降序,与消息上方「按仓(异常包裹)」块顺序一致;数量相同按首次出现顺序 - 组内:**保持服务层原顺序**(已按 `pendingHours` 降序,压得最久的排最前),不重新排序 - 仓名缺失的行统一归到「未知仓」一组,不会被拆成散行 2. **取前 N 条改为按仓配额**(`pickDetailRows`) - 真数据验证时发现:140 条异常里山东青岗集仓占大头,直接 `slice(0, 40)` 会让 **40 条明细全是同一个仓、其余 6 个仓一条都看不到** - 规则:仓数 ≥ 额度 → 每仓 1 条(砍掉异常最少的仓);否则每仓先保底 1 条,剩余额度按各仓剩余条数比例分(最大余数法,总数正好等于额度) 3. 明细仍是 **4 段**「仓|快递单号|快递|异常类型」,编号全局连续,不带发货时间 / 待处理时长 ## 同步与兼容性 - 无接口变更、无配置项变更、无库表变更,前端无需改动 - 分支基于 `e9923d7`;期间 main 前进 2 个提交(#78 缺货补货监控),改动文件**零重叠**(那 2 个提交只动 `binReplenish*` 与 `BinReplenishMonitor`) ## 验证 **单测 19/19 通过**,新增 4 条: - 同仓相邻 + 组间按异常数降序 + 组内保持原序 + 编号全局连续 - 仓名缺失归到「未知仓」一组 - 大仓不能吃满额度、每仓至少 1 条 - 额度少于仓数时每仓只取 1 条(含额度 0 / 超额度的边界) **本地真数据干跑**(`POST /notify/run {dryRun:true}`,140 条异常 / 列 40 条 / 4219 字节): ``` 1~31. 简尚-山东青岗集仓 32~33. 简尚-崔桥工厂仓 34~35. 简尚-河南洛宁仓 36~37. 简尚-睢宁仓 38. 简尚-山东品牌仓 39. 简尚-新苏北仓 40. 简尚-崔桥工厂品牌仓 ``` - 连续段数 7 = 去重仓数 7 → **同仓完全相邻,无任何仓被拆散** - 明细段数集合 `[4]` → 仍是 4 段,没有把时间/时长带回来 - `backend/scripts/check-syntax.js`:194 文件通过 ## 风险与回退 - 风险:明细额度改为按仓分配后,异常最多的仓拿到的条数会比原来少(本次青岗集 31/40,原来独占 40/40)。这是「让每个仓都能看到自己的单」的代价,额度本身(默认 30、上限 50)仍由页面配置。 - 回退:`git revert` 本提交即可,纯函数改动,无数据/状态影响。
yanhui added 1 commit 2026-10-22 14:03:50 +08:00
业务要求:推送明细「按照仓库来,相同仓库排序在一起」,方便各仓在群里只看自己那一段。

改动:
1. 明细按仓分桶后连续输出(groupRowsByWarehouse / bucketRowsByWarehouse)
   - 组间:按该仓异常包裹数降序,与上面「按仓(异常包裹)」块顺序一致;数量相同按首次出现顺序
   - 组内:保持服务层原顺序(已按 pendingHours 降序,压得最久的排最前),不重新排序
   - 仓名缺失的行统一归到「未知仓」一组,不会被拆成散行
2. 取前 N 条改为按仓配额(pickDetailRows)
   - 真数据验证时发现:140 条异常里山东青岗集仓占大头,直接 slice(0,40) 会让
     40 条明细全是同一个仓、其它 6 个仓一条都看不到
   - 规则:仓数 >= 额度时每仓 1 条(砍掉异常最少的仓);否则每仓先保底 1 条,
     剩余额度按各仓剩余条数比例分(最大余数法,总数正好等于额度)
3. 明细仍是 4 段「仓|快递单号|快递|异常类型」,编号全局连续,不带时间/时长

验证:
- 单测 19/19 通过(新增 4 条:同仓相邻+组内不乱序、未知仓归组、大仓不吃满额度、额度少于仓数)
- 本地真数据干跑(140 条异常 / 列 40 条 / 4219 字节):明细覆盖 7 个仓,
  同仓全部相邻、无任何仓被拆散;明细段数集合 [4]
  各仓条数:青岗集 31 / 崔桥 2 / 洛宁 2 / 睢宁 2 / 山东品牌 1 / 新苏北 1 / 崔桥品牌 1
- backend check-syntax:194 文件通过

风险与回退:只改推送正文的组装顺序与取数配额,不动查询、不动页面列表;
页面仍按时长降序展示全部明细。回退只需 revert 本提交。
yanhui merged commit 88913260a3 into main 2026-10-22 14:04:50 +08:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: lunanting/cangku#79
No description provided.