From 591f1a4e3f1dbf6c2c209032239bec7fcf63fc91 Mon Sep 17 00:00:00 2001
From: fuliqi <fuliqi@qq.com>
Date: 星期二, 20 二月 2024 09:17:30 +0800
Subject: [PATCH] bug修复+引入系统监控

---
 ycl-generator/src/main/resources/vm/java/mapper.java.vm                              |   91 
 ycl-generator/src/main/resources/vm/vue/v3/index.vue.vm                              |  590 +++
 ycl-pojo/src/main/java/com/ycl/system/server/Jvm.java                                |  131 
 ycl-generator/src/main/resources/vm/java/serviceImpl.java.vm                         |  169 +
 ycl-generator/src/main/java/com/ycl/generator/service/IGenTableColumnService.java    |   44 
 ycl-generator/src/main/resources/generator.yml                                       |   10 
 ycl-generator/src/main/java/com/ycl/generator/util/SqlUtil.java                      |   70 
 ycl-generator/src/main/resources/vm/java/domain.java.vm                              |  103 
 ycl-generator/pom.xml                                                                |   67 
 ycl-generator/src/main/java/com/ycl/generator/util/DateUtils.java                    |  188 +
 ycl-pojo/src/main/java/com/ycl/system/server/Mem.java                                |   61 
 ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableMapper.java             |   83 
 ycl-server/src/main/java/com/ycl/properties/PermitAllUrlProperties.java              |    2 
 sql/ry_20231130.sql                                                                  |   59 
 ycl-server/src/main/java/com/ycl/config/RedisConfig.java                             |   69 
 ycl-common/src/main/java/constant/GenConstants.java                                  |  117 
 ycl-pojo/src/main/java/com/ycl/system/server/Sys.java                                |   84 
 ycl-server/src/main/java/com/ycl/config/SecurityConfig.java                          |    4 
 ycl-generator/src/main/java/com/ycl/generator/util/VelocityInitializer.java          |   35 
 ycl-server/src/main/java/com/ycl/config/FastJson2JsonRedisSerializer.java            |   49 
 ycl-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm                         |  474 +++
 ycl-generator/src/main/java/com/ycl/generator/service/GenTableServiceImpl.java       |  522 +++
 ycl-server/pom.xml                                                                   |    7 
 ycl-generator/src/main/java/com/ycl/generator/exception/UtilException.java           |   26 
 ycl-generator/src/main/java/com/ycl/generator/service/GenTableColumnServiceImpl.java |   69 
 ycl-generator/src/main/resources/vm/xml/mapper.xml.vm                                |  135 
 ycl-common/src/main/java/utils/Arith.java                                            |  114 
 document/副本1020自贡市局运维考核平台.xlsx                                                       |    0 
 ycl-generator/src/main/resources/mapper/generator/GenTableMapper.xml                 |  202 +
 ycl-pojo/src/main/java/com/ycl/system/server/Cpu.java                                |  101 
 ycl-generator/src/main/java/com/ycl/generator/util/GenUtils.java                     |  258 +
 ycl-generator/src/main/resources/vm/java/sub-domain.java.vm                          |   74 
 ycl-server/src/main/java/com/ycl/aop/DataScopeAspect.java                            |  175 +
 ycl-server/src/main/java/com/ycl/handler/GlobalExceptionHandler.java                 |  114 
 ycl-generator/src/main/java/com/ycl/generator/util/VelocityUtils.java                |  402 ++
 ycl-generator/src/main/java/com/ycl/generator/controller/GenController.java          |  207 +
 pom.xml                                                                              |   23 
 ycl-server/src/main/java/com/ycl/system/controller/SysLogininforController.java      |   77 
 ycl-server/src/main/java/com/ycl/system/controller/SysOperlogController.java         |   64 
 ycl-generator/src/main/java/com/ycl/generator/util/PageUtils.java                    |   34 
 ycl-generator/src/main/resources/vm/vue/index-tree.vue.vm                            |  505 +++
 ycl-common/src/main/java/utils/DateUtils.java                                        |  188 +
 ycl-server/src/main/resources/application.yml                                        |    2 
 ycl-generator/src/main/java/com/ycl/generator/exception/ServiceException.java        |   74 
 ycl-generator/src/main/resources/vm/js/api.js.vm                                     |   44 
 ycl-common/src/main/java/utils/ip/IpUtils.java                                       |  383 ++
 ycl-generator/src/main/java/com/ycl/generator/service/IGenTableService.java          |  121 
 ycl-pojo/src/main/java/com/ycl/system/server/SysFile.java                            |  114 
 ycl-generator/src/main/resources/vm/sql/sql.vm                                       |   22 
 ycl-pojo/pom.xml                                                                     |    5 
 ycl-generator/src/main/resources/vm/java/service.java.vm                             |   61 
 ycl-server/src/main/java/com/ycl/system/monitor/CacheController.java                 |  111 
 ycl-generator/src/main/java/com/ycl/generator/controller/BaseController.java         |  203 +
 ycl-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml           |  127 
 ycl-generator/src/main/resources/vm/vue/v3/readme.txt                                |    1 
 ycl-server/src/main/java/com/ycl/system/monitor/ServerController.java                |   27 
 ycl-generator/src/main/java/com/ycl/generator/config/GenConfig.java                  |   73 
 ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableColumnMapper.java       |   60 
 ycl-generator/src/main/resources/vm/vue/index.vue.vm                                 |  602 +++
 ycl-generator/src/main/resources/vm/java/controller.java.vm                          |  115 
 ycl-server/src/main/java/com/ycl/system/monitor/SysUserOnlineController.java         |   80 
 /dev/null                                                                            |   30 
 ycl-generator/src/main/java/com/ycl/generator/domain/GenTableColumn.java             |  373 ++
 ycl-pojo/src/main/java/com/ycl/system/Server.java                                    |  237 +
 ycl-generator/src/main/java/com/ycl/generator/domain/GenTable.java                   |  373 ++
 ycl-generator/src/main/java/com/ycl/generator/util/SecurityUtils.java                |  181 +
 66 files changed, 9,130 insertions(+), 86 deletions(-)

diff --git "a/document/\345\211\257\346\234\2541020\350\207\252\350\264\241\345\270\202\345\261\200\350\277\220\347\273\264\350\200\203\346\240\270\345\271\263\345\217\260.xlsx" "b/document/\345\211\257\346\234\2541020\350\207\252\350\264\241\345\270\202\345\261\200\350\277\220\347\273\264\350\200\203\346\240\270\345\271\263\345\217\260.xlsx"
new file mode 100644
index 0000000..dfe6322
--- /dev/null
+++ "b/document/\345\211\257\346\234\2541020\350\207\252\350\264\241\345\270\202\345\261\200\350\277\220\347\273\264\350\200\203\346\240\270\345\271\263\345\217\260.xlsx"
Binary files differ
diff --git a/pom.xml b/pom.xml
index ac7f7f8..c6df984 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,6 +19,7 @@
         <module>ycl-common</module>
         <module>ycl-server</module>
         <module>ycl-pojo</module>
+        <module>ycl-generator</module>
     </modules>
 
     <properties>
@@ -38,12 +39,15 @@
         <jaxb-api.version>2.3.1</jaxb-api.version>
         <poi.version>4.1.2</poi.version>
         <hutool.version>5.8.22</hutool.version>
+        <oshi.version>6.4.0</oshi.version>
         <kaptcha.version>2.3.3</kaptcha.version>
         <easyexcel.version>3.3.2</easyexcel.version>
         <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
         <spring-boot.version>3.0.6</spring-boot.version>
         <mapstruct-plus.version>1.3.5</mapstruct-plus.version>
         <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
+        <velocity.version>2.3</velocity.version>
+        <commons.collections.version>3.2.2</commons.collections.version>
         <!-- 鎻掍欢鐗堟湰 -->
         <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
         <maven-war-plugin.version>3.2.2</maven-war-plugin.version>
@@ -74,19 +78,36 @@
     </profiles>
     <dependencyManagement>
         <dependencies>
+            <!-- 鑾峰彇绯荤粺淇℃伅 -->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.version}</version>
+            </dependency>
             <!-- 瑙f瀽瀹㈡埛绔搷浣滅郴缁熴�佹祻瑙堝櫒绛� -->
             <dependency>
                 <groupId>eu.bitwalker</groupId>
                 <artifactId>UserAgentUtils</artifactId>
                 <version>${bitwalker.version}</version>
             </dependency>
-
+            <!-- velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
+            <dependency>
+                <groupId>org.apache.velocity</groupId>
+                <artifactId>velocity-engine-core</artifactId>
+                <version>${velocity.version}</version>
+            </dependency>
             <!-- io甯哥敤宸ュ叿绫� -->
             <dependency>
                 <groupId>commons-io</groupId>
                 <artifactId>commons-io</artifactId>
                 <version>${commons.io.version}</version>
             </dependency>
+            <!-- collections宸ュ叿绫� -->
+            <dependency>
+                <groupId>commons-collections</groupId>
+                <artifactId>commons-collections</artifactId>
+                <version>${commons.collections.version}</version>
+            </dependency>
             <!-- excel宸ュ叿 -->
             <dependency>
                 <groupId>org.apache.poi</groupId>
diff --git a/sql/ry_20231130.sql b/sql/ry_20231130.sql
index 457bb09..705e32d 100644
--- a/sql/ry_20231130.sql
+++ b/sql/ry_20231130.sql
@@ -910,3 +910,62 @@
 insert into sys_config
 values (6, '鐢ㄦ埛鐧诲綍-榛戝悕鍗曞垪琛�', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null,
         '璁剧疆鐧诲綍IP榛戝悕鍗曢檺鍒讹紝澶氫釜鍖归厤椤逛互;鍒嗛殧锛屾敮鎸佸尮閰嶏紙*閫氶厤銆佺綉娈碉級');
