Browse Source

Merge remote-tracking branch 'origin/dev' into 4.X

疯狂的狮子Li 1 year ago
parent
commit
e5661a2cf4
74 changed files with 398 additions and 269 deletions
  1. 1 1
      .run/ruoyi-monitor-admin.run.xml
  2. 1 1
      .run/ruoyi-server.run.xml
  3. 1 1
      .run/ruoyi-xxl-job-admin.run.xml
  4. 1 1
      README.md
  5. 9 9
      pom.xml
  6. 1 1
      ruoyi-admin/pom.xml
  7. 6 3
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
  8. 6 1
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
  9. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
  10. 9 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
  11. 2 2
      ruoyi-admin/src/main/resources/application-dev.yml
  12. 2 2
      ruoyi-admin/src/main/resources/application-prod.yml
  13. 3 5
      ruoyi-admin/src/main/resources/application.yml
  14. 1 1
      ruoyi-common/pom.xml
  15. 0 16
      ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
  16. 10 0
      ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
  17. 4 4
      ruoyi-common/src/main/java/com/ruoyi/common/core/mapper/BaseMapperPlus.java
  18. 6 20
      ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/AesEncryptor.java
  19. 3 3
      ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/Base64Encryptor.java
  20. 6 9
      ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/RsaEncryptor.java
  21. 6 9
      ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/Sm2Encryptor.java
  22. 6 18
      ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/Sm4Encryptor.java
  23. 15 14
      ruoyi-common/src/main/java/com/ruoyi/common/excel/ExcelDownHandler.java
  24. 68 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/EncryptUtils.java
  25. 0 3
      ruoyi-common/src/main/java/com/ruoyi/common/utils/StreamUtils.java
  26. 2 4
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
  27. 52 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/redis/QueueUtils.java
  28. 1 1
      ruoyi-demo/pom.xml
  29. 1 1
      ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java
  30. 3 3
      ruoyi-demo/src/main/java/com/ruoyi/demo/controller/queue/BoundedQueueController.java
  31. 3 3
      ruoyi-demo/src/main/java/com/ruoyi/demo/controller/queue/PriorityQueueController.java
  32. 1 1
      ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java
  33. 1 1
      ruoyi-extend/pom.xml
  34. 1 1
      ruoyi-extend/ruoyi-monitor-admin/pom.xml
  35. 1 1
      ruoyi-extend/ruoyi-xxl-job-admin/pom.xml
  36. 1 1
      ruoyi-framework/pom.xml
  37. 1 1
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/SaTokenConfig.java
  38. 2 1
      ruoyi-framework/src/main/java/com/ruoyi/framework/encrypt/MybatisDecryptInterceptor.java
  39. 2 1
      ruoyi-framework/src/main/java/com/ruoyi/framework/encrypt/MybatisEncryptInterceptor.java
  40. 16 6
      ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
  41. 1 1
      ruoyi-generator/pom.xml
  42. 2 2
      ruoyi-generator/src/main/resources/vm/java/vo.java.vm
  43. 1 1
      ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
  44. 1 1
      ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
  45. 1 1
      ruoyi-job/pom.xml
  46. 1 1
      ruoyi-oss/pom.xml
  47. 1 1
      ruoyi-sms/pom.xml
  48. 1 1
      ruoyi-system/pom.xml
  49. 4 2
      ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
  50. 5 1
      ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
  51. 2 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
  52. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
  53. 4 1
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
  54. 1 0
      ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
  55. 2 2
      ruoyi-ui-vue3/package.json
  56. 17 21
      ruoyi-ui-vue3/src/components/DictTag/index.vue
  57. 30 8
      ruoyi-ui-vue3/src/components/TopNav/index.vue
  58. 1 1
      ruoyi-ui-vue3/src/layout/components/Navbar.vue
  59. 2 2
      ruoyi-ui-vue3/src/layout/components/TagsView/index.vue
  60. 1 1
      ruoyi-ui-vue3/src/settings.js
  61. 1 1
      ruoyi-ui-vue3/src/views/index.vue
  62. 12 12
      ruoyi-ui-vue3/src/views/register.vue
  63. 4 4
      ruoyi-ui-vue3/src/views/system/dict/data.vue
  64. 1 1
      ruoyi-ui-vue3/src/views/system/user/profile/index.vue
  65. 2 2
      ruoyi-ui-vue3/vite/plugins/setup-extend.js
  66. 1 1
      ruoyi-ui/package.json
  67. 20 23
      ruoyi-ui/src/components/DictTag/index.vue
  68. 12 8
      ruoyi-ui/src/components/TopNav/index.vue
  69. 1 1
      ruoyi-ui/src/store/modules/dict.js
  70. 1 1
      ruoyi-ui/src/views/index.vue
  71. 2 2
      ruoyi-ui/src/views/system/dict/data.vue
  72. 1 1
      ruoyi-ui/src/views/system/user/profile/index.vue
  73. 0 5
      ruoyi-ui/src/views/system/user/profile/userAvatar.vue
  74. 4 4
      script/docker/docker-compose.yml

+ 1 - 1
.run/ruoyi-monitor-admin.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:4.8.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:4.8.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-server.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-server:4.8.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-server:4.8.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-xxl-job-admin.run.xml

@@ -2,7 +2,7 @@
   <configuration default="false" name="ruoyi-xxl-job-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
     <deployment type="dockerfile">
       <settings>
-        <option name="imageTag" value="ruoyi/ruoyi-xxl-job-admin:4.8.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-xxl-job-admin:4.8.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile" />
       </settings>

+ 1 - 1
README.md

@@ -10,7 +10,7 @@
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
 [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
 <br>
-[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.8.0-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.8.1-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
 [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.7-blue.svg)]()
 [![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]()
 [![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()

+ 9 - 9
pom.xml

@@ -6,15 +6,15 @@
 
     <groupId>com.ruoyi</groupId>
     <artifactId>ruoyi-vue-plus</artifactId>
-    <version>4.8.0</version>
+    <version>4.8.1</version>
 
     <name>RuoYi-Vue-Plus</name>
     <url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
     <description>RuoYi-Vue-Plus后台管理系统</description>
 
     <properties>
-        <ruoyi-vue-plus.version>4.8.0</ruoyi-vue-plus.version>
-        <spring-boot.version>2.7.13</spring-boot.version>
+        <ruoyi-vue-plus.version>4.8.1</ruoyi-vue-plus.version>
+        <spring-boot.version>2.7.16</spring-boot.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>
@@ -22,20 +22,20 @@
         <spring-boot.mybatis>2.2.2</spring-boot.mybatis>
         <springdoc.version>1.6.15</springdoc.version>
         <poi.version>5.2.3</poi.version>
-        <easyexcel.version>3.3.1</easyexcel.version>
+        <easyexcel.version>3.3.2</easyexcel.version>
         <velocity.version>2.3</velocity.version>
-        <satoken.version>1.35.0.RC</satoken.version>
-        <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
+        <satoken.version>1.36.0</satoken.version>
+        <mybatis-plus.version>3.5.3.2</mybatis-plus.version>
         <p6spy.version>3.9.1</p6spy.version>
-        <hutool.version>5.8.18</hutool.version>
+        <hutool.version>5.8.20</hutool.version>
         <okhttp.version>4.10.0</okhttp.version>
-        <spring-boot-admin.version>2.7.10</spring-boot-admin.version>
+        <spring-boot-admin.version>2.7.11</spring-boot-admin.version>
         <redisson.version>3.20.1</redisson.version>
         <lock4j.version>2.2.3</lock4j.version>
         <dynamic-ds.version>3.5.2</dynamic-ds.version>
         <alibaba-ttl.version>2.14.2</alibaba-ttl.version>
         <xxl-job.version>2.4.0</xxl-job.version>
-        <lombok.version>1.18.26</lombok.version>
+        <lombok.version>1.18.30</lombok.version>
         <bouncycastle.version>1.72</bouncycastle.version>
         <!-- 离线IP地址定位库 -->
         <ip2region.version>2.7.0</ip2region.version>

+ 1 - 1
ruoyi-admin/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>

+ 6 - 3
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java

@@ -91,9 +91,12 @@ public class SysDeptController extends BaseController {
             return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
         } else if (dept.getParentId().equals(deptId)) {
             return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
-        } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())
-            && deptService.selectNormalChildrenDeptById(deptId) > 0) {
-            return R.fail("该部门包含未停用的子部门!");
+        } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())) {
+            if (deptService.selectNormalChildrenDeptById(deptId) > 0) {
+                return R.fail("该部门包含未停用的子部门!");
+            } else if (deptService.checkDeptExistUser(deptId)) {
+                return R.fail("该部门下存在已分配用户,不能禁用!");
+            }
         }
         return toAjax(deptService.updateDept(dept));
     }

