Просмотр исходного кода

新增 角色、用户、权限 模式
新增 execl导出字典处理器

18339543638 2 лет назад
Родитель
Сommit
5cae3154b6
58 измененных файлов с 1033 добавлено и 492 удалено
  1. 0 3
      tr-framework/src/main/java/cn/tr/core/strategy/LoginUserStrategy.java
  2. 0 41
      tr-framework/src/main/java/cn/tr/core/strategy/auth/AuthStrategy.java
  3. 0 69
      tr-framework/src/main/java/cn/tr/core/strategy/auth/UserOperator.java
  4. 0 54
      tr-framework/src/main/java/cn/tr/core/strategy/auth/bo/AuthenticationDTO.java
  5. 0 84
      tr-framework/src/main/java/cn/tr/core/strategy/auth/bo/UserAccountInfoBO.java
  6. 4 4
      tr-modules/tr-module-system/pom.xml
  7. 4 15
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/controller/SysDictItemController.java
  8. 26 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictItemSmallDTO.java
  9. 0 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictItemPO.java
  10. 0 3
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictPO.java
  11. 14 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/ISysDictItemService.java
  12. 2 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/ISysDictService.java
  13. 27 52
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictItemServiceImpl.java
  14. 2 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/impl/SysDictServiceImpl.java
  15. 41 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/excel/DictExcelHandlerAdapter.java
  16. 3 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/dict/DictItemMapper.java
  17. 19 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/oauth2/OAuth2Mapper.java
  18. 0 20
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/oauth2/UserLoginInfoMapper.java
  19. 25 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysRoleMapper.java
  20. 27 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysRoleMenuMapper.java
  21. 3 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/mapper/user/SysUserMapper.java
  22. 3 5
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/LoginTypeMatcher.java
  23. 14 8
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/CurrentUserController.java
  24. 6 10
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/OAuth2ServerController.java
  25. 0 35
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/controller/vo/SwitchTenantUserVO.java
  26. 35 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/dto/OAuth2PswLoginInfoDTO.java
  27. 8 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/operator/OAuth2UserOperator.java
  28. 6 7
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/OAuth2PswModelConfig.java
  29. 6 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/AbstractOAuth2PswUserOperator.java
  30. 34 5
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/LoginOAuth2PswUserOperator.java
  31. 33 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/OAuth2PswUserOperatorManager.java
  32. 90 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/controller/SysRoleController.java
  33. 32 22
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuDTO.java
  34. 10 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysMenuQueryDTO.java
  35. 55 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysRoleDTO.java
  36. 17 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysRoleMenuDTO.java
  37. 34 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysRoleQueryDTO.java
  38. 5 2
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysUserDTO.java
  39. 25 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysRoleMenuPO.java
  40. 50 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysRolePO.java
  41. 21 23
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/po/SysUserPO.java
  42. 8 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysMenuRepository.java
  43. 18 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysRoleMenuRepository.java
  44. 17 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysRoleRepository.java
  45. 1 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysUserRepository.java
  46. 18 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysMenuService.java
  47. 23 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysRoleMenuService.java
  48. 54 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysRoleService.java
  49. 8 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/ISysUserService.java
  50. 13 1
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysMenuServiceImpl.java
  51. 43 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysRoleMenuServiceImpl.java
  52. 93 0
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysRoleServiceImpl.java
  53. 31 10
      tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/service/impl/SysUserServiceImpl.java
  54. 13 0
      tr-modules/tr-module-system/src/main/resources/mapper/user/SysMenuMapper.xml
  55. 6 3
      tr-modules/tr-module-system/src/main/resources/mapper/user/SysUserMapper.xml
  56. 0 2
      tr-plugins/tr-spring-boot-starter-plugin-biz-excel/src/main/java/cn/tr/plugin/excel/annotation/Excel.java
  57. 2 2
      tr-plugins/tr-spring-boot-starter-plugin-biz-excel/src/main/java/cn/tr/plugin/excel/config/ExcelHandlerAdapter.java
  58. 4 0
      tr-test/src/main/resources/application.yml

+ 0 - 3
tr-framework/src/main/java/cn/tr/core/strategy/LoginUserStrategy.java

@@ -1,10 +1,7 @@
 package cn.tr.core.strategy;
 
 
-import cn.tr.core.pojo.LoginResult;
 import cn.tr.core.strategy.auth.ILoginUser;
-
-import java.util.function.Function;
 import java.util.function.Supplier;
 
 /**

+ 0 - 41
tr-framework/src/main/java/cn/tr/core/strategy/auth/AuthStrategy.java

@@ -1,41 +0,0 @@
-package cn.tr.core.strategy.auth;
-
-import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-/**
- * @ClassName : AuthStrategy
- * @Description : 认证策略
- * @Author : LF
- * @Date: 2023年03月24日
- */
-public class AuthStrategy {
-    private AuthStrategy(){
-
-    }
-
-    private List<UserOperator> granters=new ArrayList<>();
-
-    public static AuthStrategy tr=new AuthStrategy();
-
-
-    public void addGranter(UserOperator... authGranters){
-        if(authGranters!=null){
-            granters.addAll(Stream.of(authGranters).collect(Collectors.toList()));
-        }
-    }
-
-    /**
-     * 根据loginType找到相应的处理器
-     * @param loginType
-     * @return
-     */
-    public UserOperator matchGranter(String loginType){
-        return granters
-                .stream()
-                .filter(auth-> auth.match(loginType))
-                .findFirst()
-                .orElse(null);
-    }
-}

+ 0 - 69
tr-framework/src/main/java/cn/tr/core/strategy/auth/UserOperator.java

@@ -1,69 +0,0 @@
-/**
- * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package cn.tr.core.strategy.auth;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.http.useragent.UserAgent;
-import cn.hutool.http.useragent.UserAgentUtil;
-import cn.tr.core.utils.IpUtil;
-import cn.tr.core.utils.ServletUtils;
-import cn.tr.core.strategy.auth.bo.UserAccountInfoBO;
-import cn.tr.core.strategy.auth.bo.AuthenticationDTO;
-
-import javax.servlet.http.HttpServletRequest;
-import java.util.Date;
-import java.util.Optional;
-
-/**
- * 用户操作接口.
- *
- * @author lifang
- */
-public interface UserOperator extends LoginTypeMatcher {
-	/**
-	 *
-	 * @param authentication 认证参数
-	 * @return
-	 */
-	UserAccountInfoBO login(AuthenticationDTO authentication);
-
-	/**
-	 * 修改当前密码
-	 *
-	 * @param oldPassword 旧密码
-	 * @param newPassword 新密码
-	 * @return
-	 */
-	public boolean updatePassword(String oldPassword, String newPassword);
-
-	/**
-	 * 填充用户登录信息
-	 * @param loginUser
-	 */
-	default void fillUserAgentInfo(UserAccountInfoBO loginUser){
-		HttpServletRequest request = ServletUtils.getRequest();
-		UserAgent userAgent = Optional.ofNullable(UserAgentUtil.parse(request.getHeader("User-Agent"))).orElse(new UserAgent());
-		String ipAddress = ServletUtils.getClientIP();
-		loginUser.setIpAddress(ipAddress);
-		loginUser.setLoginLocation(IpUtil.getCityInfo(ipAddress));
-		loginUser.setBrowser(ObjectUtil.isEmpty(userAgent.getBrowser())?"未知":userAgent.getBrowser().getName());
-		loginUser.setOs(ObjectUtil.isEmpty(userAgent.getOs())?"未知":userAgent.getOs().getName());
-		loginUser.setLoginTime(new Date());
-	};
-
-
-
-}

+ 0 - 54
tr-framework/src/main/java/cn/tr/core/strategy/auth/bo/AuthenticationDTO.java

@@ -1,54 +0,0 @@
-package cn.tr.core.strategy.auth.bo;
-
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-import org.hibernate.validator.constraints.Length;
-
-import javax.validation.constraints.NotEmpty;
-import javax.validation.constraints.Pattern;
-
-/**
- * 用于登陆传递账号密码
- *
- * @author FrozenWatermelon
- * @date 2020/7/1
- */
-@Data
-public class AuthenticationDTO {
-
-	/**
-	 * 用户名
-	 */
-	@ApiModelProperty(value = "账号",required = true)
-	@NotEmpty(message = "登录账号不能为空")
-	@Length(min = 4, max = 16, message = "账号长度为 4-16 位")
-	@Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母")
-	protected String username;
-
-	/**
-	 * 密码
-	 */
-
-	@ApiModelProperty(value = "密码", required = true)
-	@NotEmpty(message = "密码不能为空")
-	@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
-	private String password;
-
-	@ApiModelProperty(value = "验证码,验证码开启时,需要传递")
-	@NotEmpty(message = "验证码不能为空", groups = CodeEnableGroup.class)
-	private String captchaVerification;
-
-	/**
-	 * loginType 参考SysTypeEnum
-	 */
-	@ApiModelProperty(value = "登录方式",required = true)
-	@NotEmpty(message = "登录方式不能为空")
-	protected String loginType;
-
-
-	/**
-	 * 开启验证码的 Group
-	 */
-	public interface CodeEnableGroup {
-	}
-}

