update 重构 将代码生成vm模板替换为fm模板 语法更清晰明了

This commit is contained in:
疯狂的狮子Li
2026-06-18 14:59:06 +08:00
parent 06d4e6d7f1
commit f04197b401
34 changed files with 1671 additions and 1689 deletions
+9 -9
View File
@@ -32,7 +32,7 @@ description: 在仓库内按代码生成器模板、项目 reference 文档和
1. 先判断任务类型,并按“文档读取规则”读取当前任务需要的 reference。
2. 确认目标模块,优先复用同模块中最近似功能的写法。
3. 新增标准 CRUD 代码前,先读取 `ruoyi-modules/ruoyi-gen/src/main/resources/vm/` 下的模板。
3. 新增标准 CRUD 代码前,先读取 `ruoyi-modules/ruoyi-gen/src/main/resources/fm/` 下的 FreeMarker 模板。
4. 命名和分层保持与仓库一致:
`domain` entity、`domain.bo``domain.vo``mapper``service``service.impl``controller`
5. 优先在生成器结构上扩展,不要自行发明新的分层。
@@ -108,14 +108,14 @@ Vue 3、TypeScript API 文件、生成式列表页、表单状态、字典和日
标准生成器模板通常对应:
- `vm/java/domain.java.vm` -> entity
- `vm/java/bo.java.vm` -> bo
- `vm/java/vo.java.vm` -> vo
- `vm/java/mapper.java.vm` -> mapper
- `vm/java/service.java.vm` -> service interface
- `vm/java/serviceImpl.java.vm` -> service impl
- `vm/java/controller.java.vm` -> controller
- `vm/xml/mapper.xml.vm` -> 自定义 XML mapper 起点
- `fm/java/domain.java.ftl` -> entity
- `fm/java/bo.java.ftl` -> bo
- `fm/java/vo.java.ftl` -> vo
- `fm/java/mapper.java.ftl` -> mapper
- `fm/java/service.java.ftl` -> service interface
- `fm/java/serviceImpl.java.ftl` -> service impl
- `fm/java/controller.java.ftl` -> controller
- `fm/xml/mapper.xml.ftl` -> 自定义 XML mapper 起点
## 任务分型
@@ -2,7 +2,7 @@
## 优先参考的代码来源
- `ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/*.vm`
- `ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/*.ftl`
- `ruoyi-modules/ruoyi-demo/...`
- `ruoyi-modules/ruoyi-system/...`
- `ruoyi-modules/ruoyi-workflow/...`
@@ -2,18 +2,18 @@
## 优先参考的代码来源
- `ruoyi-modules/ruoyi-gen/src/main/resources/vm/<frontendType>/*.vm`
- 默认 Vue 模板在 `vm/vue`React 模板在 `vm/react`
- `ruoyi-modules/ruoyi-gen/src/main/resources/fm/<frontendType>/*.ftl`
- 默认 Vue 模板在 `fm/vue`React 模板在 `fm/react`
- 前端工程中与目标模块最接近的现有页面
当前 boot4 仓库通常只含后端与 generator 前端模板;如果前端工程不在当前 root,先以 generator 模板约定为准,再对照用户提供的前端目录或相邻仓库。
## 前端模板选择规则
- `gen_table.frontend_type` 存字符串,值直接对应 `vm` 下的模板目录,例如 `vue``react`
- 生成器按 `vm/<frontendType>/api.ts.vm``types.ts.vm``index.*.vm``index-tree.*.vm` 查找模板。
- 页面输出后缀由页面模板文件名决定:`index.vue.vm` 输出 `index.vue``index.tsx.vm` 输出 `index.tsx`
- 新增其他前端时优先只新增 `vm/<frontendType>` 目录和对应 VM 文件,不在 Java 代码里增加数字枚举或硬编码分支。
- `gen_table.frontend_type` 存字符串,值直接对应 `fm` 下的模板目录,例如 `vue``react`
- 生成器按 `fm/<frontendType>/api.ts.ftl``types.ts.ftl``index.*.ftl``index-tree.*.ftl` 查找模板。
- 页面输出后缀由页面模板文件名决定:`index.vue.ftl` 输出 `index.vue``index.tsx.ftl` 输出 `index.tsx`
- 新增其他前端时优先只新增 `fm/<frontendType>` 目录和对应 FTL 文件,不在 Java 代码里增加数字枚举或硬编码分支。
## API 文件规则
+1 -9
View File
@@ -14,7 +14,7 @@
<properties>
<!-- 项目基础配置 -->
<revision>5.5.3</revision>
<revision>6.0.0</revision>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>21</java.version>
@@ -52,7 +52,6 @@
<lombok.version>1.18.42</lombok.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<fesod.version>2.0.2-incubating</fesod.version>
<velocity.version>2.4.1</velocity.version>
<fory.version>1.2.0</fory.version>
<!-- 三方集成与业务扩展相关依赖版本 -->
@@ -192,13 +191,6 @@
<version>${fesod.version}</version>
</dependency>
<!-- velocity代码生成使用模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
+3 -3
View File
@@ -46,10 +46,10 @@
<artifactId>ruoyi-common-log</artifactId>
</dependency>
<!--velocity代码生成使用模板 -->
<!-- FreeMarker代码生成模板 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
<!-- AnyLine Spring JDBC 环境 -->
@@ -81,7 +81,7 @@ public interface GenConstants {
String SORT_FIELD = "sortField";
/**
* 默认前端模板类型,对应 vm/vue 目录。
* 默认前端模板类型,对应模板根目录下的 vue 目录。
*/
String FRONTEND_TYPE_VUE = "vue";
@@ -262,26 +262,34 @@ public interface GenConstants {
*/
String REQUIRE = "1";
// 模板根路径与后缀
String TEMPLATE_ROOT_PATH = "fm";
String TEMPLATE_FILE_SUFFIX = ".ftl";
String TEMPLATE_RESOURCE_PREFIX = "classpath*:";
String TEMPLATE_PAGE_PATTERN_SUFFIX = ".*" + TEMPLATE_FILE_SUFFIX;
// 后端源码模板
String JAVA_DOMAIN_TEMPLATE_PATH = "vm/java/domain.java.vm";
String JAVA_VO_TEMPLATE_PATH = "vm/java/vo.java.vm";
String JAVA_BO_TEMPLATE_PATH = "vm/java/bo.java.vm";
String JAVA_MAPPER_TEMPLATE_PATH = "vm/java/mapper.java.vm";
String JAVA_SERVICE_TEMPLATE_PATH = "vm/java/service.java.vm";
String JAVA_SERVICE_IMPL_TEMPLATE_PATH = "vm/java/serviceImpl.java.vm";
String JAVA_CONTROLLER_TEMPLATE_PATH = "vm/java/controller.java.vm";
String JAVA_TEMPLATE_ROOT_PATH = TEMPLATE_ROOT_PATH + "/java";
String JAVA_DOMAIN_TEMPLATE_PATH = JAVA_TEMPLATE_ROOT_PATH + "/domain.java" + TEMPLATE_FILE_SUFFIX;
String JAVA_VO_TEMPLATE_PATH = JAVA_TEMPLATE_ROOT_PATH + "/vo.java" + TEMPLATE_FILE_SUFFIX;
String JAVA_BO_TEMPLATE_PATH = JAVA_TEMPLATE_ROOT_PATH + "/bo.java" + TEMPLATE_FILE_SUFFIX;
String JAVA_MAPPER_TEMPLATE_PATH = JAVA_TEMPLATE_ROOT_PATH + "/mapper.java" + TEMPLATE_FILE_SUFFIX;
String JAVA_SERVICE_TEMPLATE_PATH = JAVA_TEMPLATE_ROOT_PATH + "/service.java" + TEMPLATE_FILE_SUFFIX;
String JAVA_SERVICE_IMPL_TEMPLATE_PATH = JAVA_TEMPLATE_ROOT_PATH + "/serviceImpl.java" + TEMPLATE_FILE_SUFFIX;
String JAVA_CONTROLLER_TEMPLATE_PATH = JAVA_TEMPLATE_ROOT_PATH + "/controller.java" + TEMPLATE_FILE_SUFFIX;
// MyBatis MapperXML 模板
String XML_MAPPER_TEMPLATE_PATH = "vm/xml/mapper.xml.vm";
String XML_TEMPLATE_ROOT_PATH = TEMPLATE_ROOT_PATH + "/xml";
String XML_MAPPER_TEMPLATE_PATH = XML_TEMPLATE_ROOT_PATH + "/mapper.xml" + TEMPLATE_FILE_SUFFIX;
// 前端源码模板
String FRONTEND_API_TEMPLATE_NAME = "api.ts.vm";
String FRONTEND_TYPES_TEMPLATE_NAME = "types.ts.vm";
String FRONTEND_API_TEMPLATE_NAME = "api.ts" + TEMPLATE_FILE_SUFFIX;
String FRONTEND_TYPES_TEMPLATE_NAME = "types.ts" + TEMPLATE_FILE_SUFFIX;
String FRONTEND_INDEX_TEMPLATE_PREFIX = "index";
String FRONTEND_INDEX_TREE_TEMPLATE_PREFIX = "index-tree";
// 数据库SQL模板
String SQL_ORACLE_TEMPLATE_PATH = "vm/sql/oracle.sql.vm";
String SQL_POSTGRES_TEMPLATE_PATH = "vm/sql/postgres.sql.vm";
String SQL_SQLSERVER_TEMPLATE_PATH = "vm/sql/sqlserver.sql.vm";
String SQL_MYSQL_TEMPLATE_PATH = "vm/sql/mysql.sql.vm";
String SQL_TEMPLATE_ROOT_PATH = TEMPLATE_ROOT_PATH + "/sql";
String SQL_ORACLE_TEMPLATE_PATH = SQL_TEMPLATE_ROOT_PATH + "/oracle.sql" + TEMPLATE_FILE_SUFFIX;
String SQL_POSTGRES_TEMPLATE_PATH = SQL_TEMPLATE_ROOT_PATH + "/postgres.sql" + TEMPLATE_FILE_SUFFIX;
String SQL_SQLSERVER_TEMPLATE_PATH = SQL_TEMPLATE_ROOT_PATH + "/sqlserver.sql" + TEMPLATE_FILE_SUFFIX;
String SQL_MYSQL_TEMPLATE_PATH = SQL_TEMPLATE_ROOT_PATH + "/mysql.sql" + TEMPLATE_FILE_SUFFIX;
/**
* 固定模板路径集合,前端模板按 frontendType 动态解析。
@@ -62,7 +62,7 @@ public class GenTable extends BaseEntity {
private String tplCategory;
/**
* 前端模板类型,对应 vm 下的模板目录
* 前端模板类型,对应 fm 下的模板目录
*/
private String frontendType;
@@ -132,6 +132,80 @@ public class GenTableColumn extends BaseEntity {
return StringUtils.capitalize(javaField);
}
/**
* 获取适合界面展示的字段注释,去除括号内的枚举说明。
*
* @return 字段展示名称
*/
public String getColumnLabel() {
int index = StringUtils.indexOf(this.columnComment, "");
if (index != StringUtils.INDEX_NOT_FOUND) {
return StringUtils.substring(this.columnComment, 0, index);
}
return this.columnComment;
}
/**
* 获取 TypeScript 字段类型。
*
* @return TypeScript 类型
*/
public String getTsType() {
if (StringUtils.containsAny(this.javaField, "id", "Id")) {
return "string | number";
}
if (StringUtils.equalsAny(this.javaType,
GenConstants.TYPE_LONG, GenConstants.TYPE_INTEGER, GenConstants.TYPE_DOUBLE,
"Float", GenConstants.TYPE_BIGDECIMAL)) {
return "number";
}
if (StringUtils.equals(this.javaType, GenConstants.TYPE_BOOLEAN)) {
return "boolean";
}
return "string";
}
/**
* 获取开关启用值的前端字面量。
*
* @return 前端字面量
*/
public String getSwitchActiveValue() {
if (StringUtils.equals(this.javaType, GenConstants.TYPE_BOOLEAN)) {
return "true";
}
if (StringUtils.equalsAny(this.javaType, GenConstants.TYPE_INTEGER, GenConstants.TYPE_LONG)) {
return "0";
}
return "'0'";
}
/**
* 获取开关停用值的前端字面量。
*
* @return 前端字面量
*/
public String getSwitchInactiveValue() {
if (StringUtils.equals(this.javaType, GenConstants.TYPE_BOOLEAN)) {
return "false";
}
if (StringUtils.equalsAny(this.javaType, GenConstants.TYPE_INTEGER, GenConstants.TYPE_LONG)) {
return "1";
}
return "'1'";
}
/**
* 是否为日期范围查询字段。
*
* @return 日期范围查询字段返回 {@code true}
*/
public boolean isDateRangeQuery() {
return isQuery()
&& StringUtils.equals(this.htmlType, GenConstants.HTML_DATETIME)
&& StringUtils.equals(this.queryType, GenConstants.QUERY_BETWEEN);
}
/**
* 判断当前列是否为主键列。
*
@@ -6,6 +6,7 @@ import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import cn.hutool.extra.template.engine.freemarker.FreemarkerEngine;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -59,6 +60,7 @@ public class TemplateEngineUtils {
static {
// 模板引擎初始化
GenProperties properties = SpringUtils.getBean(GenProperties.class);
properties.getTemplateConfig().setCustomEngine(FreemarkerEngine.class);
TEMPLATE_ENGINE = TemplateUtil.createEngine(properties.getTemplateConfig());
TEMPLATE_MAPPER = PathNamedTemplate.form(TEMPLATE_ENGINE, GenConstants.TEMPLATE_PATHS);
}
@@ -104,11 +106,14 @@ public class TemplateEngineUtils {
context.put("author", genTable.getFunctionAuthor());
context.put("datetime", DateUtils.now());
context.put("pkColumn", genTable.getPkColumn());
String dicts = getDicts(genTable);
context.put("importList", getImportList(genTable));
context.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
context.put("columns", genTable.getColumns());
context.put("table", genTable);
context.put("dicts", getDicts(genTable));
context.put("dicts", dicts);
context.put("dictsNoSymbol", StringUtils.replace(dicts, "'", StringUtils.EMPTY));
setColumnFeatureContext(context, genTable, dicts);
// 向模板上下文写入菜单相关变量
String options = genTable.getOptions();
Dict paramsObj = JsonUtils.parseMap(options);
@@ -133,6 +138,8 @@ public class TemplateEngineUtils {
context.put("enableSort", enableSort && ObjectUtil.isNotNull(sortColumn));
context.put("sortColumn", sortColumn);
context.put("sortField", ObjectUtil.isNotNull(sortColumn) ? sortColumn.getJavaField() : StringUtils.EMPTY);
context.put("statusActiveValue", ObjectUtil.isNotNull(statusColumn) ? statusColumn.getSwitchActiveValue() : StringUtils.EMPTY);
context.put("statusInactiveValue", ObjectUtil.isNotNull(statusColumn) ? statusColumn.getSwitchInactiveValue() : StringUtils.EMPTY);
// 向树形模板上下文写入树字段相关变量
if (GenConstants.TPL_TREE.equals(tplCategory)) {
@@ -142,6 +149,71 @@ public class TemplateEngineUtils {
return context;
}
/**
* 写入模板中常用的列派生开关,避免在模板内反复扫描和处理。
*
* @param context 模板上下文
* @param genTable 代码生成业务表对象
* @param dicts 字典类型表达式
*/
private static void setColumnFeatureContext(Dict context, GenTable genTable, String dicts) {
boolean hasBetween = false;
boolean needImagePreview = false;
boolean needImageUpload = false;
boolean needFileUpload = false;
boolean needEditor = false;
boolean needCheckbox = false;
boolean needSelect = false;
boolean needTextArea = false;
boolean needDigit = false;
boolean needDateField = false;
boolean needSwitchField = false;
String firstTreeListField = StringUtils.EMPTY;
for (GenTableColumn column : genTable.getColumns()) {
boolean writable = column.isInsert() || column.isEdit();
hasBetween = hasBetween || column.isQuery() && StringUtils.equals(column.getQueryType(), GenConstants.QUERY_BETWEEN);
needImagePreview = needImagePreview || column.isList() && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_IMAGE_UPLOAD);
needImageUpload = needImageUpload || writable && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_IMAGE_UPLOAD);
needFileUpload = needFileUpload || writable && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_FILE_UPLOAD);
needEditor = needEditor || writable && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_EDITOR);
needCheckbox = needCheckbox || writable && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_CHECKBOX);
needSelect = needSelect || (writable || column.isQuery()) && StringUtils.equalsAny(column.getHtmlType(),
GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_SWITCH);
needTextArea = needTextArea || writable && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_TEXTAREA);
needDigit = needDigit || writable && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_INPUT_NUMBER);
needDateField = needDateField || writable && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_DATETIME);
needSwitchField = needSwitchField || (writable || column.isList()) && StringUtils.equals(column.getHtmlType(), GenConstants.HTML_SWITCH);
if (StringUtils.isBlank(firstTreeListField) && column.isList()) {
firstTreeListField = column.getJavaField();
}
}
boolean needDateRange = hasDateRangeQuery(genTable);
context.put("hasBetween", hasBetween);
context.put("needAddDateRange", needDateRange);
context.put("needDateRange", needDateRange);
context.put("needDict", StringUtils.isNotBlank(dicts));
context.put("needImagePreview", needImagePreview);
context.put("needImageUpload", needImageUpload);
context.put("needFileUpload", needFileUpload);
context.put("needEditor", needEditor);
context.put("needCheckbox", needCheckbox);
context.put("needSelect", needSelect);
context.put("needTextArea", needTextArea);
context.put("needDigit", needDigit);
context.put("needDateField", needDateField);
context.put("needSwitchField", needSwitchField);
context.put("firstTreeListField", firstTreeListField);
}
private static boolean hasDateRangeQuery(GenTable genTable) {
for (GenTableColumn column : genTable.getColumns()) {
if (column.isDateRangeQuery()) {
return true;
}
}
return false;
}
/**
* 向树形模板上下文写入树字段相关变量。
*
@@ -168,6 +240,9 @@ public class TemplateEngineUtils {
context.put("treeRootValue", treeRootValue);
context.put("treeRootValueJavaLiteral", getJavaLiteral(treeParentColumn, treeRootValue));
context.put("treeRootValueTsLiteral", getTsLiteral(treeParentColumn, treeRootValue));
context.put("treeParentCap", StringUtils.capitalize(treeParentCode));
context.put("treeAncestorsCap", StringUtils.capitalize(ObjectUtil.isNotNull(treeAncestorsColumn) ? treeAncestorsColumn.getJavaField() : StringUtils.EMPTY));
context.put("treeOrderCap", StringUtils.capitalize(ObjectUtil.isNotNull(treeOrderColumn) ? treeOrderColumn.getJavaField() : StringUtils.EMPTY));
String expandTreeName = paramsObj.getStr(GenConstants.TREE_NAME);
int expandColumn = 0;
for (GenTableColumn column : genTable.getColumns()) {
@@ -241,7 +316,7 @@ public class TemplateEngineUtils {
}
/**
* 获取模板,支持按前端模板类型动态加载 vm/{frontendType} 下的模板。
* 获取模板,支持按前端模板类型动态加载模板根目录下的模板。
*
* @param templatePath 模板路径
* @return 带路径名的模板
@@ -278,27 +353,27 @@ public class TemplateEngineUtils {
String frontendPath = getFrontendPath(genTable.getFrontendType());
// templatePath
// genFilePathFormat
if (template.contains("domain.java.vm")) {
if (template.contains("domain.java.")) {
fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
} else if (template.contains("vo.java.vm")) {
} else if (template.contains("vo.java.")) {
fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className);
} else if (template.contains("bo.java.vm")) {
} else if (template.contains("bo.java.")) {
fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className);
} else if (template.contains("mapper.java.vm")) {
} else if (template.contains("mapper.java.")) {
fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
} else if (template.contains("service.java.vm")) {
} else if (template.contains("service.java.")) {
fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
} else if (template.contains("serviceImpl.java.vm")) {
} else if (template.contains("serviceImpl.java.")) {
fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
} else if (template.contains("controller.java.vm")) {
} else if (template.contains("controller.java.")) {
fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
} else if (template.contains("mapper.xml.vm")) {
} else if (template.contains("mapper.xml.")) {
fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
} else if (template.contains("sql.vm")) {
} else if (template.contains("sql.")) {
fileName = businessName + "Menu.sql";
} else if (template.contains("api.ts.vm")) {
} else if (template.contains("api.ts.")) {
fileName = StringUtils.format("{}/api/{}/{}/index.ts", frontendPath, moduleName, businessName);
} else if (template.contains("types.ts.vm")) {
} else if (template.contains("types.ts.")) {
fileName = StringUtils.format("{}/api/{}/{}/types.ts", frontendPath, moduleName, businessName);
} else if (isFrontendPageTemplate(template, GenConstants.FRONTEND_INDEX_TEMPLATE_PREFIX)) {
fileName = StringUtils.format("{}/views/{}/{}/index.{}", frontendPath, moduleName, businessName,
@@ -329,7 +404,9 @@ public class TemplateEngineUtils {
*/
private static String getFrontendPageExtension(String template, String templatePrefix) {
String fileName = getTemplateFileName(template);
return fileName.substring((templatePrefix + ".").length(), fileName.length() - ".vm".length());
int suffixIndex = fileName.lastIndexOf('.');
String withoutTemplateSuffix = suffixIndex >= 0 ? fileName.substring(0, suffixIndex) : fileName;
return withoutTemplateSuffix.substring((templatePrefix + ".").length());
}
private static String getFrontendApiTemplatePath(String frontendType) {
@@ -363,7 +440,7 @@ public class TemplateEngineUtils {
}
private static String getFrontendTemplatePath(String frontendType, String templateName) {
return StringUtils.format("vm/{}/{}", resolveFrontendType(frontendType), templateName);
return StringUtils.format("{}/{}/{}", GenConstants.TEMPLATE_ROOT_PATH, resolveFrontendType(frontendType), templateName);
}
/**
@@ -375,27 +452,33 @@ public class TemplateEngineUtils {
*/
private static String getFrontendPageTemplatePath(String frontendType, String templatePrefix) {
String type = resolveFrontendType(frontendType);
String pattern = StringUtils.format("classpath*:vm/{}/{}.*.vm", type, templatePrefix);
String templatePathPattern = getFrontendPageTemplatePathPattern(type, templatePrefix);
String resourcePattern = GenConstants.TEMPLATE_RESOURCE_PREFIX + templatePathPattern;
try {
Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(pattern);
Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(resourcePattern);
if (resources.length == 0) {
throw new ServiceException(StringUtils.format("未找到前端模板: vm/{}/{}.*.vm", type, templatePrefix));
throw new ServiceException(StringUtils.format("未找到前端模板: {}", templatePathPattern));
}
return Arrays.stream(resources)
.map(Resource::getFilename)
.filter(StringUtils::isNotBlank)
.sorted()
.findFirst()
.map(fileName -> StringUtils.format("vm/{}/{}", type, fileName))
.orElseThrow(() -> new ServiceException(StringUtils.format("未找到前端模板: vm/{}/{}.*.vm", type, templatePrefix)));
.map(fileName -> StringUtils.format("{}/{}/{}", GenConstants.TEMPLATE_ROOT_PATH, type, fileName))
.orElseThrow(() -> new ServiceException(StringUtils.format("未找到前端模板: {}", templatePathPattern)));
} catch (IOException e) {
throw new ServiceException(StringUtils.format("读取前端模板失败: vm/{}/{}.*.vm", type, templatePrefix), e);
throw new ServiceException(StringUtils.format("读取前端模板失败: {}", templatePathPattern), e);
}
}
private static String getFrontendPageTemplatePathPattern(String frontendType, String templatePrefix) {
return StringUtils.format("{}/{}/{}{}", GenConstants.TEMPLATE_ROOT_PATH, frontendType,
templatePrefix, GenConstants.TEMPLATE_PAGE_PATTERN_SUFFIX);
}
private static boolean isFrontendPageTemplate(String template, String templatePrefix) {
String fileName = getTemplateFileName(template);
return fileName.startsWith(templatePrefix + ".") && fileName.endsWith(".vm");
return fileName.startsWith(templatePrefix + ".") && fileName.endsWith(GenConstants.TEMPLATE_FILE_SUFFIX);
}
private static String getTemplateFileName(String template) {
@@ -430,10 +513,6 @@ public class TemplateEngineUtils {
} else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
importList.add("java.math.BigDecimal");
}
if (!column.isSuperColumn() && GenConstants.QUERY_BETWEEN.equals(column.getQueryType())) {
importList.add("java.util.HashMap");
importList.add("java.util.Map");
}
}
return importList;
}
@@ -0,0 +1,63 @@
package ${packageName}.domain.bo;
import ${packageName}.domain.${ClassName};
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import java.io.Serial;
import java.io.Serializable;
<#if hasBetween>
import java.util.HashMap;
import java.util.Map;
</#if>
import lombok.Data;
import jakarta.validation.constraints.*;
<#list importList as import>
import ${import};
</#list>
/**
* ${functionName}业务对象 ${tableName}
*
* @author ${author}
* @date ${datetime}
*/
@Data
@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false)
public class ${ClassName}Bo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
<#list columns as column>
<#if !table.isSuperColumn(column.javaField) && (column.query || column.insert || column.edit)>
/**
* ${column.columnComment}
*/
<#if column.insert && column.edit>
<#assign Group = "AddGroup.class, EditGroup.class">
<#elseif column.insert>
<#assign Group = "AddGroup.class">
<#elseif column.edit>
<#assign Group = "EditGroup.class">
</#if>
<#if column.required>
<#if column.javaType == 'String'>
@NotBlank(message = "${column.columnComment}不能为空", groups = { ${Group} })
<#else>
@NotNull(message = "${column.columnComment}不能为空", groups = { ${Group} })
</#if>
</#if>
private ${column.javaType} ${column.javaField};
</#if>
</#list>
<#if hasBetween>
/**
* 查询参数
*/
private Map<String, Object> params = new HashMap<>();
</#if>
}
@@ -3,9 +3,9 @@ package ${packageName}.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
#if($enableExport)
<#if enableExport>
import jakarta.servlet.http.HttpServletResponse;
#end
</#if>
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
@@ -18,16 +18,16 @@ import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
#if($enableExport)
<#if enableExport>
import org.dromara.common.excel.utils.ExcelBuilder;
#end
</#if>
import ${packageName}.domain.vo.${ClassName}Vo;
import ${packageName}.domain.bo.${ClassName}Bo;
import ${packageName}.service.I${ClassName}Service;
#if($table.crud)
<#if table.crud>
import org.dromara.common.core.domain.PageResult;
#elseif($table.tree)
#end
<#elseif table.tree>
</#if>
/**
* ${functionName}
@@ -48,21 +48,21 @@ public class ${ClassName}Controller extends BaseController {
*/
@SaCheckPermission("${permissionPrefix}:list")
@GetMapping("/list")
#if($table.crud)
<#if table.crud>
public R<PageResult<${ClassName}Vo>> list(${ClassName}Bo bo, PageQuery pageQuery) {
return R.ok(${className}Service.queryPageList(bo, pageQuery));
}
#elseif($table.tree)
<#elseif table.tree>
public R<List<${ClassName}Vo>> list(${ClassName}Bo bo) {
List<${ClassName}Vo> list = ${className}Service.queryList(bo);
return R.ok(list);
}
#end
</#if>
/**
* 导出${functionName}列表
*/
#if($enableExport)
<#if enableExport>
@SaCheckPermission("${permissionPrefix}:export")
@Log(title = "${functionName}", businessType = BusinessType.EXPORT)
@PostMapping("/export")
@@ -70,7 +70,7 @@ public class ${ClassName}Controller extends BaseController {
List<${ClassName}Vo> list = ${className}Service.queryList(bo);
ExcelBuilder.of(list, ${ClassName}Vo.class).sheetName("${functionName}").toResponse(response);
}
#end
</#if>
/**
* 获取${functionName}详细信息
@@ -92,11 +92,11 @@ public class ${ClassName}Controller extends BaseController {
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) {
#if($enableUnique)
<#if enableUnique>
if (!${className}Service.checkUnique(bo)) {
return R.fail("新增${functionName}失败,组合唯一字段已存在");
}
#end
</#if>
return toAjax(${className}Service.insertByBo(bo));
}
@@ -108,15 +108,15 @@ public class ${ClassName}Controller extends BaseController {
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) {
#if($enableUnique)
<#if enableUnique>
if (!${className}Service.checkUnique(bo)) {
return R.fail("修改${functionName}失败,组合唯一字段已存在");
}
#end
</#if>
return toAjax(${className}Service.updateByBo(bo));
}
#if($enableStatus)
<#if enableStatus>
/**
* 修改${functionName}状态
*/
@@ -126,9 +126,9 @@ public class ${ClassName}Controller extends BaseController {
public R<Void> changeStatus(@RequestBody ${ClassName}Bo bo) {
return toAjax(${className}Service.updateStatus(bo.get${pkColumn.capJavaField}(), bo.get${statusColumn.capJavaField}()));
}
#end
</#if>
#if($enableSort)
<#if enableSort>
/**
* 调整${functionName}排序
*/
@@ -138,7 +138,7 @@ public class ${ClassName}Controller extends BaseController {
public R<Void> updateSort(@RequestBody ${ClassName}Bo bo) {
return toAjax(${className}Service.updateSort(bo.get${pkColumn.capJavaField}(), bo.get${sortColumn.capJavaField}()));
}
#end
</#if>
/**
* 删除${functionName}
@@ -153,3 +153,5 @@ public class ${ClassName}Controller extends BaseController {
return toAjax(${className}Service.deleteWithValidByIds(List.of(${pkColumn.javaField}s), true));
}
}
@@ -4,9 +4,9 @@ import org.dromara.common.mybatis.core.domain.BaseEntity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
#foreach ($import in $importList)
<#list importList as import>
import ${import};
#end
</#list>
import java.io.Serial;
@@ -16,34 +16,35 @@ import java.io.Serial;
* @author ${author}
* @date ${datetime}
*/
#set($Entity="BaseEntity")
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("${tableName}")
public class ${ClassName} extends ${Entity} {
public class ${ClassName} extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField))
<#list columns as column>
<#if !table.isSuperColumn(column.javaField)>
/**
* $column.columnComment
* ${column.columnComment}
*/
#if($column.javaField=='delFlag')
<#if column.javaField=='delFlag'>
@TableLogic
#end
#if($column.javaField=='version')
</#if>
<#if column.javaField=='version'>
@Version
#end
#if($column.isPk==1)
@TableId(value = "$column.columnName")
#elseif($column.needTableField)
@TableField(value = "$column.columnName")
#end
private $column.javaType $column.javaField;
</#if>
<#if column.pk>
@TableId(value = "${column.columnName}")
<#elseif column.needTableField>
@TableField(value = "${column.columnName}")
</#if>
private ${column.javaType} ${column.javaField};
#end
#end
</#if>
</#list>
}
@@ -13,3 +13,6 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> {
}
@@ -2,10 +2,10 @@ package ${packageName}.service;
import ${packageName}.domain.vo.${ClassName}Vo;
import ${packageName}.domain.bo.${ClassName}Bo;
#if($table.crud)
<#if table.crud>
import org.dromara.common.core.domain.PageResult;
import org.dromara.common.mybatis.core.page.PageQuery;
#end
</#if>
import java.util.Collection;
import java.util.List;
@@ -26,7 +26,7 @@ public interface I${ClassName}Service {
*/
${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField});
#if($table.crud)
<#if table.crud>
/**
* 分页查询${functionName}列表
*
@@ -35,7 +35,7 @@ public interface I${ClassName}Service {
* @return ${functionName}分页列表
*/
PageResult<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery);
#end
</#if>
/**
* 查询符合条件的${functionName}列表
@@ -45,7 +45,7 @@ public interface I${ClassName}Service {
*/
List<${ClassName}Vo> queryList(${ClassName}Bo bo);
#if($enableUnique)
<#if enableUnique>
/**
* 校验${functionName}是否满足组合唯一约束
*
@@ -53,7 +53,7 @@ public interface I${ClassName}Service {
* @return 是否唯一
*/
boolean checkUnique(${ClassName}Bo bo);
#end
</#if>
/**
* 新增${functionName}
@@ -71,7 +71,7 @@ public interface I${ClassName}Service {
*/
Boolean updateByBo(${ClassName}Bo bo);
#if($enableStatus)
<#if enableStatus>
/**
* 修改${functionName}状态
*
@@ -80,9 +80,9 @@ public interface I${ClassName}Service {
* @return 是否修改成功
*/
Boolean updateStatus(${pkColumn.javaType} ${pkColumn.javaField}, ${statusColumn.javaType} status);
#end
</#if>
#if($enableSort)
<#if enableSort>
/**
* 调整${functionName}排序
*
@@ -91,7 +91,7 @@ public interface I${ClassName}Service {
* @return 是否修改成功
*/
Boolean updateSort(${pkColumn.javaType} ${pkColumn.javaField}, ${sortColumn.javaType} sortValue);
#end
</#if>
/**
* 校验并批量删除${functionName}信息
@@ -102,3 +102,6 @@ public interface I${ClassName}Service {
*/
Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid);
}
@@ -3,15 +3,15 @@ package ${packageName}.service.impl;
import cn.hutool.core.util.ObjectUtil;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
#if($table.crud)
<#if table.crud>
import org.dromara.common.core.domain.PageResult;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
#end
</#if>
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
#if($enableUnique)
<#if enableUnique>
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
#end
</#if>
import org.dromara.common.mybatis.core.query.QueryBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -21,9 +21,9 @@ import ${packageName}.domain.vo.${ClassName}Vo;
import ${packageName}.domain.${ClassName};
import ${packageName}.mapper.${ClassName}Mapper;
import ${packageName}.service.I${ClassName}Service;
#if($table.tree)
<#if table.tree>
import org.dromara.common.core.exception.ServiceException;
#end
</#if>
import java.util.ArrayList;
import java.util.List;
@@ -43,20 +43,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
private final ${ClassName}Mapper ${className}Mapper;
#set($TreeParentCap = "")
#if("" != $treeParentCode)
#set($TreeParentCap = $treeParentCode.substring(0,1).toUpperCase() + $treeParentCode.substring(1))
#end
#set($TreeAncestorsCap = "")
#if("" != $treeAncestorsField)
#set($TreeAncestorsCap = $treeAncestorsField.substring(0,1).toUpperCase() + $treeAncestorsField.substring(1))
#end
#set($TreeOrderCap = "")
#if("" != $treeOrderField)
#set($TreeOrderCap = $treeOrderField.substring(0,1).toUpperCase() + $treeOrderField.substring(1))
#end
/**
/**
* 查询${functionName}
*
* @param ${pkColumn.javaField} 主键
@@ -67,7 +54,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
return ${className}Mapper.selectVoById(${pkColumn.javaField});
}
#if($table.crud)
<#if table.crud>
/**
* 分页查询${functionName}列表
*
@@ -81,7 +68,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
Page<${ClassName}Vo> result = ${className}Mapper.selectVoPage(pageQuery.build(), lqw);
return PageResult.build(result.getRecords(), result.getTotal());
}
#end
</#if>
/**
* 查询符合条件的${functionName}列表
@@ -95,7 +82,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
return ${className}Mapper.selectVoList(lqw);
}
#if($enableUnique)
<#if enableUnique>
/**
* 校验${functionName}是否满足组合唯一约束
*
@@ -105,84 +92,78 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
@Override
public boolean checkUnique(${ClassName}Bo bo) {
boolean hasUniqueValue = true;
#foreach($column in $uniqueColumns)
#if($column.javaType == 'String')
<#list uniqueColumns as column>
<#if column.javaType == 'String'>
hasUniqueValue = hasUniqueValue && StringUtils.isNotBlank(bo.get${column.capJavaField}());
#else
<#else>
hasUniqueValue = hasUniqueValue && bo.get${column.capJavaField}() != null;
#end
#end
</#if>
</#list>
if (!hasUniqueValue) {
return true;
}
LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery();
#foreach($column in $uniqueColumns)
<#list uniqueColumns as column>
lqw.eq(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}());
#end
</#list>
lqw.ne(bo.get${pkColumn.capJavaField}() != null, ${ClassName}::get${pkColumn.capJavaField}, bo.get${pkColumn.capJavaField}());
return !${className}Mapper.exists(lqw);
}
#end
</#if>
private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) {
#set($hasBetween = false)
#foreach ($column in $columns)
#if($column.query && $column.queryType == 'BETWEEN')
#set($hasBetween = true)
#end
#end
#if($hasBetween)
<#if hasBetween>
Map<String, Object> params = bo.getParams();
#end
</#if>
return QueryBuilder.lambda(${ClassName}.class)
#foreach($column in $columns)
#if($column.query)
#set($queryType=$column.queryType)
#set($javaType=$column.javaType)
#set($AttrName=$column.capJavaField)
#set($mpMethod=$column.queryType.toLowerCase())
#if($queryType != 'BETWEEN')
#if($javaType == 'String')
#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())')
#if($queryType == 'LIKE')
.likeIfText(${ClassName}::get$AttrName, bo.get$AttrName())
#elseif($queryType == 'EQ')
.eqIfText(${ClassName}::get$AttrName, bo.get$AttrName())
#elseif($queryType == 'NE')
.neIfText(${ClassName}::get$AttrName, bo.get$AttrName())
#else
.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName())
#end
#else
#set($condition='bo.get'+$AttrName+'() != null')
#if($queryType == 'EQ')
.eqIfPresent(${ClassName}::get$AttrName, bo.get$AttrName())
#elseif($queryType == 'NE')
.neIfPresent(${ClassName}::get$AttrName, bo.get$AttrName())
#elseif($queryType == 'GT')
.gtIfPresent(${ClassName}::get$AttrName, bo.get$AttrName())
#elseif($queryType == 'LT')
.ltIfPresent(${ClassName}::get$AttrName, bo.get$AttrName())
#else
.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName())
#end
#end
#else
.betweenParams(${ClassName}::get$AttrName, params, "begin$AttrName", "end$AttrName")
#end
#end
#end
#if($table.tree && "" != $treeAncestorsField)
.orderByAsc(${ClassName}::get${TreeAncestorsCap})
#end
#if($table.tree && "" != $treeParentCode)
.orderByAsc(${ClassName}::get${TreeParentCap})
#end
#if($table.tree && "" != $treeOrderField)
.orderByAsc(${ClassName}::get${TreeOrderCap})
#elseif($enableSort)
<#list columns as column>
<#if column.query>
<#assign queryType = column.queryType>
<#assign javaType = column.javaType>
<#assign AttrName = column.capJavaField>
<#assign mpMethod = column.queryType?lower_case>
<#if queryType != 'BETWEEN'>
<#if javaType == 'String'>
<#assign condition = 'StringUtils.isNotBlank(bo.get'+AttrName+'())'>
<#if queryType == 'LIKE'>
.likeIfText(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
<#elseif queryType == 'EQ'>
.eqIfText(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
<#elseif queryType == 'NE'>
.neIfText(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
<#else>
.${mpMethod}(${condition}, ${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
</#if>
<#else>
<#assign condition = 'bo.get'+AttrName+'() != null'>
<#if queryType == 'EQ'>
.eqIfPresent(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
<#elseif queryType == 'NE'>
.neIfPresent(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
<#elseif queryType == 'GT'>
.gtIfPresent(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
<#elseif queryType == 'LT'>
.ltIfPresent(${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
<#else>
.${mpMethod}(${condition}, ${ClassName}::get${column.capJavaField}, bo.get${column.capJavaField}())
</#if>
</#if>
<#else>
.betweenParams(${ClassName}::get${column.capJavaField}, params, "begin${column.capJavaField}", "end${column.capJavaField}")
</#if>
</#if>
</#list>
<#if table.tree && "" != treeAncestorsField>
.orderByAsc(${ClassName}::get${treeAncestorsCap})
</#if>
<#if table.tree && "" != treeParentCode>
.orderByAsc(${ClassName}::get${treeParentCap})
</#if>
<#if table.tree && "" != treeOrderField>
.orderByAsc(${ClassName}::get${treeOrderCap})
<#elseif enableSort>
.orderByAsc(${ClassName}::get${sortColumn.capJavaField})
#end
</#if>
.orderByAsc(${ClassName}::get${pkColumn.capJavaField})
.build();
}
@@ -196,9 +177,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
@Override
public Boolean insertByBo(${ClassName}Bo bo) {
${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class);
#if($table.tree)
<#if table.tree>
fillTreeMetaBeforeSave(add, false);
#end
</#if>
validEntityBeforeSave(add);
boolean flag = ${className}Mapper.insert(add) > 0;
if (flag) {
@@ -216,14 +197,14 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
@Override
public Boolean updateByBo(${ClassName}Bo bo) {
${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class);
#if($table.tree)
<#if table.tree>
fillTreeMetaBeforeSave(update, true);
#end
</#if>
validEntityBeforeSave(update);
return ${className}Mapper.updateById(update) > 0;
}
#if($enableStatus)
<#if enableStatus>
/**
* 修改${functionName}状态
*
@@ -238,9 +219,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
.eq(${ClassName}::get${pkColumn.capJavaField}, ${pkColumn.javaField})
.update();
}
#end
</#if>
#if($enableSort)
<#if enableSort>
/**
* 调整${functionName}排序
*
@@ -255,7 +236,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
.eq(${ClassName}::get${pkColumn.capJavaField}, ${pkColumn.javaField})
.update();
}
#end
</#if>
/**
* 保存前的数据校验
@@ -264,51 +245,51 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
// 可在此扩展通用业务校验
}
#if($table.tree)
<#if table.tree>
private void fillTreeMetaBeforeSave(${ClassName} entity, boolean updateMode) {
#if("" != $treeParentCode)
if (entity.get${TreeParentCap}() == null) {
entity.set${TreeParentCap}(${treeRootValueJavaLiteral});
<#if "" != treeParentCode>
if (entity.get${treeParentCap}() == null) {
entity.set${treeParentCap}(${treeRootValueJavaLiteral});
}
if (ObjectUtil.equal(entity.get${pkColumn.capJavaField}(), entity.get${TreeParentCap}())) {
if (ObjectUtil.equal(entity.get${pkColumn.capJavaField}(), entity.get${treeParentCap}())) {
throw new ServiceException("${functionName}父节点不能选择自身");
}
#if("" != $treeAncestorsField)
<#if "" != treeAncestorsField>
${ClassName} parent = null;
if (!ObjectUtil.equal(entity.get${TreeParentCap}(), ${treeRootValueJavaLiteral})) {
parent = ${className}Mapper.selectById(entity.get${TreeParentCap}());
if (!ObjectUtil.equal(entity.get${treeParentCap}(), ${treeRootValueJavaLiteral})) {
parent = ${className}Mapper.selectById(entity.get${treeParentCap}());
if (ObjectUtil.isNull(parent)) {
throw new ServiceException("${functionName}父节点不存在");
}
}
if (updateMode && entity.get${pkColumn.capJavaField}() != null && ObjectUtil.isNotNull(parent)
&& containsAncestor(parent.get${TreeAncestorsCap}(), entity.get${pkColumn.capJavaField}())) {
&& containsAncestor(parent.get${treeAncestorsCap}(), entity.get${pkColumn.capJavaField}())) {
throw new ServiceException("不能选择当前节点或其子节点作为父节点");
}
String newAncestors = resolveAncestors(entity.get${TreeParentCap}(), parent);
String newAncestors = resolveAncestors(entity.get${treeParentCap}(), parent);
if (updateMode && entity.get${pkColumn.capJavaField}() != null) {
${ClassName} oldEntity = ${className}Mapper.selectById(entity.get${pkColumn.capJavaField}());
if (ObjectUtil.isNull(oldEntity)) {
throw new ServiceException("${functionName}不存在,无法修改");
}
String oldAncestors = oldEntity.get${TreeAncestorsCap}();
entity.set${TreeAncestorsCap}(newAncestors);
String oldAncestors = oldEntity.get${treeAncestorsCap}();
entity.set${treeAncestorsCap}(newAncestors);
if (!StringUtils.equals(oldAncestors, newAncestors)) {
updateChildrenAncestors(entity.get${pkColumn.capJavaField}(), newAncestors, oldAncestors);
}
} else {
entity.set${TreeAncestorsCap}(newAncestors);
entity.set${treeAncestorsCap}(newAncestors);
}
#end
#end
</#if>
</#if>
}
#if("" != $treeAncestorsField)
<#if "" != treeAncestorsField>
private String resolveAncestors(${treeParentColumn.javaType} parentId, ${ClassName} parent) {
if (ObjectUtil.equal(parentId, ${treeRootValueJavaLiteral})) {
return "${treeRootValue}";
}
String parentAncestors = parent.get${TreeAncestorsCap}();
String parentAncestors = parent.get${treeAncestorsCap}();
if (StringUtils.isBlank(parentAncestors)) {
return String.valueOf(parentId);
}
@@ -317,18 +298,18 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
private void updateChildrenAncestors(${pkColumn.javaType} currentId, String newAncestors, String oldAncestors) {
List<${ClassName}> children = ${className}Mapper.lambda()
.select(${ClassName}::get${pkColumn.capJavaField}, ${ClassName}::get${TreeAncestorsCap})
.findInSet(currentId, ${ClassName}::get${TreeAncestorsCap})
.select(${ClassName}::get${pkColumn.capJavaField}, ${ClassName}::get${treeAncestorsCap})
.findInSet(currentId, ${ClassName}::get${treeAncestorsCap})
.list();
List<${ClassName}> updateList = new ArrayList<>();
for (${ClassName} child : children) {
String ancestors = child.get${TreeAncestorsCap}();
String ancestors = child.get${treeAncestorsCap}();
if (StringUtils.isBlank(ancestors)) {
continue;
}
${ClassName} update = new ${ClassName}();
update.set${pkColumn.capJavaField}(child.get${pkColumn.capJavaField}());
update.set${TreeAncestorsCap}(StringUtils.replaceOnce(ancestors, oldAncestors, newAncestors));
update.set${treeAncestorsCap}(StringUtils.replaceOnce(ancestors, oldAncestors, newAncestors));
updateList.add(update);
}
if (!updateList.isEmpty()) {
@@ -344,8 +325,8 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
}
return false;
}
#end
#end
</#if>
</#if>
/**
* 校验并批量删除${functionName}信息
@@ -362,3 +343,5 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
return ${className}Mapper.deleteByIds(ids) > 0;
}
}
@@ -1,8 +1,8 @@
package ${packageName}.domain.vo;
#foreach ($import in $importList)
<#list importList as import>
import ${import};
#end
</#list>
import ${packageName}.domain.${ClassName};
import org.apache.fesod.sheet.annotation.ExcelIgnoreUnannotated;
import org.apache.fesod.sheet.annotation.ExcelProperty;
@@ -33,36 +33,33 @@ public class ${ClassName}Vo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if($column.list)
<#list columns as column>
<#if column.list>
/**
* $column.columnComment
* ${column.columnComment}
*/
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if(${column.dictType} && ${column.dictType} != '')
@ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
<#assign parentheseIndex = column.columnComment?index_of("")>
<#if column.dictType?has_content>
@ExcelProperty(value = "${column.columnLabel}", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "${column.dictType}")
#elseif($parentheseIndex != -1)
@ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
#else
@ExcelProperty(value = "${comment}")
#end
private $column.javaType $column.javaField;
<#elseif parentheseIndex != -1>
@ExcelProperty(value = "${column.columnLabel}", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "${column.readConverterExp}()")
<#else>
@ExcelProperty(value = "${column.columnLabel}")
</#if>
private ${column.javaType} ${column.javaField};
#if($column.htmlType == "imageUpload")
<#if column.htmlType == "imageUpload">
/**
* ${column.columnComment}Url
*/
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
private String ${column.javaField}Url;
#end
#end
#end
</#if>
</#if>
</#list>
}
@@ -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 type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types';
@@ -6,7 +6,7 @@ import type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } fro
* 查询${functionName}列表
*/
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',
method: 'get',
params: query
@@ -45,13 +45,13 @@ export function update${BusinessName}(data: ${BusinessName}Form) {
});
}
#if($enableStatus)
<#if enableStatus>
/**
* 修改${functionName}状态
*/
export function change${BusinessName}Status(
${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>({
url: '/${moduleName}/${businessName}/changeStatus',
@@ -63,14 +63,14 @@ export function change${BusinessName}Status(
});
}
#end
#if($enableSort)
</#if>
<#if enableSort>
/**
* 调整${functionName}排序
*/
export function update${BusinessName}Sort(
${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>({
url: '/${moduleName}/${businessName}/updateSort',
@@ -82,7 +82,7 @@ export function update${BusinessName}Sort(
});
}
#end
</#if>
/**
* 删除${functionName}
*/
@@ -92,3 +92,7 @@ export function del${BusinessName}(${pkColumn.javaField}: string | number | Arra
method: 'delete'
});
}
@@ -1,66 +1,22 @@
#set($needDict = $dicts != '')
#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 { DeleteOutlined<#if enableExport>, DownloadOutlined</#if>, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons';
import {
ModalForm,
PageContainer,
#if($needCheckbox)
<#if needCheckbox>
ProFormCheckbox,
#end
#if($needDateField)
</#if>
<#if needDateField>
ProFormDateTimePicker,
#end
#if($needDigit)
</#if>
<#if needDigit>
ProFormDigit,
#end
#if($needSelect)
</#if>
<#if needSelect>
ProFormSelect,
#end
#if($needTextArea)
</#if>
<#if needTextArea>
ProFormTextArea,
#end
</#if>
ProFormText,
ProFormTreeSelect,
ProTable,
@@ -68,62 +24,62 @@ import {
type ProColumns
} from '@ant-design/pro-components';
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 type { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
import {
add${BusinessName},
#if($enableStatus)
<#if enableStatus>
change${BusinessName}Status,
#end
</#if>
del${BusinessName},
get${BusinessName},
list${BusinessName},
#if($enableSort)
<#if enableSort>
update${BusinessName}Sort,
#end
</#if>
update${BusinessName}
} from '@/api/${moduleName}/${businessName}';
#if($needDict)
<#if needDict>
import DictTag from '@/components/common/DictTag';
#end
#if($needFileUpload)
</#if>
<#if needFileUpload>
import FileUpload from '@/components/common/FileUpload';
#end
#if($needImagePreview)
</#if>
<#if needImagePreview>
import ImagePreview from '@/components/common/ImagePreview';
#end
#if($needImageUpload)
</#if>
<#if needImageUpload>
import ImageUpload from '@/components/common/ImageUpload';
#end
#if($needEditor)
</#if>
<#if needEditor>
import RichTextEditor from '@/components/common/RichTextEditor';
#end
</#if>
import RowActions from '@/components/common/RowActions';
#if($needDict)
<#if needDict>
import { useDict } from '@/hooks/useDict';
#end
#if($enableExport)
</#if>
<#if enableExport>
import { useTableExport } from '@/hooks/useTableExport';
#end
</#if>
import { useTreeTableExpand } from '@/hooks/useTreeTableExpand';
import { useUserStore } from '@/stores/userStore';
#if($needDict)
<#if needDict>
import { dictOptions } from '@/utils/dict';
#end
#if($enableStatus)
</#if>
<#if enableStatus>
import { confirmAction } from '@/utils/modal';
#end
</#if>
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 = {
${treeParentCode}: ${treeRootValueTsLiteral},
#foreach($column in $columns)
#if(($column.insert || $column.edit) && !$column.pk && $column.htmlType == "checkbox")
<#list columns as column>
<#if (column.insert || column.edit) && !column.pk && column.htmlType == "checkbox">
${column.javaField}: [],
#end
#end
</#if>
</#list>
};
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
#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;
<#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>;
#end
</#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)
<#if needDict>
const dicts = useDict(${dicts});
#end
</#if>
const [treeOptions, setTreeOptions] = useState<${BusinessName}VO[]>([]);
const [tableRows, setTableRows] = useState<${BusinessName}VO[]>([]);
const { expandAll, expandedRowKeys, onExpandedRowsChange, syncExpandedRows, toggleExpandAll } =
useTreeTableExpand<${BusinessName}VO>(row => row.${treeCode});
const [modalOpen, { setTrue: openModal, setFalse: closeModal }] = useBoolean(false);
const [modalTitle, setModalTitle] = useState('');
#if($enableExport)
<#if enableExport>
const { updateExportParams, exportFile } = useTableExport();
#end
</#if>
const canAdd = hasPermi(userInfo, ['${permissionPrefix}:add']);
const canEdit = hasPermi(userInfo, ['${permissionPrefix}:edit']);
const canRemove = hasPermi(userInfo, ['${permissionPrefix}:remove']);
#if($enableExport)
<#if enableExport>
const canExport = hasPermi(userInfo, ['${permissionPrefix}:export']);
#end
</#if>
const treeSelectData = useMemo(
() => [{ title: '顶级节点', value: ${treeRootValueTsLiteral}, children: toTreeSelectData(treeOptions) }],
[treeOptions]
@@ -184,7 +138,7 @@ export default function ${BusinessName}Page() {
const openAdd = async (row?: ${BusinessName}VO) => {
await loadTreeOptions();
form.resetFields();
form.setFieldsValue({ ...default${BusinessName}Form, ${treeParentCode}: row?.${treeCode} || ${treeRootValueTsLiteral} });
form.setFieldsValue({ ...default${BusinessName}Form, ${treeParentCode}: row?.${treeCode} || treeRootValueTsLiteral });
setModalTitle('添加${functionName}');
openModal();
};
@@ -192,20 +146,20 @@ export default function ${BusinessName}Page() {
const openEdit = async (row: ${BusinessName}VO) => {
await loadTreeOptions(row.${treeCode});
const res = await get${BusinessName}(row.${pkColumn.javaField});
const data = #if($needDateField)toDayjsFields({ ...res.data }, [
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
const data = <#if needDateField>toDayjsFields({ ...res.data }, [
<#list columns as column>
<#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>
</#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(',');
}
#end
#end
</#if>
</#list>
form.resetFields();
form.setFieldsValue(data);
setModalTitle('修改${functionName}');
@@ -213,20 +167,20 @@ export default function ${BusinessName}Page() {
};
const submitForm = async (values: ${BusinessName}Form) => {
const submitValues = #if($needDateField)formatDateTimeFields({ ...values }, [
#foreach($column in $columns)
#if(($column.insert || $column.edit) && $column.htmlType == "datetime")
const submitValues = <#if needDateField>formatDateTimeFields({ ...values }, [
<#list columns as column>
<#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>
</#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(',');
}
#end
#end
</#if>
</#list>
submitValues.${pkColumn.javaField} ? await update${BusinessName}(submitValues) : await add${BusinessName}(submitValues);
message.success('操作成功');
form.resetFields();
@@ -240,15 +194,15 @@ export default function ${BusinessName}Page() {
actionRef.current?.reload();
};
#if($enableStatus)
<#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 confirmAction(`确认要"${r'${text}'}"吗?`);
await change${BusinessName}Status(row.${pkColumn.javaField}, status);
message.success(`${text}成功`);
message.success(`${r'${text}'}成功`);
actionRef.current?.reload();
} catch {
row.${statusField} = previousStatus;
@@ -256,76 +210,74 @@ export default function ${BusinessName}Page() {
}
};
#end
#if($enableSort)
</#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();
};
#end
</#if>
const columns: ProColumns<${BusinessName}VO>[] = [
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($dictType=$column.dictType)
#if($column.list && !$column.pk)
#if($enableStatus && $statusField == $javaField)
<#list columns as column>
<#if column.list && !column.pk>
<#if enableStatus && statusField == column.javaField>
{
title: '#comment($column)',
dataIndex: '${javaField}',
title: '${column.columnLabel}',
dataIndex: '${column.javaField}',
valueType: 'select',
width: 100,
#if("" != $dictType)
fieldProps: { options: dictOptions(dicts.${dictType}) },
#end
<#if column.dictType?has_content>
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
</#if>
render: (_, row) => (
<Switch
checked={row.${javaField} === ${statusField}ActiveValue}
checked={row.${column.javaField} === ${statusField}ActiveValue}
disabled={!canEdit}
onChange={checked => handleStatusChange(row, checked)}
/>
)
},
#elseif($enableSort && $sortField == $javaField)
<#elseif enableSort && sortField == column.javaField>
{
title: '#comment($column)',
dataIndex: '${javaField}',
title: '${column.columnLabel}',
dataIndex: '${column.javaField}',
search: false,
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")
{ title: '#comment($column)', dataIndex: '${javaField}', valueType: 'dateTime', search: #if($column.query)true#else false#end, width: 170 },
#elseif($column.htmlType == "imageUpload")
<#elseif column.htmlType == "datetime">
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}', valueType: 'dateTime', search: <#if column.query>true<#else> false</#if>, width: 170 },
<#elseif column.htmlType == "imageUpload">
{
title: '#comment($column)',
dataIndex: '${javaField}Url',
title: '${column.columnLabel}',
dataIndex: '${column.javaField}Url',
search: false,
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)',
dataIndex: '${javaField}',
title: '${column.columnLabel}',
dataIndex: '${column.javaField}',
valueType: 'select',
fieldProps: { options: dictOptions(dicts.${dictType}) },
render: (_, row) => <DictTag options={dicts.${dictType}} value={row.${javaField}} />
fieldProps: { options: dictOptions(dicts.${column.dictType}) },
render: (_, row) => <DictTag options={dicts.${column.dictType}} value={row.${column.javaField}} />
},
#elseif($column.htmlType == "switch")
<#elseif column.htmlType == "switch">
{
title: '#comment($column)',
dataIndex: '${javaField}',
title: '${column.columnLabel}',
dataIndex: '${column.javaField}',
valueType: 'select',
width: 100,
render: (_, row) => <Switch checked={row.${javaField} === #switchActiveValue($column)} disabled />
render: (_, row) => <Switch checked={row.${column.javaField} === ${column.switchActiveValue}} disabled />
},
#else
{ title: '#comment($column)', dataIndex: '${javaField}'#if(!$column.query), search: false#end },
#end
#end
#end
<#else>
{ title: '${column.columnLabel}', dataIndex: '${column.javaField}'<#if !column.query>, search: false</#if> },
</#if>
</#if>
</#list>
{
title: '操作',
valueType: 'option',
@@ -341,7 +293,7 @@ export default function ${BusinessName}Page() {
label: '删除',
icon: <DeleteOutlined />,
danger: true,
confirm: `是否确认删除${functionName}编号为"#[[${row.]]#${pkColumn.javaField}#[[}]]#"的数据项?`,
confirm: `是否确认删除${functionName}编号为"${r'${row.'}${pkColumn.javaField}${r'}'}"的数据项?`,
onClick: () => remove(row)
}
]}
@@ -368,9 +320,9 @@ export default function ${BusinessName}Page() {
const rows = handleTree<${BusinessName}VO>(res.data || [], '${treeCode}', '${treeParentCode}');
setTableRows(rows);
syncExpandedRows(rows, expandAll);
#if($enableExport)
<#if enableExport>
updateExportParams(params);
#end
</#if>
return { data: rows, total: rows.length, success: true };
}}
toolbar={{ title: '${functionName}列表' }}
@@ -386,16 +338,16 @@ export default function ${BusinessName}Page() {
onClick={() => toggleExpandAll(tableRows)}
>
展开/折叠
</Button>#if($enableExport),
</Button><#if enableExport>,
canExport && (
<Button
key="export"
icon={<DownloadOutlined />}
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_#[[${Date.now()}]]#.xlsx`)}
onClick={() => exportFile('/${moduleName}/${businessName}/export', () => `${businessName}_${r'${Date.now()}'}.xlsx`)}
>
导出
</Button>
)#end
)</#if>
]}
/>
@@ -411,62 +363,65 @@ export default function ${BusinessName}Page() {
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($field == $treeParentCode)
<#list columns as column>
<#if (column.insert || column.edit) && !column.pk>
<#assign field = column.javaField>
<#if field == treeParentCode>
<ProFormTreeSelect
name="${field}"
label="#comment($column)"
#if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end
name="${column.javaField}"
label="${column.columnLabel}"
<#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if>
fieldProps={{
allowClear: true,
treeDefaultExpandAll: true,
treeData: treeSelectData,
placeholder: '请选择#comment($column)'
placeholder: '请选择${column.columnLabel}'
}}
/>
#elseif($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")
<#elseif 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="${field}"
label="#comment($column)"
name="${column.javaField}"
label="${column.columnLabel}"
valuePropName="checked"
getValueProps={value => ({ checked: value === #switchActiveValue($column) })}
normalize={checked => (checked ? #switchActiveValue($column) : #switchInactiveValue($column))}
getValueProps={value => ({ checked: value === ${column.switchActiveValue} })}
normalize={checked => (checked ? ${column.switchActiveValue} : ${column.switchInactiveValue})}
>
<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>
<#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="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<#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="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end>
<#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="${field}" label="#comment($column)" #if($column.required)rules={[{ required: true, message: '#comment($column)不能为空' }]}#end />
#end
#end
#end
<#else>
<ProFormText name="${column.javaField}" label="${column.columnLabel}" <#if column.required>rules={[{ required: true, message: '${column.columnLabel}不能为空' }]}</#if> />
</#if>
</#if>
</#list>
</ModalForm>
</PageContainer>
);
}
@@ -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>
);
}
@@ -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>;
}
@@ -17,3 +17,6 @@ values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, 4, '#
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, 5, '#', '', 'N', 'Y', 'F', '0', '0', '${permissionPrefix}:export', '#', 1761000000000000103, 1761100000000000001, sysdate(), null, null, '');
@@ -17,3 +17,6 @@ values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, 4, '#
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, 5, '#', '', 'N', 'Y', 'F', '0', '0', '${permissionPrefix}:export', '#', 1761000000000000103, 1761100000000000001, sysdate, null, null, '');
@@ -18,3 +18,6 @@ values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, 4, '#
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, 5, '#', '', 'N', 'Y', 'F', '0', '0', '${permissionPrefix}:export', '#', 1761000000000000103, 1761100000000000001, now(), null, null, '');
@@ -17,3 +17,6 @@ values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, 4, '#
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, 5, '#', '', 'N', 'Y', 'F', '0', '0', '${permissionPrefix}:export', '#', 1761000000000000103, 1761100000000000001, getdate(), null, null, '');
@@ -52,13 +52,13 @@ export const update${BusinessName} = (data: ${BusinessName}Form) => {
});
};
#if($enableStatus)
<#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) => {
export const change${BusinessName}Status = (${pkColumn.javaField}: string | number, status: <#if statusColumn.javaType == 'Boolean'>boolean<#elseif statusColumn.javaType == 'String'>string<#else> number</#if>) => {
return request({
url: '/${moduleName}/${businessName}/changeStatus',
method: 'put',
@@ -68,15 +68,15 @@ export const change${BusinessName}Status = (${pkColumn.javaField}: string | numb
}
});
};
#end
</#if>
#if($enableSort)
<#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) => {
export const update${BusinessName}Sort = (${pkColumn.javaField}: string | number, sortValue: <#if sortColumn.javaType == 'String' || sortColumn.javaType == 'LocalDateTime'>string<#else> number</#if>) => {
return request({
url: '/${moduleName}/${businessName}/updateSort',
method: 'put',
@@ -86,7 +86,7 @@ export const update${BusinessName}Sort = (${pkColumn.javaField}: string | number
}
});
};
#end
</#if>
/**
* 删除${functionName}
@@ -98,3 +98,6 @@ export const del${BusinessName} = (${pkColumn.javaField}: string | number | Arra
method: 'delete'
});
};
@@ -8,70 +8,62 @@
</div>
</template>
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.htmlType == "input" || $column.htmlType == "textarea")
<el-form-item label="${comment}" prop="${column.javaField}">
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${comment}" clearable @keyup.enter="handleQuery" />
<#list columns as column>
<#if column.query>
<#if column.htmlType == "input" || column.htmlType == "textarea">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${column.columnLabel}" clearable @keyup.enter="handleQuery" />
</el-form-item>
#elseif($column.htmlType == "inputNumber")
<el-form-item label="${comment}" prop="${column.javaField}">
<#elseif column.htmlType == "inputNumber">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input-number v-model="queryParams.${column.javaField}" controls-position="right" />
</el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
#elseif($column.htmlType == "switch" && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
<#elseif column.htmlType == "switch" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
#elseif($column.htmlType == "switch")
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
#if($column.javaType == "Boolean")
<#elseif column.htmlType == "switch">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
<#if column.javaType == "Boolean">
<el-option label="是" :value="true" />
<el-option label="否" :value="false" />
#elseif($column.javaType == "Integer" || $column.javaType == "Long")
<#elseif column.javaType == "Integer" || column.javaType == "Long">
<el-option label="开启" :value="0" />
<el-option label="关闭" :value="1" />
#else
<#else>
<el-option label="开启" value="0" />
<el-option label="关闭" value="1" />
#end
</#if>
</el-select>
</el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable>
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}">
<#elseif column.htmlType == "datetime" && column.queryType != "BETWEEN">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-date-picker clearable
v-model="queryParams.${column.javaField}"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择${comment}"
placeholder="选择${column.columnLabel}"
/>
</el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}" style="width: 308px">
<#elseif column.htmlType == "datetime" && column.queryType == "BETWEEN">
<el-form-item label="${column.columnLabel}" style="width: 308px">
<el-date-picker
v-model="dateRange${AttrName}"
v-model="dateRange${column.capJavaField}"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
@@ -80,9 +72,9 @@
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
/>
</el-form-item>
#end
#end
#end
</#if>
</#if>
</#list>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -100,9 +92,9 @@
<div class="toolbar-actions">
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button>
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
#if($enableExport)
<#if enableExport>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['${moduleName}:${businessName}:export']">导出</el-button>
#end
</#if>
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
</div>
</div>
@@ -117,122 +109,115 @@
:default-expand-all="isExpandAll"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
#set($firstTreeListField = "")
#foreach($tempColumn in $columns)
#if(!$tempColumn.pk && $tempColumn.list && "" != $tempColumn.javaField && $firstTreeListField == "")
#set($firstTreeListField = $tempColumn.javaField)
#end
#end
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.pk)
#elseif($enableStatus && $statusField == $javaField)
#if($javaField == $firstTreeListField)
<el-table-column label="${comment}" prop="${javaField}">
#else
<el-table-column label="${comment}" align="center" prop="${javaField}">
#end
<#assign firstTreeListField = "">
<#list columns as tempColumn>
<#if !tempColumn.pk && tempColumn.list && "" != tempColumn.javaField && firstTreeListField == "">
<#assign firstTreeListField = tempColumn.javaField>
</#if>
</#list>
<#list columns as column>
<#if column.pk>
<#elseif enableStatus && statusField == column.javaField>
<#if column.javaField == firstTreeListField>
<el-table-column label="${column.columnLabel}" prop="${column.javaField}">
<#else>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
</#if>
<template #default="scope">
<el-switch
v-model="scope.row.${javaField}"
v-model="scope.row.${column.javaField}"
:active-value="${statusField}ActiveValue"
:inactive-value="${statusField}InactiveValue"
@change="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
#elseif($enableSort && $sortField == $javaField)
#if($javaField == $firstTreeListField)
<el-table-column label="${comment}" prop="${javaField}" width="160">
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" width="160">
#end
<#elseif enableSort && sortField == column.javaField>
<#if column.javaField == firstTreeListField>
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" width="160">
<#else>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="160">
</#if>
<template #default="scope">
#if($column.javaType == "LocalDateTime")
<#if column.javaType == "LocalDateTime">
<el-date-picker
v-model="scope.row.${javaField}"
v-model="scope.row.${column.javaField}"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择${comment}"
placeholder="选择${column.columnLabel}"
@change="handleSortChange(scope.row)"
/>
#else
<el-input-number v-model="scope.row.${javaField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
#end
<#else>
<el-input-number v-model="scope.row.${column.javaField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
</#if>
</template>
</el-table-column>
#elseif($column.list && $column.htmlType == "switch")
#if($javaField == $firstTreeListField)
<el-table-column label="${comment}" prop="${javaField}" width="120">
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" width="120">
#end
<#elseif column.list && column.htmlType == "switch">
<#if column.javaField == firstTreeListField>
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" width="120">
<#else>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="120">
</#if>
<template #default="scope">
<el-switch
v-model="scope.row.${javaField}"
#if($column.javaType == "Boolean")
v-model="scope.row.${column.javaField}"
<#if column.javaType == "Boolean">
:active-value="true"
:inactive-value="false"
#elseif($column.javaType == "Integer" || $column.javaType == "Long")
<#elseif column.javaType == "Integer" || column.javaType == "Long">
:active-value="0"
:inactive-value="1"
#else
<#else>
active-value="0"
inactive-value="1"
#end
</#if>
disabled
/>
</template>
</el-table-column>
#elseif($column.list && $column.htmlType == "datetime")
#if($javaField == $firstTreeListField)
<el-table-column label="${comment}" prop="${javaField}" width="180">
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
#end
<#elseif column.list && column.htmlType == "datetime">
<#if column.javaField == firstTreeListField>
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" width="180">
<#else>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="180">
</#if>
<template #default="scope">
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
<span>{{ parseTime(scope.row.${column.javaField}, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
#if($javaField == $firstTreeListField)
<el-table-column label="${comment}" prop="${javaField}Url" width="100">
#else
<el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
#end
<#elseif column.list && column.htmlType == "imageUpload">
<#if column.javaField == firstTreeListField>
<el-table-column label="${column.columnLabel}" prop="${column.javaField}Url" width="100">
<#else>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}Url" width="100">
</#if>
<template #default="scope">
<image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
<image-preview :src="scope.row.${column.javaField}Url" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && $column.dictColumn)
#if($javaField == $firstTreeListField)
<el-table-column label="${comment}" prop="${javaField}">
#else
<el-table-column label="${comment}" align="center" prop="${javaField}">
#end
<#elseif column.list && column.dictColumn>
<#if column.javaField == firstTreeListField>
<el-table-column label="${column.columnLabel}" prop="${column.javaField}">
<#else>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
</#if>
<template #default="scope">
#if($column.htmlType == "checkbox")
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
#else
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
#end
<#if column.htmlType == "checkbox">
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField} ? scope.row.${column.javaField}.split(',') : []"/>
<#else>
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField}"/>
</#if>
</template>
</el-table-column>
#elseif($column.list && "" != $javaField)
#if($javaField == $firstTreeListField)
<el-table-column label="${comment}" prop="${javaField}" />
#else
<el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
#end
#if($enableStatus && !$statusColumn.list)
<#elseif column.list && "" != column.javaField>
<#if column.javaField == firstTreeListField>
<el-table-column label="${column.columnLabel}" prop="${column.javaField}" />
<#else>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" />
</#if>
</#if>
</#list>
<#if enableStatus && !statusColumn.list>
<el-table-column label="${statusColumn.columnComment}" align="center" prop="${statusField}">
<template #default="scope">
<el-switch
@@ -243,11 +228,11 @@
/>
</template>
</el-table-column>
#end
#if($enableSort && !$sortColumn.list)
</#if>
<#if enableSort && !sortColumn.list>
<el-table-column label="${sortColumn.columnComment}" align="center" prop="${sortField}" width="160">
<template #default="scope">
#if($sortColumn.javaType == "LocalDateTime")
<#if sortColumn.javaType == "LocalDateTime">
<el-date-picker
v-model="scope.row.${sortField}"
type="datetime"
@@ -255,12 +240,12 @@
placeholder="选择${sortColumn.columnComment}"
@change="handleSortChange(scope.row)"
/>
#else
<#else>
<el-input-number v-model="scope.row.${sortField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
#end
</#if>
</template>
</el-table-column>
#end
</#if>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
@@ -279,137 +264,129 @@
<!-- 添加或修改${functionName}对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
#foreach($column in $columns)
#set($field=$column.javaField)
#if(($column.insert || $column.edit) && !$column.pk)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#set($dictType=$column.dictType)
#if("" != $treeParentCode && $column.javaField == $treeParentCode)
<el-form-item label="${comment}" prop="${treeParentCode}">
<#list columns as column>
<#if (column.insert || column.edit) && !column.pk>
<#if "" != treeParentCode && column.javaField == treeParentCode>
<el-form-item label="${column.columnLabel}" prop="${treeParentCode}">
<el-tree-select
v-model="form.${treeParentCode}"
:data="${businessName}Options"
:props="{ value: '${treeCode}', label: '${treeName}', children: 'children' } as any"
value-key="${treeCode}"
placeholder="请选择${comment}"
placeholder="请选择${column.columnLabel}"
check-strictly
/>
</el-form-item>
#elseif($column.htmlType == "input")
<el-form-item label="${comment}" prop="${field}">
<el-input v-model="form.${field}" placeholder="请输入${comment}" />
<#elseif column.htmlType == "input">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input v-model="form.${column.javaField}" placeholder="请输入${column.columnLabel}" />
</el-form-item>
#elseif($column.htmlType == "inputNumber")
<el-form-item label="${comment}" prop="${field}">
<el-input-number v-model="form.${field}" controls-position="right" />
<#elseif column.htmlType == "inputNumber">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input-number v-model="form.${column.javaField}" controls-position="right" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}" prop="${field}">
<image-upload v-model="form.${field}"/>
<#elseif column.htmlType == "imageUpload">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<image-upload v-model="form.${column.javaField}"/>
</el-form-item>
#elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}" prop="${field}">
<file-upload v-model="form.${field}"/>
<#elseif column.htmlType == "fileUpload">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<file-upload v-model="form.${column.javaField}"/>
</el-form-item>
#elseif($column.htmlType == "editor")
<el-form-item label="${comment}">
<editor v-model="form.${field}" :min-height="192"/>
<#elseif column.htmlType == "editor">
<el-form-item label="${column.columnLabel}">
<editor v-model="form.${column.javaField}" :min-height="192"/>
</el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}">
<#elseif column.htmlType == "select" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
<el-option
v-for="dict in ${dictType}"
v-for="dict in ${column.dictType}"
:key="dict.value"
:label="dict.label"
#if($column.javaType == "Integer" || $column.javaType == "Long")
<#if column.javaType == "Integer" || column.javaType == "Long">
:value="parseInt(dict.value)"
#else
<#else>
:value="dict.value"
#end
</#if>
></el-option>
</el-select>
</el-form-item>
#elseif($column.htmlType == "select" && $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}">
<#elseif column.htmlType == "select" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}">
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-checkbox-group v-model="form.${column.javaField}">
<el-checkbox
v-for="dict in ${dictType}"
v-for="dict in ${column.dictType}"
:key="dict.value"
:label="dict.value">
{{dict.label}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}">
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-checkbox-group v-model="form.${column.javaField}">
<el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}">
<#elseif column.htmlType == "radio" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-radio-group v-model="form.${column.javaField}">
<el-radio
v-for="dict in ${dictType}"
v-for="dict in ${column.dictType}"
:key="dict.value"
#if($column.javaType == "Integer" || $column.javaType == "Long")
<#if column.javaType == "Integer" || column.javaType == "Long">
:value="parseInt(dict.value)"
#else
<#else>
:value="dict.value"
#end
</#if>
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "radio" && $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}">
<#elseif column.htmlType == "radio" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-radio-group v-model="form.${column.javaField}">
<el-radio value="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "switch")
<el-form-item label="${comment}" prop="${field}">
<#elseif column.htmlType == "switch">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-switch
v-model="form.${field}"
#if($column.javaType == "Boolean")
v-model="form.${column.javaField}"
<#if column.javaType == "Boolean">
:active-value="true"
:inactive-value="false"
#elseif($column.javaType == "Integer" || $column.javaType == "Long")
<#elseif column.javaType == "Integer" || column.javaType == "Long">
:active-value="0"
:inactive-value="1"
#else
<#else>
active-value="0"
inactive-value="1"
#end
</#if>
/>
</el-form-item>
#elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}">
<#elseif column.htmlType == "datetime">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-date-picker clearable
v-model="form.${field}"
v-model="form.${column.javaField}"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择${comment}"
placeholder="选择${column.columnLabel}"
/>
</el-form-item>
#elseif($column.htmlType == "textarea")
<el-form-item label="${comment}" prop="${field}">
<el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
<#elseif column.htmlType == "textarea">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input v-model="form.${column.javaField}" type="textarea" placeholder="请输入内容" />
</el-form-item>
#end
#end
#end
</#if>
</#if>
</#list>
</el-form>
<template #footer>
<div class="dialog-footer">
@@ -421,56 +398,49 @@
</div>
</template>
#set($needAddDateRange = false)
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($needAddDateRange = true)
#end
#end
<script setup name="${BusinessName}" lang="ts">
import {
add${BusinessName},
#if($enableStatus)
<#if enableStatus>
change${BusinessName}Status,
#end
</#if>
del${BusinessName},
get${BusinessName},
list${BusinessName},
#if($enableSort)
<#if enableSort>
update${BusinessName}Sort,
#end
</#if>
update${BusinessName}
} from '@/api/${moduleName}/${businessName}';
import { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
import { useLoading } from '@/hooks/async/useLoading';
import { useFormDialog } from '@/hooks/dialog/useFormDialog';
#if($needAddDateRange)
<#if needAddDateRange>
import { useDateRangeQuery } from '@/hooks/form/useDateRangeQuery';
#end
</#if>
import { useSearchReset } from '@/hooks/form/useSearchReset';
import { useSearchToggle } from '@/hooks/form/useSearchToggle';
import { useTreeTableExpand } from '@/hooks/tree/useTreeTableExpand';
#if(${dicts} != '')
<#if needDict>
import { useDict } from '@/utils/dict';
#end
</#if>
import modal from '@/plugins/modal';
import { handleTree } from '@/utils/ruoyi';
#if($enableExport)
<#if enableExport>
import { download as requestDownload } from '@/utils/request';
#end
</#if>
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
<#if needDict>
const { ${dictsNoSymbol} } = toRefs<any>(useDict(${dicts}));
#end
</#if>
#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
<#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>
type ${BusinessName}Option = {
${treeCode}: #if($treeParentColumn.javaType == 'String')string#else number#end;
${treeCode}: <#if treeParentColumn.javaType == 'String'>string<#else> number</#if>;
${treeName}: string;
children?: ${BusinessName}Option[];
};
@@ -490,65 +460,58 @@ const { isExpandAll, handleToggleExpandAll } = useTreeTableExpand<${BusinessName
data: ${businessName}List
});
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
<#list columns as column>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
const {
dateRange: dateRange${AttrName},
applyDateRange: apply${AttrName}DateRange,
resetDateRange: reset${AttrName}DateRange
} = useDateRangeQuery('${AttrName}');
#end
#end
dateRange: dateRange${column.capJavaField},
applyDateRange: apply${column.capJavaField}DateRange,
resetDateRange: reset${column.capJavaField}DateRange
} = useDateRangeQuery('${column.capJavaField}');
</#if>
</#list>
const initFormData: ${BusinessName}Form = {
#foreach ($column in $columns)
#if($column.insert || $column.edit)
#if($column.htmlType == "checkbox")
$column.javaField: []#if($foreach.count != $columns.size()),#end
#else
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
#end
<#list columns as column>
<#if column.insert || column.edit>
<#if column.htmlType == "checkbox">
${column.javaField}: [],
<#else>
${column.javaField}: undefined,
</#if>
</#if>
</#list>
}
const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
form: {...initFormData},
queryParams: {
#foreach ($column in $columns)
#if($column.query)
#if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
$column.javaField: undefined,
#end
#end
#end
<#list columns as column>
<#if column.query>
<#if column.htmlType != "datetime" || column.queryType != "BETWEEN">
${column.javaField}: undefined,
</#if>
</#if>
</#list>
params: {
#foreach ($column in $columns)
#if($column.query)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
#end
<#list columns as column>
<#if column.query>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
${column.javaField}: undefined,
</#if>
</#if>
</#list>
}
},
rules: {
#foreach ($column in $columns)
#if($column.insert || $column.edit)
#if($column.required)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
$column.javaField: [
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch" || $column.htmlType == "inputNumber")"change"#else"blur"#end }
]#if($foreach.count != $columns.size()),#end
#end
#end
#end
<#list columns as column>
<#if column.insert || column.edit>
<#if column.required>
${column.javaField}: [
{ required: true, message: "${column.columnLabel}不能为空", trigger: <#if column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch" || column.htmlType == "inputNumber">"change"<#else>"blur"</#if> }
],
</#if>
</#if>
</#list>
}
});
@@ -562,18 +525,17 @@ const { dialog, resetForm: reset, openDialog, showDialog, closeDialog } = useFor
/** 查询${functionName}列表 */
const getList = async () => {
await withLoading(async () => {
#if($needAddDateRange)
<#if needAddDateRange>
let params = queryParams.value;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
params = apply${AttrName}DateRange(params);
#end
#end
<#list columns as column>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
params = apply${column.capJavaField}DateRange(params);
</#if>
</#list>
const res = await list${BusinessName}(params);
#else
<#else>
const res = await list${BusinessName}(queryParams.value);
#end
</#if>
const data = handleTree<${BusinessName}VO>(res.data, '${treeCode}', '${treeParentCode}');
if (data) {
${businessName}List.value = data;
@@ -605,12 +567,11 @@ const { resetQuery } = useSearchReset({
queryFormRef,
queryParams,
resetExtras: () => {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
reset${AttrName}DateRange();
#end
#end
<#list columns as column>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
reset${column.capJavaField}DateRange();
</#if>
</#list>
},
afterReset: () => {
handleQuery();
@@ -637,11 +598,11 @@ const handleUpdate = async (row: Partial<${BusinessName}VO>) => {
}
const res = await get${BusinessName}(row.${pkColumn.javaField});
Object.assign(form.value, res.data);
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(",");
#end
#end
<#list columns as column>
<#if column.htmlType == "checkbox">
form.value.${column.javaField} = form.value.${column.javaField}.split(",");
</#if>
</#list>
showDialog('修改${functionName}');
};
@@ -650,11 +611,11 @@ const submitForm = () => {
${businessName}FormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(",");
#end
#end
<#list columns as column>
<#if column.htmlType == "checkbox">
form.value.${column.javaField} = form.value.${column.javaField}.join(",");
</#if>
</#list>
if (form.value.${pkColumn.javaField}) {
await update${BusinessName}(form.value).finally(() => (buttonLoading.value = false));
} else {
@@ -685,7 +646,7 @@ const filterTreeOptions = (options: ${BusinessName}Option[], excludeId: string |
}));
};
#if($enableStatus)
<#if enableStatus>
/** 状态修改 */
const handleStatusChange = async (row: Partial<${BusinessName}VO>) => {
const text = row.${statusField} === ${statusField}ActiveValue ? '启用' : '停用';
@@ -697,9 +658,9 @@ const handleStatusChange = async (row: Partial<${BusinessName}VO>) => {
row.${statusField} = row.${statusField} === ${statusField}ActiveValue ? ${statusField}InactiveValue : ${statusField}ActiveValue;
}
};
#end
</#if>
#if($enableSort)
<#if enableSort>
/** 排序调整 */
const handleSortChange = async (row: Partial<${BusinessName}VO>) => {
try {
@@ -709,9 +670,9 @@ const handleSortChange = async (row: Partial<${BusinessName}VO>) => {
await getList();
}
};
#end
</#if>
#if($enableExport)
<#if enableExport>
/** 导出按钮操作 */
const handleExport = () => {
requestDownload(
@@ -719,12 +680,13 @@ const handleExport = () => {
{
...queryParams.value
},
`${businessName}_#[[${new Date().getTime()}]]#.xlsx`
`${businessName}_${r'${new Date().getTime()}'}.xlsx`
);
};
#end
</#if>
onMounted(() => {
getList();
});
</script>
@@ -8,70 +8,62 @@
</div>
</template>
<el-form ref="queryFormRef" :model="queryParams" :inline="true" class="query-form">
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.htmlType == "input" || $column.htmlType == "textarea")
<el-form-item label="${comment}" prop="${column.javaField}">
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${comment}" clearable @keyup.enter="handleQuery" />
<#list columns as column>
<#if column.query>
<#if column.htmlType == "input" || column.htmlType == "textarea">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${column.columnLabel}" clearable @keyup.enter="handleQuery" />
</el-form-item>
#elseif($column.htmlType == "inputNumber")
<el-form-item label="${comment}" prop="${column.javaField}">
<#elseif column.htmlType == "inputNumber">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input-number v-model="queryParams.${column.javaField}" controls-position="right" />
</el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable >
<el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
#elseif($column.htmlType == "switch" && "" != $dictType)
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable >
<el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
<#elseif column.htmlType == "switch" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
<el-option v-for="dict in ${column.dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
</el-select>
</el-form-item>
#elseif($column.htmlType == "switch")
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable >
#if($column.javaType == "Boolean")
<#elseif column.htmlType == "switch">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
<#if column.javaType == "Boolean">
<el-option label="是" :value="true" />
<el-option label="否" :value="false" />
#elseif($column.javaType == "Integer" || $column.javaType == "Long")
<#elseif column.javaType == "Integer" || column.javaType == "Long">
<el-option label="开启" :value="0" />
<el-option label="关闭" :value="1" />
#else
<#else>
<el-option label="开启" value="0" />
<el-option label="关闭" value="1" />
#end
</#if>
</el-select>
</el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
<el-form-item label="${comment}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable >
<#elseif (column.htmlType == "select" || column.htmlType == "radio") && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${column.columnLabel}" clearable >
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}">
<#elseif column.htmlType == "datetime" && column.queryType != "BETWEEN">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-date-picker clearable
v-model="queryParams.${column.javaField}"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择${comment}"
placeholder="请选择${column.columnLabel}"
/>
</el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}" style="width: 308px">
<#elseif column.htmlType == "datetime" && column.queryType == "BETWEEN">
<el-form-item label="${column.columnLabel}" style="width: 308px">
<el-date-picker
v-model="dateRange${AttrName}"
v-model="dateRange${column.capJavaField}"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
range-separator="-"
@@ -80,9 +72,9 @@
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
/>
</el-form-item>
#end
#end
#end
</#if>
</#if>
</#list>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -101,9 +93,9 @@
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button>
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button>
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button>
#if($enableExport)
<#if enableExport>
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['${moduleName}:${businessName}:export']">导出</el-button>
#end
</#if>
<right-toolbar v-model:show-search="showSearch" :search="false" @query-table="getList"></right-toolbar>
</div>
</div>
@@ -111,112 +103,105 @@
<el-table v-loading="loading" border class="data-table" :data="${businessName}List" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.pk)
<el-table-column label="${comment}" align="center" prop="${javaField}" v-if="${column.list}" />
#elseif($enableStatus && $statusField == $javaField)
<el-table-column label="${comment}" align="center" prop="${javaField}">
<#list columns as column>
<#if column.pk && column.list>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" />
<#elseif enableStatus && statusField == column.javaField>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
<template #default="scope">
<el-switch
v-model="scope.row.${javaField}"
v-model="scope.row.${column.javaField}"
:active-value="${statusField}ActiveValue"
:inactive-value="${statusField}InactiveValue"
@change="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
#elseif($enableSort && $sortField == $javaField)
<el-table-column label="${comment}" align="center" prop="${javaField}" width="160">
<#elseif enableSort && sortField == column.javaField>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="160">
<template #default="scope">
#if($column.javaType == "LocalDateTime")
<#if column.javaType == "LocalDateTime">
<el-date-picker
v-model="scope.row.${javaField}"
v-model="scope.row.${column.javaField}"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="选择${comment}"
placeholder="选择${column.columnLabel}"
@change="handleSortChange(scope.row)"
/>
#else
<el-input-number v-model="scope.row.${javaField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
#end
<#else>
<el-input-number v-model="scope.row.${column.javaField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
</#if>
</template>
</el-table-column>
#elseif($column.list && $column.htmlType == "switch")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="120">
<#elseif column.list && column.htmlType == "switch">
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="120">
<template #default="scope">
<el-switch
v-model="scope.row.${javaField}"
#if($column.javaType == "Boolean")
v-model="scope.row.${column.javaField}"
<#if column.javaType == "Boolean">
:active-value="true"
:inactive-value="false"
#elseif($column.javaType == "Integer" || $column.javaType == "Long")
<#elseif column.javaType == "Integer" || column.javaType == "Long">
:active-value="0"
:inactive-value="1"
#else
<#else>
active-value="0"
inactive-value="1"
#end
</#if>
disabled
/>
</template>
</el-table-column>
#elseif($column.list && $column.htmlType == "datetime")
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
<#elseif column.list && column.htmlType == "datetime">
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
<span>{{ parseTime(scope.row.${column.javaField}, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
<el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
<#elseif column.list && column.htmlType == "imageUpload">
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}Url" width="100">
<template #default="scope">
<image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
<image-preview :src="scope.row.${column.javaField}Url" :width="50" :height="50"/>
</template>
</el-table-column>
#elseif($column.list && $column.dictColumn)
<el-table-column label="${comment}" align="center" prop="${javaField}">
<#elseif column.list && column.dictColumn>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}">
<template #default="scope">
#if($column.htmlType == "checkbox")
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
#else
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
#end
<#if column.htmlType == "checkbox">
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField} ? scope.row.${column.javaField}.split(',') : []"/>
<#else>
<dict-tag :options="${column.dictType}" :value="scope.row.${column.javaField}"/>
</#if>
</template>
</el-table-column>
#elseif($column.list && "" != $javaField)
<el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
#if($enableStatus && !$statusColumn.list)
<#elseif column.list && "" != column.javaField>
<el-table-column label="${column.columnLabel}" align="center" prop="${column.javaField}" />
</#if>
</#list>
<#if enableStatus && !statusColumn.list>
<el-table-column label="${statusColumn.columnComment}" align="center" prop="${statusField}">
<template #default="scope">
<el-switch
v-model="scope.row.${statusField}"
#if($statusColumn.javaType == "Boolean")
<#if statusColumn.javaType == "Boolean">
:active-value="true"
:inactive-value="false"
#elseif($statusColumn.javaType == "Integer" || $statusColumn.javaType == "Long")
<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">
:active-value="0"
:inactive-value="1"
#else
<#else>
active-value="0"
inactive-value="1"
#end
</#if>
@change="handleStatusChange(scope.row)"
/>
</template>
</el-table-column>
#end
#if($enableSort && !$sortColumn.list)
</#if>
<#if enableSort && !sortColumn.list>
<el-table-column label="${sortColumn.columnComment}" align="center" prop="${sortField}" width="160">
<template #default="scope">
#if($sortColumn.javaType == "LocalDateTime")
<#if sortColumn.javaType == "LocalDateTime">
<el-date-picker
v-model="scope.row.${sortField}"
type="datetime"
@@ -224,12 +209,12 @@
placeholder="选择${sortColumn.columnComment}"
@change="handleSortChange(scope.row)"
/>
#else
<#else>
<el-input-number v-model="scope.row.${sortField}" controls-position="right" :min="0" @change="handleSortChange(scope.row)" />
#end
</#if>
</template>
</el-table-column>
#end
</#if>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
@@ -247,126 +232,117 @@
<!-- 添加或修改${functionName}对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
#foreach($column in $columns)
#set($field=$column.javaField)
#if(($column.insert || $column.edit) && !$column.pk)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#set($dictType=$column.dictType)
#if($column.htmlType == "input")
<el-form-item label="${comment}" prop="${field}">
<el-input v-model="form.${field}" placeholder="请输入${comment}" />
<#list columns as column>
<#if (column.insert || column.edit) && !column.pk>`n<#if column.htmlType == "input">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input v-model="form.${column.javaField}" placeholder="请输入${column.columnLabel}" />
</el-form-item>
#elseif($column.htmlType == "inputNumber")
<el-form-item label="${comment}" prop="${field}">
<el-input-number v-model="form.${field}" controls-position="right" />
<#elseif column.htmlType == "inputNumber">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input-number v-model="form.${column.javaField}" controls-position="right" />
</el-form-item>
#elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}" prop="${field}">
<image-upload v-model="form.${field}"/>
<#elseif column.htmlType == "imageUpload">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<image-upload v-model="form.${column.javaField}"/>
</el-form-item>
#elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}" prop="${field}">
<file-upload v-model="form.${field}"/>
<#elseif column.htmlType == "fileUpload">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<file-upload v-model="form.${column.javaField}"/>
</el-form-item>
#elseif($column.htmlType == "editor")
<el-form-item label="${comment}">
<editor v-model="form.${field}" :min-height="192"/>
<#elseif column.htmlType == "editor">
<el-form-item label="${column.columnLabel}">
<editor v-model="form.${column.javaField}" :min-height="192"/>
</el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}">
<#elseif column.htmlType == "select" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
<el-option
v-for="dict in ${dictType}"
v-for="dict in ${column.dictType}"
:key="dict.value"
:label="dict.label"
#if($column.javaType == "Integer" || $column.javaType == "Long")
<#if column.javaType == "Integer" || column.javaType == "Long">
:value="parseInt(dict.value)"
#else
<#else>
:value="dict.value"
#end
</#if>
></el-option>
</el-select>
</el-form-item>
#elseif($column.htmlType == "select" && $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}">
<#elseif column.htmlType == "select" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-select v-model="form.${column.javaField}" placeholder="请选择${column.columnLabel}">
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}">
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-checkbox-group v-model="form.${column.javaField}">
<el-checkbox
v-for="dict in ${dictType}"
v-for="dict in ${column.dictType}"
:key="dict.value"
:label="dict.value">
{{dict.label}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-checkbox-group v-model="form.${field}">
<#elseif column.htmlType == "checkbox" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-checkbox-group v-model="form.${column.javaField}">
<el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}">
<#elseif column.htmlType == "radio" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-radio-group v-model="form.${column.javaField}">
<el-radio
v-for="dict in ${dictType}"
v-for="dict in ${column.dictType}"
:key="dict.value"
#if($column.javaType == "Integer" || $column.javaType == "Long")
<#if column.javaType == "Integer" || column.javaType == "Long">
:value="parseInt(dict.value)"
#else
<#else>
:value="dict.value"
#end
</#if>
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "radio" && $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-radio-group v-model="form.${field}">
<#elseif column.htmlType == "radio" && column.dictType?has_content>
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-radio-group v-model="form.${column.javaField}">
<el-radio value="1">请选择字典生成</el-radio>
</el-radio-group>
</el-form-item>
#elseif($column.htmlType == "switch")
<el-form-item label="${comment}" prop="${field}">
<#elseif column.htmlType == "switch">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-switch
v-model="form.${field}"
#if($column.javaType == "Boolean")
v-model="form.${column.javaField}"
<#if column.javaType == "Boolean">
:active-value="true"
:inactive-value="false"
#elseif($column.javaType == "Integer" || $column.javaType == "Long")
<#elseif column.javaType == "Integer" || column.javaType == "Long">
:active-value="0"
:inactive-value="1"
#else
<#else>
active-value="0"
inactive-value="1"
#end
</#if>
/>
</el-form-item>
#elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}">
<#elseif column.htmlType == "datetime">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-date-picker clearable
v-model="form.${field}"
v-model="form.${column.javaField}"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择${comment}">
placeholder="请选择${column.columnLabel}">
</el-date-picker>
</el-form-item>
#elseif($column.htmlType == "textarea")
<el-form-item label="${comment}" prop="${field}">
<el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
<#elseif column.htmlType == "textarea">
<el-form-item label="${column.columnLabel}" prop="${column.javaField}">
<el-input v-model="form.${column.javaField}" type="textarea" placeholder="请输入内容" />
</el-form-item>
#end
#end
#end
</#if>
</#if>
</#list>
</el-form>
<template #footer>
<div class="dialog-footer">
@@ -378,121 +354,107 @@
</div>
</template>
#set($needAddDateRange = false)
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($needAddDateRange = true)
#end
#end
<script setup name="${BusinessName}" lang="ts">
import {
add${BusinessName},
#if($enableStatus)
<#if enableStatus>
change${BusinessName}Status,
#end
</#if>
del${BusinessName},
get${BusinessName},
list${BusinessName},
#if($enableSort)
<#if enableSort>
update${BusinessName}Sort,
#end
</#if>
update${BusinessName}
} from '@/api/${moduleName}/${businessName}';
import { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from '@/api/${moduleName}/${businessName}/types';
import { useLoading } from '@/hooks/async/useLoading';
import { useFormDialog } from '@/hooks/dialog/useFormDialog';
#if($needAddDateRange)
<#if needAddDateRange>
import { useDateRangeQuery } from '@/hooks/form/useDateRangeQuery';
#end
</#if>
import { useSearchReset } from '@/hooks/form/useSearchReset';
import { useSearchToggle } from '@/hooks/form/useSearchToggle';
import { useTableSelection } from '@/hooks/table/useTableSelection';
#if(${dicts} != '')
<#if needDict>
import { useDict } from '@/utils/dict';
#end
</#if>
import modal from '@/plugins/modal';
#if($enableExport)
<#if enableExport>
import { download as requestDownload } from '@/utils/request';
#end
</#if>
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
<#if needDict>
const { ${dictsNoSymbol} } = toRefs<any>(useDict(${dicts}));
#end
</#if>
#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
<#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>
const ${businessName}List = ref<${BusinessName}VO[]>([]);
const buttonLoading = ref(false);
const { loading, withLoading } = useLoading(true);
const { showSearch } = useSearchToggle();
const total = ref(0);
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
<#list columns as column>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
const {
dateRange: dateRange${AttrName},
applyDateRange: apply${AttrName}DateRange,
resetDateRange: reset${AttrName}DateRange
} = useDateRangeQuery('${AttrName}');
#end
#end
dateRange: dateRange${column.capJavaField},
applyDateRange: apply${column.capJavaField}DateRange,
resetDateRange: reset${column.capJavaField}DateRange
} = useDateRangeQuery('${column.capJavaField}');
</#if>
</#list>
const queryFormRef = ref<ElFormInstance>();
const ${businessName}FormRef = ref<ElFormInstance>();
const initFormData: ${BusinessName}Form = {
#foreach ($column in $columns)
#if($column.insert || $column.edit)
#if($column.htmlType == "checkbox")
$column.javaField: []#if($foreach.count != $columns.size()),#end
#else
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
#end
<#list columns as column>
<#if column.insert || column.edit>
<#if column.htmlType == "checkbox">
${column.javaField}: [],
<#else>
${column.javaField}: undefined,
</#if>
</#if>
</#list>
}
const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
#foreach ($column in $columns)
#if($column.query)
#if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
$column.javaField: undefined,
#end
#end
#end
<#list columns as column>
<#if column.query>
<#if column.htmlType != "datetime" || column.queryType != "BETWEEN">
${column.javaField}: undefined,
</#if>
</#if>
</#list>
params: {
#foreach ($column in $columns)
#if($column.query)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
#end
#end
#end
<#list columns as column>
<#if column.query>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
${column.javaField}: undefined,
</#if>
</#if>
</#list>
}
},
rules: {
#foreach ($column in $columns)
#if($column.insert || $column.edit)
#if($column.required)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
$column.javaField: [
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "switch" || $column.htmlType == "inputNumber")"change"#else"blur"#end }
]#if($foreach.count != $columns.size()),#end
#end
#end
#end
<#list columns as column>
<#if column.insert || column.edit>
<#if column.required>
${column.javaField}: [
{ required: true, message: "${column.columnLabel}不能为空", trigger: <#if column.htmlType == "select" || column.htmlType == "radio" || column.htmlType == "switch" || column.htmlType == "inputNumber">"change"<#else>"blur"</#if> }
],
</#if>
</#if>
</#list>
}
});
@@ -507,18 +469,17 @@ const { dialog, resetForm: reset, openDialog, showDialog, closeDialog } = useFor
/** 查询${functionName}列表 */
const getList = async () => {
await withLoading(async () => {
#if($needAddDateRange)
<#if needAddDateRange>
let params = queryParams.value;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
params = apply${AttrName}DateRange(params);
#end
#end
<#list columns as column>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
params = apply${column.capJavaField}DateRange(params);
</#if>
</#list>
const res = await list${BusinessName}(params);
#else
<#else>
const res = await list${BusinessName}(queryParams.value);
#end
</#if>
${businessName}List.value = res.data?.rows;
total.value = res.data?.total;
});
@@ -543,12 +504,11 @@ const { resetQuery } = useSearchReset({
pageSizeKey: 'pageSize',
initialPageSize: 10,
resetExtras: () => {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
reset${AttrName}DateRange();
#end
#end
<#list columns as column>
<#if column.htmlType == "datetime" && column.queryType == "BETWEEN">
reset${column.capJavaField}DateRange();
</#if>
</#list>
},
afterReset: () => {
handleQuery();
@@ -566,11 +526,11 @@ const handleUpdate = async (row?: Partial<${BusinessName}VO>) => {
const _${pkColumn.javaField} = row?.${pkColumn.javaField} || ids.value[0];
const res = await get${BusinessName}(_${pkColumn.javaField});
Object.assign(form.value, res.data);
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(",");
#end
#end
<#list columns as column>
<#if column.htmlType == "checkbox">
form.value.${column.javaField} = form.value.${column.javaField}.split(",");
</#if>
</#list>
showDialog('修改${functionName}');
};
@@ -579,11 +539,11 @@ const submitForm = () => {
${businessName}FormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(",");
#end
#end
<#list columns as column>
<#if column.htmlType == "checkbox">
form.value.${column.javaField} = form.value.${column.javaField}.join(",");
</#if>
</#list>
if (form.value.${pkColumn.javaField}) {
await update${BusinessName}(form.value).finally(() => (buttonLoading.value = false));
} else {
@@ -606,19 +566,19 @@ const handleDelete = async (row?: Partial<${BusinessName}VO>) => {
};
/** 导出按钮操作 */
#if($enableExport)
<#if enableExport>
const handleExport = () => {
requestDownload(
'${moduleName}/${businessName}/export',
{
...queryParams.value
},
`${businessName}_#[[${new Date().getTime()}]]#.xlsx`
`${businessName}_${r'${new Date().getTime()}'}.xlsx`
);
};
#end
</#if>
#if($enableStatus)
<#if enableStatus>
/** 状态修改 */
const handleStatusChange = async (row: Partial<${BusinessName}VO>) => {
const text = row.${statusField} === ${statusField}ActiveValue ? '启用' : '停用';
@@ -630,9 +590,9 @@ const handleStatusChange = async (row: Partial<${BusinessName}VO>) => {
row.${statusField} = row.${statusField} === ${statusField}ActiveValue ? ${statusField}InactiveValue : ${statusField}ActiveValue;
}
};
#end
</#if>
#if($enableSort)
<#if enableSort>
/** 排序调整 */
const handleSortChange = async (row: Partial<${BusinessName}VO>) => {
try {
@@ -642,9 +602,10 @@ const handleSortChange = async (row: Partial<${BusinessName}VO>) => {
await getList();
}
};
#end
</#if>
onMounted(() => {
getList();
});
</script>
@@ -0,0 +1,50 @@
import type { BaseEntity<#if !table.tree>, PageQuery</#if> } from '@/api/types';
export interface ${BusinessName}VO {
<#list columns as column>
<#if column.list>
/**
* ${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.columnComment}
*/
${column.javaField}?: ${column.tsType};
</#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?: any;
}
@@ -4,3 +4,6 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
</mapper>
@@ -13,4 +13,4 @@ gen:
# 模版加载模式
resourceMode: CLASSPATH
# 模板加载路径
# path: vm
# path: fm
@@ -1,62 +0,0 @@
package ${packageName}.domain.bo;
import ${packageName}.domain.${ClassName};
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import java.io.Serial;
import java.io.Serializable;
import lombok.Data;
import jakarta.validation.constraints.*;
#foreach ($import in $importList)
import ${import};
#end
/**
* ${functionName}业务对象 ${tableName}
*
* @author ${author}
* @date ${datetime}
*/
@Data
@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false)
public class ${ClassName}Bo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
#set($hasBetween = false)
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit))
/**
* $column.columnComment
*/
#if($column.insert && $column.edit)
#set($Group="AddGroup.class, EditGroup.class")
#elseif($column.insert)
#set($Group="AddGroup.class")
#elseif($column.edit)
#set($Group="EditGroup.class")
#end
#if($column.required)
#if($column.javaType == 'String')
@NotBlank(message = "$column.columnComment不能为空", groups = { $Group })
#else
@NotNull(message = "$column.columnComment不能为空", groups = { $Group })
#end
#end
private $column.javaType $column.javaField;
#end
#if($column.query && $column.queryType == 'BETWEEN')
#set($hasBetween = true)
#end
#end
#if($hasBetween)
/**
* 查询参数
*/
private Map<String, Object> params = new HashMap<>();
#end
}
@@ -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>
);
}
@@ -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>;
}
@@ -1,61 +0,0 @@
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;
}