Browse Source

代码生成模板支持主子表

RuoYi 4 years ago
parent
commit
052ab8866d
25 changed files with 802 additions and 124 deletions
  1. 48 2
      ruoyi-admin/src/main/resources/static/ruoyi/js/common.js
  2. 14 0
      ruoyi-admin/src/main/resources/static/ruoyi/js/ry-ui.js
  3. 7 47
      ruoyi-admin/src/main/resources/templates/demo/table/subdata.html
  4. 3 0
      ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
  5. 21 0
      ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
  6. 50 1
      ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
  7. 9 4
      ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
  8. 7 0
      ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java
  9. 7 0
      ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java
  10. 63 11
      ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableServiceImpl.java
  11. 40 3
      ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
  12. 32 20
      ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
  13. 46 4
      ruoyi-generator/src/main/resources/templates/tool/gen/edit.html
  14. 1 1
      ruoyi-generator/src/main/resources/templates/tool/gen/gen.html
  15. 100 1
      ruoyi-generator/src/main/resources/vm/html/add.html.vm
  16. 102 1
      ruoyi-generator/src/main/resources/vm/html/edit.html.vm
  17. 3 3
      ruoyi-generator/src/main/resources/vm/html/list-tree.html.vm
  18. 3 3
      ruoyi-generator/src/main/resources/vm/html/list.html.vm
  19. 4 4
      ruoyi-generator/src/main/resources/vm/java/controller.java.vm
  20. 22 2
      ruoyi-generator/src/main/resources/vm/java/domain.java.vm
  21. 30 0
      ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
  22. 57 0
      ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
  23. 75 0
      ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm
  24. 40 1
      ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
  25. 18 16
      sql/ry_20200617.sql

+ 48 - 2
ruoyi-admin/src/main/resources/static/ruoyi/js/common.js

@@ -308,7 +308,7 @@ function createMenuItem(dataUrl, menuName) {
     return false;
 }
 
-//日志打印封装处理
+// 日志打印封装处理
 var log = {
     log: function(msg) {
         console.log(msg);
@@ -324,7 +324,7 @@ var log = {
     }
 };
 
-//本地缓存处理
+// 本地缓存处理
 var storage = {
     set: function(key, value) {
         window.localStorage.setItem(key, value);
@@ -340,6 +340,52 @@ var storage = {
     }
 };
 
+// 主子表操作封装处理
+var sub = {
+    editColumn: function() {
+    	var count = $("#" + table.options.id).bootstrapTable('getData').length;
+    	var params = new Array();
+    	for (var dataIndex = 0; dataIndex <= count; dataIndex++) {
+    		var columns = $('#' + table.options.id + ' tr[data-index="' + dataIndex + '"] td');
+    		var obj = new Object();
+    		for (var i = 0; i < columns.length; i++) {
+    			var inputValue = $(columns[i]).find('input');
+    			var selectValue = $(columns[i]).find('select');
+    			var key = table.options.columns[i].field;
+    			if ($.common.isNotEmpty(inputValue.val())) {
+    				obj[key] = inputValue.val();
+    			} else if ($.common.isNotEmpty(selectValue.val())) {
+    				obj[key] = selectValue.val();
+    			} else {
+    				obj[key] = "";
+    			}
+    		}
+    		params.push({ index: dataIndex, row: obj });
+    	}
+    	$("#" + table.options.id).bootstrapTable("updateRow", params);
+    },
+    delColumn: function(column) {
+    	var subColumn = $.common.isEmpty(column) ? "index" : column;
+    	var ids = $.table.selectColumns(subColumn);
+        if (ids.length == 0) {
+            $.modal.alertWarning("请至少选择一条记录");
+            return;
+        }
+        $("#" + table.options.id).bootstrapTable('remove', { field: subColumn, values: ids });
+        if($.common.equals("index", subColumn))
+        {
+        	sub.resetIndex();
+        }
+    },
+    resetIndex: function(msg) {
+    	var count = $("#" + table.options.id).bootstrapTable('getData').length;
+        for (var index = 0; index <= count; index++) {
+            // 重置序号
+            $("#" + table.options.id).bootstrapTable('updateRow', { index: index, row: { index: parseInt(index + 1) } })
+        }
+    }
+};
+
 /** 设置全局ajax处理 */
 $.ajaxSetup({
     complete: function(XMLHttpRequest, textStatus) {

+ 14 - 0
ruoyi-admin/src/main/resources/static/ruoyi/js/ry-ui.js

@@ -1523,6 +1523,20 @@ var table = {
                  });
             	return json;
             },
+            // 数据字典转下拉框
+            dictToSelect: function(datas, value, name) {
+            	var actions = [];
+            	actions.push($.common.sprintf("<select class='form-control' name='%s'>", name));
+                $.each(datas, function(index, dict) {
+                	actions.push($.common.sprintf("<option value='%s'", dict.dictValue));
+                    if (dict.dictValue == ('' + value)) {
+                    	actions.push(' selected');
+                    }
+                    actions.push($.common.sprintf(">%s</option>", dict.dictLabel));
+                });
+                actions.push('</select>');
+                return actions.join('');
+            },
             // 获取obj对象长度
             getLength: function(obj) {
                 var count = 0;  

+ 7 - 47
ruoyi-admin/src/main/resources/templates/demo/table/subdata.html

@@ -63,8 +63,8 @@
             <h4 class="form-header h4">商品数据</h4>
             <div class="row">
                 <div class="col-sm-12">
-                    <button type="button" class="btn btn-white btn-sm" onclick="return addColumn()"><i class="fa fa-plus"> 增加</i></button>
-                    <button type="button" class="btn btn-white btn-sm" onclick="return delColumn()"><i class="fa fa-minus"> 删除</i></button>
+                    <button type="button" class="btn btn-white btn-sm" onclick="addColumn()"><i class="fa fa-plus"> 增加</i></button>
+                    <button type="button" class="btn btn-white btn-sm" onclick="sub.delColumn()"><i class="fa fa-minus"> 删除</i></button>
                     <div class="col-sm-12 select-table table-striped">
 					    <table id="bootstrap-table"></table>
 					</div>
@@ -150,28 +150,9 @@
             autoclose: true
         });
         
-        function addColumn(){
+        function addColumn() {
         	var count = $("#" + table.options.id).bootstrapTable('getData').length;
-        	
-			var params = new Array();
-			for (var dataIndex = 0; dataIndex <= count; dataIndex++) {
-			    var columns = $('#' + table.options.id + ' tr[data-index="' + dataIndex + '"] td');
-			    var obj = new Object();
-			    for (var i = 0; i < columns.length; i++) {
-			        var inputValue = $(columns[i]).find('input');
-			        var selectValue = $(columns[i]).find('select');
-			        var key = table.options.columns[i].field;
-			        if ($.common.isNotEmpty(inputValue.val())) {
-			            obj[key] = inputValue.val();
-			        } else if ($.common.isNotEmpty(selectValue.val())) {
-			            obj[key] = selectValue.val();
-			        } else {
-			            obj[key] = "";
-			        }
-			    }
-			    params.push({ index: dataIndex, row: obj });
-			}
-			$("#" + table.options.id).bootstrapTable("updateRow", params);
+        	sub.editColumn();
         	
         	$("#" + table.options.id).bootstrapTable('insertRow', {
         		index: count,
@@ -182,35 +163,14 @@
                 	price: "",
                 	type: "",
                 }
-        	})
-        	resetIndex();
-        }
-        
-        function delColumn(){
-        	var ids = $.table.selectColumns("index");
-        	if (ids.length == 0) {
-    			$.modal.alertWarning("请至少选择一条记录");
-    			return;
-    		}
-        	$("#" + table.options.id).bootstrapTable('remove', {
-        	    field: 'index',
-        	    values: ids
-        	})
-        	resetIndex();
-        }
-        
-        function resetIndex() {
-            var count = $("#" + table.options.id).bootstrapTable('getData').length;
-            for (var index = 0; index <= count; index++) {
-                // 重置序号
-                $("#" + table.options.id).bootstrapTable('updateRow', { index: index, row: { index: parseInt(index + 1) } })
-            }
+        	});
+        	sub.resetIndex();
         }
     </script>
 </body>
 </html>
 
