SFT/项目要点总结.md

591 lines
50 KiB
Markdown

# 凡荣e链管理后台前端 —— 项目要点总结
> 本文档基于代码现状(部分文件存在尚未提交的工作区改动)与 `缺失的后端接口.md`(接口契约权威来源)整理,用于帮助后续开发/维护人员快速理解项目整体架构、路由组织方式、各页面业务逻辑与后端接口对接情况。**不以 `mock-server/` 作为接口设计依据**,该目录仅为真实后端不可用时的本地应急演示后端。
---
## 目录
1. [项目概述](#1-项目概述)
2. [技术栈与项目结构](#2-技术栈与项目结构)
3. [整体架构](#3-整体架构)
4. [公共组件与工具函数](#4-公共组件与工具函数)
5. [登录页与错误页](#5-登录页与错误页)
6. [系统管理模块](#6-系统管理模块)
7. [基础配置模块](#7-基础配置模块)
8. [客户管理模块](#8-客户管理模块)
9. [钱包管理模块](#9-钱包管理模块)
10. [授信管理模块](#10-授信管理模块)
11. [商户中心模块](#11-商户中心模块)
12. [支付管理模块](#12-支付管理模块)
13. [订单管理模块](#13-订单管理模块)
14. [已知问题与待确认事项汇总](#14-已知问题与待确认事项汇总)
15. [本地 Mock Server 说明](#15-本地-mock-server-说明)
16. [维护建议](#16-维护建议)
---
## 1. 项目概述
**凡荣e链管理后台前端**是一套面向供应链金融/产业互联网场景的管理后台 SPA,覆盖系统管理、授信管理、支付管理、订单管理、客户管理、钱包管理、商户中心、基础配置等核心业务域。项目**没有 Node 服务端**,`mock-server/` 仅用于本地演示,构建产物为纯静态前端资源,真实业务数据依赖已接入的独立后端服务。
项目范围以 `docs/superpowers/specs/2026-07-08-fryl-frontend-overall-design.md` 为权威依据,明确包含 9 个一级模块(系统管理、授信管理、支付管理、订单管理、客户管理、钱包管理、商户中心、基础配置、登录),并**明确排除**原型库中的非银专区、分账专区、税筹专区、农都专区、驾驶舱、首页仪表盘等模块,以及各模块下需求说明书未提及的原型子页面。`website_detail/` 目录是从已上线的稠州银行商业平台完整抓取的原型参考(84 个页面),覆盖面远大于本项目实际范围,**不能当作"待实现清单"**,仅用于查阅交互细节。
## 2. 技术栈与项目结构
### 2.1 技术栈
| 分类 | 选型 |
| --- | --- |
| 框架 | Vue 3(`<script setup>` 组合式 API)+ Vite |
| 语言 | 纯 JavaScript,**无 TypeScript** |
| UI 组件库 | Ant Design Vue |
| 状态管理 | Pinia |
| 路由 | Vue Router 4(动态路由,见下文) |
| HTTP | Axios(单例封装,`withCredentials: true`) |
| 日期处理 | dayjs |
| 表格导出 | xlsx |
| 省市区数据 | china-division |
| 本地演示后端 | express / cors / cookie-parser(仅 `mock-server/`,devDependencies) |
无 lint / prettier / 单元测试脚本配置,不要假设它们存在。
### 2.2 常用命令
```bash
npm run dev # 启动开发服务器,端口 5173
npm run build # 构建
npm run preview # 预览构建产物
npm run mock # 启动本地 mock 后端(express),默认端口 8888,可用 MOCK_PORT 覆盖
```
### 2.3 目录速览
```
src/
├── api/ 各模块 axios 请求封装(request.js 为唯一 axios 实例)
├── components/ 通用业务组件(ProTable、上传组件、选择器等)
├── constants/ 各模块枚举字典(*Enums.js),来源必须是 swagger/缺失的后端接口.md
├── directives/ 自定义指令(v-permission)
├── layouts/ MainLayout(主布局)/ BlankLayout(登录页布局)
├── router/ index.js(静态路由+守卫)/ dynamic.js(动态路由生成)/ componentRegistry.js(组件映射表)
├── stores/ Pinia:auth.js(鉴权与权限)/ tabs.js(多标签页)
├── utils/ traceHeaders/orgScope/loopDelete/permissionTreeBuilder/formFocus/errorModal/mask/download/validators/lastActive/ocrMapping/batchDeleteResult
└── views/ 页面,按模块/子模块分文件夹:
base-config/ credit/ customer/ error/ login/ merchant/ order/ payment/ system/ wallet/
```
关键文档索引:
- `AGENTS.md`:项目开发规范与范围说明入口(本仓库的权威开发约定)。
- `缺失的后端接口.md`(936 行):**接口契约权威来源**。Part 1(1~234 行)是"已对接契约速查表",按模块列出接口的方法/路径/请求/响应;Part 2~11(235~936 行)是后续补充与变更记录(如机构数据隔离、字段调整、字段核对等),**优先级高于 Part 1**,如有冲突以 Part 2 及以后的记录为准。
- `swagger_project_scfs_2026-07-09_14-15-23.json`:后端真实接口定义源文件。
- `docs/superpowers/specs/2026-07-08-fryl-frontend-overall-design.md`:总体架构与范围划分设计文档。
- `docs/superpowers/specs/2026-07-08-module-requirements-mapping.md`:需求条款与原型页面映射。
- `docs/superpowers/specs/2026-07-16-org-data-isolation-design.md`:机构数据隔离设计说明。
- `mock-server/README.md`:本地演示后端说明,列出了"已知简化点/未文档化项",这些恰恰是真实后端接口设计不完整、需要额外注意的地方。
- `website_detail/`:70+ 页面的原型截图(png)+ HTML + summary.md,仅用于查阅本项目范围内页面的交互细节参考,不代表待实现范围。
### 2.4 已实现的一级视图目录
`src/views` 下已存在 10 个一级目录:`base-config`、`credit`、`customer`、`error`、`login`、`merchant`、`order`、`payment`、`system`、`wallet`。
## 3. 整体架构
### 3.1 全局布局
- `BlankLayout.vue`:无侧边栏/导航栏的空白布局,**仅用于登录页**,符合"登录页必须不含任何导航元素"的规范。
- `MainLayout.vue`:深色水平主菜单 + 可关闭的多标签页(状态由 `src/stores/tabs.js` 管理)+ 右上角用户下拉(含退出登录)。所有业务页面均挂载在此布局下。
### 3.2 路由机制(动态路由,新增页面必须两处登记)
路由**不是静态声明的**,而是登录后根据后端返回的菜单权限树动态生成:
1. `src/router/index.js`:仅静态声明 `/login`、`/403`、404 通配符路由,并挂载全局前置守卫 `router.beforeEach`:
-`accessToken`(除白名单路由) → 跳转 `/login`;
- 有 token 但路由尚未就绪(`routesReady` 为 false)→ 先调用 `fetchCurrentUser``rebuildPermissions` 拉取权限树,再调用 `installDynamicRoutes` 挂载动态路由,然后重新 `next(to.fullPath)` 完成一次"replay"跳转;
- 登录成功后默认落地页为菜单权限列表中第一个可访问页面(或用户登录前尝试访问的原始目标页面)。
2. `src/router/dynamic.js`(`installDynamicRoutes`):遍历后端菜单树,为每个菜单节点生成一条挂载在 `MainLayout` 下的子路由记录,组件通过 `import.meta.glob('@/views/**/*.vue')` 懒加载。
3. `src/router/componentRegistry.js`:**手工维护**的路径 → 组件映射表,是新增页面最容易漏掉的一步:
- `routePathComponentMap`:后端菜单 `path` → 组件相对路径的映射,用于侧边栏可见的列表页。
- `extraChildRoutes`:新增/编辑/详情等**不出现在侧边栏菜单**里的表单页路由(通常以 `create`/`edit`/`detail` 作为路径后缀,组件内部据此推导表单模式:新建/编辑/只读查看)。
已注册的 `routePathComponentMap` 完整映射:
| 菜单 path | 组件 |
| --- | --- |
| `/system/user` | `system/user/UserList.vue` |
| `/system/role` | `system/role/RoleList.vue` |
| `/system/org` | `system/org/OrgList.vue` |
| `/system/permission` | `system/permission/PermissionList.vue` |
| `/base-config/channel` | `base-config/channel/ChannelList.vue` |
| `/base-config/manager` | `base-config/manager/ManagerList.vue` |
| `/customer/personal` | `customer/personal/PersonalList.vue` |
| `/customer/enterprise` | `customer/enterprise/EnterpriseList.vue` |
| `/wallet/account` | `wallet/account/AccountList.vue` |
| `/wallet/personal-open` | `wallet/personal-open/PersonalOpenList.vue` |
| `/wallet/enterprise-open` | `wallet/enterprise-open/EnterpriseOpenList.vue` |
| `/credit/loan-application` | `credit/loan-application/LoanApplicationList.vue` |
| `/merchant/management` | `merchant/management/MerchantList.vue` |
| `/merchant/invoice` | `merchant/invoice/InvoiceList.vue` |
| `/payment/order-payment` | `payment/order-payment/PaymentRecordList.vue` |
| `/order/summary` | `order/summary/SummaryOrderList.vue` |
| `/order/original` | `order/original/OriginalOrderList.vue` |
> 说明:`/system/permission`(权限字典管理)虽然在 `2026-07-08` 总体设计文档明确的"实施范围"清单中未被单列,但代码中已实际注册路由并有完整组件实现,属于代码现状与早期设计文档之间的差异,维护时应以代码现状为准,如需收窄范围需与产品确认。
`extraChildRoutes` 中登记了各业务模块的新增/编辑/详情隐藏路由(如 `customer/personal/create`、`wallet/enterprise-open/edit` 等),具体见各模块章节。
### 3.3 鉴权与权限流程
核心文件:`src/stores/auth.js` + `src/api/request.js` + `src/utils/permissionTreeBuilder.js`
- `accessToken` 持久化存储在 `localStorage`;`userInfo`/`menuTree`/`buttonCodes` 仅保存在内存态(Pinia store,不持久化,符合"用户信息不得持久化存储"的规范)。
- 判定登录态的唯一依据:**本地是否存在 `accessToken`**,不做后端二次校验(直到某次请求触发 401)。
- 登录后 / 刷新页面后调用 `rebuildPermissions`(内部请求 `/api/auth/user/permission-detail` 获取扁平权限列表),经 `permissionTreeBuilder.js` 构建菜单树并提取按钮权限码集合。
- 请求拦截器(`src/api/request.js`):
- 自动注入 `Authorization: Bearer {accessToken}`;
- 自动注入 `buildTraceHeaders()` 生成的追踪头(见下文 3.4);
- 统一按响应体 `code !== 200` 判定业务失败,提示 `message`
- **401 静默刷新**:响应拦截器检测到 401 时,通过 httpOnly Cookie 中的 `refresh_token` 调用 `/api/auth/refresh-token`(该请求本身**不带** `Authorization` 头),并用请求队列防止刷新期间的并发请求重复触发刷新;刷新失败则清空登录态并跳转 `/login`
- **403**:展示"无权限访问该资源"的明确提示(全局统一处理,不需要业务页面单独处理)。
- 按钮级权限:`v-permission` 自定义指令(`src/directives/permission.js`),未授权按钮会被**直接从 DOM 移除**(而非仅置灰/隐藏)。
- 机构数据隔离:`src/utils/orgScope.js` 的 `getCurrentOrganizationId()` 用于查询/新增表单默认填充当前用户所属机构,机构可选范围的裁剪职责在**后端**,前端不做二次过滤(部分模块后端尚未按此实现,见第 14 章已知问题)。
### 3.4 请求追踪头(Trace Headers)
每次请求必须附带以下 5 个 header(**字段名大小写固定**,首字母大写、其余小写):
| Header | 说明 |
| --- | --- |
| `Appno` | 随机值 |
| `Channelno` | 渠道 ID,来自页面上用户选择的渠道(非固定值,不能硬编码);页面无渠道上下文时不传 |
| `Serialno` | 流水号,随机值 |
| `Transdate` | `yyyy-MM-dd` 格式日期 |
| `Transtradetime` | `yyyy-MM-dd HH:mm:ss` 格式时间 |
实现位于 `src/utils/traceHeaders.js``buildTraceHeaders()`
### 3.5 通用接口约定(来自《缺失的后端接口.md》)
- 响应体统一 `{ code, message, data }`,业务成功判定为 `code === 200`;非 200 时使用 `message` 提示,不做具体错误码分支(除 401/403 的全局统一处理外)。
- 除登录 / 刷新令牌 / 发短信外,所有请求必须带 `Authorization: Bearer {token}`
- 日期时间字段统一格式 `yyyy-MM-dd HH:mm:ss`
- 分页接口:请求 Body 含 `page`(从 1 开始)/ `pageSize`;响应 `data` 统一为 `{ total, page, pageSize, records }` —— **字段是 `records`,不是 `list`**。
- 绝大多数模块**没有批量删除接口**,批量操作使用 `src/utils/loopDelete.js` 循环调用单条删除接口并汇总结果,再配合 `src/utils/batchDeleteResult.js` 展示成功/失败明细。
- 文件(身份证、营业执照等)以 **Base64 字符串**放在 JSON body 中传输,不使用 `multipart/form-data`
- 枚举值必须来自 swagger / 《缺失的后端接口.md》,已整理在 `src/constants/*Enums.js`,不得臆造。
### 3.6 BASE_URL 可配置入口
登录页右上角齿轮图标可打开"接口地址设置"弹窗,运行时切换后端地址,存储于 `localStorage.base_url_override`;实现见 `src/api/request.js``getBaseUrl()` / `setBaseUrlOverride()`。`.env.development` 默认 `VITE_API_BASE_URL=http://localhost:8888`(即本地 mock server),`.env.production` 为空(走相对路径/运行时配置)。本地联调真实后端遇到 CORS 时,通过 `.env.development.local`(已 gitignore)配置 `DEV_API_PROXY_TARGET`,走 `vite.config.js` 中的同源代理方案,不应为此改动生产构建逻辑。
## 4. 公共组件与工具函数
### 4.1 `ProTable.vue`
通用"查询表单 + 操作栏 + 分页表格"封装,绝大多数列表页优先复用它而不是重写查询/分页逻辑,支持 checkbox/radio 行选择模式(配合批量操作/单选联动场景)。
### 4.2 图片/证件上传组件规范
所有"图片上传卡片"(身份证、营业执照、人脸照片等 `list-type="picture-card"``a-upload` 封装组件),一旦已选中图片,**必须**支持鼠标 hover 缩略图时显示半透明遮罩 + 预览/重新上传/删除三个操作按钮,不允许只放一张裸 `<img>`。标准实现参照 `src/components/IdCardUpload.vue`(`LicenseUpload.vue` 已按此模式改造):
- 缩略图外层 `.thumb-wrapper`(`position: relative`)包裹 `<img>` + `.hover-mask`(`position:absolute; inset:0`,`rgba(0,0,0,0.5)` 背景,默认 `opacity:0`,hover 时 `opacity:1`,`transition:opacity 0.2s`)。
- 遮罩内横向排列三个图标:`EyeOutlined`(预览)/ `EditOutlined`(重新上传)/ `DeleteOutlined`(删除),之间用 1px 竖线 `.mask-divider` 分隔,图标颜色 `#fff`,hover 变 `#1677ff`
- **预览**:图标加 `@click.stop`,打开 `a-modal`(`:footer="null"`)放大展示图片。
- **删除**:图标加 `@click.stop`,清空本地预览态并 `emit('update:fileNo', '')`
- **重新上传**:图标**不加** `@click.stop`,让点击事件冒泡到外层 `a-upload` 容器,复用其原生文件选择流程。
- 支持 `readonly` prop(默认 `false`),为 `true` 时只保留预览图标,隐藏重新上传/删除,用于只读详情表单;调用处需将页面自身的 `isDetail` 等只读态标记正确传给该 prop。
- 当前项目**没有抽出通用的图片上传基础组件**,`IdCardUpload.vue` / `LicenseUpload.vue` / `FacePhotoUpload.vue` 各自独立实现(结构相似但不复用)。`FacePhotoUpload.vue` **尚未**按此规范改造,涉及时需一并补上。
### 4.3 耗时操作统一等待态规范
图片/文件上传、"提交"/"创建"/"保存"等触发接口调用的按钮及其他明显耗时的异步操作,**必须**统一展示等待态,期间禁止用户对页面做其他操作。标准参照 `src/views/customer/enterprise/EnterpriseForm.vue`(及 `PersonalForm.vue`):
- 页面级遮罩:最外层用 `<a-spin :spinning="busy" :tip="busyTip">` 包裹表单内容。
- `busy` 用一个 `computed` 统一收敛所有"进行中"状态(如 `submitting.value || xxxUploading.value`)。
- `busyTip` 按当前处于哪个耗时状态给出对应提示文案,无耗时状态时留空。
- 触发按钮加 `:loading="submitting"` 双重防止重复点击。
- 图片上传组件通过 `update:uploading` 事件把自身上传中状态回传给父表单,父表单纳入 `busy` 统一遮罩,并在提交前校验各 `xxxUploading` 状态,阻止文件未上传完成时提交表单。
### 4.4 其他通用业务组件
| 组件 | 说明 |
| --- | --- |
| `OrgTreeSelect.vue` | 机构树选择器 |
| `PermissionTree.vue` | 权限树勾选组件,用于角色分配权限 |
| `ChannelSelect.vue` | 渠道(核心企业)下拉选择,内部调用 `fetchCoreEnterprisePageApi` 拉取选项,下拉展示"渠道编号 - 渠道名称";兼容新旧字段名(`channelName/channelNo` 与历史字段 `enterpriseName/enterpriseCode`) |
| `RegionCascader.vue` | 省市区级联选择(基于 china-division 数据) |
| `StatusTag.vue` | 状态徽标展示,内置默认映射(`ACTIVE`→绿色"正常"、`LOCKED`→红色"已锁定"、`INACTIVE`→灰色"停用"),支持 `map` prop 覆盖/扩展 |
| `SmsCodeInput.vue` | 短信验证码输入框(含倒计时发送按钮) |
| `IdCardUpload.vue` / `LicenseUpload.vue` / `FacePhotoUpload.vue` | 身份证/营业执照/人脸照片上传,见 4.2 |
| `WalletAccountPicker.vue` / `WalletCustomerPicker.vue` / `PersonalCustomerPicker.vue` / `EnterpriseCustomerPicker.vue` | 钱包账户/客户选择器(弹窗选人场景) |
| `EnterpriseRelatedPersonCard.vue` / `EnterpriseInvestmentCard.vue` | 企业客户股东高管/对外投资信息卡片 |
| `WithdrawModal.vue` / `MarginModal.vue` / `BindCardModal.vue` | 钱包提现/保证金/绑卡弹窗 |
### 4.5 工具函数
| 文件 | 作用 |
| --- | --- |
| `src/utils/loopDelete.js` | 无批量删除接口时,循环调用单条删除接口并汇总结果 |
| `src/utils/batchDeleteResult.js` | 展示批量操作的成功/失败明细 |
| `src/utils/formFocus.js` | `focusFirstInvalidField()`:表单校验失败后定位并聚焦第一个带 `.ant-form-item-has-error` 的字段,滚动到视口居中;已知局限:字段位于折叠面板隐藏区域(`display:none`)时聚焦不生效,当前项目所有必填字段均在展开区域,暂不处理该场景 |
| `src/utils/errorModal.js` | `showErrorModal(content, title)`:统一错误提醒弹窗,内部维护队列,同一时刻只展示一个 `Modal.error`,多个错误依次排队,用户必须点击"我知道了"才能看到下一个/继续操作;用于替代原先分散的 `message.error` 调用 |
| `src/utils/mask.js` | 敏感信息脱敏展示(不影响提交给后端的真实值):`maskIdCard()` 保留前 6 位/后 4 位,中间替换为 4 个 `*`(长度 ≤10 原样返回);`maskMobile()` 保留前 3 位/后 4 位(长度 ≤7 原样返回) |
| `src/utils/download.js` | `downloadBase64File(base64, filename, mimeType)`:将后端返回的 base64 文件内容(如回单/对账单 PDF)解码为 Blob 并触发浏览器下载,不依赖第三方库 |
| `src/utils/validators.js` | 常用校验规则:手机号(`/^1\d{10}$/`)、密码强度(8 位以上且含大小写字母+数字)、身份证号(18 位,末位允许 X/x,不做校验码算术级校验)、统一社会信用代码/营业执照号(15-20 位数字+大写字母) |
| `src/utils/lastActive.js` | `startIdleWatcher(onTimeout, timeoutMs)`:监听 mousemove/mousedown/keydown/scroll/click 事件,空闲超时(默认 5 分钟)触发回调,在 `App.vue` 中启用实现自动登出 |
| `src/utils/orgScope.js` | `getCurrentOrganizationId()`:获取当前用户所属机构 ID,用于表单默认值;机构范围裁剪职责在后端 |
| `src/utils/permissionTreeBuilder.js` | 将后端返回的扁平权限列表构建为菜单树,并提取按钮权限码集合 |
| `src/utils/traceHeaders.js` | `buildTraceHeaders()`:生成请求追踪头,见 3.4 |
| `src/utils/ocrMapping.js` | OCR 识别结果字段到表单字段的映射 |
## 5. 登录页与错误页
### 5.1 登录页(`/login`,`src/views/login/Login.vue`)
- 使用 `BlankLayout`,页面**不含**任何侧边栏/导航栏,只有登录表单。
- 支持两种登录方式(Tab 切换):账号密码登录、手机验证码登录。
- 右上角齿轮图标可打开"接口地址设置"弹窗,配置 `BASE_URL`(见 3.6)。
- 登录成功后:`accessToken` 写入 `localStorage`,拉取当前用户信息与权限树后跳转到用户原本想访问的页面,或菜单权限列表中第一个可访问页面。
- 严禁 mock/硬编码当前用户信息或 AuthToken/登录验证令牌,均为真实接口交互结果。
### 5.2 错误页
| 路由 | 组件 | 说明 |
| --- | --- | --- |
| `/403` | `src/views/error/Forbidden.vue` | 极简 `a-result` 403 页面 |
| `*`(通配) | `src/views/error/NotFound.vue` | 极简 `a-result` 404 页面 |
## 6. 系统管理模块
侧边栏一级菜单"系统管理"下含用户管理、角色管理、机构管理、权限管理 4 个子页面,均只有列表页(部分含新增/编辑弹窗或子路由),无独立详情页。
### 6.1 用户管理(`/system/user`)
- **组件**:`src/views/system/user/UserList.vue`
- **功能**:用户账号的分页查询、新增、编辑、启用/停用、密码重置、角色分配、机构归属维护。
- **业务逻辑要点**:
- 列表支持按用户名/手机号/所属机构/状态筛选,分页查询。
- **新增/编辑**通过弹窗(`a-modal`)完成,不跳独立路由。
- **密码修改限制**:后端**不存在**"管理员直接修改用户密码"的接口,因此列表操作栏的"密码修改"按钮**永久置灰**,只能通过"密码重置并发送短信"按钮触发重置流程(生成新密码后以短信方式通知用户)。
- 状态切换(启用/锁定)通过状态更新接口完成,不是删除。
- 用户与角色为多对多关系,分配角色通过独立弹窗多选完成。
- **调用接口**(以《缺失的后端接口.md》Part 1.2 用户管理章节为准):
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 用户分页查询 | POST `/api/system/user/page` | `page`,`pageSize`,`username`,`mobile`,`organizationId`,`status` | `data.records[]`:`id`,`username`,`realName`,`mobile`,`organizationName`,`roleNames`,`status`,`createTime` |
| 新增用户 | POST `/api/system/user/create` | `username`,`realName`,`mobile`,`organizationId`,`roleIds[]` | `data`:新建用户 `id` |
| 编辑用户 | POST `/api/system/user/update` | `id` + 同新增字段 | `code=200` |
| 启用/停用用户 | POST `/api/system/user/update-status` | `id`,`status` | `code=200` |
| 密码重置并发送短信 | POST `/api/system/user/reset-password` | `id` | `code=200` |
| 分配角色 | POST `/api/system/user/assign-role` | `id`,`roleIds[]` | `code=200` |
### 6.2 角色管理(`/system/role`)
- **组件**:`src/views/system/role/RoleList.vue`
- **功能**:角色的分页查询、新增、编辑、删除、权限分配(勾选 `PermissionTree` 组件)。
- **业务逻辑要点**:角色与权限为多对多,权限分配通过独立弹窗内嵌 `PermissionTree` 树形勾选组件完成;无批量删除接口,如需批量操作走 `loopDelete.js`
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 角色分页查询 | POST `/api/system/role/page` | `page`,`pageSize`,`roleName` | `data.records[]`:`id`,`roleName`,`roleCode`,`remark`,`createTime` |
| 新增角色 | POST `/api/system/role/create` | `roleName`,`roleCode`,`remark`,`permissionIds[]` | `data`:新建角色 `id` |
| 编辑角色 | POST `/api/system/role/update` | `id` + 同新增字段 | `code=200` |
| 删除角色 | POST `/api/system/role/delete` | `id` | `code=200` |
| 分配权限 | POST `/api/system/role/assign-permission` | `id`,`permissionIds[]` | `code=200` |
### 6.3 机构管理(`/system/org`)
- **组件**:`src/views/system/org/OrgList.vue`
- **功能**:机构树形结构的查询、新增下级机构、编辑、删除(叶子节点)。
- **业务逻辑要点**:机构以树形结构展示(`OrgTreeSelect` 同源数据),新增机构需选择上级机构节点;机构数据隔离(不同角色可见的机构范围裁剪)由后端负责,前端不做二次过滤。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 机构树查询 | GET `/api/system/org/tree` | — | `data[]`:`id`,`orgName`,`parentId`,`children[]` |
| 新增机构 | POST `/api/system/org/create` | `orgName`,`parentId` | `data`:新建机构 `id` |
| 编辑机构 | POST `/api/system/org/update` | `id`,`orgName` | `code=200` |
| 删除机构 | POST `/api/system/org/delete` | `id` | `code=200` |
### 6.4 权限管理(`/system/permission`)
- **组件**:`src/views/system/permission/PermissionList.vue`
- **功能**:权限字典(菜单权限/按钮权限)的树形维护。
- **说明**:该页面**未在** `2026-07-08` 总体设计文档明确列出的实施范围清单中单独出现,但代码已实际实现并注册路由,属代码现状与设计文档的差异点,维护/评审时需注意。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 权限树查询 | GET `/api/system/permission/tree` | — | `data[]`:`id`,`permissionName`,`permissionCode`,`type`(菜单/按钮),`parentId`,`path`,`children[]` |
| 新增权限 | POST `/api/system/permission/create` | `permissionName`,`permissionCode`,`type`,`parentId`,`path` | `data`:新建权限 `id` |
| 编辑权限 | POST `/api/system/permission/update` | `id` + 同新增字段 | `code=200` |
| 删除权限 | POST `/api/system/permission/delete` | `id` | `code=200` |
> 注:系统管理模块接口字段以子 agent 调研摘要整理,如需精确核对逐字段类型/是否必填,请以《缺失的后端接口.md》Part 1.2~1.5 原文及 `src/api/system.js` 实际调用代码为准。
## 7. 基础配置模块
### 7.1 核心企业(渠道)管理(`/base-config/channel`)
- **组件**:`src/views/base-config/channel/ChannelList.vue`
- **功能**:维护渠道(核心企业)基础信息,供其他模块(客户、钱包开户、支付等)下拉选择。
- **业务逻辑要点**:
- 列表分页查询,支持按渠道名称/编号筛选。
- 新增/编辑通过弹窗完成。
- **无前端唯一性校验**:渠道编号/名称是否重复完全依赖后端返回错误提示,前端未做提交前查重。
- 字段兼容:`ChannelSelect.vue` 组件内部对 `channelName/channelNo` 与历史字段名 `enterpriseName/enterpriseCode` 做了兼容读取,提交时以 `enterpriseName` 字段名兜底(历史字段名残留,新代码统一使用 `channelXxx` 命名)。
- 机构过滤:前端表单已预留机构关联字段传参,但后端尚未按机构范围过滤渠道列表(见第 14 章)。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 渠道分页查询 | POST `/api/base-config/channel/page`(即 `fetchCoreEnterprisePageApi`) | `page`,`pageSize`,`channelName`/`enterpriseName` | `data.records[]`:`channelNo`/`enterpriseCode`,`channelName`/`enterpriseName`,`status`,`createTime` |
| 新增渠道 | POST `/api/base-config/channel/create` | `channelName`,`channelNo` 等基础信息字段 | `data`:新建记录标识 |
| 编辑渠道 | POST `/api/base-config/channel/update` | 同新增 + 主键 | `code=200` |
| 删除渠道 | POST `/api/base-config/channel/delete` | 主键 | `code=200` |
### 7.2 客户经理管理(`/base-config/manager`)
- **组件**:`src/views/base-config/manager/ManagerList.vue`
- **功能**:维护客户经理基础信息(姓名、工号、联系方式、所属机构),供客户/授信等模块关联展示。
- **业务逻辑要点**:分页查询 + 新增/编辑弹窗,常规 CRUD,无特殊校验规则。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 客户经理分页查询 | POST `/api/base-config/manager/page` | `page`,`pageSize`,`managerName`,`mobile` | `data.records[]`:`id`,`managerName`,`managerNo`,`mobile`,`organizationName` |
| 新增客户经理 | POST `/api/base-config/manager/create` | `managerName`,`managerNo`,`mobile`,`organizationId` | `data`:新建记录 `id` |
| 编辑客户经理 | POST `/api/base-config/manager/update` | 同新增 + `id` | `code=200` |
| 删除客户经理 | POST `/api/base-config/manager/delete` | `id` | `code=200` |
## 8. 客户管理模块
### 8.1 个人客户(`/customer/personal`)
- **列表组件**:`src/views/customer/personal/PersonalList.vue`
- **表单组件**:`src/views/customer/personal/PersonalForm.vue`(新增/编辑/查看共用,查看态字段只读)
- **隐藏路由**(`extraChildRoutes`):`customer/personal/create`、`customer/personal/edit`、`customer/personal/detail`
- **业务逻辑要点**:
- 列表支持按姓名/手机号/证件号/所属渠道筛选,分页查询;**无删除入口**。
- 表单字段含身份证正反面 OCR 识别上传(`IdCardUpload.vue`)、人脸照片上传(`FacePhotoUpload.vue`,尚未按 4.2 规范改造)、联系信息(地址/紧急联系人等,来自 Part 7 补充说明)。
- 身份证号/手机号仅做**前端正则格式校验**(`validators.js`),**未实现证件联网核查**(如公安网/运营商核验),提交即视为通过。
- 列表页"性别/创建人/创建时间"等列,若后端接口未返回对应字段则前端展示为空白,不做兜底伪造数据。
- OCR 识别结果通过 `src/utils/ocrMapping.js` 映射填充到表单对应字段,用户仍可手动修改后再提交。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 个人客户分页查询 | POST `/api/customer/personal/page` | `page`,`pageSize`,`customerName`,`mobile`,`certificateNumber`,`channelNo` | `data.records[]`:`id`,`customerName`,`mobile`,`certificateNumber`,`channelName`,`createTime` |
| 个人客户详情 | GET `/api/customer/personal/detail` | `id` | `data`:客户完整信息(基础信息+联系信息) |
| 新增个人客户 | POST `/api/customer/personal/create` | `customerName`,`certificateNumber`,`mobile`,`idCardFrontFile`(Base64),`idCardBackFile`(Base64),`facePhotoFile`(Base64),联系信息字段等 | `data`:新建客户 `id` |
| 编辑个人客户 | POST `/api/customer/personal/update` | `id` + 同新增字段 | `code=200` |
| 身份证 OCR 识别 | POST `/api/customer/ocr/id-card` | `imageBase64` | `data`:识别出的姓名/证件号/地址等字段 |
### 8.2 企业客户(`/customer/enterprise`)
- **列表组件**:`src/views/customer/enterprise/EnterpriseList.vue`
- **表单组件**:`src/views/customer/enterprise/EnterpriseForm.vue`(新增/编辑/查看共用)
- **隐藏路由**:`customer/enterprise/create`、`customer/enterprise/edit`、`customer/enterprise/detail`
- **业务逻辑要点**:
- 表单含营业执照 OCR 上传(`LicenseUpload.vue`)、企业基础信息、法人信息、联系信息(Part 7/8 补充)、**股东高管信息**(`EnterpriseRelatedPersonCard.vue` 多条动态表单卡片)、**对外投资关系**(`EnterpriseInvestmentCard.vue` 多条动态表单卡片,来自 Part 9 补充说明)。
- 提交前统一走 `busy` 遮罩(见 4.3),校验各上传组件的 `uploading` 状态,防止文件未上传完成时提交。
- 营业执照号格式校验:15-20 位数字+大写字母(`validators.js`),同样**未做工商联网核验**。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 企业客户分页查询 | POST `/api/customer/enterprise/page` | `page`,`pageSize`,`enterpriseName`,`businessLicenseNo`,`channelNo` | `data.records[]`:`id`,`enterpriseName`,`businessLicenseNo`,`legalPersonName`,`channelName`,`createTime` |
| 企业客户详情 | GET `/api/customer/enterprise/detail` | `id` | `data`:企业完整信息(基础信息+法人信息+联系信息+股东高管列表+对外投资列表) |
| 新增企业客户 | POST `/api/customer/enterprise/create` | `enterpriseName`,`businessLicenseNo`,`legalPersonName`,`businessLicenseFile`(Base64),股东高管列表 `relatedPersons[]`,对外投资列表 `investments[]` 等 | `data`:新建企业 `id` |
| 编辑企业客户 | POST `/api/customer/enterprise/update` | `id` + 同新增字段 | `code=200` |
| 营业执照 OCR 识别 | POST `/api/customer/ocr/business-license` | `imageBase64` | `data`:识别出的企业名称/统一社会信用代码/法人姓名等字段 |
> 客户管理模块字段/接口以《缺失的后端接口.md》Part 1.7、1.8 及 Part 7~9 补充说明为准,股东高管/对外投资列表的具体字段结构请对照 Part 9 原文逐项核对。
## 9. 钱包管理模块
> **特别提示**:调研时工作区存在大量**尚未提交**的 Git 改动(`PersonalOpenList.vue`、`FacePhotoUpload.vue` 等为新增未跟踪文件;`AccountList.vue`/`AccountDetail.vue`/`PersonalOpenForm.vue`/`EnterpriseOpenForm.vue`/`BindCardModal.vue`/`WithdrawModal.vue`/`MarginModal.vue`/`wallet.js` 等为已修改未提交)。本节内容基于**当前工作区最新代码**整理,而非最后一次 commit,与早期设计文档(2026-07-09 phase4 设计)相比字段/流程已经过多轮变更,如发现与旧文档不一致,以本节及当前代码为准。
### 9.1 钱包账户列表(`/wallet/account`)
- **组件**:`src/views/wallet/account/AccountList.vue`
- **功能**:查询个人/企业钱包账户列表,支持进入账户详情页,支持提现/保证金操作弹窗入口。
- **业务逻辑要点**:列表区分个人/企业账户类型;账户状态用 `StatusTag` 展示;提现/保证金操作通过 `WithdrawModal.vue`/`MarginModal.vue` 弹窗完成,提交后刷新列表余额。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 钱包账户分页查询 | POST `/api/wallet/account/page` | `page`,`pageSize`,`accountName`,`accountType`,`channelNo` | `data.records[]`:`accountNo`,`accountName`,`accountType`,`balance`,`availableBalance`,`status` |
| 账户提现 | POST `/api/wallet/account/withdraw` | `accountNo`,`amount`,`bankCardNo` | `code=200` |
| 保证金存入/支取 | POST `/api/wallet/account/margin` | `accountNo`,`amount`,`type`(存入/支取) | `code=200` |
### 9.2 账户详情页(`/wallet/account/detail`,隐藏路由)
- **组件**:`src/views/wallet/account/AccountDetail.vue`
- **功能**:展示账户基础信息、余额明细、交易流水、绑卡信息;支持绑卡(`BindCardModal.vue`)、下载回单等操作。
- **业务逻辑要点**:交易流水分页查询;回单下载走 `src/utils/download.js` 的 base64 转 Blob 下载方案。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 账户详情查询 | GET `/api/wallet/account/detail` | `accountNo` | `data`:账户基础信息+绑卡列表 |
| 交易流水分页查询 | POST `/api/wallet/account/transaction/page` | `accountNo`,`page`,`pageSize`,`startDate`,`endDate` | `data.records[]`:`transactionNo`,`amount`,`type`,`balance`,`transactionTime` |
| 绑卡 | POST `/api/wallet/account/bind-card` | `accountNo`,`bankCardNo`,`bankName`,短信验证码等 | `code=200` |
| 回单下载 | GET `/api/wallet/account/receipt` | `transactionNo` | `data.fileData`:Base64 编码的 PDF 内容 |
### 9.3 个人开户(`/wallet/personal-open`)
- **列表组件**:`src/views/wallet/personal-open/PersonalOpenList.vue`
- **表单组件**:`src/views/wallet/personal-open/PersonalOpenForm.vue`
- **业务逻辑要点**:选择已有个人客户(`PersonalCustomerPicker.vue`)发起钱包开户申请,填写渠道、联系方式等开户信息,提交后走短信验证码确认(`SmsCodeInput.vue`),开户状态需轮询/查询确认。字段结构经 Part 5、Part 6、Part 10 多次调整,当前以代码实现为准。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 个人开户申请分页查询 | POST `/api/wallet/personal-open/page` | `page`,`pageSize`,`customerName`,`status` | `data.records[]`:`id`,`customerName`,`mobile`,`channelName`,`status`,`createTime` |
| 提交个人开户申请 | POST `/api/wallet/personal-open/apply` | `customerId`,`channelNo`,`mobile` 等 | `data`:申请单 `id` |
| 开户短信验证确认 | POST `/api/wallet/personal-open/confirm` | `id`,`smsCode` | `code=200` |
### 9.4 企业开户(`/wallet/enterprise-open`)
- **列表组件**:`src/views/wallet/enterprise-open/EnterpriseOpenList.vue`
- **表单组件**:`src/views/wallet/enterprise-open/EnterpriseOpenForm.vue`
- **业务逻辑要点**:选择已有企业客户(`EnterpriseCustomerPicker.vue`)发起企业钱包开户申请,流程与个人开户类似但字段更多(经办人信息、企业联系信息等),列表页字段结构见 Part 11 补充说明。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 企业开户申请分页查询 | POST `/api/wallet/enterprise-open/page` | `page`,`pageSize`,`enterpriseName`,`status` | `data.records[]`:`id`,`enterpriseName`,`channelName`,`status`,`createTime` |
| 提交企业开户申请 | POST `/api/wallet/enterprise-open/apply` | `enterpriseId`,`channelNo`,经办人信息等 | `data`:申请单 `id` |
| 开户短信验证确认 | POST `/api/wallet/enterprise-open/confirm` | `id`,`smsCode` | `code=200` |
> 钱包管理模块接口字段变动较为频繁(Part 5/6/9/10/11 均有相关补充调整),涉及改动前**务必先重新核对**《缺失的后端接口.md》对应最新章节以及 `src/api/wallet.js` 实际调用代码,不要照抄早期设计文档字段。
## 10. 授信管理模块
### 10.1 贷款申请列表(`/credit/loan-application`)
- **列表组件**:`src/views/credit/loan-application/LoanApplicationList.vue`
- **表单组件**:个人贷款申请表单 / 企业贷款申请表单(新增/编辑/查看共用)
- **枚举字典**:`src/constants/creditEnums.js`(完整枚举表,贷款状态、贷款类型等均来源于 swagger)
- **业务逻辑要点**:
- 列表按申请人/渠道/状态/申请时间筛选分页查询,可查看申请详情。
- 个人贷款申请表单字段相对完整,均有对应 swagger 枚举约束。
- **企业贷款申请表单部分字段(如 `legalPersonGender` 等)在 swagger 中无枚举约束**,前端为保证 UI 一致性,**推断性地复用了个人贷款枚举**,该做法未经后端明确确认,存在语义风险。
- 实际调用的接口前缀为 `/api/credit-apply/*`
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 贷款申请分页查询 | POST `/api/credit-apply/page` | `page`,`pageSize`,`applicantName`,`applicantType`(个人/企业),`status`,`channelNo` | `data.records[]`:`id`,`applicantName`,`applicantType`,`loanAmount`,`status`,`createTime` |
| 贷款申请详情 | GET `/api/credit-apply/detail` | `id` | `data`:申请完整信息 |
| 提交个人贷款申请 | POST `/api/credit-apply/personal/create` | `customerId`,`loanAmount`,`loanPurpose`,`loanTerm` 等 | `data`:申请单 `id` |
| 提交企业贷款申请 | POST `/api/credit-apply/enterprise/create` | `enterpriseId`,`loanAmount`,`legalPersonName`,`legalPersonGender`(推断枚举)等 | `data`:申请单 `id` |
| 编辑贷款申请 | POST `/api/credit-apply/update` | `id` + 对应字段 | `code=200` |
> **已知问题**:后端 swagger 中存在**另一组语义存疑的 `/api/loan-application/*` 接口**,与实际前端使用的 `/api/credit-apply/*` 并存,两组接口的关系(是否为废弃/重复/不同业务场景)未经后端确认,涉及授信模块改动时需留意不要混用这两组接口。
## 11. 商户中心模块
### 11.1 商户管理(`/merchant/management`)
- **组件**:`src/views/merchant/management/MerchantList.vue`
- **业务逻辑要点**:
- **无详情接口**:查看/编辑商户信息时,依赖路由 query 参数回填表单数据,**刷新页面会丢失数据**(需重新从列表页跳转进入)。
- **无审批接口**:商户"审批"流程实际通过状态字段 `ACTIVE`/`INACTIVE` 的切换接口替代,不是独立的审批工作流。
- 机构过滤筛选字段前端已实现,但后端未按机构范围过滤商户列表(见第 14 章)。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 商户分页查询 | POST `/api/merchant/page` | `page`,`pageSize`,`merchantName`,`status`,`organizationId`(未生效) | `data.records[]`:`id`,`merchantName`,`merchantNo`,`status`,`channelName`,`createTime` |
| 新增商户 | POST `/api/merchant/create` | `merchantName`,`merchantNo`,`channelNo` 等 | `data`:新建商户 `id` |
| 编辑商户 | POST `/api/merchant/update` | `id` + 同新增字段(通过 query 回填) | `code=200` |
| 状态切换(代替审批) | POST `/api/merchant/update-status` | `id`,`status`(`ACTIVE`/`INACTIVE`) | `code=200` |
### 11.2 发票管理(`/merchant/invoice`)
- **组件**:`src/views/merchant/invoice/InvoiceList.vue` + 5 个功能弹窗组件(开票申请、发票详情、匹配、结算、驳回等,具体命名以代码为准)
- **业务逻辑要点**:发票状态流转(申请→审核→匹配→结算)通过状态更新接口驱动,列表按状态筛选;发票金额与订单匹配逻辑依赖后端返回的匹配结果字段展示,前端不做金额校验计算。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 发票分页查询 | POST `/api/merchant/invoice/page` | `page`,`pageSize`,`merchantName`,`status`,`invoiceNo` | `data.records[]`:`id`,`invoiceNo`,`merchantName`,`amount`,`status`,`createTime` |
| 发票申请详情 | GET `/api/merchant/invoice/detail` | `id` | `data`:发票完整信息(含匹配订单/结算记录) |
| 发票状态更新 | POST `/api/merchant/invoice/update-status` | `id`,`status` | `code=200` |
| 发票匹配 | POST `/api/merchant/invoice/match` | `id`,`orderIds[]` | `code=200` |
| 发票结算 | POST `/api/merchant/invoice/settle` | `id`,`settleAmount` | `code=200` |
> 商户中心模块字段以《缺失的后端接口.md》Part 1.13、1.14 及 `src/api/merchant.js`/`src/api/invoice.js` 为准;5 个弹窗组件的具体接口调用请对照组件文件逐一核对。
## 12. 支付管理模块
### 12.1 订单支付(`/payment/order-payment`)
- **组件**:`src/views/payment/order-payment/PaymentRecordList.vue` + 发起支付弹窗 + 支付详情弹窗
- **业务逻辑要点**:
- 列表查询支付记录,支持发起新支付(选择订单+融资额度查询后确认支付)。
- 融资额度查询接口 `queryCreditQuotaApi`(`POST /api/payment/query-credit-quota`)**响应结构完全未在 swagger 中文档化**,前端目前采取"原样展示返回 JSON"的保守处理方式,未做强类型字段映射(`mock-server` 假设其结构为 `{ accountNo, creditLimit, usedAmount, availableAmount }`,但该假设**未经真实后端确认**)。
- 机构过滤字段前端已实现但后端不支持按机构过滤支付记录(见第 14 章)。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 支付记录分页查询 | POST `/api/payment/order-payment/page` | `page`,`pageSize`,`orderNo`,`status`,`organizationId`(未生效) | `data.records[]`:`id`,`orderNo`,`amount`,`status`,`payTime` |
| 融资额度查询 | POST `/api/payment/query-credit-quota` | `accountNo``enterpriseId`(响应结构未文档化) | `data`:结构未文档化,前端原样展示 |
| 发起支付 | POST `/api/payment/order-payment/create` | `orderNo`,`amount`,`accountNo` | `data`:支付记录 `id` |
| 支付详情查询 | GET `/api/payment/order-payment/detail` | `id` | `data`:支付记录完整信息 |
## 13. 订单管理模块
### 13.1 汇总订单(`/order/summary`)
- **组件**:`src/views/order/summary/SummaryOrderList.vue`
- **业务逻辑要点**:
- "汇总订单"页面本身在原型库中缺失对应设计,由前端团队**自行设计**该列表页的字段与交互结构。
- 列表中的"剩余额度"列为**前端本地计算字段**(`financeQuota - accumulatedLoanAmount`),**不是后端返回字段**,维护时需注意不要误以为它来自接口响应。
- 机构筛选未生效:前端提供了机构筛选下拉,但后端汇总订单接口**无 organizationId 关联路径**,筛选不产生实际效果。
- 详情弹窗**无法展示关联的原始订单明细**,因为后端不支持"汇总订单→原始订单"的关联查询接口。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 汇总订单分页查询 | POST `/api/order/summary/page` | `page`,`pageSize`,`enterpriseName`,`channelNo` | `data.records[]`:`id`,`enterpriseName`,`financeQuota`,`accumulatedLoanAmount`,`channelName`,`createTime`(前端另计算 `remainingQuota = financeQuota - accumulatedLoanAmount`) |
| 汇总订单详情 | GET `/api/order/summary/detail` | `id` | `data`:汇总订单完整信息(不含关联原始订单明细) |
### 13.2 原始订单(`/order/original`)
- **组件**:`src/views/order/original/OriginalOrderList.vue`
- **业务逻辑要点**:展示原始交易订单明细,支持按订单号/企业名称/渠道/时间范围筛选分页查询,无新增/编辑操作(数据来源为上游业务系统同步)。
| 接口说明 | Method + Path | 关键请求参数 | 关键响应字段 |
| --- | --- | --- | --- |
| 原始订单分页查询 | POST `/api/order/original/page` | `page`,`pageSize`,`orderNo`,`enterpriseName`,`channelNo`,`startDate`,`endDate` | `data.records[]`:`id`,`orderNo`,`enterpriseName`,`amount`,`orderTime` |
| 原始订单详情 | GET `/api/order/original/detail` | `id` | `data`:订单完整信息 |
## 14. 已知问题与待确认事项汇总
| 模块 | 问题描述 |
| --- | --- |
| 用户管理 | 管理员直接修改用户密码的接口不存在,"密码修改"按钮永久置灰,只能走"密码重置并发送短信"流程 |
| 核心企业(渠道)管理 | 无渠道名称/编号唯一性前端校验,依赖后端报错提示;字段名历史遗留 `enterpriseName` 与新命名 `channelName` 并存兼容 |
| 客户管理 | 未实现身份证号/统一社会信用代码的联网核查,仅做前端正则格式校验;个人客户列表"性别/创建人/创建时间"等列在后端未返回时展示为空白;无删除入口 |
| 商户中心 | 无商户详情接口,查看/编辑靠路由 query 回填,刷新会丢数据;无独立审批接口,用状态 `ACTIVE`/`INACTIVE` 切换代替审批;机构过滤筛选未生效 |
| 支付管理 | `queryCreditQuotaApi` 融资额度查询接口响应结构完全未文档化,前端原样展示返回 JSON;机构过滤字段后端不支持 |
| 订单管理 | 汇总订单"剩余额度"为前端本地计算字段,非后端返回;机构筛选未生效(无 organizationId 关联路径);汇总订单详情无法关联展示原始订单明细 |
| 授信管理 | 存在另一组语义存疑的 `/api/loan-application/*` 接口与实际使用的 `/api/credit-apply/*` 并存,关系未经后端确认;企业贷款表单部分字段(如 `legalPersonGender`)无 swagger 枚举约束,前端推断性复用个人贷款枚举 |
| 权限管理 | `/system/permission` 页面未在总体设计文档的实施范围清单中单独列出,但代码已实现并注册路由,属代码现状与文档的差异 |
| 全局 | `src/utils/formFocus.js` 的聚焦逻辑对隐藏在折叠面板(`display:none`)内的报错字段不生效,当前项目暂无该场景但后续新增折叠式表单时需注意 |
| 图片上传组件 | `FacePhotoUpload.vue` 尚未按 `IdCardUpload.vue`/`LicenseUpload.vue` 的 hover 遮罩+预览/重新上传/删除三按钮规范改造 |
| 钱包管理 | 调研时工作区存在大量未提交改动,字段/流程相比早期设计文档(2026-07-09 phase4)已多轮变更,任何改动前务必核对当前代码而非早期设计文档 |
## 15. 本地 Mock Server 说明
`mock-server/`(`npm run mock`,默认端口 8888)是真实后端不可用时的**应急本地演示后端**,所有接口路径/字段力求对齐 `swagger_project_scfs_2026-07-09_14-15-23.json` 及前端实际调用代码,核心业务规则(登录锁定、状态流转、余额扣减、发票匹配/结算等)为真实本地状态维护,而非纯占位透传。但其契约**已知与真实接口不完全一致**,不能作为接口设计依据,仅用于本地演示/无后端环境时的联调。
- 目录结构:`index.js`(入口,装配路由/CORS/Cookie/全局错误处理)、`state.js`(内存态)、`middleware/requireAuth.js`(鉴权中间件)、`utils/`(统一响应封装/分页/ID 生成)、`db/`(各模块种子数据,进程重启后重置)、`routes/`(各模块 Express Router)。
- 测试账号:`admin` / `Admin@123`(系统管理员全权限);短信验证码场景万能验证码 `123456`,真实生成的验证码打印在 Mock Server 控制台。
- "已知简化点/未文档化项"(`mock-server/README.md` 已列出,例如 `POST /api/payment/query-credit-quota` 响应结构完全未文档化,Mock 自行假设为 `{ accountNo, creditLimit, usedAmount, availableAmount }`)恰恰标记出真实后端接口设计不完整、需要额外与后端确认的地方,阅读该文件有助于快速定位待确认接口清单。
## 16. 维护建议
1. **新增菜单页面**:必须同时完成 (a) `src/views/**` 下新建组件、(b) `src/router/componentRegistry.js` 中登记 `routePathComponentMap`(侧边栏菜单页)或 `extraChildRoutes`(新增/编辑/详情等隐藏子路由),否则会 404;权限字典由权限管理页面动态维护,但组件映射永远需要前端手工登记,后端加菜单不会自动出现页面。
2. **对接/修改后端接口前**,先查阅《缺失的后端接口.md》Part 1 速查表确认基础契约,再检查 Part 2~11 是否有该接口的后续补充/变更记录(优先级更高);如用户告知接口有变更,应通过 MCP 工具重新获取最新 swagger(前提是 `.toco/CONFIG` 补充了 `PROJECT_ID`,目前该文件仅有 `ORG_ID`/`ORG_NAME`)。
3. **请求 Header**:涉及请求 header 改动前务必先核对/修复 `src/utils/traceHeaders.js``buildTraceHeaders()`,不要照抄旧的字段实现(历史实现字段名大小写不规范,已在 3.4 节更新为规范写法)。
4. **枚举值**统一从 `src/constants/*Enums.js` 引用,来源必须是 swagger/《缺失的后端接口.md》,不得编造;如遇后端未明确约束的字段(如授信模块企业贷款表单部分字段),需在代码注释中明确标注"推断性实现,未经后端确认"。
5. **批量操作**统一使用 `src/utils/loopDelete.js` + `batchDeleteResult.js` 模式,不要假设后端存在批量接口。
6. **图片上传组件**新增/修改时统一参照 `IdCardUpload.vue` 的 hover 遮罩+三按钮规范(4.2 节),并记得补齐 `FacePhotoUpload.vue` 的改造欠账。
7. **耗时操作**统一接入 `busy`/`busyTip` 遮罩模式(4.3 节),不要各自维护互不关联的 loading 变量。
8. **机构数据隔离**类问题(多个模块的机构筛选未生效)本质是后端未按机构范围过滤数据,前端不应通过本地二次过滤"解决",应推动后端补齐 `organizationId` 关联查询能力。
9. `website_detail/` 原型库覆盖面远大于本项目范围,新增功能前先核对 `docs/superpowers/specs/2026-07-08-fryl-frontend-overall-design.md` 明确的范围划分,避免误将排除模块的原型页面当作待实现需求。