From 441fb733d892331c1723b5b4bda7f00b1ada3da2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Wed, 3 Jun 2026 14:08:57 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E5=A2=9E=E5=8A=A0=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=94=9F=E6=88=90=E6=A8=A1=E6=9D=BF=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20skill=20=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .codex/skills/frontend-crud-coding/SKILL.md | 20 +- .../frontend-crud-coding/agents/openai.yaml | 4 +- .../references/examples.md | 8 +- .../references/frontend.md | 21 +- gen/ts/api.ts.vm | 100 +++ gen/ts/types.ts.vm | 61 ++ gen/vue/index-tree.vue.vm | 730 ++++++++++++++++++ gen/vue/index.vue.vm | 650 ++++++++++++++++ 8 files changed, 1573 insertions(+), 21 deletions(-) create mode 100644 gen/ts/api.ts.vm create mode 100644 gen/ts/types.ts.vm create mode 100644 gen/vue/index-tree.vue.vm create mode 100644 gen/vue/index.vue.vm diff --git a/.codex/skills/frontend-crud-coding/SKILL.md b/.codex/skills/frontend-crud-coding/SKILL.md index 80eb2cc..1e23211 100644 --- a/.codex/skills/frontend-crud-coding/SKILL.md +++ b/.codex/skills/frontend-crud-coding/SKILL.md @@ -1,11 +1,11 @@ --- name: frontend-crud-coding -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 前端模板。 +description: 在当前 plus-ui-new 前端项目中按真实 Vue 3 + TypeScript + Element Plus + oxlint/oxfmt 代码风格生成或修改页面、API、types、hooks 接入和样式壳。用于新增或修改标准 CRUD 列表页、树表页、系统管理页、监控页、workflow 页面、demo 页面,补齐与后端接口对应的 src/api、types 和 src/views 代码;触发后应先读取适用 references,再阅读目标模块真实代码和项目内 gen 代码生成模板。 --- # 前端编码规范 -先对齐当前前端项目里的真实实现,再参考关联后端工程的代码生成器模板。不要只套通用 Vue 模板,也不要把 generator 模板原样复制进来而忽略当前项目已经演进出的 hooks、页面壳、类型入口和下载方式。 +先对齐当前前端项目里的真实实现,再参考项目内 `gen` 目录下的代码生成模板。不要只套通用 Vue 模板,也不要把 generator 模板原样复制进来而忽略当前项目已经演进出的 hooks、页面壳、类型入口和下载方式。 ## 执行流程 @@ -16,7 +16,11 @@ description: 在当前 plus-ui-new 前端项目中按真实 Vue 3 + TypeScript + - 树表优先看 `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` 模板确认基础骨架。 +4. 新增标准页面前,对照项目内模板确认基础骨架: + - API 模板:`gen/ts/api.ts.vm` + - types 模板:`gen/ts/types.ts.vm` + - 标准单表页模板:`gen/vue/index.vue.vm` + - 树表页模板:`gen/vue/index-tree.vue.vm` 5. 新增代码时通常同步维护 `src/api///index.ts`、`types.ts`、`src/views///index.vue`。 6. 增强已有页面时只做增量修改,保留原页面的树筛选、导入导出、列显隐、权限、字典、弹窗和路由跳转能力。 7. 修改完成后按影响范围运行验证:优先 `pnpm exec vue-tsc --noEmit`,改动页面或导入时再跑 `pnpm lint`,大范围变更再跑 `pnpm build`。 @@ -33,13 +37,13 @@ description: 在当前 plus-ui-new 前端项目中按真实 Vue 3 + TypeScript + 1. 目标目录下最近似页面、API、types 的真实实现。 2. 当前项目公共 hooks、组件、工具和样式约定。 -3. 关联后端工程中的 generator 前端模板。 +3. 项目内 `gen` 代码生成模板。 4. 通用 Vue 3 / Element Plus 习惯。 也就是说: - 同模块已有页面怎么写,优先怎么写。 -- 没有现成页面时,使用 generator 模板作为骨架,再改成当前项目风格。 +- 没有现成页面时,使用项目内 `gen` 模板作为骨架,再改成当前项目风格。 - 复杂模块不能为了“标准 CRUD”退化成裸模板页。 ## 仓库通用规则 @@ -81,7 +85,7 @@ description: 在当前 plus-ui-new 前端项目中按真实 Vue 3 + TypeScript + ### 1. 标准单表 CRUD -以后端 generator 模板和 `src/views/demo/demo/index.vue` 为主要起点,补齐列表、搜索、分页、新增、编辑、删除、导出、权限、类型和验证。 +以 `gen/vue/index.vue.vm`、`gen/ts/*.vm` 和 `src/views/demo/demo/index.vue` 为主要起点,补齐列表、搜索、分页、新增、编辑、删除、导出、权限、类型和验证。 ### 2. 树表 CRUD @@ -107,7 +111,7 @@ workflow 目录优先参考 `src/views/workflow/*`。流程定义、流程实例 - API 路径、函数名、权限标识与后端接口保持一致。 - 标准页查询、重置、分页、弹窗、提交、删除、导出流程闭环完整。 - 复杂页面保留原有交互能力和业务约束。 -- 代码体现当前项目 hooks、页面壳和下载方式,而不是 generator 裸输出。 +- 代码体现当前项目 hooks、页面壳和下载方式,而不是 `gen` 模板裸输出。 - 交付前说明运行过的验证命令;如果无法验证,说明原因。 ## 快速检查清单 @@ -135,5 +139,5 @@ workflow 目录优先参考 `src/views/workflow/*`。流程定义、流程实例 例如: -- 使用 `$frontend-crud-coding` 为 `/system/client` 补一套标准 CRUD 页面,参考 `demo/demo`、`system/client` 和 boot4 generator 模板。 +- 使用 `$frontend-crud-coding` 为 `/system/client` 补一套标准 CRUD 页面,参考 `gen` 模板、`demo/demo` 和 `system/client`。 - 使用 `$frontend-crud-coding` 修改 `workflow/category` 列表页,增加导出按钮和状态筛选,保持当前 workflow 风格。 diff --git a/.codex/skills/frontend-crud-coding/agents/openai.yaml b/.codex/skills/frontend-crud-coding/agents/openai.yaml index 76e9efe..0999fc7 100644 --- a/.codex/skills/frontend-crud-coding/agents/openai.yaml +++ b/.codex/skills/frontend-crud-coding/agents/openai.yaml @@ -1,7 +1,7 @@ interface: display_name: "前端编码" - short_description: "按 plus-ui-new 真实代码和 boot4 模板编写前端 CRUD" - default_prompt: "使用 $frontend-crud-coding 先读取适用 reference,再按当前 plus-ui-new 真实页面、hooks、API/types 约定和 boot4 generator 模板实现前端修改。" + short_description: "按 plus-ui-new 真实代码和 gen 模板编写前端 CRUD" + default_prompt: "使用 $frontend-crud-coding 先读取适用 reference,再按当前 plus-ui-new 真实页面、hooks、API/types 约定和项目内 gen 模板实现前端修改。" policy: allow_implicit_invocation: true diff --git a/.codex/skills/frontend-crud-coding/references/examples.md b/.codex/skills/frontend-crud-coding/references/examples.md index a87e0f1..e816f1f 100644 --- a/.codex/skills/frontend-crud-coding/references/examples.md +++ b/.codex/skills/frontend-crud-coding/references/examples.md @@ -7,14 +7,14 @@ ```text 使用 $frontend-crud-coding 为 system/client 补一套前端 CRUD 页面。 后端接口已经有 /system/client/list、/system/client/{id}、POST /system/client、PUT /system/client、DELETE /system/client/{ids}。 -请参考 boot4 generator 模板、src/views/demo/demo/index.vue 和现有 system/client 风格实现。 +请参考项目内 gen 模板、src/views/demo/demo/index.vue 和现有 system/client 风格实现。 ``` ### 期望执行方式 - 先看 `src/api/system/client/*` 和 `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`。 +- 对照项目内 `gen/ts/api.ts.vm`、`gen/ts/types.ts.vm`、`gen/vue/index.vue.vm`。 - 生成或修改 `api/index.ts`、`types.ts`、`views/.../index.vue`。 - 使用 `AxiosPromise` from `@/utils/api-types`、`PageResult` from `@/api/types`、`useLoading`、`useFormDialog`、`useSearchReset`、`useTableSelection`。 @@ -88,7 +88,7 @@ ### 用户提问示例 ```text -使用 $frontend-crud-coding 给 system/client 页面接入 PUT /system/client/changeStatus,状态字段 status,参考 generator 模板。 +使用 $frontend-crud-coding 给 system/client 页面接入 PUT /system/client/changeStatus,状态字段 status,参考 gen 模板。 ``` ### 期望执行方式 @@ -107,7 +107,7 @@ 2. 新增状态筛选和导出 3. API 路径沿用后端接口 4. 参考 system/config 的工具栏与导出交互 -5. 参考 boot4 generator 模板补齐缺失 types +5. 参考 gen 模板补齐缺失 types ``` ## 不推荐的任务描述 diff --git a/.codex/skills/frontend-crud-coding/references/frontend.md b/.codex/skills/frontend-crud-coding/references/frontend.md index 2cf6805..8b4d72d 100644 --- a/.codex/skills/frontend-crud-coding/references/frontend.md +++ b/.codex/skills/frontend-crud-coding/references/frontend.md @@ -9,7 +9,11 @@ - workflow 页:`src/views/workflow/*`、`src/api/workflow/*`。 - 监控页:`src/views/monitor/*`、`src/api/monitor/*`。 - 公共 hooks:`src/hooks/async/useLoading.ts`、`src/hooks/dialog/*`、`src/hooks/form/*`、`src/hooks/table/*`、`src/hooks/tree/*`。 -- 后端 generator 模板:`D:\git-sources\Plus相关\RuoYi-Vue-Plus-boot4\ruoyi-modules\ruoyi-gen\src\main\resources\vm\ts\*.vm` 与 `vm\vue\*.vm`。 +- 项目内 generator 模板: + `gen/ts/api.ts.vm` + `gen/ts/types.ts.vm` + `gen/vue/index.vue.vm` + `gen/vue/index-tree.vue.vm` ## 基础栈与格式 @@ -40,7 +44,7 @@ `changeXxxStatus` -> `PUT ///changeStatus` - query string 用 `params`,请求体用 `data`。 - 加密、防重复提交等 headers 直接写在请求配置里,例如用户重置密码中的 `isEncrypt`、`repeatSubmit`。 -- 当前仓库有些 API 使用 `export const`,有些使用 `export function`;新增标准 CRUD 优先跟随 generator 和相邻模块。 +- 当前仓库有些 API 使用 `export const`,有些使用 `export function`;新增标准 CRUD 优先跟随 `gen/ts/api.ts.vm` 和相邻模块。 - 只有相邻模块已有 `export default { ... }` 聚合时才新增默认导出。 ## 类型文件规则 @@ -121,12 +125,15 @@ - 新增子节点时从当前行回填 `parentId`。 - 删除确认文案优先使用业务名称,而不是批量 ID 文案。 -## 与生成器模板的关系 +## 与 gen 模板的关系 -- generator 模板是标准骨架,不是最终答案。 -- 当前前端项目已经把 generator 风格升级为 hooks 版:`useLoading`、`useFormDialog`、`useSearchReset`、`useTableSelection`、`useDateRangeQuery`。 -- 新增标准 CRUD 时,先从 generator 确认字段、权限、导出、状态切换、排序、日期范围等,再落成当前项目的实际页面壳。 -- 修改已有页面时,不要把现有强业务逻辑替换回 generator 的简化逻辑。 +- `gen` 是当前前端项目内的生成模板,优先于外部后端工程拷贝的模板。 +- 新增标准单表页面时读取 `gen/vue/index.vue.vm`、`gen/ts/api.ts.vm`、`gen/ts/types.ts.vm`。 +- 新增树表页面时读取 `gen/vue/index-tree.vue.vm`、`gen/ts/api.ts.vm`、`gen/ts/types.ts.vm`。 +- `gen` 模板是标准骨架,不是最终答案;落地时仍要对照目标模块真实页面和公共 hooks。 +- 当前前端项目已经把生成页升级为 hooks 版:`useLoading`、`useFormDialog`、`useSearchReset`、`useTableSelection`、`useDateRangeQuery`。 +- 新增标准 CRUD 时,先从 `gen` 确认字段、权限、导出、状态切换、排序、日期范围等,再落成当前项目的实际页面壳。 +- 修改已有页面时,不要把现有强业务逻辑替换回 `gen` 的简化逻辑。 ## 验证规则 diff --git a/gen/ts/api.ts.vm b/gen/ts/api.ts.vm new file mode 100644 index 0000000..79205e3 --- /dev/null +++ b/gen/ts/api.ts.vm @@ -0,0 +1,100 @@ +import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types'; +import type { PageResult } from '@/api/types'; +import type { AxiosPromise } from '@/utils/api-types'; +import request from '@/utils/request'; + +/** + * 查询${functionName}列表 + * @param query + * @returns {*} + */ + +export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise> => { + return request({ + url: '/${moduleName}/${businessName}/list', + method: 'get', + params: query + }); +}; + +/** + * 查询${functionName}详细 + * @param ${pkColumn.javaField} + */ +export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'get' + }); +}; + +/** + * 新增${functionName} + * @param data + */ +export const add${BusinessName} = (data: ${BusinessName}Form) => { + return request({ + url: '/${moduleName}/${businessName}', + method: 'post', + data: data + }); +}; + +/** + * 修改${functionName} + * @param data + */ +export const update${BusinessName} = (data: ${BusinessName}Form) => { + return request({ + url: '/${moduleName}/${businessName}', + method: 'put', + data: data + }); +}; + +#if($enableStatus) +/** + * 修改${functionName}状态 + * @param ${pkColumn.javaField} + * @param status + */ +export const change${BusinessName}Status = (${pkColumn.javaField}: string | number, status: #if($statusColumn.javaType == 'String')string#else number#end) => { + return request({ + url: '/${moduleName}/${businessName}/changeStatus', + method: 'put', + data: { + ${pkColumn.javaField}, + ${statusField}: status + } + }); +}; +#end + +#if($enableSort) +/** + * 调整${functionName}排序 + * @param ${pkColumn.javaField} + * @param sortValue + */ +export const update${BusinessName}Sort = (${pkColumn.javaField}: string | number, sortValue: #if($sortColumn.javaType == 'String' || $sortColumn.javaType == 'LocalDateTime')string#else number#end) => { + return request({ + url: '/${moduleName}/${businessName}/updateSort', + method: 'put', + data: { + ${pkColumn.javaField}, + ${sortField}: sortValue + } + }); +}; +#end + +/** + * 删除${functionName} + * @param ${pkColumn.javaField} + */ +export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array) => { + return request({ + url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + method: 'delete' + }); +}; diff --git a/gen/ts/types.ts.vm b/gen/ts/types.ts.vm new file mode 100644 index 0000000..eeef5f5 --- /dev/null +++ b/gen/ts/types.ts.vm @@ -0,0 +1,61 @@ +export interface ${BusinessName}VO { +#foreach ($column in $columns) +#if($column.list) + /** + * $column.columnComment + */ + $column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#if($column.htmlType == "imageUpload") + /** + * ${column.columnComment}Url + */ + ${column.javaField}Url: string; +#end +#end +#end +#if ($table.tree) + /** + * 子对象 + */ + children: ${BusinessName}VO[]; +#end +} + +export interface ${BusinessName}Form extends BaseEntity { +#foreach ($column in $columns) +#if($column.insert || $column.edit) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end +} + +export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{ + +#foreach ($column in $columns) +#if($column.query) + /** + * $column.columnComment + */ + $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number; + #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number; + #elseif($column.javaType == 'Boolean') boolean; + #else string; + #end +#end +#end + /** + * 日期范围参数 + */ + params?: any; +} diff --git a/gen/vue/index-tree.vue.vm b/gen/vue/index-tree.vue.vm new file mode 100644 index 0000000..91f52bd --- /dev/null +++ b/gen/vue/index-tree.vue.vm @@ -0,0 +1,730 @@ + + +#set($needAddDateRange = false) +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($needAddDateRange = true) +#end +#end + diff --git a/gen/vue/index.vue.vm b/gen/vue/index.vue.vm new file mode 100644 index 0000000..8773322 --- /dev/null +++ b/gen/vue/index.vue.vm @@ -0,0 +1,650 @@ + + +#set($needAddDateRange = false) +#foreach ($column in $columns) +#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") +#set($needAddDateRange = true) +#end +#end +