64 Commits

Author SHA1 Message Date
38fa3f2127 fix: 隧道断线自愈 + 修复配置负缓存永久固化
远端 RST 会把隧道反复踢掉(09-20 实测当天断 5 次,每次存活 15~25 分钟)。原先的
实现把「一次网络抖动」放大成「整个开发栈不可用」,根因有两处,本次一并修掉。

1) scripts/start-remote.mjs —— 隧道断了却拉着应用陪葬

   隧道进程 exit 时直接 stopChildren(),把后端和前端一起杀掉,于是每一次 RST 都
   升级成一次「网站打不开」,还得靠外部守护清残留、整树重启才能恢复。

   改为「退避重连隧道本身,后端/前端进程不受影响」——这正是 autossh 的语义
   (autossh 只负责重启 ssh,从不牵连被它服务的应用)。建立失败走 1s→30s 指数
   退避,建立成功即重置退避。

   顺带补齐保活参数:TCPKeepAlive=yes、ConnectTimeout=10,探活间隔 30s → 15s,
   以便更快发现已被对端 RST 的死连接。

2) backend/src/config/cloudDatabase.js —— 配置负缓存被永久固化

   系统库读取失败时把「空候选」写进缓存,而入口判断是
   `if (cachedCloudConfigCandidates)` —— [] 在 JS 里是 truthy,于是这次失败被
   永久固化:之后永不重试,直接抛「业务数据库尚未配置」500,隧道恢复了也没用,
   必须重启后端。

   改为「带 TTL 的负缓存」(默认 30s,可用 CLOUD_DB_CONFIG_NEGATIVE_TTL_MS 调整):
   入口用 `!== null` 判断,失败态到期自动重新解析,使隧道恢复后无需人工干预。
   缓存清理收敛到 invalidateCloudConfigCache() 单点,避免日后只清数组、忘了清
   TTL 时间戳而退化回「永不过期」。同时让「测试连接」入口显式失效,保证用户改完
   配置点测试能立即看到真实结果。

   顺带把请求超时默认值 600000ms → 60000ms:10 分钟 × maxAttempts=2 最坏挂
   20 分钟,用户体感就是「卡死」;冷查实测 16~42s,60s 仍有充足余量。

验证:
- 新增 backend/test/cloudDatabaseConfigCache.test.js,锁定负缓存三段语义
  (TTL 内不重复解析 / 到期必须重试 / 上游恢复后自动复原且成功态不被 TTL 淘汰);
  test/remote-access.test.mjs 补隧道保活参数、退避曲线,以及「自愈循环不得调用
  stopChildren」的防腐化断言。
- 两处均做对照组实验:去掉保护后测试如实报错(负缓存 → 报 TTL 到期未重试;
  隧道 → 把 stopChildren 加回去即被用例抓住),证明用例真能拦住回归。
- 后端全量 340 项 / 339 通过,唯一失败为 resilientSecretStore 的 Windows 权限
  断言(环境固有,与本次无关);check-syntax 通过。
- 本地实测:kill 掉隧道进程后 1 秒内自动重建(PID 36268 → 15816),后端进程
  PID 未变(29580)、/health 仍返回 200。
