feat: 仓储物流转运异常页新增「导出异常明细」(Excel / CSV) #72

Merged
yanhui merged 1 commits from codex/yanhui-wle-export-20261022 into main 2026-10-22 10:00:22 +08:00
Collaborator

目的与范围

  • 解决的问题:业务要在「仓储中心物流转运异常」页把异常明细拿去做线下跟进 / 归档,
    目前只能看(表格分页),没法导出。本次加一个「导出」按钮(Excel .xlsx / CSV .csv),
    导出的是当前核验日 + 当前筛选下全部异常明细,不是当前屏。
  • 修改的模块/文件(6 个,全部属于本任务):
    • backend/src/api/warehouseLogisticsException.js — 新增 GET /api/warehouse-logistics-exception/export
    • backend/src/services/warehouseLogisticsExceptionService.js — 导出入口 + 缓存改按 核验日|明细上限 分键
    • backend/src/services/warehouseLogisticsExceptionRegistry.js — 仅补注释(说明「京喜京东」10-22 撤回全剔)
    • backend/test/warehouseLogisticsException.test.js — 新增 2 个用例
    • frontend/src/api/warehouseLogisticsException.js — 导出接口(超时 5 分钟)
    • frontend/src/pages/WarehouseLogisticsException/index.jsx — 导出下拉 + 明细过滤抽出共用
  • 是否使用 AI 及负责开发者:AI 辅助开发,开发者 yanhui。

口径未做任何改动:承运商剔除(顺丰系全剔 / 京喜京东 / 睢宁中通按仓条件 / 武进安能 / 中铁 /
壹米滴答 / 自提 / 线下 / 商家配送)、订单终止与刷单信誉单剔除、异常 5 类判定,
全部沿用已合并的 #71。导出只换「取多少条」和「输出成文件」,不换判定。

两个实现要点

  1. 缓存由单槽改成按 核验日|明细上限 分键的 Map(上限 8 条)。
    页面按默认条数取、导出按 5000 条取,单槽缓存会互相踢掉 —— 导出一次之后,
    页面下一次自动刷新就要重查库(20~40s,业务会当成「页面卡了」)。
  2. 导出列单独定义 EXPORT_COLUMNS(13 列纯文本标题),页面明细过滤抽成 filterDetailOrders 共用。
    页面列头用了 Tooltip,直接复用列定义会把表头导出成 [object Object];
    过滤共用同一个函数,才能保证「导出的就是页面看到的」。

