368 lines
14 KiB
Markdown
368 lines
14 KiB
Markdown
# 状态中心 ↔ 艺赛旗并行开发方案
|
|
|
|
## 核心原则:契约驱动,各自独立,最后对接
|
|
|
|
双方只通过 **HTTP 回调契约** 交互,这个契约在交接文档里已经明确定义。在对接前,双方各自用假数据/假回调验证自己的逻辑,互不阻塞。
|
|
|
|
---
|
|
|
|
## 对接契约(双方共同遵守)
|
|
|
|
### 基础信息
|
|
- **状态中心地址**:联调时给艺赛旗实际 IP,如 `http://192.168.x.x:8000`
|
|
- **鉴权**:所有回调必须带 header `X-Agent-Token: <token>`(默认 `dev-agent-token`,上线换正式值)
|
|
- **幂等键**:`complete` 回调可带 `idempotencyKey`,重发同键不会二次推进
|
|
|
|
### 三个回调接口(艺赛旗调状态中心)
|
|
|
|
#### 1. 节点开始
|
|
```bash
|
|
POST /api/jobs/{jobId}/nodes/{nodeCode}/start
|
|
Content-Type: application/json
|
|
X-Agent-Token: dev-agent-token
|
|
|
|
{
|
|
"attemptNo": 1,
|
|
"executorPlatform": "iS-RPA",
|
|
"operator": "agent"
|
|
}
|
|
```
|
|
|
|
#### 2. 节点成功
|
|
```bash
|
|
POST /api/jobs/{jobId}/nodes/{nodeCode}/complete
|
|
Content-Type: application/json
|
|
X-Agent-Token: dev-agent-token
|
|
|
|
{
|
|
"attemptNo": 1,
|
|
"executorRunId": "YD-RUN-001",
|
|
"idempotencyKey": "uuid-xxx",
|
|
"businessRefs": {
|
|
"contractSystemNo": "HT2026...", // 三把钥匙,对应节点必传
|
|
"rebateOrderNo": "FL2026...",
|
|
"m5OrderNo": "M5-xxx",
|
|
"receiptNoticeNo": "SH-xxx"
|
|
},
|
|
"summary": { "orderCount": 12 },
|
|
"artifacts": [
|
|
{
|
|
"artifactType": "SOURCE_EXCEL",
|
|
"storagePath": "/data/jobs/xxx/orders.xlsx",
|
|
"fileHash": "sha256:abc",
|
|
"visibleRoles": ["PURCHASER", "PLANNER"],
|
|
"isMasked": false
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**返回**:`{"ok": true, "next_node": "OCR_EXTRACT"}` ← 艺赛旗拿到 `next_node` 继续跑下一节点
|
|
|
|
#### 3. 节点失败
|
|
```bash
|
|
POST /api/jobs/{jobId}/nodes/{nodeCode}/fail
|
|
Content-Type: application/json
|
|
X-Agent-Token: dev-agent-token
|
|
|
|
{
|
|
"attemptNo": 1,
|
|
"errorCode": "SYS_LOGIN_FAIL", // 见交接文档错误码表
|
|
"errorSummary": "验证码识别失败",
|
|
"retryable": true, // 系统类填 true,业务类填 false
|
|
"routeRole": "OPS", // OPS/PLANNER/PURCHASER
|
|
"artifacts": []
|
|
}
|
|
```
|
|
|
|
**返回**:`{"ok": true, "job_status": "FAILED_RETRYABLE"}`
|
|
|
|
### 必须回传的业务编号(三把钥匙)
|
|
|
|
| 节点 | 必传字段 | 说明 |
|
|
| --- | --- | --- |
|
|
| CONTRACT_CREATE | `contractSystemNo` | 合同编号(后续返利、M5靠它串) |
|
|
| REBATE_HEADER | `rebateOrderNo` | 返利中心总单号 |
|
|
| M5_RECEIPT_NOTICE | `receiptNoticeNo` | 收货通知单号(全链终点) |
|
|
|
|
不传或传空,状态中心返回 **400 拒绝**。
|
|
|
|
### 错误码规范(部分,全表见交接文档)
|
|
|
|
| 错误码 | 含义 | retryable | routeRole |
|
|
| --- | --- | --- | --- |
|
|
| SYS_LOGIN_FAIL | 登录失败 | true | OPS |
|
|
| SYS_PAGE_TIMEOUT | 页面超时 | true | OPS |
|
|
| UI_ELEMENT_NOT_FOUND | 页面改版找不到元素 | false | OPS |
|
|
| BIZ_CONTRACT_DISABLED | 供应商合同被禁 | false | PURCHASER |
|
|
| M5_QC_MISSING | M5质管资料缺失 | - | - |
|
|
| REBATE_DUP_CODE | 返利重复编码 | false | PURCHASER |
|
|
|
|
**特殊规则**:`M5_QC_MISSING` 无条件转 `FAILED_MANUAL`,`retryable` 填什么都没用。
|
|
|
|
---
|
|
|
|
## 状态中心这边(你的任务)
|
|
|
|
### 阶段1:独立验证(不依赖艺赛旗)
|
|
**时间**:1-2天
|
|
**目标**:后端在真 MySQL 上用假回调跑通全链
|
|
|
|
#### 任务
|
|
1. **环境准备**
|
|
- Docker 起 MySQL 8,执行 `schema.sql` 建库。
|
|
- 配 `MYSQL_DSN`,起后端服务。
|
|
- 前端 `npm run dev` 起来。
|
|
|
|
2. **用假回调跑通一单**
|
|
- 方式1:用 curl 按顺序调回调接口。
|
|
- 方式2:用前端"开发:节点回调模拟"区域的按钮。
|
|
- **路径**:建单 → ORDER_FETCH start/complete → PRODUCT_MATCH run(有 MULTI) → 人工确认 → SOURCE_ADD 人工提交 → CONTRACT_CREATE complete(带合同编号) → ... → ARCHIVE_JOB。
|
|
- **验证点**:
|
|
- job 状态正确推进(PENDING → RUNNING → WAITING_USER → ...)。
|
|
- 业务编号正确落库(合同编号、返利总单号、M5单号、收货通知单号)。
|
|
- job_node 每个节点有历史记录,attempt_no 正确。
|
|
- user_task 在该创建时创建,提交后关闭。
|
|
- job_artifact 证据落库。
|
|
- 条件节点(OCR_EXTRACT/SOURCE_ADD)正确跳过或执行。
|
|
|
|
3. **发现并修复真实问题**
|
|
- SQL 语法问题(如 MySQL 8 的保留字冲突)。
|
|
- JSON 列序列化问题(Python dict → MySQL JSON → 前端拿到的是对象还是字符串)。
|
|
- 事务回滚是否正确。
|
|
- datetime 字段格式(MySQL 存的 `YYYY-MM-DD HH:MM:SS`,前端拿到的格式)。
|
|
- 幂等逻辑是否真的防重(重复 complete 同一节点,状态不会乱)。
|
|
|
|
4. **记录真实 API 响应**
|
|
- 把 `GET /api/jobs/{id}` 的完整响应存下来,给 UI 优化做参考。
|
|
|
|
#### 产出
|
|
- ✅ 一个能在真 MySQL 上跑通全链的后端(用假回调验证)。
|
|
- ✅ 一份真实响应示例 + 发现的问题清单。
|
|
- ✅ 前端能正常展示真实数据(不再依赖 `demoJobDetailMap`)。
|
|
|
|
### 阶段2:优化与补全(不依赖艺赛旗)
|
|
**时间**:2-3天
|
|
**目标**:UI 优化 + 补缺失接口 + 加调度重试
|
|
|
|
#### 任务
|
|
1. **UI 优化**
|
|
- 按刚才的方案,分区 + 可折叠 + 调试开关。
|
|
- 基于阶段1 的真实响应,确保所有字段正确展示。
|
|
|
|
2. **补缺失接口**
|
|
- `GET /api/jobs/{id}/match/unmatched`:返回该 job 未命中的订单行列表。
|
|
- 其他小接口(如果阶段1 发现有遗漏)。
|
|
|
|
3. **调度与重试(任务6)**
|
|
- 定时建单:每天早上扫前一天订单。
|
|
- 系统类错误自动重试(`FAILED_RETRYABLE` 状态的 job,重试 1-2 次)。
|
|
- 超时升级:合同审批超时、人工待办超时转 OPS。
|
|
|
|
#### 产出
|
|
- ✅ 优化后的前端(信息分层清晰,调试模式可开关)。
|
|
- ✅ 完整的接口(验收点名的都实现)。
|
|
- ✅ 调度器能定时触发建单和重试。
|
|
|
|
### 阶段3:准备对接(等艺赛旗阶段2 完成)
|
|
**时间**:半天
|
|
**目标**:给艺赛旗提供联调环境
|
|
|
|
#### 任务
|
|
1. **部署联调环境**
|
|
- 把后端部署到艺赛旗能访问的机器(或你本机开端口映射)。
|
|
- 给艺赛旗提供:基础地址(如 `http://192.168.x.x:8000`) + 正式 `X-Agent-Token`。
|
|
|
|
2. **准备测试数据**
|
|
- 在库里建几个不同类型的 job:
|
|
- 医药城线上单(会跳过 OCR_EXTRACT)。
|
|
- 线下单(会走 OCR_EXTRACT)。
|
|
- 有对码 MULTI 的单。
|
|
- 缺货源的单(会走 SOURCE_ADD)。
|
|
- 每个 job 停在 ORDER_FETCH 节点,等艺赛旗来调 start/complete 推进。
|
|
|
|
3. **写联调检查表**
|
|
- 逐节点列验收点,双方对着检查表勾。
|
|
|
|
#### 产出
|
|
- ✅ 一个可供艺赛旗调用的联调环境。
|
|
- ✅ 测试数据 + 联调检查表。
|
|
|
|
---
|
|
|
|
## 艺赛旗那边(你要转述给他们)
|
|
|
|
### 阶段1:独立开发(不依赖状态中心)
|
|
**时间**:2-3周(他们的活重)
|
|
**目标**:每个节点的页面自动化都能独立跑通
|
|
|
|
#### 任务
|
|
1. **理解回调契约**
|
|
- 仔细读 `给艺赛旗的开发交接.md`。
|
|
- 确认三个回调接口的字段、错误码表。
|
|
|
|
2. **逐节点开发页面自动化**
|
|
- **节点顺序**(他们的优先级):
|
|
1. ORDER_FETCH(订单获取):登录医药城/小药药 → 导出 Excel → 存证据。
|
|
2. CONTRACT_CREATE(合同建单):登录合同系统 → 填表 → 上传 PDF(医药城) → 提交送审 → 拿到合同编号。
|
|
3. REBATE_HEADER(返利总单):登录返利中心 → 按合同编号查总单 → 填必填项 → 保存 → 拿到返利总单号。
|
|
4. REBATE_IMPORT(返利细单):下载模板 → 填字段 → 上传 → 读成功/失败行。
|
|
5. REBATE_SUBMIT(返利送审):点"提交送审"按钮。
|
|
6. M5_CREATE_ORDER(M5建单):桌面自动化 → 录单 → **停,不保存**。
|
|
7. CONTRACT_APPROVE_WAIT(合同审批):定时查审批状态(到点被状态中心扫到时才查一次)。
|
|
|
|
- **每个节点独立验证**:
|
|
- 不调状态中心,在自己环境里跑(比如用测试账号登录真实系统,手工给初始数据)。
|
|
- 验证能拿到业务编号(合同编号、返利总单号等)。
|
|
- 验证错误情况能识别出正确的错误码(如登录失败是 `SYS_LOGIN_FAIL`,合同被禁是 `BIZ_CONTRACT_DISABLED`)。
|
|
|
|
3. **本地模拟回调**
|
|
- 自己起个假的状态中心(或者直接用 curl 打印 JSON),验证回调 payload 格式对不对。
|
|
- 示例(他们自己写个小脚本验证):
|
|
```python
|
|
# 假的状态中心 mock.py
|
|
from flask import Flask, request, jsonify
|
|
app = Flask(__name__)
|
|
|
|
@app.route('/api/jobs/<job_id>/nodes/<node_code>/complete', methods=['POST'])
|
|
def complete(job_id, node_code):
|
|
data = request.json
|
|
print(f"收到 {node_code} complete:", data)
|
|
# 检查必传字段
|
|
if node_code == 'CONTRACT_CREATE' and not data.get('businessRefs', {}).get('contractSystemNo'):
|
|
return jsonify({"error": "缺少合同编号"}), 400
|
|
return jsonify({"ok": True, "next_node": "下一节点"})
|
|
|
|
app.run(port=8000)
|
|
```
|
|
|
|
#### 产出
|
|
- ✅ 每个节点的页面自动化脚本(iS-RPA 流程)。
|
|
- ✅ 能正确识别各种错误并返回对应错误码。
|
|
- ✅ 能拿到三把钥匙(合同编号、返利总单号、收货通知单号)。
|
|
|
|
### 阶段2:准备对接(等状态中心阶段3 准备好)
|
|
**时间**:1天
|
|
**目标**:改成调真实状态中心接口
|
|
|
|
#### 任务
|
|
1. **获取联调环境信息**
|
|
- 从状态中心拿到:基础地址 + `X-Agent-Token`。
|
|
|
|
2. **改造回调逻辑**
|
|
- 把阶段1 的假回调改成调真实状态中心接口。
|
|
- **关键**:拿到 `complete` 返回的 `next_node`,继续跑下一节点(不要自己写死顺序)。
|
|
|
|
3. **小范围试跑**
|
|
- 先跑一个最简单的节点(如 ORDER_FETCH),验证回调能调通、状态中心能正确推进。
|
|
|
|
#### 产出
|
|
- ✅ 能调通状态中心回调接口的 RPA 脚本。
|
|
|
|
---
|
|
|
|
## 联调阶段(双方一起)
|
|
|
|
**时间**:3-5天
|
|
**目标**:端到端跑通一单真实流程
|
|
|
|
### 任务
|
|
1. **按节点逐个验证**
|
|
- 顺序:ORDER_FETCH → (OCR_EXTRACT) → PRODUCT_MATCH(状态中心内部) → (SOURCE_ADD 人工) → CONTRACT_CREATE → ...
|
|
- 每个节点验证:
|
|
- RPA 能正确调 start/complete/fail。
|
|
- 状态中心正确推进到下一节点或转人工。
|
|
- 业务编号正确落库。
|
|
- 证据正确存储。
|
|
|
|
2. **跑完整链**
|
|
- 医药城线上单(跳过 OCR)。
|
|
- 线下单(走 OCR)。
|
|
- 有对码 MULTI 的单(走人工确认)。
|
|
- 缺货源的单(走 SOURCE_ADD 人工)。
|
|
- 合同审批等待(定时查几次,验证不会死等)。
|
|
|
|
3. **异常场景**
|
|
- 登录失败 → 重试。
|
|
- 页面改版找不到元素 → 转 OPS。
|
|
- M5 质管缺失 → 直接 FAILED_MANUAL,不重试。
|
|
- 返利重复编码 → 该单挂起,整批继续。
|
|
|
|
4. **对照验收规范逐条勾**
|
|
- 打开 `实施与验收规范.md`,每个节点的代码验收 + 业务验收两栏逐条过。
|
|
|
|
### 产出
|
|
- ✅ 一个能端到端跑通的完整流程(从订单获取到归档)。
|
|
- ✅ 验收报告(哪些通过,哪些有问题)。
|
|
|
|
---
|
|
|
|
## 时间线(并行开发)
|
|
|
|
```
|
|
第1周 第2周 第3周
|
|
状态中心 │────阶段1────│───阶段2───│──阶段3──│────联调────│
|
|
真MySQL跑通 UI优化+补全 准备环境 与艺赛旗对接
|
|
(1-2天) (2-3天) (半天) (3-5天)
|
|
|
|
艺赛旗 │────────────阶段1────────────│─阶段2─│────联调────│
|
|
独立开发各节点页面自动化 改真回调 与状态中心对接
|
|
(2-3周) (1天) (3-5天)
|
|
```
|
|
|
|
**关键点**:
|
|
- 前两周双方完全独立,互不阻塞。
|
|
- 状态中心先做完(1周内),等艺赛旗追上。
|
|
- 艺赛旗开发周期长(页面自动化细节多),但不影响状态中心进度。
|
|
- 第3周开始联调,双方都已在各自环境验证过,对接就是走形式。
|
|
|
|
---
|
|
|
|
## 给艺赛旗的检查清单(转述)
|
|
|
|
在开始联调前,艺赛旗必须自证能做到:
|
|
|
|
### 功能检查
|
|
- [ ] 能登录医药城/小药药/合同系统/返利中心/M5,并正确处理验证码/超时。
|
|
- [ ] 能导出订单 Excel 并存到指定路径。
|
|
- [ ] 能建合同、上传 PDF(医药城)、拿到合同编号。
|
|
- [ ] 能在返利中心按合同编号查总单、填表、拿到返利总单号。
|
|
- [ ] 能下载返利细单模板、填字段、上传、读成功/失败行。
|
|
- [ ] 能点返利送审按钮。
|
|
- [ ] 能用桌面自动化在 M5 录单(但不保存)。
|
|
- [ ] 能定时查合同审批状态(不是连续轮询,是到点查一次)。
|
|
|
|
### 回调检查
|
|
- [ ] 知道何时调 start、何时调 complete、何时调 fail。
|
|
- [ ] complete 时能正确带 `businessRefs`(三把钥匙对应节点必传)。
|
|
- [ ] fail 时能正确识别错误码(`SYS_*` vs `BIZ_*`,`retryable` 填对)。
|
|
- [ ] 拿到 `next_node` 后能继续跑下一节点(不写死顺序)。
|
|
- [ ] 所有回调都带 `X-Agent-Token` header。
|
|
|
|
### 异常检查
|
|
- [ ] 登录失败时返回 `SYS_LOGIN_FAIL`,`retryable=true`。
|
|
- [ ] 页面改版找不到元素时返回 `UI_ELEMENT_NOT_FOUND`,`retryable=false`,`routeRole=OPS`。
|
|
- [ ] M5 质管缺失时返回 `M5_QC_MISSING`(状态中心会直接转 FAILED_MANUAL,不重试)。
|
|
- [ ] 供应商合同被禁时返回 `BIZ_CONTRACT_DISABLED`,`retryable=false`,`routeRole=PURCHASER`。
|
|
|
|
---
|
|
|
|
## 总结
|
|
|
|
**你现在要做的**:
|
|
1. 马上开始阶段1(真 MySQL 跑通),1-2天搞定。
|
|
2. 接着做阶段2(UI 优化 + 补全),2-3天搞定。
|
|
3. 然后做阶段3(准备联调环境),半天搞定。
|
|
4. **这时你这边已经全部做完**,等艺赛旗追上(他们要 2-3 周)。
|
|
|
|
**艺赛旗要做的**(你转述给他们):
|
|
1. 阶段1:独立开发各节点页面自动化,2-3周。期间不需要状态中心配合,自己用假数据验证。
|
|
2. 阶段2:拿到状态中心联调环境信息后,改成调真实接口,1天。
|
|
3. 联调阶段:双方一起按检查表逐条验收,3-5天。
|
|
|
|
**不会互相阻塞**:你 1 周内做完你的,艺赛旗 2-3 周做完他们的,最后 3-5 天一起联调。
|
|
|
|
---
|
|
|
|
要我把这份文档发给艺赛旗吗?或者你先看看有没有要调整的。
|