Skip to content

管理前端 · 设计总览

这一组设计文档回答的不是「forge-admin-web 怎么用」,而是「它为什么是一台渲染引擎,而不是一堆手写页面」。只想把控制台跑起来、配出页面,请读使用指南;想知道一份 PageSchema 从下发到变成屏幕上的表格,中间经过哪些层、为什么这么分,本篇是入口。

前端的设计可以浓缩成一句话:以 PageSchema 为单一输入,用一台通用渲染引擎解释出所有页面;业务字段一律不写死,可变性收敛到一张多维加权注册表里。

一个核心矛盾,一个解法

后台管理天然面临一个矛盾:

  • 一方面,每个实体的增删改查页面长得高度雷同——表格、表单、详情、搜索、分页,结构一模一样。
  • 另一方面,每个实体的字段又各不相同——商品有价格和上架状态,订单有金额和收货地址。

传统做法「一个实体一套页面」把雷同的结构抄了 N 遍,新增实体的成本是线性的。forge 前端的解法是把结构与字段彻底分离

  • 结构由前端的通用引擎兜住,写一次、所有实体共享。
  • 字段由后端 schema 描述,前端按 schema 解释。

新增实体的前端成本因此趋近于零。这是整个前端最重要的设计取舍:

设计取舍选项选择理由
页面如何产生A. 每实体手写页面;B. schema 驱动通用引擎B把线性成本压成常数;新增实体零前端改动
字段表现谁定A. 前端写死控件;B. 后端下发中立组件名,前端选实现BUI 库可换、字段可覆盖,前后端解耦
可变性放哪A. 散落在各页面 if-else;B. 收敛到一张注册表B自定义有唯一入口,覆盖优先级可计算

三条设计主线

主线解决的问题关键载体
整体架构九层如何分工、数据如何单向流动views / components / widgets / stores / api
请求时序登录、启动、列表、保存、详情各自的全链路router / Pinia / axios / ResourceListView
渲染引擎(★)字段如何选到组件、自定义如何覆盖内置createRegistry / fieldRegistry / selectFieldWidget

阅读顺序建议

先看整体架构建立分层心智,再看请求时序理解动态流程,最后用渲染引擎吃透最精彩的多维加权注册表。横切关注点(雪花 ID、统一错误、URL 单一事实源)集中在网络层与状态

设计取舍速览

后续各篇会展开,这里先给全景:

  • PageSchema 是唯一输入:前端不缓存业务模型定义,只缓存 schema 与数据。schema 与数据两条请求线分离(元数据 vs 业务数据),元数据可长缓存、数据按需刷新。
  • 多维加权注册表:可变性(哪个字段用哪个组件)不写在页面里,而是声明在一张注册表里,按 field > model > component > dataType > scene 的数量级权重选最具体者。借鉴 oinone 的 SPI 思路,去掉 IoC/装饰器,保留纯函数 + 类型安全。
  • URL 即列表状态:翻页/搜索/排序/筛选全部编码进 URL,组件不另存状态,刷新与分享天然可还原。
  • 雪花 ID 全程字符串:用 json-bigint 在 axios 反序列化阶段把长整型转字符串,杜绝 JS Number 精度丢失。
  • 统一错误处理:响应拦截器集中弹错、集中处理 401,业务 catch 块刻意留空,避免重复弹窗。

与后端协议的边界

前端只认 protocol.ts 里的接口定义。这些 schema 由后端的声明式建模与视图协议合成,前端不参与生产:

协议每个字段被前端如何消费、哪些已声明但未消费,见协议消费映射

下一步