# abacus-static-framework — 架构文档(ARCHITECTURE) > 模块、依赖、契约、目录布局的**唯一权威**(本仓库视角)。新增/重命名/移动模块或调整依赖方向,必须先改本文,再改代码(同一个 commit)。 > 上游:`PRD.md`(行为)。前后端共享约束见工作区 `docs/`(`../../../../docs/coding-standards.md`、`../../../../docs/architecture.md`),本文不复制其正文。 ## 0. 阅读指引 本文描述前端底座的模块划分与依赖方向;§2 模块清单与 §6 目录一一对应,§3.2 是跨模块接口契约(写代码必须遵守)。新会话先读 §2 + §6 定位任务归属,再动手。 ## 1. 领域模型(Domain Model) ### 1.1 实体 前端无持久化实体;领域概念即运行时状态: | 实体 | 字段 | 关系 | 持久化? | |---|---|---|---| | 用户会话(userStore) | access_token/refresh_token/expires_dt/user_type | 全局单例 | 否(localStorage) | | 菜单/路由(permissionStore) | routes(过滤后)、menuTree | 依赖后端菜单接口 | 否(内存) | | 应用设置(settingsStore) | backendServices、loginType、loginAddress | 来自 window.frameBaseConfig | 否(运行时注入) | ### 1.2 派生概念(非持久化) - `backendServices` 别名→真实服务名映射(`window.frameBaseConfig` 注入)。 - 当前路由上下文(`currentRouter()`)用于组装 commonParam(menuName/moduleId/moduleName)。 ### 1.3 不变量(任何模块都必须维护) - I1. `src/framework/**` 只读:业务代码不得 import 后修改框架文件;框架变更只能由框架负责人进行。 - I2. 业务请求一律经 `framework/utils/request.ts`,禁止裸 `axios`/`fetch`。 - I3. 服务别名首段必须是 `settingsStore.backendServices` 中已注册的键。 ## 2. 模块清单 按依赖层级从低到高排列。 ### Layer 0 — framework/utils(基础设施) ``` ## 模块名:framework/utils - 职责:请求管线(request.ts)、标准工具(standard/*:vxe、dataHandleUtil、globalHandle、security、baiduMap) - 不负责:业务逻辑、页面状态 - 输入:各业务模块的请求配置 - 输出:统一响应体解包后的数据 / Blob;标准工具函数 - 关键类型/接口:request(config) -> Promise;gridDefaultProps(opts);useQueryParamsHandle(...) - 持有状态:token 刷新队列(模块内闭包)、settingsStore 引用 ``` ### Layer 0 — framework/components/standard(视觉基座) ``` ## 模块名:framework/components/standard - 职责:标准 UI 组件(AbForm/AbQueryForm/AbSection/ClickCopy/FilePreviewDialog/ImportExcel/LogShow/RealTimeSearchSelect/SensitiveText/Text/BottomFloat) - 不负责:业务特有布局(业务自建 components) - 输入:props/插槽 - 输出:统一风格组件 - 持有状态:无(受控组件) ``` ### Layer 1 — framework/store(有状态服务) ``` ## 模块名:framework/store - 职责:全局 Pinia 状态(settings:backendServices/loginType;permission:菜单生成与过滤;user:token/业务域) - 不负责:页面级状态(业务自建 store) - 输入:window.frameBaseConfig、后端菜单接口 - 输出:状态与 actions - 持有状态:是 ``` ### Layer 2 — framework/router + hooks + directives(路由与通用逻辑) ``` ## 模块名:framework/router + hooks + directives - 职责:静态路由与动态路由装配支持;useVxeTableHandle 等通用组合式函数;v-debounce/v-throttle 指令 - 不负责:业务菜单路由(subsystem/router/dynamicRouter.ts) - 输入:permissionStore 过滤后的路由 - 输出:可用路由表、表格查询联动能力 - 持有状态:路由表(由 permissionStore 维护) ``` ### Layer 3 — subsystem(业务可写区) ``` ## 模块名:subsystem - 职责:业务子系统(api 封装、dynamicRouter 菜单路由、views 页面、extend 扩展、自建 components/hooks/store/styles/types/utils) - 不负责:框架能力(一律复用 framework) - 输入:后端接口、用户操作 - 输出:业务页面与接口调用 - 持有状态:业务自身状态(自建 store) ``` ## 3. 依赖图(DAG) ```mermaid graph TD subsystem --> framework_utils[framework/utils] subsystem --> framework_components[framework/components/standard] subsystem --> framework_hooks[framework/hooks] subsystem --> framework_router[framework/router] framework_router --> framework_store[framework/store] framework_hooks --> framework_utils framework_hooks --> framework_components framework_store --> framework_utils framework_utils --> framework_store ``` ### 3.1 依赖方向规则 - 高层依赖低层;业务(subsystem)依赖框架(framework),框架各层按上图单向;**反向依赖一律禁止**(如 framework 不得 import subsystem)。 - 例外:`framework/utils/request.ts` 依赖 `framework/store`(settingsStore)获取别名映射——两者同属 framework 层,允许。 ### 3.2 跨模块接口契约(写代码时必须遵守的签名) ``` // module: framework/utils/request // request(config: {url, method, params|data, headers?, custom?}) -> Promise // status===200 已解包 data;ArrayBuffer 返回整个 response // url 首段 = 服务别名(I3),自动携带 token/commonParam(I2) // module: framework/utils/standard/vxe // gridDefaultProps(opts: {params, rowConfig, pagerConfig, proxyConfig, columns}) -> VxeGridProps // module: framework/hooks/useVxeTableHandle // useQueryParamsHandle(params, page, sorts, filters) -> query params // 分页契约 {data,total},见共享规范 §6.4 // useTableQueryReload(...) / useInVxeGridSearch(...) ``` ## 4. 持久化与边界 - 无后端式持久化;前端持久化仅 token(localStorage,由 userStore 管理)。 - 外部边界:所有 HTTP 请求必须经 request.ts;开发期经 vite proxy;运行时经 Nginx 反代;`window.frameBaseConfig` 由宿主页面注入(含 backendServices)。 ## 5. 测试边界 - 无自动化单测(PRD 已声明);每页面人工冒烟(列表/查询/新增/编辑/导出)。 - 真机/真环境必验:多数据源路由、Kafka 消费、XXL-JOB 调度、Nacos 配置拉取、真实数据库迁移(属后端,但前端联调需一并验证)。 ## 6. 目录结构(与 §2 模块清单一一对应) ``` src/ ├── framework/ # Layer 0~2(只读共享) │ ├── api/ components/ hooks/ layout/ router/ store/ styles/ types/ utils/ views/ directives/ │ └── utils/request.ts # 请求管线(契约见 §3.2) ├── subsystem/ # Layer 3(业务可写区) │ ├── api/<服务别名>/ # 按 Controller 分 ts(如 sms/{index,applog,abnormal,config}.ts) │ ├── router/dynamicRouter.ts # 菜单路由唯一注册点 │ ├── views/<一级菜单>/<二级菜单>/index.vue │ ├── extend/ # 框架扩展钩子 │ └── (自建) components/ hooks/ store/ styles/ types/ utils/ ├── permission.ts # 全局路由守卫(生成/过滤动态路由) └── main.ts # 入口 ``` ## 7. 自检(架构健康度三问) 1. 出 bug 了,能否 30 秒内指出是 framework 还是 subsystem、哪个子目录的责任? 2. 替换 UI 库/表格库,改动能否控制在 framework/components 与 utils/standard 内 + 适配层? 3. 加新业务页面,能否立刻说出落在 `subsystem/views/<一级>/<二级>/` 哪个位置? ## 8. 待办与已知技术负债 - 前端 README 引用的 `docs/` 文档中心已补齐(`../../../../docs/`)。 - 旧框架兼容入口 `externalOldERPIndex`(data.js)仅在需要兼容历史模块时配置。 ## 9. 文档变更协议 - 加/删模块或改依赖方向 → 改本文 §2 + §3,同一 commit。 - 改对外签名(request/gridDefaultProps 等)→ 先改 §3.2,再改代码。 - 与 `PRD.md` 冲突 → 以 `PRD.md` 为准,回改本文;与共享 `docs/coding-standards.md` 冲突 → 以 docs/ 为准并回改本文。