+ 0 - 84
tr-framework/src/main/java/cn/tr/core/strategy/auth/bo/UserAccountInfoBO.java

@@ -1,84 +0,0 @@
-package cn.tr.core.strategy.auth.bo;
-
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * 用户账户信息
- *
- * @author Kevin
- */
-@Data
-@NoArgsConstructor
-public class UserAccountInfoBO implements Serializable {
-
-    private static final long serialVersionUID = 1L;
-
-    private String id;
-
-    private String loginType;
-
-    /**
-     * 用户头像
-     */
-    private String avatar;
-
-    /**
-     * token
-     */
-    private String token;
-
-    /**
-     * 用户平台
-     */
-    private String userPlatform;
-
-    /**
-     * 用户名
-     */
-    private String username;
-
-    /**
-     * 昵称
-     */
-    private String nickname;
-
-    /**
-     * 性别
-     */
-    private String sex;
-
-    /**
-     * 登录时间
-     */
-    private Date loginTime;
-
-    /**
-     * 登录IP地址
-     */
-    private String ipAddress;
-
-
-    /**
-     * 登录地点
-     */
-    private String loginLocation;
-
-    /**
-     * 浏览器类型
-     */
-    private String browser;
-
-    /**
-     * 操作系统
-     */
-    private String os;
-
-    /**
-     * 租户id
-     */
-    private String tenantId;
-}

+ 4 - 4
tr-modules/tr-module-system/pom.xml

@@ -38,10 +38,10 @@
             <artifactId>tr-spring-boot-starter-plugin-satoken</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>cn.tr</groupId>
-            <artifactId>tr-spring-boot-starter-plugin-mp-enhance-actable</artifactId>
-        </dependency>
+        <!--<dependency>-->
+            <!--<groupId>cn.tr</groupId>-->
+            <!--<artifactId>tr-spring-boot-starter-plugin-mp-enhance-actable</artifactId>-->
+        <!--</dependency>-->
 
         <dependency>
             <groupId>cn.tr</groupId>

+ 4 - 15
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/controller/SysDictItemController.java

@@ -8,10 +8,9 @@ import cn.tr.core.validation.Update;
 import cn.tr.module.sys.dict.dto.SysDictDTO;
 import cn.tr.module.sys.dict.dto.SysDictItemDTO;
 import cn.tr.module.sys.dict.dto.SysDictItemQueryDTO;
+import cn.tr.module.sys.dict.dto.SysDictItemSmallDTO;
 import cn.tr.module.sys.dict.service.ISysDictItemService;
 import cn.tr.module.sys.dict.service.ISysDictService;
-import cn.tr.plugin.dict.bo.DictBO;
-import cn.tr.plugin.dict.config.cache.DictManager;
 import cn.tr.plugin.mybatis.base.BaseController;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
 import io.swagger.annotations.Api;
