# 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<data>；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<data>   // 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/ 为准并回改本文。