-<!-- 查询方式 -->
+<!-- 商品类型 -->
 <script id="goodsTypeTpl" type="text/x-jquery-tmpl">
 <div>
 <select class='form-control' name='goods[${index}].type'>

+ 3 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java

@@ -13,6 +13,9 @@ public class GenConstants
     /** 树表(增删改查) */
     public static final String TPL_TREE = "tree";
 
+    /** 主子表(增删改查) */
+    public static final String TPL_SUB = "sub";
+
     /** 树编码字段 */
     public static final String TREE_CODE = "treeCode";
 

+ 21 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java

@@ -1,6 +1,7 @@
 package com.ruoyi.generator.controller;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import javax.servlet.http.HttpServletResponse;
@@ -15,12 +16,15 @@ import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
+import com.alibaba.fastjson.JSON;
 import com.ruoyi.common.annotation.Log;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.CxSelect;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.core.text.Convert;
 import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.security.PermissionUtils;
 import com.ruoyi.generator.domain.GenTable;
 import com.ruoyi.generator.domain.GenTableColumn;
@@ -126,7 +130,24 @@ public class GenController extends BaseController
     public String edit(@PathVariable("tableId") Long tableId, ModelMap mmap)
     {
         GenTable table = genTableService.selectGenTableById(tableId);
+        List<GenTable> genTables = genTableService.selectGenTableAll();
+        List<CxSelect> cxSelect = new ArrayList<CxSelect>();
+        for (GenTable genTable : genTables)
+        {
+            if (!StringUtils.equals(table.getTableName(), genTable.getTableName()))
+            {
+                CxSelect cxTable = new CxSelect(genTable.getTableName(), genTable.getTableName() + ':' + genTable.getTableComment());
+                List<CxSelect> cxColumns = new ArrayList<CxSelect>();
+                for (GenTableColumn tableColumn : genTable.getColumns())
+                {
+                    cxColumns.add(new CxSelect(tableColumn.getColumnName(), tableColumn.getColumnName() + ':' + tableColumn.getColumnComment()));
+                }
+                cxTable.setS(cxColumns);
+                cxSelect.add(cxTable);
+            }
+        }
         mmap.put("table", table);
+        mmap.put("data", JSON.toJSON(cxSelect));
         return prefix + "/edit";
     }
 

+ 50 - 1
ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java

@@ -28,11 +28,17 @@ public class GenTable extends BaseEntity
     @NotBlank(message = "表描述不能为空")
     private String tableComment;
 
+    /** 关联父表的表名 */
+    private String subTableName;
+
+    /** 本表关联父表的外键名 */
+    private String subTableFkName;
+
     /** 实体类名称(首字母大写) */
     @NotBlank(message = "实体类名称不能为空")
     private String className;
 
-    /** 使用的模板(crud单表操作 tree树表操作) */
+    /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */
     private String tplCategory;
 
     /** 生成包路径 */
@@ -58,6 +64,9 @@ public class GenTable extends BaseEntity
     /** 主键信息 */
     private GenTableColumn pkColumn;
 
+    /** 子表信息 */
+    private GenTable subTable;
+
     /** 表列信息 */
     @Valid
     private List<GenTableColumn> columns;
@@ -104,6 +113,26 @@ public class GenTable extends BaseEntity
         this.tableComment = tableComment;
     }
 
+    public String getSubTableName()
+    {
+        return subTableName;
+    }
+
+    public void setSubTableName(String subTableName)
+    {
+        this.subTableName = subTableName;
+    }
+
+    public String getSubTableFkName()
+    {
+        return subTableFkName;
+    }
+
+    public void setSubTableFkName(String subTableFkName)
+    {
+        this.subTableFkName = subTableFkName;
+    }
+
     public String getClassName()
     {
         return className;
@@ -184,6 +213,16 @@ public class GenTable extends BaseEntity
         this.pkColumn = pkColumn;
     }
 
+    public GenTable getSubTable()
+    {
+        return subTable;
+    }
+
+    public void setSubTable(GenTable subTable)
+    {
+        this.subTable = subTable;
+    }
+
     public List<GenTableColumn> getColumns()
     {
         return columns;
@@ -234,6 +273,16 @@ public class GenTable extends BaseEntity
         this.treeName = treeName;
     }
 
+    public boolean isSub()
+    {
+        return isSub(this.tplCategory);
+    }
+
+    public static boolean isSub(String tplCategory)
+    {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);
+    }
+
     public boolean isTree()
     {
         return isTree(this.tplCategory);

+ 9 - 4
ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java

@@ -138,6 +138,11 @@ public class GenTableColumn extends BaseEntity
         return javaField;
     }
 