@@ -34,13 +33,12 @@ import java.util.*;
 @AllArgsConstructor
 public class SysDictItemController extends BaseController {
     private final ISysDictItemService dictItemService;
-    private final DictManager dictManager;
     private final ISysDictService dictService;
 
     @PostMapping("/query/list")
     @ApiOperationSupport(author = "lf")
-    @ApiOperation(value = "根据条件查询字典",notes = "无权限")
-    public CommonResult<List<DictBO>> selectList(@RequestBody SysDictItemQueryDTO query){
+    @ApiOperation(value = "查询相应字典下所有字典项",notes = "无权限")
+    public CommonResult<List<SysDictItemSmallDTO>> selectList(@RequestBody SysDictItemQueryDTO query){
         if(StrUtil.isEmpty(query.getDictCode())){
             SysDictDTO dict = dictService.selectDictById(query.getDictCode());
             if(dict==null){
@@ -48,16 +46,7 @@ public class SysDictItemController extends BaseController {
             }
             query.setDictCode(dict.getDictCode());
         }
-        return CommonResult.success(dictManager.lookAllByDictCode(query.getDictCode()));
-    }
-
-    @PostMapping("/reload")
-    @ApiOperationSupport(author = "lf")
-    @SaCheckPermission("sys:dictItem:reload")
-    @ApiOperation(value = "刷新缓存",notes = "权限: sys:dictItem:reload")
-    public CommonResult<Void> reload(){
-        dictItemService.reloadCache();
-        return CommonResult.success();
+        return CommonResult.success(dictItemService.selectDictItemsByDictCode(query.getDictCode()));
     }
 
 

+ 26 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/dto/SysDictItemSmallDTO.java

@@ -0,0 +1,26 @@
+package cn.tr.module.sys.dict.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @ClassName : SysDictItemSmallDTO
+ * @Description : 字典项简略信息
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Data
+public class SysDictItemSmallDTO implements Serializable {
+    private static final long serialVersionUID = -2738872740080930736L;
+
+    private String value;
+
+    private String label;
+
+    private Integer sort;
+
+    private String remark;
+
+    private String color;
+}

+ 0 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictItemPO.java

@@ -3,8 +3,6 @@ package cn.tr.module.sys.dict.po;
 import cn.tr.plugin.mybatis.pojo.BasePO;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;

+ 0 - 3
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/po/SysDictPO.java

@@ -10,8 +10,6 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 import org.springframework.stereotype.Indexed;
 
-import javax.persistence.Column;
-
 /**
  * 字典对象 sys_dict
  *
@@ -31,7 +29,6 @@ public class SysDictPO extends BasePO {
 
 
     @ApiModelProperty(value = "字典编码")
-    @Column(unique = true)
     private String dictCode;
 
     @ApiModelProperty(value = "字典名称")

+ 14 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/ISysDictItemService.java

@@ -2,6 +2,9 @@ package cn.tr.module.sys.dict.service;
 
 import cn.tr.module.sys.dict.dto.SysDictItemDTO;
 import cn.tr.module.sys.dict.dto.SysDictItemQueryDTO;
+import cn.tr.module.sys.dict.dto.SysDictItemSmallDTO;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
 
 import java.util.Collection;
 import java.util.List;
@@ -50,7 +53,16 @@ public interface ISysDictItemService {
     boolean updateDictItemById(SysDictItemDTO source);
 
     /**
-     * 刷新缓存
+     * 根据字典码获取所有的字典项信息
+     * @param dictCode 字典码
+     * @return 字典项列表
      */
-    void reloadCache();
+    @Cacheable(value = "sys:dict",key = "#dictCode")
+    List<SysDictItemSmallDTO> selectDictItemsByDictCode(String dictCode);
+
+
+    @CacheEvict(value = "sys:dict",key = "#dictCode")
+    default void delCache(String dictCode){
+
+    };
 }

+ 2 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/dict/service/ISysDictService.java

@@ -36,10 +36,10 @@ public interface ISysDictService {
     List<SysDictDTO> selectDictByIds(Collection<String> ids);
     /**
      * 根据字典code查询字典
-     * @param id 字典
+     * @param dictCode 字典code
      * @return 字典
      */
-    SysDictDTO selectDictByCode(String id);
+    SysDictDTO selectDictByCode(String dictCode);
 
     /**
      * 新增日志

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

@@ -3,23 +3,16 @@ package cn.tr.module.sys.dict.service.impl;
 import cn.hutool.core.collection.CollUtil;
 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.dict.dto.SysDictDTO;
-import cn.tr.module.sys.dict.dto.SysDictItemDTO;
-import cn.tr.module.sys.dict.dto.SysDictItemQueryDTO;
-import cn.tr.module.sys.dict.dto.SysDictQueryDTO;
+import cn.tr.module.sys.dict.dto.*;
 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.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;
-import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.CommandLineRunner;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import java.util.*;
@@ -32,12 +25,15 @@ import java.util.stream.Collectors;
  * @Date: 2023年03月24日
  */
 @Slf4j
-@AllArgsConstructor
 @Service
-public class SysDictItemServiceImpl implements ISysDictItemService, CommandLineRunner {
-    private final SysDictItemRepository dictItemRepository;
-    private final ISysDictService dictService;
-    private final DictManager dictManager;
+public class SysDictItemServiceImpl implements ISysDictItemService {
+    @Autowired
+    private SysDictItemRepository dictItemRepository;
+    @Autowired
+    private ISysDictService dictService;
+    @Autowired
+    @Lazy
+    private ISysDictItemService self;
 
     @Override
     public List<SysDictItemDTO> selectDictItemDataList(SysDictItemQueryDTO query) {
@@ -65,7 +61,7 @@ public class SysDictItemServiceImpl implements ISysDictItemService, CommandLineR
     public boolean insertDictItem(SysDictItemDTO source) {
         boolean result = dictItemRepository.insert(DictItemMapper.INSTANCE.toDictItemPO(source)) != 0;
         if(result){
-            loadDict(source);
+            refreshDictByDictId(source.getDictId());
         }
         return result;
     }
@@ -81,7 +77,6 @@ public class SysDictItemServiceImpl implements ISysDictItemService, CommandLineR
             return CollectionUtil.size(ids);
         }
         int result = dictItemRepository.deleteBatchIds(ids);
-
         List<SysDictDTO> dicts = dictService.selectDictByIds(
                 items.stream().map(SysDictItemPO::getDictId).collect(Collectors.toSet())
         );
@@ -91,7 +86,7 @@ public class SysDictItemServiceImpl implements ISysDictItemService, CommandLineR
             if(dict==null){
                 return;
             }
-            dictManager.evict(dict.getDictCode(),item.getValue());
+            refreshDictByDictId(dict.getDictId());
         });
         return result;
     }
@@ -100,49 +95,29 @@ public class SysDictItemServiceImpl implements ISysDictItemService, CommandLineR
     public boolean updateDictItemById(SysDictItemDTO source) {
         boolean result = dictItemRepository.updateById(DictItemMapper.INSTANCE.toDictItemPO(source)) != 0;
         if(result){
-            loadDict(source);
+            refreshDictByDictId(source.getDictId());
         }
         return result;
     }
 
     @Override
-    public void reloadCache() {
-        List<SysDictDTO> allDict = dictService.selectDictDataList(new SysDictQueryDTO());
-        Map< String, SysDictDTO> dictMap = allDict.stream().collect(Collectors.groupingBy(SysDictDTO::getDictId, Collectors.collectingAndThen(Collectors.toList(), CollUtil::getFirst)));
-        List<SysDictItemDTO> allDictItems = this.selectDictItemDataList(new SysDictItemQueryDTO());
-        Map<String, List<DictBO>> loadMap = allDictItems.stream()
-                .collect(Collectors.groupingBy(dict->dictMap.get(dict.getDictId()).getDictCode(),
-                        Collectors.collectingAndThen(Collectors.toList(),
-                                value -> value.stream().map(item -> DictBO.builder()
-                                        .value(item.getValue())
-                                        .label(item.getLabel())
-                                        .color(item.getColor())
-                                        .sort(item.getSort())
-                                        .build()
-                                )
-                                        .collect(Collectors.toList())
-                        )
-                        )
-                );
-        dictManager.loadAll(loadMap);
+    public List<SysDictItemSmallDTO> selectDictItemsByDictCode(String dictCode) {
+        SysDictDTO dict = dictService.selectDictByCode(dictCode);
+        if(dict==null){
+            return new ArrayList<>();
+        }
+        List<SysDictItemSmallDTO> result = DictItemMapper.INSTANCE.toDictItemSmallDtoList(dictItemRepository.selectList(new LambdaQueryWrapper<SysDictItemPO>()
+                .eq(SysDictItemPO::getDictId, dict.getDictId())));
+        result.sort(Comparator.comparing(SysDictItemSmallDTO::getSort));
+        return result;
     }
 
-    private void loadDict(SysDictItemDTO source){
-        SysDictDTO dict = dictService.selectDictById(source.getDictId());
+    private void refreshDictByDictId(String dictId){
+        SysDictDTO dict = dictService.selectDictById(dictId);
         if(dict==null){
-            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"所选字典不存在,添加失败");
+            return;
         }
-        dictManager.load(dict.getDictCode(),Arrays.asList( DictBO.builder()
-                .value(source.getValue())
-                .label(source.getLabel())
-                .color(source.getColor())
-                .sort(source.getSort())
-                .build()));
-    }
+        self.delCache(dict.getDictCode());
 
-    @Override
-    public void run(String... args) throws Exception {
-        reloadCache();
-        log.info("================== 字典加载完毕  ==================");
     }
 }

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

@@ -61,10 +61,10 @@ public class SysDictServiceImpl implements ISysDictService {
     }
 
     @Override
-    public SysDictDTO selectDictByCode(String code) {
+    public SysDictDTO selectDictByCode(String dictCode) {
         return DictMapper.INSTANCE.toDictDto(dictRepository.selectOne(
                 new LambdaQueryWrapper<SysDictPO>()
-                        .eq(SysDictPO::getDictCode,code)
+                        .eq(SysDictPO::getDictCode,dictCode)
                         .last("limit 1")
                 )
         );

+ 41 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/excel/DictExcelHandlerAdapter.java

@@ -0,0 +1,41 @@
+package cn.tr.module.sys.excel;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.tr.module.sys.dict.dto.SysDictItemSmallDTO;
+import cn.tr.module.sys.dict.service.ISysDictItemService;
+import cn.tr.module.sys.dict.service.ISysDictService;
+import cn.tr.plugin.excel.config.ExcelHandlerAdapter;
+
+import java.util.List;
+
+/**
+ * @ClassName : DictExcelHandlerAdapter
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+
+public class DictExcelHandlerAdapter implements ExcelHandlerAdapter {
+    private ISysDictItemService dictItemService;
+
+    public DictExcelHandlerAdapter() {
+        dictItemService=SpringUtil.getBean(ISysDictItemService.class);
+    }
+
+    @Override
+    public Object format(Object value, String[] args) {
+        if(value==null||args==null||args.length==0){
+            return null;
+        }
+        String dictCode = args[0];
+        List<SysDictItemSmallDTO> dictItems = dictItemService.selectDictItemsByDictCode(dictCode);
+        if(CollectionUtil.isEmpty(dictItems)){
+            return null;
+        }
+        return dictItems.stream()
+                .filter(item-> StrUtil.equals(String.valueOf(value),item.getValue()))
+                .map(SysDictItemSmallDTO::getLabel);
+    }
+}

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

@@ -1,6 +1,7 @@
 package cn.tr.module.sys.mapper.dict;
 
 import cn.tr.module.sys.dict.dto.SysDictItemDTO;
+import cn.tr.module.sys.dict.dto.SysDictItemSmallDTO;
 import cn.tr.module.sys.dict.po.SysDictItemPO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
@@ -22,4 +23,6 @@ public interface DictItemMapper {
     SysDictItemDTO toDictItemDto(SysDictItemPO source);
 
     List<SysDictItemDTO> toDictItemDtoList(List<SysDictItemPO> source);
+
+    List<SysDictItemSmallDTO> toDictItemSmallDtoList(List<SysDictItemPO> source);
 }

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

@@ -0,0 +1,19 @@
+package cn.tr.module.sys.mapper.oauth2;
+
+import cn.tr.module.sys.oauth2.dto.OAuth2PswLoginInfoDTO;
+import cn.tr.module.sys.user.dto.SysUserDTO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * @ClassName : OAuth2Mapper
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Mapper
+public interface OAuth2Mapper {
+    OAuth2Mapper INSTANCE = Mappers.getMapper(OAuth2Mapper.class);
+
+    OAuth2PswLoginInfoDTO  toPswLoginInfo(SysUserDTO source);
+}

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

@@ -1,20 +0,0 @@
-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/SysRoleMapper.java

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

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

@@ -0,0 +1,27 @@
+package cn.tr.module.sys.mapper.user;
+
+import cn.tr.module.sys.user.dto.SysRoleMenuDTO;
+import cn.tr.module.sys.user.po.SysRoleMenuPO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * @ClassName : SysRoleMenuMapper
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Mapper
+public interface SysRoleMenuMapper {
+    SysRoleMenuMapper INSTANCE = Mappers.getMapper(SysRoleMenuMapper.class);
+
+    List<SysRoleMenuDTO> toSysRoleMenuDTOList(List<SysRoleMenuPO> source);
+
+    List<SysRoleMenuPO> toSysRoleMenuPOList(List<SysRoleMenuDTO> source);
+
+    SysRoleMenuDTO toSysRoleMenuDTO(SysRoleMenuPO source);
+
+    SysRoleMenuPO toSysRoleMenuPO(SysRoleMenuDTO source);
+}

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

@@ -27,5 +27,8 @@ public interface SysUserMapper {
 
     SysUserDTO toUserDTO(SysUserPO source);
 
+
+    List<SysUserDTO> toUserDTOList(List<SysUserPO> source);
+
     SysUserPO toUserPO(SysUserDTO source);
 }

+ 3 - 5
tr-framework/src/main/java/cn/tr/core/strategy/auth/LoginTypeMatcher.java → tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/LoginTypeMatcher.java

@@ -1,4 +1,4 @@
-package cn.tr.core.strategy.auth;
+package cn.tr.module.sys.oauth2;
 
 /**
  * @ClassName : LoginTypeMatcher
@@ -10,10 +10,8 @@ package cn.tr.core.strategy.auth;
 public interface LoginTypeMatcher {
 
     /**
-     * 匹配登录系统
-     * @param loginType 匹配登录系统
-     * @return
+     * 匹配登录体系
      */
-    boolean match(String loginType);
+    String matchLoginType();
 
 }

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

@@ -1,8 +1,11 @@
 package cn.tr.module.sys.oauth2.controller;
 
-import cn.hutool.core.lang.tree.TreeUtil;
+import cn.tr.core.exception.ServiceException;
+import cn.tr.core.exception.TRExcCode;
 import cn.tr.core.pojo.CommonResult;
-import cn.tr.module.sys.user.service.ISysUserService;
+import cn.tr.module.sys.oauth2.psw.operator.AbstractOAuth2PswUserOperator;
+import cn.tr.module.sys.oauth2.psw.operator.OAuth2PswUserOperatorManager;
+import cn.tr.plugin.security.context.LoginUserContextHolder;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
@@ -10,8 +13,6 @@ 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 :
@@ -23,11 +24,16 @@ import javax.swing.plaf.TreeUI;
 @Api(tags = "当前账号用户操作")
 @AllArgsConstructor
 public class CurrentUserController {
-    private final ISysUserService userService;
-    @ApiOperation("当前用户的个人账户信息")
+    private final OAuth2PswUserOperatorManager pswUserOperatorManager;
+    @ApiOperation("当前用户的登陆信息")
+    @GetMapping("/login-info")
     public CommonResult accountInfo(){
-        //todo
-        return CommonResult.success();
+        String stpType = LoginUserContextHolder.getStpType();
+        AbstractOAuth2PswUserOperator operator = pswUserOperatorManager.matchLoginType(stpType);
+        if(operator==null){
+            throw new ServiceException(TRExcCode.USER_ERROR_A0200,String.format("账号体系[{%s}]不存在",stpType));
+        }
+        return CommonResult.success(operator.getUserLoginInfo());
     }
 
     @GetMapping("/get-permission-info")

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

@@ -15,9 +15,10 @@ import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
 import cn.tr.core.pojo.CommonResult;
 import cn.tr.module.sys.oauth2.dto.OAuth2UpdatePswDTO;
-import cn.tr.module.sys.oauth2.psw.operator.LoginOAuth2PswUserOperator;
+import cn.tr.module.sys.oauth2.psw.operator.AbstractOAuth2PswUserOperator;
 import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
 import cn.tr.module.sys.oauth2.dto.OAuth2RefreshDTO;
+import cn.tr.module.sys.oauth2.psw.operator.OAuth2PswUserOperatorManager;
 import cn.tr.plugin.security.context.LoginUserContextHolder;
 import cn.tr.plugin.security.utils.SaTokenUtils;
 import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
@@ -27,9 +28,6 @@ import lombok.AllArgsConstructor;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import java.util.List;
-import java.util.Optional;
-
 /**
  * @ClassName : OAuth2ServerController
  * @Description : oauth2接口
@@ -41,7 +39,7 @@ import java.util.Optional;
 @Api(tags = "OAuth2 密码模式")
 @AllArgsConstructor
 public class OAuth2ServerController {
-    private final List<LoginOAuth2PswUserOperator> operators;
+    private final OAuth2PswUserOperatorManager pswUserOperatorManager;
     @ApiOperation("获取token")
     @ApiOperationSupport(author = "lf")
     @GetMapping("/token")
@@ -88,14 +86,12 @@ public class OAuth2ServerController {
         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()){
+        AbstractOAuth2PswUserOperator operator = pswUserOperatorManager.matchLoginType(stpType);
+        if(operator==null){
             throw new ServiceException(TRExcCode.USER_ERROR_A0200,String.format("账号体系[{%s}]不存在",stpType));
         }
         SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
-        return CommonResult.success(operator.get()
+        return CommonResult.success(operator
                 .updatePsw(psw.getOldPsw(),psw.getNewPsw()));
     }
 

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

@@ -1,35 +0,0 @@
-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;
-
-}

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

@@ -0,0 +1,35 @@
+package cn.tr.module.sys.oauth2.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @ClassName : OAuth2PswLoginInfoDTO
+ * @Description : oauth2 密码登录用户信息
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Data
+public class OAuth2PswLoginInfoDTO implements Serializable {
+    private static final long serialVersionUID = -4315373653934784347L;
+
+    private String userId;
+
+    private String username;
+
+    private String nickname;
+
+    private String avatar;
+
+    private String lastLoginIp;
+
+    private String lastLoginAddress;
+
+    private Date lastLoginDate;
+
+    private String phone;
+
+    private String email;
+}

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

@@ -15,7 +15,7 @@
  */
 package cn.tr.module.sys.oauth2.operator;
 
-import cn.tr.core.strategy.auth.LoginTypeMatcher;
+import cn.tr.module.sys.oauth2.LoginTypeMatcher;
 import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
 import cn.tr.module.sys.oauth2.enums.OAuth2ModelEnum;
 
@@ -45,4 +45,11 @@ public interface OAuth2UserOperator extends LoginTypeMatcher {
 	 * @return
 	 */
 	boolean updatePsw(String oldPsw,String newPsw);
+
+
+	/**
+	 * 获取当前用户登录信息
+	 * @return
+	 */
+	Object getUserLoginInfo();
 }

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

@@ -6,7 +6,9 @@ import cn.hutool.core.util.StrUtil;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
 import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
+import cn.tr.module.sys.oauth2.psw.operator.AbstractOAuth2PswUserOperator;
 import cn.tr.module.sys.oauth2.psw.operator.LoginOAuth2PswUserOperator;
+import cn.tr.module.sys.oauth2.psw.operator.OAuth2PswUserOperatorManager;
 import cn.tr.plugin.security.context.LoginUserContextHolder;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -27,8 +29,7 @@ import java.util.Optional;
 public class OAuth2PswModelConfig {
     private final SaOAuth2Config cfg;
 
-    private final List<LoginOAuth2PswUserOperator> operators;
-
+    private final OAuth2PswUserOperatorManager pswUserOperatorManager;
     @PostConstruct
     public void init(){
         cfg.setDoLoginHandle((username,psw)->{
@@ -36,16 +37,14 @@ public class OAuth2PswModelConfig {
             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()){
+            AbstractOAuth2PswUserOperator operator = pswUserOperatorManager.matchLoginType(stpType);
+            if(operator==null){
                 throw new ServiceException(TRExcCode.USER_ERROR_A0200,String.format("账号体系[{%s}]不存在",stpType));
             }
             OAuth2PswReqDTO parm = new OAuth2PswReqDTO()
                     .setPassword(psw)
                     .setUsername(username);
-            return SaResult.ok(operator.get().auth(parm));
+            return SaResult.ok(operator.auth(parm));
         });
     }
 }

+ 6 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/AbstractOAuth2PswUserOperator.java

@@ -2,6 +2,7 @@ package cn.tr.module.sys.oauth2.psw.operator;
 
 import cn.tr.module.sys.oauth2.enums.OAuth2ModelEnum;
 import cn.tr.module.sys.oauth2.operator.OAuth2UserOperator;
+import org.springframework.cache.annotation.CacheEvict;
 
 /**
  * @ClassName : OAuth2PswUserOperator
@@ -15,4 +16,9 @@ public abstract class AbstractOAuth2PswUserOperator implements OAuth2UserOperato
     public OAuth2ModelEnum oauth2Model() {
         return OAuth2ModelEnum.psw;
     }
+
+    @CacheEvict(value = "oauth2-psw-loginInfo",key = "#userId",allEntries = true)
+    public void delUserLoginInfoCache(String userId){
+
+    };
 }

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

@@ -6,7 +6,10 @@ 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.IpUtil;
 import cn.tr.core.utils.PswUtils;
+import cn.tr.core.utils.ServletUtils;
+import cn.tr.module.sys.mapper.oauth2.OAuth2Mapper;
 import cn.tr.module.sys.oauth2.dto.OAuth2PswReqDTO;
 import cn.tr.module.sys.user.dto.SysUserDTO;
 import cn.tr.module.sys.user.enums.UserStatusEnum;
@@ -14,8 +17,13 @@ import cn.tr.module.sys.user.service.ISysUserService;
 import cn.tr.plugin.biz.tenant.context.TenantContextHolder;
 import cn.tr.plugin.security.utils.SaTokenUtils;
 import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
+import java.util.Date;
+
 /**
  * @ClassName : LoginOauth2PswUserOperator
  * @Description : 默认账号体系登录操作
@@ -23,9 +31,12 @@ import org.springframework.stereotype.Component;
  * @Date: 2023年03月31日
  */
 @Component
-@AllArgsConstructor
 public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
-    private final ISysUserService sysUserService;
+    @Autowired
+    @Lazy
+    private LoginOAuth2PswUserOperator self;
+    @Autowired
+    private ISysUserService sysUserService;
     @Override
     public String auth(OAuth2PswReqDTO source) {
         String username = source.getUsername();
@@ -48,6 +59,18 @@ public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
         }
         StpLogic stpUtil = SaTokenUtils.getStpUtil();
         stpUtil.login(user.getUserId());
+
+        //更新最后登录信息
+        String cityInfo = IpUtil.getCityInfo(ServletUtils.getClientIP());
+        SysUserDTO updateUser = new SysUserDTO();
+        updateUser.setUserId(user.getUserId());
+        updateUser.setLastLoginDate(new Date());
+        updateUser.setLastLoginIp(ServletUtils.getClientIP());
+        updateUser.setLastLoginAddress(cityInfo);
+        sysUserService.updateSysUserById(updateUser);
+        //清除缓存
+        self.delUserLoginInfoCache(user.getUserId());
+
         return stpUtil.getTokenValue();
     }
 
@@ -58,8 +81,14 @@ public class LoginOAuth2PswUserOperator extends AbstractOAuth2PswUserOperator{
     }
 
     @Override
-    public boolean match(String loginType) {
-        //默认登录体系
-        return StrUtil.isEmpty(loginType)||StrUtil.equals(StpUtil.TYPE,loginType);
+    @Cacheable(value = "oauth2-psw-loginInfo")
+    public Object getUserLoginInfo() {
+        String loginId =String.valueOf( SaTokenUtils.getStpUtil().getLoginId());
+        return OAuth2Mapper.INSTANCE.toPswLoginInfo(sysUserService.selectSysUserById(loginId));
+    }
+
+    @Override
+    public String matchLoginType() {
+        return StpUtil.TYPE;
     }
 }

+ 33 - 0
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/oauth2/psw/operator/OAuth2PswUserOperatorManager.java

@@ -0,0 +1,33 @@
+package cn.tr.module.sys.oauth2.psw.operator;
+
+import org.springframework.context.annotation.Configuration;
+import java.util.*;
+/**
+ * @ClassName : OAuth2PswUserOperatorManager
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Configuration
+public class OAuth2PswUserOperatorManager {
+
+    private final Map<String,AbstractOAuth2PswUserOperator> operatorMap=new HashMap<>();
+
+    public OAuth2PswUserOperatorManager(List<AbstractOAuth2PswUserOperator> operators) {
+        operators.forEach(this::addOperator);
+    }
+
+
+    public void addOperator(AbstractOAuth2PswUserOperator operator){
+        operatorMap.compute(operator.matchLoginType(),(k,v1)->{
+            if(v1==null){
+                return operator;
+            }
+            throw new UnsupportedOperationException(String.format("[AbstractOAuth2PswUserOperator] matchLoginType :{%s} 不能重复注册",operator.matchLoginType()));
+        });
+    }
+
+    public AbstractOAuth2PswUserOperator matchLoginType(String loginType){
+        return operatorMap.get(loginType);
+    }
+}

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

@@ -0,0 +1,90 @@
+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.SysRoleDTO;
+import cn.tr.module.sys.user.dto.SysRoleMenuDTO;
+import cn.tr.module.sys.user.dto.SysRoleQueryDTO;
+import cn.tr.module.sys.user.service.ISysRoleMenuService;
+import cn.tr.module.sys.user.service.ISysRoleService;
+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.*;
+
+/**
+ * @ClassName : SysRoleController
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月24日
+ */
+@RestController
+@RequestMapping("/sys/role")
+@Api(tags = "角色")
+@AllArgsConstructor
+public class SysRoleController extends BaseController {
+    private final ISysRoleService RoleService;
+    private final ISysRoleMenuService roleMenuService;
+
+    @PostMapping("/query/page")
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation(value = "根据条件查询角色",notes = "权限: sys:role:query")
+    @SaCheckPermission("sys:role:query")
+    public TableDataInfo<SysRoleDTO> selectList(@RequestBody SysRoleQueryDTO query){
+        startPage();
+        return getDataTable(RoleService.selectSysRoleList(query));
+    }
+
+    @PostMapping("/assign")
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation(value = "为角色分配权限",notes = "权限: sys:role:assign")
+    @SaCheckPermission("sys:role:assign")
+    public CommonResult<Boolean> selectList(@RequestBody List<SysRoleMenuDTO> source){
+        roleMenuService.assignRoleMenu(source);
+        return CommonResult.success(true);
+    }
+
+    @GetMapping("/detail/{id}")
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation(value = "根据id查询角色",notes = "权限: sys:role:query")
+    @SaCheckPermission("sys:role:query")
+    public CommonResult<SysRoleDTO> findById(@PathVariable("id") String id){
+        return CommonResult.success(RoleService.selectSysRoleById(id));
+    }
+
+    @PostMapping("/edit")
+    @ApiOperationSupport(author = "lf")
+    @SaCheckPermission("sys:role:edit")
+    @ApiOperation(value = "根据id更新角色",notes = "权限: sys:role:edit")
+    public CommonResult<Boolean> edit(@RequestBody@Validated(Update.class) SysRoleDTO source){
+        return CommonResult.success(RoleService.updateSysRoleById(source));
+    }
+
+    @PostMapping("/add")
+    @ApiOperationSupport(author = "lf")
+    @SaCheckPermission("sys:role:add")
+    @ApiOperation(value = "新增角色",notes = "权限: sys:role:add")
+    public CommonResult<Boolean> add(@RequestBody@Validated(Insert.class) SysRoleDTO source){
+        return CommonResult.success(RoleService.insertSysRole(source));
+    }
+    
+    @PostMapping("/deleteByIds")
+    @ApiOperationSupport(author = "lf")
+    @ApiOperation(value = "删除角色",notes = "权限: sys:role:del")
+    @SaCheckPermission("sys:role:del")
+    public CommonResult<Integer> deleteByIds(@RequestBody Collection<String> ids){
+        return CommonResult.success(RoleService.deleteSysRoleByIds(ids));
+    }
+    
+
+    //todo 导出
+
+}

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

@@ -1,14 +1,16 @@
 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 cn.tr.core.validation.Insert;
+import cn.tr.core.validation.Update;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
 /**
  * 菜单对象 sys_menu
  *
@@ -17,69 +19,77 @@ import lombok.ToString;
  */
 @Data
 @ToString
-@TableName("sys_menu")
 @EqualsAndHashCode(callSuper = true)
 public class SysMenuDTO extends TreeNode<String> {
 
     private static final long serialVersionUID = 1L;
 
-    @Comment(value = "主键")
-    @TableId
+    @ApiModelProperty(value = "主键")
+    @NotEmpty(message = "菜单主键不能为空",groups = Update.class)
     private String id;
 
-    @Comment(value = "父级id 顶级目录的父级id为0")
+    @ApiModelProperty(value = "父级id 顶级目录的父级id为0",required = true)
+    @NotEmpty(message = "父级id不能为空",groups = {Update.class, Insert.class})
     private String parentId;
 
-    @Comment("排序")
+    @ApiModelProperty(value="排序",required = true)
+    @NotEmpty(message = "排序不能为空",groups = {Update.class, Insert.class})
     private Integer sort;
 
-    @Comment(value = "菜单类型 dir目录;menu菜单;button按钮")
+    @ApiModelProperty(value = "菜单类型 dir目录;menu菜单;button按钮",required = true)
+    @NotEmpty(message = "菜单类型不能为空",groups = {Update.class, Insert.class})
     private String menuType;
 
 
-    @Comment(value = "菜单名称")
+    @ApiModelProperty(value = "菜单名称",required = true)
+    @NotEmpty(message = "菜单名称不能为空",groups = {Update.class, Insert.class})
     private String name;
 
-    @Comment(value = "路由地址")
+    @ApiModelProperty(value = "路由地址")
     private String routePath;
 
 
-    @Comment(value = "组件路径")
+    @ApiModelProperty(value = "组件路径")
     private String component;
 
 
-    @Comment(value = "权限标识")
+    @ApiModelProperty(value = "权限标识")
     private String permission;
 
 
-    @Comment(value = "图标")
+    @ApiModelProperty(value = "图标")
     private String icon;
 
-    @Comment(value = "是否缓存 0不缓存;1缓存")
+    @ApiModelProperty(value = "是否缓存 0不缓存;1缓存",required = true)
+    @NotNull(message = "缓存状态不能为空",groups = {Update.class, Insert.class})
     private Boolean keepalive;
 
 
-    @Comment(value = "是否外链 0否;1是")
+    @ApiModelProperty(value = "是否外链 0否;1是",required = true)
+    @NotNull(message = "外链状态不能为空",groups = {Update.class, Insert.class})
     private Boolean linkExternal;
 
 
-    @Comment(value = "是否显示 0隐藏;1显示")
+    @ApiModelProperty(value = "是否显示 0隐藏;1显示",required = true)
+    @NotNull(message = "显示装填不能为空",groups = {Update.class, Insert.class})
     private Boolean visible;
 
 
-    @Comment(value = "是否内嵌 0不内嵌;1、内嵌")
+    @ApiModelProperty(value = "是否内嵌 0不内嵌;1、内嵌",required = true)
+    @NotNull(message = "内嵌状态不能为空",groups = {Update.class, Insert.class})
     private Boolean frame;
 
 
-    @Comment(value = "外部链接")
+    @ApiModelProperty(value = "外部链接",required = true)
     private String linkUrl;
 
 
-    @Comment(value = "备注")
+    @ApiModelProperty(value = "备注")
     private String remarks;
 
 
-    @Comment(value = "状态 0正常;1停用")
+    @ApiModelProperty(value = "状态 0正常;1停用",required = true)
+    @NotNull(message = "菜单状态不能为空",groups = {Update.class, Insert.class})
     private Boolean disable;
 
 }

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

@@ -1,5 +1,7 @@
 package cn.tr.module.sys.user.dto;
 
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
@@ -11,6 +13,14 @@ import java.io.Serializable;
  * @Date: 2023年04月01日
  */
 @Data
+@ApiModel("菜单查询参数")
 public class SysMenuQueryDTO implements Serializable {
     private static final long serialVersionUID = -262693810220247854L;
+
+
+    @ApiModelProperty("菜单名称")
+    private String name;
+
+    @ApiModelProperty("菜单状态")
+    private Boolean disable;
 }

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

@@ -0,0 +1,55 @@
+package cn.tr.module.sys.user.dto;
+
+import cn.tr.core.validation.Insert;
+import cn.tr.core.validation.Update;
+import cn.tr.plugin.mybatis.pojo.TenantPO;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+
+/**
+ * @ClassName : SysRolePO
+ * @Description : 系统角色
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Data
+public class SysRoleDTO extends TenantPO {
+    @ApiModelProperty(value = "角色id",required = true)
+    @NotEmpty(message = "角色id不能为空",groups = {Insert.class, Update.class})
+    private String id;
+
+    @ApiModelProperty(value = "角色编码",required = true)
+    @NotEmpty(message = "角色编码不能为空",groups = {Insert.class, Update.class})
+    private String roleCode;
+
+    @ApiModelProperty(value = "角色名称",required = true)
+    @NotEmpty(message = "角色名称不能为空",groups = {Insert.class, Update.class})
+    private String roleName;
+
+    @ApiModelProperty(value = "数据范围 1、全部数据权限;2、自定义数据权限;3、本部门数据权限;4、本部门及以下数据权限",required = true)
+    @NotEmpty(message = "数据范围不能为空",groups = {Insert.class, Update.class})
+    private String dataScope;
+
+    @ApiModelProperty(value = "角色类型 user:用户角色  app:应用角色  tenant:租户角色",required = true)
+    @NotEmpty(message = "角色类型不能为空",groups = {Insert.class, Update.class})
+    private String type;
+
+    @ApiModelProperty(value = "排序",required = true)
+    @NotEmpty(message = "排序不能为空",groups = {Insert.class, Update.class})
+    private Integer sort;
+
+    @ApiModelProperty(value = "是否启用 0、启用 1、关闭",required = true)
+    @NotEmpty(message = "启用状态 不能为空",groups = {Insert.class, Update.class})
+    private Boolean disable;
+
+    @ApiModelProperty(value = "是否为管理员角色",readOnly = true)
+    @JsonIgnoreProperties(allowGetters = true)
+    private Boolean admin;
+
+
+    @ApiModelProperty("备注")
+    private String remark;
+}

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

@@ -0,0 +1,17 @@
+package cn.tr.module.sys.user.dto;
+import lombok.Data;
+
+/**
+ * @ClassName : SysRoleMenuPO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月04日
+ */
+@Data
+public class SysRoleMenuDTO {
+    private String id;
+
+    private String roleId;
+
+    private String menuId;
+}

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

@@ -0,0 +1,34 @@
+package cn.tr.module.sys.user.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * @ClassName : SysRoleQueryDTO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月01日
+ */
+@Data
+@ApiModel("角色查询参数")
+public class SysRoleQueryDTO implements Serializable {
+    private static final long serialVersionUID = -262693810220247854L;
+    @ApiModelProperty(value = "角色编码")
+    private String roleCode;
+
+    @ApiModelProperty(value = "角色名称")
+    private String roleName;
+
+    @ApiModelProperty(value = "角色类型",required = true)
+    @NotNull(message = "角色类型不能为空")
+    private String type;
+
+    @ApiModelProperty(value = "是否启用 0、启用 1、关闭")
+    private Boolean disable;
+
+
+}

+ 5 - 2
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/dto/SysUserDTO.java

@@ -86,13 +86,16 @@ public class SysUserDTO {
      * 最后登录IP
      */
     @Excel(name = "最后登录IP")
-    private String loginIp;
+    private String lastLoginIp;
+
+    @Excel(name = "最后登录地址")
+    private String lastLoginAddress;
 
     /**
      * 最后登录时间
      */
     @Excel(name = "最后登录时间",dateFormat = DatePattern.CHINESE_DATE_TIME_PATTERN)
-    private Date loginDate;
+    private Date lastLoginDate;
 
     /**
      * 备注

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

@@ -0,0 +1,25 @@
+package cn.tr.module.sys.user.po;
+
+import cn.tr.core.annotation.Comment;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * @ClassName : SysRoleMenuPO
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月04日
+ */
+@Data
+@TableName("sys_role_menu")
+public class SysRoleMenuPO {
+    @TableId
+    private String id;
+
+    @Comment("角色id")
+    private String roleId;
+
+    @Comment("菜单id")
+    private String menuId;
+}

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

@@ -0,0 +1,50 @@
+package cn.tr.module.sys.user.po;
+
+import cn.tr.core.annotation.ColumnDefaultValue;
+import cn.tr.core.annotation.Comment;
+import cn.tr.plugin.mybatis.pojo.TenantPO;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * @ClassName : SysRolePO
+ * @Description : 系统角色
+ * @Author : LF
+ * @Date: 2023年04月03日
+ */
+@Data
+@TableName("sys_role")
+public class SysRolePO extends TenantPO {
+    @TableId
+    @Comment("角色id")
+    private String id;
+
+    @Comment("角色编码")
+    private String roleCode;
+
+    @Comment("角色名称")
+    private String roleName;
+
+    @Comment("数据范围 1、全部数据权限;2、自定义数据权限;3、本部门数据权限;4、本部门及以下数据权限")
+    private String dataScope;
+
+    @Comment("角色类型 user:用户角色  app:应用角色  tenant:租户角色")
+    private String type;
+
+    @Comment("备注")
+    private String remark;
+
+    @Comment("是否为管理员账号, 0、否 1、是")
+    @ColumnDefaultValue("0")
+    @TableField(updateStrategy = FieldStrategy.NEVER)
+    private Boolean admin;
+
+    @Comment("排序")
+    private Integer sort;
+
+    @Comment("是否启用 0、启用 1、关闭")
+    private Boolean disable;
+}

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

@@ -5,11 +5,8 @@ import cn.tr.core.annotation.Comment;
 import cn.tr.module.sys.user.enums.UserStatusEnum;
 import cn.tr.plugin.mybatis.pojo.TenantPO;
 import com.baomidou.mybatisplus.annotation.*;
-import com.gitee.sunchenbin.mybatis.actable.annotation.ColumnComment;
 import lombok.Data;
 import org.apache.ibatis.type.JdbcType;
-
-import java.time.LocalDateTime;
 import java.util.Date;
 
 /**
@@ -21,11 +18,11 @@ import java.util.Date;
 @Data
 @TableName("sys_user")
 public class SysUserPO extends TenantPO {
-    @ColumnComment("用户主键Id")
+    @Comment("用户主键Id")
     @TableId
     private String userId;
 
-    @ColumnComment("用户名")
+    @Comment("用户名")
     @TableField(updateStrategy = FieldStrategy.NEVER)
     private String username;
 
@@ -33,51 +30,52 @@ public class SysUserPO extends TenantPO {
      * {@link cn.tr.core.utils.PswUtils#encryptPassword(String)} 加密
      * {@link cn.tr.core.utils.PswUtils#matchesPassword(String, String)} (String)} 匹配密码
      */
-    @ColumnComment("密码")
+    @Comment("密码")
     private String password;
 
-    @ColumnComment("昵称")
+    @Comment("昵称")
     private String nickname;
 
-    @ColumnComment("性别")
+    @Comment("性别")
     private String gender;
 
-    @ColumnComment("部门id")
+    @Comment("部门id")
     private String deptId;
 
-    @ColumnComment("手机号")
+    @Comment("手机号")
     private String phone;
 
-    @ColumnComment("邮箱地址")
+    @Comment("邮箱地址")
     private String email;
 
-    @ColumnComment("出生日期")
+    @Comment("出生日期")
     private Date birthday;
 
-    @ColumnComment("岗位id")
+    @Comment("岗位id")
     private String postIds;
 
-    @ColumnComment("用户头像")
+    @Comment("用户头像")
     private String avatar;
 
     /**
      * {@link UserStatusEnum#getValue()}
      */
-    @ColumnComment("用户状态")
+    @Comment("用户状态")
     private String status;
 
-    @ColumnComment("最后登录IP")
-    private String loginIp;
+    @Comment("最后登录IP")
+    private String lastLoginIp;
+
+    @Comment("最后登录地址")
+    private String lastLoginAddress;
 
-    @ColumnComment("最后登录时间")
-    private LocalDateTime loginDate;
+    @Comment("最后登录时间")
+    private Date lastLoginDate;
 
-    @ColumnComment("备注")
+
+    @Comment("备注")
     private String remark;
 
-        /**
-     * 是否删除
-     */
     @Comment("删除标记")
     @ColumnDefaultValue("0")
     @TableLogic

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

@@ -3,8 +3,9 @@ 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.apache.ibatis.annotations.Param;
 import org.springframework.stereotype.Repository;
-
+import java.util.*;
 /**
  * @ClassName : SysUserRepository
  * @Description :
@@ -14,4 +15,10 @@ import org.springframework.stereotype.Repository;
 @Mapper
 @Repository
 public interface SysMenuRepository extends BaseMapper<SysMenuPO> {
+    /**
+     * 找到角色下的所有菜单信息
+     * @param roleId 角色id
+     * @return
+     */
+    List<SysMenuPO> findAllMenuByRoleId(@Param("roleId") String roleId);
 }

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

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

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

@@ -0,0 +1,17 @@
+package cn.tr.module.sys.user.repository;
+
+import cn.tr.module.sys.user.po.SysRolePO;
+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 SysRoleRepository extends BaseMapper<SysRolePO> {
+}

+ 1 - 1
tr-modules/tr-module-system/src/main/java/cn/tr/module/sys/user/repository/SysUserRepository.java

@@ -20,5 +20,5 @@ public interface SysUserRepository extends RecoverMapper<SysUserPO> {
      * @param username 用户名
      * @return
      */
-    SysUserPO selectUserIgnoreDelByUsername(@Param("username") String username);
+    SysUserPO selectUserByUsernameIgnoreDel(@Param("username") String username);
 }

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

@@ -5,7 +5,8 @@ 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 org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
 
 import java.util.Collection;
 import java.util.List;
@@ -73,4 +74,20 @@ public interface ISysMenuService extends ITreeService {
      * @return 删除数量
      */
     int deleteSysMenuByIds(Collection<String> ids);
+
+
+    /**
+     * 找到角色id下的所有菜单信息
+     * @param roleId
+     * @return
+     */
+    @Cacheable(value = "sys:rolemenu",key = "#roleId")
+    List<SysMenuDTO> findAllMenuByRoleId(String roleId);
+
+
+    @CacheEvict(value = "sys:rolemenu",key = "#roleId")
+    default void delCache(String roleId){
+
+    };
+
 }

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

@@ -0,0 +1,23 @@
+package cn.tr.module.sys.user.service;
+
+import cn.tr.module.sys.user.dto.SysRoleMenuDTO;
+
+import java.util.*;
+
+/**
+ * @ClassName : ISysRoleMenuService
+ * @Description : 角色菜单关联关系
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+
+public interface ISysRoleMenuService {
+
+    /**
+     * 为角色分配菜单
+     * @param source 角色菜单关联信息
+     * @return
+     */
+    void assignRoleMenu(List<SysRoleMenuDTO> source);
+
+}

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

@@ -0,0 +1,54 @@
+package cn.tr.module.sys.user.service;
+
+import cn.tr.module.sys.user.dto.SysRoleDTO;
+import cn.tr.module.sys.user.dto.SysRoleQueryDTO;
+import cn.tr.plugin.mybatis.service.ITreeService;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @ClassName : ISysRoleService
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+
+public interface ISysRoleService {
+
+    /**
+     * 根据条件查询
+     * @param query 查询参数
+     * @return
+     */
+    List<SysRoleDTO> selectSysRoleList(SysRoleQueryDTO query);
+
+
+    /**
+     * 根据id查询操作角色
+     * @param id 角色id
+     * @return 角色
+     */
+    SysRoleDTO selectSysRoleById(String id);
+
+    /**
+     * 更新角色
+     * @param source 更新角色
+     * @return true:更新成功
+     */
+    boolean updateSysRoleById(SysRoleDTO source);
+
+    /**
+     * 新增角色
+     * @param source 新增角色
+     * @return true:新增成功
+     */
+    boolean insertSysRole(SysRoleDTO source);
+
+    /**
+     * 根据id删除角色
+     * @param ids 角色id
+     * @return 删除数量
+     */
+    int deleteSysRoleByIds(Collection<String> ids);
+}

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

@@ -56,6 +56,14 @@ public interface ISysUserService {
      */
     boolean insertSysUser(SysUserDTO source);
 
+
+    /**
+     * 忽略租户,根据用户名查询
+     * @param username 用户名
+     * @return
+     */
+    List<SysUserDTO> selectUserByUsernameIgnoreTenant(String username);
+
     /**
      * 根据id删除用户
      * @param ids 用户id

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

@@ -1,10 +1,14 @@
 package cn.tr.module.sys.user.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 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.po.SysMenuPO;
 import cn.tr.module.sys.user.repository.SysMenuRepository;
 import cn.tr.module.sys.user.service.ISysMenuService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 
@@ -23,7 +27,10 @@ public class SysMenuServiceImpl implements ISysMenuService {
     private final SysMenuRepository menuRepository;
     @Override
     public List<SysMenuDTO> selectSysMenuList(SysMenuQueryDTO query) {
-        return null;
+        return SysMenuMapper.INSTANCE.toSysMenuDTOList(menuRepository.selectList(new LambdaQueryWrapper<SysMenuPO>()
+                .like(StrUtil.isNotEmpty(query.getName()),SysMenuPO::getName,query.getName())
+                .eq(ObjectUtil.isNotNull(query.getDisable()),SysMenuPO::getDisable,query.getDisable()))
+        );
     }
 
     @Override
@@ -44,4 +51,9 @@ public class SysMenuServiceImpl implements ISysMenuService {
     public int deleteSysMenuByIds(Collection<String> ids) {
         return menuRepository.deleteBatchIds(ids);
     }
+
+    @Override
+    public List<SysMenuDTO> findAllMenuByRoleId(String roleId) {
+        return SysMenuMapper.INSTANCE.toSysMenuDTOList(menuRepository.findAllMenuByRoleId(roleId));
+    }
 }

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

@@ -0,0 +1,43 @@
+package cn.tr.module.sys.user.service.impl;
+
+import cn.tr.module.sys.mapper.user.SysRoleMenuMapper;
+import cn.tr.module.sys.user.dto.SysRoleMenuDTO;
+import cn.tr.module.sys.user.po.SysRoleMenuPO;
+import cn.tr.module.sys.user.repository.SysRoleMenuRepository;
+import cn.tr.module.sys.user.service.ISysMenuService;
+import cn.tr.module.sys.user.service.ISysRoleMenuService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName : SysRoleMenuServiceImpl
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年04月04日
+ */
+@Service
+@AllArgsConstructor
+public class SysRoleMenuServiceImpl extends ServiceImpl<SysRoleMenuRepository,SysRoleMenuPO> implements ISysRoleMenuService {
+    private final ISysMenuService menuService;
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void assignRoleMenu(List<SysRoleMenuDTO> source) {
+        List<SysRoleMenuPO> roleMenus = SysRoleMenuMapper.INSTANCE.toSysRoleMenuPOList(source);
+        Map<String, List<SysRoleMenuPO>> collect = roleMenus.stream()
+                .collect(Collectors.groupingBy(SysRoleMenuPO::getRoleId));
+        collect.forEach((k,relations)->{
+            baseMapper.delete(new LambdaQueryWrapper<SysRoleMenuPO>().eq(SysRoleMenuPO::getRoleId,k));
+            saveBatch(relations);
+            //清除角色缓存
+            menuService.delCache(k);
+        });
+    }
+}

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

@@ -0,0 +1,93 @@
+package cn.tr.module.sys.user.service.impl;
+
+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.sys.mapper.user.SysRoleMapper;
+import cn.tr.module.sys.user.dto.SysRoleDTO;
+import cn.tr.module.sys.user.dto.SysRoleQueryDTO;
+import cn.tr.module.sys.user.po.SysRolePO;
+import cn.tr.module.sys.user.repository.SysRoleRepository;
+import cn.tr.module.sys.user.service.ISysRoleService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * @ClassName : SysRoleServiceImpl
+ * @Description :
+ * @Author : LF
+ * @Date: 2023年03月31日
+ */
+@Service
+@AllArgsConstructor
+public class SysRoleServiceImpl implements ISysRoleService {
+    private final SysRoleRepository roleRepository;
+    @Override
+    public List<SysRoleDTO> selectSysRoleList(SysRoleQueryDTO query) {
+        return SysRoleMapper.INSTANCE.toSysRoleDTOList(roleRepository.selectList(new LambdaQueryWrapper<SysRolePO>()
+                .like(StrUtil.isNotEmpty(query.getRoleCode()),SysRolePO::getRoleCode,query.getRoleCode())
+                .like(StrUtil.isNotEmpty(query.getRoleName()),SysRolePO::getRoleName,query.getRoleName()).eq(SysRolePO::getType,query.getType()
+                ).like(ObjectUtil.isNotNull(query.getDisable()),SysRolePO::getDisable,query.getDisable())
+        ));
+    }
+
+    @Override
+    public SysRoleDTO selectSysRoleById(String id) {
+        return SysRoleMapper.INSTANCE.toSysRoleDTO(roleRepository.selectById(id));
+    }
+
+    @Override
+    public boolean updateSysRoleById(SysRoleDTO source) {
+        SysRolePO po = SysRoleMapper.INSTANCE.toSysRolePO(source);
+        validateRoleSource(po);
+        return roleRepository.updateById(po)!=0;
+    }
+
+    @Override
+    @Transactional
+    public boolean insertSysRole(SysRoleDTO source) {
+        SysRolePO po = SysRoleMapper.INSTANCE.toSysRolePO(source);
+        validateRoleSource(po);
+        return roleRepository.insert(po)!=0;
+    }
+
+    @Override
+    public int deleteSysRoleByIds(Collection<String> ids) {
+        //todo 校验
+        List<SysRolePO> role = roleRepository.selectBatchIds(ids);
+        Optional<SysRolePO> adminRole = role.stream()
+                .filter(po->Boolean.TRUE.equals(po.getAdmin()))
+                .findFirst();
+        if(adminRole.isPresent()){
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"管理员角色无法删除");
+        }
+        return roleRepository.deleteBatchIds(ids);
+    }
+
+    private void validateRoleSource(SysRolePO source){
+        SysRolePO role = roleRepository.selectOne(new LambdaQueryWrapper<SysRolePO>()
+                .eq(SysRolePO::getRoleName, source.getRoleName())
+                .eq(SysRolePO::getRoleCode, source.getRoleCode())
+                .last("limit 1"));
+        if(role!=null&& StrUtil.equals(role.getId(),source.getId())){
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("角色编码{%s}或角色名称{%s}不能重复",source.getRoleCode(),source.getRoleName()));
+        }
+        if(Boolean.TRUE.equals(source.getAdmin())){
+            role = roleRepository.selectOne(new LambdaQueryWrapper<SysRolePO>()
+                    .eq(SysRolePO::getAdmin, true)
+                    .last("limit 1"));
+            if(role!=null&& StrUtil.equals(role.getId(),source.getId())){
+                throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"管理员角色已存在,请勿重复添加");
+            }else if(role!=null){
+                throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,"管理员角色无法操作");
+            }
+        }
+    }
+}

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

