feat: 新增大货库存监控(26 仓) #27

Merged
youruo merged 1 commits from codex/large-stock-monitor-0923 into main 2026-09-23 14:01:45 +08:00
Collaborator

目的与范围

  • 解决的问题:按《库存监控》表格在侧边栏补齐一级组「大货库存监控」与 26 个仓库二级菜单,提供共用页面(/planning/large-stock-monitor/:warehouseSlug),表头与口径取自业务库实际字段。
  • 修改的模块/文件(相对 main 共 13 个文件、+1699 行、0 删除):
    • 新增:backend/src/api/largeStockMonitor.js、backend/src/config/largeStockMonitorConfig.js、backend/src/services/largeStockMonitorFlow.js、backend/scripts/verify-large-stock-monitor.js、frontend/src/api/largeStockMonitor.js、frontend/src/constants/largeStockMonitor.js、frontend/src/pages/LargeStockMonitor/{index.jsx,style.css}
    • 修改:backend/src/index.js(+2)、frontend/src/config/sidebarNavigation.js(+15)、frontend/src/layouts/BasicLayout.jsx(+10)、frontend/src/constants/sidebarPages.js(+1)、frontend/src/router/index.jsx(+5)
  • 是否使用 AI 及负责开发者:使用 AI(WorkBuddy)辅助实现与验证,负责开发者 lunanting。

同步与兼容性

  • 起始基线 SHA:490c68f7d729073c9bb8a490ee09b10c3981fe4a
  • 最近同步的 main SHA:254d1dd9f92f534567817f1aa55129051a291893
  • 待审核任务分支 SHA:2bc949099ba7fc6dba0db1dfa0b2bc47f6721f48
  • 并行 PR、共享接口、迁移/配置影响:仅新增独立路由 /api/large-stock-monitor 与前端路由/菜单条目;无数据表迁移、无依赖变更、无配置变更。对既有文件只追加条目,未改动已有行。
  • 冲突及处理理由(共 4 处):
    1. backend/src/index.js:双方在相邻位置新增路由 require 与挂载,取并集,双方路由均保留。
    2. frontend/src/router/index.jsx:双方在相邻位置新增 lazy 组件,取并集。
    3. frontend/src/config/sidebarNavigation.js:主仓库新增「模块化库存监控」组、本分支新增「大货库存监控」组,两个组并列保留。
    4. scripts/start-remote.mjs:双方都加了 shell: process.platform === 'win32'(Windows spawn EINVAL 修复),仅注释措辞不同,采用主仓库表述;该文件最终与 main 一致、未进 diff。
  • 另需注意的一处跨分支差异:本分支基线 490c68f 仍保留 backend/src/api/dashboard.js 及其 require/挂载,而 main 已将其删除。已按 main 的现状移除 dashboardRoutes 的 require 与挂载,否则后端启动会在 require('./api/dashboard') 处崩溃。
  • 如何确认保留了其他开发者的已有行为:最终 diff 相对 main 为纯新增(0 删除行);主仓库新增的 productAnalysis / marketingEvents / promotionModule / productMonitoring / modularStockMonitor / mkhBom 等路由与菜单全部保留;npm run check 结果与 origin/main 基线一致。

验证

实际执行的命令与结果(均对应最终提交 2bc9490):

  • npm --prefix backend run check:346 用例,345 通过,1 失败 —— resilientSecretStore.test.js 的 “secret backup survives outside the repository with owner-only permissions”(期望 0600、实际 0666)。在 worktree 检出干净的 origin/main(254d1dd) 运行同一文件同样失败,确认为本机 Windows 权限语义导致的基线既有失败,与本次变更无关。
  • npm --prefix frontend run check(lint + test + build):全部通过。18 项测试通过;构建成功,产物含独立的 LargeStockMonitor-DKudgC8f.js 分块,无 Circular chunk;verify-planning-entry 校验通过。
  • 修复记录:sidebarNavigation.js / BasicLayout.jsx 最初导入常量未带 .js 扩展名,Vite 可解析但 node --test 的 ESM 加载失败(retiredNavigation.test.mjs 报 ERR_MODULE_NOT_FOUND),已补全扩展名。
  • node backend/scripts/verify-large-stock-monitor.js:遍历 26 仓,26/26 全部有数据、0 异常,截止时刻统一 2026-09-23 01:00。
  • 负载实测(overview 单次请求端到端耗时):崔桥工厂半成品包装项目仓主仓 1475ms / 运���C崔桥工厂仓专用仓主仓 1065ms / 崔桥工厂仓主仓 1253ms / 崔桥工厂京东仓主仓 1272ms / 崔桥工厂品牌仓主仓 1641ms / 河南洛宁仓主仓 1212ms,均返回 200。
  • 未运行或受阻的检查及原因:第三方 MSSQL 只读副本 JSReportReplica 对 sys.tables 返回空、sys.dm_db_partition_stats 提示 The user does not have permission to perform this action,因此无法取得大表行数与 EXPLAIN 执行计划。仅取得快照表 rpt.pm_stockMonitor 精确行数 59,630。流水查询均带 仓库 + 日期区间 过滤(本月 1 日 ~ 截止时刻 01:00),但缺少索引命中率与扫描行数证据。全程只用只读 SELECT,未执行任何 DDL 或写入。此项为已知证据缺口,请评审判断是否需补充或暂缓部署。
  • 人工验证路径:本地登录后端预览账号,逐仓打开「大货库存监控 → 26 个二级菜单」,核对期末数量与仓库助手提供的 22 号期末数据。

