Skip to content

前端工程规范 ​

面向对象:前端开发者、代码评审者、AI Agent。

本文维护 digital-construction-ui(Vue 3 + TypeScript + Element Plus)的代码组织与实现规范。页面视觉、布局与交互状态见界面与交互规范,跨端契约见公共开发约定。

决策优先级 ​

  1. 当前用户指令、适用业务基线、已核实的接口与权限契约,以及有依据的合理假设;
  2. 项目本地 UI 规范;
  3. 同类型成熟页面和公共组件;
  4. Vue 3、Element Plus、项目 hooks/API/types 的既有约定;
  5. 通用前端实践。

成熟页面是本地证据,不是绝对真理。若它与前两项冲突,说明差异并按目标修正。

当前用户指令、适用业务基线和原型表达的业务要求决定业务内容与动作含义;信息分组、布局、控件形态和样式由 UI 规范与成熟组件决定,原型不作为 UI 还原稿(见原型与证据)。不能套成熟布局就自动增加无来源的 Tab、统计卡或业务动作;标准 B 端页面优先复用成熟组件,不为装饰性细节另造组件。冲突按根 AGENTS.md 的授权、暂停和范围规则处理。

开始方式 ​

  1. 核对当前任务的业务流程、接口契约和权限要求,沿用已有基线,不另设确认点。
  2. 核对根因和必须保持的正确行为,从页面、API/types、共享组件与 Hook 的直接依赖开始,按任务分级依据证据扩展影响边界并收敛调查,不按改动行数预判风险。新增模式、上下文不足或涉及共享机制时,核验最接近的成熟页面。原型驱动任务记录图/页/区域定位,仅记录歧义或有意改动的短对照,不逐字段抄录;成熟页面只是证据,不自动带入原型未显示且无需求来源的功能。
  3. 按实际可见影响读取界面与交互规范相关章节:内容、按钮数量、文字长度、显隐、交互或布局变化都可触发,不限于名称含“样式”的任务。工具栏、操作列等标准区域优先复用经核验符合当前规范的共享结构与样例;整页调整按实际覆盖范围扩大阅读。
  4. 判断是标准 CRUD、树表、强业务页、工作流页,还是仅 API/types 修改。

