update 优化 skill 内容

This commit is contained in:
疯狂的狮子Li
2026-06-03 11:39:45 +08:00
parent c004cbc86c
commit 6b039422b3
4 changed files with 238 additions and 316 deletions
+76 -73
View File
@@ -1,76 +1,66 @@
--- ---
name: frontend-crud-coding name: frontend-crud-coding
description: 在当前前端项目中按现有 Vue 3 + TypeScript + Element Plus 代码风格生成或修改页面、API、types、组件接入和样式。用于新增列表页、表单弹窗页、树表页、系统管理页、workflow 页面,以及补全与后端接口对应的 src/api 和 src/views 代码。 description: 在当前 plus-ui-new 前端项目中按真实 Vue 3 + TypeScript + Element Plus + oxlint/oxfmt 代码风格生成或修改页面、API、types、hooks 接入和样式。用于新增或修改标准 CRUD 列表页、树表页、系统管理页、监控页、workflow 页面、demo 页面,补齐与 RuoYi-Vue-Plus boot4 后端接口对应的 src/api、types 和 src/views 代码;触发后应先读取适用 references,再阅读目标模块真实代码和后端 generator 前端模板
--- ---
# 前端编码规范 # 前端编码规范
先对齐当前前端项目里的真实实现,再参考关联后端工程代码生成器产出的前端模板。不要只套通用 Vue 模板,也不要把生成器模板原样照搬而忽略当前前端项目的实际演进 先对齐当前前端项目里的真实实现,再参考关联后端工程代码生成器模板。不要只套通用 Vue 模板,也不要把 generator 模板原样复制进来而忽略当前项目已经演进出的 hooks、页面壳、类型入口和下载方式
## 适用场景
在下面这些任务里优先使用此 skill:
- 新增标准 CRUD 列表页、弹窗表单页、树表页。
- 补齐后端新增接口对应的 `src/api``src/views``types.ts`
- 按系统管理、监控、工作流、demo 模块现有方式扩展页面功能。
- 调整已有列表页的搜索、导出、导入、树筛选、列显隐、权限按钮、样式壳。
- 把关联后端工程中的 generator 模板转换为符合当前前端项目风格的实际代码。
## 不适用场景
下面这些任务不要机械套用本 skill 的 CRUD 规则:
- 纯展示型落地页、营销页、可视化大屏。
- 完全独立的低代码设计器或第三方嵌入页。
- 全局框架升级、Vite 配置改造、构建链路迁移。
- 与当前项目目录结构明显不同的实验性页面。
## 执行流程 ## 执行流程
1. 先定位目标模块,并阅读 `src/api/<module>/<business>``src/views/<module>/<business>` 下最近似页面 1. 判断任务类型:新增标准 CRUD、树表、已有页面增强、复杂业务页、只补 API/types
2. 再参考关联后端工程 `ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts``vm/vue` 下的生成器模板,确认标准 CRUD 的基础骨架 2. 按“文档读取规则”读取必要 reference,不一次性展开所有资料
3. 新增代码时同时维护 `api/index.ts``api/types.ts``views/.../index.vue`,必要时补相关子页面或弹窗页。 3. 阅读目标目录下最近似的真实代码:
4. 页面结构、样式组织、状态管理、权限指令、下载导出、字典使用都以仓库现有模式为准 - 标准单表优先看 `src/views/demo/demo/index.vue``src/api/demo/demo/*`
5. 如果后端接口与生成器套路一致,可以用 generator 模板作为起点;如果当前前端项目已有更强约定,以当前项目约定覆盖模板默认行为 - 树表优先看 `src/views/demo/tree/index.vue``src/views/workflow/category/index.vue`
- 系统复杂页优先看 `src/views/system/user/index.vue``system/role``system/post``system/config`
- workflow 业务页优先看 `src/views/workflow/*` 同类页面。
4. 新增标准页面前,对照后端工程 `D:\git-sources\Plus相关\RuoYi-Vue-Plus-boot4\ruoyi-modules\ruoyi-gen\src\main\resources\vm\ts``vm\vue` 模板确认基础骨架。
5. 新增代码时通常同步维护 `src/api/<module>/<business>/index.ts``types.ts``src/views/<module>/<business>/index.vue`
6. 增强已有页面时只做增量修改,保留原页面的树筛选、导入导出、列显隐、权限、字典、弹窗和路由跳转能力。
7. 修改完成后按影响范围运行验证:优先 `pnpm exec vue-tsc --noEmit`,改动页面或导入时再跑 `pnpm lint`,大范围变更再跑 `pnpm build`
## 文档读取规则
- 前端 API、types、页面、hooks、样式和验证规则,先读 [references/frontend.md](references/frontend.md)。
- 不确定任务边界、需要标准用例或提问方式时,再读 [references/examples.md](references/examples.md)。
- reference 只约束实现方式和自检范围;发生冲突时,以当前模块真实代码和实际调用点为准。
## 优先级规则 ## 优先级规则
发生冲突时按下面顺序决策: 发生冲突时按下面顺序决策:
1. 当前目录下最近似页面的真实实现。 1. 目标目录下最近似页面、API、types 的真实实现。
2. 当前项目公共组件、公共工具、公共样式约定。 2. 当前项目公共 hooks、组件、工具和样式约定。
3. 关联后端工程中的 generator 模板。 3. 关联后端工程中的 generator 前端模板。
4. 通用 Vue / Element Plus 习惯。 4. 通用 Vue 3 / Element Plus 习惯。
也就是说: 也就是说:
-模块已有页面怎么写,优先怎么写。 - 同模块已有页面怎么写,优先怎么写。
- 没有现成页面时,再退回到 generator 模板骨架 - 没有现成页面时,使用 generator 模板作为骨架,再改成当前项目风格
- 没有现成模式时,才使用通用框架默认写法 - 复杂模块不能为了“标准 CRUD”退化成裸模板页
## 主要规则
详细规则见 [references/frontend.md](references/frontend.md)。
使用案例见 [references/examples.md](references/examples.md)。
## 仓库通用规则 ## 仓库通用规则
- 遵循 [`.editorconfig`](../../../.editorconfig)UTF-8、LF、默认 2 空格缩进。 - 遵循 [`.editorconfig`](../../../.editorconfig)UTF-8、LF、2 空格缩进Markdown 例外
- 遵循 [`.prettierrc`](../../../.prettierrc):单引号、分号、`printWidth: 150``trailingComma: none` - 当前仓库没有 `.prettierrc`,格式脚本是 `pnpm run fmt` 调用 `oxfmt .`lint 脚本是 `pnpm lint` 调用 `oxlint src`
- 页面优先使用 `<script setup name="Xxx" lang="ts">` - 页面优先使用 `<script setup name="Xxx" lang="ts">`
- 优先复用仓库已有基础设施,例如 `request``proxy?.$modal``proxy?.download``proxy?.useDict``pagination``right-toolbar` - API 返回类型优先从 `@/utils/api-types` 引入 `AxiosPromise`,分页结果从 `@/api/types` 引入 `PageResult`
- 对于标准 CRUD 页,允许先按后端生成器模板组织 `api/types/index.vue` 骨架,再补齐当前前端项目自己的页面壳、样式和交互 - 请求统一通过 `@/utils/request`,导出下载使用 `import { download as requestDownload } from '@/utils/request';`
- 新页面不要无故引入另一套状态管理、另一套请求封装或另一套 UI 风格 - 标准列表页优先复用 `useLoading``useSearchToggle``useSearchReset``useTableSelection``useFormDialog``useDateRangeQuery`
- 页面壳优先使用 `p-2 app-container <module>-<business>-page``search-panel``toolbar-shell``data-table``right-toolbar``pagination`
- 新页面不要无故引入另一套状态管理、请求封装、样式体系或权限写法。
## 目录映射规则 ## 目录映射规则
通常按下面的对应关系组织代码: 通常按下面关系组织代码:
- 后端路由 `/system/user/*` 对应 `src/api/system/user/*``src/views/system/user/*` - 后端 `/system/user/*` 对应 `src/api/system/user/*``src/views/system/user/*`
- 后端路由 `/monitor/xxx/*` 对应 `src/api/monitor/xxx/*``src/views/monitor/xxx/*` - 后端 `/monitor/xxx/*` 对应 `src/api/monitor/xxx/*``src/views/monitor/xxx/*`
- 后端路由 `/workflow/xxx/*` 对应 `src/api/workflow/xxx/*``src/views/workflow/xxx/*` - 后端 `/workflow/xxx/*` 对应 `src/api/workflow/xxx/*``src/views/workflow/xxx/*`
- 后端路由 `/demo/xxx/*` 对应 `src/api/demo/xxx/*``src/views/demo/xxx/*` - 后端 `/demo/xxx/*` 对应 `src/api/demo/xxx/*``src/views/demo/xxx/*`
标准新增通常至少包含: 标准新增通常至少包含:
@@ -81,56 +71,69 @@ description: 在当前前端项目中按现有 Vue 3 + TypeScript + Element Plus
按业务复杂度,可能继续补: 按业务复杂度,可能继续补:
- 导入弹窗 - 导入弹窗
- 分配角色 - 详情抽屉或详情
- 详情页 - 树筛选面板
- 编辑页 - 列显隐配置
- 子组件 - 分配/授权子页面
- 自定义 SCSS 样式 - 自定义 SCSS 样式
## 任务分型 ## 任务分型
### 1. 标准单表 CRUD ### 1. 标准单表 CRUD
目标是快速补齐 `api + types + index.vue`,优先参考 generator 模板,再贴近 demo 或系统模块现有页 以后端 generator 模板和 `src/views/demo/demo/index.vue` 为主要起点,补齐列表、搜索、分页、新增、编辑、删除、导出、权限、类型和验证
### 2. 强业务页面 ### 2. 树表 CRUD
如果页面包含树筛选、导入导出、更多操作、状态切换、角色分配、复杂校验、联动选择,则优先参考 `src/views/system/user/index.vue` 一类更完整页面 `src/views/demo/tree/index.vue``src/views/workflow/category/index.vue` 为主要起点。列表接口通常返回数组而不是 `PageResult`,页面使用 `handleTree``useTreeTableExpand``Query` 通常不继承 `PageQuery`
### 3. 工作流页面 ### 3. 强业务页面
如果页面属于流程定义、分类、任务、实例等 workflow 目录,优先参考 `src/views/workflow/*`,不要硬套系统管理模块的页面骨架 如果页面包含树筛选、导入导出、更多菜单、状态切换、角色分配、详情抽屉、复杂校验、联动选择或独立路由,优先增量修改现有页面。不要重写成简单 CRUD
### 4. 工作流页面
workflow 目录优先参考 `src/views/workflow/*`。流程定义、流程实例、任务列表、请假申请等页面通常有业务按钮、弹窗和路由跳转,不要硬套 system 模块。
### 5. 只补 API 和 types
只维护 `src/api/<module>/<business>/index.ts``types.ts`,但仍要与后端路由、返回结构、当前模块导入方式和类型入口一致。
## 输出要求 ## 输出要求
使用本 skill 时,默认期望产出应满足: 使用本 skill 时,默认期望产出应满足:
- 类型完整,不把大量 `any` 塞进页面逻辑里 - 类型完整,不把页面逻辑大量写成 `any`
- 查询、重置、分页、弹窗、删除、导出流程闭环完整 - API 路径、函数名、权限标识与后端接口保持一致
- 权限指令、字典、公共组件接入到位 - 标准页查询、重置、分页、弹窗、提交、删除、导出流程闭环完整
- 样式尽量贴合现有页面壳,而不是只保证“功能能跑” - 复杂页面保留原有交互能力和业务约束
- 如果是从 generator 模板演化而来,要体现出当前前端项目已有增强,而不是模板裸输出。 - 代码体现当前项目 hooks、页面壳和下载方式,而不是 generator 裸输出。
- 交付前说明运行过的验证命令;如果无法验证,说明原因。
## 快速检查清单 ## 快速检查清单
- API 路径与后端路由完全对应 - `AxiosPromise` 是否来自 `@/utils/api-types`
- `src/api` 中同时维护 `index.ts``types.ts` - `PageResult` 是否来自 `@/api/types`
- 列表页查询、重置、导出、删除、弹窗提交流程与现有页一致。 - API `params``data` 是否与后端方法一致。
- 继续使用项目内权限指令与公共组件 - 日期范围是否通过 `useDateRangeQuery` 或附近页面现有方式处理
- 表单、查询、弹窗、表格样式优先复用现有布局类和 SCSS 片段 - 列表 loading 是否通过 `useLoading` 或原页面方式维护
- 缩进、引号、分号与仓库格式一致 - 弹窗是否通过 `useFormDialog` 或原页面方式维护
- 多选状态是否通过 `useTableSelection` 或原页面方式维护。
- 权限指令是否保持同文件一致,默认使用当前项目主流 `v-hasPermi`
- 导出是否使用 `requestDownload('<module>/<business>/export', { ...queryParams.value }, '<name>_<time>.xlsx')`
- 页面壳是否保留 `search-panel``table-panel``toolbar-shell``data-table``right-toolbar``pagination`
## 推荐提问方式 ## 推荐提问方式
推荐把请求描述到下面这个粒度: 推荐把请求描述到下面粒度:
- 目标模块和业务名 - 目标模块和业务名
- 后端接口前缀 - 后端接口前缀
- 是新增页面还是修改页面 - 是新增页面修改页面,还是只补 API/types
- 是否需要导入、导出、树筛选、状态切换、字典、权限按钮 - 是否需要导入、导出、树筛选、树表、状态切换、字典、权限按钮
- 希望参考哪个现有页面 - 希望参考哪个现有页面
例如: 例如:
- 使用 `$frontend-crud-coding``/system/client` 补一套标准 CRUD 页面,参考 `system/user` generator 模板。 - 使用 `$frontend-crud-coding``/system/client` 补一套标准 CRUD 页面,参考 `demo/demo``system/client` 和 boot4 generator 模板。
- 使用 `$frontend-crud-coding` 修改 `workflow/category` 列表页,增加导出按钮和状态筛选,保持当前项目风格。 - 使用 `$frontend-crud-coding` 修改 `workflow/category` 列表页,增加导出按钮和状态筛选,保持当前 workflow 风格。
@@ -1,7 +1,7 @@
interface: interface:
display_name: "前端编码" display_name: "前端编码"
short_description: "按当前前端项目约定编写页面与 API" short_description: "按 plus-ui-new 真实代码和 boot4 模板编写前端 CRUD"
default_prompt: "使用 $frontend-crud-coding 在当前前端项目里按现有约定实现页面和 API 修改。" default_prompt: "使用 $frontend-crud-coding 先读取适用 reference,再按当前 plus-ui-new 真实页面、hooks、API/types 约定和 boot4 generator 模板实现前端修改。"
policy: policy:
allow_implicit_invocation: true allow_implicit_invocation: true
@@ -7,67 +7,66 @@
```text ```text
使用 $frontend-crud-coding 为 system/client 补一套前端 CRUD 页面。 使用 $frontend-crud-coding 为 system/client 补一套前端 CRUD 页面。
后端接口已经有 /system/client/list、/system/client/{id}、POST /system/client、PUT /system/client、DELETE /system/client/{ids}。 后端接口已经有 /system/client/list、/system/client/{id}、POST /system/client、PUT /system/client、DELETE /system/client/{ids}。
请参考 generator 模板和现有的 system/user、system/config 页面风格实现。 请参考 boot4 generator 模板、src/views/demo/demo/index.vue 和现有 system/client 风格实现。
``` ```
### 期望执行方式 ### 期望执行方式
- 先看 `src/api/system/client/*` 是否已存在。 - 先看 `src/api/system/client/*``src/views/system/client/index.vue` 是否已存在。
- 再看 `src/views/system/client/index.vue` 是否为空或缺失 - 再看 `src/views/demo/demo/index.vue` 的标准 hooks 版 CRUD 骨架
- 参考同目录系统模块页面,确定是否需要搜索卡片、表格卡片、弹窗、导出按钮 - 对照 boot4 generator 的 `ts/api.ts.vm``ts/types.ts.vm``vue/index.vue.vm`
- 再参考关联后端工程中的 generator 模板,补齐基础骨架 - 生成或修改 `api/index.ts``types.ts``views/.../index.vue`
- 使用 `AxiosPromise` from `@/utils/api-types``PageResult` from `@/api/types``useLoading``useFormDialog``useSearchReset``useTableSelection`
### 期望产物 ## 案例 2:新增树表页面
- `src/api/system/client/index.ts`
- `src/api/system/client/types.ts`
- `src/views/system/client/index.vue`
## 案例 2:把 generator 模板落成当前项目风格
### 用户提问示例 ### 用户提问示例
```text ```text
使用 $frontend-crud-coding 按 generator 模板为 demo/order 生成一个标准页面,但不要直接复制模板,要改成当前前端项目现有样式壳和工具链写法 使用 $frontend-crud-coding 为 demo/tree2 新增树表 CRUD,接口返回数组,字段包含 id、parentId、name、orderNum
参考 src/views/demo/tree/index.vue 和 workflow/category。
``` ```
### 期望执行方式 ### 期望执行方式
- 先看 generator 的 `ts/types/index.vue` 模板 - 优先判断这是树表,不生成分页 `PageResult` 页面
- 再看 `src/views/demo/demo/index.vue``src/views/system/user/index.vue` 的实际风格差异 - API 列表返回 `AxiosPromise<Tree2VO[]>`
- 生成的页面要使用当前项目里的 `right-toolbar``pagination``proxy?.$modal``proxy?.download` - `Query` 不继承 `PageQuery`
- 页面使用 `handleTree``row-key``tree-props``useTreeTableExpand``el-tree-select`
- 新增子节点时从当前行带入 `parentId`
## 案例 3:修改已有列表页 ## 案例 3:修改已有复杂列表页
### 用户提问示例 ### 用户提问示例
```text ```text
使用 $frontend-crud-coding 修改 system/user 页面: 使用 $frontend-crud-coding 修改 system/user 页面:
1. 新增一个创建时间快捷筛选 1. 新增一个创建时间快捷筛选
2. 导出按钮放到更多菜单中 2. 导出按钮保留在更多菜单中
3. 保持现有样式和交互不变 3. 保持现有树筛选、导入、列显隐、详情抽屉和角色分配不变
``` ```
### 期望执行方式 ### 期望执行方式
- 优先阅读现有 `src/views/system/user/index.vue` - 判断这是“已有复杂页面增强”,不是重新生成 CRUD
- 判断这是“已有页面增强”,不是“重新生成页面” - 优先阅读 `src/views/system/user/index.vue`
- 保留树筛选、导入导出、列显隐、角色分配等现有能力 - 保留 `TreePanel`、导入弹窗、`right-toolbar` 列显隐、`UserViewDrawer`、角色分配路由、权限控制
- 增量修改,而不是重写整个页面 - 增量修改搜索和查询参数处理
## 案例 4补齐复杂业务页面 ## 案例 4修改 workflow 页面
### 用户提问示例 ### 用户提问示例
```text ```text
使用 $frontend-crud-coding 为 workflow/category 增加导入、导出和状态切换功能,参考 system/user 的完整页面能力,但保持 workflow 模块自己的风格。 使用 $frontend-crud-coding 为 workflow/category 增加状态筛选和导出按钮,保持 workflow 模块自己的树表风格。
``` ```
### 期望执行方式 ### 期望执行方式
- 优先看 `src/views/workflow/category/index.vue` - 优先看 `src/views/workflow/category/index.vue``src/api/workflow/category/*`
- 再看 `src/views/system/user/index.vue` 里复杂列表页的做法 - 判断是否需要后端新增导出接口;前端导出路径保持 `workflow/category/export`
- 迁移需要的能力,不把用户模块专属逻辑照搬到 workflow 页面 - 迁移 system/user 的用户专属逻辑
- 保留树表、`useTreeTableExpand``handleTree` 和分类弹窗逻辑。
## 案例 5:只补 API 和 types ## 案例 5:只补 API 和 types
@@ -80,33 +79,48 @@
### 期望执行方式 ### 期望执行方式
- 只维护 `src/api/monitor/cache/index.ts``src/api/monitor/cache/types.ts` - 只维护 `src/api/monitor/cache/index.ts``src/api/monitor/cache/types.ts`
- 仍然要与后端路由、现有 API 风格、返回类型保持一致 - 仍然检查同目录 monitor API 的 `export function` / `export const` 风格
- 返回类型使用 `AxiosPromise` from `@/utils/api-types`
- 不创建页面,不改路由。
## 案例 6推荐的高质量任务描述 ## 案例 6接入后端新增状态切换接口
下面这种描述最容易得到稳定结果: ### 用户提问示例
```text ```text
使用 $frontend-crud-coding 在当前前端项目中新增一个 `/system/notice` 列表页增强: 使用 $frontend-crud-coding 给 system/client 页面接入 PUT /system/client/changeStatus,状态字段 status,参考 generator 模板。
```
### 期望执行方式
- API 增加 `changeClientStatus(id, status)`
- types 确认 `status` 类型是 string、number 还是 boolean。
- 表格列用 `el-switch`active/inactive 值跟后端字段类型一致。
- 切换失败时回滚原状态。
- 权限使用 `system:client:edit` 或后端实际权限。
## 推荐的高质量任务描述
```text
使用 $frontend-crud-coding 在当前前端项目中新增 `/system/notice` 列表页增强:
1. 保留现有页面 1. 保留现有页面
2. 新增状态筛选和导出 2. 新增状态筛选和导出
3. API 路径沿用后端现有接口 3. API 路径沿用后端接口
4. 参考 system/user 的工具栏与导出交互 4. 参考 system/config 的工具栏与导出交互
5. 参考 generator 模板补齐缺失 types 定义 5. 参考 boot4 generator 模板补齐缺失 types
``` ```
## 不推荐的任务描述 ## 不推荐的任务描述
下面这种描述太模糊,容易让产物偏离项目:
```text ```text
帮我写个后台页面 帮我写个后台页面
``` ```
更好的写法至少补充: 更好的写法至少补充:
- 模块名 - 模块名
- 业务名 - 业务名
- 后端接口前缀 - 后端接口前缀
- 是新增还是修改 - 是新增还是修改
- 是否需要分页、导出、树表、字典、权限
- 想参考哪个现有页面 - 想参考哪个现有页面
@@ -2,240 +2,145 @@
## 优先参考的代码来源 ## 优先参考的代码来源
- 关联后端工程中的生成器模板: - 当前目标目录下最近似页面、API、types。
`ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/*.vm` - 标准单表:`src/views/demo/demo/index.vue``src/api/demo/demo/index.ts``src/api/demo/demo/types.ts`
`ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/*.vm` - 树表:`src/views/demo/tree/index.vue``src/views/workflow/category/index.vue`
- `src/api/system/user/index.ts` - 复杂系统页:`src/views/system/user/index.vue``src/views/system/role/index.vue``src/views/system/post/index.vue``src/views/system/config/index.vue`
- `src/api/system/user/types.ts` - workflow 页:`src/views/workflow/*``src/api/workflow/*`
- `src/views/system/user/index.vue` - 监控页:`src/views/monitor/*``src/api/monitor/*`
- `src/views/demo/demo/index.vue` - 公共 hooks`src/hooks/async/useLoading.ts``src/hooks/dialog/*``src/hooks/form/*``src/hooks/table/*``src/hooks/tree/*`
- `src/views/system/*` - 后端 generator 模板:`D:\git-sources\Plus相关\RuoYi-Vue-Plus-boot4\ruoyi-modules\ruoyi-gen\src\main\resources\vm\ts\*.vm``vm\vue\*.vm`
- `src/views/workflow/*`
- `src/components/*`
- `src/assets/styles/components/*`
## 基础栈与格式 ## 基础栈与格式
- 技术栈是 Vue 3 + TypeScript + Element Plus + Vite。 - 技术栈是 Vue 3 + TypeScript + Element Plus + Vite + Pinia
- 请求统一通过 `@/utils/request` - 包管理按仓库现状使用 pnpm
- API 返回值类型常用 `AxiosPromise<T>` - `.editorconfig` 要求 UTF-8、LF、2 空格缩进
- 项目默认 2 空格缩进 - 当前仓库没有 `.prettierrc`;格式化使用 `pnpm run fmt`lint 使用 `pnpm lint`
- 使用单引号和分号。
- 不要在一个页面里混入与仓库不一致的格式和写法。 - 不要在一个页面里混入与仓库不一致的格式和写法。
## 决策顺序
写代码时按下面顺序取样:
1. 当前业务目录下最近似页面。
2. 当前模块下最近似 API/types 文件。
3. 当前项目的公共组件、公共工具、公共样式。
4. 关联后端工程的 generator 模板。
5. 通用 Vue 3 / Element Plus 默认写法。
如果上述规则冲突,优先相信当前项目真实代码。
## API 文件规则 ## API 文件规则
- 标准 CRUD 的 API、types、列表页骨架可以先参考后端生成器模板,再根据当前前端项目风格落地 - 标准 API 文件放在 `src/api/<module>/<business>/index.ts`,同目录维护 `types.ts`
- API 文件通常放在 `src/api/<module>/<business>/index.ts` - import 顺序优先跟随附近文件,标准生成页常见形式:
- 同目录维护 `types.ts` `import type { XxxForm, XxxQuery, XxxVO } from '@/api/<module>/<business>/types';`
- 常见 import 形式: `import type { PageResult } from '@/api/types';`
`import type { AxiosPromise } from '@/utils/api-types';`
`import request from '@/utils/request';` `import request from '@/utils/request';`
`import { AxiosPromise } from 'axios';` - 不要从 `axios` 引入 `AxiosPromise`
`import { XxxForm, XxxQuery, XxxVO } from './types';` - 列表分页接口通常返回 `AxiosPromise<PageResult<XxxVO>>`
`import { PageResult } from '@/api/types';` - 树表列表接口通常返回 `AxiosPromise<XxxVO[]>`
- 列表接口通常返回 `AxiosPromise<PageResult<XxxVO>>` - 详情接口返回 `AxiosPromise<XxxVO>`;复杂详情返回单独的 `InfoVO`
- 详情接口返回 `AxiosPromise<XxxVO>` 或更复杂的 `InfoVO` - 标准函数命名:
- 特殊请求参数沿用现有实现,例如: `listXxx` -> `GET /<module>/<business>/list`
`parseStrEmpty(userId)` `getXxx` -> `GET /<module>/<business>/{id}`
`headers: { isEncrypt: true, repeatSubmit: false }` `addXxx` -> `POST /<module>/<business>`
`params` 用于 query string`data` 用于 body。 `updateXxx` -> `PUT /<module>/<business>`
- 当前仓库部分模块会在文件底部 `export default { ... }`,已有模块使用这种形式时继续保持一致。 `delXxx` -> `DELETE /<module>/<business>/{id or ids}`
`changeXxxStatus` -> `PUT /<module>/<business>/changeStatus`
### API 文件建议结构 - query string 用 `params`,请求体用 `data`
- 加密、防重复提交等 headers 直接写在请求配置里,例如用户重置密码中的 `isEncrypt``repeatSubmit`
标准 CRUD 一般按这个顺序组织: - 当前仓库有些 API 使用 `export const`,有些使用 `export function`;新增标准 CRUD 优先跟随 generator 和相邻模块。
- 只有相邻模块已有 `export default { ... }` 聚合时才新增默认导出。
1. import 区
2. 列表接口
3. 详情接口
4. 新增接口
5. 修改接口
6. 删除接口
7. 特殊接口
8. 可选的 `export default`
### API 常见判断
- 如果后端是列表分页接口,前端通常返回 `AxiosPromise<PageResult<XxxVO>>`
- 如果后端返回复合结构,例如 `user + roles + posts`,单独定义 `InfoVO`
- 如果接口需要加密或关闭重复提交,直接在 `headers` 里表达,不要另起封装。
## 类型文件规则 ## 类型文件规则
- 类型文件通常定义 `Query``VO``Form`,必要时补 `InfoVO``ResetPwdForm` 等扩展类型。 - 标准类型定义 `VO``Form``Query`,必要时补 `InfoVO``TreeVO``ResetPwdForm` 等扩展类型。
- `Query` 一般继承 `PageQuery` - `Form` 通常继承 `BaseEntity`
- `VO` 常继承 `BaseEntity` - 非树表 `Query` 常继承 `PageQuery`
- ID 字段通常使用 `string | number` - 树表 `Query` 通常不继承 `PageQuery`
- 列表页多选 ID 常用 `Array<string | number>` - ID 字段通常使用 `string | number`,批量删除参数使用 `string | number | Array<string | number>`
- 数组字段在表单里常直接用 `string[]``number[]` 或宽松类型,优先跟随现有模块 - Java 数值类型映射为 `number`Boolean 映射为 `boolean`,日期/文本默认 `string`
- 日期范围查询保留 `params?: any`,不要因为它看起来宽松就删掉。
### 类型拆分建议 - 列表对象、表单对象、查询对象职责分开;字段不一致时不要强行复用一个接口。
- 能明确写出类型时不要用 `any`;组件库、字典或历史接口确实无法收窄时再保留。
- `VO` 面向列表和详情展示。
- `Form` 面向新增和编辑。
- `Query` 面向列表筛选。
- `InfoVO` 面向详情页、编辑页、弹窗预加载等复合返回结构。
### 类型字段策略
- 能明确写出类型时,不要偷懒用 `any`
- 只有在当前模块已有宽松写法或后端返回非常不稳定时,才保留 `any`
- 如果列表和表单字段明显不同,不要强行复用一个接口类型。
## Vue 页面结构规则 ## Vue 页面结构规则
- 标准 CRUD 页可先参考生成器的 `index.vue.vm` 骨架,再按本仓库现有页面补强。
- 页面优先使用 `<script setup name="Xxx" lang="ts">` - 页面优先使用 `<script setup name="Xxx" lang="ts">`
- 常见列表页结构: - 标准根节点使用 `class="p-2 app-container <module>-<business>-page"`;已有页面是特殊布局时保持原样。
搜索区卡片、表格区卡片、工具栏、分页、编辑弹窗。 - 标准列表页结构:
- 常见页面状态包括: 搜索卡片 `search-panel`
`loading``showSearch``ids``single``multiple``total` 表格卡片 `table-panel`
- 表单和查询对象通常通过 `reactive<PageData<Form, Query>>({...})` 管理。 工具栏 `toolbar-shell`
- 弹窗状态通常使用: 表格 `data-table`
`const dialog = reactive<DialogOption>({ visible: false, title: '' });` `right-toolbar`
- 表单 ref 通常命名为 `queryFormRef``xxxFormRef` `pagination`
- 复杂页面可补充树面板、导入弹窗、子弹窗、路由跳转逻辑。 新增/编辑 `el-dialog`
- 搜索区通过 `useSearchToggle` 控制 `showSearch`,头部点击切换。
### 标准页面骨架 - 列表 loading 通过 `useLoading(true)``withLoading`
- 选择状态通过 `useTableSelection<XxxVO>(item => item.id)` 返回 `ids``single``multiple``handleSelectionChange`
标准页面通常包含这些区域: - 表单弹窗优先使用 `useFormDialog({ form, formRef, initialFormData })`,返回 `dialog``resetForm``openDialog``showDialog``closeDialog`
- 仅需要简单弹窗状态或一个页面多个弹窗时使用 `useDialogState`
1. 搜索区 - 日期范围查询优先使用 `useDateRangeQuery()`;带后端参数名时使用 `useDateRangeQuery('CreateTime')` 等相邻页面模式。
2. 表格区 - 查询和表单状态通常放在 `reactive<PageData<Form, Query>>({ form, queryParams, rules })`,再 `toRefs(data)`
3. 工具栏
4. 分页
5. 编辑弹窗
复杂页面可以额外增加:
- 左侧树筛选
- 导入弹窗
- 二级对话框
- 独立详情页
- 路由跳转按钮
- 列显隐控制
### 页面命名建议
- 页面组件名通常为业务名,例如 `name="User"``name="Demo"`
- 页面根类名尽量带模块语义,例如:
`system-user-page`
`demo-demo-page`
`workflow-category-page`
## 页面行为规则 ## 页面行为规则
- `getList` 负责发起列表请求、处理 loading、回填 `rows` `total` - `getList` 负责设置 loading、调用列表接口、回填列表`total`
- `handleQuery` 先把 `pageNum` 置为 `1`,再重新查询 - `handleQuery` 先把 `queryParams.value.pageNum = 1`,再调用 `getList()`;树表无分页时只调用 `getList()`
- `resetQuery` 负责清空查询表单、日期范围、树节点选择,然后重新加载 - `resetQuery` 使用 `useSearchReset`,分页页传 `pageNumKey: 'pageNum'`,需要时传 `pageSizeKey``resetExtras`
- `handleSelectionChange` 更新 `ids``single``multiple` - `handleAdd` 使用 `openDialog('添加xxx')`;如果有树/联动选项,打开前后按现有页面加载选项
- `handleAdd` 重置表单并打开新增弹窗 - `handleUpdate``reset()`,再按行或 `ids.value[0]` 查详情,`Object.assign(form.value, res.data)`,最后 `showDialog('修改xxx')`
- `handleUpdate` 查详情后回填表单并打开编辑弹窗 - `submitForm` 表单校验通过后设置 `buttonLoading`,根据主键判断新增或修改,成功后 `modal.msgSuccess('操作成功')`、关闭弹窗、刷新列表
- `submitForm` 使用表单校验,通过后调用新增或修改接口,再提示成功并刷新列表 - `handleDelete` 使用 `modal.confirm(...)` 二次确认,再调用删除接口,成功提示并刷新。
- `handleDelete` 通常使用 `proxy?.$modal.confirm(...)` 二次确认 - `handleExport` 使用 `requestDownload('<module>/<business>/export', { ...queryParams.value }, '<business>_<timestamp>.xlsx')`
- `handleExport` 使用 `proxy?.download(...)` - 状态切换失败时要把 switch 值回滚,参考 generator 模板和现有 `system/user``system/role`
- 日期范围查询沿用 `proxy?.addDateRange(queryParams.value, dateRange.value)` - 导入上传使用 `globalHeaders()``import.meta.env.VITE_APP_BASE_API``ElUpload`,优先参考 `system/user` 或流程定义页面
- 需要更稳妥地处理确认框或异步异常时,可沿用 `await-to-js``to(...)` 风格。
### 页面逻辑建议
- 新增和编辑优先共用一套弹窗和表单。
- `reset()``cancel()` 分开写,避免关闭弹窗时状态残留。
- `handleUpdate()` 先查详情再 `Object.assign(form.value, res.data)`
- 删除、状态切换、解锁、重置密码这类危险操作优先保留确认提示。
- 列表页只做列表页职责,复杂复合逻辑优先拆到子组件或独立页面。
## 字典、权限与公共工具 ## 字典、权限与公共工具
- 字典通常通过 - 字典使用 `useDict`
`const { xxx_dict } = toRefs<any>(proxy?.useDict('xxx_dict'));` `const { sys_normal_disable } = toRefs<any>(useDict('sys_normal_disable'));`
- 权限指令以仓库现状为准,存在 `v-hasPermi``v-has-permi` 两种写法;新增代码优先跟随所在目录附近文件,不要在同一文件里混用新的变体 - 新增代码默认使用当前项目主流 `v-hasPermi`
- 常用公共能力: - 如果正在修改的文件已经混用或使用 `v-has-permi`,保持同文件现状,不为统一写法而重排无关代码。
`proxy?.$modal` - `el-dropdown-item` 延迟加载导致权限指令不可靠时,使用 `v-if="checkPermi([...])"`,参考 `system/user`
`proxy?.download` - 常用工具:
`proxy?.useDict` `modal` from `@/plugins/modal`
`proxy?.getConfigKey` `download as requestDownload` from `@/utils/request`
`checkPermi` `useDict` from `@/utils/dict`
`useUserStore` `checkPermi` from `@/utils/permission`
`handleTree``parseStrEmpty` from `@/utils/ruoyi`
### 权限规则
- 所有增删改导入导出按钮都先看附近页面是否有权限控制。
- 新按钮默认补权限指令,除非它是纯展示行为。
- 如果同目录页面使用 `v-hasPermi`,新代码优先继续用 `v-hasPermi`
- 如果同目录页面使用 `v-has-permi`,新代码优先继续用 `v-has-permi`
## 组件与样式规则 ## 组件与样式规则
- 优先复用公共组件: - 优先复用公共组件:`right-toolbar``pagination``DictTag` / `dict-tag``ImageUpload` / `image-upload``ImagePreview` / `image-preview``FileUpload` / `file-upload``Editor` / `editor``TreePanel`
`right-toolbar` - 标准页面尽量使用已有页面壳类,不堆大量内联样式。
`pagination` - 复杂页面需要 scoped SCSS 时优先复用:
`ImageUpload`
`ImagePreview`
`FileUpload`
`Editor`
`DictTag`
- 页面样式不要堆大量内联样式,优先沿用仓库里的布局类和组件样式。
- 已有页面使用 SCSS 模块片段时,继续沿用:
`@use '@/assets/styles/components/page-shell' as pageShell;` `@use '@/assets/styles/components/page-shell' as pageShell;`
`@include pageShell.xxx;` 再按现有 mixin 使用。
- 类名命名保持模块化,例如: - 不要为了单页需求修改全局组件样式。
`system-user-page` - 类名保持模块语义:`system-client-page``workflow-category-page``demo-demo-page`
`demo-demo-page`
`table-panel`
`search-panel`
`toolbar-shell`
### 样式落点建议 ## 树表规则
- 页面只需要轻量调整时,优先复用已有通用类 - 树表列表接口通常返回数组,页面通过 `handleTree<T>(res.data, 'id', 'parentId')` 组树
- 页面结构明显复杂时,优先在 `<style lang="scss" scoped>` 中通过 `@use` 复用组件样式片段 - 使用 `row-key``:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"`
- 不要为了单页需求破坏全局组件样式 - 展开/折叠使用 `useTreeTableExpand`
- 表单中上级节点使用 `el-tree-select`
- 新增子节点时从当前行回填 `parentId`
- 删除确认文案优先使用业务名称,而不是批量 ID 文案。
## 与生成器模板的关系 ## 与生成器模板的关系
- 关联后端工程生成器给出的前端结构可以作为起点,但真实页面通常更完整,包含: - generator 模板是标准骨架,不是最终答案。
树筛选、列显隐、导入导出、更多操作、SCSS 页面壳、复杂表单校验、独立子页面 - 当前前端项目已经把 generator 风格升级为 hooks 版:`useLoading``useFormDialog``useSearchReset``useTableSelection``useDateRangeQuery`
- 因此新增页面时,不要只满足“能跑”,要先看所在模块已有页面的复杂度和 UI 组织方式 - 新增标准 CRUD 时,先从 generator 确认字段、权限、导出、状态切换、排序、日期范围等,再落成当前项目的实际页面壳
- 修改已有页面时,不要把现有强业务逻辑替换回 generator 的简化逻辑。
### 什么时候优先看 generator ## 验证规则
- 新增一个标准单表 CRUD 页面时 - 只改文档或 skill:运行 skill 基础校验即可
- 当前项目里还没有这个业务对应页面时 - 改前端 TS/Vue/API/types:优先运行 `pnpm exec vue-tsc --noEmit`
- 你只拿到了后端路由和字段信息时 - 改页面模板、import、权限或较多文件:再运行 `pnpm lint`
- 改公共 hooks、组件、构建相关或大范围页面:再运行 `pnpm build`
### 什么时候优先看现有页面 - 如果验证因为环境、依赖或权限失败,交付时说明失败命令和原因。
- 当前模块已经有同类页面时。
- 页面包含树筛选、导入导出、联动弹窗、路由跳转时。
- 任务是“修改已有页面”而不是“新建页面”时。
## 避免事项 ## 避免事项
- 不要直接把后端仓库里的前端模板原样复制进来 - 不要`axios` 引入 `AxiosPromise`
- 不要跳过 `types.ts`,把类型全堆在页面里 - 不要绕开 `request``requestDownload` 自造请求/下载封装
- 不要绕开 `request` 自己再包一层请求工具 - 不要跳过 `types.ts`,把类型全写在页面里
- 不要引入与仓库现状不一致的 CSS 组织方式 - 不要删除日期范围 `params`、权限指令、导出、导入、树筛选、列显隐等现有能力
- 不要为了省事删掉权限控制、导出、导入、树筛选、日期范围等现有交互能力 - 不要为了“更整洁”重写复杂页面的大块业务逻辑
- 不要在新增标准页里使用与仓库不一致的 UI 壳或状态管理方式。
## 交付前自检
交付前至少检查这些点:
- 页面能否完整走通查询、新增、编辑、删除、导出流程。
- 类型是否与接口返回结构一致。
- 是否保留了原页面已有的权限和交互能力。
- 是否沿用了当前模块已有的组件和样式壳。
- 是否只是“生成器裸页”,如果是,需要继续补齐到当前项目风格。