+    public String getCapJavaField()
+    {
+        return StringUtils.capitalize(javaField);
+    }
+
     public void setIsPk(String isPk)
     {
         this.isPk = isPk;
@@ -326,9 +331,9 @@ public class GenTableColumn extends BaseEntity
     public static boolean isSuperColumn(String javaField)
     {
         return StringUtils.equalsAnyIgnoreCase(javaField,
-                //BaseEntity
+                // BaseEntity
                 "createBy", "createTime", "updateBy", "updateTime", "remark",
-                //TreeEntity
+                // TreeEntity
                 "parentName", "parentId", "orderNum", "ancestors");
     }
 
@@ -339,8 +344,8 @@ public class GenTableColumn extends BaseEntity
 
     public static boolean isUsableColumn(String javaField)
     {
-        //isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单
-        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId" , "orderNum");
+        // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单
+        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum");
     }
 
     public String readConverterExp()

+ 7 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java

@@ -34,6 +34,13 @@ public interface GenTableMapper
      */
     public List<GenTable> selectDbTableListByNames(String[] tableNames);
 
+    /**
+     * 查询所有表信息
+     * 
+     * @return 表信息集合
+     */
+    public List<GenTable> selectGenTableAll();
+
     /**
      * 查询表ID业务信息
      * 

+ 7 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java

@@ -35,6 +35,13 @@ public interface IGenTableService
      */
     public List<GenTable> selectDbTableListByNames(String[] tableNames);
 
+    /**
+     * 查询所有表信息
+     * 
+     * @return 表信息集合
+     */
+    public List<GenTable> selectGenTableAll();
+
     /**
      * 查询业务信息
      * 

+ 63 - 11
ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableServiceImpl.java

@@ -99,6 +99,16 @@ public class GenTableServiceImpl implements IGenTableService
         return genTableMapper.selectDbTableListByNames(tableNames);
     }
 
+    /**
+     * 查询所有表信息
+     * 
+     * @return 表信息集合
+     */
+    public List<GenTable> selectGenTableAll()
+    {
+        return genTableMapper.selectGenTableAll();
+    }
+
     /**
      * 修改业务
      * 
@@ -182,9 +192,10 @@ public class GenTableServiceImpl implements IGenTableService
         Map<String, String> dataMap = new LinkedHashMap<>();
         // 查询表信息
         GenTable table = genTableMapper.selectGenTableById(tableId);
-        // 查询列信息
-        List<GenTableColumn> columns = table.getColumns();
-        setPkColumn(table, columns);
+        // 设置主子表信息
+        setSubTable(table);
+        // 设置主键列信息
+        setPkColumn(table);
         VelocityInitializer.initVelocity();
 
         VelocityContext context = VelocityUtils.prepareContext(table);
@@ -244,9 +255,10 @@ public class GenTableServiceImpl implements IGenTableService
     {
         // 查询表信息
         GenTable table = genTableMapper.selectGenTableByName(tableName);
-        // 查询列信息
-        List<GenTableColumn> columns = table.getColumns();
-        setPkColumn(table, columns);
+        // 设置主子表信息
+        setSubTable(table);
+        // 设置主键列信息
+        setPkColumn(table);
 
         VelocityInitializer.initVelocity();
 
@@ -301,17 +313,28 @@ public class GenTableServiceImpl implements IGenTableService
                 throw new BusinessException("树名称字段不能为空");
             }
         }
+        else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
+        {
+            if (StringUtils.isEmpty(genTable.getSubTableName()))
+            {
+                throw new BusinessException("关联子表的表名不能为空");
+            }
+            else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
+            {
+                throw new BusinessException("子表关联的外键名不能为空");
+            }
+        }
     }
 
     /**
      * 设置主键列信息
      * 
-     * @param genTable 业务表信息
-     * @param columns 业务字段列表
+     * @param table 业务表信息
      */
-    public void setPkColumn(GenTable table, List<GenTableColumn> columns)
+    public void setPkColumn(GenTable table)
     {
-        for (GenTableColumn column : columns)
+
+        for (GenTableColumn column : table.getColumns())
         {
             if (column.isPk())
             {
@@ -321,7 +344,36 @@ public class GenTableServiceImpl implements IGenTableService
         }
         if (StringUtils.isNull(table.getPkColumn()))
         {
-            table.setPkColumn(columns.get(0));
+            table.setPkColumn(table.getColumns().get(0));
+        }
+        if (GenConstants.TPL_SUB.equals(table.getTplCategory()))
+        {
+            for (GenTableColumn column : table.getSubTable().getColumns())
+            {
+                if (column.isPk())
+                {
+                    table.getSubTable().setPkColumn(column);
+                    break;
+                }
+            }
+            if (StringUtils.isNull(table.getSubTable().getPkColumn()))
+            {
+                table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
+            }
+        }
+    }
+
+    /**
+     * 设置主子表信息
+     * 
+     * @param table 业务表信息
+     */
+    public void setSubTable(GenTable table)
+    {
+        String subTableName = table.getSubTableName();
+        if (StringUtils.isNotEmpty(subTableName))
+        {
+            table.setSubTable(genTableMapper.selectGenTableByName(subTableName));
         }
     }
 

+ 40 - 3
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java

@@ -49,7 +49,7 @@ public class VelocityUtils
         velocityContext.put("author", genTable.getFunctionAuthor());
         velocityContext.put("datetime", DateUtils.getDate());
         velocityContext.put("pkColumn", genTable.getPkColumn());
-        velocityContext.put("importList", getImportList(genTable.getColumns()));
+        velocityContext.put("importList", getImportList(genTable));
         velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
         velocityContext.put("columns", genTable.getColumns());
         velocityContext.put("table", genTable);
@@ -57,6 +57,10 @@ public class VelocityUtils
         {
             setTreeVelocityContext(velocityContext, genTable);
         }
+        if (GenConstants.TPL_SUB.equals(tplCategory))
+        {
+            setSubVelocityContext(velocityContext, genTable);
+        }
         return velocityContext;
     }
 
@@ -82,6 +86,24 @@ public class VelocityUtils
         }
     }
 
