This commit is contained in:
2026-08-13 11:57:33 +08:00
parent 5a48992d78
commit 16dc03a2e2
102 changed files with 3656 additions and 120 deletions
@@ -0,0 +1,238 @@
# 平台供应商前端接口交接单
## 接入约定
- Base path:`/api/platform/v1/suppliers`
- 浏览器请求继续使用 Gateway `/api` 前缀,不在前端硬编码服务地址。
- 仅平台端账号可访问,供应商固定属于平台公共作用域 `tenantId=0`。
- 供应商是独立业务档案,不复用或修改往来单位 Partner。
- 所有接口使用统一 `ApiResponse<T>`:
```json
{
"code": "200",
"message": "success",
"data": {},
"requestId": null,
"traceId": null,
"timestamp": "2026-08-13T03:00:00Z"
}
```
- 普通业务失败、参数校验失败通常仍返回 HTTP 200,前端必须以 body `code === "200"` 判断业务成功。认证、网关或基础设施拒绝仍可能返回真实 HTTP 401、403、503。
- Java `Long` 标识在 JSON 中按字符串消费,包括 `id`、`tenantId`、`createdBy`、`updatedBy`,不得转成 JavaScript `number`。
## 接口清单
| 功能 | 方法与路径 | 权限码 |
|---|---|---|
| 列表 | `GET /api/platform/v1/suppliers` | `platform:supplier:list` |
| 分类统计 | `GET /api/platform/v1/suppliers/stats` | `platform:supplier:list` |
| 详情 | `GET /api/platform/v1/suppliers/{id}?tenantId=0` | `platform:supplier:list` |
| 新增 | `POST /api/platform/v1/suppliers?tenantId=0` | `platform:supplier:create` |
| 编辑 | `PUT /api/platform/v1/suppliers/{id}?tenantId=0` | `platform:supplier:edit` |
| 启停 | `PATCH /api/platform/v1/suppliers/{id}/status?tenantId=0` | `platform:supplier:status` |
列表和统计的 `tenantId` 可省略;传入时只能是 `0`。详情、新增、编辑、启停当前要求显式传 `tenantId=0`。
## 列表查询
查询参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `tenantId` | string | 否 | 只能为 `0` |
| `page` | integer | 否 | 默认 `1`,最小 `1` |
| `size` | integer | 否 | 默认 `20`,范围 `1..200` |
| `category` | enum | 否 | 供应商分类 |
| `scope` | enum | 否 | 仅订舱分类适用 |
| `region` | string | 否 | 地区精确匹配,最长 80 |
| `status` | enum | 否 | 合作状态 |
| `keyword` | string | 否 | 按供应商名称或联系人模糊匹配 |
分页响应 `data`:
```json
{
"records": [],
"page": 1,
"size": 20,
"total": 0,
"pages": 0
}
```
`records` 元素使用下述 Supplier 字段。`page/size/total/pages` 是整数分页元数据。
## Supplier 字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `id` | string | 供应商 ID |
| `tenantId` | string | 固定为 `0` |
| `name` | string | 供应商名称,平台内唯一 |
| `category` | enum | 分类 |
| `scope` | enum/null | 订舱供应商必填;其他分类为 `null` |
| `region` | string | 地区 |
| `legalRepresentative` | string | 法人代表 |
| `contactName` | string | 联系人 |
| `phone` | string | 联系电话 |
| `email` | string/null | 电子邮箱 |
| `address` | string/null | 公司地址 |
| `businessLicenseNo` | string/null | 营业执照号/统一社会信用代码 |
| `licenseFileId` | string/null | File 服务返回的营业执照文件 ID,只允许十进制数字字符串 |
| `status` | enum | 合作状态 |
| `settlementPeriod` | enum | 结算周期 |
| `remark` | string/null | 备注 |
| `createdBy` | string/null | 创建人 ID |
| `createdAt` | datetime | 创建时间 |
| `updatedBy` | string/null | 最后修改人 ID |
| `updatedAt` | datetime | 最后修改时间 |
| `deleted` | boolean | 逻辑删除标记;正常响应为 `false` |
| `version` | integer | 乐观锁版本 |
营业执照上传由 File 服务完成。Supplier 新增或编辑只提交 `licenseFileId`;查看操作使用该 ID获取文件,不把 URL、base64 或文件二进制提交到 Supplier 接口。原型要求营业执照查看由前端使用居中弹框承载。
## 新增与编辑
新增和编辑使用相同请求体:
```json
{
"name": "示例供应商有限公司",
"category": "BOOKING",
"scope": "DOMESTIC",
"region": "宁波",
"legalRepresentative": "张三",
"contactName": "李经理",
"phone": "13800000000",
"email": "supplier@example.com",
"address": "宁波市示例路 1 号",
"businessLicenseNo": "91330000XXXXXXXXXX",
"licenseFileId": "192000000000000001",
"status": "ACTIVE",
"settlementPeriod": "MONTHLY_30",
"remark": ""
}
```
必填字段:`name`、`category`、`region`、`legalRepresentative`、`contactName`、`phone`、`status`、`settlementPeriod`。`BOOKING` 时 `scope` 必填;其他分类 `scope` 必须传 `null` 或省略。
新增成功的 `data` 是供应商 ID 字符串。编辑成功的 `data` 为 `null`。
## 启停
```json
{ "status": "INACTIVE" }
```
只接受 `ACTIVE` 或 `INACTIVE`。接口不物理删除供应商。
## 分类统计
`GET /stats` 的响应 `data`:
```json
{
"booking": 8,
"customs": 5,
"trucking": 6,
"certificate": 3
}
```
## 枚举
供应商分类:
| 值 | 展示文案 |
|---|---|
| `BOOKING` | 订舱 |
| `CUSTOMS` | 报关 |
| `TRUCKING` | 拖车 |
| `CERTIFICATE` | 证书 |
订舱范围:
| 值 | 展示文案 |
|---|---|
| `DOMESTIC` | 国内 |
| `INTERNATIONAL` | 国外 |
合作状态:
| 值 | 展示文案 |
|---|---|
| `ACTIVE` | 合作中 |
| `INACTIVE` | 停用 |
结算周期:
| 值 | 展示文案 |
|---|---|
| `MONTHLY_30` | 月结30天 |
| `MONTHLY_45` | 月结45天 |
| `MONTHLY_60` | 月结60天 |
| `MONTHLY_90` | 月结90天 |
| `PER_TRANSACTION` | 票结 |
| `IMMEDIATE` | 现结 |
## 错误码
| `code` | 场景 | 前端处理建议 |
|---|---|---|
| `200` | 成功 | 使用 `data` |
| `A0400` | `tenantId` 非 0、请求格式或查询参数非法 | 显示参数错误,不重试 |
| `A0401` | 未登录或登录态失效 | 进入统一登录失效流程 |
| `A0403` | 非平台用户或缺少对应权限 | 显示无权限 |
| `A0404` | 供应商不存在 | 提示记录不存在并刷新列表 |
| `A0409` | 供应商名称重复或并发唯一键冲突 | 保留表单并提示名称已存在 |
| `A0422` | 字段校验失败、订舱范围规则不满足 | 使用 `message`/`data` 显示字段错误 |
| `S0500` | 未预期服务异常 | 展示通用错误并记录 `requestId/traceId` |
| `S0503` | Warehouse 数据库不可用 | 展示稍后重试并记录 `requestId/traceId` |
校验错误时 `data` 可能为字段到错误信息的映射,例如:
```json
{
"code": "A0422",
"message": "name: must not be blank",
"data": { "name": "must not be blank" },
"requestId": "...",
"traceId": "...",
"timestamp": "..."
}
```
## 契约来源
- OpenAPI:`warehouse/src/main/resources/openapi/supplier-v1.yaml`
- Controller:`warehouse/src/main/java/com/baiyue/warehouse/controller/PlatformSupplierController.java`
- DTO:`warehouse/src/main/java/com/baiyue/warehouse/dto/SupplierDtos.java`
权限码已在接口层冻结,但 IAM 权限初始化不属于本次 warehouse 文件所有权,联调前需确认 IAM 已落库并授予目标平台角色。
## 初始化与验收
- Warehouse 模块表迁移:`warehouse/src/main/resources/db/warehouse-supplier.sql`
- IAM 权限迁移:`iam/src/main/resources/db/platform-supplier-permissions.sql`
- 测试/存量环境唯一执行入口:`deploy/sql/头程数据库统一增量-MySQL8.sql`
- 权限固定 ID:`5103080..5103083`,依次对应 `list/create/edit/status`;`PLATFORM_ADMIN` 默认获得全部四项权限。
- Admin 测试环境验收模块:`scripts/admin-test-env-modules/suppliers.mjs`
- 验收模块静态契约:`scripts/admin-test-env-modules/suppliers-contract.test.mjs`
离线验证:
```powershell
mvn -pl warehouse,iam -am test
node --test scripts/admin-test-env-modules/suppliers-contract.test.mjs
pwsh scripts/local-db-full-acceptance.ps1 -DryRun
```
仅在当前对话已明确授权测试环境 API 验收后,才能运行下列命令。该模块会新增一条带本轮 marker 的供应商档案,并在结束时停用;由于供应商契约不提供删除接口,记录会保留为 `INACTIVE`。
```powershell
node scripts/admin-test-env-acceptance.mjs --modules suppliers
```
模块覆盖列表、统计、新增、详情、编辑、启停、重复名称、非法 scope、客户账号权限拒绝、`tenantId != 0` 和错误响应 `requestId/traceId`。本轮代码交付不执行该测试环境命令。