@@ -1,5 +1,7 @@
 package cn.tr.module.sys.user.service.impl;
 
+import cn.hutool.core.collection.CollectionUtil;
+import cn.tr.core.annotation.TenantIgnore;
 import cn.tr.core.exception.ServiceException;
 import cn.tr.core.exception.TRExcCode;
 import cn.tr.core.utils.PswUtils;
@@ -10,7 +12,8 @@ import cn.tr.module.sys.user.service.ISysUserService;
 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.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import java.util.Arrays;
@@ -24,9 +27,14 @@ import java.util.List;
  * @Date: 2023年03月31日
  */
 @Service
-@AllArgsConstructor
 public class SysUserServiceImpl implements ISysUserService {
-    private final SysUserRepository userRepository;
+    @Autowired
+    private  SysUserRepository userRepository;
+
+    @Autowired
+    @Lazy
+    private ISysUserService userService;
+
     @Override
     public List<SysUserDTO> selectSysUserList(SysUserQueryDTO query) {
         return null;
@@ -71,18 +79,31 @@ public class SysUserServiceImpl implements ISysUserService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public boolean insertSysUser(SysUserDTO source) {
-        SysUserPO user = userRepository.selectUserIgnoreDelByUsername(source.getUsername());
-        if(user==null){
-            return userRepository.insert(user)!=0;
+        //所有租户下的正常使用的账号
+        List<SysUserDTO> allUsingUser = userService.selectUserByUsernameIgnoreTenant(source.getUsername());
+        if(CollectionUtil.isNotEmpty(allUsingUser)){
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("系统中已存在账户{%s},不可重复添加",source.getUsername()));
+        }
+        //当前租户下的账号
+        SysUserPO delUser = userRepository.selectUserByUsernameIgnoreDel(source.getUsername());
+        if(delUser==null){
+            return userRepository.insert(delUser)!=0;
         }
-        if(Boolean.TRUE.equals(user.getDeleted())){
-            userRepository.recoverBatch(Arrays.asList(user));
-            return userRepository.updateById(user)!=0;
+        if(Boolean.TRUE.equals(delUser.getDeleted())){
+            userRepository.recoverBatch(Arrays.asList(delUser));
+            return userRepository.updateById(delUser)!=0;
         }else {
-            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("账户{%s}已存在,不可重复添加",source.getUsername()));
+            throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001,String.format("当前租户中已存在账户{%s},不可重复添加",source.getUsername()));
         }
     }
 
+    @Override
+    @TenantIgnore
+    public List<SysUserDTO> selectUserByUsernameIgnoreTenant(String username) {
+        return SysUserMapper.INSTANCE.toUserDTOList(userRepository.selectList(new LambdaQueryWrapper<SysUserPO>()
+                .eq(SysUserPO::getUsername,username)));
+    }
+
     @Override
     @Transactional(rollbackFor = Exception.class)
     public int deleteSysUserByIds(Collection<String> ids) {

+ 13 - 0
tr-modules/tr-module-system/src/main/resources/mapper/user/SysMenuMapper.xml

@@ -0,0 +1,13 @@
+<?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="cn.tr.module.sys.user.repository.SysUserRepository">
+
+
+    <select id="selectUserByUsernameIgnoreDel" resultType="cn.tr.module.sys.user.po.SysUserPO">
+        select * from sys_user where username=#{username}
+    </select>
+
+
+</mapper>

+ 6 - 3
tr-modules/tr-module-system/src/main/resources/mapper/user/SysUserMapper.xml

@@ -2,11 +2,14 @@
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="cn.tr.module.sys.user.repository.SysUserRepository">
+<mapper namespace="cn.tr.module.sys.user.repository.SysMenuRepository">
 
 
-    <select id="selectUserIgnoreDelByUsername" resultType="cn.tr.module.sys.user.po.SysUserPO">
-        select * from sys_user where username=#{username}
+    <select id="findAllMenuByRoleId" resultType="cn.tr.module.sys.user.po.SysMenuPO" parameterType="java.lang.String">
+            select m.*
+            from (select * from sys_role where id=#{roleId}) as r
+            left join sys_role_menu  as rm on rm.role_id=r.id
+            left join sys_menu as m on m.id = rm.menu_id
     </select>
 
 

+ 0 - 2
tr-plugins/tr-spring-boot-starter-plugin-biz-excel/src/main/java/cn/tr/plugin/excel/annotation/Excel.java

@@ -1,7 +1,5 @@
 package cn.tr.plugin.excel.annotation;
 
-import cn.hutool.core.annotation.Alias;
-import cn.hutool.core.date.DatePattern;
 import cn.tr.plugin.excel.config.ExcelHandlerAdapter;
 import org.apache.poi.ss.usermodel.HorizontalAlignment;
 import org.apache.poi.ss.usermodel.IndexedColors;

+ 2 - 2
tr-plugins/tr-spring-boot-starter-plugin-biz-excel/src/main/java/cn/tr/plugin/excel/config/ExcelHandlerAdapter.java

@@ -5,8 +5,8 @@ package cn.tr.plugin.excel.config;
  * 
  * @author ruoyi
  */
-public interface ExcelHandlerAdapter
-{
+public interface
+ExcelHandlerAdapter {
     /**
      * 格式化
      * 

+ 4 - 0
tr-test/src/main/resources/application.yml

@@ -9,6 +9,10 @@ mybatis-plus:
   mapper-locations: classpath*:com/gitee/sunchenbin/mybatis/actable/mapping/*/*.xml,classpath*:mapper/*/*.xml
   configuration:
     log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+  global-config:
+    db-config:
+      logic-delete-value: 1
+      logic-delete-field: deleted
 spring:
   datasource:
     type: com.alibaba.druid.pool.DruidDataSource