# Forge Admin 前端开发与组件规范
本规范适用于 `forge-admin-ui` 的 Vue 3 页面、组件和接口代码。项目级约束以仓库根目录 `AGENTS.md` 为准;本文件补充前端实现细则。
## 1. 技术与基本约定
- 使用 Vue 3 Composition API 与 `
```
- Import 按「第三方 → `@/` 项目路径 → 相对路径」分组;删除未使用 import。
- 组件默认使用 `defineOptions({ name: '...' })`,名称与组件文件一致。
- Props 必须声明类型、默认值和必要时的 validator;对象、数组默认值使用工厂函数。
- Emits 只暴露必要事件,事件名描述已经发生的业务结果,例如 `submit-success`、`selection-change`。
- 不在模板中写复杂计算、数组过滤或深层取值;提取为 `computed`、`resolveXxx` 或 `isXxx` 函数。
- `v-for` 必须使用稳定的 `:key`,禁止用数组下标作为可排序、可编辑列表的 key。
- 异步请求必须处理 loading、异常和 finally;用户可见的失败使用 `window.$message` 或页面内错误态说明。
### 9.2 状态边界
| 状态类型 | 放置位置 | 示例 |
| --- | --- | --- |
| 单个控件、弹窗、筛选值 | 当前组件 `ref` | `modalVisible`、`selectedOrgId` |
| 基于当前状态推导的展示值 | `computed` | `filteredRows`、`canSubmit` |
| 可复用请求/交互逻辑 | `src/composables/useXxx` | `useDict`、`usePermission` |
| 登录态、主题、跨页会话 | Pinia Store | `useUserStore`、`useAppStore` |
| 不随渲染变化的映射/常量 | 模块顶层 `const` | `USER_STATUS_DICT` |
- 组件不能直接修改父组件传入的对象或数组;通过事件上抛,或先复制后提交。
- `watch` 只处理副作用(重新请求、同步外部值、清理资源),不能替代本应使用的 `computed`。
- 组件卸载后仍可能返回的异步请求,需要避免继续写失效状态;轮询、事件监听和定时器必须在卸载时清理。
- 不把接口返回对象无差别地扩散到全局 Store;先明确数据归属和失效策略。
### 9.3 模板与可访问性
- 有业务语义的容器使用 `header`、`main`、`section`、`aside`、`nav`、`article`,不要只堆叠 `div`。
- 非按钮元素不可承担点击行为;需要点击时用 `button`,或补齐 `role`、`tabindex`、键盘 Enter/Space 行为。
- 图标按钮必须带 `title` 或 `aria-label`;图片必须说明 `alt`,装饰图片才可空 alt。
- 对话框、抽屉和全屏工作台打开后,焦点应落在可操作区域;关闭后尽量回到触发元素。
- 长文本在列表、树节点、标签中要配置省略、完整标题或可展开查看,不能让列撑破页面。
## 10. 表单、表格与 CRUD 规范
### 10.1 Schema 与表单
- 查询 Schema、编辑 Schema 使用 `computed` 生成,特别是依赖字典、权限或上下文的 options。
- 字段 `field` 与后端 DTO 字段保持一致;展示 label 可以改中文,字段编码不随意改名。
- 新增、编辑、详情有差异时使用 `beforeRenderForm`、`beforeRenderDetail` 或字段权限配置,禁止复制三套表单。
- 详情优先配置完整 `editSchema`,保证字典、枚举和敏感字段按业务规则展示;`AiCrudPage` 会在遗漏 Schema 时按可见表格列生成只读兜底详情,防止空白弹窗,但不能替代正式 Schema。
- 提交前处理使用 `beforeSubmit`;返回 `false` 时明确阻止提交,异步逻辑必须 `await`。
- 复杂结构化编辑(基础信息、可排序明细、高级设置、预览)使用独立全屏工作台或同路由页面,不塞进侧边抽屉。
- 少字段、单一职责的编辑才使用 Modal 或 Drawer;关闭、取消不能污染未确认草稿。
### 10.2 表格
- 表格默认密度为 `medium`,仅高密度审计、日志或对比场景使用 `small`;不要把整站默认设为紧凑。
- `columns` 只承载列配置与必要渲染函数;超过三段逻辑的单元格渲染抽为小组件。
- 表格单元格只表达一种信息层级:用户、组织、应用等实体使用 `SystemTableCell` 的主标题 + 辅助标识;关联关系显示主值与可展开 `+N`;枚举状态才使用 `DictTag`;普通属性保持纯文字。不要在每个单元格叠加图标、色块和 Tag。
- 用户类实体以真实姓名或昵称为主标题,登录名以 `@username` 作为辅助标识;主标题区域可点击查看详情。性别等低频属性保留在详情或列设置,不挤占主列表。
- 操作列使用文字链接和项目语义色;常用操作直接显示,多个低频操作才放进“更多”。
- 分页接口统一传 `pageNum`、`pageSize`;远端排序、筛选参数必须与后端接口定义一致。
- 文件图片字段通过 `AuthImage` 渲染;下载链接通过 `getFileUrl(fileId)` 获取。
- 空态要区分“暂无数据”与“没有匹配结果”;筛选后为空时提供重置或调整筛选的明确入口。
### 10.3 删除与危险操作
- 删除、批量删除、重置密码、权限变更、状态流转必须二次确认,并明确对象和影响范围。
- 删除成功后刷新当前列表;分页最后一页被清空时回退到有效页。
- 按钮禁用状态不是安全边界,前端仍需按权限条件隐藏或禁用,后端必须继续校验权限。
## 11. 路由、权限与导航
- 路由页面放在 `src/views//`,目录和路由业务域一致;动态路由由现有路由装配机制生成,不手写冲突路径。
- 新增菜单、按钮权限后,页面通过现有 `usePermission` 或权限指令判断展示;不能仅依赖前端隐藏来保护操作。
- 不为一次跳转滥用全局 Store。可由 URL 表达的筛选、记录 ID、页签等状态优先使用路由 query/params。
- 从列表打开独立设计器、预览或复杂工作台时,按既有交互选择独立页签或同路由工作区,并保证返回路径可用。
- `KeepAlive` 页面需要处理路由参数切换、激活后的刷新与资源释放,不能假设 `onMounted` 只会运行一次。
## 12. 请求、文件与安全
### 12.1 请求
- 所有请求通过 `@/utils/request` 或现有 API 模块;禁止在组件内新建 Axios 实例。
- API 模块函数以动词和资源命名,例如 `fetchUserPage`、`createUser`、`updateUser`、`removeUsers`。
- 明确约定请求参数位置:查询用 `params`,JSON 提交用 `data`;不要把对象序列化后拼进 URL。
- 不记录 Token、密码、手机号、身份证、银行卡、API Key 或完整服务端异常到控制台与埋点。
- 前端只做交互层校验和脱敏展示,权限、租户、数据范围、加密解密必须由后端最终控制。
### 12.2 文件
- 上传字段存储 `fileId`,表单与接口不要把临时 URL 当作持久业务值。
- 预览、下载、图片渲染统一复用项目文件工具和鉴权组件;不要自行拼接 OSS 地址或 Token。
- 批量导入、导出、下载属于阻塞性操作,应有局部 loading、防重复提交和可理解的失败反馈。
## 13. 样式工程规范
### 13.1 样式层次
1. 能用 Naive UI Props 解决的,不新增 CSS。
2. 能用 UnoCSS 表达的局部布局与间距,优先使用 UnoCSS。
3. 组件结构、主题兼容、复杂 hover/响应式规则使用当前 SFC 的 `