# SRM 与 STP 数据交换接口方案说明书
| 文档名称 | SRM 与 STP 数据交换接口方案说明书 |
| :--- | :-------------------- |
| 文档版本 | V1.0 |
| 编制日期 | 2026-06-26 |
| 编制人 | 叶伟文 |
## 1. 项目背景与目标
### 1.1 背景
当前,供应商关系管理系统与智慧招标平台各自独立运行,存在数据孤岛。供应商需在两套系统中分别维护信息、管理账号,在跨平台操作时需重复登录,严重影响用户体验与业务协同效率。
### 1.2 目标
* **数据互通**:实现供应商主数据、采购计划、中标资料在两个系统间的实时或准实时同步。
* **业务协同**:打通从供应商准入、招标到合同签订的全流程,实现业务流程无缝衔接。
* **体验优化**:构建统一登录认证体系,实现"一次登录,两平台通行"的无感跳转体验。
## 2. 总体架构设计
### 2.1 系统交互架构图
```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 ` |
| `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重定向到SRM,URL中携带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` | 系统内部错误 | 数据库连接超时 |