Files
bj_power/案例.md
T
SunYF 132c3ed6bd docs(test): 更新电表箱装配业务回归测试文档
- 将文档从代码审计任务转换为端到端业务回归测试链路
- 重新组织文档结构为链路总览、示例数据基线和详细步骤
- 添加完整的业务场景清单涵盖WMS/MES/工位终端三大系统
- 定义统一的测试数据包括产品型号、物料清单、工位派工等
- 提供详细的步骤断言和数量等式验证方法
- 建立贯穿全链路的数据流向和状态变更追踪体系
2026-09-21 10:48:53 +08:00

822 lines
47 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.
# 电表箱成品装配 · 端到端业务回归测试链路
> 本文档是**一条从头走到尾、环环相扣、不许断、禁止分支**的完整回归测试链路。
> 以「装配 1 台成品电表箱」为主线,从物料还没进公司门开始,一路走到成品入库、多余料退回库房、成品可追溯。
> 每一步的**前置数据都由它前面的步骤产出**;每一步都给出**具体数值的断言**(表名·字段·期望值·数量等式)。
> 全链路只有一条路径,没有"如果…就…"、没有"否则"、没有"另一种情况"。
>
> 涉及三个系统:库房系统(WMS,端口 8890,接口前缀 `/api`)、产线系统(MES,端口 8888,接口前缀 `/api/v1`)、工位终端(端口 8892,接口前缀 `/api`)。
> 系统之间内部互调用 `X-API-TOKEN` 头保护(值 `Hardman_2026`)。
> 登录态用 JWT:库房/工位终端登录后带 `Authorization: Bearer <token>`;产线系统同理。
---
## 一、链路总览(一条主线)
```
【主数据准备】
建产品型号(电表箱) → 建物料档案(铁架子/门子/电气件/螺丝/成品) → 建库区(A区)
→ 建产品物料清单BOM(4种料, 各归属装配工序) → 建工艺流程(3个流程绑工位2/5·6/8)
→ 工位派工(工位2=工序1, 工位5=工序2, 工位6=工序2, 工位8=工序3)
【物料进厂:入库 → 检验】
结构件按批次入库(铁架子/门子/螺丝, 质量状态=未检)
→ 电气件按序列号SN入库(4颗, 质量状态=未检)
→ 来料检验(逐批/逐SN判合格 → 库存质量状态改「合格」)
【工单与排产】
建工单(电表箱, 数量1, 状态=已创建) → 日排产(生产日D, 计划1台, 状态=待执行)
→ 工单下发(已创建→已下发) → 工单开工(已下发→执行中, 联动排产 待执行→执行中)
【备料与出库(生产日D早上)】
生成备料单(按排产+派工算料, 同步工单物料台账, 立即自动出库只领「合格」品)
→ 库存扣减(铁架子-1/门子-1/电气件SN×2/螺丝-3), 台账累计出库达标置「领料完结」
→ 接料确认(4张备料单 已接料=已发出, 状态置「已完结」)
【上线装配:3道工序顺序流转】
工件上线(SN=WP-DX-0001, 状态=已上线, 当前工序=0)
→ 报工工序1(工位2, 绑铁架子批次+门子批次 → 当前工序=1)
→ 报工工序2(工位5, 绑2颗电气件SN → 当前工序=2) 〔工位6是同工序并行位〕
→ 拧紧上报(工位8, 拧2颗螺丝, 写2条拧紧记录+扭矩判定)
→ 报工工序3(工位8, 绑螺丝批次 → 当前工序=3)
【完工与成品入库】
完工(兜底校验3工序物料齐套 → 工件状态=已完工, 建关联追溯,
工单已完工数+1, 排产已完成数+1置「已完成」,
成品回流库房库存(成品SN=工件SN, 品类=成品, 数量1, 合格, 在库),
反冲核销台账已消耗量〔只核销台账, 不再动库存, 库存已在出库时扣过〕)
→ 工单完工流转(执行中→已完成)
【多余料回仓库 + 追溯】
工位退料(工位8, 螺丝用剩1颗 → 库房预建待确认退库单)
→ 库管确认收货(退库单置「已收货」, 螺丝加回 1 颗置「未检」, 在库总量 97→98)
→ 成品追溯(按成品SN回查: 工序时间线/操作人/物料批次SN/拧紧数据 全链路可追)
```
**贯穿全链路的 1 台成品**:成品序列号 `WP-DX-0001`,工单 `WO-20260922-001`,产品 `DX-100 电表箱`
---
## 二、示例数据基线(全链路统一口径)
### 2.1 产品与物料
| 编码 | 名称 | 品类 | 管理方式 | 说明 |
|---|---|---|---|---|
| DX-100 | 电表箱 | 成品 | 序列号(2) | 本链路装配的成品 |
| TLJ-01 | 铁架子 | 原材料 | 结构件·批次(1) | 工序1装配,单台用量1 |
| MEN-01 | 门子 | 原材料 | 结构件·批次(1) | 工序1装配,单台用量1 |
| DQJ-01 | 电气件 | 原材料 | 电气件·序列号(2) | 工序2装配,单台用量2 |
| LS-01 | 螺丝 | 原材料 | 结构件·批次(1) | 工序3装配,单台用量2,损耗率50% |
### 2.2 产品物料清单(BOM,产品 DX-100,清单名「默认」)
| 物料 | 管理方式 | 单台用量 | 损耗率 | 装配工序 |
|---|---|---|---|---|
| TLJ-01 铁架子 | 结构件(1) | 1 | 0% | 工序1 |
| MEN-01 门子 | 结构件(1) | 1 | 0% | 工序1 |
| DQJ-01 电气件 | 电气件(2) | 2 | 0% | 工序2 |
| LS-01 螺丝 | 结构件(1) | 2 | 50% | 工序3 |
> 螺丝损耗率 50% 的含义:按「试拧/滑牙预留」,单台标准备料 = 2 ×(1+50%) = 3 颗;实际装配拧 2 颗,剩 1 颗完工后退回库房。这是"多余的料回仓库"的数据来源。
### 2.3 工位派工(生产日 D,班次=单班)
| 工位号 | 工序编号 | 承担装配 |
|---|---|---|
| 2 | 工序1 | 装铁架子 + 门子 |
| 5 | 工序2 | 装电气件(本工件走此工位) |
| 6 | 工序2 | 装电气件(同工序并行位,本工件不经过) |
| 8 | 工序3 | 拧螺丝 |
> 连续性校验:按工位号升序,工序编号为 `1,2,2,3`,单调不降、不穿插,合法。
### 2.4 工艺流程(每个工位绑定一个启用流程)
| 流程名 | 绑定工位 | 工序步骤 |
|---|---|---|
| 装铁架子门子 | 工位2 | 步骤「装铁架子」、步骤「装门子」 |
| 装电气件 | 工位5、工位6 | 步骤「装电气件」 |
| 拧螺丝 | 工位8 | 步骤「拧螺丝1」(扭矩采集,标准:扭矩 RANGE 8~12)、步骤「拧螺丝2」(扭矩采集,标准:扭矩 RANGE 8~12) |
> 工位8 的流程含 **2 个扭矩采集步骤**,所以拧紧汇总里「应拧颗数=2」;实拧 2 颗即满足。
### 2.5 工单 / 排产 / 批次 / 序列号
- 工单号 `WO-20260922-001`,产品 DX-100,数量 **1** 台。
- 生产日 **D = 2026-09-22**`生成备料单` 取"系统当天"作为派工生效日,因此**派工生效日 = 排产日 = 备料日 = D = 执行回归测试的当天**;入库/建单可在 D-1=2026-09-21 完成)。
- 入库批次 / 序列号:
- 铁架子批次 `PC-TLJ-001`,入库 **5**
- 门子批次 `PC-MEN-001`,入库 **5**
- 螺丝批次 `PC-LS-001`,入库 **100**
- 电气件序列号 `SN-DQ-001``SN-DQ-002``SN-DQ-003``SN-DQ-004`,各 1 颗(共 **4** 颗)
- 成品序列号(=工件序列号):`WP-DX-0001`
### 2.6 数量主线(最终必须闭合的等式,逐步在下方断言)
| 物料 | 入库 | 出库到工位 | 退回库房 | 期末在库 | 装进成品 |
|---|---|---|---|---|---|
| 铁架子 TLJ-01 | 5 | 1 | 0 | 4 | 1 |
| 门子 MEN-01 | 5 | 1 | 0 | 4 | 1 |
| 电气件 DQJ-01 | 4(SN) | 2(SN001,002) | 0 | 2(SN003,004) | 2 |
| 螺丝 LS-01 | 100 | 3 | 1 | 98 | 2 |
| 成品 DX-100 | — | — | — | 1(WP-DX-0001) | — |
---
## 三、端到端步骤
> 每一步统一格式:
> - **前置**:本步开始前必须已存在的数据(且都来自前面步骤)。
> - **操作**:角色 + 系统 + 菜单 + 接口 + 请求体关键字段。
> - **系统反应**:业务语言描述系统做了什么。
> - **数据变化**:哪张表、哪个字段、变成什么值。
> - **断言**:具体数值 / 状态 / 条数 / 等式。
### 阶段一 · 主数据准备
---
## Step 1:建产品型号(电表箱)
**前置**:无(链路起点)。产线系统已登录(账号具备"产品型号"维护权限)。
**操作**:工艺员在【产线系统 → 基础数据 → 产品型号】点"新增",填:名称=电表箱、编码=DX-100、规格型号=DX-100 户用单相、单位=台、类别=成品、启用=是。
- 接口:`POST /api/v1/product-types`
- 请求体:`{"name":"电表箱","code":"DX-100","spec":"DX-100 户用单相","unit":"台","category":"成品","isActive":true}`
**系统反应**:新增一条产品型号并启用。
**数据变化**:产品型号表新增一行:编码=DX-100、名称=电表箱、规格=DX-100 户用单相、单位=台、类别=成品、启用=是。
**断言**
- `GET /api/v1/product-types?code=DX-100` 返回 1 条,名称=电表箱、启用=是。
- 记下返回的产品型号主键 id(记作 `${productTypeId}`),Step 10 建工单要用。
---
## Step 2:建物料档案(5 个物料)
**前置**Step 1 完成(成品 DX-100 也在此建档,供成品入库带出名称)。库房系统已登录(账号具备"物料档案:新增"权限)。
**操作**:仓管在【库房系统 → 基础数据 → 物料档案】逐个"新增"。
- 接口:`POST /api/material/create`
- 5 次请求体(除说明外全部必填:图号/名称/规格/单位/品类/类型):
| # | 请求体 |
|---|---|
| 铁架子 | `{"code":"TLJ-01","name":"铁架子","spec":"TLJ-01","unit":"个","itemType":1,"manageMode":1,"safetyStock":10}` |
| 门子 | `{"code":"MEN-01","name":"门子","spec":"MEN-01","unit":"个","itemType":1,"manageMode":1,"safetyStock":10}` |
| 电气件 | `{"code":"DQJ-01","name":"电气件","spec":"DQJ-01","unit":"个","itemType":1,"manageMode":2,"safetyStock":10}` |
| 螺丝 | `{"code":"LS-01","name":"螺丝","spec":"M4×10","unit":"颗","itemType":1,"manageMode":1,"safetyStock":50}` |
| 成品 | `{"code":"DX-100","name":"电表箱","spec":"DX-100 户用单相","unit":"台","itemType":3,"manageMode":2,"safetyStock":0}` |
**系统反应**:新增 5 条物料档案;结构件按批次管理、电气件按序列号管理自动置位;图号唯一校验通过。
**数据变化**:物料表新增 5 行。以铁架子为例:图号=TLJ-01、名称=铁架子、管理方式=1、按批次管理=是、按序列号管理=否、品类=1(原材料)、安全库存=10。电气件 DQJ-01:管理方式=2、按序列号管理=是。成品 DX-100:品类=3(成品)、管理方式=2。
**断言**
- `GET /api/material/query?code=TLJ-01` 等逐个返回 1 条,管理方式与上表一致。
- 铁架子/门子/螺丝 管理方式=1;电气件/成品 管理方式=2。
- 重复提交同一图号返回冲突提示"图号已存在"。
---
## Step 3:建仓库区域(A 区)
**前置**:Step 2 完成。库房系统已登录(账号具备"区域:新增"权限)。
**操作**:仓管在【库房系统 → 库位管理 → 区域】新增一级区域。
- 接口:`POST /api/zone/node/create`
- 请求体:`{"level":1,"code":"A","name":"合格品存储区"}`
**系统反应**:新增一级区域,区域编码自动转大写为 A。
**数据变化**:区域表新增一行:层级=1、编码=A、区域编码=A、名称=合格品存储区。
**断言**
- `GET /api/zone/list` 含层级=1、区域编码=A 的记录。
- Step 7/8 入库时 `zoneCode=A` 必须能命中此区域。
---
## Step 4:建产品物料清单(BOM)
**前置**Step 1(产品 DX-100)、Step 2(4 种零部件物料档案已存在)。产线系统已登录。
**操作**:工艺员在【产线系统 → 基础数据 → 产品物料清单】为 DX-100 维护清单(清单名「默认」),录入 4 行物料并指定各自装配工序。
- 接口:`PUT /api/v1/bom`
- 请求体(关键:每行的 `manageMode` 管理方式、`unitQty` 单台用量、`lossRate` 损耗率、`processCode` 装配工序):
```json
{
"productCode": "DX-100",
"bomName": "默认",
"items": [
{"materialCode":"TLJ-01","materialName":"铁架子","unit":"个","manageMode":"1","unitQty":1,"lossRate":0,"processCode":1},
{"materialCode":"MEN-01","materialName":"门子","unit":"个","manageMode":"1","unitQty":1,"lossRate":0,"processCode":1},
{"materialCode":"DQJ-01","materialName":"电气件","unit":"个","manageMode":"2","unitQty":2,"lossRate":0,"processCode":2},
{"materialCode":"LS-01","materialName":"螺丝","unit":"颗","manageMode":"1","unitQty":2,"lossRate":50,"processCode":3}
]
}
```
**系统反应**:按「产品编码+清单名+物料编码」覆盖式保存 4 行物料清单。
**数据变化**:物料清单表新增 4 行,产品编码=DX-100、清单名=默认。铁架子行:装配工序=1、单台用量=1、损耗率=0。电气件行:装配工序=2、单台用量=2、管理方式=2。螺丝行:装配工序=3、单台用量=2、损耗率=50。
**断言**
- `GET /api/v1/bom?productCode=DX-100&bomName=默认` 返回 **4** 行。
- 各行的 装配工序 / 单台用量 / 损耗率 / 管理方式 与请求体一致。
- 工序分布:工序1 有 2 种料(铁架子、门子)、工序2 有 1 种料(电气件)、工序3 有 1 种料(螺丝)。
---
## Step 5:建工艺流程(3 个流程,绑定工位 2/5·6/8)
**前置**:工位 2、5、6、8 为系统内置工位(种子数据已存在)。产线系统已登录。
**操作**:工艺员在【产线系统 → 工艺管理 → 工艺流程】新建 3 个启用流程,并绑定工位、维护工序步骤。
- 接口:`POST /api/v1/process-flows`
- 流程1(装铁架子门子,绑工位2):
```json
{"name":"装铁架子门子","status":"ACTIVE","stations":[2],
"steps":[{"seq":1,"name":"装铁架子","collectType":"手动"},{"seq":2,"name":"装门子","collectType":"手动"}]}
```
- 流程2(装电气件,绑工位5、6):
```json
{"name":"装电气件","status":"ACTIVE","stations":[5,6],
"steps":[{"seq":1,"name":"装电气件","collectType":"扫码"}]}
```
- 流程3(拧螺丝,绑工位8,2 个扭矩步骤 + 扭矩 RANGE 标准):
```json
{"name":"拧螺丝","status":"ACTIVE","stations":[8],
"steps":[
{"seq":1,"name":"拧螺丝1","collectType":"扭矩","isTorque":true,
"criteria":[{"name":"扭矩","unit":"N·m","logic":"RANGE","min":8,"max":12}]},
{"seq":2,"name":"拧螺丝2","collectType":"扭矩","isTorque":true,
"criteria":[{"name":"扭矩","unit":"N·m","logic":"RANGE","min":8,"max":12}]}
]}
```
**系统反应**:新建 3 个流程;把工位2→流程1、工位5和6→流程2、工位8→流程3 绑定;覆盖式重建各流程的工序步骤与考核标准。
**数据变化**
- 工艺流程表新增 3 行,状态=启用(ACTIVE)。
- 工位表:工位2 的流程id=流程1;工位5、工位6 的流程id=流程2;工位8 的流程id=流程3。
- 工序步骤表:流程1 有 2 步;流程2 有 1 步;流程3 有 2 步且"是否扭矩"=是。
- 考核标准表:流程3 的两步各挂 1 条"扭矩 / RANGE / 8~12"标准。
**断言**
- `GET /api/v1/stations` 中工位2/5/6/8 的流程绑定与上表一致。
- `GET /api/v1/process-flows?stationNo=8` 返回流程3,含 2 个扭矩步骤 → 决定 Step 19 拧紧"应拧颗数=2"。
---
## Step 6:工位派工(工位↔工序,生产日 D)
**前置**Step 5 完成(工位2/5/6/8 已绑流程)。产线系统已登录。生产日 D = 执行当天。
**操作**:生产主管在【产线系统 → 生产管理 → 工位派工】为生产日 D 逐工位派工。
- 接口:`POST /api/v1/station-process/save`(逐条保存,同工位同天同班次唯一)
- 4 次请求体:
```json
{"stationNo":2,"processCode":1,"effectDate":"2026-09-22","shift":"","operator":"主管01"}
{"stationNo":5,"processCode":2,"effectDate":"2026-09-22","shift":"","operator":"主管01"}
{"stationNo":6,"processCode":2,"effectDate":"2026-09-22","shift":"","operator":"主管01"}
{"stationNo":8,"processCode":3,"effectDate":"2026-09-22","shift":"","operator":"主管01"}
```
**系统反应**:覆盖式保存 4 条派工;保存前做连续性校验(工序号沿工位号 1,2,2,3 单调不降,通过)。
**数据变化**:工位派工表新增 4 行,生效日=2026-09-22、班次=空:(工位2,工序1)、(工位5,工序2)、(工位6,工序2)、(工位8,工序3)。
**断言**
- `GET /api/v1/station-process?effectDate=2026-09-22` 返回 **4** 行,工位→工序映射与上表一致。
- `GET /api/v1/station-process/route?effectDate=2026-09-22` 派生路线:工位串 `2,5,6,8`、工序集合 `1,2,3`
- 反例(可选验证):把工位4 派为工序1(夹在工位2工序1与工位5工序2之间但破坏单调)时保存被拒,提示"工序编号必须沿工位号单调不降、不可穿插"。
---
### 阶段二 · 物料进厂:入库 → 检验
---
## Step 7:结构件入库(铁架子 / 门子 / 螺丝,按批次)
**前置**Step 2(物料档案)、Step 3(A 区)。库房系统已登录。3 种结构件随货带供应商质检报告单号(外部单号,非本系统检验记录)。
**操作**:仓管在【库房系统 → 入库管理 → 结构件入库】按批次录入。
- 接口:`POST /api/inbound/create`
- 3 次请求体(`inspectionNo` 检测单号必填、`zoneCode` 区域必填、`quantity`>0):
```json
{"inboundType":"purchase","materialCode":"TLJ-01","batchNo":"PC-TLJ-001","quantity":5,"zoneCode":"A","inspectionNo":"QC-TLJ-20260921","operator":"库管01"}
{"inboundType":"purchase","materialCode":"MEN-01","batchNo":"PC-MEN-001","quantity":5,"zoneCode":"A","inspectionNo":"QC-MEN-20260921","operator":"库管01"}
{"inboundType":"purchase","materialCode":"LS-01","batchNo":"PC-LS-001","quantity":100,"zoneCode":"A","inspectionNo":"QC-LS-20260921","operator":"库管01"}
```
**系统反应**:每笔在事务内建"入库单 + 库存行 + 入库明细"。结构件走批次管理,不允许携带 SN 清单。库存行质量状态先置「未检」(等 Step 9 检验判定)。
**数据变化**
- 入库单表新增 3 行,入库单号形如 `IB<12位>`,数量分别 5/5/100,检测单号回填。
- 库存表新增 3 行(管理方式=1):铁架子批次 PC-TLJ-001 数量=5、门子批次 PC-MEN-001 数量=5、螺丝批次 PC-LS-001 数量=100;质量状态=未检、状态=在库、区域=A、锁定量=0。
- 入库明细表新增 3 行(按批次号 + 数量)。
**断言**
- `GET /api/stock/query?materialCode=TLJ-01` 返回批次 PC-TLJ-001,数量=5、质量状态=未检、状态=在库。
- 门子数量=5、螺丝数量=100,同样质量状态=未检。
- 3 笔入库单数量合计 = 5+5+100 = 110。
---
## Step 8:电气件入库(4 颗 SN)
**前置**Step 2(电气件档案 DQJ-01 管理方式=2)、Step 3(A 区)。库房系统已登录。
**操作**:仓管在【库房系统 → 入库管理 → 电气件入库】逐个扫 SN 录入。
- 接口:`POST /api/inbound/create`
- 请求体(电气件用 `snList`,不带 quantity):
```json
{"inboundType":"purchase","materialCode":"DQJ-01","snList":["SN-DQ-001","SN-DQ-002","SN-DQ-003","SN-DQ-004"],"zoneCode":"A","inspectionNo":"QC-DQJ-20260921","operator":"库管01"}
```
**系统反应**:对每个 SN 建一条库存行(管理方式=2,数量=1),SN 全局唯一防重;质量状态置「未检」。
**数据变化**
- 入库单表新增 1 行,数量=4(=SN 个数)。
- 库存表新增 4 行(管理方式=2):SN-DQ-001/002/003/004,各数量=1、质量状态=未检、状态=在库、区域=A。
- 入库明细表新增 4 行(每 SN 一行,数量=1)。
**断言**
- `GET /api/stock/query?materialCode=DQJ-01` 返回 4 条 SN 行,各数量=1、质量状态=未检。
- 重复入库同一 SN 返回冲突提示"SN 已存在"。
---
## Step 9:来料检验(逐批 / 逐 SN 判合格)
**前置**Step 7、Step 8 完成——库存里已有 3 个批次行 + 4 个 SN 行(质量状态=未检)。库房系统已登录。
**操作**:质检员在【库房系统 → 质量管理 → 来料检验】按批次号/SN 逐条判合格。
- 接口:`POST /api/inspection/create``targetId` 传批次号或 SN,系统自动识别类型并定位到那条库存行;`status` 只能"合格/不合格"
- 7 次请求体(全部判合格):
```json
{"targetId":"PC-TLJ-001","status":"合格","inspectionType":"来料检","inspectQty":5,"passQty":5,"inspector":"质检01"}
{"targetId":"PC-MEN-001","status":"合格","inspectionType":"来料检","inspectQty":5,"passQty":5,"inspector":"质检01"}
{"targetId":"PC-LS-001","status":"合格","inspectionType":"来料检","inspectQty":100,"passQty":100,"inspector":"质检01"}
{"targetId":"SN-DQ-001","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"}
{"targetId":"SN-DQ-002","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"}
{"targetId":"SN-DQ-003","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"}
{"targetId":"SN-DQ-004","status":"合格","inspectionType":"来料检","inspectQty":1,"passQty":1,"inspector":"质检01"}
```
**系统反应**:每条检验在事务内建检验记录,并把定位到的那条库存行质量状态由「未检」改为「合格」。这一步是 Step 14 自动出库能领到货的前提(出库只领"合格"品)。
**数据变化**
- 检验记录表新增 7 行:目标类型(批次/SN 自动判定)、目标id、物料编码(由库存行回填)、状态=合格、检验数量、合格数量。
- 库存表:3 个批次行 + 4 个 SN 行的质量状态 全部由「未检」→「合格」。
**断言**
- `GET /api/inspection/query?materialCode=LS-01` 返回状态=合格 的记录。
- `GET /api/stock/query?materialCode=TLJ-01`:批次 PC-TLJ-001 质量状态=**合格**。
- 7 个目标(3 批次 + 4 SN)质量状态全部=合格;未检数量=0。
- 反例(可选):把某批判"不合格"后,该批在 Step 14 自动出库时被跳过(仅合格品可领料上线)。
---
### 阶段三 · 工单与排产
---
## Step 10:建工单(电表箱,数量 1)
**前置**Step 1(产品型号 DX-100,主键 `${productTypeId}`)。产线系统已登录。**产线上当前没有其他「执行中/已暂停」工单**(单工单互斥,否则 Step 12 下发会被拦)。
**操作**:计划员在【产线系统 → 生产管理 → 工单管理】点"新建工单",选产品型号=电表箱、数量=1、完成日期=2026-09-22。
- 接口:`POST /api/v1/work-orders`
- 请求体:
```json
{"productTypeId":${productTypeId},"productCode":"DX-100","productName":"电表箱","quantity":1,"dueDate":"2026-09-22"}
```
**系统反应**:创建工单,工单号未指定时按规则自动生成 `WO-<当天>-001`;状态恒为「已创建」(不允许直接建到后续状态)。
**数据变化**:工单表新增一行:工单号=`WO-20260922-001`(记作 `${orderNo}`)、产品编码=DX-100、产品名称=电表箱、数量=1、状态=**已创建(CREATED)**、已完工数=0。
**断言**
- `GET /api/v1/work-orders?orderNo=WO-20260922-001` 返回 1 条,数量=1、状态=已创建、已完工数=0。
- 记下工单主键 id(记作 `${orderId}`),Step 12/13 状态流转要用。
---
## Step 11:日排产(生产日 D,计划 1 台)
**前置**Step 10(工单 `${orderNo}` 状态=已创建,非终态可排产)。
**操作**:计划员在【产线系统 → 生产管理 → 日排产】为该工单排产到生产日 D。
- 接口:`POST /api/v1/daily-plans`
- 请求体:`{"orderNo":"WO-20260922-001","planDate":"2026-09-22","planQty":1}`
**系统反应**:校验该工单所有日排产累计不超过未开工数量(=数量1−已完工0−在产0=1),本次排 1 台,通过。新建排产,状态默认「待执行」。
**数据变化**:日排产表新增一行:工单号=WO-20260922-001、排产日=2026-09-22、计划数量=1、已完成数量=0、状态=**待执行(PENDING)**。
**断言**
- `GET /api/v1/daily-plans?orderNo=WO-20260922-001` 返回 1 条,计划数量=1、状态=待执行。
- 反例(可选):再排 planQty=1(累计2 > 未开工1)被拒,提示"排产合计数量超过未开工数量"。
---
## Step 12:工单下发(已创建 → 已下发)
**前置**:Step 10(工单状态=已创建)、Step 11(已排产)。产线无其他在产工单。
**操作**:计划员在【工单管理】对该工单点"下发"。
- 接口:`POST /api/v1/work-orders/status`
- 请求体:`{"id":${orderId},"status":"RELEASED","reason":"排产完成,下发生产"}`
**系统反应**:校验流转合法(已创建可下发)+ 单工单互斥(产线无其他执行中/暂停工单),状态改为「已下发」。
**数据变化**:工单表该行状态 由 已创建(CREATED) → **已下发(RELEASED)**;写状态变更日志(原状态/新状态/原因)。
**断言**
- `GET /api/v1/work-orders/:id``${orderId}`)状态=已下发。
- 非法流转(如已创建直接→执行中跳过下发,或→已完成)被拒,提示"不允许从「已创建」变更为「X」"。
---
## Step 13:工单开工(已下发 → 执行中,联动排产)
**前置**:Step 12(工单状态=已下发)、Step 11(排产状态=待执行)。
**操作**:生产主管在【工单管理】对该工单点"开工"。
- 接口:`POST /api/v1/work-orders/status`
- 请求体:`{"id":${orderId},"status":"IN_PROGRESS","reason":"产线开工"}`
**系统反应**:状态改为「执行中」;联动把该工单「待执行」的日排产置为「执行中」。
**数据变化**
- 工单表:状态 已下发(RELEASED) → **执行中(IN_PROGRESS)**
- 日排产表:WO-20260922-001 / 2026-09-22 那行状态 待执行(PENDING) → **执行中(PROCESSING)**
**断言**
- 工单状态=执行中。
- `GET /api/v1/daily-plans?orderNo=WO-20260922-001` 排产状态=执行中。
---
### 阶段四 · 备料与出库(生产日 D 早上)
---
## Step 14:生成备料单(按排产+派工算料,同步台账,自动出库领合格品)
**前置**Step 4BOM)、Step 6(生产日 D 的工位派工)、Step 9(库存全部合格)、Step 11(排产日 D 计划 1 台)、Step 13(工单执行中)。**执行当天 = D = 2026-09-22**(生成备料单用"系统当天"匹配派工生效日)。
**操作**:仓管/计划员在【产线系统 → 生产管理 → 备料管理】点"生成备料单",选排产日=2026-09-22。
- 接口:`POST /api/v1/material-requests/generate`
- 请求体:`{"planDate":"2026-09-22"}`
**系统反应**(一次触发三件事,顺序执行):
1. **算料**:按 BOM 物料的装配工序,拆到当天该工序派工的工位,生成工位级备料单。数量 = 工位分配产量 × 单台用量 ×(1+损耗率)。工序2 派到工位5、6,产量 1 台按工位号拆分给到工位5(工位6 分得 0,不生成)。
2. **同步台账**:把工单级需求总量下发库房「工单物料台账」(按物料聚合,需求量 = 工单数量 × 单台用量 ×(1+损耗率),向上取整)。
3. **自动出库**:对每张备料单按 FIFO 从"合格"库存领料——结构件按批次逐批扣、电气件按 SN 逐颗扣;出库量达标后回写备料单已发出量并置「已锁定」,台账累计出库达标置「领料完结」。
**数据变化**
- **备料单表**新增 4 行(工单 WO-20260922-001,排产日 2026-09-22):
| 备料单 | 物料 | 工位 | 工序 | 需求量 | 已发出 | 状态 |
|---|---|---|---|---|---|---|
| MR…001 | 铁架子 TLJ-01 | 2 | 1 | 1 | 1 | 已锁定(LOCKED) |
| MR…002 | 门子 MEN-01 | 2 | 1 | 1 | 1 | 已锁定 |
| MR…003 | 电气件 DQJ-01 | 5 | 2 | 2 | 2 | 已锁定 |
| MR…004 | 螺丝 LS-01 | 8 | 3 | 3 | 3 | 已锁定 |
- **工单物料台账表**新增 4 行:铁架子 总量1/出库1、门子 总量1/出库1、电气件 总量2/出库2、螺丝 总量3/出库3;4 行状态均=**领料完结**。
- **库存表扣减**:铁架子批次 PC-TLJ-001 数量 5→**4**;门子批次 PC-MEN-001 5→**4**;螺丝批次 PC-LS-001 100→**97**;电气件 SN-DQ-001、SN-DQ-002 状态 在库→**出库**SN-DQ-003/004 仍在库)。
- **出库单表**新增 5 笔(出库即扣库存,状态=已出库):铁架子 1 笔(数量1,批次PC-TLJ-001)、门子 1 笔(数量1)、螺丝 1 笔(数量3,批次PC-LS-001)、电气件 2 笔(每 SN 一笔,各数量1)。
- **出库明细表**:结构件按批次记、电气件按 SN 记。
**断言**
- `GET /api/v1/material-requests?orderNo=WO-20260922-001` 返回 **4** 张备料单,需求量分别 1/1/2/3、已发出=需求量、状态=已锁定。
- 台账:`GET /api/ledger/query?orderNo=WO-20260922-001`(库房侧)返回 4 行,出库量=总量、状态=领料完结。
- 库存:铁架子=4、门子=4、螺丝=97;电气件在库 SN 数=2SN-DQ-003、SN-DQ-004),出库 SN 数=2SN-DQ-001、SN-DQ-002)。
- **数量等式(出库阶段)**:铁架子 5=4+1;门子 5=4+1;螺丝 100=97+3;电气件 4=2(在库)+2(出库)。
---
## Step 15:接料确认(工位收到料)
**前置**:Step 14 生成 4 张备料单且已自动出库(已发出量>0)。工位终端已登录(Step 16 前的工位账号)或产线备料页人工确认。
**操作**:工位/仓管对 4 张备料单逐张确认接料(一键确认本批全部剩余)。
- 接口:`POST /api/v1/material-requests/receive`
- 4 次请求体(`qty` 传 0 表示"确认本批全部剩余"):
```json
{"requestNo":"MR…001","qty":0}
{"requestNo":"MR…002","qty":0}
{"requestNo":"MR…003","qty":0}
{"requestNo":"MR…004","qty":0}
```
**系统反应**:把已接料量累加到"已发出量"上限(不超接);当已发出≥需求量且已接料≥已发出时,备料单状态置「已完结」(送达与接料双完结)。
**数据变化**:4 张备料单:已接料量=已发出量(1/1/2/3),状态 已锁定(LOCKED) → **已完结(DONE)**;回填接料时间、接料人。
**断言**
- `GET /api/v1/material-requests?orderNo=WO-20260922-001` 4 张单 已接料量=已发出量、状态=已完结。
- 配送进度:在途量(已发出−已接料)= 0。
---
### 阶段五 · 上线装配(3 道工序顺序流转,禁止跳站)
---
## Step 16:工件上线(进线登记)
**前置**Step 13(工单执行中)、Step 15(4 张备料单已完结,料已到工位)。工位终端已登录(工位2 账号)。
**操作**:操作工在【工位终端 → 上线】扫工件序列号,选工单。
- 接口:`POST /api/v1/workpiece/online`
- 请求体:`{"sn":"WP-DX-0001","orderNo":"WO-20260922-001","workOrderId":${orderId}}`
**系统反应**:登记一台在制工件进线;路线不冗余存储,由当天工位派工实时派生(工位串 2,5,6,8)。当前工序置 0(尚未报任何工序)。
**数据变化**:工件表新增一行:序列号=WP-DX-0001、工单号=WO-20260922-001、状态=**已上线(ONLINE)**、当前工序=**0**。
**断言**
- `GET /api/v1/workpieces/in-process?orderNo=WO-20260922-001` 含 WP-DX-0001,状态=已上线、当前工序=0。
- 重复上线同一序列号被拒(工件已存在)。
---
## Step 17:报工工序 1(工位 2 · 装铁架子 + 门子)
**前置**:Step 16(工件已上线、当前工序=0)、Step 5(工位2 绑「装铁架子门子」流程)、Step 15(铁架子批次 PC-TLJ-001、门子批次 PC-MEN-001 已到工位2)。工位终端已登录(工位2)。
**操作**:操作工在工位2 扫工件号 → 装铁架子、装门子 → 扫两个结构件批次号绑定 → 点"报工"。
- 接口:`POST /api/v1/workpiece/process/report`
- 请求体(`binds` 结构件的 `bindValue` 传批次号):
```json
{"sn":"WP-DX-0001","processCode":1,"stationNo":2,
"binds":[{"materialCode":"TLJ-01","bindValue":"PC-TLJ-001"},
{"materialCode":"MEN-01","bindValue":"PC-MEN-001"}]}
```
**系统反应**:顺序校验(请求工序1 = 当前工序0+1,通过)→ 落装机绑定 → 齐套校验(工序1 的铁架子、门子各至少绑 1 个批次,通过)→ 在同一事务内写报工实绩、推进工件状态。任一步失败整体回滚。
**数据变化**
- 工件装配绑定表新增 2 行:WP-DX-0001 绑 铁架子批次 PC-TLJ-001、门子批次 PC-MEN-001(工序1、工位2)。
- 工件工序实绩表新增 1 行:工序=1、工位=2、状态=已完成、结果=**合格(OK)**、操作人、作业时长。
- 工件表:当前工序 0→**1**、状态 已上线(ONLINE)→**在制(PROCESSING)**。
**断言**
- 工件当前工序=1、状态=在制。
- `GET /api/v1/workpiece/process/records?sn=WP-DX-0001` 有工序1 记录,工位=2、结果=合格。
- 反例:若只绑铁架子不绑门子,报工被拒并返回缺料清单(门子未绑齐)。
---
## Step 18:报工工序 2(工位 5 · 装 2 颗电气件)
**前置**Step 17(当前工序=1)、Step 5(工位5 绑「装电气件」流程)、Step 15(电气件 SN-DQ-001、SN-DQ-002 已到工位5)。工位终端已登录(工位5)。
**操作**:操作工在工位5 扫工件号 → 逐颗扫 2 个电气件序列号绑定 → 点"报工"。
- 接口:`POST /api/v1/workpiece/process/report`
- 请求体(电气件的 `bindValue` 传序列号,必须绑满单台用量 2 颗):
```json
{"sn":"WP-DX-0001","processCode":2,"stationNo":5,
"binds":[{"materialCode":"DQJ-01","bindValue":"SN-DQ-001"},
{"materialCode":"DQJ-01","bindValue":"SN-DQ-002"}]}
```
**系统反应**:顺序校验(工序2 = 当前工序1+1,通过)→ 落绑定 → 齐套校验(电气件按单台用量逐颗序列号,必须绑满 2 颗,通过)→ 写实绩、推进工件状态。
> 说明:工位6 与工位5 同为工序2(并行位),本工件走工位5 完成工序2;工位6 在本链路不产生该工件的报工记录。
**数据变化**
- 工件装配绑定表新增 2 行:WP-DX-0001 绑 电气件 SN-DQ-001、SN-DQ-002(工序2、工位5)。
- 工件工序实绩表新增 1 行:工序=2、工位=5、状态=已完成、结果=合格(OK)。
- 工件表:当前工序 1→**2**、状态=在制(PROCESSING)。
**断言**
- 工件当前工序=2。
- `GET /api/v1/workpiece/process/records?sn=WP-DX-0001` 有工序2 记录,工位=5、结果=合格。
- 反例:只绑 1 颗电气件(少于单台用量2)报工被拒,提示电气件未绑齐。
---
## Step 19:拧紧上报(工位 8 · 拧 2 颗螺丝,扭矩判定)
**前置**:Step 5(工位8 绑「拧螺丝」流程,含 2 个扭矩步骤,扭矩标准 RANGE 8~12)、Step 15(螺丝批次 PC-LS-001 已到工位8)。工件当前工序=2(拧紧属工序3 工位,先采拧紧数据再报工序3)。工位终端已登录(工位8)。
**操作**:拧紧工具/操作工在工位8 对 2 颗螺丝分别上报扭矩。
- 接口:`POST /api/v1/torque/report`(工位终端经 `POST /api/internal/torque/report` 转发)
- 2 次请求体(`strain`=扭矩值 N·m,落在 8~12 内):
```json
{"sn":"WP-DX-0001","workOrderNo":"WO-20260922-001","stationNo":"8","screwNo":"1","strain":10,"angle":95,"operator":"操作工08"}
{"sn":"WP-DX-0001","workOrderNo":"WO-20260922-001","stationNo":"8","screwNo":"2","strain":11,"angle":92,"operator":"操作工08"}
```
**系统反应**:每颗写一条拧紧记录;并按「扭矩 / RANGE 8~12」标准自动判定,各写一条步骤考核数据(10、11 均在区间内 → 合格)。
**数据变化**
- 拧紧记录表新增 2 行:WP-DX-0001 / 工位8 / 螺丝序号1(扭矩10)、序号2(扭矩11),结果=合格(OK)。
- 步骤考核数据表新增 2 行:考核标准=扭矩、判定逻辑=区间(RANGE)、值=10 与 11、是否合格=是。
**断言**
- `GET /api/v1/torque/records?sn=WP-DX-0001&stationNo=8` 返回 2 条,扭矩=10、11,结果=合格。
- 拧紧汇总「应拧颗数=2、实拧颗数=2、合格=2、不合格=0」,满足判定=是。
- 反例:上报扭矩=13(超上限12)时该条判定=不合格(NG),并触发一条「拧紧扭矩不合格」预警。
---
## Step 20:报工工序 3(工位 8 · 装螺丝批次)
**前置**Step 18(当前工序=2)、Step 19(2 颗螺丝已拧紧合格)、Step 5(工位8 绑「拧螺丝」流程)。工位终端已登录(工位8)。
**操作**:操作工在工位8 扫工件号 → 扫螺丝批次号绑定 → 点"报工"。
- 接口:`POST /api/v1/workpiece/process/report`
- 请求体(结构件螺丝 `bindValue` 传批次号,至少绑 1 个批次):
```json
{"sn":"WP-DX-0001","processCode":3,"stationNo":8,
"binds":[{"materialCode":"LS-01","bindValue":"PC-LS-001"}]}
```
**系统反应**:顺序校验(工序3 = 当前工序2+1,通过)→ 落绑定 → 齐套校验(螺丝至少绑 1 个批次,通过)→ 写实绩、推进工件状态。工件走完全部 3 道工序。
**数据变化**
- 工件装配绑定表新增 1 行:WP-DX-0001 绑 螺丝批次 PC-LS-001(工序3、工位8)。
- 工件工序实绩表新增 1 行:工序=3、工位=8、状态=已完成、结果=合格(OK)。
- 工件表:当前工序 2→**3**、状态=在制(PROCESSING)。
**断言**
- 工件当前工序=3(= 路线工序总数)。
- `GET /api/v1/workpiece/process/records?sn=WP-DX-0001` 有工序1/2/3 三条实绩,结果均=合格。
- 反例:在工序2 未完成时直接报工序3(跳站),被拒提示"工序顺序不符,应在工位2 报工"。
---
### 阶段六 · 完工与成品入库
---
## Step 21:完工(兜底齐套校验 + 成品回流 + 反冲核销)
**前置**:Step 20(工件当前工序=3,三道工序物料均已绑齐)。工位终端已登录(下线工位)。
**操作**:操作工在【工位终端 → 下线完工】扫工件号,确认结构件批次与电气件序列号清单,点"完工"。
- 接口:`POST /api/v1/workpiece/done`
- 请求体(`batchItems` 结构件批次号、`serialItems` 电气件序列号):
```json
{"sn":"WP-DX-0001",
"batchItems":["PC-TLJ-001","PC-MEN-001","PC-LS-001"],
"serialItems":["SN-DQ-001","SN-DQ-002"]}
```
**系统反应**(一个事务内顺序完成 5 件事):
1. **兜底齐套校验**:复核工艺路线中每道工序的装配物料是否都绑齐(工序1 铁架子+门子、工序2 电气件×2、工序3 螺丝),通过。
2. **工件置完工**:工件状态改「已完工」,记完工时间。
3. **建关联追溯**:以成品序列号为主键,记录工单号、经过的工位串(`2,5,6,8`)、结构件批次清单、电气件序列号清单,形成"这台成品用了哪些料"的正向追溯。
4. **进度回写**:工单已完工数 +1(状态回「执行中」,不自动置已完成);日排产已完成数 +1,达计划量 1 → 排产置「已完成」。
5. **成品回流库房 + 反冲核销**:把成品作为一条新库存回流到库房(成品序列号=工件序列号);反冲按 BOM 单台用量核销工单台账的"已消耗量"(**只核销台账,不再动库存——库存已在 Step 14 出库时扣过**)。
**数据变化**
- 工件表:WP-DX-0001 状态 在制(PROCESSING)→**已完工(DONE)**,完工时间回填。
- 关联追溯表新增 1 行:成品序列号=WP-DX-0001、工单号=WO-20260922-001、工位串=2,5,6,8、批次清单=[PC-TLJ-001,PC-MEN-001,PC-LS-001]、序列号清单=[SN-DQ-001,SN-DQ-002]。
- 工单表:已完工数 0→**1**、状态=执行中(IN_PROGRESS)。
- 日排产表:已完成数 0→**1**,状态 执行中(PROCESSING)→**已完成(DONE)**。
- 库房库存表新增 1 行(成品回流):管理方式=2、品类=**成品(3)**、物料编码=DX-100、序列号=WP-DX-0001、数量=1、质量状态=合格、状态=在库、入库单号=`MES:WO-20260922-001`
- 工单物料台账表:铁架子已消耗 0→1、门子 0→1、电气件 0→2、螺丝 0→3(消耗量=单台用量×(1+损耗率) 取整:螺丝=2×1.5=3)。
**断言**
- 工件状态=已完工。
- `GET /api/v1/work-orders?orderNo=WO-20260922-001` 已完工数=1。
- `GET /api/v1/daily-plans?orderNo=WO-20260922-001` 已完成数=1、状态=已完成。
- 库房侧 `GET /api/stock/query?materialCode=DX-100` 返回 1 条成品库存,序列号=WP-DX-0001、品类=成品、数量=1、质量状态=合格、状态=在库。
- 台账已消耗量:铁架子1、门子1、电气件2、螺丝3;核销不产生新出库单、不再改动库存数量(螺丝库存仍=97)。
---
## Step 22:工单完工流转(执行中 → 已完成)
**前置**Step 21(工单已完工数=1 = 工单数量1,状态=执行中)。
**操作**:计划员在【产线系统 → 工单管理】对该工单点"完工"。
- 接口:`POST /api/v1/work-orders/status`
- 请求体:`{"id":${orderId},"status":"DONE","reason":"1 台已全部完工"}`
**系统反应**:校验流转合法(执行中可置已完成),状态改「已完成」。这是工单终态。
**数据变化**:工单表:状态 执行中(IN_PROGRESS)→**已完成(DONE)**;写状态变更日志。
**断言**
- `GET /api/v1/work-orders/:id` 状态=已完成、已完工数=1、数量=1。
- 已完工数=数量,工单闭合。
---
### 阶段七 · 多余料回仓库 + 成品追溯
---
## Step 23:工位退料(工位 8 · 螺丝用剩 1 颗)
**前置**:Step 21 完工。螺丝单台标准备料 3 颗(含 50% 损耗预留),实装拧 2 颗,剩 1 颗需退回库房。工位终端已登录(工位8)。
**操作**:操作工在【工位终端 → 退料】选工单、物料=螺丝、数量=1、原因="装配用剩退库",提交。
- 接口:`POST /api/return-material`(工位终端 → 产线内部接口 → 库房预建退库单)
- 请求体:
```json
{"orderNo":"WO-20260922-001","stationNo":8,"sn":"WP-DX-0001",
"materialCode":"LS-01","materialName":"螺丝","spec":"M4×10","unit":"颗",
"qty":1,"reason":"装配用剩退库"}
```
**系统反应**:产线系统落一条退料事件日志,转调库房预建一张「待确认收货」退库单(来源=工位)。库存在库管确认收货后才加回。
**数据变化**:库房退库单表新增 1 行:退库单号=`RT<...>`、来源类型=工位(station)、工单号=WO-20260922-001、工位=8、物料=LS-01 螺丝、数量=1、原因=装配用剩退库、状态=**待确认(PENDING)**。
**断言**
- 库房侧退库单列表存在该单,状态=待确认、数量=1。
- 此刻螺丝库存仍=97(尚未加回,等 Step 24 确认)。
---
## Step 24:库管确认收货(退库单 → 已收货,库存加回)
**前置**:Step 23(退库单待确认)。库房系统已登录(库管账号)。
**操作**:库管在【库房系统 → 退库管理】对该退库单点"确认收货",退库类型选"剩余物料",指定回退库位 A 区、批次 PC-LS-001。
- 接口:`POST /api/return-order/confirm`
- 请求体:`{"returnNo":"RT<上一步单号>","returnType":"surplus","zoneCode":"A","batchNo":"PC-LS-001"}`
**系统反应**:在一个事务内把退库单置「已收货」并把库存加回。剩余物料(surplus)按口径置质量状态「**未检**」——用剩的料不直接判合格,需复检后方可再上线,因此不并入原「合格」批次行,而是独立成一条未检库存行(同批次号 PC-LS-001、数量 1、质量状态未检)。
**数据变化**
- 退库单表:状态 待确认(PENDING)→**已收货(RECEIVED)**,回填收货人、收货时间。
- 库房库存表新增 1 行(螺丝退库):管理方式=1、物料=LS-01、批次=PC-LS-001、数量=1、质量状态=**未检**、状态=在库、区域=A、入库单号=`RET:RT<单号>`
- 工单物料台账表(螺丝行):已退回量 0→**1**;净领用(已出库 3 − 已退回 1 = 2)< 需求量 3,状态由「领料完结」**回退为「进行中」**(退料回补缺口,允许后续再补料)。
**断言**
- 退库单状态=已收货。
- `GET /api/stock/query?materialCode=LS-01`:合格批次 PC-LS-001 数量=97(未变),另有一条未检 PC-LS-001 数量=1;螺丝在库总量=97+1=**98**。
- 台账螺丝行:已出库=3、已退回=1、净领用=2、已消耗=3、状态=进行中。
- **数量等式(螺丝全链路闭合)**:入库 100 = 出库 3 + 期末在库 97;出库 3 = 装进成品 2 + 退回 1;退回 1 → 未检库存 1。总库存 98 = 97(合格) + 1(未检退回)。
---
## Step 25:成品追溯(按成品序列号回查全链路)
**前置**:Step 21(关联追溯已建)、Step 19(拧紧记录)、Step 17~20(三道工序实绩)。产线系统或工位终端已登录。
**操作**:质量员在【产线系统 → 追溯查询】扫成品序列号 WP-DX-0001。
- 接口:`GET /api/v1/trace?sn=WP-DX-0001`(工位终端经 `GET /api/trace?sn=` 代理)
**系统反应**:以成品序列号汇总回查:工件状态、工单、经过的工位串、每道工序的报工时间与操作人、装机的结构件批次与电气件序列号、拧紧扭矩数据。
**数据变化**:只读查询,不改数据。
**断言**
- 追溯返回:成品序列号=WP-DX-0001、工单=WO-20260922-001、工件状态=已完工、工位串=2,5,6,8。
- 工序时间线含工序1(工位2)、工序2(工位5)、工序3(工位8) 三条实绩,结果均合格。
- 物料清单:铁架子批次 PC-TLJ-001、门子批次 PC-MEN-001、螺丝批次 PC-LS-001、电气件序列号 SN-DQ-001 与 SN-DQ-002。
- 拧紧数据:2 颗,扭矩 10 与 11,均合格。
---
## 四、全链路数量等式总断言(跑完必须全部闭合)
| 物料 | 入库(Step7/8) | 出库到工位(Step14) | 装进成品(Step17~21) | 退回库房(Step23/24) | 期末在库 |
|---|---|---|---|---|---|
| 铁架子 TLJ-01 | 5 | 1 | 1 | 0 | 4 |
| 门子 MEN-01 | 5 | 1 | 1 | 0 | 4 |
| 电气件 DQJ-01 | 4(SN) | 2(SN001/002) | 2 | 0 | 2(SN003/004 在库) |
| 螺丝 LS-01 | 100 | 3 | 2 | 1 | 98(97合格+1未检) |
| 成品 DX-100 | — | — | 下线 1(WP-DX-0001) | — | 1(合格·在库) |
**闭合校验(逐条必须成立)**
- 铁架子:5 = 4(在库) + 1(装进成品)。
- 门子:5 = 4(在库) + 1(装进成品)。
- 电气件:4 = 2(SN003/004 在库) + 2(SN001/002 装进成品)。
- 螺丝:100 = 97(合格在库) + 3(出库);出库 3 = 2(装进成品) + 1(退回未检);期末在库 98 = 97 + 1。
- 工单:数量 1 = 已完工 1;工单状态=已完成。
- 日排产:计划 1 = 已完成 1;排产状态=已完成。
- 台账(Step21 反冲后、Step24 退库后最终态):铁架子 已出库=已消耗=总量=1、状态领料完结;门子 已出库=已消耗=总量=1、状态领料完结;电气件 已出库=已消耗=总量=2、状态领料完结;螺丝 已出库=总量=3、已消耗=3(按 BOM 单台标准量 2×1.5 计)、已退回=1、净领用=2、状态因退料回退为进行中。
- 关联追溯:成品 WP-DX-0001 的批次清单 3 项 + 序列号清单 2 项,与装进成品列完全一致。
---
## 五、回归后数据复位(供重复执行)
> 本链路会写入成品序列号 WP-DX-0001(全局唯一)、批次 PC-* 与序列号 SN-DQ-*(全局唯一)。重复执行前需清理,否则上线/入库会撞唯一约束。
复位顺序(与建数据相反):
1. 删除关联追溯、工件工序实绩、工件装配绑定、拧紧记录、步骤考核数据(按 sn=WP-DX-0001)。
2. 删除工件(WP-DX-0001)、日排产、工单(WO-20260922-001)及其状态日志。
3. 删除备料单、工单物料台账(按 orderNo)。
4. 删除库房退库单、出库单及明细、入库单及明细、检验记录、库存行(成品 DX-100 与 4 种零部件的批次/SN 行)。
5. 删除工位派工(生产日 D)、工艺流程与工序步骤/考核标准、产品物料清单、物料档案、产品型号、区域 A(如与其他用例共用则保留)。
> 若只需快速重跑,可保留主数据(Step1~6),仅清理 Step7 起的库存/单据/工件数据,并从 Step7 重新入库。