mirror of
https://gitee.com/JavaLionLi/plus-ui.git
synced 2026-09-15 08:25:10 +08:00
refactor gen templates to freemarker
This commit is contained in:
parent
117bb0ef8c
commit
ef9d9482c4
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: frontend-crud-coding
|
name: frontend-crud-coding
|
||||||
description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript + Umi Max + Ant Design ProComponents + oxlint/oxfmt 代码风格生成或修改页面、API、types、hooks 接入、样式和项目内置 gen/*.vm 代码生成模板。用于新增或修改标准 CRUD 列表页、树表页、系统管理页、监控页、workflow 页面、demo 页面,补齐与 RuoYi-Vue-Plus boot4 后端接口对应的 src/api、types 和 src/pages 代码,或维护 gen/api.ts.vm、gen/types.ts.vm、gen/index.tsx.vm、gen/index-tree.tsx.vm;触发后应先读取适用 references,再阅读目标模块真实代码和项目内置 gen 模板。
|
description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript + Umi Max + Ant Design ProComponents + oxlint/oxfmt 代码风格生成或修改页面、API、types、hooks 接入、样式和项目内置 gen/*.ftl 代码生成模板。用于新增或修改标准 CRUD 列表页、树表页、系统管理页、监控页、workflow 页面、demo 页面,补齐与 RuoYi-Vue-Plus boot4 后端接口对应的 src/api、types 和 src/pages 代码,或维护 gen/api.ts.ftl、gen/types.ts.ftl、gen/index.tsx.ftl、gen/index-tree.tsx.ftl;触发后应先读取适用 references,再阅读目标模块真实代码和项目内置 gen 模板。
|
||||||
---
|
---
|
||||||
|
|
||||||
# 前端编码规范
|
# 前端编码规范
|
||||||
@ -16,10 +16,10 @@ description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript
|
|||||||
- 树表优先看 `src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
- 树表优先看 `src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
||||||
- 系统复杂页优先看 `src/pages/system/user/index.tsx`、`system/role`、`system/post`、`system/config`。
|
- 系统复杂页优先看 `src/pages/system/user/index.tsx`、`system/role`、`system/post`、`system/config`。
|
||||||
- workflow 业务页优先看 `src/pages/workflow/*` 与 `src/api/workflow/*` 同类页面。
|
- workflow 业务页优先看 `src/pages/workflow/*` 与 `src/api/workflow/*` 同类页面。
|
||||||
4. 新增或维护代码生成能力时,优先阅读当前仓库 `gen/api.ts.vm`、`gen/types.ts.vm`、`gen/index.tsx.vm`、`gen/index-tree.tsx.vm`。这些是 React 版内置生成模板,页面模板必须输出当前项目 React/TSX 风格。
|
4. 新增或维护代码生成能力时,优先阅读当前仓库 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。这些是 React 版内置 FreeMarker 生成模板,页面模板必须输出当前项目 React/TSX 风格。
|
||||||
5. 需要从 Vue 版本迁移经验时,参考 `D:\git-sources\Plus相关\plus-ui-new\.codex\skills\frontend-crud-coding` 和 `.claude\agents`,只吸收任务分型、增量修改和自检原则。
|
5. 需要从 Vue 版本迁移经验时,参考 `D:\git-sources\Plus相关\plus-ui-new\.codex\skills\frontend-crud-coding` 和 `.claude\agents`,只吸收任务分型、增量修改和自检原则。
|
||||||
6. 新增标准页面前,可以对照后端工程 `D:\git-sources\Plus相关\RuoYi-Vue-Plus-boot4\ruoyi-modules\ruoyi-gen\src\main\resources\vm` 确认字段、权限和导出能力,但输出和 `gen/` 模板必须保持 React 项目风格。
|
6. 新增标准页面前,可以对照后端工程 `D:\git-sources\Plus相关\RuoYi-Vue-Plus-boot4\ruoyi-modules\ruoyi-gen\src\main\resources\fm` 确认字段、权限和导出能力,但输出和 `gen/` 模板必须保持 React 项目风格。
|
||||||
7. 新增代码时通常同步维护 `src/api/<module>/<business>/index.ts`、`types.ts`、`src/pages/<module>/<business>/index.tsx`;如果是生成模板优化,同步维护 `gen/` 对应 `.vm`。
|
7. 新增代码时通常同步维护 `src/api/<module>/<business>/index.ts`、`types.ts`、`src/pages/<module>/<business>/index.tsx`;如果是生成模板优化,同步维护 `gen/` 对应 `.ftl`。
|
||||||
8. 增强已有页面时只做增量修改,保留原页面的树筛选、导入导出、列显隐、权限、字典、弹窗、抽屉和路由跳转能力。
|
8. 增强已有页面时只做增量修改,保留原页面的树筛选、导入导出、列显隐、权限、字典、弹窗、抽屉和路由跳转能力。
|
||||||
9. 修改完成后按影响范围运行验证:优先 `pnpm exec tsc --noEmit` 或 `pnpm lint`;大范围页面、公共组件、构建配置变更再跑 `pnpm build`。
|
9. 修改完成后按影响范围运行验证:优先 `pnpm exec tsc --noEmit` 或 `pnpm lint`;大范围页面、公共组件、构建配置变更再跑 `pnpm build`。
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ description: 在当前 plus-ui-react 前端项目中按真实 React + TypeScript
|
|||||||
|
|
||||||
1. 目标目录下最近似页面、API、types 的真实实现。
|
1. 目标目录下最近似页面、API、types 的真实实现。
|
||||||
2. 当前项目公共 hooks、组件、工具、样式和请求封装约定。
|
2. 当前项目公共 hooks、组件、工具、样式和请求封装约定。
|
||||||
3. 当前项目内置 `gen/*.vm` React 代码生成模板。
|
3. 当前项目内置 `gen/*.ftl` React 代码生成模板。
|
||||||
4. Vue 参考项目 `.codex` / `.claude` 中的任务分型和工作流。
|
4. Vue 参考项目 `.codex` / `.claude` 中的任务分型和工作流。
|
||||||
5. 关联后端工程 generator 模板。
|
5. 关联后端工程 generator 模板。
|
||||||
6. 通用 React / Ant Design ProComponents 习惯。
|
6. 通用 React / Ant Design ProComponents 习惯。
|
||||||
@ -108,12 +108,12 @@ workflow 目录优先参考 `src/pages/workflow/*`。流程定义、流程实例
|
|||||||
|
|
||||||
### 6. 维护 React 生成模板
|
### 6. 维护 React 生成模板
|
||||||
|
|
||||||
模板只放在当前仓库 `gen/` 下,除非用户明确要求写入 boot4 后端工程。维护时保持 Velocity 变量和文件名不变:
|
模板只放在当前仓库 `gen/` 下,除非用户明确要求写入 boot4 后端工程。维护时保持 FreeMarker 变量和文件名不变:
|
||||||
|
|
||||||
- `gen/api.ts.vm`
|
- `gen/api.ts.ftl`
|
||||||
- `gen/types.ts.vm`
|
- `gen/types.ts.ftl`
|
||||||
- `gen/index.tsx.vm`
|
- `gen/index.tsx.ftl`
|
||||||
- `gen/index-tree.tsx.vm`
|
- `gen/index-tree.tsx.ftl`
|
||||||
|
|
||||||
模板内容必须生成当前 React 项目代码,并优先使用已有公共工具:`useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useTableSelection`、`useTableExport`、`confirmAction`、`toPageQuery`、`toTableData`、`handleTree`、`formatDateTimeFields`、`toDayjsFields`。不要把 Vue 模板、Element Plus 组件或 `src/views` 路径写入这些模板。
|
模板内容必须生成当前 React 项目代码,并优先使用已有公共工具:`useDateRangeQuery`、`dictOptions`、`useTreeTableExpand`、`useTableSelection`、`useTableExport`、`confirmAction`、`toPageQuery`、`toTableData`、`handleTree`、`formatDateTimeFields`、`toDayjsFields`。不要把 Vue 模板、Element Plus 组件或 `src/views` 路径写入这些模板。
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
- 先看 `src/api/system/client/*` 和 `src/pages/system/client/index.tsx` 是否已存在。
|
- 先看 `src/api/system/client/*` 和 `src/pages/system/client/index.tsx` 是否已存在。
|
||||||
- 再看 `src/pages/demo/demo/index.tsx` 的标准 React CRUD 骨架。
|
- 再看 `src/pages/demo/demo/index.tsx` 的标准 React CRUD 骨架。
|
||||||
- 新增标准生成能力时优先对照当前仓库 `gen/index.tsx.vm`、`gen/api.ts.vm`、`gen/types.ts.vm`;boot4 generator 只用于核对字段、权限和接口。
|
- 新增标准生成能力时优先对照当前仓库 `gen/index.tsx.ftl`、`gen/api.ts.ftl`、`gen/types.ts.ftl`;boot4 generator 只用于核对字段、权限和接口。
|
||||||
- 生成或修改 `api/index.ts`、`types.ts`、`pages/.../index.tsx`。
|
- 生成或修改 `api/index.ts`、`types.ts`、`pages/.../index.tsx`。
|
||||||
- 使用 `request<R<PageResult<T>>>`、`ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
- 使用 `request<R<PageResult<T>>>`、`ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
||||||
- 日期范围、字典 options、确认框、loading 等优先使用 `useDateRangeQuery`、`dictOptions`、`confirmAction`、`useLoading` 等项目工具。
|
- 日期范围、字典 options、确认框、loading 等优先使用 `useDateRangeQuery`、`dictOptions`、`confirmAction`、`useLoading` 等项目工具。
|
||||||
@ -46,8 +46,8 @@
|
|||||||
|
|
||||||
### 期望执行方式
|
### 期望执行方式
|
||||||
|
|
||||||
- 读取 `gen/api.ts.vm`、`gen/types.ts.vm`、`gen/index.tsx.vm`、`gen/index-tree.tsx.vm`。
|
- 读取 `gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
||||||
- 保持 Velocity 变量、宏和文件名不变。
|
- 保持 FreeMarker 变量、宏和文件名不变。
|
||||||
- 普通表模板继续使用 `useTableSelection`、`useTableExport`、`useDateRangeQuery`、`dictOptions`、`confirmAction`。
|
- 普通表模板继续使用 `useTableSelection`、`useTableExport`、`useDateRangeQuery`、`dictOptions`、`confirmAction`。
|
||||||
- 树表模板继续使用 `handleTree`、`filterTree`、`useTreeTableExpand`、`dictOptions`。
|
- 树表模板继续使用 `handleTree`、`filterTree`、`useTreeTableExpand`、`dictOptions`。
|
||||||
- 输出仍是 React TSX 项目代码,不写 Vue `src/views`、Element Plus 或 `AxiosPromise`。
|
- 输出仍是 React TSX 项目代码,不写 Vue `src/views`、Element Plus 或 `AxiosPromise`。
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
## 优先参考的代码来源
|
## 优先参考的代码来源
|
||||||
|
|
||||||
- 当前目标目录下最近似页面、API、types。
|
- 当前目标目录下最近似页面、API、types。
|
||||||
- 当前仓库内置 React 生成模板:`gen/api.ts.vm`、`gen/types.ts.vm`、`gen/index.tsx.vm`、`gen/index-tree.tsx.vm`。
|
- 当前仓库内置 React 生成模板:`gen/api.ts.ftl`、`gen/types.ts.ftl`、`gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl`。
|
||||||
- 标准单表:`src/pages/demo/demo/index.tsx`、`src/api/demo/demo/index.ts`、`src/api/demo/demo/types.ts`。
|
- 标准单表:`src/pages/demo/demo/index.tsx`、`src/api/demo/demo/index.ts`、`src/api/demo/demo/types.ts`。
|
||||||
- 树表:`src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
- 树表:`src/pages/demo/tree/index.tsx`、`src/pages/workflow/category/index.tsx`。
|
||||||
- 复杂系统页:`src/pages/system/user/index.tsx`、`src/pages/system/role/index.tsx`、`src/pages/system/post/index.tsx`、`src/pages/system/config/index.tsx`。
|
- 复杂系统页:`src/pages/system/user/index.tsx`、`src/pages/system/role/index.tsx`、`src/pages/system/post/index.tsx`、`src/pages/system/config/index.tsx`。
|
||||||
@ -127,9 +127,9 @@
|
|||||||
|
|
||||||
## 与 gen 模板、Vue 参考项目和后端生成器的关系
|
## 与 gen 模板、Vue 参考项目和后端生成器的关系
|
||||||
|
|
||||||
- 当前仓库 `gen/*.vm` 是 React 版内置代码生成模板,是维护生成能力时的第一参考。
|
- 当前仓库 `gen/*.ftl` 是 React 版内置代码生成模板,是维护生成能力时的第一参考。
|
||||||
- `gen/index.tsx.vm`、`gen/index-tree.tsx.vm` 内容必须生成 React TSX 页面。
|
- `gen/index.tsx.ftl`、`gen/index-tree.tsx.ftl` 内容必须生成 React TSX 页面。
|
||||||
- 修改公共 hooks/工具后,如果它们能简化标准生成页,要同步评估 `gen/*.vm` 是否需要更新。
|
- 修改公共 hooks/工具后,如果它们能简化标准生成页,要同步评估 `gen/*.ftl` 是否需要更新。
|
||||||
- Vue skill 和 `.claude/agents` 提供的是任务分型、优先级、增量修改、自检方式,不是 React 实现模板。
|
- Vue skill 和 `.claude/agents` 提供的是任务分型、优先级、增量修改、自检方式,不是 React 实现模板。
|
||||||
- boot4 后端 generator 模板可用于确认字段、权限、导出、状态切换、排序、日期范围等,但不是最终答案。
|
- boot4 后端 generator 模板可用于确认字段、权限、导出、状态切换、排序、日期范围等,但不是最终答案。
|
||||||
- 当前 React 项目的核心骨架是 `ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
- 当前 React 项目的核心骨架是 `ProTable`、`ModalForm`、`RowActions`、`useTableSelection`、`useTableExport`。
|
||||||
@ -137,7 +137,7 @@
|
|||||||
|
|
||||||
## 验证规则
|
## 验证规则
|
||||||
|
|
||||||
- 只改文档、skill 或 `gen/*.vm` 模板:至少运行 skill 基础校验或 `git diff --check`;如果模板改动依赖项目工具,优先再跑 `pnpm lint`。
|
- 只改文档、skill 或 `gen/*.ftl` 模板:至少运行 skill 基础校验或 `git diff --check`;如果模板改动依赖项目工具,优先再跑 `pnpm lint`。
|
||||||
- 改前端 TS/TSX/API/types:优先运行 `pnpm exec tsc --noEmit` 或 `pnpm lint`。
|
- 改前端 TS/TSX/API/types:优先运行 `pnpm exec tsc --noEmit` 或 `pnpm lint`。
|
||||||
- 改页面、import、权限或较多文件:运行 `pnpm lint`。
|
- 改页面、import、权限或较多文件:运行 `pnpm lint`。
|
||||||
- 改公共 hooks、组件、构建相关或大范围页面:再运行 `pnpm build`。
|
- 改公共 hooks、组件、构建相关或大范围页面:再运行 `pnpm build`。
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { #if(!$table.tree)PageResult, #end R } from '@/api/types';
|
import type { <#if !table.tree>PageResult, </#if> R } from '@/api/types';
|
||||||
import request from '@/api/request';
|
import request from '@/api/request';
|
||||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types';
|
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types';
|
||||||
|
|
||||||
@ -6,7 +6,7 @@ import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } fro
|
|||||||
* 查询${functionName}列表
|
* 查询${functionName}列表
|
||||||
*/
|
*/
|
||||||
export function list${BusinessName}(query?: ${BusinessName}Query) {
|
export function list${BusinessName}(query?: ${BusinessName}Query) {
|
||||||
return request<R<#if($table.tree)${BusinessName}VO[]#else PageResult<${BusinessName}VO>#end>>({
|
return request<R<<#if table.tree>${BusinessName}VO[]<#else> PageResult<${BusinessName}VO></#if>>>({
|
||||||
url: '/${moduleName}/${businessName}/list',
|
url: '/${moduleName}/${businessName}/list',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params: query
|
params: query
|
||||||
@ -45,13 +45,13 @@ export function update${BusinessName}(data: ${BusinessName}Form) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#if($enableStatus)
|
<#if enableStatus>
|
||||||
/**
|
/**
|
||||||
* 修改${functionName}状态
|
* 修改${functionName}状态
|
||||||
*/
|
*/
|
||||||
export function change${BusinessName}Status(
|
export function change${BusinessName}Status(
|
||||||
${pkColumn.javaField}: string | number,
|
${pkColumn.javaField}: string | number,
|
||||||
${statusField}: #if($statusColumn.javaType == 'Boolean')boolean#elseif($statusColumn.javaType == 'Integer' || $statusColumn.javaType == 'Long')number#else string#end
|
${statusField}: <#if statusColumn.javaType == 'Boolean'>boolean<#elseif statusColumn.javaType == 'Integer' || statusColumn.javaType == 'Long'>number<#else> string</#if>
|
||||||
) {
|
) {
|
||||||
return request<R>({
|
return request<R>({
|
||||||
url: '/${moduleName}/${businessName}/changeStatus',
|
url: '/${moduleName}/${businessName}/changeStatus',
|
||||||
@ -63,14 +63,14 @@ export function change${BusinessName}Status(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#end
|
</#if>
|
||||||
#if($enableSort)
|
<#if enableSort>
|
||||||
/**
|
/**
|
||||||
* 调整${functionName}排序
|
* 调整${functionName}排序
|
||||||
*/
|
*/
|
||||||
export function update${BusinessName}Sort(
|
export function update${BusinessName}Sort(
|
||||||
${pkColumn.javaField}: string | number,
|
${pkColumn.javaField}: string | number,
|
||||||
${sortField}: #if($sortColumn.javaType == 'LocalDateTime' || $sortColumn.javaType == 'String')string#else number#end
|
${sortField}: <#if sortColumn.javaType == 'LocalDateTime' || sortColumn.javaType == 'String'>string<#else> number</#if>
|
||||||
) {
|
) {
|
||||||
return request<R>({
|
return request<R>({
|
||||||
url: '/${moduleName}/${businessName}/updateSort',
|
url: '/${moduleName}/${businessName}/updateSort',
|
||||||
@ -82,7 +82,7 @@ export function update${BusinessName}Sort(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#end
|
</#if>
|
||||||
/**
|
/**
|
||||||
* 删除${functionName}
|
* 删除${functionName}
|
||||||
*/
|
*/
|
||||||
@ -92,3 +92,7 @@ export function del${BusinessName}(${pkColumn.javaField}: string | number | Arra
|
|||||||
method: 'delete'
|
method: 'delete'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,66 +1,22 @@
|
|||||||
#set($needDict = $dicts != '')
|
import { DeleteOutlined<#if enableExport>, DownloadOutlined</#if>, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons';
|
||||||
#set($needImagePreview = false)
|
|
||||||
#set($needImageUpload = false)
|
|
||||||
#set($needFileUpload = false)
|
|
||||||
#set($needEditor = false)
|
|
||||||
#set($needCheckbox = false)
|
|
||||||
#set($needSelect = false)
|
|
||||||
#set($needTextArea = false)
|
|
||||||
#set($needDigit = false)
|
|
||||||
#set($needDateField = false)
|
|
||||||
#set($needSwitchField = false)
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if($column.list && $column.htmlType == "imageUpload")
|
|
||||||
#set($needImagePreview = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "imageUpload")
|
|
||||||
#set($needImageUpload = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "fileUpload")
|
|
||||||
#set($needFileUpload = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "editor")
|
|
||||||
#set($needEditor = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
|
|
||||||
#set($needCheckbox = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit || $column.query) && ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch"))
|
|
||||||
#set($needSelect = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "textarea")
|
|
||||||
#set($needTextArea = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "inputNumber")
|
|
||||||
#set($needDigit = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
|
|
||||||
#set($needDateField = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit || $column.list) && $column.htmlType == "switch")
|
|
||||||
#set($needSwitchField = true)
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
#macro(comment $column)#set($idx=$column.columnComment.indexOf("("))#if($idx != -1)$column.columnComment.substring(0, $idx)#else$column.columnComment#end#end
|
|
||||||
import { DeleteOutlined#if($enableExport), DownloadOutlined#end, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons';
|
|
||||||
import {
|
import {
|
||||||
ModalForm,
|
ModalForm,
|
||||||
PageContainer,
|
PageContainer,
|
||||||
#if($needCheckbox)
|
<#if needCheckbox>
|
||||||
ProFormCheckbox,
|
ProFormCheckbox,
|
||||||
#end
|
</#if>
|
||||||
#if($needDateField)
|
<#if needDateField>
|
||||||
ProFormDateTimePicker,
|
ProFormDateTimePicker,
|
||||||
#end
|
</#if>
|
||||||
#if($needDigit)
|
<#if needDigit>
|
||||||
ProFormDigit,
|
ProFormDigit,
|
||||||
#end
|
</#if>
|
||||||
#if($needSelect)
|
<#if needSelect>
|
||||||
ProFormSelect,
|
ProFormSelect,
|
||||||
#end
|
</#if>
|
||||||
#if($needTextArea)
|
<#if needTextArea>
|
||||||
ProFormTextArea,
|
ProFormTextArea,
|
||||||
#end
|
</#if>
|
||||||
ProFormText,
|
ProFormText,
|
||||||
ProFormTreeSelect,
|
ProFormTreeSelect,
|
||||||
ProTable,
|
ProTable,
|
||||||
@ -68,62 +24,62 @@ import {
|
|||||||
type ProColumns
|
type ProColumns
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { useBoolean } from 'ahooks';
|
import { useBoolean } from 'ahooks';
|
||||||
import { Button, Form, message#if($enableStatus || $needSwitchField), Switch#end#if($enableSort), InputNumber#end } from 'antd';
|
import { Button, Form, message<#if enableStatus || needSwitchField>, Switch</#if><#if enableSort>, InputNumber</#if> } from 'antd';
|
||||||
import { useMemo, useRef, useState } from 'react';
|
import { useMemo, useRef, useState } from 'react';
|
||||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||||
import {
|
import {
|
||||||
add${BusinessName},
|
add${BusinessName},
|
||||||
#if($enableStatus)
|
<#if enableStatus>
|
||||||
change${BusinessName}Status,
|
change${BusinessName}Status,
|
||||||
#end
|
</#if>
|
||||||
del${BusinessName},
|
del${BusinessName},
|
||||||
get${BusinessName},
|
get${BusinessName},
|
||||||
list${BusinessName},
|
list${BusinessName},
|
||||||
#if($enableSort)
|
<#if enableSort>
|
||||||
update${BusinessName}Sort,
|
update${BusinessName}Sort,
|
||||||
#end
|
</#if>
|
||||||
update${BusinessName}
|
update${BusinessName}
|
||||||
} from '@/api/${moduleName}/${businessName}';
|
} from '@/api/${moduleName}/${businessName}';
|
||||||
#if($needDict)
|
<#if needDict>
|
||||||
import DictTag from '@/components/common/DictTag';
|
import DictTag from '@/components/common/DictTag';
|
||||||
#end
|
</#if>
|
||||||
#if($needFileUpload)
|
<#if needFileUpload>
|
||||||
import FileUpload from '@/components/common/FileUpload';
|
import FileUpload from '@/components/common/FileUpload';
|
||||||
#end
|
</#if>
|
||||||
#if($needImagePreview)
|
<#if needImagePreview>
|
||||||
import ImagePreview from '@/components/common/ImagePreview';
|
import ImagePreview from '@/components/common/ImagePreview';
|
||||||
#end
|
</#if>
|
||||||
#if($needImageUpload)
|
<#if needImageUpload>
|
||||||
import ImageUpload from '@/components/common/ImageUpload';
|
import ImageUpload from '@/components/common/ImageUpload';
|
||||||
#end
|
</#if>
|
||||||
#if($needEditor)
|
<#if needEditor>
|
||||||
import RichTextEditor from '@/components/common/RichTextEditor';
|
import RichTextEditor from '@/components/common/RichTextEditor';
|
||||||
#end
|
</#if>
|
||||||
import RowActions from '@/components/common/RowActions';
|
import RowActions from '@/components/common/RowActions';
|
||||||
#if($needDict)
|
<#if needDict>
|
||||||
import { useDict } from '@/hooks/useDict';
|
import { useDict } from '@/hooks/useDict';
|
||||||
#end
|
</#if>
|
||||||
#if($enableExport)
|
<#if enableExport>
|
||||||
import { useTableExport } from '@/hooks/useTableExport';
|
import { useTableExport } from '@/hooks/useTableExport';
|
||||||
#end
|
</#if>
|
||||||
import { useTreeTableExpand } from '@/hooks/useTreeTableExpand';
|
import { useTreeTableExpand } from '@/hooks/useTreeTableExpand';
|
||||||
import { useUserStore } from '@/stores/userStore';
|
import { useUserStore } from '@/stores/userStore';
|
||||||
#if($needDict)
|
<#if needDict>
|
||||||
import { dictOptions } from '@/utils/dict';
|
import { dictOptions } from '@/utils/dict';
|
||||||
#end
|
</#if>
|
||||||
#if($enableStatus)
|
<#if enableStatus>
|
||||||
import { confirmAction } from '@/utils/modal';
|
import { confirmAction } from '@/utils/modal';
|
||||||
#end
|
</#if>
|
||||||
import { hasPermi } from '@/utils/permission';
|
import { hasPermi } from '@/utils/permission';
|
||||||
import { filterTree#if($needDateField), formatDateTimeFields#end, handleTree#if($needDateField), toDayjsFields#end } from '@/utils/ruoyi';
|
import { filterTree<#if needDateField>, formatDateTimeFields</#if>, handleTree<#if needDateField>, toDayjsFields</#if> } from '@/utils/ruoyi';
|
||||||
|
|
||||||
const default${BusinessName}Form: ${BusinessName}Form = {
|
const default${BusinessName}Form: ${BusinessName}Form = {
|
||||||
${treeParentCode}: ${treeRootValueTsLiteral},
|
${treeParentCode}: ${treeRootValueTsLiteral},
|
||||||
#foreach($column in $columns)
|
<#list columns as column>
|
||||||
#if(($column.insert || $column.edit) && !$column.pk && $column.htmlType == "checkbox")
|
<#if (column.insert || column.edit) && !column.pk && column.htmlType == "checkbox">
|
||||||
${column.javaField}: [],
|
${column.javaField}: [],
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#list>
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ${BusinessName}SelectNode {
|
interface ${BusinessName}SelectNode {
|
||||||
@ -140,36 +96,34 @@ function toTreeSelectData(nodes: ${BusinessName}VO[]): ${BusinessName}SelectNode
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
#macro(switchActiveValue $column)#if($column.javaType == "Boolean")true#elseif($column.javaType == "Integer" || $column.javaType == "Long")0#else'0'#end#end
|
<#if enableStatus>
|
||||||
#macro(switchInactiveValue $column)#if($column.javaType == "Boolean")false#elseif($column.javaType == "Integer" || $column.javaType == "Long")1#else'1'#end#end
|
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
||||||
#if($enableStatus)
|
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
||||||
const ${statusField}ActiveValue = #if($statusColumn.javaType == "Boolean")true#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")0#else'0'#end;
|
|
||||||
const ${statusField}InactiveValue = #if($statusColumn.javaType == "Boolean")false#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")1#else'1'#end;
|
|
||||||
|
|
||||||
#end
|
</#if>
|
||||||
export default function ${BusinessName}Page() {
|
export default function ${BusinessName}Page() {
|
||||||
const actionRef = useRef<ActionType | undefined>(undefined);
|
const actionRef = useRef<ActionType | undefined>(undefined);
|
||||||
const [form] = Form.useForm<${BusinessName}Form>();
|
const [form] = Form.useForm<${BusinessName}Form>();
|
||||||
const userInfo = useUserStore(state => state.userInfo);
|
const userInfo = useUserStore(state => state.userInfo);
|
||||||
#if($needDict)
|
<#if needDict>
|
||||||
const dicts = useDict(${dicts});
|
const dicts = useDict(${dicts});
|
||||||
#end
|
</#if>
|
||||||
const [treeOptions, setTreeOptions] = useState<${BusinessName}VO[]>([]);
|
const [treeOptions, setTreeOptions] = useState<${BusinessName}VO[]>([]);
|
||||||
const [tableRows, setTableRows] = useState<${BusinessName}VO[]>([]);
|
const [tableRows, setTableRows] = useState<${BusinessName}VO[]>([]);
|
||||||
const { expandAll, expandedRowKeys, onExpandedRowsChange, syncExpandedRows, toggleExpandAll } =
|
const { expandAll, expandedRowKeys, onExpandedRowsChange, syncExpandedRows, toggleExpandAll } =
|
||||||
useTreeTableExpand<${BusinessName}VO>(row => row.${treeCode});
|
useTreeTableExpand<${BusinessName}VO>(row => row.${treeCode});
|
||||||
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
||||||
const [modalTitle, setModalTitle] = useState('');
|
const [modalTitle, setModalTitle] = useState('');
|
||||||
#if($enableExport)
|
<#if enableExport>
|
||||||
const { updateExportParams, exportFile } = useTableExport();
|
const { updateExportParams, exportFile } = useTableExport();
|
||||||
#end
|
</#if>
|
||||||
|
|
||||||
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
||||||
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
||||||
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
||||||
#if($enableExport)
|
<#if enableExport>
|
||||||
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
||||||
#end
|
</#if>
|
||||||
const treeSelectData = useMemo(
|
const treeSelectData = useMemo(
|
||||||
() => [{ title: '顶级节点', value: ${treeRootValueTsLiteral}, children: toTreeSelectData(treeOptions) }],
|
() => [{ title: '顶级节点', value: ${treeRootValueTsLiteral}, children: toTreeSelectData(treeOptions) }],
|
||||||
[treeOptions]
|
[treeOptions]
|
||||||
@ -184,7 +138,7 @@ export default function ${BusinessName}Page() {
|
|||||||
const openAdd = async (row?: ${BusinessName}VO) => {
|
const openAdd = async (row?: ${BusinessName}VO) => {
|
||||||
await loadTreeOptions();
|
await loadTreeOptions();
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
form.setFieldsValue({ ...default${BusinessName}Form, ${treeParentCode}: row?.${treeCode} || ${treeRootValueTsLiteral} });
|
form.setFieldsValue({ ...default${BusinessName}Form, ${treeParentCode}: row?.${treeCode} || treeRootValueTsLiteral });
|
||||||
setModalTitle('添加${functionName}');
|
setModalTitle('添加${functionName}');
|
||||||
openModal();
|
openModal();
|
||||||
};
|
};
|
||||||
@ -192,20 +146,20 @@ export default function ${BusinessName}Page() {
|
|||||||
const openEdit = async (row: ${BusinessName}VO) => {
|
const openEdit = async (row: ${BusinessName}VO) => {
|
||||||
await loadTreeOptions(row.${treeCode});
|
await loadTreeOptions(row.${treeCode});
|
||||||
const res = await get${BusinessName}(row.${pkColumn.javaField});
|
const res = await get${BusinessName}(row.${pkColumn.javaField});
|
||||||
const data = #if($needDateField)toDayjsFields({ ...res.data }, [
|
const data = <#if needDateField>toDayjsFields({ ...res.data }, [
|
||||||
#foreach($column in $columns)
|
<#list columns as column>
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
|
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||||
'${column.javaField}',
|
'${column.javaField}',
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#list>
|
||||||
])#else{ ...res.data }#end;
|
])<#else>{ ...res.data }</#if>;
|
||||||
#foreach($column in $columns)
|
<#list columns as column>
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
|
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||||
if (typeof data.${column.javaField} === 'string') {
|
if (typeof data.${column.javaField} === 'string') {
|
||||||
data.${column.javaField} = data.${column.javaField}.split(',');
|
data.${column.javaField} = data.${column.javaField}.split(',');
|
||||||
}
|
}
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#list>
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
form.setFieldsValue(data);
|
form.setFieldsValue(data);
|
||||||
setModalTitle('修改${functionName}');
|
setModalTitle('修改${functionName}');
|
||||||
@ -213,20 +167,20 @@ export default function ${BusinessName}Page() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const submitForm = async (values: ${BusinessName}Form) => {
|
const submitForm = async (values: ${BusinessName}Form) => {
|
||||||
const submitValues = #if($needDateField)formatDateTimeFields({ ...values }, [
|
const submitValues = <#if needDateField>formatDateTimeFields({ ...values }, [
|
||||||
#foreach($column in $columns)
|
<#list columns as column>
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
|
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||||
'${column.javaField}',
|
'${column.javaField}',
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#list>
|
||||||
])#else{ ...values }#end;
|
])<#else>{ ...values }</#if>;
|
||||||
#foreach($column in $columns)
|
<#list columns as column>
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
|
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||||
if (Array.isArray(submitValues.${column.javaField})) {
|
if (Array.isArray(submitValues.${column.javaField})) {
|
||||||
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
||||||
}
|
}
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#list>
|
||||||
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
||||||
message.success('操作成功');
|
message.success('操作成功');
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
@ -240,15 +194,15 @@ export default function ${BusinessName}Page() {
|
|||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
#if($enableStatus)
|
<#if enableStatus>
|
||||||
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
||||||
const previousStatus = row.${statusField};
|
const previousStatus = row.${statusField};
|
||||||
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
||||||
const text = checked ? '启用' : '停用';
|
const text = checked ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await confirmAction(`确认要"${text}"吗?`);
|
await confirmAction(`确认要"${r'${text}'}"吗?`);
|
||||||
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
||||||
message.success(`${text}成功`);
|
message.success(`${r'${text}'}成功`);
|
||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
} catch {
|
} catch {
|
||||||
row.${statusField} = previousStatus;
|
row.${statusField} = previousStatus;
|
||||||
@ -256,76 +210,74 @@ export default function ${BusinessName}Page() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#end
|
</#if>
|
||||||
#if($enableSort)
|
<#if enableSort>
|
||||||
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
||||||
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
||||||
message.success('排序更新成功');
|
message.success('排序更新成功');
|
||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
#end
|
</#if>
|
||||||
const columns: ProColumns<${BusinessName}VO>[] = [
|
const columns: ProColumns<${BusinessName}VO>[] = [
|
||||||
#foreach($column in $columns)
|
<#list columns as column>
|
||||||
#set($javaField=$column.javaField)
|
<#if column.list && !column.pk>
|
||||||
#set($dictType=$column.dictType)
|
<#if enableStatus && statusField == column.javaField>
|
||||||
#if($column.list && !$column.pk)
|
|
||||||
#if($enableStatus && $statusField == $javaField)
|
|
||||||
{
|
{
|
||||||
title: '#comment($column)',
|
title: '${column.columnLabel}',
|
||||||
dataIndex: '${javaField}',
|
dataIndex: '${column.javaField}',
|
||||||
valueType: 'select',
|
valueType: 'select',
|
||||||
width: 100,
|
width: 100,
|
||||||
#if("" != $dictType)
|
<#if column.dictType?has_content>
|
||||||
fieldProps: { options: dictOptions(dicts.${dictType}) },
|
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||||
#end
|
</#if>
|
||||||
render: (_, row) => (
|
render: (_, row) => (
|
||||||
<Switch
|
<Switch
|
||||||
checked={row.${javaField} === ${statusField}ActiveValue}
|
checked={row.${column.javaField} === ${statusField}ActiveValue}
|
||||||
disabled={!canEdit}
|
disabled={!canEdit}
|
||||||
onChange={checked => handleStatusChange(row, checked)}
|
onChange={checked => handleStatusChange(row, checked)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
#elseif($enableSort && $sortField == $javaField)
|
<#elseif enableSort && sortField == column.javaField>
|
||||||
{
|
{
|
||||||
title: '#comment($column)',
|
title: '${column.columnLabel}',
|
||||||
dataIndex: '${javaField}',
|
dataIndex: '${column.javaField}',
|
||||||
search: false,
|
search: false,
|
||||||
width: 130,
|
width: 130,
|
||||||
render: (_, row) => <InputNumber min={0} value={row.${javaField} as number} onChange={value => handleSortChange(row, value)} />
|
render: (_, row) => <InputNumber min={0} value={row.${column.javaField} as number} onChange={value => handleSortChange(row, value)} />
|
||||||
},
|
},
|
||||||
#elseif($column.htmlType == "datetime")
|
<#elseif column.htmlType == "datetime">
|
||||||
{ title: '#comment($column)', dataIndex: '${javaField}', valueType: 'dateTime', search: #if($column.query)true#else false#end, width: 170 },
|
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}', valueType: 'dateTime', search: <#if column.query>true<#else> false</#if>, width: 170 },
|
||||||
#elseif($column.htmlType == "imageUpload")
|
<#elseif column.htmlType == "imageUpload">
|
||||||
{
|
{
|
||||||
title: '#comment($column)',
|
title: '${column.columnLabel}',
|
||||||
dataIndex: '${javaField}Url',
|
dataIndex: '${column.javaField}Url',
|
||||||
search: false,
|
search: false,
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (_, row) => <ImagePreview src={row.${javaField}Url || String(row.${javaField} || '')} width={50} height={50} />
|
render: (_, row) => <ImagePreview src={row.${column.javaField}Url || String(row.${column.javaField} || '')} width={50} height={50} />
|
||||||
},
|
},
|
||||||
#elseif($column.dictColumn)
|
<#elseif column.dictColumn>
|
||||||
{
|
{
|
||||||
title: '#comment($column)',
|
title: '${column.columnLabel}',
|
||||||
dataIndex: '${javaField}',
|
dataIndex: '${column.javaField}',
|
||||||
valueType: 'select',
|
valueType: 'select',
|
||||||
fieldProps: { options: dictOptions(dicts.${dictType}) },
|
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||||
render: (_, row) => <DictTag options={dicts.${dictType}} value={row.${javaField}} />
|
render: (_, row) => <DictTag options={dicts.${column.dictType}} value={row.${column.javaField}} />
|
||||||
},
|
},
|
||||||
#elseif($column.htmlType == "switch")
|
<#elseif column.htmlType == "switch">
|
||||||
{
|
{
|
||||||
title: '#comment($column)',
|
title: '${column.columnLabel}',
|
||||||
dataIndex: '${javaField}',
|
dataIndex: '${column.javaField}',
|
||||||
valueType: 'select',
|
valueType: 'select',
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (_, row) => <Switch checked={row.${javaField} === #switchActiveValue($column)} disabled />
|
render: (_, row) => <Switch checked={row.${column.javaField} === ${column.switchActiveValue}} disabled />
|
||||||
},
|
},
|
||||||
#else
|
<#else>
|
||||||
{ title: '#comment($column)', dataIndex: '${javaField}'#if(!$column.query), search: false#end },
|
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}'<#if !column.query>, search: false</#if> },
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#list>
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
@ -341,7 +293,7 @@ export default function ${BusinessName}Page() {
|
|||||||
label: '删除',
|
label: '删除',
|
||||||
icon: <DeleteOutlined />,
|
icon: <DeleteOutlined />,
|
||||||
danger: true,
|
danger: true,
|
||||||
confirm: `是否确认删除${functionName}编号为"#[[${row.]]#${pkColumn.javaField}#[[}]]#"的数据项?`,
|
confirm: `是否确认删除${functionName}编号为"${r'${row.'}${pkColumn.javaField}${r'}'}"的数据项?`,
|
||||||
onClick: () => remove(row)
|
onClick: () => remove(row)
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
@ -368,9 +320,9 @@ export default function ${BusinessName}Page() {
|
|||||||
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
|
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
|
||||||
setTableRows(rows);
|
setTableRows(rows);
|
||||||
syncExpandedRows(rows, expandAll);
|
syncExpandedRows(rows, expandAll);
|
||||||
#if($enableExport)
|
<#if enableExport>
|
||||||
updateExportParams(params);
|
updateExportParams(params);
|
||||||
#end
|
</#if>
|
||||||
return { data: rows, total: rows.length, success: true };
|
return { data: rows, total: rows.length, success: true };
|
||||||
}}
|
}}
|
||||||
toolbar={{ title: '${functionName}列表' }}
|
toolbar={{ title: '${functionName}列表' }}
|
||||||
@ -386,16 +338,16 @@ export default function ${BusinessName}Page() {
|
|||||||
onClick={() => toggleExpandAll(tableRows)}
|
onClick={() => toggleExpandAll(tableRows)}
|
||||||
>
|
>
|
||||||
展开/折叠
|
展开/折叠
|
||||||
</Button>#if($enableExport),
|
</Button><#if enableExport>,
|
||||||
canExport && (
|
canExport && (
|
||||||
<Button
|
<Button
|
||||||
key="export"
|
key="export"
|
||||||
icon={<DownloadOutlined />}
|
icon={<DownloadOutlined />}
|
||||||
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_#[[${Date.now()}]]#.xlsx`)}
|
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_${r'${Date.now()}'}.xlsx`)}
|
||||||
>
|
>
|
||||||
导出
|
导出
|
||||||
</Button>
|
</Button>
|
||||||
)#end
|
)</#if>
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@ -411,62 +363,65 @@ export default function ${BusinessName}Page() {
|
|||||||
onFinish={submitForm}
|
onFinish={submitForm}
|
||||||
>
|
>
|
||||||
<ProFormText name="${pkColumn.javaField}" hidden />
|
<ProFormText name="${pkColumn.javaField}" hidden />
|
||||||
#foreach($column in $columns)
|
<#list columns as column>
|
||||||
#if(($column.insert || $column.edit) && !$column.pk)
|
<#if (column.insert || column.edit) && !column.pk>
|
||||||
#set($field=$column.javaField)
|
<#assign field = column.javaField>
|
||||||
#set($dictType=$column.dictType)
|
<#if field == treeParentCode>
|
||||||
#if($field == $treeParentCode)
|
|
||||||
<ProFormTreeSelect
|
<ProFormTreeSelect
|
||||||
name="${field}"
|
name="${column.javaField}"
|
||||||
label="#comment($column)"
|
label="${column.columnLabel}"
|
||||||
#if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end
|
<#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
treeDefaultExpandAll: true,
|
treeDefaultExpandAll: true,
|
||||||
treeData: treeSelectData,
|
treeData: treeSelectData,
|
||||||
placeholder: '请选择#comment($column)'
|
placeholder: '请选择${column.columnLabel}'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
#elseif($column.htmlType == "input")
|
<#elseif column.htmlType == "input">
|
||||||
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
#elseif($column.htmlType == "textarea")
|
<#elseif column.htmlType == "textarea">
|
||||||
<ProFormTextArea name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
<ProFormTextArea name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
#elseif($column.htmlType == "inputNumber")
|
<#elseif column.htmlType == "inputNumber">
|
||||||
<ProFormDigit name="${field}" label="#comment($column)" min={0} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
<ProFormDigit name="${column.javaField}" label="${column.columnLabel}" min={0} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch") && "" != $dictType)
|
<#elseif (column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch") && column.dictType?has_content>
|
||||||
<ProFormSelect name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
<ProFormSelect name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
#elseif($column.htmlType == "checkbox" && "" != $dictType)
|
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
||||||
<ProFormCheckbox.Group name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
<ProFormCheckbox.Group name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
#elseif($column.htmlType == "switch")
|
<#elseif column.htmlType == "switch">
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="${field}"
|
name="${column.javaField}"
|
||||||
label="#comment($column)"
|
label="${column.columnLabel}"
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
getValueProps={value => ({ checked: value === #switchActiveValue($column) })}
|
getValueProps={value => ({ checked: value === ${column.switchActiveValue} })}
|
||||||
normalize={checked => (checked ? #switchActiveValue($column) : #switchInactiveValue($column))}
|
normalize={checked => (checked ? ${column.switchActiveValue} : ${column.switchInactiveValue})}
|
||||||
>
|
>
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
#elseif($column.htmlType == "datetime")
|
<#elseif column.htmlType == "datetime">
|
||||||
<ProFormDateTimePicker name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
<ProFormDateTimePicker name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
#elseif($column.htmlType == "imageUpload")
|
<#elseif column.htmlType == "imageUpload">
|
||||||
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
|
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||||
<ImageUpload />
|
<ImageUpload />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
#elseif($column.htmlType == "fileUpload")
|
<#elseif column.htmlType == "fileUpload">
|
||||||
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
|
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||||
<FileUpload />
|
<FileUpload />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
#elseif($column.htmlType == "editor")
|
<#elseif column.htmlType == "editor">
|
||||||
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
|
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||||
<RichTextEditor />
|
<RichTextEditor />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
#else
|
<#else>
|
||||||
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#if>
|
||||||
#end
|
</#list>
|
||||||
</ModalForm>
|
</ModalForm>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
409
gen/index.tsx.ftl
Normal file
409
gen/index.tsx.ftl
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
import { DeleteOutlined<#if enableExport>, DownloadOutlined</#if>, EditOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
|
import {
|
||||||
|
ModalForm,
|
||||||
|
PageContainer,
|
||||||
|
<#if needCheckbox>
|
||||||
|
ProFormCheckbox,
|
||||||
|
</#if>
|
||||||
|
<#if needDateField>
|
||||||
|
ProFormDateTimePicker,
|
||||||
|
</#if>
|
||||||
|
<#if needDigit>
|
||||||
|
ProFormDigit,
|
||||||
|
</#if>
|
||||||
|
<#if needSelect>
|
||||||
|
ProFormSelect,
|
||||||
|
</#if>
|
||||||
|
<#if needTextArea>
|
||||||
|
ProFormTextArea,
|
||||||
|
</#if>
|
||||||
|
ProFormText,
|
||||||
|
ProTable,
|
||||||
|
type ActionType,
|
||||||
|
type ProColumns
|
||||||
|
} from '@ant-design/pro-components';
|
||||||
|
import { useBoolean } from 'ahooks';
|
||||||
|
import { Button, Form, message, Popconfirm<#if enableStatus || needSwitchField>, Switch</#if><#if enableSort>, InputNumber</#if> } from 'antd';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
||||||
|
import {
|
||||||
|
add${BusinessName},
|
||||||
|
<#if enableStatus>
|
||||||
|
change${BusinessName}Status,
|
||||||
|
</#if>
|
||||||
|
del${BusinessName},
|
||||||
|
get${BusinessName},
|
||||||
|
list${BusinessName},
|
||||||
|
<#if enableSort>
|
||||||
|
update${BusinessName}Sort,
|
||||||
|
</#if>
|
||||||
|
update${BusinessName}
|
||||||
|
} from '@/api/${moduleName}/${businessName}';
|
||||||
|
<#if needDict>
|
||||||
|
import DictTag from '@/components/common/DictTag';
|
||||||
|
</#if>
|
||||||
|
<#if needFileUpload>
|
||||||
|
import FileUpload from '@/components/common/FileUpload';
|
||||||
|
</#if>
|
||||||
|
<#if needImagePreview>
|
||||||
|
import ImagePreview from '@/components/common/ImagePreview';
|
||||||
|
</#if>
|
||||||
|
<#if needImageUpload>
|
||||||
|
import ImageUpload from '@/components/common/ImageUpload';
|
||||||
|
</#if>
|
||||||
|
<#if needEditor>
|
||||||
|
import RichTextEditor from '@/components/common/RichTextEditor';
|
||||||
|
</#if>
|
||||||
|
import RowActions from '@/components/common/RowActions';
|
||||||
|
<#if needDict>
|
||||||
|
import { useDict } from '@/hooks/useDict';
|
||||||
|
</#if>
|
||||||
|
<#if needDateRange>
|
||||||
|
import { useDateRangeQuery } from '@/hooks/useDateRangeQuery';
|
||||||
|
</#if>
|
||||||
|
<#if enableExport>
|
||||||
|
import { useTableExport } from '@/hooks/useTableExport';
|
||||||
|
</#if>
|
||||||
|
import { useTableSelection } from '@/hooks/useTableSelection';
|
||||||
|
import { useUserStore } from '@/stores/userStore';
|
||||||
|
<#if needDict>
|
||||||
|
import { dictOptions } from '@/utils/dict';
|
||||||
|
</#if>
|
||||||
|
<#if enableStatus>
|
||||||
|
import { confirmAction } from '@/utils/modal';
|
||||||
|
</#if>
|
||||||
|
import { hasPermi } from '@/utils/permission';
|
||||||
|
import { <#if needDateField>formatDateTimeFields, toDayjsFields, </#if> toPageQuery, toTableData } from '@/utils/ruoyi';
|
||||||
|
|
||||||
|
const default${BusinessName}Form: ${BusinessName}Form = {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && !column.pk && column.htmlType == "checkbox">
|
||||||
|
${column.javaField}: [],
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
};
|
||||||
|
|
||||||
|
<#if enableStatus>
|
||||||
|
const ${statusField}ActiveValue = <#if statusColumn.javaType == "Boolean">true<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">0<#else>'0'</#if>;
|
||||||
|
const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'</#if>;
|
||||||
|
|
||||||
|
</#if>
|
||||||
|
export default function ${BusinessName}Page() {
|
||||||
|
const actionRef = useRef<ActionType | undefined>(undefined);
|
||||||
|
const [form] = Form.useForm<${BusinessName}Form>();
|
||||||
|
const userInfo = useUserStore(state => state.userInfo);
|
||||||
|
<#if needDict>
|
||||||
|
const dicts = useDict(${dicts});
|
||||||
|
</#if>
|
||||||
|
const { ids, selectedOne, handleSelectionChange, clearSelection } = useTableSelection<${BusinessName}VO>(
|
||||||
|
row => row.${pkColumn.javaField}
|
||||||
|
);
|
||||||
|
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
||||||
|
const [modalTitle, setModalTitle] = useState('');
|
||||||
|
<#if enableExport>
|
||||||
|
const { updateExportParams, exportFile } = useTableExport();
|
||||||
|
</#if>
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
const { applyDateRange: apply${column.capJavaField}DateRange } = useDateRangeQuery('${column.capJavaField}');
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
||||||
|
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
||||||
|
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
||||||
|
<#if enableExport>
|
||||||
|
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
const openAdd = () => {
|
||||||
|
form.resetFields();
|
||||||
|
form.setFieldsValue(default${BusinessName}Form);
|
||||||
|
setModalTitle('添加${functionName}');
|
||||||
|
openModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const openEdit = async (row?: ${BusinessName}VO) => {
|
||||||
|
const target = row || selectedOne;
|
||||||
|
if (!target?.${pkColumn.javaField}) return;
|
||||||
|
const res = await get${BusinessName}(target.${pkColumn.javaField});
|
||||||
|
const data = <#if needDateField>toDayjsFields({ ...res.data }, [
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||||
|
'${column.javaField}',
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
])<#else>{ ...res.data }</#if>;
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||||
|
if (typeof data.${column.javaField} === 'string') {
|
||||||
|
data.${column.javaField} = data.${column.javaField}.split(',');
|
||||||
|
}
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
form.resetFields();
|
||||||
|
form.setFieldsValue(data);
|
||||||
|
setModalTitle('修改${functionName}');
|
||||||
|
openModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitForm = async (values: ${BusinessName}Form) => {
|
||||||
|
const submitValues = <#if needDateField>formatDateTimeFields({ ...values }, [
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && column.htmlType == "datetime">
|
||||||
|
'${column.javaField}',
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
])<#else>{ ...values }</#if>;
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && column.htmlType == "checkbox">
|
||||||
|
if (Array.isArray(submitValues.${column.javaField})) {
|
||||||
|
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
||||||
|
}
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
||||||
|
message.success('操作成功');
|
||||||
|
form.resetFields();
|
||||||
|
actionRef.current?.reload();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const remove = async (row?: ${BusinessName}VO) => {
|
||||||
|
await del${BusinessName}(row?.${pkColumn.javaField} || ids);
|
||||||
|
message.success('删除成功');
|
||||||
|
clearSelection();
|
||||||
|
actionRef.current?.reloadAndRest?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
<#if enableStatus>
|
||||||
|
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
||||||
|
const previousStatus = row.${statusField};
|
||||||
|
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
||||||
|
const text = checked ? '启用' : '停用';
|
||||||
|
try {
|
||||||
|
await confirmAction(`确认要"${r'${text}'}"吗?`);
|
||||||
|
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
||||||
|
message.success(`${r'${text}'}成功`);
|
||||||
|
actionRef.current?.reload();
|
||||||
|
} catch {
|
||||||
|
row.${statusField} = previousStatus;
|
||||||
|
actionRef.current?.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
</#if>
|
||||||
|
<#if enableSort>
|
||||||
|
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
||||||
|
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
||||||
|
message.success('排序更新成功');
|
||||||
|
actionRef.current?.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
</#if>
|
||||||
|
const columns: ProColumns<${BusinessName}VO>[] = [
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.list>
|
||||||
|
<#if enableStatus && statusField == column.javaField>
|
||||||
|
{
|
||||||
|
title: '${column.columnLabel}',
|
||||||
|
dataIndex: '${column.javaField}',
|
||||||
|
valueType: 'select',
|
||||||
|
width: 100,
|
||||||
|
<#if column.dictType?has_content>
|
||||||
|
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||||
|
</#if>
|
||||||
|
render: (_, row) => (
|
||||||
|
<Switch
|
||||||
|
checked={row.${column.javaField} === ${statusField}ActiveValue}
|
||||||
|
disabled={!canEdit}
|
||||||
|
onChange={checked => handleStatusChange(row, checked)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
<#elseif enableSort && sortField == column.javaField>
|
||||||
|
{
|
||||||
|
title: '${column.columnLabel}',
|
||||||
|
dataIndex: '${column.javaField}',
|
||||||
|
search: false,
|
||||||
|
width: 130,
|
||||||
|
render: (_, row) => <InputNumber min={0} value={row.${column.javaField} as number} onChange={value => handleSortChange(row, value)} />
|
||||||
|
},
|
||||||
|
<#elseif column.htmlType == "datetime">
|
||||||
|
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}', valueType: 'dateTime', search: <#if column.query && column.queryType != "BETWEEN">true<#else> false</#if>, width: 170 },
|
||||||
|
<#elseif column.htmlType == "imageUpload">
|
||||||
|
{
|
||||||
|
title: '${column.columnLabel}',
|
||||||
|
dataIndex: '${column.javaField}Url',
|
||||||
|
search: false,
|
||||||
|
width: 100,
|
||||||
|
render: (_, row) => <ImagePreview src={row.${column.javaField}Url || String(row.${column.javaField} || '')} width={50} height={50} />
|
||||||
|
},
|
||||||
|
<#elseif column.dictColumn>
|
||||||
|
{
|
||||||
|
title: '${column.columnLabel}',
|
||||||
|
dataIndex: '${column.javaField}',
|
||||||
|
valueType: 'select',
|
||||||
|
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
|
||||||
|
render: (_, row) => <DictTag options={dicts.${column.dictType}} value={row.${column.javaField}} />
|
||||||
|
},
|
||||||
|
<#elseif column.htmlType == "switch">
|
||||||
|
{
|
||||||
|
title: '${column.columnLabel}',
|
||||||
|
dataIndex: '${column.javaField}',
|
||||||
|
valueType: 'select',
|
||||||
|
width: 100,
|
||||||
|
render: (_, row) => <Switch checked={row.${column.javaField} === ${column.switchActiveValue}} disabled />
|
||||||
|
},
|
||||||
|
<#else>
|
||||||
|
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}'<#if !column.query>, search: false</#if> },
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}Range', valueType: 'dateTimeRange', hideInTable: true },
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
valueType: 'option',
|
||||||
|
width: 92,
|
||||||
|
fixed: 'right',
|
||||||
|
render: (_, row) => (
|
||||||
|
<RowActions
|
||||||
|
actions={[
|
||||||
|
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
|
||||||
|
canRemove && {
|
||||||
|
key: 'delete',
|
||||||
|
label: '删除',
|
||||||
|
icon: <DeleteOutlined />,
|
||||||
|
danger: true,
|
||||||
|
confirm: `是否确认删除${functionName}编号为"${r'${row.'}${pkColumn.javaField}${r'}'}"的数据项?`,
|
||||||
|
onClick: () => remove(row)
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer title="${functionName}">
|
||||||
|
<ProTable<${BusinessName}VO, ${BusinessName}Query<#if needDateRange> & Record<string, unknown></#if>>
|
||||||
|
actionRef={actionRef}
|
||||||
|
rowKey="${pkColumn.javaField}"
|
||||||
|
columns={columns}
|
||||||
|
scroll={{ x: 1000 }}
|
||||||
|
search={{ labelWidth: 90 }}
|
||||||
|
pagination={{ defaultPageSize: 10, showSizeChanger: true }}
|
||||||
|
rowSelection={{ selectedRowKeys: ids, onChange: handleSelectionChange }}
|
||||||
|
request={async params => {
|
||||||
|
<#if needDateRange>
|
||||||
|
let query = toPageQuery(params);
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query && column.htmlType == "datetime" && column.queryType == "BETWEEN">
|
||||||
|
query = apply${column.capJavaField}DateRange(query, params.${column.javaField}Range as [string, string] | undefined);
|
||||||
|
delete query.${column.javaField}Range;
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#else>
|
||||||
|
const query = toPageQuery(params);
|
||||||
|
</#if>
|
||||||
|
<#if enableExport>
|
||||||
|
updateExportParams(query);
|
||||||
|
</#if>
|
||||||
|
const res = await list${BusinessName}(query);
|
||||||
|
return toTableData(res);
|
||||||
|
}}
|
||||||
|
toolbar={{ title: '${functionName}列表' }}
|
||||||
|
toolBarRender={() => [
|
||||||
|
canAdd && (
|
||||||
|
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={openAdd}>
|
||||||
|
新增
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
canEdit && (
|
||||||
|
<Button key="edit" disabled={!selectedOne} icon={<EditOutlined />} onClick={() => openEdit()}>
|
||||||
|
修改
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
canRemove && (
|
||||||
|
<Popconfirm key="delete" title={`是否确认删除${functionName}编号为"${r'${ids}'}"的数据项?`} onConfirm={() => remove()}>
|
||||||
|
<Button danger disabled={!ids.length} icon={<DeleteOutlined />}>
|
||||||
|
删除
|
||||||
|
</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
)<#if enableExport>,
|
||||||
|
canExport && (
|
||||||
|
<Button
|
||||||
|
key="export"
|
||||||
|
icon={<DownloadOutlined />}
|
||||||
|
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_${r'${Date.now()}'}.xlsx`)}
|
||||||
|
>
|
||||||
|
导出
|
||||||
|
</Button>
|
||||||
|
)</#if>
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ModalForm<${BusinessName}Form>
|
||||||
|
title={modalTitle}
|
||||||
|
open={modalOpen}
|
||||||
|
width={560}
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
initialValues={default${BusinessName}Form}
|
||||||
|
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
|
||||||
|
onOpenChange={open => !open && closeModal()}
|
||||||
|
onFinish={submitForm}
|
||||||
|
>
|
||||||
|
<ProFormText name="${pkColumn.javaField}" hidden />
|
||||||
|
<#list columns as column>
|
||||||
|
<#if (column.insert || column.edit) && !column.pk>
|
||||||
|
<#assign field = column.javaField>
|
||||||
|
<#if column.htmlType == "input">
|
||||||
|
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
|
<#elseif column.htmlType == "textarea">
|
||||||
|
<ProFormTextArea name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
|
<#elseif column.htmlType == "inputNumber">
|
||||||
|
<ProFormDigit name="${column.javaField}" label="${column.columnLabel}" min={0} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
|
<#elseif (column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch") && column.dictType?has_content>
|
||||||
|
<ProFormSelect name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
|
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
|
||||||
|
<ProFormCheckbox.Group name="${column.javaField}" label="${column.columnLabel}" options={dictOptions(dicts.${column.dictType})} <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
|
<#elseif column.htmlType == "switch">
|
||||||
|
<Form.Item
|
||||||
|
name="${column.javaField}"
|
||||||
|
label="${column.columnLabel}"
|
||||||
|
valuePropName="checked"
|
||||||
|
getValueProps={value => ({ checked: value === ${column.switchActiveValue} })}
|
||||||
|
normalize={checked => (checked ? ${column.switchActiveValue} : ${column.switchInactiveValue})}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<#elseif column.htmlType == "datetime">
|
||||||
|
<ProFormDateTimePicker name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
|
<#elseif column.htmlType == "imageUpload">
|
||||||
|
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||||
|
<ImageUpload />
|
||||||
|
</Form.Item>
|
||||||
|
<#elseif column.htmlType == "fileUpload">
|
||||||
|
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||||
|
<FileUpload />
|
||||||
|
</Form.Item>
|
||||||
|
<#elseif column.htmlType == "editor">
|
||||||
|
<Form.Item name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>>
|
||||||
|
<RichTextEditor />
|
||||||
|
</Form.Item>
|
||||||
|
<#else>
|
||||||
|
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
</ModalForm>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
460
gen/index.tsx.vm
460
gen/index.tsx.vm
@ -1,460 +0,0 @@
|
|||||||
#set($needDict = $dicts != '')
|
|
||||||
#set($needDateRange = false)
|
|
||||||
#set($needImagePreview = false)
|
|
||||||
#set($needImageUpload = false)
|
|
||||||
#set($needFileUpload = false)
|
|
||||||
#set($needEditor = false)
|
|
||||||
#set($needCheckbox = false)
|
|
||||||
#set($needSelect = false)
|
|
||||||
#set($needTextArea = false)
|
|
||||||
#set($needDigit = false)
|
|
||||||
#set($needDateField = false)
|
|
||||||
#set($needSwitchField = false)
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
|
||||||
#set($needDateRange = true)
|
|
||||||
#end
|
|
||||||
#if($column.list && $column.htmlType == "imageUpload")
|
|
||||||
#set($needImagePreview = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "imageUpload")
|
|
||||||
#set($needImageUpload = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "fileUpload")
|
|
||||||
#set($needFileUpload = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "editor")
|
|
||||||
#set($needEditor = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
|
|
||||||
#set($needCheckbox = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit || $column.query) && ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch"))
|
|
||||||
#set($needSelect = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "textarea")
|
|
||||||
#set($needTextArea = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "inputNumber")
|
|
||||||
#set($needDigit = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
|
|
||||||
#set($needDateField = true)
|
|
||||||
#end
|
|
||||||
#if(($column.insert || $column.edit || $column.list) && $column.htmlType == "switch")
|
|
||||||
#set($needSwitchField = true)
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
#macro(comment $column)#set($idx=$column.columnComment.indexOf("("))#if($idx != -1)$column.columnComment.substring(0, $idx)#else$column.columnComment#end#end
|
|
||||||
import { DeleteOutlined#if($enableExport), DownloadOutlined#end, EditOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import {
|
|
||||||
ModalForm,
|
|
||||||
PageContainer,
|
|
||||||
#if($needCheckbox)
|
|
||||||
ProFormCheckbox,
|
|
||||||
#end
|
|
||||||
#if($needDateField)
|
|
||||||
ProFormDateTimePicker,
|
|
||||||
#end
|
|
||||||
#if($needDigit)
|
|
||||||
ProFormDigit,
|
|
||||||
#end
|
|
||||||
#if($needSelect)
|
|
||||||
ProFormSelect,
|
|
||||||
#end
|
|
||||||
#if($needTextArea)
|
|
||||||
ProFormTextArea,
|
|
||||||
#end
|
|
||||||
ProFormText,
|
|
||||||
ProTable,
|
|
||||||
type ActionType,
|
|
||||||
type ProColumns
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { useBoolean } from 'ahooks';
|
|
||||||
import { Button, Form, message, Popconfirm#if($enableStatus || $needSwitchField), Switch#end#if($enableSort), InputNumber#end } from 'antd';
|
|
||||||
import { useRef, useState } from 'react';
|
|
||||||
import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
|
|
||||||
import {
|
|
||||||
add${BusinessName},
|
|
||||||
#if($enableStatus)
|
|
||||||
change${BusinessName}Status,
|
|
||||||
#end
|
|
||||||
del${BusinessName},
|
|
||||||
get${BusinessName},
|
|
||||||
list${BusinessName},
|
|
||||||
#if($enableSort)
|
|
||||||
update${BusinessName}Sort,
|
|
||||||
#end
|
|
||||||
update${BusinessName}
|
|
||||||
} from '@/api/${moduleName}/${businessName}';
|
|
||||||
#if($needDict)
|
|
||||||
import DictTag from '@/components/common/DictTag';
|
|
||||||
#end
|
|
||||||
#if($needFileUpload)
|
|
||||||
import FileUpload from '@/components/common/FileUpload';
|
|
||||||
#end
|
|
||||||
#if($needImagePreview)
|
|
||||||
import ImagePreview from '@/components/common/ImagePreview';
|
|
||||||
#end
|
|
||||||
#if($needImageUpload)
|
|
||||||
import ImageUpload from '@/components/common/ImageUpload';
|
|
||||||
#end
|
|
||||||
#if($needEditor)
|
|
||||||
import RichTextEditor from '@/components/common/RichTextEditor';
|
|
||||||
#end
|
|
||||||
import RowActions from '@/components/common/RowActions';
|
|
||||||
#if($needDict)
|
|
||||||
import { useDict } from '@/hooks/useDict';
|
|
||||||
#end
|
|
||||||
#if($needDateRange)
|
|
||||||
import { useDateRangeQuery } from '@/hooks/useDateRangeQuery';
|
|
||||||
#end
|
|
||||||
#if($enableExport)
|
|
||||||
import { useTableExport } from '@/hooks/useTableExport';
|
|
||||||
#end
|
|
||||||
import { useTableSelection } from '@/hooks/useTableSelection';
|
|
||||||
import { useUserStore } from '@/stores/userStore';
|
|
||||||
#if($needDict)
|
|
||||||
import { dictOptions } from '@/utils/dict';
|
|
||||||
#end
|
|
||||||
#if($enableStatus)
|
|
||||||
import { confirmAction } from '@/utils/modal';
|
|
||||||
#end
|
|
||||||
import { hasPermi } from '@/utils/permission';
|
|
||||||
import { #if($needDateField)formatDateTimeFields, toDayjsFields, #end toPageQuery, toTableData } from '@/utils/ruoyi';
|
|
||||||
|
|
||||||
const default${BusinessName}Form: ${BusinessName}Form = {
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if(($column.insert || $column.edit) && !$column.pk && $column.htmlType == "checkbox")
|
|
||||||
${column.javaField}: [],
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
};
|
|
||||||
|
|
||||||
#macro(switchActiveValue $column)#if($column.javaType == "Boolean")true#elseif($column.javaType == "Integer" || $column.javaType == "Long")0#else'0'#end#end
|
|
||||||
#macro(switchInactiveValue $column)#if($column.javaType == "Boolean")false#elseif($column.javaType == "Integer" || $column.javaType == "Long")1#else'1'#end#end
|
|
||||||
#if($enableStatus)
|
|
||||||
const ${statusField}ActiveValue = #if($statusColumn.javaType == "Boolean")true#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")0#else'0'#end;
|
|
||||||
const ${statusField}InactiveValue = #if($statusColumn.javaType == "Boolean")false#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")1#else'1'#end;
|
|
||||||
|
|
||||||
#end
|
|
||||||
export default function ${BusinessName}Page() {
|
|
||||||
const actionRef = useRef<ActionType | undefined>(undefined);
|
|
||||||
const [form] = Form.useForm<${BusinessName}Form>();
|
|
||||||
const userInfo = useUserStore(state => state.userInfo);
|
|
||||||
#if($needDict)
|
|
||||||
const dicts = useDict(${dicts});
|
|
||||||
#end
|
|
||||||
const { ids, selectedOne, handleSelectionChange, clearSelection } = useTableSelection<${BusinessName}VO>(
|
|
||||||
row => row.${pkColumn.javaField}
|
|
||||||
);
|
|
||||||
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
|
|
||||||
const [modalTitle, setModalTitle] = useState('');
|
|
||||||
#if($enableExport)
|
|
||||||
const { updateExportParams, exportFile } = useTableExport();
|
|
||||||
#end
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if($column.query && $column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
|
||||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
|
||||||
const { applyDateRange: apply${AttrName}DateRange } = useDateRangeQuery('${AttrName}');
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
|
|
||||||
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
|
|
||||||
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
|
|
||||||
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
|
|
||||||
#if($enableExport)
|
|
||||||
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
|
|
||||||
#end
|
|
||||||
|
|
||||||
const openAdd = () => {
|
|
||||||
form.resetFields();
|
|
||||||
form.setFieldsValue(default${BusinessName}Form);
|
|
||||||
setModalTitle('添加${functionName}');
|
|
||||||
openModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const openEdit = async (row?: ${BusinessName}VO) => {
|
|
||||||
const target = row || selectedOne;
|
|
||||||
if (!target?.${pkColumn.javaField}) return;
|
|
||||||
const res = await get${BusinessName}(target.${pkColumn.javaField});
|
|
||||||
const data = #if($needDateField)toDayjsFields({ ...res.data }, [
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
|
|
||||||
'${column.javaField}',
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
])#else{ ...res.data }#end;
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
|
|
||||||
if (typeof data.${column.javaField} === 'string') {
|
|
||||||
data.${column.javaField} = data.${column.javaField}.split(',');
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
form.resetFields();
|
|
||||||
form.setFieldsValue(data);
|
|
||||||
setModalTitle('修改${functionName}');
|
|
||||||
openModal();
|
|
||||||
};
|
|
||||||
|
|
||||||
const submitForm = async (values: ${BusinessName}Form) => {
|
|
||||||
const submitValues = #if($needDateField)formatDateTimeFields({ ...values }, [
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
|
|
||||||
'${column.javaField}',
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
])#else{ ...values }#end;
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if(($column.insert || $column.edit) && $column.htmlType == "checkbox")
|
|
||||||
if (Array.isArray(submitValues.${column.javaField})) {
|
|
||||||
submitValues.${column.javaField} = submitValues.${column.javaField}.join(',');
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
|
|
||||||
message.success('操作成功');
|
|
||||||
form.resetFields();
|
|
||||||
actionRef.current?.reload();
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const remove = async (row?: ${BusinessName}VO) => {
|
|
||||||
await del${BusinessName}(row?.${pkColumn.javaField} || ids);
|
|
||||||
message.success('删除成功');
|
|
||||||
clearSelection();
|
|
||||||
actionRef.current?.reloadAndRest?.();
|
|
||||||
};
|
|
||||||
|
|
||||||
#if($enableStatus)
|
|
||||||
const handleStatusChange = async (row: ${BusinessName}VO, checked: boolean) => {
|
|
||||||
const previousStatus = row.${statusField};
|
|
||||||
const status = checked ? ${statusField}ActiveValue : ${statusField}InactiveValue;
|
|
||||||
const text = checked ? '启用' : '停用';
|
|
||||||
try {
|
|
||||||
await confirmAction(`确认要"${text}"吗?`);
|
|
||||||
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
|
|
||||||
message.success(`${text}成功`);
|
|
||||||
actionRef.current?.reload();
|
|
||||||
} catch {
|
|
||||||
row.${statusField} = previousStatus;
|
|
||||||
actionRef.current?.reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#end
|
|
||||||
#if($enableSort)
|
|
||||||
const handleSortChange = async (row: ${BusinessName}VO, value?: number | null) => {
|
|
||||||
await update${BusinessName}Sort(row.${pkColumn.javaField}, value || 0);
|
|
||||||
message.success('排序更新成功');
|
|
||||||
actionRef.current?.reload();
|
|
||||||
};
|
|
||||||
|
|
||||||
#end
|
|
||||||
const columns: ProColumns<${BusinessName}VO>[] = [
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#set($javaField=$column.javaField)
|
|
||||||
#set($dictType=$column.dictType)
|
|
||||||
#if($column.list)
|
|
||||||
#if($enableStatus && $statusField == $javaField)
|
|
||||||
{
|
|
||||||
title: '#comment($column)',
|
|
||||||
dataIndex: '${javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
width: 100,
|
|
||||||
#if("" != $dictType)
|
|
||||||
fieldProps: { options: dictOptions(dicts.${dictType}) },
|
|
||||||
#end
|
|
||||||
render: (_, row) => (
|
|
||||||
<Switch
|
|
||||||
checked={row.${javaField} === ${statusField}ActiveValue}
|
|
||||||
disabled={!canEdit}
|
|
||||||
onChange={checked => handleStatusChange(row, checked)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
},
|
|
||||||
#elseif($enableSort && $sortField == $javaField)
|
|
||||||
{
|
|
||||||
title: '#comment($column)',
|
|
||||||
dataIndex: '${javaField}',
|
|
||||||
search: false,
|
|
||||||
width: 130,
|
|
||||||
render: (_, row) => <InputNumber min={0} value={row.${javaField} as number} onChange={value => handleSortChange(row, value)} />
|
|
||||||
},
|
|
||||||
#elseif($column.htmlType == "datetime")
|
|
||||||
{ title: '#comment($column)', dataIndex: '${javaField}', valueType: 'dateTime', search: #if($column.query && $column.queryType != "BETWEEN")true#else false#end, width: 170 },
|
|
||||||
#elseif($column.htmlType == "imageUpload")
|
|
||||||
{
|
|
||||||
title: '#comment($column)',
|
|
||||||
dataIndex: '${javaField}Url',
|
|
||||||
search: false,
|
|
||||||
width: 100,
|
|
||||||
render: (_, row) => <ImagePreview src={row.${javaField}Url || String(row.${javaField} || '')} width={50} height={50} />
|
|
||||||
},
|
|
||||||
#elseif($column.dictColumn)
|
|
||||||
{
|
|
||||||
title: '#comment($column)',
|
|
||||||
dataIndex: '${javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
fieldProps: { options: dictOptions(dicts.${dictType}) },
|
|
||||||
render: (_, row) => <DictTag options={dicts.${dictType}} value={row.${javaField}} />
|
|
||||||
},
|
|
||||||
#elseif($column.htmlType == "switch")
|
|
||||||
{
|
|
||||||
title: '#comment($column)',
|
|
||||||
dataIndex: '${javaField}',
|
|
||||||
valueType: 'select',
|
|
||||||
width: 100,
|
|
||||||
render: (_, row) => <Switch checked={row.${javaField} === #switchActiveValue($column)} disabled />
|
|
||||||
},
|
|
||||||
#else
|
|
||||||
{ title: '#comment($column)', dataIndex: '${javaField}'#if(!$column.query), search: false#end },
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
#if($column.query && $column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
|
||||||
{ title: '#comment($column)', dataIndex: '${javaField}Range', valueType: 'dateTimeRange', hideInTable: true },
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
valueType: 'option',
|
|
||||||
width: 92,
|
|
||||||
fixed: 'right',
|
|
||||||
render: (_, row) => (
|
|
||||||
<RowActions
|
|
||||||
actions={[
|
|
||||||
canEdit && { key: 'edit', label: '修改', icon: <EditOutlined />, onClick: () => openEdit(row) },
|
|
||||||
canRemove && {
|
|
||||||
key: 'delete',
|
|
||||||
label: '删除',
|
|
||||||
icon: <DeleteOutlined />,
|
|
||||||
danger: true,
|
|
||||||
confirm: `是否确认删除${functionName}编号为"#[[${row.]]#${pkColumn.javaField}#[[}]]#"的数据项?`,
|
|
||||||
onClick: () => remove(row)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer title="${functionName}">
|
|
||||||
<ProTable<${BusinessName}VO, ${BusinessName}Query#if($needDateRange) & Record<string, unknown>#end>
|
|
||||||
actionRef={actionRef}
|
|
||||||
rowKey="${pkColumn.javaField}"
|
|
||||||
columns={columns}
|
|
||||||
scroll={{ x: 1000 }}
|
|
||||||
search={{ labelWidth: 90 }}
|
|
||||||
pagination={{ defaultPageSize: 10, showSizeChanger: true }}
|
|
||||||
rowSelection={{ selectedRowKeys: ids, onChange: handleSelectionChange }}
|
|
||||||
request={async params => {
|
|
||||||
#if($needDateRange)
|
|
||||||
let query = toPageQuery(params);
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if($column.query && $column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
|
||||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
|
||||||
query = apply${AttrName}DateRange(query, params.${column.javaField}Range as [string, string] | undefined);
|
|
||||||
delete query.${column.javaField}Range;
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
#else
|
|
||||||
const query = toPageQuery(params);
|
|
||||||
#end
|
|
||||||
#if($enableExport)
|
|
||||||
updateExportParams(query);
|
|
||||||
#end
|
|
||||||
const res = await list${BusinessName}(query);
|
|
||||||
return toTableData(res);
|
|
||||||
}}
|
|
||||||
toolbar={{ title: '${functionName}列表' }}
|
|
||||||
toolBarRender={() => [
|
|
||||||
canAdd && (
|
|
||||||
<Button key="add" type="primary" icon={<PlusOutlined />} onClick={openAdd}>
|
|
||||||
新增
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
canEdit && (
|
|
||||||
<Button key="edit" disabled={!selectedOne} icon={<EditOutlined />} onClick={() => openEdit()}>
|
|
||||||
修改
|
|
||||||
</Button>
|
|
||||||
),
|
|
||||||
canRemove && (
|
|
||||||
<Popconfirm key="delete" title={`是否确认删除${functionName}编号为"#[[${ids}]]#"的数据项?`} onConfirm={() => remove()}>
|
|
||||||
<Button danger disabled={!ids.length} icon={<DeleteOutlined />}>
|
|
||||||
删除
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>
|
|
||||||
)#if($enableExport),
|
|
||||||
canExport && (
|
|
||||||
<Button
|
|
||||||
key="export"
|
|
||||||
icon={<DownloadOutlined />}
|
|
||||||
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_#[[${Date.now()}]]#.xlsx`)}
|
|
||||||
>
|
|
||||||
导出
|
|
||||||
</Button>
|
|
||||||
)#end
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ModalForm<${BusinessName}Form>
|
|
||||||
title={modalTitle}
|
|
||||||
open={modalOpen}
|
|
||||||
width={560}
|
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
initialValues={default${BusinessName}Form}
|
|
||||||
modalProps={{ destroyOnHidden: true, onCancel: closeModal }}
|
|
||||||
onOpenChange={open => !open && closeModal()}
|
|
||||||
onFinish={submitForm}
|
|
||||||
>
|
|
||||||
<ProFormText name="${pkColumn.javaField}" hidden />
|
|
||||||
#foreach($column in $columns)
|
|
||||||
#if(($column.insert || $column.edit) && !$column.pk)
|
|
||||||
#set($field=$column.javaField)
|
|
||||||
#set($dictType=$column.dictType)
|
|
||||||
#if($column.htmlType == "input")
|
|
||||||
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
|
||||||
#elseif($column.htmlType == "textarea")
|
|
||||||
<ProFormTextArea name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
|
||||||
#elseif($column.htmlType == "inputNumber")
|
|
||||||
<ProFormDigit name="${field}" label="#comment($column)" min={0} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
|
||||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch") && "" != $dictType)
|
|
||||||
<ProFormSelect name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
|
||||||
#elseif($column.htmlType == "checkbox" && "" != $dictType)
|
|
||||||
<ProFormCheckbox.Group name="${field}" label="#comment($column)" options={dictOptions(dicts.${dictType})} #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
|
||||||
#elseif($column.htmlType == "switch")
|
|
||||||
<Form.Item
|
|
||||||
name="${field}"
|
|
||||||
label="#comment($column)"
|
|
||||||
valuePropName="checked"
|
|
||||||
getValueProps={value => ({ checked: value === #switchActiveValue($column) })}
|
|
||||||
normalize={checked => (checked ? #switchActiveValue($column) : #switchInactiveValue($column))}
|
|
||||||
>
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
#elseif($column.htmlType == "datetime")
|
|
||||||
<ProFormDateTimePicker name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
|
||||||
#elseif($column.htmlType == "imageUpload")
|
|
||||||
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
|
|
||||||
<ImageUpload />
|
|
||||||
</Form.Item>
|
|
||||||
#elseif($column.htmlType == "fileUpload")
|
|
||||||
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
|
|
||||||
<FileUpload />
|
|
||||||
</Form.Item>
|
|
||||||
#elseif($column.htmlType == "editor")
|
|
||||||
<Form.Item name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
|
|
||||||
<RichTextEditor />
|
|
||||||
</Form.Item>
|
|
||||||
#else
|
|
||||||
<ProFormText name="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
</ModalForm>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
57
gen/types.ts.ftl
Normal file
57
gen/types.ts.ftl
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import type { BaseEntity<#if !table.tree>, PageQuery</#if> } from '@/api/types';
|
||||||
|
|
||||||
|
export interface ${BusinessName}VO {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.list || column.pk>
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}
|
||||||
|
*/
|
||||||
|
${column.javaField}: ${column.tsType};
|
||||||
|
<#if column.htmlType == "imageUpload">
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}Url
|
||||||
|
*/
|
||||||
|
${column.javaField}Url?: string;
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
<#if table.tree>
|
||||||
|
/**
|
||||||
|
* 子对象
|
||||||
|
*/
|
||||||
|
children?: ${BusinessName}VO[];
|
||||||
|
</#if>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ${BusinessName}Form extends BaseEntity {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.insert || column.edit || column.pk>
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}
|
||||||
|
*/
|
||||||
|
<#if column.htmlType == "checkbox">
|
||||||
|
${column.javaField}?: string | string[];
|
||||||
|
<#else>
|
||||||
|
${column.javaField}?: ${column.tsType};
|
||||||
|
</#if>
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ${BusinessName}Query<#if !table.tree> extends PageQuery</#if> {
|
||||||
|
<#list columns as column>
|
||||||
|
<#if column.query>
|
||||||
|
/**
|
||||||
|
* ${column.columnComment}
|
||||||
|
*/
|
||||||
|
${column.javaField}?: ${column.tsType};
|
||||||
|
</#if>
|
||||||
|
</#list>
|
||||||
|
/**
|
||||||
|
* 日期范围参数
|
||||||
|
*/
|
||||||
|
params?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
import type { BaseEntity#if(!$table.tree), PageQuery#end } from '@/api/types';
|
|
||||||
|
|
||||||
#macro(tsType $column)#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
|
|
||||||
|
|
||||||
export interface ${BusinessName}VO {
|
|
||||||
#foreach ($column in $columns)
|
|
||||||
#if($column.list || $column.pk)
|
|
||||||
/**
|
|
||||||
* $column.columnComment
|
|
||||||
*/
|
|
||||||
$column.javaField: #tsType($column);
|
|
||||||
#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.pk)
|
|
||||||
/**
|
|
||||||
* $column.columnComment
|
|
||||||
*/
|
|
||||||
#if($column.htmlType == "checkbox")
|
|
||||||
$column.javaField?: string | string[];
|
|
||||||
#else
|
|
||||||
$column.javaField?: #tsType($column);
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ${BusinessName}Query#if(!$table.tree) extends PageQuery#end {
|
|
||||||
#foreach ($column in $columns)
|
|
||||||
#if($column.query)
|
|
||||||
/**
|
|
||||||
* $column.columnComment
|
|
||||||
*/
|
|
||||||
$column.javaField?: #tsType($column);
|
|
||||||
#end
|
|
||||||
#end
|
|
||||||
/**
|
|
||||||
* 日期范围参数
|
|
||||||
*/
|
|
||||||
params?: Record<string, unknown>;
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user