50 KiB
凡荣e链管理后台前端 —— 项目要点总结
本文档基于代码现状(部分文件存在尚未提交的工作区改动)与
缺失的后端接口.md(接口契约权威来源)整理,用于帮助后续开发/维护人员快速理解项目整体架构、路由组织方式、各页面业务逻辑与后端接口对接情况。不以mock-server/作为接口设计依据,该目录仅为真实后端不可用时的本地应急演示后端。
目录
- 项目概述
- 技术栈与项目结构
- 整体架构
- 公共组件与工具函数
- 登录页与错误页
- 系统管理模块
- 基础配置模块
- 客户管理模块
- 钱包管理模块
- 授信管理模块
- 商户中心模块
- 支付管理模块
- 订单管理模块
- 已知问题与待确认事项汇总
- 本地 Mock Server 说明
- 维护建议
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 常用命令
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 路由机制(动态路由,新增页面必须两处登记)
路由不是静态声明的,而是登录后根据后端返回的菜单权限树动态生成:
src/router/index.js:仅静态声明/login、/403、404 通配符路由,并挂载全局前置守卫router.beforeEach:- 无
accessToken(除白名单路由) → 跳转/login; - 有 token 但路由尚未就绪(
routesReady为 false)→ 先调用fetchCurrentUser或rebuildPermissions拉取权限树,再调用installDynamicRoutes挂载动态路由,然后重新next(to.fullPath)完成一次"replay"跳转; - 登录成功后默认落地页为菜单权限列表中第一个可访问页面(或用户登录前尝试访问的原始目标页面)。
- 无
src/router/dynamic.js(installDynamicRoutes):遍历后端菜单树,为每个菜单节点生成一条挂载在MainLayout下的子路由记录,组件通过import.meta.glob('@/views/**/*.vue')懒加载。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容器,复用其原生文件选择流程。 - 支持
readonlyprop(默认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),同样未做工商联网核验。
- 表单含营业执照 OCR 上传(
| 接口说明 | 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. 维护建议
- 新增菜单页面:必须同时完成 (a)
src/views/**下新建组件、(b)src/router/componentRegistry.js中登记routePathComponentMap(侧边栏菜单页)或extraChildRoutes(新增/编辑/详情等隐藏子路由),否则会 404;权限字典由权限管理页面动态维护,但组件映射永远需要前端手工登记,后端加菜单不会自动出现页面。 - 对接/修改后端接口前,先查阅《缺失的后端接口.md》Part 1 速查表确认基础契约,再检查 Part 2~11 是否有该接口的后续补充/变更记录(优先级更高);如用户告知接口有变更,应通过 MCP 工具重新获取最新 swagger(前提是
.toco/CONFIG补充了PROJECT_ID,目前该文件仅有ORG_ID/ORG_NAME)。 - 请求 Header:涉及请求 header 改动前务必先核对/修复
src/utils/traceHeaders.js的buildTraceHeaders(),不要照抄旧的字段实现(历史实现字段名大小写不规范,已在 3.4 节更新为规范写法)。 - 枚举值统一从
src/constants/*Enums.js引用,来源必须是 swagger/《缺失的后端接口.md》,不得编造;如遇后端未明确约束的字段(如授信模块企业贷款表单部分字段),需在代码注释中明确标注"推断性实现,未经后端确认"。 - 批量操作统一使用
src/utils/loopDelete.js+batchDeleteResult.js模式,不要假设后端存在批量接口。 - 图片上传组件新增/修改时统一参照
IdCardUpload.vue的 hover 遮罩+三按钮规范(4.2 节),并记得补齐FacePhotoUpload.vue的改造欠账。 - 耗时操作统一接入
busy/busyTip遮罩模式(4.3 节),不要各自维护互不关联的 loading 变量。 - 机构数据隔离类问题(多个模块的机构筛选未生效)本质是后端未按机构范围过滤数据,前端不应通过本地二次过滤"解决",应推动后端补齐
organizationId关联查询能力。 website_detail/原型库覆盖面远大于本项目范围,新增功能前先核对docs/superpowers/specs/2026-07-08-fryl-frontend-overall-design.md明确的范围划分,避免误将排除模块的原型页面当作待实现需求。