feat: 每日进销存增加定时截图通知 #33

Merged
youruo merged 4 commits from codex/daily-inventory-notify-0924 into main 2026-09-27 08:13:04 +08:00
Collaborator

目的与范围

  • 解决的问题:每日进销存数据需要每天早上自动推送给指定人员。本 PR 增加「定时截图通知」:按配置时间(默认每天 01:00,Asia/Shanghai)自动打开生产页面、等数据加载完成后整页截图、上传到对象存储,再用统一通知中心逐人推送(含数据日期、生成时间、图片地址、页面链接)。
  • 修改的模块/文件:
    • 后端:backend/src/services/dailyInventoryNotificationSettings.js(配置/幂等/执行记录,存 system_config)、backend/src/services/dailyInventoryScreenshot.js(Playwright 截图 + 上传)、backend/src/jobs/dailyInventoryNotificationJob.js(调度、单实例锁、重试退避、逐人通知)、backend/src/api/dailyInventoryNotification.js(管理员接口)、backend/src/index.js(注册路由与调度器)、backend/Dockerfile.production(安装 Chromium 与中文字体)、backend/test/dailyInventoryNotification.test.js(17 项单测)
    • 前端:frontend/src/pages/DailyInventory/index.jsx(管理员可见「通知设置」弹窗:启用开关、通知时间、收件人增删、立即测试)、frontend/src/api/dailyInventoryNotification.js、style.css
  • 是否使用 AI 及负责开发者:由 AI(WorkBuddy)在 youruo 的账号与独立工作目录完成,负责人 youruo。

同步与兼容性

  • 起始基线 SHA:db2362307d9e9f300e9f1a40f039a981876f8609
  • 最近同步的 main SHA:28cfb1b33069d91b203bd4e2d5b205d1ca1ed6dd(PR #40、#41 已合入,本分支已同步)
  • 待审核任务分支 SHA:3bfc48b8b36a22ab422a6566c1637fc7d5f1c42a
  • 并行 PR、共享接口、迁移/配置影响:依赖已合并的 PR #32(页面数据来源);复用已有 system_config 配置键,不新增表;后端镜像新增 Chromium 与 fonts-noto-cjk,首次构建时间变长;不改动统一通知中心与对象存储的既有接口。
  • 冲突及处理理由:合并分支 codex/daily-inventory-snapshot-0924 时 backend/src/index.js 冲突(同 PR #32 与 main 的冲突来源)。采用已解决冲突的分支 A 版本,再补回本分支的通知接口 require、/api/daily-inventory-notification 路由注册与调度器启动,双方行为均保留。
  • 如何确认保留了其他开发者的已有行为:相对分支 A 的 index.js 差异仅为本分支通知相关的 4 处新增;未修改客退、MKH、BOM、权限等他人模块。

权限与安全

  • 配置与「立即测试」接口强制 role === 'admin';后端再次校验并规范化收件人(trim、去空、去重、单人 50 字、最多 20 人)。
  • 对外接口只返回「是否已配置」与脱敏预览,从不返回通知中心 projectSecret、对象存储 secretAccessKey。
  • 截图使用服务端签发的 15 分钟短时效 JWT 写入浏览器 localStorage,令牌不出现在 URL、日志或响应中;整页截图,不含浏览器地址栏。
  • 上传成功拿到 HTTPS 地址后才发通知;幂等键 = 业务日期 + 收件人,测试推送带随机数且不写幂等记录。

验证

  • 实际执行的命令及结果:
    • node --test backend/test/dailyInventoryNotification.test.js → 17/17 通过(收件人规范化、时间校验、幂等键、对象键、重试退避、通知正文)。
    • npm --prefix backend run check → 365 项,364 通过,唯一失败为 resilientSecretStore.test.js 在 Windows 权限语义下的既有失败,与本改动无关。
    • npm --prefix frontend run check → lint 通过、21 项测试通过、build 成功,无���环 chunk 警告。
  • 未运行或失败的检查及原因:真实截图上传与通知中心推送需在部署后通过页面「立即测试」按钮验证(依赖生产 Playwright 浏览器与对象存储/通知中心配置)。
  • 人工验证路径:管理员登录 → 每日进销存 → 通知设置 → 填写收件人并保存 → 立即测试(应返回截图地址并收到一条通知)。

风险与回退

  • 已知风险:1) 生产镜像需下载 Chromium,首次构建时间增加(已确认服务器可访问 Playwright CDN 与 Debian 镜像源);2) 未配置对象存储或统一通知中心时任务记录原因并跳过,不会推送;3) 截图等待上限 3 分钟,页面异常时放弃本次推送。
  • 回退方式:revert 合并提交;或把 system_config 中 daily_inventory_notification_config 的 enabled 置为 false、设置环境变量 DAILY_INVENTORY_NOTIFICATION_ENABLED=false,无需回滚代码即可停止推送。已上传的截图对象保留在对象存储,可手工清理。