+
+
+-- ----------------------------
+-- 18銆佷唬鐮佺敓鎴愪笟鍔¤〃
+-- ----------------------------
+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 '琛ㄦ弿杩�',
+                           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鏍戣〃鎿嶄綔锛�',
+                           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 '鐢熸垚鍔熻兘浣滆��',
+                           gen_type          char(1)         default '0'                comment '鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級',
+                           gen_path          varchar(200)    default '/'                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 = '浠g爜鐢熸垚涓氬姟琛�';
+
+-- ----------------------------
+-- 19銆佷唬鐮佺敓鎴愪笟鍔¤〃瀛楁
+-- ----------------------------
+drop table if exists gen_table_column;
+create table gen_table_column (
+                                  column_id         bigint(20)      not null auto_increment    comment '缂栧彿',
+                                  table_id          varchar(64)                                comment '褰掑睘琛ㄧ紪鍙�',
+                                  column_name       varchar(200)                               comment '鍒楀悕绉�',
+                                  column_comment    varchar(500)                               comment '鍒楁弿杩�',
+                                  column_type       varchar(100)                               comment '鍒楃被鍨�',
+                                  java_type         varchar(500)                               comment 'JAVA绫诲瀷',
+                                  java_field        varchar(200)                               comment 'JAVA瀛楁鍚�',
+                                  is_pk             char(1)                                    comment '鏄惁涓婚敭锛�1鏄級',
+                                  is_increment      char(1)                                    comment '鏄惁鑷锛�1鏄級',
+                                  is_required       char(1)                                    comment '鏄惁蹇呭~锛�1鏄級',
+                                  is_insert         char(1)                                    comment '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級',
+                                  is_edit           char(1)                                    comment '鏄惁缂栬緫瀛楁锛�1鏄級',
+                                  is_list           char(1)                                    comment '鏄惁鍒楄〃瀛楁锛�1鏄級',
+                                  is_query          char(1)                                    comment '鏄惁鏌ヨ瀛楁锛�1鏄級',
+                                  query_type        varchar(200)    default 'EQ'               comment '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級',
+                                  html_type         varchar(200)                               comment '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級',
+                                  dict_type         varchar(200)    default ''                 comment '瀛楀吀绫诲瀷',
+                                  sort              int                                        comment '鎺掑簭',
+                                  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+                                  create_time 	    datetime                                   comment '鍒涘缓鏃堕棿',
+                                  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+                                  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+                                  primary key (column_id)
+) engine=innodb auto_increment=1 comment = '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�';
\ No newline at end of file
diff --git a/ycl-common/src/main/java/constant/GenConstants.java b/ycl-common/src/main/java/constant/GenConstants.java
new file mode 100644
index 0000000..cdcb260
--- /dev/null
+++ b/ycl-common/src/main/java/constant/GenConstants.java
@@ -0,0 +1,117 @@
+package constant;
+
+/**
+ * 浠g爜鐢熸垚閫氱敤甯搁噺
+ * 
+ * @author ruoyi
+ */
+public class GenConstants
+{
+    /** 鍗曡〃锛堝鍒犳敼鏌ワ級 */
+    public static final String TPL_CRUD = "crud";
+
+    /** 鏍戣〃锛堝鍒犳敼鏌ワ級 */
+    public static final String TPL_TREE = "tree";
+
+    /** 涓诲瓙琛紙澧炲垹鏀规煡锛� */
+    public static final String TPL_SUB = "sub";
+
+    /** 鏍戠紪鐮佸瓧娈� */
+    public static final String TREE_CODE = "treeCode";
+
+    /** 鏍戠埗缂栫爜瀛楁 */
+    public static final String TREE_PARENT_CODE = "treeParentCode";
+
+    /** 鏍戝悕绉板瓧娈� */
+    public static final String TREE_NAME = "treeName";
+
+    /** 涓婄骇鑿滃崟ID瀛楁 */
+    public static final String PARENT_MENU_ID = "parentMenuId";
+
+    /** 涓婄骇鑿滃崟鍚嶇О瀛楁 */
+    public static final String PARENT_MENU_NAME = "parentMenuName";
+
+    /** 鏁版嵁搴撳瓧绗︿覆绫诲瀷 */
+    public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
+
+    /** 鏁版嵁搴撴枃鏈被鍨� */
+    public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
+
+    /** 鏁版嵁搴撴椂闂寸被鍨� */
+    public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
+
+    /** 鏁版嵁搴撴暟瀛楃被鍨� */
+    public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
+            "bit", "bigint", "float", "double", "decimal" };
+
+    /** 椤甸潰涓嶉渶瑕佺紪杈戝瓧娈� */
+    public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
+
+    /** 椤甸潰涓嶉渶瑕佹樉绀虹殑鍒楄〃瀛楁 */
+    public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
+            "update_time" };
+
+    /** 椤甸潰涓嶉渶瑕佹煡璇㈠瓧娈� */
+    public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
+            "update_time", "remark" };
+
+    /** Entity鍩虹被瀛楁 */
+    public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
+
+    /** Tree鍩虹被瀛楁 */
+    public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };
+
+    /** 鏂囨湰妗� */
+    public static final String HTML_INPUT = "input";
+
+    /** 鏂囨湰鍩� */
+    public static final String HTML_TEXTAREA = "textarea";
+
+    /** 涓嬫媺妗� */
+    public static final String HTML_SELECT = "select";
+
+    /** 鍗曢�夋 */
+    public static final String HTML_RADIO = "radio";
+
+    /** 澶嶉�夋 */
+    public static final String HTML_CHECKBOX = "checkbox";
+
+    /** 鏃ユ湡鎺т欢 */
+    public static final String HTML_DATETIME = "datetime";
+
+    /** 鍥剧墖涓婁紶鎺т欢 */
+    public static final String HTML_IMAGE_UPLOAD = "imageUpload";
+
+    /** 鏂囦欢涓婁紶鎺т欢 */
+    public static final String HTML_FILE_UPLOAD = "fileUpload";
+
+    /** 瀵屾枃鏈帶浠� */
+    public static final String HTML_EDITOR = "editor";
+
+    /** 瀛楃涓茬被鍨� */
+    public static final String TYPE_STRING = "String";
+
+    /** 鏁村瀷 */
+    public static final String TYPE_INTEGER = "Integer";
+
+    /** 闀挎暣鍨� */
+    public static final String TYPE_LONG = "Long";
+
+    /** 娴偣鍨� */
+    public static final String TYPE_DOUBLE = "Double";
+
+    /** 楂樼簿搴﹁绠楃被鍨� */
+    public static final String TYPE_BIGDECIMAL = "BigDecimal";
+
+    /** 鏃堕棿绫诲瀷 */
+    public static final String TYPE_DATE = "Date";
+
+    /** 妯$硦鏌ヨ */
+    public static final String QUERY_LIKE = "LIKE";
+
+    /** 鐩哥瓑鏌ヨ */
+    public static final String QUERY_EQ = "EQ";
+
+    /** 闇�瑕� */
+    public static final String REQUIRE = "1";
+}
diff --git a/ycl-common/src/main/java/json/JacksonObjectMapper.java b/ycl-common/src/main/java/json/JacksonObjectMapper.java
deleted file mode 100644
index 894da8c..0000000
--- a/ycl-common/src/main/java/json/JacksonObjectMapper.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package json;
-
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
-
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.format.DateTimeFormatter;
-
-import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
-
-/**
- * 瀵硅薄鏄犲皠鍣�:鍩轰簬jackson灏咼ava瀵硅薄杞负json锛屾垨鑰呭皢json杞负Java瀵硅薄
- * 灏咼SON瑙f瀽涓篔ava瀵硅薄鐨勮繃绋嬬О涓� [浠嶫SON鍙嶅簭鍒楀寲Java瀵硅薄]
- * 浠嶫ava瀵硅薄鐢熸垚JSON鐨勮繃绋嬬О涓� [搴忓垪鍖朖ava瀵硅薄鍒癑SON]
- */
-public class JacksonObjectMapper extends ObjectMapper {
-
-    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
-    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
-//    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
-    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
-
-    public JacksonObjectMapper() {
-        super();
-        //鏀跺埌鏈煡灞炴�ф椂涓嶆姤寮傚父
-        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
-
-        //鍙嶅簭鍒楀寲鏃讹紝灞炴�т笉瀛樺湪鐨勫吋瀹瑰鐞�
-        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
-
-        SimpleModule simpleModule = new SimpleModule()
-                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
-                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
-                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
-                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
-                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
-                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
-
-        //娉ㄥ唽鍔熻兘妯″潡 渚嬪锛屽彲浠ユ坊鍔犺嚜瀹氫箟搴忓垪鍖栧櫒鍜屽弽搴忓垪鍖栧櫒
-        this.registerModule(simpleModule);
-    }
-}
diff --git a/ycl-common/src/main/java/utils/Arith.java b/ycl-common/src/main/java/utils/Arith.java
new file mode 100644
index 0000000..e119b33
--- /dev/null
+++ b/ycl-common/src/main/java/utils/Arith.java
@@ -0,0 +1,114 @@
+package utils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * 绮剧‘鐨勬诞鐐规暟杩愮畻
+ * 
+ * @author ruoyi
+ */
+public class Arith
+{
+
+    /** 榛樿闄ゆ硶杩愮畻绮惧害 */
+    private static final int DEF_DIV_SCALE = 10;
+
+    /** 杩欎釜绫讳笉鑳藉疄渚嬪寲 */
+    private Arith()
+    {
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫姞娉曡繍绠椼��
+     * @param v1 琚姞鏁�
+     * @param v2 鍔犳暟
+     * @return 涓や釜鍙傛暟鐨勫拰
+     */
+    public static double add(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.add(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫噺娉曡繍绠椼��
+     * @param v1 琚噺鏁�
+     * @param v2 鍑忔暟
+     * @return 涓や釜鍙傛暟鐨勫樊
+     */
+    public static double sub(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.subtract(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勪箻娉曡繍绠椼��
+     * @param v1 琚箻鏁�
+     * @param v2 涔樻暟
+     * @return 涓や釜鍙傛暟鐨勭Н
+     */
+    public static double mul(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.multiply(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵锛堢浉瀵癸級绮剧‘鐨勯櫎娉曡繍绠楋紝褰撳彂鐢熼櫎涓嶅敖鐨勬儏鍐垫椂锛岀簿纭埌
+     * 灏忔暟鐐逛互鍚�10浣嶏紝浠ュ悗鐨勬暟瀛楀洓鑸嶄簲鍏ャ��
+     * @param v1 琚櫎鏁�
+     * @param v2 闄ゆ暟
+     * @return 涓や釜鍙傛暟鐨勫晢
+     */
+    public static double div(double v1, double v2)
+    {
+        return div(v1, v2, DEF_DIV_SCALE);
+    }
+
+    /**
+     * 鎻愪緵锛堢浉瀵癸級绮剧‘鐨勯櫎娉曡繍绠椼�傚綋鍙戠敓闄や笉灏界殑鎯呭喌鏃讹紝鐢眘cale鍙傛暟鎸�
+     * 瀹氱簿搴︼紝浠ュ悗鐨勬暟瀛楀洓鑸嶄簲鍏ャ��
+     * @param v1 琚櫎鏁�
+     * @param v2 闄ゆ暟
+     * @param scale 琛ㄧず琛ㄧず闇�瑕佺簿纭埌灏忔暟鐐逛互鍚庡嚑浣嶃��
+     * @return 涓や釜鍙傛暟鐨勫晢
+     */
+    public static double div(double v1, double v2, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException(
+                    "The scale must be a positive integer or zero");
+        }
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        if (b1.compareTo(BigDecimal.ZERO) == 0)
+        {
+            return BigDecimal.ZERO.doubleValue();
+        }
+        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫皬鏁颁綅鍥涜垗浜斿叆澶勭悊銆�
+     * @param v 闇�瑕佸洓鑸嶄簲鍏ョ殑鏁板瓧
+     * @param scale 灏忔暟鐐瑰悗淇濈暀鍑犱綅
+     * @return 鍥涜垗浜斿叆鍚庣殑缁撴灉
+     */
+    public static double round(double v, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException(
+                    "The scale must be a positive integer or zero");
+        }
+        BigDecimal b = new BigDecimal(Double.toString(v));
+        BigDecimal one = BigDecimal.ONE;
+        return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
+    }
+}
diff --git a/ycl-common/src/main/java/utils/DateUtils.java b/ycl-common/src/main/java/utils/DateUtils.java
new file mode 100644
index 0000000..131b9ce
--- /dev/null
+++ b/ycl-common/src/main/java/utils/DateUtils.java
@@ -0,0 +1,188 @@
+package utils;
+
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.util.Date;
+
+/**
+ * 鏃堕棿宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils
+{
+    public static String YYYY = "yyyy";
+
+    public static String YYYY_MM = "yyyy-MM";
+
+    public static String YYYY_MM_DD = "yyyy-MM-dd";
+
+    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+
+    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+    private static String[] parsePatterns = {
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", 
+            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+    /**
+     * 鑾峰彇褰撳墠Date鍨嬫棩鏈�
+     * 
+     * @return Date() 褰撳墠鏃ユ湡
+     */
+    public static Date getNowDate()
+    {
+        return new Date();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡, 榛樿鏍煎紡涓簓yyy-MM-dd
+     * 
+     * @return String
+     */
+    public static String getDate()
+    {
+        return dateTimeNow(YYYY_MM_DD);
+    }
+
+    public static final String getTime()
+    {
+        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
+    }
+
+    public static final String dateTimeNow()
+    {
+        return dateTimeNow(YYYYMMDDHHMMSS);
+    }
+
+    public static final String dateTimeNow(final String format)
+    {
+        return parseDateToStr(format, new Date());
+    }
+
+    public static final String dateTime(final Date date)
+    {
+        return parseDateToStr(YYYY_MM_DD, date);
+    }
+
+    public static final String parseDateToStr(final String format, final Date date)
+    {
+        return new SimpleDateFormat(format).format(date);
+    }
+
+    public static final Date dateTime(final String format, final String ts)
+    {
+        try
+        {
+            return new SimpleDateFormat(format).parse(ts);
+        }
+        catch (ParseException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�2018/08/08
+     */
+    public static final String datePath()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyy/MM/dd");
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�20180808
+     */
+    public static final String dateTime()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyyMMdd");
+    }
+
+    /**
+     * 鏃ユ湡鍨嬪瓧绗︿覆杞寲涓烘棩鏈� 鏍煎紡
+     */
+    public static Date parseDate(Object str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        try
+        {
+            return parseDate(str.toString(), parsePatterns);
+        }
+        catch (ParseException e)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * 鑾峰彇鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂�
+     */
+    public static Date getServerStartDate()
+    {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 璁$畻鐩稿樊澶╂暟
+     */
+    public static int differentDaysByMillisecond(Date date1, Date date2)
+    {
+        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
+    }
+
+    /**
+     * 璁$畻鏃堕棿宸�
+     *
+     * @param endDate 鏈�鍚庢椂闂�
+     * @param startTime 寮�濮嬫椂闂�
+     * @return 鏃堕棿宸紙澶�/灏忔椂/鍒嗛挓锛�
+     */
+    public static String timeDistance(Date endDate, Date startTime)
+    {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // long ns = 1000;
+        // 鑾峰緱涓や釜鏃堕棿鐨勬绉掓椂闂村樊寮�
+        long diff = endDate.getTime() - startTime.getTime();
+        // 璁$畻宸灏戝ぉ
+        long day = diff / nd;
+        // 璁$畻宸灏戝皬鏃�
+        long hour = diff % nd / nh;
+        // 璁$畻宸灏戝垎閽�
+        long min = diff % nd % nh / nm;
+        // 璁$畻宸灏戠//杈撳嚭缁撴灉
+        // long sec = diff % nd % nh % nm / ns;
+        return day + "澶�" + hour + "灏忔椂" + min + "鍒嗛挓";
+    }
+
+    /**
+     * 澧炲姞 LocalDateTime ==> Date
+     */
+    public static Date toDate(LocalDateTime temporalAccessor)
+    {
+        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+
+    /**
+     * 澧炲姞 LocalDate ==> Date
+     */
+    public static Date toDate(LocalDate temporalAccessor)
+    {
+        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
+        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+}
diff --git a/ycl-common/src/main/java/utils/ip/IpUtils.java b/ycl-common/src/main/java/utils/ip/IpUtils.java
new file mode 100644
index 0000000..e42b5cf
--- /dev/null
+++ b/ycl-common/src/main/java/utils/ip/IpUtils.java
@@ -0,0 +1,383 @@
+package utils.ip;
+
+import jakarta.servlet.http.HttpServletRequest;
+import utils.ServletUtils;
+import utils.StringUtils;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 鑾峰彇IP鏂规硶
+ * 
+ * @author ruoyi
+ */
+public class IpUtils
+{
+    public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
+    // 鍖归厤 ip
+    public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
+    public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
+    // 鍖归厤缃戞
+    public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
+
+    /**
+     * 鑾峰彇瀹㈡埛绔疘P
+     * 
+     * @return IP鍦板潃
+     */
+    public static String getIpAddr()
+    {
+        return getIpAddr(ServletUtils.getRequest());
+    }
+
+    /**
+     * 鑾峰彇瀹㈡埛绔疘P
+     * 
+     * @param request 璇锋眰瀵硅薄
+     * @return IP鍦板潃
+     */
+    public static String getIpAddr(HttpServletRequest request)
+    {
+        if (request == null)
+        {
+            return "unknown";
+        }
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("X-Forwarded-For");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("X-Real-IP");
+        }
+
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getRemoteAddr();
+        }
+
+        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
+    }
+
+    /**
+     * 妫�鏌ユ槸鍚︿负鍐呴儴IP鍦板潃
+     * 
+     * @param ip IP鍦板潃
+     * @return 缁撴灉
+     */
+    public static boolean internalIp(String ip)
+    {
+        byte[] addr = textToNumericFormatV4(ip);
+        return internalIp(addr) || "127.0.0.1".equals(ip);
+    }
+
+    /**
+     * 妫�鏌ユ槸鍚︿负鍐呴儴IP鍦板潃
+     * 
+     * @param addr byte鍦板潃
+     * @return 缁撴灉
+     */
+    private static boolean internalIp(byte[] addr)
+    {
+        if (StringUtils.isNull(addr) || addr.length < 2)
+        {
+            return true;
+        }
+        final byte b0 = addr[0];
+        final byte b1 = addr[1];
+        // 10.x.x.x/8
+        final byte SECTION_1 = 0x0A;
+        // 172.16.x.x/12
+        final byte SECTION_2 = (byte) 0xAC;
+        final byte SECTION_3 = (byte) 0x10;
+        final byte SECTION_4 = (byte) 0x1F;
+        // 192.168.x.x/16
+        final byte SECTION_5 = (byte) 0xC0;
+        final byte SECTION_6 = (byte) 0xA8;
+        switch (b0)
+        {
+            case SECTION_1:
+                return true;
+            case SECTION_2:
+                if (b1 >= SECTION_3 && b1 <= SECTION_4)
+                {
+                    return true;
+                }
+            case SECTION_5:
+                switch (b1)
+                {
+                    case SECTION_6:
+                        return true;
+                }
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 灏咺Pv4鍦板潃杞崲鎴愬瓧鑺�
+     * 
+     * @param text IPv4鍦板潃
+     * @return byte 瀛楄妭
+     */
+    public static byte[] textToNumericFormatV4(String text)
+    {
+        if (text.length() == 0)
+        {
+            return null;
+        }
+
+        byte[] bytes = new byte[4];
+        String[] elements = text.split("\\.", -1);
+        try
+        {
+            long l;
+            int i;
+            switch (elements.length)
+            {
+                case 1:
+                    l = Long.parseLong(elements[0]);
+                    if ((l < 0L) || (l > 4294967295L))
+                    {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
+                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 2:
+                    l = Integer.parseInt(elements[0]);
+                    if ((l < 0L) || (l > 255L))
+                    {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l & 0xFF);
+                    l = Integer.parseInt(elements[1]);
+                    if ((l < 0L) || (l > 16777215L))
+                    {
+                        return null;
+                    }
+                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 3:
+                    for (i = 0; i < 2; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L))
+                        {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    l = Integer.parseInt(elements[2]);
+                    if ((l < 0L) || (l > 65535L))
+                    {
+                        return null;
+                    }
+                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 4:
+                    for (i = 0; i < 4; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L))
+                        {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    break;
+                default:
+                    return null;
+            }
+        }
+        catch (NumberFormatException e)
+        {
+            return null;
+        }
+        return bytes;
+    }
+
+    /**
+     * 鑾峰彇IP鍦板潃
+     * 
+     * @return 鏈湴IP鍦板潃
+     */
+    public static String getHostIp()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostAddress();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "127.0.0.1";
+    }
+
+    /**
+     * 鑾峰彇涓绘満鍚�
+     * 
+     * @return 鏈湴涓绘満鍚�
+     */
+    public static String getHostName()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostName();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "鏈煡";
+    }
+
+    /**
+     * 浠庡绾у弽鍚戜唬鐞嗕腑鑾峰緱绗竴涓潪unknown IP鍦板潃
+     *
+     * @param ip 鑾峰緱鐨処P鍦板潃
+     * @return 绗竴涓潪unknown IP鍦板潃
+     */
+    public static String getMultistageReverseProxyIp(String ip)
+    {
+        // 澶氱骇鍙嶅悜浠g悊妫�娴�
+        if (ip != null && ip.indexOf(",") > 0)
+        {
+            final String[] ips = ip.trim().split(",");
+            for (String subIp : ips)
+            {
+                if (false == isUnknown(subIp))
+                {
+                    ip = subIp;
+                    break;
+                }
+            }
+        }
+        return StringUtils.substring(ip, 0, 255);
+    }
+
+    /**
+     * 妫�娴嬬粰瀹氬瓧绗︿覆鏄惁涓烘湭鐭ワ紝澶氱敤浜庢娴婬TTP璇锋眰鐩稿叧
+     *
+     * @param checkString 琚娴嬬殑瀛楃涓�
+     * @return 鏄惁鏈煡
+     */
+    public static boolean isUnknown(String checkString)
+    {
+        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
+    }
+
+    /**
+     * 鏄惁涓篒P
+     */
+    public static boolean isIP(String ip)
+    {
+        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
+    }
+
+    /**
+     * 鏄惁涓篒P锛屾垨 *涓洪棿闅旂殑閫氶厤绗﹀湴鍧�
+     */
+    public static boolean isIpWildCard(String ip)
+    {
+        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
+    }
+
+    /**
+     * 妫�娴嬪弬鏁版槸鍚﹀湪ip閫氶厤绗﹂噷
+     */
+    public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
+    {
+        String[] s1 = ipWildCard.split("\\.");
+        String[] s2 = ip.split("\\.");
+        boolean isMatchedSeg = true;
+        for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
+        {
+            if (!s1[i].equals(s2[i]))
+            {
+                isMatchedSeg = false;
+                break;
+            }
+        }
+        return isMatchedSeg;
+    }
+
+    /**
+     * 鏄惁涓虹壒瀹氭牸寮忓:鈥�10.10.10.1-10.10.10.99鈥濈殑ip娈靛瓧绗︿覆
+     */
+    public static boolean isIPSegment(String ipSeg)
+    {
+        return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
+    }
+
+    /**
+     * 鍒ゆ柇ip鏄惁鍦ㄦ寚瀹氱綉娈典腑
+     */
+    public static boolean ipIsInNetNoCheck(String iparea, String ip)
+    {
+        int idx = iparea.indexOf('-');
+        String[] sips = iparea.substring(0, idx).split("\\.");
+        String[] sipe = iparea.substring(idx + 1).split("\\.");
+        String[] sipt = ip.split("\\.");
+        long ips = 0L, ipe = 0L, ipt = 0L;
+        for (int i = 0; i < 4; ++i)
+        {
+            ips = ips << 8 | Integer.parseInt(sips[i]);
+            ipe = ipe << 8 | Integer.parseInt(sipe[i]);
+            ipt = ipt << 8 | Integer.parseInt(sipt[i]);
+        }
+        if (ips > ipe)
+        {
+            long t = ips;
+            ips = ipe;
+            ipe = t;
+        }
+        return ips <= ipt && ipt <= ipe;
+    }
+
+    /**
+     * 鏍¢獙ip鏄惁绗﹀悎杩囨护涓茶鍒�
+     * 
+     * @param filter 杩囨护IP鍒楄〃,鏀寔鍚庣紑'*'閫氶厤,鏀寔缃戞濡�:`10.10.10.1-10.10.10.99`
+     * @param ip 鏍¢獙IP鍦板潃
+     * @return boolean 缁撴灉
+     */
+    public static boolean isMatchedIp(String filter, String ip)
+    {
+        if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
+        {
+            return false;
+        }
+        String[] ips = filter.split(";");
+        for (String iStr : ips)
+        {
+            if (isIP(iStr) && iStr.equals(ip))
+            {
+                return true;
+            }
+            else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
+            {
+                return true;
+            }
+            else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/ycl-generator/.gitignore b/ycl-generator/.gitignore
deleted file mode 100644
index 25137b1..0000000
--- a/ycl-generator/.gitignore
+++ /dev/null
@@ -1,22 +0,0 @@
-# Created by .ignore support plugin (hsz.mobi)
-### Example user template template
-# IntelliJ project files11
-.idea
-*.iml
-out
-gen
-*.class
-/target/
-/*/target/
-
-# Log file
-*.log
-
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
diff --git a/ycl-generator/README.md b/ycl-generator/README.md
deleted file mode 100644
index 9827c76..0000000
--- a/ycl-generator/README.md
+++ /dev/null
@@ -1,45 +0,0 @@
-## Mybatis plus CodeGenerator浠g爜鐢熸垚鍣�
-> 鏈暀绋嬪弬鑰冨畼缃戦噸鏂板畾涔夌紪鍐欙紝鑳藉蹇�熸惌寤洪」鐩剼鎵嬫灦
-### 浠g爜鐢熸垚璇存槑
-褰撴湁涓�涓柊鐨勪笟鍔″疄鐜版椂锛屽鎺ュ彛鐨勫姛鑳藉疄鐜颁笂锛屾垜浠�氬父鏉ヨ闇�瑕佹瀯寤轰笅闈㈢殑淇℃伅锛�
-
-- PO绫�
-
-  鏁版嵁搴撹〃鍜屽疄浣撶被鐨勬槧灏� Java Bean銆�
-
-- DAO灞�
-
-  闇�瑕佺紪鍐欐帴鍙� Mapper 锛屾帴鍙� Mapper 闇�瑕佸幓缁ф壙 MP 涓殑 BaseMapper 鎺ュ彛銆�
-
-- Service灞�
-
-  缂栧啓 Service 灞傛帴鍙e拰瀹炵幇绫汇�備笟鍔℃帴鍙i渶瑕佸幓缁ф壙 MP 涓殑 IService锛屼笟鍔″疄鐜扮被闇�瑕佺户鎵� MP 涓殑 ServiceImpl 鍜� 瀹炵幇涓氬姟鎺ュ彛銆�
-
-- Controller灞�
-
-  缂栧啓 Controller 骞舵爣娉� Spring MVC 涓殑鐩稿叧娉ㄨВ銆�
-
-鈥�       浠庝笂闈㈢殑鍚勭被浠g爜涓彲浠ユ斁涓嬶紝浠g爜閮芥槸妯℃澘鎬х殑锛屽鏋滅敤鎵嬪伐copy銆佷慨鏀圭殑鏂瑰紡鏉ュ疄鐜帮紝澶儲浜轰篃娌℃晥鐜囷紝鑰岃繖鏃跺氨鏄唬鐮佺敓鎴愬櫒灏忓睍韬墜鐨勬椂鍊欙紝**浣跨敤浠g爜鐢熸垚鍣ㄧ敓鎴愭ā鏉挎�х殑浠g爜锛屽噺灏戞墜宸ユ搷浣滅殑绻佺悙锛岄泦涓簿鍔涘湪涓氬姟寮�鍙戜笂锛屾彁鍗囧紑鍙戞晥鐜囥��**
-
-鈥�	AutoGenerator 鏄� MyBatis-Plus 鐨勪唬鐮佺敓鎴愬櫒锛岄�氳繃 AutoGenerator 鍙互蹇�熺敓鎴� Mapper鎺ュ彛銆丒ntity瀹炰綋绫汇�丮apper XML銆丼ervice銆丆ontroller 绛夊悇涓ā鍧楃殑浠g爜锛屾瀬澶х殑鎻愬崌浜嗗紑鍙戞晥鐜囥��
-
-### 鍏蜂綋浣跨敤姝ラ
-1. 鎵撳紑 CodeGenerator 绫�
-2. 淇敼瀵瑰簲鐨勫弬鏁板嵆鍙�
-   鐩稿叧鍙傛暟浠嬬粛锛�
-   ```yaml
-    DB_TYPE: 鏁版嵁搴撶被鍨嬶紝 榛樿鏄� MySQL
-    DB_NAME: 鏁版嵁搴撳悕锛岀敤鎴蜂慨鏀逛负鑷繁鐨勬暟鎹簱
-    HOST_NAME: 鏁版嵁搴揑P锛� 榛樿 localhost
-    JDBC_USERNAME: 鏁版嵁搴撶敤鎴峰悕锛� 榛樿锛歳oot
-    JDBC_PASSWORD: 鏁版嵁搴撳瘑鐮侊紝榛樿锛歳oot
-    TABLES: 闇�瑕佺敓鎴愪唬鐮佺殑琛紝 鏁扮粍
-    PACKAGE_PARENT_NAME: 浠g爜鐢熸垚鐨勫寘缁撴瀯
-    IS_DTO: 鏄惁鐢熸垚DTO锛� 榛樿锛歠alse
-    AUTHOR: 浣滆�呭悕绉帮紝 榛樿锛歩theima
-   
-3. 杩愯main鏂规硶鎵ц鐢熸垚浠g爜
-4. 鎷疯礉鍒拌嚜宸辩殑椤圭洰涓嵆鍙�
-
-
-
diff --git a/ycl-generator/pom.xml b/ycl-generator/pom.xml
index 8da5f1e..1b40e42 100644
--- a/ycl-generator/pom.xml
+++ b/ycl-generator/pom.xml
@@ -2,69 +2,38 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>ycl-generator</artifactId>
-    <version>1.0-SNAPSHOT</version>
-
     <parent>
         <artifactId>zgyw</artifactId>
         <groupId>com.ycl</groupId>
         <version>1.0-SNAPSHOT</version>
     </parent>
+    <modelVersion>4.0.0</modelVersion>
 
-    <properties>
-        <maven.compiler.source>17</maven.compiler.source>
-        <maven.compiler.target>17</maven.compiler.target>
-    </properties>
+    <artifactId>ycl-generator</artifactId>
+
+    <description>
+        generator浠g爜鐢熸垚
+    </description>
 
     <dependencies>
+
+        <!--velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
         <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-            <scope>runtime</scope>
-            <version>5.1.49</version>
-        </dependency>
-        <dependency>
-            <groupId>org.projectlombok</groupId>
-            <artifactId>lombok</artifactId>
-            <optional>true</optional>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
         </dependency>
 
-        <!--mybatis plus 璧锋渚濊禆-->
+        <!-- collections宸ュ叿绫� -->
         <dependency>
-            <groupId>com.baomidou</groupId>
-            <artifactId>mybatis-plus-boot-starter</artifactId>
-            <version>3.4.2</version>
-        </dependency>
-
-        <!--mp 浠g爜鐢熸垚鍣�-->
-        <dependency>
-            <groupId>com.baomidou</groupId>
-            <artifactId>mybatis-plus-generator</artifactId>
-            <version>3.4.1</version>
-        </dependency>
-
-
-        <dependency>
-            <groupId>io.swagger</groupId>
-            <artifactId>swagger-annotations</artifactId>
-            <version>1.5.20</version>
+            <groupId>commons-collections</groupId>
+            <artifactId>commons-collections</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.freemarker</groupId>
-            <artifactId>freemarker</artifactId>
-            <version>2.3.30</version>
+            <groupId>com.ycl</groupId>
+            <artifactId>ycl-pojo</artifactId>
+            <version>1.0-SNAPSHOT</version>
         </dependency>
 
     </dependencies>
-</project>
+
+</project>
\ No newline at end of file
diff --git a/ycl-generator/src/main/java/CodeGenerator.java b/ycl-generator/src/main/java/CodeGenerator.java
deleted file mode 100644
index 465c2bf..0000000
--- a/ycl-generator/src/main/java/CodeGenerator.java
+++ /dev/null
@@ -1,258 +0,0 @@
-import com.baomidou.mybatisplus.annotation.DbType;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.generator.AutoGenerator;
-import com.baomidou.mybatisplus.generator.InjectionConfig;
-import com.baomidou.mybatisplus.generator.config.*;
-import com.baomidou.mybatisplus.generator.config.po.TableInfo;
-import com.baomidou.mybatisplus.generator.config.rules.DateType;
-import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
-import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
-
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @Description: 浠g爜鐢熸垚宸ュ叿
- */
-public class CodeGenerator {
-
-    // ================= 鑷畾涔夐厤缃�  =================
-
-    private static final DbType DB_TYPE = DbType.MYSQL;
-    private static final String DB_NAME = "";
-    private static final String HOST_NAME = "";
-    private static final String JDBC_URL = "jdbc:mysql://" + HOST_NAME + ":3306/" + DB_NAME + "?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=UTF-8";
-    private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
-
-    private static final String JDBC_USERNAME = "root";
-    private static final String JDBC_PASSWORD = "root";
-
-    /**
-     * 闇�瑕佺敓鎴愪唬鐮佺殑鏁版嵁搴撹〃鍚�(鍙互鑷富娣诲姞)
-     */
-    private static String[] TABLES = new String[]{};
-    /**
-     * 鐢熸垚鏂囦欢鏍圭洰褰曞強鍖呭悕
-     */
-    private static final String ROOT_DIR = System.getProperty("user.dir") + "/src/main/java";
-    //java鏂囦欢澶逛笅璺緞
-    private static final String PACKAGE_PARENT_NAME = "com.ycl.ycl-server";
-
-    private static final String PACKAGE_CONTROLLER_NAME = "controller";
-    private static final String PACKAGE_SERVICE_NAME = "service";
-    private static final String PACKAGE_SERVICEIMPL_NAME = "service.impl";
-    //entity
-    private static final String PACKAGE_ENTITY_NAME = "pojo";
-    // 涓�鑸儏鍐典笅瑕佸厛鐢熸垚 DTO绫� 鐒跺悗淇敼姝ゅ弬鏁板啀鐢熸垚 PO 绫汇��
-    private static final Boolean IS_DTO = false;
-
-    private static final String PACKAGE_MAPPER_NAME = "mapper";
-    private static final String RESOURCES_DIR = System.getProperty("user.dir") + "/src/main/resources";
-    private static final String MAPPER_XML_PATH = "mapper";
-    /**
-     * 鐢熸垚浠g爜鐨凘author
-     */
-    private static final String AUTHOR = "ycl";
-
-    /**
-     * 鏁版嵁搴撹〃鍚嶅墠缂�
-     */
-    private static final String[] TABLE_PREFIXS = new String[]{"tb_"};
-
-
-    public static void main(String[] args) {
-        AutoGenerator mpg = new AutoGenerator();
-
-        mpg.setDataSource(getDataSourceConfig());
-        // 灏佽闇�瑕佺敓鎴愮殑鏁版嵁搴撶殑鎵�鏈夌殑琛紝 濡傛灉鎯冲崟鐙寚瀹氳〃锛屽彲浠ユ敞閲�
-        getDbAllTables(getDataSourceConfig());
-
-        mpg.setGlobalConfig(getGlobalConfig());
-        mpg.setStrategy(getStrategyConfig());
-        mpg.setPackageInfo(getPackageConfig());
-        mpg.setCfg(getInjectionConfig());
-        // 閫夋嫨 freemarker 寮曟搸锛岄粯璁� Velocity
-        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
-        mpg.setTemplate(getTemplateConfig());
-        // 鎵ц鐢熸垚
-        mpg.execute();
-    }
-
-    /**
-     * 鑾峰彇鏁版嵁搴撲腑鐨勬墍鏈夌殑琛紝灏佽鍒版暟缁勶紝寰呯敓鎴愪唬鐮�
-     *
-     * @param dataSourceConfig
-     */
-    private static void getDbAllTables(DataSourceConfig dataSourceConfig) {
-
-        List<String> dbTables = new ArrayList<>();
-
-        Connection conn = dataSourceConfig.getConn();
-        try {
-            DatabaseMetaData metaData = conn.getMetaData();
-
-            ResultSet resultSet = metaData.getTables(null, null, null, new String[]{"TABLE"});
-
-            while (resultSet.next()) {
-                dbTables.add(resultSet.getString("TABLE_NAME"));
-            }
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-        if (dbTables.size() == 0) {
-            throw new RuntimeException("褰撳墠鏁版嵁搴撲笅鏃犺〃");
-        }
-
-        TABLES = dbTables.toArray(new String[dbTables.size()]);
-        System.out.println("鏁版嵁搴撹〃锛�");
-        System.out.println(dbTables);
-    }
-
-    /**
-     * 鏁版嵁婧愰厤缃�
-     *
-     * @return
-     */
-    private static DataSourceConfig getDataSourceConfig() {
-        DataSourceConfig dsc = new DataSourceConfig();
-        dsc.setDbType(DB_TYPE);
-        dsc.setDriverName(JDBC_DRIVER);
-        dsc.setUrl(JDBC_URL);
-        dsc.setUsername(JDBC_USERNAME);
-        dsc.setPassword(JDBC_PASSWORD);
-        return dsc;
-    }
-
-    /**
-     * 鍏ㄥ眬閰嶇疆
-     *
-     * @return
-     */
-    private static GlobalConfig getGlobalConfig() {
-        GlobalConfig gc = new GlobalConfig();
-        //鐢熸垚鍚庢槸鍚︽墦寮�璧勬簮绠$悊鍣�
-        gc.setOpen(false);
-        gc.setOutputDir(ROOT_DIR);
-        //閲嶆柊鐢熸垚鏃舵枃浠舵槸鍚﹁鐩�
-        gc.setFileOverride(true);
-        //AR 妯″紡
-        gc.setActiveRecord(false);
-        //涓婚敭绛栫暐
-        gc.setIdType(IdType.AUTO);
-        //瀹氫箟鐢熸垚鐨勫疄浣撶被涓棩鏈熺被鍨�
-        gc.setDateType(DateType.ONLY_DATE);
-        //寮�鍚疭wagger2妯″紡
-        gc.setSwagger2(true);
-        if (IS_DTO) {
-            gc.setEntityName("%sDTO");
-        }
-
-        // XML 浜岀骇缂撳瓨
-        gc.setEnableCache(false);
-        // XML ResultMap
-        gc.setBaseResultMap(true);
-        // XML columList
-        gc.setBaseColumnList(true);
-        gc.setAuthor(AUTHOR);
-        gc.setMapperName("%sMapper");
-        gc.setXmlName("%sMapper");
-        gc.setServiceName("%sService");
-        gc.setServiceImplName("%sServiceImpl");
-        gc.setControllerName("%sController");
-        return gc;
-    }
-
-    /**
-     * 鐢熸垚绛栫暐閰嶇疆
-     *
-     * @return
-     */
-    private static StrategyConfig getStrategyConfig() {
-        StrategyConfig strategy = new StrategyConfig();
-        // 姝ゅ鍙互淇敼涓烘偍鐨勮〃鍓嶇紑
-        strategy.setTablePrefix(TABLE_PREFIXS);
-        // 琛ㄥ悕鐢熸垚绛栫暐
-        strategy.setNaming(NamingStrategy.underline_to_camel);
-        // 闇�瑕佺敓鎴愮殑琛�
-        strategy.setInclude(TABLES);
-        // 鏋勫缓鑰呮ā鍨�
-        strategy.setChainModel(true);
-
-        // lombok 妯″瀷 @Accessors(chain = true) setter閾惧紡鎿嶄綔
-        strategy.setEntityLombokModel(true);
-        //restful api椋庢牸鎺у埗鍣�
-        strategy.setRestControllerStyle(true);
-        //url涓┘宄拌浆杩炲瓧绗�
-        strategy.setControllerMappingHyphenStyle(true);
-
-        return strategy;
-    }
-
-    /**
-     * 鐢熸垚鍖呭悕璁剧疆
-     *
-     * @return
-     */
-    private static PackageConfig getPackageConfig() {
-        // 4.鐢熸垚鏂囦欢鎵�鍦ㄥ寘閰嶇疆锛�
-        PackageConfig pc = new PackageConfig();
-//        pc.setModuleName(DB_NAME);
-        pc.setParent(PACKAGE_PARENT_NAME);
-        pc.setController(PACKAGE_CONTROLLER_NAME);
-        pc.setService(PACKAGE_SERVICE_NAME);
-        pc.setServiceImpl(PACKAGE_SERVICEIMPL_NAME);
-        pc.setEntity(PACKAGE_ENTITY_NAME);
-        pc.setMapper(PACKAGE_MAPPER_NAME);
-        return pc;
-    }
-
-    /**
-     * xml鏂囦欢閰嶇疆
-     *
-     * @return
-     */
-    private static InjectionConfig getInjectionConfig() {
-        InjectionConfig cfg = new InjectionConfig() {
-            @Override
-            public void initMap() {
-                Map<String, Object> map = new HashMap<String, Object>();
-                //map.put("abc", this.getConfig().getGlobalConfig().getAuthor() + "-rb");
-                this.setMap(map);
-            }
-        };
-        //xml鐢熸垚璺緞
-        List<FileOutConfig> focList = new ArrayList<>();
-        // 濡傛灉妯℃澘寮曟搸鏄� freemarker
-        //String templatePath = "/templates/mapper.xml.ftl";
-        // 濡傛灉妯℃澘寮曟搸鏄� velocity
-        // String templatePath = "/templates/mapper.xml.vm";
-        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
-            @Override
-            public String outputFile(TableInfo tableInfo) {
-                return RESOURCES_DIR + "/" + MAPPER_XML_PATH + "/" + tableInfo.getEntityName() + "Mapper.xml";
-            }
-        });
-
-        cfg.setFileOutConfigList(focList);
-
-        return cfg;
-    }
-
-    /**
-     * 鍏抽棴榛樿 xml 鐢熸垚
-     *
-     * @return
-     */
-    private static TemplateConfig getTemplateConfig() {
-        TemplateConfig tc = new TemplateConfig();
-//        tc.setXml(null);
-        return tc;
-    }
-}
-
diff --git a/ycl-generator/src/main/java/com/ycl/generator/config/GenConfig.java b/ycl-generator/src/main/java/com/ycl/generator/config/GenConfig.java
new file mode 100644
index 0000000..a2d2a0a
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/config/GenConfig.java
@@ -0,0 +1,73 @@
+package com.ycl.generator.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+/**
+ * 璇诲彇浠g爜鐢熸垚鐩稿叧閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "gen")
+@PropertySource(value = { "classpath:generator.yml" })
+public class GenConfig
+{
+    /** 浣滆�� */
+    public static String author;
+
+    /** 鐢熸垚鍖呰矾寰� */
+    public static String packageName;
+
+    /** 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸false */
+    public static boolean autoRemovePre;
+
+    /** 琛ㄥ墠缂�(绫诲悕涓嶄細鍖呭惈琛ㄥ墠缂�) */
+    public static String tablePrefix;
+
+    public static String getAuthor()
+    {
+        return author;
+    }
+
+    @Value("${author}")
+    public void setAuthor(String author)
+    {
+        GenConfig.author = author;
+    }
+
+    public static String getPackageName()
+    {
+        return packageName;
+    }
+
+    @Value("${packageName}")
+    public void setPackageName(String packageName)
+    {
+        GenConfig.packageName = packageName;
+    }
+
+    public static boolean getAutoRemovePre()
+    {
+        return autoRemovePre;
+    }
+
+    @Value("${autoRemovePre}")
+    public void setAutoRemovePre(boolean autoRemovePre)
+    {
+        GenConfig.autoRemovePre = autoRemovePre;
+    }
+
+    public static String getTablePrefix()
+    {
+        return tablePrefix;
+    }
+
+    @Value("${tablePrefix}")
+    public void setTablePrefix(String tablePrefix)
+    {
+        GenConfig.tablePrefix = tablePrefix;
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/controller/BaseController.java b/ycl-generator/src/main/java/com/ycl/generator/controller/BaseController.java
new file mode 100644
index 0000000..6049ea4
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/controller/BaseController.java
@@ -0,0 +1,203 @@
+package com.ycl.generator.controller;
+
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.ycl.generator.util.DateUtils;
+import com.ycl.generator.util.PageUtils;
+import com.ycl.generator.util.SecurityUtils;
+import com.ycl.generator.util.SqlUtil;
+import com.ycl.system.AjaxResult;
+import com.ycl.system.model.LoginUser;
+import com.ycl.system.page.PageDomain;
+import com.ycl.system.page.TableDataInfo;
+import com.ycl.system.page.TableSupport;
+import constant.HttpStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+import utils.StringUtils;
+
+import java.beans.PropertyEditorSupport;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * web灞傞�氱敤鏁版嵁澶勭悊
+ * 
+ * @author ruoyi
+ */
+public class BaseController
+{
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 灏嗗墠鍙颁紶閫掕繃鏉ョ殑鏃ユ湡鏍煎紡鐨勫瓧绗︿覆锛岃嚜鍔ㄨ浆鍖栦负Date绫诲瀷
+     */
+    @InitBinder
+    public void initBinder(WebDataBinder binder)
+    {
+        // Date 绫诲瀷杞崲
+        binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
+        {
+            @Override
+            public void setAsText(String text)
+            {
+                setValue(DateUtils.parseDate(text));
+            }
+        });
+    }
+
+    /**
+     * 璁剧疆璇锋眰鍒嗛〉鏁版嵁
+     */
+    protected void startPage()
+    {
+        PageUtils.startPage();
+    }
+
+    /**
+     * 璁剧疆璇锋眰鎺掑簭鏁版嵁
+     */
+    protected void startOrderBy()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
+        {
+            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+            PageHelper.orderBy(orderBy);
+        }
+    }
+
+    /**
+     * 娓呯悊鍒嗛〉鐨勭嚎绋嬪彉閲�
+     */
+    protected void clearPage()
+    {
+        PageUtils.clearPage();
+    }
+
+    /**
+     * 鍝嶅簲璇锋眰鍒嗛〉鏁版嵁
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected TableDataInfo getDataTable(List<?> list)
+    {
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("鏌ヨ鎴愬姛");
+        rspData.setRows(list);
+        rspData.setTotal(new PageInfo(list).getTotal());
+        return rspData;
+    }
+
+    /**
+     * 杩斿洖鎴愬姛
+     */
+    public AjaxResult success()
+    {
+        return AjaxResult.success();
+    }
+
+    /**
+     * 杩斿洖澶辫触娑堟伅
+     */
+    public AjaxResult error()
+    {
+        return AjaxResult.error();
+    }
+
+    /**
+     * 杩斿洖鎴愬姛娑堟伅
+     */
+    public AjaxResult success(String message)
+    {
+        return AjaxResult.success(message);
+    }
+    
+    /**
+     * 杩斿洖鎴愬姛娑堟伅
+     */
+    public AjaxResult success(Object data)
+    {
+        return AjaxResult.success(data);
+    }
+
+    /**
+     * 杩斿洖澶辫触娑堟伅
+     */
+    public AjaxResult error(String message)
+    {
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 杩斿洖璀﹀憡娑堟伅
+     */
+    public AjaxResult warn(String message)
+    {
+        return AjaxResult.warn(message);
+    }
+
+    /**
+     * 鍝嶅簲杩斿洖缁撴灉
+     * 
+     * @param rows 褰卞搷琛屾暟
+     * @return 鎿嶄綔缁撴灉
+     */
+    protected AjaxResult toAjax(int rows)
+    {
+        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
+    }
+
+    /**
+     * 鍝嶅簲杩斿洖缁撴灉
+     * 
+     * @param result 缁撴灉
+     * @return 鎿嶄綔缁撴灉
+     */
+    protected AjaxResult toAjax(boolean result)
+    {
+        return result ? success() : error();
+    }
+
+    /**
+     * 椤甸潰璺宠浆
+     */
+    public String redirect(String url)
+    {
+        return StringUtils.format("redirect:{}", url);
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛缂撳瓨淇℃伅
+     */
+    public LoginUser getLoginUser()
+    {
+        return SecurityUtils.getLoginUser();
+    }
+
+    /**
+     * 鑾峰彇鐧诲綍鐢ㄦ埛id
+     */
+    public Long getUserId()
+    {
+        return getLoginUser().getUserId();
+    }
+
+    /**
+     * 鑾峰彇鐧诲綍閮ㄩ棬id
+     */
+    public Long getDeptId()
+    {
+        return getLoginUser().getDeptId();
+    }
+
+    /**
+     * 鑾峰彇鐧诲綍鐢ㄦ埛鍚�
+     */
+    public String getUsername()
+    {
+        return getLoginUser().getUsername();
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/controller/GenController.java b/ycl-generator/src/main/java/com/ycl/generator/controller/GenController.java
new file mode 100644
index 0000000..b5f8060
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/controller/GenController.java
@@ -0,0 +1,207 @@
+package com.ycl.generator.controller;
+
+import annotation.Log;
+import com.ycl.generator.domain.GenTable;
+import com.ycl.generator.domain.GenTableColumn;
+import com.ycl.generator.service.IGenTableColumnService;
+import com.ycl.generator.service.IGenTableService;
+import com.ycl.system.AjaxResult;
+import com.ycl.system.page.TableDataInfo;
+import enumeration.BusinessType;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import utils.text.Convert;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浠g爜鐢熸垚 鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/tool/gen")
+public class GenController extends BaseController
+{
+    @Autowired
+    private IGenTableService genTableService;
+
+    @Autowired
+    private IGenTableColumnService genTableColumnService;
+
+    /**
+     * 鏌ヨ浠g爜鐢熸垚鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping("/list")
+    public TableDataInfo genList(GenTable genTable)
+    {
+        startPage();
+        List<GenTable> list = genTableService.selectGenTableList(genTable);
+        return getDataTable(list);
+    }
+
+    /**
+     * 淇敼浠g爜鐢熸垚涓氬姟
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:query')")
+    @GetMapping(value = "/{tableId}")
+    public AjaxResult getInfo(@PathVariable Long tableId)
+    {
+        GenTable table = genTableService.selectGenTableById(tableId);
+        List<GenTable> tables = genTableService.selectGenTableAll();
+        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("info", table);
+        map.put("rows", list);
+        map.put("tables", tables);
+        return success(map);
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁搴撳垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping("/db/list")
+    public TableDataInfo dataList(GenTable genTable)
+    {
+        startPage();
+        List<GenTable> list = genTableService.selectDbTableList(genTable);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏌ヨ鏁版嵁琛ㄥ瓧娈靛垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping(value = "/column/{tableId}")
+    public TableDataInfo columnList(Long tableId)
+    {
+        TableDataInfo dataInfo = new TableDataInfo();
+        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
+        dataInfo.setRows(list);
+        dataInfo.setTotal(list.size());
+        return dataInfo;
+    }
+
+    /**
+     * 瀵煎叆琛ㄧ粨鏋勶紙淇濆瓨锛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:import')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.IMPORT)
+    @PostMapping("/importTable")
+    public AjaxResult importTableSave(String tables)
+    {
+        String[] tableNames = Convert.toStrArray(tables);
+        // 鏌ヨ琛ㄤ俊鎭�
+        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
+        genTableService.importGenTable(tableList);
+        return success();
+    }
+
+    /**
+     * 淇敼淇濆瓨浠g爜鐢熸垚涓氬姟
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
+    {
+        genTableService.validateEdit(genTable);
+        genTableService.updateGenTable(genTable);
+        return success();
+    }
+
+    /**
+     * 鍒犻櫎浠g爜鐢熸垚
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{tableIds}")
+    public AjaxResult remove(@PathVariable Long[] tableIds)
+    {
+        genTableService.deleteGenTableByIds(tableIds);
+        return success();
+    }
+
+    /**
+     * 棰勮浠g爜
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
+    @GetMapping("/preview/{tableId}")
+    public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
+    {
+        Map<String, String> dataMap = genTableService.previewCode(tableId);
+        return success(dataMap);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/download/{tableName}")
+    public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
+    {
+        byte[] data = genTableService.downloadCode(tableName);
+        genCode(response, data);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/genCode/{tableName}")
+    public AjaxResult genCode(@PathVariable("tableName") String tableName)
+    {
+        genTableService.generatorCode(tableName);
+        return success();
+    }
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @GetMapping("/synchDb/{tableName}")
+    public AjaxResult synchDb(@PathVariable("tableName") String tableName)
+    {
+        genTableService.synchDb(tableName);
+        return success();
+    }
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+    @GetMapping("/batchGenCode")
+    public void batchGenCode(HttpServletResponse response, String tables) throws IOException
+    {
+        String[] tableNames = Convert.toStrArray(tables);
+        byte[] data = genTableService.downloadCode(tableNames);
+        genCode(response, data);
+    }
+
+    /**
+     * 鐢熸垚zip鏂囦欢
+     */
+    private void genCode(HttpServletResponse response, byte[] data) throws IOException
+    {
+        response.reset();
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
+        response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
+        response.addHeader("Content-Length", "" + data.length);
+        response.setContentType("application/octet-stream; charset=UTF-8");
+        IOUtils.write(data, response.getOutputStream());
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/domain/GenTable.java b/ycl-generator/src/main/java/com/ycl/generator/domain/GenTable.java
new file mode 100644
index 0000000..1e807d3
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/domain/GenTable.java
@@ -0,0 +1,373 @@
+package com.ycl.generator.domain;
+
+import com.ycl.system.entity.BaseEntity;
+import constant.GenConstants;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import org.apache.commons.lang3.ArrayUtils;
+import utils.StringUtils;
+
+import java.util.List;
+
+/**
+ * 涓氬姟琛� gen_table
+ *
+ * @author ruoyi
+ */
+public class GenTable extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 缂栧彿 */
+    private Long tableId;
+
+    /** 琛ㄥ悕绉� */
+    @NotBlank(message = "琛ㄥ悕绉颁笉鑳戒负绌�")
+    private String tableName;
+
+    /** 琛ㄦ弿杩� */
+    @NotBlank(message = "琛ㄦ弿杩颁笉鑳戒负绌�")
+    private String tableComment;
+
+    /** 鍏宠仈鐖惰〃鐨勮〃鍚� */
+    private String subTableName;
+
+    /** 鏈〃鍏宠仈鐖惰〃鐨勫閿悕 */
+    private String subTableFkName;
+
+    /** 瀹炰綋绫诲悕绉�(棣栧瓧姣嶅ぇ鍐�) */
+    @NotBlank(message = "瀹炰綋绫诲悕绉颁笉鑳戒负绌�")
+    private String className;
+
+    /** 浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔 sub涓诲瓙琛ㄦ搷浣滐級 */
+    private String tplCategory;
+
+    /** 鐢熸垚鍖呰矾寰� */
+    @NotBlank(message = "鐢熸垚鍖呰矾寰勪笉鑳戒负绌�")
+    private String packageName;
+
+    /** 鐢熸垚妯″潡鍚� */
+    @NotBlank(message = "鐢熸垚妯″潡鍚嶄笉鑳戒负绌�")
+    private String moduleName;
+
+    /** 鐢熸垚涓氬姟鍚� */
+    @NotBlank(message = "鐢熸垚涓氬姟鍚嶄笉鑳戒负绌�")
+    private String businessName;
+
+    /** 鐢熸垚鍔熻兘鍚� */
+    @NotBlank(message = "鐢熸垚鍔熻兘鍚嶄笉鑳戒负绌�")
+    private String functionName;
+
+    /** 鐢熸垚浣滆�� */
+    @NotBlank(message = "浣滆�呬笉鑳戒负绌�")
+    private String functionAuthor;
+
+    /** 鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級 */
+    private String genType;
+
+    /** 鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級 */
+    private String genPath;
+
+    /** 涓婚敭淇℃伅 */
+    private GenTableColumn pkColumn;
+
+    /** 瀛愯〃淇℃伅 */
+    private GenTable subTable;
+
+    /** 琛ㄥ垪淇℃伅 */
+    @Valid
+    private List<GenTableColumn> columns;
+
+    /** 鍏跺畠鐢熸垚閫夐」 */
+    private String options;
+
+    /** 鏍戠紪鐮佸瓧娈� */
+    private String treeCode;
+
+    /** 鏍戠埗缂栫爜瀛楁 */
+    private String treeParentCode;
+
+    /** 鏍戝悕绉板瓧娈� */
+    private String treeName;
+
+    /** 涓婄骇鑿滃崟ID瀛楁 */
+    private String parentMenuId;
+
+    /** 涓婄骇鑿滃崟鍚嶇О瀛楁 */
+    private String parentMenuName;
+
+    public Long getTableId()
+    {
+        return tableId;
+    }
+
+    public void setTableId(Long tableId)
+    {
+        this.tableId = tableId;
+    }
+
+    public String getTableName()
+    {
+        return tableName;
+    }
+
+    public void setTableName(String tableName)
+    {
+        this.tableName = tableName;
+    }
+
+    public String getTableComment()
+    {
+        return tableComment;
+    }
+
+    public void setTableComment(String tableComment)
+    {
+        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;
+    }
+
+    public void setClassName(String className)
+    {
+        this.className = className;
+    }
+
+    public String getTplCategory()
+    {
+        return tplCategory;
+    }
+
+    public void setTplCategory(String tplCategory)
+    {
+        this.tplCategory = tplCategory;
+    }
+
+    public String getPackageName()
+    {
+        return packageName;
+    }
+
+    public void setPackageName(String packageName)
+    {
+        this.packageName = packageName;
+    }
+
+    public String getModuleName()
+    {
+        return moduleName;
+    }
+
+    public void setModuleName(String moduleName)
+    {
+        this.moduleName = moduleName;
+    }
+
+    public String getBusinessName()
+    {
+        return businessName;
+    }
+
+    public void setBusinessName(String businessName)
+    {
+        this.businessName = businessName;
+    }
+
+    public String getFunctionName()
+    {
+        return functionName;
+    }
+
+    public void setFunctionName(String functionName)
+    {
+        this.functionName = functionName;
+    }
+
+    public String getFunctionAuthor()
+    {
+        return functionAuthor;
+    }
+
+    public void setFunctionAuthor(String functionAuthor)
+    {
+        this.functionAuthor = functionAuthor;
+    }
+
+    public String getGenType()
+    {
+        return genType;
+    }
+
+    public void setGenType(String genType)
+    {
+        this.genType = genType;
+    }
+
+    public String getGenPath()
+    {
+        return genPath;
+    }
+
+    public void setGenPath(String genPath)
+    {
+        this.genPath = genPath;
+    }
+
+    public GenTableColumn getPkColumn()
+    {
+        return pkColumn;
+    }
+
+    public void setPkColumn(GenTableColumn pkColumn)
+    {
+        this.pkColumn = pkColumn;
+    }
+
+    public GenTable getSubTable()
+    {
+        return subTable;
+    }
+
+    public void setSubTable(GenTable subTable)
+    {
+        this.subTable = subTable;
+    }
+
+    public List<GenTableColumn> getColumns()
+    {
+        return columns;
+    }
+
+    public void setColumns(List<GenTableColumn> columns)
+    {
+        this.columns = columns;
+    }
+
+    public String getOptions()
+    {
+        return options;
+    }
+
+    public void setOptions(String options)
+    {
+        this.options = options;
+    }
+
+    public String getTreeCode()
+    {
+        return treeCode;
+    }
+
+    public void setTreeCode(String treeCode)
+    {
+        this.treeCode = treeCode;
+    }
+
+    public String getTreeParentCode()
+    {
+        return treeParentCode;
+    }
+
+    public void setTreeParentCode(String treeParentCode)
+    {
+        this.treeParentCode = treeParentCode;
+    }
+
+    public String getTreeName()
+    {
+        return treeName;
+    }
+
+    public void setTreeName(String treeName)
+    {
+        this.treeName = treeName;
+    }
+
+    public String getParentMenuId()
+    {
+        return parentMenuId;
+    }
+
+    public void setParentMenuId(String parentMenuId)
+    {
+        this.parentMenuId = parentMenuId;
+    }
+
+    public String getParentMenuName()
+    {
+        return parentMenuName;
+    }
+
+    public void setParentMenuName(String parentMenuName)
+    {
+        this.parentMenuName = parentMenuName;
+    }
+
+    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);
+    }
+
+    public static boolean isTree(String tplCategory)
+    {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
+    }
+
+    public boolean isCrud()
+    {
+        return isCrud(this.tplCategory);
+    }
+
+    public static boolean isCrud(String tplCategory)
+    {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
+    }
+
+    public boolean isSuperColumn(String javaField)
+    {
+        return isSuperColumn(this.tplCategory, javaField);
+    }
+
+    public static boolean isSuperColumn(String tplCategory, String javaField)
+    {
+        if (isTree(tplCategory))
+        {
+            return StringUtils.equalsAnyIgnoreCase(javaField,
+                    ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY));
+        }
+        return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/domain/GenTableColumn.java b/ycl-generator/src/main/java/com/ycl/generator/domain/GenTableColumn.java
new file mode 100644
index 0000000..cb66384
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/domain/GenTableColumn.java
@@ -0,0 +1,373 @@
+package com.ycl.generator.domain;
+
+import com.ycl.system.entity.BaseEntity;
+import jakarta.validation.constraints.NotBlank;
+import utils.StringUtils;
+
+/**
+ * 浠g爜鐢熸垚涓氬姟瀛楁琛� gen_table_column
+ * 
+ * @author ruoyi
+ */
+public class GenTableColumn extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 缂栧彿 */
+    private Long columnId;
+
+    /** 褰掑睘琛ㄧ紪鍙� */
+    private Long tableId;
+
+    /** 鍒楀悕绉� */
+    private String columnName;
+
+    /** 鍒楁弿杩� */
+    private String columnComment;
+
+    /** 鍒楃被鍨� */
+    private String columnType;
+
+    /** JAVA绫诲瀷 */
+    private String javaType;
+
+    /** JAVA瀛楁鍚� */
+    @NotBlank(message = "Java灞炴�т笉鑳戒负绌�")
+    private String javaField;
+
+    /** 鏄惁涓婚敭锛�1鏄級 */
+    private String isPk;
+
+    /** 鏄惁鑷锛�1鏄級 */
+    private String isIncrement;
+
+    /** 鏄惁蹇呭~锛�1鏄級 */
+    private String isRequired;
+
+    /** 鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級 */
+    private String isInsert;
+
+    /** 鏄惁缂栬緫瀛楁锛�1鏄級 */
+    private String isEdit;
+
+    /** 鏄惁鍒楄〃瀛楁锛�1鏄級 */
+    private String isList;
+
+    /** 鏄惁鏌ヨ瀛楁锛�1鏄級 */
+    private String isQuery;
+
+    /** 鏌ヨ鏂瑰紡锛圗Q绛変簬銆丯E涓嶇瓑浜庛�丟T澶т簬銆丩T灏忎簬銆丩IKE妯$硦銆丅ETWEEN鑼冨洿锛� */
+    private String queryType;
+
+    /** 鏄剧ず绫诲瀷锛坕nput鏂囨湰妗嗐�乼extarea鏂囨湰鍩熴�乻elect涓嬫媺妗嗐�乧heckbox澶嶉�夋銆乺adio鍗曢�夋銆乨atetime鏃ユ湡鎺т欢銆乮mage鍥剧墖涓婁紶鎺т欢銆乽pload鏂囦欢涓婁紶鎺т欢銆乪ditor瀵屾枃鏈帶浠讹級 */
+    private String htmlType;
+
+    /** 瀛楀吀绫诲瀷 */
+    private String dictType;
+
+    /** 鎺掑簭 */
+    private Integer sort;
+
+    public void setColumnId(Long columnId)
+    {
+        this.columnId = columnId;
+    }
+
+    public Long getColumnId()
+    {
+        return columnId;
+    }
+
+    public void setTableId(Long tableId)
+    {
+        this.tableId = tableId;
+    }
+
+    public Long getTableId()
+    {
+        return tableId;
+    }
+
+    public void setColumnName(String columnName)
+    {
+        this.columnName = columnName;
+    }
+
+    public String getColumnName()
+    {
+        return columnName;
+    }
+
+    public void setColumnComment(String columnComment)
+    {
+        this.columnComment = columnComment;
+    }
+
+    public String getColumnComment()
+    {
+        return columnComment;
+    }
+
+    public void setColumnType(String columnType)
+    {
+        this.columnType = columnType;
+    }
+
+    public String getColumnType()
+    {
+        return columnType;
+    }
+
+    public void setJavaType(String javaType)
+    {
+        this.javaType = javaType;
+    }
+
+    public String getJavaType()
+    {
+        return javaType;
+    }
+
+    public void setJavaField(String javaField)
+    {
+        this.javaField = javaField;
+    }
+
+    public String getJavaField()
+    {
+        return javaField;
+    }
+
+    public String getCapJavaField()
+    {
+        return StringUtils.capitalize(javaField);
+    }
+
+    public void setIsPk(String isPk)
+    {
+        this.isPk = isPk;
+    }
+
+    public String getIsPk()
+    {
+        return isPk;
+    }
+
+    public boolean isPk()
+    {
+        return isPk(this.isPk);
+    }
+
+    public boolean isPk(String isPk)
+    {
+        return isPk != null && StringUtils.equals("1", isPk);
+    }
+
+    public String getIsIncrement()
+    {
+        return isIncrement;
+    }
+
+    public void setIsIncrement(String isIncrement)
+    {
+        this.isIncrement = isIncrement;
+    }
+
+    public boolean isIncrement()
+    {
+        return isIncrement(this.isIncrement);
+    }
+
+    public boolean isIncrement(String isIncrement)
+    {
+        return isIncrement != null && StringUtils.equals("1", isIncrement);
+    }
+
+    public void setIsRequired(String isRequired)
+    {
+        this.isRequired = isRequired;
+    }
+
+    public String getIsRequired()
+    {
+        return isRequired;
+    }
+
+    public boolean isRequired()
+    {
+        return isRequired(this.isRequired);
+    }
+
+    public boolean isRequired(String isRequired)
+    {
+        return isRequired != null && StringUtils.equals("1", isRequired);
+    }
+
+    public void setIsInsert(String isInsert)
+    {
+        this.isInsert = isInsert;
+    }
+
+    public String getIsInsert()
+    {
+        return isInsert;
+    }
+
+    public boolean isInsert()
+    {
+        return isInsert(this.isInsert);
+    }
+
+    public boolean isInsert(String isInsert)
+    {
+        return isInsert != null && StringUtils.equals("1", isInsert);
+    }
+
+    public void setIsEdit(String isEdit)
+    {
+        this.isEdit = isEdit;
+    }
+
+    public String getIsEdit()
+    {
+        return isEdit;
+    }
+
+    public boolean isEdit()
+    {
+        return isInsert(this.isEdit);
+    }
+
+    public boolean isEdit(String isEdit)
+    {
+        return isEdit != null && StringUtils.equals("1", isEdit);
+    }
+
+    public void setIsList(String isList)
+    {
+        this.isList = isList;
+    }
+
+    public String getIsList()
+    {
+        return isList;
+    }
+
+    public boolean isList()
+    {
+        return isList(this.isList);
+    }
+
+    public boolean isList(String isList)
+    {
+        return isList != null && StringUtils.equals("1", isList);
+    }
+
+    public void setIsQuery(String isQuery)
+    {
+        this.isQuery = isQuery;
+    }
+
+    public String getIsQuery()
+    {
+        return isQuery;
+    }
+
+    public boolean isQuery()
+    {
+        return isQuery(this.isQuery);
+    }
+
+    public boolean isQuery(String isQuery)
+    {
+        return isQuery != null && StringUtils.equals("1", isQuery);
+    }
+
+    public void setQueryType(String queryType)
+    {
+        this.queryType = queryType;
+    }
+
+    public String getQueryType()
+    {
+        return queryType;
+    }
+
+    public String getHtmlType()
+    {
+        return htmlType;
+    }
+
+    public void setHtmlType(String htmlType)
+    {
+        this.htmlType = htmlType;
+    }
+
+    public void setDictType(String dictType)
+    {
+        this.dictType = dictType;
+    }
+
+    public String getDictType()
+    {
+        return dictType;
+    }
+
+    public void setSort(Integer sort)
+    {
+        this.sort = sort;
+    }
+
+    public Integer getSort()
+    {
+        return sort;
+    }
+
+    public boolean isSuperColumn()
+    {
+        return isSuperColumn(this.javaField);
+    }
+
+    public static boolean isSuperColumn(String javaField)
+    {
+        return StringUtils.equalsAnyIgnoreCase(javaField,
+                // BaseEntity
+                "createBy", "createTime", "updateBy", "updateTime", "remark",
+                // TreeEntity
+                "parentName", "parentId", "orderNum", "ancestors");
+    }
+
+    public boolean isUsableColumn()
+    {
+        return isUsableColumn(javaField);
+    }
+
+    public static boolean isUsableColumn(String javaField)
+    {
+        // isSuperColumn()涓殑鍚嶅崟鐢ㄤ簬閬垮厤鐢熸垚澶氫綑Domain灞炴�э紝鑻ユ煇浜涘睘鎬у湪鐢熸垚椤甸潰鏃堕渶瑕佺敤鍒颁笉鑳藉拷鐣ワ紝鍒欐斁鍦ㄦ澶勭櫧鍚嶅崟
+        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
+    }
+
+    public String readConverterExp()
+    {
+        String remarks = StringUtils.substringBetween(this.columnComment, "锛�", "锛�");
+        StringBuffer sb = new StringBuffer();
+        if (StringUtils.isNotEmpty(remarks))
+        {
+            for (String value : remarks.split(" "))
+            {
+                if (StringUtils.isNotEmpty(value))
+                {
+                    Object startStr = value.subSequence(0, 1);
+                    String endStr = value.substring(1);
+                    sb.append("").append(startStr).append("=").append(endStr).append(",");
+                }
+            }
+            return sb.deleteCharAt(sb.length() - 1).toString();
+        }
+        else
+        {
+            return this.columnComment;
+        }
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/exception/ServiceException.java b/ycl-generator/src/main/java/com/ycl/generator/exception/ServiceException.java
new file mode 100644
index 0000000..c8b2a7c
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/exception/ServiceException.java
@@ -0,0 +1,74 @@
+package com.ycl.generator.exception;
+
+/**
+ * 涓氬姟寮傚父
+ * 
+ * @author ruoyi
+ */
+public final class ServiceException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 閿欒鐮�
+     */
+    private Integer code;
+
+    /**
+     * 閿欒鎻愮ず
+     */
+    private String message;
+
+    /**
+     * 閿欒鏄庣粏锛屽唴閮ㄨ皟璇曢敊璇�
+     *
+     * 鍜� {@link CommonResult#getDetailMessage()} 涓�鑷寸殑璁捐
+     */
+    private String detailMessage;
+
+    /**
+     * 绌烘瀯閫犳柟娉曪紝閬垮厤鍙嶅簭鍒楀寲闂
+     */
+    public ServiceException()
+    {
+    }
+
+    public ServiceException(String message)
+    {
+        this.message = message;
+    }
+
+    public ServiceException(String message, Integer code)
+    {
+        this.message = message;
+        this.code = code;
+    }
+
+    public String getDetailMessage()
+    {
+        return detailMessage;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+
+    public ServiceException setMessage(String message)
+    {
+        this.message = message;
+        return this;
+    }
+
+    public ServiceException setDetailMessage(String detailMessage)
+    {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+}
\ No newline at end of file
diff --git a/ycl-generator/src/main/java/com/ycl/generator/exception/UtilException.java b/ycl-generator/src/main/java/com/ycl/generator/exception/UtilException.java
new file mode 100644
index 0000000..0f300f6
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/exception/UtilException.java
@@ -0,0 +1,26 @@
+package com.ycl.generator.exception;
+
+/**
+ * 宸ュ叿绫诲紓甯�
+ * 
+ * @author ruoyi
+ */
+public class UtilException extends RuntimeException
+{
+    private static final long serialVersionUID = 8247610319171014183L;
+
+    public UtilException(Throwable e)
+    {
+        super(e.getMessage(), e);
+    }
+
+    public UtilException(String message)
+    {
+        super(message);
+    }
+
+    public UtilException(String message, Throwable throwable)
+    {
+        super(message, throwable);
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableColumnMapper.java b/ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableColumnMapper.java
new file mode 100644
index 0000000..ed12dd3
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableColumnMapper.java
@@ -0,0 +1,60 @@
+package com.ycl.generator.mapper;
+
+import java.util.List;
+import com.ycl.generator.domain.GenTableColumn;
+
+/**
+ * 涓氬姟瀛楁 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface GenTableColumnMapper
+{
+    /**
+     * 鏍规嵁琛ㄥ悕绉版煡璇㈠垪淇℃伅
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 鍒椾俊鎭�
+     */
+    public List<GenTableColumn> selectDbTableColumnsByName(String tableName);
+
+    /**
+     * 鏌ヨ涓氬姟瀛楁鍒楄〃
+     * 
+     * @param tableId 涓氬姟瀛楁缂栧彿
+     * @return 涓氬姟瀛楁闆嗗悎
+     */
+    public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
+
+    /**
+     * 鏂板涓氬姟瀛楁
+     * 
+     * @param genTableColumn 涓氬姟瀛楁淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 淇敼涓氬姟瀛楁
+     * 
+     * @param genTableColumn 涓氬姟瀛楁淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 鍒犻櫎涓氬姟瀛楁
+     * 
+     * @param genTableColumns 鍒楁暟鎹�
+     * @return 缁撴灉
+     */
+    public int deleteGenTableColumns(List<GenTableColumn> genTableColumns);
+
+    /**
+     * 鎵归噺鍒犻櫎涓氬姟瀛楁
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteGenTableColumnByIds(Long[] ids);
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableMapper.java b/ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableMapper.java
new file mode 100644
index 0000000..757a424
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/mapper/GenTableMapper.java
@@ -0,0 +1,83 @@
+package com.ycl.generator.mapper;
+
+import java.util.List;
+import com.ycl.generator.domain.GenTable;
+
+/**
+ * 涓氬姟 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface GenTableMapper
+{
+    /**
+     * 鏌ヨ涓氬姟鍒楄〃
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 涓氬姟闆嗗悎
+     */
+    public List<GenTable> selectGenTableList(GenTable genTable);
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    public List<GenTable> selectDbTableList(GenTable genTable);
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     * 
+     * @param tableNames 琛ㄥ悕绉扮粍
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    public List<GenTable> selectDbTableListByNames(String[] tableNames);
+
+    /**
+     * 鏌ヨ鎵�鏈夎〃淇℃伅
+     * 
+     * @return 琛ㄤ俊鎭泦鍚�
+     */
+    public List<GenTable> selectGenTableAll();
+
+    /**
+     * 鏌ヨ琛↖D涓氬姟淇℃伅
+     * 
+     * @param id 涓氬姟ID
+     * @return 涓氬姟淇℃伅
+     */
+    public GenTable selectGenTableById(Long id);
+
+    /**
+     * 鏌ヨ琛ㄥ悕绉颁笟鍔′俊鎭�
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 涓氬姟淇℃伅
+     */
+    public GenTable selectGenTableByName(String tableName);
+
+    /**
+     * 鏂板涓氬姟
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertGenTable(GenTable genTable);
+
+    /**
+     * 淇敼涓氬姟
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateGenTable(GenTable genTable);
+
+    /**
+     * 鎵归噺鍒犻櫎涓氬姟
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteGenTableByIds(Long[] ids);
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/service/GenTableColumnServiceImpl.java b/ycl-generator/src/main/java/com/ycl/generator/service/GenTableColumnServiceImpl.java
new file mode 100644
index 0000000..efc66b8
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/service/GenTableColumnServiceImpl.java
@@ -0,0 +1,69 @@
+package com.ycl.generator.service;
+
+import com.ycl.generator.domain.GenTableColumn;
+import com.ycl.generator.mapper.GenTableColumnMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import utils.text.Convert;
+
+import java.util.List;
+
+/**
+ * 涓氬姟瀛楁 鏈嶅姟灞傚疄鐜�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class GenTableColumnServiceImpl implements IGenTableColumnService 
+{
+	@Autowired
+	private GenTableColumnMapper genTableColumnMapper;
+
+	/**
+     * 鏌ヨ涓氬姟瀛楁鍒楄〃
+     * 
+     * @param tableId 涓氬姟瀛楁缂栧彿
+     * @return 涓氬姟瀛楁闆嗗悎
+     */
+	@Override
+	public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId)
+	{
+	    return genTableColumnMapper.selectGenTableColumnListByTableId(tableId);
+	}
+	
+    /**
+     * 鏂板涓氬姟瀛楁
+     * 
+     * @param genTableColumn 涓氬姟瀛楁淇℃伅
+     * @return 缁撴灉
+     */
+	@Override
+	public int insertGenTableColumn(GenTableColumn genTableColumn)
+	{
+	    return genTableColumnMapper.insertGenTableColumn(genTableColumn);
+	}
+	
+	/**
+     * 淇敼涓氬姟瀛楁
+     * 
+     * @param genTableColumn 涓氬姟瀛楁淇℃伅
+     * @return 缁撴灉
+     */
+	@Override
+	public int updateGenTableColumn(GenTableColumn genTableColumn)
+	{
+	    return genTableColumnMapper.updateGenTableColumn(genTableColumn);
+	}
+
+	/**
+     * 鍒犻櫎涓氬姟瀛楁瀵硅薄
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+	@Override
+	public int deleteGenTableColumnByIds(String ids)
+	{
+		return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));
+	}
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/service/GenTableServiceImpl.java b/ycl-generator/src/main/java/com/ycl/generator/service/GenTableServiceImpl.java
new file mode 100644
index 0000000..b93a708
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/service/GenTableServiceImpl.java
@@ -0,0 +1,522 @@
+package com.ycl.generator.service;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.ycl.generator.domain.GenTable;
+import com.ycl.generator.domain.GenTableColumn;
+import com.ycl.generator.exception.ServiceException;
+import com.ycl.generator.mapper.GenTableColumnMapper;
+import com.ycl.generator.mapper.GenTableMapper;
+import com.ycl.generator.util.GenUtils;
+import com.ycl.generator.util.SecurityUtils;
+import com.ycl.generator.util.VelocityInitializer;
+import com.ycl.generator.util.VelocityUtils;
+import constant.Constants;
+import constant.GenConstants;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import utils.StringUtils;
+import utils.text.CharsetKit;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * 涓氬姟 鏈嶅姟灞傚疄鐜�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class GenTableServiceImpl implements IGenTableService
+{
+    private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);
+
+    @Autowired
+    private GenTableMapper genTableMapper;
+
+    @Autowired
+    private GenTableColumnMapper genTableColumnMapper;
+
+    /**
+     * 鏌ヨ涓氬姟淇℃伅
+     * 
+     * @param id 涓氬姟ID
+     * @return 涓氬姟淇℃伅
+     */
+    @Override
+    public GenTable selectGenTableById(Long id)
+    {
+        GenTable genTable = genTableMapper.selectGenTableById(id);
+        setTableFromOptions(genTable);
+        return genTable;
+    }
+
+    /**
+     * 鏌ヨ涓氬姟鍒楄〃
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 涓氬姟闆嗗悎
+     */
+    @Override
+    public List<GenTable> selectGenTableList(GenTable genTable)
+    {
+        return genTableMapper.selectGenTableList(genTable);
+    }
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    @Override
+    public List<GenTable> selectDbTableList(GenTable genTable)
+    {
+        return genTableMapper.selectDbTableList(genTable);
+    }
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     * 
+     * @param tableNames 琛ㄥ悕绉扮粍
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    @Override
+    public List<GenTable> selectDbTableListByNames(String[] tableNames)
+    {
+        return genTableMapper.selectDbTableListByNames(tableNames);
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夎〃淇℃伅
+     * 
+     * @return 琛ㄤ俊鎭泦鍚�
+     */
+    @Override
+    public List<GenTable> selectGenTableAll()
+    {
+        return genTableMapper.selectGenTableAll();
+    }
+
+    /**
+     * 淇敼涓氬姟
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public void updateGenTable(GenTable genTable)
+    {
+        String options = JSON.toJSONString(genTable.getParams());
+        genTable.setOptions(options);
+        int row = genTableMapper.updateGenTable(genTable);
+        if (row > 0)
+        {
+            for (GenTableColumn cenTableColumn : genTable.getColumns())
+            {
+                genTableColumnMapper.updateGenTableColumn(cenTableColumn);
+            }
+        }
+    }
+
+    /**
+     * 鍒犻櫎涓氬姟瀵硅薄
+     * 
+     * @param tableIds 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public void deleteGenTableByIds(Long[] tableIds)
+    {
+        genTableMapper.deleteGenTableByIds(tableIds);
+        genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
+    }
+
+    /**
+     * 瀵煎叆琛ㄧ粨鏋�
+     * 
+     * @param tableList 瀵煎叆琛ㄥ垪琛�
+     */
+    @Override
+    @Transactional
+    public void importGenTable(List<GenTable> tableList)
+    {
+        String operName = SecurityUtils.getUsername();
+        try
+        {
+            for (GenTable table : tableList)
+            {
+                String tableName = table.getTableName();
+                GenUtils.initTable(table, operName);
+                int row = genTableMapper.insertGenTable(table);
+                if (row > 0)
+                {
+                    // 淇濆瓨鍒椾俊鎭�
+                    List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+                    for (GenTableColumn column : genTableColumns)
+                    {
+                        GenUtils.initColumnField(column, table);
+                        genTableColumnMapper.insertGenTableColumn(column);
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("瀵煎叆澶辫触锛�" + e.getMessage());
+        }
+    }
+
+    /**
+     * 棰勮浠g爜
+     * 
+     * @param tableId 琛ㄧ紪鍙�
+     * @return 棰勮鏁版嵁鍒楄〃
+     */
+    @Override
+    public Map<String, String> previewCode(Long tableId)
+    {
+        Map<String, String> dataMap = new LinkedHashMap<>();
+        // 鏌ヨ琛ㄤ俊鎭�
+        GenTable table = genTableMapper.selectGenTableById(tableId);
+        // 璁剧疆涓诲瓙琛ㄤ俊鎭�
+        setSubTable(table);
+        // 璁剧疆涓婚敭鍒椾俊鎭�
+        setPkColumn(table);
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 鑾峰彇妯℃澘鍒楄〃
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+        for (String template : templates)
+        {
+            // 娓叉煋妯℃澘
+            StringWriter sw = new StringWriter();
+            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+            tpl.merge(context, sw);
+            dataMap.put(template, sw.toString());
+        }
+        return dataMap;
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 鏁版嵁
+     */
+    @Override
+    public byte[] downloadCode(String tableName)
+    {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ZipOutputStream zip = new ZipOutputStream(outputStream);
+        generatorCode(tableName, zip);
+        IOUtils.closeQuietly(zip);
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     */
+    @Override
+    public void generatorCode(String tableName)
+    {
+        // 鏌ヨ琛ㄤ俊鎭�
+        GenTable table = genTableMapper.selectGenTableByName(tableName);
+        // 璁剧疆涓诲瓙琛ㄤ俊鎭�
+        setSubTable(table);
+        // 璁剧疆涓婚敭鍒椾俊鎭�
+        setPkColumn(table);
+
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 鑾峰彇妯℃澘鍒楄〃
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+        for (String template : templates)
+        {
+            if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
+            {
+                // 娓叉煋妯℃澘
+                StringWriter sw = new StringWriter();
+                Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+                tpl.merge(context, sw);
+                try
+                {
+                    String path = getGenPath(table, template);
+                    FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
+                }
+                catch (IOException e)
+                {
+                    throw new ServiceException("娓叉煋妯℃澘澶辫触锛岃〃鍚嶏細" + table.getTableName());
+                }
+            }
+        }
+    }
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     */
+    @Override
+    @Transactional
+    public void synchDb(String tableName)
+    {
+        GenTable table = genTableMapper.selectGenTableByName(tableName);
+        List<GenTableColumn> tableColumns = table.getColumns();
+        Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));
+
+        List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+        if (StringUtils.isEmpty(dbTableColumns))
+        {
+            throw new ServiceException("鍚屾鏁版嵁澶辫触锛屽師琛ㄧ粨鏋勪笉瀛樺湪");
+        }
+        List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
+
+        dbTableColumns.forEach(column -> {
+            GenUtils.initColumnField(column, table);
+            if (tableColumnMap.containsKey(column.getColumnName()))
+            {
+                GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
+                column.setColumnId(prevColumn.getColumnId());
+                if (column.isList())
+                {
+                    // 濡傛灉鏄垪琛紝缁х画淇濈暀鏌ヨ鏂瑰紡/瀛楀吀绫诲瀷閫夐」
+                    column.setDictType(prevColumn.getDictType());
+                    column.setQueryType(prevColumn.getQueryType());
+                }
+                if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
+                        && (column.isInsert() || column.isEdit())
+                        && ((column.isUsableColumn()) || (!column.isSuperColumn())))
+                {
+                    // 濡傛灉鏄�(鏂板/淇敼&闈炰富閿�/闈炲拷鐣ュ強鐖跺睘鎬�)锛岀户缁繚鐣欏繀濉�/鏄剧ず绫诲瀷閫夐」
+                    column.setIsRequired(prevColumn.getIsRequired());
+                    column.setHtmlType(prevColumn.getHtmlType());
+                }
+                genTableColumnMapper.updateGenTableColumn(column);
+            }
+            else
+            {
+                genTableColumnMapper.insertGenTableColumn(column);
+            }
+        });
+
+        List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
+        if (StringUtils.isNotEmpty(delColumns))
+        {
+            genTableColumnMapper.deleteGenTableColumns(delColumns);
+        }
+    }
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @param tableNames 琛ㄦ暟缁�
+     * @return 鏁版嵁
+     */
+    @Override
+    public byte[] downloadCode(String[] tableNames)
+    {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ZipOutputStream zip = new ZipOutputStream(outputStream);
+        for (String tableName : tableNames)
+        {
+            generatorCode(tableName, zip);
+        }
+        IOUtils.closeQuietly(zip);
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 鏌ヨ琛ㄤ俊鎭苟鐢熸垚浠g爜
+     */
+    private void generatorCode(String tableName, ZipOutputStream zip)
+    {
+        // 鏌ヨ琛ㄤ俊鎭�
+        GenTable table = genTableMapper.selectGenTableByName(tableName);
+        // 璁剧疆涓诲瓙琛ㄤ俊鎭�
+        setSubTable(table);
+        // 璁剧疆涓婚敭鍒椾俊鎭�
+        setPkColumn(table);
+
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 鑾峰彇妯℃澘鍒楄〃
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+        for (String template : templates)
+        {
+            // 娓叉煋妯℃澘
+            StringWriter sw = new StringWriter();
+            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+            tpl.merge(context, sw);
+            try
+            {
+                // 娣诲姞鍒皕ip
+                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
+                IOUtils.write(sw.toString(), zip, Constants.UTF8);
+                IOUtils.closeQuietly(sw);
+                zip.flush();
+                zip.closeEntry();
+            }
+            catch (IOException e)
+            {
+                log.error("娓叉煋妯℃澘澶辫触锛岃〃鍚嶏細" + table.getTableName(), e);
+            }
+        }
+    }
+
+    /**
+     * 淇敼淇濆瓨鍙傛暟鏍¢獙
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     */
+    @Override
+    public void validateEdit(GenTable genTable)
+    {
+        if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))
+        {
+            String options = JSON.toJSONString(genTable.getParams());
+            JSONObject paramsObj = JSON.parseObject(options);
+            if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))
+            {
+                throw new ServiceException("鏍戠紪鐮佸瓧娈典笉鑳戒负绌�");
+            }
+            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE)))
+            {
+                throw new ServiceException("鏍戠埗缂栫爜瀛楁涓嶈兘涓虹┖");
+            }
+            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME)))
+            {
+                throw new ServiceException("鏍戝悕绉板瓧娈典笉鑳戒负绌�");
+            }
+            else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
+            {
+                if (StringUtils.isEmpty(genTable.getSubTableName()))
+                {
+                    throw new ServiceException("鍏宠仈瀛愯〃鐨勮〃鍚嶄笉鑳戒负绌�");
+                }
+                else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
+                {
+                    throw new ServiceException("瀛愯〃鍏宠仈鐨勫閿悕涓嶈兘涓虹┖");
+                }
+            }
+        }
+    }
+
+    /**
+     * 璁剧疆涓婚敭鍒椾俊鎭�
+     * 
+     * @param table 涓氬姟琛ㄤ俊鎭�
+     */
+    public void setPkColumn(GenTable table)
+    {
+        for (GenTableColumn column : table.getColumns())
+        {
+            if (column.isPk())
+            {
+                table.setPkColumn(column);
+                break;
+            }
+        }
+        if (StringUtils.isNull(table.getPkColumn()))
+        {
+            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));
+        }
+    }
+
+    /**
+     * 璁剧疆浠g爜鐢熸垚鍏朵粬閫夐」鍊�
+     * 
+     * @param genTable 璁剧疆鍚庣殑鐢熸垚瀵硅薄
+     */
+    public void setTableFromOptions(GenTable genTable)
+    {
+        JSONObject paramsObj = JSON.parseObject(genTable.getOptions());
+        if (StringUtils.isNotNull(paramsObj))
+        {
+            String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
+            String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
+            String treeName = paramsObj.getString(GenConstants.TREE_NAME);
+            String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID);
+            String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
+
+            genTable.setTreeCode(treeCode);
+            genTable.setTreeParentCode(treeParentCode);
+            genTable.setTreeName(treeName);
+            genTable.setParentMenuId(parentMenuId);
+            genTable.setParentMenuName(parentMenuName);
+        }
+    }
+
+    /**
+     * 鑾峰彇浠g爜鐢熸垚鍦板潃
+     * 
+     * @param table 涓氬姟琛ㄤ俊鎭�
+     * @param template 妯℃澘鏂囦欢璺緞
+     * @return 鐢熸垚鍦板潃
+     */
+    public static String getGenPath(GenTable table, String template)
+    {
+        String genPath = table.getGenPath();
+        if (StringUtils.equals(genPath, "/"))
+        {
+            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
+        }
+        return genPath + File.separator + VelocityUtils.getFileName(template, table);
+    }
+}
\ No newline at end of file
diff --git a/ycl-generator/src/main/java/com/ycl/generator/service/IGenTableColumnService.java b/ycl-generator/src/main/java/com/ycl/generator/service/IGenTableColumnService.java
new file mode 100644
index 0000000..2d66f8f
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/service/IGenTableColumnService.java
@@ -0,0 +1,44 @@
+package com.ycl.generator.service;
+
+import java.util.List;
+import com.ycl.generator.domain.GenTableColumn;
+
+/**
+ * 涓氬姟瀛楁 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface IGenTableColumnService
+{
+    /**
+     * 鏌ヨ涓氬姟瀛楁鍒楄〃
+     * 
+     * @param tableId 涓氬姟瀛楁缂栧彿
+     * @return 涓氬姟瀛楁闆嗗悎
+     */
+    public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
+
+    /**
+     * 鏂板涓氬姟瀛楁
+     * 
+     * @param genTableColumn 涓氬姟瀛楁淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 淇敼涓氬姟瀛楁
+     * 
+     * @param genTableColumn 涓氬姟瀛楁淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 鍒犻櫎涓氬姟瀛楁淇℃伅
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteGenTableColumnByIds(String ids);
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/service/IGenTableService.java b/ycl-generator/src/main/java/com/ycl/generator/service/IGenTableService.java
new file mode 100644
index 0000000..ed9aaaf
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/service/IGenTableService.java
@@ -0,0 +1,121 @@
+package com.ycl.generator.service;
+
+import java.util.List;
+import java.util.Map;
+import com.ycl.generator.domain.GenTable;
+
+/**
+ * 涓氬姟 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface IGenTableService
+{
+    /**
+     * 鏌ヨ涓氬姟鍒楄〃
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 涓氬姟闆嗗悎
+     */
+    public List<GenTable> selectGenTableList(GenTable genTable);
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    public List<GenTable> selectDbTableList(GenTable genTable);
+
+    /**
+     * 鏌ヨ鎹簱鍒楄〃
+     * 
+     * @param tableNames 琛ㄥ悕绉扮粍
+     * @return 鏁版嵁搴撹〃闆嗗悎
+     */
+    public List<GenTable> selectDbTableListByNames(String[] tableNames);
+
+    /**
+     * 鏌ヨ鎵�鏈夎〃淇℃伅
+     * 
+     * @return 琛ㄤ俊鎭泦鍚�
+     */
+    public List<GenTable> selectGenTableAll();
+
+    /**
+     * 鏌ヨ涓氬姟淇℃伅
+     * 
+     * @param id 涓氬姟ID
+     * @return 涓氬姟淇℃伅
+     */
+    public GenTable selectGenTableById(Long id);
+
+    /**
+     * 淇敼涓氬姟
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     * @return 缁撴灉
+     */
+    public void updateGenTable(GenTable genTable);
+
+    /**
+     * 鍒犻櫎涓氬姟淇℃伅
+     * 
+     * @param tableIds 闇�瑕佸垹闄ょ殑琛ㄦ暟鎹甀D
+     * @return 缁撴灉
+     */
+    public void deleteGenTableByIds(Long[] tableIds);
+
+    /**
+     * 瀵煎叆琛ㄧ粨鏋�
+     * 
+     * @param tableList 瀵煎叆琛ㄥ垪琛�
+     */
+    public void importGenTable(List<GenTable> tableList);
+
+    /**
+     * 棰勮浠g爜
+     * 
+     * @param tableId 琛ㄧ紪鍙�
+     * @return 棰勮鏁版嵁鍒楄〃
+     */
+    public Map<String, String> previewCode(Long tableId);
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 鏁版嵁
+     */
+    public byte[] downloadCode(String tableName);
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 鏁版嵁
+     */
+    public void generatorCode(String tableName);
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     */
+    public void synchDb(String tableName);
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @param tableNames 琛ㄦ暟缁�
+     * @return 鏁版嵁
+     */
+    public byte[] downloadCode(String[] tableNames);
+
+    /**
+     * 淇敼淇濆瓨鍙傛暟鏍¢獙
+     * 
+     * @param genTable 涓氬姟淇℃伅
+     */
+    public void validateEdit(GenTable genTable);
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/util/DateUtils.java b/ycl-generator/src/main/java/com/ycl/generator/util/DateUtils.java
new file mode 100644
index 0000000..46c492d
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/util/DateUtils.java
@@ -0,0 +1,188 @@
+package com.ycl.generator.util;
+
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.util.Date;
+
+/**
+ * 鏃堕棿宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils
+{
+    public static String YYYY = "yyyy";
+
+    public static String YYYY_MM = "yyyy-MM";
+
+    public static String YYYY_MM_DD = "yyyy-MM-dd";
+
+    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+
+    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+
+    private static String[] parsePatterns = {
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", 
+            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+    /**
+     * 鑾峰彇褰撳墠Date鍨嬫棩鏈�
+     * 
+     * @return Date() 褰撳墠鏃ユ湡
+     */
+    public static Date getNowDate()
+    {
+        return new Date();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡, 榛樿鏍煎紡涓簓yyy-MM-dd
+     * 
+     * @return String
+     */
+    public static String getDate()
+    {
+        return dateTimeNow(YYYY_MM_DD);
+    }
+
+    public static final String getTime()
+    {
+        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
+    }
+
+    public static final String dateTimeNow()
+    {
+        return dateTimeNow(YYYYMMDDHHMMSS);
+    }
+
+    public static final String dateTimeNow(final String format)
+    {
+        return parseDateToStr(format, new Date());
+    }
+
+    public static final String dateTime(final Date date)
+    {
+        return parseDateToStr(YYYY_MM_DD, date);
+    }
+
+    public static final String parseDateToStr(final String format, final Date date)
+    {
+        return new SimpleDateFormat(format).format(date);
+    }
+
+    public static final Date dateTime(final String format, final String ts)
+    {
+        try
+        {
+            return new SimpleDateFormat(format).parse(ts);
+        }
+        catch (ParseException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�2018/08/08
+     */
+    public static final String datePath()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyy/MM/dd");
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�20180808
+     */
+    public static final String dateTime()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyyMMdd");
+    }
+
+    /**
+     * 鏃ユ湡鍨嬪瓧绗︿覆杞寲涓烘棩鏈� 鏍煎紡
+     */
+    public static Date parseDate(Object str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        try
+        {
+            return parseDate(str.toString(), parsePatterns);
+        }
+        catch (ParseException e)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * 鑾峰彇鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂�
+     */
+    public static Date getServerStartDate()
+    {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 璁$畻鐩稿樊澶╂暟
+     */
+    public static int differentDaysByMillisecond(Date date1, Date date2)
+    {
+        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
+    }
+
+    /**
+     * 璁$畻鏃堕棿宸�
+     *
+     * @param endDate 鏈�鍚庢椂闂�
+     * @param startTime 寮�濮嬫椂闂�
+     * @return 鏃堕棿宸紙澶�/灏忔椂/鍒嗛挓锛�
+     */
+    public static String timeDistance(Date endDate, Date startTime)
+    {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // long ns = 1000;
+        // 鑾峰緱涓や釜鏃堕棿鐨勬绉掓椂闂村樊寮�
+        long diff = endDate.getTime() - startTime.getTime();
+        // 璁$畻宸灏戝ぉ
+        long day = diff / nd;
+        // 璁$畻宸灏戝皬鏃�
+        long hour = diff % nd / nh;
+        // 璁$畻宸灏戝垎閽�
+        long min = diff % nd % nh / nm;
+        // 璁$畻宸灏戠//杈撳嚭缁撴灉
+        // long sec = diff % nd % nh % nm / ns;
+        return day + "澶�" + hour + "灏忔椂" + min + "鍒嗛挓";
+    }
+
+    /**
+     * 澧炲姞 LocalDateTime ==> Date
+     */
+    public static Date toDate(LocalDateTime temporalAccessor)
+    {
+        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+
+    /**
+     * 澧炲姞 LocalDate ==> Date
+     */
+    public static Date toDate(LocalDate temporalAccessor)
+    {
+        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
+        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/util/GenUtils.java b/ycl-generator/src/main/java/com/ycl/generator/util/GenUtils.java
new file mode 100644
index 0000000..a923808
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/util/GenUtils.java
@@ -0,0 +1,258 @@
+package com.ycl.generator.util;
+
+import com.ycl.generator.config.GenConfig;
+import com.ycl.generator.domain.GenTable;
+import com.ycl.generator.domain.GenTableColumn;
+import constant.GenConstants;
+import org.apache.commons.lang3.RegExUtils;
+import utils.StringUtils;
+
+import java.util.Arrays;
+
+/**
+ * 浠g爜鐢熸垚鍣� 宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class GenUtils
+{
+    /**
+     * 鍒濆鍖栬〃淇℃伅
+     */
+    public static void initTable(GenTable genTable, String operName)
+    {
+        genTable.setClassName(convertClassName(genTable.getTableName()));
+        genTable.setPackageName(GenConfig.getPackageName());
+        genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
+        genTable.setBusinessName(getBusinessName(genTable.getTableName()));
+        genTable.setFunctionName(replaceText(genTable.getTableComment()));
+        genTable.setFunctionAuthor(GenConfig.getAuthor());
+        genTable.setCreateBy(operName);
+    }
+
+    /**
+     * 鍒濆鍖栧垪灞炴�у瓧娈�
+     */
+    public static void initColumnField(GenTableColumn column, GenTable table)
+    {
+        String dataType = getDbType(column.getColumnType());
+        String columnName = column.getColumnName();
+        column.setTableId(table.getTableId());
+        column.setCreateBy(table.getCreateBy());
+        // 璁剧疆java瀛楁鍚�
+        column.setJavaField(StringUtils.toCamelCase(columnName));
+        // 璁剧疆榛樿绫诲瀷
+        column.setJavaType(GenConstants.TYPE_STRING);
+        column.setQueryType(GenConstants.QUERY_EQ);
+
+        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;
+            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);
+
+            // 濡傛灉鏄诞鐐瑰瀷 缁熶竴鐢˙igDecimal
+            String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
+            if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
+            {
+                column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
+            }
+            // 濡傛灉鏄暣褰�
+            else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)
+            {
+                column.setJavaType(GenConstants.TYPE_INTEGER);
+            }
+            // 闀挎暣褰�
+            else
+            {
+                column.setJavaType(GenConstants.TYPE_LONG);
+            }
+        }
+
+        // 鎻掑叆瀛楁锛堥粯璁ゆ墍鏈夊瓧娈甸兘闇�瑕佹彃鍏ワ級
+        column.setIsInsert(GenConstants.REQUIRE);
+
+        // 缂栬緫瀛楁
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk())
+        {
+            column.setIsEdit(GenConstants.REQUIRE);
+        }
+        // 鍒楄〃瀛楁
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk())
+        {
+            column.setIsList(GenConstants.REQUIRE);
+        }
+        // 鏌ヨ瀛楁
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk())
+        {
+            column.setIsQuery(GenConstants.REQUIRE);
+        }
+
+        // 鏌ヨ瀛楁绫诲瀷
+        if (StringUtils.endsWithIgnoreCase(columnName, "name"))
+        {
+            column.setQueryType(GenConstants.QUERY_LIKE);
+        }
+        // 鐘舵�佸瓧娈佃缃崟閫夋
+        if (StringUtils.endsWithIgnoreCase(columnName, "status"))
+        {
+            column.setHtmlType(GenConstants.HTML_RADIO);
+        }
+        // 绫诲瀷&鎬у埆瀛楁璁剧疆涓嬫媺妗�
+        else if (StringUtils.endsWithIgnoreCase(columnName, "type")
+                || StringUtils.endsWithIgnoreCase(columnName, "sex"))
+        {
+            column.setHtmlType(GenConstants.HTML_SELECT);
+        }
+        // 鍥剧墖瀛楁璁剧疆鍥剧墖涓婁紶鎺т欢
+        else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
+        {
+            column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
+        }
+        // 鏂囦欢瀛楁璁剧疆鏂囦欢涓婁紶鎺т欢
+        else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
+        {
+            column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
+        }
+        // 鍐呭瀛楁璁剧疆瀵屾枃鏈帶浠�
+        else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
+        {
+            column.setHtmlType(GenConstants.HTML_EDITOR);
+        }
+    }
+
+    /**
+     * 鏍¢獙鏁扮粍鏄惁鍖呭惈鎸囧畾鍊�
+     * 
+     * @param arr 鏁扮粍
+     * @param targetValue 鍊�
+     * @return 鏄惁鍖呭惈
+     */
+    public static boolean arraysContains(String[] arr, String targetValue)
+    {
+        return Arrays.asList(arr).contains(targetValue);
+    }
+
+    /**
+     * 鑾峰彇妯″潡鍚�
+     * 
+     * @param packageName 鍖呭悕
+     * @return 妯″潡鍚�
+     */
+    public static String getModuleName(String packageName)
+    {
+        int lastIndex = packageName.lastIndexOf(".");
+        int nameLength = packageName.length();
+        return StringUtils.substring(packageName, lastIndex + 1, nameLength);
+    }
+
+    /**
+     * 鑾峰彇涓氬姟鍚�
+     * 
+     * @param tableName 琛ㄥ悕
+     * @return 涓氬姟鍚�
+     */
+    public static String getBusinessName(String tableName)
+    {
+        int lastIndex = tableName.lastIndexOf("_");
+        int nameLength = tableName.length();
+        return StringUtils.substring(tableName, lastIndex + 1, nameLength);
+    }
+
+    /**
+     * 琛ㄥ悕杞崲鎴怞ava绫诲悕
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 绫诲悕
+     */
+    public static String convertClassName(String tableName)
+    {
+        boolean autoRemovePre = GenConfig.getAutoRemovePre();
+        String tablePrefix = GenConfig.getTablePrefix();
+        if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))
+        {
+            String[] searchList = StringUtils.split(tablePrefix, ",");
+            tableName = replaceFirst(tableName, searchList);
+        }
+        return StringUtils.convertToCamelCase(tableName);
+    }
+
+    /**
+     * 鎵归噺鏇挎崲鍓嶇紑
+     * 
+     * @param replacementm 鏇挎崲鍊�
+     * @param searchList 鏇挎崲鍒楄〃
+     * @return
+     */
+    public static String replaceFirst(String replacementm, String[] searchList)
+    {
+        String text = replacementm;
+        for (String searchString : searchList)
+        {
+            if (replacementm.startsWith(searchString))
+            {
+                text = replacementm.replaceFirst(searchString, "");
+                break;
+            }
+        }
+        return text;
+    }
+
+    /**
+     * 鍏抽敭瀛楁浛鎹�
+     * 
+     * @param text 闇�瑕佽鏇挎崲鐨勫悕瀛�
+     * @return 鏇挎崲鍚庣殑鍚嶅瓧
+     */
+    public static String replaceText(String text)
+    {
+        return RegExUtils.replaceAll(text, "(?:琛▅鑻ヤ緷)", "");
+    }
+
+    /**
+     * 鑾峰彇鏁版嵁搴撶被鍨嬪瓧娈�
+     * 
+     * @param columnType 鍒楃被鍨�
+     * @return 鎴彇鍚庣殑鍒楃被鍨�
+     */
+    public static String getDbType(String columnType)
+    {
+        if (StringUtils.indexOf(columnType, "(") > 0)
+        {
+            return StringUtils.substringBefore(columnType, "(");
+        }
+        else
+        {
+            return columnType;
+        }
+    }
+
+    /**
+     * 鑾峰彇瀛楁闀垮害
+     * 
+     * @param columnType 鍒楃被鍨�
+     * @return 鎴彇鍚庣殑鍒楃被鍨�
+     */
+    public static Integer getColumnLength(String columnType)
+    {
+        if (StringUtils.indexOf(columnType, "(") > 0)
+        {
+            String length = StringUtils.substringBetween(columnType, "(", ")");
+            return Integer.valueOf(length);
+        }
+        else
+        {
+            return 0;
+        }
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/util/PageUtils.java b/ycl-generator/src/main/java/com/ycl/generator/util/PageUtils.java
new file mode 100644
index 0000000..9b71898
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/util/PageUtils.java
@@ -0,0 +1,34 @@
+package com.ycl.generator.util;
+
+import com.github.pagehelper.PageHelper;
+import com.ycl.system.page.PageDomain;
+import com.ycl.system.page.TableSupport;
+
+/**
+ * 鍒嗛〉宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class PageUtils extends PageHelper
+{
+    /**
+     * 璁剧疆璇锋眰鍒嗛〉鏁版嵁
+     */
+    public static void startPage()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+        String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+        Boolean reasonable = pageDomain.getReasonable();
+        PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
+    }
+
+    /**
+     * 娓呯悊鍒嗛〉鐨勭嚎绋嬪彉閲�
+     */
+    public static void clearPage()
+    {
+        PageHelper.clearPage();
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/util/SecurityUtils.java b/ycl-generator/src/main/java/com/ycl/generator/util/SecurityUtils.java
new file mode 100644
index 0000000..c2b3841
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/util/SecurityUtils.java
@@ -0,0 +1,181 @@
+package com.ycl.generator.util;
+
+
+import com.ycl.generator.exception.ServiceException;
+import com.ycl.system.entity.SysRole;
+import com.ycl.system.model.LoginUser;
+import constant.Constants;
+import constant.HttpStatus;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.util.PatternMatchUtils;
+import utils.StringUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 瀹夊叏鏈嶅姟宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class SecurityUtils
+{
+
+    /**
+     * 鐢ㄦ埛ID
+     **/
+    public static Long getUserId()
+    {
+        try
+        {
+            return getLoginUser().getUserId();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("鑾峰彇鐢ㄦ埛ID寮傚父", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬ID
+     **/
+    public static Long getDeptId()
+    {
+        try
+        {
+            return getLoginUser().getDeptId();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("鑾峰彇閮ㄩ棬ID寮傚父", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛璐︽埛
+     **/
+    public static String getUsername()
+    {
+        try
+        {
+            return getLoginUser().getUsername();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("鑾峰彇鐢ㄦ埛璐︽埛寮傚父", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛
+     **/
+    public static LoginUser getLoginUser()
+    {
+        try
+        {
+            return (LoginUser) getAuthentication().getPrincipal();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("鑾峰彇鐢ㄦ埛淇℃伅寮傚父", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇Authentication
+     */
+    public static Authentication getAuthentication()
+    {
+        return SecurityContextHolder.getContext().getAuthentication();
+    }
+
+    /**
+     * 鐢熸垚BCryptPasswordEncoder瀵嗙爜
+     *
+     * @param password 瀵嗙爜
+     * @return 鍔犲瘑瀛楃涓�
+     */
+    public static String encryptPassword(String password)
+    {
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        return passwordEncoder.encode(password);
+    }
+
+    /**
+     * 鍒ゆ柇瀵嗙爜鏄惁鐩稿悓
+     *
+     * @param rawPassword 鐪熷疄瀵嗙爜
+     * @param encodedPassword 鍔犲瘑鍚庡瓧绗�
+     * @return 缁撴灉
+     */
+    public static boolean matchesPassword(String rawPassword, String encodedPassword)
+    {
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        return passwordEncoder.matches(rawPassword, encodedPassword);
+    }
+
+    /**
+     * 鏄惁涓虹鐞嗗憳
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public static boolean isAdmin(Long userId)
+    {
+        return userId != null && 1L == userId;
+    }
+
+    /**
+     * 楠岃瘉鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
+     * 
+     * @param permission 鏉冮檺瀛楃涓�
+     * @return 鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
+     */
+    public static boolean hasPermi(String permission)
+    {
+        return hasPermi(getLoginUser().getPermissions(), permission);
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鍖呭惈鏉冮檺
+     * 
+     * @param authorities 鏉冮檺鍒楄〃
+     * @param permission 鏉冮檺瀛楃涓�
+     * @return 鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
+     */
+    public static boolean hasPermi(Collection<String> authorities, String permission)
+    {
+        return authorities.stream().filter(StringUtils::hasText)
+                .anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
+    }
+
+    /**
+     * 楠岃瘉鐢ㄦ埛鏄惁鎷ユ湁鏌愪釜瑙掕壊
+     * 
+     * @param role 瑙掕壊鏍囪瘑
+     * @return 鐢ㄦ埛鏄惁鍏峰鏌愯鑹�
+     */
+    public static boolean hasRole(String role)
+    {
+        List<SysRole> roleList = getLoginUser().getUser().getRoles();
+        Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
+        return hasRole(roles, role);
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鍖呭惈瑙掕壊
+     * 
+     * @param roles 瑙掕壊鍒楄〃
+     * @param role 瑙掕壊
+     * @return 鐢ㄦ埛鏄惁鍏峰鏌愯鑹叉潈闄�
+     */
+    public static boolean hasRole(Collection<String> roles, String role)
+    {
+        return roles.stream().filter(StringUtils::hasText)
+                .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
+    }
+
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/util/SqlUtil.java b/ycl-generator/src/main/java/com/ycl/generator/util/SqlUtil.java
new file mode 100644
index 0000000..e1b9bef
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/util/SqlUtil.java
@@ -0,0 +1,70 @@
+package com.ycl.generator.util;
+
+import com.ycl.generator.exception.UtilException;
+import utils.StringUtils;
+
+/**
+ * sql鎿嶄綔宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class SqlUtil
+{
+    /**
+     * 瀹氫箟甯哥敤鐨� sql鍏抽敭瀛�
+     */
+    public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()";
+
+    /**
+     * 浠呮敮鎸佸瓧姣嶃�佹暟瀛椼�佷笅鍒掔嚎銆佺┖鏍笺�侀�楀彿銆佸皬鏁扮偣锛堟敮鎸佸涓瓧娈垫帓搴忥級
+     */
+    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
+
+    /**
+     * 闄愬埗orderBy鏈�澶ч暱搴�
+     */
+    private static final int ORDER_BY_MAX_LENGTH = 500;
+
+    /**
+     * 妫�鏌ュ瓧绗︼紝闃叉娉ㄥ叆缁曡繃
+     */
+    public static String escapeOrderBySql(String value)
+    {
+        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
+        {
+            throw new UtilException("鍙傛暟涓嶇鍚堣鑼冿紝涓嶈兘杩涜鏌ヨ");
+        }
+        if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
+        {
+            throw new UtilException("鍙傛暟宸茶秴杩囨渶澶ч檺鍒讹紝涓嶈兘杩涜鏌ヨ");
+        }
+        return value;
+    }
+
+    /**
+     * 楠岃瘉 order by 璇硶鏄惁绗﹀悎瑙勮寖
+     */
+    public static boolean isValidOrderBySql(String value)
+    {
+        return value.matches(SQL_PATTERN);
+    }
+
+    /**
+     * SQL鍏抽敭瀛楁鏌�
+     */
+    public static void filterKeyword(String value)
+    {
+        if (StringUtils.isEmpty(value))
+        {
+            return;
+        }
+        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
+        for (String sqlKeyword : sqlKeywords)
+        {
+            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
+            {
+                throw new UtilException("鍙傛暟瀛樺湪SQL娉ㄥ叆椋庨櫓");
+            }
+        }
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/util/VelocityInitializer.java b/ycl-generator/src/main/java/com/ycl/generator/util/VelocityInitializer.java
new file mode 100644
index 0000000..1653a6a
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/util/VelocityInitializer.java
@@ -0,0 +1,35 @@
+package com.ycl.generator.util;
+
+import constant.Constants;
+import org.apache.velocity.app.Velocity;
+
+import java.util.Properties;
+
+/**
+ * VelocityEngine宸ュ巶
+ * 
+ * @author ruoyi
+ */
+public class VelocityInitializer
+{
+    /**
+     * 鍒濆鍖杤m鏂规硶
+     */
+    public static void initVelocity()
+    {
+        Properties p = new Properties();
+        try
+        {
+            // 鍔犺浇classpath鐩綍涓嬬殑vm鏂囦欢
+            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+            // 瀹氫箟瀛楃闆�
+            p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
+            // 鍒濆鍖朧elocity寮曟搸锛屾寚瀹氶厤缃甈roperties
+            Velocity.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/ycl-generator/src/main/java/com/ycl/generator/util/VelocityUtils.java b/ycl-generator/src/main/java/com/ycl/generator/util/VelocityUtils.java
new file mode 100644
index 0000000..8ba1ad6
--- /dev/null
+++ b/ycl-generator/src/main/java/com/ycl/generator/util/VelocityUtils.java
@@ -0,0 +1,402 @@
+package com.ycl.generator.util;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.ycl.generator.domain.GenTable;
+import com.ycl.generator.domain.GenTableColumn;
+import constant.GenConstants;
+import org.apache.velocity.VelocityContext;
+import utils.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 妯℃澘澶勭悊宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class VelocityUtils
+{
+    /** 椤圭洰绌洪棿璺緞 */
+    private static final String PROJECT_PATH = "main/java";
+
+    /** mybatis绌洪棿璺緞 */
+    private static final String MYBATIS_PATH = "main/resources/mapper";
+
+    /** 榛樿涓婄骇鑿滃崟锛岀郴缁熷伐鍏� */
+    private static final String DEFAULT_PARENT_MENU_ID = "3";
+
+    /**
+     * 璁剧疆妯℃澘鍙橀噺淇℃伅
+     *
+     * @return 妯℃澘鍒楄〃
+     */
+    public static VelocityContext prepareContext(GenTable genTable)
+    {
+        String moduleName = genTable.getModuleName();
+        String businessName = genTable.getBusinessName();
+        String packageName = genTable.getPackageName();
+        String tplCategory = genTable.getTplCategory();
+        String functionName = genTable.getFunctionName();
+
+        VelocityContext velocityContext = new VelocityContext();
+        velocityContext.put("tplCategory", genTable.getTplCategory());
+        velocityContext.put("tableName", genTable.getTableName());
+        velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "銆愯濉啓鍔熻兘鍚嶇О銆�");
+        velocityContext.put("ClassName", genTable.getClassName());
+        velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
+        velocityContext.put("moduleName", genTable.getModuleName());
+        velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
+        velocityContext.put("businessName", genTable.getBusinessName());
+        velocityContext.put("basePackage", getPackagePrefix(packageName));
+        velocityContext.put("packageName", packageName);
+        velocityContext.put("author", genTable.getFunctionAuthor());
+        velocityContext.put("datetime", DateUtils.getDate());
+        velocityContext.put("pkColumn", genTable.getPkColumn());
+        velocityContext.put("importList", getImportList(genTable));
+        velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
+        velocityContext.put("columns", genTable.getColumns());
+        velocityContext.put("table", genTable);
+        velocityContext.put("dicts", getDicts(genTable));
+        setMenuVelocityContext(velocityContext, genTable);
+        if (GenConstants.TPL_TREE.equals(tplCategory))
+        {
+            setTreeVelocityContext(velocityContext, genTable);
+        }
+        if (GenConstants.TPL_SUB.equals(tplCategory))
+        {
+            setSubVelocityContext(velocityContext, genTable);
+        }
+        return velocityContext;
+    }
+
+    public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
+    {
+        String options = genTable.getOptions();
+        JSONObject paramsObj = JSON.parseObject(options);
+        String parentMenuId = getParentMenuId(paramsObj);
+        context.put("parentMenuId", parentMenuId);
+    }
+
+    public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)
+    {
+        String options = genTable.getOptions();
+        JSONObject paramsObj = JSON.parseObject(options);
+        String treeCode = getTreecode(paramsObj);
+        String treeParentCode = getTreeParentCode(paramsObj);
+        String treeName = getTreeName(paramsObj);
+
+        context.put("treeCode", treeCode);
+        context.put("treeParentCode", treeParentCode);
+        context.put("treeName", treeName);
+        context.put("expandColumn", getExpandColumn(genTable));
+        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
+        {
+            context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE));
+        }
+        if (paramsObj.containsKey(GenConstants.TREE_NAME))
+        {
+            context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME));
+        }
+    }
+
+    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()));
+    }
+
+    /**
+     * 鑾峰彇妯℃澘淇℃伅
+     *
+     * @return 妯℃澘鍒楄〃
+     */
+    public static List<String> getTemplateList(String tplCategory)
+    {
+        List<String> templates = new ArrayList<String>();
+        templates.add("vm/java/domain.java.vm");
+        templates.add("vm/java/mapper.java.vm");
+        templates.add("vm/java/service.java.vm");
+        templates.add("vm/java/serviceImpl.java.vm");
+        templates.add("vm/java/controller.java.vm");
+        templates.add("vm/xml/mapper.xml.vm");
+        templates.add("vm/sql/sql.vm");
+        templates.add("vm/js/api.js.vm");
+        if (GenConstants.TPL_CRUD.equals(tplCategory))
+        {
+            templates.add("vm/vue/index.vue.vm");
+        }
+        else if (GenConstants.TPL_TREE.equals(tplCategory))
+        {
+            templates.add("vm/vue/index-tree.vue.vm");
+        }
+        else if (GenConstants.TPL_SUB.equals(tplCategory))
+        {
+            templates.add("vm/vue/index.vue.vm");
+            templates.add("vm/java/sub-domain.java.vm");
+        }
+        return templates;
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢鍚�
+     */
+    public static String getFileName(String template, GenTable genTable)
+    {
+        // 鏂囦欢鍚嶇О
+        String fileName = "";
+        // 鍖呰矾寰�
+        String packageName = genTable.getPackageName();
+        // 妯″潡鍚�
+        String moduleName = genTable.getModuleName();
+        // 澶у啓绫诲悕
+        String className = genTable.getClassName();
+        // 涓氬姟鍚嶇О
+        String businessName = genTable.getBusinessName();
+
+        String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
+        String mybatisPath = MYBATIS_PATH + "/" + moduleName;
+        String vuePath = "vue";
+
+        if (template.contains("domain.java.vm"))
+        {
+            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);
+        }
+        else if (template.contains("service.java.vm"))
+        {
+            fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
+        }
+        else if (template.contains("serviceImpl.java.vm"))
+        {
+            fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
+        }
+        else if (template.contains("controller.java.vm"))
+        {
+            fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
+        }
+        else if (template.contains("mapper.xml.vm"))
+        {
+            fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
+        }
+        else if (template.contains("sql.vm"))
+        {
+            fileName = businessName + "Menu.sql";
+        }
+        else if (template.contains("api.js.vm"))
+        {
+            fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName);
+        }
+        else if (template.contains("index.vue.vm"))
+        {
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+        }
+        else if (template.contains("index-tree.vue.vm"))
+        {
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+        }
+        return fileName;
+    }
+
+    /**
+     * 鑾峰彇鍖呭墠缂�
+     *
+     * @param packageName 鍖呭悕绉�
+     * @return 鍖呭墠缂�鍚嶇О
+     */
+    public static String getPackagePrefix(String packageName)
+    {
+        int lastIndex = packageName.lastIndexOf(".");
+        return StringUtils.substring(packageName, 0, lastIndex);
+    }
+
+    /**
+     * 鏍规嵁鍒楃被鍨嬭幏鍙栧鍏ュ寘
+     * 
+     * @param genTable 涓氬姟琛ㄥ璞�
+     * @return 杩斿洖闇�瑕佸鍏ョ殑鍖呭垪琛�
+     */
+    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()))
+            {
+                importList.add("java.util.Date");
+                importList.add("com.fasterxml.jackson.annotation.JsonFormat");
+            }
+            else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType()))
+            {
+                importList.add("java.math.BigDecimal");
+            }
+        }
+        return importList;
+    }
+
+    /**
+     * 鏍规嵁鍒楃被鍨嬭幏鍙栧瓧鍏哥粍
+     * 
+     * @param genTable 涓氬姟琛ㄥ璞�
+     * @return 杩斿洖瀛楀吀缁�
+     */
+    public static String getDicts(GenTable genTable)
+    {
+        List<GenTableColumn> columns = genTable.getColumns();
+        Set<String> dicts = new HashSet<String>();
+        addDicts(dicts, columns);
+        if (StringUtils.isNotNull(genTable.getSubTable()))
+        {
+            List<GenTableColumn> subColumns = genTable.getSubTable().getColumns();
+            addDicts(dicts, subColumns);
+        }
+        return StringUtils.join(dicts, ", ");
+    }
+
+    /**
+     * 娣诲姞瀛楀吀鍒楄〃
+     * 
+     * @param dicts 瀛楀吀鍒楄〃
+     * @param columns 鍒楅泦鍚�
+     */
+    public static void addDicts(Set<String> dicts, List<GenTableColumn> columns)
+    {
+        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 }))
+            {
+                dicts.add("'" + column.getDictType() + "'");
+            }
+        }
+    }
+
+    /**
+     * 鑾峰彇鏉冮檺鍓嶇紑
+     *
+     * @param moduleName 妯″潡鍚嶇О
+     * @param businessName 涓氬姟鍚嶇О
+     * @return 杩斿洖鏉冮檺鍓嶇紑
+     */
+    public static String getPermissionPrefix(String moduleName, String businessName)
+    {
+        return StringUtils.format("{}:{}", moduleName, businessName);
+    }
+
+    /**
+     * 鑾峰彇涓婄骇鑿滃崟ID瀛楁
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 涓婄骇鑿滃崟ID瀛楁
+     */
+    public static String getParentMenuId(JSONObject paramsObj)
+    {
+        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
+                && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID)))
+        {
+            return paramsObj.getString(GenConstants.PARENT_MENU_ID);
+        }
+        return DEFAULT_PARENT_MENU_ID;
+    }
+
+    /**
+     * 鑾峰彇鏍戠紪鐮�
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 鏍戠紪鐮�
+     */
+    public static String getTreecode(JSONObject paramsObj)
+    {
+        if (paramsObj.containsKey(GenConstants.TREE_CODE))
+        {
+            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 鑾峰彇鏍戠埗缂栫爜
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 鏍戠埗缂栫爜
+     */
+    public static String getTreeParentCode(JSONObject paramsObj)
+    {
+        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
+        {
+            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 鑾峰彇鏍戝悕绉�
+     *
+     * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+     * @return 鏍戝悕绉�
+     */
+    public static String getTreeName(JSONObject paramsObj)
+    {
+        if (paramsObj.containsKey(GenConstants.TREE_NAME))
+        {
+            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 鑾峰彇闇�瑕佸湪鍝竴鍒椾笂闈㈡樉绀哄睍寮�鎸夐挳
+     *
+     * @param genTable 涓氬姟琛ㄥ璞�
+     * @return 灞曞紑鎸夐挳鍒楀簭鍙�
+     */
+    public static int getExpandColumn(GenTable genTable)
+    {
+        String options = genTable.getOptions();
+        JSONObject paramsObj = JSON.parseObject(options);
+        String treeName = paramsObj.getString(GenConstants.TREE_NAME);
+        int num = 0;
+        for (GenTableColumn column : genTable.getColumns())
+        {
+            if (column.isList())
+            {
+                num++;
+                String columnName = column.getColumnName();
+                if (columnName.equals(treeName))
+                {
+                    break;
+                }
+            }
+        }
+        return num;
+    }
+}
diff --git a/ycl-generator/src/main/resources/generator.yml b/ycl-generator/src/main/resources/generator.yml
new file mode 100644
index 0000000..27511ce
--- /dev/null
+++ b/ycl-generator/src/main/resources/generator.yml
@@ -0,0 +1,10 @@
+# 浠g爜鐢熸垚
+gen: 
+  # 浣滆��
+  author: ruoyi
+  # 榛樿鐢熸垚鍖呰矾寰� system 闇�鏀规垚鑷繁鐨勬ā鍧楀悕绉� 濡� system monitor tool
+  packageName: com.ycl.system
+  # 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸false
+  autoRemovePre: false
+  # 琛ㄥ墠缂�锛堢敓鎴愮被鍚嶄笉浼氬寘鍚〃鍓嶇紑锛屽涓敤閫楀彿鍒嗛殧锛�
+  tablePrefix: sys_
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ycl-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
new file mode 100644
index 0000000..9963014
--- /dev/null
+++ b/ycl-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.generator.mapper.GenTableColumnMapper">
+
+    <resultMap type="GenTableColumn" id="GenTableColumnResult">
+        <id     property="columnId"       column="column_id"      />
+        <result property="tableId"        column="table_id"       />
+        <result property="columnName"     column="column_name"    />
+        <result property="columnComment"  column="column_comment" />
+        <result property="columnType"     column="column_type"    />
+        <result property="javaType"       column="java_type"      />
+        <result property="javaField"      column="java_field"     />
+        <result property="isPk"           column="is_pk"          />
+        <result property="isIncrement"    column="is_increment"   />
+        <result property="isRequired"     column="is_required"    />
+        <result property="isInsert"       column="is_insert"      />
+        <result property="isEdit"         column="is_edit"        />
+        <result property="isList"         column="is_list"        />
+        <result property="isQuery"        column="is_query"       />
+        <result property="queryType"      column="query_type"     />
+        <result property="htmlType"       column="html_type"      />
+        <result property="dictType"       column="dict_type"      />
+        <result property="sort"           column="sort"           />
+        <result property="createBy"       column="create_by"      />
+        <result property="createTime"     column="create_time"    />
+        <result property="updateBy"       column="update_by"      />
+        <result property="updateTime"     column="update_time"    />
+    </resultMap>
+
+	<sql id="selectGenTableColumnVo">
+        select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column
+    </sql>
+
+    <select id="selectGenTableColumnListByTableId" parameterType="Long" resultMap="GenTableColumnResult">
+        <include refid="selectGenTableColumnVo"/>
+        where table_id = #{tableId}
+        order by sort
+    </select>
+
+    <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
+		select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
+		from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
+		order by ordinal_position
+	</select>
+
+    <insert id="insertGenTableColumn" parameterType="GenTableColumn" useGeneratedKeys="true" keyProperty="columnId">
+        insert into gen_table_column (
+			<if test="tableId != null and tableId != ''">table_id,</if>
+			<if test="columnName != null and columnName != ''">column_name,</if>
+			<if test="columnComment != null and columnComment != ''">column_comment,</if>
+			<if test="columnType != null and columnType != ''">column_type,</if>
+			<if test="javaType != null and javaType != ''">java_type,</if>
+			<if test="javaField != null  and javaField != ''">java_field,</if>
+			<if test="isPk != null and isPk != ''">is_pk,</if>
+			<if test="isIncrement != null and isIncrement != ''">is_increment,</if>
+			<if test="isRequired != null and isRequired != ''">is_required,</if>
+			<if test="isInsert != null and isInsert != ''">is_insert,</if>
+			<if test="isEdit != null and isEdit != ''">is_edit,</if>
+			<if test="isList != null and isList != ''">is_list,</if>
+			<if test="isQuery != null and isQuery != ''">is_query,</if>
+			<if test="queryType != null and queryType != ''">query_type,</if>
+			<if test="htmlType != null and htmlType != ''">html_type,</if>
+			<if test="dictType != null and dictType != ''">dict_type,</if>
+			<if test="sort != null">sort,</if>
+			<if test="createBy != null and createBy != ''">create_by,</if>
+			create_time
+         )values(
+			<if test="tableId != null and tableId != ''">#{tableId},</if>
+			<if test="columnName != null and columnName != ''">#{columnName},</if>
+			<if test="columnComment != null and columnComment != ''">#{columnComment},</if>
+			<if test="columnType != null and columnType != ''">#{columnType},</if>
+			<if test="javaType != null and javaType != ''">#{javaType},</if>
+			<if test="javaField != null and javaField != ''">#{javaField},</if>
+			<if test="isPk != null and isPk != ''">#{isPk},</if>
+			<if test="isIncrement != null and isIncrement != ''">#{isIncrement},</if>
+			<if test="isRequired != null and isRequired != ''">#{isRequired},</if>
+			<if test="isInsert != null and isInsert != ''">#{isInsert},</if>
+			<if test="isEdit != null and isEdit != ''">#{isEdit},</if>
+			<if test="isList != null and isList != ''">#{isList},</if>
+			<if test="isQuery != null and isQuery != ''">#{isQuery},</if>
+			<if test="queryType != null and queryType != ''">#{queryType},</if>
+			<if test="htmlType != null and htmlType != ''">#{htmlType},</if>
+			<if test="dictType != null and dictType != ''">#{dictType},</if>
+			<if test="sort != null">#{sort},</if>
+			<if test="createBy != null and createBy != ''">#{createBy},</if>
+			sysdate()
+         )
+    </insert>
+
+    <update id="updateGenTableColumn" parameterType="GenTableColumn">
+        update gen_table_column
+        <set>
+            <if test="columnComment != null">column_comment = #{columnComment},</if>
+            <if test="javaType != null">java_type = #{javaType},</if>
+            <if test="javaField != null">java_field = #{javaField},</if>
+            <if test="isInsert != null">is_insert = #{isInsert},</if>
+            <if test="isEdit != null">is_edit = #{isEdit},</if>
+            <if test="isList != null">is_list = #{isList},</if>
+            <if test="isQuery != null">is_query = #{isQuery},</if>
+            <if test="isRequired != null">is_required = #{isRequired},</if>
+            <if test="queryType != null">query_type = #{queryType},</if>
+            <if test="htmlType != null">html_type = #{htmlType},</if>
+            <if test="dictType != null">dict_type = #{dictType},</if>
+            <if test="sort != null">sort = #{sort},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            update_time = sysdate()
+        </set>
+        where column_id = #{columnId}
+    </update>
+
+    <delete id="deleteGenTableColumnByIds" parameterType="Long">
+        delete from gen_table_column where table_id in
+        <foreach collection="array" item="tableId" open="(" separator="," close=")">
+            #{tableId}
+        </foreach>
+    </delete>
+
+    <delete id="deleteGenTableColumns">
+        delete from gen_table_column where column_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.columnId}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/ycl-generator/src/main/resources/mapper/generator/GenTableMapper.xml
new file mode 100644
index 0000000..6edb0c7
--- /dev/null
+++ b/ycl-generator/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ycl.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="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="genType"        column="gen_type"          />
+		<result property="genPath"        column="gen_path"          />
+		<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">
+        <id     property="columnId"       column="column_id"      />
+        <result property="tableId"        column="table_id"       />
+        <result property="columnName"     column="column_name"    />
+        <result property="columnComment"  column="column_comment" />
+        <result property="columnType"     column="column_type"    />
+        <result property="javaType"       column="java_type"      />
+        <result property="javaField"      column="java_field"     />
+        <result property="isPk"           column="is_pk"          />
+        <result property="isIncrement"    column="is_increment"   />
+        <result property="isRequired"     column="is_required"    />
+        <result property="isInsert"       column="is_insert"      />
+        <result property="isEdit"         column="is_edit"        />
+        <result property="isList"         column="is_list"        />
+        <result property="isQuery"        column="is_query"       />
+        <result property="queryType"      column="query_type"     />
+        <result property="htmlType"       column="html_type"      />
+        <result property="dictType"       column="dict_type"      />
+        <result property="sort"           column="sort"           />
+        <result property="createBy"       column="create_by"      />
+        <result property="createTime"     column="create_time"    />
+        <result property="updateBy"       column="update_by"      />
+        <result property="updateTime"     column="update_time"    />
+    </resultMap>
+	
+	<sql id="selectGenTableVo">
+        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, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
+    </sql>
+    
+    <select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
+		<include refid="selectGenTableVo"/>
+		<where>
+			<if test="tableName != null and tableName != ''">
+				AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
+			</if>
+			<if test="tableComment != null and tableComment != ''">
+				AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
+			</if>
+			<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+				AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+				AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+			</if>
+		</where>
+	</select>
+
+	<select id="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult">
+		select table_name, table_comment, create_time, update_time from information_schema.tables
+		where table_schema = (select database())
+		AND table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%'
+		AND table_name NOT IN (select table_name from gen_table)
+		<if test="tableName != null and tableName != ''">
+			AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
+		</if>
+		<if test="tableComment != null and tableComment != ''">
+			AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
+		</if>
+		<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+			AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+		</if>
+		<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+			AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+		</if>
+        order by create_time desc
+	</select>
+	
+	<select id="selectDbTableListByNames" resultMap="GenTableResult">
+		select table_name, table_comment, create_time, update_time from information_schema.tables
+		where table_name NOT LIKE 'qrtz_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
+		and table_name in
+	    <foreach collection="array" item="name" open="(" separator="," close=")">
+ 			#{name}
+        </foreach> 
+	</select>
+	
+	<select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
+		select table_name, table_comment, create_time, update_time from information_schema.tables
+		where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database())
+		and table_name = #{tableName}
+	</select>
+	
+	<select id="selectGenTableById" parameterType="Long" 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.gen_type, t.gen_path, 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_id = #{tableId} order by c.sort
+	</select>
+	
+	<select id="selectGenTableByName" 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.gen_type, t.gen_path, 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>
+			<if test="tableComment != null and tableComment != ''">table_comment,</if>
+			<if test="className != null and className != ''">class_name,</if>
+			<if test="tplCategory != null and tplCategory != ''">tpl_category,</if>
+			<if test="packageName != null and packageName != ''">package_name,</if>
+			<if test="moduleName != null and moduleName != ''">module_name,</if>
+			<if test="businessName != null and businessName != ''">business_name,</if>
+			<if test="functionName != null and functionName != ''">function_name,</if>
+			<if test="functionAuthor != null and functionAuthor != ''">function_author,</if>
+			<if test="genType != null and genType != ''">gen_type,</if>
+			<if test="genPath != null and genPath != ''">gen_path,</if>
+			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+			create_time
+         )values(
+			<if test="tableName != null">#{tableName},</if>
+			<if test="tableComment != null and tableComment != ''">#{tableComment},</if>
+			<if test="className != null and className != ''">#{className},</if>
+			<if test="tplCategory != null and tplCategory != ''">#{tplCategory},</if>
+			<if test="packageName != null and packageName != ''">#{packageName},</if>
+			<if test="moduleName != null and moduleName != ''">#{moduleName},</if>
+			<if test="businessName != null and businessName != ''">#{businessName},</if>
+			<if test="functionName != null and functionName != ''">#{functionName},</if>
+			<if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if>
+			<if test="genType != null and genType != ''">#{genType},</if>
+			<if test="genPath != null and genPath != ''">#{genPath},</if>
+			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+			sysdate()
+         )
+    </insert>
+    
+    <update id="updateGenTable" parameterType="GenTable">
+        update gen_table
+        <set>
+            <if test="tableName != null">table_name = #{tableName},</if>
+            <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if>
+            <if test="subTableName != null">sub_table_name = #{subTableName},</if>
+            <if test="subTableFkName != null">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="genType != null and genType != ''">gen_type = #{genType},</if>
+            <if test="genPath != null and genPath != ''">gen_path = #{genPath},</if>
+            <if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if>
+            <if test="packageName != null and packageName != ''">package_name = #{packageName},</if>
+            <if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if>
+            <if test="businessName != null and businessName != ''">business_name = #{businessName},</if>
+            <if test="functionName != null and functionName != ''">function_name = #{functionName},</if>
+            <if test="options != null and options != ''">options = #{options},</if>
+            <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            update_time = sysdate()
+        </set>
+        where table_id = #{tableId}
+    </update>
+    
+    <delete id="deleteGenTableByIds" parameterType="Long">
+        delete from gen_table where table_id in 
+        <foreach collection="array" item="tableId" open="(" separator="," close=")">
+            #{tableId}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/templates/controller.java.ftl b/ycl-generator/src/main/resources/templates/controller.java.ftl
deleted file mode 100644
index c420637..0000000
--- a/ycl-generator/src/main/resources/templates/controller.java.ftl
+++ /dev/null
@@ -1,44 +0,0 @@
-package ${package.Controller};
-
-import org.springframework.web.bind.annotation.RequestMapping;
-<#if restControllerStyle>
-import org.springframework.web.bind.annotation.RestController;
-<#else>
-import org.springframework.stereotype.Controller;
-</#if>
-<#if superControllerClassPackage??>
-import ${superControllerClassPackage};
-</#if>
-import ${package.Service}.${table.serviceName};
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * <p>
- * ${table.comment!} 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author ${author}
- */
-@Slf4j
-<#if restControllerStyle>
-@RestController
-<#else>
-@Controller
-</#if>
-<#if kotlin>
-class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
-<#else>
-<#if superControllerClass??>
-public class ${table.controllerName} extends ${superControllerClass} {
-<#else>
-@RequestMapping("${entity?uncap_first}")
-public class ${table.controllerName} {
-</#if>
-
-    @Autowired
-    private ${table.serviceName}  ${table.serviceName?uncap_first};
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/templates/default/controller.btl b/ycl-generator/src/main/resources/templates/default/controller.btl
deleted file mode 100644
index a7064ca..0000000
--- a/ycl-generator/src/main/resources/templates/default/controller.btl
+++ /dev/null
@@ -1,37 +0,0 @@
-package ${entity.controllerPackage};
-
-import cn.exrick.xboot.base.XbootBaseController;
-import cn.exrick.xboot.common.utils.PageUtil;
-import cn.exrick.xboot.common.utils.ResultUtil;
-import cn.exrick.xboot.common.vo.PageVo;
-import cn.exrick.xboot.common.vo.Result;
-import ${entity.entityPackage}.${entity.className};
-import ${entity.servicePackage}.${entity.className}Service;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.transaction.annotation.Transactional;
-
-
-/**
- * @author ${entity.author}
- */
-@Slf4j
-@RestController
-@Api(description = "${entity.description}绠$悊鎺ュ彛")
-@RequestMapping("/xboot/${entity.classNameLowerCase}")
-@Transactional
-public class ${entity.className}Controller extends XbootBaseController<${entity.className}, ${entity.primaryKeyType}>{
-
-    @Autowired
-    private ${entity.className}Service ${entity.classNameLowerCase}Service;
-
-    @Override
-    public ${entity.className}Service getService() {
-        return ${entity.classNameLowerCase}Service;
-    }
-
-}
diff --git a/ycl-generator/src/main/resources/templates/default/controller.java.btl b/ycl-generator/src/main/resources/templates/default/controller.java.btl
deleted file mode 100644
index 92b5afa..0000000
--- a/ycl-generator/src/main/resources/templates/default/controller.java.btl
+++ /dev/null
@@ -1,39 +0,0 @@
-package ${package.Controller};
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-<% if(restControllerStyle){ %>
-import org.springframework.web.bind.annotation.RestController;
-<% }else{ %>
-import org.springframework.stereotype.Controller;
-<% } %>
-<% if(isNotEmpty(superControllerClassPackage)){ %>
-import ${superControllerClassPackage};
-<% } %>
-
-/**
- * <p>
- * ${table.comment!} 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-<% if(restControllerStyle){ %>
-@RestController
-<% }else{ %>
-@Controller
-<% } %>
-@RequestMapping("<% if(isNotEmpty(package.ModuleName)){ %>/${package.ModuleName}<% } %>/<% if(isNotEmpty(controllerMappingHyphenStyle)){ %>${controllerMappingHyphen}<% }else{ %>${table.entityPath}<% } %>")
-<% if(kotlin){ %>
-class ${table.controllerName}<% if(isNotEmpty(superControllerClass)){ %> : ${superControllerClass}()<% } %>
-<% }else{ %>
-    <% if(isNotEmpty(superControllerClass)){ %>
-public class ${table.controllerName} extends ${superControllerClass} {
-    <% }else{ %>
-public class ${table.controllerName} {
-    <% } %>
-
-}
-<% } %>
diff --git a/ycl-generator/src/main/resources/templates/default/controller.java.ftl b/ycl-generator/src/main/resources/templates/default/controller.java.ftl
deleted file mode 100644
index 69a9f81..0000000
--- a/ycl-generator/src/main/resources/templates/default/controller.java.ftl
+++ /dev/null
@@ -1,39 +0,0 @@
-package ${package.Controller};
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-<#if restControllerStyle>
-import org.springframework.web.bind.annotation.RestController;
-<#else>
-import org.springframework.stereotype.Controller;
-</#if>
-<#if superControllerClassPackage??>
-import ${superControllerClassPackage};
-</#if>
-
-/**
- * <p>
- * ${table.comment!} 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-<#if restControllerStyle>
-@RestController
-<#else>
-@Controller
-</#if>
-@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
-<#if kotlin>
-class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
-<#else>
-<#if superControllerClass??>
-public class ${table.controllerName} extends ${superControllerClass} {
-<#else>
-public class ${table.controllerName} {
-</#if>
-
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/templates/default/controller.java.vm b/ycl-generator/src/main/resources/templates/default/controller.java.vm
deleted file mode 100644
index bbe5936..0000000
--- a/ycl-generator/src/main/resources/templates/default/controller.java.vm
+++ /dev/null
@@ -1,41 +0,0 @@
-package ${package.Controller};
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-#if(${restControllerStyle})
-import org.springframework.web.bind.annotation.RestController;
-#else
-import org.springframework.stereotype.Controller;
-#end
-#if(${superControllerClassPackage})
-import ${superControllerClassPackage};
-#end
-
-/**
- * <p>
- * $!{table.comment} 鍓嶇鎺у埗鍣�
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-#if(${restControllerStyle})
-@RestController
-#else
-@Controller
-#end
-@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
-#if(${kotlin})
-class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end
-
-#else
-#if(${superControllerClass})
-public class ${table.controllerName} extends ${superControllerClass} {
-#else
-public class ${table.controllerName} {
-#end
-
-}
-
-#end
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/templates/default/dao.btl b/ycl-generator/src/main/resources/templates/default/dao.btl
deleted file mode 100644
index 06772e2..0000000
--- a/ycl-generator/src/main/resources/templates/default/dao.btl
+++ /dev/null
@@ -1,14 +0,0 @@
-package ${entity.daoPackage};
-
-import cn.exrick.xboot.base.XbootBaseDao;
-import ${entity.entityPackage}.${entity.className};
-
-import java.util.List;
-
-/**
- * ${entity.description}鏁版嵁澶勭悊灞�
- * @author ${entity.author}
- */
-public interface ${entity.className}Dao extends XbootBaseDao<${entity.className},${entity.primaryKeyType}> {
-
-}
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/templates/default/entity.btl b/ycl-generator/src/main/resources/templates/default/entity.btl
deleted file mode 100644
index 6f79a22..0000000
--- a/ycl-generator/src/main/resources/templates/default/entity.btl
+++ /dev/null
@@ -1,24 +0,0 @@
-package ${entity.entityPackage};
-
-import cn.exrick.xboot.base.XbootBaseEntity;
-import com.baomidou.mybatisplus.annotations.TableName;
-import io.swagger.annotations.ApiModelProperty;
-import io.swagger.annotations.ApiModel;
-import lombok.Data;
-
-import javax.persistence.Entity;
-import javax.persistence.Table;
-
-/**
- * @author ${entity.author}
- */
-@Data
-@Entity
-@Table(name = "${entity.tableName}")
-@TableName("${entity.tableName}")
-@ApiModel(value = "${entity.description}")
-public class ${entity.className} extends XbootBaseEntity {
-
-    private static final long serialVersionUID = 1L;
-
-}
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/templates/default/entity.java.btl b/ycl-generator/src/main/resources/templates/default/entity.java.btl
deleted file mode 100644
index a9616c4..0000000
--- a/ycl-generator/src/main/resources/templates/default/entity.java.btl
+++ /dev/null
@@ -1,162 +0,0 @@
-package ${package.Entity};
-<% for(pkg in table.importPackages){ %>
-import ${pkg};
-<% } %>
-<% if(swagger2){ %>
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-<% } %>
-<% if(entityLombokModel){ %>
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.experimental.Accessors;
-<% } %>
-/**
- * <p>
- * ${table.comment!}
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-<% if(entityLombokModel){ %>
-@Data
-    <% if(isNotEmpty(superEntityClass)){ %>
-@EqualsAndHashCode(callSuper = true)
-    <% }else{ %>
-@EqualsAndHashCode(callSuper = false)
-    <% } %>
-@Accessors(chain = true)
-<% } %>
-<% if(table.convert){ %>
-@TableName("${table.name}")
-<% } %>
-<% if(swagger2){ %>
-@ApiModel(value="${entity}瀵硅薄", description="${table.comment!''}")
-<% } %>
-<% if(isNotEmpty(superEntityClass)){ %>
-public class ${entity} extends ${superEntityClass}<% if(activeRecord){ %><${entity}><%}%>{
-<% }else if(activeRecord){ %>
-public class ${entity} extends Model<${entity}> {
-<% }else{ %>
-public class ${entity} implements Serializable {
-<% } %>
-
-<% if(entitySerialVersionUID){ %>
-    private static final long serialVersionUID = 1L;
-<% } %>
-<% /** -----------BEGIN 瀛楁寰幆閬嶅巻----------- **/ %>
-<% for(field in table.fields){ %>
-    <%
-    if(field.keyFlag){
-        var keyPropertyName = field.propertyName;
-    }
-    %>
-
-    <% if(isNotEmpty(field.comment)){ %>
-        <% if(swagger2){ %>
-    @ApiModelProperty(value = "${field.comment}")
-        <% }else{ %>
-    /**
-     * ${field.comment}
-     */
-        <% } %>
-    <% } %>
-    <% if(field.keyFlag){ %>
-    <%
-    /*涓婚敭*/
-    %>
-        <% if(field.keyIdentityFlag){ %>
-    @TableId(value = "${field.name}", type = IdType.AUTO)
-        <% }else if(isNotEmpty(idType)){ %>
-    @TableId(value = "${field.name}", type = IdType.${idType})
-        <% }else if(field.convert){ %>
-    @TableId("${field.name}")
-         <% } %>
-    <%
-    /*鏅�氬瓧娈�*/
-    %>
-    <% }else if(isNotEmpty(field.fill)){ %>
-        <% if(field.convert){ %>
-    @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
-        <% }else{ %>
-    @TableField(fill = FieldFill.${field.fill})
-        <% } %>
-    <% }else if(field.convert){ %>
-    @TableField("${field.name}")
-    <% } %>
-    <%
-    /*涔愯閿佹敞瑙�*/
-    %>
-    <% if(versionFieldName!'' == field.name){ %>
-    @Version
-    <% } %>
-    <%
-    /*閫昏緫鍒犻櫎娉ㄨВ*/
-    %>
-    <% if(logicDeleteFieldName!'' == field.name){ %>
-    @TableLogic
-    <% } %>
-    private ${field.propertyType} ${field.propertyName};
-<% } %>
-<% /** -----------END 瀛楁寰幆閬嶅巻----------- **/ %>
-
-<% if(!entityLombokModel){ %>
-    <% for(field in table.fields){ %>
-        <%
-        var getprefix ='';
-        if(field.propertyType=='boolean'){
-            getprefix='is';
-        }else{
-            getprefix='get';
-        }
-        %>
-    public ${field.propertyType} ${getprefix}${field.capitalName}() {
-        return ${field.propertyName};
-    }
-
-        <% if(entityBuilderModel){ %>
-    public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-        <% }else{ %>
-    public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-        <% } %>
-        this.${field.propertyName} = ${field.propertyName};
-        <% if(entityBuilderModel){ %>
-        return this;
-        <% } %>
-    }
-
-    <% } %>
-<% } %>
-<% if(entityColumnConstant){ %>
-   <% for(field in table.fields){ %>
-    public static final String ${strutil.toUpperCase(field.name)} = "${field.name}";
-
-   <% } %>
-<% } %>
-<% if(activeRecord){ %>
-    @Override
-    protected Serializable pkVal() {
-    <% if(isNotEmpty(keyPropertyName)){ %>
-        return this.${keyPropertyName};
-    <% }else{ %>
-        return null;
-    <% } %>
-    }
-
-<% } %>
-<% if(!entityLombokModel){ %>
-    @Override
-    public String toString() {
-        return "${entity}{" +
-    <% for(field in table.fields){ %>
-       <% if(fieldLP.index==0){ %>
-        "${field.propertyName}=" + ${field.propertyName} +
-       <% }else{ %>
-        ", ${field.propertyName}=" + ${field.propertyName} +
-       <% } %>
-    <% } %>
-        "}";
-    }
-<% } %>
-}
diff --git a/ycl-generator/src/main/resources/templates/default/entity.java.ftl b/ycl-generator/src/main/resources/templates/default/entity.java.ftl
deleted file mode 100644
index e399243..0000000
--- a/ycl-generator/src/main/resources/templates/default/entity.java.ftl
+++ /dev/null
@@ -1,152 +0,0 @@
-package ${package.Entity};
-
-<#list table.importPackages as pkg>
-    import ${pkg};
-</#list>
-<#if swagger2>
-    import io.swagger.annotations.ApiModel;
-    import io.swagger.annotations.ApiModelProperty;
-</#if>
-<#if entityLombokModel>
-    import lombok.Data;
-    import lombok.EqualsAndHashCode;
-    import lombok.experimental.Accessors;
-</#if>
-
-/**
-* <p>
-    * ${table.comment!}
-    * </p>
-*
-* @author ${author}
-* @since ${date}
-*/
-<#if entityLombokModel>
-    @Data
-    <#if superEntityClass??>
-        @EqualsAndHashCode(callSuper = true)
-    <#else>
-        @EqualsAndHashCode(callSuper = false)
-    </#if>
-    @Accessors(chain = true)
-</#if>
-<#if table.convert>
-    @TableName("${table.name}")
-</#if>
-<#if swagger2>
-    @ApiModel(value="${entity}瀵硅薄", description="${table.comment!}")
-</#if>
-<#if superEntityClass??>
-    public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
-<#elseif activeRecord>
-    public class ${entity} extends Model<${entity}> {
-<#else>
-    public class ${entity} implements Serializable {
-</#if>
-
-<#if entitySerialVersionUID>
-    private static final long serialVersionUID = 1L;
-</#if>
-<#-- ----------  BEGIN 瀛楁寰幆閬嶅巻  ---------->
-<#list table.fields as field>
-    <#if field.keyFlag>
-        <#assign keyPropertyName="${field.propertyName}"/>
-    </#if>
-
-    <#if field.comment!?length gt 0>
-        <#if swagger2>
-            @ApiModelProperty(value = "${field.comment}")
-        <#else>
-            /**
-            * ${field.comment}
-            */
-        </#if>
-    </#if>
-    <#if field.keyFlag>
-    <#-- 涓婚敭 -->
-        <#if field.keyIdentityFlag>
-            @TableId(value = "${field.name}", type = IdType.AUTO)
-        <#elseif idType??>
-            @TableId(value = "${field.name}", type = IdType.${idType})
-        <#elseif field.convert>
-            @TableId("${field.name}")
-        </#if>
-    <#-- 鏅�氬瓧娈� -->
-    <#elseif field.fill??>
-    <#-- -----   瀛樺湪瀛楁濉厖璁剧疆   ----->
-        <#if field.convert>
-            @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
-        <#else>
-            @TableField(fill = FieldFill.${field.fill})
-        </#if>
-    <#elseif field.convert>
-        @TableField("${field.name}")
-    </#if>
-<#-- 涔愯閿佹敞瑙� -->
-    <#if (versionFieldName!"") == field.name>
-        @Version
-    </#if>
-<#-- 閫昏緫鍒犻櫎娉ㄨВ -->
-    <#if (logicDeleteFieldName!"") == field.name>
-        @TableLogic
-    </#if>
-    private ${field.propertyType} ${field.propertyName};
-</#list>
-<#------------  END 瀛楁寰幆閬嶅巻  ---------->
-
-<#if !entityLombokModel>
-    <#list table.fields as field>
-        <#if field.propertyType == "boolean">
-            <#assign getprefix="is"/>
-        <#else>
-            <#assign getprefix="get"/>
-        </#if>
-        public ${field.propertyType} ${getprefix}${field.capitalName}() {
-        return ${field.propertyName};
-        }
-
-        <#if entityBuilderModel>
-            public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-        <#else>
-            public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-        </#if>
-        this.${field.propertyName} = ${field.propertyName};
-        <#if entityBuilderModel>
-            return this;
-        </#if>
-        }
-    </#list>
-</#if>
-
-<#if entityColumnConstant>
-    <#list table.fields as field>
-        public static final String ${field.name?upper_case} = "${field.name}";
-
-    </#list>
-</#if>
-<#if activeRecord>
-    @Override
-    protected Serializable pkVal() {
-    <#if keyPropertyName??>
-        return this.${keyPropertyName};
-    <#else>
-        return null;
-    </#if>
-    }
-
-</#if>
-<#if !entityLombokModel>
-    @Override
-    public String toString() {
-    return "${entity}{" +
-    <#list table.fields as field>
-        <#if field_index==0>
-            "${field.propertyName}=" + ${field.propertyName} +
-        <#else>
-            ", ${field.propertyName}=" + ${field.propertyName} +
-        </#if>
-    </#list>
-    "}";
-    }
-</#if>
-}
diff --git a/ycl-generator/src/main/resources/templates/default/entity.java.vm b/ycl-generator/src/main/resources/templates/default/entity.java.vm
deleted file mode 100644
index 3b0e551..0000000
--- a/ycl-generator/src/main/resources/templates/default/entity.java.vm
+++ /dev/null
@@ -1,153 +0,0 @@
-package ${package.Entity};
-
-#foreach($pkg in ${table.importPackages})
-import ${pkg};
-#end
-#if(${swagger2})
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-#end
-#if(${entityLombokModel})
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.experimental.Accessors;
-#end
-
-/**
- * <p>
- * $!{table.comment}
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-#if(${entityLombokModel})
-@Data
-#if(${superEntityClass})
-@EqualsAndHashCode(callSuper = true)
-#else
-@EqualsAndHashCode(callSuper = false)
-#end
-@Accessors(chain = true)
-#end
-#if(${table.convert})
-@TableName("${table.name}")
-#end
-#if(${swagger2})
-@ApiModel(value="${entity}瀵硅薄", description="$!{table.comment}")
-#end
-#if(${superEntityClass})
-public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
-#elseif(${activeRecord})
-public class ${entity} extends Model<${entity}> {
-#else
-public class ${entity} implements Serializable {
-#end
-
-#if(${entitySerialVersionUID})
-private static final long serialVersionUID=1L;
-#end
-## ----------  BEGIN 瀛楁寰幆閬嶅巻  ----------
-#foreach($field in ${table.fields})
-
-#if(${field.keyFlag})
-#set($keyPropertyName=${field.propertyName})
-#end
-#if("$!field.comment" != "")
-#if(${swagger2})
-    @ApiModelProperty(value = "${field.comment}")
-#else
-    /**
-     * ${field.comment}
-     */
-#end
-#end
-#if(${field.keyFlag})
-## 涓婚敭
-#if(${field.keyIdentityFlag})
-    @TableId(value = "${field.name}", type = IdType.AUTO)
-#elseif(!$null.isNull(${idType}) && "$!idType" != "")
-    @TableId(value = "${field.name}", type = IdType.${idType})
-#elseif(${field.convert})
-    @TableId("${field.name}")
-#end
-## 鏅�氬瓧娈�
-#elseif(${field.fill})
-## -----   瀛樺湪瀛楁濉厖璁剧疆   -----
-#if(${field.convert})
-    @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
-#else
-    @TableField(fill = FieldFill.${field.fill})
-#end
-#elseif(${field.convert})
-    @TableField("${field.name}")
-#end
-## 涔愯閿佹敞瑙�
-#if(${versionFieldName}==${field.name})
-    @Version
-#end
-## 閫昏緫鍒犻櫎娉ㄨВ
-#if(${logicDeleteFieldName}==${field.name})
-    @TableLogic
-#end
-    private ${field.propertyType} ${field.propertyName};
-#end
-## ----------  END 瀛楁寰幆閬嶅巻  ----------
-
-#if(!${entityLombokModel})
-#foreach($field in ${table.fields})
-#if(${field.propertyType.equals("boolean")})
-#set($getprefix="is")
-#else
-#set($getprefix="get")
-#end
-
-    public ${field.propertyType} ${getprefix}${field.capitalName}() {
-        return ${field.propertyName};
-    }
-
-#if(${entityBuilderModel})
-    public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-#else
-    public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-#end
-        this.${field.propertyName} = ${field.propertyName};
-#if(${entityBuilderModel})
-        return this;
-#end
-    }
-#end
-#end
-
-#if(${entityColumnConstant})
-#foreach($field in ${table.fields})
-    public static final String ${field.name.toUpperCase()} = "${field.name}";
-
-#end
-#end
-#if(${activeRecord})
-    @Override
-    protected Serializable pkVal() {
-#if(${keyPropertyName})
-        return this.${keyPropertyName};
-#else
-        return null;
-#end
-    }
-
-#end
-#if(!${entityLombokModel})
-    @Override
-    public String toString() {
-        return "${entity}{" +
-#foreach($field in ${table.fields})
-#if($!{foreach.index}==0)
-        "${field.propertyName}=" + ${field.propertyName} +
-#else
-        ", ${field.propertyName}=" + ${field.propertyName} +
-#end
-#end
-        "}";
-    }
-#end
-}
diff --git a/ycl-generator/src/main/resources/templates/default/entity.kt.btl b/ycl-generator/src/main/resources/templates/default/entity.kt.btl
deleted file mode 100644
index 5b6f3e9..0000000
--- a/ycl-generator/src/main/resources/templates/default/entity.kt.btl
+++ /dev/null
@@ -1,124 +0,0 @@
-package ${package.Entity}
-<% for(pkg in table.importPackages){ %>
-import ${pkg}
-<% } %>
-<% if(swagger2){ %>
-import io.swagger.annotations.ApiModel
-import io.swagger.annotations.ApiModelProperty
-<% } %>
-/**
- * <p>
- * ${table.comment!}
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-<% if(table.convert){ %>
-@TableName("${table.name}")
-<% } %>
-<% if(swagger2){ %>
-@ApiModel(value="${entity}瀵硅薄", description="${table.comment!''}")
-<% } %>
-<% if(isNotEmpty(superEntityClass)){ %>
-class ${entity} : ${superEntityClass}<% if(activeRecord){ %><${entity}><%}%>{
-<% }else if(activeRecord){ %>
-class ${entity} : Model<${entity}> {
-<% }else{ %>
-class ${entity} : Serializable {
-<% } %>
-
-<% /** -----------BEGIN 瀛楁寰幆閬嶅巻----------- **/ %>
-<% for(field in table.fields){ %>
-    <%
-    if(field.keyFlag){
-        var keyPropertyName = field.propertyName;
-    }
-    %>
-
-    <% if(isNotEmpty(field.comment)){ %>
-        <% if(swagger2){ %>
-    @ApiModelProperty(value = "${field.comment}")
-        <% }else{ %>
-    /**
-     * ${field.comment}
-     */
-        <% } %>
-    <% } %>
-    <% if(field.keyFlag){ %>
-    <%
-    /*涓婚敭*/
-    %>
-        <% if(field.keyIdentityFlag){ %>
-    @TableId(value = "${field.name}", type = IdType.AUTO)
-        <% }else if(isNotEmpty(idType)){ %>
-    @TableId(value = "${field.name}", type = IdType.${idType})
-        <% }else if(field.convert){ %>
-    @TableId("${field.name}")
-         <% } %>
-    <%
-    /*鏅�氬瓧娈�*/
-    %>
-    <% }else if(isNotEmpty(field.fill)){ %>
-        <% if(field.convert){ %>
-    @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
-        <% }else{ %>
-    @TableField(fill = FieldFill.${field.fill})
-        <% } %>
-    <% }else if(field.convert){ %>
-    @TableField("${field.name}")
-    <% } %>
-    <%
-    /*涔愯閿佹敞瑙�*/
-    %>
-    <% if(versionFieldName!'' == field.name){ %>
-    @Version
-    <% } %>
-    <%
-    /*閫昏緫鍒犻櫎娉ㄨВ*/
-    %>
-    <% if(logicDeleteFieldName!'' == field.name){ %>
-    @TableLogic
-    <% } %>
-    <% if(field.propertyType == 'Integer'){ %>
-    var ${field.propertyName}: Int ? = null
-    <% }else{ %>
-    var ${field.propertyName}: ${field.propertyType} ? = null
-    <% } %>
-<% } %>
-<% /** -----------END 瀛楁寰幆閬嶅巻----------- **/ %>
-
-<% if(entityColumnConstant){ %>
-    companion object {
-   <% for(field in table.fields){ %>
-    const val ${strutil.toUpperCase(field.name)} : String = "${field.name}"
-   <% } %>
-    }
-<% } %>
-<% if(activeRecord){ %>
-    @Override
-    override fun pkVal(): Serializable? {
-    <% if(isNotEmpty(keyPropertyName)){ %>
-        return this.${keyPropertyName}
-    <% }else{ %>
-        return null;
-    <% } %>
-    }
-
-<% } %>
-
-<% if(!entityLombokModel){ %>
-    @Override
-    override fun toString(): String  {
-        return "${entity}{" +
-    <% for(field in table.fields){ %>
-       <% if(fieldLP.index==0){ %>
-        "${field.propertyName}=" + ${field.propertyName} +
-       <% }else{ %>
-        ", ${field.propertyName}=" + ${field.propertyName} +
-       <% } %>
-    <% } %>
-        "}"
-    }
-<% } %>
-}
diff --git a/ycl-generator/src/main/resources/templates/default/entity.kt.ftl b/ycl-generator/src/main/resources/templates/default/entity.kt.ftl
deleted file mode 100644
index a7b14c4..0000000
--- a/ycl-generator/src/main/resources/templates/default/entity.kt.ftl
+++ /dev/null
@@ -1,115 +0,0 @@
-package ${package.Entity}
-
-<#list table.importPackages as pkg>
-import ${pkg}
-</#list>
-<#if swagger2>
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-</#if>
-/**
- * <p>
- * ${table.comment}
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-<#if table.convert>
-@TableName("${table.name}")
-</#if>
-<#if swagger2>
-    @ApiModel(value="${entity}瀵硅薄", description="${table.comment!}")
-</#if>
-<#if superEntityClass??>
-class ${entity} : ${superEntityClass}<#if activeRecord><${entity}></#if> {
-<#elseif activeRecord>
-class ${entity} : Model<${entity}>() {
-<#else>
-class ${entity} : Serializable {
-</#if>
-
-<#-- ----------  BEGIN 瀛楁寰幆閬嶅巻  ---------->
-<#list table.fields as field>
-<#if field.keyFlag>
-    <#assign keyPropertyName="${field.propertyName}"/>
-</#if>
-
-<#if field.comment!?length gt 0>
-<#if swagger2>
-        @ApiModelProperty(value = "${field.comment}")
-<#else>
-    /**
-     * ${field.comment}
-     */
-</#if>
-</#if>
-<#if field.keyFlag>
-<#-- 涓婚敭 -->
-<#if field.keyIdentityFlag>
-    @TableId(value = "${field.name}", type = IdType.AUTO)
-<#elseif idType ??>
-    @TableId(value = "${field.name}", type = IdType.${idType})
-<#elseif field.convert>
-    @TableId("${field.name}")
-</#if>
-<#-- 鏅�氬瓧娈� -->
-<#elseif field.fill??>
-<#-- -----   瀛樺湪瀛楁濉厖璁剧疆   ----->
-<#if field.convert>
-    @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
-<#else>
-    @TableField(fill = FieldFill.${field.fill})
-</#if>
-<#elseif field.convert>
-    @TableField("${field.name}")
-</#if>
-<#-- 涔愯閿佹敞瑙� -->
-<#if (versionFieldName!"") == field.name>
-    @Version
-</#if>
-<#-- 閫昏緫鍒犻櫎娉ㄨВ -->
-<#if (logicDeleteFieldName!"") == field.name>
-    @TableLogic
-</#if>
-    <#if field.propertyType == "Integer">
-    var ${field.propertyName}: Int? = null
-    <#else>
-    var ${field.propertyName}: ${field.propertyType}? = null
-    </#if>
-</#list>
-<#-- ----------  END 瀛楁寰幆閬嶅巻  ---------->
-
-
-<#if entityColumnConstant>
-    companion object {
-<#list table.fields as field>
-
-        const val ${field.name.toUpperCase()} : String = "${field.name}"
-
-</#list>
-    }
-
-</#if>
-<#if activeRecord>
-    override fun pkVal(): Serializable? {
-<#if keyPropertyName??>
-        return ${keyPropertyName}
-<#else>
-        return null
-</#if>
-    }
-
-</#if>
-    override fun toString(): String {
-        return "${entity}{" +
-<#list table.fields as field>
-<#if field_index==0>
-        "${field.propertyName}=" + ${field.propertyName} +
-<#else>
-        ", ${field.propertyName}=" + ${field.propertyName} +
-</#if>
-</#list>
-        "}"
-    }
-}
diff --git a/ycl-generator/src/main/resources/templates/default/entity.kt.vm b/ycl-generator/src/main/resources/templates/default/entity.kt.vm
deleted file mode 100644
index adcef6a..0000000
--- a/ycl-generator/src/main/resources/templates/default/entity.kt.vm
+++ /dev/null
@@ -1,114 +0,0 @@
-package ${package.Entity};
-
-#foreach($pkg in ${table.importPackages})
-import ${pkg};
-#end
-#if(${swagger2})
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-#end
-/**
- * <p>
- * $!{table.comment}
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-#if(${table.convert})
-@TableName("${table.name}")
-#end
-#if(${swagger2})
-@ApiModel(value="${entity}瀵硅薄", description="$!{table.comment}")
-#end
-#if(${superEntityClass})
-class ${entity} : ${superEntityClass}#if(${activeRecord})<${entity}>#end() {
-#elseif(${activeRecord})
-class ${entity} : Model<${entity}>() {
-#else
-class ${entity} : Serializable {
-#end
-
-## ----------  BEGIN 瀛楁寰幆閬嶅巻  ----------
-#foreach($field in ${table.fields})
-#if(${field.keyFlag})
-#set($keyPropertyName=${field.propertyName})
-#end
-#if("$!field.comment" != "")
-    #if(${swagger2})
-    @ApiModelProperty(value = "${field.comment}")
-    #else
-    /**
-     * ${field.comment}
-     */
-    #end
-#end
-#if(${field.keyFlag})
-## 涓婚敭
-#if(${field.keyIdentityFlag})
-    @TableId(value = "${field.name}", type = IdType.AUTO)
-#elseif(!$null.isNull(${idType}) && "$!idType" != "")
-    @TableId(value = "${field.name}", type = IdType.${idType})
-#elseif(${field.convert})
-    @TableId("${field.name}")
-#end
-## 鏅�氬瓧娈�
-#elseif(${field.fill})
-## -----   瀛樺湪瀛楁濉厖璁剧疆   -----
-#if(${field.convert})
-    @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
-#else
-    @TableField(fill = FieldFill.${field.fill})
-#end
-#elseif(${field.convert})
-    @TableField("${field.name}")
-#end
-## 涔愯閿佹敞瑙�
-#if(${versionFieldName}==${field.name})
-    @Version
-#end
-## 閫昏緫鍒犻櫎娉ㄨВ
-#if(${logicDeleteFieldName}==${field.name})
-    @TableLogic
-#end
-    #if(${field.propertyType} == "Integer")
-    var ${field.propertyName}: Int? = null
-    #else
-    var ${field.propertyName}: ${field.propertyType}? = null
-    #end
-#end
-## ----------  END 瀛楁寰幆閬嶅巻  ----------
-
-
-#if(${entityColumnConstant})
-    companion object {
-#foreach($field in ${table.fields})
-
-        const val ${field.name.toUpperCase()} : String = "${field.name}"
-
-#end
-    }
-
-#end
-#if(${activeRecord})
-    override fun pkVal(): Serializable? {
-#if(${keyPropertyName})
-        return ${keyPropertyName}
-#else
-        return null
-#end
-    }
-
-#end
-    override fun toString(): String {
-        return "${entity}{" +
-#foreach($field in ${table.fields})
-#if($!{foreach.index}==0)
-        "${field.propertyName}=" + ${field.propertyName} +
-#else
-        ", ${field.propertyName}=" + ${field.propertyName} +
-#end
-#end
-        "}"
-    }
-}
diff --git a/ycl-generator/src/main/resources/templates/default/mapper.java.btl b/ycl-generator/src/main/resources/templates/default/mapper.java.btl
deleted file mode 100644
index 95bf7ad..0000000
--- a/ycl-generator/src/main/resources/templates/default/mapper.java.btl
+++ /dev/null
@@ -1,20 +0,0 @@
-package ${package.Mapper};
-
-import ${package.Entity}.${entity};
-import ${superMapperClassPackage};
-
-/**
- * <p>
- * ${table.comment!} Mapper 鎺ュ彛
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-<% if(kotlin){ %>
-interface ${table.mapperName} : ${superMapperClass}<${entity}>
-<% }else{ %>
-public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
-
-}
-<% } %>
diff --git a/ycl-generator/src/main/resources/templates/default/mapper.java.ftl b/ycl-generator/src/main/resources/templates/default/mapper.java.ftl
deleted file mode 100644
index 53da4ae..0000000
--- a/ycl-generator/src/main/resources/templates/default/mapper.java.ftl
+++ /dev/null
@@ -1,20 +0,0 @@
-package ${package.Mapper};
-
-import ${package.Entity}.${entity};
-import ${superMapperClassPackage};
-
-/**
- * <p>
- * ${table.comment!} Mapper 鎺ュ彛
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-<#if kotlin>
-interface ${table.mapperName} : ${superMapperClass}<${entity}>
-<#else>
-public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
-
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/templates/default/mapper.java.vm b/ycl-generator/src/main/resources/templates/default/mapper.java.vm
deleted file mode 100644
index 3a6f3a5..0000000
--- a/ycl-generator/src/main/resources/templates/default/mapper.java.vm
+++ /dev/null
@@ -1,20 +0,0 @@
-package ${package.Mapper};
-
-import ${package.Entity}.${entity};
-import ${superMapperClassPackage};
-
-/**
- * <p>
- * $!{table.comment} Mapper 鎺ュ彛
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-#if(${kotlin})
-interface ${table.mapperName} : ${superMapperClass}<${entity}>
-#else
-public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
-
-}
-#end
diff --git a/ycl-generator/src/main/resources/templates/default/mapper.xml.btl b/ycl-generator/src/main/resources/templates/default/mapper.xml.btl
deleted file mode 100644
index 4de8945..0000000
--- a/ycl-generator/src/main/resources/templates/default/mapper.xml.btl
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="${package.Mapper}.${table.mapperName}">
-
-<% if(enableCache){ %>
-    <!-- 寮�鍚簩绾х紦瀛� -->
-    <cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
-
-<% } %>
-<% if(baseResultMap){ %>
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
-<% for(field in table.fields){ %>
-   <% /** 鐢熸垚涓婚敭鎺掑湪绗竴浣� **/ %>
-   <% if(field.keyFlag){ %>
-        <id column="${field.name}" property="${field.propertyName}" />
-   <% } %>
-<% } %>
-<% for(field in table.commonFields){ %>
-    <% /** 鐢熸垚鍏叡瀛楁 **/ %>
-    <result column="${field.name}" property="${field.propertyName}" />
-<% } %>
-<% for(field in table.fields){ %>
-   <% /** 鐢熸垚鏅�氬瓧娈� **/ %>
-   <% if(!field.keyFlag){ %>
-        <result column="${field.name}" property="${field.propertyName}" />
-   <% } %>
-<% } %>
-    </resultMap>
-<% } %>
-<% if(baseColumnList){ %>
-    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
-    <sql id="Base_Column_List">
-<% for(field in table.commonFields){ %>
-        ${field.name},
-<% } %>
-        ${table.fieldNames}
-    </sql>
-
-<% } %>
-</mapper>
diff --git a/ycl-generator/src/main/resources/templates/default/mapper.xml.ftl b/ycl-generator/src/main/resources/templates/default/mapper.xml.ftl
deleted file mode 100644
index d9ca71c..0000000
--- a/ycl-generator/src/main/resources/templates/default/mapper.xml.ftl
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="${package.Mapper}.${table.mapperName}">
-
-<#if enableCache>
-    <!-- 寮�鍚簩绾х紦瀛� -->
-    <cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
-
-</#if>
-<#if baseResultMap>
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
-<#list table.fields as field>
-<#if field.keyFlag><#--鐢熸垚涓婚敭鎺掑湪绗竴浣�-->
-        <id column="${field.name}" property="${field.propertyName}" />
-</#if>
-</#list>
-<#list table.commonFields as field><#--鐢熸垚鍏叡瀛楁 -->
-    <result column="${field.name}" property="${field.propertyName}" />
-</#list>
-<#list table.fields as field>
-<#if !field.keyFlag><#--鐢熸垚鏅�氬瓧娈� -->
-        <result column="${field.name}" property="${field.propertyName}" />
-</#if>
-</#list>
-    </resultMap>
-
-</#if>
-<#if baseColumnList>
-    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
-    <sql id="Base_Column_List">
-<#list table.commonFields as field>
-        ${field.name},
-</#list>
-        ${table.fieldNames}
-    </sql>
-
-</#if>
-</mapper>
diff --git a/ycl-generator/src/main/resources/templates/default/mapper.xml.vm b/ycl-generator/src/main/resources/templates/default/mapper.xml.vm
deleted file mode 100644
index 3af28b0..0000000
--- a/ycl-generator/src/main/resources/templates/default/mapper.xml.vm
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="${package.Mapper}.${table.mapperName}">
-
-#if(${enableCache})
-    <!-- 寮�鍚簩绾х紦瀛� -->
-    <cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
-
-#end
-#if(${baseResultMap})
-    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
-    <resultMap id="BaseResultMap" type="${package.Entity}.${entity}">
-#foreach($field in ${table.fields})
-#if(${field.keyFlag})##鐢熸垚涓婚敭鎺掑湪绗竴浣�
-        <id column="${field.name}" property="${field.propertyName}" />
-#end
-#end
-#foreach($field in ${table.commonFields})##鐢熸垚鍏叡瀛楁
-    <result column="${field.name}" property="${field.propertyName}" />
-#end
-#foreach($field in ${table.fields})
-#if(!${field.keyFlag})##鐢熸垚鏅�氬瓧娈�
-        <result column="${field.name}" property="${field.propertyName}" />
-#end
-#end
-    </resultMap>
-
-#end
-#if(${baseColumnList})
-    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
-    <sql id="Base_Column_List">
-#foreach($field in ${table.commonFields})
-        ${field.name},
-#end
-        ${table.fieldNames}
-    </sql>
-
-#end
-</mapper>
diff --git a/ycl-generator/src/main/resources/templates/default/service.java.btl b/ycl-generator/src/main/resources/templates/default/service.java.btl
deleted file mode 100644
index 6b9de49..0000000
--- a/ycl-generator/src/main/resources/templates/default/service.java.btl
+++ /dev/null
@@ -1,19 +0,0 @@
-package ${package.Service};
-
-import ${package.Entity}.${entity};
-import ${superServiceClassPackage};
-
-/**
- * <p>
- * ${table.comment!} 鏈嶅姟绫�
- * </p>
- *
- * @author ${author}
- */
-<% if(kotlin){ %>
-interface ${table.serviceName} : ${superServiceClass}<${entity}>
-<% }else{ %>
-public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
-
-}
-<% } %>
diff --git a/ycl-generator/src/main/resources/templates/default/service.java.ftl b/ycl-generator/src/main/resources/templates/default/service.java.ftl
deleted file mode 100644
index f9e01c0..0000000
--- a/ycl-generator/src/main/resources/templates/default/service.java.ftl
+++ /dev/null
@@ -1,19 +0,0 @@
-package ${package.Service};
-
-import ${package.Entity}.${entity};
-import ${superServiceClassPackage};
-
-/**
- * <p>
- * ${table.comment!} 鏈嶅姟绫�
- * </p>
- *
- * @author ${author}
- */
-<#if kotlin>
-interface ${table.serviceName} : ${superServiceClass}<${entity}>
-<#else>
-public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
-
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/templates/default/service.java.vm b/ycl-generator/src/main/resources/templates/default/service.java.vm
deleted file mode 100644
index 1e0c4f0..0000000
--- a/ycl-generator/src/main/resources/templates/default/service.java.vm
+++ /dev/null
@@ -1,19 +0,0 @@
-package ${package.Service};
-
-import ${package.Entity}.${entity};
-import ${superServiceClassPackage};
-
-/**
- * <p>
- * $!{table.comment} 鏈嶅姟绫�
- * </p>
- *
- * @author ${author}
- */
-#if(${kotlin})
-interface ${table.serviceName} : ${superServiceClass}<${entity}>
-#else
-public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
-
-}
-#end
diff --git a/ycl-generator/src/main/resources/templates/default/serviceImpl.btl b/ycl-generator/src/main/resources/templates/default/serviceImpl.btl
deleted file mode 100644
index 010991c..0000000
--- a/ycl-generator/src/main/resources/templates/default/serviceImpl.btl
+++ /dev/null
@@ -1,32 +0,0 @@
-package ${entity.serviceImplPackage};
-
-import ${entity.daoPackage}.${entity.className}Dao;
-import ${entity.entityPackage}.${entity.className};
-import ${entity.servicePackage}.${entity.className}Service;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.Pageable;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * ${entity.description}鎺ュ彛瀹炵幇
- * @author ${entity.author}
- */
-@Slf4j
-@Service
-@Transactional
-public class ${entity.className}ServiceImpl implements ${entity.className}Service {
-
-    @Autowired
-    private ${entity.className}Dao ${entity.classNameLowerCase}Dao;
-
-    @Override
-    public ${entity.className}Dao getRepository() {
-        return ${entity.classNameLowerCase}Dao;
-    }
-}
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/templates/default/serviceImpl.java.btl b/ycl-generator/src/main/resources/templates/default/serviceImpl.java.btl
deleted file mode 100644
index 9a62911..0000000
--- a/ycl-generator/src/main/resources/templates/default/serviceImpl.java.btl
+++ /dev/null
@@ -1,26 +0,0 @@
-package ${package.ServiceImpl};
-
-import ${package.Entity}.${entity};
-import ${package.Mapper}.${table.mapperName};
-import ${package.Service}.${table.serviceName};
-import ${superServiceImplClassPackage};
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * ${table.comment!} 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-@Service
-<% if(kotlin){ %>
-open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
-
-}
-<% }else{ %>
-public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
-
-}
-<% } %>
diff --git a/ycl-generator/src/main/resources/templates/default/serviceImpl.java.ftl b/ycl-generator/src/main/resources/templates/default/serviceImpl.java.ftl
deleted file mode 100644
index aeebd14..0000000
--- a/ycl-generator/src/main/resources/templates/default/serviceImpl.java.ftl
+++ /dev/null
@@ -1,26 +0,0 @@
-package ${package.ServiceImpl};
-
-import ${package.Entity}.${entity};
-import ${package.Mapper}.${table.mapperName};
-import ${package.Service}.${table.serviceName};
-import ${superServiceImplClassPackage};
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * ${table.comment!} 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-@Service
-<#if kotlin>
-open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
-
-}
-<#else>
-public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
-
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/templates/default/serviceImpl.java.vm b/ycl-generator/src/main/resources/templates/default/serviceImpl.java.vm
deleted file mode 100644
index a5ed504..0000000
--- a/ycl-generator/src/main/resources/templates/default/serviceImpl.java.vm
+++ /dev/null
@@ -1,26 +0,0 @@
-package ${package.ServiceImpl};
-
-import ${package.Entity}.${entity};
-import ${package.Mapper}.${table.mapperName};
-import ${package.Service}.${table.serviceName};
-import ${superServiceImplClassPackage};
-import org.springframework.stereotype.Service;
-
-/**
- * <p>
- * $!{table.comment} 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author ${author}
- * @since ${date}
- */
-@Service
-#if(${kotlin})
-open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
-
-}
-#else
-public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
-
-}
-#end
diff --git a/ycl-generator/src/main/resources/templates/entity.java.ftl b/ycl-generator/src/main/resources/templates/entity.java.ftl
deleted file mode 100644
index 65145ff..0000000
--- a/ycl-generator/src/main/resources/templates/entity.java.ftl
+++ /dev/null
@@ -1,155 +0,0 @@
-package ${package.Entity};
-
-<#list table.importPackages as pkg>
-import ${pkg};
-</#list>
-<#if swagger2>
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-</#if>
-<#if entityLombokModel>
-import lombok.Data;
-</#if>
-<#if chainModel>
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.NoArgsConstructor;
-</#if>
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableName;
-
-/**
- * <p>
- * ${table.comment!}
- * </p>
- *
- * @author ${author}
- */
-<#if entityLombokModel>
-@Data
-</#if>
-<#if chainModel>
-@Builder
-@NoArgsConstructor
-@AllArgsConstructor
-</#if>
-<#if swagger2>
-@TableName("${table.name}")
-</#if>
-<#if swagger2>
-@ApiModel(value="${entity}", description="${table.comment!}")
-</#if>
-<#if superEntityClass??>
-public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
-<#elseif activeRecord>
-public class ${entity} extends Model<${entity}> {
-<#else>
-public class ${entity} implements Serializable {
-</#if>
-
-    private static final long serialVersionUID = 1L;
-<#-- ----------  BEGIN 瀛楁寰幆閬嶅巻  ---------->
-<#list table.fields as field>
-    <#if field.keyFlag>
-        <#assign keyPropertyName="${field.propertyName}"/>
-    </#if>
-
-    <#if field.comment!?length gt 0>
-    <#if swagger2>
-    @ApiModelProperty(value = "${field.comment}")
-    <#else>
-    /**
-     * ${field.comment}
-     */
-    </#if>
-    </#if>
-    <#if swagger2>
-    <#if field.keyFlag>
-    <#-- 涓婚敭 -->
-        <#--<#if field.keyIdentityFlag>-->
-    <#--@TableId(value = "${field.name}", type = IdType.AUTO)-->
-        <#if idType??>
-    @TableId(value = "${field.name}", type = IdType.${idType})
-        <#elseif field.convert>
-    @TableId("${field.name}")
-        </#if>
-    <#-- 鏅�氬瓧娈� -->
-   <#-- <#elseif field.fill??>
-    &lt;#&ndash; -----   瀛樺湪瀛楁濉厖璁剧疆   ---&ndash;&gt;
-        <#if field.convert>
-    @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
-        <#else>
-    @TableField(fill = FieldFill.${field.fill})
-        </#if>-->
-    <#else>
-    @TableField("${field.name}")
-    </#if>
-    </#if>
-<#-- 涔愯閿佹敞瑙� -->
-    <#if (versionFieldName!"") == field.name>
-    @Version
-    </#if>
-<#-- 閫昏緫鍒犻櫎娉ㄨВ -->
-    <#if (logicDeleteFieldName!"") == field.name>
-    @TableLogic
-    </#if>
-    private ${field.propertyType} ${field.propertyName};
-</#list>
-<#------------  END 瀛楁寰幆閬嶅巻  ---------->
-
-<#if !entityLombokModel>
-    <#list table.fields as field>
-        <#if field.propertyType == "boolean">
-            <#assign getprefix="is"/>
-        <#else>
-            <#assign getprefix="get"/>
-        </#if>
-    public ${field.propertyType} ${getprefix}${field.capitalName}() {
-        return ${field.propertyName};
-    }
-
-        <#if entityBuilderModel>
-    public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-        <#else>
-    public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
-        </#if>
-        this.${field.propertyName} = ${field.propertyName};
-        <#if entityBuilderModel>
-        return this;
-        </#if>
-    }
-    </#list>
-</#if>
-
-<#if entityColumnConstant>
-    <#list table.fields as field>
-    public static final String ${field.name?upper_case} = "${field.name}";
-
-    </#list>
-</#if>
-<#if activeRecord>
-    @Override
-    protected Serializable pkVal() {
-    <#if keyPropertyName??>
-        return this.${keyPropertyName};
-    <#else>
-        return null;
-    </#if>
-    }
-
-</#if>
-<#if !entityLombokModel>
-    @Override
-    public String toString() {
-        return "${entity}{" +
-    <#list table.fields as field>
-        <#if field_index==0>
-        "${field.propertyName}=" + ${field.propertyName} +
-        <#else>
-        ", ${field.propertyName}=" + ${field.propertyName} +
-        </#if>
-    </#list>
-        "}";
-    }
-</#if>
-}
diff --git a/ycl-generator/src/main/resources/templates/mapper.java.ftl b/ycl-generator/src/main/resources/templates/mapper.java.ftl
deleted file mode 100644
index d9d9f4f..0000000
--- a/ycl-generator/src/main/resources/templates/mapper.java.ftl
+++ /dev/null
@@ -1,21 +0,0 @@
-package ${package.Mapper};
-
-import ${package.Entity}.${entity};
-import ${superMapperClassPackage};
-import org.apache.ibatis.annotations.Mapper;
-
-/**
- * <p>
- * ${table.comment!} Mapper 鎺ュ彛
- * </p>
- *
- * @author ${author}
- */
-@Mapper
-<#if kotlin>
-interface ${table.mapperName} : ${superMapperClass}<${entity}>
-<#else>
-public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
-
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/templates/service.java.ftl b/ycl-generator/src/main/resources/templates/service.java.ftl
deleted file mode 100644
index f9e01c0..0000000
--- a/ycl-generator/src/main/resources/templates/service.java.ftl
+++ /dev/null
@@ -1,19 +0,0 @@
-package ${package.Service};
-
-import ${package.Entity}.${entity};
-import ${superServiceClassPackage};
-
-/**
- * <p>
- * ${table.comment!} 鏈嶅姟绫�
- * </p>
- *
- * @author ${author}
- */
-<#if kotlin>
-interface ${table.serviceName} : ${superServiceClass}<${entity}>
-<#else>
-public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
-
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/templates/serviceImpl.java.ftl b/ycl-generator/src/main/resources/templates/serviceImpl.java.ftl
deleted file mode 100644
index 8777730..0000000
--- a/ycl-generator/src/main/resources/templates/serviceImpl.java.ftl
+++ /dev/null
@@ -1,30 +0,0 @@
-package ${package.ServiceImpl};
-
-import ${package.Entity}.${entity};
-import ${package.Mapper}.${table.mapperName};
-import ${package.Service}.${table.serviceName};
-import ${superServiceImplClassPackage};
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.beans.factory.annotation.Autowired;
-
-/**
- * <p>
- * ${table.comment!} 鏈嶅姟瀹炵幇绫�
- * </p>
- *
- * @author ${author}
- */
-@Slf4j
-@Service
-@Transactional
-<#if kotlin>
-open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
-
-}
-<#else>
-public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
-
-}
-</#if>
diff --git a/ycl-generator/src/main/resources/vm/java/controller.java.vm b/ycl-generator/src/main/resources/vm/java/controller.java.vm
new file mode 100644
index 0000000..9e32eb7
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/java/controller.java.vm
@@ -0,0 +1,115 @@
+package ${packageName}.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ycl.common.annotation.Log;
+import com.ycl.common.core.controller.BaseController;
+import com.ycl.common.core.domain.AjaxResult;
+import com.ycl.common.enums.BusinessType;
+import ${packageName}.domain.${ClassName};
+import ${packageName}.service.I${ClassName}Service;
+import com.ycl.common.utils.poi.ExcelUtil;
+#if($table.crud || $table.sub)
+import com.ycl.common.core.page.TableDataInfo;
+#elseif($table.tree)
+#end
+
+/**
+ * ${functionName}Controller
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@RestController
+@RequestMapping("/${moduleName}/${businessName}")
+public class ${ClassName}Controller extends BaseController
+{
+    @Autowired
+    private I${ClassName}Service ${className}Service;
+
+    /**
+     * 鏌ヨ${functionName}鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')")
+    @GetMapping("/list")
+#if($table.crud || $table.sub)
+    public TableDataInfo list(${ClassName} ${className})
+    {
+        startPage();
+        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+        return getDataTable(list);
+    }
+#elseif($table.tree)
+    public AjaxResult list(${ClassName} ${className})
+    {
+        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+        return success(list);
+    }
+#end
+
+    /**
+     * 瀵煎嚭${functionName}鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
+    @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ${ClassName} ${className})
+    {
+        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+        ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
+        util.exportExcel(response, list, "${functionName}鏁版嵁");
+    }
+
+    /**
+     * 鑾峰彇${functionName}璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')")
+    @GetMapping(value = "/{${pkColumn.javaField}}")
+    public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
+    {
+        return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));
+    }
+
+    /**
+     * 鏂板${functionName}
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')")
+    @Log(title = "${functionName}", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ${ClassName} ${className})
+    {
+        return toAjax(${className}Service.insert${ClassName}(${className}));
+    }
+
+    /**
+     * 淇敼${functionName}
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')")
+    @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ${ClassName} ${className})
+    {
+        return toAjax(${className}Service.update${ClassName}(${className}));
+    }
+
+    /**
+     * 鍒犻櫎${functionName}
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')")
+    @Log(title = "${functionName}", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{${pkColumn.javaField}s}")
+    public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
+    {
+        return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s));
+    }
+}
diff --git a/ycl-generator/src/main/resources/vm/java/domain.java.vm b/ycl-generator/src/main/resources/vm/java/domain.java.vm
new file mode 100644
index 0000000..748d7e6
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/java/domain.java.vm
@@ -0,0 +1,103 @@
+package ${packageName}.domain;
+
+#foreach ($import in $importList)
+import ${import};
+#end
+import com.ycl.common.annotation.Excel;
+#if($table.crud || $table.sub)
+import com.ycl.common.core.domain.BaseEntity;
+#elseif($table.tree)
+import com.ycl.common.core.domain.TreeEntity;
+#end
+
+/**
+ * ${functionName}瀵硅薄 ${tableName}
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+#if($table.crud || $table.sub)
+#set($Entity="BaseEntity")
+#elseif($table.tree)
+#set($Entity="TreeEntity")
+#end
+public class ${ClassName} extends ${Entity}
+{
+    private static final long serialVersionUID = 1L;
+
+#foreach ($column in $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')
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
+#else
+    @Excel(name = "${comment}")
+#end
+#end
+    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))
+#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
+
+#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)
+#foreach ($column in $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
+#if($table.sub)
+            .append("${subclassName}List", get${subClassName}List())
+#end
+            .toString();
+    }
+}
diff --git a/ycl-generator/src/main/resources/vm/java/mapper.java.vm b/ycl-generator/src/main/resources/vm/java/mapper.java.vm
new file mode 100644
index 0000000..7e7d7c2
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/java/mapper.java.vm
@@ -0,0 +1,91 @@
+package ${packageName}.mapper;
+
+import java.util.List;
+import ${packageName}.domain.${ClassName};
+#if($table.sub)
+import ${packageName}.domain.${subClassName};
+#end
+
+/**
+ * ${functionName}Mapper鎺ュ彛
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface ${ClassName}Mapper 
+{
+    /**
+     * 鏌ヨ${functionName}
+     * 
+     * @param ${pkColumn.javaField} ${functionName}涓婚敭
+     * @return ${functionName}
+     */
+    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+    /**
+     * 鏌ヨ${functionName}鍒楄〃
+     * 
+     * @param ${className} ${functionName}
+     * @return ${functionName}闆嗗悎
+     */
+    public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
+
+    /**
+     * 鏂板${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 缁撴灉
+     */
+    public int insert${ClassName}(${ClassName} ${className});
+
+    /**
+     * 淇敼${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 缁撴灉
+     */
+    public int update${ClassName}(${ClassName} ${className});
+
+    /**
+     * 鍒犻櫎${functionName}
+     * 
+     * @param ${pkColumn.javaField} ${functionName}涓婚敭
+     * @return 缁撴灉
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+    /**
+     * 鎵归噺鍒犻櫎${functionName}
+     * 
+     * @param ${pkColumn.javaField}s 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+#if($table.sub)
+
+    /**
+     * 鎵归噺鍒犻櫎${subTable.functionName}
+     * 
+     * @param ${pkColumn.javaField}s 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+    
+    /**
+     * 鎵归噺鏂板${subTable.functionName}
+     * 
+     * @param ${subclassName}List ${subTable.functionName}鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batch${subClassName}(List<${subClassName}> ${subclassName}List);
+    
+
+    /**
+     * 閫氳繃${functionName}涓婚敭鍒犻櫎${subTable.functionName}淇℃伅
+     * 
+     * @param ${pkColumn.javaField} ${functionName}ID
+     * @return 缁撴灉
+     */
+    public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});
+#end
+}
diff --git a/ycl-generator/src/main/resources/vm/java/service.java.vm b/ycl-generator/src/main/resources/vm/java/service.java.vm
new file mode 100644
index 0000000..264882b
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/java/service.java.vm
@@ -0,0 +1,61 @@
+package ${packageName}.service;
+
+import java.util.List;
+import ${packageName}.domain.${ClassName};
+
+/**
+ * ${functionName}Service鎺ュ彛
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Service 
+{
+    /**
+     * 鏌ヨ${functionName}
+     * 
+     * @param ${pkColumn.javaField} ${functionName}涓婚敭
+     * @return ${functionName}
+     */
+    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+    /**
+     * 鏌ヨ${functionName}鍒楄〃
+     * 
+     * @param ${className} ${functionName}
+     * @return ${functionName}闆嗗悎
+     */
+    public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
+
+    /**
+     * 鏂板${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 缁撴灉
+     */
+    public int insert${ClassName}(${ClassName} ${className});
+
+    /**
+     * 淇敼${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 缁撴灉
+     */
+    public int update${ClassName}(${ClassName} ${className});
+
+    /**
+     * 鎵归噺鍒犻櫎${functionName}
+     * 
+     * @param ${pkColumn.javaField}s 闇�瑕佸垹闄ょ殑${functionName}涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+
+    /**
+     * 鍒犻櫎${functionName}淇℃伅
+     * 
+     * @param ${pkColumn.javaField} ${functionName}涓婚敭
+     * @return 缁撴灉
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+}
diff --git a/ycl-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ycl-generator/src/main/resources/vm/java/serviceImpl.java.vm
new file mode 100644
index 0000000..3cb525a
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -0,0 +1,169 @@
+package ${packageName}.service.impl;
+
+import java.util.List;
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
+import com.ycl.common.utils.DateUtils;
+#break
+#end
+#end
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+#if($table.sub)
+import java.util.ArrayList;
+import com.ycl.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;
+
+/**
+ * ${functionName}Service涓氬姟灞傚鐞�
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Service
+public class ${ClassName}ServiceImpl implements I${ClassName}Service 
+{
+    @Autowired
+    private ${ClassName}Mapper ${className}Mapper;
+
+    /**
+     * 鏌ヨ${functionName}
+     * 
+     * @param ${pkColumn.javaField} ${functionName}涓婚敭
+     * @return ${functionName}
+     */
+    @Override
+    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+    {
+        return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+    }
+
+    /**
+     * 鏌ヨ${functionName}鍒楄〃
+     * 
+     * @param ${className} ${functionName}
+     * @return ${functionName}
+     */
+    @Override
+    public List<${ClassName}> select${ClassName}List(${ClassName} ${className})
+    {
+        return ${className}Mapper.select${ClassName}List(${className});
+    }
+
+    /**
+     * 鏂板${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 缁撴灉
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int insert${ClassName}(${ClassName} ${className})
+    {
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime')
+        ${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
+    }
+
+    /**
+     * 淇敼${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 缁撴灉
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int update${ClassName}(${ClassName} ${className})
+    {
+#foreach ($column in $columns)
+#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});
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎${functionName}
+     * 
+     * @param ${pkColumn.javaField}s 闇�瑕佸垹闄ょ殑${functionName}涓婚敭
+     * @return 缁撴灉
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s)
+    {
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
+#end
+        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s);
+    }
+
+    /**
+     * 鍒犻櫎${functionName}淇℃伅
+     * 
+     * @param ${pkColumn.javaField} ${functionName}涓婚敭
+     * @return 缁撴灉
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+    {
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
+#end
+        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+    }
+#if($table.sub)
+
+    /**
+     * 鏂板${subTable.functionName}淇℃伅
+     * 
+     * @param ${className} ${functionName}瀵硅薄
+     */
+    public void insert${subClassName}(${ClassName} ${className})
+    {
+        List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
+        ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
+        if (StringUtils.isNotNull(${subclassName}List))
+        {
+            List<${subClassName}> list = new ArrayList<${subClassName}>();
+            for (${subClassName} ${subclassName} : ${subclassName}List)
+            {
+                ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});
+                list.add(${subclassName});
+            }
+            if (list.size() > 0)
+            {
+                ${className}Mapper.batch${subClassName}(list);
+            }
+        }
+    }
+#end
+}
diff --git a/ycl-generator/src/main/resources/vm/java/sub-domain.java.vm b/ycl-generator/src/main/resources/vm/java/sub-domain.java.vm
new file mode 100644
index 0000000..2170974
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/java/sub-domain.java.vm
@@ -0,0 +1,74 @@
+package ${packageName}.domain;
+
+#foreach ($import in $subImportList)
+import ${import};
+#end
+import com.ycl.common.annotation.Excel;
+import com.ycl.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')
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @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();
+    }
+}
diff --git a/ycl-generator/src/main/resources/vm/js/api.js.vm b/ycl-generator/src/main/resources/vm/js/api.js.vm
new file mode 100644
index 0000000..9295524
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/js/api.js.vm
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ${functionName}鍒楄〃
+export function list${BusinessName}(query) {
+  return request({
+    url: '/${moduleName}/${businessName}/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ${functionName}璇︾粏
+export function get${BusinessName}(${pkColumn.javaField}) {
+  return request({
+    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+    method: 'get'
+  })
+}
+
+// 鏂板${functionName}
+export function add${BusinessName}(data) {
+  return request({
+    url: '/${moduleName}/${businessName}',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼${functionName}
+export function update${BusinessName}(data) {
+  return request({
+    url: '/${moduleName}/${businessName}',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎${functionName}
+export function del${BusinessName}(${pkColumn.javaField}) {
+  return request({
+    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+    method: 'delete'
+  })
+}
diff --git a/ycl-generator/src/main/resources/vm/sql/sql.vm b/ycl-generator/src/main/resources/vm/sql/sql.vm
new file mode 100644
index 0000000..0575583
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/sql/sql.vm
@@ -0,0 +1,22 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳鐖惰彍鍗旾D
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}鏌ヨ', @parentId, '1',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}鏂板', @parentId, '2',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}淇敼', @parentId, '3',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}鍒犻櫎', @parentId, '4',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}瀵煎嚭', @parentId, '5',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export',       '#', 'admin', sysdate(), '', null, '');
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ycl-generator/src/main/resources/vm/vue/index-tree.vue.vm
new file mode 100644
index 0000000..a4c64a0
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -0,0 +1,505 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="璇疯緭鍏�${comment}"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option
+            v-for="dict in dict.type.${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="閫夋嫨${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+	    <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="el-icon-sort"
+          size="mini"
+          @click="toggleExpandAll"
+        >灞曞紑/鎶樺彔</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-if="refreshTable"
+      v-loading="loading"
+      :data="${businessName}List"
+      row-key="${treeCode}"
+      :default-expand-all="isExpandAll"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template slot-scope="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+      <el-table-column label="${comment}" prop="${javaField}" />
+#else
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-plus"
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:add']"
+          >鏂板</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+        <el-form-item label="${comment}" prop="${treeParentCode}">
+          <treeselect v-model="form.${treeParentCode}" :options="${businessName}Options" :normalizer="normalizer" placeholder="璇烽�夋嫨${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="閫夋嫨${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "${BusinessName}",
+#if(${dicts} != '')
+  dicts: [${dicts}],
+#end
+  components: {
+    Treeselect
+  },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // ${functionName}琛ㄦ牸鏁版嵁
+      ${businessName}List: [],
+      // ${functionName}鏍戦�夐」
+      ${businessName}Options: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁灞曞紑锛岄粯璁ゅ叏閮ㄥ睍寮�
+      isExpandAll: true,
+      // 閲嶆柊娓叉煋琛ㄦ牸鐘舵��
+      refreshTable: true,
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      // $comment鏃堕棿鑼冨洿
+      daterange${AttrName}: [],
+#end
+#end
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+#foreach ($column in $columns)
+#if($column.query)
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+#foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+        $column.javaField: [
+          { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+        ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ${functionName}鍒楄〃 */
+    getList() {
+      this.loading = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      this.queryParams.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
+        this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
+        this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
+      }
+#end
+#end
+      list${BusinessName}(this.queryParams).then(response => {
+        this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+        this.loading = false;
+      });
+    },
+    /** 杞崲${functionName}鏁版嵁缁撴瀯 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.${treeCode},
+        label: node.${treeName},
+        children: node.children
+      };
+    },
+	/** 鏌ヨ${functionName}涓嬫媺鏍戠粨鏋� */
+    getTreeselect() {
+      list${BusinessName}().then(response => {
+        this.${businessName}Options = [];
+        const data = { ${treeCode}: 0, ${treeName}: '椤剁骇鑺傜偣', children: [] };
+        data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+        this.${businessName}Options.push(data);
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      this.daterange${AttrName} = [];
+#end
+#end
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null && row.${treeCode}) {
+        this.form.${treeParentCode} = row.${treeCode};
+      } else {
+        this.form.${treeParentCode} = 0;
+      }
+      this.open = true;
+      this.title = "娣诲姞${functionName}";
+    },
+    /** 灞曞紑/鎶樺彔鎿嶄綔 */
+    toggleExpandAll() {
+      this.refreshTable = false;
+      this.isExpandAll = !this.isExpandAll;
+      this.$nextTick(() => {
+        this.refreshTable = true;
+      });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null) {
+        this.form.${treeParentCode} = row.${treeCode};
+      }
+      get${BusinessName}(row.${pkColumn.javaField}).then(response => {
+        this.form = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        this.form.$column.javaField = this.form.${column.javaField}.split(",");
+#end
+#end
+        this.open = true;
+        this.title = "淇敼${functionName}";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.#[[$]]#refs["form"].validate(valid => {
+        if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+          this.form.$column.javaField = this.form.${column.javaField}.join(",");
+#end
+#end
+          if (this.form.${pkColumn.javaField} != null) {
+            update${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            add${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + row.${pkColumn.javaField} + '"鐨勬暟鎹」锛�').then(function() {
+        return del${BusinessName}(row.${pkColumn.javaField});
+      }).then(() => {
+        this.getList();
+        this.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
diff --git a/ycl-generator/src/main/resources/vm/vue/index.vue.vm b/ycl-generator/src/main/resources/vm/vue/index.vue.vm
new file mode 100644
index 0000000..6296014
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/vue/index.vue.vm
@@ -0,0 +1,602 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="璇疯緭鍏�${comment}"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option
+            v-for="dict in dict.type.${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="璇烽�夋嫨${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['${moduleName}:${businessName}:edit']"
+        >淇敼</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['${moduleName}:${businessName}:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['${moduleName}:${businessName}:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template slot-scope="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="璇烽�夋嫨${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+#if($table.sub)
+        <el-divider content-position="center">${subTable.functionName}淇℃伅</el-divider>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd${subClassName}">娣诲姞</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDelete${subClassName}">鍒犻櫎</el-button>
+          </el-col>
+        </el-row>
+        <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="搴忓彿" align="center" prop="index" width="50"/>
+#foreach($column in $subTable.columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk || $javaField == ${subTableFkclassName})
+#elseif($column.list && $column.htmlType == "input")
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.$javaField" placeholder="璇疯緭鍏�$comment" />
+            </template>
+          </el-table-column>
+#elseif($column.list && $column.htmlType == "datetime")
+          <el-table-column label="$comment" prop="${javaField}" width="240">
+            <template slot-scope="scope">
+              <el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="璇烽�夋嫨$comment" />
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="璇烽�夋嫨$comment">
+                <el-option
+                  v-for="dict in dict.type.$column.dictType"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="璇烽�夋嫨$comment">
+                <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+              </el-select>
+            </template>
+          </el-table-column>
+#end
+#end
+        </el-table>
+#end
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+export default {
+  name: "${BusinessName}",
+#if(${dicts} != '')
+  dicts: [${dicts}],
+#end
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+#if($table.sub)
+      // 瀛愯〃閫変腑鏁版嵁
+      checked${subClassName}: [],
+#end
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // ${functionName}琛ㄦ牸鏁版嵁
+      ${businessName}List: [],
+#if($table.sub)
+      // ${subTable.functionName}琛ㄦ牸鏁版嵁
+      ${subclassName}List: [],
+#end
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      // $comment鏃堕棿鑼冨洿
+      daterange${AttrName}: [],
+#end
+#end
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+#foreach ($column in $columns)
+#if($column.query)
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+#foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+        $column.javaField: [
+          { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+        ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ${functionName}鍒楄〃 */
+    getList() {
+      this.loading = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      this.queryParams.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
+        this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
+        this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
+      }
+#end
+#end
+      list${BusinessName}(this.queryParams).then(response => {
+        this.${businessName}List = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      };
+#if($table.sub)
+      this.${subclassName}List = [];
+#end
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      this.daterange${AttrName} = [];
+#end
+#end
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.${pkColumn.javaField})
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞${functionName}";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
+      get${BusinessName}(${pkColumn.javaField}).then(response => {
+        this.form = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        this.form.$column.javaField = this.form.${column.javaField}.split(",");
+#end
+#end
+#if($table.sub)
+        this.${subclassName}List = response.data.${subclassName}List;
+#end
+        this.open = true;
+        this.title = "淇敼${functionName}";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      this.#[[$]]#refs["form"].validate(valid => {
+        if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+          this.form.$column.javaField = this.form.${column.javaField}.join(",");
+#end
+#end
+#if($table.sub)
+          this.form.${subclassName}List = this.${subclassName}List;
+#end
+          if (this.form.${pkColumn.javaField} != null) {
+            update${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            add${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids;
+      this.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + ${pkColumn.javaField}s + '"鐨勬暟鎹」锛�').then(function() {
+        return del${BusinessName}(${pkColumn.javaField}s);
+      }).then(() => {
+        this.getList();
+        this.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+#if($table.sub)
+	/** ${subTable.functionName}搴忓彿 */
+    row${subClassName}Index({ row, rowIndex }) {
+      row.index = rowIndex + 1;
+    },
+    /** ${subTable.functionName}娣诲姞鎸夐挳鎿嶄綔 */
+    handleAdd${subClassName}() {
+      let obj = {};
+#foreach($column in $subTable.columns)
+#if($column.pk || $column.javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $javaField)
+      obj.$column.javaField = "";
+#end
+#end
+      this.${subclassName}List.push(obj);
+    },
+    /** ${subTable.functionName}鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete${subClassName}() {
+      if (this.checked${subClassName}.length == 0) {
+        this.#[[$modal]]#.msgError("璇峰厛閫夋嫨瑕佸垹闄ょ殑${subTable.functionName}鏁版嵁");
+      } else {
+        const ${subclassName}List = this.${subclassName}List;
+        const checked${subClassName} = this.checked${subClassName};
+        this.${subclassName}List = ${subclassName}List.filter(function(item) {
+          return checked${subClassName}.indexOf(item.index) == -1
+        });
+      }
+    },
+    /** 澶嶉�夋閫変腑鏁版嵁 */
+    handle${subClassName}SelectionChange(selection) {
+      this.checked${subClassName} = selection.map(item => item.index)
+    },
+#end
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('${moduleName}/${businessName}/export', {
+        ...this.queryParams
+      }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/ycl-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm b/ycl-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
new file mode 100644
index 0000000..7bbd2fc
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
@@ -0,0 +1,474 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="璇疯緭鍏�${comment}"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option
+            v-for="dict in ${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="閫夋嫨${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}" style="width: 308px">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          value-format="YYYY-MM-DD"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="Sort"
+          @click="toggleExpandAll"
+        >灞曞紑/鎶樺彔</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-if="refreshTable"
+      v-loading="loading"
+      :data="${businessName}List"
+      row-key="${treeCode}"
+      :default-expand-all="isExpandAll"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template #default="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template #default="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+      <el-table-column label="${comment}" prop="${javaField}" />
+#else
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">淇敼</el-button>
+          <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']">鏂板</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+        <el-form-item label="${comment}" prop="${treeParentCode}">
+          <el-tree-select
+            v-model="form.${treeParentCode}"
+            :data="${businessName}Options"
+            :props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
+            value-key="${treeCode}"
+            placeholder="璇烽�夋嫨${comment}"
+            check-strictly
+          />
+        </el-form-item>
+#elseif($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="閫夋嫨${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+          <el-button @click="cancel">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+const { proxy } = getCurrentInstance();
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
+#end
+
+const ${businessName}List = ref([]);
+const ${businessName}Options = ref([]);
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const title = ref("");
+const isExpandAll = ref(true);
+const refreshTable = ref(true);
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const daterange${AttrName} = ref([]);
+#end
+#end
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    #foreach ($column in $columns)
+#if($column.query)
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  },
+  rules: {
+    #foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+    $column.javaField: [
+      { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+    ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+function getList() {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
+    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
+    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
+  }
+#end
+#end
+  list${BusinessName}(queryParams.value).then(response => {
+    ${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+    loading.value = false;
+  });
+}
+
+/** 鏌ヨ${functionName}涓嬫媺鏍戠粨鏋� */
+function getTreeselect() {
+  list${BusinessName}().then(response => {
+    ${businessName}Options.value = [];
+    const data = { ${treeCode}: 0, ${treeName}: '椤剁骇鑺傜偣', children: [] };
+    data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+    ${businessName}Options.value.push(data);
+  });
+}
+	
+// 鍙栨秷鎸夐挳
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+// 琛ㄥ崟閲嶇疆
+function reset() {
+  form.value = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  };
+  proxy.resetForm("${businessName}Ref");
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+  getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  daterange${AttrName}.value = [];
+#end
+#end
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+function handleAdd(row) {
+  reset();
+  getTreeselect();
+  if (row != null && row.${treeCode}) {
+    form.value.${treeParentCode} = row.${treeCode};
+  } else {
+    form.value.${treeParentCode} = 0;
+  }
+  open.value = true;
+  title.value = "娣诲姞${functionName}";
+}
+
+/** 灞曞紑/鎶樺彔鎿嶄綔 */
+function toggleExpandAll() {
+  refreshTable.value = false;
+  isExpandAll.value = !isExpandAll.value;
+  nextTick(() => {
+    refreshTable.value = true;
+  });
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+async function handleUpdate(row) {
+  reset();
+  await getTreeselect();
+  if (row != null) {
+    form.value.${treeParentCode} = row.${treeCode};
+  }
+  get${BusinessName}(row.${pkColumn.javaField}).then(response => {
+    form.value = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+    open.value = true;
+    title.value = "淇敼${functionName}";
+  });
+}
+
+/** 鎻愪氦鎸夐挳 */
+function submitForm() {
+  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
+    if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+      form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+      if (form.value.${pkColumn.javaField} != null) {
+        update${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("淇敼鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      } else {
+        add${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("鏂板鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      }
+    }
+  });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete(row) {
+  proxy.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + row.${pkColumn.javaField} + '"鐨勬暟鎹」锛�').then(function() {
+    return del${BusinessName}(row.${pkColumn.javaField});
+  }).then(() => {
+    getList();
+    proxy.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+  }).catch(() => {});
+}
+
+getList();
+</script>
diff --git a/ycl-generator/src/main/resources/vm/vue/v3/index.vue.vm b/ycl-generator/src/main/resources/vm/vue/v3/index.vue.vm
new file mode 100644
index 0000000..8b25665
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/vue/v3/index.vue.vm
@@ -0,0 +1,590 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="璇疯緭鍏�${comment}"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option
+            v-for="dict in ${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="璇烽�夋嫨${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}" style="width: 308px">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          value-format="YYYY-MM-DD"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['${moduleName}:${businessName}:edit']"
+        >淇敼</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['${moduleName}:${businessName}:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['${moduleName}:${businessName}:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template #default="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template #default="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">淇敼</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="璇烽�夋嫨${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+#if($table.sub)
+        <el-divider content-position="center">${subTable.functionName}淇℃伅</el-divider>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" icon="Plus" @click="handleAdd${subClassName}">娣诲姞</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" icon="Delete" @click="handleDelete${subClassName}">鍒犻櫎</el-button>
+          </el-col>
+        </el-row>
+        <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="搴忓彿" align="center" prop="index" width="50"/>
+#foreach($column in $subTable.columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk || $javaField == ${subTableFkclassName})
+#elseif($column.list && $column.htmlType == "input")
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template #default="scope">
+              <el-input v-model="scope.row.$javaField" placeholder="璇疯緭鍏�$comment" />
+            </template>
+          </el-table-column>
+#elseif($column.list && $column.htmlType == "datetime")
+          <el-table-column label="$comment" prop="${javaField}" width="240">
+            <template #default="scope">
+              <el-date-picker clearable
+                v-model="scope.row.$javaField"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨$comment">
+              </el-date-picker>
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template #default="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="璇烽�夋嫨$comment">
+                <el-option
+                  v-for="dict in $column.dictType"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template #default="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="璇烽�夋嫨$comment">
+                <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+              </el-select>
+            </template>
+          </el-table-column>
+#end
+#end
+        </el-table>
+#end
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+          <el-button @click="cancel">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+const { proxy } = getCurrentInstance();
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
+#end
+
+const ${businessName}List = ref([]);
+#if($table.sub)
+const ${subclassName}List = ref([]);
+#end
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref([]);
+#if($table.sub)
+const checked${subClassName} = ref([]);
+#end
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const daterange${AttrName} = ref([]);
+#end
+#end
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    #foreach ($column in $columns)
+#if($column.query)
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  },
+  rules: {
+    #foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+    $column.javaField: [
+      { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+    ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+function getList() {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
+    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
+    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
+  }
+#end
+#end
+  list${BusinessName}(queryParams.value).then(response => {
+    ${businessName}List.value = response.rows;
+    total.value = response.total;
+    loading.value = false;
+  });
+}
+
+// 鍙栨秷鎸夐挳
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+// 琛ㄥ崟閲嶇疆
+function reset() {
+  form.value = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  };
+#if($table.sub)
+  ${subclassName}List.value = [];
+#end
+  proxy.resetForm("${businessName}Ref");
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  daterange${AttrName}.value = [];
+#end
+#end
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+// 澶氶�夋閫変腑鏁版嵁
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.${pkColumn.javaField});
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "娣诲姞${functionName}";
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+function handleUpdate(row) {
+  reset();
+  const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
+  get${BusinessName}(_${pkColumn.javaField}).then(response => {
+    form.value = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+#if($table.sub)
+    ${subclassName}List.value = response.data.${subclassName}List;
+#end
+    open.value = true;
+    title.value = "淇敼${functionName}";
+  });
+}
+
+/** 鎻愪氦鎸夐挳 */
+function submitForm() {
+  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
+    if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+      form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+#if($table.sub)
+      form.value.${subclassName}List = ${subclassName}List.value;
+#end
+      if (form.value.${pkColumn.javaField} != null) {
+        update${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("淇敼鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      } else {
+        add${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("鏂板鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      }
+    }
+  });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete(row) {
+  const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value;
+  proxy.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + _${pkColumn.javaField}s + '"鐨勬暟鎹」锛�').then(function() {
+    return del${BusinessName}(_${pkColumn.javaField}s);
+  }).then(() => {
+    getList();
+    proxy.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+  }).catch(() => {});
+}
+
+#if($table.sub)
+/** ${subTable.functionName}搴忓彿 */
+function row${subClassName}Index({ row, rowIndex }) {
+  row.index = rowIndex + 1;
+}
+
+/** ${subTable.functionName}娣诲姞鎸夐挳鎿嶄綔 */
+function handleAdd${subClassName}() {
+  let obj = {};
+#foreach($column in $subTable.columns)
+#if($column.pk || $column.javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $javaField)
+  obj.$column.javaField = "";
+#end
+#end
+  ${subclassName}List.value.push(obj);
+}
+
+/** ${subTable.functionName}鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete${subClassName}() {
+  if (checked${subClassName}.value.length == 0) {
+    proxy.#[[$modal]]#.msgError("璇峰厛閫夋嫨瑕佸垹闄ょ殑${subTable.functionName}鏁版嵁");
+  } else {
+    const ${subclassName}s = ${subclassName}List.value;
+    const checked${subClassName}s = checked${subClassName}.value;
+    ${subclassName}List.value = ${subclassName}s.filter(function(item) {
+      return checked${subClassName}s.indexOf(item.index) == -1
+    });
+  }
+}
+
+/** 澶嶉�夋閫変腑鏁版嵁 */
+function handle${subClassName}SelectionChange(selection) {
+  checked${subClassName}.value = selection.map(item => item.index)
+}
+
+#end
+/** 瀵煎嚭鎸夐挳鎿嶄綔 */
+function handleExport() {
+  proxy.download('${moduleName}/${businessName}/export', {
+    ...queryParams.value
+  }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+}
+
+getList();
+</script>
diff --git a/ycl-generator/src/main/resources/vm/vue/v3/readme.txt b/ycl-generator/src/main/resources/vm/vue/v3/readme.txt
new file mode 100644
index 0000000..99239bb
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/vue/v3/readme.txt
@@ -0,0 +1 @@
+如果使用的是RuoYi-Vue3前端,那么需要覆盖一下此目录的模板index.vue.vm、index-tree.vue.vm文件到上级vue目录。
\ No newline at end of file
diff --git a/ycl-generator/src/main/resources/vm/xml/mapper.xml.vm b/ycl-generator/src/main/resources/vm/xml/mapper.xml.vm
new file mode 100644
index 0000000..0ceb3d8
--- /dev/null
+++ b/ycl-generator/src/main/resources/vm/xml/mapper.xml.vm
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
+    
+    <resultMap type="${ClassName}" id="${ClassName}Result">
+#foreach ($column in $columns)
+        <result property="${column.javaField}"    column="${column.columnName}"    />
+#end
+    </resultMap>
+#if($table.sub)
+
+    <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
+        <collection property="${subclassName}List" notNullColumn="sub_${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="sub_${column.columnName}"    />
+#end
+    </resultMap>
+#end
+
+    <sql id="select${ClassName}Vo">
+        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName}
+    </sql>
+
+    <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result">
+        <include refid="select${ClassName}Vo"/>
+        <where>  
+#foreach($column in $columns)
+#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)})
+#if($column.query)
+#if($column.queryType == "EQ")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName = #{$javaField}</if>
+#elseif($queryType == "NE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName != #{$javaField}</if>
+#elseif($queryType == "GT")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &gt; #{$javaField}</if>
+#elseif($queryType == "GTE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &gt;= #{$javaField}</if>
+#elseif($queryType == "LT")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &lt; #{$javaField}</if>
+#elseif($queryType == "LTE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &lt;= #{$javaField}</if>
+#elseif($queryType == "LIKE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName like concat('%', #{$javaField}, '%')</if>
+#elseif($queryType == "BETWEEN")
+            <if test="params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if>
+#end
+#end
+#end
+        </where>
+    </select>
+    
+    <select id="select${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
+#if($table.crud || $table.tree)
+        <include refid="select${ClassName}Vo"/>
+        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+#elseif($table.sub)
+        select#foreach($column in $columns) a.$column.columnName#if($foreach.count != $columns.size()),#end#end,
+           #foreach($column in $subTable.columns) b.$column.columnName as sub_$column.columnName#if($foreach.count != $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>
+        
+    <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end>
+        insert into ${tableName}
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
+            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName,</if>
+#end
+#end
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
+            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">#{$column.javaField},</if>
+#end
+#end
+         </trim>
+    </insert>
+
+    <update id="update${ClassName}" parameterType="${ClassName}">
+        update ${tableName}
+        <trim prefix="SET" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName)
+            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName = #{$column.javaField},</if>
+#end
+#end
+        </trim>
+        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+    </update>
+
+    <delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}">
+        delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+    </delete>
+
+    <delete id="delete${ClassName}By${pkColumn.capJavaField}s" parameterType="String">
+        delete from ${tableName} where ${pkColumn.columnName} in 
+        <foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")">
+            #{${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="${pkColumn.javaType}">
+        delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
+    </delete>
+
+    <insert id="batch${subClassName}">
+        insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values
+		<foreach item="item" index="index" collection="list" separator=",">
+            (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end)
+        </foreach>
+    </insert>
+#end
+</mapper>
\ No newline at end of file
diff --git a/ycl-pojo/pom.xml b/ycl-pojo/pom.xml
index 539b465..7eba8e3 100644
--- a/ycl-pojo/pom.xml
+++ b/ycl-pojo/pom.xml
@@ -17,6 +17,11 @@
     </properties>
 
     <dependencies>
+        <!-- 鑾峰彇绯荤粺淇℃伅 -->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-core</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.ycl</groupId>
             <artifactId>ycl-common</artifactId>
diff --git a/ycl-pojo/src/main/java/com/ycl/system/Server.java b/ycl-pojo/src/main/java/com/ycl/system/Server.java
new file mode 100644
index 0000000..9ba10f7
--- /dev/null
+++ b/ycl-pojo/src/main/java/com/ycl/system/Server.java
@@ -0,0 +1,237 @@
+package com.ycl.system;
+
+import com.ycl.system.server.*;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.CentralProcessor.TickType;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.FileSystem;
+import oshi.software.os.OSFileStore;
+import oshi.software.os.OperatingSystem;
+import oshi.util.Util;
+import utils.Arith;
+import utils.ip.IpUtils;
+
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * 鏈嶅姟鍣ㄧ浉鍏充俊鎭�
+ * 
+ * @author ruoyi
+ */
+public class Server
+{
+    private static final int OSHI_WAIT_SECOND = 1000;
+    
+    /**
+     * CPU鐩稿叧淇℃伅
+     */
+    private Cpu cpu = new Cpu();
+
+    /**
+     * 鍏у瓨鐩稿叧淇℃伅
+     */
+    private Mem mem = new Mem();
+
+    /**
+     * JVM鐩稿叧淇℃伅
+     */
+    private Jvm jvm = new Jvm();
+
+    /**
+     * 鏈嶅姟鍣ㄧ浉鍏充俊鎭�
+     */
+    private Sys sys = new Sys();
+
+    /**
+     * 纾佺洏鐩稿叧淇℃伅
+     */
+    private List<SysFile> sysFiles = new LinkedList<SysFile>();
+
+    public Cpu getCpu()
+    {
+        return cpu;
+    }
+
+    public void setCpu(Cpu cpu)
+    {
+        this.cpu = cpu;
+    }
+
+    public Mem getMem()
+    {
+        return mem;
+    }
+
+    public void setMem(Mem mem)
+    {
+        this.mem = mem;
+    }
+
+    public Jvm getJvm()
+    {
+        return jvm;
+    }
+
+    public void setJvm(Jvm jvm)
+    {
+        this.jvm = jvm;
+    }
+
+    public Sys getSys()
+    {
+        return sys;
+    }
+
+    public void setSys(Sys sys)
+    {
+        this.sys = sys;
+    }
+
+    public List<SysFile> getSysFiles()
+    {
+        return sysFiles;
+    }
+
+    public void setSysFiles(List<SysFile> sysFiles)
+    {
+        this.sysFiles = sysFiles;
+    }
+
+    public void copyTo() throws Exception
+    {
+        SystemInfo si = new SystemInfo();
+        HardwareAbstractionLayer hal = si.getHardware();
+
+        setCpuInfo(hal.getProcessor());
+
+        setMemInfo(hal.getMemory());
+
+        setSysInfo();
+
+        setJvmInfo();
+
+        setSysFiles(si.getOperatingSystem());
+    }
+
+    /**
+     * 璁剧疆CPU淇℃伅
+     */
+    private void setCpuInfo(CentralProcessor processor)
+    {
+        // CPU淇℃伅
+        long[] prevTicks = processor.getSystemCpuLoadTicks();
+        Util.sleep(OSHI_WAIT_SECOND);
+        long[] ticks = processor.getSystemCpuLoadTicks();
+        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
+        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
+        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
+        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
+        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
+        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
+        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
+        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
+        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
+        cpu.setCpuNum(processor.getLogicalProcessorCount());
+        cpu.setTotal(totalCpu);
+        cpu.setSys(cSys);
+        cpu.setUsed(user);
+        cpu.setWait(iowait);
+        cpu.setFree(idle);
+    }
+
+    /**
+     * 璁剧疆鍐呭瓨淇℃伅
+     */
+    private void setMemInfo(GlobalMemory memory)
+    {
+        mem.setTotal(memory.getTotal());
+        mem.setUsed(memory.getTotal() - memory.getAvailable());
+        mem.setFree(memory.getAvailable());
+    }
+
+    /**
+     * 璁剧疆鏈嶅姟鍣ㄤ俊鎭�
+     */
+    private void setSysInfo()
+    {
+        Properties props = System.getProperties();
+        sys.setComputerName(IpUtils.getHostName());
+        sys.setComputerIp(IpUtils.getHostIp());
+        sys.setOsName(props.getProperty("os.name"));
+        sys.setOsArch(props.getProperty("os.arch"));
+        sys.setUserDir(props.getProperty("user.dir"));
+    }
+
+    /**
+     * 璁剧疆Java铏氭嫙鏈�
+     */
+    private void setJvmInfo() throws UnknownHostException
+    {
+        Properties props = System.getProperties();
+        jvm.setTotal(Runtime.getRuntime().totalMemory());
+        jvm.setMax(Runtime.getRuntime().maxMemory());
+        jvm.setFree(Runtime.getRuntime().freeMemory());
+        jvm.setVersion(props.getProperty("java.version"));
+        jvm.setHome(props.getProperty("java.home"));
+    }
+
+    /**
+     * 璁剧疆纾佺洏淇℃伅
+     */
+    private void setSysFiles(OperatingSystem os)
+    {
+        FileSystem fileSystem = os.getFileSystem();
+        List<OSFileStore> fsArray = fileSystem.getFileStores();
+        for (OSFileStore fs : fsArray)
+        {
+            long free = fs.getUsableSpace();
+            long total = fs.getTotalSpace();
+            long used = total - free;
+            SysFile sysFile = new SysFile();
+            sysFile.setDirName(fs.getMount());
+            sysFile.setSysTypeName(fs.getType());
+            sysFile.setTypeName(fs.getName());
+            sysFile.setTotal(convertFileSize(total));
+            sysFile.setFree(convertFileSize(free));
+            sysFile.setUsed(convertFileSize(used));
+            sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));
+            sysFiles.add(sysFile);
+        }
+    }
+
+    /**
+     * 瀛楄妭杞崲
+     * 
+     * @param size 瀛楄妭澶у皬
+     * @return 杞崲鍚庡��
+     */
+    public String convertFileSize(long size)
+    {
+        long kb = 1024;
+        long mb = kb * 1024;
+        long gb = mb * 1024;
+        if (size >= gb)
+        {
+            return String.format("%.1f GB", (float) size / gb);
+        }
+        else if (size >= mb)
+        {
+            float f = (float) size / mb;
+            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
+        }
+        else if (size >= kb)
+        {
+            float f = (float) size / kb;
+            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
+        }
+        else
+        {
+            return String.format("%d B", size);
+        }
+    }
+}
diff --git a/ycl-pojo/src/main/java/com/ycl/system/server/Cpu.java b/ycl-pojo/src/main/java/com/ycl/system/server/Cpu.java
new file mode 100644
index 0000000..5b594f8
--- /dev/null
+++ b/ycl-pojo/src/main/java/com/ycl/system/server/Cpu.java
@@ -0,0 +1,101 @@
+package com.ycl.system.server;
+
+import utils.Arith;
+
+/**
+ * CPU鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Cpu
+{
+    /**
+     * 鏍稿績鏁�
+     */
+    private int cpuNum;
+
+    /**
+     * CPU鎬荤殑浣跨敤鐜�
+     */
+    private double total;
+
+    /**
+     * CPU绯荤粺浣跨敤鐜�
+     */
+    private double sys;
+
+    /**
+     * CPU鐢ㄦ埛浣跨敤鐜�
+     */
+    private double used;
+
+    /**
+     * CPU褰撳墠绛夊緟鐜�
+     */
+    private double wait;
+
+    /**
+     * CPU褰撳墠绌洪棽鐜�
+     */
+    private double free;
+
+    public int getCpuNum()
+    {
+        return cpuNum;
+    }
+
+    public void setCpuNum(int cpuNum)
+    {
+        this.cpuNum = cpuNum;
+    }
+
+    public double getTotal()
+    {
+        return Arith.round(Arith.mul(total, 100), 2);
+    }
+
+    public void setTotal(double total)
+    {
+        this.total = total;
+    }
+
+    public double getSys()
+    {
+        return Arith.round(Arith.mul(sys / total, 100), 2);
+    }
+
+    public void setSys(double sys)
+    {
+        this.sys = sys;
+    }
+
+    public double getUsed()
+    {
+        return Arith.round(Arith.mul(used / total, 100), 2);
+    }
+
+    public void setUsed(double used)
+    {
+        this.used = used;
+    }
+
+    public double getWait()
+    {
+        return Arith.round(Arith.mul(wait / total, 100), 2);
+    }
+
+    public void setWait(double wait)
+    {
+        this.wait = wait;
+    }
+
+    public double getFree()
+    {
+        return Arith.round(Arith.mul(free / total, 100), 2);
+    }
+
+    public void setFree(double free)
+    {
+        this.free = free;
+    }
+}
diff --git a/ycl-pojo/src/main/java/com/ycl/system/server/Jvm.java b/ycl-pojo/src/main/java/com/ycl/system/server/Jvm.java
new file mode 100644
index 0000000..91d334e
--- /dev/null
+++ b/ycl-pojo/src/main/java/com/ycl/system/server/Jvm.java
@@ -0,0 +1,131 @@
+package com.ycl.system.server;
+
+import utils.Arith;
+import utils.DateUtils;
+
+import java.lang.management.ManagementFactory;
+
+/**
+ * JVM鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Jvm
+{
+    /**
+     * 褰撳墠JVM鍗犵敤鐨勫唴瀛樻�绘暟(M)
+     */
+    private double total;
+
+    /**
+     * JVM鏈�澶у彲鐢ㄥ唴瀛樻�绘暟(M)
+     */
+    private double max;
+
+    /**
+     * JVM绌洪棽鍐呭瓨(M)
+     */
+    private double free;
+
+    /**
+     * JDK鐗堟湰
+     */
+    private String version;
+
+    /**
+     * JDK璺緞
+     */
+    private String home;
+
+    public double getTotal()
+    {
+        return Arith.div(total, (1024 * 1024), 2);
+    }
+
+    public void setTotal(double total)
+    {
+        this.total = total;
+    }
+
+    public double getMax()
+    {
+        return Arith.div(max, (1024 * 1024), 2);
+    }
+
+    public void setMax(double max)
+    {
+        this.max = max;
+    }
+
+    public double getFree()
+    {
+        return Arith.div(free, (1024 * 1024), 2);
+    }
+
+    public void setFree(double free)
+    {
+        this.free = free;
+    }
+
+    public double getUsed()
+    {
+        return Arith.div(total - free, (1024 * 1024), 2);
+    }
+
+    public double getUsage()
+    {
+        return Arith.mul(Arith.div(total - free, total, 4), 100);
+    }
+
+    /**
+     * 鑾峰彇JDK鍚嶇О
+     */
+    public String getName()
+    {
+        return ManagementFactory.getRuntimeMXBean().getVmName();
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public void setVersion(String version)
+    {
+        this.version = version;
+    }
+
+    public String getHome()
+    {
+        return home;
+    }
+
+    public void setHome(String home)
+    {
+        this.home = home;
+    }
+
+    /**
+     * JDK鍚姩鏃堕棿
+     */
+    public String getStartTime()
+    {
+        return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate());
+    }
+
+    /**
+     * JDK杩愯鏃堕棿
+     */
+    public String getRunTime()
+    {
+        return DateUtils.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate());
+    }
+
+    /**
+     * 杩愯鍙傛暟
+     */
+    public String getInputArgs()
+    {
+        return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();
+    }
+}
diff --git a/ycl-pojo/src/main/java/com/ycl/system/server/Mem.java b/ycl-pojo/src/main/java/com/ycl/system/server/Mem.java
new file mode 100644
index 0000000..e62a9a1
--- /dev/null
+++ b/ycl-pojo/src/main/java/com/ycl/system/server/Mem.java
@@ -0,0 +1,61 @@
+package com.ycl.system.server;
+
+import utils.Arith;
+
+/**
+ * 鍏у瓨鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Mem
+{
+    /**
+     * 鍐呭瓨鎬婚噺
+     */
+    private double total;
+
+    /**
+     * 宸茬敤鍐呭瓨
+     */
+    private double used;
+
+    /**
+     * 鍓╀綑鍐呭瓨
+     */
+    private double free;
+
+    public double getTotal()
+    {
+        return Arith.div(total, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setTotal(long total)
+    {
+        this.total = total;
+    }
+
+    public double getUsed()
+    {
+        return Arith.div(used, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setUsed(long used)
+    {
+        this.used = used;
+    }
+
+    public double getFree()
+    {
+        return Arith.div(free, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setFree(long free)
+    {
+        this.free = free;
+    }
+
+    public double getUsage()
+    {
+        return Arith.mul(Arith.div(used, total, 4), 100);
+    }
+}
diff --git a/ycl-pojo/src/main/java/com/ycl/system/server/Sys.java b/ycl-pojo/src/main/java/com/ycl/system/server/Sys.java
new file mode 100644
index 0000000..4801d15
--- /dev/null
+++ b/ycl-pojo/src/main/java/com/ycl/system/server/Sys.java
@@ -0,0 +1,84 @@
+package com.ycl.system.server;
+
+/**
+ * 绯荤粺鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Sys
+{
+    /**
+     * 鏈嶅姟鍣ㄥ悕绉�
+     */
+    private String computerName;
+
+    /**
+     * 鏈嶅姟鍣↖p
+     */
+    private String computerIp;
+
+    /**
+     * 椤圭洰璺緞
+     */
+    private String userDir;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String osName;
+
+    /**
+     * 绯荤粺鏋舵瀯
+     */
+    private String osArch;
+
+    public String getComputerName()
+    {
+        return computerName;
+    }
+
+    public void setComputerName(String computerName)
+    {
+        this.computerName = computerName;
+    }
+
+    public String getComputerIp()
+    {
+        return computerIp;
+    }
+
+    public void setComputerIp(String computerIp)
+    {
+        this.computerIp = computerIp;
+    }
+
+    public String getUserDir()
+    {
+        return userDir;
+    }
+
+    public void setUserDir(String userDir)
+    {
+        this.userDir = userDir;
+    }
+
+    public String getOsName()
+    {
+        return osName;
+    }
+
+    public void setOsName(String osName)
+    {
+        this.osName = osName;
+    }
+
+    public String getOsArch()
+    {
+        return osArch;
+    }
+
+    public void setOsArch(String osArch)
+    {
+        this.osArch = osArch;
+    }
+}
diff --git a/ycl-pojo/src/main/java/com/ycl/system/server/SysFile.java b/ycl-pojo/src/main/java/com/ycl/system/server/SysFile.java
new file mode 100644
index 0000000..5606356
--- /dev/null
+++ b/ycl-pojo/src/main/java/com/ycl/system/server/SysFile.java
@@ -0,0 +1,114 @@
+package com.ycl.system.server;
+
+/**
+ * 绯荤粺鏂囦欢鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class SysFile
+{
+    /**
+     * 鐩樼璺緞
+     */
+    private String dirName;
+
+    /**
+     * 鐩樼绫诲瀷
+     */
+    private String sysTypeName;
+
+    /**
+     * 鏂囦欢绫诲瀷
+     */
+    private String typeName;
+
+    /**
+     * 鎬诲ぇ灏�
+     */
+    private String total;
+
+    /**
+     * 鍓╀綑澶у皬
+     */
+    private String free;
+
+    /**
+     * 宸茬粡浣跨敤閲�
+     */
+    private String used;
+
+    /**
+     * 璧勬簮鐨勪娇鐢ㄧ巼
+     */
+    private double usage;
+
+    public String getDirName()
+    {
+        return dirName;
+    }
+
+    public void setDirName(String dirName)
+    {
+        this.dirName = dirName;
+    }
+
+    public String getSysTypeName()
+    {
+        return sysTypeName;
+    }
+
+    public void setSysTypeName(String sysTypeName)
+    {
+        this.sysTypeName = sysTypeName;
+    }
+
+    public String getTypeName()
+    {
+        return typeName;
+    }
+
+    public void setTypeName(String typeName)
+    {
+        this.typeName = typeName;
+    }
+
+    public String getTotal()
+    {
+        return total;
+    }
+
+    public void setTotal(String total)
+    {
+        this.total = total;
+    }
+
+    public String getFree()
+    {
+        return free;
+    }
+
+    public void setFree(String free)
+    {
+        this.free = free;
+    }
+
+    public String getUsed()
+    {
+        return used;
+    }
+
+    public void setUsed(String used)
+    {
+        this.used = used;
+    }
+
+    public double getUsage()
+    {
+        return usage;
+    }
+
+    public void setUsage(double usage)
+    {
+        this.usage = usage;
+    }
+}
diff --git a/ycl-server/pom.xml b/ycl-server/pom.xml
index 1e5d560..55b6025 100644
--- a/ycl-server/pom.xml
+++ b/ycl-server/pom.xml
@@ -17,7 +17,12 @@
     </properties>
 
     <dependencies>
-
+        <!-- 浠g爜鐢熸垚-->
+        <dependency>
+            <groupId>com.ycl</groupId>
+            <artifactId>ycl-generator</artifactId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>com.ycl</groupId>
             <artifactId>ycl-pojo</artifactId>
diff --git a/ycl-server/src/main/java/com/ycl/aop/DataScopeAspect.java b/ycl-server/src/main/java/com/ycl/aop/DataScopeAspect.java
new file mode 100644
index 0000000..f10ed83
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/aop/DataScopeAspect.java
@@ -0,0 +1,175 @@
+package com.ycl.aop;
+
+import annotation.DataScope;
+import com.ycl.context.PermissionContextHolder;
+import com.ycl.system.entity.BaseEntity;
+import com.ycl.system.entity.SysRole;
+import com.ycl.system.entity.SysUser;
+import com.ycl.system.model.LoginUser;
+import com.ycl.utils.SecurityUtils;
+import com.ycl.utils.StringUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.stereotype.Component;
+import utils.text.Convert;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鏁版嵁杩囨护澶勭悊
+ *
+ * @author ruoyi
+ */
+@Aspect
+@Component
+public class DataScopeAspect
+{
+    /**
+     * 鍏ㄩ儴鏁版嵁鏉冮檺
+     */
+    public static final String DATA_SCOPE_ALL = "1";
+
+    /**
+     * 鑷畾鏁版嵁鏉冮檺
+     */
+    public static final String DATA_SCOPE_CUSTOM = "2";
+
+    /**
+     * 閮ㄩ棬鏁版嵁鏉冮檺
+     */
+    public static final String DATA_SCOPE_DEPT = "3";
+
+    /**
+     * 閮ㄩ棬鍙婁互涓嬫暟鎹潈闄�
+     */
+    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
+
+    /**
+     * 浠呮湰浜烘暟鎹潈闄�
+     */
+    public static final String DATA_SCOPE_SELF = "5";
+
+    /**
+     * 鏁版嵁鏉冮檺杩囨护鍏抽敭瀛�
+     */
+    public static final String DATA_SCOPE = "dataScope";
+
+    @Before("@annotation(controllerDataScope)")
+    public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
+    {
+        clearDataScope(point);
+        handleDataScope(point, controllerDataScope);
+    }
+
+    protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
+    {
+        // 鑾峰彇褰撳墠鐨勭敤鎴�
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        if (StringUtils.isNotNull(loginUser))
+        {
+            SysUser currentUser = loginUser.getUser();
+            // 濡傛灉鏄秴绾х鐞嗗憳锛屽垯涓嶈繃婊ゆ暟鎹�
+            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
+            {
+                String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
+                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
+                        controllerDataScope.userAlias(), permission);
+            }
+        }
+    }
+
+    /**
+     * 鏁版嵁鑼冨洿杩囨护
+     *
+     * @param joinPoint 鍒囩偣
+     * @param user 鐢ㄦ埛
+     * @param deptAlias 閮ㄩ棬鍒悕
+     * @param userAlias 鐢ㄦ埛鍒悕
+     * @param permission 鏉冮檺瀛楃
+     */
+    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission)
+    {
+        StringBuilder sqlString = new StringBuilder();
+        List<String> conditions = new ArrayList<String>();
+
+        for (SysRole role : user.getRoles())
+        {
+            String dataScope = role.getDataScope();
+            if (!DATA_SCOPE_CUSTOM.equals(dataScope) && conditions.contains(dataScope))
+            {
+                continue;
+            }
+            if (StringUtils.isNotEmpty(permission) && StringUtils.isNotEmpty(role.getPermissions())
+                    && !StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
+            {
+                continue;
+            }
+            if (DATA_SCOPE_ALL.equals(dataScope))
+            {
+                sqlString = new StringBuilder();
+                conditions.add(dataScope);
+                break;
+            }
+            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(
+                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
+                        role.getRoleId()));
+            }
+            else if (DATA_SCOPE_DEPT.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
+            }
+            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(
+                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
+                        deptAlias, user.getDeptId(), user.getDeptId()));
+            }
+            else if (DATA_SCOPE_SELF.equals(dataScope))
+            {
+                if (StringUtils.isNotBlank(userAlias))
+                {
+                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
+                }
+                else
+                {
+                    // 鏁版嵁鏉冮檺涓轰粎鏈汉涓旀病鏈塽serAlias鍒悕涓嶆煡璇换浣曟暟鎹�
+                    sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
+                }
+            }
+            conditions.add(dataScope);
+        }
+
+        // 澶氳鑹叉儏鍐典笅锛屾墍鏈夎鑹查兘涓嶅寘鍚紶閫掕繃鏉ョ殑鏉冮檺瀛楃锛岃繖涓椂鍊檚qlString涔熶細涓虹┖锛屾墍浠ヨ闄愬埗涓�涓�,涓嶆煡璇换浣曟暟鎹�
+        if (StringUtils.isEmpty(conditions))
+        {
+            sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
+        }
+
+        if (StringUtils.isNotBlank(sqlString.toString()))
+        {
+            Object params = joinPoint.getArgs()[0];
+            if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
+            {
+                BaseEntity baseEntity = (BaseEntity) params;
+                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
+            }
+        }
+    }
+
+    /**
+     * 鎷兼帴鏉冮檺sql鍓嶅厛娓呯┖params.dataScope鍙傛暟闃叉娉ㄥ叆
+     */
+    private void clearDataScope(final JoinPoint joinPoint)
+    {
+        Object params = joinPoint.getArgs()[0];
+        if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
+        {
+            BaseEntity baseEntity = (BaseEntity) params;
+            baseEntity.getParams().put(DATA_SCOPE, "");
+        }
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/config/FastJson2JsonRedisSerializer.java b/ycl-server/src/main/java/com/ycl/config/FastJson2JsonRedisSerializer.java
new file mode 100644
index 0000000..44131e8
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/config/FastJson2JsonRedisSerializer.java
@@ -0,0 +1,49 @@
+package com.ycl.config;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.JSONWriter;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import java.nio.charset.Charset;
+
+/**
+ * Redis浣跨敤FastJson搴忓垪鍖�
+ * 
+ * @author ruoyi
+ */
+public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
+{
+    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+
+    private Class<T> clazz;
+
+    public FastJson2JsonRedisSerializer(Class<T> clazz)
+    {
+        super();
+        this.clazz = clazz;
+    }
+
+    @Override
+    public byte[] serialize(T t) throws SerializationException
+    {
+        if (t == null)
+        {
+            return new byte[0];
+        }
+        return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
+    }
+
+    @Override
+    public T deserialize(byte[] bytes) throws SerializationException
+    {
+        if (bytes == null || bytes.length <= 0)
+        {
+            return null;
+        }
+        String str = new String(bytes, DEFAULT_CHARSET);
+
+        return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/config/RedisConfig.java b/ycl-server/src/main/java/com/ycl/config/RedisConfig.java
new file mode 100644
index 0000000..86babf0
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/config/RedisConfig.java
@@ -0,0 +1,69 @@
+package com.ycl.config;
+
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.script.DefaultRedisScript;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * redis閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig extends CachingConfigurerSupport
+{
+    @Bean
+    @SuppressWarnings(value = { "unchecked", "rawtypes" })
+    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
+    {
+        RedisTemplate<Object, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
+
+        // 浣跨敤StringRedisSerializer鏉ュ簭鍒楀寲鍜屽弽搴忓垪鍖杛edis鐨刱ey鍊�
+        template.setKeySerializer(new StringRedisSerializer());
+        template.setValueSerializer(serializer);
+
+        // Hash鐨刱ey涔熼噰鐢⊿tringRedisSerializer鐨勫簭鍒楀寲鏂瑰紡
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(serializer);
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
+    @Bean
+    public DefaultRedisScript<Long> limitScript()
+    {
+        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
+        redisScript.setScriptText(limitScriptText());
+        redisScript.setResultType(Long.class);
+        return redisScript;
+    }
+
+    /**
+     * 闄愭祦鑴氭湰
+     */
+    private String limitScriptText()
+    {
+        return "local key = KEYS[1]\n" +
+                "local count = tonumber(ARGV[1])\n" +
+                "local time = tonumber(ARGV[2])\n" +
+                "local current = redis.call('get', key);\n" +
+                "if current and tonumber(current) > count then\n" +
+                "    return tonumber(current);\n" +
+                "end\n" +
+                "current = redis.call('incr', key)\n" +
+                "if tonumber(current) == 1 then\n" +
+                "    redis.call('expire', key, time)\n" +
+                "end\n" +
+                "return tonumber(current);";
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/config/SecurityConfig.java b/ycl-server/src/main/java/com/ycl/config/SecurityConfig.java
index 7005cfa..de57a5f 100644
--- a/ycl-server/src/main/java/com/ycl/config/SecurityConfig.java
+++ b/ycl-server/src/main/java/com/ycl/config/SecurityConfig.java
@@ -24,8 +24,6 @@
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 import org.springframework.security.web.authentication.logout.LogoutFilter;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 import org.springframework.web.filter.CorsFilter;
 
 /**
@@ -71,7 +69,7 @@
     /**
      * 鍏佽鍖垮悕璁块棶鐨勫湴鍧�
      */
-    @Autowired
+    @Resource
     private PermitAllUrlProperties permitAllUrl;
 
     @Bean
diff --git a/ycl-server/src/main/java/com/ycl/handler/GlobalExceptionHandler.java b/ycl-server/src/main/java/com/ycl/handler/GlobalExceptionHandler.java
new file mode 100644
index 0000000..bcaade1
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/handler/GlobalExceptionHandler.java
@@ -0,0 +1,114 @@
+package com.ycl.handler;
+
+import com.ycl.exception.DemoModeException;
+import com.ycl.exception.ServiceException;
+import com.ycl.system.AjaxResult;
+import com.ycl.utils.StringUtils;
+import constant.HttpStatus;
+import jakarta.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+/**
+ * 鍏ㄥ眬寮傚父澶勭悊鍣�
+ * 
+ * @author ruoyi
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler
+{
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    /**
+     * 鏉冮檺鏍¢獙寮傚父
+     */
+    @ExceptionHandler(AccessDeniedException.class)
+    public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鏉冮檺鏍¢獙澶辫触'{}'", requestURI, e.getMessage());
+        return AjaxResult.error(HttpStatus.FORBIDDEN, "娌℃湁鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉�");
+    }
+
+    /**
+     * 璇锋眰鏂瑰紡涓嶆敮鎸�
+     */
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
+            HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',涓嶆敮鎸�'{}'璇锋眰", requestURI, e.getMethod());
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 涓氬姟寮傚父
+     */
+    @ExceptionHandler(ServiceException.class)
+    public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
+    {
+        log.error(e.getMessage(), e);
+        Integer code = e.getCode();
+        return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 鎷︽埅鏈煡鐨勮繍琛屾椂寮傚父
+     */
+    @ExceptionHandler(RuntimeException.class)
+    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓鏈煡寮傚父.", requestURI, e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 绯荤粺寮傚父
+     */
+    @ExceptionHandler(Exception.class)
+    public AjaxResult handleException(Exception e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("璇锋眰鍦板潃'{}',鍙戠敓绯荤粺寮傚父.", requestURI, e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 鑷畾涔夐獙璇佸紓甯�
+     */
+    @ExceptionHandler(BindException.class)
+    public AjaxResult handleBindException(BindException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getAllErrors().get(0).getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 鑷畾涔夐獙璇佸紓甯�
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 婕旂ず妯″紡寮傚父
+     */
+    @ExceptionHandler(DemoModeException.class)
+    public AjaxResult handleDemoModeException(DemoModeException e)
+    {
+        return AjaxResult.error("婕旂ず妯″紡锛屼笉鍏佽鎿嶄綔");
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/properties/PermitAllUrlProperties.java b/ycl-server/src/main/java/com/ycl/properties/PermitAllUrlProperties.java
index a924f8d..f876a8f 100644
--- a/ycl-server/src/main/java/com/ycl/properties/PermitAllUrlProperties.java
+++ b/ycl-server/src/main/java/com/ycl/properties/PermitAllUrlProperties.java
@@ -34,7 +34,7 @@
     @Override
     public void afterPropertiesSet()
     {
-        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
+        RequestMappingHandlerMapping mapping = applicationContext.getBean("requestMappingHandlerMapping",RequestMappingHandlerMapping.class);
         Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
 
         map.keySet().forEach(info -> {
diff --git a/ycl-server/src/main/java/com/ycl/system/controller/SysLogininforController.java b/ycl-server/src/main/java/com/ycl/system/controller/SysLogininforController.java
new file mode 100644
index 0000000..2871824
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/system/controller/SysLogininforController.java
@@ -0,0 +1,77 @@
+package com.ycl.system.controller;
+
+import annotation.Log;
+import com.ycl.system.AjaxResult;
+import com.ycl.system.domain.SysLogininfor;
+import com.ycl.system.page.TableDataInfo;
+import com.ycl.system.service.ISysLogininforService;
+import com.ycl.system.service.SysPasswordService;
+import com.ycl.utils.poi.ExcelUtil;
+import enumeration.BusinessType;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 绯荤粺璁块棶璁板綍
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/logininfor")
+public class SysLogininforController extends BaseController
+{
+    @Autowired
+    private ISysLogininforService logininforService;
+
+    @Autowired
+    private SysPasswordService passwordService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysLogininfor logininfor)
+    {
+        startPage();
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        return getDataTable(list);
+    }
+
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysLogininfor logininfor)
+    {
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
+        util.exportExcel(response, list, "鐧诲綍鏃ュ織");
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{infoIds}")
+    public AjaxResult remove(@PathVariable Long[] infoIds)
+    {
+        return toAjax(logininforService.deleteLogininforByIds(infoIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        logininforService.cleanLogininfor();
+        return success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
+    @Log(title = "璐︽埛瑙i攣", businessType = BusinessType.OTHER)
+    @GetMapping("/unlock/{userName}")
+    public AjaxResult unlock(@PathVariable("userName") String userName)
+    {
+        passwordService.clearLoginRecordCache(userName);
+        return success();
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/system/controller/SysOperlogController.java b/ycl-server/src/main/java/com/ycl/system/controller/SysOperlogController.java
new file mode 100644
index 0000000..cc0c16d
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/system/controller/SysOperlogController.java
@@ -0,0 +1,64 @@
+package com.ycl.system.controller;
+
+import annotation.Log;
+import com.ycl.system.AjaxResult;
+import com.ycl.system.domain.SysOperLog;
+import com.ycl.system.page.TableDataInfo;
+import com.ycl.system.service.ISysOperLogService;
+import com.ycl.utils.poi.ExcelUtil;
+import enumeration.BusinessType;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/operlog")
+public class SysOperlogController extends BaseController
+{
+    @Autowired
+    private ISysOperLogService operLogService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysOperLog operLog)
+    {
+        startPage();
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        return getDataTable(list);
+    }
+
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysOperLog operLog)
+    {
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
+        util.exportExcel(response, list, "鎿嶄綔鏃ュ織");
+    }
+
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.DELETE)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds)
+    {
+        return toAjax(operLogService.deleteOperLogByIds(operIds));
+    }
+
+    @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.CLEAN)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        operLogService.cleanOperLog();
+        return success();
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/system/monitor/CacheController.java b/ycl-server/src/main/java/com/ycl/system/monitor/CacheController.java
new file mode 100644
index 0000000..0b6e57c
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/system/monitor/CacheController.java
@@ -0,0 +1,111 @@
+package com.ycl.system.monitor;
+
+import com.ycl.system.AjaxResult;
+import com.ycl.system.domain.SysCache;
+import constant.CacheConstants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import utils.StringUtils;
+
+import java.util.*;
+
+/**
+ * 缂撳瓨鐩戞帶
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/cache")
+public class CacheController
+{
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    private final static List<SysCache> caches = new ArrayList<SysCache>();
+    {
+        caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "鐢ㄦ埛淇℃伅"));
+        caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "閰嶇疆淇℃伅"));
+        caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "鏁版嵁瀛楀吀"));
+        caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "楠岃瘉鐮�"));
+        caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "闃查噸鎻愪氦"));
+        caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "闄愭祦澶勭悊"));
+        caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "瀵嗙爜閿欒娆℃暟"));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
+        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
+        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
+
+        Map<String, Object> result = new HashMap<>(3);
+        result.put("info", info);
+        result.put("dbSize", dbSize);
+
+        List<Map<String, String>> pieList = new ArrayList<>();
+        commandStats.stringPropertyNames().forEach(key -> {
+            Map<String, String> data = new HashMap<>(2);
+            String property = commandStats.getProperty(key);
+            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+            pieList.add(data);
+        });
+        result.put("commandStats", pieList);
+        return AjaxResult.success(result);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getNames")
+    public AjaxResult cache()
+    {
+        return AjaxResult.success(caches);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getKeys/{cacheName}")
+    public AjaxResult getCacheKeys(@PathVariable String cacheName)
+    {
+        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        return AjaxResult.success(cacheKeys);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getValue/{cacheName}/{cacheKey}")
+    public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
+    {
+        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
+        SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
+        return AjaxResult.success(sysCache);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheName/{cacheName}")
+    public AjaxResult clearCacheName(@PathVariable String cacheName)
+    {
+        Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheKey/{cacheKey}")
+    public AjaxResult clearCacheKey(@PathVariable String cacheKey)
+    {
+        redisTemplate.delete(cacheKey);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheAll")
+    public AjaxResult clearCacheAll()
+    {
+        Collection<String> cacheKeys = redisTemplate.keys("*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/system/monitor/ServerController.java b/ycl-server/src/main/java/com/ycl/system/monitor/ServerController.java
new file mode 100644
index 0000000..42a1575
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/system/monitor/ServerController.java
@@ -0,0 +1,27 @@
+package com.ycl.system.monitor;
+
+import com.ycl.system.AjaxResult;
+import com.ycl.system.Server;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 鏈嶅姟鍣ㄧ洃鎺�
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/server")
+public class ServerController
+{
+    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Server server = new Server();
+        server.copyTo();
+        return AjaxResult.success(server);
+    }
+}
diff --git a/ycl-server/src/main/java/com/ycl/system/monitor/SysUserOnlineController.java b/ycl-server/src/main/java/com/ycl/system/monitor/SysUserOnlineController.java
new file mode 100644
index 0000000..3a16283
--- /dev/null
+++ b/ycl-server/src/main/java/com/ycl/system/monitor/SysUserOnlineController.java
@@ -0,0 +1,80 @@
+package com.ycl.system.monitor;
+
+import annotation.Log;
+import com.ycl.system.AjaxResult;
+import com.ycl.system.controller.BaseController;
+import com.ycl.system.domain.SysUserOnline;
+import com.ycl.system.model.LoginUser;
+import com.ycl.system.page.TableDataInfo;
+import com.ycl.system.service.ISysUserOnlineService;
+import com.ycl.utils.redis.RedisCache;
+import constant.CacheConstants;
+import enumeration.BusinessType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import utils.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 鍦ㄧ嚎鐢ㄦ埛鐩戞帶
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/online")
+public class SysUserOnlineController extends BaseController
+{
+    @Autowired
+    private ISysUserOnlineService userOnlineService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @PreAuthorize("@ss.hasPermi('monitor:online:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(String ipaddr, String userName)
+    {
+        Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
+        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
+        for (String key : keys)
+        {
+            LoginUser user = redisCache.getCacheObject(key);
+            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
+            }
+            else if (StringUtils.isNotEmpty(ipaddr))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
+            }
+            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
+            }
+            else
+            {
+                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
+            }
+        }
+        Collections.reverse(userOnlineList);
+        userOnlineList.removeAll(Collections.singleton(null));
+        return getDataTable(userOnlineList);
+    }
+
+    /**
+     * 寮洪��鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
+    @Log(title = "鍦ㄧ嚎鐢ㄦ埛", businessType = BusinessType.FORCE)
+    @DeleteMapping("/{tokenId}")
+    public AjaxResult forceLogout(@PathVariable String tokenId)
+    {
+        redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
+        return success();
+    }
+}
diff --git a/ycl-server/src/main/resources/application.yml b/ycl-server/src/main/resources/application.yml
index 1f21e84..6cb55a0 100644
--- a/ycl-server/src/main/resources/application.yml
+++ b/ycl-server/src/main/resources/application.yml
@@ -52,7 +52,7 @@
   # 浠ょ墝瀵嗛挜
   secret: 1212121hsodhsdhasdhsaldhsalhdlsahdlsad1212121hsodhsdhasdhsaldhsalhdlsahdlsad1212121hsodhsdhasdhsaldhsalhdlsahdlsad1212121hsodhsdhasdhsaldhsalhdlsahdlsad1212121hsodhsdhasdhsaldhsalhdlsahdlsad1212121hsodhsdhasdhsaldhsalhdlsahdlsadlsadhsaldhsalhdlsahdlsadlsad
   # 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
-  expireTime: 30
+  expireTime: 300
 
 #MP閰嶇疆
 mybatis-plus:

--
Gitblit v1.8.0