|
|
fe195114e4
|
feat(wle): 钉钉推送明细按仓聚集,并给每个仓保底 1 条
业务要求:推送明细「按照仓库来,相同仓库排序在一起」,方便各仓在群里只看自己那一段。
改动:
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 本提交。
|
2026-10-22 14:02:43 +08:00 |
|
|
|
7939816b64
|
fix(wle): 推送明细再去掉末尾「待处理小时数」
业务三次要求(2026-10-22):明细最后面的超时时间也不要。
- buildDetailLine 现在是 4 段:仓|快递单号|快递|异常类型
- 删除仅此处使用的 formatHours()(不留死代码)
- 「无快递单号时退回内部单号」的兜底按业务确认保留
- 文件头/函数注释补第三条口径,单测断言正好 4 段且不含 17.3h 这类时长
|
2026-10-22 11:56:11 +08:00 |
|
|
|
b223db7961
|
fix(wle): 推送明细第二列改为快递单号
业务二次要求(2026-10-22):明细里显示快递单号,不要内部单号。
- buildDetailLine 第二段从 `oId` 改为 `trackingNo`(上游 `logistic_id`)
- 未揽收 / 无物流单的包裹本来就没有快递单号 → 退回 `oId`,
否则这条在群里无法定位(不让它变成「无单号」)
- 单测:样例带 trackingNo 并断言内部单号不出现;补「无 trackingNo 时退回 oId」用例
- 文件头与函数注释同步口径
|
2026-10-22 11:46:06 +08:00 |
|
|
|
57debbe022
|
fix(wle): 钉钉推送明细去掉发货时间列
业务反馈(2026-10-22):推送明细里不需要发货时间。
- buildDetailLine 从「仓|内部单号|快递|异常类型|发货时间|待处理」
改为「仓|内部单号|快递|异常类型|待处理小时数」
- 删除仅此处使用的 shortTime() 及其导出,不留死代码
- 文件头补口径说明,防止以后把 sendTime 加回去
- 单测同步:断言新列序,并显式断言消息里不出现 sendTime(传了也不能渲染)
|
2026-10-22 11:40:11 +08:00 |
|
|
|
bdc2cf9fd6
|
feat(wle): 仓储转运异常每天定点推文本到钉钉群
在「仓储中心物流转运异常」页新增「异常通知」:每天 09:10(可改)把当天核验批次
的异常情况以**文本消息**推到钉钉群,0 条也推(用来确认任务没挂)。
为什么是 text 而不是 Excel 附件:钉钉群自定义机器人 webhook 只支持
text/markdown/link/actionCard,发文件必须走企业内部应用(AppKey/AppSecret/
robotCode/openConversationId 四项凭据 + 应用权限 + 机器人进群)。业务确认
「群里看文本就够,要明细点链接去页面导出」,于是走最轻的 webhook。
后端
- 新增 services/dingtalkRobotWebhookSender.js:POST /robot/send + msgtype=text
· 加签 urlEncode(base64(HmacSHA256(secret, "timestamp\nsecret"))),timestamp 毫秒
· text.content 按 UTF-8 **字节**截断到 20000(钉钉硬上限),不切半个汉字
· webhook 严格匹配 ^/robot/send$ 且必须有 access_token;errcode/errmsg 原样抛
- 新增 services/warehouseLogisticsExceptionNotifySettings.js:
· webhookUrl 存在 system_config(完整回显,业务要核对);加签密钥走
resilientSecretStore,接口只回 configured + 掩码,留空=沿用已存
· sendTime 非法退回 09:10;maxDetailRows 0~50 默认 30
· 状态 lastSentDate(按推送日去重)等存 system_config
- 新增 jobs/warehouseLogisticsExceptionNotifyJob.js:
· buildNotifyText:抬头【仓储物流转运异常】→ 发货/包裹/异常/异常率 → 分类型
→ 剔除数 → 按仓(只列有异常的仓)→ 明细前 N 条 → 页面链接(带 date)
· 明细行「仓|内部单号|快递|异常类型|发货时间|待处理」,字段内换行压平
· 超长从明细末尾逐条砍并标记 truncated(truncated 只表示被字节上限砍过,
不表示「按配置只列前 N 条」)
· 每分钟 tick 比对北京时间 HH:mm == 配置 sendTime,改时间不用重启
- api:GET/PUT /notify/settings、GET /notify/state、POST /notify/run
(dryRun 预览不校验凭据;probe 只发一句测试文本、不查业务数据)
前端
- 「导出」右侧新增「异常通知」(铃铛)弹窗:开关、推送时间、Webhook、加签密钥、
明细条数、@所有人、页面链接、上次推送结果、三段帮助说明
- 「测试通道」「预览正文」「保存」「立即推送到群」
- 预览改成弹窗内受控区块:本项目跑 React 19 + antd v5,Modal.info 静态方法
拿不到 context 会**静默不渲染**(只留一行 warning,看着像后端没返回)
同步与兼容
- 新配置首次读取为空 → ready=false,页面提示「Webhook 地址还没配」,不影响页面其它功能
- 定时任务只在 enabled=true 时生效;本地 ENABLE_BACKGROUND_JOBS=false 不跑,用页面按钮验
验证
- backend/test/warehouseLogisticsExceptionNotify.test.js 15/15:正文结构与数字、
0 条平安消息、条数上限、字节精简、Webhook 校验、加签 crypto 手算对齐、errcode 透传
- 后端全量 465 项 / 463 过(2 项既有环境失败:Windows 权限位、负缓存需隧道故障态)
- 前端 eslint 0、build 成功
- 真数据干跑:144 条异常 / 列 30 条 / 3768 字节 / 20s,按仓包裹数合计 144 对得上
- playwright 真渲染:弹窗字段 Webhook/加签密钥/明细条数/@所有人/页面链接,
旧字段 AppKey/AppSecret/robotCode/群会话 ID 零残留;预览内联渲染出正文
风险与回退
- 钉钉侧失败只会记 lastState.lastError 并在页面展示,不影响页面取数
- 回退:删除 index.js 里的 startWarehouseLogisticsExceptionNotifyScheduler 注册即可停推送
|
2026-10-22 11:00:10 +08:00 |
|
|
|
117d59c9f0
|
fix: 每日进销存截图按业务日期归档并补充幂等/执行记录测试
定时任务在凌晨 01:00 推送的是「昨日」数据,但截图对象键原先直接取执行时刻的北京日期,
导致归档目录与通知里的业务日期不一致(daily-inventory/2026-09-26/... 装的是 09-25 的数据)。
现改为由定时任务显式传入业务日期,目录与文件名统一用业务日期、时间仍用执行时刻:
daily-inventory/2026-09-25/daily-inventory-20260925-010000.png
另补充验收要求 8 的测试:
· buildScreenshotNames 归档命名(含业务日期与执行日期不同的场景)
· markNotified / hasNotified 幂等:同业务日同用户只成功一次,跨日期互不影响
· appendRunRecord 保留执行时间、截图地址、通知对象与失败原因
|
2026-09-27 14:53:05 +08:00 |
|
|
|
3bfc48b8b3
|
Merge branch 'codex/daily-inventory-snapshot-0924' into codex/daily-inventory-notify-0924
冲突文件:backend/src/index.js
处理理由:采用已解决好与他人 PR #40/#41 冲突的分支 A 版本,再补回本分支的通知接口
require、/api/daily-inventory-notification 路由注册与调度器启动,双方行为均保留。
|
2026-09-26 12:18:11 +08:00 |
|
|
|
734b974f45
|
Merge branch 'main' into codex/daily-inventory-snapshot-0924(同步 PR #40/#41)
冲突文件:backend/src/index.js
处理理由:main 侧(他人 PR #40、#41)新增崔桥工厂仓客退三类路由 require 与注册、统一 404 与 JSON 错误处理中间件;
本分支仅新增每日进销存快照任务的 require 与 startDailyInventorySnapshotScheduler() 调用。
采用 main 版本文件并补回本分支两处改动,双方行为均保留。
|
2026-09-26 12:16:30 +08:00 |
|
|
|
b0f56b27f5
|
客退看板首仓改为崔桥工厂仓(数据源:崔桥工厂客退临时上架仓)
按 2026-09-25 业务口径,第一张子看板由「横林二仓客退数据监控」改为
「崔桥工厂仓客退数据监控」,取数仓位同步改为聚水潭「崔桥工厂客退临时上架仓」。
- 仓库配置:简尚-崔桥工厂仓 wms_co_id=15038426,客退位 customize_qty_1
- key 由 henglin2 改为 cuiqiao,同步改路由 / 侧边栏 / 路由映射 / 权限条目
- 旧路径 returns-inventory/henlin2* 保留为重定向,避免历史链接 404
- 核销看板(returnMonitorService)仍指向横林二仓,前端入口已下线,本次未动
副本取证:该仓客退位当前只有 2 编码 / 2 件(退货单有量:ERP 3115 条 +
奇门 1812 条),属「客退上架库存未同步进副本」,页面需靠导入功能补数据。
|
2026-09-25 14:16:11 +08:00 |
|
|
|
c4ea12e9ba
|
fix: 修正截图站点地址与通知正文链接,生产镜像补充 Chromium 与中文字体
- 截图默认站点改为生产主站 ck.yydd.ai(原默认值指向无关域名)
- 通知正文补充「页面地址」,便于在通知中心直接打开
- 服务身份增加 daily_inventory 页面权限声明
- Dockerfile 安装 Chromium 与 fonts-noto-cjk,否则容器内无法截图且中文显示为方块
|
2026-09-24 11:59:36 +08:00 |
|
|
|
56fba389e4
|
feat: 每日进销存增加定时截图通知
设置(仅管理员)
- 可配置是否启用、通知时间(默认 01:00 Asia/Shanghai)、多名通知用户
- 收件人在后端规范化:去空、去重、限长限量,配置持久化到 system_config
- 接口不返回通知中心密钥与对象存储密钥,只给是否已配置与脱敏预览
定时任务
- 单实例锁(MySQL GET_LOCK),按配置时间触发,命中后 30 分钟内失败最多补跑 3 次
- 服务端签发 15 分钟短时效 JWT 作为专用身份,令牌只写入浏览器 localStorage
- 等数据真正渲染完成(有数据行、无加载中、无错误提示)才截图,展开滚动容器后整页截图
- 对象键形如 daily-inventory/2026-09-25/daily-inventory-20260925-010000.png
- 截图上传成功后才逐用户发通知,单人失败不影响他人;正式推送按「业务日期+收件人」幂等
- 立即测试走同一链路但幂等键带随机数,不影响次日正式推送
- 每次执行记录时间、截图地址、通知对象、成功状态与失败原因
测试
- 覆盖收件人去重、通知时间校验、幂等键、业务日期与对象键、重试退避(17 项)
|
2026-09-24 11:22:51 +08:00 |
|
|
|
9dbe2793a5
|
feat: 每日进销存改为全部从数据库取数
- 期初数量改由本地快照表 daily_inventory_snapshot 提供(上一业务日期末),
每日 01:30 定时任务落库,接口侧缺失时补写兜底,逐日自动滚动
- 新增 dailyInventorySnapshotDb / dailyInventorySnapshotJob 与手动补跑脚本
- dailyInventoryBaseline 瘦身为纯仓库映射,去掉所有硬编码业务数值
- 12 个流水列因业务库缺单据表返回空值,前端灰底显示「—」
- 修复 qty 全为 0 的仓库期末显示 null 的缺陷
- 新增 docs/库存流水单据表需求.md 给 DBA
|
2026-09-24 11:20:30 +08:00 |
|
|
|
b3f4d1af64
|
feat: 客退数据监控五仓看板与本地运行稳定性加固
功能:
- 退货库存预警:横林二仓/苏北/睢宁/山东青岗集/河南洛宁 五张看板,
按各仓客退上架仓对应的自定义库存位取数(各仓位不同:横林/苏北/睢宁 c1,山东 c2)
- 支持导入聚水潭「箱及仓位库存」导出文件覆盖创建时间、件数、供应商
(副本只有仓库级数量,没有箱级维度,真实上架时间只能靠导入)
- 退货入库核销与每日库存监控:状态落本地系统库,含定时任务与差异清单
- 服务端导出(xlsx/csv),不受列表分页与展示上限约束
稳定性:
- 前端幂等请求在后端重启窗口内自动退避重连,不再直接抛 500
- 后端补齐统一 JSON 错误兜底与 /api JSON 404,异常不再返回 HTML
- 隧道 ssh 改为绝对路径解析并隐藏窗口,避免非交互式启动 ENOENT 与黑窗弹窗
- 业务库 DATETIME 按北京时间解析(useUTC: false),修复时间显示整体 +8 小时
合并:与上游「隧道断线自愈 + 配置负缓存」为同一问题的两份实现,
本分支采用上游方案(带 TTL 的负缓存 + 统一失效函数 + 单测)。
|
2026-09-23 11:32:16 +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 |
|
|
|
fe831c32fd
|
feat: MKH-BOM 补货预警排除在途加工单、缺货通知推送、导出功能
- 补货预警:接入加工单(链接服务器 bi_processing_work_orders),有未完成加工单则不预警,新增在途加工量列
- 新增每日 09:00 缺货/预警通知推送(cron + 统一通知中心 + 幂等键)
- 新增导出:商品清单 / 配件明细,XLSX / CSV,按当前筛选条件全量
- 配件仓位:新增 loadComponentLocations 批量加载器(导出/列表展开共用)
|
2026-09-17 10:01:13 +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 |
|
lunanting
|
d9ebbba61e
|
refactor: remove commerce monitoring feature suites
|
2026-09-12 18:49:37 +08:00 |
|
lunanting
|
ec8949cfbf
|
Initial public PDD edition without market, Claw, skills or platform switching
|
2026-09-12 11:51:44 +08:00 |
|