Sfoglia il codice sorgente

新增 代码生成模块
新增 菜单
删除 auth模块

18339543638 2 anni fa
parent
commit
48b7337176
100 ha cambiato i file con 4264 aggiunte e 618 eliminazioni
  1. 12 0
      tr-dependencies/pom.xml
  2. 0 12
      tr-framework/src/main/java/cn/tr/core/constant/AuthConstant.java
  3. 2 0
      tr-framework/src/main/java/cn/tr/core/exception/TRExcCode.java
  4. 43 0
      tr-framework/src/main/java/cn/tr/core/tree/TreeNode.java
  5. 101 0
      tr-framework/src/main/java/cn/tr/core/utils/TreeUtil.java
  6. 1 1
      tr-modules/pom.xml
  7. 0 21
      tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/bo/RoleSmartBO.java
  8. 0 33
      tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/bo/UserInfoInTokenBO.java
  9. 0 47
      tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/config/FillUserAccountConfig.java
  10. 0 67
      tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/controller/AuthController.java
  11. 0 46
      tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/controller/CurrentUserController.java
  12. 0 25
      tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/controller/vo/AuthInfoVO.java
  13. 10 7
      tr-modules/tr-module-gen/pom.xml
  14. 26 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/enums/GenBuildInEnum.java
  15. 61 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/util/CommonDownloadUtil.java
  16. 54 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/util/CommonResponseUtil.java
  17. 91 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/util/GenDbTypeUtil.java
  18. 190 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/controller/GenBasicController.java
  19. 77 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/entity/CommonPageRequest.java
  20. 146 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/entity/CommonValidList.java
  21. 91 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/entity/GenBasic.java
  22. 45 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/CommonSortOrderEnum.java
  23. 58 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenEffectTypeEnum.java
  24. 55 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenJavaTypeEnum.java
  25. 37 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenTypeEnum.java
  26. 37 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenYesNoEnum.java
  27. 29 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/mapper/GenBasicMapper.java
  28. 5 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/mapper/mapping/GenBasicMapper.xml
  29. 98 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicAddParam.java
  30. 104 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicEditParam.java
  31. 35 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicIdParam.java
  32. 44 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicPageParam.java
  33. 35 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicTableColumnParam.java
  34. 59 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/result/GenBasicPreviewResult.java
  35. 40 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/result/GenBasicTableColumnResult.java
  36. 36 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/result/GenBasicTableResult.java
  37. 121 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/service/GenBasicService.java
  38. 631 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/service/impl/GenBasicServiceImpl.java
  39. 125 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/controller/GenConfigController.java
  40. 95 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/entity/GenConfig.java
  41. 25 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/mapper/GenConfigMapper.java
  42. 5 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/mapper/mapping/GenConfigMapper.xml
  43. 95 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigAddParam.java
  44. 107 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigEditParam.java
  45. 35 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigIdParam.java
  46. 43 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigListParam.java
  47. 51 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigPageParam.java
  48. 77 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/service/GenConfigService.java
  49. 95 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/service/impl/GenConfigServiceImpl.java
  50. 13 0
      tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/package-info.java
  51. 2 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictDTO.java
  52. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictItemServiceImpl.java
  53. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictServiceImpl.java
  54. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/log/config/OperateConfig.java
  55. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/log/service/impl/SysOperLogServiceImpl.java
  56. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/dict/DictItemMapper.java
  57. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/dict/DictMapper.java
  58. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/log/OperLogMapper.java
  59. 20 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/oauth2/UserLoginInfoMapper.java
  60. 25 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysMenuMapper.java
  61. 10 3
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysUserMapper.java
  62. 63 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/config/SaOAuth2TemplateImpl.java
  63. 0 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/constant/OAuth2Constant.java
  64. 47 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/CurrentUserController.java
  65. 108 13
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/OAuth2ServerController.java
  66. 35 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/vo/SwitchTenantUserVO.java
  67. 23 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2DTO.java
  68. 2 6
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2PswReqDTO.java
  69. 19 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2RefreshDTO.java
  70. 27 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2UpdatePswDTO.java
  71. 2 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/operator/OAuth2UserOperator.java
  72. 7 8
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/OAuth2PswModelConfig.java
  73. 9 7
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/LoginOAuth2PswUserOperator.java
  74. 78 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysMenuController.java
  75. 85 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuDTO.java
  76. 16 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuQueryDTO.java
  77. 16 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysUserQueryDTO.java
  78. 82 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysMenuPO.java
  79. 2 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysUserPO.java
  80. 17 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysMenuRepository.java
  81. 76 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysMenuService.java
  82. 17 7
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysUserService.java
  83. 0 55
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/SysUserServiceImpl.java
  84. 47 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysMenuServiceImpl.java
  85. 77 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysUserServiceImpl.java
  86. 0 2
      tr-plugins/pom.xml
  87. 0 47
      tr-plugins/tr-spring-boot-starter-plugin-auth2/pom.xml
  88. 0 15
      tr-plugins/tr-spring-boot-starter-plugin-auth2/src/main/java/cn/tr/plugin/auth2/server/SaOAuth2ServerApplication.java
  89. 0 62
      tr-plugins/tr-spring-boot-starter-plugin-auth2/src/main/java/cn/tr/plugin/auth2/server/SaOAuth2ServerController.java
  90. 0 35
      tr-plugins/tr-spring-boot-starter-plugin-auth2/src/main/java/cn/tr/plugin/auth2/server/SaOAuth2TemplateImpl.java
  91. 1 1
      tr-plugins/tr-spring-boot-starter-plugin-biz-tenant/src/main/java/cn/tr/plugin/biz/tenant/context/TenantContextHolder.java
  92. 30 0
      tr-plugins/tr-spring-boot-starter-plugin-biz-tenant/src/main/resources/META-INF/spring-configuration-metadata.json
  93. 8 13
      tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/pojo/BasePO.java
  94. 19 0
      tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/pojo/TenantPO.java
  95. 26 0
      tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/service/ITreeService.java
  96. 21 3
      tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/bo/UserLoginInfoBO.java
  97. 25 38
      tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/config/LoginUserStrategyConfig.java
  98. 67 22
      tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/config/TrSaTokenWebConfig.java
  99. 4 3
      tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/context/LoginUserContextHolder.java
  100. 4 1
      tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/filter/TrSaTokenFilter.java

+ 12 - 0
tr-dependencies/pom.xml

@@ -60,6 +60,11 @@
 
         <!--阿里云短信-->
         <ali.core.version>4.6.0</ali.core.version>
+
+        <!--渲染模板引擎-->
+        <beetl.version>1.2.40.Beetl.RELEASE</beetl.version>
+
+
         <ali.dysmsapi.version>2.2.1</ali.dysmsapi.version>
     </properties>
 
@@ -422,6 +427,13 @@
                 <version>${ali.dysmsapi.version}</version>
             </dependency>
             <!--阿里云短信-->
+
+            <dependency>
+                <groupId>com.ibeetl</groupId>
+                <artifactId>beetl-framework-starter</artifactId>
+                <version>${beetl.version}</version>
+            </dependency>
+
         </dependencies>
     </dependencyManagement>
 </project>

+ 0 - 12
tr-framework/src/main/java/cn/tr/core/constant/AuthConstant.java

@@ -1,12 +0,0 @@
-package cn.tr.core.constant;
-
-/**
- * @Interface : AuthConstant
- * @Description :
- * @Author : LF
- * @Date: 2023年03月24日
- */
-
-public interface AuthConstant {
-    String ACCOUNT_USER="accountUser";
-}

+ 2 - 0
tr-framework/src/main/java/cn/tr/core/exception/TRExcCode.java

@@ -54,6 +54,8 @@ public enum TRExcCode implements BaseCode {
     USER_ERROR_A0241("A0241", "用户验证码尝试次数超限"),
     USER_ERROR_A0242("A0242", "用户未登录"),
 
+    USER_ERROR_A0243("A0243", "OAuth2 认证失败"),
+    USER_ERROR_A0244("A0244", "用户尚未选择租户信息"),
     /**** 权限 **/
     USER_ERROR_A0300("A0300", "访问权限异常"),
     USER_ERROR_A0301("A0301", "访问未授权"),

+ 43 - 0
tr-framework/src/main/java/cn/tr/core/tree/TreeNode.java

@@ -0,0 +1,43 @@
+package cn.tr.core.tree;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree基类
+ * 
+ * @author ruoyi
+ */
+@Data
+public abstract class TreeNode<PK>
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 父节点
+     */
+    private PK parentId;
+
+    /**
+     * 顺序
+     */
+    private Integer sort;
+
+    /**
+     * 子节点集合
+     */
+    private List<TreeNode<PK>> children = new ArrayList<>();
+
+    /**
+     * 节点路径
+     */
+    private String nodePath;
+
+    @JsonIgnore
+    public abstract PK getId();
+
+    @JsonIgnore
+    public abstract String getName();
+}

+ 101 - 0
tr-framework/src/main/java/cn/tr/core/utils/TreeUtil.java

@@ -0,0 +1,101 @@
+package cn.tr.core.utils;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.tr.core.tree.TreeNode;
+import lombok.experimental.UtilityClass;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : TreeUtil
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+@UtilityClass
+public class TreeUtil {
+    /**
+     * 获取ID对应的节点,如果有多个ID相同的节点,只返回第一个。<br>
+     * 此方法只查找此节点及子节点,采用递归深度优先遍历。
+     *
+     * @param <T>  ID类型
+     * @param node 节点
+     * @param id   ID
+     * @return 节点
+     * @since 5.2.4
+     */
+    public static <T> TreeNode<T> getNode(TreeNode<T> node, T id) {
+        if (ObjectUtil.equal(id, node.getId())) {
+            return node;
+        }
+        final List<TreeNode<T>> children = node.getChildren();
+        if (null == children) {
+            return null;
+        }
+
+        // 查找子节点
+        TreeNode<T> childNode;
+        for (TreeNode<T> child : children) {
+            childNode = getNode(child, id);
+            if(childNode!=null){
+                return childNode;
+            }
+        }
+
+        // 未找到节点
+        return null;
+    }
+    /**
+     * 将传入的数组转变为树状结构
+     * @param sources
+     * @return
+     */
+    public static  List<TreeNode> buildTree(Collection<TreeNode> sources){
+        return buildTree(sources,null);
+    };
+
+    public static  <D extends TreeNode> List<D> buildTree(Collection<D > sources, List<String> excludeNodeIds){
+        if(CollectionUtil.isNotEmpty(excludeNodeIds)){
+            sources=sources.stream()
+                    .filter(source->!excludeNodeIds.contains(source.getId()))
+                    .collect(Collectors.toList());
+        }
+        //找到顶级节点
+        sources.stream().filter(source-> ObjectUtil.isNull(source.getSort())).forEach(source->source.setSort(999));
+        List<D> result = sources.stream()
+                .filter(node -> StrUtil.equals("0",String.valueOf(node.getParentId())))
+                .collect(Collectors.toList());
+        if(CollectionUtil.isEmpty(result)){
+            return result;
+        }
+        Map<Object, List<TreeNode>> groupByParentId = sources.stream()
+                .filter(node ->!StrUtil.equals("0",String.valueOf(node.getParentId())))
+                .collect(Collectors.groupingBy(TreeNode::getParentId));
+        result.forEach(topNode->{
+            topNode.setNodePath(topNode.getName());
+            fillChildNode(topNode,groupByParentId);
+        });
+        CollectionUtil.sort(result, Comparator.comparing(TreeNode::getSort));
+        return result;
+    }
+
+    /**
+     * 填充叶子子节点
+     */
+    private static void fillChildNode(TreeNode source, Map<Object, List<TreeNode>> groupByParentIdMap){
+        Object parentId = source.getId();
+        List<TreeNode> children = groupByParentIdMap.get(parentId);
+        if(CollectionUtil.isEmpty(children)){
+            return;
+        }
+        source.setChildren(children);
+        children.forEach(child->{
+            child.setNodePath(Optional.ofNullable(source.getName()).orElse("")+"/"+child.getName());
+            fillChildNode(child,groupByParentIdMap);
+        });
+        CollectionUtil.sort(children,Comparator.comparing(TreeNode::getSort));
+    }
+}

+ 1 - 1
tr-modules/pom.xml

@@ -13,8 +13,8 @@
     <packaging>pom</packaging>
     <version>${revision}</version>
     <modules>
-        <module>tr-module-auth</module>
         <module>tr-module-system</module>
+        <module>tr-module-gen</module>
     </modules>
 
 

+ 0 - 21
tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/bo/RoleSmartBO.java

@@ -1,21 +0,0 @@
-package cn.tr.module.auth.bo;
-
-import io.swagger.annotations.ApiModel;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-/**
- * @ClassName : RoleSmartBO
- * @Description :
- * @Author : JR
- * @Date: 2022年11月23日
- */
-@Data
-@ApiModel("角色")
-@NoArgsConstructor
-@AllArgsConstructor(staticName = "of")
-public class RoleSmartBO {
-    private String roleName;
-    private String roleCode;
-}

+ 0 - 33
tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/bo/UserInfoInTokenBO.java

@@ -1,33 +0,0 @@
-package cn.tr.module.auth.bo;
-
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
-
-import java.io.Serializable;
-
-/**
- * @ClassName : UserInfoInTokenBO
- * @Description : 与token绑定的用户信息
- * @Author : JR
- * @Date: 2022年11月22日
- */
-@Data
-@NoArgsConstructor
-@Builder
-@Accessors(chain = true)
-@AllArgsConstructor
-public class UserInfoInTokenBO implements Serializable {
-
-    private static final long serialVersionUID = 8622890101502110767L;
-
-    private String userId;
-
-    private String username;
-
-    private String nickname;
-
-    private String avatar;
-}

+ 0 - 47
tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/config/FillUserAccountConfig.java

@@ -1,47 +0,0 @@
-package cn.tr.module.auth.config;
-
-import cn.tr.core.enums.WebFilterOrderEnum;
-import cn.tr.core.strategy.auth.bo.UserAccountInfoBO;
-import cn.tr.core.constant.AuthConstant;
-import cn.tr.plugin.security.bo.LoginUserBO;
-import cn.tr.plugin.security.context.LoginUserContextHolder;
-import cn.tr.plugin.security.utils.SaTokenUtils;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import javax.servlet.*;
-import java.io.IOException;
-
-/**
- * @ClassName : FillUserAccountFilter
- * @Description : 填充当前用户账户信息
- * @Author : LF
- * @Date: 2023年03月02日
- */
-@Configuration
-public class FillUserAccountConfig{
-    /**
-     * 过滤器设置登录方式
-     */
-    @Bean
-    public FilterRegistrationBean fillUserAccount(){
-        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new FillUserAccountFilter());
-        filterRegistrationBean.addUrlPatterns("/*");
-        filterRegistrationBean.setOrder(WebFilterOrderEnum.FILL_LOGIN_TYPE-100);
-        return filterRegistrationBean;
-    }
-
-
-    class FillUserAccountFilter implements Filter {
-        @Override
-        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
-            try {
-                UserAccountInfoBO accountInfo = SaTokenUtils.getValue(AuthConstant.ACCOUNT_USER, UserAccountInfoBO.class);
-                LoginUserContextHolder.setUser(new LoginUserBO(accountInfo.getId(),accountInfo.getUsername(),accountInfo.getTenantId()));
-            }catch (Exception e){}
-            filterChain.doFilter(servletRequest,servletResponse);
-        }
-    }
-}
-

+ 0 - 67
tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/controller/AuthController.java

@@ -1,67 +0,0 @@
-package cn.tr.module.auth.controller;
-
-import cn.dev33.satoken.annotation.SaIgnore;
-import cn.tr.core.exception.TRExcCode;
-import cn.tr.core.pojo.CommonResult;
-import cn.tr.core.strategy.auth.AuthStrategy;
-import cn.tr.core.strategy.auth.bo.UserAccountInfoBO;
-import cn.tr.core.constant.AuthConstant;
-import cn.tr.module.auth.controller.vo.AuthInfoVO;
-import cn.tr.core.strategy.auth.bo.AuthenticationDTO;
-import cn.tr.core.strategy.auth.UserOperator;
-import cn.tr.plugin.operatelog.annotation.OperateLog;
-import cn.tr.plugin.security.utils.SaTokenUtils;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.AllArgsConstructor;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
-
-/**
- * @ClassName : AuthController
- * @Description :
- * @Author : LF
- * @Date: 2023年03月24日
- */
-@RestController
-@RequestMapping("/ua")
-@Api(tags = "认证接口")
-@AllArgsConstructor
-public class AuthController {
-
-    @OperateLog( name = "登录认证", isLogin = true)
-    @PostMapping("/login")
-    @SaIgnore
-    @ApiOperation("登录认证")
-    public CommonResult<AuthInfoVO> login(@Validated @RequestBody AuthenticationDTO authentication) {
-        UserOperator authGranter = AuthStrategy.tr.matchGranter(authentication.getLoginType());
-        if(authGranter==null){
-            return CommonResult.error(TRExcCode.USER_ERROR_A0200,"登录方式错误");
-        }
-        UserAccountInfoBO accountInfo = authGranter.login(authentication);
-        SaTokenUtils.set(AuthConstant.ACCOUNT_USER,accountInfo);
-        return CommonResult.success(AuthInfoVO.of(accountInfo.getToken(),
-                authentication.getLoginType()));
-    }
-
-    @ApiOperation(value = "刷新令牌")
-    @PostMapping("/refresh-token")
-    @SaIgnore
-    public CommonResult<Boolean> refreshToken(@RequestParam("refreshToken") String refreshToken) {
-        SaTokenUtils.getStpUtil().updateLastActivityToNow(refreshToken);
-        return CommonResult.success(true);
-    }
-
-    @OperateLog( name = "用户登出")
-    @ApiOperation(value = "用户登出",notes = "清除token,清除权限缓存")
-    @PostMapping("/logout")
-    public CommonResult<Boolean> logout() {
-        SaTokenUtils.logout();
-        return CommonResult.success(true);
-    }
-
-
-
-
-
-}

+ 0 - 46
tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/controller/CurrentUserController.java

@@ -1,46 +0,0 @@
-package cn.tr.module.auth.controller;
-
-import cn.tr.core.pojo.CommonResult;
-import cn.tr.core.strategy.auth.bo.UserAccountInfoBO;
-import cn.tr.module.auth.bo.UserInfoInTokenBO;
-import cn.tr.core.constant.AuthConstant;
-import cn.tr.plugin.security.utils.SaTokenUtils;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * @ClassName : CurrentUserController
- * @Description :
- * @Author : LF
- * @Date: 2023年03月24日
- */
-@RestController
-@RequestMapping("/user")
-@Api(tags = "当前用户信息接口")
-@AllArgsConstructor
-public class CurrentUserController {
-
-    @ApiOperation(value = "获取账号中心信息")
-    @GetMapping("/accountInfo")
-    public CommonResult<UserAccountInfoBO> accountInfo(){
-        return CommonResult.success(SaTokenUtils.getValue(AuthConstant.ACCOUNT_USER, UserAccountInfoBO.class));
-    }
-
-
-
-    @ApiOperation(value = "当前用户账号信息")
-    @GetMapping("/basicInfo")
-    public CommonResult<UserInfoInTokenBO> userInfo() {
-        UserAccountInfoBO accountInfo = SaTokenUtils.getValue(AuthConstant.ACCOUNT_USER, UserAccountInfoBO.class);
-        return CommonResult.success(UserInfoInTokenBO.builder()
-                .userId(accountInfo.getId())
-                .username(accountInfo.getUsername())
-                .nickname(accountInfo.getNickname())
-                .avatar(accountInfo.getAvatar())
-                .build());
-    }
-}

+ 0 - 25
tr-modules/tr-module-auth/src/main/java/cn/tr/module/auth/controller/vo/AuthInfoVO.java

@@ -1,25 +0,0 @@
-package cn.tr.module.auth.controller.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName AuthInfoVo.java
- * @Description TODO
- * @createTime 2022年08月01日 14:28:00
- */
-@Data
-@ApiModel("授权结果")
-@AllArgsConstructor(staticName = "of")
-public class AuthInfoVO {
-
-    @ApiModelProperty("令牌")
-    private String accessToken;
-
-    @ApiModelProperty("登录方式")
-    private String loginType;
-}

+ 10 - 7
tr-modules/tr-module-auth/pom.xml → tr-modules/tr-module-gen/pom.xml

@@ -10,32 +10,35 @@
     <modelVersion>4.0.0</modelVersion>
 
     <version>${revision}</version>