优先参考的代码来源 ​

  • 标准单表:src/views/system/client/index.vue、src/api/system/client/index.ts、src/api/system/client/types.ts。
  • 树表:src/views/workflow/category/index.vue。
  • 系统复杂页:src/views/system/user/index.vue、system/role、system/post、system/config。
  • 强业务页:
    • 工程结构树与单位工程:src/views/business/engineeringConfig/index.vue(含 nodeForm.vue、moveDialog.vue、sitePicker.vue)
    • 项目范围与授权(单页多 Tab 工作台):src/views/business/projectScope/index.vue(含 components/GrantPanel.vue、components/UserScopePanel.vue、components/NodeMembersPanel.vue、components/TemplatePanel.vue)
    • 工点库:src/views/business/siteLibrary/index.vue
    • 工程手续办理(台账 + 流程表单):src/views/business/engineeringProcedures/**(annualPlan/index.vue、flowForm/index.vue、stage/ProcedureLedgerPage.vue、summary/index.vue)
  • 公共 hooks:src/hooks/async/useLoading.ts、src/hooks/dialog/*、src/hooks/form/*、src/hooks/table/*、src/hooks/tree/*。
  • 项目内 gen 模板:gen/api.ts.ftl、gen/types.ts.ftl、gen/index.vue.ftl、gen/index-tree.vue.ftl。

基础栈与格式 ​

  • Vue 3 + TypeScript + Element Plus + Vite + Pinia + UnoCSS。
  • pnpm;pnpm run fmt(oxfmt)、pnpm lint(oxlint)。
  • .editorconfig:UTF-8、LF、2 空格缩进。
  • 不写本机绝对路径到交付内容;跨环境引用用 Gitee URL + 分支 + 路径。

两套页面风格 ​

标准 CRUD / 系统页 ​

  • <script setup name="Xxx" lang="ts">。
  • 根节点 class="p-2 app-container <module>-<business>-page"。
  • 结构:搜索卡片 search-panel → 表格卡片 table-panel → 工具栏 toolbar-shell → data-table → right-toolbar → pagination → el-dialog。
  • hooks:useSearchToggle、useLoading(true) + withLoading、useTableSelection<XxxVO>(item => item.id)、useFormDialog({ form, formRef, initialFormData })、useDateRangeQuery、useSearchReset。
  • 参考 src/views/system/client/index.vue。

既有强业务页 ​

  • src/views/business/** 使用自定义布局:el-card 分栏、el-tree、el-dialog、proxy?.$modal、v-hasPermi、scoped SCSS、自定义 class(如 project-config-page、structure-card、tree-scroll)。
  • 修改时只增量改;新增子组件/弹窗参考同目录现有子组件。
  • 新强业务页优先模仿这些页面,不套 gen。

页面实现契约 ​

  • 标准 B 端页面复用成熟页面的布局、筛选区、表格、弹窗、权限控制和交互节奏,只重新设计真实业务差异。
  • 数据源、枚举含义、查询范围、保存粒度和流程推进等会改变行为的内容先查资料、调用链和同级先例,能确定时沿用并记录;仍缺关键事实时按根 AGENTS.md 只澄清具体缺项,暂停依赖该决定的实现,其余已授权工作继续。实施统一遵循根规则的“开始实施”开关。本次适用的鉴权、校验、错误处理和失败恢复落实在责任边界并复用统一机制,不逐层重复实现,也不因此扩建产品能力。
  • 新强业务页面或权限、只读、状态、提交行为变化时,明确受影响的最小状态矩阵:业务状态 × 用户角色 × 可见/只读/可操作 × 动作结果。矩阵覆盖实际不同的权限或行为分支,不枚举不存在的组合;相同行为可选代表性用例,但不能合并权限边界不同的分支。局部改动沿用已有矩阵,只核对受影响项;它是实现检查表,不要求额外创建正式文档。
  • 类型、枚举和状态含义来自真实接口契约,优先复用项目 API/types 和字典;不得用 any、重复常量或页面内临时映射掩盖契约不一致。
  • 防御、校验、组件与 Hook 抽取及异常处理统一按实现简洁性执行。

API 文件规则 ​

  • 标准 API 放 src/api/<module>/<business>/index.ts,同目录维护 types.ts。
  • 业务 API 示例:src/api/business/projectScope/index.ts、src/api/business/engineeringConfig/projectNode.ts、src/api/business/engineeringProcedure/index.ts。
  • AxiosPromise 从 @/utils/api-types 引入,PageResult 从 @/api/types 引入;不要从 axios 引 AxiosPromise。
  • 列表分页通常返回 AxiosPromise<PageResult<XxxVO>>;树表通常返回 AxiosPromise<XxxVO[]>。
  • 标准函数命名:listXxx、getXxx、addXxx、updateXxx、delXxx、changeXxxStatus。
  • query string 用 params,请求体用 data。
  • 加密、防重复提交等 headers 直接写在请求配置里。
  • 相邻文件已有 export const 或 export function 时跟随;新增标准 CRUD 优先跟随 gen/api.ts.ftl 和相邻模块。

类型文件规则 ​

  • 标准类型定义 VO、Form、Query,必要时补 InfoVO、TreeVO、ResetPwdForm 等扩展类型。
  • Form 通常继承 BaseEntity;非树表 Query 继承 PageQuery;树表 Query 通常不继承 PageQuery。
  • ID 通常 string | number,批量删除参数 string | number | Array<string | number>。
  • 日期范围查询保留项目所需的 params 结构;新增类型优先使用 Record<string, unknown>,修改旧代码时避免无关的大范围类型重写。
  • 列表、表单、查询对象职责分开;不得用 any 掩盖接口字段、枚举或状态不一致。框架边界确实无法收窄时才局部使用,并说明原因。

大整数 ID 约定 ​

ID 的接收、传递、列表与详情合并及接口排查统一遵循公共开发约定 · 前后端大整数 ID 约定。

组织单位选择器 OrgUnitSelect 内部树节点与选中键统一字符串匹配,兼容 CSV 字符串 ID 与接口安全数字 ID;对外已选项保持调用方原值、新选项透传组织接口原值,不将任何 ID 数字化。

权限规则 ​

  • 权限复用项目路由、菜单和按钮机制,并区分不可见、只读、不可操作;前端隐藏按钮不能代替鉴权,也不能绕过只读和数据范围限制。
  • 权限码格式、前后端与菜单的一致性要求及回归检查见公共开发约定 · 三段式权限码。
  • 默认 v-hasPermi;el-dropdown-item 延迟加载不可靠时用 v-if="checkPermi([...])"。

Vue 页面行为规则 ​

标准页 ​

  • getList 负责设置 loading、调用列表接口、回填列表和 total。
  • handleQuery 先把 queryParams.value.pageNum = 1,再 getList();树表无分页时只 getList()。
  • resetQuery 使用 useSearchReset,分页页传 pageNumKey: 'pageNum'。
  • handleAdd 使用 openDialog('添加xxx')。
  • handleUpdate 先 reset(),查详情,Object.assign(form.value, res.data),showDialog('修改xxx')。
  • submitForm 校验通过后设 buttonLoading,按主键新增/修改,成功后 modal.msgSuccess('操作成功')、关弹窗、刷新。
  • handleDelete 用 modal.confirm(...) 二次确认,删除后提示并刷新。
  • handleExport 用 requestDownload('<module>/<business>/export', { ...queryParams.value }, '<business>_<timestamp>.xlsx')。
  • 状态切换失败时回滚 switch 值。

强业务页 ​

  • 保持现有方法命名和交互(如 onNodeClick、handleAddChild、filterNode)。
  • 弹窗用 el-dialog 或 ElMessageBox,按原页面写法。
  • 修改树结构后按原逻辑刷新左树、中列、详情。
  • 新增子页面/组件先看同目录现有子组件再动手。
  • 状态矩阵按“页面实现契约”的适用范围核对,不因修改强业务页就重新整理全页状态和角色。

异步与失败状态 ​

按本次受影响的异步交互处理适用状态:读取数据时处理加载、空数据和请求失败;写入动作处理防重复触发、成功后的刷新/关闭/跳转及失败后的状态恢复;存在无权限、只读或服务端数据变化语义时处理对应反馈。无需为不适用的状态增加页面功能。

  • 提交、删除、状态切换等操作防重复触发;失败后恢复按钮、表单或开关状态。
  • 成功后明确刷新、关闭或跳转行为,避免页面仍显示旧数据。
  • 服务端数据已变化或当前状态不再允许操作时,展示可理解的反馈,并按需要重新获取最新数据。

可访问性底线 ​

表单标签、图标按钮、键盘焦点和状态提示满足基础可访问性;状态和危险程度不能只靠颜色表达,禁用状态应能解释原因。操作不能只依赖颜色表达。

组件、样式与字典 ​

  • 复用 right-toolbar、pagination、DictTag/dict-tag、ImageUpload、ImagePreview、FileUpload、Editor、TreePanel。
  • 标准页 scoped SCSS:@use '@/assets/styles/components/page-shell' as pageShell;。
  • 强业务页按现有 scoped 样式继续,不因新增功能重排全局样式。
  • 类名保持模块语义:project-config-page、site-library-page、engineering-procedure-page。
  • 颜色只用语义令牌,不在页面里写死浅色字面值;令牌表、状态色用法和 <style scoped> 里暗色规则的写法见界面与交互规范第 2.1 节。深色模式状态统一走 @/hooks/useThemeMode,页面不得自建第二份主题状态。
  • 字典:const { sys_normal_disable } = toRefs(useDict('sys_normal_disable'));,不要用 any 掩盖字典类型。
  • 常用:modal from @/plugins/modal、download as requestDownload from @/utils/request、useDict from @/utils/dict、handleTree/parseStrEmpty from @/utils/ruoyi。

树表规则 ​

  • 列表返回数组,handleTree<T>(res.data, 'id', 'parentId') 组树。
  • 使用 row-key、:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"。
  • 展开/折叠使用 useTreeTableExpand。
  • 表单上级节点使用 el-tree-select;新增子节点从当前行回填 parentId。
  • 工程结构树注意节点类型(ROOT/LINE/PACKAGE/BID/SITE)与状态标签逻辑,不要把历史 PROJECT 值当作可创建节点。

与 gen 模板的关系 ​

  • 新增标准页面读 gen/index.vue.ftl、gen/api.ts.ftl、gen/types.ts.ftl;树表读 gen/index-tree.vue.ftl。
  • gen 是骨架不是答案;落地时对照目标模块真实页面。
  • 修改强业务页不要把 gen 简化逻辑覆盖现有业务。

视觉设计边界 ​

标准 CRUD、树表、系统管理和普通强业务后台不做大范围视觉重设计。官网、登录页、门户、大屏等表现型页面沿用本地 UI 规范、既有组件和本规范的接口、权限、异步状态与页面验证要求;决策驾驶舱类大屏参考 src/views/cockpit/** 的现有实现:独立全屏路由(登录必需、菜单隐藏)、平台令牌取色、echarts 随浅深主题重建、演示数据集中于 src/views/cockpit/mock.ts 并在页面标注模拟数据,不套用 B 端台账的令牌与台账验收条目;确需视觉调整时按实际覆盖范围读取界面与交互规范。方案自查不是用户批准点,审批边界遵循根 AGENTS.md;本地 UI 规范与项目既有组件始终优先于外部设计参考。

验证 ​

  • 任务分级、真实页面证据及完成边界遵循根 AGENTS.md;测试复用、覆盖缺口和共享机制范围遵循公共开发约定 · 验证范围。通过验证入口执行所选检查,不因缺少浏览器自动增加与风险无关的类型、lint 或接口检查。
  • 可见界面按本次需求来源检查漏做、改义和多做;有原型时核对原型来源和对应区域,没有原型不增加材料门槛。源码、类型检查、构建和示例预览不构成真实页面证据,常规任务不强制先做预览。
  • 验证方式遵循根 AGENTS.md:Agent 根据实际影响和风险选择静态、定向测试、接口或浏览器等足够的证据,用户显式要求浏览器时执行;不因功能交互、改动数量或页面类型机械启动浏览器。局部样式、文案默认核对差异与规范,公共样式即使只改一处也先核实影响;不自动把未选浏览器的任务转交用户待验收。
  • 选用浏览器后,从实际页面入口点击、输入、选择和提交,不以 API 请求或内部状态注入冒充用户操作;文件上传的工具限制按根规则例外处理,随后继续所需页面核验。网络、日志和数据库各证明其覆盖的结果。按实际影响覆盖相关角色、状态、动作结果及适用失败场景,不因页面属于强业务页扩大为全角色回归。使用主要角色的真实账号或等价角色切换能力,核对可见、只读/禁用、可操作及结果;工具栏和操作列变化还需核对对齐、顺序、完整显示、间距、固定列及显隐变化后的布局。关键页面或明确要求的视觉问题保留截图,普通任务不强制逐页留图。
  • 小改动验证直接影响范围,普通页面按需执行相关 spec、类型检查或 lint。公共 hooks 和构建配置按验证范围的共享机制原则核对实际影响,能可靠收敛时执行相关检查;影响范围无法可靠收敛、实际改变构建流程或产物组织及打包行为、大范围页面变化及正式模块交付时执行完整构建。不因文件属于公共 hooks 或构建配置而将无行为变化的改动升级为完整构建。
  • lint、格式检查优先传入受影响文件或目录;类型检查保留项目级依赖分析,不机械裁成单文件检查。自动化针对实际行为和稳定契约,普通文案、样式或实现形式不新增低价值测试。
  • 登录、角色选择和验证受阻排障见环境配置与运行 · 验证范围。证据只记录角色,不泄露凭据;单一管理员账号检查或类型、lint、build 结果不能表述为多角色业务验收通过。

避免事项 ​

  • 不要从 axios 引入 AxiosPromise。
  • 不要绕开 request / requestDownload 自造请求/下载封装。
  • 不要删除日期范围 params、权限指令、导出、导入、树筛选、列显隐。
  • 不要把强业务页(business/**)重写成 hooks 标准页,除非明确要求。
  • 不要为了“更整洁”大改用户已写好的复杂页面。
  • 不要为可能的未来复用提前抽取大量组件、Hook 或配置层。
  • 不要在同一文件混入两套风格。
  • 不要自造偏离 UI 规范的面板/滚动结构(自造页头卡、筛选卡、自定义 calc(100vh - Npx) 滚动容器等),不要引入规范色板之外的色系。