2026-09-22 19:32:40 +08:00
4946018251 Merge pull request 'fix: MKH-BOM 新增日销订单表兜底,修复上游快照漏算导致「库存 0 却不报缺货」' (#18) 2026-09-19 14:20:52 +08:00
3e64702f12 fix: MKH-BOM 新增日销订单表兜底,修复上游快照漏算导致「库存 0 却不报缺货」
背景
- 业务反馈 MKHDNZ0409260601548 近 15 天实发 2 件、库存 0,页面既不报缺货也不进任何预警。
- 根因是双重盲区:
  ① 上游 rpt.pm_stockMonitor.fifteenAvgSale 漏算 —— 快照 09-18 下,窗口内有真实发货的
     178 个 MKH 成品编码里有 24 个被记成 0;其中 16 个订单全部来自样品专用店铺(上游同样
     不计样品单,属合理口径),剩 8 个是真实店铺(天猫/京东/拼多多)。该列是**保留两位
     小数的日均**(最小非零 0.07 = 1 件 ÷ 15 天),无法用四舍五入解释。
  ② 快照日销 = 0 且待发货订单 = 0 时,判定直接落到「无销量」分支、hasWarning=false,
     彻底排除在预警之外 —— 库存为 0 也救不回来。

改动
- 日销兜底(服务文件头新增 ⑦-a):**快照日销 ≤ 0 且近 15 天有真实发货**时,日销改用
  订单表实算值 = 已发货件数 ÷ 15;快照 > 0 一律以上游为准,不覆盖,避免两套口径打架。
  · 排除样品/测试专用店铺(shop_name 含「样品」「测试」),与上游口径对齐
  · 窗口 = 含今天在内的 15 个自然日,与分母同口径
  · 结果透出 dailySaleSource('snapshot'|'orders') / snapshotDailySale / recentShippedQty
- 取数:loadPendingOrderIndex 重构为 loadOrderIndex,一条查询同时覆盖「待发货
  (send_date IS NULL)」与「近 15 天已发货(send_date 在窗口内)」。实测合并后总耗时
  约 1.25s ≈ 单查待发货,而拆成两条独立查询要在现有开销之上再加一次全表扫描
  (首轮冷执行计划下 qmcust 单表可劣化到 20s+)。
- PENDING_ORDER_TABLES 更名 ORDER_TABLES:两张表的口径没变,只是不再仅服务待发货。
- 前端:日销来自兜底时加虚线下划 + 悬停说明,业务拿该数字与源系统 fifteenAvgSale
  对照时不会被误判为数据错误。

验证
- 语法检查:151 文件通过。
- 后端测试:338 项 337 通过。唯一失败为 resilientSecretStore 的权限断言(期望 0o600、
  Windows 实际 0o666),平台固有,与本改动无关。
- 新增回归测试:兜底生效 / 快照非零不覆盖 / 无发货不兜底 / 与订单驱动的优先级 /
  订单源降级时退化成旧口径;订单索引测试补充「已发货同编码跨表累加」与「样品、测试店排除」断言。
- 真实数据端到端(本地接口 /api/mkh-bom/list,4,223 个成品):
  · MKHDNZ0409260601548:日销 0 → 0.1333(source=orders),不再隐身
  · 日销 > 0 的商品 177 → 198;有效预警(缺货 + 预警)18 → 28
  · 21 个等级变化**全部是「无销量 → 缺货/正常/已排产」**,没有任何既有预警被降级
  · 其中 10 个新缺货均为「库存 0 + 近 15 天真实发货 9~27 件」的真盲区
  · 样品店排除按整行生效:实测某编码窗口内 5 件(含样品店 1 件)→ 索引记为 4 件
- 前端 eslint 通过、vite build 通过。

风险与回退
- 只影响「快照日销 = 0」的商品,快照 > 0 的商品行为完全不变。
- 订单源不可用时兜底自动失效,退化成旧口径(不会误报)。
- 回退:本提交可整体 revert,无表结构变更、无数据迁移。
2026-09-19 13:24:15 +08:00
d650fd02f2 Merge pull request 'fix: MKH-BOM 待发货订单合并两张渠道表,修复天猫/淘宝订单漏报' (#17) 2026-09-19 13:06:11 +08:00
f156b90dbb fix: MKH-BOM 待发货订单合并两张渠道表,修复天猫/淘宝订单漏报
问题
  MKHDNZ0409260700059、MKHDNZ0409260601228 等成品明明有待发货订单,
  补货预警却显示 0 单、判为「不预警」,业务反馈到系统。

根因
  业务库的订单按渠道拆成**互不重叠的两张表**,而 loadPendingOrderIndex()
  只读了 rpt.jst_Orders(京东/京喜/拼多多/抖音/得物/唯品会),
  天猫 / 淘宝 / 1688 / 阿里巴巴渠道的待发货需求**全部被漏掉**。

实测(2026-09-19,近 30 天窗口)
  - 两表店铺名交集 0(jst_Orders 398 店 vs qmcust 78 店),so_id 交集 5 条,
    o_id 交集 **0 条** —— 合并无重复计件风险;
  - jst_Orders 里 `shop_name LIKE '%天猫%'` = **0 行**
    (不是命名差异:同一品牌在不同平台是不同店铺名,按品牌名反查会误判);
  - MKH 成品待发货:仅 jst_Orders = 36 编码 / 50 件  →
    合并后 = **40 编码 / 56 件**,补回 4 个编码:
    MKHDNZ0409260700059 / MKHDNZ0409260601228 /
    MKHDNZ0409260601530 / MKHDNZ0409260700498。

修复
  - PENDING_ORDER_TABLE → PENDING_ORDER_TABLES(两张表,新增 qmcust 源);
  - Promise.allSettled 并行读取,按 o_id 去重后合并(去重为防御性逻辑);
  - 部分源失败时**保留成功源的数据**并透出 degraded=true,用短 TTL 尽快重试,
    不再像原先那样单源失败就整表降级为空索引(那会静默漏报全部需求);
  - 口径范围:**渠道全并**(2026-09-19 业务确认),含 1688 / 阿里巴巴 /
    分销导单专用店铺。

测试
  - 新增 2 个回归测试:两张表都读到 + 跨表同 o_id 只计一次 + 组合装不计入;
    单源失败时 degraded=true 且成功源数据保留。
  - 后端 337 项:336 通过,1 项失败为 Windows 平台固有差异
    (resilientSecretStore 断言 0o600,Windows 实际 0o666),与本改动无关。
  - 语法检查 151 文件通过。
2026-09-19 12:25:43 +08:00
cc66e5100f Merge pull request 'feat: MKH-BOM 补货预警(订单驱动 + 配件不足)与日销口径改近 15 天' (#16) 2026-09-18 17:56:13 +08:00
b7aca2343b feat(配件库存监控/MKH-BOM): 新增「采购在途」数量列与在途明细弹窗,补货预警改按结余库存判定
配件库存监控:
- 列表「实时库存」后新增「采购在途数量」列,口径 SUM(MAX(0, jst_purchaseItem.qty - inQty))
- 顶部「实时库存合计」后新增可点击「采购在途」卡片,弹窗展示在途明细
  (商品编码/商品名称/采购数量/已入库/在途数量/计划到货日期/采购单号),支持关键词、排序、分页
- 新增后端接口 GET /api/modular-stock-monitor/purchase-in-transit
- 筛选器品类改直查 jst_sku 主表,避免新增 OUTER APPLY 拖慢筛选
- 采购在途列仅取数展示,不参与 ORDER BY / 聚合(规避 MSSQL 对 OUTER APPLY 列的灾难性执行计划)

MKH-BOM 补货预警:
- 日销驱动与已排产分支改用「结余库存 = 现有库存 - 待发货件数」判定可用天数与预警等级
- 建议补货量按 ceil(3 天日销 + 待发货件数 - 现有库存) 计算
- 新增 scope=work-order 范围筛选;列表新增「结余库存」列
- 打印模板剥离公司名前缀,打印字号调大

测试:mkhBomService 单测新增结余库存缓冲/紧张用例与回归用例
2026-09-18 17:44:01 +08:00
be52bdd0b5 feat(配件库存监控/MKH-BOM): 两页面新增「同步最新数据」按钮
需求:配件库存监控、MKH-BOM 资料两个页面各加一个同步按钮,任何时候点击都能
立即拉取最新数据,不必等凌晨 00:00 的定时刷新。

后端:
- mkhBomService 新增 clearMkhBomCache():清空本页全部服务端缓存
  (businessBom / officialBomIndex / officialBomDetail / productBom /
  mkhProduct / replenishIndex / workOrderIndex / pendingOrderIndex /
  componentStock / componentLocation),返回 syncedAt + 各缓存清除条目数。
- modularStockMonitorService 新增 syncModularStock():本页无进程内缓存
  (每次请求直连副本库),同步动作 = 重新解析并返回最新监控日,前端据此重拉列表。
- 新增接口 POST /api/mkh-bom/sync、POST /api/modular-stock-monitor/sync。

前端:
- api/mkhBom.js 新增 syncMkhBom;api/modularStockMonitor.js 新增 syncModularStock。
- 两个页面工具栏各加「同步最新数据」主按钮(SyncOutlined,带 loading 态),
  点击 → 调后端 sync → 成功后重新拉列表(MKH-BOM 页同时清空展开明细缓存
  detailCache,避免看到旧的配件明细)→ 提示「已同步最新数据」;
  失败时展示后端返回的错误信息。

口径说明(重要):
- 两页数据来自副本库 JSReportReplica,由上游聚水潭同步;应用层无法触发上游拉取。
  本按钮的作用是「清服务端缓存 + 直连副本库重取最新」,保证看到的不是
  2~15 分钟前的缓存结果,而不是重新跑一遍上游同步。
- 后端已内置的 dailyRefresh(cron 0 0 * * *,Asia/Shanghai)刷的是
  summary_daily_* / summary_monthly_* 汇总表,不覆盖这两页数据源,
  与本按钮既不重复也不冲突,可并存。

验证:
- 后端 4 个改动文件 node --check 全部通过。
- 前端 4 个改动文件(含 2 个 jsx)用 @babel/parser 解析全部通过。
- 实测:syncModularStock 返回 monitorDate=2026-09-16;
  clearMkhBomCache 返回 syncedAt 与各缓存清除条目数。
- 单测 mkhBomService.test.js 40/40 通过,无回归。
- 前端 lint/build 未运行:frontend/node_modules 仍是之前被中断 npm ci 破坏的
  坏目录(frontend/node_modules_broken_0917/,未纳入提交)。
  合并前需在本机 npm ci 恢复后,打开两个页面确认按钮渲染与点击效果。
- 后端改动需重启服务后才生效。
2026-09-17 18:14:57 +08:00
bc8c46d5be 配件库存监控:未配置MKH 不进任何缺货/预警
业务确认(2026-09-17):未配置MKH 的配件不属于模块化体系,预警列一律显示「正常」,
既不报缺货(实时库存<=0)也不报预警(可用天数<=7)。

实现:
- 新增 buildWarningOrderSql() 统一表达式(0缺货/1预警/2正常),未配置MKH(cfg.configured=0) 直接判 2。
- 列表映射 mapRow 改用 SQL 算好的 warningOrder 推导 warningLevel(删除重复 normalizeWarningLevel,
  避免前后端各算一份导致排序与显示不一致)。
- 汇总计数 buildSummary.outOfStockCount / lowStockDaysCount 改用统一表达式,不再计入未配置MKH。
- 筛选 buildFilters:按预警等级筛选、onlyWarning=1(仅看缺货/预警)均排除未配置MKH。

实测(接口直跑,目标仓 794 SKU):
- 未配置MKH 95 个全部判「正常」(其中 55 个库存=0、58 个可用天数<=7,原会预警)。
- summary.outOfStockCount=13 / lowStockDaysCount=3,与已配置MKH 页面分布一致。
- onlyWarning=1 返回 16 条,0 条未配置MKH。
2026-09-17 16:41:25 +08:00
0bb7c5905d fix(模块化库存监控): 已配置MKH 改从聚水潭 SKU 级 BOM 维护(jst_skuBomItem)判定
业务反馈上一版「已配置MKH」数量不对(仅 29 个),原因是用了
jst_comboProductItem 组合装引用口径,漏掉了真正以 MKH 成品为父项的 BOM 配件。

修正:
- 数据源由 jst_comboProductItem 改为 rpt.jst_skuBomItem(聚水潭 SKU 级 BOM 明细,
  含配件商品编码 map_outer_sku_id)。
- 判定口径:目标仓商品编码出现在 jst_skuBomItem.map_outer_sku_id,且父项
  sku_id 以 'MKH' 开头(即被某 MKH 模块化成品 BOM 引用为配件) → 已配置MKH。
- 实测目标仓 794 个 SKU 中 699 个命中(map_outer_sku_id 匹配、父项 MKH 过滤),
  95 个未配置,合计 794,与接口返回 summary 一致。
- 同步前端状态列 tooltip 与页脚口径说明。
- 移除对「产品资料系统数据库商品档案」「jst_comboProductItem 组合装」两套旧口径的依赖。

注:pm_bomBaseInfo(聚水潭 BOM 维护) 的配件行无 SKU 编码列(仅中文品名/位号),
其组件 SKU 编码实际落在 jst_skuBomItem.map_outer_sku_id,故采用后者。
2026-09-17 16:20:17 +08:00
e6ea1246f9 配件库存监控:已配置MKH改为"被MKH模块化成品引用"判定
- backend/src/services/modularStockMonitorService.js
  - 「已配置MKH」判定口径切回 jst_comboProductItem 组合装引用:
    该 SKU 出现在 jst_comboProductItem.src_sku_id 且 combine_sku_id 以 'MKH' 开头
    即视为被 MKH 模块化成品(组合装/成品档案)引用为配件。
  - 移除产品资料系统数据库覆盖清单逻辑(resolveProductCoverage / productCoveredCsv),
    产品资料库仅保留作图片来源。
  - 实测目标仓 794 SKU 中 29 个命中(原产品资料库口径 661 已废弃)。
- frontend/src/pages/ModularStockMonitor/index.jsx
  - 状态列 tooltip 文案同步为「是否被 MKH 模块化成品作为配件引用」。

注:本改动会令已配置MKH数量从 661 降至 29(数据使然,非 bug)。
2026-09-17 16:01:20 +08:00
75a8795723 配件库存监控:表头"SKU编码"改为"商品编码"
- frontend/src/pages/ModularStockMonitor/index.jsx
  - 表格列头 "SKU编码" → "商品编码"
  - MKH 配置状态 tooltip 文案同步调整
  - 搜索框 placeholder "SKU 编码 / 名称" → "商品编码 / 名称"
- backend/src/services/modularStockMonitorService.js
  - 文件头注释同步更新(仅文案,无逻辑改动)

关于"从 BOM 维护匹配已配置 MKH 成品编码":
已探测 rpt.pm_bomBaseInfo 与目标仓 SKU 的编码体系完全脱钩
(sku_id/i_id/name 均 0 命中),若直接切换数据源会导致已配置数
从 661 归零。经用户确认,本次保留现有产品资料库判定口径,
仅做表头文案变更。
2026-09-17 15:44:30 +08:00
8ba052649d feat: 补货预警-日销为0有代发订单时按库存÷代发件数算可用天数预警
- ⑩订单驱动分支改为:可用天数 = 现有库存 ÷ 代发(待发货)订单件数
  · 可用天数 = 0(无库存)→ 缺货
  · 0 < 可用天数 < 3 天 → 预警(建议补到 3 天缓冲:3×代发件数−现有库存)
  · 可用天数 ≥ 3 天 → 库存充足,不预警(阈值语义与日销分支一致)
- buildReplenishMetrics 订单驱动分支不再把 stockDays 记 null,统一如实记录
- 同步前端「可用天数」列/导出/数据口径说明文案(不再显示「按订单」)
- 更新 mkhBomService.test.js 对应用例,单测 40/40 通过
2026-09-17 15:04:50 +08:00
3e02c3e393 feat: 日销口径由近 7 天改为近 15 天(MKH 补货预警 + 模块化库存监控)
业务要求「近7日日销」改「近30天日销」。实测业务库与产品资料库均无 30 天日销,
已实现的最长周期是 pm_stockMonitor.fifteenAvgSale(15 天),经与业务确认改用 15 天。

为什么没有 30 天(2026-09-17 实测,避免重复排查):
- rpt.pm_stockMonitor 只有 threeAvgSale(3天)/sevenAvgSale(7天)/fifteenAvgSale(15天),
  且整表只保留 1 天快照(2026-09-16),攒不出 30 天历史
- rpt.dws_sn_sales_full_info_di(stat_date+skuid+goods_count,新鲜到 09-15)
  里 MKH 商品 0 个;目标仓 794 个 SKU 命中也是 0
- rpt.dws_order_sales_cost_detail_di 停在 2025-04(历史归档)
- rpt.jst_salesOutboundInfo 只有出库单头,无 SKU 明细;业务库无出库明细表
- rpt.op_BarcodeSalePrice30dDaily 名字带 30d,但只有 salePrice 没有销量

改动:
- backend/src/services/mkhBomService.js
  · SALE_WINDOW_DAYS 7 → 15,新增 DAILY_SALE_COLUMN='fifteenAvgSale',
    监控快照 SQL 按该常量插值取数(以后改口径只改常量)
  · buildReplenishMetrics 入参 sevenAvgSale → avgSale(语义与周期解耦)
  · 文件头 ⑦ 补「为什么是 15 天」的完整排查结论;⑦ / ⑩ / ⑪ 实测数字按新口径更新
- backend/src/services/modularStockMonitorService.js
  · 取数列与 API 字段名 sevenAvgSale/avgShip7d → fifteenAvgSale/avgShip15d
    (字段名同步改,避免名不副实)
- frontend/src/pages/MkhBomData/index.jsx
  · 列头与口径说明「近7日」→「近15天」;动态文案兜底 7 → 15
- frontend/src/pages/ModularStockMonitor/index.jsx
  · 列头「近7日日均发货量」→「近15天日均发货量」,dataIndex 同步改
  · 口径说明补充:可用天数仍沿用 jsUseDays(源系统口径),与日销并非同一时间窗

影响(同一份 09-16 快照,7 天 vs 15 天):
  有销商品  114 → 170   周期拉长,更多商品进得了「有销」集合
  补货预警   25 → 19    反而变少:15 天日销普遍低于 7 天(近期销量走低),
                         可用天数 = 库存 ÷ 日销 随之变大,跌破 3 天的变少
  缺货        9 → 10
  已排产     11 → 13
  订单驱动   14 → 8     更多商品自己有日销,不再需要靠订单兜底
  配件不足   10 → 12
「预警变少」是口径变化的正常结果,不是 bug。

验证:
- 后端语法检查 151 个文件通过
- mkhBomService + mkhReplenishAlertJob 单测 52/52 通过
- 后端全量 334 tests / 333 pass(唯一失败是 resilientSecretStore 的
  Windows 文件权限断言,与本改动无关的环境固有问题)
- 接口实测:total 4223 / warningCount 19 / outOfStockCount 10 /
  saleWindowDays 15 / componentShortageCount 12
2026-09-17 14:06:50 +08:00
06952d8a04 Merge remote-tracking branch 'origin/main' into codex/mkh-alert-export-0917
origin/main 已前进 11 个提交(PR #11~#15),其中 #11「配件仓位只取箱及仓位库存表」
与 #12「从模块化成品列表排除配件档案」改动了与本分支相同的三个文件。

冲突处理(3 个文件,逐处保留双方意图,未使用 ours/theirs 批量取舍):
- backend/src/services/mkhBomService.js(4 处):取本分支侧。本分支的 ⑤~⑪ 注释与
  loadComponentLocations 是 origin/main 那段的超集,且双方都已删除
  buildInventoryWarehouseMap 回退链,语义一致;同时并入 origin/main 收紧后的
  MKH_WHERE(必须是 jst_skuBomItem 正式父项)与文件头 ① 的新口径说明。
- backend/test/mkhBomService.test.js(1 处):hunk 边界冲突,双方各缺一个 `});`。
  origin/main 新增的「无箱记录不回退仓库」测试按语义插在仓位测试之后,
  再接本分支新增的测试,两处闭合各自补回。
- frontend/src/pages/MkhBomData/index.jsx(2 处):合并双方文案。数据口径采用
  origin/main 的表述(正式 BOM 父项、仓位只取 rpt.jst_packInventoryInfo),
  并保留本分支的补货预警 / 待发货订单 / 在途加工单 / 配件不足四段说明。

顺带校正 mkhBomService.js 注释中因成品口径收紧而过期的数字
(成品总数 4408 → 见 ①,预警数 26 → 25),仅改注释,不动逻辑。

合并后重新验证:后端语法检查 151 个文件通过;mkhBomService + mkhReplenishAlertJob
单测 52/52 通过;接口实测 total 4223 / warningCount 25 / componentShortageCount 10。
2026-09-17 13:52:40 +08:00
f69d26796e feat: MKH-BOM 补货预警支持待发订单驱动与配件不足标记
补货预警在原有「销量 + 库存」口径之外增加两条判定,均不改变已上线行为:

1. 待发订单驱动
   - MKH 成品条码历史无销售量、但存在未发货订单时,同样进入补货预警。
   - 建议补货量按「未发货件数 − 现有库存」计算,无订单时不参与该口径。
   - 列表新增待发货订单列,展示件数、单数与最早下单时间。

2. 配件不足
   - 对判定为缺货或预警的商品,按 BOM 计算可组装数:
     可组装数 = 各配件 ⌊(现有库存 − 未完成加工单占用) ÷ 单台用量⌋ 取最小值。
   - 可组装数为 0 时标记「配件不足,无法补货」并保留在清单中,
     建议补货量显示「—」,同时给出短板配件及其库存。
   - 配件库存只认「简尚-崔桥工厂半成品包装项目仓」的现有库存,
     按业务确认不计采购在途。
   - 配件库存查询失败时降级为空索引并标记 componentStockDegraded,
     不写入缓存,避免把瞬时故障固化为错误数据。

导出与通知文案同步:导出新增「配件不足」列、补货量按同一口径输出;
缺货通知在配件不足时插入短板配件提示并把建议补货量显示为「—」。

验证:backend 相关单测全部通过(新增 9 例);语法检查通过;
前端 eslint 零错误且 vite build 通过;接口实测与页面渲染结果见 PR。
2026-09-17 12:18:32 +08:00
a928135a63 Merge pull request 'fix: 兼容生产服务器旧版 Git' (#15)
Avoid unsupported git -C and branch --show-current commands in the production build script.
2026-09-17 11:56:10 +08:00
lunanting
5302b22fc1 fix: 兼容生产服务器旧版Git 2026-09-17 11:55:37 +08:00
fd89eb64d2 Merge pull request 'build: 使用兼容生产环境的前端构建流程' (#14)
Use standard Vite and an isolated Node.js 22 production build script verified against the deployed SHA.
2026-09-17 11:54:50 +08:00
lunanting
31a4b0aebb build: 使用兼容生产环境的前端构建流程 2026-09-17 11:54:03 +08:00
611165dded Merge pull request 'docs: 修正生产部署运行时命令' (#13)
Use commands compatible with the production Git and build the frontend under Node.js 22.
2026-09-17 11:46:14 +08:00
lunanting
e1c2ad1ea6 docs: 修正生产部署运行时命令 2026-09-17 11:45:37 +08:00
2b096ed2e2 Merge pull request 'fix: 从模块化成品列表排除配件档案' (#12)
Only designated warehouse SKU records that are official BOM parents appear as modular finished products.
2026-09-17 11:43:38 +08:00
lunanting
986174076f fix: 仅展示正式BOM父项商品 2026-09-17 11:42:50 +08:00
ecfd97787d Merge pull request 'fix: 配件仓位仅使用箱及仓位库存表' (#11)
Use rpt.jst_packInventoryInfo as the sole BOM location source and document explicit owner merge authorization.
2026-09-17 11:15:47 +08:00
lunanting
80028665c5 docs: allow explicit owner merge authorization 2026-09-17 11:14:46 +08:00
lunanting
3a87d8ecba fix: use pack inventory for BOM locations 2026-09-17 10:26:54 +08:00
897bbd2afd Merge remote-tracking branch 'origin/main' into codex/mkh-alert-export-0917
远端 6c00977(PR #10 "show MKH component warehouse locations")与本地的
通知推送 / 导出 / 在途加工单改动改到了同一批文件,手工合并如下:

配件的仓位与库存统一到 loadComponentLocationData(),列表展开、单品明细、
导出配件明细三处共用(新增 loadComponentLocations 作为兼容入口):

- 仓位四级兜底链:真货位 bin_group/bin → 箱号 pack_id → 库存正数量仓库
  (未分箱)→ jst_sku.other_3 商品档案仓(暂无箱号)
- 库存与仓位一次查询同时产出,两条查询都成功才写缓存(TTL 10 分钟)
- 修正远端版本的仓库关联列:仓名必须用 jst_warehouseInfo.Id = p.wh_id;
  jst_packInventoryInfo.wms_co_id 全表 NULL,用它关联 85,152 行全部取不到仓名。
  (库存表相反,必须用 w.wms_co_id = i.wms_co_id)
- 前端口径说明同时保留补货预警/在途加工单与新仓位口径
2026-09-17 10:06:26 +08:00
fe831c32fd feat: MKH-BOM 补货预警排除在途加工单、缺货通知推送、导出功能
- 补货预警:接入加工单(链接服务器 bi_processing_work_orders),有未完成加工单则不预警,新增在途加工量列
- 新增每日 09:00 缺货/预警通知推送(cron + 统一通知中心 + 幂等键)
- 新增导出:商品清单 / 配件明细,XLSX / CSV,按当前筛选条件全量
- 配件仓位:新增 loadComponentLocations 批量加载器(导出/列表展开共用)
2026-09-17 10:01:13 +08:00
6c0097753f Merge pull request 'fix: show MKH component warehouse locations' (#10) from codex/fix-bom-location-0917 into main 2026-09-17 09:52:44 +08:00
lunanting
006737e4ae fix: show MKH component warehouse locations 2026-09-17 09:39:25 +08:00
50202557d9 Merge pull request 'fix: restrict MKH products and use official BOM tables' (#9) from codex/bom-warehouse-filter-0916 into main 2026-09-16 21:03:57 +08:00
lunanting
1c72df7f36 Merge remote-tracking branch 'origin/main' into codex/bom-warehouse-filter-0916
# Conflicts:
#	backend/src/services/mkhBomService.js
2026-09-16 21:02:07 +08:00
4aed4d543d Merge pull request 'fix: 从包装库存读取 BOM 配件仓位' (#8) from codex/bom-pack-location-0916 into main 2026-09-16 21:00:01 +08:00
lunanting
8e5d427b3a fix: read MKH details from official BOM tables 2026-09-16 20:56:26 +08:00
lunanting
3bf7b9f208 fix: restrict MKH BOM list to designated warehouse 2026-09-16 18:02:28 +08:00
lunanting
65d009dcdc fix: read BOM locations from pack inventory 2026-09-16 17:52:49 +08:00
3fe0e55ad6 Merge pull request 'fix: show MKH BOM details in drill-down' (#7) from codex/fix-mkh-bom-drilldown into main 2026-09-16 16:58:54 +08:00
lunanting
3ccba5f460 fix: show MKH BOM details in drill-down 2026-09-16 14:57:05 +08:00
4c2ebef988 Merge pull request 'feat: 启用运营分析模块,新增模块化库存监控与 MKH-BOM 资料' (#6) from yanhui/codex/yanhui-operation-modules-001 into main
经项目负责人 yanhui 授权合并(2026-09-16)。

基线 main: 8448f7a0e849ac04c7f572bb3fb1fa89765c0945
待合并提交: 445347e664a555cdc8bc2a0a7c488f111db2039e

验证:前端 lint 通过 / test 16-16 通过 / vite build 通过;
后端语法检查 149 文件通过、node --test 38-39 通过
(唯一失败 resilientSecretStore.test.js 为 Windows 文件权限语义差异,不涉及本次改动)。
2026-09-16 13:49:35 +08:00
445347e664 feat: 启用运营分析模块,新增模块化库存监控与 MKH-BOM 资料
本次将此前被列入退役名单的运营分析相关模块恢复为可用,并新增「模块化库存监控」
一级菜单及其两个子页面。

主要变更:
1. 恢复启用:商品监控、激励看板、营销活动、推广模块、商品分析
   - retiredFeatures 移出对应退役名单与清表语句,改为正常保留
   - 补齐后端路由、前端页面与 API 封装、侧边栏配置、桌面客户端能力项
   - 同步更新 retiredFeatures / retiredRoutes / retiredNavigation / desktopSessionService 测试
2. 新增「模块化库存监控」一级菜单
   - 配件库存监控:仅取「简尚-崔桥工厂半成品包装项目仓」SKU 的实时库存、
     当日入库/出库、近 7 日日均发货量、库存可用天数与预警(库存可用天数 ≤ 7 预警)
   - MKH-BOM资料:按商品编码展示配件明细、数量、仓位、库存,支持 A4 纵向打印
3. 新增产品资料系统数据库(PostgreSQL)连接模块:读取系统库 database_configs 中
   name = product_information_database 的配置,凭据只从配置读取,不落代码
4. 新增系统设置页配置项:商品标签配置、部门商品标签配置、部门SKU负责人配置
5. 旧 /api/dashboard 接口迁移至 /api/productAnalysis,仪表盘预览页改用新接口,
   相应移除 dashboard 路由模块及其测试
6. 修复 retiredRoutes 测试在 Windows 下挂起超时的问题:该测试用
   parent.filename.endsWith('/api/planningUpload.js') 判断是否注入 mock,
   而 Windows 的 filename 为反斜杠路径,导致判断恒为 false、mock 全部失效、
   真实模块去连中央系统库而挂起(Linux CI 正常)。改为平台无关的路径匹配。
7. .gitignore 忽略本地验证产物(outputs/、.git-status.txt)

验证:
- 前端:lint / test(16 项)/ build(含 planning entry 校验)全部通过
- 后端:语法检查 149 个文件通过;测试 38/39 通过
- 已知未通过项:resilientSecretStore.test.js 断言密钥备份文件权限为 0o600,
  Windows 下 chmod 无法表达该权限(实际为 0o666),属既有的平台相关失败,
  与本次改动无关,本次未修改该文件
- 说明:本机 frontend/ 下存在未纳入版本库的旧依赖备份目录 node_modules_old_*,
  会污染 ESLint 扫描(十余万条第三方报错),故 lint 步骤以
  --ignore-pattern node_modules_old_*/** 排除后执行,其余步骤与仓库 check 一致

未提交内容:本地验证截图 outputs/ 与 .git-status.txt 已被 .gitignore 排除。
2026-09-15 16:53:12 +08:00
8448f7a0e8 Merge pull request 'feat: support product information PostgreSQL config' (#5) from codex/add-product-information-postgres into main 2026-09-12 21:34:32 +08:00
lunanting
4b1e004b3c feat: support product information PostgreSQL config 2026-09-12 21:34:07 +08:00
d726dfd4cb Merge pull request 'docs: require database load and index validation' (#4) from codex/database-index-guidelines into main 2026-09-12 19:49:57 +08:00
lunanting
3c1895a9e2 docs: require database load and index validation 2026-09-12 19:48:57 +08:00
490c68f7d7 Merge pull request #3: remove commerce monitoring feature suites
Validated frontend, backend, remote-access and dashboard route checks.
2026-09-12 18:51:35 +08:00
lunanting
d9ebbba61e refactor: remove commerce monitoring feature suites 2026-09-12 18:49:37 +08:00
lunanting
36948c98ca refactor: remove store and operations feature suites 2026-09-12 17:50:26 +08:00
lunanting
1d87c3f94c docs: define safe production deployment workflow 2026-09-12 17:38:11 +08:00
lunanting
4f78a5b512 security: run managed Redis unprivileged 2026-09-12 17:33:26 +08:00