+ 6 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java

@@ -88,6 +88,9 @@ public class SysPostController extends BaseController {
             return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
         } else if (!postService.checkPostCodeUnique(post)) {
             return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
+        } else if (UserConstants.POST_DISABLE.equals(post.getStatus())
+            && postService.countUserPostById(post.getPostId()) > 0) {
+            return R.fail("该岗位下存在已分配用户,不能禁用!");
         }
         return toAjax(postService.updatePost(post));
     }
@@ -109,7 +112,9 @@ public class SysPostController extends BaseController {
      */
     @GetMapping("/optionselect")
     public R<List<SysPost>> optionselect() {
-        List<SysPost> posts = postService.selectPostAll();
+        SysPost post = new SysPost();
+        post.setStatus(UserConstants.POST_NORMAL);
+        List<SysPost> posts = postService.selectPostList(post);
         return R.ok(posts);
     }
 }

+ 2 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java

@@ -78,8 +78,8 @@ public class SysProfileController extends BaseController {
     /**
      * 重置密码
      *
-     * @param newPassword 密码
-     * @param oldPassword 密码
+     * @param newPassword 密码
+     * @param oldPassword 密码
      */
     @Log(title = "个人信息", businessType = BusinessType.UPDATE)
     @PutMapping("/updatePwd")

+ 9 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java

@@ -21,6 +21,7 @@ import com.ruoyi.common.helper.LoginHelper;
 import com.ruoyi.common.utils.StreamUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.system.domain.SysPost;
 import com.ruoyi.system.domain.vo.SysUserExportVo;
 import com.ruoyi.system.domain.vo.SysUserImportVo;
 import com.ruoyi.system.listener.SysUserImportListener;
@@ -117,9 +118,13 @@ public class SysUserController extends BaseController {
     public R<Map<String, Object>> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
         userService.checkUserDataScope(userId);
         Map<String, Object> ajax = new HashMap<>();
-        List<SysRole> roles = roleService.selectRoleAll();
+        SysRole role = new SysRole();
+        role.setStatus(UserConstants.ROLE_NORMAL);
+        SysPost post = new SysPost();
+        post.setStatus(UserConstants.POST_NORMAL);
+        List<SysRole> roles = roleService.selectRoleList(role);
         ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin()));