+    public static void setSubVelocityContext(VelocityContext context, GenTable genTable)
+    {
+        GenTable subTable = genTable.getSubTable();
+        String subTableName = genTable.getSubTableName();
+        String subTableFkName = genTable.getSubTableFkName();
+        String subClassName = genTable.getSubTable().getClassName();
+        String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
+
+        context.put("subTable", subTable);
+        context.put("subTableName", subTableName);
+        context.put("subTableFkName", subTableFkName);
+        context.put("subTableFkClassName", subTableFkClassName);
+        context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
+        context.put("subClassName", subClassName);
+        context.put("subclassName", StringUtils.uncapitalize(subClassName));
+        context.put("subImportList", getImportList(genTable.getSubTable()));
+    }
+
     /**
      * 获取模板信息
      * 
@@ -105,6 +127,11 @@ public class VelocityUtils
             templates.add("vm/html/tree.html.vm");
             templates.add("vm/html/list-tree.html.vm");
         }
+        else if (GenConstants.TPL_SUB.equals(tplCategory))
+        {
+            templates.add("vm/html/list.html.vm");
+            templates.add("vm/java/sub-domain.java.vm");
+        }
         templates.add("vm/html/add.html.vm");
         templates.add("vm/html/edit.html.vm");
         templates.add("vm/sql/sql.vm");
@@ -135,6 +162,10 @@ public class VelocityUtils
         {
             fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
         }
+        if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
+        {
+            fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
+        }
         else if (template.contains("mapper.java.vm"))
         {
             fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
@@ -213,12 +244,18 @@ public class VelocityUtils
     /**
      * 根据列类型获取导入包
      * 
-     * @param column 列集合
+     * @param genTable 业务表对象
      * @return 返回需要导入的包列表
      */
-    public static HashSet<String> getImportList(List<GenTableColumn> columns)
+    public static HashSet<String> getImportList(GenTable genTable)
     {
+        List<GenTableColumn> columns = genTable.getColumns();
+        GenTable subGenTable = genTable.getSubTable();
         HashSet<String> importList = new HashSet<String>();
+        if (StringUtils.isNotNull(subGenTable))
+        {
+            importList.add("java.util.List");
+        }
         for (GenTableColumn column : columns)
         {
             if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType()))

+ 32 - 20
ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml

@@ -5,23 +5,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 <mapper namespace="com.ruoyi.generator.mapper.GenTableMapper">
 
 	<resultMap type="GenTable" id="GenTableResult">
-	    <id     property="tableId"        column="table_id"        />
-		<result property="tableName"      column="table_name"      />
-		<result property="tableComment"   column="table_comment"   />
-		<result property="className"      column="class_name"      />
-		<result property="tplCategory"    column="tpl_category"    />
-		<result property="packageName"    column="package_name"    />
-		<result property="moduleName"     column="module_name"     />
-		<result property="businessName"   column="business_name"   />
-		<result property="functionName"   column="function_name"   />
-		<result property="functionAuthor" column="function_author" />
-		<result property="options"        column="options"         />
-		<result property="createBy"       column="create_by"       />
-		<result property="createTime"     column="create_time"     />
-		<result property="updateBy"       column="update_by"       />
-		<result property="updateTime"     column="update_time"     />
-		<result property="remark"         column="remark"          />
-		<collection  property="columns"  javaType="java.util.List"  resultMap="GenTableColumnResult" />
+	    <id     property="tableId"        column="table_id"          />
+		<result property="tableName"      column="table_name"        />
+		<result property="tableComment"   column="table_comment"     />
+		<result property="subTableName"   column="sub_table_name"    />
+		<result property="subTableFkName" column="sub_table_fk_name" />
+		<result property="className"      column="class_name"        />
+		<result property="tplCategory"    column="tpl_category"      />
+		<result property="packageName"    column="package_name"      />
+		<result property="moduleName"     column="module_name"       />
+		<result property="businessName"   column="business_name"     />
+		<result property="functionName"   column="function_name"     />
+		<result property="functionAuthor" column="function_author"   />
+		<result property="options"        column="options"           />
+		<result property="createBy"       column="create_by"         />
+		<result property="createTime"     column="create_time"       />
+		<result property="updateBy"       column="update_by"         />
+		<result property="updateTime"     column="update_time"       />
+		<result property="remark"         column="remark"            />
+		<collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" />
 	</resultMap>
 	
 	<resultMap type="GenTableColumn" id="GenTableColumnResult">
@@ -50,7 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 	
 	<sql id="selectGenTableVo">
-        select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, options, create_by, create_time, update_by, update_time, remark from gen_table
+        select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, options, create_by, create_time, update_by, update_time, remark from gen_table
     </sql>
     
     <select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
@@ -94,7 +96,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	</select>
 	
 	<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
-	    SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
+	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
 			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
 		FROM gen_table t
 			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@@ -102,13 +104,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	</select>
 	
 	<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
-	    SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
+	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
 			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
 		FROM gen_table t
 			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
 		where t.table_name = #{tableName} order by c.sort
 	</select>
 	
