From c17948510c07a9f90dc9a60b6bd9baf5797c44c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Fri, 17 Apr 2026 18:24:04 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E9=87=8D=E6=9E=84=20=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E5=99=A8=E5=90=84?= =?UTF-8?q?=E9=A1=B9=E5=8A=9F=E8=83=BD=20update=20=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=88=A4=E6=96=AD=E5=8F=AF=E6=A0=B9=E6=8D=AE?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E6=95=B0=E6=8D=AE=E5=BA=93=E7=B2=BE=E7=A1=AE?= =?UTF-8?q?=E8=AF=86=E5=88=AB=20=E5=AF=B9=E5=BA=94=E7=9A=84java=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=20update=20=E4=BC=98=E5=8C=96java=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=90=8D=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93=E5=90=8D=E4=B8=8D?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E5=88=99=E5=A2=9E=E5=8A=A0=E5=88=AB=E5=90=8D?= =?UTF-8?q?=E6=B3=A8=E8=A7=A3=20update=20=E5=A2=9E=E5=8A=A0=20=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E5=AF=BC=E5=87=BA=20=E6=98=AF=E5=90=A6=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=88=87=E6=8D=A2=20=E6=98=AF=E5=90=A6=E7=BB=84?= =?UTF-8?q?=E5=90=88=E5=94=AF=E4=B8=80=E6=A0=A1=E9=AA=8C=20=E6=98=AF?= =?UTF-8?q?=E5=90=A6=E6=8E=92=E5=BA=8F=E8=B0=83=E6=95=B4=20=E5=92=8C?= =?UTF-8?q?=E6=A0=91=E7=BB=93=E6=9E=84=E7=9B=B8=E5=85=B3=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=AD=89=E5=8A=9F=E8=83=BD=E9=80=89=E6=8B=A9=20update=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=87=AA=E5=AE=9A=E4=B9=89=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=20=E5=AF=BC=E5=87=BA=E5=85=A8=E9=83=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20update=20=E5=88=A0=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E4=B8=BB=E5=AD=90=E8=A1=A8=E7=9B=B8=E5=85=B3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dromara/gen/constant/GenConstants.java | 65 +++++ .../dromara/gen/controller/GenController.java | 6 +- .../java/org/dromara/gen/domain/GenTable.java | 72 +++++- .../dromara/gen/domain/GenTableColumn.java | 26 ++ .../gen/service/GenTableServiceImpl.java | 103 ++++++-- .../dromara/gen/service/IGenTableService.java | 7 - .../java/org/dromara/gen/util/GenUtils.java | 116 ++++++++- .../dromara/gen/util/TemplateEngineUtils.java | 107 ++++++++- .../main/resources/vm/java/controller.java.vm | 40 ++++ .../src/main/resources/vm/java/domain.java.vm | 2 + .../main/resources/vm/java/service.java.vm | 32 +++ .../resources/vm/java/serviceImpl.java.vm | 203 ++++++++++++++-- .../src/main/resources/vm/ts/api.ts.vm | 36 +++ .../main/resources/vm/vue/index-tree.vue.vm | 224 +++++++++++++++++- .../src/main/resources/vm/vue/index.vue.vm | 183 +++++++++++++- 15 files changed, 1137 insertions(+), 85 deletions(-) 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 65e53067c..c79f02cc8 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 @@ -45,6 +45,56 @@ public interface GenConstants { */ String PARENT_MENU_NAME = "parentMenuName"; + /** + * 是否启用导出能力 + */ + String ENABLE_EXPORT = "enableExport"; + + /** + * 是否启用状态切换能力 + */ + String ENABLE_STATUS = "enableStatus"; + + /** + * 状态字段 + */ + String STATUS_FIELD = "statusField"; + + /** + * 是否启用组合唯一校验 + */ + String ENABLE_UNIQUE = "enableUnique"; + + /** + * 组合唯一字段 + */ + String UNIQUE_FIELDS = "uniqueFields"; + + /** + * 是否启用排序调整能力 + */ + String ENABLE_SORT = "enableSort"; + + /** + * 排序字段 + */ + String SORT_FIELD = "sortField"; + + /** + * 树根节点值 + */ + String TREE_ROOT_VALUE = "treeRootValue"; + + /** + * 树祖级字段 + */ + String TREE_ANCESTORS = "treeAncestors"; + + /** + * 树排序字段 + */ + String TREE_ORDER_FIELD = "treeOrderField"; + /** * 数据库字符串类型 */ @@ -128,6 +178,16 @@ public interface GenConstants { */ String HTML_DATETIME = "datetime"; + /** + * 开关控件 + */ + String HTML_SWITCH = "switch"; + + /** + * 数字输入控件 + */ + String HTML_INPUT_NUMBER = "inputNumber"; + /** * 图片上传控件 */ @@ -168,6 +228,11 @@ public interface GenConstants { */ String TYPE_BIGDECIMAL = "BigDecimal"; + /** + * 布尔类型 + */ + String TYPE_BOOLEAN = "Boolean"; + /** * 时间类型 */ diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java index c349b745a..460e95245 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java @@ -55,19 +55,17 @@ public class GenController extends BaseController { * 修改代码生成业务 * * @param tableId 表ID - * @return 表、字段与可选业务表信息 + * @return 表与字段信息 */ @RepeatSubmit() @SaCheckPermission("tool:gen:query") @GetMapping(value = "/{tableId}") public R> getInfo(@PathVariable Long tableId) { GenTable table = genTableService.selectGenTableById(tableId); - List tables = genTableService.selectGenTableAll(); List list = genTableService.selectGenTableColumnListByTableId(tableId); - Map map = new HashMap<>(3); + Map map = new HashMap<>(2); map.put("info", table); map.put("rows", list); - map.put("tables", tables); return R.ok(map); } 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 097145b8c..29da27e17 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 @@ -51,16 +51,6 @@ public class GenTable extends BaseEntity { @NotBlank(message = "表描述不能为空") private String tableComment; - /** - * 关联父表的表名 - */ - private String subTableName; - - /** - * 本表关联父表的外键名 - */ - private String subTableFkName; - /** * 实体类名称(首字母大写) */ @@ -68,7 +58,7 @@ public class GenTable extends BaseEntity { private String className; /** - * 使用的模板(crud单表操作 tree树表操作 sub主子表操作) + * 使用的模板(crud单表操作 tree树表操作) */ private String tplCategory; @@ -172,6 +162,66 @@ public class GenTable extends BaseEntity { @TableField(exist = false) private String parentMenuName; + /** + * 是否启用导出 + */ + @TableField(exist = false) + private Boolean enableExport; + + /** + * 是否启用状态切换 + */ + @TableField(exist = false) + private Boolean enableStatus; + + /** + * 状态字段 + */ + @TableField(exist = false) + private String statusField; + + /** + * 是否启用组合唯一校验 + */ + @TableField(exist = false) + private Boolean enableUnique; + + /** + * 组合唯一字段 + */ + @TableField(exist = false) + private List uniqueFields; + + /** + * 是否启用排序调整 + */ + @TableField(exist = false) + private Boolean enableSort; + + /** + * 排序字段 + */ + @TableField(exist = false) + private String sortField; + + /** + * 树根节点值 + */ + @TableField(exist = false) + private String treeRootValue; + + /** + * 树祖级字段 + */ + @TableField(exist = false) + private String treeAncestorsField; + + /** + * 树排序字段 + */ + @TableField(exist = false) + private String treeOrderField; + /** * 请求参数 */ 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 eed90061f..d1a13bd31 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 @@ -10,6 +10,7 @@ import lombok.EqualsAndHashCode; import org.apache.ibatis.type.JdbcType; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.gen.constant.GenConstants; /** * 代码生成业务字段表 gen_table_column @@ -307,6 +308,31 @@ public class GenTableColumn extends BaseEntity { return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); } + /** + * 判断当前列是否需要显式声明 MP 字段映射。 + * + * @return 字段名与下划线列名不一致时返回 {@code true} + */ + public boolean isNeedTableField() { + if (StringUtils.isAnyBlank(this.columnName, this.javaField)) { + return false; + } + return !StringUtils.equalsIgnoreCase(this.columnName, StringUtils.toUnderScoreCase(this.javaField)); + } + + /** + * 判断当前列是否属于字典控件列。 + * + * @return 仅当已配置字典类型且显示类型支持字典时返回 {@code true} + */ + public boolean isDictColumn() { + return StringUtils.isNotBlank(this.dictType) && StringUtils.equalsAny(this.htmlType, + GenConstants.HTML_SELECT, + GenConstants.HTML_RADIO, + GenConstants.HTML_CHECKBOX, + GenConstants.HTML_SWITCH); + } + /** * 从字段注释中解析字典读转换表达式。 * diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java index 3b68e0b0c..b025c6b8b 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java @@ -1,6 +1,7 @@ package org.dromara.gen.service; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Dict; @@ -220,17 +221,6 @@ public class GenTableServiceImpl implements IGenTableService { }).toList(); } - /** - * 查询所有表信息 - * - * @return 表信息集合 - */ - @Override - public List selectGenTableAll() { - return fillTableColumns(baseMapper.selectList(new LambdaQueryWrapper() - .orderByAsc(GenTable::getTableId))); - } - /** * 修改业务 * @@ -239,6 +229,7 @@ public class GenTableServiceImpl implements IGenTableService { @Transactional(rollbackFor = Exception.class) @Override public void updateGenTable(GenTable genTable) { + normalizeColumnOptions(genTable.getColumns()); String options = JsonUtils.toJsonString(genTable.getParams()); genTable.setOptions(options); int row = baseMapper.updateById(genTable); @@ -372,16 +363,13 @@ public class GenTableServiceImpl implements IGenTableService { List templates = TemplateEngineUtils.getTemplateList(table.getTplCategory(), table.getDataName()); for (PathNamedTemplate template : templates) { String pathName = template.getPathName(); - // 渲染模板 - if (!StringUtils.containsAny(pathName, "sql.vm", "api.ts.vm", "types.ts.vm", "index.vue.vm", "index-tree.vue.vm")) { - // 渲染模板 - try { - String render = template.render(context); - String path = getGenPath(table, pathName); - FileUtils.writeUtf8String(render, path); - } catch (Exception e) { - throw new ServiceException("渲染模板失败,表名:" + table.getTableName()); - } + try { + String render = template.render(context); + String path = getGenPath(table, pathName); + FileUtils.writeUtf8String(render, path); + } catch (Exception e) { + log.error("渲染模板失败,表名:{},模板:{}", table.getTableName(), pathName, e); + throw new ServiceException("渲染模板失败,表名:" + table.getTableName() + ",模板:" + pathName); } } } @@ -426,6 +414,7 @@ public class GenTableServiceImpl implements IGenTableService { saveColumns.add(column); }); if (CollUtil.isNotEmpty(saveColumns)) { + normalizeColumnOptions(saveColumns); genTableColumnMapper.insertOrUpdateBatch(saveColumns); } List delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName())); @@ -506,6 +495,7 @@ public class GenTableServiceImpl implements IGenTableService { */ @Override public void validateEdit(GenTable genTable) { + validateOptionColumns(genTable); if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) { String options = JsonUtils.toJsonString(genTable.getParams()); Dict paramsObj = JsonUtils.parseMap(options); @@ -519,6 +509,52 @@ public class GenTableServiceImpl implements IGenTableService { } } + private void validateOptionColumns(GenTable genTable) { + Map params = genTable.getParams(); + if (CollUtil.isEmpty(params) || CollUtil.isEmpty(genTable.getColumns())) { + return; + } + Set validFields = new HashSet<>(); + genTable.getColumns().forEach(column -> { + validFields.add(column.getColumnName()); + validFields.add(column.getJavaField()); + }); + validateOptionField(validFields, params.get(GenConstants.STATUS_FIELD), "状态字段"); + validateOptionField(validFields, params.get(GenConstants.SORT_FIELD), "排序字段"); + validateOptionField(validFields, params.get(GenConstants.TREE_ANCESTORS), "树祖级字段"); + validateOptionField(validFields, params.get(GenConstants.TREE_ORDER_FIELD), "树排序字段"); + Object uniqueFields = params.get(GenConstants.UNIQUE_FIELDS); + if (uniqueFields instanceof Collection collection) { + for (Object field : collection) { + validateOptionField(validFields, field, "组合唯一字段"); + } + } + } + + private void validateOptionField(Set validFields, Object field, String label) { + if (ObjectUtil.isNull(field)) { + return; + } + String fieldValue = Convert.toStr(field); + if (StringUtils.isBlank(fieldValue)) { + return; + } + if (!validFields.contains(fieldValue)) { + throw new ServiceException(label + "不存在,请刷新字段后重试"); + } + } + + private void normalizeColumnOptions(List columns) { + if (CollUtil.isEmpty(columns)) { + return; + } + for (GenTableColumn column : columns) { + if (!column.isDictColumn()) { + column.setDictType(StringUtils.EMPTY); + } + } + } + /** * 查询业务表并补齐其列信息。 * @@ -588,12 +624,32 @@ public class GenTableServiceImpl implements IGenTableService { String treeName = paramsObj.getStr(GenConstants.TREE_NAME); Long parentMenuId = paramsObj.getLong(GenConstants.PARENT_MENU_ID); String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME); + Boolean enableExport = Convert.toBool(paramsObj.get(GenConstants.ENABLE_EXPORT), true); + Boolean enableStatus = Convert.toBool(paramsObj.get(GenConstants.ENABLE_STATUS), false); + String statusField = paramsObj.getStr(GenConstants.STATUS_FIELD); + Boolean enableUnique = Convert.toBool(paramsObj.get(GenConstants.ENABLE_UNIQUE), false); + List uniqueFields = Convert.toList(String.class, paramsObj.get(GenConstants.UNIQUE_FIELDS)); + Boolean enableSort = Convert.toBool(paramsObj.get(GenConstants.ENABLE_SORT), false); + String sortField = paramsObj.getStr(GenConstants.SORT_FIELD); + String treeRootValue = paramsObj.getStr(GenConstants.TREE_ROOT_VALUE); + String treeAncestorsField = paramsObj.getStr(GenConstants.TREE_ANCESTORS); + String treeOrderField = paramsObj.getStr(GenConstants.TREE_ORDER_FIELD); genTable.setTreeCode(treeCode); genTable.setTreeParentCode(treeParentCode); genTable.setTreeName(treeName); genTable.setParentMenuId(parentMenuId); genTable.setParentMenuName(parentMenuName); + genTable.setEnableExport(enableExport); + genTable.setEnableStatus(enableStatus); + genTable.setStatusField(statusField); + genTable.setEnableUnique(enableUnique); + genTable.setUniqueFields(uniqueFields); + genTable.setEnableSort(enableSort); + genTable.setSortField(sortField); + genTable.setTreeRootValue(treeRootValue); + genTable.setTreeAncestorsField(treeAncestorsField); + genTable.setTreeOrderField(treeOrderField); } } @@ -605,11 +661,12 @@ public class GenTableServiceImpl implements IGenTableService { * @return 生成地址 */ public static String getGenPath(GenTable table, String template) { + String relativePath = StringUtils.replace(TemplateEngineUtils.getFileName(template, table), "/", File.separator); String genPath = table.getGenPath(); if (StringUtils.equals(genPath, "/")) { - return System.getProperty("user.dir") + File.separator + "src" + File.separator + TemplateEngineUtils.getFileName(template, table); + return System.getProperty("user.dir") + File.separator + "src" + File.separator + relativePath; } - return genPath + File.separator + TemplateEngineUtils.getFileName(template, table); + return genPath + File.separator + relativePath; } } diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java index 39ff6ffe5..93922d563 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java @@ -50,13 +50,6 @@ public interface IGenTableService { */ List selectDbTableListByNames(String[] tableNames, String dataName); - /** - * 查询所有表信息 - * - * @return 表信息集合 - */ - List selectGenTableAll(); - /** * 查询业务信息 * diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java index 27faa9799..b82ba1e55 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java +++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java @@ -45,9 +45,11 @@ public class GenUtils { * @param table 所属业务表对象 */ public static void initColumnField(GenTableColumn column, GenTable table) { - String dataType = getDbType(column.getColumnType()); + String dataType = getDbType(column.getColumnType()).toLowerCase(); // 统一转小写 避免有些数据库默认大写问题 如果需要特别书写方式 请在实体类增加注解标注别名 String columnName = column.getColumnName().toLowerCase(); + Integer columnLength = getColumnLength(column.getColumnType()); + Integer columnScale = getColumnScale(column.getColumnType()); column.setTableId(table.getTableId()); column.setCreateTime(null); column.setUpdateTime(null); @@ -59,17 +61,18 @@ public class GenUtils { if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) { // 字符串长度超过500设置为文本域 - Integer columnLength = getColumnLength(column.getColumnType()); String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; + if (isBooleanColumn(dataType, columnLength, columnScale, columnName)) { + column.setJavaType(GenConstants.TYPE_BOOLEAN); + htmlType = GenConstants.HTML_SWITCH; + } column.setHtmlType(htmlType); } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) { column.setJavaType(GenConstants.TYPE_DATE); column.setHtmlType(GenConstants.HTML_DATETIME); } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) { - column.setHtmlType(GenConstants.HTML_INPUT); - // 数据库的数字字段与java不匹配 且很多数据库的数字字段很模糊 例如oracle只有number没有细分 - // 所以默认数字类型全为Long可在界面上自行编辑想要的类型 有什么特殊需求也可以在这里特殊处理 - column.setJavaType(GenConstants.TYPE_LONG); + column.setJavaType(resolveNumberJavaType(dataType, columnLength, columnScale, columnName)); + column.setHtmlType(GenConstants.TYPE_BOOLEAN.equals(column.getJavaType()) ? GenConstants.HTML_SWITCH : GenConstants.HTML_INPUT_NUMBER); } // BO对象 默认插入勾选 @@ -93,29 +96,102 @@ public class GenUtils { if (StringUtils.endsWithIgnoreCase(columnName, "name")) { column.setQueryType(GenConstants.QUERY_LIKE); } + if (GenConstants.HTML_DATETIME.equals(column.getHtmlType()) && column.isQuery()) { + column.setQueryType(GenConstants.QUERY_BETWEEN); + } // 状态字段设置单选框 + if (isSwitchColumn(columnName) || GenConstants.TYPE_BOOLEAN.equals(column.getJavaType())) { + column.setHtmlType(GenConstants.HTML_SWITCH); + } + // 状态字段设置单选框/开关 if (StringUtils.endsWithIgnoreCase(columnName, "status")) { - column.setHtmlType(GenConstants.HTML_RADIO); + column.setHtmlType(GenConstants.TYPE_BOOLEAN.equals(column.getJavaType()) ? GenConstants.HTML_SWITCH : GenConstants.HTML_RADIO); } // 类型&性别字段设置下拉框 else if (StringUtils.endsWithIgnoreCase(columnName, "type") || StringUtils.endsWithIgnoreCase(columnName, "sex")) { column.setHtmlType(GenConstants.HTML_SELECT); } + // 排序字段设置数字输入控件 + else if (isSortColumn(columnName)) { + column.setHtmlType(GenConstants.HTML_INPUT_NUMBER); + } // 图片字段设置图片上传控件 - else if (StringUtils.endsWithIgnoreCase(columnName, "image")) { + else if (StringUtils.endsWithAny(columnName, "image", "avatar", "logo", "picture")) { column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD); } // 文件字段设置文件上传控件 - else if (StringUtils.endsWithIgnoreCase(columnName, "file")) { + else if (StringUtils.endsWithAny(columnName, "file", "attachment")) { column.setHtmlType(GenConstants.HTML_FILE_UPLOAD); } + // 备注描述类字段设置文本域 + else if (StringUtils.endsWithAny(columnName, "remark", "description", "desc", "note")) { + column.setHtmlType(GenConstants.HTML_TEXTAREA); + } // 内容字段设置富文本控件 - else if (StringUtils.endsWithIgnoreCase(columnName, "content")) { + else if (StringUtils.endsWithAny(columnName, "content", "html", "body")) { column.setHtmlType(GenConstants.HTML_EDITOR); } } + private static String resolveNumberJavaType(String dataType, Integer columnLength, Integer columnScale, String columnName) { + if (isBooleanColumn(dataType, columnLength, columnScale, columnName)) { + return GenConstants.TYPE_BOOLEAN; + } + if (arraysContains(new String[]{"decimal", "numeric", "money", "smallmoney"}, dataType)) { + return columnScale > 0 ? GenConstants.TYPE_BIGDECIMAL : resolveIntegerJavaType(columnLength); + } + if (arraysContains(new String[]{"float", "float4", "float8", "double", "real", "double precision"}, dataType)) { + return GenConstants.TYPE_DOUBLE; + } + if (arraysContains(new String[]{"bigint", "int8", "bigserial"}, dataType)) { + return GenConstants.TYPE_LONG; + } + if (arraysContains(new String[]{"smallint", "mediumint", "int", "int2", "int4", "integer", "smallserial", "serial"}, dataType)) { + return GenConstants.TYPE_INTEGER; + } + if (StringUtils.equals(dataType, "number")) { + if (columnScale > 0) { + return GenConstants.TYPE_BIGDECIMAL; + } + return resolveIntegerJavaType(columnLength); + } + return GenConstants.TYPE_LONG; + } + + private static String resolveIntegerJavaType(Integer columnLength) { + if (columnLength > 0 && columnLength <= 9) { + return GenConstants.TYPE_INTEGER; + } + return GenConstants.TYPE_LONG; + } + + private static boolean isBooleanColumn(String dataType, Integer columnLength, Integer columnScale, String columnName) { + if (columnScale > 0) { + return false; + } + if (StringUtils.equalsAny(dataType, "bit", "boolean", "bool")) { + return true; + } + if (StringUtils.equalsAny(dataType, "tinyint", "number", "numeric", "decimal", "char", "nchar") + && columnLength == 1 && isSwitchColumn(columnName)) { + return true; + } + return false; + } + + private static boolean isSwitchColumn(String columnName) { + return StringUtils.endsWithAny(columnName, "status", "flag", "enabled", "disabled", "available", "visible") + || columnName.startsWith("is_") + || columnName.startsWith("has_") + || columnName.startsWith("enable_") + || columnName.startsWith("disable_"); + } + + private static boolean isSortColumn(String columnName) { + return StringUtils.endsWithAny(columnName, "sort", "order_num", "order", "rank", "seq", "sequence"); + } + /** * 校验数组是否包含指定值 * @@ -219,14 +295,30 @@ public class GenUtils { */ public static Integer getColumnLength(String columnType) { if (StringUtils.indexOf(columnType, "(") > 0) { - String length = StringUtils.substringBetween(columnType, "(", ")"); + String length = StringUtils.substringBetween(columnType, "(", ")").trim(); // 处理 decimal(10,2) 这类带精度的类型,只取长度部分 if (length.contains(",")) { - length = StringUtils.substringBefore(length, ","); + length = StringUtils.substringBefore(length, ",").trim(); } return Integer.valueOf(length); } else { return 0; } } + + /** + * 获取字段精度 + * + * @param columnType 列类型 + * @return 字段精度,未声明精度时返回 0 + */ + public static Integer getColumnScale(String columnType) { + if (StringUtils.indexOf(columnType, "(") > 0) { + String length = StringUtils.substringBetween(columnType, "(", ")").trim(); + if (length.contains(",")) { + return Integer.valueOf(StringUtils.substringAfter(length, ",").trim()); + } + } + return 0; + } } 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 8f5d2c2ec..7ab9fe74b 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 @@ -3,6 +3,7 @@ package org.dromara.gen.util; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; 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 lombok.AccessLevel; @@ -108,6 +109,22 @@ public class TemplateEngineUtils { Dict paramsObj = JsonUtils.parseMap(options); String parentMenuId = getParentMenuId(paramsObj); context.put("parentMenuId", parentMenuId); + boolean enableExport = getBooleanOption(paramsObj, GenConstants.ENABLE_EXPORT, true); + boolean enableStatus = getBooleanOption(paramsObj, GenConstants.ENABLE_STATUS, false); + boolean enableUnique = getBooleanOption(paramsObj, GenConstants.ENABLE_UNIQUE, false); + boolean enableSort = getBooleanOption(paramsObj, GenConstants.ENABLE_SORT, false); + GenTableColumn statusColumn = getColumn(genTable, paramsObj.getStr(GenConstants.STATUS_FIELD)); + GenTableColumn sortColumn = getColumn(genTable, paramsObj.getStr(GenConstants.SORT_FIELD)); + List uniqueColumns = getColumns(genTable, paramsObj.get(GenConstants.UNIQUE_FIELDS)); + context.put("enableExport", enableExport); + context.put("enableStatus", enableStatus && ObjectUtil.isNotNull(statusColumn)); + context.put("statusColumn", statusColumn); + context.put("statusField", ObjectUtil.isNotNull(statusColumn) ? statusColumn.getJavaField() : StringUtils.EMPTY); + context.put("enableUnique", enableUnique && CollUtil.isNotEmpty(uniqueColumns)); + context.put("uniqueColumns", uniqueColumns); + context.put("enableSort", enableSort && ObjectUtil.isNotNull(sortColumn)); + context.put("sortColumn", sortColumn); + context.put("sortField", ObjectUtil.isNotNull(sortColumn) ? sortColumn.getJavaField() : StringUtils.EMPTY); // 向树形模板上下文写入树字段相关变量 if (GenConstants.TPL_TREE.equals(tplCategory)) { @@ -128,10 +145,21 @@ public class TemplateEngineUtils { String treeCode = getTreeCode(paramsObj); String treeParentCode = getTreeParentCode(paramsObj); String treeName = getTreeName(paramsObj); + GenTableColumn treeParentColumn = getColumn(genTable, paramsObj.getStr(GenConstants.TREE_PARENT_CODE)); + GenTableColumn treeAncestorsColumn = getColumn(genTable, paramsObj.getStr(GenConstants.TREE_ANCESTORS)); + GenTableColumn treeOrderColumn = getColumn(genTable, paramsObj.getStr(GenConstants.TREE_ORDER_FIELD)); + String treeRootValue = getTreeRootValue(paramsObj, treeParentColumn); context.put("treeCode", treeCode); context.put("treeParentCode", treeParentCode); context.put("treeName", treeName); + context.put("treeParentColumn", treeParentColumn); + context.put("treeAncestorsField", ObjectUtil.isNotNull(treeAncestorsColumn) ? treeAncestorsColumn.getJavaField() : StringUtils.EMPTY); + context.put("treeOrderField", ObjectUtil.isNotNull(treeOrderColumn) ? treeOrderColumn.getJavaField() : StringUtils.EMPTY); + context.put("treeOrderColumn", treeOrderColumn); + context.put("treeRootValue", treeRootValue); + context.put("treeRootValueJavaLiteral", getJavaLiteral(treeParentColumn, treeRootValue)); + context.put("treeRootValueTsLiteral", getTsLiteral(treeParentColumn, treeRootValue)); String expandTreeName = paramsObj.getStr(GenConstants.TREE_NAME); int expandColumn = 0; for (GenTableColumn column : genTable.getColumns()) { @@ -307,7 +335,7 @@ public class TemplateEngineUtils { for (GenTableColumn column : columns) { if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny( column.getHtmlType(), - new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) { + new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX, GenConstants.HTML_SWITCH })) { dicts.add("'" + column.getDictType() + "'"); } } @@ -376,4 +404,81 @@ public class TemplateEngineUtils { } return StringUtils.EMPTY; } + + /** + * 获取树根节点值。 + * + * @param paramsObj 其他选项 + * @param treeParentColumn 父节点字段 + * @return 树根节点值 + */ + public static String getTreeRootValue(Dict paramsObj, GenTableColumn treeParentColumn) { + String defaultValue = "0"; + if (ObjectUtil.isNotNull(treeParentColumn) && StringUtils.equals(treeParentColumn.getJavaType(), GenConstants.TYPE_STRING)) { + defaultValue = "0"; + } + if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_ROOT_VALUE)) { + return StringUtils.blankToDefault(paramsObj.getStr(GenConstants.TREE_ROOT_VALUE), defaultValue); + } + return defaultValue; + } + + private static boolean getBooleanOption(Dict paramsObj, String key, boolean defaultValue) { + if (CollUtil.isEmpty(paramsObj) || !paramsObj.containsKey(key)) { + return defaultValue; + } + return Convert.toBool(paramsObj.get(key), defaultValue); + } + + private static GenTableColumn getColumn(GenTable genTable, String field) { + if (StringUtils.isBlank(field) || CollUtil.isEmpty(genTable.getColumns())) { + return null; + } + for (GenTableColumn column : genTable.getColumns()) { + if (StringUtils.equalsAny(field, column.getColumnName(), column.getJavaField())) { + return column; + } + } + return null; + } + + private static List getColumns(GenTable genTable, Object fieldValues) { + List fields = new ArrayList<>(); + if (fieldValues instanceof Collection collection) { + collection.stream().map(Convert::toStr).forEach(fields::add); + } else if (ObjectUtil.isNotNull(fieldValues)) { + fields.addAll(StringUtils.str2List(Convert.toStr(fieldValues), StringUtils.SEPARATOR, true, true)); + } + List columns = new ArrayList<>(); + for (String field : fields) { + GenTableColumn column = getColumn(genTable, field); + if (ObjectUtil.isNotNull(column)) { + columns.add(column); + } + } + return columns; + } + + private static String getJavaLiteral(GenTableColumn column, String value) { + if (ObjectUtil.isNull(column) || StringUtils.isBlank(value)) { + return "null"; + } + if (StringUtils.equals(column.getJavaType(), GenConstants.TYPE_LONG)) { + return value + "L"; + } + if (StringUtils.equalsAny(column.getJavaType(), GenConstants.TYPE_INTEGER, GenConstants.TYPE_DOUBLE, GenConstants.TYPE_BIGDECIMAL)) { + return value; + } + return "\"" + value + "\""; + } + + private static String getTsLiteral(GenTableColumn column, String value) { + if (ObjectUtil.isNull(column) || StringUtils.isBlank(value)) { + return "undefined"; + } + if (StringUtils.equalsAny(column.getJavaType(), GenConstants.TYPE_LONG, GenConstants.TYPE_INTEGER, GenConstants.TYPE_DOUBLE, GenConstants.TYPE_BIGDECIMAL)) { + return value; + } + return "'" + value + "'"; + } } diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm index 2c3bf82f8..36c54ac03 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm @@ -3,7 +3,9 @@ package ${packageName}.controller; import java.util.List; import lombok.RequiredArgsConstructor; +#if($enableExport) import jakarta.servlet.http.HttpServletResponse; +#end import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; import org.springframework.web.bind.annotation.*; @@ -16,7 +18,9 @@ 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) import org.dromara.common.excel.utils.ExcelUtil; +#end import ${packageName}.domain.vo.${ClassName}Vo; import ${packageName}.domain.bo.${ClassName}Bo; import ${packageName}.service.I${ClassName}Service; @@ -58,6 +62,7 @@ public class ${ClassName}Controller extends BaseController { /** * 导出${functionName}列表 */ +#if($enableExport) @SaCheckPermission("${permissionPrefix}:export") @Log(title = "${functionName}", businessType = BusinessType.EXPORT) @PostMapping("/export") @@ -65,6 +70,7 @@ public class ${ClassName}Controller extends BaseController { List<${ClassName}Vo> list = ${className}Service.queryList(bo); ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response); } +#end /** * 获取${functionName}详细信息 @@ -86,6 +92,11 @@ public class ${ClassName}Controller extends BaseController { @RepeatSubmit() @PostMapping() public R add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) { +#if($enableUnique) + if (!${className}Service.checkUnique(bo)) { + return R.fail("新增${functionName}失败,组合唯一字段已存在"); + } +#end return toAjax(${className}Service.insertByBo(bo)); } @@ -97,9 +108,38 @@ public class ${ClassName}Controller extends BaseController { @RepeatSubmit() @PutMapping() public R edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) { +#if($enableUnique) + if (!${className}Service.checkUnique(bo)) { + return R.fail("修改${functionName}失败,组合唯一字段已存在"); + } +#end return toAjax(${className}Service.updateByBo(bo)); } +#if($enableStatus) + /** + * 修改${functionName}状态 + */ + @SaCheckPermission("${permissionPrefix}:edit") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody ${ClassName}Bo bo) { + return toAjax(${className}Service.updateStatus(bo.get${pkColumn.capJavaField}(), bo.get${statusColumn.capJavaField}())); + } +#end + +#if($enableSort) + /** + * 调整${functionName}排序 + */ + @SaCheckPermission("${permissionPrefix}:edit") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @PutMapping("/updateSort") + public R updateSort(@RequestBody ${ClassName}Bo bo) { + return toAjax(${className}Service.updateSort(bo.get${pkColumn.capJavaField}(), bo.get${sortColumn.capJavaField}())); + } +#end + /** * 删除${functionName} * diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm index ef38136aa..e25863fb5 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm @@ -38,6 +38,8 @@ public class ${ClassName} extends ${Entity} { #end #if($column.isPk==1) @TableId(value = "$column.columnName") +#elseif($column.needTableField) + @TableField(value = "$column.columnName") #end private $column.javaType $column.javaField; diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm index f3e18f435..a94225245 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm @@ -45,6 +45,16 @@ public interface I${ClassName}Service { */ List<${ClassName}Vo> queryList(${ClassName}Bo bo); +#if($enableUnique) + /** + * 校验${functionName}是否满足组合唯一约束 + * + * @param bo ${functionName} + * @return 是否唯一 + */ + boolean checkUnique(${ClassName}Bo bo); +#end + /** * 新增${functionName} * @@ -61,6 +71,28 @@ public interface I${ClassName}Service { */ Boolean updateByBo(${ClassName}Bo bo); +#if($enableStatus) + /** + * 修改${functionName}状态 + * + * @param ${pkColumn.javaField} 主键 + * @param status 状态值 + * @return 是否修改成功 + */ + Boolean updateStatus(${pkColumn.javaType} ${pkColumn.javaField}, ${statusColumn.javaType} status); +#end + +#if($enableSort) + /** + * 调整${functionName}排序 + * + * @param ${pkColumn.javaField} 主键 + * @param sortValue 排序值 + * @return 是否修改成功 + */ + Boolean updateSort(${pkColumn.javaType} ${pkColumn.javaField}, ${sortColumn.javaType} sortValue); +#end + /** * 校验并批量删除${functionName}信息 * diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm index 73a8193a7..ce5a6dff3 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm @@ -1,5 +1,6 @@ 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) @@ -7,6 +8,9 @@ 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($enableStatus || $enableSort) +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +#end import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; @@ -17,7 +21,11 @@ import ${packageName}.domain.vo.${ClassName}Vo; import ${packageName}.domain.${ClassName}; import ${packageName}.mapper.${ClassName}Mapper; import ${packageName}.service.I${ClassName}Service; +#if($table.tree) +import org.dromara.common.core.exception.ServiceException; +#end +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Collection; @@ -35,6 +43,19 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { private final ${ClassName}Mapper baseMapper; +#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} * @@ -42,7 +63,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { * @return ${functionName} */ @Override - public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){ + public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}) { return baseMapper.selectVoById(${pkColumn.javaField}); } @@ -74,7 +95,37 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { return baseMapper.selectVoList(lqw); } +#if($enableUnique) + /** + * 校验${functionName}是否满足组合唯一约束 + * + * @param bo ${functionName} + * @return 是否唯一 + */ + @Override + public boolean checkUnique(${ClassName}Bo bo) { + boolean hasUniqueValue = true; +#foreach($column in $uniqueColumns) +#if($column.javaType == 'String') + hasUniqueValue = hasUniqueValue && StringUtils.isNotBlank(bo.get${column.capJavaField}()); +#else + hasUniqueValue = hasUniqueValue && bo.get${column.capJavaField}() != null; +#end +#end + if (!hasUniqueValue) { + return true; + } + LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery(); +#foreach($column in $uniqueColumns) + 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 !baseMapper.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) @@ -87,10 +138,8 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { #foreach($column in $columns) #if($column.query) #set($queryType=$column.queryType) -#set($javaField=$column.javaField) #set($javaType=$column.javaType) -#set($columnName=$column.columnName) -#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($AttrName=$column.capJavaField) #set($mpMethod=$column.queryType.toLowerCase()) #if($queryType != 'BETWEEN') #if($javaType == 'String') @@ -101,14 +150,22 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName()); #else lqw.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null, - ${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName")); + ${ClassName}::get$AttrName, params.get("begin$AttrName"), params.get("end$AttrName")); #end #end -#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) -#if($column.isPk==1) - lqw.orderByAsc(${ClassName}::get$AttrName); #end +#if($table.tree && "" != $treeAncestorsField) + lqw.orderByAsc(${ClassName}::get${TreeAncestorsCap}); #end +#if($table.tree && "" != $treeParentCode) + lqw.orderByAsc(${ClassName}::get${TreeParentCap}); +#end +#if($table.tree && "" != $treeOrderField) + lqw.orderByAsc(${ClassName}::get${TreeOrderCap}); +#elseif($enableSort) + lqw.orderByAsc(${ClassName}::get${sortColumn.capJavaField}); +#end + lqw.orderByAsc(${ClassName}::get${pkColumn.capJavaField}); return lqw; } @@ -121,11 +178,13 @@ 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) + fillTreeMetaBeforeSave(add, false); +#end validEntityBeforeSave(add); boolean flag = baseMapper.insert(add) > 0; -#set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)}) if (flag) { - bo.set$pk(add.get$pk()); + bo.set${pkColumn.capJavaField}(add.get${pkColumn.capJavaField}()); } return flag; } @@ -139,17 +198,133 @@ 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) + fillTreeMetaBeforeSave(update, true); +#end validEntityBeforeSave(update); return baseMapper.updateById(update) > 0; } +#if($enableStatus) + /** + * 修改${functionName}状态 + * + * @param ${pkColumn.javaField} 主键 + * @param status 状态值 + * @return 是否修改成功 + */ + @Override + public Boolean updateStatus(${pkColumn.javaType} ${pkColumn.javaField}, ${statusColumn.javaType} status) { + return baseMapper.update(null, new LambdaUpdateWrapper<${ClassName}>() + .set(${ClassName}::get${statusColumn.capJavaField}, status) + .eq(${ClassName}::get${pkColumn.capJavaField}, ${pkColumn.javaField})) > 0; + } +#end + +#if($enableSort) + /** + * 调整${functionName}排序 + * + * @param ${pkColumn.javaField} 主键 + * @param sortValue 排序值 + * @return 是否修改成功 + */ + @Override + public Boolean updateSort(${pkColumn.javaType} ${pkColumn.javaField}, ${sortColumn.javaType} sortValue) { + return baseMapper.update(null, new LambdaUpdateWrapper<${ClassName}>() + .set(${ClassName}::get${sortColumn.capJavaField}, sortValue) + .eq(${ClassName}::get${pkColumn.capJavaField}, ${pkColumn.javaField})) > 0; + } +#end + /** * 保存前的数据校验 */ - private void validEntityBeforeSave(${ClassName} entity){ - //TODO 做一些数据校验,如唯一约束 + private void validEntityBeforeSave(${ClassName} entity) { + // 可在此扩展通用业务校验 } +#if($table.tree) + private void fillTreeMetaBeforeSave(${ClassName} entity, boolean updateMode) { +#if("" != $treeParentCode) + if (entity.get${TreeParentCap}() == null) { + entity.set${TreeParentCap}(${treeRootValueJavaLiteral}); + } + if (ObjectUtil.equal(entity.get${pkColumn.capJavaField}(), entity.get${TreeParentCap}())) { + throw new ServiceException("${functionName}父节点不能选择自身"); + } +#if("" != $treeAncestorsField) + ${ClassName} parent = null; + if (!ObjectUtil.equal(entity.get${TreeParentCap}(), ${treeRootValueJavaLiteral})) { + parent = baseMapper.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}())) { + throw new ServiceException("不能选择当前节点或其子节点作为父节点"); + } + String newAncestors = resolveAncestors(entity.get${TreeParentCap}(), parent); + if (updateMode && entity.get${pkColumn.capJavaField}() != null) { + ${ClassName} oldEntity = baseMapper.selectById(entity.get${pkColumn.capJavaField}()); + if (ObjectUtil.isNull(oldEntity)) { + throw new ServiceException("${functionName}不存在,无法修改"); + } + 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); + } +#end +#end + } +#if("" != $treeAncestorsField) + + private String resolveAncestors(${treeParentColumn.javaType} parentId, ${ClassName} parent) { + if (ObjectUtil.equal(parentId, ${treeRootValueJavaLiteral})) { + return "${treeRootValue}"; + } + String parentAncestors = parent.get${TreeAncestorsCap}(); + if (StringUtils.isBlank(parentAncestors)) { + return String.valueOf(parentId); + } + return parentAncestors + StringUtils.SEPARATOR + parentId; + } + + private void updateChildrenAncestors(${pkColumn.javaType} currentId, String newAncestors, String oldAncestors) { + List<${ClassName}> children = baseMapper.selectList(new LambdaQueryWrapper<${ClassName}>() + .select(${ClassName}::get${pkColumn.capJavaField}, ${ClassName}::get${TreeAncestorsCap}())); + List<${ClassName}> updateList = new ArrayList<>(); + for (${ClassName} child : children) { + String ancestors = child.get${TreeAncestorsCap}(); + if (StringUtils.isBlank(ancestors) || !containsAncestor(ancestors, currentId)) { + continue; + } + ${ClassName} update = new ${ClassName}(); + update.set${pkColumn.capJavaField}(child.get${pkColumn.capJavaField}()); + update.set${TreeAncestorsCap}(StringUtils.replaceOnce(ancestors, oldAncestors, newAncestors)); + updateList.add(update); + } + if (!updateList.isEmpty()) { + baseMapper.updateBatchById(updateList); + } + } + + private boolean containsAncestor(String ancestors, ${pkColumn.javaType} nodeId) { + for (String item : StringUtils.splitList(ancestors)) { + if (StringUtils.equals(item, String.valueOf(nodeId))) { + return true; + } + } + return false; + } +#end +#end + /** * 校验并批量删除${functionName}信息 * @@ -159,8 +334,8 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service { */ @Override public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) { - if(isValid){ - //TODO 做一些业务上的校验,判断是否需要校验 + if (isValid) { + // 可在此扩展删除前业务校验 } return baseMapper.deleteByIds(ids) > 0; } diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm index da6f9eeda..79205e39a 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm @@ -52,6 +52,42 @@ export const update${BusinessName} = (data: ${BusinessName}Form) => { }); }; +#if($enableStatus) +/** + * 修改${functionName}状态 + * @param ${pkColumn.javaField} + * @param status + */ +export const change${BusinessName}Status = (${pkColumn.javaField}: string | number, status: #if($statusColumn.javaType == 'String')string#else number#end) => { + return request({ + url: '/${moduleName}/${businessName}/changeStatus', + method: 'put', + data: { + ${pkColumn.javaField}, + ${statusField}: status + } + }); +}; +#end + +#if($enableSort) +/** + * 调整${functionName}排序 + * @param ${pkColumn.javaField} + * @param sortValue + */ +export const update${BusinessName}Sort = (${pkColumn.javaField}: string | number, sortValue: #if($sortColumn.javaType == 'String' || $sortColumn.javaType == 'LocalDateTime')string#else number#end) => { + return request({ + url: '/${moduleName}/${businessName}/updateSort', + method: 'put', + data: { + ${pkColumn.javaField}, + ${sortField}: sortValue + } + }); +}; +#end + /** * 删除${functionName} * @param ${pkColumn.javaField} diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm index ca5fade8f..91f52bdbe 100644 --- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm +++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm @@ -22,12 +22,37 @@ +#elseif($column.htmlType == "inputNumber") + + + #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType) +#elseif($column.htmlType == "switch" && "" != $dictType) + + + + + +#elseif($column.htmlType == "switch") + + +#if($column.javaType == "Boolean") + + +#elseif($column.javaType == "Integer" || $column.javaType == "Long") + + +#else + + +#end + + #elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType) @@ -75,6 +100,9 @@
新增 展开/折叠 +#if($enableExport) + 导出 +#end
@@ -104,6 +132,64 @@ #set($comment=$column.columnComment) #end #if($column.pk) +#elseif($enableStatus && $statusField == $javaField) +#if($javaField == $firstTreeListField) + +#else + +#end + + +#elseif($enableSort && $sortField == $javaField) +#if($javaField == $firstTreeListField) + +#else + +#end + + +#elseif($column.list && $column.htmlType == "switch") +#if($javaField == $firstTreeListField) + +#else + +#end + + #elseif($column.list && $column.htmlType == "datetime") #if($javaField == $firstTreeListField) @@ -124,7 +210,7 @@ -#elseif($column.list && $column.dictType && "" != $column.dictType) +#elseif($column.list && $column.dictColumn) #if($javaField == $firstTreeListField) #else @@ -145,6 +231,35 @@ #end #end +#end +#if($enableStatus && !$statusColumn.list) + + + +#end +#if($enableSort && !$sortColumn.list) + + + #end