## 目的与范围 - 解决的问题:每日进销存数据需要每天早上自动推送给指定人员。本 PR 增加「定时截图通知」:按配置时间(默认每天 01:00,Asia/Shanghai)自动打开生产页面、等数据加载完成后整页截图、上传到对象存储,再用统一通知中心逐人推送(含数据日期、生成时间、图片地址、页面链接)。 - 修改的模块/文件: - 后端:backend/src/services/dailyInventoryNotificationSettings.js(配置/幂等/执行记录,存 system_config)、backend/src/services/dailyInventoryScreenshot.js(Playwright 截图 + 上传)、backend/src/jobs/dailyInventoryNotificationJob.js(调度、单实例锁、重试退避、逐人通知)、backend/src/api/dailyInventoryNotification.js(管理员接口)、backend/src/index.js(注册路由与调度器)、backend/Dockerfile.production(安装 Chromium 与中文字体)、backend/test/dailyInventoryNotification.test.js(17 项单测) - 前端:frontend/src/pages/DailyInventory/index.jsx(管理员可见「通知设置」弹窗:启用开关、通知时间、收件人增删、立即测试)、frontend/src/api/dailyInventoryNotification.js、style.css - 是否使用 AI 及负责开发者:由 AI(WorkBuddy)在 youruo 的账号与独立工作目录完成,负责人 youruo。 ## 同步与兼容性 - 起始基线 SHA:db2362307d9e9f300e9f1a40f039a981876f8609 - 最近同步的 main SHA:28cfb1b33069d91b203bd4e2d5b205d1ca1ed6dd(PR #40、#41 已合入,本分支已同步) - 待审核任务分支 SHA:3bfc48b8b36a22ab422a6566c1637fc7d5f1c42a - 并行 PR、共享接口、迁移/配置影响:依赖已合并的 PR #32(页面数据来源);复用已有 system_config 配置键,不新增表;后端镜像新增 Chromium 与 fonts-noto-cjk,首次构建时间变长;不改动统一通知中心与对象存储的既有接口。 - 冲突及处理理由:合并分支 codex/daily-inventory-snapshot-0924 时 backend/src/index.js 冲突(同 PR #32 与 main 的冲突来源)。采用已解决冲突的分支 A 版本,再补回本分支的通知接口 require、/api/daily-inventory-notification 路由注册与调度器启动,双方行为均保留。 - 如何确认保留了其他开发者的已有行为:相对分支 A 的 index.js 差异仅为本分支通知相关的 4 处新增;未修改客退、MKH、BOM、权限等他人模块。 ## 权限与安全 - 配置与「立即测试」接口强制 role === 'admin';后端再次校验并规范化收件人(trim、去空、去重、单人 50 字、最多 20 人)。 - 对外接口只返回「是否已配置」与脱敏预览,**从不返回**通知中心 projectSecret、对象存储 secretAccessKey。 - 截图使用服务端签发的 15 分钟短时效 JWT 写入浏览器 localStorage,令牌不出现在 URL、日志或响应中;整页截图,不含浏览器地址栏。 - 上传成功拿到 HTTPS 地址后才发通知;幂等键 = 业务日期 + 收件人,测试推送带随机数且不写幂等记录。 ## 验证 - 实际执行的命令及结果: - node --test backend/test/dailyInventoryNotification.test.js → 17/17 通过(收件人规范化、时间校验、幂等键、对象键、重试退避、通知正文)。 - npm --prefix backend run check → 365 项,364 通过,唯一失败为 resilientSecretStore.test.js 在 Windows 权限语义下的既有失败,与本改动无关。 - npm --prefix frontend run check → lint 通过、21 项测试通过、build 成功,无���环 chunk 警告。 - 未运行或失败的检查及原因:真实截图上传与通知中心推送需在部署后通过页面「立即测试」按钮验证(依赖生产 Playwright 浏览器与对象存储/通知中心配置)。 - 人工验证路径:管理员登录 → 每日进销存 → 通知设置 → 填写收件人并保存 → 立即测试(应返回截图地址并收到一条通知)。 ## 风险与回退 - 已知风险:1) 生产镜像需下载 Chromium,首次构建时间增加(已确认服务器可访问 Playwright CDN 与 Debian 镜像源);2) 未配置对象存储或统一通知中心时任务记录原因并跳过,不会推送;3) 截图等待上限 3 分钟,页面异常时放弃本次推送。 - 回退方式:revert 合并提交;或把 system_config 中 daily_inventory_notification_config 的 enabled 置为 false、设置环境变量 DAILY_INVENTORY_NOTIFICATION_ENABLED=false,无需回滚代码即可停止推送。已上传的截图对象保留在对象存储,可手工清理。
youruo added 6 commits 2026-09-24 12:10:18 +08:00
- 期初数量改由本地快照表 daily_inventory_snapshot 提供(上一业务日期末),
  每日 01:30 定时任务落库,接口侧缺失时补写兜底,逐日自动滚动