+	<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
+	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
+			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+		FROM gen_table t
+			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+		order by c.sort
+	</select>
+	
 	<insert id="insertGenTable" parameterType="GenTable" useGeneratedKeys="true" keyProperty="tableId">
         insert into gen_table (
 			<if test="tableName != null">table_name,</if>
@@ -144,6 +154,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <set>
             <if test="tableName != null">table_name = #{tableName},</if>
             <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if>
+            <if test="subTableName != null and subTableName != ''">sub_table_name = #{subTableName},</if>
+            <if test="subTableFkName != null and subTableFkName != ''">sub_table_fk_name = #{subTableFkName},</if>
             <if test="className != null and className != ''">class_name = #{className},</if>
             <if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if>
             <if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if>

+ 46 - 4
ruoyi-generator/src/main/resources/templates/tool/gen/edit.html

@@ -92,6 +92,7 @@
 					                            <select class='form-control' id="tplCategory" name='tplCategory' style="width: 100%">
 												    <option value="crud" th:field="*{tplCategory}">单表(增删改查)</option>
 												    <option value="tree" th:field="*{tplCategory}">树表(增删改查)</option>
+												    <option value="sub" th:field="*{tplCategory}">主子表(增删改查)</option>
 												</select>
 					                        </div>
 					                    </div>
@@ -133,6 +134,31 @@
 					                    </div>
 					                </div>
 					            </div>
+					            <div class="hidden" id="subInfo">
+					            <h4 class="form-header h4">关联信息</h4>
+					            <div class="row">
+					                <div class="col-sm-6">
+					                    <div class="form-group">
+					                        <label class="col-sm-4 control-label is-required" title="关联子表的表名, 如:sys_user">关联子表的表名:<i class="fa fa-question-circle-o"></i></label>
+					                        <div class="col-sm-8">
+					                            <select class='type form-control' id="subTableName" name='subTableName' th:attr='data-value=*{subTableName}' style="width: 100%">
+					                                <option value="">---请选择---</option>
+												</select>
+					                        </div>
+					                    </div>
+					                </div>
+					                <div class="col-sm-6">
+					                    <div class="form-group">
+					                        <label class="col-sm-4 control-label is-required" title="子表关联的外键名, 如:user_id">子表关联的外键名:<i class="fa fa-question-circle-o"></i></label>
+					                        <div class="col-sm-8">
+					                            <select class='router form-control' id="subTableFkName" name='subTableFkName' th:attr='data-value=*{subTableFkName}' style="width: 100%">
+					                                <option value="">---请选择---</option>
+												</select>
+					                        </div>
+					                    </div>
+					                </div>
+					            </div>
+					            </div>
 					            <div class="hidden" id="otherInfo">
 					            <h4 class="form-header h4">其他信息</h4>
 					            <div class="row">
@@ -192,8 +218,9 @@
     <th:block th:include="include :: select2-js" />
     <th:block th:include="include :: bootstrap-table-reorder-js" />
     <script th:src="@{/js/jquery.tmpl.js}"></script>
-    <script type="text/javascript">
-	    /*用户信息-修改*/
+    <th:block th:include="include :: jquery-cxselect-js" />
+    <script th:inline="javascript">
+	    /* 用户信息-修改 */
 	    $("#form-table-edit").validate({
 	    	rules: {
 	    	    tableName: {
@@ -201,7 +228,15 @@
 	    	    },
 	    	},
 			focusCleanup: true
-		}); 
+		});
+	    
+	    /* 表级联信息 */
+   		var data = [[${data}]];
+    	$('#subInfo').cxSelect({
+    	  selects: ['type', 'router'],
+    	  jsonValue: 'v',
+    	  data: data
+    	});
 	    
 	    function submitHandler() {
 	        if ($.validate.form()) {
@@ -404,12 +439,19 @@
 				$("#treeParentCode").select2("val", [""]);
 				$("#treeName").select2("val", [""]);
 				$("#otherInfo").addClass("hidden");
-				
+				$("#subInfo").addClass("hidden");
 			} else if("tree" == tplCategory){
 				$("#otherInfo").removeClass("hidden");
 				$("#treeCode").attr("required", "true");
 				$("#treeParentCode").attr("required", "true");
 				$("#treeName").attr("required", "true");
+				$("#subInfo").addClass("hidden");
+			} else if("sub" == tplCategory){
+				$("#subInfo").removeClass("hidden");
+				$("#treeCode").select2("val", [""]);
+				$("#treeParentCode").select2("val", [""]);
+				$("#treeName").select2("val", [""]);
+				$("#otherInfo").addClass("hidden");
 			}
         }
 		

+ 1 - 1
ruoyi-generator/src/main/resources/templates/tool/gen/gen.html

@@ -143,7 +143,7 @@
 		                	value = value.replace(/</g, "&lt;");
 		                	value = value.replace(/>/g, "&gt;");
 		                    var templateName = index.substring(index.lastIndexOf("/") + 1, index.length).replace(/\.vm/g, "");
-		                    if(!$.common.equals("sql", templateName) && !$.common.equals("tree.html", templateName)){
+		                    if(!$.common.equals("sql", templateName) && !$.common.equals("tree.html", templateName) && !$.common.equals("sub-domain.java", templateName)){
 			                    items.push({
 			                        title: templateName , content: "<pre class=\"layui-code\">" + value + "</pre>"
 			                    })

+ 100 - 1
ruoyi-generator/src/main/resources/vm/html/add.html.vm

@@ -12,6 +12,9 @@
 <body class="white-bg">
     <div class="wrapper wrapper-content animated fadeInRight ibox-content">
         <form class="form-horizontal m" id="form-${businessName}-add">
+#if($table.sub)
+            <h4 class="form-header h4">${functionName}信息</h4>
+#end
 #foreach($column in $columns)
 #set($field=$column.javaField)
 #if($column.insert && !$column.pk)
@@ -103,6 +106,18 @@
 #end
 #end
 #end
+#end
+#if($table.sub)
+            <h4 class="form-header h4">${subTable.functionName}信息</h4>
+            <div class="row">
+                <div class="col-sm-12">
+                    <button type="button" class="btn btn-white btn-sm" onclick="addColumn()"><i class="fa fa-plus"> 增加</i></button>
+                    <button type="button" class="btn btn-white btn-sm" onclick="sub.delColumn()"><i class="fa fa-minus"> 删除</i></button>
+                    <div class="col-sm-12 select-table table-striped">
+                        <table id="bootstrap-table"></table>
+                    </div>
+                </div>
+            </div>
 #end
         </form>
     </div>
@@ -113,8 +128,15 @@
 #break
 #end
 #end
-    <script type="text/javascript">
+    <script th:inline="javascript">
         var prefix = ctx + "${moduleName}/${businessName}"
+#if($table.sub)
+#foreach($column in $subTable.columns)
+#if(${column.dictType} != '')
+        var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]];
+#end
+#end
+#end
         $("#form-${businessName}-add").validate({
             focusCleanup: true
         });
@@ -153,6 +175,83 @@
                $("#treeName").val(body.find('#treeName').val());
                layer.close(index);
         }
+#end
+#if($table.sub)
+
+        $(function() {
+            var options = {
+                pagination: false,
+                showSearch: false,
+                showRefresh: false,
+                showToggle: false,
+                showColumns: false,
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'index',
+                    align: 'center',
+                    title: "序号"
+                },
+#foreach($column in $subTable.columns)
+#set($dictType=$column.dictType)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk || $javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $dictType)
+                {
+                    field: '${javaField}',
+                    align: 'center',
+                    title: '${comment}',
+                    formatter: function(value, row, index) {
+                        var name = $.common.sprintf("${subclassName}List[%s].${javaField}", index);
+                        return $.common.dictToSelect(${javaField}Datas, value, name);
+                    }
+                #if($velocityCount != $subTable.columns.size())},#end
+
+#else
+                {
+                    field: '${javaField}',
+                    align: 'center',
+                    title: '${comment}',
+                    formatter: function(value, row, index) {
+                        var html = $.common.sprintf("<input class='form-control' type='text' name='${subclassName}List[%s].${javaField}' value='%s'>", index, value);
+                        return html;
+                    }
+                #if($velocityCount != $subTable.columns.size())},#end
+
+#end
+#end
+                }]
+            };
+            $.table.init(options);
+        });
+
+        function addColumn() {
+            var count = $("#" + table.options.id).bootstrapTable('getData').length;
+            sub.editColumn();
+        	
+            $("#" + table.options.id).bootstrapTable('insertRow', {
+                index: count,
+                row: {
+                    index: $.table.serialNumber(count),
+#foreach($column in $subTable.columns)
+#set($javaField=$column.javaField)
+#if($column.pk || $javaField == ${subTableFkclassName})
+#else
+                    ${javaField}: ""#if($velocityCount != $subTable.columns.size()),#end
+
+#end
+#end
+                }
+            });
+            sub.resetIndex();
+        }
 #end
     </script>
 </body>

