add SRM 与 STP 数据交换接口方案说明书

This commit is contained in:
2026-06-26 18:31:42 +08:00
parent 65c5a75f34
commit 521f745d1d
2 changed files with 474 additions and 91 deletions
@@ -0,0 +1,413 @@
# SRM 与 STP 数据交换接口方案说明书
| 文档名称 | SRM 与 STP 数据交换接口方案说明书 |
| :--- | :-------------------- |
| 文档版本 | V1.0 |
| 编制日期 | 2026-06-26 |
| 编制人 | 叶伟文 |
## 1. 项目背景与目标
### 1.1 背景
当前,供应商关系管理系统与智慧招标平台各自独立运行,存在数据孤岛。供应商需在两套系统中分别维护信息、管理账号,在跨平台操作时需重复登录,严重影响用户体验与业务协同效率。
### 1.2 目标
* **数据互通**:实现供应商主数据、采购计划、中标资料在两个系统间的实时或准实时同步。
* **业务协同**:打通从供应商准入、招标到合同签订的全流程,实现业务流程无缝衔接。
* **体验优化**:构建统一登录认证体系,实现"一次登录,两平台通行"的无感跳转体验。
## 2. 总体架构设计
### 2.1 系统交互架构图
```svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 450" font-family="Microsoft YaHei, sans-serif">
<defs>
<marker id="arrowPink" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
<path d="M0,0 L0,6 L9,3 z" fill="#c2185b"/>
</marker>
<marker id="arrowBlue" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
<path d="M0,0 L0,6 L9,3 z" fill="#1565c0"/>
</marker>
<linearGradient id="gradSrm" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#1565c0"/>
<stop offset="100%" stop-color="#1e88e5"/>
</linearGradient>
<linearGradient id="gradStp" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#c2185b"/>
<stop offset="100%" stop-color="#e91e63"/>
</linearGradient>
<filter id="shadow" x="-5%" y="-5%" width="110%" height="110%">
<feDropShadow dx="2" dy="3" stdDeviation="3" flood-opacity="0.15"/>
</filter>
</defs>
<!-- 标题 -->
<text x="400" y="35" text-anchor="middle" font-size="22" font-weight="bold" fill="#333">SRM 与 STP 系统交互架构</text>
<!-- SRM 系统框 -->
<rect x="60" y="70" width="280" height="320" rx="12" fill="url(#gradSrm)" filter="url(#shadow)"/>
<text x="200" y="105" text-anchor="middle" font-size="20" font-weight="bold" fill="#fff">供应商管理系统</text>
<rect x="80" y="125" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="200" y="151" text-anchor="middle" font-size="14" fill="#fff">供应商库管理</text>
<rect x="80" y="175" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="200" y="201" text-anchor="middle" font-size="14" fill="#fff">采购计划管理</text>
<rect x="80" y="225" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="200" y="251" text-anchor="middle" font-size="14" fill="#fff">合同管理</text>
<rect x="80" y="275" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="200" y="301" text-anchor="middle" font-size="14" fill="#fff">中标资料归档</text>
<rect x="80" y="325" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="200" y="351" text-anchor="middle" font-size="14" fill="#fff">认证与鉴权中心</text>
<!-- STP 系统框 -->
<rect x="460" y="70" width="280" height="320" rx="12" fill="url(#gradStp)" filter="url(#shadow)"/>
<text x="600" y="105" text-anchor="middle" font-size="20" font-weight="bold" fill="#fff">智慧招标平台</text>
<rect x="480" y="125" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="600" y="151" text-anchor="middle" font-size="14" fill="#fff">供应商准入审核</text>
<rect x="480" y="175" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="600" y="201" text-anchor="middle" font-size="14" fill="#fff">招标项目管理</text>
<rect x="480" y="225" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="600" y="251" text-anchor="middle" font-size="14" fill="#fff">AI采购委托书</text>
<rect x="480" y="275" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="600" y="301" text-anchor="middle" font-size="14" fill="#fff">定标与资料转交</text>
<rect x="480" y="325" width="240" height="40" rx="6" fill="rgba(255,255,255,0.2)"/>
<text x="600" y="351" text-anchor="middle" font-size="14" fill="#fff">认证与鉴权中心</text>
<!-- 中间接口通道 -->
<rect x="370" y="195" width="60" height="60" rx="30" fill="#fff" stroke="#666" stroke-width="1.5" filter="url(#shadow)"/>
<text x="400" y="222" text-anchor="middle" font-size="11" font-weight="bold" fill="#333">API</text>
<text x="400" y="240" text-anchor="middle" font-size="11" fill="#666">网关</text>
<!-- 接口连线:SRM -> STP -->
<line x1="340" y1="145" x2="460" y2="145" stroke="#c2185b" stroke-width="2" marker-end="url(#arrowPink)"/>
<text x="400" y="138" text-anchor="middle" font-size="10" fill="#c2185b">供应商库查询</text>
<line x2="340" y2="290" x1="460" y1="290" stroke="#c2185b" stroke-width="2" marker-end="url(#arrowPink)"/>
<text x="400" y="283" text-anchor="middle" font-size="10" fill="#c2185b">中标资料接收</text>
<line x1="340" y1="340" x2="460" y2="340" stroke="#c2185b" stroke-width="2" marker-end="url(#arrowPink)"/>
<line x1="460" y1="340" x2="340" y2="340" stroke="#1565c0" stroke-width="2" marker-end="url(#arrowBlue)"/>
<text x="400" y="333" text-anchor="middle" font-size="10" fill="#333">登录/票据验证</text>
<!-- 接口连线:STP -> SRM -->
<line x1="460" y1="175" x2="340" y2="175" stroke="#1565c0" stroke-width="2" marker-end="url(#arrowBlue)"/>
<text x="400" y="168" text-anchor="middle" font-size="10" fill="#1565c0">供应商自动注册</text>
<line x1="460" y1="240" x2="340" y2="240" stroke="#1565c0" stroke-width="2" marker-end="url(#arrowBlue)"/>
<text x="400" y="233" text-anchor="middle" font-size="10" fill="#1565c0">采购计划查询</text>
<!-- 技术栈标注 -->
<rect x="250" y="420" width="300" height="24" rx="12" fill="#f5f5f5"/>
<text x="400" y="437" text-anchor="middle" font-size="11" fill="#555">协议:HTTPS | 格式:JSON | 认证:私钥签名 + Token</text>
</svg>
```
## 3. 接口详细设计
### 3.1 供应商库信息查询接口
**提供方:** SRM
**消费方:** STP
**接口清单**
| 序号 | 接口名称 | 请求方式 | 接口路径(暂拟) | 说明 |
| :-- | :------ | :---- | :--------------------------------- | :------------------------------- |
| 1 | 供应商名称查询 | `GET` | `/api/v1/supplier/query/by-name` | 根据供应商名称返回匹配到的供应商对象列表,没有则返回空列表。 |
| 2 | 供应商税号查询 | `GET` | `/api/v1/supplier/query/by-tax-id` | 根据供应商税号返回匹配到的供应商对象,没有则返回空对象。 |
| 3 | 供应商ID查询 | `GET` | `/api/v1/supplier/query/by-id` | 根据SRM系统内部ID返回对应的供应商对象,没有则返回空对象。 |
| 4 | 供应商标签查询 | `GET` | `/api/v1/supplier/query/by-tags` | 根据给定的标签集合返回匹配到的供应商对象列表,没有则返回空列表。 |
| 5 | 全量供应商同步 | `GET` | `/api/v1/supplier/sync/full` | 返回所有供应商对象,用于全量数据同步。 |
| 6 | 增量供应商同步 | `GET` | `/api/v1/supplier/sync/delta` | 返回从指定时间至今发生变更的供应商对象,用于增量同步。 |
**通用请求头**
| 参数名 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `Authorization` | `String` | 是 | 认证令牌,格式为 `Bearer <token>` |
| `Content-Type` | `String` | 是 | `application/json` |
**供应商对象结构(举例)**
| 字段名 | 类型 | 说明 |
| :------------- | :-------------- | :---------------------- |
| `supplierId` | `String` | 系统内ID |
| `supplierName` | `String` | 供应商名称 |
| `taxId` | `String` | 税号 |
| `score` | `Integer` | 综合评分 |
| `tags` | `Array[String]` | 标签列表 |
| `status` | `String` | 状态,如"ACTIVE","INACTIVE" |
| `contactInfo` | `Object` | 联系方式 |
| `createTime` | `String` | 创建时间 |
| `updateTime` | `String` | 更新时间 |
---
### 3.2 供应商自动注册接口
**提供方:** SRM
**消费方:** STP
```mermaid
sequenceDiagram
participant STP as STP
participant SRM as SRM
STP->>SRM: POST /api/v1/supplier/register (供应商注册信息)
SRM-->>SRM: 校验数据完整性与合规性
alt 注册成功
SRM-->>SRM: 生成系统内ID
SRM-->>STP: 200 OK { "code":"0", "supplierId":"SRM_2024001" }
else 注册失败
SRM-->>STP: 400 Bad Request { "code":"ERR_001", "message":"税号已存在" }
end
```
**请求参数(暂定)**
| 参数名 | 类型 | 必填 | 说明 |
| :--------------- | :------- | :-- | :----- |
| `supplierName` | `String` | 是 | 供应商名称 |
| `taxId` | `String` | 是 | 税号 |
| `contactInfo` | `Object` | 是 | 联系方式 |
| `qualifications` | `Array` | 否 | 资质文件列表 |
**返回参数(成功)**
| 参数名 | 类型 | 说明 |
| :--- | :--- | :--- |
| `code` | `String` | 业务状态码,成功为"0" |
| `supplierId` | `String` | SRM系统内ID |
---
### 3.3 采购计划查询接口
**提供方:** SRM
**消费方:** STP
```mermaid
sequenceDiagram
participant STP as STP (AI模块)
participant SRM as SRM
STP->>SRM: GET /api/v1/purchase-plan/query?account=xxx
SRM-->>SRM: 查询该采购员关联的采购计划
alt 存在计划
SRM-->>STP: 200 OK { "code":"0", "data":[计划对象列表] }
else 不存在计划
SRM-->>STP: 200 OK { "code":"0", "data":[] }
end
```
**请求参数**
| 参数名 | 类型 | 必填 | 位置 | 说明 |
| :--- | :--- | :--- | :--- | :--- |
| `account` | `String` | 是 | `Query` | 采购人员账号 |
**返回数据对象**
| 字段名 | 类型 | 说明 |
| :------------- | :------- | :----- |
| `planId` | `String` | 计划ID |
| `planName` | `String` | 计划名称 |
| `budget` | `Float` | 预算金额 |
| `requiredDate` | `String` | 需求日期 |
| `items` | `Array` | 采购物料明细 |
---
### 3.4 统一登录与无感跳转接口
本节详细描述如何通过**统一登录**和**无感跳转**实现“一次登录,两平台通行”。
#### 3.4.1 统一登录
统一登录解决供应商在两个平台拥有独立账号、需重复输入密码的问题。任一平台均可作为登录入口,调用对方提供的登录验证接口,验证通过后建立本地会话。
**场景1:供应商在SRM端输入STP的账号密码登录**
```mermaid
sequenceDiagram
participant User as 供应商
participant SRM
participant STP
User->>SRM: 输入STP用户名/密码,点击登录
SRM->>STP: POST /api/v1/auth/login/for-srm { username, password, returnUrl }
STP-->>STP: 校验用户合法性
alt 校验成功
STP-->>SRM: 200 { code:0, userInfo:{ stpId, srmId, name, taxId, ... } }
SRM-->>SRM: 建立本地会话,关联SRM ID
SRM-->>User: 登录成功,返回SRM首页
else 校验失败
STP-->>SRM: 401 { code:ERR_AUTH_001, message:"用户名或密码错误" }
SRM-->>User: 提示错误
end
```
**场景2:供应商在STP端输入SRM的账号密码登录(流程对称)**
```mermaid
sequenceDiagram
participant User as 供应商
participant STP
participant SRM
User->>STP: 输入SRM用户名/密码,点击登录
STP->>SRM: POST /api/v1/auth/login/for-stp { username, password, returnUrl }
SRM-->>SRM: 校验用户合法性
alt 校验成功
SRM-->>STP: 200 { code:0, userInfo:{ srmId, name, taxId, ... } }
STP-->>STP: 建立本地会话
STP-->>User: 登录成功,返回STP首页
else 校验失败
SRM-->>STP: 401 错误
STP-->>User: 提示错误
end
```
**接口定义:STP登录验证接口(供SRM调用)**
| 项目 | 内容 |
| :--- | :--- |
| **提供方** | STP |
| **路径** | `/api/v1/auth/login/for-srm` |
| **方法** | `POST` |
| **请求体** | `{ "username":"供应商STP账号", "password":"密码" }` |
| **成功响应** | `{ "code":"0", "userInfo":{ "stpId":"STP内部ID", "srmId":"关联的SRM ID", "name":"公司名", "taxId":"税号" } }` |
| **失败响应** | `{ "code":"ERR_AUTH_001", "message":"用户名或密码错误" }` |
**接口定义:SRM登录验证接口(供STP调用)**
| 项目 | 内容 |
| :--- | :--- |
| **提供方** | SRM |
| **路径** | `/api/v1/auth/login/for-stp` |
| **方法** | `POST` |
| **请求体** | `{ "username":"供应商SRM账号", "password":"密码" }` |
| **成功响应** | `{ "code":"0", "userInfo":{ "srmId":"SRM内部ID", "name":"公司名", "taxId":"税号" } }` |
| **失败响应** | `{ "code":"ERR_AUTH_001", "message":"用户名或密码错误" }` |
> **说明:** `returnUrl`参数可选,用于指定验证成功后跳转的目标页面。两个系统在验证通过后,返回的用户信息中必须包含 `srmId`,以便对方建立本地会话并关联供应商身份。
#### 3.4.2 无感跳转(已登录状态下的跨系统切换)
当供应商已在任一方登录,点击指向另一方系统的链接时,通过临时跳转票据实现免密登录。
**STP → SRM 无感跳转流程:**
```mermaid
sequenceDiagram
participant User as 供应商
participant STP
participant SRM
Note over User,SRM: 前提:供应商已登录STP
User->>STP: 点击“查看SRM合同”链接
STP->>STP: 生成Ticket (srmId, stpSessionId, timestamp)
STP->>STP: 使用STP私钥签名
STP->>User: 302重定向到SRMURL中携带Ticket
User->>SRM: 访问SRM,携带Ticket
SRM->>SRM: 使用STP公钥验签
SRM->>STP: POST /api/v1/auth/session/validate { stpSessionId, srmId }
STP-->>SRM: 200 OK { valid: true }
SRM-->>SRM: 根据srmId建立本地会话
SRM-->>User: 登录成功,展示SRM页面
```
**SRM → STP 无感跳转流程(对称,略)**
**跳转票据(Ticket)结构**
| 字段 | 类型 | 说明 |
| :--- | :--- | :--- |
| `srmId` | `String` | 供应商在SRM中的ID(必填) |
| `sessionId` | `String` | 来源系统当前登录会话ID |
| `timestamp` | `Long` | 生成时间戳,有效期建议5分钟 |
| `nonce` | `String` | 随机数,防重放 |
| `signature` | `String` | 对上述字段的签名(来源系统私钥) |
**会话有效性验证接口**
| 项目 | STP会话验证(供SRM调用) | SRM会话验证(供STP调用) |
| :--- | :--- | :--- |
| **提供方** | STP | SRM |
| **路径** | `/api/v1/auth/session/validate` | `/api/v1/auth/session/validate` |
| **方法** | `POST` | `POST` |
| **请求体** | `{ "sessionId":"STP会话ID", "srmId":"SRM ID" }` | `{ "sessionId":"SRM会话ID" }` |
| **成功响应** | `{ "code":"0", "valid": true }` | `{ "code":"0", "valid": true }` |
| **失败响应** | `{ "code":"0", "valid": false }` | `{ "code":"0", "valid": false }` |
---
### 3.5 中标资料转交接口
**提供方:** SRM
**消费方:** STP
```mermaid
sequenceDiagram
participant STP
participant SRM
Note over STP: 定标完成,整理资料
STP->>SRM: POST /api/v1/bid-result/transfer (中标资料包)
SRM-->>SRM: 校验数据完整性
SRM-->>SRM: 归档中标资料、投标过程数据等
alt 成功
SRM-->>STP: 200 OK { "code":"0", "recordId":"ARCH_2024001" }
else 失败
SRM-->>STP: 500 / 400 { "code":"ERR_002", "message":"资料不完整" }
end
```
**请求体结构**
| 参数名 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `projectId` | `String` | 是 | 招标项目ID |
| `bidResult` | `Object` | 是 | 定标结果 |
| `bidProcessData` | `Object` | 是 | 投标过程数据 |
| `supplierBidFiles` | `Array` | 是 | 供应商投标文件URL列表 |
---
## 4. 接口清单总表
| 模块 | 接口名称 | 请求方 | 提供方 | 协议 |
| :--- | :--- | :--- | :--- | :--- |
| **供应商信息** | 供应商名称查询 | STP | SRM | REST |
| | 供应商税号查询 | STP | SRM | REST |
| | 供应商ID查询 | STP | SRM | REST |
| | 供应商标签查询 | STP | SRM | REST |
| | 全量供应商同步 | STP | SRM | REST |
| | 增量供应商同步 | STP | SRM | REST |
| **供应商注册** | 供应商自动注册 | STP | SRM | REST |
| **采购计划** | 采购计划查询 | STP | SRM | REST |
| **登录认证** | SRM登录验证 | SRM | STP | REST |
| | STP登录验证 | STP | SRM | REST |
| | STP会话有效性验证 | SRM | STP | REST |
| | SRM会话有效性验证 | STP | SRM | REST |
| | STP→SRM无感跳转 | SRM | STP | REST+签名 |
| | SRM→STP无感跳转 | STP | SRM | REST+签名 |
| **中标转交** | 中标资料接收 | STP | SRM | REST |
## 5. 安全设计
| 维度 | 策略 | 说明 |
| :--- | :--- | :--- |
| **传输安全** | HTTPS/TLS 1.2+ | 所有接口通信必须使用HTTPS加密传输。 |
| **身份认证** | Token / 证书 | 系统间API调用采用Token认证;无感跳转采用RSA私钥签名验证。 |
| **防重放** | 时间戳 + 随机数 | 跳转票据和关键请求携带时间戳和随机数,有效期建议5分钟。 |
| **数据脱敏** | 日志脱敏 | 税号、联系方式等敏感信息在日志中必须脱敏处理。 |
| **访问控制** | 最小权限原则 | 接口调用方仅能访问其业务所必需的数据。 |
## 6. 错误码规范
| 错误码 | 说明 | 示例 |
| :--- | :--- | :--- |
| `0` | 成功 | — |
| `ERR_AUTH_001` | 认证失败 | Token无效或已过期 |
| `ERR_AUTH_002` | 签名验证失败 | 跳转票据签名不匹配 |
| `ERR_PARAM_001` | 参数缺失/格式错误 | 必填字段为空 |
| `ERR_BIZ_001` | 供应商已存在 | 注册时税号重复 |
| `ERR_BIZ_002` | 供应商不存在 | ID查询无结果 |
| `ERR_SYS_001` | 系统内部错误 | 数据库连接超时 |