-    <artifactId>tr-module-auth</artifactId>
+    <artifactId>tr-module-gen</artifactId>
 
 
-    <description>认证模块</description>
+    <description>代码生成器</description>
 
     <dependencies>
         <dependency>
             <groupId>cn.tr</groupId>
-            <artifactId>tr-spring-boot-starter-plugin-satoken</artifactId>
+            <artifactId>tr-framework</artifactId>
         </dependency>
 
-
         <dependency>
             <groupId>cn.tr</groupId>
-            <artifactId>tr-spring-boot-starter-plugin-doc</artifactId>
+            <artifactId>tr-spring-boot-starter-plugin-mybatis</artifactId>
         </dependency>
 
         <dependency>
             <groupId>cn.tr</groupId>
-            <artifactId>tr-spring-boot-starter-plugin-operatelog</artifactId>
+            <artifactId>tr-spring-boot-starter-plugin-doc</artifactId>
         </dependency>
 
         <dependency>
             <groupId>cn.tr</groupId>
-            <artifactId>tr-spring-boot-starter-plugin-banner</artifactId>
+            <artifactId>tr-spring-boot-starter-plugin-web</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.ibeetl</groupId>
+            <artifactId>beetl-framework-starter</artifactId>
+        </dependency>
     </dependencies>
 </project>

+ 26 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/enums/GenBuildInEnum.java

@@ -0,0 +1,26 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 代码生成标识枚举
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+public enum GenBuildInEnum {
+
+}

+ 61 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/util/CommonDownloadUtil.java

@@ -0,0 +1,61 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.core.util;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.URLUtil;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * 文件下载工具类,使用本类前,对参数校验的异常使用CommonResponseUtil.renderError()方法进行渲染
+ *
+ * @author xuyuxiang
+ * @date 2020/8/5 21:45
+ */
+public class CommonDownloadUtil {
+
+    /**
+     * 下载文件
+     *
+     * @param file     要下载的文件
+     * @param response 响应
+     * @author xuyuxiang
+     * @date 2020/8/5 21:46
+     */
+    public static void download(File file, HttpServletResponse response) {
+        download(file.getName(), FileUtil.readBytes(file), response);
+    }
+
+    /**
+     * 下载文件
+     *
+     * @author xuyuxiang
+     * @date 2022/7/31 10:57
+     */
+    public static void download(String fileName, byte[] fileBytes, HttpServletResponse response) {
+        try {
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLUtil.encode(fileName));
+            response.addHeader("Content-Length", "" + fileBytes.length);
+            response.setHeader("Access-Control-Allow-Origin", "*");
+            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
+            response.setContentType("application/octet-stream;charset=UTF-8");
+            IoUtil.write(response.getOutputStream(), true, fileBytes);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 54 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/util/CommonResponseUtil.java

@@ -0,0 +1,54 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.core.util;
+
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.ContentType;
+import cn.hutool.json.JSONUtil;
+import cn.tr.core.exception.TRExcCode;
+import cn.tr.core.pojo.CommonResult;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 通用响应工具类
+ *
+ * @author xuyuxiang
+ * @date 2022/8/4 9:40
+ **/
+public class CommonResponseUtil {
+
+    /**
+     * 以流的方式响应错误信息,默认错误消息
+     *
+     * @author xuyuxiang
+     * @date 2022/8/4 9:41
+     **/
+    public static void renderError(HttpServletResponse response) throws IOException {
+        renderError(response, null);
+    }
+
+    /**
+     * 以流的方式响应错误信息,指定错误消息
+     *
+     * @author xuyuxiang
+     * @date 2022/8/4 9:41
+     **/
+    public static void renderError(HttpServletResponse response, String msg) throws IOException {
+        response.setCharacterEncoding(CharsetUtil.UTF_8);
+        response.setContentType(ContentType.JSON.toString());
+        response.getWriter().write(JSONUtil.toJsonStr(ObjectUtil.isNotEmpty(msg)? CommonResult.error(TRExcCode.SYSTEM_ERROR_B0001,msg):CommonResult.error(TRExcCode.SYSTEM_ERROR_B0001)));
+    }
+}

+ 91 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/core/util/GenDbTypeUtil.java

@@ -0,0 +1,91 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.core.util;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.tr.module.gen.modular.basic.enums.GenJavaTypeEnum;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 数据库类型工具类
+ *
+ * @author xuyuxiang
+ * @date 2022/10/26 16:33
+ **/
+@Slf4j
+public class GenDbTypeUtil {
+
+    /**
+     * 根据数据库字段类型获取Java类型
+     *
+     * @author xuyuxiang
+     * @date 2022/10/26 16:34
+     **/
+    public static String getJavaTypeBySqlType(String dataType) {
+        if(ObjectUtil.isEmpty(dataType)) {
+            log.info(">>> 字段的数据库类型为空,使用默认值String");
+            return GenJavaTypeEnum.String.getValue();
+        }
+        dataType = dataType.toUpperCase();
+        if(dataType.startsWith("INT")) {
+            //如果以int开头,则直接返回int,兼容pgsql中int2 int8等
+            return GenJavaTypeEnum.Integer.getValue();
+        }
+        switch(dataType){
+            case "NVARCHAR":
+            case "NVARCHAR2":
+            case "CHAR":
+            case "VARCHAR":
+            case "ENUM":
+            case "SET":
+            case "TEXT":
+            case "LONGTEXT":
+            case "NCHAR":
+            case "BLOB":
+            case "NCLOB":
+            case "IMAGE":
+                return GenJavaTypeEnum.String.getValue();
+            case "INTEGER":
+            case "BIGINT":
+            case "NUMBER":
+            case "ID":
+                return GenJavaTypeEnum.Long.getValue();
+            case "TINYINT":
+            case "SMALLINT":
+            case "MEDIUMINT":
+                return GenJavaTypeEnum.Integer.getValue();
+            case "BIT":
+            case "BOOLEAN":
+                return GenJavaTypeEnum.Boolean.getValue();
+            case "FLOAT":
+                return GenJavaTypeEnum.Float.getValue();
+            case "DOUBLE":
+            case "MONEY":
+            case "SMALLMONEY":
+                return GenJavaTypeEnum.Double.getValue();
+            case "DECIMAL":
+            case "NUMERIC":
+            case "REAL":
+                return GenJavaTypeEnum.BigDecimal.getValue();
+            case "DATE":
+            case "DATETIME":
+            case "YEAR":
+            case "TIME":
+            case "TIMESTAMP":
+                return GenJavaTypeEnum.Date.getValue();
+            default:
+                log.info(">>> 字段的数据库类型:{}无法匹配,使用默认值String", dataType);
+                return GenJavaTypeEnum.String.getValue();
+        }
+    }
+}

+ 190 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/controller/GenBasicController.java

@@ -0,0 +1,190 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.controller;
+
+import cn.tr.core.pojo.CommonResult;
+import cn.tr.module.gen.modular.basic.entity.CommonValidList;
+import cn.tr.module.gen.modular.basic.entity.GenBasic;
+import cn.tr.module.gen.modular.basic.param.*;
+import cn.tr.module.gen.modular.basic.result.GenBasicPreviewResult;
+import cn.tr.module.gen.modular.basic.result.GenBasicTableColumnResult;
+import cn.tr.module.gen.modular.basic.result.GenBasicTableResult;
+import cn.tr.module.gen.modular.basic.service.GenBasicService;
+import cn.tr.plugin.mybatis.base.BaseController;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import com.github.xiaoymin.knife4j.annotations.ApiSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+import java.io.IOException;
+import java.util.*;
+/**
+ * 代码生成基础控制器
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Api(tags = "代码生成基础控制器")
+@ApiSupport(author = "SNOWY_TEAM", order = 1)
+@RestController
+@Validated
+public class GenBasicController extends BaseController {
+
+    @Resource
+    private GenBasicService genBasicService;
+
+    /**
+     * 获取代码生成基础分页
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 1)
+    @ApiOperation("获取代码生成基础分页")
+    @GetMapping("/gen/basic/page")
+    public CommonResult<Page<GenBasic>> page(GenBasicPageParam genBasicPageParam) {
+
+        return CommonResult.success(genBasicService.page(genBasicPageParam));
+    }
+
+    /**
+     * 添加代码生成基础
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:47
+     */
+    @ApiOperationSupport(order = 2)
+    @ApiOperation("添加代码生成基础")
+    @PostMapping("/gen/basic/add")
+    public CommonResult<GenBasic> add(@RequestBody @Valid GenBasicAddParam genBasicAddParam) {
+        return CommonResult.success(genBasicService.add(genBasicAddParam));
+    }
+
+    /**
+     * 编辑代码生成基础
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:47
+     */
+    @ApiOperationSupport(order = 3)
+    @ApiOperation("编辑代码生成基础")
+    @PostMapping("/gen/basic/edit")
+    public CommonResult<GenBasic> edit(@RequestBody @Valid GenBasicEditParam genBasicEditParam) {
+        return CommonResult.success(genBasicService.edit(genBasicEditParam));
+    }
+
+    /**
+     * 删除代码生成基础
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 4)
+    @ApiOperation("删除代码生成基础")
+    @PostMapping("/gen/basic/delete")
+    public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                               CommonValidList<GenBasicIdParam> genBasicIdParamList) {
+        genBasicService.delete(genBasicIdParamList);
+        return CommonResult.success();
+    }
+
+    /**
+     * 获取代码生成基础详情
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 5)
+    @ApiOperation("获取代码生成基础详情")
+    @GetMapping("/gen/basic/detail")
+    public CommonResult<GenBasic> detail(@Valid GenBasicIdParam genBasicIdParam) {
+        return CommonResult.success(genBasicService.detail(genBasicIdParam));
+    }
+
+    /**
+     * 获取所有表信息
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 6)
+    @ApiOperation("获取所有表信息")
+    @GetMapping("/gen/basic/tables")
+    public CommonResult<List<GenBasicTableResult>> dbsTable() {
+        return CommonResult.success(genBasicService.tables());
+    }
+
+    /**
+     * 获取表内所有字段信息
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 7)
+    @ApiOperation("获取表内所有字段信息")
+    @GetMapping("/gen/basic/tableColumns")
+    public CommonResult<List<GenBasicTableColumnResult>> tableColumns(GenBasicTableColumnParam genBasicTableColumnParam) {
+        return CommonResult.success(genBasicService.tableColumns(genBasicTableColumnParam));
+    }
+
+    /**
+     * 执行代码生成
+     *
+     * @author xuyuxiang
+     * @date 2022/6/21 15:44
+     **/
+    @ApiOperationSupport(order = 8)
+    @ApiOperation("执行代码生成(压缩包)")
+    @GetMapping(value = "/gen/basic/execGenZip", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+    public void execGenZip(@Valid GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
+        genBasicService.execGenZip(genBasicIdParam, response);
+    }
+
+    /**
+     * 执行代码生成
+     *
+     * @author yubaoshan
+     * @date 2022/10/31 02:17
+     **/
+    @ApiOperationSupport(order = 9)
+    @ApiOperation("执行代码生成(项目内)")
+    @PostMapping(value = "/gen/basic/execGenPro")
+    public CommonResult<String> execGenPro(@RequestBody @Valid GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
+        genBasicService.execGenPro(genBasicIdParam, response);
+        return CommonResult.success();
+    }
+
+    /**
+     * 预览代码生成
+     *
+     * @author xuyuxiang
+     * @date 2022/6/21 15:44
+     **/
+    @ApiOperationSupport(order = 10)
+    @ApiOperation("预览代码生成")
+    @GetMapping(value = "/gen/basic/previewGen")
+    public CommonResult<GenBasicPreviewResult> previewGen(@Valid GenBasicIdParam genBasicIdParam) {
+        return CommonResult.success(genBasicService.previewGen(genBasicIdParam));
+    }
+}
+

+ 77 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/entity/CommonPageRequest.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.entity;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.metadata.OrderItem;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import vip.xiaonuo.common.util.CommonServletUtil;
+
+import java.util.List;
+
+/**
+ * 通用分页请求
+ *
+ * @author xuyuxiang
+ * @date 2021/12/18 14:43
+ */
+public class CommonPageRequest {
+
+    private static final String PAGE_SIZE_PARAM_NAME = "size";
+
+    private static final String PAGE_PARAM_NAME = "current";
+
+    private static final Integer PAGE_SIZE_MAX_VALUE = 100;
+
+    public static <T> Page<T> defaultPage() {
+        return defaultPage(null);
+    }
+
+    public static <T> Page<T> defaultPage(List<OrderItem> orderItemList) {
+
+        int size = 20;
+
+        int page = 1;
+
+        //每页条数
+        String pageSizeString = CommonServletUtil.getParamFromRequest(PAGE_SIZE_PARAM_NAME);
+        if (ObjectUtil.isNotEmpty(pageSizeString)) {
+            try {
+                size = Convert.toInt(pageSizeString);
+                if(size > PAGE_SIZE_MAX_VALUE) {
+                    size = PAGE_SIZE_MAX_VALUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                size = 20;
+            }
+        }
+
+        //第几页
+        String pageString = CommonServletUtil.getParamFromRequest(PAGE_PARAM_NAME);
+        if (ObjectUtil.isNotEmpty(pageString)) {
+            try {
+                page = Convert.toInt(pageString);
+            } catch (Exception e) {
+                e.printStackTrace();
+                page = 1;
+            }
+        }
+        Page<T> objectPage = new Page<>(page, size);
+        if (ObjectUtil.isNotEmpty(orderItemList)) {
+            objectPage.setOrders(orderItemList);
+        }
+        return objectPage;
+    }
+}

+ 146 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/entity/CommonValidList.java

@@ -0,0 +1,146 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.entity;
+
+import lombok.Data;
+
+import javax.validation.Valid;
+import java.util.*;
+
+/**
+ * 可被校验的通用List
+ *
+ * @author xuyuxiang
+ * @date 2022/7/28 16:08
+ **/
+@Data
+public class CommonValidList<E> implements List<E> {
+
+    @Valid
+    private List<E> list = new LinkedList<>();
+
+    @Override
+    public int size() {
+        return list.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return list.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        return list.contains(o);
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return list.iterator();
+    }
+
+    @Override
+    public Object[] toArray() {
+        return list.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] a) {
+        return list.toArray(a);
+    }
+
+    @Override
+    public boolean add(E e) {
+        return list.add(e);
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        return list.remove(o);
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> c) {
+        return list.containsAll(c);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends E> c) {
+        return list.addAll(c);
+    }
+
+    @Override
+    public boolean addAll(int index, Collection<? extends E> c) {
+        return list.addAll(index, c);
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> c) {
+        return list.removeAll(c);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> c) {
+        return list.retainAll(c);
+    }
+
+    @Override
+    public void clear() {
+        list.clear();
+    }
+
+    @Override
+    public E get(int index) {
+        return list.get(index);
+    }
+
+    @Override
+    public E set(int index, E element) {
+        return list.set(index, element);
+    }
+
+    @Override
+    public void add(int index, E element) {
+        list.add(index, element);
+    }
+
+    @Override
+    public E remove(int index) {
+        return list.remove(index);
+    }
+
+    @Override
+    public int indexOf(Object o) {
+        return list.indexOf(o);
+    }
+
+    @Override
+    public int lastIndexOf(Object o) {
+        return list.lastIndexOf(o);
+    }
+
+    @Override
+    public ListIterator<E> listIterator() {
+        return list.listIterator();
+    }
+
+    @Override
+    public ListIterator<E> listIterator(int index) {
+        return list.listIterator(index);
+    }
+
+    @Override
+    public List<E> subList(int fromIndex, int toIndex) {
+        return list.subList(fromIndex, toIndex);
+    }
+}

+ 91 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/entity/GenBasic.java

@@ -0,0 +1,91 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.entity;
+
+import cn.tr.plugin.mybatis.pojo.BasePO;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 代码生成基础
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+@TableName("gen_basic")
+public class GenBasic extends BasePO {
+
+    /** id */
+    @ApiModelProperty(value = "id", position = 1)
+    private String id;
+
+    /** 主表名称 */
+    @ApiModelProperty(value = "主表名称", position = 2)
+    private String dbTable;
+
+    /** 主表主键 */
+    @ApiModelProperty(value = "主表主键", position = 3)
+    private String dbTableKey;
+
+    /** 表前缀移除 */
+    @ApiModelProperty(value = "表前缀移除", position = 4)
+    private String tablePrefix;
+
+    /** 生成方式 */
+    @ApiModelProperty(value = "生成方式", position = 5)
+    private String generateType;
+
+    /** 所属模块 */
+    @ApiModelProperty(value = "所属模块", position = 6)
+    private String module;
+
+    /** 上级目录 */
+    @ApiModelProperty(value = "上级目录", position = 7)
+    private String menuPid;
+
+    /** 功能名 */
+    @ApiModelProperty(value = "功能名", position = 8)
+    private String functionName;
+
+    /** 业务名 */
+    @ApiModelProperty(value = "业务名", position = 9)
+    private String busName;
+
+    /** 类名 */
+    @ApiModelProperty(value = "类名", position = 10)
+    private String className;
+
+    /** 表单布局 */
+    @ApiModelProperty(value = "表单布局", position = 11)
+    private String formLayout;
+
+    /** 使用栅格 */
+    @ApiModelProperty(value = "使用栅格", position = 12)
+    private String gridWhether;
+
+    /** 排序 */
+    @ApiModelProperty(value = "排序", position = 13)
+    private Integer sortCode;
+
+    /** 包名 */
+    @ApiModelProperty(value = "包名", position = 14)
+    private String packageName;
+
+    /** 作者 */
+    @ApiModelProperty(value = "作者", position = 15)
+    private String authorName;
+}

+ 45 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/CommonSortOrderEnum.java

@@ -0,0 +1,45 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.enums;
+
+import lombok.Getter;
+import vip.xiaonuo.common.exception.CommonException;
+
+/**
+ * 通用排序方式枚举
+ *
+ * @author xuyuxiang
+ * @date 2022/7/13 17:48
+ **/
+@Getter
+public enum CommonSortOrderEnum {
+
+    /** 升序 */
+    ASC("ASCEND"),
+
+    /** 降序 */
+    DESC("DESCEND");
+
+    private final String value;
+
+    CommonSortOrderEnum(String value) {
+        this.value = value;
+    }
+
+    public static void validate(String value) {
+        boolean flag = ASC.getValue().toLowerCase().equals(value) || DESC.getValue().toLowerCase().equals(value);
+        if(!flag) {
+            throw new CommonException("不支持该排序方式:{}", value);
+        }
+    }
+}

+ 58 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenEffectTypeEnum.java

@@ -0,0 +1,58 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.enums;
+
+import lombok.Getter;
+
+/**
+ * 作用类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2022/10/28 9:57
+ **/
+@Getter
+public enum GenEffectTypeEnum {
+
+    /** 输入框 */
+    INPUT("INPUT"),
+
+    /** 文本框 */
+    TEXTAREA("TEXTAREA"),
+
+    /** 下拉框 */
+    SELECT("SELECT"),
+
+    /** 单选框 */
+    RADIO("RADIO"),
+
+    /** 复选框 */
+    CHECKBOX("CHECKBOX"),
+
+    /** 日期选择器 */
+    DATEPICKER("DATEPICKER"),
+
+    /** 时间选择器 */
+    TIMEPICKER("TIMEPICKER"),
+
+    /** 数字输入框 */
+    INPUTNUMBER("INPUTNUMBER"),
+
+    /** 滑动数字条 */
+    SLIDER("SLIDER");
+
+    private final String value;
+
+    GenEffectTypeEnum(String value) {
+        this.value = value;
+    }
+}

+ 55 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenJavaTypeEnum.java

@@ -0,0 +1,55 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.enums;
+
+import lombok.Getter;
+
+/**
+ * Java类型枚举
+ *
+ * @author xuyuxiang
+ * @date 2022/10/28 9:57
+ **/
+@Getter
+public enum GenJavaTypeEnum {
+
+    /** Integer */
+    Integer("Integer"),
+
+    /** Long */
+    Long("Long"),
+
+    /** String */
+    String("String"),
+
+    /** Boolean */
+    Boolean("Boolean"),
+
+    /** Float */
+    Float("Float"),
+
+    /** Double */
+    Double("Double"),
+
+    /** Date */
+    Date("Date"),
+
+    /** BigDecimal */
+    BigDecimal("BigDecimal");
+
+    private final String value;
+
+    GenJavaTypeEnum(String value) {
+        this.value = value;
+    }
+}

+ 37 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenTypeEnum.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.enums;
+
+import lombok.Getter;
+
+/**
+ * 生成方式枚举
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+public enum GenTypeEnum {
+
+    /** 压缩包 */
+    ZIP("ZIP"),
+
+    /** 项目内 */
+    PRO("PRO");
+
+    private final String value;
+
+    GenTypeEnum(String value) {
+        this.value = value;
+    }
+}

+ 37 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/enums/GenYesNoEnum.java

@@ -0,0 +1,37 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.enums;
+
+import lombok.Getter;
+
+/**
+ * 是与否枚举
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+public enum GenYesNoEnum {
+
+    /** 是 */
+    Y("Y"),
+
+    /** 否 */
+    N("N");
+
+    private final String value;
+
+    GenYesNoEnum(String value) {
+        this.value = value;
+    }
+}