风险与回退

  • 已知风险:
    1. 期末口径变更:期末数量改用聚水潭实时库存 jst_inventoryInfo(按 wms_co_id 单仓),不再用 pm_stockMonitor.jsStock。后者 warehouse 是「归属仓」口径,会把已调拨到外仓的货仍计在本仓名下(崔桥工厂仓因此虚高约 2.2 万)。仓库助手核对的 9 仓中,山东品牌仓、崔桥工厂品牌仓为 0 差异,其余差异可由 23 日上午仓间调拨/出入库解释;但因业务库无历史结存表,报表本身无法回看「某日期末」。
    2. 期初为倒推值:期初 = 期末 − 采购进仓 + 采购退货 + 销售出仓 − 销售退货(页面标「估」)。业务库无调拨单与其它出库单据表,这部分出库追踪不到,倒推值偏大。
    3. 6 列无数据源:加工进仓、加工出仓、盘点、调拨出、调拨入、其它出库在业务库无对应单据表,显示「—」。
    4. 缺少执行计划证据:见「验证」节最后一栏。
  • 回退方式和数据兼容性:本 PR 为纯新增,无迁移、无数据结构变更、无依赖变更;git revert 2bc9490 即可完整回退,不影响其他已上线功能。
## 目的与范围 - 解决的问题:按《库存监控》表格在侧边栏补齐一级组「大货库存监控」与 26 个仓库二级菜单,提供共用页面(`/planning/large-stock-monitor/:warehouseSlug`),表头与口径取自业务库实际字段。 - 修改的模块/文件(相对 main 共 13 个文件、+1699 行、0 删除): - 新增:`backend/src/api/largeStockMonitor.js`、`backend/src/config/largeStockMonitorConfig.js`、`backend/src/services/largeStockMonitorFlow.js`、`backend/scripts/verify-large-stock-monitor.js`、`frontend/src/api/largeStockMonitor.js`、`frontend/src/constants/largeStockMonitor.js`、`frontend/src/pages/LargeStockMonitor/{index.jsx,style.css}` - 修改:`backend/src/index.js`(+2)、`frontend/src/config/sidebarNavigation.js`(+15)、`frontend/src/layouts/BasicLayout.jsx`(+10)、`frontend/src/constants/sidebarPages.js`(+1)、`frontend/src/router/index.jsx`(+5) - 是否使用 AI 及负责开发者:使用 AI(WorkBuddy)辅助实现与验证,负责开发者 lunanting。 ## 同步与兼容性 - 起始基线 SHA:`490c68f7d729073c9bb8a490ee09b10c3981fe4a` - 最近同步的 main SHA:`254d1dd9f92f534567817f1aa55129051a291893` - 待审核任务分支 SHA:`2bc949099ba7fc6dba0db1dfa0b2bc47f6721f48` - 并行 PR、共享接口、迁移/配置影响:仅新增独立路由 `/api/large-stock-monitor` 与前端路由/菜单条目;无数据表迁移、无依赖变更、无配置变更。对既有文件只追加条目,未改动已有行。 - 冲突及处理理由(共 4 处): 1. `backend/src/index.js`:双方在相邻位置新增路由 require 与挂载,取并集,双方路由均保留。 2. `frontend/src/router/index.jsx`:双方在相邻位置新增 lazy 组件,取并集。 3. `frontend/src/config/sidebarNavigation.js`:主仓库新增「模块化库存监控」组、本分支新增「大货库存监控」组,两个组并列保留。 4. `scripts/start-remote.mjs`:双方都加了 `shell: process.platform === 'win32'`(Windows spawn EINVAL 修复),仅注释措辞不同,采用主仓库表述;该文件最终与 main 一致、未进 diff。 - 另需注意的一处跨分支差异:本分支基线 `490c68f` 仍保留 `backend/src/api/dashboard.js` 及其 require/挂载,而 main 已将其删除。已按 main 的现状移除 `dashboardRoutes` 的 require 与挂载,否则后端启动会在 `require('./api/dashboard')` 处崩溃。 - 如何确认保留了其他开发者的已有行为:最终 diff 相对 main 为纯新增(0 删除行);主仓库新增的 productAnalysis / marketingEvents / promotionModule / productMonitoring / modularStockMonitor / mkhBom 等路由与菜单全部保留;`npm run check` 结果与 origin/main 基线一致。 ## 验证 实际执行的命令与结果(均对应最终提交 `2bc9490`): - `npm --prefix backend run check`:346 用例,345 通过,1 失败 —— `resilientSecretStore.test.js` 的 “secret backup survives outside the repository with owner-only permissions”(期望 0600、实际 0666)。在 worktree 检出干净的 `origin/main`(254d1dd) 运行同一文件同样失败,确认为本机 Windows 权限语义导致的**基线既有失败**,与本次变更无关。 - `npm --prefix frontend run check`(lint + test + build):全部通过。18 项测试通过;构建成功,产物含独立的 `LargeStockMonitor-DKudgC8f.js` 分块,无 Circular chunk;`verify-planning-entry` 校验通过。 - 修复记录:`sidebarNavigation.js` / `BasicLayout.jsx` 最初导入常量未带 `.js` 扩展名,Vite 可解析但 `node --test` 的 ESM 加载失败(`retiredNavigation.test.mjs` 报 ERR_MODULE_NOT_FOUND),已补全扩展名。 - `node backend/scripts/verify-large-stock-monitor.js`:遍历 26 仓,26/26 全部有数据、0 异常,截止时刻统一 `2026-09-23 01:00`。 - 负载实测(overview 单次请求端到端耗时):崔桥工厂半成品包装项目仓主仓 1475ms / 运���C崔桥工厂仓专用仓主仓 1065ms / 崔桥工厂仓主仓 1253ms / 崔桥工厂京东仓主仓 1272ms / 崔桥工厂品牌仓主仓 1641ms / 河南洛宁仓主仓 1212ms,均返回 200。 - 未运行或受阻的检查及原因:第三方 MSSQL 只读副本 `JSReportReplica` 对 `sys.tables` 返回空、`sys.dm_db_partition_stats` 提示 `The user does not have permission to perform this action`,因此**无法取得大表行数与 EXPLAIN 执行计划**。仅取得快照表 `rpt.pm_stockMonitor` 精确行数 59,630。流水查询均带 `仓库 + 日期区间` 过滤(本月 1 日 ~ 截止时刻 01:00),但缺少索引命中率与扫描行数证据。全程只用只读 SELECT,未执行任何 DDL 或写入。此项为已知证据缺口,请评审判断是否需补充或暂缓部署。 - 人工验证路径:本地登录后端预览账号,逐仓打开「大货库存监控 → 26 个二级菜单」,核对期末数量与仓库助手提供的 22 号期末数据。 ## 风险与回退 - 已知风险: 1. **期末口径变更**:期末数量改用聚水潭实时库存 `jst_inventoryInfo`(按 `wms_co_id` 单仓),不再用 `pm_stockMonitor.jsStock`。后者 warehouse 是「归属仓」口径,会把已调拨到外仓的货仍计在本仓名下(崔桥工厂仓因此虚高约 2.2 万)。仓库助手核对的 9 仓中,山东品牌仓、崔桥工厂品牌仓为 0 差异,其余差异可由 23 日上午仓间调拨/出入库解释;但因业务库无历史结存表,报表本身无法回看「某日期末」。 2. **期初为倒推值**:期初 = 期末 − 采购进仓 + 采购退货 + 销售出仓 − 销售退货(页面标「估」)。业务库无调拨单与其它出库单据表,这部分出库追踪不到,倒推值偏大。 3. **6 列无数据源**:加工进仓、加工出仓、盘点、调拨出、调拨入、其它出库在业务库无对应单据表,显示「—」。 4. **缺少执行计划证据**:见「验证」节最后一栏。 - 回退方式和数据兼容性:本 PR 为纯新增,无迁移、无数据结构变更、无依赖变更;`git revert 2bc9490` 即可完整回退,不影响其他已上线功能。
youruo added 1 commit 2026-09-23 13:55:06 +08:00
按「库存监控」表格在侧边栏增加一级/二级菜单与共用页面
(路由 /planning/large-stock-monitor/:warehouseSlug)。