+ 102 - 1
ruoyi-generator/src/main/resources/vm/html/edit.html.vm

@@ -12,6 +12,9 @@
 <body class="white-bg">
     <div class="wrapper wrapper-content animated fadeInRight ibox-content">
         <form class="form-horizontal m" id="form-${businessName}-edit" th:object="${${className}}">
+#if($table.sub)
+            <h4 class="form-header h4">${functionName}信息</h4>
+#end
             <input name="${pkColumn.javaField}" th:field="*{${pkColumn.javaField}}" type="hidden">
 #foreach($column in $columns)
 #if($column.edit && !$column.pk)
@@ -103,6 +106,18 @@
 #end
 #end
 #end
+#end
+#if($table.sub)
+            <h4 class="form-header h4">${subTable.functionName}信息</h4>
+            <div class="row">
+                <div class="col-sm-12">
+                    <button type="button" class="btn btn-white btn-sm" onclick="addColumn()"><i class="fa fa-plus"> 增加</i></button>
+                    <button type="button" class="btn btn-white btn-sm" onclick="sub.delColumn()"><i class="fa fa-minus"> 删除</i></button>
+                    <div class="col-sm-12 select-table table-striped">
+                        <table id="bootstrap-table"></table>
+                    </div>
+                </div>
+            </div>
 #end
         </form>
     </div>
@@ -113,8 +128,15 @@
 #break
 #end
 #end
-    <script type="text/javascript">
+    <script th:inline="javascript">
         var prefix = ctx + "${moduleName}/${businessName}";
+#if($table.sub)
+#foreach($column in $subTable.columns)
+#if(${column.dictType} != '')
+        var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]];
+#end
+#end
+#end
         $("#form-${businessName}-edit").validate({
             focusCleanup: true
         });
@@ -153,6 +175,85 @@
                $("#treeName").val(body.find('#treeName').val());
                layer.close(index);
         }
+#end
+#if($table.sub)
+
+        $(function() {
+            var options = {
+                data: [[${${className}.${subclassName}List}]],
+                pagination: false,
+                showSearch: false,
+                showRefresh: false,
+                showToggle: false,
+                showColumns: false,
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'index',
+                    align: 'center',
+                    title: "序号"
+                },
+#foreach($column in $subTable.columns)
+#set($dictType=$column.dictType)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk || $javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $dictType)
+                {
+                    field: '${javaField}',
+                    align: 'center',
+                    title: '${comment}',
+                    formatter: function(value, row, index) {
+                        var name = $.common.sprintf("${subclassName}List[%s].${javaField}", index);
+                        return $.common.dictToSelect(${javaField}Datas, value, name);
+                    }
+                #if($velocityCount != $subTable.columns.size())},#end
+
+#else
+                {
+                    field: '${javaField}',
+                    align: 'center',
+                    title: '${comment}',
+                    formatter: function(value, row, index) {
+                        var html = $.common.sprintf("<input class='form-control' type='text' name='${subclassName}List[%s].${javaField}' value='%s'>", index, value);
+                        return html;
+                    }
+				#if($velocityCount != $subTable.columns.size())},#end
+
+#end
+#end
+                }]
+            };
+            $.table.init(options);
+            sub.resetIndex();
+        });
+
+        function addColumn() {
+            var count = $("#" + table.options.id).bootstrapTable('getData').length;
+            sub.editColumn();
+        	
+            $("#" + table.options.id).bootstrapTable('insertRow', {
+                index: count,
+                row: {
+                    index: $.table.serialNumber(count),
+#foreach($column in $subTable.columns)
+#set($javaField=$column.javaField)
+#if($column.pk || $javaField == ${subTableFkclassName})
+#else
+                    ${javaField}: ""#if($velocityCount != $subTable.columns.size()),#end
+
+#end
+#end
+        	    }
+            });
+            sub.resetIndex();
+        }
 #end
     </script>
 </body>

+ 3 - 3
ruoyi-generator/src/main/resources/vm/html/list-tree.html.vm

@@ -101,7 +101,7 @@
                 exportUrl: prefix + "/export",
                 modalName: "${functionName}",
                 columns: [{
-                    field: 'selectItem', 
+                    field: 'selectItem',
                     radio: true
                 },
 #foreach($column in $columns)
@@ -116,7 +116,7 @@
 #if($column.pk)
 #elseif($column.list && "" != $dictType)
                 {
-                    field: '${javaField}', 
+                    field: '${javaField}',
                     title: '${comment}',
                     align: 'left',
                     formatter: function(value, row, index) {
@@ -125,7 +125,7 @@
                 },
 #elseif($column.list && "" != $javaField)
                 {
-                    field: '${javaField}', 
+                    field: '${javaField}',
                     title: '${comment}',
                     align: 'left'
                 },

+ 3 - 3
ruoyi-generator/src/main/resources/vm/html/list.html.vm

@@ -112,13 +112,13 @@
 #end
 #if($column.pk)
                 {
-                    field: '${javaField}', 
+                    field: '${javaField}',
                     title: '${comment}',
                     visible: false
                 },
 #elseif($column.list && "" != $dictType)
                 {
-                    field: '${javaField}', 
+                    field: '${javaField}',
                     title: '${comment}',
                     formatter: function(value, row, index) {
                        return $.table.selectDictLabel(${javaField}Datas, value);
@@ -126,7 +126,7 @@
                 },
 #elseif($column.list && "" != $javaField)
                 {
-                    field: '${javaField}', 
+                    field: '${javaField}',
                     title: '${comment}'
                 },
 #end                

+ 4 - 4
ruoyi-generator/src/main/resources/vm/java/controller.java.vm

@@ -17,7 +17,7 @@ import ${packageName}.service.I${ClassName}Service;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.utils.poi.ExcelUtil;
-#if($table.crud)
+#if($table.crud || $table.sub)
 import com.ruoyi.common.core.page.TableDataInfo;
 #elseif($table.tree)
 import com.ruoyi.common.utils.StringUtils;
@@ -46,7 +46,7 @@ public class ${ClassName}Controller extends BaseController
         return prefix + "/${businessName}";
     }
 
-#if($table.crud)
+#if($table.crud || $table.sub)
     /**
      * 查询${functionName}列表
      */
@@ -87,7 +87,7 @@ public class ${ClassName}Controller extends BaseController
         return util.exportExcel(list, "${businessName}");
     }
 
-#if($table.crud)
+#if($table.crud || $table.sub)
     /**
      * 新增${functionName}
      */
@@ -146,7 +146,7 @@ public class ${ClassName}Controller extends BaseController
         return toAjax(${className}Service.update${ClassName}(${className}));
     }
 