+ 29 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/mapper/GenBasicMapper.java

@@ -0,0 +1,29 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.mapper;
+
+import cn.tr.module.gen.modular.basic.entity.GenBasic;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 代码生成基础Mapper接口
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Mapper
+@Repository
+public interface GenBasicMapper extends BaseMapper<GenBasic> {
+}

+ 5 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/mapper/mapping/GenBasicMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.gen.modular.basic.mapper.GenBasicMapper">
+
+</mapper>

+ 98 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicAddParam.java

@@ -0,0 +1,98 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 代码生成基础添加参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+public class GenBasicAddParam {
+
+    /** 主表名称 */
+    @ApiModelProperty(value = "主表名称", required = true, position = 1)
+    @NotNull(message = "dbTable不能为空")
+    private String dbTable;
+
+    /** 主表主键 */
+    @ApiModelProperty(value = "主表主键", required = true, position = 2)
+    @NotNull(message = "dbTableKey不能为空")
+    private String dbTableKey;
+
+    /** 表前缀移除 */
+    @ApiModelProperty(value = "表前缀移除", required = true, position = 3)
+    @NotNull(message = "tablePrefix不能为空")
+    private String tablePrefix;
+
+    /** 生成方式 */
+    @ApiModelProperty(value = "生成方式", required = true, position = 4)
+    @NotNull(message = "generateType不能为空")
+    private String generateType;
+
+    /** 所属模块 */
+    @ApiModelProperty(value = "所属模块", required = true, position = 5)
+    @NotNull(message = "module不能为空")
+    private String module;
+
+    /** 上级目录 */
+    @ApiModelProperty(value = "上级目录", required = true, position = 6)
+    @NotNull(message = "menuPid不能为空")
+    private String menuPid;
+
+    /** 功能名 */
+    @ApiModelProperty(value = "功能名", required = true, position = 7)
+    @NotNull(message = "functionName不能为空")
+    private String functionName;
+
+    /** 业务名 */
+    @ApiModelProperty(value = "业务名", required = true, position = 8)
+    @NotNull(message = "busName不能为空")
+    private String busName;
+
+    /** 类名 */
+    @ApiModelProperty(value = "类名", required = true, position = 9)
+    @NotNull(message = "className不能为空")
+    private String className;
+
+    /** 表单布局 */
+    @ApiModelProperty(value = "表单布局", required = true, position = 10)
+    @NotNull(message = "formLayout不能为空")
+    private String formLayout;
+
+    /** 使用栅格 */
+    @ApiModelProperty(value = "使用栅格", required = true, position = 11)
+    @NotNull(message = "gridWhether不能为空")
+    private String gridWhether;
+
+    /** 排序 */
+    @ApiModelProperty(value = "排序", required = true, position = 12)
+    @NotNull(message = "sortCode不能为空")
+    private Integer sortCode;
+
+    /** 作者名 */
+    @ApiModelProperty(value = "作者名", required = true, position = 13)
+    private String authorName;
+
+    /** 包名 */
+    @ApiModelProperty(value = "包名", required = true, position = 14)
+    private String packageName;
+}

+ 104 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicEditParam.java

@@ -0,0 +1,104 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * 代码生成基础编辑参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+public class GenBasicEditParam {
+
+    /** id */
+    @ApiModelProperty(value = "id", position = 1)
+    @NotNull(message = "id不能为空")
+    private String id;
+
+    /** 主表名称 */
+    @ApiModelProperty(value = "主表名称", position = 2)
+    @NotNull(message = "dbTable不能为空")
+    private String dbTable;
+
+    /** 主表主键 */
+    @ApiModelProperty(value = "主表主键", position = 3)
+    @NotNull(message = "dbTableKey不能为空")
+    private String dbTableKey;
+
+    /** 表前缀移除 */
+    @ApiModelProperty(value = "表前缀移除", position = 4)
+    @NotNull(message = "tablePrefix不能为空")
+    private String tablePrefix;
+
+    /** 生成方式 */
+    @ApiModelProperty(value = "生成方式", position = 5)
+    @NotNull(message = "generateType不能为空")
+    private String generateType;
+
+    /** 所属模块 */
+    @ApiModelProperty(value = "所属模块", position = 6)
+    @NotNull(message = "module不能为空")
+    private String module;
+
+    /** 上级目录 */
+    @ApiModelProperty(value = "上级目录", position = 7)
+    @NotNull(message = "menuPid不能为空")
+    private String menuPid;
+
+    /** 功能名 */
+    @ApiModelProperty(value = "功能名", position = 8)
+    @NotNull(message = "functionName不能为空")
+    private String functionName;
+
+    /** 业务名 */
+    @ApiModelProperty(value = "业务名", position = 9)
+    @NotNull(message = "busName不能为空")
+    private String busName;
+
+    /** 类名 */
+    @ApiModelProperty(value = "类名", position = 10)
+    @NotNull(message = "className不能为空")
+    private String className;
+
+    /** 表单布局 */
+    @ApiModelProperty(value = "表单布局", position = 11)
+    @NotNull(message = "formLayout不能为空")
+    private String formLayout;
+
+    /** 使用栅格 */
+    @ApiModelProperty(value = "使用栅格", position = 12)
+    @NotNull(message = "gridWhether不能为空")
+    private String gridWhether;
+
+    /** 排序 */
+    @ApiModelProperty(value = "排序", position = 13)
+    @NotNull(message = "sortCode不能为空")
+    private Integer sortCode;
+
+    /** 作者名 */
+    @ApiModelProperty(value = "作者名", required = true, position = 14)
+    @NotNull(message = "authorName不能为空")
+    private String authorName;
+
+    /** 包名 */
+    @ApiModelProperty(value = "包名 */", position = 15)
+    private String packageName;
+}

