ForgeFlow-ERP/docs/superpowers/specs/2026-06-11-miniapp-operation-report-sync-design.md
2026-06-12 16:00:56 +08:00

94 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Miniapp Operation Report Sync Design
## Goal
解决“生产执行 · 工序报工”每次刷新都要等待十几秒的问题。页面刷新只负责查看小程序报工列表ERP 同步改成显式按钮触发;同步范围由系统固定为“从上次同步成功时间起自动补齐”,不允许用户手工选择同步时间,避免漏同步。
## Problem
当前前端进入页面或点击刷新时,请求 `/production/miniapp-operation-reports` 会带上 `sync_to_erp=true``limit=800`。后端接口默认也会执行同步逻辑对每条小程序报工逐条匹配生产台账或旧工单、工序、员工、ERP 报工记录,并更新累计值。数据库在远程 MySQL 上,逐条查询和写入会被网络往返延迟放大,所以一次刷新可能需要十几秒。
## Business Rules
- `刷新列表` 只读取小程序报工数据,使用页面日期筛选范围,不能创建或更新 ERP 报工。
- `同步到 ERP` 不使用页面日期筛选范围。
- 同步范围固定为“上次同步成功时间之后,到本次同步开始时间止”。
- 如果没有上次同步成功时间,首次同步从现有小程序报工数据中最早的记录开始。
- 同步成功后更新上次同步成功时间。
- 同步失败时不更新上次同步成功时间,下次点击同步继续从旧时间补齐。
- 同步按钮在同步过程中显示加载状态并禁用,防止用户连续点击造成重复请求。
- 同一条小程序报工重复同步必须幂等,不能重复累计 ERP 报工数量。
- 页面日期筛选只影响“看哪些数据”,绝不影响“同步哪些数据”。
## Backend Design
新增一个明确的同步接口:
```text
POST /production/miniapp-operation-reports/sync
```
该接口不接受用户传入的开始日期和结束日期。服务端读取系统配置中的上次同步成功时间,计算本次同步窗口:
```text
sync_from = 上次同步成功时间,如果不存在则为空
sync_to = 当前服务端时间
```
查询范围使用小程序报工的更新时间或创建时间,保证历史日期的补报、修改、驳回也能被纳入同步。接口循环调用现有 `_sync_miniapp_item_to_erp()`,复用当前 ERP 报工幂等差额逻辑。同步全部成功后,更新上次同步成功时间为 `sync_to`
同步状态存储复用 `sys_system_config`
```text
config_code: MINIAPP_OPERATION_REPORT_LAST_SYNCED_AT
config_name: 小程序报工上次同步成功时间
config_value: 2026-06-11 10:30:00
```
为了降低重复请求风险,同步接口在更新配置前对该配置行加数据库锁。前端禁用按钮解决正常用户重复点击,后端锁解决异常并发请求。
## Frontend Design
工序报工页面顶部保留日期筛选和刷新按钮,并新增同步区:
- `刷新列表`:请求 `/production/miniapp-operation-reports?sync_to_erp=false`,只读加载当前日期范围内的小程序报工。
- `同步到 ERP`:请求 `POST /production/miniapp-operation-reports/sync`,按钮进入 `同步中...` 状态并禁用。
- 同步完成后自动调用 `刷新列表`
- 页面显示上次同步成功时间。
- 成功提示展示本次同步范围和结果数量。
- 失败提示说明“同步失败,上次同步成功时间未更新,可稍后重试”。
## Response Shape
同步接口返回:
```json
{
"sync_from": "2026-06-01 10:00:00",
"sync_to": "2026-06-11 15:30:00",
"last_synced_at": "2026-06-11 15:30:00",
"total": 120,
"synced": 115,
"skipped": 5,
"failed": 0
}
```
`skipped` 表示小程序报工无法匹配有效生产台账、旧工单、有效工序,或没有有效数量。`failed` 初版只在单条同步被捕获为可恢复失败时使用;如果发生数据库级错误,接口直接失败并不更新同步时间。
## Error Handling
- 同步过程中出现数据库异常时,事务回滚,不更新 `MINIAPP_OPERATION_REPORT_LAST_SYNCED_AT`
- 如果没有需要同步的数据,接口返回 `total=0`,并仍可更新上次同步成功时间为本次 `sync_to`,表示系统已经确认这一段时间没有新变化。
- 如果小程序报工被驳回,沿用现有 `_sync_miniapp_item_to_erp()` 对已同步报工的解绑逻辑。
- 前端同步失败时解除按钮禁用,并展示错误提示。
## Verification
- 后端测试覆盖列表接口 `sync_to_erp=false` 时不写 ERP。
- 后端测试覆盖同步接口从上次同步成功时间自动补齐,且不接受前端筛选范围。
- 后端测试覆盖同步成功后更新上次同步成功时间,失败时不更新。
- 前端静态测试覆盖列表刷新传 `sync_to_erp=false`
- 前端静态测试覆盖同步按钮调用独立同步接口、同步中禁用、同步完成后刷新列表。
- 运行后端相关测试、前端静态脚本和前端构建。