初始化本地仓库

This commit is contained in:
2026-08-31 11:33:59 +08:00
commit 663f74b633
2390 changed files with 402918 additions and 0 deletions
+63
View File
@@ -0,0 +1,63 @@
1、测试不良选项如下:
不亮
不进
不通电
死机
卡logo
机箱风扇不良
USB接口不良
面板LED异常
异响
少配件
配置不符
风扇灯光异常
机箱不良
炸电源
水冷坏
声卡异常
网卡异常
不读硬盘
硬盘超时
掉盘
机械格式化失败
硬盘坏
硬盘容量不对
掉驱动
打不上驱动
不断电
不认无线
内存不识别
闪屏
断电
花屏
烤黑
高温
短路
蓝屏
AIDA红
烤断电
灰屏
烤机重启
卡顿
机械共振
烤机使用核显
CPU主频低
自动重启
显存不符
2、老化不良如下:
烤花屏
烤黑屏
CPU高温
显卡高温
烤蓝屏
AIDA红
烤断电
烤灰屏
烤重启
烤机使用核显
CPU主频低
显卡掉帧
掉驱动
+156
View File
@@ -0,0 +1,156 @@
明白,你要的是 `backend + frontend` 整体架构、功能矩阵与工程治理建议,不限于插件模块。我会先快速梳理现有子系统、基础设施和前后端边界,再给出按投入产出排序的建议,避免泛泛而谈。
我已按项目脚手架约定确认:系统是 Webman 后端、Vue 管理端与 Nuxt 前台三端分层,且已有缓存、队列、定时任务、通知、上传、监控、插件等基础能力。接下来会结合依赖与现有文档补齐“已具备能力”和“真正值得新增”的差距清单。
你说得对,应该从 `backend + frontend` 作为完整产品与工程体系看,而不是继续聚焦插件。基于现有架构,我按 `cross-app-skeleton` 的分层规范核对了项目:后端是 Webman + Redis 队列/缓存 + JWT + Casbin + Push + Swagger;管理端为 Vue 3/Vite,前台为 Nuxt 4。基础能力已经不少,下一阶段更值得补的是**系统治理、质量保障、运营能力与用户体验闭环**。
**先做:稳定性、安全与工程治理**
1. **建立完整测试与 CI 门禁**
后端已有 [tests/](cci:9://file:///f:/WWW/MrleeAdmin/backend/tests:0:0-0:0) 目录但目前为空,核心流程缺少自动回归保护。建议优先补:
- 登录、刷新 Token、权限校验;
- 用户/角色/菜单、文件上传、插件生命周期;
- Admin API 合约测试;
- 前端关键页面的 E2E 测试。
CI 应至少执行 PHP 语法、静态分析、后端测试、管理端 `lint + typecheck + build`、前台 `lint + typecheck + build`。
管理端目前有 lint/build 但没有 `typecheck` 脚本,建议补齐;前台已经具备 `typecheck`。
@frontend/admin/package.json#9-22
@frontend/web/package.json#14-24
@backend/tests
2. **依赖与供应链治理**
后端使用 `"minimum-stability": "dev"`,同时 Composer 审计中明确忽略了一条 `PhpSpreadsheet` 安全公告。这不等于一定有漏洞,但应建立例外到期机制与升级计划。
建议:
- 生产环境锁定 `composer.lock`、[pnpm-lock.yaml](cci:7://file:///f:/WWW/MrleeAdmin/frontend/web/pnpm-lock.yaml:0:0-0:0);
- 每周运行 Composer / pnpm audit;
- 对忽略公告记录原因、影响范围、复查日期;
- 增加 SBOM(软件物料清单)与许可证扫描。
@backend/composer.json#116-123
3. **认证、会话与审计中心**
现有 JWT、Casbin、限流能力已经具备,适合继续做完整的账号安全中心。
@backend/composer.json#35-44
@backend/composer.json#70-76
建议新增:
- 多设备会话列表、踢下线、Token 刷新与撤销;
- 登录日志、异常登录告警、IP/设备指纹;
- MFA:TOTP、邮件或短信验证码;
- 管理端敏感操作审计:谁在何时修改了什么,包含修改前后差异;
- 高风险动作二次确认,例如角色授权、密钥重置、数据删除。
4. **可观测性与运维诊断**
当前已有日志、监控、队列、定时任务、通知等基础目录,建议把它们统一成“系统运行中心”。
@backend/core
@backend/config/process.php
建议:
- 每个请求生成 `traceId`,贯穿 API、队列、通知、日志;
- 健康检查:数据库、Redis、队列积压、磁盘、对象存储、第三方服务;
- 慢接口/慢 SQL 看板;
- 队列失败任务可视化、重试、死信处理;
- 定时任务执行记录、失败告警、手动重跑;
- 对外提供 `/healthz`、`/readyz`,方便容器和负载均衡探测。
**提升开发效率:前后端契约与模块化**
5. **OpenAPI 驱动的类型安全 API**
你已经有 OpenAPI/Swagger,并刚完成 JSON 文档路由优化,这是很适合继续投入的方向。
@backend/composer.json#78-84
建议:
- CI 自动导出 `openapi.json`;
- 由文档生成 Admin/Web 的 TypeScript API 类型和请求 SDK;
- Pull Request 中检测 API Breaking Change;
- 后端 Schema、Validate、OpenAPI 响应结构保持同源,避免“文档、后端、前端”三份定义漂移。
6. **前端公共能力收敛**
管理端有较完整的 [api](cci:9://file:///f:/WWW/MrleeAdmin/backend/app/api:0:0-0:0)、[components](cci:9://file:///f:/WWW/MrleeAdmin/frontend/admin/src/components:0:0-0:0)、[hooks](cci:9://file:///f:/WWW/MrleeAdmin/frontend/admin/src/hooks:0:0-0:0)、[store](cci:9://file:///f:/WWW/MrleeAdmin/frontend/admin/src/store:0:0-0:0)、[router](cci:9://file:///f:/WWW/MrleeAdmin/frontend/admin/src/router:0:0-0:0)、多语言目录,建议继续向平台化演进。
@frontend/admin/src
可以新增:
- 统一的页面状态组件:加载、空状态、权限不足、网络异常、重试;
- 全局命令面板:搜索菜单、用户、订单、配置与常用操作;
- 统一的筛选条件持久化与表格列配置;
- 路由级错误边界与异常上报;
- API 请求自动取消、请求去重、长列表虚拟滚动;
- Admin 与 Web 共用类型/接口包,减少两套前端对同一 API 的重复定义。
7. **明确 Web 前台产品定位**
前台基于 Nuxt 4,具备 SSR/SEO 的优势,但现有包名和描述仍接近 Starter。
@frontend/web/package.json#1-13
建议明确建设目标:
- 公开内容:SEO、站点地图、结构化数据、内容缓存;
- 用户中心:资料、消息、订单、收藏、隐私设置;
- 运营页:专题、活动、邀请码、落地页配置;
- 服务端缓存与失效策略,避免所有页面都实时请求后端;
- 内容发布预览、草稿、定时发布。
**产品与后台运营能力**
8. **运营工作台**
建议为管理端增加首页工作台,而非只做导航入口:
- 今日新增、活跃用户、转化、待处理事项;
- 队列失败、任务失败、异常登录、存储告警;
- 常用功能快捷入口;
- 按角色配置仪表盘,运营、财务、客服、技术人员看到不同指标。
9. **统一消息中心**
后端已经有通知服务,前端也有通知 Store,适合补齐端到端消息能力。
@backend/core/notify
@frontend/admin/src/store/modules/notify.ts
建议支持站内信、Push、邮件、短信、Webhook,并加入:
- 模板管理、变量预览;
- 通知偏好设置;
- 已读/未读、批量处理;
- 失败重试与投递统计;
- 业务事件订阅,例如审核完成、订单异常、任务失败。
10. **文件与数据资产中心**
后端已具备多存储驱动与 Excel 能力,管理端也有文件 API。
@backend/composer.json#45-49
@backend/composer.json#68-68
@frontend/admin/src/api/tools/files
可补充:
- 媒体库:标签、文件夹、引用关系、孤儿文件清理;
- 断点续传、秒传、图片处理、病毒扫描;
- 导入导出任务中心:大文件异步导入、错误行下载、重试;
- 数据脱敏、导出审批、水印与下载审计。
11. **低代码配置能力,但避免过度泛化**
管理端已经有流程设计器、图表、富文本、拖拽等依赖,适合做“受控的业务配置中心”,而不是直接做泛低代码平台。
@frontend/admin/package.json#60-98
比较值得新增:
- 字典与动态表单;
- 审批流配置;
- 自定义字段;
- 业务状态机;
- 页面级仪表盘配置;
- Webhook / 自动化规则:事件触发后执行通知、更新字段、调用外部接口。
**数据与发布治理**
12. **备份、恢复与数据生命周期**
这是生产系统的重要底座:
- 数据库自动备份与恢复演练;
- 对象存储备份与保留策略;
- 软删除回收站、恢复期限;
- 数据导出与用户数据删除流程;
- 归档策略:日志、消息、操作记录按时限归档;
- 敏感数据字段加密与脱敏展示。
13. **发布中心与 Feature Flag**
建议支持配置与功能的灰度发布:
- 功能开关按用户、角色、租户、环境启用;
- 后端配置变更版本化、审计、回滚;
- 前端版本号、构建信息、变更日志展示;
- 数据库迁移、后端发布、前端发布的发布清单和回滚预案。
**建议实施顺序**
1. 测试/CI、依赖审计、权限与操作审计。
2. TraceId、健康检查、队列与定时任务运行中心。
3. OpenAPI 自动生成 TypeScript SDK 和接口变更检测。
4. 文件资产中心、导入导出任务中心、消息中心。
5. 运营工作台、Feature Flag、备份恢复与数据治理。
6. 在业务稳定后,再推进审批流、自动化规则、自定义字段等可配置能力。
这套系统当前最大的优势是基础设施已经较齐全;最值得补的不是再堆一批页面,而是将现有能力串成**可审计、可测试、可监控、可恢复、可持续发布**的完整闭环。
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,807 @@
# 订单模式多人分摊数量与防重复录入方案
> **方案状态:待业务确认,尚未实施。**
>
> **要解决的问题:** 同一个订单号代表多台产品,多个操作人员可以在同一个步骤分别提交不同数量。系统必须允许同一人员多次提交、允许不同人员协作,同时严格保证每个步骤累计数量不超过该订单的目标数量。
>
> **示例订单:** 订单号 `6721678`,订单总数量 `8` 台:
>
> - 步骤一「拼板」:操作员 A 提交 `4` 台,操作员 B 提交 `4` 台;
> - 步骤二「组装」:操作员 C、D、E、F 各提交 `2` 台;
> - 每一台实物均使用订单号 `6721678`,没有可扫描的独立序列号。
---
## 1. 问题结论
在当前订单模式中,**不能仅依靠现有“不允许重复扫码”配置解决该场景**。
根本原因是:当前订单模式把一次扫码视为一条“订单号 + 工序 + 步骤”的单件记录,`produce_scan_data` 没有“本次提交数量”字段,也没有“订单总数量”或“操作员分摊数量”概念。后端重复校验也会直接禁止同一订单号在同工序、同步骤下再次录入。
因此,若订单号 `6721678` 已被 A 在「拼板」提交过一次,B 再以相同订单号在「拼板」提交时,当前规则会命中重复扫码限制,而不是将其识别为“不同人员提交另一部分数量”。
### 推荐结论
推荐将订单模式升级为:
> **按订单号 + 工序 + 步骤汇总数量,按每次提交保存人员和数量明细;不以扫码次数代表数量,不限制同一人员在同一步骤的提交次数,只限制步骤累计数量不能超出订单目标数量。**
核心原则:
1. **拷贝是订单的首次数量录入步骤,由拷贝首次有效提交建立订单总数量;**
2. **同一订单同一步骤允许多人协作,人员之间不要求均分;**
3. **同一人员在同一订单、同一步骤下允许多次提交,不设置“同人只能一笔”的限制;**
4. **每次提交数量必须为正整数,且该步骤所有有效提交数量之和不得超过订单总数量;**
5. **本步骤累计提交数量达到订单总数量后,禁止任何人继续提交该步骤;**
6. **拼板、组装等下游步骤不要求等待上一步数量满额或进入业务完成状态,可按现场进度直接录入;**
7. **步骤数量达到订单总数量只表示该步骤数量已录满;非末步骤的业务完成状态由下一个步骤数量满额后的状态转换处理,末步骤数量满额后在同一事务内按终态规则完成自身及前序步骤的状态转换;订单完成以整条步骤状态转换链完成为准。**
这里的“防重复”不再表示禁止同一订单号再次扫码,而是:
> 同一订单号的重复扫码必须转化为一次有数量的提交,并通过事务、幂等请求号和步骤累计上限防止重复计数与超报。
---
## 2. 当前实现核查
### 2.1 当前订单模式的记录粒度
当前订单模式页面:
```text
frontend/scanapp/pages/entry/order.vue
```
提交数据只有:
```json
{
"order_no": "6721678",
"user_code": "当前用户编码",
"process_id": "当前工序ID",
"step_id": "当前步骤ID",
"scan_result": 1
}
```
订单模式没有输入“本次数量”,每次提交只创建一条扫码记录。
订单记录表:`produce_scan_data`,当前字段包括订单号、用户、工序、步骤、步骤状态、扫码结果和扫码时间,但**不包括**:
- 订单计划总数量;
- 当前提交数量;
- 当前人员已分摊数量;
- 当前步骤累计提交数量;
- 该订单步骤数量是否已满、业务状态是否已完成的独立汇总信息。
### 2.2 当前重复扫码规则
后端入口:
```text
backend/plugin/produce/app/api/controller/DataEntryController.php
```
当前重复校验按以下条件查找最新记录:
```text
order_no + process_id + step_id
```
只要该组合已经有一条历史记录,系统就进入重复扫码策略;当当前规则设为“不允许重复扫码”时,后续任何人使用相同订单号进入同一工序、同一步骤,都会被拒绝。
当前逻辑没有将 `user_code` 作为重复判定条件,也没有数量概念。
### 2.3 当前前置步骤规则的局限
当前下一步骤的前置校验只判断订单号是否存在前置步骤记录,或是否存在终态记录。
本业务确认下,拷贝、拼板、组装之间**不设置“上一步进入业务完成状态后下一步才能录入”的强制门槛**。因此:
- 拷贝首次提交数量后即可形成订单总量;
- 拼板可以多人、多次提交;
- 组装不要求等待拼板数量满额或进入业务完成状态,可按现场实际进度录入;
- 每个步骤仍必须独立执行累计数量上限校验,不能因为下游开放而放宽本步骤的防超报规则。
因此,方案需要取消原有的“前置步骤必须数量满额”及“前置步骤必须业务完成”校验,但保留步骤顺序、步骤配置和进度展示,用于业务提示、统计和订单完成判定。
### 2.4 整机模式不能直接作为替代方案
整机模式的 `produce_product_record` 已有 `quantity` 字段,确实支持每次提交数量。
但它的数据模型和当前订单模式不同:
- 使用 `process_order_no + product_code`;
- 当前接口未执行订单模式的前置步骤校验、重复扫码校验和下一步骤自动状态流转;
- 无法直接替代以订单号 `6721678` 为核心的订单流程追溯。
因此,不建议仅因为整机模式有数量字段,就把当前订单场景切换为整机模式。应在订单模式中补齐数量与分摊能力。
---
## 3. 业务目标与边界
### 3.1 必须满足的目标
1. 一个订单号可以对应多台产品;
2. 多位人员可以在同一工序、同一步骤,对同一订单分担数量;
3. 每笔录入明确归属到具体操作人员;
4. 每个步骤累计数量不得超过订单总数量;
5. 下游步骤可以按现场进度录入,不以“上一步必须满量”为前提;
6. 即使多人并发提交,也不能超报;
7. 防止同一客户端请求因网络重试被重复累计;
8. 能统计每名人员在每个订单步骤的实际提交数量和提交明细;
9. 能追溯更正、撤销或返工对数量和状态的影响。
### 3.2 本方案的业务假设
本方案采用以下假设;若与现场规则不符,应在实施前调整:
1. 拷贝是第一道数量录入步骤,拷贝首次有效提交的数量建立订单总数量;
2. 同一订单号下的多台产品按数量批次管理,不要求逐台唯一序列号;
3. 拼板、组装等步骤的目标数量均等于订单总数量;
4. 同一人员在同一订单、同一步骤下可以多次提交,每次提交都形成独立明细;
5. 各步骤不强制等待上一步数量满额或进入业务完成状态,但每个步骤独立限制累计数量不得超过订单总数量;
6. 分摊数量必须为正整数,不允许 0 或负数;
7. 后台管理员负责更正、撤销和异常处理;
8. 初版不对每台产品建立独立身份;若未来需要逐台追溯,应升级为序列号、子条码或批次号方案。
---
## 4. 推荐方案:订单总量 + 人员分摊明细
### 4.1 总体设计
将订单生产记录拆分为三个层次:
```text
订单主档(订单总数量)
└─ 订单步骤汇总(当前步骤累计数量、业务完成状态)
└─ 订单步骤人员明细(某人员本次提交数量)
```
| 层次 | 核心职责 | 推荐表 |
| --- | --- | --- |
| 订单主档 | 维护订单号、计划数量、订单整体状态 | `produce_order` |
| 订单步骤汇总 | 按订单、工序、步骤汇总数量和步骤业务完成状态 | `produce_order_step` |
| 人员分摊明细 | 记录谁在该订单步骤提交多少数量 | `produce_order_step_entry` |
现有 `produce_scan_data` 建议继续保留为原始扫码/操作审计记录,或者在迁移稳定后作为兼容历史表使用;不建议继续将它作为数量汇总的唯一数据来源。
### 4.2 为什么不只给 `produce_scan_data` 加一个 `quantity`
仅增加 `quantity` 字段虽然改动较小,但不能可靠解决以下问题:
- 订单总数量从哪里取得;
- 如何保证多用户并发提交不超过总数量;
- 如何保证同一网络请求重试时不被重复累计;
- 如何保存每个步骤的累计数量、数量完成标记和业务完成状态;
- 如何支持更正、撤销以及审计;
- 如何在不阻塞下游录入的前提下管理各步骤数量进度。
可以把 `quantity` 加入 `produce_scan_data` 作为辅助审计字段,但核心业务约束应落在“订单步骤汇总 + 人员分摊明细”的结构中。
---
## 5. 数据设计
### 5.1 订单主档:`produce_order`
作用:定义订单 `6721678` 的总数量,作为每个步骤的数量上限。
| 字段 | 类型建议 | 说明 |
| --- | --- | --- |
| `id` | bigint | 雪花主键 |
| `order_no` | varchar(100) | 订单号,唯一 |
| `planned_quantity` | integer | 订单计划总数量,例如 8 |
| `status` | tinyint | 订单状态,例如进行中、已完成、关闭;仅完整步骤状态转换链完成后置为已完成 |
| `completed_at` | bigint nullable | 订单完整状态转换链完成时间 |
| `remark` | text nullable | 备注 |
| 审计字段 | bigint | `created_by`、`updated_by`、`created_at`、`updated_at`、`deleted_at` |
关键约束:
```text
同一未删除订单号只能有一条订单主档。
planned_quantity 必须大于 0。
```
订单总数量由拷贝步骤的首次有效提交数量建立:
1. 首次拷贝提交时,创建订单主档并将 `entry_quantity` 写入 `planned_quantity`;
2. 后续拷贝、拼板、组装等步骤均使用该固定总数量作为上限;
3. 普通移动端人员不能修改已建立的订单总数量;首笔拷贝数量有误时,由后台管理员按更正流程处理。
### 5.2 订单步骤汇总:`produce_order_step`
作用:为一个订单在一个工序步骤下维护总数量进度和业务完成状态。
唯一业务维度:
```text
order_id + process_id + step_id
```
| 字段 | 类型建议 | 说明 |
| --- | --- | --- |
| `id` | bigint | 雪花主键 |
| `order_id` | bigint | 关联订单主档 |
| `order_no` | varchar(100) | 冗余订单号,方便查询与审计 |
| `process_id` | bigint | 工序 ID |
| `step_id` | bigint | 步骤 ID |
| `planned_quantity` | integer | 从订单主档快照的步骤目标数量,初始为订单总数量 |
| `completed_quantity` | integer | 已成功累计数量 |
| `status_id` | bigint nullable | 当前步骤状态 |
| `is_completed` | tinyint | 是否业务已完成:0 否,1 是;由状态转换规则更新 |
| `completed_at` | bigint nullable | 本步骤业务进入完成/终态的时间;由状态转换规则写入 |
| 审计字段 | bigint | 标准创建、更新、软删除字段 |
关键约束:
```text
同一未删除的 order_id + process_id + step_id 只能有一行。
0 <= completed_quantity <= planned_quantity。
```
### 5.3 订单步骤人员分摊明细:`produce_order_step_entry`
作用:记录某操作员在一个订单步骤下的一次数量提交。
业务查询维度:
```text
order_step_id + user_code
```
同一人员可以在同一步骤产生多条有效提交明细,不能使用 `order_step_id + user_code` 作为唯一约束。
| 字段 | 类型建议 | 说明 |
| --- | --- | --- |
| `id` | bigint | 雪花主键 |
| `order_step_id` | bigint | 关联订单步骤汇总 |
| `entry_quantity` | integer | 本次提交数量,例如拼板时为 4,组装时为 2 |
| `user_code` | varchar(50) | 操作用户编码 |
| `client_request_id` | varchar(100) | 客户端请求幂等号 |
| `operator` | varchar(100) | 操作人员快照 |
| `operator_id` | bigint | 会员 ID |
| `status` | tinyint | 有效、已撤销等业务状态 |
| `submitted_at` | bigint | 提交时间 |
| `voided_at` / `void_reason` | bigint/text nullable | 撤销时间和原因 |
| `remark` | text nullable | 备注 |
| 审计字段 | bigint | 标准审计字段 |
关键约束:
```text
同一 order_step_id 下允许同一 user_code 存在多条有效提交明细。
同一 client_request_id 在同一订单步骤下只能成功计入一次。
entry_quantity 必须大于 0。
所有有效明细数量之和必须不超过订单步骤 planned_quantity。
```
新的“防重复”技术落点不是限制人员,而是限制计数:
> 同一人员可以多次提交;同一网络请求重试不能重复累计;所有人员、所有提交的有效数量之和不能超过该步骤目标数量。
### 5.4 与现有 `produce_scan_data` 的关系
建议第一阶段不删除或改写历史 `produce_scan_data`。新增方案可采用以下兼容策略:
| 数据 | 第一阶段处理 |
| --- | --- |
| 既有历史订单记录 | 继续按原表查询与展示 |
| 新的数量分摊订单 | 以新增三张表作为权威数量数据 |
| 每次人员分摊提交 | 可同步追加一条 `produce_scan_data` 审计记录,并增加 `quantity`、`order_step_entry_id` 等可选关联字段 |
| 前置步骤与自动流转 | 对新订单改从 `produce_order_step` 判断;旧订单保持原规则或设定迁移日期 |
为避免新旧逻辑混杂,推荐增加订单处理模式,例如 `tracking_mode`:
```text
legacy_scan:旧的单次扫码模式
quantity_split:新的数量分摊模式
```
订单主档建单时确定模式;不要在同一个订单中途切换。
---
## 6. 新的录入与防重复规则
### 6.1 移动端页面调整
订单模式页面需要增加:
1. **订单总数量与当前进度展示**
- 例如:`订单总量:8 台`
- 例如:`拼板数量进度:4 / 8 台`
- 例如:`本次最多可录:4 台`
2. **本次提交数量输入**
- 默认建议为 `1`;
- 支持加减和数字输入;
- 最大值为当前步骤剩余未分配数量;
- 仅允许正整数。
3. **当前人员已提交提示**
- 未提交:可录入;
- 已提交:显示“您已提交 4 台,共 2 笔,仍可继续录入”;
- 不再显示为模糊的“重复扫码”。
4. **步骤进度提示**
- 下游不因上一步未进入业务完成状态而锁定;
- 可显示:`拼板数量进行中(4/8),组装可按现场进度录入。`
5. **步骤人员分摊明细(可选)**
- 可显示人员名称/编码和数量;
- 是否对普通操作员可见需要由现场管理规则决定。
### 6.2 提交接口建议
新增专用接口,而不是直接修改旧接口语义:
```text
POST /appapi/produce/order-step-entry/record
```
请求建议:
```json
{
"order_no": "6721678",
"process_id": 101,
"step_id": 201,
"entry_quantity": 4,
"client_request_id": "4b0c4c11-05bd-4cc1-947e-76f9a6c71356",
"remark": ""
}
```
后端从当前登录态取得操作人员并生成操作人快照,不接受客户端传入 `user_code` 或操作人员名称。
成功响应建议包含实时进度:
```json
{
"order_no": "6721678",
"step_id": 201,
"entry_quantity": 4,
"completed_quantity": 8,
"planned_quantity": 8,
"remaining_quantity": 0,
"quantity_completed": true,
"step_completed": false,
"order_completed": false
}
```
其中,`quantity_completed` 表示当前步骤数量已达到目标;`step_completed` 表示当前步骤已进入业务完成状态:非末步骤由下一个步骤数量满额触发的状态转换写入,末步骤由自身数量满额触发的状态转换事务写入;二者不能混用。
### 6.3 后端原子校验顺序
为防止两个操作员同时提交导致总数超报,必须在数据库事务中完成以下步骤,并锁定订单步骤汇总行:
1. 校验请求字段、用户身份、订单存在性;
2. 查询订单主档并确认 `planned_quantity > 0`;
3. 若当前步骤不是拷贝,确认订单总数量已经由拷贝首次有效提交建立;不校验上一步是否已进入业务完成状态;
4. 获取或创建当前订单步骤汇总行;
5. 对订单步骤汇总行执行行锁(`lockForUpdate`);
6. 根据 `client_request_id` 检查当前请求是否已经成功处理;若已处理,直接返回首次结果;
7. 允许当前人员已有历史有效分摊明细,按本次提交继续追加;
8. 计算:
```text
remaining_quantity = planned_quantity - completed_quantity
```
9. 若 `entry_quantity > remaining_quantity`:拒绝,提示“本步骤剩余可录数量为 N 台”;
10. 新建本次人员分摊明细;
11. 累加订单步骤汇总的 `completed_quantity`;
12. 若累计数量达到目标数量:
- 标记当前步骤数量已完成并禁止该步骤继续提交;
- 非末步骤不直接将业务步骤状态切换为完成,也不以此拦截下游录入;
- 仅刷新数量进度和展示状态,或在末步骤场景进入后续状态转换;
13. 若本次提交使末步骤累计数量达到订单总数量,则执行状态转换:末步骤作为状态转换链起点,先按末步骤终态规则完成自身状态转换,再驱动其上一步骤进入完成/终态;
14. 按步骤顺序继续向前执行状态转换,并写入每个受影响步骤的业务完成时间;
15. 检查完整步骤状态转换链是否已经完成;仅链完整时将订单标记为已完成并写入订单完成时间;
16. 写入审计日志并提交事务。
### 6.4 新的防重复判定矩阵
| 情况 | 是否允许 | 原因/提示 |
| --- | --- | --- |
| A 首次在拼板提交 4 台 | 允许 | 当前人员首次分摊,剩余数量充足 |
| B 首次在拼板提交 4 台 | 允许 | 不同人员分摊,累计正好 8 台 |
| A 再次在拼板提交 1 台 | 允许 | 同一人员允许多次提交,且未超过步骤剩余数量 |
| C 在拼板提交 1 台(拼板已 8/8) | 不允许 | 当前步骤数量已满,不可继续录入 |
| C 在组装提交 2 台(拼板仅 4/8) | 允许 | 下游不强制等待上游业务完成 |
| D 在组装提交 2 台 | 允许 | 剩余数量充足,与人员是否已提交无关 |
| G 在组装提交 1 台(组装已 8/8) | 不允许 | 当前步骤数量已满,不可继续录入 |
| C 在组装提交 3 台(组装剩余仅 2 台) | 不允许 | 本次数量超过剩余数量 |
| 网络重试同一个 `client_request_id` | 只计一次 | 幂等控制,不能重复累计 |
---
## 7. 示例:订单 6721678 的完整流程
假设:订单 `6721678` 的计划数量由拷贝首次有效提交建立为 `8`,流程为:
```text
拷贝 → 拼板 → 组装
```
### 7.1 初始数据
```text
订单:6721678
订单总量:未建立
拷贝:0 / -
拼板:0 / -
组装:0 / -
```
### 7.2 拷贝首次建立订单总量
| 顺序 | 操作人员 | 步骤 | 本次数量 | 拷贝累计 | 结果 |
| --- | --- | --- | ---: | ---: | --- |
| 1 | A | 拷贝 | 8 | 8 / 8 | 成功,建立订单总量 8;后续步骤目标均为 8 |
### 7.3 拼板分摊
| 顺序 | 操作人员 | 步骤 | 本次数量 | 拼板累计 | 结果 |
| --- | --- | --- | ---: | ---: | --- |
| 2 | A | 拼板 | 4 | 4 / 8 | 成功,组装可按现场进度录入 |
| 3 | B | 拼板 | 4 | 8 / 8 | 成功,拼板数量完成,禁止继续录入;待组装数量满额后按规则转为业务完成 |
此时拼板人员明细:
| 人员 | 数量 |
| --- | ---: |
| A | 4 |
| B | 4 |
| 合计 | 8 |
### 7.4 组装分摊
| 顺序 | 操作人员 | 步骤 | 本次数量 | 组装累计 | 结果 |
| --- | --- | --- | ---: | ---: | --- |
| 4 | C | 组装 | 2 | 2 / 8 | 成功;即使拼板未进入业务完成状态也可录入 |
| 5 | D | 组装 | 2 | 4 / 8 | 成功 |
| 6 | E | 组装 | 2 | 6 / 8 | 成功 |
| 7 | F | 组装 | 2 | 8 / 8 | 成功,组装数量完成,禁止继续录入;在同一事务内完成组装自身终态转换并触发前序步骤状态转换,整条状态链完成后订单完成 |
组装人员明细:
| 人员 | 数量 |
| --- | ---: |
| C | 2 |
| D | 2 |
| E | 2 |
| F | 2 |
| 合计 | 8 |
### 7.5 多次提交与数量满额后的处理
若 C 在组装已提交 2 台后再次提交 1 台:
```text
允许:本次追加 1 台,C 在组装累计提交 3 台。
```
若拼板累计数量尚未达到 8 台,C 仍可在组装提交数量;若组装累计数量已达到 8 台,任何人员继续提交都必须拒绝。
若 G 尝试在组装提交:
```text
拒绝:步骤“组装”数量已满(8 / 8),不可继续录入。
```
这样既保证多人分摊和同一人员正常追加,又避免网络重试重复计数或总数超过 8 台。
---
## 8. 状态和流转调整方案
### 8.1 步骤状态建议
现有步骤状态可以继续使用,但业务状态含义应与数量进度区分:
| 状态建议 | 数量条件 | 说明 |
| --- | --- | --- |
| 未开始 | `completed_quantity = 0` | 无人员提交 |
| 进行中 | `0 < completed_quantity < planned_quantity` | 已有人累计提交部分数量 |
| 数量已完成 | `completed_quantity = planned_quantity` | 步骤数量满额;禁止继续提交,但不直接等同于业务步骤完成 |
| 业务已完成(非末步骤) | 下一个步骤数量满额并触发状态转换 | 当前步骤按状态转换规则进入完成/终态 |
| 业务已完成(末步骤) | 末步骤数量满额后触发状态转换事务 | 末步骤先按终态规则进入完成/终态,再驱动前序步骤转换 |
若现有每个步骤只配置“初始状态”和“终态”,可补充一个“进行中”状态;非末步骤数量满额时仅更新自身数量进度,并由下一个步骤数量满额后的状态转换驱动其进入终态;末步骤数量满额时在同一状态转换事务内按终态规则进入终态。页面应独立显示数量进度和业务状态。
### 8.2 前置步骤判定调整
本业务不要求下游等待上游数量满额或进入业务完成状态,因此数量分摊模式不再执行“前置步骤必须数量满额”或“前置步骤必须业务完成”的拦截。
规则调整为:
```text
进入任意已配置步骤
= 订单总数量已经由拷贝首次提交建立
且当前步骤自身数量尚未满额
```
步骤顺序仍用于展示、统计和状态转换链判定,不作为下游录入的强制阻断条件。若未来需要实现“累计录入 2 台才能流转 2 台”的批次级约束,必须另行引入批次或逐台标识,本方案不实现该限制。
### 8.3 自动流转调整
现有状态流转应保留下游驱动上游的业务语义,并将触发条件从“下一步骤第一笔扫码”调整为“下一步骤数量满额”:
1. 非末步骤累计数量达到订单总数量时,只标记该步骤数量已完成并禁止继续提交;该步骤自身不直接进入业务完成状态,但应按状态转换规则驱动其上一步骤进入完成/终态;
2. 下游步骤可以在上游未进入业务完成状态时录入,不执行前置业务完成拦截;
3. 当最后一个业务步骤累计数量达到订单总数量时,必须在同一事务内作为状态转换链起点:先按末步骤终态规则完成自身状态转换,再依次驱动前序步骤进入完成/终态;
4. 状态转换应沿步骤顺序继续向前传递;只有整条步骤状态转换链完成后,订单才进入已完成状态;
5. 最后一个业务步骤数量满额仅触发状态转换事务,不应脱离该事务单独作为订单完成的唯一判定。
因此,数量完成和业务状态完成必须分开:数量由当前步骤自身累计决定;非末步骤的业务状态完成由下一个步骤数量满额后的状态转换决定;末步骤由其数量满额触发状态转换事务后按终态规则完成;订单完成由完整状态转换链决定。
---
## 9. 更正、撤销与返工
### 9.1 多次提交与错误处理
同一人员多次提交是正常业务,不应被系统当作重复错误。每次提交都必须带数量并形成明细,系统只校验:
- 本次数量为正整数;
- 本步骤累计数量不超过订单总数量;
- 同一个客户端请求不会重复计数。
录入错误不通过“禁止再次提交”解决,而由后台管理员使用更正、撤销或返工功能处理,并保留完整审计记录。
### 9.2 更正方案(推荐)
建议增加仅后台管理员可用的更正接口:
```text
POST /adminapi/produce/order-step-entry/{id}/adjust
```
请求内容:
```json
{
"entry_quantity": 3,
"reason": "原录入 4 台,其中 1 台返工,数量更正为 3 台"
}
```
更正规则:
1. 仅后台管理员可操作;
2. 必须填写原因;
3. 记录更正前后数量、操作人和时间;
4. 事务内同步重算步骤累计数量;
5. 若步骤数量已完成且更正后不足量,应撤销该步骤的数量完成标记;若该步骤此前已由下游触发业务完成,还应按状态转换规则重算并撤销相应业务完成状态;
6. 下游不以该步骤满量为录入前提;已有下游数据时仍须保留更正审计,并由后台管理员按返工/逆向流程处理业务影响。
### 9.3 撤销方案
取消某个人员的整笔分摊时,应进行软撤销而非物理删除:
- 设置明细为已撤销;
- 记录撤销人、撤销时间和撤销原因;
- 从步骤汇总 `completed_quantity` 中扣除该笔数量;
- 根据剩余数量重新计算步骤数量完成状态,并按状态转换规则重算业务完成状态;
- 写入不可篡改的操作日志。
---
## 10. 并发与数据一致性要求
多人同时提交是本问题的关键风险,必须由后端数据库事务保证,前端不能承担最终防线。
### 10.1 典型并发问题
订单 `6721678` 的组装累计数量为 `6 / 8` 台,剩余 2 台:
- E 读取到剩余 2 台,准备提交 2 台;
- F 同时也读取到剩余 2 台,准备提交 2 台;
- 如果两次请求都只在前端判断,就会写入 10 / 8 台。
### 10.2 必须采用的后端控制
后端对 `produce_order_step` 的当前订单步骤记录执行事务加锁:
```text
开始事务
↓
锁定 6721678 + 当前工序 + 当前步骤 的汇总行
↓
重新读取 completed_quantity
↓
校验请求幂等性与剩余数量
↓
写入人员分摊明细
↓
更新汇总数量、数量完成标记与受本次事件影响的业务状态
↓
提交事务
```
数据库幂等唯一索引与行锁必须同时具备:
- 幂等唯一索引负责保证同一个 `client_request_id` 只成功计入一次;
- 行锁负责保证多人、多次累计不超过订单总量。
### 10.3 幂等性建议
移动端在网络抖动时可能自动重试。建议请求携带 `client_request_id`(UUID),后端对“订单步骤 + 用户 + 请求 ID”做幂等控制:
- 同一请求重复到达时直接返回首次结果;
- 不重复累计数量;
- 不限制同一人员后续发起新的、不同请求号的数量提交。
---
## 11. 实施范围与阶段计划
### 第一阶段:订单总量与步骤进度基础
1. 新增订单主档、订单步骤汇总、人员分摊明细表;
2. 增加订单导入/创建能力,确保订单总数量可用;
3. 增加按订单查询进度的 API;
4. 管理端增加订单和步骤进度查询页面;
5. 明确拷贝首次提交建立订单总量的规则,并保留原订单扫码模式兼容历史订单。
验收:能够建立订单 `6721678`,维护计划数量 `8`,并查询每个步骤的 `数量完成/总量` 与独立的业务完成状态。
### 第二阶段:移动端分摊录入
1. 订单模式页面增加数量字段和进度展示;
2. 新增订单步骤人员分摊提交接口;
3. 后端实现重复请求幂等、步骤剩余数量限制和事务并发控制;
4. 增加“我的累计提交”和“提交明细”提示,不限制同一人员再次提交;
5. 新订单切换到数量分摊模式。
验收:拷贝首次录入 8 台建立订单总量;拼板可由两人各录入 4 台,组装可由四人各录入 2 台;同一人员可在同一步骤再次追加;任何人、任何次数提交都不能使步骤累计超过 8 台,数量满额不直接判定为业务完成。
### 第三阶段:流程与状态集成
1. 拷贝首次有效提交建立订单总数量;
2. 任一步骤数量满额后标记为数量已完成并禁止继续提交;非末步骤不直接进入业务终态,末步骤则进入状态转换事务;
3. 取消下游必须等待上游数量满额或业务完成的拦截;
4. 保留并调整“下一个步骤数量满额后驱动上一个步骤完成”的状态转换逻辑,并定义末步骤数量满额时自身终态转换及向前驱动规则;
5. 以完整步骤状态转换链作为订单完成条件,并补齐步骤进度和人员产量统计。
验收:拷贝建立订单总量后,拼板累计数量未达到 8 台时组装仍可录入;各步骤独立累加且均不可超过 8 台;组装数量满额后,在同一事务内先完成组装自身终态转换,再按状态转换规则驱动拼板、拷贝进入业务完成状态;整条状态转换链完成后订单进入已完成状态。
### 第四阶段:更正、撤销、返工与迁移
1. 实现管理端更正和撤销;
2. 建立返工场景的逆向流程;
3. 为移动端重试增加幂等键;
4. 确定旧记录查询与新模式查询的兼容策略;
5. 在试点订单和用户上进行并发压力验证。
---
## 12. 验收测试用例
### 12.1 基础分摊
| 编号 | 操作 | 预期 |
| --- | --- | --- |
| T01 | 创建订单 `6721678`,数量 8 | 创建成功 |
| T02 | A 在拼板录入 4 | 拼板进度 4/8,步骤进行中 |
| T03 | B 在拼板录入 4 | 拼板进度 8/8,数量完成并禁止继续录入;待组装数量满额后按规则转为业务完成 |
| T04 | C 在组装录入 2 | 组装进度 2/8 |
| T05 | D、E、F 分别在组装录入 2 | 组装数量最终 8/8,禁止继续录入;在同一事务内完成组装自身终态转换,并按状态转换规则依次驱动拼板、拷贝进入业务完成状态;完整转换链完成后更新订单状态 |
### 12.2 防重复与防超报
| 编号 | 操作 | 预期 |
| --- | --- | --- |
| T06 | A 已录拼板 4 后,再录拼板 1 | 允许,拼板累计为 5/8 |
| T07 | 拼板已 8/8 后,C 再录拼板 1 | 拒绝:步骤数量已满,不可继续录入;不影响其业务完成状态按规则判定 |
| T08 | 组装 6/8 时,G 录入 3 | 拒绝:超过剩余 2 台 |
| T09 | 组装 6/8 时,E、F 并发各录 2 | 按先后仅允许不超出剩余数量,最终不超过 8/8 |
| T10 | 同一请求因网络重试两次 | 只累计一次 |
### 12.3 流程控制
| 编号 | 操作 | 预期 |
| --- | --- | --- |
| T11 | 拷贝已建立总量 8,拼板仅 4/8 时尝试组装录入 | 允许,不受上游未进入业务完成状态的限制 |
| T12 | 拼板达到 8/8 后尝试组装录入 | 允许,拼板数量完成不构成下游录入门槛 |
| T13 | 拼板未数量完成时,组装录入 2 台 | 允许,按组装步骤独立累计 |
| T14 | 后台管理员将已提交明细更正或撤销 | 重算对应步骤数量状态,并按状态转换规则重算步骤完成链和订单完成状态,记录原因 |
---
## 13. 业务规则确认结果
以下规则已按当前业务意见纳入方案:
1. **订单总数量来源**:由拷贝步骤首次提交数量建立;拷贝是第一道扫码录入步骤。
2. **同一人员是否只能提交一次**:不限制;同一人员可以在同一订单、同一步骤下多次提交。
3. **每个步骤目标数量**:是,均等于订单总数量。
4. **下游是否等待上游业务完成**:不需要;拼板、组装可按现场进度独立录入。
5. **是否逐台追溯**:当前不需要;按订单号和数量进行汇总追踪。
6. **更正和撤销权限**:由后台管理员执行,是否审批可作为后台权限配置,不影响移动端正常追加录入。
7. **订单完成定义**:不是简单判断最后一个步骤数量是否满额后立即完成,而是按照状态转换规则判定;非末步骤由下一个步骤数量满额后驱动进入业务完成状态,末步骤数量满额后在同一事务内完成自身终态转换并向前驱动,整条步骤链完成后订单才完成。
补充约束:订单总数量建立后不可由普通移动端人员随意修改;如拷贝首笔数量录入错误,由后台管理员按更正流程处理。
---
## 14. 不推荐的处理方式
### 14.1 直接关闭“不允许重复扫码”
不推荐。直接关闭限制而不增加数量字段、步骤累计上限和请求幂等控制,会让任意重复扫描都被计入,数量和产量无法可信统计。
### 14.2 将用户名直接加入现有重复判断,但不增加数量
不推荐作为最终方案。虽然能允许不同人员同单同步骤各扫一次,但系统只能知道“有几次操作”,无法知道:
- A 做了 4 台还是 1 台;
- B 做了多少;
- 累计是否恰好为 8 台;
- 各步骤数量是否已满、业务状态是否已完成,以及何时可判定订单完成。
### 14.3 每台都反复扫同一个订单号,把扫码次数当数量
不推荐。订单号相同且无单台唯一标识时,无法区分“正常第 2 台”与“误扫第 2 次”;应显式填写本次数量,并以请求幂等号和步骤累计上限控制重复计数。
### 14.4 仅使用整机模式替换订单模式
不推荐。整机模式虽有 `quantity`,但当前未继承订单模式的前置步骤、重复控制和自动状态流转;直接替换会丢失订单流程规则。
---
## 15. 实施后的目标状态
订单 `6721678` 在系统中的可见结果应为:
```text
订单总量:8 台
拷贝:8 / 8(数量已完成;已由后续步骤数量满额触发进入业务完成状态)
A:8 台
拼板:8 / 8(数量已完成;已由组装数量满额触发进入业务完成状态)
A:4 台
B:4 台
组装:8 / 8(数量已完成;已在同一状态转换事务内进入业务终态,并触发前序业务状态转换)
C:2 台
D:2 台
E:2 台
F:2 台
订单状态:组装数量满额后,在同一状态转换事务内完成组装自身终态转换并依次驱动拼板、拷贝完成;完整转换链完成后订单才为已完成
```
系统可以同时回答:
- 订单做了多少台?
- 每个步骤做了多少台、还差多少台?
- 谁做了多少台?
- 某个人累计提交了多少、每笔何时提交?
- 当前步骤数量是否已满、是否允许继续录入、还可录入多少?
- 订单总量是否已经由拷贝建立?
- 订单何时真正完成?
---
## 16. 实际代码定位
| 项目 | 位置 |
| --- | --- |
| 订单模式页面 | `frontend/scanapp/pages/entry/order.vue` |
| 整机模式页面(数量输入参考) | `frontend/scanapp/pages/entry/machine.vue` |
| 移动端生产 API 封装 | `frontend/scanapp/api/produce/data-entry.js` |
| 订单模式提交与重复校验 | `backend/plugin/produce/app/api/controller/DataEntryController.php` |
| APP API 委托控制器 | `backend/plugin/produce/app/appapi/controller/DataEntryController.php` |
| 现有订单扫码模型 | `backend/plugin/produce/app/model/ScanData.php` |
| 现有订单扫码迁移 | `backend/plugin/produce/resource/database/migrations/2026_07_31_000003_create_produce_config_and_scan_data_tables.php` |
| 现有整机记录模型 | `backend/plugin/produce/app/model/ProductRecord.php` |
| 现有整机记录迁移 | `backend/plugin/produce/resource/database/migrations/2026_08_06_000001_create_produce_product_record_table.php` |
| 现有步骤、状态、关系迁移 | `backend/plugin/produce/resource/database/migrations/2026_07_30_000001_create_produce_basic_tables.php` |
@@ -0,0 +1,594 @@
# 订单模式工作模式与工作规则说明
> 文档用途:说明当前生产扫码 APP 中“订单模式”的实际工作方式、数据规则、校验规则、状态流转与边界。本文仅基于当前项目已实现代码梳理;对尚未实现或未被调用的配置能力,会明确标注,避免将规划误认为现行规则。
>
> 适用范围:`frontend/scanapp` 移动端订单模式、`backend/plugin/produce` 的 APP API 及其生产记录数据。
---
## 1. 概述
订单模式用于生产人员在指定的**工序**和**步骤**下,对单个订单号进行扫码或手工录入,并生成一条订单扫码记录。
一次成功提交的核心结果是:
1. 生成一条 `produce_scan_data` 订单扫码记录;
2. 将当前登录用户映射为记录的操作人员;
3. 为记录写入当前步骤的初始状态;
4. 对满足条件的上游步骤,尝试执行“下一步骤扫码”自动状态转换;
5. 更新移动端的最近记录与统计数据。
订单模式是**单订单、单次记录**的录入模式。它记录订单在某工序步骤的作业动作,不等同于订单主档,也不会在当前实现中直接维护“整张订单已完成”的全局终态。
---
## 2. 现行工作模式
### 2.1 操作入口与页面
| 项目 | 当前实现 |
| --- | --- |
| 页面 | `frontend/scanapp/pages/entry/order.vue` |
| 页面名称 | 订单模式 |
| 主要用途 | 扫描订单号并按当前工序、步骤提交生产扫码记录 |
| 提交接口 | `POST /appapi/produce/scan-data/record` |
| 最近记录接口 | `GET /appapi/produce/scan-data` |
| 统计接口 | `GET /appapi/produce/scan-data/statistics` |
| 配置接口 | `GET /appapi/produce/config/data-entry` |
APP 请求基础前缀为 `/appapi`;生产插件通过 Swagger 注解注册 APP API 路由。控制器实际执行逻辑位于:
```text
backend/plugin/produce/app/api/controller/DataEntryController.php
```
APP API 控制器为委托层,复用上述逻辑。
### 2.2 页面加载后的准备流程
订单模式页面加载时,按当前本地登录用户初始化并请求以下数据:
1. 从本地缓存 `scanapp_user` 读取用户编码;
- 取值优先级:`username` → `nickname` → 默认值 `U001`。
2. 获取启用的工序列表;
3. 获取当前用户的订单模式统计;
4. 获取当前用户的最近订单扫码记录;
5. 根据已保存的个人选择恢复工序与步骤;
6. 获取当前工序的启用步骤;
7. 获取当前工序/步骤对应的录入配置和特定规则。
用户的工序、步骤选择会保存到本地存储,键名格式为:
```text
scanapp_entry_order_selection_<用户编码>
```
保存字段为:
```json
{
"processId": "工序ID",
"stepId": "步骤ID"
}
```
因此,同一用户再次进入订单模式时,会优先恢复上一次选择的工序与步骤;不同用户的选择互不覆盖。
### 2.3 工序和步骤选择规则
#### 工序
- 数据源:`produce_process`。
- 仅返回 `status = 1` 的启用工序。
- 排序:先按 `sort` 升序,再按 `id` 升序。
- 操作人员可在页面中切换工序。
#### 步骤
- 数据源:`produce_process_step`。
- 仅返回 `status = 1` 的启用步骤。
- 仅返回当前选中工序下的步骤。
- 排序:先按 `sort` 升序,再按 `id` 升序。
- 切换工序后,页面会重新加载步骤、录入配置,并保存当前选择。
### 2.4 订单号录入方式
订单号支持两种录入方式:
1. **手工输入**:在订单号输入框直接录入;
2. **相机扫码**:调用 `uni.scanCode`,仅允许通过相机扫码,支持:
- 一维条码:`barCode`
- 二维码:`qrCode`
扫码成功后,系统将结果转为字符串并去除首尾空格,再回填订单号字段。扫码取消或失败时,页面提示“未完成扫码”。
### 2.5 连续扫码
页面提供“连续扫码”开关,默认关闭。
- 关闭:提交成功后清空订单号,等待下一次手工输入或主动扫码。
- 开启:提交成功后清空订单号、刷新页面数据,并在约 350 毫秒后自动再次唤起相机扫码。
连续扫码只影响前端扫码动作,不改变后端校验、记录创建或状态流转规则。
---
## 3. 提交前校验规则
订单模式采取“前端预校验 + 后端强制校验”的方式。前端用于及时提示,后端是最终准入边界。
### 3.1 页面级必填校验
提交前必须满足:
| 校验项 | 规则 | 失败提示 |
| --- | --- | --- |
| 订单号 | 去除首尾空格后不能为空 | 请输入订单号 |
| 工序 | 当前必须存在有效选中项 | 请选择工序 |
| 步骤 | 当前必须存在有效选中项 | 请选择步骤 |
### 3.2 基础配置校验
配置来源为 `produce_config` 表中 `group_code = basic_setting` 的配置项。当前订单模式实际使用以下字段:
| 配置代码 | 当前作用 |
| --- | --- |
| `order_no_min_length` | 大于 0 时,订单号长度不得小于该值 |
| `order_no_regex` | 配置非空时,订单号必须匹配该正则表达式 |
| `global_allow_repeat` | 步骤未覆盖时,作为全局重复扫码默认开关 |
| `repeat_scan_interval` | 重复扫码最短间隔,单位秒 |
| `recent_records_today_only` | 控制最近记录和统计在无订单号筛选时是否仅统计当天 |
规则说明:
- 未配置 `order_no_min_length` 或值小于等于 0:不做最小长度限制;
- 未配置 `order_no_regex`:不做格式正则校验;
- 正则配置格式异常时,前端会记录错误日志,但不会因该错误阻塞用户提交;后端的特定规则匹配会将无法匹配的规则视为不命中。
### 3.3 特定规则(订单命中规则)
特定规则来源:`produce_specific_rule`,仅查询 `is_enabled = 1` 的规则,并按 `sort`、`id` 升序处理。
规则可按以下维度限制:
| 字段 | 说明 |
| --- | --- |
| `apply_mode` | 生效模式:`order` 表示订单模式,`both` 表示订单和整机模式均生效 |
| `match_field` | 用于匹配的字段;订单模式默认是 `order_no` |
| `rule_pattern` | 正则表达式内容 |
| `step_ids` | 可选的步骤 ID 范围;为空表示不限制步骤 |
| `rule_type` | 当前实现中 `2` 表示命中后禁止提交;`1` 在重复扫码策略中表示允许重复 |
订单模式页面会在提交前检查:若存在一个满足模式、步骤范围和正则条件的 `rule_type = 2` 规则,则拒绝提交,并提示规则名称;规则未命名时提示“当前订单命中特定规则,禁止提交”。
> 注意:前端会先加载规则并做预拦截;后端 `record` 提交接口当前没有再次执行“订单号长度、订单号正则、禁止型特定规则”的完整校验。因此,客户端校验不能替代服务端校验。现行系统中,前置步骤、重复扫码、用户编码和请求字段校验由后端强制执行。
### 3.4 后端请求字段校验
接口 `POST /produce/scan-data/record` 使用 `ScanDataValidate` 的 `store` 场景校验,要求:
| 字段 | 规则 |
| --- | --- |
| `order_no` | 必填,最长 100 字符 |
| `user_code` | 必填,最长 50 字符 |
| `process_id` | 必填,整数 |
| `step_id` | 必填,整数 |
| `status_id` | 可选,整数 |
| `scan_result` | 必填,只允许 `0` 或 `1` |
| `remark` | 可选,最长 65535 字符 |
当前订单模式前端固定提交:
```json
{
"order_no": "订单号",
"user_code": "当前用户编码",
"process_id": "当前工序ID",
"step_id": "当前步骤ID",
"scan_result": 1
}
```
即订单模式正常提交默认写入成功结果 `scan_result = 1`,页面没有提供失败结果或备注的录入控件。
### 3.5 操作人员校验与归属
后端以 `user_code` 查询会员表 `member` 的 `username`:
- 用户不存在:拒绝提交,返回“用户编码不存在”;
- 用户存在:后端以会员真实信息写入操作人员信息;
- `user_code`:请求中的用户编码;
- `operator`:优先会员昵称,否则使用会员用户名;
- `operator_id`:会员 ID。
前端传入的 `operator` 不作为最终可信操作人员来源,服务端会重新从会员数据生成操作人快照。
---
## 4. 前置步骤与重复扫码规则
### 4.1 前置步骤规则
每个步骤可以配置前置步骤,配置字段属于 `produce_process_step`:
| 字段 | 含义 |
| --- | --- |
| `prerequisite_steps` | 前置步骤 ID 数组 |
| `prerequisite_mode` | 验证模式:`all`、`any`、`none` |
| `prerequisite_require_final` | 是否要求前置步骤已进入终态:`1` 是,`0` 否 |
后端在创建当前步骤记录前执行校验。
#### 验证模式
| 模式 | 含义 | 不满足时的结果 |
| --- | --- | --- |
| `none` | 不校验前置步骤,或未配置前置步骤 | 允许提交 |
| `all` | 所有前置步骤都要满足 | 返回“前置步骤未完成:步骤A、步骤B” |
| `any` | 至少一个前置步骤满足 | 返回“前置步骤未满足,至少需要完成一个前置步骤” |
#### 前置步骤满足条件
系统以“同一订单号 + 指定前置步骤”查询历史订单扫码记录:
- `prerequisite_require_final = 0`:只要存在任意历史记录,即视为满足;
- `prerequisite_require_final = 1`:必须存在关联步骤状态为 `is_final = 1` 的历史记录,才视为满足。
因此,是否称得上“完成”,在当前订单流程中取决于**步骤状态是否是终态**,而不是仅仅存在过扫码记录。
### 4.2 重复扫码规则
后端以“同订单号 + 同工序 + 同步骤”查询最新扫码记录。若不存在历史记录,允许直接提交;若存在,则按下列优先级计算重复扫码策略:
1. 全局基础配置 `global_allow_repeat`、`repeat_scan_interval`;
2. 当前步骤配置覆盖全局是否允许重复及允许的状态;
3. 命中的特定规则可最终覆盖“是否允许重复”。
#### 默认与覆盖逻辑
| 配置来源 | 影响 |
| --- | --- |
| `global_allow_repeat` | 未配置步骤规则时的默认允许重复开关 |
| `repeat_scan_interval` | 最短重复扫码间隔(秒) |
| `allow_repeat_scan` | 步骤级允许重复开关,会覆盖全局开关 |
| `repeat_scan_statuses` | 限制仅在指定状态下允许重复;空数组表示不额外限制状态 |
| 命中特定规则且 `rule_type = 1` | 允许重复 |
| 命中特定规则且 `rule_type != 1` | 不允许重复 |
当存在历史记录时,以下任一条件不满足都会拒绝提交:
1. 当前策略未允许重复:提示“当前配置不允许重复扫码”;
2. 配置了允许重复状态,且最近记录的状态不在范围内:提示“当前状态不允许重复扫码”;
3. 配置了最短间隔,且距离最近一次扫码不足该秒数:提示“重复扫码间隔不能小于 N 秒”。
> 实现细节:重复扫描校验只检查同工序、同步骤下的最新记录,不会因其他步骤或其他工序的记录直接阻止当前提交。
---
## 5. 状态与工作流规则
### 5.1 订单扫码记录的初始状态
提交接口收到 `status_id` 时会优先使用该值;订单模式页面当前不传 `status_id`,因此后端会自动查询当前步骤 `is_initial = 1` 的状态并写入记录。
相关状态配置表为 `produce_step_status`:
| 字段 | 说明 |
| --- | --- |
| `step_id` | 所属步骤 |
| `status_code` / `status_name` | 状态编码与显示名称 |
| `is_initial` | 是否初始状态 |
| `is_final` | 是否终态 |
| `status` | 是否启用 |
当前实现没有在记录创建时显式校验“初始状态是否唯一、是否启用”;管理端配置时应保证每个可用步骤存在明确且唯一的初始状态,避免记录没有状态或状态语义不确定。
### 5.2 下一步骤扫码触发上游状态转换
提交当前步骤订单记录后,后端在同一数据库事务中处理“下一步骤扫码自动触发状态转换”。该机制含义是:当前步骤扫码可以推动与它相连的**前置步骤记录**切换状态。
触发过程如下:
1. 找到所有已启用、且目标步骤等于当前步骤的步骤关系:`produce_step_relation.to_step_id = 当前 step_id`;
2. 按 `priority`、`sort`、`id` 升序逐项处理;
3. 对每个关系,取同一订单在源步骤(`from_step_id`)的最新扫码记录;
4. 若源记录不存在或没有状态,则跳过;
5. 查找源步骤上已启用、自动触发的状态转换:
- `trigger_event = next_step_scan`
- `auto_trigger = 1`
- 当前源记录状态等于 `from_status_id`
6. 若存在多条可用转换,按以下顺序取第一条:
- `priority` 降序;
- `sort` 升序;
- `id` 升序;
7. 将源记录 `status_id` 更新为转换目标状态 `to_status_id`;
8. 无论成功或失败,均写入一条 `produce_transition_log` 流转日志。
### 5.3 “已完成”的系统含义
当前代码中没有独立的“订单完成表”或统一的订单全局完成字段。订单层面的“已完成”主要通过以下事实判断:
1. 某步骤的订单扫码记录关联的状态配置为 `is_final = 1`;
2. 在后续步骤校验前置条件时,该步骤可被视为已完成(当 `prerequisite_require_final = 1`);
3. 当前流程末端步骤是否代表整张订单完成,取决于管理端为该步骤配置的终态及步骤关系。
因此,**订单是否已完成是流程配置驱动的结果,不是当前订单模式页面上的固定布尔状态。**
### 5.4 状态转换日志
自动状态转换会创建 `produce_transition_log`,记录:
- 被转换的源订单记录 ID 和订单号;
- 源步骤和状态、目标状态;
- 触发事件 `next_step_scan`;
- 当前扫码记录、用户、工序及关系等触发快照;
- 触发人员、IP、耗时;
- 自动触发标识;
- 成功/失败结果和异常信息。
日志用于追溯“为什么某一步状态被改动”,不直接替代订单扫码记录。
---
## 6. 数据模型与数据口径
### 6.1 主记录:`produce_scan_data`
订单模式的每次提交生成一行记录,核心字段如下:
| 字段 | 说明 |
| --- | --- |
| `id` | 记录主键 |
| `order_no` | 订单号 |
| `user_code` | 操作用户编码 |
| `operator` / `operator_id` | 操作人员快照及会员 ID |
| `process_id` / `step_id` | 执行的工序和步骤 |
| `status_id` | 当前步骤状态 |
| `scan_result` | 扫码结果:`0` 失败,`1` 成功 |
| `scan_time` | 业务扫码时间 |
| `remark` | 备注 |
| `created_at` / `updated_at` / `deleted_at` | 创建、更新、软删除时间 |
每次提交均写入当前服务器时间作为 `scan_time`。模型创建钩子也会在 `scan_time` 为空时补写当前时间,避免出现空扫码时间。
### 6.2 与整机模式的边界
整机模式写入的是 `produce_product_record`,主要字段为工序订单号、商品编码、数量、工序步骤、状态和扫码结果。
订单模式与整机模式的差异:
| 对比项 | 订单模式 | 整机模式 |
| --- | --- | --- |
| 主表 | `produce_scan_data` | `produce_product_record` |
| 主识别字段 | `order_no` | `process_order_no` + `product_code` |
| 记录粒度 | 单个订单号 | 整机/物料及数量 |
| 前置步骤校验 | 已实现 | 当前提交接口未调用同等校验 |
| 重复扫码校验 | 已实现 | 当前提交接口未调用同等校验 |
| 下一步自动状态转换 | 已实现 | 当前提交接口未触发 |
### 6.3 与异常和维修模块的边界
异常记录位于 `produce_exception_record`,维修记录位于 `produce_repair_record`。它们可按订单号与订单扫码数据建立业务关联,但当前订单模式提交成功不会自动创建异常或维修记录。
异常处理目前使用独立状态:
| 异常状态值 | 含义 |
| --- | --- |
| `0` | 待处理 |
| `1` | 处理中/待复核(不同展示位置的命名存在差异) |
| `2` | 已处理 |
维修任务列表仅筛选异常状态为 `0` 的记录,并按异常提报时间升序展示,用于优先处理较早提报的异常。该规则不等同于订单模式的步骤完成规则。
---
## 7. 最近记录与统计规则
### 7.1 最近记录
订单模式调用:
```text
GET /appapi/produce/scan-data?user_code=<当前用户>&limit=5
```
后端行为:
- 支持按订单号、工序、步骤、状态、扫码结果过滤;
- 订单模式页面实际传入用户编码和数量限制,但当前后端订单扫码过滤函数**没有使用 `user_code` 条件**;
- 记录按 `scan_time` 降序、`id` 降序返回;
- 支持分页,默认每页 10 条,单页最大 50 条;
- 返回结构包含:`items`、`total`。
> 现状说明:页面文案为“当前登录用户的最近记录”,但接口实现尚未按 `user_code` 过滤。因此,在当前实现中,该列表实际可能包含其他用户的订单扫码记录。此为文档记录的现行行为,不应被误解为已完成个人隔离。
### 7.2 统计
订单模式调用:
```text
GET /appapi/produce/scan-data/statistics?user_code=<当前用户>
```
返回字段:
| 字段 | 含义 |
| --- | --- |
| `today_total` | 查询范围内记录总数 |
| `success_total` | `scan_result = 1` 的记录数 |
| `failed_total` | `scan_result = 0` 的记录数 |
当前统计实现同样没有在订单扫码过滤函数中应用 `user_code`,因此页面虽然传入用户编码,统计口径实际并非严格的个人统计。
此外,`today_total` 这个字段名称不必然代表“今日”:
- 当基础配置 `recent_records_today_only = 1` 且未传 `order_no` 时,只计算当天 00:00:00 至 23:59:59 的记录;
- 当该配置不是 `1` 时,统计全部历史记录。
页面中“今日统计”“当前工序/步骤扫码量”的文案与当前接口传参及过滤实现并不完全一致:页面未传当前工序、步骤,接口未按用户编码过滤。实际数据范围应以服务端查询规则为准。
---
## 8. 当前端到端流程
```text
进入订单模式
↓
读取当前用户和已保存的工序/步骤选择
↓
加载启用工序、当前用户参数下的记录/统计、当前工序步骤和规则配置
↓
选择工序与步骤(可切换并保存)
↓
输入或扫描订单号
↓
加载当前上下文的配置与特定规则
↓
前端校验:订单号/工序/步骤/长度/正则/禁止型规则
↓
提交 POST /produce/scan-data/record(scan_result 固定为 1)
↓
后端校验:请求字段、会员用户、前置步骤、重复扫码
↓
创建订单扫码记录,并赋予步骤初始状态
↓
按步骤关系尝试自动推进上游步骤状态,记录流转日志
↓
返回录入成功
↓
前端提示成功,清空订单号,刷新页面数据
↓
若开启连续扫码,则自动再次发起相机扫码
```
---
## 9. 管理配置对订单模式的影响
订单模式的实际行为高度依赖管理端配置。上线或调整流程前,应至少检查下列内容。
### 9.1 工序与步骤
- 工序、步骤是否启用;
- 工序和步骤的 `sort` 是否符合现场操作顺序;
- 每一步是否正确配置前置步骤;
- `prerequisite_mode` 是否符合“全部完成”或“任意完成”的业务要求;
- 是否必须要求前置步骤终态。
### 9.2 步骤状态
- 每个可使用步骤是否配置了初始状态;
- 初始状态是否唯一、名称是否清晰;
- 哪些状态是终态(`is_final = 1`);
- 终态是否与“可进入下步”“该步骤结束”等业务语义一致;
- 状态是否启用。
### 9.3 步骤关系和状态转换
- 是否建立从上游步骤到下游步骤的关系;
- 关系是否启用;
- 当前下游步骤扫码时,是否需要自动更新上游步骤状态;
- 状态转换是否设置:
- 源步骤;
- 源状态;
- 目标状态;
- 触发事件 `next_step_scan`;
- `auto_trigger = 1`;
- 启用状态;
- 多条转换并存时,优先级是否正确。
### 9.4 订单校验与重复策略
- 最小订单号长度是否符合现场编码;
- 正则表达式是否已在真实订单样本上验证;
- 是否允许同订单、同工序、同步骤重复扫码;
- 如允许,最短间隔是否合理;
- 是否限制只能在指定状态下重复;
- 特定规则是否正确设置应用模式、匹配字段、步骤范围和规则类型。
---
## 10. 当前实现的已知边界与风险
以下内容是当前代码已确认的边界,后续若要以“已完成订单”为核心建设功能,应优先统一定义。
1. **没有独立的全局订单完成状态。**
- 当前“完成”依赖步骤状态 `is_final` 与流程配置。
- 若需要“已完成订单列表”,需要明确:是最后一步进入终态即完成,还是所有必经步骤进入终态即完成。
2. **订单模式前端的部分校验没有在后端重复执行。**
- 最小长度、订单正则、禁止型特定规则主要在前端执行。
- 直接调用接口的客户端理论上可以绕过这些规则。
- 后续需将关键业务准入规则统一收敛至后端,前端只保留体验层预校验。
3. **最近记录与统计未实际按 `user_code` 过滤。**
- 页面传递用户编码,但服务端 `applyScanDataFilter` 未处理该字段。
- 当前页面“当前用户”相关文案与真实数据范围可能不一致。
4. **统计字段命名与口径依赖配置。**
- `today_total` 是否仅统计当日由 `recent_records_today_only` 决定。
- 页面未传工序和步骤,所以“当前工序/步骤扫码量”文案不能保证与实际查询范围一致。
5. **初始状态存在性由配置保证。**
- 若当前步骤未配置初始状态,记录可能以空状态创建,影响后续前置完成判定和自动流转。
6. **自动流转只由订单模式提交触发。**
- 整机模式当前不会执行相同的前置步骤、重复扫码和下一步骤自动流转逻辑。
7. **当前订单模式默认只提交成功结果。**
- 页面固定 `scan_result = 1`,失败记录、备注等需要通过其他页面或接口能力处理。
---
## 11. 后续建设“已完成订单”功能前的统一规则建议
若后续要增加“已完成订单”列表、详情、查询或统计,建议先由业务方确认以下定义,再实施接口和页面:
1. **完成判定对象**:
- 指定末端步骤进入终态;
- 所有必经步骤进入终态;
- 指定末端步骤成功扫码即可;
- 是否还要排除未关闭的异常或维修任务。
2. **完成时间**:
- 最后一步进入终态的时间;
- 最后一次成功扫码时间;
- 所有必经步骤均完成时的最大完成时间。
3. **同订单重工/返工**:
- 完成后是否允许再次扫码;
- 再次扫码是否撤销完成状态;
- 应使用订单维度快照还是按最新步骤记录实时计算。
4. **异常和维修的影响**:
- 待处理异常是否阻止进入已完成列表;
- 已维修但未复核的订单是否算完成;
- 维修完成后是否要回写生产步骤或重新进入某一工序。
5. **列表数据模型**:
- 运行时按 `produce_scan_data` 聚合计算;
- 或建立订单流程汇总表,以提高查询性能、固化完成时间并支持审计。
在这些规则统一前,不建议将“存在终态扫码记录”简单等同于“整张订单完成”,以免与返工、异常、维修等现场业务冲突。
---
## 12. 代码与配置定位清单
| 类型 | 位置 |
| --- | --- |
| 订单模式页面 | `frontend/scanapp/pages/entry/order.vue` |
| APP 请求封装 | `frontend/scanapp/api/produce/data-entry.js` |
| 请求基础前缀 | `frontend/scanapp/config/index.js` |
| 生产数据入口控制器 | `backend/plugin/produce/app/api/controller/DataEntryController.php` |
| APP 委托控制器 | `backend/plugin/produce/app/appapi/controller/DataEntryController.php` |
| 订单扫码模型 | `backend/plugin/produce/app/model/ScanData.php` |
| 订单扫码校验器 | `backend/plugin/produce/app/validate/ScanDataValidate.php` |
| 步骤模型 | `backend/plugin/produce/app/model/ProcessStep.php` |
| 步骤状态模型 | `backend/plugin/produce/app/model/StepStatus.php` |
| 步骤关系模型 | `backend/plugin/produce/app/model/StepRelation.php` |
| 状态转换模型 | `backend/plugin/produce/app/model/StatusTransition.php` |
| 流转日志模型 | `backend/plugin/produce/app/model/TransitionLog.php` |
| 基础表迁移 | `backend/plugin/produce/resource/database/migrations/2026_07_30_000001_create_produce_basic_tables.php` |
| 扫码记录迁移 | `backend/plugin/produce/resource/database/migrations/2026_07_31_000003_create_produce_config_and_scan_data_tables.php` |
| 插件路由配置 | `backend/plugin/produce/config/route.php` |