-        ajax.put("posts", postService.selectPostAll());
+        ajax.put("posts", postService.selectPostList(post));
         if (ObjectUtil.isNotNull(userId)) {
             SysUser sysUser = userService.selectUserById(userId);
             ajax.put("user", sysUser);
@@ -136,6 +141,7 @@ public class SysUserController extends BaseController {
     @Log(title = "用户管理", businessType = BusinessType.INSERT)
     @PostMapping
     public R<Void> add(@Validated @RequestBody SysUser user) {
+        deptService.checkDeptDataScope(user.getDeptId());
         if (!userService.checkUserNameUnique(user)) {
             return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
         } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
@@ -156,6 +162,7 @@ public class SysUserController extends BaseController {
     public R<Void> edit(@Validated @RequestBody SysUser user) {
         userService.checkUserAllowed(user);
         userService.checkUserDataScope(user.getUserId());
+        deptService.checkDeptDataScope(user.getDeptId());
         if (!userService.checkUserNameUnique(user)) {
             return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
         } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {

+ 2 - 2
ruoyi-admin/src/main/resources/application-dev.yml

@@ -19,8 +19,8 @@ xxl.job:
   executor:
     # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册
     appname: xxl-job-executor
-    # 执行器端口号 执行器从9101开始往后写
-    port: 9101
+    # 28080 端口 随着主应用端口飘逸 避免集群冲突
+    port: 2${server.port}
     # 执行器注册:默认IP:PORT
     address:
     # 执行器IP:默认自动获取IP

+ 2 - 2
ruoyi-admin/src/main/resources/application-prod.yml

@@ -22,8 +22,8 @@ xxl.job:
   executor:
     # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册
     appname: xxl-job-executor
-    # 执行器端口号 执行器从9101开始往后写
-    port: 9101
+    # 28080 端口 随着主应用端口飘逸 避免集群冲突
+    port: 2${server.port}
     # 执行器注册:默认IP:PORT
     address:
     # 执行器IP:默认自动获取IP

+ 3 - 5
ruoyi-admin/src/main/resources/application.yml

@@ -5,11 +5,7 @@ ruoyi:
   # 版本
   version: ${ruoyi-vue-plus.version}
   # 版权年份
-  copyrightYear: 2022
-  # 实例演示开关
-  demoEnabled: true
-  # 获取ip地址开关
-  addressEnabled: true
+  copyrightYear: 2023
   # 缓存懒加载
   cacheLazy: false
 
@@ -107,6 +103,8 @@ sa-token:
   # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义
   # token最低活跃时间 (指定时间无操作就过期) 单位: 秒
   active-timeout: 1800
+  # 允许动态设置 token 有效期
+  dynamic-active-timeout: true
   # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
   is-concurrent: true
   # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)

+ 1 - 1
ruoyi-common/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 0 - 16
ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java

@@ -1,7 +1,6 @@
 package com.ruoyi.common.config;
 
 import lombok.Data;
-import lombok.Getter;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 
@@ -32,23 +31,8 @@ public class RuoYiConfig {
     private String copyrightYear;
 
     /**
-     * 实例演示开关
-     */
-    private boolean demoEnabled;
-
-    /**
      * 缓存懒加载
      */
     private boolean cacheLazy;
 
-    /**
-     * 获取地址开关
-     */
-    @Getter
-    private static boolean addressEnabled;
-
-    public void setAddressEnabled(boolean addressEnabled) {
-        RuoYiConfig.addressEnabled = addressEnabled;
-    }
-
 }

+ 10 - 0
ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java

@@ -53,6 +53,16 @@ public interface UserConstants {
     String DEPT_DISABLE = "1";
 
     /**
+     * 岗位正常状态
+     */
+    String POST_NORMAL = "0";
+
+    /**
+     * 岗位停用状态
+     */
+    String POST_DISABLE = "1";
+
+    /**
      * 字典正常状态
      */
     String DICT_NORMAL = "0";

+ 4 - 4
ruoyi-common/src/main/java/com/ruoyi/common/core/mapper/BaseMapperPlus.java

@@ -180,12 +180,12 @@ public interface BaseMapperPlus<M, T, V> extends BaseMapper<T> {
      * 分页查询VO
      */
     default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
-        IPage<T> pageData = this.selectPage(page, wrapper);
-        IPage<C> voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
-        if (CollUtil.isEmpty(pageData.getRecords())) {
+        List<T> list = this.selectList(page, wrapper);
+        IPage<C> voPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
+        if (CollUtil.isEmpty(list)) {
             return (P) voPage;
         }
-        voPage.setRecords(BeanCopyUtils.copyList(pageData.getRecords(), voClass));
+        voPage.setRecords(BeanCopyUtils.copyList(list, voClass));
         return (P) voPage;
     }
 

+ 6 - 20
ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/AesEncryptor.java

@@ -1,14 +1,9 @@
 package com.ruoyi.common.encrypt.encryptor;
 
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.symmetric.AES;
 import com.ruoyi.common.encrypt.EncryptContext;
 import com.ruoyi.common.enums.AlgorithmType;
 import com.ruoyi.common.enums.EncodeType;
-
-import java.nio.charset.StandardCharsets;
+import com.ruoyi.common.utils.EncryptUtils;
 
 /**
  * AES算法实现
@@ -18,20 +13,11 @@ import java.nio.charset.StandardCharsets;
  */
 public class AesEncryptor extends AbstractEncryptor {
 
-    private final AES aes;
+    private final EncryptContext context;
 
     public AesEncryptor(EncryptContext context) {
         super(context);
-        String password = context.getPassword();
-        if (StrUtil.isBlank(password)) {
-            throw new IllegalArgumentException("AES没有获得秘钥信息");
-        }
-        // aes算法的秘钥要求是16位、24位、32位
-        int[] array = {16, 24, 32};
-        if (!ArrayUtil.contains(array, password.length())) {
-            throw new IllegalArgumentException("AES秘钥长度应该为16位、24位、32位,实际为" + password.length() + "位");
-        }
-        aes = SecureUtil.aes(context.getPassword().getBytes(StandardCharsets.UTF_8));
+        this.context = context;
     }
 
     /**
@@ -51,9 +37,9 @@ public class AesEncryptor extends AbstractEncryptor {
     @Override
     public String encrypt(String value, EncodeType encodeType) {
         if (encodeType == EncodeType.HEX) {
-            return aes.encryptHex(value);
+            return EncryptUtils.encryptByAesHex(value, context.getPassword());
         } else {
-            return aes.encryptBase64(value);
+            return EncryptUtils.encryptByAes(value, context.getPassword());
         }
     }
 
@@ -64,6 +50,6 @@ public class AesEncryptor extends AbstractEncryptor {
      */
     @Override
     public String decrypt(String value) {
-        return this.aes.decryptStr(value);
+        return EncryptUtils.decryptByAes(value, context.getPassword());
     }
 }

+ 3 - 3
ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/Base64Encryptor.java

@@ -1,9 +1,9 @@
 package com.ruoyi.common.encrypt.encryptor;
 
-import cn.hutool.core.codec.Base64;
 import com.ruoyi.common.encrypt.EncryptContext;
 import com.ruoyi.common.enums.AlgorithmType;
 import com.ruoyi.common.enums.EncodeType;
+import com.ruoyi.common.utils.EncryptUtils;
 
 /**
  * Base64算法实现
@@ -33,7 +33,7 @@ public class Base64Encryptor extends AbstractEncryptor {
      */
     @Override
     public String encrypt(String value, EncodeType encodeType) {
-        return Base64.encode(value);
+        return EncryptUtils.encryptByBase64(value);
     }
 
     /**
@@ -43,6 +43,6 @@ public class Base64Encryptor extends AbstractEncryptor {
      */
     @Override
     public String decrypt(String value) {
-        return Base64.decodeStr(value);
+        return EncryptUtils.decryptByBase64(value);
     }
 }

+ 6 - 9
ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/RsaEncryptor.java

@@ -1,12 +1,9 @@
 package com.ruoyi.common.encrypt.encryptor;
 
-import cn.hutool.core.codec.Base64;
-import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
 import com.ruoyi.common.encrypt.EncryptContext;
 import com.ruoyi.common.enums.AlgorithmType;
 import com.ruoyi.common.enums.EncodeType;
+import com.ruoyi.common.utils.EncryptUtils;
 import com.ruoyi.common.utils.StringUtils;
 
 
@@ -18,7 +15,7 @@ import com.ruoyi.common.utils.StringUtils;
  */
 public class RsaEncryptor extends AbstractEncryptor {
 
-    private final RSA rsa;
+    private final EncryptContext context;
 
     public RsaEncryptor(EncryptContext context) {
         super(context);
@@ -27,7 +24,7 @@ public class RsaEncryptor extends AbstractEncryptor {
         if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
             throw new IllegalArgumentException("RSA公私钥均需要提供,公钥加密,私钥解密。");
         }
-        this.rsa = SecureUtil.rsa(Base64.decode(privateKey), Base64.decode(publicKey));
+        this.context = context;
     }
 
     /**
@@ -47,9 +44,9 @@ public class RsaEncryptor extends AbstractEncryptor {
     @Override
     public String encrypt(String value, EncodeType encodeType) {
         if (encodeType == EncodeType.HEX) {
-            return rsa.encryptHex(value, KeyType.PublicKey);
+            return EncryptUtils.encryptByRsaHex(value, context.getPublicKey());
         } else {
-            return rsa.encryptBase64(value, KeyType.PublicKey);
+            return EncryptUtils.encryptByRsa(value, context.getPublicKey());
         }
     }
 
@@ -60,6 +57,6 @@ public class RsaEncryptor extends AbstractEncryptor {
      */
     @Override
     public String decrypt(String value) {
-        return this.rsa.decryptStr(value, KeyType.PrivateKey);
+        return EncryptUtils.decryptByRsa(value, context.getPrivateKey());
     }
 }

+ 6 - 9
ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/Sm2Encryptor.java

@@ -1,13 +1,10 @@
 package com.ruoyi.common.encrypt.encryptor;
 
 
-import cn.hutool.core.codec.Base64;
-import cn.hutool.crypto.SmUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.SM2;
 import com.ruoyi.common.encrypt.EncryptContext;
 import com.ruoyi.common.enums.AlgorithmType;
 import com.ruoyi.common.enums.EncodeType;
+import com.ruoyi.common.utils.EncryptUtils;
 import com.ruoyi.common.utils.StringUtils;
 
 /**
@@ -18,7 +15,7 @@ import com.ruoyi.common.utils.StringUtils;
  */
 public class Sm2Encryptor extends AbstractEncryptor {
 
-    private final SM2 sm2;
+    private final EncryptContext context;
 
     public Sm2Encryptor(EncryptContext context) {
         super(context);
@@ -27,7 +24,7 @@ public class Sm2Encryptor extends AbstractEncryptor {
         if (StringUtils.isAnyEmpty(privateKey, publicKey)) {
             throw new IllegalArgumentException("SM2公私钥均需要提供,公钥加密,私钥解密。");
         }
-        this.sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
+        this.context = context;
     }
 
     /**
@@ -47,9 +44,9 @@ public class Sm2Encryptor extends AbstractEncryptor {
     @Override
     public String encrypt(String value, EncodeType encodeType) {
         if (encodeType == EncodeType.HEX) {
-            return sm2.encryptHex(value, KeyType.PublicKey);
+            return EncryptUtils.encryptBySm2Hex(value, context.getPublicKey());
         } else {
-            return sm2.encryptBase64(value, KeyType.PublicKey);
+            return EncryptUtils.encryptBySm2(value, context.getPublicKey());
         }
     }
 
@@ -60,6 +57,6 @@ public class Sm2Encryptor extends AbstractEncryptor {
      */
     @Override
     public String decrypt(String value) {
-        return this.sm2.decryptStr(value, KeyType.PrivateKey);
+        return EncryptUtils.decryptBySm2(value, context.getPrivateKey());
     }
 }

+ 6 - 18
ruoyi-common/src/main/java/com/ruoyi/common/encrypt/encryptor/Sm4Encryptor.java

@@ -1,13 +1,9 @@
 package com.ruoyi.common.encrypt.encryptor;
 
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.SmUtil;
-import cn.hutool.crypto.symmetric.SM4;
 import com.ruoyi.common.encrypt.EncryptContext;
 import com.ruoyi.common.enums.AlgorithmType;
 import com.ruoyi.common.enums.EncodeType;
-
-import java.nio.charset.StandardCharsets;
+import com.ruoyi.common.utils.EncryptUtils;
 
 /**
  * sm4算法实现
@@ -17,19 +13,11 @@ import java.nio.charset.StandardCharsets;
  */
 public class Sm4Encryptor extends AbstractEncryptor {
 
-    private final SM4 sm4;
+    private final EncryptContext context;
 
     public Sm4Encryptor(EncryptContext context) {
         super(context);
-        String password = context.getPassword();
-        if (StrUtil.isBlank(password)) {
-            throw new IllegalArgumentException("SM4没有获得秘钥信息");
-        }
-        // sm4算法的秘钥要求是16位长度
-        if (16 != password.length()) {
-            throw new IllegalArgumentException("SM4秘钥长度应该为16位,实际为" + password.length() + "位");
-        }
-        this.sm4 = SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8));
+        this.context = context;
     }
 
     /**
@@ -49,9 +37,9 @@ public class Sm4Encryptor extends AbstractEncryptor {
     @Override
     public String encrypt(String value, EncodeType encodeType) {
         if (encodeType == EncodeType.HEX) {
-            return sm4.encryptHex(value);
+            return EncryptUtils.encryptBySm4Hex(value, context.getPassword());
         } else {
-            return sm4.encryptBase64(value);
+            return EncryptUtils.encryptBySm4(value, context.getPassword());
         }
     }
 
@@ -62,6 +50,6 @@ public class Sm4Encryptor extends AbstractEncryptor {
      */
     @Override
     public String decrypt(String value) {
-        return this.sm4.decryptStr(value);
+        return EncryptUtils.decryptBySm4(value, context.getPassword());
     }
 }

+ 15 - 14
ruoyi-common/src/main/java/com/ruoyi/common/excel/ExcelDownHandler.java

@@ -5,7 +5,9 @@ import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.EnumUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
-import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.FieldCache;
+import com.alibaba.excel.metadata.FieldWrapper;
+import com.alibaba.excel.util.ClassUtils;
 import com.alibaba.excel.write.handler.SheetWriteHandler;
 import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
 import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
@@ -83,16 +85,18 @@ public class ExcelDownHandler implements SheetWriteHandler {
         Sheet sheet = writeSheetHolder.getSheet();
         // 开始设置下拉框 HSSFWorkbook
         DataValidationHelper helper = sheet.getDataValidationHelper();
-        Field[] fields = writeWorkbookHolder.getClazz().getDeclaredFields();
         Workbook workbook = writeWorkbookHolder.getWorkbook();
-        int length = fields.length;
-        for (int i = 0; i < length; i++) {
+        FieldCache fieldCache = ClassUtils.declaredFields(writeWorkbookHolder.getClazz(), writeWorkbookHolder);
+        for (Map.Entry<Integer, FieldWrapper> entry : fieldCache.getSortedFieldMap().entrySet()) {
+            Integer index = entry.getKey();
+            FieldWrapper wrapper = entry.getValue();
+            Field field = wrapper.getField();
             // 循环实体中的每个属性
             // 可选的下拉值
             List<String> options = new ArrayList<>();
-            if (fields[i].isAnnotationPresent(ExcelDictFormat.class)) {
+            if (field.isAnnotationPresent(ExcelDictFormat.class)) {
                 // 如果指定了@ExcelDictFormat,则使用字典的逻辑
-                ExcelDictFormat format = fields[i].getDeclaredAnnotation(ExcelDictFormat.class);
+                ExcelDictFormat format = field.getDeclaredAnnotation(ExcelDictFormat.class);
                 String dictType = format.dictType();
                 String converterExp = format.readConverterExp();
                 if (StrUtil.isNotBlank(dictType)) {
@@ -105,20 +109,14 @@ public class ExcelDownHandler implements SheetWriteHandler {
                     // 如果指定了确切的值,则直接解析确切的值
                     options = StrUtil.split(converterExp, format.separator(), true, true);
                 }
-            } else if (fields[i].isAnnotationPresent(ExcelEnumFormat.class)) {
+            } else if (field.isAnnotationPresent(ExcelEnumFormat.class)) {
                 // 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑
-                ExcelEnumFormat format = fields[i].getDeclaredAnnotation(ExcelEnumFormat.class);
+                ExcelEnumFormat format = field.getDeclaredAnnotation(ExcelEnumFormat.class);
                 List<Object> values = EnumUtil.getFieldValues(format.enumClass(), format.textField());
                 options = StreamUtils.toList(values, String::valueOf);
             }
             if (ObjectUtil.isNotEmpty(options)) {
                 // 仅当下拉可选项不为空时执行
-                // 获取列下标,默认为当前循环次数
-                int index = i;
-                if (fields[i].isAnnotationPresent(ExcelProperty.class)) {
-                    // 如果指定了列下标,以指定的为主
-                    index = fields[i].getDeclaredAnnotation(ExcelProperty.class).index();
-                }
                 if (options.size() > 20) {
                     // 这里限制如果可选项大于20,则使用额外表形式
                     dropDownWithSheet(helper, workbook, sheet, index, options);
@@ -128,6 +126,9 @@ public class ExcelDownHandler implements SheetWriteHandler {
                 }
             }
         }
+        if (CollUtil.isEmpty(dropDownOptions)) {
+            return;
+        }
         dropDownOptions.forEach(everyOptions -> {
             // 如果传递了下拉框选择器参数
             if (!everyOptions.getNextOptions().isEmpty()) {

+ 68 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/EncryptUtils.java

@@ -68,6 +68,25 @@ public class EncryptUtils {
     }
 
     /**
+     * AES加密
+     *
+     * @param data     待解密数据
+     * @param password 秘钥字符串
+     * @return 加密后字符串, 采用Hex编码
+     */
+    public static String encryptByAesHex(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("AES需要传入秘钥信息");
+        }
+        // aes算法的秘钥要求是16位、24位、32位
+        int[] array = {16, 24, 32};
+        if (!ArrayUtil.contains(array, password.length())) {
+            throw new IllegalArgumentException("AES秘钥长度要求为16位、24位、32位");
+        }
+        return SecureUtil.aes(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8);
+    }
+
+    /**
      * AES解密
      *
      * @param data     待解密数据
@@ -106,6 +125,25 @@ public class EncryptUtils {
     }
 
     /**
+     * sm4加密
+     *
+     * @param data     待加密数据
+     * @param password 秘钥字符串
+     * @return 加密后字符串, 采用Base64编码
+     */
+    public static String encryptBySm4Hex(String data, String password) {
+        if (StrUtil.isBlank(password)) {
+            throw new IllegalArgumentException("SM4需要传入秘钥信息");
+        }
+        // sm4算法的秘钥要求是16位长度
+        int sm4PasswordLength = 16;
+        if (sm4PasswordLength != password.length()) {
+            throw new IllegalArgumentException("SM4秘钥长度要求为16位");
+        }
+        return SmUtil.sm4(password.getBytes(StandardCharsets.UTF_8)).encryptHex(data, StandardCharsets.UTF_8);
+    }
+
+    /**
      * sm4解密
      *
      * @param data     待解密数据
@@ -153,6 +191,21 @@ public class EncryptUtils {
     }
 
     /**
+     * sm2公钥加密
+     *
+     * @param data      待加密数据
+     * @param publicKey 公钥
+     * @return 加密后字符串, 采用Hex编码
+     */
+    public static String encryptBySm2Hex(String data, String publicKey) {
+        if (StrUtil.isBlank(publicKey)) {
+            throw new IllegalArgumentException("SM2需要传入公钥进行加密");
+        }
+        SM2 sm2 = SmUtil.sm2(null, publicKey);
+        return sm2.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey);
+    }
+
+    /**
      * sm2私钥解密
      *
      * @param data       待加密数据
@@ -196,6 +249,21 @@ public class EncryptUtils {
     }
 
     /**
+     * rsa公钥加密
+     *
+     * @param data      待加密数据
+     * @param publicKey 公钥
+     * @return 加密后字符串, 采用Hex编码
+     */
+    public static String encryptByRsaHex(String data, String publicKey) {
+        if (StrUtil.isBlank(publicKey)) {
+            throw new IllegalArgumentException("RSA需要传入公钥进行加密");
+        }
+        RSA rsa = SecureUtil.rsa(null, publicKey);
+        return rsa.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey);
+    }
+
+    /**
      * rsa私钥解密
      *
      * @param data       待加密数据

+ 0 - 3
ruoyi-common/src/main/java/com/ruoyi/common/utils/StreamUtils.java

@@ -30,7 +30,6 @@ public class StreamUtils {
         if (CollUtil.isEmpty(collection)) {
             return CollUtil.newArrayList();
         }
-        // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
         return collection.stream().filter(function).collect(Collectors.toList());
     }
 
@@ -71,7 +70,6 @@ public class StreamUtils {
         if (CollUtil.isEmpty(collection)) {
             return CollUtil.newArrayList();
         }
-        // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
         return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
     }
 
@@ -190,7 +188,6 @@ public class StreamUtils {
             .stream()
             .map(function)
             .filter(Objects::nonNull)
-            // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
             .collect(Collectors.toList());
     }
 

+ 2 - 4
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java

@@ -196,10 +196,8 @@ public class ExcelUtil {
             // 合并处理器
             builder.registerWriteHandler(new CellMergeStrategy(list, true));
         }
-        if (CollUtil.isNotEmpty(options)) {
-            // 添加下拉框操作
-            builder.registerWriteHandler(new ExcelDownHandler(options));
-        }
+        // 添加下拉框操作
+        builder.registerWriteHandler(new ExcelDownHandler(options));
         builder.doWrite(list);
     }
 

+ 52 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/redis/QueueUtils.java

@@ -132,6 +132,32 @@ public class QueueUtils {
     }
 
     /**
+     * 优先队列获取一个队列数据 没有数据返回 null(不支持延迟队列)
+     *
+     * @param queueName 队列名
+     */
+    public static <T> T getPriorityQueueObject(String queueName) {
+        RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
+        return queue.poll();
+    }
+
+    /**
+     * 优先队列删除队列数据(不支持延迟队列)
+     */
+    public static <T> boolean removePriorityQueueObject(String queueName, T data) {
+        RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
+        return queue.remove(data);
+    }
+
+    /**
+     * 优先队列销毁队列 所有阻塞监听 报错(不支持延迟队列)
+     */
+    public static <T> boolean destroyPriorityQueue(String queueName) {
+        RPriorityBlockingQueue<T> queue = CLIENT.getPriorityBlockingQueue(queueName);
+        return queue.delete();
+    }
+
+    /**
      * 尝试设置 有界队列 容量 用于限制数量
      *
      * @param queueName 队列名
@@ -170,6 +196,32 @@ public class QueueUtils {
     }
 
     /**
+     * 有界队列获取一个队列数据 没有数据返回 null(不支持延迟队列)
+     *
+     * @param queueName 队列名
+     */
+    public static <T> T getBoundedQueueObject(String queueName) {
+        RBoundedBlockingQueue<T> queue = CLIENT.getBoundedBlockingQueue(queueName);
+        return queue.poll();
+    }
+
+    /**
+     * 有界队列删除队列数据(不支持延迟队列)
+     */
+    public static <T> boolean removeBoundedQueueObject(String queueName, T data) {
+        RBoundedBlockingQueue<T> queue = CLIENT.getBoundedBlockingQueue(queueName);
+        return queue.remove(data);
+    }
+
+    /**
+     * 有界队列销毁队列 所有阻塞监听 报错(不支持延迟队列)
+     */
+    public static <T> boolean destroyBoundedQueue(String queueName) {
+        RBoundedBlockingQueue<T> queue = CLIENT.getBoundedBlockingQueue(queueName);
+        return queue.delete();
+    }
+
+    /**
      * 订阅阻塞队列(可订阅所有实现类 例如: 延迟 优先 有界 等)
      */
     public static <T> void subscribeBlockingQueue(String queueName, Consumer<T> consumer) {

+ 1 - 1
ruoyi-demo/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/RedisCacheController.java

@@ -34,7 +34,7 @@ public class RedisCacheController {
      * 如果没有,就调用方法,然后把结果缓存起来
      * 这个注解「一般用在查询方法上」
      * <p>
-     * 重点说明: 缓存注解严与其他筛选数据功能一起使用
+     * 重点说明: 缓存注解严与其他筛选数据功能一起使用
      * 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题
      * <p>
      * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数

+ 3 - 3
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/queue/BoundedQueueController.java

@@ -35,7 +35,7 @@ public class BoundedQueueController {
     @GetMapping("/add")
     public R<Void> add(String queueName, int capacity) {
         // 用完了一定要销毁 否则会一直存在
-        boolean b = QueueUtils.destroyQueue(queueName);
+        boolean b = QueueUtils.destroyBoundedQueue(queueName);
         log.info("通道: {} , 删除: {}", queueName, b);
         // 初始化设置一次即可
         if (QueueUtils.trySetBoundedQueueCapacity(queueName, capacity)) {
@@ -64,7 +64,7 @@ public class BoundedQueueController {
     @GetMapping("/remove")
     public R<Void> remove(String queueName) {
         String data = "data-" + 5;
-        if (QueueUtils.removeQueueObject(queueName, data)) {
+        if (QueueUtils.removeBoundedQueueObject(queueName, data)) {
             log.info("通道: {} , 删除数据: {}", queueName, data);
         } else {
             return R.fail("操作失败");
@@ -81,7 +81,7 @@ public class BoundedQueueController {
     public R<Void> get(String queueName) {
         String data;
         do {
-            data = QueueUtils.getQueueObject(queueName);
+            data = QueueUtils.getBoundedQueueObject(queueName);
             log.info("通道: {} , 获取数据: {}", queueName, data);
         } while (data != null);
         return R.ok("操作成功");

+ 3 - 3
ruoyi-demo/src/main/java/com/ruoyi/demo/controller/queue/PriorityQueueController.java

@@ -34,7 +34,7 @@ public class PriorityQueueController {
     @GetMapping("/add")
     public R<Void> add(String queueName) {
         // 用完了一定要销毁 否则会一直存在
-        boolean b = QueueUtils.destroyQueue(queueName);
+        boolean b = QueueUtils.destroyPriorityQueue(queueName);
         log.info("通道: {} , 删除: {}", queueName, b);
 
         for (int i = 0; i < 10; i++) {
@@ -63,7 +63,7 @@ public class PriorityQueueController {
         PriorityDemo data = new PriorityDemo();
         data.setName(name);
         data.setOrderNum(orderNum);
-        if (QueueUtils.removeQueueObject(queueName, data)) {
+        if (QueueUtils.removePriorityQueueObject(queueName, data)) {
             log.info("通道: {} , 删除数据: {}", queueName, data);
         } else {
             return R.fail("操作失败");
@@ -80,7 +80,7 @@ public class PriorityQueueController {
     public R<Void> get(String queueName) {
         PriorityDemo data;
         do {
-            data = QueueUtils.getQueueObject(queueName);
+            data = QueueUtils.getPriorityQueueObject(queueName);
             log.info("通道: {} , 获取数据: {}", queueName, data);
         } while (data != null);
         return R.ok("操作成功");

+ 1 - 1
ruoyi-demo/src/main/java/com/ruoyi/demo/mapper/TestDemoMapper.java

@@ -33,7 +33,7 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemoMapper, TestDemo,
         @DataColumn(key = "deptName", value = "dept_id"),
         @DataColumn(key = "userName", value = "user_id")
     })
-    <P extends IPage<TestDemo>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
+    List<TestDemo> selectList(IPage<TestDemo> page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
 
     @Override
     @DataPermission({

+ 1 - 1
ruoyi-extend/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>ruoyi-extend</artifactId>

+ 1 - 1
ruoyi-extend/ruoyi-monitor-admin/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-extend</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>

+ 1 - 1
ruoyi-extend/ruoyi-xxl-job-admin/pom.xml

@@ -4,7 +4,7 @@
     <parent>
         <artifactId>ruoyi-extend</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <artifactId>ruoyi-xxl-job-admin</artifactId>
     <packaging>jar</packaging>

+ 1 - 1
ruoyi-framework/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SaTokenConfig.java

@@ -51,7 +51,7 @@ public class SaTokenConfig implements WebMvcConfigurer {
                     // 有效率影响 用于临时测试
                     // if (log.isDebugEnabled()) {
                     //     log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout());
-                    //     log.debug("临时有效时间: {}", StpUtil.getTokenActivityTimeout());
+                    //     log.debug("临时有效时间: {}", StpUtil.getTokenActiveTimeout());
                     // }
 
                 });

+ 2 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/encrypt/MybatisDecryptInterceptor.java

@@ -1,6 +1,7 @@
 package com.ruoyi.framework.encrypt;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.ObjectUtil;
 import com.ruoyi.common.annotation.EncryptField;
 import com.ruoyi.common.encrypt.EncryptContext;
@@ -76,7 +77,7 @@ public class MybatisDecryptInterceptor implements Interceptor {
         Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass());
         try {
             for (Field field : fields) {
-                field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field));
+                field.set(sourceObject, this.decryptField(Convert.toStr(field.get(sourceObject)), field));
             }
         } catch (Exception e) {
             log.error("处理解密字段时出错", e);

+ 2 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/encrypt/MybatisEncryptInterceptor.java

@@ -1,6 +1,7 @@
 package com.ruoyi.framework.encrypt;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.ObjectUtil;
 import com.ruoyi.common.annotation.EncryptField;
 import com.ruoyi.common.encrypt.EncryptContext;
@@ -86,7 +87,7 @@ public class MybatisEncryptInterceptor implements Interceptor {
         Set<Field> fields = encryptorManager.getFieldCache(sourceObject.getClass());
         try {
             for (Field field : fields) {
-                field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field));
+                field.set(sourceObject, this.encryptField(Convert.toStr(field.get(sourceObject)), field));
             }
         } catch (Exception e) {
             log.error("处理加密字段时出错", e);

+ 16 - 6
ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java

@@ -8,6 +8,7 @@ import cn.hutool.http.HttpStatus;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.exception.DemoModeException;
 import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.exception.base.BaseException;
 import com.ruoyi.common.utils.StreamUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.mybatis.spring.MyBatisSystemException;
@@ -105,18 +106,27 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(ServiceException.class)
     public R<Void> handleServiceException(ServiceException e, HttpServletRequest request) {
-        log.error(e.getMessage(), e);
+        log.error(e.getMessage());
         Integer code = e.getCode();
         return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
     }
 
     /**
+     * 业务异常
+     */
+    @ExceptionHandler(BaseException.class)
+    public R<Void> handleBaseException(BaseException e, HttpServletRequest request) {
+        log.error(e.getMessage());
+        return R.fail(e.getMessage());
+    }
+
+    /**
      * 请求路径中缺少必需的路径变量
      */
     @ExceptionHandler(MissingPathVariableException.class)
     public R<Void> handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) {
         String requestURI = request.getRequestURI();
-        log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
+        log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI);
         return R.fail(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
     }
 
@@ -126,7 +136,7 @@ public class GlobalExceptionHandler {
     @ExceptionHandler(MethodArgumentTypeMismatchException.class)
     public R<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
         String requestURI = request.getRequestURI();
-        log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
+        log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI);
         return R.fail(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
     }
 
@@ -155,7 +165,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(BindException.class)
     public R<Void> handleBindException(BindException e) {
-        log.error(e.getMessage(), e);
+        log.error(e.getMessage());
         String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ", ");
         return R.fail(message);
     }
@@ -165,7 +175,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(ConstraintViolationException.class)
     public R<Void> constraintViolationException(ConstraintViolationException e) {
-        log.error(e.getMessage(), e);
+        log.error(e.getMessage());
         String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ", ");
         return R.fail(message);
     }
@@ -175,7 +185,7 @@ public class GlobalExceptionHandler {
      */
     @ExceptionHandler(MethodArgumentNotValidException.class)
     public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
-        log.error(e.getMessage(), e);
+        log.error(e.getMessage());
         String message = e.getBindingResult().getFieldError().getDefaultMessage();
         return R.fail(message);
     }

+ 1 - 1
ruoyi-generator/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

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

@@ -10,7 +10,7 @@ import com.ruoyi.common.convert.ExcelDictConvert;
 import lombok.Data;
 import java.util.Date;
 
-
+import java.io.Serializable;
 
 /**
  * ${functionName}视图对象 ${tableName}
@@ -20,7 +20,7 @@ import java.util.Date;
  */
 @Data
 @ExcelIgnoreUnannotated
-public class ${ClassName}Vo {
+public class ${ClassName}Vo implements Serializable {
 
     private static final long serialVersionUID = 1L;
 

+ 1 - 1
ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm

@@ -434,7 +434,7 @@ export default {
       this.reset();
       this.getTreeselect();
       if (row != null && row.${treeCode}) {
-        this.form.${treeParentCode} = row.${treeCode};
+        this.form.${treeParentCode} = row.${treeParentCode};
       } else {
         this.form.${treeParentCode} = 0;
       }

+ 1 - 1
ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm

@@ -398,7 +398,7 @@ function handleAdd(row) {
   reset();
   getTreeselect();
   if (row != null && row.${treeCode}) {
-    form.value.${treeParentCode} = row.${treeCode};
+    form.value.${treeParentCode} = row.${treeParentCode};
   } else {
     form.value.${treeParentCode} = 0;
   }

+ 1 - 1
ruoyi-job/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>

+ 1 - 1
ruoyi-oss/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
ruoyi-sms/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
ruoyi-system/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.8.0</version>
+        <version>4.8.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 4 - 2
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java

@@ -19,7 +19,8 @@ import java.util.List;
 public interface SysRoleMapper extends BaseMapperPlus<SysRoleMapper, SysRole, SysRole> {
 
     @DataPermission({
-        @DataColumn(key = "deptName", value = "d.dept_id")
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "us.user_id")
     })
     Page<SysRole> selectPageRoleList(@Param("page") Page<SysRole> page, @Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
 
@@ -30,7 +31,8 @@ public interface SysRoleMapper extends BaseMapperPlus<SysRoleMapper, SysRole, Sy
      * @return 角色数据集合信息
      */
     @DataPermission({
-        @DataColumn(key = "deptName", value = "d.dept_id")
+        @DataColumn(key = "deptName", value = "d.dept_id"),
+        @DataColumn(key = "userName", value = "us.user_id")
     })
     List<SysRole> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
 

+ 5 - 1
ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java

@@ -143,9 +143,13 @@ public class SysLoginService {
     public void logout() {
         try {
             LoginUser loginUser = LoginHelper.getLoginUser();
-            StpUtil.logout();
             recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
         } catch (NotLoginException ignored) {
+        } finally {
+            try {
+                StpUtil.logout();
+            } catch (NotLoginException ignored) {
+            }
         }
     }
 

+ 2 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java

@@ -72,6 +72,8 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
      */
     @Override
     public List<Tree<Long>> selectDeptTreeList(SysDept dept) {
+        // 只查询未禁用部门
+        dept.setStatus(UserConstants.DEPT_NORMAL);
         List<SysDept> depts = this.selectDeptList(dept);
         return buildDeptTreeSelect(depts);
     }

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java

@@ -147,7 +147,7 @@ public class SysPostServiceImpl implements ISysPostService {
         for (Long postId : postIds) {
             SysPost post = selectPostById(postId);
             if (countUserPostById(postId) > 0) {
-                throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName()));
+                throw new ServiceException(String.format("%1$s已分配,不能删除!", post.getPostName()));
             }
         }
         return baseMapper.deleteBatchIds(Arrays.asList(postIds));

+ 4 - 1
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java

@@ -268,6 +268,9 @@ public class SysRoleServiceImpl implements ISysRoleService {
      */
     @Override
     public int updateRoleStatus(SysRole role) {
+        if (UserConstants.ROLE_DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) {
+            throw new ServiceException("角色已分配,不能禁用!");
+        }
         return baseMapper.updateById(role);
     }
 
@@ -360,7 +363,7 @@ public class SysRoleServiceImpl implements ISysRoleService {
             checkRoleAllowed(role);
             checkRoleDataScope(roleId);
             if (countUserRoleByRoleId(roleId) > 0) {
-                throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName()));
+                throw new ServiceException(String.format("%1$s已分配,不能删除!", role.getRoleName()));
             }
         }
         List<Long> ids = Arrays.asList(roleIds);

+ 1 - 0
ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml

@@ -36,6 +36,7 @@
         from sys_role r
                  left join sys_user_role sur on sur.role_id = r.role_id
                  left join sys_user u on u.user_id = sur.user_id
+                 left join sys_user us on us.user_name = r.create_by
                  left join sys_dept d on u.dept_id = d.dept_id
     </sql>
 

+ 2 - 2
ruoyi-ui-vue3/package.json

@@ -1,6 +1,6 @@
 {
   "name": "ruoyi-vue-plus",
-  "version": "4.8.0",
+  "version": "4.8.1",
   "description": "RuoYi-Vue-Plus后台管理系统",
   "author": "LionLi",
   "license": "MIT",
@@ -38,6 +38,6 @@
     "vite": "3.2.3",
     "vite-plugin-compression": "0.5.1",
     "vite-plugin-svg-icons": "2.0.1",
-    "vite-plugin-vue-setup-extend": "0.4.0"
+    "unplugin-vue-setup-extend-plus": "0.4.9"
   }
 }

+ 17 - 21
ruoyi-ui-vue3/src/components/DictTag/index.vue

@@ -3,7 +3,7 @@
     <template v-for="(item, index) in options">
       <template v-if="values.includes(item.value)">
         <span
-          v-if="item.elTagType == 'default' || item.elTagType == ''"
+          v-if="(item.elTagType == 'default' || item.elTagType == '') && (item.elTagClass == '' || item.elTagClass == null)"
           :key="item.value"
           :index="index"
           :class="item.elTagClass"
@@ -41,34 +41,30 @@ const props = defineProps({
     type: Boolean,
     default: true,
   },
+  separator: {
+    type: String,
+    default: ",",
+  }
 });
 
 const values = computed(() => {
-  if (props.value !== null && typeof props.value !== 'undefined') {
-    return Array.isArray(props.value) ? props.value : [String(props.value)];
-  } else {
-    return [];
-  }
+  if (props.value === null || typeof props.value === 'undefined' || props.value === '') return [];
+  return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator);
 });
 
 const unmatch = computed(() => {
   unmatchArray.value = [];
-  if (props.value !== null && typeof props.value !== "undefined") {
-    // 传入值为非数组
-    if (!Array.isArray(props.value)) {
-      if (props.options.some((v) => v.value == props.value)) return false;
-      unmatchArray.value.push(props.value);
-      return true;
-    }
-    // 传入值为Array
-    props.value.forEach((item) => {
-      if (!props.options.some((v) => v.value == item))
-        unmatchArray.value.push(item);
-    });
-    return true;
-  }
   // 没有value不显示
-  return false;
+  if (props.value === null || typeof props.value === 'undefined' || props.value === '' || props.options.length === 0) return false
+  // 传入值为数组
+  let unmatch = false // 添加一个标志来判断是否有未匹配项
+  values.value.forEach(item => {
+    if (!props.options.some(v => v.value === item)) {
+      unmatchArray.value.push(item)
+      unmatch = true // 如果有未匹配项,将标志设置为true
+    }
+  })
+  return unmatch // 返回标志的值
 });
 
 function handleArray(array) {

+ 30 - 8
ruoyi-ui-vue3/src/components/TopNav/index.vue

@@ -6,10 +6,12 @@
     :ellipsis="false"
   >
     <template v-for="(item, index) in topMenus">
-      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
-        ><svg-icon :icon-class="item.meta.icon" />
-        {{ item.meta.title }}</el-menu-item
-      >
+      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber">
+        <svg-icon
+        v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
+        :icon-class="item.meta.icon"/>
+        {{ item.meta.title }}
+      </el-menu-item>
     </template>
 
     <!-- 顶部菜单超出数量折叠 -->
@@ -19,10 +21,12 @@
         <el-menu-item
           :index="item.path"
           :key="index"
-          v-if="index >= visibleNumber"
-          ><svg-icon :icon-class="item.meta.icon" />
-          {{ item.meta.title }}</el-menu-item
-        >
+          v-if="index >= visibleNumber">
+        <svg-icon
+          v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
+          :icon-class="item.meta.icon"/>
+        {{ item.meta.title }}
+        </el-menu-item>
       </template>
     </el-sub-menu>
   </el-menu>
@@ -189,4 +193,22 @@ onMounted(() => {
   padding: 0 5px !important;
   margin: 0 10px !important;
 }
+
+/* 背景色隐藏 */
+.topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus, .topmenu-container.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover, .topmenu-container.el-menu--horizontal>.el-submenu .el-submenu__title:hover {
+  background-color: #ffffff !important;
+}
+
+/* 图标右间距 */
+.topmenu-container .svg-icon {
+  margin-right: 4px;
+}
+
+/* topmenu more arrow */
+.topmenu-container .el-sub-menu .el-sub-menu__icon-arrow {
+  position: static;
+  vertical-align: middle;
+  margin-left: 8px;
+  margin-top: 0px;
+}
 </style>

+ 1 - 1
ruoyi-ui-vue3/src/layout/components/Navbar.vue

@@ -33,7 +33,7 @@
               <router-link to="/user/profile">
                 <el-dropdown-item>个人中心</el-dropdown-item>
               </router-link>
-              <el-dropdown-item command="setLayout">
+              <el-dropdown-item command="setLayout" v-if="settingsStore.showSettings">
                 <span>布局设置</span>
               </el-dropdown-item>
               <el-dropdown-item divided command="logout">

+ 2 - 2
ruoyi-ui-vue3/src/layout/components/TagsView/index.vue

@@ -280,7 +280,7 @@ function handleScroll() {
           height: 8px;
           border-radius: 50%;
           position: relative;
-          margin-right: 2px;
+          margin-right: 5px;
         }
       }
     }
@@ -335,4 +335,4 @@ function handleScroll() {
     }
   }
 }
-</style>
+</style>

+ 1 - 1
ruoyi-ui-vue3/src/settings.js

@@ -10,7 +10,7 @@ export default {
   /**
    * 是否系统布局配置
    */
-  showSettings: false,
+  showSettings: true,
 
   /**
    * 是否显示顶部导航

+ 1 - 1
ruoyi-ui-vue3/src/views/index.vue

@@ -103,7 +103,7 @@
 </template>
 
 <script setup name="Index">
-const version = ref('4.8.0')
+const version = ref('4.8.1')
 
 function goTarget(url) {
   window.open(url, '__blank')

+ 12 - 12
ruoyi-ui-vue3/src/views/register.vue

@@ -3,11 +3,11 @@
     <el-form ref="registerRef" :model="registerForm" :rules="registerRules" class="register-form">
       <h3 class="title">RuoYi-Vue-Plus后台管理系统</h3>
       <el-form-item prop="username">
-        <el-input 
-          v-model="registerForm.username" 
-          type="text" 
-          size="large" 
-          auto-complete="off" 
+        <el-input
+          v-model="registerForm.username"
+          type="text"
+          size="large"
+          auto-complete="off"
           placeholder="账号"
         >
           <template #prefix><svg-icon icon-class="user" class="el-input__icon input-icon" /></template>
@@ -17,7 +17,7 @@
         <el-input
           v-model="registerForm.password"
           type="password"
-          size="large" 
+          size="large"
           auto-complete="off"
           placeholder="密码"
           @keyup.enter="handleRegister"
@@ -29,7 +29,7 @@
         <el-input
           v-model="registerForm.confirmPassword"
           type="password"
-          size="large" 
+          size="large"
           auto-complete="off"
           placeholder="确认密码"
           @keyup.enter="handleRegister"
@@ -39,7 +39,7 @@
       </el-form-item>
       <el-form-item prop="code" v-if="captchaEnabled">
         <el-input
-          size="large" 
+          size="large"
           v-model="registerForm.code"
           auto-complete="off"
           placeholder="验证码"
@@ -55,7 +55,7 @@
       <el-form-item style="width:100%;">
         <el-button
           :loading="loading"
-          size="large" 
+          size="large"
           type="primary"
           style="width:100%;"
           @click.prevent="handleRegister"
@@ -143,10 +143,10 @@ function handleRegister() {
 
 function getCode() {
   getCodeImg().then(res => {
-    captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled;
+    captchaEnabled.value = res.data.captchaEnabled === undefined ? true : res.data.captchaEnabled;
     if (captchaEnabled.value) {
-      codeUrl.value = "data:image/gif;base64," + res.img;
-      registerForm.value.uuid = res.uuid;
+      codeUrl.value = "data:image/gif;base64," + res.data.img;
+      registerForm.value.uuid = res.data.uuid;
     }
   });
 }

+ 4 - 4
ruoyi-ui-vue3/src/views/system/dict/data.vue

@@ -91,8 +91,8 @@
          <el-table-column label="字典编码" align="center" prop="dictCode" />
          <el-table-column label="字典标签" align="center" prop="dictLabel">
             <template #default="scope">
-               <span v-if="scope.row.listClass == '' || scope.row.listClass == 'default'">{{ scope.row.dictLabel }}</span>
-               <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass">{{ scope.row.dictLabel }}</el-tag>
+              <span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
+              <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
             </template>
          </el-table-column>
          <el-table-column label="字典键值" align="center" prop="dictValue" />
@@ -197,8 +197,8 @@ const typeOptions = ref([]);
 const route = useRoute();
 // 数据标签回显样式
 const listClassOptions = ref([
-  { value: "default", label: "默认" }, 
-  { value: "primary", label: "主要" }, 
+  { value: "default", label: "默认" },
+  { value: "primary", label: "主要" },
   { value: "success", label: "成功" },
   { value: "info", label: "信息" },
   { value: "warning", label: "警告" },

+ 1 - 1
ruoyi-ui-vue3/src/views/system/user/profile/index.vue

@@ -10,7 +10,7 @@
                </template>
                <div>
                   <div class="text-center">
-                     <userAvatar :user="state.user" />
+                     <userAvatar />
                   </div>
                   <ul class="list-group list-group-striped">
                      <li class="list-group-item">

+ 2 - 2
ruoyi-ui-vue3/vite/plugins/setup-extend.js

@@ -1,5 +1,5 @@
-import setupExtend from 'vite-plugin-vue-setup-extend'
+import setupExtend from 'unplugin-vue-setup-extend-plus/vite'
 
 export default function createSetupExtend() {
-    return setupExtend()
+    return setupExtend({})
 }

+ 1 - 1
ruoyi-ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "ruoyi-vue-plus",
-  "version": "4.8.0",
+  "version": "4.8.1",
   "description": "RuoYi-Vue-Plus后台管理系统",
   "author": "LionLi",
   "license": "MIT",

+ 20 - 23
ruoyi-ui/src/components/DictTag/index.vue

@@ -3,7 +3,7 @@
     <template v-for="(item, index) in options">
       <template v-if="values.includes(item.value)">
         <span
-          v-if="item.raw.listClass == 'default' || item.raw.listClass == ''"
+          v-if="(item.raw.listClass == 'default' || item.raw.listClass == '') && (item.raw.cssClass == '' || item.raw.cssClass == null)"
           :key="item.value"
           :index="index"
           :class="item.raw.cssClass"
@@ -40,6 +40,10 @@ export default {
     showValue: {
       type: Boolean,
       default: true,
+    },
+    separator: {
+      type: String,
+      default: ","
     }
   },
   data() {
@@ -49,35 +53,28 @@ export default {
   },
   computed: {
     values() {
-      if (this.value !== null && typeof this.value !== 'undefined') {
-        return Array.isArray(this.value) ? this.value : [String(this.value)];
-      } else {
-        return [];
-      }
+      if (this.value === null || typeof this.value === 'undefined' || this.value === '') return []
+      return Array.isArray(this.value) ? this.value.map(item => '' + item) : String(this.value).split(this.separator)
     },
-    unmatch(){
-      this.unmatchArray = [];
-      if (this.value !== null && typeof this.value !== 'undefined') {
-        // 传入值为非数组
-        if(!Array.isArray(this.value)){
-          if(this.options.some(v=> v.value == this.value )) return false;
-          this.unmatchArray.push(this.value);
-          return true;
-        }
-        // 传入值为Array
-        this.value.forEach(item => {
-          if (!this.options.some(v=> v.value == item )) this.unmatchArray.push(item)
-        });
-        return true;
-      }
+    unmatch() {
+      this.unmatchArray = []
       // 没有value不显示
-      return false;
+      if (this.value === null || typeof this.value === 'undefined' || this.value === '' || this.options.length === 0) return false
+      // 传入值为数组
+      let unmatch = false // 添加一个标志来判断是否有未匹配项
+      this.values.forEach(item => {
+        if (!this.options.some(v => v.value === item)) {
+          this.unmatchArray.push(item)
+          unmatch = true // 如果有未匹配项,将标志设置为true
+        }
+      })
+      return unmatch // 返回标志的值
     },
 
   },
   filters: {
     handleArray(array) {
-      if(array.length===0) return '';
+      if (array.length === 0) return '';
       return array.reduce((pre, cur) => {
         return pre + ' ' + cur;
       })

+ 12 - 8
ruoyi-ui/src/components/TopNav/index.vue

@@ -5,10 +5,12 @@
     @select="handleSelect"
   >
     <template v-for="(item, index) in topMenus">
-      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
-        ><svg-icon :icon-class="item.meta.icon" />
-        {{ item.meta.title }}</el-menu-item
-      >
+      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber">
+        <svg-icon
+        v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
+        :icon-class="item.meta.icon"/>
+        {{ item.meta.title }}
+      </el-menu-item>
     </template>
 
     <!-- 顶部菜单超出数量折叠 -->
@@ -18,10 +20,12 @@
         <el-menu-item
           :index="item.path"
           :key="index"
-          v-if="index >= visibleNumber"
-          ><svg-icon :icon-class="item.meta.icon" />
-          {{ item.meta.title }}</el-menu-item
-        >
+          v-if="index >= visibleNumber">
+          <svg-icon
+            v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
+            :icon-class="item.meta.icon"/>
+          {{ item.meta.title }}
+        </el-menu-item>
       </template>
     </el-submenu>
   </el-menu>

+ 1 - 1
ruoyi-ui/src/store/modules/dict.js

@@ -14,7 +14,7 @@ const mutations = {
     try {
       for (let i = 0; i < state.dict.length; i++) {
         if (state.dict[i].key == key) {
-          state.dict.splice(i, i)
+          state.dict.splice(i, 1)
           return true
         }
       }

+ 1 - 1
ruoyi-ui/src/views/index.vue

@@ -114,7 +114,7 @@ export default {
   data() {
     return {
       // 版本号
-      version: "4.8.0",
+      version: "4.8.1",
     };
   },
   methods: {

+ 2 - 2
ruoyi-ui/src/views/system/dict/data.vue

@@ -95,8 +95,8 @@
       <el-table-column label="字典编码" align="center" prop="dictCode" />
       <el-table-column label="字典标签" align="center" prop="dictLabel">
         <template slot-scope="scope">
-          <span v-if="scope.row.listClass == '' || scope.row.listClass == 'default'">{{scope.row.dictLabel}}</span>
-          <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass">{{scope.row.dictLabel}}</el-tag>
+          <span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
+          <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
         </template>
       </el-table-column>
       <el-table-column label="字典键值" align="center" prop="dictValue" />

+ 1 - 1
ruoyi-ui/src/views/system/user/profile/index.vue

@@ -8,7 +8,7 @@
           </div>
           <div>
             <div class="text-center">
-              <userAvatar :user="user" />
+              <userAvatar />
             </div>
             <ul class="list-group list-group-striped">
               <li class="list-group-item">

+ 0 - 5
ruoyi-ui/src/views/system/user/profile/userAvatar.vue

@@ -61,11 +61,6 @@ import { debounce } from '@/utils'
 
 export default {
   components: { VueCropper },
-  props: {
-    user: {
-      type: Object
-    }
-  },
   data() {
     return {
       // 是否显示弹出层

+ 4 - 4
script/docker/docker-compose.yml

@@ -100,7 +100,7 @@ services:
     network_mode: "host"
 
   ruoyi-server1:
-    image: ruoyi/ruoyi-server:4.8.0
+    image: ruoyi/ruoyi-server:4.8.1
     container_name: ruoyi-server1
     environment:
       # 时区上海
@@ -115,7 +115,7 @@ services:
     network_mode: "host"
 
   ruoyi-server2:
-    image: "ruoyi/ruoyi-server:4.8.0"
+    image: "ruoyi/ruoyi-server:4.8.1"
     container_name: ruoyi-server2
     environment:
       # 时区上海
@@ -130,7 +130,7 @@ services:
     network_mode: "host"
 
   ruoyi-monitor-admin:
-    image: ruoyi/ruoyi-monitor-admin:4.8.0
+    image: ruoyi/ruoyi-monitor-admin:4.8.1
     container_name: ruoyi-monitor-admin
     environment:
       # 时区上海
@@ -142,7 +142,7 @@ services:
     network_mode: "host"
 
   ruoyi-xxl-job-admin:
-    image: ruoyi/ruoyi-xxl-job-admin:4.8.0
+    image: ruoyi/ruoyi-xxl-job-admin:4.8.1
     container_name: ruoyi-xxl-job-admin
     environment:
       # 时区上海