后端:
- 新增 largeStockMonitorConfig.js:26 仓配置,含 wms_co_id / 快照仓名 / routeKey / slug 映射
- 新增 largeStockMonitor.js:config / overview / sku-list 三个接口
- 新增 largeStockMonitorFlow.js:采购进仓、采购退货、销售出仓、销售退货四类单据流水取数
- 新增 verify-large-stock-monitor.js:26 仓端到端校验脚本
- index.js:挂载 /api/large-stock-monitor 路由

口径说明:
- 库存周转天数 = 月度发货总件数 / 月度日均库存件数 × 100%,下沉到 SQL CASE WHEN 计算
- 四级分级(滞销预警/慢流/呆滞/僵尸)按库龄 + 周转率双维度判定
- 期末数量取聚水潭实际库存 jst_inventoryInfo(按 wms_co_id 单仓),
  不用 pm_stockMonitor.jsStock —— 后者 warehouse 是「归属仓」口径,
  会把已调拨到外仓的货仍计在本仓名下(崔桥工厂仓因此虚高约 2.2 万)
- 截止时刻统一为快照日次日 01:00(跑批时点),库龄/分级均以此为基准,不再用 GETDATE()

前端:
- 新增 LargeStockMonitor 页面、18 列定义、API 封装与样式
- 路由与侧边栏:26 条二级菜单 + 权限点

