diff --git a/.codex/skills/ruoyi-plus-ai-coding/SKILL.md b/.codex/skills/ruoyi-plus-ai-coding/SKILL.md index 5bbabd863..33ed52780 100644 --- a/.codex/skills/ruoyi-plus-ai-coding/SKILL.md +++ b/.codex/skills/ruoyi-plus-ai-coding/SKILL.md @@ -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 起点 ## 任务分型 diff --git a/.codex/skills/ruoyi-plus-ai-coding/references/backend.md b/.codex/skills/ruoyi-plus-ai-coding/references/backend.md index 0c84848d4..cc9841fac 100644 --- a/.codex/skills/ruoyi-plus-ai-coding/references/backend.md +++ b/.codex/skills/ruoyi-plus-ai-coding/references/backend.md @@ -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/...` diff --git a/.codex/skills/ruoyi-plus-ai-coding/references/frontend.md b/.codex/skills/ruoyi-plus-ai-coding/references/frontend.md index 72e17a9a8..87f8caf8d 100644 --- a/.codex/skills/ruoyi-plus-ai-coding/references/frontend.md +++ b/.codex/skills/ruoyi-plus-ai-coding/references/frontend.md @@ -2,18 +2,18 @@ ## 优先参考的代码来源 -- `ruoyi-modules/ruoyi-gen/src/main/resources/vm//*.vm` -- 默认 Vue 模板在 `vm/vue`,React 模板在 `vm/react` +- `ruoyi-modules/ruoyi-gen/src/main/resources/fm//*.ftl` +- 默认 Vue 模板在 `fm/vue`,React 模板在 `fm/react` - 前端工程中与目标模块最接近的现有页面 当前 boot4 仓库通常只含后端与 generator 前端模板;如果前端工程不在当前 root,先以 generator 模板约定为准,再对照用户提供的前端目录或相邻仓库。 ## 前端模板选择规则 -- `gen_table.frontend_type` 存字符串,值直接对应 `vm` 下的模板目录,例如 `vue`、`react`。 -- 生成器按 `vm//api.ts.vm`、`types.ts.vm`、`index.*.vm`、`index-tree.*.vm` 查找模板。 -- 页面输出后缀由页面模板文件名决定:`index.vue.vm` 输出 `index.vue`,`index.tsx.vm` 输出 `index.tsx`。 -- 新增其他前端时优先只新增 `vm/` 目录和对应 VM 文件,不在 Java 代码里增加数字枚举或硬编码分支。 +- `gen_table.frontend_type` 存字符串,值直接对应 `fm` 下的模板目录,例如 `vue`、`react`。 +- 生成器按 `fm//api.ts.ftl`、`types.ts.ftl`、`index.*.ftl`、`index-tree.*.ftl` 查找模板。 +- 页面输出后缀由页面模板文件名决定:`index.vue.ftl` 输出 `index.vue`,`index.tsx.ftl` 输出 `index.tsx`。 +- 新增其他前端时优先只新增 `fm/` 目录和对应 FTL 文件,不在 Java 代码里增加数字枚举或硬编码分支。 ## API 文件规则 diff --git a/pom.xml b/pom.xml index 48fd0963c..3f9475474 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ - 5.5.3 + 6.0.0 UTF-8 UTF-8 21 @@ -52,7 +52,6 @@ 1.18.42 0.15.0 2.0.2-incubating - 2.4.1 1.2.0 @@ -192,13 +191,6 @@ ${fesod.version} - - - org.apache.velocity - velocity-engine-core - ${velocity.version} - - com.baomidou diff --git a/ruoyi-modules/ruoyi-gen/pom.xml b/ruoyi-modules/ruoyi-gen/pom.xml index ac4a5661e..d99a403db 100644 --- a/ruoyi-modules/ruoyi-gen/pom.xml +++ b/ruoyi-modules/ruoyi-gen/pom.xml @@ -46,10 +46,10 @@ ruoyi-common-log - + - org.apache.velocity - velocity-engine-core + org.freemarker + freemarker diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java index ddf49b892..7cf2f2cad 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java @@ -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 动态解析。 diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java index 1f4da6243..221a92dc2 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java @@ -62,7 +62,7 @@ public class GenTable extends BaseEntity { private String tplCategory; /** - * 前端模板类型,对应 vm 下的模板目录 + * 前端模板类型,对应 fm 下的模板目录 */ private String frontendType; diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java index 5136177cb..bb6ac75fe 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java @@ -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); + } + /** * 判断当前列是否为主键列。 * diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/TemplateEngineUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/TemplateEngineUtils.java index b20e78815..60219397a 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/TemplateEngineUtils.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/TemplateEngineUtils.java @@ -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; } diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/bo.java.ftl b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/bo.java.ftl new file mode 100644 index 000000000..991460802 --- /dev/null +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/bo.java.ftl @@ -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; + +import lombok.Data; +import jakarta.validation.constraints.*; +<#list importList as import> +import ${import}; + + +/** + * ${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 column.required> +<#if column.javaType == 'String'> + @NotBlank(message = "${column.columnComment}不能为空", groups = { ${Group} }) +<#else> + @NotNull(message = "${column.columnComment}不能为空", groups = { ${Group} }) + + + private ${column.javaType} ${column.javaField}; + + + +<#if hasBetween> + /** + * 查询参数 + */ + private Map params = new HashMap<>(); + + +} + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/controller.java.ftl similarity index 94% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/controller.java.ftl index 3ac280c67..9b39684b8 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/controller.java.ftl @@ -3,9 +3,9 @@ package ${packageName}.controller; import java.util.List; import lombok.RequiredArgsConstructor; -#if($enableExport) +<#if enableExport> import jakarta.servlet.http.HttpServletResponse; -#end + 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 + 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> + /** * ${functionName} @@ -48,21 +48,21 @@ public class ${ClassName}Controller extends BaseController { */ @SaCheckPermission("${permissionPrefix}:list") @GetMapping("/list") -#if($table.crud) +<#if table.crud> public R> list(${ClassName}Bo bo, PageQuery pageQuery) { return R.ok(${className}Service.queryPageList(bo, pageQuery)); } -#elseif($table.tree) +<#elseif table.tree> public R> list(${ClassName}Bo bo) { List<${ClassName}Vo> list = ${className}Service.queryList(bo); return R.ok(list); } -#end + /** * 导出${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 + /** * 获取${functionName}详细信息 @@ -92,11 +92,11 @@ public class ${ClassName}Controller extends BaseController { @RepeatSubmit() @PostMapping() public R add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) { -#if($enableUnique) +<#if enableUnique> if (!${className}Service.checkUnique(bo)) { return R.fail("新增${functionName}失败,组合唯一字段已存在"); } -#end + return toAjax(${className}Service.insertByBo(bo)); } @@ -108,15 +108,15 @@ public class ${ClassName}Controller extends BaseController { @RepeatSubmit() @PutMapping() public R edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) { -#if($enableUnique) +<#if enableUnique> if (!${className}Service.checkUnique(bo)) { return R.fail("修改${functionName}失败,组合唯一字段已存在"); } -#end + return toAjax(${className}Service.updateByBo(bo)); } -#if($enableStatus) +<#if enableStatus> /** * 修改${functionName}状态 */ @@ -126,9 +126,9 @@ public class ${ClassName}Controller extends BaseController { public R changeStatus(@RequestBody ${ClassName}Bo bo) { return toAjax(${className}Service.updateStatus(bo.get${pkColumn.capJavaField}(), bo.get${statusColumn.capJavaField}())); } -#end + -#if($enableSort) +<#if enableSort> /** * 调整${functionName}排序 */ @@ -138,7 +138,7 @@ public class ${ClassName}Controller extends BaseController { public R updateSort(@RequestBody ${ClassName}Bo bo) { return toAjax(${className}Service.updateSort(bo.get${pkColumn.capJavaField}(), bo.get${sortColumn.capJavaField}())); } -#end + /** * 删除${functionName} @@ -153,3 +153,5 @@ public class ${ClassName}Controller extends BaseController { return toAjax(${className}Service.deleteWithValidByIds(List.of(${pkColumn.javaField}s), true)); } } + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/domain.java.ftl similarity index 50% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/domain.java.ftl index e25863fb5..c1fda8a5c 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/domain.java.ftl @@ -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 + 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 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 column.pk> + @TableId(value = "${column.columnName}") +<#elseif column.needTableField> + @TableField(value = "${column.columnName}") + + private ${column.javaType} ${column.javaField}; -#end -#end + + } + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/mapper.java.ftl similarity index 99% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/mapper.java.ftl index 0922401ec..acf164c78 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/mapper.java.ftl @@ -13,3 +13,6 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> { } + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/service.java.ftl similarity index 95% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/service.java.ftl index a94225245..60688565b 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/service.java.ftl @@ -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 + 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 + /** * 查询符合条件的${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 + /** * 新增${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($enableSort) +<#if enableSort> /** * 调整${functionName}排序 * @@ -91,7 +91,7 @@ public interface I${ClassName}Service { * @return 是否修改成功 */ Boolean updateSort(${pkColumn.javaType} ${pkColumn.javaField}, ${sortColumn.javaType} sortValue); -#end + /** * 校验并批量删除${functionName}信息 @@ -102,3 +102,6 @@ public interface I${ClassName}Service { */ Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid); } + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/serviceImpl.java.ftl similarity index 71% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/serviceImpl.java.ftl index d6e15e721..8a9b14644 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/serviceImpl.java.ftl @@ -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 + import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -#if($enableUnique) +<#if enableUnique> import com.baomidou.mybatisplus.core.toolkit.Wrappers; -#end + 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 + 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 + /** * 查询符合条件的${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 (!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 + lqw.ne(bo.get${pkColumn.capJavaField}() != null, ${ClassName}::get${pkColumn.capJavaField}, bo.get${pkColumn.capJavaField}()); return !${className}Mapper.exists(lqw); } -#end + 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 params = bo.getParams(); -#end + 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}()) + +<#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}()) + + +<#else> + .betweenParams(${ClassName}::get${column.capJavaField}, params, "begin${column.capJavaField}", "end${column.capJavaField}") + + + +<#if table.tree && "" != treeAncestorsField> + .orderByAsc(${ClassName}::get${treeAncestorsCap}) + +<#if table.tree && "" != treeParentCode> + .orderByAsc(${ClassName}::get${treeParentCap}) + +<#if table.tree && "" != treeOrderField> + .orderByAsc(${ClassName}::get${treeOrderCap}) +<#elseif enableSort> .orderByAsc(${ClassName}::get${sortColumn.capJavaField}) -#end + .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 + 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 + 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($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 + /** * 保存前的数据校验 @@ -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("" != $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 + + /** * 校验并批量删除${functionName}信息 @@ -362,3 +343,5 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { return ${className}Mapper.deleteByIds(ids) > 0; } } + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/vo.java.ftl similarity index 59% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/vo.java.ftl index 999715488..f8638258c 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/java/vo.java.ftl @@ -1,8 +1,8 @@ package ${packageName}.domain.vo; -#foreach ($import in $importList) +<#list importList as import> import ${import}; -#end + 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}") + + 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 + + + } + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/react/api.ts.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/react/api.ts.ftl similarity index 77% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/react/api.ts.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/react/api.ts.ftl index 0ff896bd5..a02ce3855 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/react/api.ts.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/react/api.ts.ftl @@ -1,4 +1,4 @@ -import type { #if(!$table.tree)PageResult, #end R } from '@/api/types'; +import type { <#if !table.tree>PageResult, 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#end>>({ + return request${BusinessName}VO[]<#else> PageResult<${BusinessName}VO>>>({ 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 ) { return request({ url: '/${moduleName}/${businessName}/changeStatus', @@ -63,14 +63,14 @@ export function change${BusinessName}Status( }); } -#end -#if($enableSort) + +<#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 ) { return request({ url: '/${moduleName}/${businessName}/updateSort', @@ -82,7 +82,7 @@ export function update${BusinessName}Sort( }); } -#end + /** * 删除${functionName} */ @@ -92,3 +92,7 @@ export function del${BusinessName}(${pkColumn.javaField}: string | number | Arra method: 'delete' }); } + + + + diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/react/index-tree.tsx.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/react/index-tree.tsx.ftl similarity index 50% rename from ruoyi-modules/ruoyi-gen/src/main/resources/vm/react/index-tree.tsx.vm rename to ruoyi-modules/ruoyi-gen/src/main/resources/fm/react/index-tree.tsx.ftl index c3952c827..26c3cdc68 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/react/index-tree.tsx.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/fm/react/index-tree.tsx.ftl @@ -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, EditOutlined, PlusOutlined, SortAscendingOutlined } from '@ant-design/icons'; import { ModalForm, PageContainer, -#if($needCheckbox) +<#if needCheckbox> ProFormCheckbox, -#end -#if($needDateField) + +<#if needDateField> ProFormDateTimePicker, -#end -#if($needDigit) + +<#if needDigit> ProFormDigit, -#end -#if($needSelect) + +<#if needSelect> ProFormSelect, -#end -#if($needTextArea) + +<#if needTextArea> ProFormTextArea, -#end + 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 enableSort>, InputNumber } 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 + del${BusinessName}, get${BusinessName}, list${BusinessName}, -#if($enableSort) +<#if enableSort> update${BusinessName}Sort, -#end + update${BusinessName} } from '@/api/${moduleName}/${businessName}'; -#if($needDict) +<#if needDict> import DictTag from '@/components/common/DictTag'; -#end -#if($needFileUpload) + +<#if needFileUpload> import FileUpload from '@/components/common/FileUpload'; -#end -#if($needImagePreview) + +<#if needImagePreview> import ImagePreview from '@/components/common/ImagePreview'; -#end -#if($needImageUpload) + +<#if needImageUpload> import ImageUpload from '@/components/common/ImageUpload'; -#end -#if($needEditor) + +<#if needEditor> import RichTextEditor from '@/components/common/RichTextEditor'; -#end + import RowActions from '@/components/common/RowActions'; -#if($needDict) +<#if needDict> import { useDict } from '@/hooks/useDict'; -#end -#if($enableExport) + +<#if enableExport> import { useTableExport } from '@/hooks/useTableExport'; -#end + import { useTreeTableExpand } from '@/hooks/useTreeTableExpand'; import { useUserStore } from '@/stores/userStore'; -#if($needDict) +<#if needDict> import { dictOptions } from '@/utils/dict'; -#end -#if($enableStatus) + +<#if enableStatus> import { confirmAction } from '@/utils/modal'; -#end + import { hasPermi } from '@/utils/permission'; -import { filterTree#if($needDateField), formatDateTimeFields#end, handleTree#if($needDateField), toDayjsFields#end } from '@/utils/ruoyi'; +import { filterTree<#if needDateField>, formatDateTimeFields, handleTree<#if needDateField>, toDayjsFields } 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 + + }; 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'; +const ${statusField}InactiveValue = <#if statusColumn.javaType == "Boolean">false<#elseif statusColumn.javaType == "Integer" || statusColumn.javaType == "Long">1<#else>'1'; -#end + export default function ${BusinessName}Page() { const actionRef = useRef(undefined); const [form] = Form.useForm<${BusinessName}Form>(); const userInfo = useUserStore(state => state.userInfo); -#if($needDict) +<#if needDict> const dicts = useDict(${dicts}); -#end + 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 + 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 + 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") + + + ])<#else>{ ...res.data }; +<#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 + + 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") + + + ])<#else>{ ...values }; +<#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 + + 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 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 && !$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}) }, + render: (_, row) => ( 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) => handleSortChange(row, value)} /> + render: (_, row) => 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, 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) => + render: (_, row) => }, -#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) => + fieldProps: { options: dictOptions(dicts.${column.dictType}) }, + render: (_, row) => }, -#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) => + render: (_, row) => }, -#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 }, + + + { title: '操作', valueType: 'option', @@ -341,7 +293,7 @@ export default function ${BusinessName}Page() { label: '删除', icon: , 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 + return { data: rows, total: rows.length, success: true }; }} toolbar={{ title: '${functionName}列表' }} @@ -386,16 +338,16 @@ export default function ${BusinessName}Page() { onClick={() => toggleExpandAll(tableRows)} > 展开/折叠 - #if($enableExport), + <#if enableExport>, canExport && ( - )#end + ) ]} /> @@ -411,62 +363,65 @@ export default function ${BusinessName}Page() { onFinish={submitForm} >