- 新增 dailyInventorySnapshotDb / dailyInventorySnapshotJob 与手动补跑脚本
- dailyInventoryBaseline 瘦身为纯仓库映射,去掉所有硬编码业务数值
- 12 个流水列因业务库缺单据表返回空值,前端灰底显示「—」
- 修复 qty 全为 0 的仓库期末显示 null 的缺陷
- 新增 docs/库存流水单据表需求.md 给 DBA
列出每日进销存 12 个流水列无法从业务库还原的具体原因、
缺失的 4 类单据表、以及已有采购/销售单据口径不一致的实测偏差,供 DBA 补齐。
设置(仅管理员)
- 可配置是否启用、通知时间(默认 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 项)
- 截图默认站点改为生产主站 ck.yydd.ai(原默认值指向无关域名)
- 通知正文补充「页面地址」,便于在通知中心直接打开
- 服务身份增加 daily_inventory 页面权限声明
- Dockerfile 安装 Chromium 与 fonts-noto-cjk,否则容器内无法截图且中文显示为方块
youruo added 2 commits 2026-09-27 08:10:09 +08:00
冲突文件:backend/src/index.js
处理理由:main 侧(他人 PR #40、#41)新增崔桥工厂仓客退三类路由 require 与注册、统一 404 与 JSON 错误处理中间件;
本分支仅新增每日进销存快照任务的 require 与 startDailyInventorySnapshotScheduler() 调用。
采用 main 版本文件并补回本分支两处改动,双方行为均保留。
冲突文件:backend/src/index.js
处理理由:采用已解决好与他人 PR #40/#41 冲突的分支 A 版本,再补回本分支的通知接口
require、/api/daily-inventory-notification 路由注册与调度器启动,双方行为均保留。
youruo merged commit daf3646470 into main 2026-09-27 08:13:04 +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#33
No description provided.