# 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 的 `