+ 35 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 代码生成基础Id参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+public class GenBasicIdParam {
+
+    /** id */
+    @ApiModelProperty(value = "id", required = true)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 44 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicPageParam.java

@@ -0,0 +1,44 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 代码生成基础查询参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ */
+@Getter
+@Setter
+public class GenBasicPageParam {
+
+    /** 当前页 */
+    @ApiModelProperty(value = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @ApiModelProperty(value = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+}

+ 35 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/param/GenBasicTableColumnParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 数据源库字段列表参数
+ *
+ * @author xuyuxiang
+ * @date 2022/7/29 9:59
+ */
+@Getter
+@Setter
+public class GenBasicTableColumnParam {
+
+    /** 表名称 */
+    @ApiModelProperty(value = "表名称", required = true)
+    @NotBlank(message = "表名称不能为空")
+    private String tableName;
+}

+ 59 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/result/GenBasicPreviewResult.java

@@ -0,0 +1,59 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.result;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * 预览代码生成结果
+ *
+ * @author xuyuxiang
+ * @date 2022/10/28 17:03
+ **/
+@Getter
+@Setter
+public class GenBasicPreviewResult {
+
+    /** SQL代码结果集 */
+    @ApiModelProperty(value = "SQL代码结果集", position = 1)
+    private List<GenBasicCodeResult> genBasicCodeSqlResultList;
+
+    /** 前端代码结果集 */
+    @ApiModelProperty(value = "前端代码结果集", position = 2)
+    private List<GenBasicCodeResult> genBasicCodeFrontendResultList;
+
+    /** 后端代码结果集 */
+    @ApiModelProperty(value = "后端代码结果集", position = 3)
+    private List<GenBasicCodeResult> genBasicCodeBackendResultList;
+
+    @Getter
+    @Setter
+    public static class GenBasicCodeResult {
+
+        /** 代码文件名称 */
+        @ApiModelProperty(value = "代码文件名称", position = 1)
+        private String codeFileName;
+
+        /** 代码文件带路径名称 */
+        @ApiModelProperty(value = "代码文件带路径名称", position = 2)
+        private String codeFileWithPathName;
+
+        /** 代码文件内容 */
+        @ApiModelProperty(value = "代码文件内容", position = 2)
+        private String codeFileContent;
+    }
+}

+ 40 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/result/GenBasicTableColumnResult.java

@@ -0,0 +1,40 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.result;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 数据库表字段结果
+ *
+ * @author xuyuxiang
+ * @date 2022/7/19 19:06
+ **/
+@Getter
+@Setter
+public class GenBasicTableColumnResult {
+
+    /** 字段名称 */
+    @ApiModelProperty(value = "字段名称", position = 1)
+    private String columnName;
+
+    /** 字段类型 */
+    @ApiModelProperty(value = "字段类型", position = 2)
+    private String typeName;
+
+    /** 字段注释 */
+    @ApiModelProperty(value = "字段注释", position = 3)
+    private String columnRemark;
+}

+ 36 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/result/GenBasicTableResult.java

@@ -0,0 +1,36 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.result;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * 数据库表结果
+ *
+ * @author xuyuxiang
+ * @date 2022/7/19 19:06
+ **/
+@Getter
+@Setter
+public class GenBasicTableResult {
+
+    /** 表名称 */
+    @ApiModelProperty(value = "表名称", position = 1)
+    private String tableName;
+
+    /** 表注释 */
+    @ApiModelProperty(value = "表注释", position = 2)
+    private String tableRemark;
+}

+ 121 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/service/GenBasicService.java

@@ -0,0 +1,121 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.service;
+
+import cn.tr.module.gen.modular.basic.entity.GenBasic;
+import cn.tr.module.gen.modular.basic.param.*;
+import cn.tr.module.gen.modular.basic.result.GenBasicPreviewResult;
+import cn.tr.module.gen.modular.basic.result.GenBasicTableColumnResult;
+import cn.tr.module.gen.modular.basic.result.GenBasicTableResult;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * 代码生成基础Service接口
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+public interface GenBasicService extends IService<GenBasic> {
+
+    /**
+     * 查询代码生成基础分页
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    Page<GenBasic> page(GenBasicPageParam genBasicPageParam);
+
+    /**
+     * 添加代码生成基础
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    GenBasic add(GenBasicAddParam genBasicAddParam);
+
+    /**
+     * 编辑代码生成基础
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    GenBasic edit(GenBasicEditParam genBasicEditParam);
+
+    /**
+     * 删除代码生成基础
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    void delete(List<GenBasicIdParam> genBasicIdParamList);
+
+    /**
+     * 获取代码生成基础详情
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    GenBasic detail(GenBasicIdParam genBasicIdParam);
+
+    /**
+     * 获取代码生成基础详情
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     **/
+    GenBasic queryEntity(String id);
+
+    /**
+     * 获取所有表信息
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     **/
+    List<GenBasicTableResult> tables();
+
+    /**
+     * 获取表内所有字段信息
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     **/
+    List<GenBasicTableColumnResult> tableColumns(GenBasicTableColumnParam genBasicTableColumnParam);
+
+    /**
+     * 执行代码生成
+     *
+     * @author xuyuxiang yubaoshan
+     * @date 2022/10/28 9:37
+     **/
+    void execGenZip(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException;
+
+    /**
+     * 执行代码生成
+     *
+     * @author xuyuxiang
+     * @date 2022/10/28 9:37
+     **/
+    void execGenPro(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException;
+
+    /**
+     * 预览代码生成
+     *
+     * @author xuyuxiang
+     * @date 2022/10/28 17:08
+     **/
+    GenBasicPreviewResult previewGen(GenBasicIdParam genBasicIdParam);
+}

+ 631 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/basic/service/impl/GenBasicServiceImpl.java

@@ -0,0 +1,631 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.basic.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.core.util.ZipUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
+import cn.tr.module.gen.core.util.CommonDownloadUtil;
+import cn.tr.module.gen.core.util.CommonResponseUtil;
+import cn.tr.module.gen.core.util.GenDbTypeUtil;
+import cn.tr.module.gen.modular.basic.entity.CommonPageRequest;
+import cn.tr.module.gen.modular.basic.entity.GenBasic;
+import cn.tr.module.gen.modular.basic.enums.CommonSortOrderEnum;
+import cn.tr.module.gen.modular.basic.enums.GenEffectTypeEnum;
+import cn.tr.module.gen.modular.basic.enums.GenYesNoEnum;
+import cn.tr.module.gen.modular.basic.mapper.GenBasicMapper;
+import cn.tr.module.gen.modular.basic.param.*;
+import cn.tr.module.gen.modular.basic.result.GenBasicPreviewResult;
+import cn.tr.module.gen.modular.basic.result.GenBasicTableColumnResult;
+import cn.tr.module.gen.modular.basic.result.GenBasicTableResult;
+import cn.tr.module.gen.modular.basic.service.GenBasicService;
+import cn.tr.module.gen.modular.config.entity.GenConfig;
+import cn.tr.module.gen.modular.config.param.GenConfigAddParam;
+import cn.tr.module.gen.modular.config.service.GenConfigService;
+import com.baomidou.mybatisplus.autoconfigure.MybatisPlusProperties;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.beetl.core.Configuration;
+import org.beetl.core.GroupTemplate;
+import org.beetl.core.Template;
+import org.beetl.core.resource.ClasspathResourceLoader;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.support.JdbcUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.sql.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * 代码生成基础Service接口实现类
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Service
+public class GenBasicServiceImpl extends ServiceImpl<GenBasicMapper, GenBasic> implements GenBasicService {
+
+    private static final String DB_URL_KEY = "spring.datasource.dynamic.datasource.master.url";
+
+    private static final String DB_USERNAME_KEY = "spring.datasource.dynamic.datasource.master.username";
+
+    private static final String DB_PASSWORD_KEY = "spring.datasource.dynamic.datasource.master.password";
+
+    private static final String MODULE_KEY = "biz";
+
+    private static final String GEN_PROJECT_FRONT_PLUGIN_KEY = "snowy-admin-web";
+
+    private static final String GEN_PROJECT_PLUGIN_KEY = "snowy-plugin";
+
+    private static final String GEN_PROJECT_PLUGIN_BIZ_KEY = GEN_PROJECT_PLUGIN_KEY + File.separator + "snowy-plugin-biz";
+
+    private static final List<JSONObject> GEN_SQL_FILE_LIST = CollectionUtil.newArrayList(
+            JSONUtil.createObj().set("name", "Mysql.sql.btl"),
+            JSONUtil.createObj().set("name", "Oracle.sql.btl"));
+
+    private static final List<JSONObject> GEN_FRONT_FILE_LIST = CollectionUtil.newArrayList(
+            JSONUtil.createObj().set("name", "Api.js.btl").set("path", "api" + File.separator + MODULE_KEY),
+            JSONUtil.createObj().set("name", "form.vue.btl").set("path",  "views" + File.separator + MODULE_KEY),
+            JSONUtil.createObj().set("name", "index.vue.btl").set("path",  "views" + File.separator + MODULE_KEY));
+
+    private static final List<JSONObject> GEN_BACKEND_FILE_LIST = CollectionUtil.newArrayList(
+            JSONUtil.createObj().set("name", "Controller.java.btl").set("path", "controller"),
+            JSONUtil.createObj().set("name", "Entity.java.btl").set("path", "entity"),
+            JSONUtil.createObj().set("name", "Enum.java.btl").set("path", "enums"),
+            JSONUtil.createObj().set("name", "Mapper.java.btl").set("path", "mapper"),
+            JSONUtil.createObj().set("name", "Mapper.xml.btl").set("path", "mapper" + File.separator + "mapping"),
+            JSONUtil.createObj().set("name", "AddParam.java.btl").set("path", "param"),
+            JSONUtil.createObj().set("name", "EditParam.java.btl").set("path", "param"),
+            JSONUtil.createObj().set("name", "IdParam.java.btl").set("path", "param"),
+            JSONUtil.createObj().set("name", "PageParam.java.btl").set("path", "param"),
+            JSONUtil.createObj().set("name", "Service.java.btl").set("path", "service"),
+            JSONUtil.createObj().set("name", "ServiceImpl.java.btl").set("path", "service" + File.separator + "impl"));
+
+    private static final String SORT_CODE_KEY = "SORT_CODE";
+
+    private static final String CREATE_USER_KEY = "CREATE_USER";
+
+    private static final String CREATE_TIME_KEY = "CREATE_TIME";
+
+    private static final String UPDATE_USER_KEY = "UPDATE_USER";
+
+    private static final String UPDATE_TIME_KEY = "UPDATE_TIME";
+
+    @Resource
+    private Environment environment;
+
+    @Resource
+    private MybatisPlusProperties mybatisPlusProperties;
+
+    @Resource
+    private GenConfigService genConfigService;
+
+    @Override
+    public Page<GenBasic> page(GenBasicPageParam genBasicPageParam) {
+        QueryWrapper<GenBasic> queryWrapper = new QueryWrapper<>();
+
+        if(ObjectUtil.isAllNotEmpty(genBasicPageParam.getSortField(), genBasicPageParam.getSortOrder())) {
+            CommonSortOrderEnum.validate(genBasicPageParam.getSortOrder());
+            queryWrapper.orderBy(true, genBasicPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
+                    StrUtil.toUnderlineCase(genBasicPageParam.getSortField()));
+        } else {
+            queryWrapper.lambda().orderByAsc(GenBasic::getSortCode);
+        }
+        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public GenBasic add(GenBasicAddParam genBasicAddParam) {
+        GenBasic genBasic = BeanUtil.toBean(genBasicAddParam, GenBasic.class);
+        this.save(genBasic);
+        GenBasicTableColumnParam tableColumnParam = new GenBasicTableColumnParam();
+        tableColumnParam.setTableName(genBasic.getDbTable());
+        List<GenBasicTableColumnResult> resultList = this.tableColumns(tableColumnParam);
+        for (int i = 0; i < resultList.size(); i++) {
+            GenBasicTableColumnResult item = resultList.get(i);
+            GenConfigAddParam addParam = new GenConfigAddParam();
+            addParam.setBasicId(genBasic.getId());
+            if (item.getColumnName().equals(genBasic.getDbTableKey())) {
+                addParam.setIsTableKey(GenYesNoEnum.Y.getValue());
+            } else {
+                addParam.setIsTableKey(GenYesNoEnum.N.getValue());
+            }
+            addParam.setFieldName(item.getColumnName());
+            addParam.setFieldType(item.getTypeName());
+            addParam.setFieldRemark(item.getColumnRemark());
+            addParam.setFieldJavaType(GenDbTypeUtil.getJavaTypeBySqlType(item.getTypeName()));
+            addParam.setEffectType(GenEffectTypeEnum.INPUT.getValue().toLowerCase());
+            // 除主键、删除标志、创建人、创建时间、修改人和修改时间外,所有默认在列表显示、在增改显示、非列省略、非必填,非查询
+            String logicDeleteField = mybatisPlusProperties.getGlobalConfig().getDbConfig().getLogicDeleteField();
+            if(ObjectUtil.isEmpty(logicDeleteField)) {
+                logicDeleteField = "DELETE_FLAG";
+            }
+            if(genBasic.getDbTableKey().equalsIgnoreCase(item.getColumnName()) ||
+                    logicDeleteField.equalsIgnoreCase(item.getColumnName()) ||
+                    CREATE_USER_KEY.equalsIgnoreCase(item.getColumnName()) ||
+                    CREATE_TIME_KEY.equalsIgnoreCase(item.getColumnName()) ||
+                    UPDATE_USER_KEY.equalsIgnoreCase(item.getColumnName()) ||
+                    UPDATE_TIME_KEY.equalsIgnoreCase(item.getColumnName())) {
+                addParam.setWhetherTable(GenYesNoEnum.N.getValue());
+                addParam.setWhetherAddUpdate(GenYesNoEnum.N.getValue());
+            } else {
+                addParam.setWhetherTable(GenYesNoEnum.Y.getValue());
+                addParam.setWhetherAddUpdate(GenYesNoEnum.Y.getValue());
+            }
+            addParam.setWhetherRetract(GenYesNoEnum.N.getValue());
+            addParam.setWhetherRequired(GenYesNoEnum.N.getValue());
+            addParam.setQueryWhether(GenYesNoEnum.N.getValue());
+            addParam.setSortCode(i);
+            GenConfig genConfig = BeanUtil.toBean(addParam, GenConfig.class);
+            genConfigService.save(genConfig);
+        }
+        return genBasic;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public GenBasic edit(GenBasicEditParam genBasicEditParam) {
+        GenBasic genBasic = this.queryEntity(genBasicEditParam.getId());
+        BeanUtil.copyProperties(genBasicEditParam, genBasic);
+        this.updateById(genBasic);
+        return genBasic;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void delete(List<GenBasicIdParam> genBasicIdParamList) {
+        List<String> basicIdIdList = CollStreamUtil.toList(genBasicIdParamList, GenBasicIdParam::getId);
+        if(ObjectUtil.isNotEmpty(basicIdIdList)) {
+            // 级联删除配置
+            genConfigService.remove(new LambdaQueryWrapper<GenConfig>().in(GenConfig::getBasicId, basicIdIdList));
+            // 执行删除
+            this.removeBatchByIds(basicIdIdList);
+        }
+    }
+
+    @Override
+    public GenBasic detail(GenBasicIdParam genBasicIdParam) {
+        return this.queryEntity(genBasicIdParam.getId());
+    }
+
+    @Override
+    public GenBasic queryEntity(String id) {
+        GenBasic genBasic = this.getById(id);
+        if(ObjectUtil.isEmpty(genBasic)) {
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("代码生成基础不存在,id值为:{%s}", id));
+        }
+        return genBasic;
+    }
+
+    @Override
+    public List<GenBasicTableResult> tables() {
+        Connection conn = null;
+        ResultSet rs = null;
+        try {
+            conn = DriverManager.getConnection(Objects.requireNonNull(environment.getProperty(DB_URL_KEY)),
+                    Objects.requireNonNull(environment.getProperty(DB_USERNAME_KEY)),
+                    Objects.requireNonNull(environment.getProperty(DB_PASSWORD_KEY)));
+            DatabaseMetaData metaData = conn.getMetaData();
+            String url = metaData.getURL();
+            String schema = null;
+            if (url.toLowerCase().contains("oracle")) {
+                schema = metaData.getUserName();
+            }
+            List<GenBasicTableResult> tables = new ArrayList<>();
+            rs = metaData.getTables(null, schema, "%", new String[]{"TABLE", "VIEW"});
+            while (rs.next()) {
+                String tableName = rs.getString("TABLE_NAME").toUpperCase();
+                if (!tableName.startsWith("ACT_")) {
+                    GenBasicTableResult genBasicTableResult = new GenBasicTableResult();
+                    genBasicTableResult.setTableName(tableName);
+                    String remarks = rs.getString("REMARKS");
+                    if(ObjectUtil.isEmpty(remarks)) {
+                        genBasicTableResult.setTableRemark(tableName);
+                    } else {
+                        genBasicTableResult.setTableRemark(remarks);
+                    }
+                    tables.add(genBasicTableResult);
+                }
+            }
+            return tables;
+        } catch (SQLException sqlException) {
+            sqlException.printStackTrace();
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"获取数据库表失败");
+        } finally {
+            JdbcUtils.closeResultSet(rs);
+            JdbcUtils.closeConnection(conn);
+        }
+    }
+
+    @Override
+    public List<GenBasicTableColumnResult> tableColumns(GenBasicTableColumnParam genBasicTableColumnParam) {
+        Connection conn = null;
+        ResultSet rs = null;
+        try {
+            conn = DriverManager.getConnection(Objects.requireNonNull(environment.getProperty(DB_URL_KEY)),
+                    Objects.requireNonNull(environment.getProperty(DB_USERNAME_KEY)),
+                    Objects.requireNonNull(environment.getProperty(DB_PASSWORD_KEY)));
+            DatabaseMetaData metaData = conn.getMetaData();
+            String url = metaData.getURL();
+            String schema = null;
+            if (url.toLowerCase().contains("oracle")) {
+                schema = metaData.getUserName();
+            }
+            List<GenBasicTableColumnResult> columns = new ArrayList<>();
+            rs = metaData.getColumns(null, schema, genBasicTableColumnParam.getTableName(), "%");
+            while (rs.next()) {
+                String columnName = rs.getString("COLUMN_NAME").toUpperCase();
+                GenBasicTableColumnResult genBasicTableColumnResult = new GenBasicTableColumnResult();
+                genBasicTableColumnResult.setColumnName(columnName);
+                String remarks = rs.getString("REMARKS");
+                if(ObjectUtil.isEmpty(remarks)) {
+                    genBasicTableColumnResult.setColumnRemark(columnName);
+                } else {
+                    genBasicTableColumnResult.setColumnRemark(remarks);
+                }
+                String typeName = rs.getString("TYPE_NAME").toUpperCase();
+                if(ObjectUtil.isEmpty(typeName)) {
+                    genBasicTableColumnResult.setTypeName("NONE");
+                } else {
+                    genBasicTableColumnResult.setTypeName(typeName);
+                }
+                columns.add(genBasicTableColumnResult);
+            }
+            return columns;
+        } catch (SQLException sqlException) {
+            sqlException.printStackTrace();
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("获取数据库表字段失败,表名称:{%s}", genBasicTableColumnParam.getTableName()));
+        } finally {
+            JdbcUtils.closeResultSet(rs);
+            JdbcUtils.closeConnection(conn);
+        }
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void execGenZip(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
+        File tempFolder = this.genTempFolder(genBasicIdParam, response, true);
+        if(tempFolder == null) {
+            CommonResponseUtil.renderError(response, "代码生成基础不存在,id值为:" + genBasicIdParam.getId());
+            return;
+        }
+        // 压缩
+        File zip = ZipUtil.zip(tempFolder);
+        // 压缩完毕删除临时目录
+        FileUtil.del(tempFolder);
+        // 下载
+        CommonDownloadUtil.download(zip, response);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void execGenPro(GenBasicIdParam genBasicIdParam, HttpServletResponse response) throws IOException {
+        File tempFolder = this.genTempFolder(genBasicIdParam, response, false);
+        // 定义前端生成的目录
+        String genProjectFrontendPath = System.getProperty("user.dir") + File.separator + GEN_PROJECT_FRONT_PLUGIN_KEY + File.separator + "src";
+
+        if(!FileUtil.exist(genProjectFrontendPath)) {
+            throw new  ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("前端代码生成位置:{%s}不存在,请检查位置", genProjectFrontendPath));
+        }
+
+        // 定义后端生成的目录
+        String genProjectBackendPath = System.getProperty("user.dir") + File.separator + GEN_PROJECT_PLUGIN_BIZ_KEY + File.separator + "src" +
+                File.separator + "main" + File.separator + "java";
+
+        if(!FileUtil.exist(genProjectBackendPath)) {
+            throw new  ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("后端代码生成位置:{%s}不存在,请检查位置", genProjectBackendPath));
+        }
+        try {
+            GenBasic genBasic = this.queryEntity(genBasicIdParam.getId());
+
+//            // 生成菜单
+//            String menuId = sysMenuApi.addForGenMenu(genBasic.getMenuPid(), genBasic.getBusName(), genBasic.getModule(), genBasic.getFunctionName(),
+//                    StrUtil.SLASH + MODULE_KEY + StrUtil.SLASH + genBasic.getBusName());
+//
+//            // 生成按钮
+//            sysButtonApi.addForGenButton(menuId, genBasic.getClassName(), genBasic.getFunctionName());
+//
+//            // 授权菜单
+//            sysRoleApi.grantForGenMenuAndButton(menuId);
+
+            //前端代码移动到前端
+            FileUtil.moveContent(FileUtil.file(tempFolder + File.separator + "frontend"), FileUtil.file(genProjectFrontendPath), true);
+
+            // 后端代码移动到后端
+            FileUtil.moveContent(FileUtil.file(tempFolder + File.separator + "backend"), FileUtil.file(genProjectBackendPath), true);
+
+            // 移动完毕删除临时目录
+            FileUtil.del(tempFolder);
+        } catch (Exception e) {
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"代码生成异常");
+        }
+    }
+
+    /**
+     * 获取临时目录
+     *
+     * @author xuyuxiang yubaoshan
+     * @date 2022/10/28 21:36
+     */
+    private File genTempFolder(GenBasicIdParam genBasicIdParam, HttpServletResponse response, boolean isZip) throws IOException {
+        GenBasic genBasic = this.getById(genBasicIdParam.getId());
+        if(ObjectUtil.isEmpty(genBasic)) {
+            // 如果是压缩包下载应该使用CommonResponseUtil渲染异常
+            if(isZip) {
+                return null;
+            } else {
+                // 否则可以直接抛出异常
+                throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("代码生成基础不存在,id值为:{%s}", genBasicIdParam.getId()));
+            }
+        }
+        GenBasicPreviewResult genBasicPreviewResult = this.previewGen(genBasicIdParam);
+        // 先删除压缩包
+        FileUtil.del(FileUtil.getTmpDirPath() + File.separator + genBasic.getFunctionName() + ".zip");
+        // 生成临时目录
+        File tempFolder = FileUtil.file(FileUtil.getTmpDirPath() + File.separator + genBasic.getFunctionName());
+        // 生成SQL代码到临时目录
+        genBasicPreviewResult.getGenBasicCodeSqlResultList().forEach(genBasicCodeResult ->
+                FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator +
+                        genBasicCodeResult.getCodeFileWithPathName())));
+        // 生成前端代码到临时目录
+        genBasicPreviewResult.getGenBasicCodeFrontendResultList().forEach(genBasicCodeResult ->
+                FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+                        + "frontend" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
+        // 生成后端代码到临时目录
+        genBasicPreviewResult.getGenBasicCodeBackendResultList().forEach(genBasicCodeResult ->
+                FileUtil.writeUtf8String(genBasicCodeResult.getCodeFileContent(), FileUtil.file(tempFolder + File.separator
+                        + "backend" + File.separator + genBasicCodeResult.getCodeFileWithPathName())));
+        return tempFolder;
+    }
+
+    @Override
+    public GenBasicPreviewResult previewGen(GenBasicIdParam genBasicIdParam) {
+        GenBasic genBasic = this.queryEntity(genBasicIdParam.getId());
+        JSONObject bindingJsonObject = this.getBindingJsonObject(genBasic);
+        GenBasicPreviewResult genBasicPreviewResult = new GenBasicPreviewResult();
+        try {
+            // SQL基础路径
+            String genSqlBasicPath = "sql";
+            // SQL
+            GroupTemplate groupTemplateSql = new GroupTemplate(new ClasspathResourceLoader("sqlend"),
+                    Configuration.defaultConfiguration());
+            List<GenBasicPreviewResult.GenBasicCodeResult> genBasicCodeSqlResultList = CollectionUtil.newArrayList();
+            GEN_SQL_FILE_LIST.forEach(fileJsonObject -> {
+                String fileTemplateName = fileJsonObject.getStr("name");
+                GenBasicPreviewResult.GenBasicCodeResult genBasicCodeSqlResult = new GenBasicPreviewResult.GenBasicCodeResult();
+                Template templateSql = groupTemplateSql.getTemplate(fileTemplateName);
+                templateSql.binding(bindingJsonObject);
+                String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
+                genBasicCodeSqlResult.setCodeFileName(resultName);
+                genBasicCodeSqlResult.setCodeFileWithPathName(genSqlBasicPath + File.separator + resultName);
+                genBasicCodeSqlResult.setCodeFileContent(templateSql.render());
+                genBasicCodeSqlResultList.add(genBasicCodeSqlResult);
+            });
+            genBasicPreviewResult.setGenBasicCodeSqlResultList(genBasicCodeSqlResultList);
+
+            // 前端基础路径
+            String genFrontBasicPath = "";
+            // 前端
+            GroupTemplate groupTemplateFront = new GroupTemplate(new ClasspathResourceLoader("frontend"),
+                    Configuration.defaultConfiguration());
+            List<GenBasicPreviewResult.GenBasicCodeResult> genBasicCodeFrontendResultList = CollectionUtil.newArrayList();
+            GEN_FRONT_FILE_LIST.forEach(fileJsonObject -> {
+                String fileTemplateName = fileJsonObject.getStr("name");
+                String fileTemplatePath = fileJsonObject.getStr("path");
+                GenBasicPreviewResult.GenBasicCodeResult genBasicCodeFrontResult = new GenBasicPreviewResult.GenBasicCodeResult();
+                Template templateFront = groupTemplateFront.getTemplate(fileTemplateName);
+                templateFront.binding(bindingJsonObject);
+                String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
+                if(fileTemplateName.equalsIgnoreCase("Api.js.btl")) {
+                    resultName = StrUtil.lowerFirst(genBasic.getClassName()) + resultName;
+                    genBasicCodeFrontResult.setCodeFileName(resultName);
+                    genBasicCodeFrontResult.setCodeFileWithPathName(genFrontBasicPath + fileTemplatePath + File.separator + resultName);
+                } else {
+                    genBasicCodeFrontResult.setCodeFileName(resultName);
+                    genBasicCodeFrontResult.setCodeFileWithPathName(genFrontBasicPath + fileTemplatePath + File.separator + genBasic.getBusName() + File.separator + resultName);
+                }
+                genBasicCodeFrontResult.setCodeFileContent(templateFront.render());
+                genBasicCodeFrontendResultList.add(genBasicCodeFrontResult);
+            });
+            genBasicPreviewResult.setGenBasicCodeFrontendResultList(genBasicCodeFrontendResultList);
+
+            // 后端基础路径
+            String genBackendBasicPath = StrUtil.replace(genBasic.getPackageName(), StrUtil.DOT, File.separator) +
+                    File.separator + MODULE_KEY + File.separator + "modular" +  File.separator + genBasic.getBusName() + File.separator;
+            // 后端
+            GroupTemplate groupTemplateBackEnd = new GroupTemplate(new ClasspathResourceLoader("backend"),
+                    Configuration.defaultConfiguration());
+            List<GenBasicPreviewResult.GenBasicCodeResult> genBasicCodeBackendResultList = CollectionUtil.newArrayList();
+            GEN_BACKEND_FILE_LIST.forEach(fileJsonObject -> {
+                String fileTemplateName = fileJsonObject.getStr("name");
+                String fileTemplatePath = fileJsonObject.getStr("path");
+                GenBasicPreviewResult.GenBasicCodeResult genBasicCodeBackendResult = new GenBasicPreviewResult.GenBasicCodeResult();
+                Template templateBackend = groupTemplateBackEnd.getTemplate(fileTemplateName);
+                templateBackend.binding(bindingJsonObject);
+                String resultName = StrUtil.removeSuffix(fileTemplateName, ".btl");
+                if(fileTemplateName.equalsIgnoreCase("Entity.java.btl")) {
+                    resultName = ".java";
+                }
+                genBasicCodeBackendResult.setCodeFileName(genBasic.getClassName() + resultName);
+                genBasicCodeBackendResult.setCodeFileWithPathName(genBackendBasicPath + fileTemplatePath + File.separator + genBasic.getClassName() + resultName);
+                genBasicCodeBackendResult.setCodeFileContent(templateBackend.render());
+                genBasicCodeBackendResultList.add(genBasicCodeBackendResult);
+            });
+            genBasicPreviewResult.setGenBasicCodeBackendResultList(genBasicCodeBackendResultList);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"代码生成异常");
+        }
+        return genBasicPreviewResult;
+    }
+
+    /**
+     * 根据代码生成基础获取构造的参数
+     *
+     * @author xuyuxiang
+     * @date 2022/10/28 21:36
+     */
+    public JSONObject getBindingJsonObject(GenBasic genBasic) {
+        JSONObject bindingJsonObject = JSONUtil.createObj();
+        // 代码模块名
+        bindingJsonObject.set("moduleName", MODULE_KEY);
+        // 功能名
+        bindingJsonObject.set("functionName", genBasic.getFunctionName());
+        // 业务名
+        bindingJsonObject.set("busName", genBasic.getBusName());
+        // 包名
+        bindingJsonObject.set("packageName", genBasic.getPackageName());
+        // 库名
+        bindingJsonObject.set("dbTable", genBasic.getDbTable());
+        // 类名
+        bindingJsonObject.set("className", genBasic.getClassName());
+        // 类首字母小写名
+        bindingJsonObject.set("classNameFirstLower", StrUtil.lowerFirst(genBasic.getClassName()));
+        // 主键名
+        bindingJsonObject.set("dbTableKey", genBasic.getDbTableKey());
+        // 主键Java类型
+        bindingJsonObject.set("dbTableKeyJavaType", "String");
+        // 主键名驼峰
+        bindingJsonObject.set("dbTableKeyCamelCase", StrUtil.toCamelCase(genBasic.getDbTableKey().toLowerCase()));
+        // 主键首字母大写名
+        bindingJsonObject.set("dbTableKeyFirstUpper", StrUtil.upperFirst(genBasic.getDbTableKey().toLowerCase()));
+        // 主键注释
+        bindingJsonObject.set("dbTableKeyRemark", genBasic.getDbTableKey());
+        // 表单布局
+        bindingJsonObject.set("formLayout", genBasic.getFormLayout());
+        // 使用栅格
+        bindingJsonObject.set("gridWhether", genBasic.getGridWhether().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
+        // 父菜单ID
+        bindingJsonObject.set("parentId", genBasic.getMenuPid());
+        // 菜单ID
+        bindingJsonObject.set("menuId", IdWorker.getIdStr());
+        // 菜单编码
+        bindingJsonObject.set("menuCode", RandomUtil.randomString(10));
+        // 菜单路径
+        bindingJsonObject.set("menuPath", StrUtil.SLASH + MODULE_KEY + StrUtil.SLASH + genBasic.getBusName());
+        // 菜单组件
+        bindingJsonObject.set("menuComponent", MODULE_KEY + StrUtil.SLASH + genBasic.getBusName() + StrUtil.SLASH + "index");
+        // 模块ID
+        bindingJsonObject.set("moduleId", genBasic.getModule());
+        // 添加按钮ID
+        bindingJsonObject.set("addButtonId", IdWorker.getIdStr());
+        // 编辑按钮ID
+        bindingJsonObject.set("editButtonId", IdWorker.getIdStr());
+        // 删除按钮ID
+        bindingJsonObject.set("deleteButtonId", IdWorker.getIdStr());
+        // 批量删除按钮ID
+        bindingJsonObject.set("batchDeleteButtonId", IdWorker.getIdStr());
+        // 作者
+        bindingJsonObject.set("authorName", genBasic.getAuthorName());
+        // 生成时间
+        bindingJsonObject.set("genTime", DateUtil.format(DateTime.now(), " yyyy/MM/dd HH:mm"));
+        // 定义配置详情列表
+        List<JSONObject> configList = CollectionUtil.newArrayList();
+        // 定义是否有排序字段
+        AtomicBoolean hasSortCodeField = new AtomicBoolean(false);
+        genConfigService.list(new LambdaQueryWrapper<GenConfig>().eq(GenConfig::getBasicId, genBasic.getId()))
+                .forEach(genConfig -> {
+                    // 定义字段信息
+                    JSONObject configItem = JSONUtil.createObj();
+                    if(genConfig.getFieldName().equalsIgnoreCase(SORT_CODE_KEY)) {
+                        hasSortCodeField.set(true);
+                    }
+                    // 如果是主键,则无需作为添加参数,需要作为编辑参数,需要主键注解
+                    if(genConfig.getFieldName().equalsIgnoreCase(genBasic.getDbTableKey())) {
+                        configItem.set("needAdd", false);
+                        configItem.set("needEdit", true);
+                        configItem.set("needPage", false);
+                        configItem.set("needPageType", "none");
+                        configItem.set("required", true);
+                        configItem.set("needTableId", true);
+                        bindingJsonObject.set("dbTableKeyJavaType", genConfig.getFieldJavaType());
+                        bindingJsonObject.set("dbTableKeyRemark", genConfig.getFieldRemark());
+                    } else {
+                        // 排除删除标志
+                        String logicDeleteField = mybatisPlusProperties.getGlobalConfig().getDbConfig().getLogicDeleteField();
+                        if(ObjectUtil.isEmpty(logicDeleteField)) {
+                            logicDeleteField = "DELETE_FLAG";
+                        }
+                        if(genConfig.getFieldName().equalsIgnoreCase(logicDeleteField)) {
+                            configItem.set("needAdd", false);
+                            configItem.set("needEdit", false);
+                            configItem.set("needPage", false);
+                            configItem.set("needPageType", "none");
+                            configItem.set("required", false);
+                            configItem.set("needTableId", false);
+                        } else {
+                            boolean needAddAndUpdate = genConfig.getWhetherAddUpdate().equalsIgnoreCase(GenYesNoEnum.Y.getValue());
+                            configItem.set("needAdd", needAddAndUpdate);
+                            configItem.set("needEdit", needAddAndUpdate);
+                            configItem.set("needPage", genConfig.getQueryWhether().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
+                            configItem.set("needPageType", genConfig.getQueryType());
+                            configItem.set("required", genConfig.getWhetherRequired().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
+                            configItem.set("needTableId", false);
+                        }
+                    }
+                    // 列显示
+                    configItem.set("whetherTable", genConfig.getWhetherTable().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
+                    // 列省略
+                    configItem.set("whetherRetract", genConfig.getWhetherRetract().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
+                    // 增改
+                    configItem.set("whetherAddUpdate", genConfig.getWhetherAddUpdate().equalsIgnoreCase(GenYesNoEnum.Y.getValue()));
+                    // 作用类型
+                    configItem.set("effectType", genConfig.getEffectType());
+                    // 字典值
+                    configItem.set("dictTypeCode", genConfig.getDictTypeCode());
+                    // 实体类型
+                    configItem.set("fieldJavaType", genConfig.getFieldJavaType());
+                    // 字段驼峰名
+                    configItem.set("fieldNameCamelCase", StrUtil.toCamelCase(genConfig.getFieldName().toLowerCase()));
+                    // 字段驼峰首字母大写名
+                    configItem.set("fieldNameCamelCaseFirstUpper", StrUtil.upperFirst(StrUtil.toCamelCase(genConfig.getFieldName().toLowerCase())));
+                    // 字段注释
+                    configItem.set("fieldRemark", genConfig.getFieldRemark());
+                    // 是否需要自动插入
+                    configItem.set("needAutoInsert", CREATE_USER_KEY.equalsIgnoreCase(genConfig.getFieldName()) ||
+                            CREATE_TIME_KEY.equalsIgnoreCase(genConfig.getFieldName()));
+                    // 是否需要自动更新
+                    configItem.set("needAutoUpdate", UPDATE_USER_KEY.equalsIgnoreCase(genConfig.getFieldName()) ||
+                            UPDATE_TIME_KEY.equalsIgnoreCase(genConfig.getFieldName()));
+                    configList.add(configItem);
+
+                });
+        // 配置信息
+        bindingJsonObject.set("configList", configList);
+        // 有排序字段
+        bindingJsonObject.set("hasSortCodeField", hasSortCodeField.get());
+        return bindingJsonObject;
+    }
+}

+ 125 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/controller/GenConfigController.java

@@ -0,0 +1,125 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.controller;
+
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import com.github.xiaoymin.knife4j.annotations.ApiSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.common.pojo.CommonValidList;
+import vip.xiaonuo.gen.modular.config.entity.GenConfig;
+import vip.xiaonuo.gen.modular.config.param.GenConfigEditParam;
+import vip.xiaonuo.gen.modular.config.param.GenConfigIdParam;
+import vip.xiaonuo.gen.modular.config.param.GenConfigListParam;
+import vip.xiaonuo.gen.modular.config.service.GenConfigService;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 代码生成详细配置控制器
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Api(tags = "代码生成详细配置控制器")
+@ApiSupport(author = "SNOWY_TEAM", order = 2)
+@RestController
+@Validated
+public class GenConfigController {
+
+    @Resource
+    private GenConfigService genConfigService;
+
+    /**
+     * 获取代码生成详细配置分页
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 1)
+    @ApiOperation("获取代码生成详细配置分页")
+    @GetMapping("/gen/config/list")
+    public CommonResult<List<GenConfig>> list(GenConfigListParam genConfigListParam) {
+        return CommonResult.data(genConfigService.list(genConfigListParam));
+    }
+
+    /**
+     * 编辑代码生成详细配置
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:47
+     */
+    @ApiOperationSupport(order = 2)
+    @ApiOperation("编辑代码生成详细配置")
+    @CommonLog("编辑代码生成详细配置")
+    @PostMapping("/gen/config/edit")
+    public CommonResult<String> edit(@RequestBody @Valid GenConfigEditParam genConfigEditParam) {
+        genConfigService.edit(genConfigEditParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除代码生成详细配置
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 3)
+    @ApiOperation("删除代码生成详细配置")
+    @CommonLog("删除代码生成详细配置")
+    @PostMapping("/gen/config/delete")
+    public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                               CommonValidList<GenConfigIdParam> genConfigIdParamList) {
+        genConfigService.delete(genConfigIdParamList);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 获取代码生成详细配置详情
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:00
+     */
+    @ApiOperationSupport(order = 4)
+    @ApiOperation("获取代码生成详细配置详情")
+    @GetMapping("/gen/config/detail")
+    public CommonResult<GenConfig> detail(@Valid GenConfigIdParam genConfigIdParam) {
+        return CommonResult.data(genConfigService.detail(genConfigIdParam));
+    }
+
+    /**
+     * 批量编辑代码生成详细配置
+     *
+     * @author yubaoshan
+     * @date 2022/4/24 20:47
+     */
+    @ApiOperationSupport(order = 5)
+    @ApiOperation("批量编辑代码生成详细配置")
+    @CommonLog("批量编辑代码生成详细配置")
+    @PostMapping("/gen/config/editBatch")
+    public CommonResult<String> editBatch(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                                      CommonValidList<GenConfigEditParam> genConfigEditParamList) {
+        genConfigService.editBatch(genConfigEditParamList);
+        return CommonResult.ok();
+    }
+}

+ 95 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/entity/GenConfig.java

@@ -0,0 +1,95 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import vip.xiaonuo.common.pojo.CommonEntity;
+
+/**
+ * 代码生成详细配置
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+@TableName("GEN_CONFIG")
+public class GenConfig extends CommonEntity {
+
+    /** id */
+    @ApiModelProperty(value = "id", position = 1)
+    private String id;
+
+    /** 基础ID */
+    @ApiModelProperty(value = "基础ID", position = 2)
+    private String basicId;
+
+    /** 是否主键 */
+    @ApiModelProperty(value = "是否主键", position = 3)
+    private String isTableKey;
+
+    /** 字段 */
+    @ApiModelProperty(value = "字段", position = 4)
+    private String fieldName;
+
+    /** 注释 */
+    @ApiModelProperty(value = "注释", position = 5)
+    private String fieldRemark;
+
+    /** 类型 */
+    @ApiModelProperty(value = "类型", position = 6)
+    private String fieldType;
+
+    /** 实体类型 */
+    @ApiModelProperty(value = "实体类型", position = 7)
+    private String fieldJavaType;
+
+    /** 作用类型 */
+    @ApiModelProperty(value = "作用类型", position = 8)
+    private String effectType;
+
+    /** 字典 */
+    @ApiModelProperty(value = "字典", position = 9)
+    private String dictTypeCode;
+
+    /** 列表显示 */
+    @ApiModelProperty(value = "列表显示", position = 10)
+    private String whetherTable;
+
+    /** 列省略 */
+    @ApiModelProperty(value = "列省略", position = 11)
+    private String whetherRetract;
+
+    /** 增改 */
+    @ApiModelProperty(value = "增改", position = 12)
+    private String whetherAddUpdate;
+
+    /** 必填 */
+    @ApiModelProperty(value = "必填", position = 13)
+    private String whetherRequired;
+
+    /** 查询 */
+    @ApiModelProperty(value = "查询", position = 14)
+    private String queryWhether;
+
+    /** 查询方式 */
+    @ApiModelProperty(value = "查询方式", position = 15)
+    private String queryType;
+
+    /** 排序 */
+    @ApiModelProperty(value = "排序", position = 16)
+    private String sortCode;
+}

+ 25 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/mapper/GenConfigMapper.java

@@ -0,0 +1,25 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.mapper;
+
+import cn.tr.module.gen.modular.config.entity.GenConfig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * 代码生成详细配置Mapper接口
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+public interface GenConfigMapper extends BaseMapper<GenConfig> {
+}

+ 5 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/mapper/mapping/GenConfigMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="vip.xiaonuo.gen.modular.config.mapper.GenConfigMapper">
+
+</mapper>

+ 95 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigAddParam.java

@@ -0,0 +1,95 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 代码生成详细配置添加参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+public class GenConfigAddParam {
+
+    /** 基础ID */
+    @ApiModelProperty(value = "基础ID", required = true, position = 1)
+    @NotBlank(message = "basicId不能为空")
+    private String basicId;
+
+    /** 是否是主键 */
+    @ApiModelProperty(value = "是否是主键", required = true, position = 2)
+    @NotBlank(message = "isTableKey不能为空")
+    private String isTableKey;
+
+    /** 字段 */
+    @ApiModelProperty(value = "字段", required = true, position = 3)
+    @NotBlank(message = "fieldName不能为空")
+    private String fieldName;
+
+    /** 注释 */
+    @ApiModelProperty(value = "注释", required = true, position = 4)
+    @NotBlank(message = "fieldRemark不能为空")
+    private String fieldRemark;
+
+    /** 类型 */
+    @ApiModelProperty(value = "类型", required = true, position = 5)
+    @NotBlank(message = "fieldType不能为空")
+    private String fieldType;
+
+    /** 实体类型 */
+    @ApiModelProperty(value = "实体类型", position = 6)
+    private String fieldJavaType;
+
+    /** 作用类型 */
+    @ApiModelProperty(value = "作用类型", position = 7)
+    private String effectType;
+
+    /** 字典 */
+    @ApiModelProperty(value = "字典", position = 8)
+    private String dictTypeCode;
+
+    /** 列表显示 */
+    @ApiModelProperty(value = "列表显示", position = 9)
+    private String whetherTable;
+
+    /** 列省略 */
+    @ApiModelProperty(value = "列省略", position = 10)
+    private String whetherRetract;
+
+    /** 增改 */
+    @ApiModelProperty(value = "增改", position = 11)
+    private String whetherAddUpdate;
+
+    /** 必填 */
+    @ApiModelProperty(value = "必填", position = 12)
+    private String whetherRequired;
+
+    /** 查询 */
+    @ApiModelProperty(value = "查询", position = 13)
+    private String queryWhether;
+
+    /** 查询方式 */
+    @ApiModelProperty(value = "查询方式", position = 14)
+    private String queryType;
+
+    /** 排序 */
+    @ApiModelProperty(value = "排序", position = 15)
+    private Integer sortCode;
+}

+ 107 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigEditParam.java

@@ -0,0 +1,107 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 代码生成详细配置编辑参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+public class GenConfigEditParam {
+
+    /** id */
+    @ApiModelProperty(value = "id", required = true, position = 1)
+    @NotBlank(message = "id不能为空")
+    private String id;
+
+    /** 基础ID */
+    @ApiModelProperty(value = "基础ID", required = true, position = 2)
+    @NotBlank(message = "basicId不能为空")
+    private String basicId;
+
+    /** 是否主键 */
+    @ApiModelProperty(value = "是否主键", required = true, position = 3)
+    @NotBlank(message = "isTableKey不能为空")
+    private String isTableKey;
+
+    /** 字段 */
+    @ApiModelProperty(value = "字段", required = true, position = 4)
+    @NotBlank(message = "fieldName不能为空")
+    private String fieldName;
+
+    /** 注释 */
+    @ApiModelProperty(value = "注释", required = true, position = 5)
+    @NotBlank(message = "fieldRemark不能为空")
+    private String fieldRemark;
+
+    /** 类型 */
+    @ApiModelProperty(value = "类型", required = true, position = 6)
+    @NotBlank(message = "fieldType不能为空")
+    private String fieldType;
+
+    /** 实体类型 */
+    @ApiModelProperty(value = "实体类型", required = true, position = 7)
+    @NotBlank(message = "fieldJavaType不能为空")
+    private String fieldJavaType;
+
+    /** 作用类型 */
+    @ApiModelProperty(value = "作用类型", required = true, position = 8)
+    @NotBlank(message = "effectType不能为空")
+    private String effectType;
+
+    /** 字典 */
+    @ApiModelProperty(value = "字典", required = true, position = 9)
+    private String dictTypeCode;
+
+    /** 列表显示 */
+    @ApiModelProperty(value = "列表显示", required = true, position = 10)
+    @NotBlank(message = "whetherTable不能为空")
+    private String whetherTable;
+
+    /** 列省略 */
+    @ApiModelProperty(value = "列省略", required = true, position = 11)
+    @NotBlank(message = "whetherRetract不能为空")
+    private String whetherRetract;
+
+    /** 增改 */
+    @ApiModelProperty(value = "增改", required = true, position = 12)
+    @NotBlank(message = "whetherAddUpdate不能为空")
+    private String whetherAddUpdate;
+
+    /** 必填 */
+    @ApiModelProperty(value = "必填", required = true, position = 13)
+    @NotBlank(message = "whetherRequired不能为空")
+    private String whetherRequired;
+
+    /** 查询 */
+    @ApiModelProperty(value = "查询", required = true, position = 14)
+    @NotBlank(message = "queryWhether不能为空")
+    private String queryWhether;
+
+    /** 查询方式 */
+    @ApiModelProperty(value = "查询方式", required = true, position = 15)
+    private String queryType;
+
+    /** 排序 */
+    @ApiModelProperty(value = "排序", required = true, position = 16)
+    private Integer sortCode;
+}

+ 35 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 代码生成详细配置Id参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Getter
+@Setter
+public class GenConfigIdParam {
+
+    /** id */
+    @ApiModelProperty(value = "id", required = true)
+    @NotBlank(message = "id不能为空")
+    private String id;
+}

+ 43 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigListParam.java

@@ -0,0 +1,43 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 代码生成详细配置查询参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ */
+@Getter
+@Setter
+public class GenConfigListParam {
+
+    /** 排序字段 */
+    @ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 基础ID */
+    @ApiModelProperty(value = "基础ID")
+    @NotBlank(message = "basicId不能为空")
+    private String basicId;
+}

+ 51 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/param/GenConfigPageParam.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 代码生成详细配置查询参数
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ */
+@Getter
+@Setter
+public class GenConfigPageParam {
+
+    /** 当前页 */
+    @ApiModelProperty(value = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @ApiModelProperty(value = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 基础ID */
+    @ApiModelProperty(value = "基础ID")
+    @NotBlank(message = "basicId不能为空")
+    private String basicId;
+}

+ 77 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/service/GenConfigService.java

@@ -0,0 +1,77 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.service;
+
+import cn.tr.module.gen.modular.config.entity.GenConfig;
+import cn.tr.module.gen.modular.config.param.GenConfigEditParam;
+import cn.tr.module.gen.modular.config.param.GenConfigIdParam;
+import cn.tr.module.gen.modular.config.param.GenConfigListParam;
+import com.baomidou.mybatisplus.extension.service.IService;
+import java.util.List;
+
+/**
+ * 代码生成详细配置配置Service接口
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+public interface GenConfigService extends IService<GenConfig> {
+
+    /**
+     * 查询代码生成详细配置列表
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    List<GenConfig> list(GenConfigListParam genConfigListParam);
+
+    /**
+     * 编辑代码生成详细配置
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    void edit(GenConfigEditParam genConfigEditParam);
+
+    /**
+     * 删除代码生成详细配置
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    void delete(List<GenConfigIdParam> genConfigIdParamList);
+
+    /**
+     * 获取代码生成详细配置详情
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     */
+    GenConfig detail(GenConfigIdParam genConfigIdParam);
+
+    /**
+     * 获取代码生成详细配置详情
+     *
+     * @author yubaoshan
+     * @date 2022/10/25 22:33
+     **/
+    GenConfig queryEntity(String id);
+
+    /**
+     * 批量编辑代码生成详细配置
+     *
+     * @author xuyuxiang
+     * @date 2022/10/28 13:49
+     **/
+    void editBatch(List<GenConfigEditParam> genConfigEditParamList);
+}

+ 95 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/modular/config/service/impl/GenConfigServiceImpl.java

@@ -0,0 +1,95 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen.modular.config.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
+import cn.tr.module.gen.modular.basic.enums.CommonSortOrderEnum;
+import cn.tr.module.gen.modular.config.entity.GenConfig;
+import cn.tr.module.gen.modular.config.mapper.GenConfigMapper;
+import cn.tr.module.gen.modular.config.param.GenConfigEditParam;
+import cn.tr.module.gen.modular.config.param.GenConfigIdParam;
+import cn.tr.module.gen.modular.config.param.GenConfigListParam;
+import cn.tr.module.gen.modular.config.service.GenConfigService;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+
+/**
+ * 代码生成详情配置Service接口实现类
+ *
+ * @author yubaoshan
+ * @date 2022/10/25 22:33
+ **/
+@Service
+public class GenConfigServiceImpl extends ServiceImpl<GenConfigMapper, GenConfig> implements GenConfigService {
+
+    @Override
+    public List<GenConfig> list(GenConfigListParam genConfigListParam) {
+        QueryWrapper<GenConfig> queryWrapper = new QueryWrapper<>();
+
+        queryWrapper.lambda().eq(GenConfig::getBasicId, genConfigListParam.getBasicId());
+        if(ObjectUtil.isAllNotEmpty(genConfigListParam.getSortField(), genConfigListParam.getSortOrder())) {
+            CommonSortOrderEnum.validate(genConfigListParam.getSortOrder());
+            queryWrapper.orderBy(true, genConfigListParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
+                    StrUtil.toUnderlineCase(genConfigListParam.getSortField()));
+        } else {
+            queryWrapper.lambda().orderByAsc(GenConfig::getSortCode);
+        }
+        return this.list(queryWrapper);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void edit(GenConfigEditParam genConfigEditParam) {
+        GenConfig genConfig = this.queryEntity(genConfigEditParam.getId());
+        BeanUtil.copyProperties(genConfigEditParam, genConfig);
+        this.updateById(genConfig);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void delete(List<GenConfigIdParam> genConfigIdParamList) {
+        List<String> basicIdIdList = CollStreamUtil.toList(genConfigIdParamList, GenConfigIdParam::getId);
+        if(ObjectUtil.isNotEmpty(basicIdIdList)) {
+            // 执行删除
+            this.removeBatchByIds(basicIdIdList);
+        }
+    }
+
+    @Override
+    public GenConfig detail(GenConfigIdParam genConfigIdParam) {
+        return this.queryEntity(genConfigIdParam.getId());
+    }
+
+    @Override
+    public GenConfig queryEntity(String id) {
+        GenConfig genConfig = this.getById(id);
+        if(ObjectUtil.isEmpty(genConfig)) {
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("代码生成详情配置不存在,id值为:{%s}", id));
+        }
+        return genConfig;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void editBatch(List<GenConfigEditParam> genConfigEditParamList) {
+        genConfigEditParamList.forEach(this::edit);
+    }
+}

+ 13 - 0
tr-modules/tr-module-gen/src/main/java/cn/tr/module/gen/package-info.java

@@ -0,0 +1,13 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package cn.tr.module.gen;

+ 2 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictDTO.java

@@ -9,6 +9,7 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
 import javax.validation.constraints.NotNull;
+import java.io.Serializable;
 
 /**
  * 字典对象 sys_dict
@@ -18,8 +19,7 @@ import javax.validation.constraints.NotNull;
  */
 @Data
 @ToString
-@EqualsAndHashCode(callSuper = true)
-public class SysDictDTO extends BasePO {
+public class SysDictDTO implements Serializable {
     private static final long serialVersionUID = 1L;
 
     @ApiModelProperty(value = "主键")

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictItemServiceImpl.java

@@ -13,7 +13,7 @@ import cn.tr.module.sys.dict.po.SysDictItemPO;
 import cn.tr.module.sys.dict.repository.SysDictItemRepository;
 import cn.tr.module.sys.dict.service.ISysDictItemService;
 import cn.tr.module.sys.dict.service.ISysDictService;
-import cn.tr.module.sys.mapper.DictItemMapper;
+import cn.tr.module.sys.mapper.dict.DictItemMapper;
 import cn.tr.plugin.dict.bo.DictBO;
 import cn.tr.plugin.dict.config.cache.DictManager;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictServiceImpl.java

@@ -9,7 +9,7 @@ import cn.tr.module.sys.dict.dto.SysDictQueryDTO;
 import cn.tr.module.sys.dict.po.SysDictPO;
 import cn.tr.module.sys.dict.repository.SysDictRepository;
 import cn.tr.module.sys.dict.service.ISysDictService;
-import cn.tr.module.sys.mapper.DictMapper;
+import cn.tr.module.sys.mapper.dict.DictMapper;
 import cn.tr.plugin.dict.config.cache.DictManager;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.AllArgsConstructor;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/log/config/OperateConfig.java

@@ -1,6 +1,6 @@
 package cn.tr.module.sys.log.config;
 
-import cn.tr.module.sys.mapper.OperLogMapper;
+import cn.tr.module.sys.mapper.log.OperLogMapper;
 import cn.tr.module.sys.log.service.ISysOperLogService;
 import cn.tr.plugin.operatelog.strategy.OperateStrategy;
 import lombok.AllArgsConstructor;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/log/service/impl/SysOperLogServiceImpl.java

@@ -1,6 +1,6 @@
 package cn.tr.module.sys.log.service.impl;
 
-import cn.tr.module.sys.mapper.OperLogMapper;
+import cn.tr.module.sys.mapper.log.OperLogMapper;
 import cn.tr.module.sys.log.dto.SysOperLogDTO;
 import cn.tr.module.sys.log.dto.SysOpeLogQueryDTO;
 import cn.tr.module.sys.log.repository.SysOperLogRepository;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/DictItemMapper.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/dict/DictItemMapper.java

@@ -1,4 +1,4 @@
-package cn.tr.module.sys.mapper;
+package cn.tr.module.sys.mapper.dict;
 
 import cn.tr.module.sys.dict.dto.SysDictItemDTO;
 import cn.tr.module.sys.dict.po.SysDictItemPO;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/DictMapper.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/dict/DictMapper.java

@@ -1,4 +1,4 @@
-package cn.tr.module.sys.mapper;
+package cn.tr.module.sys.mapper.dict;
 
 import cn.tr.module.sys.dict.dto.SysDictDTO;
 import cn.tr.module.sys.dict.po.SysDictPO;

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/OperLogMapper.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/log/OperLogMapper.java

@@ -1,4 +1,4 @@
-package cn.tr.module.sys.mapper;
+package cn.tr.module.sys.mapper.log;
 
 import cn.tr.module.sys.log.dto.SysOperLogDTO;
 import cn.tr.module.sys.log.po.SysOperLogPO;

+ 20 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/oauth2/UserLoginInfoMapper.java

@@ -0,0 +1,20 @@
+package cn.tr.module.sys.mapper.oauth2;
+
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
+import cn.tr.module.sys.oauth2.controller.vo.SwitchTenantUserVO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.*;
+/**
+ * @ClassName : UserLoginInfoMapper
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Mapper
+public interface UserLoginInfoMapper {
+    UserLoginInfoMapper INSTANCE = Mappers.getMapper(UserLoginInfoMapper.class);
+
+    List<SwitchTenantUserVO> toSwtichTenantUserList(List<UserLoginInfoBO> sources);
+}

+ 25 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysMenuMapper.java

@@ -0,0 +1,25 @@
+package cn.tr.module.sys.mapper.user;
+
+import cn.tr.module.sys.user.dto.SysMenuDTO;
+import cn.tr.module.sys.user.po.SysMenuPO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * @ClassName : SysMenuMapper
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Mapper
+public interface SysMenuMapper {
+    SysMenuMapper INSTANCE = Mappers.getMapper(SysMenuMapper.class);
+
+    List<SysMenuDTO> toSysMenuDTOList(List<SysMenuPO> source);
+
+    SysMenuDTO toSysMenuDTO(SysMenuPO source);
+
+    SysMenuPO toSysMenuPO(SysMenuDTO source);
+}

+ 10 - 3
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/SysUserMapper.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysUserMapper.java

@@ -1,9 +1,11 @@
-package cn.tr.module.sys.mapper;
+package cn.tr.module.sys.mapper.user;
 
-import cn.tr.module.sys.oauth2.bo.UserLoginInfoBO;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
 import cn.tr.module.sys.user.po.SysUserPO;
 import org.mapstruct.Mapper;
 import cn.tr.module.sys.user.dto.SysUserDTO;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
 import org.mapstruct.factory.Mappers;
 import java.util.*;
 /**
@@ -16,7 +18,12 @@ import java.util.*;
 public interface SysUserMapper {
     SysUserMapper INSTANCE = Mappers.getMapper(SysUserMapper.class);
 
-    List<UserLoginInfoBO> toUserLoginValidateDTOList(List<SysUserPO> source);
+    @Mappings(
+            @Mapping(source = "userId",target = "userId")
+    )
+    List<UserLoginInfoBO> toUserLoginInfoDTOList(List<SysUserPO> source);
+
+    UserLoginInfoBO toUserLoginInfoDTO(SysUserPO source);
 
     SysUserDTO toUserDTO(SysUserPO source);
 

+ 63 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/config/SaOAuth2TemplateImpl.java

@@ -0,0 +1,63 @@
+package cn.tr.module.sys.oauth2.config;
+
+import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
+import cn.dev33.satoken.oauth2.model.SaClientModel;
+import cn.hutool.core.util.StrUtil;
+import cn.tr.module.sys.oauth2.psw.properties.TrOAuth2PswClientProperties;
+import cn.tr.plugin.security.utils.SaTokenUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+@Slf4j
+@EnableConfigurationProperties(TrOAuth2PswClientProperties.class)
+public  class SaOAuth2TemplateImpl extends SaOAuth2Template implements CommandLineRunner {
+    private final static Map<String,SaClientModel> clientMap=new HashMap();
+    private final  TrOAuth2PswClientProperties pswClientProperties;
+
+    public SaOAuth2TemplateImpl(TrOAuth2PswClientProperties pswClientProperties) {
+        this.pswClientProperties = pswClientProperties;
+    }
+
+    @Override
+    public String randomAccessToken(String clientId, Object loginId, String scope) {
+        return  SaTokenUtils.getStpUtil().createLoginSession(loginId);
+    }
+
+    // 根据 id 获取 Client 信息
+    @Override
+    public SaClientModel getClientModel(String clientId) {
+        return clientMap.get(clientId);
+    }
+
+    @Override
+    public String getOpenid(String clientId, Object loginId) {
+//        StpLogic stpUtil = SaTokenUtils.getStpUtil();
+//        SaSession session = stpUtil.getSessionByLoginId(loginId);
+//        if(ObjectUtil.isEmpty(session)){
+//            throw new ServiceException(TRExcCode.USER_ERROR_A0242);
+//        }
+//        UserAccountInfoBO accountInfo = session.getModel(AuthConstant.ACCOUNT_USER, UserAccountInfoBO.class);
+//        return accountInfo.getId();
+        return String.valueOf(loginId);
+    }
+
+    @Override
+    public void run(String... args) {
+        if(pswClientProperties==null|| StrUtil.isEmpty(pswClientProperties.getClientId())){
+            log.warn("[TrOAuth2PswClientProperties] default-client not allocation");
+        }else {
+            clientMap.put(pswClientProperties.getClientId(),
+                    new SaClientModel()
+                            .setClientId(pswClientProperties.getClientId())
+                            .setClientSecret(pswClientProperties.getClientSecret())
+                            .setIsAutoMode(true));
+            log.info("[TrOAuth2PswClientProperties] default-client: clientId:{} load success",pswClientProperties.getClientId());
+        }
+    }
+}

+ 0 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/constant/OAuth2Constant.java

@@ -12,10 +12,4 @@ public interface OAuth2Constant {
      * 当前token所绑定得到租户用户列表
      */
     String tenantUsers="Tenant_users";
-
-
-    /**
-     * 当前token所绑定的用户
-     */
-    String bindUser="Bind_User";
 }

+ 47 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/CurrentUserController.java

@@ -0,0 +1,47 @@
+package cn.tr.module.sys.oauth2.controller;
+
+import cn.hutool.core.lang.tree.TreeUtil;
+import cn.tr.core.pojo.CommonResult;
+import cn.tr.module.sys.user.service.ISysUserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.swing.plaf.TreeUI;
+
+/**
+ * @ClassName : CurrentUserController
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+@RestController
+@RequestMapping("/user")
+@Api(tags = "当前账号用户操作")
+@AllArgsConstructor
+public class CurrentUserController {
+    private final ISysUserService userService;
+    @ApiOperation("当前用户的个人账户信息")
+    public CommonResult accountInfo(){
+        //todo
+        return CommonResult.success();
+    }
+
+    @GetMapping("/get-permission-info")
+    @ApiOperation( "获取登录用户的权限信息")
+    public CommonResult getPermissionInfo() {
+        // 拼接结果返回
+
+        return CommonResult.success(null);
+    }
+
+    @GetMapping("/list-menus")
+    @ApiOperation("获得登录用户的菜单列表")
+    public CommonResult getMenus() {
+        return CommonResult.success(null);
+    }
+
+}

+ 108 - 13
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/OAuth2ServerController.java

@@ -1,23 +1,42 @@
 package cn.tr.module.sys.oauth2.controller;
 
+import cn.dev33.satoken.annotation.SaIgnore;
 import cn.dev33.satoken.context.SaHolder;
 import cn.dev33.satoken.context.model.SaRequest;
 import cn.dev33.satoken.context.model.SaResponse;
+import cn.dev33.satoken.exception.SaTokenException;
 import cn.dev33.satoken.oauth2.SaOAuth2Manager;
 import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
 import cn.dev33.satoken.oauth2.logic.SaOAuth2Handle;
 import cn.dev33.satoken.oauth2.model.SaClientModel;
+import cn.dev33.satoken.util.SaResult;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
-import cn.tr.module.sys.oauth2.bo.OAuth2PswReqBO;
+import cn.tr.core.pojo.CommonResult;
+import cn.tr.module.sys.mapper.oauth2.UserLoginInfoMapper;
+import cn.tr.module.sys.oauth2.dto.OAuth2UpdatePswDTO;
+import cn.tr.module.sys.oauth2.psw.operator.LoginOAuth2PswUserOperator;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
+import cn.tr.module.sys.oauth2.constant.OAuth2Constant;
+import cn.tr.module.sys.oauth2.controller.vo.SwitchTenantUserVO;
+import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
+import cn.tr.module.sys.oauth2.dto.OAuth2RefreshDTO;
+import cn.tr.module.sys.user.enums.UserStatusEnum;
+import cn.tr.plugin.security.constant.SecurityConstant;
+import cn.tr.plugin.security.context.LoginUserContextHolder;
+import cn.tr.plugin.security.utils.SaTokenUtils;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Optional;
 
 /**
  * @ClassName : OAuth2ServerController
@@ -26,23 +45,99 @@ import org.springframework.web.bind.annotation.RestController;
  * @Date: 2023年03月31日
  */
 @RestController
-@RequestMapping("/ua")
-@Api(tags = "认证接口")
+@RequestMapping("/oauth2/psw")
+@Api(tags = "OAuth2 密码模式")
 @AllArgsConstructor
 public class OAuth2ServerController {
-
-    @ApiOperation("OAuth2 密码模式")
+    private final List<LoginOAuth2PswUserOperator> operators;
+    @ApiOperation("获取token")
     @ApiOperationSupport(author = "lf")
-    @GetMapping("/oauth2/token")
-    public Object request(@Validated OAuth2PswReqBO source) {
+    @GetMapping("/token")
+    @SaIgnore
+    public CommonResult<Object> request(@Validated OAuth2PswReqDTO source) {
         SaRequest req = SaHolder.getRequest();
         SaResponse res = SaHolder.getResponse();
         SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
         SaClientModel cm = SaOAuth2Handle.currClientModel();
         if(cfg.getIsPassword() && (cm.isPassword || cm.isAutoMode)) {
-            return SaOAuth2Handle.password(req, res, cfg);
+            Object result = SaOAuth2Handle.password(req, res, cfg);
+            if(result instanceof SaResult){
+                SaResult saResult= (SaResult) result;
+                return CommonResult.success(saResult.getData());
+            }
+            throw new ServiceException(TRExcCode.USER_ERROR_A0200,"登录失败");
         }
-        System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());
         throw new ServiceException(TRExcCode.USER_ERROR_A0200,"暂未开放的授权模式");
     }
- }
+
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation("OAuth2 刷新令牌")
+    @GetMapping("/refresh")
+    @SaIgnore
+    public CommonResult<Object> refreshCode(@Validated OAuth2RefreshDTO source){
+        try {
+            SaResult result = (SaResult) SaOAuth2Handle.refreshToken(SaHolder.getRequest());
+            return CommonResult.success(result.getData());
+        }catch (SaTokenException e){
+            throw new ServiceException(TRExcCode.USER_ERROR_A0243,e.getMessage());
+        }catch (Exception e){
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,e.getMessage());
+        }
+    }
+
+
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation("更新当前用户密码")
+    @PostMapping("/update-psw")
+    @SaIgnore
+    public CommonResult<Boolean> updatePsw(@RequestBody @Validated OAuth2UpdatePswDTO psw){
+        SaClientModel cm = SaOAuth2Handle.currClientModel();
+        String stpType = LoginUserContextHolder.getStpType();
+        if (StrUtil.isEmpty(stpType)) {
+            throw new ServiceException(TRExcCode.USER_ERROR_A0200,"账号体系不能为空");
+        }
+        Optional<LoginOAuth2PswUserOperator> operator = operators.stream()
+                .filter(o -> o.match(stpType))
+                .findFirst();
+        if(!operator.isPresent()){
+            throw new ServiceException(TRExcCode.USER_ERROR_A0200,String.format("账号体系[{%s}]不存在",stpType));
+        }
+        SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
+        return CommonResult.success(operator.get()
+                .updatePsw(psw.getOldPsw(),psw.getNewPsw()));
+    }
+
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation("多租户模式下,获取当前username所对应的所有租户用户列表")
+    @GetMapping("/list/tenant-user")
+    @SaIgnore
+    public CommonResult<List<SwitchTenantUserVO>> tenantUsers(){
+        List<UserLoginInfoBO> infos = SaTokenUtils.getList(OAuth2Constant.tenantUsers, UserLoginInfoBO.class);
+        return CommonResult.success(UserLoginInfoMapper.INSTANCE.toSwtichTenantUserList(infos));
+    }
+
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation("多租户模式下,选择当前username所登陆的租户用户")
+    @GetMapping("/login/{userId}")
+    @SaIgnore
+    public CommonResult<Boolean> switchUser(@ApiParam("租户用户id") @PathVariable("userId") String userId){
+        List<UserLoginInfoBO> infos = SaTokenUtils.getList(OAuth2Constant.tenantUsers, UserLoginInfoBO.class);
+        if(CollectionUtil.isEmpty(infos)){
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"所选用户不存在,请刷新后重试");
+        }
+        Optional<UserLoginInfoBO> optional = infos.stream()
+                .filter(info -> StrUtil.equals(info.getUserId(), userId))
+                .findFirst();
+        if(!optional.isPresent()){
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"所选用户不存在,请刷新后重试");
+        }
+        UserLoginInfoBO loginInfo = optional.get();
+        if(!StrUtil.equals(loginInfo.getStatus(), UserStatusEnum.normal.getValue())){
+            //用户都被禁用
+            throw new ServiceException(TRExcCode.USER_ERROR_A0202);
+        }
+        SaTokenUtils.set(SecurityConstant.LOGIN_USER,loginInfo);
+        return CommonResult.success(true);
+    }
+
+}

+ 35 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/vo/SwitchTenantUserVO.java

@@ -0,0 +1,35 @@
+package cn.tr.module.sys.oauth2.controller.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @ClassName : SwitchTenantUserVO
+ * @Description : 可供选择的租户用户
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Data
+public class SwitchTenantUserVO implements Serializable {
+    private static final long serialVersionUID = 2738015085612369615L;
+    @ApiModelProperty("用户id")
+    private String userId;
+
+    @ApiModelProperty("昵称")
+    private String nickname;
+
+    @ApiModelProperty("头像")
+    private String avatar;
+
+    @ApiModelProperty("用户状态")
+    private String status;
+
+    @ApiModelProperty("最后登录IP")
+    private String loginIp;
+
+    @ApiModelProperty("租户id")
+    private String tenantId;
+
+}

+ 23 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2DTO.java

@@ -0,0 +1,23 @@
+package cn.tr.module.sys.oauth2.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+
+/**
+ * @ClassName : OAuth2DTO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Data
+public class OAuth2DTO {
+    @ApiModelProperty(value = "client_id",required = true)
+    @NotEmpty(message = "client_id不能为空")
+    private String client_id;
+
+    @ApiModelProperty(value = "client_secret",required = true)
+    @NotEmpty(message = "client_secret不能为空")
+    private String client_secret;
+}

+ 2 - 6
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/bo/OAuth2PswReqBO.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2PswReqDTO.java

@@ -1,4 +1,4 @@
-package cn.tr.module.sys.oauth2.bo;
+package cn.tr.module.sys.oauth2.dto;
 
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -17,11 +17,7 @@ import javax.validation.constraints.Pattern;
  */
 @Data
 @Accessors(chain = true)
-public class OAuth2PswReqBO {
-
-	@ApiModelProperty(value = "客户端id",required = true)
-	@NotEmpty(message = "客户端id不能为空")
-	private String client_id;
+public class OAuth2PswReqDTO extends OAuth2DTO {
 
 	@ApiModelProperty(value = "账号",required = true)
 	@NotEmpty(message = "账号不能为空")

+ 19 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2RefreshDTO.java

@@ -0,0 +1,19 @@
+package cn.tr.module.sys.oauth2.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+
+/**
+ * @ClassName : OAuth2RefreshDTO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Data
+public class OAuth2RefreshDTO extends OAuth2DTO {
+    @ApiModelProperty(value = "refresh_code",required = true)
+    @NotEmpty(message = "refresh_code不能为空")
+    private String refresh_token;
+}

+ 27 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2UpdatePswDTO.java

@@ -0,0 +1,27 @@
+package cn.tr.module.sys.oauth2.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotEmpty;
+
+/**
+ * @ClassName : OAuth2UpdatePswDTO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+@Data
+public class OAuth2UpdatePswDTO extends OAuth2DTO{
+
+    @ApiModelProperty(value = "旧密码",required = true)
+    @NotEmpty(message = "新密码不能为空")
+    @Length(min = 4, max = 16, message = "新密码长度为 4-16 位")
+    private String newPsw;
+
+    @ApiModelProperty(value = "旧密码",required = true)
+    @NotEmpty(message = "旧密码不能为空")
+    @Length(min = 4, max = 16, message = "旧密码长度为 4-16 位")
+    private String oldPsw;
+}

+ 2 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/operator/OAuth2UserOperator.java

@@ -16,7 +16,7 @@
 package cn.tr.module.sys.oauth2.operator;
 
 import cn.tr.core.strategy.auth.LoginTypeMatcher;
-import cn.tr.module.sys.oauth2.bo.OAuth2PswReqBO;
+import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
 import cn.tr.module.sys.oauth2.enums.OAuth2ModelEnum;
 
 /**
@@ -36,7 +36,7 @@ public interface OAuth2UserOperator extends LoginTypeMatcher {
 	 * @param source 认证参数
 	 * @return token 或 code
 	 */
-	String auth(OAuth2PswReqBO source);
+	String auth(OAuth2PswReqDTO source);
 
 	/**
 	 * 更新账号密码

+ 7 - 8
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/OAuth2PswModelConfig.java

@@ -5,12 +5,11 @@ import cn.dev33.satoken.util.SaResult;
 import cn.hutool.core.util.StrUtil;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
-import cn.tr.module.sys.oauth2.bo.OAuth2PswReqBO;
+import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
 import cn.tr.module.sys.oauth2.psw.operator.LoginOAuth2PswUserOperator;
-import cn.tr.module.sys.oauth2.psw.properties.TrOAuth2PswClientProperties;
 import cn.tr.plugin.security.context.LoginUserContextHolder;
 import lombok.AllArgsConstructor;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.annotation.Configuration;
 
 import javax.annotation.PostConstruct;
@@ -24,14 +23,14 @@ import java.util.Optional;
  */
 @AllArgsConstructor
 @Configuration
-@EnableConfigurationProperties(TrOAuth2PswClientProperties.class)
+@Slf4j
 public class OAuth2PswModelConfig {
     private final SaOAuth2Config cfg;
+
     private final List<LoginOAuth2PswUserOperator> operators;
 
     @PostConstruct
     public void init(){
-        //todo oss-client配置
         cfg.setDoLoginHandle((username,psw)->{
             String stpType = LoginUserContextHolder.getStpType();
             if (StrUtil.isEmpty(stpType)) {
@@ -43,9 +42,9 @@ public class OAuth2PswModelConfig {
             if(!operator.isPresent()){
                 throw new ServiceException(TRExcCode.USER_ERROR_A0200,String.format("账号体系[{%s}]不存在",stpType));
             }
-            OAuth2PswReqBO parm = new OAuth2PswReqBO()
-                    .setPassword(username)
-                    .setUsername(psw);
+            OAuth2PswReqDTO parm = new OAuth2PswReqDTO()
+                    .setPassword(psw)
+                    .setUsername(username);
             return SaResult.ok(operator.get().auth(parm));
         });
     }

+ 9 - 7
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/LoginOAuth2PswUserOperator.java

@@ -6,9 +6,10 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
+import cn.tr.core.strategy.LoginUserStrategy;
 import cn.tr.core.utils.PswUtils;
-import cn.tr.module.sys.oauth2.bo.OAuth2PswReqBO;
-import cn.tr.module.sys.oauth2.bo.UserLoginInfoBO;
+import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
 import cn.tr.module.sys.oauth2.constant.OAuth2Constant;
 import cn.tr.module.sys.user.enums.UserStatusEnum;
 import cn.tr.module.sys.user.service.ISysUserService;
@@ -31,12 +32,12 @@ import java.util.stream.Collectors;
 public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
     private final ISysUserService sysUserService;
     @Override
-    public String auth(OAuth2PswReqBO source) {
+    public String auth(OAuth2PswReqDTO source) {
         String username = source.getUsername();
         String psw = source.getPassword();
         TenantContextHolder.setIgnore(true);
         //对账号进行校验
-        List<UserLoginInfoBO> users = sysUserService.findByUsernameWhenLogin(username);
+        List<UserLoginInfoBO> users = sysUserService.findByUsernameWhenLoginNoTenant(username);
         if(CollectionUtil.isEmpty(users)){
             //账户不存在
             throw new ServiceException(TRExcCode.USER_ERROR_A0201);
@@ -61,18 +62,19 @@ public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
         stpUtil.login(username);
         //如果只有一个用户,则默认登录该用户,若绑定多个用户,在选择完成用户后进行token的绑定,多租户模式下先使用username进行登录
         String tokenValue =stpUtil.getTokenValue();
-        SaTokenUtils.set(OAuth2Constant.tenantUsers,matchUsers);
+        SaTokenUtils.setList(OAuth2Constant.tenantUsers,matchUsers);
         return tokenValue;
     }
 
     @Override
     public boolean updatePsw(String oldPsw, String newPsw) {
-        return false;
+        String username = LoginUserStrategy.tr.getCurrentUsername();
+        return  sysUserService.updatePsw(username,oldPsw,newPsw);
     }
 
     @Override
     public boolean match(String loginType) {
         //默认登录体系
-        return StrUtil.equals(StpUtil.TYPE,loginType);
+        return StrUtil.isEmpty(loginType)||StrUtil.equals(StpUtil.TYPE,loginType);
     }
 }

+ 78 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysMenuController.java

@@ -0,0 +1,78 @@
+package cn.tr.module.sys.user.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.tr.core.pojo.CommonResult;
+import cn.tr.core.pojo.TableDataInfo;
+import cn.tr.core.validation.Insert;
+import cn.tr.core.validation.Update;
+import cn.tr.module.sys.user.dto.SysMenuDTO;
+import cn.tr.module.sys.user.dto.SysMenuQueryDTO;
+import cn.tr.module.sys.user.service.ISysMenuService;
+import cn.tr.plugin.mybatis.base.BaseController;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collection;
+
+/**
+ * @ClassName : SysMenuController
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月24日
+ */
+@RestController
+@RequestMapping("/sys/menu")
+@Api(tags = "菜单")
+@AllArgsConstructor
+public class SysMenuController extends BaseController {
+    private final ISysMenuService menuService;
+
+    @PostMapping("/query/page")
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation(value = "根据条件查询菜单",notes = "权限: sys:menu:query")
+    @SaCheckPermission("sys:menu:query")
+    public TableDataInfo<SysMenuDTO> selectList(@RequestBody SysMenuQueryDTO query){
+        startPage();
+        return getDataTable(menuService.selectSysMenuList(query));
+    }
+
+    @GetMapping("/detail/{id}")
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation(value = "根据id查询菜单",notes = "权限: sys:menu:query")
+    @SaCheckPermission("sys:menu:query")
+    public CommonResult<SysMenuDTO> findById(@PathVariable("id") String id){
+        return CommonResult.success(menuService.selectSysMenuById(id));
+    }
+
+    @PostMapping("/edit")
+    @ApiOperationSupport(author = "lf")
+    @SaCheckPermission("sys:menu:edit")
+    @ApiOperation(value = "根据id更新菜单",notes = "权限: sys:menu:edit")
+    public CommonResult<Boolean> edit(@RequestBody@Validated(Update.class) SysMenuDTO source){
+        return CommonResult.success(menuService.updateSysMenuById(source));
+    }
+
+    @PostMapping("/add")
+    @ApiOperationSupport(author = "lf")
+    @SaCheckPermission("sys:menu:add")
+    @ApiOperation(value = "新增菜单",notes = "权限: sys:menu:add")
+    public CommonResult<Boolean> add(@RequestBody@Validated(Insert.class) SysMenuDTO source){
+        return CommonResult.success(menuService.insertSysMenu(source));
+    }
+    
+    @PostMapping("/deleteByIds")
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation(value = "删除菜单",notes = "权限: sys:menu:del")
+    @SaCheckPermission("sys:menu:del")
+    public CommonResult<Integer> deleteByIds(@RequestBody Collection<String> ids){
+        return CommonResult.success(menuService.deleteSysMenuByIds(ids));
+    }
+    
+
+    //todo 导出
+
+}

+ 85 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuDTO.java

@@ -0,0 +1,85 @@
+package cn.tr.module.sys.user.dto;
+
+import cn.tr.core.annotation.Comment;
+import cn.tr.core.tree.TreeNode;
+import cn.tr.plugin.mybatis.pojo.BasePO;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+/**
+ * 菜单对象 sys_menu
+ *
+ * @author tr
+ * @date 2022-11-23 15:34:37
+ */
+@Data
+@ToString
+@TableName("sys_menu")
+@EqualsAndHashCode(callSuper = true)
+public class SysMenuDTO extends TreeNode<String> {
+
+    private static final long serialVersionUID = 1L;
+
+    @Comment(value = "主键")
+    @TableId
+    private String id;
+
+    @Comment(value = "父级id 顶级目录的父级id为0")
+    private String parentId;
+
+    @Comment("排序")
+    private Integer sort;
+
+    @Comment(value = "菜单类型 dir目录;menu菜单;button按钮")
+    private String menuType;
+
+
+    @Comment(value = "菜单名称")
+    private String name;
+
+    @Comment(value = "路由地址")
+    private String routePath;
+
+
+    @Comment(value = "组件路径")
+    private String component;
+
+
+    @Comment(value = "权限标识")
+    private String permission;
+
+
+    @Comment(value = "图标")
+    private String icon;
+
+    @Comment(value = "是否缓存 0不缓存;1缓存")
+    private Boolean keepalive;
+
+
+    @Comment(value = "是否外链 0否;1是")
+    private Boolean linkExternal;
+
+
+    @Comment(value = "是否显示 0隐藏;1显示")
+    private Boolean visible;
+
+
+    @Comment(value = "是否内嵌 0不内嵌;1、内嵌")
+    private Boolean frame;
+
+
+    @Comment(value = "外部链接")
+    private String linkUrl;
+
+
+    @Comment(value = "备注")
+    private String remarks;
+
+
+    @Comment(value = "状态 0正常;1停用")
+    private Boolean disable;
+
+}

+ 16 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuQueryDTO.java

@@ -0,0 +1,16 @@
+package cn.tr.module.sys.user.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @ClassName : SysMenuQueryDTO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+@Data
+public class SysMenuQueryDTO implements Serializable {
+    private static final long serialVersionUID = -262693810220247854L;
+}

+ 16 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysUserQueryDTO.java

@@ -0,0 +1,16 @@
+package cn.tr.module.sys.user.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @ClassName : SysUserQueryDTO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+@Data
+public class SysUserQueryDTO implements Serializable {
+    private static final long serialVersionUID = -262693810220247854L;
+}

+ 82 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysMenuPO.java

@@ -0,0 +1,82 @@
+package cn.tr.module.sys.user.po;
+
+import cn.tr.plugin.mybatis.pojo.BasePO;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.ToString;
+
+import java.io.Serializable;
+
+/**
+ * 菜单对象 sys_menu
+ *
+ * @author tr
+ * @date 2022-11-23 15:34:37
+ */
+@Data
+@TableName(value = "sys_menu",autoResultMap = true)
+@ToString
+public class SysMenuPO extends BasePO {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键")
+    private String id;
+
+    @ApiModelProperty(value = "父级id 顶级目录的父级id为0")
+    private String parentId;
+
+    @ApiModelProperty("排序")
+    private Integer sort;
+
+    @ApiModelProperty(value = "菜单类型 dir目录;menu菜单;button按钮")
+    private String menuType;
+
+
+    @ApiModelProperty(value = "菜单名称")
+    private String name;
+
+    @ApiModelProperty(value = "路由地址")
+    private String routePath;
+
+
+    @ApiModelProperty(value = "组件路径")
+    private String component;
+
+
+    @ApiModelProperty(value = "权限标识")
+    private String permission;
+
+
+    @ApiModelProperty(value = "图标")
+    private String icon;
+
+    @ApiModelProperty(value = "是否缓存 0不缓存;1缓存")
+    private Boolean keepalive;
+
+
+    @ApiModelProperty(value = "是否外链 0否;1是")
+    private Boolean linkExternal;
+
+
+    @ApiModelProperty(value = "是否显示 0隐藏;1显示")
+    private Boolean visible;
+
+
+    @ApiModelProperty(value = "是否内嵌 0不内嵌;1、内嵌")
+    private Boolean frame;
+
+
+    @ApiModelProperty(value = "外部链接")
+    private String linkUrl;
+
+
+    @ApiModelProperty(value = "备注")
+    private String remarks;
+
+
+    @ApiModelProperty(value = "状态 0正常;1停用")
+    private Boolean disable;
+
+}

+ 2 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysUserPO.java

@@ -2,6 +2,7 @@ package cn.tr.module.sys.user.po;
 
 import cn.tr.module.sys.user.enums.UserStatusEnum;
 import cn.tr.plugin.mybatis.pojo.BasePO;
+import cn.tr.plugin.mybatis.pojo.TenantPO;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
@@ -18,7 +19,7 @@ import java.util.Date;
  */
 @Data
 @TableName("sys_user")
-public class SysUserPO extends BasePO {
+public class SysUserPO extends TenantPO {
     @ColumnComment("用户主键Id")
     @TableId
     private String userId;

+ 17 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysMenuRepository.java

@@ -0,0 +1,17 @@
+package cn.tr.module.sys.user.repository;
+
+import cn.tr.module.sys.user.po.SysMenuPO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @ClassName : SysUserRepository
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Mapper
+@Repository
+public interface SysMenuRepository extends BaseMapper<SysMenuPO> {
+}

+ 76 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysMenuService.java

@@ -0,0 +1,76 @@
+package cn.tr.module.sys.user.service;
+
+import cn.tr.module.sys.user.dto.SysMenuDTO;
+import cn.tr.module.sys.user.dto.SysMenuQueryDTO;
+import cn.tr.module.sys.user.dto.SysMenuDTO;
+import cn.tr.module.sys.user.dto.SysMenuQueryDTO;
+import cn.tr.plugin.mybatis.service.ITreeService;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @ClassName : ISysMenuService
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+
+public interface ISysMenuService extends ITreeService {
+
+    /**
+     * 根据条件查询构造树结构
+     * @param query 查询参数
+     * @return
+     */
+    default List<SysMenuDTO> selectSysMenuTree(SysMenuQueryDTO query){
+        return buildTree(selectSysMenuList(query));
+    };
+
+    /**
+     * 根据条件查询构造树结构
+     * @param query 查询参数
+     * @param excludeIds 构造树时排除的节点id
+     * @return
+     */
+    default List<SysMenuDTO> selectSysMenuTree(SysMenuQueryDTO query,List<String> excludeIds){
+        return buildTree(selectSysMenuList(query),excludeIds);
+    };
+
+    /**
+     * 根据条件查询
+     * @param query 查询参数
+     * @return
+     */
+    List<SysMenuDTO> selectSysMenuList(SysMenuQueryDTO query);
+
+
+    /**
+     * 根据id查询操作用户
+     * @param id 用户id
+     * @return 用户
+     */
+    SysMenuDTO selectSysMenuById(String id);
+
+    /**
+     * 更新用户
+     * @param source 更新用户
+     * @return true:更新成功
+     */
+    boolean updateSysMenuById(SysMenuDTO source);
+
+    /**
+     * 新增用户
+     * @param source 新增用户
+     * @return true:新增成功
+     */
+    boolean insertSysMenu(SysMenuDTO source);
+
+    /**
+     * 根据id删除用户
+     * @param ids 用户id
+     * @return 删除数量
+     */
+    int deleteSysMenuByIds(Collection<String> ids);
+}

+ 17 - 7
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysUserService.java

@@ -1,6 +1,7 @@
 package cn.tr.module.sys.user.service;
 import cn.tr.module.sys.user.dto.SysUserDTO;
-import cn.tr.module.sys.oauth2.bo.UserLoginInfoBO;
+import cn.tr.module.sys.user.dto.SysUserQueryDTO;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
 
 import java.util.*;
 /**
@@ -16,7 +17,7 @@ public interface ISysUserService {
      * @param query 查询参数
      * @return
      */
-    List<SysUserDTO> selectSysUerList();
+    List<SysUserDTO> selectSysUserList(SysUserQueryDTO query);
 
     /**
      * 根据id查询操作用户
@@ -30,26 +31,35 @@ public interface ISysUserService {
      * @param source 更新用户
      * @return true:更新成功
      */
-    boolean updateSysUerById(SysUserDTO source);
+    boolean updateSysUserById(SysUserDTO source);
 
     /**
-     * 登录时根据用户名查询用户
+     * 无租户登录时根据用户名查询用户
      * @param username 用户名
      * @return
      */
-    List<UserLoginInfoBO> findByUsernameWhenLogin(String username);
+    List<UserLoginInfoBO> findByUsernameWhenLoginNoTenant(String username);
+
+    /**
+     * 更新密码
+     * @param username  用户名
+     * @param oldPsw    旧密码
+     * @param newPsw    新密码
+     * @return   更新结果
+     */
+    boolean updatePsw(String username,String oldPsw,String newPsw);
 
     /**
      * 新增用户
      * @param source 新增用户
      * @return true:新增成功
      */
-    boolean insertSysUer(SysUserDTO source);
+    boolean insertSysUser(SysUserDTO source);
 
     /**
      * 根据id删除用户
      * @param ids 用户id
      * @return 删除数量
      */
-    int deleteSysUerByIds(Collection<String> ids);
+    int deleteSysUserByIds(Collection<String> ids);
 }

+ 0 - 55
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/SysUserServiceImpl.java

@@ -1,55 +0,0 @@
-package cn.tr.module.sys.user.service;
-
-import cn.tr.module.sys.mapper.SysUserMapper;
-import cn.tr.module.sys.user.dto.SysUserDTO;
-import cn.tr.module.sys.oauth2.bo.UserLoginInfoBO;
-import cn.tr.module.sys.user.po.SysUserPO;
-import cn.tr.module.sys.user.repository.SysUserRepository;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import lombok.AllArgsConstructor;
-import org.springframework.stereotype.Service;
-
-import java.util.Collection;
-import java.util.List;
-
-/**
- * @ClassName : SysUserServiceImpl
- * @Description :
- * @Author : LF
- * @Date: 2023年03月31日
- */
-@Service
-@AllArgsConstructor
-public class SysUserServiceImpl implements ISysUserService {
-    private final SysUserRepository userRepository;
-    @Override
-    public List<SysUserDTO> selectSysUerList() {
-        return null;
-    }
-
-    @Override
-    public SysUserDTO selectSysUserById(String id) {
-        return SysUserMapper.INSTANCE.toUserDTO(userRepository.selectById(id));
-    }
-
-    @Override
-    public boolean updateSysUerById(SysUserDTO source) {
-        return userRepository.updateById(SysUserMapper.INSTANCE.toUserPO(source))!=0;
-    }
-
-    @Override
-    public List<UserLoginInfoBO> findByUsernameWhenLogin(String username) {
-        return SysUserMapper.INSTANCE.toUserLoginValidateDTOList(userRepository.selectList(new LambdaQueryWrapper<SysUserPO>()
-                .eq(SysUserPO::getUsername,username)));
-    }
-
-    @Override
-    public boolean insertSysUer(SysUserDTO source) {
-        return false;
-    }
-
-    @Override
-    public int deleteSysUerByIds(Collection<String> ids) {
-        return userRepository.deleteBatchIds(ids);
-    }
-}

+ 47 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysMenuServiceImpl.java

@@ -0,0 +1,47 @@
+package cn.tr.module.sys.user.service.impl;
+
+import cn.tr.module.sys.mapper.user.SysMenuMapper;
+import cn.tr.module.sys.user.dto.SysMenuDTO;
+import cn.tr.module.sys.user.dto.SysMenuQueryDTO;
+import cn.tr.module.sys.user.repository.SysMenuRepository;
+import cn.tr.module.sys.user.service.ISysMenuService;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @ClassName : SysMenuServiceImpl
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Service
+@AllArgsConstructor
+public class SysMenuServiceImpl implements ISysMenuService {
+    private final SysMenuRepository menuRepository;
+    @Override
+    public List<SysMenuDTO> selectSysMenuList(SysMenuQueryDTO query) {
+        return null;
+    }
+
+    @Override
+    public SysMenuDTO selectSysMenuById(String id) {
+        return SysMenuMapper.INSTANCE.toSysMenuDTO(menuRepository.selectById(id));
+    }
+
+    @Override
+    public boolean updateSysMenuById(SysMenuDTO source) {
+        return menuRepository.updateById(SysMenuMapper.INSTANCE.toSysMenuPO(source))!=0;
+    }
+    @Override
+    public boolean insertSysMenu(SysMenuDTO source) {
+        return false;
+    }
+
+    @Override
+    public int deleteSysMenuByIds(Collection<String> ids) {
+        return menuRepository.deleteBatchIds(ids);
+    }
+}

+ 77 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysUserServiceImpl.java

@@ -0,0 +1,77 @@
+package cn.tr.module.sys.user.service.impl;
+
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
+import cn.tr.core.utils.PswUtils;
+import cn.tr.module.sys.mapper.user.SysUserMapper;
+import cn.tr.module.sys.user.dto.SysUserDTO;
+import cn.tr.module.sys.user.dto.SysUserQueryDTO;
+import cn.tr.module.sys.user.service.ISysUserService;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
+import cn.tr.module.sys.user.po.SysUserPO;
+import cn.tr.module.sys.user.repository.SysUserRepository;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @ClassName : SysUserServiceImpl
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Service
+@AllArgsConstructor
+public class SysUserServiceImpl implements ISysUserService {
+    private final SysUserRepository userRepository;
+    @Override
+    public List<SysUserDTO> selectSysUserList(SysUserQueryDTO query) {
+        return null;
+    }
+
+    @Override
+    public SysUserDTO selectSysUserById(String id) {
+        return SysUserMapper.INSTANCE.toUserDTO(userRepository.selectById(id));
+    }
+
+    @Override
+    public boolean updateSysUserById(SysUserDTO source) {
+        return userRepository.updateById(SysUserMapper.INSTANCE.toUserPO(source))!=0;
+    }
+
+    @Override
+    public List<UserLoginInfoBO> findByUsernameWhenLoginNoTenant(String username) {
+        return SysUserMapper.INSTANCE.toUserLoginInfoDTOList(userRepository.selectList(new LambdaQueryWrapper<SysUserPO>()
+                .eq(SysUserPO::getUsername,username)));
+    }
+
+    @Override
+    public boolean updatePsw(String username, String oldPsw, String newPsw) {
+        SysUserPO user = userRepository.selectOne(new LambdaQueryWrapper<SysUserPO>()
+                .eq(SysUserPO::getUsername, username)
+                .last("limit 1"));
+        if(user==null){
+            return true;
+        }
+        if (PswUtils.matchesPassword(oldPsw, user.getPassword())) {
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"旧密码错误");
+        }
+        SysUserPO updateUser = new SysUserPO();
+        updateUser.setUserId(user.getUserId());
+        updateUser.setPassword(PswUtils.encryptPassword(newPsw));
+        return userRepository.updateById(updateUser)!=0;
+    }
+
+    @Override
+    public boolean insertSysUser(SysUserDTO source) {
+        return false;
+    }
+
+    @Override
+    public int deleteSysUserByIds(Collection<String> ids) {
+        return userRepository.deleteBatchIds(ids);
+    }
+}

+ 0 - 2
tr-plugins/pom.xml

@@ -36,8 +36,6 @@
         <module>tr-spring-boot-starter-plugin-mp-enhance-actable</module>
         <module>tr-spring-boot-starter-plugin-biz-bean-mapper</module>
         <module>tr-spring-boot-starter-plugin-biz-constant</module>
-        <module>tr-spring-boot-starter-plugin-tree</module>
-        <module>tr-spring-boot-starter-plugin-auth2</module>
     </modules>
 
 </project>

+ 0 - 47
tr-plugins/tr-spring-boot-starter-plugin-auth2/pom.xml

@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>tr-plugins</artifactId>
-        <groupId>cn.tr</groupId>
-        <version>${revision}</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <version>${revision}</version>
-    <artifactId>tr-spring-boot-starter-plugin-auth2</artifactId>
-
-
-    <dependencies>
-        <dependency>
-            <groupId>cn.tr</groupId>
-            <artifactId>tr-framework</artifactId>
-        </dependency>
-
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-            <exclusions>
-                <exclusion>
-                    <artifactId>spring-boot-starter-logging</artifactId>
-                    <groupId>org.springframework.boot</groupId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-        <!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc -->
-        <dependency>
-            <groupId>cn.dev33</groupId>
-            <artifactId>sa-token-spring-boot-starter</artifactId>
-            <version>1.34.0</version>
-        </dependency>
-
-        <!-- Sa-Token-OAuth2.0 模块 -->
-        <dependency>
-            <groupId>cn.dev33</groupId>
-            <artifactId>sa-token-oauth2</artifactId>
-            <version>1.34.0</version>
-        </dependency>
-
-    </dependencies>
-</project>

+ 0 - 15
tr-plugins/tr-spring-boot-starter-plugin-auth2/src/main/java/cn/tr/plugin/auth2/server/SaOAuth2ServerApplication.java

@@ -1,15 +0,0 @@
-package cn.tr.plugin.auth2.server;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-/**
- * 启动:Sa-OAuth2 Server端 
- */
-@SpringBootApplication
-public class SaOAuth2ServerApplication {
-    public static void main(String[] args) {
-        SpringApplication.run(SaOAuth2ServerApplication.class, args);
-        System.out.println("\nSa-Token-OAuth Server端启动成功");
-    }
-}

+ 0 - 62
tr-plugins/tr-spring-boot-starter-plugin-auth2/src/main/java/cn/tr/plugin/auth2/server/SaOAuth2ServerController.java

@@ -1,62 +0,0 @@
-package cn.tr.plugin.auth2.server;
-
-import cn.dev33.satoken.context.SaHolder;
-import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
-import cn.dev33.satoken.oauth2.logic.SaOAuth2Handle;
-import cn.dev33.satoken.stp.StpUtil;
-import cn.dev33.satoken.util.SaResult;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * Sa-OAuth2 Server端 控制器 
- */
-@RestController
-public class SaOAuth2ServerController {
-
-    // 处理所有OAuth相关请求 
-    @RequestMapping("/oauth2/*")
-    public Object request() {
-        System.out.println("------- 进入请求: " + SaHolder.getRequest().getUrl());
-        return SaOAuth2Handle.serverRequest();
-    }
-
-    // Sa-OAuth2 定制化配置 
-    @Autowired
-    public void setSaOAuth2Config(SaOAuth2Config cfg) {
-        cfg.
-            // 配置:未登录时返回的View 
-            setNotLoginView(() -> {
-                String msg = "当前会话在OAuth-Server端尚未登录,请先访问"
-                            + "<a href='/oauth2/doLogin?name=sa&pwd=123456' target='_blank'> doLogin登录 </a>"
-                            + "进行登录之后,刷新页面开始授权";
-                return msg;
-            }).
-            // 配置:登录处理函数 
-            setDoLoginHandle((name, pwd) -> {
-                if("sa".equals(name) && "123456".equals(pwd)) {
-                    StpUtil.login(10001);
-                    return SaResult.ok();
-                }
-                return SaResult.error("账号名或密码错误");
-            }).
-            // 配置:确认授权时返回的View 
-            setConfirmView((clientId, scope) -> {
-                String msg = "<p>应用 " + clientId + " 请求授权:" + scope + "</p>"
-                        + "<p>请确认:<a href='/oauth2/doConfirm?client_id=" + clientId + "&scope=" + scope + "' target='_blank'> 确认授权 </a></p>"
-                        + "<p>确认之后刷新页面</p>";
-                return msg;
-            })
-            ;
-    }
-
-    // 全局异常拦截  
-    @ExceptionHandler
-    public SaResult handlerException(Exception e) {
-        e.printStackTrace(); 
-        return SaResult.error(e.getMessage());
-    }
-
-}

+ 0 - 35
tr-plugins/tr-spring-boot-starter-plugin-auth2/src/main/java/cn/tr/plugin/auth2/server/SaOAuth2TemplateImpl.java

@@ -1,35 +0,0 @@
-package cn.tr.plugin.auth2.server;
-
-import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
-import cn.dev33.satoken.oauth2.model.SaClientModel;
-import org.springframework.stereotype.Component;
-
-/**
- * Sa-Token OAuth2.0 整合实现 
- */
-@Component
-public class SaOAuth2TemplateImpl extends SaOAuth2Template {
-
-    // 根据 id 获取 Client 信息 
-    @Override
-    public SaClientModel getClientModel(String clientId) {
-        // 此为模拟数据,真实环境需要从数据库查询 
-        if("1001".equals(clientId)) {
-            return new SaClientModel()
-                    .setClientId("1001")
-                    .setClientSecret("aaaa-bbbb-cccc-dddd-eeee")
-                    .setAllowUrl("*")
-                    .setContractScope("userinfo")
-                    .setIsAutoMode(true);
-        }
-        return null;
-    }
-
-    // 根据ClientId 和 LoginId 获取openid 
-    @Override
-    public String getOpenid(String clientId, Object loginId) {
-        // 此为模拟数据,真实环境需要从数据库查询 
-        return "gr_SwoIN0MC1ewxHX_vfCW3BothWDZMMtx__";
-    }
-
-}

+ 1 - 1
tr-plugins/tr-spring-boot-starter-plugin-biz-tenant/src/main/java/cn/tr/plugin/biz/tenant/context/TenantContextHolder.java

@@ -46,7 +46,7 @@ public class TenantContextHolder {
      * @return 是否忽略
      */
     public static Boolean isIgnore() {
-        return SecurityContextHolder.get(TenantConstant.TENANT_ID,Boolean.class);
+        return SecurityContextHolder.get(TenantConstant.TENANT_IGNORE,Boolean.class);
     }
 
 }

+ 30 - 0
tr-plugins/tr-spring-boot-starter-plugin-biz-tenant/src/main/resources/META-INF/spring-configuration-metadata.json

@@ -0,0 +1,30 @@
+{
+  "groups": [
+    {
+      "name": "tr.tenant",
+      "type": "cn.tr.plugin.biz.tenant.properties.TenantProperties",
+      "sourceType": "cn.tr.plugin.biz.tenant.properties.TenantProperties"
+    }
+  ],
+  "properties": [
+    {
+      "name": "tr.tenant.enable",
+      "type": "java.lang.Boolean",
+      "description": "是否开启",
+      "sourceType": "cn.tr.plugin.biz.tenant.properties.TenantProperties"
+    },
+    {
+      "name": "tr.tenant.ignore-tables",
+      "type": "java.util.Set<java.lang.String>",
+      "description": "需要忽略多租户的表 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟",
+      "sourceType": "cn.tr.plugin.biz.tenant.properties.TenantProperties"
+    },
+    {
+      "name": "tr.tenant.ignore-urls",
+      "type": "java.util.Set<java.lang.String>",
+      "description": "需要忽略多租户的请求 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API!",
+      "sourceType": "cn.tr.plugin.biz.tenant.properties.TenantProperties"
+    }
+  ],
+  "hints": []
+}

+ 8 - 13
tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/pojo/BasePO.java

@@ -51,17 +51,12 @@ public class BasePO implements Serializable {
     @TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
     private String updater;
 
-    @Comment("租户id")
-
-    @TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
-    private String tenantId;
-
-    /**
-     * 是否删除
-     */
-    @Comment("删除标记")
-    @ColumnDefaultValue("0")
-    @TableLogic
-    @TableField(jdbcType = JdbcType.TINYINT)
-    private Boolean deleted;
+//    /**
+//     * 是否删除
+//     */
+//    @Comment("删除标记")
+//    @ColumnDefaultValue("0")
+//    @TableLogic
+//    @TableField(jdbcType = JdbcType.TINYINT)
+//    private Boolean deleted;
 }

+ 19 - 0
tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/pojo/TenantPO.java

@@ -0,0 +1,19 @@
+package cn.tr.plugin.mybatis.pojo;
+
+import cn.tr.core.annotation.Comment;
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import org.apache.ibatis.type.JdbcType;
+
+/**
+ * @ClassName : TenantPO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+
+public class TenantPO extends BasePO {
+    @Comment("租户id")
+    @TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
+    private String tenantId;
+}

+ 26 - 0
tr-plugins/tr-spring-boot-starter-plugin-mybatis/src/main/java/cn/tr/plugin/mybatis/service/ITreeService.java

@@ -0,0 +1,26 @@
+package cn.tr.plugin.mybatis.service;
+
+import cn.tr.core.tree.TreeNode;
+import cn.tr.core.utils.TreeUtil;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @ClassName : ITreeService
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+
+public interface ITreeService {
+    default <T extends TreeNode> List<T> buildTree(Collection<T> sources, List<String> excludeNodeIds){
+        return TreeUtil.buildTree(sources,excludeNodeIds);
+    }
+
+
+    default  <T extends TreeNode> List<T> buildTree(Collection<T> sources){
+        return buildTree(sources,null);
+    }
+
+}

+ 21 - 3
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/bo/UserLoginInfoBO.java → tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/bo/UserLoginInfoBO.java

@@ -1,7 +1,9 @@
-package cn.tr.module.sys.oauth2.bo;
+package cn.tr.plugin.security.bo;
 
 import lombok.Data;
 
+import java.io.Serializable;
+
 /**
  * @ClassName : SysLoginUserInfoDTO
  * @Description : 用户登录时需要的信息
@@ -9,17 +11,33 @@ import lombok.Data;
  * @Date: 2023年03月31日
  */
 @Data
-public class UserLoginInfoBO {
+public class UserLoginInfoBO implements Serializable {
+    private static final long serialVersionUID = 2738015085612369615L;
+    /**
+     * 用户id
+     */
+    private String userId;
+
     /**
      * 用户名
      */
     private String username;
 
     /**
-     * 昵称
+     * 密码
      */
     private String password;
 
+    /**
+     * 昵称
+     */
+    private String nickname;
+
+    /**
+     * 头像
+     */
+    private String avatar;
+
     /**
      * 用户状态
      */

+ 25 - 38
tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/config/LoginUserStrategyConfig.java

@@ -1,10 +1,11 @@
 package cn.tr.plugin.security.config;
 
-import cn.tr.core.constant.AuthConstant;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
 import cn.tr.core.strategy.auth.ILoginUser;
 import cn.tr.core.strategy.LoginUserStrategy;
-import cn.tr.core.strategy.auth.bo.UserAccountInfoBO;
-import cn.tr.plugin.security.bo.LoginUserBO;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
+import cn.tr.plugin.security.constant.SecurityConstant;
 import cn.tr.plugin.security.context.LoginUserContextHolder;
 import cn.tr.plugin.security.utils.SaTokenUtils;
 
@@ -20,44 +21,30 @@ public class LoginUserStrategyConfig {
          * 当前用户获取
          */
         LoginUserStrategy.tr.loginUserSupplier=()->{
-            LoginUserBO user = LoginUserContextHolder.getUser();
+            UserLoginInfoBO user = LoginUserContextHolder.getUser();
             if(user==null){
-                UserAccountInfoBO accountInfo = SaTokenUtils.getValue(AuthConstant.ACCOUNT_USER, UserAccountInfoBO.class);
-                return new ILoginUser() {
-                    @Override
-                    public String getUserId() {
-                        return accountInfo.getId();
-                    }
-
-                    @Override
-                    public String getUsername() {
-                        return accountInfo.getUsername();
-                    }
-
-                    @Override
-                    public String getTenantId() {
-                        return accountInfo.getTenantId();
-                    }
-                };
-            }else {
-                LoginUserBO finalUser = user;
-                return new ILoginUser() {
-                    @Override
-                    public String getUserId() {
-                        return finalUser.getUserId();
-                    }
+                user = SaTokenUtils.getValue(SecurityConstant.LOGIN_USER, UserLoginInfoBO.class);
+                if(user==null){
+                    throw new ServiceException(TRExcCode.USER_ERROR_A0244);
+                }
+            }
+            UserLoginInfoBO finalUser = user;
+            return new ILoginUser() {
+                @Override
+                public String getUserId() {
+                    return finalUser.getUserId();
+                }
 
-                    @Override
-                    public String getUsername() {
-                        return finalUser.getUsername();
-                    }
+                @Override
+                public String getUsername() {
+                    return finalUser.getUsername();
+                }
 
-                    @Override
-                    public String getTenantId() {
-                        return finalUser.getTenantId();
-                    }
-                };
-            }
+                @Override
+                public String getTenantId() {
+                    return finalUser.getTenantId();
+                }
+            };
         };
     }
 }

+ 67 - 22
tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/config/TrSaTokenWebConfig.java

@@ -1,14 +1,27 @@
 package cn.tr.plugin.security.config;
 
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.exception.BackResultException;
+import cn.dev33.satoken.exception.StopMatchException;
 import cn.dev33.satoken.interceptor.SaInterceptor;
 import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.strategy.SaStrategy;
 import cn.hutool.core.collection.CollectionUtil;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
+import cn.tr.plugin.security.constant.SecurityConstant;
 import cn.tr.plugin.security.properties.TrSaTokenProperties;
 import cn.tr.plugin.security.utils.SaTokenUtils;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -19,7 +32,7 @@ import java.util.List;
  */
 @Slf4j
 public class TrSaTokenWebConfig implements WebMvcConfigurer {
-
+    private static final List<String> IGNORE_URL = new ArrayList<>();
 
     public TrSaTokenWebConfig(TrSaTokenProperties saTokenProperties) {
         if(CollectionUtil.isNotEmpty(saTokenProperties.getIgnoreUrls())){
@@ -29,12 +42,7 @@ public class TrSaTokenWebConfig implements WebMvcConfigurer {
 
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(new SaInterceptor(handle ->
-                SaRouter
-                        .match("/**")    // 拦截的 path 列表,可以写多个 */
-                        .notMatch(IGNORE_URL)        // 排除掉的 path 列表,可以写多个
-                        .check(r -> SaTokenUtils.getStpUtil().checkLogin())      // 要执行的校验动作,可以写完整的 lambda 表达式
-        ));
+        registry.addInterceptor(new TrSaInterceptor());
     }
 
     @Override
@@ -53,21 +61,58 @@ public class TrSaTokenWebConfig implements WebMvcConfigurer {
                 .addResourceLocations("classpath:/META-INF/resources/webjars/");
     }
 
-    private static final List<String> IGNORE_URL = new ArrayList<>();
 
-//    static {
-//        IGNORE_URL.add("/actuator/**");
-//        IGNORE_URL.add("/druid/**");
-//        IGNORE_URL.add("/favicon.ico");
-//        IGNORE_URL.add("/**.html");
-//        IGNORE_URL.add("/**/*.html");
-//        IGNORE_URL.add("/error");
-//        IGNORE_URL.add("/swagger-resources/**");
-//        IGNORE_URL.add("/swagger-ui/**");
-//        IGNORE_URL.add("/webjars/**");
-//        IGNORE_URL.add("/v2/api-docs/*");
-//        IGNORE_URL.add("/v2/api-docs");
-//        IGNORE_URL.add("/v1/**");;
-//    }
 
+    static class TrSaInterceptor extends SaInterceptor{
+        public TrSaInterceptor() {
+            super(handle ->
+                    SaRouter
+                            .match("/**")    // 拦截的 path 列表,可以写多个 */
+                            .notMatch(IGNORE_URL)        // 排除掉的 path 列表,可以写多个
+                            .check(r -> {
+                                SaTokenUtils.checkout();
+                                UserLoginInfoBO loginInfo = SaTokenUtils.getValue(SecurityConstant.LOGIN_USER, UserLoginInfoBO.class);
+                                if(loginInfo==null){
+                                    throw new ServiceException(TRExcCode.USER_ERROR_A0244);
+                                }
+                            }));
+        }
+
+        @Override
+        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+            try {
+
+                if(isAnnotation && handler instanceof HandlerMethod) {
+
+                    // 获取此请求对应的 Method 处理函数
+                    Method method = ((HandlerMethod) handler).getMethod();
+
+                    // 如果此 Method 或其所属 Class 标注了 @SaIgnore,则忽略掉鉴权
+                    if(SaStrategy.me.isAnnotationPresent.apply(method, SaIgnore.class)) {
+                        return true;
+                    }
+                    //先校验认证
+                    auth.run(handler);
+                    // 注解校验
+                    SaStrategy.me.checkMethodAnnotation.accept(method);
+                }else {
+                    auth.run(handler);
+                }
+
+
+            } catch (StopMatchException e) {
+                // 停止匹配,进入Controller
+            } catch (BackResultException e) {
+                // 停止匹配,向前端输出结果
+                if(response.getContentType() == null) {
+                    response.setContentType("text/plain; charset=utf-8");
+                }
+                response.getWriter().print(e.getMessage());
+                return false;
+            }
+
+            // 通过验证
+            return true;
+        }
+    }
 }

+ 4 - 3
tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/context/LoginUserContextHolder.java

@@ -2,6 +2,7 @@ package cn.tr.plugin.security.context;
 
 import cn.tr.core.context.SecurityContextHolder;
 import cn.tr.plugin.security.bo.LoginUserBO;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
 import cn.tr.plugin.security.constant.SecurityConstant;
 
 /**
@@ -19,11 +20,11 @@ public class LoginUserContextHolder {
         SecurityContextHolder.set(SecurityConstant.STP_TYPE, stpType);
     }
 
-    public static LoginUserBO getUser(){
-        return SecurityContextHolder.get(SecurityConstant.LOGIN_USER, LoginUserBO.class);
+    public static UserLoginInfoBO getUser(){
+        return SecurityContextHolder.get(SecurityConstant.LOGIN_USER, UserLoginInfoBO.class);
     }
 
-    public static void setUser(LoginUserBO user){
+    public static void setUser(UserLoginInfoBO user){
         SecurityContextHolder.set(SecurityConstant.LOGIN_USER, user);
     }
 }

+ 4 - 1
tr-plugins/tr-spring-boot-starter-plugin-satoken/src/main/java/cn/tr/plugin/security/filter/TrSaTokenFilter.java

@@ -3,6 +3,8 @@ package cn.tr.plugin.security.filter;
 import cn.dev33.satoken.exception.NotLoginException;
 import cn.dev33.satoken.exception.NotPermissionException;
 import cn.dev33.satoken.exception.NotRoleException;
+import cn.dev33.satoken.stp.StpLogic;
+import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.tr.core.utils.ServletUtils;
 import cn.tr.plugin.security.constant.SecurityConstant;
@@ -22,7 +24,8 @@ public class TrSaTokenFilter implements Filter {
     @Override
     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
         if(StrUtil.isEmpty(LoginUserContextHolder.getStpType())){
-            LoginUserContextHolder.setStpType( ServletUtils.getHeader(SecurityConstant.STP_TYPE));
+            String stpType = ServletUtils.getHeader(SecurityConstant.STP_TYPE);
+            LoginUserContextHolder.setStpType( StrUtil.isEmpty(stpType)? StpUtil.TYPE:stpType);
         }
         try {
             filterChain.doFilter(servletRequest,servletResponse);

Some files were not shown because too many files changed in this diff