94 lines
4.8 KiB
Markdown
94 lines
4.8 KiB
Markdown
# 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`。
|
||
- 前端静态测试覆盖同步按钮调用独立同步接口、同步中禁用、同步完成后刷新列表。
|
||
- 运行后端相关测试、前端静态脚本和前端构建。
|