冲突处理:
- 主仓库已下线 /api/dashboard(backend/src/api/dashboard.js 被移除),
  相应删除 dashboardRoutes 的 require 与挂载,避免后端启动时 require 失败崩溃
- 保留主仓库新增的「模块化库存监控」菜单组及其子项
Author
Collaborator

合并授权记录

按《仓库提交与合并规范》第 6 节「仓库所有者或管理员合并授权例外」执行:

  • 授权人:仓库所有者/管理员(Gitea 账号 youruo,2026-09-23 书面指令授权)
  • 授权范围:仅限本 PR 最终提交 2bc949099ba7fc6dba0db1dfa0b2bc47f6721f48 合入 main,不包含生产服务器部署
  • 同步状态:任务分支已同步最新 main 254d1dd9f92f534567817f1aa55129051a291893,无落后提交
  • 生产部署授权:未授予。本机不存在规范要求的私钥 ~/Desktop/cangku-156.225.27.52-ssh-key/cangku-prod-root-ed25519,合并后由有权限的维护者另行部署

已验证(对应上述 SHA):

  • 后端 npm --prefix backend run check:346 用例 345 通过;唯一失败项 resilientSecretStore.test.js(期望 0600 / 实际 0666)在干净 origin/main worktree 上同样失败,属本机 Windows 权限语义的基线既有失败
  • 前端 npm --prefix frontend run check:lint + 18 项测试 + 构建全部通过,无 Circular chunk
  • backend/scripts/verify-large-stock-monitor.js:26/26 仓库有数据,0 异常
  • 已知缺口:JSReportReplica 只读副本无 sys.dm_db_partition_stats / sys.tables 权限,无法提供执行计划证据,已用端到端耗时(1.0~1.6 秒/仓)替代
## 合并授权记录 按《仓库提交与合并规范》第 6 节「仓库所有者或管理员合并授权例外」执行: - **授权人**:仓库所有者/管理员(Gitea 账号 youruo,2026-09-23 书面指令授权) - **授权范围**:仅限本 PR 最终提交 `2bc949099ba7fc6dba0db1dfa0b2bc47f6721f48` 合入 main,不包含生产服务器部署 - **同步状态**:任务分支已同步最新 main `254d1dd9f92f534567817f1aa55129051a291893`,无落后提交 - **生产部署授权**:未授予。本机不存在规范要求的私钥 `~/Desktop/cangku-156.225.27.52-ssh-key/cangku-prod-root-ed25519`,合并后由有权限的维护者另行部署 已验证(对应上述 SHA): - 后端 `npm --prefix backend run check`:346 用例 345 通过;唯一失败项 `resilientSecretStore.test.js`(期望 0600 / 实际 0666)在干净 origin/main worktree 上同样失败,属本机 Windows 权限语义的基线既有失败 - 前端 `npm --prefix frontend run check`:lint + 18 项测试 + 构建全部通过,无 Circular chunk - `backend/scripts/verify-large-stock-monitor.js`:26/26 仓库有数据,0 异常 - 已知缺口:`JSReportReplica` 只读副本无 `sys.dm_db_partition_stats` / `sys.tables` 权限,无法提供执行计划证据,已用端到端耗时(1.0~1.6 秒/仓)替代
youruo merged commit 2e52e4a393 into main 2026-09-23 14:01:45 +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#27
No description provided.