-#if($table.crud)
+#if($table.crud || $table.sub)
     /**
      * 删除${functionName}
      */

+ 22 - 2
ruoyi-generator/src/main/resources/vm/java/domain.java.vm

@@ -6,7 +6,7 @@ import ${import};
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.annotation.Excel;
-#if($table.crud)
+#if($table.crud || $table.sub)
 import com.ruoyi.common.core.domain.BaseEntity;
 #elseif($table.tree)
 import com.ruoyi.common.core.domain.TreeEntity;
@@ -18,7 +18,7 @@ import com.ruoyi.common.core.domain.TreeEntity;
  * @author ${author}
  * @date ${datetime}
  */
-#if($table.crud)
+#if($table.crud || $table.sub)
 #set($Entity="BaseEntity")
 #elseif($table.tree)
 #set($Entity="TreeEntity")
@@ -48,6 +48,11 @@ public class ${ClassName} extends ${Entity}
     private $column.javaType $column.javaField;
 
 #end
+#end
+#if($table.sub)
+    /** $table.subTable.functionName信息 */
+    private List<${subClassName}> ${subclassName}List;
+
 #end
 #foreach ($column in $columns)
 #if(!$table.isSuperColumn($column.javaField))
@@ -68,6 +73,18 @@ public class ${ClassName} extends ${Entity}
 #end
 #end
 
+#if($table.sub)
+    public List<${subClassName}> get${subClassName}List()
+    {
+        return ${subclassName}List;
+    }
+
+    public void set${subClassName}List(List<${subClassName}> ${subclassName}List)
+    {
+        this.${subclassName}List = ${subclassName}List;
+    }
+
+#end
     @Override
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -78,6 +95,9 @@ public class ${ClassName} extends ${Entity}
 #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
 #end
             .append("${column.javaField}", get${AttrName}())
+#end
+#if($table.sub)
+            .append("${subclassName}List", get${subClassName}List())
 #end
             .toString();
     }

+ 30 - 0
ruoyi-generator/src/main/resources/vm/java/mapper.java.vm

@@ -2,6 +2,9 @@ package ${packageName}.mapper;
 
 import java.util.List;
 import ${packageName}.domain.${ClassName};
+#if($table.sub)
+import ${packageName}.domain.${subClassName};
+#end
 
 /**
  * ${functionName}Mapper接口
@@ -58,4 +61,31 @@ public interface ${ClassName}Mapper
      * @return 结果
      */
     public int delete${ClassName}ByIds(String[] ${pkColumn.javaField}s);
+#if($table.sub)
+
+    /**
+     * 批量删除${subTable.functionName}
+     * 
+     * @param customerIds 需要删除的数据ID
+     * @return 结果
+     */
+    public int delete${subClassName}By${subTableFkClassName}s(String[] ${pkColumn.javaField}s);
+    
+    /**
+     * 批量新增${subTable.functionName}
+     * 
+     * @param ${subclassName}List ${subTable.functionName}列表
+     * @return 结果
+     */
+    public int batch${subClassName}(List<${subClassName}> ${subclassName}List);
+    
+
+    /**
+     * 通过${functionName}ID删除${subTable.functionName}信息
+     * 
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});
+#end
 }

+ 57 - 0
ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm

@@ -13,6 +13,12 @@ import com.ruoyi.common.utils.DateUtils;
 #end
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+#if($table.sub)
+import java.util.ArrayList;
+import com.ruoyi.common.utils.StringUtils;
+import org.springframework.transaction.annotation.Transactional;
+import ${packageName}.domain.${subClassName};
+#end
 import ${packageName}.mapper.${ClassName}Mapper;
 import ${packageName}.domain.${ClassName};
 import ${packageName}.service.I${ClassName}Service;
@@ -60,6 +66,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
      * @param ${className} ${functionName}
      * @return 结果
      */
+#if($table.sub)
+    @Transactional
+#end
     @Override
     public int insert${ClassName}(${ClassName} ${className})
     {
@@ -68,7 +77,13 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
         ${className}.setCreateTime(DateUtils.getNowDate());
 #end
 #end
+#if($table.sub)
+        int rows = ${className}Mapper.insert${ClassName}(${className});
+        insert${subClassName}(${className});
+        return rows;
+#else
         return ${className}Mapper.insert${ClassName}(${className});
+#end
     }
 
     /**
@@ -77,6 +92,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
      * @param ${className} ${functionName}
      * @return 结果
      */
+#if($table.sub)
+    @Transactional
+#end
     @Override
     public int update${ClassName}(${ClassName} ${className})
     {
@@ -84,6 +102,10 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
 #if($column.javaField == 'updateTime')
         ${className}.setUpdateTime(DateUtils.getNowDate());
 #end
+#end
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());
+        insert${subClassName}(${className});
 #end
         return ${className}Mapper.update${ClassName}(${className});
     }
@@ -94,9 +116,15 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
      * @param ids 需要删除的数据ID
      * @return 结果
      */
+#if($table.sub)
+    @Transactional
+#end
     @Override
     public int delete${ClassName}ByIds(String ids)
     {
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(Convert.toStrArray(ids));
+#end
         return ${className}Mapper.delete${ClassName}ByIds(Convert.toStrArray(ids));
     }
 
@@ -109,6 +137,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
     @Override
     public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField})
     {
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
+#end
         return ${className}Mapper.delete${ClassName}ById(${pkColumn.javaField});
     }
 #if($table.tree)
@@ -138,4 +169,30 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
         return ztrees;
     }
 #end
+#if($table.sub)
+
+    /**
+     * 新增${subTable.functionName}信息
+     * 
+     * @param ${className} ${functionName}对象
+     */
+    public void insert${subClassName}(${ClassName} ${className})
+    {
+        List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
+        Long ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
+        if (StringUtils.isNotNull(${subclassName}List))
+        {
+            List<${subClassName}> list = new ArrayList<${subClassName}>();
+            for (${subClassName} ${subclassName} : ${subclassName}List)
+            {
+                ${subclassName}.set${pkColumn.capJavaField}(${pkColumn.javaField});
+                list.add(${subclassName});
+            }
+            if (list.size() > 0)
+            {
+                ${className}Mapper.batch${subClassName}(list);
+            }
+        }
+    }
+#end
 }

