911 lines
27 KiB
Markdown
911 lines
27 KiB
Markdown
# 采购主链 RPA 一期 Implementation Plan
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** 建成采购主链一期的轻量状态中心、统一 RPA 执行适配层、企业微信手机协同入口,以及支撑 OCR、返利中心、M5 流程追踪的最小可用中台。
|
||
|
||
**Architecture:** 采用“RPA 执行平台 + Python/MySQL 状态中心 + 本地 OCR + 企业微信 H5 协同”的分层方案。状态中心负责建单、节点状态机、幂等、待办、日志、审计和执行平台路由,底层 RPA 平台只负责外部系统操作与结果回传,企业微信只负责通知与手机端操作入口。
|
||
|
||
**Tech Stack:** Python、MySQL、HTTP API、RPA 执行平台(影刀 / 艺赛旗等)、企业微信应用、本地 OCR(PaddleOCR 优先)
|
||
|
||
---
|
||
|
||
## 0. 使用说明
|
||
|
||
本文件既可作为技术实施底稿,也可作为后续拆更细执行计划的母稿。
|
||
|
||
## 1. 文档定位
|
||
|
||
本文面向开发、测试、实施和项目负责人,目标是把 [PLAN.md](/Users/yuuuu/Documents/AutoRpa/资料/PLAN.md) 进一步落成“可排期、可拆人、可建库、可对接口”的实施稿。
|
||
|
||
默认前提:
|
||
|
||
- 一期范围只覆盖 `合同扫描件/合同系统 -> 返利中心采购协议 -> M5 采购订单`
|
||
- RPA 执行平台负责页面操作
|
||
- Python + MySQL 负责状态中心
|
||
- 企业微信负责消息通知和 H5 处理入口
|
||
- OCR 一期采用本地部署方案
|
||
|
||
如果后续要正式开工,建议以本文件作为技术排期底稿,再补充具体工期、负责人和环境信息。
|
||
|
||
---
|
||
|
||
## 2. 推荐项目结构
|
||
|
||
当前仓库还没有正式代码结构,一期建议直接按下面的边界建工程,避免把流程编排、RPA 平台回调、企业微信回调、查询页混在一起。
|
||
|
||
```text
|
||
AutoRpa/
|
||
├── 资料/
|
||
│ ├── PLAN.md
|
||
│ ├── 一期开发任务清单_表结构_API草案.md
|
||
│ └── 一期需求简版说明_业务版.md
|
||
├── backend/
|
||
│ ├── app/
|
||
│ │ ├── main.py
|
||
│ │ ├── config.py
|
||
│ │ ├── db.py
|
||
│ │ ├── models/
|
||
│ │ │ ├── job.py
|
||
│ │ │ ├── job_node.py
|
||
│ │ │ ├── user_task.py
|
||
│ │ │ ├── mapping_config.py
|
||
│ │ │ ├── job_artifact.py
|
||
│ │ │ └── job_event.py
|
||
│ │ ├── schemas/
|
||
│ │ │ ├── job.py
|
||
│ │ │ ├── task.py
|
||
│ │ │ ├── node_callback.py
|
||
│ │ │ └── wecom.py
|
||
│ │ ├── api/
|
||
│ │ │ ├── jobs.py
|
||
│ │ │ ├── tasks.py
|
||
│ │ │ ├── admin.py
|
||
│ │ │ └── wecom.py
|
||
│ │ ├── services/
|
||
│ │ │ ├── intake_service.py
|
||
│ │ │ ├── workflow_service.py
|
||
│ │ │ ├── retry_service.py
|
||
│ │ │ ├── task_service.py
|
||
│ │ │ ├── executor_router.py
|
||
│ │ │ ├── ocr_service.py
|
||
│ │ │ ├── mapping_service.py
|
||
│ │ │ ├── artifact_service.py
|
||
│ │ │ └── wecom_service.py
|
||
│ │ ├── integrations/
|
||
│ │ │ ├── rpa/
|
||
│ │ │ │ ├── base_adapter.py
|
||
│ │ │ │ ├── yingdao_adapter.py
|
||
│ │ │ │ └── isearch_adapter.py
|
||
│ │ │ ├── paddle_ocr_client.py
|
||
│ │ │ └── wecom_client.py
|
||
│ │ └── views/
|
||
│ │ └── h5_task_page.py
|
||
│ ├── migrations/
|
||
│ └── tests/
|
||
│ ├── api/
|
||
│ ├── services/
|
||
│ └── integration/
|
||
├── agent-contract/
|
||
│ ├── node_callback_examples.json
|
||
│ └── error_codes.md
|
||
└── deployment/
|
||
├── env.example
|
||
├── nginx.conf
|
||
└── systemd/
|
||
```
|
||
|
||
边界原则:
|
||
|
||
- `api/` 只收发请求,不放业务流程判断
|
||
- `services/` 负责状态迁移、幂等、路由、重试、消息发送
|
||
- `integrations/` 只封装外部系统调用
|
||
- `executor_router.py` 统一决定节点该交给哪个平台执行
|
||
- `models/` 和 `schemas/` 分开,避免数据库对象和接口对象互相污染
|
||
|
||
---
|
||
|
||
## 3. 自有能力边界与多平台策略
|
||
|
||
我们自己的能力必须沉淀在状态中心中:
|
||
|
||
- 流程主状态
|
||
- 合同入池、判重、幂等
|
||
- OCR 归档和映射配置
|
||
- 手机待办、人工协同、角色路由
|
||
- 成功判定、错误码体系、证据归档
|
||
- 多平台统一查询和统一审计
|
||
|
||
RPA 平台提供的是底层执行能力:
|
||
|
||
- 桌面/UI 自动化
|
||
- 文件上传下载
|
||
- 表单填写与模板导入
|
||
- 截图、日志、录屏
|
||
- 对状态中心发起回调
|
||
|
||
多平台切换边界必须明确:
|
||
|
||
- 支持“按新单切换平台”
|
||
- 支持“按节点配置平台”
|
||
- 不支持“半节点执行过程中跨平台接力”
|
||
- 平台切换前先跑统一 POC 用例
|
||
|
||
---
|
||
|
||
## 4. 里程碑与开发任务清单
|
||
|
||
## Milestone 0:项目初始化与基础设施
|
||
|
||
目标:把后端服务、数据库连接、配置管理、日志规范先搭起来。
|
||
|
||
任务清单:
|
||
|
||
1. 创建 `backend/app/main.py`,跑通基础 HTTP 服务
|
||
2. 创建 `backend/app/config.py`,统一读取数据库、OCR、企业微信、RPA 平台回调密钥配置
|
||
3. 创建 `backend/app/db.py`,封装 MySQL 连接和事务入口
|
||
4. 建立 `backend/tests/` 目录,先接入最基础的接口测试框架
|
||
5. 创建 `deployment/env.example`,列出所有必需环境变量
|
||
6. 定义统一日志字段:`trace_id`、`job_id`、`node_code`、`task_id`
|
||
|
||
交付物:
|
||
|
||
- 服务能启动
|
||
- 健康检查接口可用
|
||
- 数据库连接可用
|
||
- 开发/测试环境变量模板可发给团队
|
||
|
||
## Milestone 1:入池建单与判重
|
||
|
||
目标:把“共享目录文件 -> 状态中心建单 -> 判重 -> 可追踪 job”跑通。
|
||
|
||
任务清单:
|
||
|
||
1. 建 `job`、`job_artifact`、`job_event` 三张核心表
|
||
2. 开发 `POST /api/jobs` 建单接口
|
||
3. 开发共享目录文件入池服务,读取文件基础元数据
|
||
4. 实现文件哈希计算与 `source_file_hash` 去重逻辑
|
||
5. 实现业务唯一键判重逻辑:`合同编号 + 合同类型 + 供应商 + 发起来源`
|
||
6. 入池失败时生成事件记录和人工待处理状态
|
||
7. 支持通过状态中心页面手工建单,作为共享目录监听的兜底入口
|
||
|
||
交付物:
|
||
|
||
- 同一合同重复上传不会生成多条未完成流程
|
||
- 文件命名异常可被识别并阻断
|
||
- 每次建单都有 `job_id`
|
||
|
||
## Milestone 2:OCR 与映射规则
|
||
|
||
目标:把扫描件变成结构化字段,并明确哪些能自动映射、哪些必须转人工。
|
||
|
||
任务清单:
|
||
|
||
1. 创建 `mapping_config` 表和版本字段
|
||
2. 建立 OCR 适配接口,统一输出 JSON
|
||
3. 保存原始 OCR JSON 到 `job_artifact`
|
||
4. 实现供应商、货品、结算方式、承付模式映射服务
|
||
5. 实现置信度阈值判断和低置信度转待办逻辑
|
||
6. 为每个 `job` 绑定 `mapping_version`
|
||
7. 把字段识别结果、映射结果写入 `job_event`
|
||
|
||
交付物:
|
||
|
||
- OCR 结果可追溯
|
||
- 映射规则支持版本化
|
||
- 低置信度不会自动猜测后继续执行
|
||
|
||
## Milestone 3:流程编排与节点状态机
|
||
|
||
目标:把节点开始、成功、失败、待人工、重试这些规则稳定下来。
|
||
|
||
任务清单:
|
||
|
||
1. 创建 `job_node` 表
|
||
2. 定义节点状态枚举与状态迁移规则
|
||
3. 定义节点尝试号 `attempt_no`
|
||
4. 开发节点开始接口 `POST /api/jobs/{jobId}/nodes/{nodeCode}/start`
|
||
5. 开发节点成功接口 `POST /api/jobs/{jobId}/nodes/{nodeCode}/complete`
|
||
6. 开发节点失败接口 `POST /api/jobs/{jobId}/nodes/{nodeCode}/fail`
|
||
7. 实现节点回调幂等控制
|
||
8. 实现节点超时扫描与升级策略
|
||
|
||
交付物:
|
||
|
||
- 节点不会重复推进
|
||
- 同一节点重复回调时可安全去重
|
||
- 失败与超时都能落事件
|
||
|
||
## Milestone 4:RPA 执行适配层与统一契约
|
||
|
||
目标:让底层 RPA 平台只做执行,不做流程主状态判断,并具备可切换能力。
|
||
|
||
任务清单:
|
||
|
||
1. 输出 `agent-contract/node_callback_examples.json`
|
||
2. 定义统一的 `base_adapter` 接口
|
||
3. 实现 `yingdao_adapter` 与 `isearch_adapter` 骨架
|
||
4. 定义平台回调鉴权方式
|
||
5. 约定统一回传字段:错误码、截图路径、日志路径、录屏路径、输出业务单号
|
||
6. 约定节点编码字典,例如 `OCR_EXTRACT`、`REBATE_IMPORT_ITEMS`、`M5_CREATE_ORDER`
|
||
7. 定义平台失败错误码分层:系统类、业务类、配置类、页面变化类、能力不满足类
|
||
8. 为每个节点定义能力标签,例如 `desktop_ui`、`file_upload`、`excel_template`、`http_callback`
|
||
9. 制作联调用的假回调脚本或 Postman 集合
|
||
|
||
交付物:
|
||
|
||
- 不同平台都可以按统一 JSON 回调
|
||
- 开发和平台实施同学对节点编码、错误码、能力标签理解一致
|
||
|
||
## Milestone 5:手机待办、企业微信与 H5 页面
|
||
|
||
目标:让业务能在手机端收到通知、看上下文、补字段、继续或转人工。
|
||
|
||
任务清单:
|
||
|
||
1. 创建 `user_task` 表
|
||
2. 实现角色路由规则:计划员、采购、质管、运维
|
||
3. 开发 `GET /api/tasks/my`
|
||
4. 开发 `POST /api/tasks/{taskId}/submit`
|
||
5. 开发 `POST /api/jobs/{jobId}/handoff`
|
||
6. 开发企业微信消息发送与模版卡片更新
|
||
7. 开发“人话状态”和“错误翻译”展示逻辑
|
||
8. 开发 H5 处理页,展示关键字段、截图、待办动作
|
||
9. 开发“为什么发给你”“修改前后对比”“提交后即时回执”
|
||
10. 接入企业微信身份识别
|
||
11. 为待办提交增加 `submit_token`,防止重复点击重复推进
|
||
12. 为高风险动作增加短时间撤回设计
|
||
|
||
交付物:
|
||
|
||
- 业务能在企业微信打开待办详情
|
||
- 人工提交只能推进一次
|
||
- 所有修改留痕
|
||
- 用户能看懂待办原因、知道该怎么处理、处理后知道系统已受理
|
||
|
||
## Milestone 6:查询页、审计与运维能力
|
||
|
||
目标:让项目负责人和运维能查问题、追流程、看证据。
|
||
|
||
任务清单:
|
||
|
||
1. 开发 `GET /api/jobs/{jobId}`
|
||
2. 开发按合同编号、供应商、日期、状态筛选列表接口
|
||
3. 展示节点轨迹、责任角色、重试记录
|
||
4. 展示 OCR 结果、映射结果、截图和日志摘要
|
||
5. 增加人工重试接口 `POST /api/jobs/{jobId}/retry`
|
||
6. 增加“整单重跑”能力,生成新的 `job`
|
||
7. 增加查看/下载审计日志
|
||
|
||
交付物:
|
||
|
||
- 出问题时能快速看出卡在哪一层
|
||
- 能区分当前实例和历史重跑实例
|
||
|
||
## Milestone 7:测试、联调与上线准备
|
||
|
||
目标:把关键链路和关键失败场景都压一遍。
|
||
|
||
任务清单:
|
||
|
||
1. 覆盖全自动正向场景
|
||
2. 覆盖 OCR 低置信度转计划员场景
|
||
3. 覆盖返利中心模板部分失败场景
|
||
4. 覆盖 M5 质管基础资料不全场景
|
||
5. 覆盖不同平台回调重复提交场景
|
||
6. 覆盖企业微信待办重复提交场景
|
||
7. 覆盖共享目录重复上传场景
|
||
8. 覆盖节点超时升级场景
|
||
9. 覆盖新单切换执行平台场景
|
||
10. 输出上线切换清单、回滚清单、账号权限清单
|
||
|
||
交付物:
|
||
|
||
- 联调报告
|
||
- UAT 场景清单
|
||
- 上线/回滚 checklist
|
||
|
||
---
|
||
|
||
## 5. 表结构草案
|
||
|
||
说明:下面是一期最低可用表结构,不追求一次做成大而全平台,先满足幂等、留痕、查询和待办协同。
|
||
|
||
### 4.1 `job`
|
||
|
||
一份合同的一次流程实例。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| id | bigint PK | 主键 |
|
||
| job_id | varchar(64) unique | 对外流程单号 |
|
||
| business_key | varchar(128) | 业务唯一键 |
|
||
| parent_job_id | varchar(64) null | 重跑来源 |
|
||
| source_type | varchar(32) | shared_folder/manual_upload |
|
||
| source_file_name | varchar(255) | 原始文件名 |
|
||
| source_file_hash | varchar(64) | 原始文件哈希 |
|
||
| contract_type | varchar(32) | 年度协议/批次合同 |
|
||
| contract_no | varchar(64) null | 合同编号 |
|
||
| supplier_name | varchar(128) null | 供应商名称 |
|
||
| planner_name | varchar(64) null | 计划员 |
|
||
| current_node_code | varchar(64) | 当前节点 |
|
||
| status | varchar(32) | PENDING/RUNNING/WAITING_USER/... |
|
||
| mapping_version | varchar(64) null | 映射配置版本 |
|
||
| executor_platform | varchar(32) null | 默认执行平台 |
|
||
| contract_system_no | varchar(64) null | 合同系统单号 |
|
||
| rebate_order_no | varchar(64) null | 返利中心总单号 |
|
||
| m5_order_no | varchar(64) null | M5 采购订单号 |
|
||
| receipt_notice_no | varchar(64) null | 收货通知单号 |
|
||
| current_role | varchar(32) null | 当前责任角色 |
|
||
| current_assignee | varchar(64) null | 当前责任人 |
|
||
| created_by | varchar(64) | 发起人或系统 |
|
||
| created_at | datetime | 创建时间 |
|
||
| updated_at | datetime | 更新时间 |
|
||
| finished_at | datetime null | 完成时间 |
|
||
|
||
索引建议:
|
||
|
||
- `uniq_job_business_open`:`business_key + status`
|
||
- `idx_job_contract_no`
|
||
- `idx_job_supplier_status`
|
||
- `idx_job_created_at`
|
||
|
||
### 4.2 `job_node`
|
||
|
||
记录每个节点每次尝试。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| id | bigint PK | 主键 |
|
||
| job_id | varchar(64) | 流程单号 |
|
||
| node_code | varchar(64) | 节点编码 |
|
||
| attempt_no | int | 第几次执行 |
|
||
| status | varchar(32) | 节点状态 |
|
||
| executor_platform | varchar(32) null | 实际执行平台 |
|
||
| executor_run_id | varchar(64) null | 平台侧任务号 |
|
||
| started_at | datetime null | 开始时间 |
|
||
| ended_at | datetime null | 结束时间 |
|
||
| duration_ms | bigint null | 耗时 |
|
||
| error_code | varchar(64) null | 错误码 |
|
||
| error_summary | varchar(500) null | 错误摘要 |
|
||
| role_at_failure | varchar(32) null | 失败时责任角色 |
|
||
| assignee_at_failure | varchar(64) null | 失败时责任人 |
|
||
| output_json | json null | 节点输出 |
|
||
| callback_idempotency_key | varchar(128) null | 回调幂等键 |
|
||
| created_at | datetime | 创建时间 |
|
||
|
||
索引建议:
|
||
|
||
- `uniq_job_node_attempt`
|
||
- `idx_job_node_status`
|
||
|
||
### 4.3 `user_task`
|
||
|
||
企业微信/H5 里的人工处理单。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| id | bigint PK | 主键 |
|
||
| task_id | varchar(64) unique | 待办编号 |
|
||
| job_id | varchar(64) | 所属流程 |
|
||
| node_code | varchar(64) | 对应节点 |
|
||
| role_code | varchar(32) | 目标角色 |
|
||
| assignee_user_id | varchar(64) null | 当前处理人 |
|
||
| title | varchar(255) | 待办标题 |
|
||
| reason_type | varchar(32) | OCR_LOW_CONF/REBATE_FAIL/... |
|
||
| reason_summary | varchar(500) | 待办原因 |
|
||
| reason_user_friendly | varchar(500) | 面向业务的人话说明 |
|
||
| why_me_text | varchar(255) | 为什么发给当前角色/当前人 |
|
||
| editable_fields_json | json | 白名单字段 |
|
||
| action_schema_json | json | 允许动作 |
|
||
| comparison_snapshot_json | json null | 原值/建议值/当前值对比 |
|
||
| status | varchar(32) | OPEN/SUBMITTED/CANCELLED/EXPIRED |
|
||
| submit_token | varchar(64) | 防重复令牌 |
|
||
| submitted_action | varchar(32) null | 继续/重试/转人工/终止 |
|
||
| submitted_payload_json | json null | 人工提交内容 |
|
||
| submitted_by | varchar(64) null | 提交人 |
|
||
| submitted_at | datetime null | 提交时间 |
|
||
| due_at | datetime null | 超时升级时间 |
|
||
| created_at | datetime | 创建时间 |
|
||
|
||
### 4.4 `mapping_config`
|
||
|
||
映射规则表,一期可以先做统一表,后续再拆子表。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| id | bigint PK | 主键 |
|
||
| config_key | varchar(128) | 业务键 |
|
||
| config_type | varchar(32) | supplier/item/settlement/payment_term/route |
|
||
| source_value | varchar(255) | 来源值 |
|
||
| target_value | varchar(255) | 目标值 |
|
||
| extra_json | json null | 扩展参数 |
|
||
| version_no | varchar(64) | 版本号 |
|
||
| is_active | tinyint | 是否生效 |
|
||
| effective_from | datetime | 生效时间 |
|
||
| effective_to | datetime null | 失效时间 |
|
||
| updated_by | varchar(64) | 更新人 |
|
||
| updated_at | datetime | 更新时间 |
|
||
|
||
### 4.5 `executor_binding_config`
|
||
|
||
节点与执行平台路由配置。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| id | bigint PK | 主键 |
|
||
| node_code | varchar(64) | 节点编码 |
|
||
| preferred_platform | varchar(32) | 首选平台 |
|
||
| fallback_platform | varchar(32) null | 备用平台 |
|
||
| required_capabilities_json | json | 所需能力标签 |
|
||
| route_policy | varchar(32) | FIXED / PREFERRED / FALLBACK |
|
||
| is_active | tinyint | 是否生效 |
|
||
| updated_by | varchar(64) | 更新人 |
|
||
| updated_at | datetime | 更新时间 |
|
||
|
||
### 4.6 `job_artifact`
|
||
|
||
存证表。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| id | bigint PK | 主键 |
|
||
| job_id | varchar(64) | 流程单号 |
|
||
| node_code | varchar(64) null | 所属节点 |
|
||
| artifact_type | varchar(32) | SOURCE_FILE/OCR_JSON/SCREENSHOT/TEMPLATE/LOG |
|
||
| storage_path | varchar(500) | 存储路径 |
|
||
| file_name | varchar(255) | 文件名 |
|
||
| file_hash | varchar(64) null | 文件哈希 |
|
||
| is_masked | tinyint | 是否脱敏 |
|
||
| visible_roles_json | json | 可见角色 |
|
||
| created_at | datetime | 创建时间 |
|
||
|
||
### 4.7 `job_event`
|
||
|
||
事件流表,用来查轨迹。
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
| --- | --- | --- |
|
||
| id | bigint PK | 主键 |
|
||
| job_id | varchar(64) | 流程单号 |
|
||
| node_code | varchar(64) null | 节点 |
|
||
| event_type | varchar(64) | JOB_CREATED/NODE_FAILED/TASK_CREATED/... |
|
||
| event_summary | varchar(500) | 事件摘要 |
|
||
| event_payload_json | json null | 事件详情 |
|
||
| operator_type | varchar(32) | SYSTEM/ROBOT/USER |
|
||
| operator_id | varchar(64) | 操作人 |
|
||
| created_at | datetime | 创建时间 |
|
||
|
||
---
|
||
|
||
## 5. MySQL DDL 示例
|
||
|
||
以下 DDL 不是最终生产版,但足够作为建库初稿。
|
||
|
||
```sql
|
||
CREATE TABLE job (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
job_id VARCHAR(64) NOT NULL UNIQUE,
|
||
business_key VARCHAR(128) NOT NULL,
|
||
parent_job_id VARCHAR(64) NULL,
|
||
source_type VARCHAR(32) NOT NULL,
|
||
source_file_name VARCHAR(255) NOT NULL,
|
||
source_file_hash VARCHAR(64) NOT NULL,
|
||
contract_type VARCHAR(32) NOT NULL,
|
||
contract_no VARCHAR(64) NULL,
|
||
supplier_name VARCHAR(128) NULL,
|
||
planner_name VARCHAR(64) NULL,
|
||
current_node_code VARCHAR(64) NOT NULL,
|
||
status VARCHAR(32) NOT NULL,
|
||
mapping_version VARCHAR(64) NULL,
|
||
executor_platform VARCHAR(32) NULL,
|
||
contract_system_no VARCHAR(64) NULL,
|
||
rebate_order_no VARCHAR(64) NULL,
|
||
m5_order_no VARCHAR(64) NULL,
|
||
receipt_notice_no VARCHAR(64) NULL,
|
||
current_role VARCHAR(32) NULL,
|
||
current_assignee VARCHAR(64) NULL,
|
||
created_by VARCHAR(64) NOT NULL,
|
||
created_at DATETIME NOT NULL,
|
||
updated_at DATETIME NOT NULL,
|
||
finished_at DATETIME NULL,
|
||
KEY idx_job_contract_no (contract_no),
|
||
KEY idx_job_supplier_status (supplier_name, status),
|
||
KEY idx_job_created_at (created_at)
|
||
);
|
||
|
||
CREATE TABLE job_node (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
job_id VARCHAR(64) NOT NULL,
|
||
node_code VARCHAR(64) NOT NULL,
|
||
attempt_no INT NOT NULL,
|
||
status VARCHAR(32) NOT NULL,
|
||
executor_platform VARCHAR(32) NULL,
|
||
executor_run_id VARCHAR(64) NULL,
|
||
started_at DATETIME NULL,
|
||
ended_at DATETIME NULL,
|
||
duration_ms BIGINT NULL,
|
||
error_code VARCHAR(64) NULL,
|
||
error_summary VARCHAR(500) NULL,
|
||
role_at_failure VARCHAR(32) NULL,
|
||
assignee_at_failure VARCHAR(64) NULL,
|
||
output_json JSON NULL,
|
||
callback_idempotency_key VARCHAR(128) NULL,
|
||
created_at DATETIME NOT NULL,
|
||
UNIQUE KEY uniq_job_node_attempt (job_id, node_code, attempt_no)
|
||
);
|
||
|
||
CREATE TABLE user_task (
|
||
id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
||
task_id VARCHAR(64) NOT NULL UNIQUE,
|
||
job_id VARCHAR(64) NOT NULL,
|
||
node_code VARCHAR(64) NOT NULL,
|
||
role_code VARCHAR(32) NOT NULL,
|
||
assignee_user_id VARCHAR(64) NULL,
|
||
title VARCHAR(255) NOT NULL,
|
||
reason_type VARCHAR(32) NOT NULL,
|
||
reason_summary VARCHAR(500) NOT NULL,
|
||
editable_fields_json JSON NOT NULL,
|
||
action_schema_json JSON NOT NULL,
|
||
status VARCHAR(32) NOT NULL,
|
||
submit_token VARCHAR(64) NOT NULL,
|
||
submitted_action VARCHAR(32) NULL,
|
||
submitted_payload_json JSON NULL,
|
||
submitted_by VARCHAR(64) NULL,
|
||
submitted_at DATETIME NULL,
|
||
due_at DATETIME NULL,
|
||
created_at DATETIME NOT NULL
|
||
);
|
||
```
|
||
|
||
---
|
||
|
||
## 6. API 草案
|
||
|
||
说明:接口统一由状态中心对外提供,RPA 平台、H5 页面、企业微信回调都走状态中心,不允许直接改数据库。
|
||
|
||
鉴权建议:
|
||
|
||
- 内部服务接口:`Authorization: Bearer <service-token>`
|
||
- RPA 平台回调接口:`X-Agent-Token`
|
||
- H5 用户接口:企业微信身份换取后端 session 或 JWT
|
||
- 幂等写接口:增加 `X-Idempotency-Key`
|
||
|
||
### 6.1 建单接口
|
||
|
||
`POST /api/jobs`
|
||
|
||
用途:
|
||
|
||
- 共享目录监听器建单
|
||
- 状态中心手工上传建单
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"sourceType": "shared_folder",
|
||
"sourceFileName": "20260625_国药控股_张三_批次合同_01.pdf",
|
||
"sourceFileHash": "6f6f5d8c...",
|
||
"contractType": "BATCH",
|
||
"supplierName": "国药控股",
|
||
"plannerName": "张三",
|
||
"executorPlatform": "YINGDAO",
|
||
"createdBy": "system-folder-watcher",
|
||
"artifacts": [
|
||
{
|
||
"artifactType": "SOURCE_FILE",
|
||
"storagePath": "/data/jobs/inbox/20260625_国药控股_张三_批次合同_01.pdf"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
响应示例:
|
||
|
||
```json
|
||
{
|
||
"jobId": "JOB202606260001",
|
||
"status": "PENDING",
|
||
"currentNodeCode": "FILE_INTAKE"
|
||
}
|
||
```
|
||
|
||
### 6.2 节点开始
|
||
|
||
`POST /api/jobs/{jobId}/nodes/{nodeCode}/start`
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"attemptNo": 1,
|
||
"executorPlatform": "YINGDAO",
|
||
"operator": "yingdao-agent-01",
|
||
"startedAt": "2026-06-26T10:00:00+08:00"
|
||
}
|
||
```
|
||
|
||
### 6.3 节点成功
|
||
|
||
`POST /api/jobs/{jobId}/nodes/{nodeCode}/complete`
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"attemptNo": 1,
|
||
"executorPlatform": "YINGDAO",
|
||
"executorRunId": "YD-RUN-20260626-001",
|
||
"endedAt": "2026-06-26T10:03:25+08:00",
|
||
"businessRefs": {
|
||
"contractSystemNo": "HT20260626018",
|
||
"rebateOrderNo": "FL20260626009",
|
||
"m5OrderNo": null,
|
||
"receiptNoticeNo": null
|
||
},
|
||
"summary": {
|
||
"importedItemCount": 18,
|
||
"failedItemCount": 0
|
||
},
|
||
"artifacts": [
|
||
{
|
||
"artifactType": "SCREENSHOT",
|
||
"storagePath": "/data/jobs/JOB202606260001/REBATE_IMPORT_ITEMS/success.png"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
约束:
|
||
|
||
- 如果没有业务编号且节点本身要求有编号,则不能直接记 `SUCCESS`
|
||
|
||
### 6.4 节点失败
|
||
|
||
`POST /api/jobs/{jobId}/nodes/{nodeCode}/fail`
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"attemptNo": 1,
|
||
"executorPlatform": "YINGDAO",
|
||
"executorRunId": "YD-RUN-20260626-001",
|
||
"endedAt": "2026-06-26T10:05:01+08:00",
|
||
"errorCode": "REBATE_TEMPLATE_PARTIAL_FAIL",
|
||
"errorSummary": "18 行中有 3 行校验失败",
|
||
"retryable": false,
|
||
"routeRole": "PURCHASER",
|
||
"artifacts": [
|
||
{
|
||
"artifactType": "SCREENSHOT",
|
||
"storagePath": "/data/jobs/JOB202606260001/REBATE_IMPORT_ITEMS/error.png"
|
||
},
|
||
{
|
||
"artifactType": "LOG",
|
||
"storagePath": "/data/jobs/JOB202606260001/REBATE_IMPORT_ITEMS/agent.log"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 6.5 我的待办
|
||
|
||
`GET /api/tasks/my`
|
||
|
||
查询参数建议:
|
||
|
||
- `status=open`
|
||
- `roleCode=PLANNER`
|
||
- `pageNo=1`
|
||
- `pageSize=20`
|
||
|
||
响应字段建议:
|
||
|
||
- `taskId`
|
||
- `jobId`
|
||
- `title`
|
||
- `reasonSummary`
|
||
- `reasonUserFriendly`
|
||
- `whyMeText`
|
||
- `nodeCode`
|
||
- `supplierName`
|
||
- `contractNo`
|
||
- `dueAt`
|
||
- `detailUrl`
|
||
|
||
### 6.6 待办提交
|
||
|
||
`POST /api/tasks/{taskId}/submit`
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"submitToken": "9f5f2c1d",
|
||
"action": "CONFIRM_AND_CONTINUE",
|
||
"payload": {
|
||
"paymentModeCode": "2",
|
||
"paymentModeDays": 30,
|
||
"settlementCode": "3"
|
||
},
|
||
"comment": "已根据合同正文修正承付模式"
|
||
}
|
||
```
|
||
|
||
动作枚举建议:
|
||
|
||
- `CONFIRM_AND_CONTINUE`
|
||
- `RETRY_CURRENT_NODE`
|
||
- `TRANSFER_MANUAL`
|
||
- `TERMINATE_JOB`
|
||
|
||
提交成功后的响应,建议额外返回:
|
||
|
||
- `accepted`: 是否已受理
|
||
- `receiptMessage`: 给用户看的即时回执
|
||
- `nextExpectedAction`: 系统接下来会做什么
|
||
- `estimatedWaitMinutes`: 预计多久有下一次结果
|
||
|
||
### 6.7 重试当前节点
|
||
|
||
`POST /api/jobs/{jobId}/retry`
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"scope": "CURRENT_NODE",
|
||
"operatorId": "zhangsan",
|
||
"reason": "计划员已修正承付模式,允许重试"
|
||
}
|
||
```
|
||
|
||
### 6.8 转派/转人工
|
||
|
||
`POST /api/jobs/{jobId}/handoff`
|
||
|
||
请求示例:
|
||
|
||
```json
|
||
{
|
||
"targetRole": "OPS",
|
||
"targetUserId": "wangwu",
|
||
"reason": "返利中心页面结构变化,需要机器人管理员处理"
|
||
}
|
||
```
|
||
|
||
### 6.9 查询整单
|
||
|
||
`GET /api/jobs/{jobId}`
|
||
|
||
返回建议包含:
|
||
|
||
- `job` 基础信息
|
||
- 当前状态
|
||
- 节点轨迹数组
|
||
- 当前待办数组
|
||
- 关键业务编号
|
||
- OCR 摘要
|
||
- 映射摘要
|
||
- 证据文件列表
|
||
- 执行平台与平台侧运行号
|
||
|
||
### 6.10 企业微信回调
|
||
|
||
`POST /api/wecom/callback`
|
||
|
||
用途:
|
||
|
||
- 卡片动作回调
|
||
- 身份事件回调
|
||
|
||
注意:
|
||
|
||
- 回调只负责接收动作和身份,不直接写业务结果
|
||
- 必须先换成状态中心标准动作,再调用内部任务提交逻辑
|
||
|
||
---
|
||
|
||
## 7. H5 页面草案
|
||
|
||
页面最低能力建议:
|
||
|
||
1. 显示合同基础信息:合同编号、供应商、计划员、当前节点
|
||
2. 显示“当前系统正在做什么”的人话状态
|
||
3. 显示 OCR 关键字段和置信度
|
||
4. 显示最近错误截图和业务可读错误说明
|
||
5. 显示“为什么发给你”
|
||
6. 显示允许修改的字段和修改前后对比
|
||
7. 显示操作按钮:继续、重试、转人工、终止
|
||
8. 显示处理历史和最近一次失败原因
|
||
9. 提交动作后显示即时回执,避免重复点击
|
||
|
||
页面路由建议:
|
||
|
||
- `/h5/tasks/{taskId}`
|
||
- `/h5/jobs/{jobId}`
|
||
|
||
---
|
||
|
||
## 8. 平台接入 POC 清单
|
||
|
||
任何新 RPA 平台接入前,先做下面的最小验证:
|
||
|
||
1. 登录目标系统并打开指定页面
|
||
2. 读取一份合同字段并调用一次外部 HTTP API
|
||
3. 在返利中心完成一次模板导入
|
||
4. 失败时自动截图并回调到状态中心
|
||
5. 验证平台日志、录屏和运行号能被统一采集
|
||
|
||
通过后,才允许接入正式流程路由。
|
||
|
||
## 9. 联调顺序建议
|
||
|
||
建议不要一上来就四方一起联调,按下面顺序推进更稳:
|
||
|
||
1. 状态中心单独完成建单、节点流转、待办流转
|
||
2. 先用假 OCR 和假 RPA 回调,把流程跑通
|
||
3. 接入真实 OCR
|
||
4. 接入真实企业微信消息和 H5 身份
|
||
5. 最后接入真实 RPA 流程
|
||
6. 再做返利中心/M5 端到端联调
|
||
|
||
---
|
||
|
||
## 10. 测试重点
|
||
|
||
接口测试重点:
|
||
|
||
- 重复建单
|
||
- 重复回调
|
||
- 重复待办提交
|
||
- 非法状态迁移
|
||
- 低置信度转待办
|
||
- 整单重跑
|
||
|
||
集成测试重点:
|
||
|
||
- OCR 返回空字段
|
||
- 返利中心部分导入失败
|
||
- M5 保存失败
|
||
- 企业微信回调延迟或重复
|
||
- 节点长时间未回调
|
||
|
||
UAT 重点:
|
||
|
||
- 计划员在手机端补录后能继续执行
|
||
- 采购能看到失败明细和截图
|
||
- 质管收到问题后只做基础资料确认
|
||
- 运维能定位页面变化或登录失效
|
||
- 待办文案是否足够人话,业务无需培训也能理解主要动作
|
||
- 用户提交后是否明确感知“系统已受理”
|
||
|
||
---
|
||
|
||
## 11. 上线前必补清单
|
||
|
||
以下内容现在还没落在代码里,但上线前必须补齐:
|
||
|
||
1. 企业微信应用信息、回调域名、可信域名
|
||
2. 共享目录所在服务器、权限和目录清理规则
|
||
3. 合同附件的访问权限与脱敏策略
|
||
4. 执行平台运行节点、账号和截图/录屏落盘路径
|
||
5. 返利中心与 M5 的测试账号、生产账号隔离
|
||
6. 错误码清单和责任角色映射表
|
||
7. 环境监控:服务存活、数据库连接、磁盘容量、回调异常告警
|
||
|
||
---
|
||
|
||
## 12. 建议下一步
|
||
|
||
如果要继续推进,建议按下面顺序立刻开工:
|
||
|
||
1. 先定表结构和节点编码
|
||
2. 再定统一 RPA 回调 JSON 契约和能力标签
|
||
3. 再做企业微信“H5 待办页”原型和人性化文案
|
||
4. 然后并行开发:状态中心后端、RPA 平台适配器、企业微信消息联调
|
||
|
||
这份文档适合作为技术 kickoff 和任务拆分底稿。
|