同步与兼容性

  • 起始基线 SHA:9cba2f8(#71 的 merge commit)
  • 最近同步的 main SHA:9cba2f8(提交前 git fetch 复核,HEAD..origin/main = 0)
  • 待审核任务分支 SHA:85e2db9(分支 codex/yanhui-wle-export-20261022)
  • 并行 PR、共享接口、迁移/配置影响:无并行 PR;不改数据库、不加迁移、不加环境变量。
    新增接口为纯增量,/list 入参与返回结构一字未改(原有调用方零影响)。
  • 冲突及处理理由:无冲突(基线即 main 头)。
  • 如何确认保留了其他开发者的已有行为:本次 diff 只覆盖 6 个文件,
    git diff --cached --stat 无其他文件;Registry 改动只有注释(无代码行变化),
    三个文档(AGENTS.md / 仓库提交与合并规范.md / 服务器部署规范.md)未在工作区变更。

验证

  • npm --prefix backend run check → syntax 通过;450 tests / 448 pass / 2 fail
    • 失败 2 项均与本任务无关,且都不在本次改动文件里:
      1. secret backup survives outside the repository with owner-only permissions
        —— Windows 下权限位是 0o666 而非 0o600,长期既有失败(平台差异)。
      2. 负缓存带 TTL:TTL 内不重复解析,到期后必须重试 —— 该用例要求系统库
        「解析失败」才走负缓存分支,本机当前 SSH 隧道在线、配置能成功读回,
        于是首查没抛「业务数据库尚未配置」→ Missing expected rejection。
        环境相关(单跑该文件同样失败,改动该用例的文件未参与本次提交)。
  • node --test backend/test/warehouseLogisticsException.test.js → 26/26 通过
    (原 24 + 新增 2:①导出行数 == 异常包裹数、字段齐全、带剔除口径;②分键缓存互不踢掉)
  • npm --prefix frontend run check → lint 0 error / test 通过 / vite build 成功(48.7s)
  • 人工验证路径(开发环境 4002,非生产库):点「导出 → Excel」,收 144 行
    (页面当页只有 20 行 → 证明是导全量);选「未揽收(7)」再导出 → 7 行;
    选一个 0 条的类型 → 只提示、不生成空文件;导出的 .xlsx 用 JSZip 解开核对表头与行数。

风险与回退

  • 已知风险:
    1. 导出走的是「同一套查询 + 上限放宽到 5000」,比列表慢(冷启动 20~40s)。
      前端超时已放到 5 分钟、按钮带 loading 防重复点;异常包裹一天最多几百,
      5000 只是兜底,真超了会在提示里明说「已截断」,不会静默少行。
    2. 每次导出多占一个缓存键(上限 8,超了淘汰最旧),内存增量可忽略。
  • 回退方式:纯前端 + 一个新增只读接口,无数据变更。
    回退只需 revert 本 PR 这一个提交 85e2db9,/list 与既有页面行为立即复原;
    没有数据库、缓存持久化或配置需要清理(缓存是进程内 Map,重启即空)。
## 目的与范围 - 解决的问题:业务要在「仓储中心物流转运异常」页把异常明细拿去做线下跟进 / 归档, 目前只能看(表格分页),没法导出。本次加一个「导出」按钮(Excel .xlsx / CSV .csv), 导出的是**当前核验日 + 当前筛选下全部异常明细**,不是当前屏。 - 修改的模块/文件(6 个,全部属于本任务): - `backend/src/api/warehouseLogisticsException.js` — 新增 `GET /api/warehouse-logistics-exception/export` - `backend/src/services/warehouseLogisticsExceptionService.js` — 导出入口 + 缓存改按 `核验日|明细上限` 分键 - `backend/src/services/warehouseLogisticsExceptionRegistry.js` — 仅补注释(说明「京喜京东」10-22 撤回全剔) - `backend/test/warehouseLogisticsException.test.js` — 新增 2 个用例 - `frontend/src/api/warehouseLogisticsException.js` — 导出接口(超时 5 分钟) - `frontend/src/pages/WarehouseLogisticsException/index.jsx` — 导出下拉 + 明细过滤抽出共用 - 是否使用 AI 及负责开发者:AI 辅助开发,开发者 yanhui。 **口径未做任何改动**:承运商剔除(顺丰系全剔 / 京喜京东 / 睢宁中通按仓条件 / 武进安能 / 中铁 / 壹米滴答 / 自提 / 线下 / 商家配送)、订单终止与刷单信誉单剔除、异常 5 类判定, 全部沿用已合并的 #71。导出只换「取多少条」和「输出成文件」,不换判定。 ### 两个实现要点 1. **缓存由单槽改成按 `核验日|明细上限` 分键的 Map(上限 8 条)**。 页面按默认条数取、导出按 5000 条取,单槽缓存会互相踢掉 —— 导出一次之后, 页面下一次自动刷新就要重查库(20~40s,业务会当成「页面卡了」)。 2. **导出列单独定义 `EXPORT_COLUMNS`(13 列纯文本标题),页面明细过滤抽成 `filterDetailOrders` 共用**。 页面列头用了 Tooltip,直接复用列定义会把表头导出成 `[object Object]`; 过滤共用同一个函数,才能保证「导出的就是页面看到的」。 ## 同步与兼容性 - 起始基线 SHA:`9cba2f8`(#71 的 merge commit) - 最近同步的 main SHA:`9cba2f8`(提交前 `git fetch` 复核,`HEAD..origin/main` = 0) - 待审核任务分支 SHA:`85e2db9`(分支 `codex/yanhui-wle-export-20261022`) - 并行 PR、共享接口、迁移/配置影响:无并行 PR;不改数据库、不加迁移、不加环境变量。 新增接口为**纯增量**,`/list` 入参与返回结构一字未改(原有调用方零影响)。 - 冲突及处理理由:无冲突(基线即 main 头)。 - 如何确认保留了其他开发者的已有行为:本次 diff 只覆盖 6 个文件, `git diff --cached --stat` 无其他文件;Registry 改动**只有注释**(无代码行变化), 三个文档(`AGENTS.md` / `仓库提交与合并规范.md` / `服务器部署规范.md`)未在工作区变更。 ## 验证 - `npm --prefix backend run check` → syntax 通过;450 tests / **448 pass / 2 fail** - 失败 2 项均**与本任务无关**,且都不在本次改动文件里: 1. `secret backup survives outside the repository with owner-only permissions` —— Windows 下权限位是 `0o666` 而非 `0o600`,**长期既有失败**(平台差异)。 2. `负缓存带 TTL:TTL 内不重复解析,到期后必须重试` —— 该用例要求系统库 「解析失败」才走负缓存分支,本机当前 SSH 隧道在线、配置能成功读回, 于是首查没抛「业务数据库尚未配置」→ `Missing expected rejection`。 **环境相关**(单跑该文件同样失败,改动该用例的文件未参与本次提交)。 - `node --test backend/test/warehouseLogisticsException.test.js` → **26/26 通过** (原 24 + 新增 2:①导出行数 == 异常包裹数、字段齐全、带剔除口径;②分键缓存互不踢掉) - `npm --prefix frontend run check` → lint 0 error / test 通过 / vite build 成功(48.7s) - 人工验证路径(开发环境 4002,非生产库):点「导出 → Excel」,收 144 行 (页面当页只有 20 行 → 证明是导全量);选「未揽收(7)」再导出 → 7 行; 选一个 0 条的类型 → 只提示、不生成空文件;导出的 .xlsx 用 JSZip 解开核对表头与行数。 ## 风险与回退 - 已知风险: 1. 导出走的是「同一套查询 + 上限放宽到 5000」,比列表慢(冷启动 20~40s)。 前端超时已放到 5 分钟、按钮带 loading 防重复点;异常包裹一天最多几百, 5000 只是兜底,真超了会在提示里明说「已截断」,不会静默少行。 2. 每次导出多占一个缓存键(上限 8,超了淘汰最旧),内存增量可忽略。 - 回退方式:纯前端 + 一个新增只读接口,无数据变更。 回退只需 revert 本 PR 这一个提交 `85e2db9`,`/list` 与既有页面行为立即复原; 没有数据库、缓存持久化或配置需要清理(缓存是进程内 Map,重启即空)。
yanhui added 1 commit 2026-10-22 09:59:32 +08:00
- 后端新增 GET /api/warehouse-logistics-exception/export:复用列表同一套口径
  (getLogisticsExceptions),只把明细上限从列表 2000 放宽到 5000,不分页,
  判定/剔除逻辑一行未改,避免「导出与页面两套口径」。
- 结果缓存由单槽改为按 `核验日|明细上限` 分键的 Map(上限 8 条):
  页面按默认条数取、导出按 5000 取,单槽会互相踢掉 —— 导出一次,页面下次
  自动刷新就得重查库(20~40s)。分键后两者互不影响。
- 前端把明细过滤抽成 filterDetailOrders,表格与导出共用同一个函数,
  保证「导出的就是页面看到的」。
- 导出列单独定义 EXPORT_COLUMNS(13 列纯文本标题):页面列用了 Tooltip,
  直接复用列定义会把表头导出成 [object Object];运单号/物流状态/最后轨迹
  为空时导出为「无运单号 / 无状态 / 无轨迹」,Excel 里不留空格。
- 导出跟随当前核验日 + 选中仓 + 选中异常类型;文件名带核验日与筛选范围
  (仓储物流转运异常_<核验日>_<仓>_<类型>);0 行时提示且不生成空文件;
  超过 5000 行时如实提示「已截断」。导出按钮做 loading,防重复点。
- 测试:新增 2 个用例 —— ①导出行数等于异常包裹数、字段齐全、带剔除口径;
  ②缓存按 limit 分键(页面 1000 条那份不被导出 5000 条顶掉)。
  warehouseLogisticsException.test.js 26/26 通过。

口径未变:承运商剔除(顺丰系全剔、京喜京东、睢宁中通按仓、武进安能/中铁/
壹米滴答/自提/线下/商家配送)、订单终止与刷单信誉单剔除、异常 5 类判定,
全部沿用 #71 已合并版本。
Author
Collaborator

合并授权记录(规范第 6 节 · 路径二)

  • 授权人:yanhui(仓库所有者,同时是本次提交的开发者)
  • 授权时间:2026-10-22 09:50 (GMT+8)
  • 授权原话:「按之前流程走 PR + 部署」(回应 AI 的「要我按之前流程走 PR + 部署吗?」)
  • 授权范围:仅本 PR #72(6 文件,+238 / -20,仓储物流转运异常页导出功能)及其生产部署;不含其他 PR、不含强推 main。
  • 授权对应的最终提交 SHA:85e2db9f923678ef7605d05809decac33da633e8
  • 基线 main SHA:9cba2f814012b45ecc207bd4e1d9f1f68eb4dedc

说明:本 PR 为 AI 辅助开发、开发者即 yanhui 本人,当前 reviews = 0,无第三方审核者可用;
按规范 6.1「仓库所有者/管理员对明确的 PR 作出书面合并指令时,该授权可以代替独立审核」,
据此执行合并。AI 未自审自合。

合并前检查(2026-10-22 10:05 GMT+8)

检查 结果
git rev-list --count HEAD..origin/main 0(基线未前进)
冲突标记扫描 backend/src + frontend/src 无
PR mergeable / state true / open
head_sha == 本地 HEAD 85e2db9 ✅
base_sha == 当前 origin/main 9cba2f8 ✅
warehouseLogisticsException.test.js 26 / 26 pass
npm --prefix backend run check 450 tests / 448 pass / 2 fail(均为既有或环境相关)
npm --prefix frontend run check lint 0 error / test pass / build 成功

两项后端失败与本 PR 无关:resilientSecretStore 是 Windows 权限位(0o666 vs 0o600)长期既有失败;
cloudDatabaseConfigCache 的负缓存用例要求系统库解析失败态,本机 SSH 隧道在线故首查不抛「业务数据库尚未配置」,
单跑该文件同样失败,且该用例文件未参与本次提交。

## 合并授权记录(规范第 6 节 · 路径二) - **授权人**:yanhui(仓库所有者,同时是本次提交的开发者) - **授权时间**:2026-10-22 09:50 (GMT+8) - **授权原话**:「按之前流程走 PR + 部署」(回应 AI 的「要我按之前流程走 PR + 部署吗?」) - **授权范围**:仅本 PR #72(6 文件,+238 / -20,仓储物流转运异常页导出功能)及其生产部署;不含其他 PR、不含强推 main。 - **授权对应的最终提交 SHA**:`85e2db9f923678ef7605d05809decac33da633e8` - **基线 main SHA**:`9cba2f814012b45ecc207bd4e1d9f1f68eb4dedc` 说明:本 PR 为 AI 辅助开发、开发者即 yanhui 本人,当前 `reviews = 0`,无第三方审核者可用; 按规范 6.1「仓库所有者/管理员对明确的 PR 作出书面合并指令时,该授权可以代替独立审核」, 据此执行合并。AI 未自审自合。 ### 合并前检查(2026-10-22 10:05 GMT+8) | 检查 | 结果 | | --- | --- | | `git rev-list --count HEAD..origin/main` | `0`(基线未前进) | | 冲突标记扫描 `backend/src` + `frontend/src` | 无 | | PR `mergeable` / `state` | `true` / `open` | | `head_sha` == 本地 HEAD | `85e2db9` ✅ | | `base_sha` == 当前 `origin/main` | `9cba2f8` ✅ | | `warehouseLogisticsException.test.js` | 26 / 26 pass | | `npm --prefix backend run check` | 450 tests / 448 pass / 2 fail(均为既有或环境相关) | | `npm --prefix frontend run check` | lint 0 error / test pass / build 成功 | 两项后端失败与本 PR 无关:`resilientSecretStore` 是 Windows 权限位(0o666 vs 0o600)长期既有失败; `cloudDatabaseConfigCache` 的负缓存用例要求系统库解析失败态,本机 SSH 隧道在线故首查不抛「业务数据库尚未配置」, 单跑该文件同样失败,且该用例文件未参与本次提交。
yanhui merged commit b30c4e949c into main 2026-10-22 10:00:22 +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#72
No description provided.