SFT/缺失的后端接口.md

247 lines
21 KiB
Markdown

# 缺失的后端接口 / 真实接口契约说明
> 更新说明:阶段1(工程基础设施+登录+系统管理)与阶段2(基础配置:核心企业/客户经理)原先按前端自
> 行设计的契约用 `mock-server/` 模拟开发。现后端已提供首版真实接口(`swagger_project_scfs_2026-07-
> 09_14-15-23.json`),前端已完成对接改造,不再使用 mock 契约。本文档改为:**Part 1** 速查已对接的
> 真实接口契约(便于前后端联调核对);**Part 2** 列出联调/开发中发现的、后端文档未覆盖或建议后续
> 补充的事项。`mock-server/` 保留作无后端环境下的应急本地演示兜底,契约与下文不一致,不作为参考。
>
> 通用约定(均已通过真实 swagger 核实):
> - 所有接口返回统一包裹结构 `{ code: number, message: string, data: any }`,`code === 200` 表示业务成功,
> 前端统一按 `code !== 200` 判断失败并展示 `message`,不再做具体错误码分支处理。
> - 除登录、刷新令牌、发送短信外,其余接口均需在请求头携带 `Authorization: Bearer {token}`。
> - 日期时间字段格式统一为 `yyyy-MM-dd HH:mm:ss`。
> - 分页查询接口(`.../page`)请求 Body 均含 `page`(从1开始)、`pageSize`;响应 `data` 统一为
> `{ total, page, pageSize, records: [...] }`(字段名为 `records`,不是 `list`)。
> - 除个别接口(见下文标注)外,增删改接口均为单条操作,不提供批量接口。
## Part 1:已提供接口契约速查
### 1.1 通用鉴权
| 接口 | 说明 |
| --- | --- |
| `POST /api/auth/login-password` | 账号密码登录,Body `{username, password}`,响应 `LoginVo` |
| `POST /api/auth/login-phone` | 手机验证码登录,Body `{phone, smsCode}`,响应 `LoginVo` |
| `POST /api/auth/send-sms-code` | 发送短信验证码,Body `{phone, businessType}`,登录场景前端暂传 `businessType: 'LOGIN'`(见 Part 2-1) |
| `POST /api/auth/refresh-token` | 刷新令牌,无 Body,依赖 httpOnly Cookie 中的 `refresh_token`(**不**携带 Authorization 头),响应 `LoginVo` |
| `POST /api/auth/logout` | 登出,无 Body |
| `POST /api/auth/user-info` | 获取当前用户信息,无 Body(基于当前 JWT),响应 `UserDetailVo` |
| `GET /api/auth/user/permission-detail?userId=` | 获取用户扁平权限列表 `UserPermissionDetailVo[]`,前端自行 `buildTreeFromFlat`/`extractMenuTree`/`extractButtonCodes` |
| `POST /api/auth/change-password` | 修改密码,Body `{oldPassword, newPassword}`(首次登录强制改密场景复用) |
| `POST /api/user/reset-password` | 管理员重置用户密码,Body `{userId}` |
| `POST /api/auth/reset-password` | 找回密码场景(未接入前端,登记备查),Body `{phone, smsCode, newPassword}` |
`LoginVo` 字段:`{ token, username, realName, userId, phone, userType, organizationId, forceChangePwd }`。
### 1.2 系统管理 —— 用户
| 接口 | Body/Query | 说明 |
| --- | --- | --- |
| `POST /api/auth/user/page` | `{organizationId, usernameLike, phone, status(ACTIVE\|LOCKED), roleId, page, pageSize}` | 响应 `records: UserPageVo[]`(含 `organizationName`/`roleNameList`,不含 `roleIds`/`createdAt`) |
| `POST /api/auth/user/create` | `{username, phone, realName, organizationId, status, email, userRoleBtoList:[{roleId}]}` | 响应 `CreateUserVo{id,status}`,不返回初始密码 |
| `POST /api/user/update` | `{id, username, phone, realName, organizationId, email, userRoleBtoList:[{userId,roleId}]}` | |
| `POST /api/user/delete` | `{userId}` | 单条 |
| `POST /api/user/lock` / `POST /api/user/unlock` | `{userId}` | |
| `GET /api/auth/user-role/list-by-user?userId=` | — | 响应 `UserRoleVo[]{id(即roleId), roleName, organizationId, isBuiltIn}`,用于编辑用户时回填已选角色 |
| `POST /api/auth/user-role/bind` / `unbind` | `{userId, roleIdList}` | 独立接口,当前未使用(create/update 已内嵌 `userRoleBtoList`) |
### 1.3 系统管理 —— 角色
| 接口 | Body | 说明 |
| --- | --- | --- |
| `POST /api/role/page` | `{roleName, page, pageSize}` | 不支持按机构/状态过滤,响应 `records: RoleVo[]` |
| `POST /api/role/detail` | `{roleId}` | 响应 `RoleDetailVo{roleName,id,organizationId,isBuiltIn,permissionIdList}` |
| `POST /api/role/create` | `{roleName, organizationId, isBuiltIn}` | 不含权限,不返回新建 id(见 Part 2-2) |
| `POST /api/role/update` | `{id, roleName, organizationId}` | 不含权限 |
| `POST /api/role/delete` | `{roleId}` | 单条 |
| `GET /api/auth/role-permission/list-by-role?roleId=` | — | 响应 `RolePermissionVo[]` |
| `POST /api/auth/role-permission/bind` / `unbind` | `{roleId, permissionIdList}` | 前端采用"查旧集合→diff→分别 bind/unbind"策略 |
角色模型**不含**数据权限范围(dataScope)字段。
### 1.4 系统管理 —— 权限字典
| 接口 | Body | 说明 |
| --- | --- | --- |
| `GET /api/permission/tree` | — | 响应嵌套树 `PermissionTreeVo[]`,顶级 `level=0` |
| `POST /api/permission/create` | `{permissionType(PAGE\|BUTTON), permissionName, permissionCode, parentId, level, sortOrder, icon, routePath, pageResourcePaths[], apiResourcePaths[]}` | 响应 `{id, permissionCode}` |
| `POST /api/permission/update` | 同上,不含 `permissionType` | |
| `POST /api/permission/delete` | `{id}` | |
### 1.5 系统管理 —— 机构
| 接口 | Body/Query | 说明 |
| --- | --- | --- |
| `GET /api/organization/query-tree` | `{organizationName?, organizationId?}` | 响应嵌套树 `OrganizationTreeNodeVo[]`,不传筛选参数时返回全树 |
| `GET /api/organization/list-all` | `{organizationName?}` | 响应扁平 `OrganizationSimpleVo[]`,用于表单"所属机构"下拉 |
| `POST /api/organization/create` | `{organizationName, parentId, remark}` | `parentId` 为数字(引用上级机构的数字 `id`),响应完整 `OrganizationDetailVo` |
| `POST /api/organization/update` | `{organizationId(字符串), organizationName, parentId, remark}` | **注意**:定位字段是字符串业务码 `organizationId`,不是数字 `id` |
| `POST /api/organization/delete` | `{organizationId(字符串)}` | 同上,响应 `data``boolean` |
机构模型关键点:`id`(数字主键,供 `parentId`/用户/角色/核心企业/客户经理的 `organizationId` 外键引用)与
`organizationId`(字符串业务码,仅用于机构自身 update/delete 定位及 query-tree 筛选参数)是两个不同字段,
同时存在于同一条机构记录上。`/api/organization/tree`(POST,无筛选参数的全量树)与 `query-tree` 功能重叠,
前端统一只使用 `query-tree`
### 1.6 基础配置 —— 核心企业 / 客户经理
| 接口 | Body | 说明 |
| --- | --- | --- |
| `POST /api/core-enterprise/page` | `{page, pageSize, enterpriseName}` | 仅支持企业名称模糊搜索,响应 `records: CoreEnterpriseVo[]` |
| `POST /api/core-enterprise/create` / `update` / `delete` | 见 `CreateCoreEnterpriseBto`/`UpdateCoreEnterpriseBto`(字段:`enterpriseCode/enterpriseName/businessLicense/organizationId/contactPerson/contactPhone/status(ACTIVE\|INACTIVE)/remark`);`delete` Body `{id}` | |
| `POST /api/customer-manager/page` | `{page, pageSize, managerName}` | 仅支持姓名模糊搜索,响应 `records: CustomerManagerVo[]` |
| `POST /api/customer-manager/create` / `update` / `delete` | 字段:`managerCode/managerName/mobilePhone/organizationId/department/status(ACTIVE\|INACTIVE)/remark`;`delete` Body `{id}` | |
核心企业、客户经理模型均**不含** `organizationName`,前端本地通过 `organization/list-all` 建 id→name 映射
展示所属机构列。
### 1.7 客户管理 —— 个人客户
| 接口 | 说明 |
| --- | --- |
| `POST /api/customer-info/personal/list` | `{organizationIdEq,customerCodeEq,customerNameLike,certificateNumberEq,page,pageSize}`,响应 `records: IndividualCustomerListVo[]`(仅 `id,organizationId,customerName,certificateType,certificateNumber,mobilePhone,ocrStatus,customerCode`,不含性别/创建人/创建时间) |
| `POST /api/customer-info/personal/detail` | `{id}``{customerCode}`,响应 `IndividualCustomerDetailVo` |
| `POST /api/customer-info/personal/create` | `CreateIndividualCustomerBto`,响应 `data`=新建id |
| `POST /api/customer-info/personal/update` | `UpdateIndividualCustomerBto` |
| `POST /api/customer-info/personal/ocr-idcard` | `{fileBase64,channelNo,fileType('01'\|'02')}`,响应 `OcrIdCardResultVo` |
| `POST /api/customer-info/personal/upload-file` | `{fileBase64,channelNo}`,响应 `{fileNo}`,个人身份证与企业营业执照图片均调用此通用接口 |
### 1.8 客户管理 —— 企业客户
| 接口 | 说明 |
| --- | --- |
| `POST /api/enterprise-customer/page` | `{page,pageSize,enterpriseName,businessLicense,mobilePhone}`,响应 `records: EnterpriseCustomerVo[]` |
| `POST /api/enterprise-customer/detail` | `{id}`,响应 `EnterpriseCustomerDetailVo` |
| `POST /api/enterprise-customer/create` | `{createEnterpriseCustomerBto,enableOcr}` |
| `POST /api/enterprise-customer/update` | `UpdateEnterpriseCustomerBto` |
### 1.9 钱包管理 —— 账户列表/账户主页
| 接口 | 说明 |
| --- | --- |
| `POST /api/wallet-account/page` | `{page,pageSize,accountName,accountNo,accountType(A1\|A2\|A3\|A6\|A7)}`,响应 `records: WalletAccountVo[]` |
| `POST /api/wallet-account/detail` | `{id}`,响应 `WalletAccountDetailVo{mainAccountNo,mainBalance,a2AccountNo,a2Balance,a6AccountNo,a6Balance,a7AccountNo,a7Balance}`(不含 accountName) |
| `POST /api/wallet-account/close` | `{id}`,销户 |
| `POST /api/wallet-account/open-sub-account` | `{accountNo}`(主账户账号),开分户 |
| `POST /api/wallet-account/update` | `{accountNo,mobile,bankCardNumber,bankNo,bankName}` |
| `POST /api/wallet-account/change-mobile` | `{accountNo,newMobile}` |
| `POST /api/wallet-account/sync-balance` | `{id}` |
| `POST /api/wallet-account/transaction-detail` | `{accountNo,channelNo,startDate,endDate,page,rows}`,响应 `TransactionDetailVo{...,detailList:TradeDetailItemVo[]}` |
| `POST /api/wallet-account/withdraw` | `{channelNo,withdrawRequestEo:WithdrawRequestEo}`,响应 `WithdrawResultVo` |
| `POST /api/wallet-account/margin-pay` / `margin-release` | `MarginOperationRequestEo{accountNo,accountName,tradeAmount,remark}`,响应 `MarginResultVo` |
| `POST /api/wallet-account/download-statement` / `download-receipt` | 均响应 `{fileData(base64 PDF)}` |
| `POST /api/wallet-account/bind-card-list` / `bind-card` / `unbind-card` | 个人绑卡管理三件套 |
### 1.10 钱包管理 —— 个人开户(`/api/wallet-management/personal-opening/*`)
| 接口 | 说明 |
| --- | --- |
| `POST .../query-customer` | 个人开户专属客户查询,响应字段同 `IndividualCustomerDetailVo` |
| `POST .../create-draft` | 提交开户草稿,响应 `{applicationNo}` |
| `POST .../query-progress` | `{applicationNo}`,响应 `ApplicationProgressVo` |
### 1.11 钱包管理 —— 企业开户申请与企业绑卡(`/api/wallet-management/enterprise-open-application/*`、`enterprise-bank-card/*`)
| 接口 | 说明 |
| --- | --- |
| `POST enterprise-open-application/list` | 响应 `records: EnterpriseAccountOpenApplicationListVo[]`(**无 id 字段**) |
| `POST enterprise-open-application/create` | `CreateEnterpriseAccountOpenBto`,响应 `{applicationNo}` |
| `POST enterprise-open-application/detail` | `{applicationNo}`,响应 `EnterpriseAccountOpenApplicationDetailVo`(**无 id 字段**) |
| `POST enterprise-open-application/update` | `UpdateEnterpriseAccountOpenApplicationBto`,**要求 `id`(int64)** |
| `POST enterprise-bank-card/list` / `bind` / `unbind` | 企业绑卡管理三件套,字段结构同个人绑卡但用 `primaryAccount`/`accountProperty` |
### 1.12 授信管理 —— 贷款申请(`/api/credit-apply/*`)
| 接口 | 说明 |
| --- | --- |
| `POST credit-apply/loan-application/list` | 柜员分页查询,入参仅支持 `loanApplicationId/applicationStatus/applicationType/customerName/createDateStart/createDateEnd`,响应 `records: LoanApplicationVo[]` |
| `POST credit-apply/loan-application/detail` | `{loanApplicationId}`,响应 `LoanApplicationDetailVo`(个人/企业字段混合于同一模型,约60余字段) |
| `POST credit-apply/personal-loan-application/create` / `update` | 个人贷款申请草稿创建/修改(仅 DRAFT 可改),响应 `data``loanApplicationId` 字符串 |
| `POST credit-apply/enterprise-loan-application/create` / `update` | 企业贷款申请草稿创建/修改,响应 `CreateEnterpriseLoanDraftResultVo` |
| `POST credit-apply/loan-application/confirm` | 申请人微信扫码确认(短验+人脸识别),移动端流程,不在本项目前端范围 |
---
## Part 2:待后端确认 / 建议补充事项
1. **`send-sms-code``businessType` 取值无 enum 文档**:swagger 仅标注为普通 `string`,登录场景前端暂定
`'LOGIN'`,需后端确认合法取值枚举(找回密码场景描述提到 `FIND_PASSWORD`,登录场景取值待确认)。
2. **`POST /api/role/create` 不返回新建记录 id**:前端已改为"创建成功后按 `roleName`+`organizationId` 反查
`role/page` 取得 id 再绑定权限"规避,建议后端补充直接返回新建 `id`(`core-enterprise/create`、
`customer-manager/create` 同样不返回新建 id,当前无需立即二次操作故不阻塞,但建议一并补充以保持接口
一致性)。
3. **批量删除接口缺失**:用户、角色、机构、核心企业、客户经理的删除接口均为单条,前端已改为循环调用
单条删除接口模拟批量交互(`src/utils/loopDelete.js`),建议后端评估是否补充原子性 batch 接口。
4. **管理员直接为其他用户指定新密码(无需旧密码)的接口不存在**:原型图中的"密码修改"入口暂保留但
置灰禁用,提示改用"密码重置"。
5. **`user/create`、`user/reset-password` 是否已实际发送短信通知用户,新密码规则(固定值/随机)未文档化**:
前端仅按约定展示"已通过短信通知用户"提示文案,不做实际校验。
6. **`role-permission/bind`/`unbind` 的语义(全量替换 vs 增量追加)未在 swagger 说明**:前端已按"先查旧
集合、计算 diff、分别调用 bind(新增项)/unbind(移除项)"的保守策略实现,不受该语义影响,但建议
后端在文档中明确。
7. **角色列表(`role/page`)不支持按所属机构过滤;核心企业、客户经理列表只支持单一名称模糊搜索**:
相比原前端自行设计的契约,过滤能力收窄,搜索表单已同步精简,若后续产品侧需要更多筛选维度,需后端
评估补充查询参数。
8. **角色数据权限范围(本机构/本机构及下级/全部)字段在真实模型中不存在**:若产品侧仍需要该能力,需
后端评估补充。
9. **用户列表/详情不返回 `roleIds`**:编辑用户角色时需额外调用 `user-role/list-by-user`,建议后端在
`UserPageVo`/`UserDetailVo` 中直接补充 `roleIdList` 以减少一次请求。
10. **权限字典种子数据需部署后手动初始化**:用户/角色/机构/权限/核心企业/客户经理各页面与按钮节点,
需部署后通过新的"系统管理 > 权限管理"页面手动创建,并授予内置管理员角色,否则登录后看不到任何
菜单。当前 `MainLayout.vue` 菜单渲染只支持两级,初始化菜单节点时层级需控制在 2 级以内。
11. **`/api/auth/reset-password`(找回密码)与登录页暂未接入**:当前登录页仅实现"账号密码"与"手机验证码"
两种登录方式,找回密码入口未在本次范围内开发,契约已在 Part 1-1 登记备查。
12. **个人客户/企业客户均无删除接口**:列表页暂不提供删除入口。
13. **营业执照无同步OCR识别接口**:`enterprise-customer/create` 的 `enableOcr` 参数用途/时序未文档化,
前端按"手动填写+提交时告知后端可异步识别"实现。
14. **企业客户股东高管信息(`enterpriseRelatedPersonBtoList`)只能在新增时一次性提交**:`update`/`detail`
接口均不支持读取或修改,编辑模式下该区块前端替换为提示文案,不可编辑。
15. **企业客户 `businessLicenseFileNo` 编辑/详情接口读取不到**:编辑模式无法回显已上传的营业执照图片。
16. **企业客户分页查询不支持按所属机构/企业编号过滤**:仅支持企业名称/营业执照号/手机号三项。
17. **个人客户 `customerCode`(客户编号)生成机制未文档化**:前端创建时不传该字段,交由后端生成。
18. **身份证/营业执照 OCR 结果字段命名未在 swagger 明确标注**(`OcrIdCardResultVo` 具体字段以实测为准),
前端 `mapOcrIdCardResult` 按常见字段名(`name/sex/nation/idcard/address/authority/birth/validDate`)
做防御性映射,识别失败或字段缺失时不阻断提交,允许手动填写。
19. **移动端确认页(个人开户 `mobile/*`、企业开户 confirm、贷款申请确认扫码后续)不属于本项目范围**:
相关接口已在后端提供但本次前端管理后台不实现对应移动端页面,登记备查。
20. **`WalletAccountDetailVo` 不含 `accountName`**:账户主页展示的账户名称改为由列表页通过路由 query
(`accountName`)传递,若用户直接刷新账户详情页地址,该字段会丢失显示为空,建议后端补充该字段。
21. **绑卡列表 `BindCardVo` 无法辨别"默认卡"**:提现/保证金默认取列表第一条作为默认卡,`accountProperty`
(借记卡/贷记卡)枚举取值未在 swagger 明确列出,前端按"01借记卡/02贷记卡"猜测渲染文案,建议后端
在文档中补充该字段真实枚举及是否存在"设为默认卡"能力。
22. **对账单/回单下载接口 `download-statement`/`download-receipt` 所需的 `originalSerialNo` 无法从交易
明细 `TradeDetailItemVo` 中直接获得独立流水号字段**:前端暂用该条记录的 `id` 字段兜底传递,若后端
实际需要的是独立业务流水号,批量下载回单功能将失败,需后端确认字段映射关系或补充响应字段。
23. **企业开户申请 `enterprise-open-application/list`、`detail` 接口返回的 Vo 均无 `id` 字段,但
`update` 接口的入参 `UpdateEnterpriseAccountOpenApplicationBto` 却要求 `id`(int64)**:前端编辑功能
已完整实现,提交更新时暂用 `applicationNo`(字符串)兜底传入 `id` 位置,该请求预计会被后端校验拒绝
或产生非预期行为,是本阶段最严重的接口契约缺口,需后端紧急评估:①在列表/详情 Vo 中补充 `id` 字段,
或②将 `update` 接口改为支持按 `applicationNo` 定位记录。
24. **`EnterpriseCustomerDetailVo``industry`(所属行业)字段**:企业开户申请表单选择企业客户后无法
自动回填所属行业,已改为用户手动填写该字段,若产品侧需要联动回填,需后端在企业客户详情接口中补充。
25. **企业开户申请受益人信息 `enterpriseAccountOpenApplicationBeneficiaryBtoList` 是否支持多条受益人
`update` 时的增删语义(全量替换 vs 增量)未在 swagger 说明**:前端当前只支持维护单条受益人信息,
提交时整体覆盖该数组,若产品侧需要多受益人管理,需后端明确该数组的更新语义。
26. **贷款申请存在两组平行接口 `/api/loan-application/*``/api/credit-apply/*`**:前者(`create-personal`
`create-enterprise`/`detail`/`page`)与后者(`personal-loan-application/create`等)字段结构不同、
用途描述均不完整,前端已选用后者(`credit-apply` 组,描述明确标注"银行柜员"场景且具备
DRAFT→CONFIRMED→SUBMITTED 状态机,与阶段4风格一致),前者暂未使用,建议后端确认是否为废弃接口或
说明二者分工,避免维护两套语义重叠的接口。
27. **个人贷款申请草稿 `CreatePersonalLoanApplicationDraftBto` 不含 `customerId`/账户号(钱包账号)字段**:
与企业贷款草稿 `CreateEnterpriseLoanDraftBto`(含 `customerId`+`accountNo`)不对称,个人贷款申请无法
与具体客户ID、具体钱包账号建立强关联,选择客户仅能回填 `customerName`/`phoneNo`/`permanentAddress`
三个文本字段,不产生外键关系,与需求文档"贷款钱包仅展示申请人已开立的钱包"的描述存在能力缺口,
建议后端为个人贷款草稿补充 `customerId`/`accountNo` 字段。
28. **贷款产品(`loanProductCode`)无独立的列表/字典查询接口**:前端改为柜员手动输入产品编号文本框,
无法做下拉选择与合法性校验,建议后端补充贷款产品字典查询接口。
29. **企业贷款草稿字段 `customerType` 无 enum 约束说明**:前端按项目既有命名习惯猜测传值 `'ENTERPRISE'`,
需后端确认合法取值(可能是 `'ENTERPRISE'`/`'BUSINESS'`/`'企业'` 等其他形式)。
30. **贷款申请没有"按企业客户查询其已开立钱包账号"的专用接口**:前端改为选定企业客户后,调用通用的
`wallet-account/page``accountName`(企业名称文本)模糊匹配钱包账户列表供人工选择,若同名不同企业
或企业名称与钱包账户名称不完全一致,可能匹配不到或匹配错误,建议后端补充按 `customerId` 精确查询
钱包账号的专用接口。
31. **法定代表人/配偶相关字段(`legalPersonEducation`/`legalPersonMarital`/`legalPersonNationality`/
`legalPersonGender`/`spouseGender` 等)均为无枚举约束的纯字符串**:前端为提升可用性复用个人贷款
对应枚举的取值域渲染下拉框,但后端未做强校验,实际入库是否要求严格匹配以实测为准。