list = this.selectList(wrapper);
+ if (CollUtil.isEmpty(list)) {
+ return CollUtil.newArrayList();
+ }
+ return MapstructUtils.convert(list, voClass);
+ }
+
+ default > P selectVoPage(IPage page, Wrapper wrapper) {
+ return selectVoPage(page, wrapper, this.currentVoClass());
+ }
+
+ /**
+ * 分页查询VO
+ */
+ default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) {
+ IPage pageData = this.selectPage(page, wrapper);
+ IPage voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
+ if (CollUtil.isEmpty(pageData.getRecords())) {
+ return (P) voPage;
+ }
+ voPage.setRecords(MapstructUtils.convert(pageData.getRecords(), voClass));
+ return (P) voPage;
+ }
+
+ default List selectObjs(Wrapper wrapper, Function super Object, C> mapper) {
+ return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
+ }
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseHelper.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseHelper.java
new file mode 100644
index 00000000..22243391
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseHelper.java
@@ -0,0 +1,76 @@
+package cc.iotkit.generator.core;
+
+import cc.iotkit.common.exception.BizException;
+import cc.iotkit.common.utils.SpringUtils;
+import cn.hutool.core.convert.Convert;
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+/**
+ * 数据库助手
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class DataBaseHelper {
+
+ private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class);
+
+ /**
+ * 获取当前数据库类型
+ */
+ public static DataBaseType getDataBaseType() {
+ DataSource dataSource = DS.determineDataSource();
+ try (Connection conn = dataSource.getConnection()) {
+ DatabaseMetaData metaData = conn.getMetaData();
+ String databaseProductName = metaData.getDatabaseProductName();
+ return DataBaseType.find(databaseProductName);
+ } catch (SQLException e) {
+ throw new BizException(e.getMessage());
+ }
+ }
+
+ public static boolean isMySql() {
+ return DataBaseType.MY_SQL == getDataBaseType();
+ }
+
+ public static boolean isH2() {
+ return DataBaseType.H2 == getDataBaseType();
+ }
+
+
+ public static boolean isOracle() {
+ return DataBaseType.ORACLE == getDataBaseType();
+ }
+
+ public static boolean isPostgerSql() {
+ return DataBaseType.POSTGRE_SQL == getDataBaseType();
+ }
+
+ public static boolean isSqlServer() {
+ return DataBaseType.SQL_SERVER == getDataBaseType();
+ }
+
+ public static String findInSet(Object var1, String var2) {
+ DataBaseType dataBasyType = getDataBaseType();
+ String var = Convert.toStr(var1);
+ if (dataBasyType == DataBaseType.SQL_SERVER) {
+ // charindex(',100,' , ',0,100,101,') <> 0
+ return String.format("charindex(',%s,' , ','+%s+',') <> 0",var, var2 );
+ } else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
+ // (select position(',100,' in ',0,100,101,')) <> 0
+ return String.format("(select position(',%s,' in ','||%s||',')) <> 0", var, var2);
+ } else if (dataBasyType == DataBaseType.ORACLE) {
+ // instr(',0,100,101,' , ',100,') <> 0
+ return String.format("instr(','||%s||',' , ',%s,') <> 0",var2, var );
+ }
+ // find_in_set(100 , '0,100,101')
+ return String.format("find_in_set('%s' , %s) <> 0", var, var2);
+ }
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseType.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseType.java
new file mode 100644
index 00000000..06168643
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DataBaseType.java
@@ -0,0 +1,51 @@
+package cc.iotkit.generator.core;
+
+import cc.iotkit.common.utils.StringUtils;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+
+/**
+ * 数据库类型
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum DataBaseType {
+
+ /**
+ * MySQL
+ */
+ MY_SQL("MySQL"),
+
+ H2("H2"),
+ /**
+ * Oracle
+ */
+ ORACLE("Oracle"),
+
+ /**
+ * PostgreSQL
+ */
+ POSTGRE_SQL("PostgreSQL"),
+
+ /**
+ * SQL Server
+ */
+ SQL_SERVER("Microsoft SQL Server");
+
+ private final String type;
+
+ public static DataBaseType find(String databaseProductName) {
+ if (StringUtils.isBlank(databaseProductName)) {
+ return null;
+ }
+ for (DataBaseType type : values()) {
+ if (type.getType().equals(databaseProductName)) {
+ return type;
+ }
+ }
+ return null;
+ }
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DbIdGenerator.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DbIdGenerator.java
new file mode 100644
index 00000000..f1c748e8
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/DbIdGenerator.java
@@ -0,0 +1,30 @@
+package cc.iotkit.generator.core;
+
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.github.yitter.contract.IdGeneratorOptions;
+import com.github.yitter.idgen.YitIdHelper;
+
+/**
+ * @author: Jay
+ * @description:
+ * @date:created in 2023/5/18 10:20
+ * @modificed by:
+ */
+public class DbIdGenerator implements IdentifierGenerator {
+
+
+ public DbIdGenerator(Short workerId) {
+// 使用网卡信息绑定雪花生成器
+// 防止集群雪花ID重复
+
+ IdGeneratorOptions options = new IdGeneratorOptions(workerId);
+ YitIdHelper.setIdGenerator(options);
+ }
+
+
+
+ @Override
+ public Number nextId(Object entity) {
+ return YitIdHelper.nextId();
+ }
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageBuilder.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageBuilder.java
new file mode 100644
index 00000000..0d5d7510
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageBuilder.java
@@ -0,0 +1,25 @@
+package cc.iotkit.generator.core;
+
+import cc.iotkit.common.api.PageRequest;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import java.io.Serializable;
+
+/**
+ * 分页查询实体类
+ *
+ * @author Lion Li
+ */
+
+
+public class PageBuilder implements Serializable {
+
+
+ public static Page build(PageRequest pageRequest) {
+ Integer pageNum = ObjectUtil.defaultIfNull(pageRequest.getPageNum(), PageQuery.DEFAULT_PAGE_NUM);
+ Integer pageSize = ObjectUtil.defaultIfNull(pageRequest.getPageSize(), PageQuery.DEFAULT_PAGE_SIZE);
+ return new Page(pageNum, pageSize);
+ }
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageQuery.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageQuery.java
new file mode 100644
index 00000000..efab0216
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/PageQuery.java
@@ -0,0 +1,113 @@
+package cc.iotkit.generator.core;
+
+import cc.iotkit.common.exception.BizException;
+import cc.iotkit.common.utils.StringUtils;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 分页查询实体类
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class PageQuery implements Serializable {
+
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 分页大小
+ */
+ private Integer pageSize;
+
+ /**
+ * 当前页数
+ */
+ private Integer pageNum;
+
+ /**
+ * 排序列
+ */
+ private String orderByColumn;
+
+ /**
+ * 排序的方向desc或者asc
+ */
+ private String isAsc;
+
+ /**
+ * 当前记录起始索引 默认值
+ */
+ public static final int DEFAULT_PAGE_NUM = 1;
+
+ /**
+ * 每页显示记录数 默认值 默认查全部
+ */
+ public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE;
+
+ public Page build() {
+ Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM);
+ Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE);
+ if (pageNum <= 0) {
+ pageNum = DEFAULT_PAGE_NUM;
+ }
+ Page page = new Page<>(pageNum, pageSize);
+ List orderItems = buildOrderItem();
+ if (CollUtil.isNotEmpty(orderItems)) {
+ page.addOrder(orderItems);
+ }
+ return page;
+ }
+
+ /**
+ * 构建排序
+ *
+ * 支持的用法如下:
+ * {isAsc:"asc",orderByColumn:"id"} order by id asc
+ * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
+ * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
+ * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
+ */
+ private List buildOrderItem() {
+ if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) {
+ return Collections.emptyList();
+ }
+ String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
+ orderBy = StringUtils.toUnderScoreCase(orderBy);
+
+ // 兼容前端排序类型
+ isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"});
+
+ String[] orderByArr = orderBy.split(StringUtils.SEPARATOR);
+ String[] isAscArr = isAsc.split(StringUtils.SEPARATOR);
+ if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) {
+ throw new BizException("排序参数有误");
+ }
+
+ List list = new ArrayList<>();
+ // 每个字段各自排序
+ for (int i = 0; i < orderByArr.length; i++) {
+ String orderByStr = orderByArr[i];
+ String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i];
+ if ("asc".equals(isAscStr)) {
+ list.add(OrderItem.asc(orderByStr));
+ } else if ("desc".equals(isAscStr)) {
+ list.add(OrderItem.desc(orderByStr));
+ } else {
+ throw new BizException("排序参数有误");
+ }
+ }
+ return list;
+ }
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/SqlUtil.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/SqlUtil.java
new file mode 100644
index 00000000..c4fb2979
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/core/SqlUtil.java
@@ -0,0 +1,58 @@
+package cc.iotkit.generator.core;
+
+import cc.iotkit.common.utils.StringUtils;
+import cn.hutool.core.exceptions.UtilException;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * sql操作工具类
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class SqlUtil {
+
+ /**
+ * 定义常用的 sql关键字
+ */
+ public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
+
+ /**
+ * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
+ */
+ public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
+
+ /**
+ * 检查字符,防止注入绕过
+ */
+ public static String escapeOrderBySql(String value) {
+ if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) {
+ 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/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTable.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTable.java
new file mode 100644
index 00000000..16c1a903
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTable.java
@@ -0,0 +1,196 @@
+package cc.iotkit.generator.domain;
+
+import cc.iotkit.common.utils.StringUtils;
+import cc.iotkit.generator.constant.GenConstants;
+import cc.iotkit.generator.core.BaseEntity;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+/**
+ * 业务表 gen_table
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("gen_table")
+public class GenTable extends BaseEntity {
+
+ /**
+ * 编号
+ */
+ @TableId(value = "table_id")
+ private Long tableId;
+
+ /**
+ * 数据源名称
+ */
+ @NotBlank(message = "数据源名称不能为空")
+ private String dataName;
+
+ /**
+ * 表名称
+ */
+ @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;
+
+ /**
+ * 生成代码方式(0zip压缩包 1自定义路径)
+ */
+ private String genType;
+
+ /**
+ * 生成路径(不填默认项目路径)
+ */
+ @TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+ private String genPath;
+
+ /**
+ * 主键信息
+ */
+ @TableField(exist = false)
+ private GenTableColumn pkColumn;
+
+ /**
+ * 表列信息
+ */
+ @Valid
+ @TableField(exist = false)
+ private List columns;
+
+ /**
+ * 其它生成选项
+ */
+ private String options;
+
+ /**
+ * 备注
+ */
+ private String remark;
+
+ /**
+ * 树编码字段
+ */
+ @TableField(exist = false)
+ private String treeCode;
+
+ /**
+ * 树父编码字段
+ */
+ @TableField(exist = false)
+ private String treeParentCode;
+
+ /**
+ * 树名称字段
+ */
+ @TableField(exist = false)
+ private String treeName;
+
+ /*
+ * 菜单id列表
+ */
+ @TableField(exist = false)
+ private List menuIds;
+
+ /**
+ * 上级菜单ID字段
+ */
+ @TableField(exist = false)
+ private String parentMenuId;
+
+ /**
+ * 上级菜单名称字段
+ */
+ @TableField(exist = false)
+ private String parentMenuName;
+
+ 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) {
+ return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
+ }
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTableColumn.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTableColumn.java
new file mode 100644
index 00000000..6535f28f
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/domain/GenTableColumn.java
@@ -0,0 +1,222 @@
+package cc.iotkit.generator.domain;
+
+import cc.iotkit.common.utils.StringUtils;
+import cc.iotkit.generator.core.BaseEntity;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.ibatis.type.JdbcType;
+
+/**
+ * 代码生成业务字段表 gen_table_column
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("gen_table_column")
+public class GenTableColumn extends BaseEntity {
+
+ /**
+ * 编号
+ */
+ @TableId(value = "column_id")
+ private Long columnId;
+
+ /**
+ * 归属表编号
+ */
+ private Long tableId;
+
+ /**
+ * 列名称
+ */
+ private String columnName;
+
+ /**
+ * 列描述
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String columnComment;
+
+ /**
+ * 列类型
+ */
+ private String columnType;
+
+ /**
+ * JAVA类型
+ */
+ private String javaType;
+
+ /**
+ * JAVA字段名
+ */
+ @NotBlank(message = "Java属性不能为空")
+ private String javaField;
+
+ /**
+ * 是否主键(1是)
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isPk;
+
+ /**
+ * 是否自增(1是)
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isIncrement;
+
+ /**
+ * 是否必填(1是)
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isRequired;
+
+ /**
+ * 是否为插入字段(1是)
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isInsert;
+
+ /**
+ * 是否编辑字段(1是)
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isEdit;
+
+ /**
+ * 是否列表字段(1是)
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isList;
+
+ /**
+ * 是否查询字段(1是)
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isQuery;
+
+ /**
+ * 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围)
+ */
+ private String queryType;
+
+ /**
+ * 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件)
+ */
+ private String htmlType;
+
+ /**
+ * 字典类型
+ */
+ private String dictType;
+
+ /**
+ * 排序
+ */
+ private Integer sort;
+
+ public String getCapJavaField() {
+ return StringUtils.capitalize(javaField);
+ }
+
+ public boolean isPk() {
+ return isPk(this.isPk);
+ }
+
+ public boolean isPk(String isPk) {
+ return isPk != null && StringUtils.equals("1", isPk);
+ }
+
+ public boolean isIncrement() {
+ return isIncrement(this.isIncrement);
+ }
+
+ public boolean isIncrement(String isIncrement) {
+ return isIncrement != null && StringUtils.equals("1", isIncrement);
+ }
+
+ public boolean isRequired() {
+ return isRequired(this.isRequired);
+ }
+
+ public boolean isRequired(String isRequired) {
+ return isRequired != null && StringUtils.equals("1", isRequired);
+ }
+
+ public boolean isInsert() {
+ return isInsert(this.isInsert);
+ }
+
+ public boolean isInsert(String isInsert) {
+ return isInsert != null && StringUtils.equals("1", isInsert);
+ }
+
+ public boolean isEdit() {
+ return isInsert(this.isEdit);
+ }
+
+ public boolean isEdit(String isEdit) {
+ return isEdit != null && StringUtils.equals("1", isEdit);
+ }
+
+ public boolean isList() {
+ return isList(this.isList);
+ }
+
+ public boolean isList(String isList) {
+ return isList != null && StringUtils.equals("1", isList);
+ }
+
+ public boolean isQuery() {
+ return isQuery(this.isQuery);
+ }
+
+ public boolean isQuery(String isQuery) {
+ return isQuery != null && StringUtils.equals("1", isQuery);
+ }
+
+ public boolean isSuperColumn() {
+ return isSuperColumn(this.javaField);
+ }
+
+ public static boolean isSuperColumn(String javaField) {
+ return StringUtils.equalsAnyIgnoreCase(javaField,
+ // BaseEntity
+ "createBy", "createTime", "updateBy", "updateTime",
+ // TreeEntity
+ "parentName", "parentId");
+ }
+
+ 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(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR);
+ }
+ }
+ return sb.deleteCharAt(sb.length() - 1).toString();
+ } else {
+ return this.columnComment;
+ }
+ }
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/dto/bo/ImportTableBo.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/dto/bo/ImportTableBo.java
new file mode 100644
index 00000000..19544e38
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/dto/bo/ImportTableBo.java
@@ -0,0 +1,24 @@
+package cc.iotkit.generator.dto.bo;
+
+import cc.iotkit.common.api.BaseDto;
+import io.swagger.annotations.ApiModelProperty;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @Author: jay
+ * @Date: 2023/6/24 16:47
+ * @Version: V1.0
+ * @Description: 导入表Bo
+ */
+@Data
+public class ImportTableBo extends BaseDto {
+
+ @ApiModelProperty(value = "表名列表", notes = "表名列表")
+ @NotEmpty(message = "表名列表不能为空")
+ private List tables;
+
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/factory/YmlPropertySourceFactory.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/factory/YmlPropertySourceFactory.java
new file mode 100644
index 00000000..cd5933b8
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/factory/YmlPropertySourceFactory.java
@@ -0,0 +1,32 @@
+package cc.iotkit.generator.factory;
+
+
+import cc.iotkit.common.utils.StringUtils;
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.env.PropertiesPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.support.DefaultPropertySourceFactory;
+import org.springframework.core.io.support.EncodedResource;
+
+import java.io.IOException;
+
+/**
+ * yml 配置源工厂
+ *
+ * @author Lion Li
+ */
+public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
+
+ @Override
+ public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException {
+ String sourceName = resource.getResource().getFilename();
+ if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) {
+ YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
+ factory.setResources(resource.getResource());
+ factory.afterPropertiesSet();
+ return new PropertiesPropertySource(sourceName, factory.getObject());
+ }
+ return super.createPropertySource(name, resource);
+ }
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableColumnMapper.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableColumnMapper.java
new file mode 100644
index 00000000..ad5a4a53
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableColumnMapper.java
@@ -0,0 +1,24 @@
+package cc.iotkit.generator.mapper;
+
+import cc.iotkit.generator.core.BaseMapperPlus;
+import cc.iotkit.generator.domain.GenTableColumn;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+
+import java.util.List;
+
+/**
+ * 业务字段 数据层
+ *
+ * @author Lion Li
+ */
+@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
+public interface GenTableColumnMapper extends BaseMapperPlus {
+ /**
+ * 根据表名称查询列信息
+ *
+ * @param tableName 表名称
+ * @return 列信息
+ */
+ List selectDbTableColumnsByName(String tableName);
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableMapper.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableMapper.java
new file mode 100644
index 00000000..42f8f9bd
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/mapper/GenTableMapper.java
@@ -0,0 +1,63 @@
+package cc.iotkit.generator.mapper;
+
+import cc.iotkit.generator.core.BaseMapperPlus;
+import cc.iotkit.generator.domain.GenTable;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 业务 数据层
+ *
+ * @author Lion Li
+ */
+@InterceptorIgnore( tenantLine = "true")
+public interface GenTableMapper extends BaseMapperPlus {
+
+ /**
+ * 查询据库列表
+ *
+ * @param genTable 查询条件
+ * @return 数据库表集合
+ */
+ @InterceptorIgnore( tenantLine = "true")
+ Page selectPageDbTableList(@Param("page") Page page, @Param("genTable") GenTable genTable);
+
+ /**
+ * 查询据库列表
+ *
+ * @param tableNames 表名称组
+ * @return 数据库表集合
+ */
+ List selectDbTableListByNames(Collection tableNames);
+
+ /**
+ * 查询所有表信息
+ *
+ * @return 表信息集合
+ */
+ List selectGenTableAll();
+
+ /**
+ * 查询表ID业务信息
+ *
+ * @param id 业务ID
+ * @return 业务信息
+ */
+ GenTable selectGenTableById(Long id);
+
+ /**
+ * 查询表名称业务信息
+ *
+ * @param tableName 表名称
+ * @return 业务信息
+ */
+ GenTable selectGenTableByName(String tableName);
+
+ List selectTableNameList(String dataName);
+
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/GenTableServiceImpl.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/GenTableServiceImpl.java
new file mode 100644
index 00000000..7887ca3e
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/GenTableServiceImpl.java
@@ -0,0 +1,463 @@
+package cc.iotkit.generator.service;
+
+import cc.iotkit.common.api.PageRequest;
+import cc.iotkit.common.api.Paging;
+import cc.iotkit.common.constant.Constants;
+import cc.iotkit.common.exception.BizException;
+import cc.iotkit.common.satoken.utils.LoginHelper;
+import cc.iotkit.common.utils.JsonUtils;
+import cc.iotkit.common.utils.StreamUtils;
+import cc.iotkit.common.utils.StringUtils;
+import cc.iotkit.common.utils.file.FileUtils;
+import cc.iotkit.generator.constant.GenConstants;
+import cc.iotkit.generator.core.DbIdGenerator;
+import cc.iotkit.generator.core.PageBuilder;
+import cc.iotkit.generator.domain.GenTable;
+import cc.iotkit.generator.domain.GenTableColumn;
+import cc.iotkit.generator.mapper.GenTableColumnMapper;
+import cc.iotkit.generator.mapper.GenTableMapper;
+import cc.iotkit.generator.util.GenUtils;
+import cc.iotkit.generator.util.VelocityInitializer;
+import cc.iotkit.generator.util.VelocityUtils;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * 业务 服务层实现
+ *
+ * @author Lion Li
+ */
+@DS("#header.datasource")
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class GenTableServiceImpl implements IGenTableService {
+
+ private final GenTableMapper baseMapper;
+ private final GenTableColumnMapper genTableColumnMapper;
+ private final DbIdGenerator identifierGenerator;
+
+ /**
+ * 查询业务字段列表
+ *
+ * @param tableId 业务字段编号
+ * @return 业务字段集合
+ */
+ @Override
+ public List selectGenTableColumnListByTableId(Long tableId) {
+ return genTableColumnMapper.selectList(new LambdaQueryWrapper()
+ .eq(GenTableColumn::getTableId, tableId)
+ .orderByAsc(GenTableColumn::getSort));
+ }
+
+ /**
+ * 查询业务信息
+ *
+ * @param id 业务ID
+ * @return 业务信息
+ */
+ @Override
+ public GenTable selectGenTableById(Long id) {
+ GenTable genTable = baseMapper.selectGenTableById(id);
+ setTableFromOptions(genTable);
+ return genTable;
+ }
+
+ @Override
+ public Paging selectPageGenTableList( PageRequest pageQuery) {
+ Page page = baseMapper.selectPage(PageBuilder.build(pageQuery), this.buildGenTableQueryWrapper(pageQuery.getData()));
+ return new Paging<>(page.getTotal(), page.getRecords());
+ }
+
+ private QueryWrapper buildGenTableQueryWrapper(GenTable genTable) {
+ Map params = genTable.getParams();
+ QueryWrapper wrapper = Wrappers.query();
+ wrapper.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
+ .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
+ .between(StringUtils.isNotBlank((CharSequence) params.get("beginTime")) && StringUtils.isNotBlank((CharSequence) params.get("endTime")),
+ "create_time", params.get("beginTime"), params.get("endTime"));
+ return wrapper;
+ }
+
+
+ @Override
+ public Paging selectPageDbTableList(PageRequest pageQuery) {
+ GenTable genTable = pageQuery.getData();
+ genTable.getParams().put("genTableNames",baseMapper.selectTableNameList(genTable.getDataName()));
+
+ Page page = baseMapper.selectPageDbTableList(PageBuilder.build(pageQuery), genTable);
+ return new Paging<>(page.getTotal(), page.getRecords());
+ }
+
+ /**
+ * 查询据库列表
+ *
+ * @param tableNames 表名称组
+ * @return 数据库表集合
+ */
+ @Override
+ public List selectDbTableListByNames(Collection tableNames) {
+ return baseMapper.selectDbTableListByNames(tableNames);
+ }
+
+ /**
+ * 查询所有表信息
+ *
+ * @return 表信息集合
+ */
+ @Override
+ public List selectGenTableAll() {
+ return baseMapper.selectGenTableAll();
+ }
+
+ /**
+ * 修改业务
+ *
+ * @param genTable 业务信息
+ * @return 结果
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void updateGenTable(GenTable genTable) {
+ String options = JsonUtils.toJsonString(genTable.getParams());
+ genTable.setOptions(options);
+ int row = baseMapper.updateById(genTable);
+ if (row > 0) {
+ for (GenTableColumn cenTableColumn : genTable.getColumns()) {
+ genTableColumnMapper.updateById(cenTableColumn);
+ }
+ }
+ }
+
+ /**
+ * 删除业务对象
+ *
+ * @param tableIds 需要删除的数据ID
+ * @return 结果
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void deleteGenTableByIds(Collection tableIds) {
+
+ baseMapper.deleteBatchIds(tableIds);
+ genTableColumnMapper.delete(new LambdaQueryWrapper().in(GenTableColumn::getTableId, tableIds));
+ }
+
+ /**
+ * 导入表结构
+ *
+ * @param tableList 导入表列表
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void importGenTable(List tableList) {
+ String operName = LoginHelper.getUsername();
+ try {
+ for (GenTable table : tableList) {
+ String tableName = table.getTableName();
+ GenUtils.initTable(table, operName);
+ int row = baseMapper.insert(table);
+ if (row > 0) {
+ // 保存列信息
+ List genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+ List saveColumns = new ArrayList<>();
+ for (GenTableColumn column : genTableColumns) {
+ GenUtils.initColumnField(column, table);
+ saveColumns.add(column);
+ }
+ if (CollUtil.isNotEmpty(saveColumns)) {
+ genTableColumnMapper.insertBatch(saveColumns);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new BizException("导入失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 预览代码
+ *
+ * @param tableId 表编号
+ * @return 预览数据列表
+ */
+ @Override
+ public Map previewCode(Long tableId) {
+ Map dataMap = new LinkedHashMap<>();
+ // 查询表信息
+ GenTable table = baseMapper.selectGenTableById(tableId);
+ List menuIds = new ArrayList<>();
+ for (int i = 0; i < 6; i++) {
+ menuIds.add((Long) identifierGenerator.nextId(null));
+ }
+ table.setMenuIds(menuIds);
+ // 设置主键列信息
+ setPkColumn(table);
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 获取模板列表
+ List 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;
+ }
+
+ /**
+ * 生成代码(下载方式)
+ *
+ * @param tableName 表名称
+ * @return 数据
+ */
+ @Override
+ public byte[] downloadCode(String tableName) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ZipOutputStream zip = new ZipOutputStream(outputStream);
+ generatorCode(tableName, zip);
+ IoUtil.close(zip);
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * 生成代码(自定义路径)
+ *
+ * @param tableName 表名称
+ */
+ @Override
+ public void generatorCode(String tableName) {
+ // 查询表信息
+ GenTable table = baseMapper.selectGenTableByName(tableName);
+ // 设置主键列信息
+ setPkColumn(table);
+
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 获取模板列表
+ List templates = VelocityUtils.getTemplateList(table.getTplCategory());
+ for (String template : templates) {
+ if (!StringUtils.containsAny(template, "sql.vm", "api.ts.vm", "types.ts.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.writeUtf8String(sw.toString(), path);
+ } catch (Exception e) {
+ throw new BizException("渲染模板失败,表名:" + table.getTableName());
+ }
+ }
+ }
+ }
+
+ /**
+ * 同步数据库
+ *
+ * @param tableName 表名称
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void synchDb(String tableName) {
+ GenTable table = baseMapper.selectGenTableByName(tableName);
+ List tableColumns = table.getColumns();
+ Map tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName);
+
+ List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+ if (CollUtil.isEmpty(dbTableColumns)) {
+ throw new BizException("同步数据失败,原表结构不存在");
+ }
+ List dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName);
+
+ List saveColumns = new ArrayList<>();
+ 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());
+ }
+ }
+ saveColumns.add(column);
+ });
+ if (CollUtil.isNotEmpty(saveColumns)) {
+ genTableColumnMapper.insertOrUpdateBatch(saveColumns);
+ }
+ List delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName()));
+ if (CollUtil.isNotEmpty(delColumns)) {
+ List ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId);
+ genTableColumnMapper.deleteBatchIds(ids);
+ }
+ }
+
+ /**
+ * 批量生成代码(下载方式)
+ *
+ * @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);
+ }
+ IoUtil.close(zip);
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * 查询表信息并生成代码
+ */
+ private void generatorCode(String tableName, ZipOutputStream zip) {
+ // 查询表信息
+ GenTable table = baseMapper.selectGenTableByName(tableName);
+ List menuIds = new ArrayList<>();
+ for (int i = 0; i < 6; i++) {
+ menuIds.add((Long) identifierGenerator.nextId(null));
+ }
+ table.setMenuIds(menuIds);
+ // 设置主键列信息
+ setPkColumn(table);
+
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 获取模板列表
+ List 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 {
+ // 添加到zip
+ zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
+ IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
+ IoUtil.close(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 = JsonUtils.toJsonString(genTable.getParams());
+ Dict paramsObj = JsonUtils.parseMap(options);
+ if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_CODE))) {
+ throw new BizException("树编码字段不能为空");
+ } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_PARENT_CODE))) {
+ throw new BizException("树父编码字段不能为空");
+ } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_NAME))) {
+ throw new BizException("树名称字段不能为空");
+ }
+ }
+ }
+
+ /**
+ * 设置主键列信息
+ *
+ * @param table 业务表信息
+ */
+ public void setPkColumn(GenTable table) {
+ for (GenTableColumn column : table.getColumns()) {
+ if (column.isPk()) {
+ table.setPkColumn(column);
+ break;
+ }
+ }
+ if (ObjectUtil.isNull(table.getPkColumn())) {
+ table.setPkColumn(table.getColumns().get(0));
+ }
+
+ }
+
+ /**
+ * 设置代码生成其他选项值
+ *
+ * @param genTable 设置后的生成对象
+ */
+ public void setTableFromOptions(GenTable genTable) {
+ Dict paramsObj = JsonUtils.parseMap(genTable.getOptions());
+ if (ObjectUtil.isNotNull(paramsObj)) {
+ String treeCode = paramsObj.getStr(GenConstants.TREE_CODE);
+ String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE);
+ String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
+ String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID);
+ String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME);
+
+ genTable.setTreeCode(treeCode);
+ genTable.setTreeParentCode(treeParentCode);
+ genTable.setTreeName(treeName);
+ genTable.setParentMenuId(parentMenuId);
+ genTable.setParentMenuName(parentMenuName);
+ }
+ }
+
+ /**
+ * 获取代码生成地址
+ *
+ * @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);
+ }
+}
+
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/IGenTableService.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/IGenTableService.java
new file mode 100644
index 00000000..7b53f199
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/service/IGenTableService.java
@@ -0,0 +1,134 @@
+package cc.iotkit.generator.service;
+
+
+import cc.iotkit.common.api.PageRequest;
+import cc.iotkit.common.api.Paging;
+import cc.iotkit.generator.domain.GenTable;
+import cc.iotkit.generator.domain.GenTableColumn;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 业务 服务层
+ *
+ * @author Lion Li
+ */
+public interface IGenTableService {
+
+ /**
+ * 查询业务字段列表
+ *
+ * @param tableId 业务字段编号
+ * @return 业务字段集合
+ */
+ List selectGenTableColumnListByTableId(Long tableId);
+
+ /**
+ * 查询业务列表
+ *
+ *
+ * @return 业务集合
+ */
+ Paging selectPageGenTableList(PageRequest pageQuery);
+
+ /**
+ * 查询据库列表
+ *
+ * @return 数据库表集合
+ */
+ Paging selectPageDbTableList(PageRequest pageQuery);
+
+ /**
+ * 查询据库列表
+ *
+ * @param tableNames 表名称组
+ * @return 数据库表集合
+ */
+ List selectDbTableListByNames(Collection tableNames);
+
+ /**
+ * 查询所有表信息
+ *
+ * @return 表信息集合
+ */
+ List selectGenTableAll();
+
+ /**
+ * 查询业务信息
+ *
+ * @param id 业务ID
+ * @return 业务信息
+ */
+ GenTable selectGenTableById(Long id);
+
+ /**
+ * 修改业务
+ *
+ * @param genTable 业务信息
+ * @return 结果
+ */
+ void updateGenTable(GenTable genTable);
+
+ /**
+ * 删除业务信息
+ *
+ * @param tableIds 需要删除的表数据ID
+ * @return 结果
+ */
+ void deleteGenTableByIds(Collection tableIds);
+
+ /**
+ * 导入表结构
+ *
+ * @param tableList 导入表列表
+ */
+ void importGenTable(List tableList);
+
+ /**
+ * 预览代码
+ *
+ * @param tableId 表编号
+ * @return 预览数据列表
+ */
+ Map previewCode(Long tableId);
+
+ /**
+ * 生成代码(下载方式)
+ *
+ * @param tableName 表名称
+ * @return 数据
+ */
+ byte[] downloadCode(String tableName);
+
+ /**
+ * 生成代码(自定义路径)
+ *
+ * @param tableName 表名称
+ * @return 数据
+ */
+ void generatorCode(String tableName);
+
+ /**
+ * 同步数据库
+ *
+ * @param tableName 表名称
+ */
+ void synchDb(String tableName);
+
+ /**
+ * 批量生成代码(下载方式)
+ *
+ * @param tableNames 表数组
+ * @return 数据
+ */
+ byte[] downloadCode(String[] tableNames);
+
+ /**
+ * 修改保存参数校验
+ *
+ * @param genTable 业务信息
+ */
+ void validateEdit(GenTable genTable);
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/GenUtils.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/GenUtils.java
new file mode 100644
index 00000000..4659c5e7
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/GenUtils.java
@@ -0,0 +1,233 @@
+package cc.iotkit.generator.util;
+
+import cc.iotkit.common.satoken.utils.LoginHelper;
+import cc.iotkit.common.utils.StringUtils;
+import cc.iotkit.generator.config.GenConfig;
+import cc.iotkit.generator.constant.GenConstants;
+import cc.iotkit.generator.domain.GenTable;
+import cc.iotkit.generator.domain.GenTableColumn;
+import cn.hutool.core.util.ReUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.Arrays;
+
+/**
+ * 代码生成器 工具类
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+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(LoginHelper.getUserId());
+ }
+
+ /**
+ * 初始化列属性字段
+ */
+ 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);
+
+ // 如果是浮点型 统一用BigDecimal
+ String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR);
+ 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);
+ }
+ }
+
+ // BO对象 默认插入勾选
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) {
+ column.setIsInsert(GenConstants.REQUIRE);
+ }
+ // BO对象 默认编辑勾选
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
+ column.setIsEdit(GenConstants.REQUIRE);
+ }
+ // BO对象 默认是否必填勾选
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
+ column.setIsRequired(GenConstants.REQUIRE);
+ }
+ // VO对象 默认返回勾选
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) {
+ column.setIsList(GenConstants.REQUIRE);
+ }
+ // BO对象 默认查询勾选
+ 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 firstIndex = tableName.indexOf("_");
+ int nameLength = tableName.length();
+ String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength);
+ businessName = StringUtils.toCamelCase(businessName);
+ return businessName;
+ }
+
+ /**
+ * 表名转换成Java类名
+ *
+ * @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, StringUtils.SEPARATOR);
+ 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 ReUtil.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/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityInitializer.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityInitializer.java
new file mode 100644
index 00000000..a47b7595
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityInitializer.java
@@ -0,0 +1,35 @@
+package cc.iotkit.generator.util;
+
+import cc.iotkit.common.constant.Constants;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.velocity.app.Velocity;
+
+import java.util.Properties;
+
+/**
+ * VelocityEngine工厂
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class VelocityInitializer {
+
+ /**
+ * 初始化vm方法
+ */
+ 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);
+ // 初始化Velocity引擎,指定配置Properties
+ Velocity.init(p);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityUtils.java b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityUtils.java
new file mode 100644
index 00000000..88b2768d
--- /dev/null
+++ b/iot-module/iot-generator/src/main/java/cc/iotkit/generator/util/VelocityUtils.java
@@ -0,0 +1,354 @@
+package cc.iotkit.generator.util;
+
+import cc.iotkit.common.utils.DateUtils;
+import cc.iotkit.common.utils.JsonUtils;
+import cc.iotkit.common.utils.StringUtils;
+import cc.iotkit.generator.constant.GenConstants;
+import cc.iotkit.generator.core.DataBaseHelper;
+import cc.iotkit.generator.domain.GenTable;
+import cc.iotkit.generator.domain.GenTableColumn;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Dict;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.velocity.VelocityContext;
+
+import java.util.*;
+
+/**
+ * 模板处理工具类
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+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);
+ }
+ return velocityContext;
+ }
+
+ public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) {
+ String options = genTable.getOptions();
+ Dict paramsObj = JsonUtils.parseMap(options);
+ String parentMenuId = getParentMenuId(paramsObj);
+ context.put("parentMenuId", parentMenuId);
+ }
+
+ public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) {
+ String options = genTable.getOptions();
+ Dict paramsObj = JsonUtils.parseMap(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.get(GenConstants.TREE_PARENT_CODE));
+ }
+ if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
+ context.put("tree_name", paramsObj.get(GenConstants.TREE_NAME));
+ }
+ }
+
+ /**
+ * 获取模板信息
+ *
+ * @return 模板列表
+ */
+ public static List getTemplateList(String tplCategory) {
+ List templates = new ArrayList();
+ templates.add("vm/java/model.java.vm");
+ templates.add("vm/java/vo.java.vm");
+ templates.add("vm/java/bo.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/java/idata.java.vm");
+ templates.add("vm/java/idataimpl.java.vm");
+ templates.add("vm/java/tbmodel.java.vm");
+ templates.add("vm/java/repository.java.vm");
+ if (DataBaseHelper.isOracle()) {
+ templates.add("vm/sql/oracle/sql.vm");
+ } else if (DataBaseHelper.isPostgerSql()) {
+ templates.add("vm/sql/postgres/sql.vm");
+ } else if (DataBaseHelper.isSqlServer()) {
+ templates.add("vm/sql/sqlserver/sql.vm");
+ } else {
+ templates.add("vm/sql/sql.vm");
+ }
+ templates.add("vm/ts/api.ts.vm");
+ templates.add("vm/ts/types.ts.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");
+ }
+ 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.endsWith("tbmodel.java.vm")) {
+ fileName = StringUtils.format("{}/data/model/Tb{}.java", javaPath, className);
+ } else if (template.endsWith("model.java.vm")) {
+ fileName = StringUtils.format("{}/model/{}.java", javaPath, className);
+ }
+ if (template.endsWith("repository.java.vm")) {
+ fileName = StringUtils.format("{}/repository/{}Repository.java", javaPath, className);
+ }
+ if (template.endsWith("idata.java.vm")) {
+ fileName = StringUtils.format("{}/data/I{}Data.java", javaPath, className);
+ } else if (template.endsWith("idataimpl.java.vm")) {
+ fileName = StringUtils.format("{}/data/impl/{}DataImpl.java", javaPath, className);
+ }
+ if (template.contains("vo.java.vm")) {
+ fileName = StringUtils.format("{}/dto/vo/{}Vo.java", javaPath, className);
+ }
+ if (template.contains("bo.java.vm")) {
+ fileName = StringUtils.format("{}/dto/bo/{}Bo.java", javaPath, className);
+ }
+ 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.ts.vm")) {
+ fileName = StringUtils.format("{}/api/{}/{}/index.ts", vuePath, moduleName, businessName);
+ } else if (template.contains("types.ts.vm")) {
+ fileName = StringUtils.format("{}/api/{}/{}/types.ts", 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 getImportList(GenTable genTable) {
+ List columns = genTable.getColumns();
+ HashSet importList = new HashSet<>();
+ 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 columns = genTable.getColumns();
+ Set dicts = new HashSet<>();
+ addDicts(dicts, columns);
+ return StringUtils.join(dicts, ", ");
+ }
+
+ /**
+ * 添加字典列表
+ *
+ * @param dicts 字典列表
+ * @param columns 列集合
+ */
+ public static void addDicts(Set dicts, List 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(Dict paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
+ && StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) {
+ return paramsObj.getStr(GenConstants.PARENT_MENU_ID);
+ }
+ return DEFAULT_PARENT_MENU_ID;
+ }
+
+ /**
+ * 获取树编码
+ *
+ * @param paramsObj 生成其他选项
+ * @return 树编码
+ */
+ public static String getTreecode(Map paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) {
+ return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE)));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 获取树父编码
+ *
+ * @param paramsObj 生成其他选项
+ * @return 树父编码
+ */
+ public static String getTreeParentCode(Dict paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
+ return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_PARENT_CODE));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 获取树名称
+ *
+ * @param paramsObj 生成其他选项
+ * @return 树名称
+ */
+ public static String getTreeName(Dict paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) {
+ return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_NAME));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 获取需要在哪一列上面显示展开按钮
+ *
+ * @param genTable 业务表对象
+ * @return 展开按钮列序号
+ */
+ public static int getExpandColumn(GenTable genTable) {
+ String options = genTable.getOptions();
+ Dict paramsObj = JsonUtils.parseMap(options);
+ String treeName = paramsObj.getStr(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/iot-module/iot-generator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/iot-module/iot-generator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000..6919707b
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+cc.iotkit.generator.config.MybatisPlusConfig
\ No newline at end of file
diff --git a/iot-module/iot-generator/src/main/resources/application-generator.yml b/iot-module/iot-generator/src/main/resources/application-generator.yml
new file mode 100644
index 00000000..19ea3641
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/application-generator.yml
@@ -0,0 +1,45 @@
+spring:
+
+
+ jpa:
+ show-sql: true
+ hibernate:
+ ddl-auto: update
+ properties:
+ hibernate:
+ format_sql: true
+
+ sql:
+ init:
+ # mysql 初始化
+ # schema-locations: classpath:sql/schema.sql
+ # postgrep 初始化
+ schema-locations: classpath:sql/schema-postgre.sql
+ mode: ALWAYS
+
+ datasource:
+ # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
+ dynamic:
+ primary: master #设置默认的数据源或者数据源组,默认值即为master
+ strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
+ datasource:
+ # 主库数据源
+ master:
+ type: ${spring.datasource.type}
+ driverClassName: ${spring.datasource.driverClassName}
+ # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
+ # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
+ url: ${spring.datasource.url}
+ username: ${spring.datasource.url}
+ password: ${spring.datasource.password}
+
+ # 从库数据源
+ slave:
+ lazy: true
+ type: ${spring.datasource.type}
+ driverClassName: ${spring.datasource.driverClassName}
+ # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
+ # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
+ url: ${spring.datasource.url}
+ username: ${spring.datasource.username}
+ password: ${spring.datasource.password}
\ No newline at end of file
diff --git a/iot-module/iot-generator/src/main/resources/common-mybatis.yml b/iot-module/iot-generator/src/main/resources/common-mybatis.yml
new file mode 100644
index 00000000..f5dc6375
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/common-mybatis.yml
@@ -0,0 +1,33 @@
+# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖
+# MyBatisPlus配置
+# https://baomidou.com/config/
+mybatis-plus:
+ # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
+ checkConfigLocation: false
+ configuration:
+ # 自动驼峰命名规则(camel case)映射
+ mapUnderscoreToCamelCase: true
+ # MyBatis 自动映射策略
+ # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
+ autoMappingBehavior: FULL
+ # MyBatis 自动映射时未知列或未知属性处理策
+ # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
+ autoMappingUnknownColumnBehavior: NONE
+ # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
+ # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
+ # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
+ logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
+ global-config:
+ # 是否打印 Logo banner
+ banner: true
+ dbConfig:
+ # 主键类型
+ # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
+ idType: ASSIGN_ID
+ # 逻辑已删除值(框架表均使用此值 禁止随意修改)
+ logicDeleteValue: 2
+ # 逻辑未删除值
+ logicNotDeleteValue: 0
+ insertStrategy: NOT_NULL
+ updateStrategy: NOT_NULL
+ whereStrategy: NOT_NULL
diff --git a/iot-module/iot-generator/src/main/resources/generator.yml b/iot-module/iot-generator/src/main/resources/generator.yml
new file mode 100644
index 00000000..aa8b9def
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/generator.yml
@@ -0,0 +1,10 @@
+# 代码生成
+gen:
+ # 作者
+ author: iita
+ # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
+ packageName: cc.iotkit.system
+ # 自动去除表前缀,默认是false
+ autoRemovePre: false
+ # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
+ tablePrefix: sys_
diff --git a/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
new file mode 100644
index 00000000..14f2d97b
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableMapper.xml
new file mode 100644
index 00000000..57ff7958
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iot-module/iot-generator/src/main/resources/mapper/package-info.md b/iot-module/iot-generator/src/main/resources/mapper/package-info.md
new file mode 100644
index 00000000..c938b1e5
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java包使用 `.` 分割 resource 目录使用 `/` 分割
+
+此文件目的 防止文件夹粘连找不到 `xml` 文件
\ No newline at end of file
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/bo.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/bo.java.vm
new file mode 100644
index 00000000..400b821a
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/bo.java.vm
@@ -0,0 +1,52 @@
+package ${packageName}.dto.bo;
+
+import ${packageName}.model.${ClassName};
+import cc.iotkit.common.api.BaseDto;
+import cc.iotkit.common.validate.AddGroup;
+import cc.iotkit.common.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+#foreach ($import in $importList)
+import ${import};
+#end
+
+/**
+ * ${functionName}业务对象 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false)
+public class ${ClassName}Bo extends BaseDto {
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit))
+ /**
+ * $column.columnComment
+ */
+#if($column.insert && $column.edit)
+#set($Group="AddGroup.class, EditGroup.class")
+#elseif($column.insert)
+#set($Group="AddGroup.class")
+#elseif($column.edit)
+#set($Group="EditGroup.class")
+#end
+#if($column.required)
+#if($column.javaType == 'String')
+ @NotBlank(message = "$column.columnComment不能为空", groups = { $Group })
+#else
+ @NotNull(message = "$column.columnComment不能为空", groups = { $Group })
+#end
+#end
+ @ApiModelProperty(value = "$column.columnComment", required = ${column.required})
+ private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/controller.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/controller.java.vm
new file mode 100644
index 00000000..566b9517
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/controller.java.vm
@@ -0,0 +1,113 @@
+package ${packageName}.controller;
+
+import java.util.List;
+
+
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import javax.servlet.http.HttpServletResponse;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import cc.iotkit.common.log.annotation.Log;
+import cc.iotkit.common.web.core.BaseController;
+import cc.iotkit.common.api.PageRequest;
+import cc.iotkit.common.api.Paging;
+import cc.iotkit.common.api.Request;
+import cc.iotkit.common.validate.AddGroup;
+import cc.iotkit.common.validate.EditGroup;
+import cc.iotkit.common.log.enums.BusinessType;
+import cc.iotkit.common.excel.utils.ExcelUtil;
+import ${packageName}.dto.vo.${ClassName}Vo;
+import ${packageName}.dto.bo.${ClassName}Bo;
+import ${packageName}.service.I${ClassName}Service;
+
+
+/**
+ * ${functionName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/${moduleName}/${businessName}")
+public class ${ClassName}Controller extends BaseController {
+
+ private final I${ClassName}Service ${className}Service;
+
+ /**
+ * 查询${functionName}列表
+ */
+ @SaCheckPermission("${permissionPrefix}:list")
+ @PostMapping("/list")
+ @ApiOperation("查询${functionName}列表")
+#if($table.crud || $table.sub)
+ public Paging<${ClassName}Vo> list( PageRequest<${ClassName}Bo> pageQuery) {
+ return ${className}Service.queryPageList(pageQuery);
+ }
+#elseif($table.tree)
+ public List<${ClassName}Vo> list(@RequestBody Request<${ClassName}Bo> query) {
+ List<${ClassName}Vo> list = ${className}Service.queryList(query.getData());
+ return list;
+ }
+#end
+
+ /**
+ * 导出${functionName}列表
+ */
+ @ApiOperation("导出${functionName}列表")
+ @SaCheckPermission("${permissionPrefix}:export")
+ @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(${ClassName}Bo bo, HttpServletResponse response) {
+ List<${ClassName}Vo> list = ${className}Service.queryList(bo);
+ ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response);
+ }
+
+ /**
+ * 获取${functionName}详细信息
+ *
+ */
+ @SaCheckPermission("${permissionPrefix}:query")
+ @PostMapping("/getDetail")
+ @ApiOperation("获取${functionName}详细信息")
+ public ${ClassName}Vo getDetail(@Validated @RequestBody Request request) {
+ return ${className}Service.queryById(request.getData());
+ }
+
+ /**
+ * 新增${functionName}
+ */
+ @SaCheckPermission("${permissionPrefix}:add")
+ @Log(title = "${functionName}", businessType = BusinessType.INSERT)
+ @PostMapping(value = "/add")
+ @ApiOperation("新增${functionName}")
+ public Long add(@Validated(AddGroup.class) @RequestBody Request<${ClassName}Bo> request) {
+ return ${className}Service.insertByBo(request.getData());
+ }
+
+ /**
+ * 修改${functionName}
+ */
+ @SaCheckPermission("${permissionPrefix}:edit")
+ @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
+ @PostMapping("/edit")
+ @ApiOperation("修改${functionName}")
+ public boolean edit(@Validated(EditGroup.class) @RequestBody Request<${ClassName}Bo> request) {
+ return ${className}Service.updateByBo(request.getData());
+ }
+
+ /**
+ * 删除${functionName}
+ *
+ */
+ @SaCheckPermission("${permissionPrefix}:remove")
+ @Log(title = "${functionName}", businessType = BusinessType.DELETE)
+ @PostMapping("/delete")
+ @ApiOperation("删除${functionName}")
+ public boolean remove(@Validated @RequestBody Request> query) {
+ return ${className}Service.deleteWithValidByIds(query.getData(), true);
+ }
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/idata.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/idata.java.vm
new file mode 100644
index 00000000..9dcec7e3
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/idata.java.vm
@@ -0,0 +1,16 @@
+package ${packageName}.data;
+
+import cc.iotkit.data.ICommonData;
+import ${packageName}.model.${ClassName};
+import java.util.List;
+
+/**
+ * 数据接口
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Data extends ICommonData<${ClassName}, Long> {
+
+
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/idataimpl.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/idataimpl.java.vm
new file mode 100644
index 00000000..aa20bb48
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/idataimpl.java.vm
@@ -0,0 +1,135 @@
+package ${packageName}.data;
+
+import ${packageName}.repository.${ClassName}Repository;
+import ${packageName}.data.I${ClassName}Data;
+import ${packageName}.data.model.Tb${ClassName};
+import ${packageName}.model.${ClassName};
+import java.util.List;
+import com.querydsl.core.types.Predicate;
+import com.querydsl.jpa.impl.JPAQueryFactory;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+import cc.iotkit.data.util.PredicateBuilder;
+
+import cc.iotkit.common.api.PageRequest;
+import cc.iotkit.common.api.Paging;
+import cc.iotkit.common.utils.StringUtils;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.Optional;
+import com.google.common.collect.Lists;
+
+
+import cc.iotkit.common.utils.MapstructUtils;
+import cc.iotkit.data.util.PageBuilder;
+
+
+import static ${packageName}.data.model.QTb${ClassName}.tb${ClassName};
+/**
+ * 数据实现接口
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Primary
+@Service
+@RequiredArgsConstructor
+public class ${ClassName}DataImpl implements I${ClassName}Data {
+
+ private final ${ClassName}Repository baseRepository;
+
+ private final JPAQueryFactory jpaQueryFactory;
+
+ @Override
+ public Paging<${ClassName}> findAll(PageRequest<${ClassName}> pageRequest) {
+ return PageBuilder.toPaging(baseRepository.findAll(buildQueryCondition(pageRequest.getData()), PageBuilder.toPageable(pageRequest))).to(${ClassName}.class);
+ }
+
+ private Predicate buildQueryCondition(${ClassName} bo) {
+ PredicateBuilder builder = PredicateBuilder.instance();
+ if(Objects.nonNull(bo)) {
+
+ #foreach($column in $columns)
+ #if($column.query)
+ #set($queryType=$column.queryType)
+ #set($javaField=$column.javaField)
+ #set($javaType=$column.javaType)
+ #set($columnName=$column.columnName)
+ #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ #if($queryType != 'BETWEEN')
+ #if($javaType == 'String')
+ #set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())')
+ #else
+ #set($condition='bo.get'+$AttrName+'() != null')
+ #end
+ builder.and($condition, () -> tb${ClassName}.${javaField}.eq(bo.get${AttrName}()));
+ #else
+ builder.and(params.get("begin$AttrName") != null && params.get("end$AttrName") != null,
+ () -> tb${ClassName}.${javaField}.bettwen(params.get("begin$AttrName"), params.get("end$AttrName")));
+ #end
+ #end
+ #end
+ }
+ return builder.build();
+ }
+
+ @Override
+ public List<${ClassName}> findByIds(Collection ids) {
+ List allById = baseRepository.findAllById(ids);
+ return MapstructUtils.convert(allById, ${ClassName}.class);
+ }
+
+ @Override
+ public ${ClassName} save(${ClassName} data) {
+ Object o = baseRepository.save(MapstructUtils.convert(data, Tb${ClassName}.class));
+ return MapstructUtils.convert(o, ${ClassName}.class);
+ }
+
+ @Override
+ public void batchSave(List<${ClassName}> data) {
+ baseRepository.saveAll(MapstructUtils.convert(data, Tb${ClassName}.class));
+ }
+
+ @Override
+ public void deleteById(Long id) {
+ baseRepository.deleteById(id);
+ }
+
+ @Override
+ public void deleteByIds(Collection ids) {
+ baseRepository.deleteAllById(ids);
+ }
+
+ @Override
+ public ${ClassName} findById(Long id) {
+ Tb${ClassName} ret = jpaQueryFactory.select(tb${ClassName}).from(tb${ClassName}).where(tb${ClassName}.id.eq(id)).fetchOne();
+ return MapstructUtils.convert(ret, ${ClassName}.class);
+ }
+
+ @Override
+ public long count() {
+ return baseRepository.count();
+ }
+
+ @Override
+ public List findAll() {
+ return MapstructUtils.convert(baseRepository.findAll(), IotContributor.class);
+ }
+
+ @Override
+ public List findAllByCondition(IotContributor data) {
+ Iterable all = baseRepository.findAll(buildQueryCondition(data));
+ return MapstructUtils.convert(Lists.newArrayList(all), IotContributor.class);
+ }
+
+ @Override
+ public IotContributor findOneByCondition(IotContributor data) {
+ Optional one = baseRepository.findOne(buildQueryCondition(data));
+
+ if(one.isPresent()){
+ return MapstructUtils.convert(one.get(), IotContributor.class);
+ }
+ return null;
+ }
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/mapper.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/mapper.java.vm
new file mode 100644
index 00000000..a367317d
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/mapper.java.vm
@@ -0,0 +1,15 @@
+package ${packageName}.mapper;
+
+import ${packageName}.domain.${ClassName};
+import ${packageName}.domain.vo.${ClassName}Vo;
+import cc.iotkit.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * ${functionName}Mapper接口
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> {
+
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/model.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/model.java.vm
new file mode 100644
index 00000000..6b75cdbb
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/model.java.vm
@@ -0,0 +1,50 @@
+package ${packageName}.model;
+
+import cc.iotkit.model.Id;
+#foreach ($column in $columns)
+#if($column.javaField=='tenantId')
+#set($IsTenant=1)
+#end
+#end
+#if($IsTenant==1)
+import cc.iotkit.model.TenantModel;
+#else
+import cc.iotkit.model.BaseModel;
+#end
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+#foreach ($import in $importList)
+import ${import};
+#end
+
+import java.io.Serializable;
+
+
+/**
+ * ${functionName}对象 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+#if($IsTenant==1)
+#set($Entity="TenantModel")
+#else
+#set($Entity="BaseModel")
+#end
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ${ClassName} extends ${Entity} implements Id, Serializable{
+
+ private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+ /**
+ * $column.columnComment
+ */
+ private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/repository.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/repository.java.vm
new file mode 100644
index 00000000..e008721e
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/repository.java.vm
@@ -0,0 +1,15 @@
+package ${packageName}.data.dao;
+
+import ${packageName}.data.model.Tb${ClassName};
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.querydsl.QuerydslPredicateExecutor;
+
+/**
+ * ${functionName}对象 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface ${ClassName}Repository extends JpaRepository, QuerydslPredicateExecutor {
+
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/service.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/service.java.vm
new file mode 100644
index 00000000..d789b777
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/service.java.vm
@@ -0,0 +1,53 @@
+package ${packageName}.service;
+
+import ${packageName}.dto.vo.${ClassName}Vo;
+import ${packageName}.dto.bo.${ClassName}Bo;
+#if($table.crud || $table.sub)
+
+#end
+import cc.iotkit.common.api.Paging;
+import cc.iotkit.common.api.PageRequest;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * ${functionName}Service接口
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Service {
+
+ /**
+ * 查询${functionName}
+ */
+ ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField});
+
+#if($table.crud || $table.sub)
+ /**
+ * 查询${functionName}列表
+ */
+ Paging<${ClassName}Vo> queryPageList(PageRequest<${ClassName}Bo> pageQuery);
+#end
+
+ /**
+ * 查询${functionName}列表
+ */
+ List<${ClassName}Vo> queryList(${ClassName}Bo bo);
+
+ /**
+ * 新增${functionName}
+ */
+ Long insertByBo(${ClassName}Bo bo);
+
+ /**
+ * 修改${functionName}
+ */
+ Boolean updateByBo(${ClassName}Bo bo);
+
+ /**
+ * 校验并批量删除${functionName}信息
+ */
+ Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid);
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/serviceImpl.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/serviceImpl.java.vm
new file mode 100644
index 00000000..995d4b62
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -0,0 +1,109 @@
+package ${packageName}.service.impl;
+
+import cc.iotkit.common.utils.MapstructUtils;
+import cc.iotkit.common.utils.StringUtils;
+#if($table.crud || $table.sub)
+import cc.iotkit.common.api.PageRequest;
+import cc.iotkit.common.api.Paging;
+#end
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import ${packageName}.dto.bo.${ClassName}Bo;
+import ${packageName}.dto.vo.${ClassName}Vo;
+import ${packageName}.model.${ClassName};
+import ${packageName}.service.I${ClassName}Service;
+import ${packageName}.data.I${ClassName}Data;
+
+import java.util.List;
+import java.util.Collection;
+import cc.iotkit.common.exception.BizException;
+
+
+/**
+ * ${functionName}Service业务层处理
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@RequiredArgsConstructor
+@Service
+public class ${ClassName}ServiceImpl implements I${ClassName}Service {
+
+ private final I${ClassName}Data baseData;
+
+ /**
+ * 查询${functionName}
+ */
+ @Override
+ public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){
+ return MapstructUtils.convert(baseData.findById(${pkColumn.javaField}), ${ClassName}Vo.class);
+ }
+
+#if($table.crud || $table.sub)
+ /**
+ * 查询${functionName}列表
+ */
+ @Override
+ public Paging<${ClassName}Vo> queryPageList(PageRequest<${ClassName}Bo> pageQuery) {
+ Paging<${ClassName}Vo> result = baseData.findAll(pageQuery.to(${ClassName}.class)).to(${ClassName}Vo.class);
+ return result;
+ }
+#end
+
+ /**
+ * 查询${functionName}列表
+ */
+ @Override
+ public List<${ClassName}Vo> queryList(${ClassName}Bo bo) {
+
+ return MapstructUtils.convert(baseData.findAllByCondition(bo.to(${ClassName}.class)), ${ClassName}Vo.class);
+ }
+
+ /**
+ * 新增${functionName}
+ */
+ @Override
+ public Long insertByBo(${ClassName}Bo bo) {
+ ${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class);
+ validEntityBeforeSave(add);
+ baseData.save(add);
+ if (add == null) {
+ throw new BizException("新增失败");
+ }
+ #set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)})
+ return add.get$pk();
+ }
+
+ /**
+ * 修改${functionName}
+ */
+ @Override
+ public Boolean updateByBo(${ClassName}Bo bo) {
+ ${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class);
+ validEntityBeforeSave(update);
+ ${ClassName} ret = baseData.save(update);
+ if(ret == null){
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 保存前的数据校验
+ */
+ private void validEntityBeforeSave(${ClassName} entity){
+ //TODO 做一些数据校验,如唯一约束
+ }
+
+ /**
+ * 批量删除${functionName}
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) {
+ if(isValid){
+ //TODO 做一些业务上的校验,判断是否需要校验
+ }
+ baseData.deleteByIds(ids);
+ return true;
+ }
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/tbmodel.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/tbmodel.java.vm
new file mode 100644
index 00000000..0f03e08f
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/tbmodel.java.vm
@@ -0,0 +1,71 @@
+package ${packageName}.data.model;
+
+import ${packageName}.model.IotContributor;
+import io.github.linpeilie.annotations.AutoMapper;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.hibernate.annotations.GenericGenerator;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+#foreach ($column in $columns)
+#if($column.javaField=='tenantId')
+#set($IsTenant=1)
+#end
+#end
+#if($IsTenant==1)
+import cc.iotkit.model.TenantModel;
+#else
+import cc.iotkit.data.model.BaseEntity;
+#end
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+#foreach ($import in $importList)
+import ${import};
+#end
+import javax.persistence.Table;
+import javax.persistence.Entity;
+
+/**
+ * ${functionName}对象 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+#if($IsTenant==1)
+#set($Entity="TenantEntity")
+#else
+#set($Entity="BaseEntity")
+#end
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@Entity
+@Table(name = "${tableName}")
+@AutoMapper(target = ${ClassName}.class)
+public class Tb${ClassName} extends ${Entity} {
+
+
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+ /**
+ * $column.columnComment
+ */
+#if($column.javaField=='delFlag')
+#end
+#if($column.javaField=='version')
+#end
+#if($column.isPk==1)
+ @Id
+ @GeneratedValue(generator = "SnowflakeIdGenerator")
+ @GenericGenerator(name = "SnowflakeIdGenerator", strategy = "cc.iotkit.data.config.id.SnowflakeIdGenerator")
+#end
+ @ApiModelProperty(value = "$column.columnComment")
+ private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/java/vo.java.vm b/iot-module/iot-generator/src/main/resources/vm/java/vo.java.vm
new file mode 100644
index 00000000..06da2d21
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/java/vo.java.vm
@@ -0,0 +1,61 @@
+package ${packageName}.dto.vo;
+
+#foreach ($import in $importList)
+import ${import};
+#end
+import ${packageName}.model.${ClassName};
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import cc.iotkit.common.excel.annotation.ExcelDictFormat;
+import cc.iotkit.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import io.swagger.annotations.ApiModelProperty;
+
+
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * ${functionName}视图对象 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ${ClassName}.class)
+public class ${ClassName}Vo implements Serializable {
+
+
+ private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if($column.list)
+ /**
+ * $column.columnComment
+ */
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if(${column.dictType} && ${column.dictType} != '')
+ @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "${column.dictType}")
+#elseif($parentheseIndex != -1)
+ @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
+#else
+ @ExcelProperty(value = "${comment}")
+#end
+ @ApiModelProperty(value = "${comment}")
+ private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/js/api.js.vm b/iot-module/iot-generator/src/main/resources/vm/js/api.js.vm
new file mode 100644
index 00000000..1df6ef37
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/js/api.js.vm
@@ -0,0 +1,47 @@
+import request from '@/utils/request'
+import { ${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO } from './types'
+
+// 查询${functionName}列表
+export function list${BusinessName}(query: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> {
+ return request({
+ url: '/${moduleName}/${businessName}/list',
+ method: 'post',
+ params: query
+ })
+}
+
+// 查询${functionName}详细
+export function get${BusinessName}(${pkColumn.javaField}: string | number) : AxiosPromise<${BusinessName}VO> {
+ return request({
+ url: '/${moduleName}/${businessName}/getDetail',
+ method: 'post',
+ data: ${pkColumn.javaField}
+ })
+}
+
+// 新增${functionName}
+export function add${BusinessName}(data: ${BusinessName}Form) {
+ return request({
+ url: '/${moduleName}/${businessName}/add',
+ method: 'post',
+ data,
+ })
+}
+
+// 修改${functionName}
+export function update${BusinessName}(data: ${BusinessName}Form) {
+ return request({
+ url: '/${moduleName}/${businessName}/edit',
+ method: 'post',
+ data,
+ })
+}
+
+// 删除${functionName}
+export function del${BusinessName}(${pkColumn.javaField}: Array) {
+ return request({
+ url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+ method: 'post',
+ data: ${pkColumn.javaField}
+ })
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/oracle/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/oracle/sql.vm
new file mode 100644
index 00000000..f6638be5
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/sql/oracle/sql.vm
@@ -0,0 +1,19 @@
+-- 菜单 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate, null, null, '${functionName}菜单');
+
+-- 按钮 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate, null, null, '');
diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/postgres/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/postgres/sql.vm
new file mode 100644
index 00000000..09233923
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/sql/postgres/sql.vm
@@ -0,0 +1,20 @@
+-- 菜单 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, now(), null, null, '${functionName}菜单');
+
+-- 按钮 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, now(), null, null, '');
+
diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/sql.vm
new file mode 100644
index 00000000..01824c27
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/sql/sql.vm
@@ -0,0 +1,19 @@
+-- 菜单 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate(), null, null, '${functionName}菜单');
+
+-- 按钮 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate(), null, null, '');
diff --git a/iot-module/iot-generator/src/main/resources/vm/sql/sqlserver/sql.vm b/iot-module/iot-generator/src/main/resources/vm/sql/sqlserver/sql.vm
new file mode 100644
index 00000000..bdf166e5
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/sql/sqlserver/sql.vm
@@ -0,0 +1,19 @@
+-- 菜单 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, getdate(), null, null, '${functionName}菜单');
+
+-- 按钮 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, getdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, getdate(), null, null, '');
diff --git a/iot-module/iot-generator/src/main/resources/vm/ts/api.ts.vm b/iot-module/iot-generator/src/main/resources/vm/ts/api.ts.vm
new file mode 100644
index 00000000..ee309bc7
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/ts/api.ts.vm
@@ -0,0 +1,48 @@
+import request from '@/utils/request';
+import {AxiosPromise} from 'axios';
+import {${BusinessName}Form, ${BusinessName}Query, ${BusinessName}VO} from './types';
+
+// 查询${functionName}列表
+export const list${BusinessName}(query: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> {
+ return request({
+ url: '/${moduleName}/${businessName}/list',
+ method: 'post',
+ params: query
+ })
+}
+
+// 查询${functionName}详细
+export const get${BusinessName}(${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> {
+ return request({
+ url: '/${moduleName}/${businessName}/getDetail',
+ method: 'post',
+ data: ${pkColumn.javaField}
+ })
+}
+
+// 新增${functionName}
+export const add${BusinessName}(data: ${BusinessName}Form) {
+ return request({
+ url: '/${moduleName}/${businessName}/add',
+ method: 'post',
+ data
+ })
+}
+
+// 修改${functionName}
+export const update${BusinessName}(data: ${BusinessName}Form) {
+ return request({
+ url: '/${moduleName}/${businessName}/edit',
+ method: 'post',
+ data: data
+ })
+}
+
+// 删除${functionName}
+export const del${BusinessName}(${pkColumn.javaField}: Array) {
+ return request({
+ url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+ method: 'post',
+ data: ${pkColumn.javaField}
+ })
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/ts/types.ts.vm b/iot-module/iot-generator/src/main/resources/vm/ts/types.ts.vm
new file mode 100644
index 00000000..99359e02
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/ts/types.ts.vm
@@ -0,0 +1,44 @@
+export interface ${BusinessName}VO {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+ /**
+ * $column.columnComment
+ */
+ $column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+ #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+ #elseif($column.javaType == 'Boolean') boolean;
+ #else string;
+ #end
+#end
+#end
+}
+
+export interface ${BusinessName}Form extends BaseEntity {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+ /**
+ * $column.columnComment
+ */
+ $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+ #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+ #elseif($column.javaType == 'Boolean') boolean;
+ #else string;
+ #end
+#end
+#end
+}
+
+export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{
+#foreach ($column in $columns)
+#if($column.query)
+ /**
+ * $column.columnComment
+ */
+ $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+ #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+ #elseif($column.javaType == 'Boolean') boolean;
+ #else string;
+ #end
+#end
+#end
+}
diff --git a/iot-module/iot-generator/src/main/resources/vm/vue/index-tree.vue.vm b/iot-module/iot-generator/src/main/resources/vm/vue/index-tree.vue.vm
new file mode 100644
index 00000000..dbfa4b98
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -0,0 +1,501 @@
+
+
+
+
+
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input" || $column.htmlType == "textarea")
+
+
+
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+
+
+
+
+
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+
+
+
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+
+
+
+#end
+#end
+#end
+
+ 搜索
+ 重置
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 展开/折叠
+
+
+
+
+
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+
+
+ {{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}
+
+
+#elseif($column.list && $column.htmlType == "imageUpload")
+
+
+
+
+
+#elseif($column.list && $column.dictType && "" != $column.dictType)
+
+
+#if($column.htmlType == "checkbox")
+
+#else
+
+#end
+
+
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+
+#else
+
+#end
+#end
+#end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+
+
+
+#elseif($column.htmlType == "input")
+
+
+
+#elseif($column.htmlType == "imageUpload")
+
+
+
+#elseif($column.htmlType == "fileUpload")
+
+
+
+#elseif($column.htmlType == "editor")
+
+
+
+#elseif($column.htmlType == "select" && "" != $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "select" && $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+
+
+
+ {{dict.label}}
+
+
+
+#elseif($column.htmlType == "checkbox" && $dictType)
+
+
+ 请选择字典生成
+
+
+#elseif($column.htmlType == "radio" && "" != $dictType)
+
+
+ {{dict.label}}
+
+
+#elseif($column.htmlType == "radio" && $dictType)
+
+
+ 请选择字典生成
+
+
+#elseif($column.htmlType == "datetime")
+
+
+
+#elseif($column.htmlType == "textarea")
+
+
+
+#end
+#end
+#end
+
+
+
+
+
+
+
+
+
diff --git a/iot-module/iot-generator/src/main/resources/vm/vue/index.vue.vm b/iot-module/iot-generator/src/main/resources/vm/vue/index.vue.vm
new file mode 100644
index 00000000..ace3446b
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/vue/index.vue.vm
@@ -0,0 +1,467 @@
+
+
+
+
+
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input" || $column.htmlType == "textarea")
+
+
+
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+
+
+
+
+
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+
+
+
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+
+
+
+#end
+#end
+#end
+
+ 搜索
+ 重置
+
+
+
+
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+
+#elseif($column.list && $column.htmlType == "datetime")
+
+
+ {{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}
+
+
+#elseif($column.list && $column.htmlType == "imageUpload")
+
+
+
+
+
+#elseif($column.list && $column.dictType && "" != $column.dictType)
+
+
+#if($column.htmlType == "checkbox")
+
+#else
+
+#end
+
+
+#elseif($column.list && "" != $javaField)
+
+#end
+#end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+
+
+
+#elseif($column.htmlType == "imageUpload")
+
+
+
+#elseif($column.htmlType == "fileUpload")
+
+
+
+#elseif($column.htmlType == "editor")
+
+
+
+#elseif($column.htmlType == "select" && "" != $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "select" && $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+
+
+
+ {{dict.label}}
+
+
+
+#elseif($column.htmlType == "checkbox" && $dictType)
+
+
+ 请选择字典生成
+
+
+#elseif($column.htmlType == "radio" && "" != $dictType)
+
+
+ {{dict.label}}
+
+
+#elseif($column.htmlType == "radio" && $dictType)
+
+
+ 请选择字典生成
+
+
+#elseif($column.htmlType == "datetime")
+
+
+
+
+#elseif($column.htmlType == "textarea")
+
+
+
+#end
+#end
+#end
+
+
+
+
+
+
+
+
+
diff --git a/iot-module/iot-generator/src/main/resources/vm/xml/mapper.xml.vm b/iot-module/iot-generator/src/main/resources/vm/xml/mapper.xml.vm
new file mode 100644
index 00000000..9fb48d99
--- /dev/null
+++ b/iot-module/iot-generator/src/main/resources/vm/xml/mapper.xml.vm
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/iot-module/pom.xml b/iot-module/pom.xml
index a0b4d164..2fda6a31 100644
--- a/iot-module/pom.xml
+++ b/iot-module/pom.xml
@@ -20,6 +20,7 @@
iot-plugin
iot-manager
iot-modbus
+ iot-generator
\ No newline at end of file
diff --git a/iot-starter/src/main/resources/application.yml b/iot-starter/src/main/resources/application.yml
index b57eaa77..59d903bd 100644
--- a/iot-starter/src/main/resources/application.yml
+++ b/iot-starter/src/main/resources/application.yml
@@ -1,5 +1,6 @@
spring:
profiles:
+# active: dev,generator # 使用application-dev.yml和代码生成器模块application-generator.yml配置
active: dev # 使用application-dev.yml 配置
# active: prd # 使用application-prd.yml 配置
# active: test # 使用application-test.yml 配置
diff --git a/iot-starter/src/main/resources/sql/schema-postgre.sql b/iot-starter/src/main/resources/sql/schema-postgre.sql
new file mode 100644
index 00000000..c593d651
--- /dev/null
+++ b/iot-starter/src/main/resources/sql/schema-postgre.sql
@@ -0,0 +1,112 @@
+
+-- ----------------------------
+-- 18、代码生成业务表
+-- ----------------------------
+drop table if exists gen_table;
+create table if not exists gen_table
+(
+ table_id int8,
+ data_name varchar(200) default ''::varchar,
+ table_name varchar(200) default ''::varchar,
+ table_comment varchar(500) default ''::varchar,
+ sub_table_name varchar(64) default ''::varchar,
+ sub_table_fk_name varchar(64) default ''::varchar,
+ class_name varchar(100) default ''::varchar,
+ tpl_category varchar(200) default 'crud'::varchar,
+ package_name varchar(100) default null::varchar,
+ module_name varchar(30) default null::varchar,
+ business_name varchar(30) default null::varchar,
+ function_name varchar(50) default null::varchar,
+ function_author varchar(50) default null::varchar,
+ gen_type char default '0'::bpchar not null,
+ gen_path varchar(200) default '/'::varchar,
+ options varchar(1000) default null::varchar,
+ create_dept int8,
+ create_by int8,
+ create_time timestamp,
+ update_by int8,
+ update_time timestamp,
+ remark varchar(500) default null::varchar,
+ constraint gen_table_pk primary key (table_id)
+ );
+
+comment on table gen_table is '代码生成业务表';
+comment on column gen_table.table_id is '编号';
+comment on column gen_table.data_name is '数据源名称';
+comment on column gen_table.table_name is '表名称';
+comment on column gen_table.table_comment is '表描述';
+comment on column gen_table.sub_table_name is '关联子表的表名';
+comment on column gen_table.sub_table_fk_name is '子表关联的外键名';
+comment on column gen_table.class_name is '实体类名称';
+comment on column gen_table.tpl_category is '使用的模板(CRUD单表操作 TREE树表操作)';
+comment on column gen_table.package_name is '生成包路径';
+comment on column gen_table.module_name is '生成模块名';
+comment on column gen_table.business_name is '生成业务名';
+comment on column gen_table.function_name is '生成功能名';
+comment on column gen_table.function_author is '生成功能作者';
+comment on column gen_table.gen_type is '生成代码方式(0zip压缩包 1自定义路径)';
+comment on column gen_table.gen_path is '生成路径(不填默认项目路径)';
+comment on column gen_table.options is '其它生成选项';
+comment on column gen_table.create_dept is '创建部门';
+comment on column gen_table.create_by is '创建者';
+comment on column gen_table.create_time is '创建时间';
+comment on column gen_table.update_by is '更新者';
+comment on column gen_table.update_time is '更新时间';
+comment on column gen_table.remark is '备注';
+
+-- ----------------------------
+-- 19、代码生成业务表字段
+-- ----------------------------
+drop table if exists gen_table_column;
+create table if not exists gen_table_column
+(
+ column_id int8,
+ table_id int8,
+ column_name varchar(200) default null::varchar,
+ column_comment varchar(500) default null::varchar,
+ column_type varchar(100) default null::varchar,
+ java_type varchar(500) default null::varchar,
+ java_field varchar(200) default null::varchar,
+ is_pk char default null::bpchar,
+ is_increment char default null::bpchar,
+ is_required char default null::bpchar,
+ is_insert char default null::bpchar,
+ is_edit char default null::bpchar,
+ is_list char default null::bpchar,
+ is_query char default null::bpchar,
+ query_type varchar(200) default 'EQ'::varchar,
+ html_type varchar(200) default null::varchar,
+ dict_type varchar(200) default ''::varchar,
+ sort int4,
+ create_dept int8,
+ create_by int8,
+ create_time timestamp,
+ update_by int8,
+ update_time timestamp,
+ constraint gen_table_column_pk primary key (column_id)
+ );
+
+comment on table gen_table_column is '代码生成业务表字段';
+comment on column gen_table_column.column_id is '编号';
+comment on column gen_table_column.table_id is '归属表编号';
+comment on column gen_table_column.column_name is '列名称';
+comment on column gen_table_column.column_comment is '列描述';
+comment on column gen_table_column.column_type is '列类型';
+comment on column gen_table_column.java_type is 'JAVA类型';
+comment on column gen_table_column.java_field is 'JAVA字段名';
+comment on column gen_table_column.is_pk is '是否主键(1是)';
+comment on column gen_table_column.is_increment is '是否自增(1是)';
+comment on column gen_table_column.is_required is '是否必填(1是)';
+comment on column gen_table_column.is_insert is '是否为插入字段(1是)';
+comment on column gen_table_column.is_edit is '是否编辑字段(1是)';
+comment on column gen_table_column.is_list is '是否列表字段(1是)';
+comment on column gen_table_column.is_query is '是否查询字段(1是)';
+comment on column gen_table_column.query_type is '查询方式(等于、不等于、大于、小于、范围)';
+comment on column gen_table_column.html_type is '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)';
+comment on column gen_table_column.dict_type is '字典类型';
+comment on column gen_table_column.sort is '排序';
+comment on column gen_table_column.create_dept is '创建部门';
+comment on column gen_table_column.create_by is '创建者';
+comment on column gen_table_column.create_time is '创建时间';
+comment on column gen_table_column.update_by is '更新者';
+comment on column gen_table_column.update_time is '更新时间';
diff --git a/iot-starter/src/main/resources/sql/schema.sql b/iot-starter/src/main/resources/sql/schema.sql
new file mode 100644
index 00000000..b9ea000a
--- /dev/null
+++ b/iot-starter/src/main/resources/sql/schema.sql
@@ -0,0 +1,60 @@
+-- ----------------------------
+-- 18、代码生成业务表
+-- ----------------------------
+create table if not exists gen_table (
+ table_id bigint(20) not null comment '编号',
+ data_name varchar(200) default '' 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 '生成代码方式(0zip压缩包 1自定义路径)',
+ gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)',
+ options varchar(1000) comment '其它生成选项',
+ create_dept bigint(20) default null comment '创建部门',
+ create_by bigint(20) default null comment '创建者',
+ create_time datetime comment '创建时间',
+ update_by bigint(20) default null comment '更新者',
+ update_time datetime comment '更新时间',
+ remark varchar(500) default null comment '备注',
+ primary key (table_id)
+) engine=innodb comment = '代码生成业务表';
+
+
+-- ----------------------------
+-- 19、代码生成业务表字段
+-- ----------------------------
+
+create table if not exists gen_table_column (
+ column_id bigint(20) not null comment '编号',
+ table_id bigint(20) 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_dept bigint(20) default null comment '创建部门',
+ create_by bigint(20) default null comment '创建者',
+ create_time datetime comment '创建时间',
+ update_by bigint(20) default null comment '更新者',
+ update_time datetime comment '更新时间',
+ primary key (column_id)
+) engine=innodb comment = '代码生成业务表字段';
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 39b40b60..028750a7 100755
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,9 @@
5.8.18
1.3.1
3.1.4
+ 1.0.6
+ 2.3
+
@@ -340,6 +343,12 @@
${project.version}
+
+ cc.iotkit
+ iot-generator
+ ${project.version}
+
+
cc.iotkit
iot-message-notify
@@ -406,6 +415,17 @@
${iot-iita-core.version}
+
+ com.github.yitter
+ yitter-idgenerator
+ ${yitter.version}
+
+
+
+ org.apache.velocity
+ velocity-engine-core
+ ${velocity.version}
+