+ 75 - 0
ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm

@@ -0,0 +1,75 @@
+package ${packageName}.domain;
+
+#foreach ($import in $subImportList)
+import ${import};
+#end
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * ${subTable.functionName}对象 ${subTableName}
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+public class ${subClassName} extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+#foreach ($column in $subTable.columns)
+#if(!$table.isSuperColumn($column.javaField))
+    /** $column.columnComment */
+#if($column.list)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($parentheseIndex != -1)
+    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+#elseif($column.javaType == 'Date')
+    @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
+#else
+    @Excel(name = "${comment}")
+#end
+#end
+    private $column.javaType $column.javaField;
+
+#end
+#end
+#foreach ($column in $subTable.columns)
+#if(!$table.isSuperColumn($column.javaField))
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+    public void set${AttrName}($column.javaType $column.javaField) 
+    {
+        this.$column.javaField = $column.javaField;
+    }
+
+    public $column.javaType get${AttrName}() 
+    {
+        return $column.javaField;
+    }
+#end
+#end
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+#foreach ($column in $subTable.columns)
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+            .append("${column.javaField}", get${AttrName}())
+#end
+            .toString();
+    }
+}

+ 40 - 1
ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm

@@ -12,6 +12,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="parentName" column="parent_name" />
 #end
     </resultMap>
+#if($table.sub)
+
+    <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
+        <collection property="${subclassName}List" notNullColumn="${subTable.pkColumn.columnName}" javaType="java.util.List" resultMap="${subClassName}Result" />
+    </resultMap>
+
+    <resultMap type="${subClassName}" id="${subClassName}Result">
+#foreach ($column in $subTable.columns)
+        <result property="${column.javaField}"    column="${column.columnName}"    />
+#end
+    </resultMap>
+#end
 
     <sql id="select${ClassName}Vo">
         select#foreach($column in $columns) $column.columnName#if($velocityCount != $columns.size()),#end#end from ${tableName}
@@ -52,7 +64,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 #end
     </select>
     
-    <select id="select${ClassName}ById" parameterType="${pkColumn.javaType}" resultMap="${ClassName}Result">
+    <select id="select${ClassName}ById" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
 #if($table.crud)
         <include refid="select${ClassName}Vo"/>
         where ${pkColumn.columnName} = #{${pkColumn.javaField}}
@@ -61,6 +73,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         from ${tableName} t
         left join ${tableName} p on p.${pkColumn.columnName} = t.${tree_parent_code}
         where t.${pkColumn.columnName} = #{${pkColumn.javaField}}
+#elseif($table.sub)
+        select#foreach($column in $columns) a.$column.columnName#if($velocityCount != $columns.size()),#end#end,
+           #foreach($column in $subTable.columns) b.$column.columnName#if($velocityCount != $subTable.columns.size()),#end#end
+
+        from ${tableName} a
+        left join ${subTableName} b on b.${subTableFkName} = a.${pkColumn.columnName}
+        where a.${pkColumn.columnName} = #{${pkColumn.javaField}}
 #end
     </select>
         
@@ -104,5 +123,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{${pkColumn.javaField}}
         </foreach>
     </delete>
+#if($table.sub)
     
+    <delete id="delete${subClassName}By${subTableFkClassName}s" parameterType="String">
+        delete from ${subTableName} where ${subTableFkName} in 
+        <foreach item="${subTableFkclassName}" collection="array" open="(" separator="," close=")">
+            #{${subTableFkclassName}}
+        </foreach>
+    </delete>
+
+    <delete id="delete${subClassName}By${subTableFkClassName}" parameterType="Long">
+        delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
+    </delete>
+
+    <insert id="batch${subClassName}">
+        insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($velocityCount != $columns.size()),#end#end) values
+		<foreach item="item" index="index" collection="list" separator=",">
+            (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($velocityCount != $columns.size()),#end#end)
+        </foreach>
+    </insert>
+#end
+
 </mapper>

+ 18 - 16
sql/ry_20200604.sql → sql/ry_20200617.sql

@@ -648,22 +648,24 @@ insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨
 -- ----------------------------
 drop table if exists gen_table;
 create table gen_table (
-  table_id          bigint(20)      not null auto_increment    comment '编号',
-  table_name        varchar(200)    default ''                 comment '表名称',
-  table_comment     varchar(500)    default ''                 comment '表描述',
-  class_name        varchar(100)    default ''                 comment '实体类名称',
-  tpl_category      varchar(200)    default 'crud'             comment '使用的模板(crud单表操作 tree树表操作)',
-  package_name      varchar(100)                               comment '生成包路径',
-  module_name       varchar(30)                                comment '生成模块名',
-  business_name     varchar(30)                                comment '生成业务名',
-  function_name     varchar(50)                                comment '生成功能名',
-  function_author   varchar(50)                                comment '生成功能作者',
-  options           varchar(1000)                              comment '其它生成选项',
-  create_by         varchar(64)     default ''                 comment '创建者',
-  create_time 	    datetime                                   comment '创建时间',
-  update_by         varchar(64)     default ''                 comment '更新者',
-  update_time       datetime                                   comment '更新时间',
-  remark            varchar(500)    default null               comment '备注',
+  table_id             bigint(20)      not null auto_increment    comment '编号',
+  table_name           varchar(200)    default ''                 comment '表名称',
+  table_comment        varchar(500)    default ''                 comment '表描述',
+  sub_table_name       varchar(64)     default null               comment '关联父表的表名',
+  sub_table_fk_name    varchar(64)     default null               comment '本表关联父表的外键名',
+  class_name           varchar(100)    default ''                 comment '实体类名称',
+  tpl_category         varchar(200)    default 'crud'             comment '使用的模板(crud单表操作 tree树表操作 sub主子表操作)',
+  package_name         varchar(100)                               comment '生成包路径',
+  module_name          varchar(30)                                comment '生成模块名',
+  business_name        varchar(30)                                comment '生成业务名',
+  function_name        varchar(50)                                comment '生成功能名',
+  function_author      varchar(50)                                comment '生成功能作者',
+  options              varchar(1000)                              comment '其它生成选项',
+  create_by            varchar(64)     default ''                 comment '创建者',
+  create_time 	       datetime                                   comment '创建时间',
+  update_by            varchar(64)     default ''                 comment '更新者',
+  update_time          datetime                                   comment '更新时间',
+  remark               varchar(500)    default null               comment '备注',
   primary key (table_id)
 ) engine=innodb auto_increment=1 comment = '代码生成业务表';