Selaa lähdekoodia

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

疯狂的狮子li 2 vuotta sitten
vanhempi
commit
0208fa14af
61 muutettua tiedostoa jossa 295 lisäystä ja 159 poistoa
  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. 23 13
      pom.xml
  6. 1 1
      ruoyi-admin/pom.xml
  7. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
  8. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
  9. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
  10. 10 13
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
  11. 0 1
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
  12. 2 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
  13. 4 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
  14. 1 1
      ruoyi-admin/src/main/resources/application.yml
  15. 2 0
      ruoyi-admin/src/main/resources/spy.properties
  16. 1 1
      ruoyi-common/pom.xml
  17. 4 0
      ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
  18. 42 16
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/PageQuery.java
  19. 4 4
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
  20. 0 1
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
  21. 1 1
      ruoyi-demo/pom.xml
  22. 1 1
      ruoyi-extend/pom.xml
  23. 1 1
      ruoyi-extend/ruoyi-monitor-admin/pom.xml
  24. 1 1
      ruoyi-extend/ruoyi-xxl-job-admin/pom.xml
  25. 1 1
      ruoyi-framework/pom.xml
  26. 1 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
  27. 7 7
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/SaTokenConfig.java
  28. 7 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/ExcludeUrlProperties.java
  29. 13 4
      ruoyi-framework/src/main/java/com/ruoyi/framework/listener/UserActionListener.java
  30. 2 3
      ruoyi-framework/src/main/java/com/ruoyi/framework/satoken/dao/PlusSaTokenDao.java
  31. 1 1
      ruoyi-generator/pom.xml
  32. 1 1
      ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt
  33. 2 1
      ruoyi-job/pom.xml
  34. 1 1
      ruoyi-oss/pom.xml
  35. 1 1
      ruoyi-sms/pom.xml
  36. 1 1
      ruoyi-system/pom.xml
  37. 2 0
      ruoyi-system/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java
  38. 2 2
      ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
  39. 2 2
      ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
  40. 4 4
      ruoyi-system/src/main/java/com/ruoyi/system/service/SysRegisterService.java
  41. 3 2
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
  42. 3 2
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
  43. 2 4
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
  44. 2 1
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOssServiceImpl.java
  45. 5 3
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
  46. 3 3
      ruoyi-ui/package.json
  47. 12 3
      ruoyi-ui/src/App.vue
  48. 3 2
      ruoyi-ui/src/assets/styles/ruoyi.scss
  49. 5 11
      ruoyi-ui/src/components/FileUpload/index.vue
  50. 3 2
      ruoyi-ui/src/utils/request.js
  51. 1 1
      ruoyi-ui/src/views/index.vue
  52. 1 1
      ruoyi-ui/src/views/monitor/logininfor/index.vue
  53. 1 1
      ruoyi-ui/src/views/monitor/operlog/index.vue
  54. 60 3
      ruoyi-ui/src/views/system/oss/index.vue
  55. 2 2
      ruoyi-ui/src/views/system/user/index.vue
  56. 20 7
      ruoyi-ui/src/views/system/user/profile/userAvatar.vue
  57. 5 5
      ruoyi-ui/src/views/tool/gen/editTable.vue
  58. 5 5
      script/docker/docker-compose.yml
  59. 1 1
      script/sql/update/oracle/update-4.2-4.3.sql
  60. 1 1
      script/sql/update/postgres/update-4.2-4.3.sql
  61. 1 1
      script/sql/update/update-4.2-4.3.sql

+ 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.3.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:4.3.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
       </settings>

+ 1 - 1
.run/ruoyi-admin.run.xml → .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.3.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-server:4.3.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.3.0" />
+        <option name="imageTag" value="ruoyi/ruoyi-xxl-job-admin:4.3.1" />
         <option name="buildOnly" value="true" />
         <option name="sourceFilePath" value="ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile" />
       </settings>

+ 1 - 1
README.md

@@ -4,7 +4,7 @@
 [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/JavaLionLi/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.3.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.3.1-success.svg)](https://gitee.com/JavaLionLi/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)]()

+ 23 - 13
pom.xml

@@ -6,46 +6,48 @@
 
     <groupId>com.ruoyi</groupId>
     <artifactId>ruoyi-vue-plus</artifactId>
-    <version>4.3.0</version>
+    <version>4.3.1</version>
 
     <name>RuoYi-Vue-Plus</name>
     <url>https://gitee.com/JavaLionLi/RuoYi-Vue-Plus</url>
     <description>RuoYi-Vue-Plus后台管理系统</description>
 
     <properties>
-        <ruoyi-vue-plus.version>4.3.0</ruoyi-vue-plus.version>
-        <spring-boot.version>2.7.3</spring-boot.version>
+        <ruoyi-vue-plus.version>4.3.1</ruoyi-vue-plus.version>
+        <spring-boot.version>2.7.5</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>
         <maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
         <spring-boot.mybatis>2.2.2</spring-boot.mybatis>
         <druid.version>1.2.12</druid.version>
-        <springdoc.version>1.6.11</springdoc.version>
-        <poi.version>5.2.2</poi.version>
+        <springdoc.version>1.6.12</springdoc.version>
+        <poi.version>5.2.3</poi.version>
         <easyexcel.version>3.1.1</easyexcel.version>
         <velocity.version>2.3</velocity.version>
-        <satoken.version>1.30.0</satoken.version>
+        <satoken.version>1.31.0</satoken.version>
         <mybatis-plus.version>3.5.2</mybatis-plus.version>
         <p6spy.version>3.9.1</p6spy.version>
-        <hutool.version>5.8.6</hutool.version>
+        <hutool.version>5.8.8</hutool.version>
         <okhttp.version>4.10.0</okhttp.version>
-        <spring-boot-admin.version>2.7.4</spring-boot-admin.version>
-        <redisson.version>3.17.6</redisson.version>
+        <spring-boot-admin.version>2.7.6</spring-boot-admin.version>
+        <redisson.version>3.17.7</redisson.version>
         <lock4j.version>2.2.2</lock4j.version>
         <dynamic-ds.version>3.5.2</dynamic-ds.version>
-        <tlog.version>1.4.3</tlog.version>
+        <tlog.version>1.5.0</tlog.version>
         <xxl-job.version>2.3.1</xxl-job.version>
         <lombok.version>1.18.24</lombok.version>
 
         <!-- 统一 guava 版本 解决隐式漏洞问题 -->
         <guava.version>31.1-jre</guava.version>
+        <!-- 临时修复 snakeyaml 漏洞 -->
+        <snakeyaml.version>1.32</snakeyaml.version>
 
         <!-- OSS 配置 -->
-        <aws-java-sdk-s3.version>1.12.300</aws-java-sdk-s3.version>
+        <aws-java-sdk-s3.version>1.12.324</aws-java-sdk-s3.version>
         <!-- SMS 配置 -->
-        <aliyun.sms.version>2.0.18</aliyun.sms.version>
-        <tencent.sms.version>3.1.591</tencent.sms.version>
+        <aliyun.sms.version>2.0.22</aliyun.sms.version>
+        <tencent.sms.version>3.1.611</tencent.sms.version>
     </properties>
 
     <!-- 依赖声明 -->
@@ -254,6 +256,13 @@
                 <version>${guava.version}</version>
             </dependency>
 
+            <!-- 临时修复 snakeyaml 漏洞 -->
+            <dependency>
+                <groupId>org.yaml</groupId>
+                <artifactId>snakeyaml</artifactId>
+                <version>${snakeyaml.version}</version>
+            </dependency>
+
             <!-- 定时任务 -->
             <dependency>
                 <groupId>com.ruoyi</groupId>
@@ -434,3 +443,4 @@
 
 </project>
 
+

+ 1 - 1
ruoyi-admin/pom.xml

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

+ 2 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java

@@ -1,11 +1,11 @@
 package com.ruoyi.web.controller.common;
 
+import cn.dev33.satoken.annotation.SaIgnore;
 import cn.hutool.captcha.AbstractCaptcha;
 import cn.hutool.captcha.generator.CodeGenerator;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.core.util.RandomUtil;
-import com.ruoyi.common.annotation.Anonymous;
 import com.ruoyi.common.constant.CacheConstants;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.domain.R;
@@ -35,7 +35,7 @@ import java.util.Map;
  *
  * @author Lion Li
  */
-@Anonymous
+@SaIgnore
 @Slf4j
 @Validated
 @RequiredArgsConstructor

+ 2 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java

@@ -42,12 +42,12 @@ public class SysUserOnlineController extends BaseController {
     @GetMapping("/list")
     public TableDataInfo<SysUserOnline> list(String ipaddr, String userName) {
         // 获取所有未过期的 token
-        List<String> keys = StpUtil.searchTokenValue("", -1, 0);
+        List<String> keys = StpUtil.searchTokenValue("", -1, 0, false);
         List<UserOnlineDTO> userOnlineDTOList = new ArrayList<>();
         for (String key : keys) {
             String token = key.replace(CacheConstants.LOGIN_TOKEN_KEY, "");
             // 如果已经过期则跳过
-            if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < 0) {
+            if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < -1) {
                 continue;
             }
             userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token));

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

@@ -1,6 +1,6 @@
 package com.ruoyi.web.controller.system;
 
-import com.ruoyi.common.annotation.Anonymous;
+import cn.dev33.satoken.annotation.SaIgnore;
 import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.utils.StringUtils;
 import lombok.RequiredArgsConstructor;
@@ -24,7 +24,7 @@ public class SysIndexController {
     /**
      * 访问首页,提示语
      */
-    @Anonymous
+    @SaIgnore
     @GetMapping("/")
     public String index() {
         return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());

+ 10 - 13
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java

@@ -1,11 +1,12 @@
 package com.ruoyi.web.controller.system;
 
-import com.ruoyi.common.annotation.Anonymous;
+import cn.dev33.satoken.annotation.SaIgnore;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.core.domain.entity.SysMenu;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginBody;
+import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.core.domain.model.SmsLoginBody;
 import com.ruoyi.common.helper.LoginHelper;
 import com.ruoyi.system.domain.vo.RouterVo;
@@ -24,7 +25,6 @@ import javax.validation.constraints.NotBlank;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * 登录验证
@@ -47,7 +47,7 @@ public class SysLoginController {
      * @param loginBody 登录信息
      * @return 结果
      */
-    @Anonymous
+    @SaIgnore
     @PostMapping("/login")
     public R<Map<String, Object>> login(@Validated @RequestBody LoginBody loginBody) {
         Map<String, Object> ajax = new HashMap<>();
@@ -64,7 +64,7 @@ public class SysLoginController {
      * @param smsLoginBody 登录信息
      * @return 结果
      */
-    @Anonymous
+    @SaIgnore
     @PostMapping("/smsLogin")
     public R<Map<String, Object>> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) {
         Map<String, Object> ajax = new HashMap<>();
@@ -80,7 +80,7 @@ public class SysLoginController {
      * @param xcxCode 小程序code
      * @return 结果
      */
-    @Anonymous
+    @SaIgnore
     @PostMapping("/xcxLogin")
     public R<Map<String, Object>> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) {
         Map<String, Object> ajax = new HashMap<>();
@@ -93,7 +93,7 @@ public class SysLoginController {
     /**
      * 退出登录
      */
-    @Anonymous
+    @SaIgnore
     @PostMapping("/logout")
     public R<Void> logout() {
         loginService.logout();
@@ -107,15 +107,12 @@ public class SysLoginController {
      */
     @GetMapping("getInfo")
     public R<Map<String, Object>> getInfo() {
-        SysUser user = userService.selectUserById(LoginHelper.getUserId());
-        // 角色集合
-        Set<String> roles = permissionService.getRolePermission(user);
-        // 权限集合
-        Set<String> permissions = permissionService.getMenuPermission(user);
+        LoginUser loginUser = LoginHelper.getLoginUser();
+        SysUser user = userService.selectUserById(loginUser.getUserId());
         Map<String, Object> ajax = new HashMap<>();
         ajax.put("user", user);
-        ajax.put("roles", roles);
-        ajax.put("permissions", permissions);
+        ajax.put("roles", loginUser.getRolePermission());
+        ajax.put("permissions", loginUser.getMenuPermission());
         return R.ok(ajax);
     }
 

+ 0 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java

@@ -100,7 +100,6 @@ public class SysOssController extends BaseController {
         if (ObjectUtil.isNull(sysOss)) {
             throw new ServiceException("文件数据不存在!");
         }
-        response.reset();
         FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
         response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
         long data;

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

@@ -1,6 +1,6 @@
 package com.ruoyi.web.controller.system;
 
-import com.ruoyi.common.annotation.Anonymous;
+import cn.dev33.satoken.annotation.SaIgnore;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.R;
 import com.ruoyi.common.core.domain.model.RegisterBody;
@@ -28,7 +28,7 @@ public class SysRegisterController extends BaseController {
     /**
      * 用户注册
      */
-    @Anonymous
+    @SaIgnore
     @PostMapping("/register")
     public R<Void> register(@Validated @RequestBody RegisterBody user) {
         if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {

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

@@ -136,7 +136,7 @@ public class SysUserController extends BaseController {
     @Log(title = "用户管理", businessType = BusinessType.INSERT)
     @PostMapping
     public R<Void> add(@Validated @RequestBody SysUser user) {
-        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName()))) {
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) {
             return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
         } else if (StringUtils.isNotEmpty(user.getPhonenumber())
             && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
@@ -158,7 +158,9 @@ public class SysUserController extends BaseController {
     public R<Void> edit(@Validated @RequestBody SysUser user) {
         userService.checkUserAllowed(user);
         userService.checkUserDataScope(user.getUserId());
-        if (StringUtils.isNotEmpty(user.getPhonenumber())
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) {
+            return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
+        } else if (StringUtils.isNotEmpty(user.getPhonenumber())
             && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
             return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
         } else if (StringUtils.isNotEmpty(user.getEmail())

+ 1 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -108,7 +108,7 @@ sa-token:
   # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
   is-share: false
   # 是否尝试从header里读取token
-  is-read-head: true
+  is-read-header: true
   # 是否尝试从cookie里读取token
   is-read-cookie: false
   # token前缀

+ 2 - 0
ruoyi-admin/src/main/resources/spy.properties

@@ -14,6 +14,8 @@ useprefix=true
 excludecategories=info,debug,result,commit,resultset
 # 日期格式
 dateformat=yyyy-MM-dd HH:mm:ss
+# SQL语句打印时间格式
+databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
 # 实际驱动可多个
 #driverlist=org.h2.Driver
 # 是否开启慢SQL记录

+ 1 - 1
ruoyi-common/pom.xml

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

+ 4 - 0
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java

@@ -1,5 +1,7 @@
 package com.ruoyi.common.annotation;
 
+import cn.dev33.satoken.annotation.SaIgnore;
+
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -10,7 +12,9 @@ import java.lang.annotation.Target;
  * 匿名访问不鉴权注解
  *
  * @author ruoyi
+ * @deprecated 将在后续版本使用Sa-Token注解 {@link SaIgnore} 代替
  */
+@Deprecated
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented

+ 42 - 16
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/PageQuery.java

@@ -1,13 +1,17 @@
 package com.ruoyi.common.core.domain;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.baomidou.mybatisplus.core.metadata.OrderItem;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.sql.SqlUtil;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * 分页查询实体类
@@ -57,30 +61,52 @@ public class PageQuery implements Serializable {
             pageNum = DEFAULT_PAGE_NUM;
         }
         Page<T> page = new Page<>(pageNum, pageSize);
-        OrderItem orderItem = buildOrderItem();
-        if (ObjectUtil.isNotNull(orderItem)) {
-            page.addOrder(orderItem);
+        List<OrderItem> orderItems = buildOrderItem();
+        if (CollUtil.isNotEmpty(orderItems)) {
+            page.addOrder(orderItems);
         }
         return page;
     }
 
-    private OrderItem buildOrderItem() {
+    /**
+     * 构建排序
+     *
+     * 支持的用法如下:
+     * {isAsc:"asc",orderByColumn:"id"} order by id asc
+     * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc
+     * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc
+     * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc
+     */
+    private List<OrderItem> buildOrderItem() {
+        if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) {
+            return null;
+        }
+        String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
+        orderBy = StringUtils.toUnderScoreCase(orderBy);
+
         // 兼容前端排序类型
-        if ("ascending".equals(isAsc)) {
-            isAsc = "asc";
-        } else if ("descending".equals(isAsc)) {
-            isAsc = "desc";
+        isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"});
+
+        String[] orderByArr = orderBy.split(",");
+        String[] isAscArr = isAsc.split(",");
+        if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) {
+            throw new ServiceException("排序参数有误");
         }
-        if (StringUtils.isNotBlank(orderByColumn)) {
-            String orderBy = SqlUtil.escapeOrderBySql(orderByColumn);
-            orderBy = StringUtils.toUnderScoreCase(orderBy);
-            if ("asc".equals(isAsc)) {
-                return OrderItem.asc(orderBy);
-            } else if ("desc".equals(isAsc)) {
-                return OrderItem.desc(orderBy);
+
+        List<OrderItem> list = new ArrayList<>();
+        // 每个字段各自排序
+        for (int i = 0; i < orderByArr.length; i++) {
+            String orderByStr = orderByArr[i];
+            String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i];
+            if ("asc".equals(isAscStr)) {
+                list.add(OrderItem.asc(orderByStr));
+            } else if ("desc".equals(isAscStr)) {
+                list.add(OrderItem.desc(orderByStr));
+            } else {
+                throw new ServiceException("排序参数有误");
             }
         }
-        return null;
+        return list;
     }
 
 }

+ 4 - 4
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java

@@ -75,11 +75,11 @@ public class R<T> implements Serializable {
         return r;
     }
 
-    public Boolean isError() {
-        return !isSuccess();
+    public static <T> Boolean isError(R<T> ret) {
+        return !isSuccess(ret);
     }
 
-    public Boolean isSuccess() {
-        return R.SUCCESS == getCode();
+    public static <T> Boolean isSuccess(R<T> ret) {
+        return R.SUCCESS == ret.getCode();
     }
 }

+ 0 - 1
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java

@@ -194,7 +194,6 @@ public class ExcelUtil {
      */
     private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException {
         String filename = encodingFilename(sheetName);
-        response.reset();
         FileUtils.setAttachmentResponseHeader(response, filename);
         response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
     }

+ 1 - 1
ruoyi-demo/pom.xml

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

+ 1 - 1
ruoyi-extend/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.3.0</version>
+        <version>4.3.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.3.0</version>
+        <version>4.3.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.3.0</version>
+        <version>4.3.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.3.0</version>
+        <version>4.3.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

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

@@ -4,6 +4,7 @@ import com.ruoyi.framework.interceptor.PlusWebInvokeTimeInterceptor;
 import com.yomahub.tlog.web.interceptor.TLogWebInterceptor;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.http.CacheControl;
 import org.springframework.web.cors.CorsConfiguration;
 import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
 import org.springframework.web.filter.CorsFilter;

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

@@ -1,7 +1,6 @@
 package com.ruoyi.framework.config;
 
-import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
-import cn.dev33.satoken.interceptor.SaRouteInterceptor;
+import cn.dev33.satoken.interceptor.SaInterceptor;
 import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
 import cn.dev33.satoken.router.SaRouter;
 import cn.dev33.satoken.stp.StpLogic;
@@ -34,14 +33,14 @@ public class SaTokenConfig implements WebMvcConfigurer {
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         // 注册路由拦截器,自定义验证规则
-        registry.addInterceptor(new SaRouteInterceptor((request, response, handler) -> {
+        registry.addInterceptor(new SaInterceptor(handler -> {
+            // 自定义注解 @Anonymous 匿名访问配置,后续版本将删除
             ExcludeUrlProperties excludeUrlProperties = SpringUtils.getBean(ExcludeUrlProperties.class);
             // 登录验证 -- 排除多个路径
             SaRouter
                 // 获取所有的
                 .match("/**")
-                // 排除下不需要拦截的
-                .notMatch(securityProperties.getExcludes())
+                // 排除下不需要拦截的(每次匹配)
                 .notMatch(excludeUrlProperties.getExcludes())
                 // 对未排除的路径进行检查
                 .check(() -> {
@@ -55,8 +54,9 @@ public class SaTokenConfig implements WebMvcConfigurer {
                     // }
 
                 });
-        })).addPathPatterns("/**");
-        registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**");
+        })).addPathPatterns("/**")
+            // 排除不需要拦截的路径
+            .excludePathPatterns(securityProperties.getExcludes());
     }
 
     @Bean

+ 7 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/ExcludeUrlProperties.java

@@ -1,5 +1,7 @@
 package com.ruoyi.framework.config.properties;
 
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.interceptor.SaInterceptor;
 import cn.hutool.core.util.ReUtil;
 import com.ruoyi.common.annotation.Anonymous;
 import com.ruoyi.common.utils.spring.SpringUtils;
@@ -13,6 +15,8 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
 import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
 import org.springframework.web.util.pattern.PathPattern;
 
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.util.*;
 import java.util.regex.Pattern;
 
@@ -20,7 +24,10 @@ import java.util.regex.Pattern;
  * 设置注解允许匿名访问的url
  *
  * @author Lion Li
+ * @deprecated 将在后续版本使用Sa-Token注解 {@link SaIgnore} 代替,
+ * 底层过滤方法详见 {@link SaInterceptor#preHandle(HttpServletRequest, HttpServletResponse, Object)}
  */
+@Deprecated
 @Lazy
 @Component
 public class ExcludeUrlProperties implements InitializingBean {

+ 13 - 4
ruoyi-framework/src/main/java/com/ruoyi/framework/listener/UserActionListener.java

@@ -50,7 +50,11 @@ public class UserActionListener implements SaTokenListener {
             dto.setTokenId(tokenValue);
             dto.setUserName(user.getUsername());
             dto.setDeptName(user.getDeptName());
-            RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
+            if(tokenConfig.getTimeout() == -1) {
+                RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
+            } else {
+                RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
+            }
             log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
         } else if (userType == UserType.APP_USER) {
             // app端 自行根据业务编写
@@ -88,14 +92,14 @@ public class UserActionListener implements SaTokenListener {
      * 每次被封禁时触发
      */
     @Override
-    public void doDisable(String loginType, Object loginId, long disableTime) {
+    public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
     }
 
     /**
      * 每次被解封时触发
      */
     @Override
-    public void doUntieDisable(String loginType, Object loginId) {
+    public void doUntieDisable(String loginType, Object loginId, String service) {
     }
 
     /**
@@ -112,5 +116,10 @@ public class UserActionListener implements SaTokenListener {
     public void doLogoutSession(String id) {
     }
 
-
+    /**
+     * 每次Token续期时触发
+     */
+    @Override
+    public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
+    }
 }

+ 2 - 3
ruoyi-framework/src/main/java/com/ruoyi/framework/satoken/dao/PlusSaTokenDao.java

@@ -170,10 +170,9 @@ public class PlusSaTokenDao implements SaTokenDao {
      * 搜索数据
      */
     @Override
-    public List<String> searchData(String prefix, String keyword, int start, int size) {
+    public List<String> searchData(String prefix, String keyword, int start, int size, boolean sortType) {
         Collection<String> keys = RedisUtils.keys(prefix + "*" + keyword + "*");
         List<String> list = new ArrayList<>(keys);
-        return SaFoxUtil.searchList(list, start, size);
+        return SaFoxUtil.searchList(list, start, size, sortType);
     }
-
 }

+ 1 - 1
ruoyi-generator/pom.xml

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

+ 1 - 1
ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt

@@ -1 +1 @@
-如果使用的是RuoYi-Vue3前端,那么需要覆盖一下此目录的模板index.vue.vm、index-tree.vue.vm文件到上级vue目录。
+濡傛灉浣跨敤鐨勬槸Vue3鍓嶇�锛岄偅涔堥渶瑕佽�鐩栦竴涓嬫�鐩�綍鐨勬ā鏉縤ndex.vue.vm銆乮ndex-tree.vue.vm鏂囦欢鍒颁笂绾�ue鐩�綍銆�

+ 2 - 1
ruoyi-job/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.3.0</version>
+        <version>4.3.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>
@@ -37,3 +37,4 @@
     </dependencies>
 
 </project>
+

+ 1 - 1
ruoyi-oss/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.3.0</version>
+        <version>4.3.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.3.0</version>
+        <version>4.3.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.3.0</version>
+        <version>4.3.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 2 - 0
ruoyi-system/src/main/java/com/ruoyi/system/listener/SysUserImportListener.java

@@ -66,6 +66,8 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
                 user = BeanUtil.toBean(userVo, SysUser.class);
                 user.setUserId(userId);
                 ValidatorUtils.validate(user);
+                userService.checkUserAllowed(user);
+                userService.checkUserDataScope(user.getUserId());
                 user.setUpdateBy(operName);
                 userService.updateUser(user);
                 successNum++;

+ 2 - 2
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java

@@ -83,10 +83,10 @@ public interface ISysUserService {
     /**
      * 校验用户名称是否唯一
      *
-     * @param userName 用户名称
+     * @param user 用户信息
      * @return 结果
      */
-    String checkUserNameUnique(String userName);
+    String checkUserNameUnique(SysUser user);
 
     /**
      * 校验手机号码是否唯一

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

@@ -125,9 +125,9 @@ public class SysLoginService {
      */
     public void logout() {
         try {
-            String username = LoginHelper.getUsername();
+            LoginUser loginUser = LoginHelper.getLoginUser();
             StpUtil.logout();
-            asyncService.recordLogininfor(username, Constants.LOGOUT, MessageUtils.message("user.logout.success"), ServletUtils.getRequest());
+            asyncService.recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"), ServletUtils.getRequest());
         } catch (NotLoginException e) {
         }
     }

+ 4 - 4
ruoyi-system/src/main/java/com/ruoyi/system/service/SysRegisterService.java

@@ -48,15 +48,15 @@ public class SysRegisterService {
         if (captchaEnabled) {
             validateCaptcha(username, registerBody.getCode(), registerBody.getUuid(), request);
         }
-
-        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(username))) {
-            throw new UserException("user.register.save.error", username);
-        }
         SysUser sysUser = new SysUser();
         sysUser.setUserName(username);
         sysUser.setNickName(username);
         sysUser.setPassword(BCrypt.hashpw(password));
         sysUser.setUserType(userType);
+
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser))) {
+            throw new UserException("user.register.save.error", username);
+        }
         boolean regFlag = userService.registerUser(sysUser);
         if (!regFlag) {
             throw new UserException("user.register.error");

+ 3 - 2
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java

@@ -13,6 +13,7 @@ import com.ruoyi.common.core.service.ConfigService;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.redis.CacheUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.system.domain.SysConfig;
 import com.ruoyi.system.mapper.SysConfigMapper;
 import com.ruoyi.system.service.ISysConfigService;
@@ -85,7 +86,7 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
      */
     @Override
     public boolean selectCaptchaEnabled() {
-        String captchaEnabled = selectConfigByKey("sys.account.captchaEnabled");
+        String captchaEnabled = SpringUtils.getAopProxy(this).selectConfigByKey("sys.account.captchaEnabled");
         if (StringUtils.isEmpty(captchaEnabled)) {
             return true;
         }
@@ -216,7 +217,7 @@ public class SysConfigServiceImpl implements ISysConfigService, ConfigService {
      */
     @Override
     public String getConfigValue(String configKey) {
-        return selectConfigByKey(configKey);
+        return SpringUtils.getAopProxy(this).selectConfigByKey(configKey);
     }
 
 }

+ 3 - 2
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java

@@ -16,6 +16,7 @@ import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StreamUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.redis.CacheUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.system.mapper.SysDictDataMapper;
 import com.ruoyi.system.mapper.SysDictTypeMapper;
 import com.ruoyi.system.service.ISysDictTypeService;
@@ -233,7 +234,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService
     @Override
     public String getDictLabel(String dictType, String dictValue, String separator) {
         StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = selectDictDataByType(dictType);
+        List<SysDictData> datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType);
 
         if (StringUtils.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas)) {
             for (SysDictData dict : datas) {
@@ -265,7 +266,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService, DictService
     @Override
     public String getDictValue(String dictType, String dictLabel, String separator) {
         StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = selectDictDataByType(dictType);
+        List<SysDictData> datas = SpringUtils.getAopProxy(this).selectDictDataByType(dictType);
 
         if (StringUtils.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas)) {
             for (SysDictData dict : datas) {

+ 2 - 4
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java

@@ -443,11 +443,9 @@ public class SysMenuServiceImpl implements ISysMenuService {
 
     /**
      * 内链域名特殊字符替换
-     *
-     * @return
      */
     public String innerLinkReplaceEach(String path) {
-        return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, "." },
-            new String[]{"", ""});
+        return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, "."},
+            new String[]{"", "", "", "/"});
     }
 }

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

@@ -9,6 +9,7 @@ import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.oss.core.OssClient;
 import com.ruoyi.oss.entity.UploadResult;
 import com.ruoyi.oss.factory.OssFactory;
@@ -50,7 +51,7 @@ public class SysOssServiceImpl implements ISysOssService {
     public List<SysOssVo> listByIds(Collection<Long> ossIds) {
         List<SysOssVo> list = new ArrayList<>();
         for (Long id : ossIds) {
-            SysOssVo vo = getById(id);
+            SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
             if (ObjectUtil.isNotNull(vo)) {
                 list.add(vo);
             }

+ 5 - 3
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java

@@ -193,12 +193,14 @@ public class SysUserServiceImpl implements ISysUserService {
     /**
      * 校验用户名称是否唯一
      *
-     * @param userName 用户名称
+     * @param user 用户信息
      * @return 结果
      */
     @Override
-    public String checkUserNameUnique(String userName) {
-        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUserName, userName));
+    public String checkUserNameUnique(SysUser user) {
+        boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
+            .eq(SysUser::getUserName, user.getUserName())
+            .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
         if (exist) {
             return UserConstants.NOT_UNIQUE;
         }

+ 3 - 3
ruoyi-ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "ruoyi-vue-plus",
-  "version": "4.3.0",
+  "version": "4.3.1",
   "description": "RuoYi-Vue-Plus后台管理系统",
   "author": "LionLi",
   "license": "MIT",
@@ -38,9 +38,9 @@
     "@riophae/vue-treeselect": "0.4.0",
     "axios": "0.24.0",
     "clipboard": "2.0.8",
-    "core-js": "3.19.1",
+    "core-js": "3.25.3",
     "echarts": "4.9.0",
-    "element-ui": "2.15.8",
+    "element-ui": "2.15.10",
     "file-saver": "2.0.5",
     "fuse.js": "6.4.3",
     "highlight.js": "9.18.5",

+ 12 - 3
ruoyi-ui/src/App.vue

@@ -1,12 +1,16 @@
 <template>
   <div id="app">
     <router-view />
+    <theme-picker />
   </div>
 </template>
 
 <script>
-export default  {
-  name:  'App',
+import ThemePicker from "@/components/ThemePicker";
+
+export default {
+  name: "App",
+  components: { ThemePicker },
     metaInfo() {
         return {
             title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
@@ -15,5 +19,10 @@ export default  {
             }
         }
     }
-}
+};
 </script>
+<style scoped>
+#app .theme-picker {
+  display: none;
+}
+</style>

+ 3 - 2
ruoyi-ui/src/assets/styles/ruoyi.scss

@@ -264,9 +264,10 @@
 }
 
 .avatar-upload-preview {
-  position: absolute;
+  position: relative;
   top: 50%;
-  transform: translate(50%, -50%);
+  left: 50%;
+  transform: translate(-50%, -50%);
   width: 200px;
   height: 200px;
   border-radius: 50%;

+ 5 - 11
ruoyi-ui/src/components/FileUpload/index.vue

@@ -74,7 +74,7 @@ export default {
       number: 0,
       uploadList: [],
       baseUrl: process.env.VUE_APP_BASE_API,
-      uploadFileUrl: process.env.VUE_APP_BASE_API + "/system/oss/upload", // 上传的图片服务器地址
+      uploadFileUrl: process.env.VUE_APP_BASE_API + "/system/oss/upload", // 上传文件服务器地址
       headers: {
         Authorization: "Bearer " + getToken(),
       },
@@ -124,15 +124,9 @@ export default {
     handleBeforeUpload(file) {
       // 校检文件类型
       if (this.fileType) {
-        let fileExtension = "";
-        if (file.name.lastIndexOf(".") > -1) {
-          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
-        }
-        const isTypeOk = this.fileType.some((type) => {
-          if (file.type.indexOf(type) > -1) return true;
-          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
-          return false;
-        });
+        const fileName = file.name.split('.');
+        const fileExt = fileName[fileName.length - 1];
+        const isTypeOk = this.fileType.indexOf(fileExt) >= 0;
         if (!isTypeOk) {
           this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
           return false;
@@ -156,7 +150,7 @@ export default {
     },
     // 上传失败
     handleUploadError(err) {
-      this.$modal.msgError("上传图片失败,请重试");
+      this.$modal.msgError("上传文件失败,请重试");
       this.$modal.closeLoading();
     },
     // 上传成功回调

+ 3 - 2
ruoyi-ui/src/utils/request.js

@@ -132,12 +132,13 @@ service.interceptors.response.use(res => {
 )
 
 // 通用下载方法
-export function download(url, params, filename) {
+export function download(url, params, filename, config) {
   downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
   return service.post(url, params, {
     transformRequest: [(params) => { return tansParams(params) }],
     headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
-    responseType: 'blob'
+    responseType: 'blob',
+    ...config
   }).then(async (data) => {
     const isLogin = await blobValidate(data);
     if (isLogin) {

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

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

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

@@ -189,8 +189,8 @@ export default {
     resetQuery() {
       this.dateRange = [];
       this.resetForm("queryForm");
+      this.queryParams.pageNum = 1;
       this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
-      this.handleQuery();
     },
     /** 多选框选中数据 */
     handleSelectionChange(selection) {

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

@@ -255,8 +255,8 @@ export default {
     resetQuery() {
       this.dateRange = [];
       this.resetForm("queryForm");
+      this.queryParams.pageNum = 1;
       this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
-      this.handleQuery();
     },
     /** 多选框选中数据 */
     handleSelectionChange(selection) {

+ 60 - 3
ruoyi-ui/src/views/system/oss/index.vue

@@ -118,7 +118,10 @@
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table v-loading="loading" :data="ossList" @selection-change="handleSelectionChange">
+    <el-table v-loading="loading" :data="ossList" @selection-change="handleSelectionChange"
+              :header-cell-class-name="handleHeaderClass"
+              @header-click="handleHeaderCLick"
+              v-if="showTable">
       <el-table-column type="selection" width="55" align="center" />
       <el-table-column label="对象存储主键" align="center" prop="ossId" v-if="false"/>
       <el-table-column label="文件名" align="center" prop="fileName" />
@@ -135,13 +138,15 @@
                 v-if="!checkFileSuffix(scope.row.fileSuffix) || !previewListResource"/>
         </template>
       </el-table-column>
-      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180"
+                       sortable="custom">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
         </template>
       </el-table-column>
       <el-table-column label="上传人" align="center" prop="createBy" />
-      <el-table-column label="服务商" align="center" prop="service" />
+      <el-table-column label="服务商" align="center" prop="service"
+                       sortable="custom"/>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button
@@ -193,6 +198,7 @@ export default {
   name: "Oss",
   data() {
     return {
+      showTable: true,
       // 按钮loading
       buttonLoading: false,
       // 遮罩层
@@ -221,6 +227,8 @@ export default {
       previewListResource: true,
       // 创建时间时间范围
       daterangeCreateTime: [],
+      // 默认排序
+      defaultSort: {prop: 'createTime', order: 'ascending'},
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -262,6 +270,7 @@ export default {
         this.ossList = response.rows;
         this.total = response.total;
         this.loading = false;
+        this.showTable = true;
       });
     },
     checkFileSuffix(fileSuffix) {
@@ -289,8 +298,11 @@ export default {
     },
     /** 重置按钮操作 */
     resetQuery() {
+      this.showTable = false;
       this.daterangeCreateTime = [];
       this.resetForm("queryForm");
+      this.queryParams.orderByColumn = this.defaultSort.prop;
+      this.queryParams.isAsc = this.defaultSort.order;
       this.handleQuery();
     },
     // 多选框选中数据
@@ -299,6 +311,51 @@ export default {
       this.single = selection.length!==1
       this.multiple = !selection.length
     },
+    // 设置列的排序为我们自定义的排序
+    handleHeaderClass({column}) {
+      column.order = column.multiOrder
+    },
+    // 点击表头进行排序
+    handleHeaderCLick(column) {
+      if (column.sortable !== 'custom') {
+        return
+      }
+      switch (column.multiOrder) {
+        case 'descending':
+          column.multiOrder = 'ascending';
+          break;
+        case 'ascending':
+          column.multiOrder = '';
+          break;
+        default:
+          column.multiOrder = 'descending';
+          break;
+      }
+      this.handleOrderChange(column.property, column.multiOrder)
+    },
+    handleOrderChange(prop, order) {
+      let orderByArr = this.queryParams.orderByColumn ? this.queryParams.orderByColumn.split(",") : [];
+      let isAscArr = this.queryParams.isAsc ? this.queryParams.isAsc.split(",") : [];
+      let propIndex = orderByArr.indexOf(prop)
+      if (propIndex !== -1) {
+        if (order) {
+          //排序里已存在 只修改排序
+          isAscArr[propIndex] = order;
+        } else {
+          //如果order为null 则删除排序字段和属性
+          isAscArr.splice(propIndex, 1);//删除排序
+          orderByArr.splice(propIndex, 1);//删除属性
+        }
+      } else {
+        //排序里不存在则新增排序
+        orderByArr.push(prop);
+        isAscArr.push(order);
+      }
+      //合并排序
+      this.queryParams.orderByColumn = orderByArr.join(",");
+      this.queryParams.isAsc = isAscArr.join(",");
+      this.getList();
+    },
     /** 任务日志列表查询 */
     handleOssConfig() {
       this.$router.push({ path: '/system/oss-config/index'})

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

@@ -576,8 +576,8 @@ export default {
         this.form = response.data.user;
         this.postOptions = response.data.posts;
         this.roleOptions = response.data.roles;
-        this.form.postIds = response.data.postIds;
-        this.form.roleIds = response.data.roleIds;
+        this.$set(this.form, "postIds", response.data.postIds);
+        this.$set(this.form, "roleIds", response.data.roleIds);
         this.open = true;
         this.title = "修改用户";
         this.form.password = "";

+ 20 - 7
ruoyi-ui/src/views/system/user/profile/userAvatar.vue

@@ -24,7 +24,7 @@
       </el-row>
       <br />
       <el-row>
-        <el-col :lg="2" :md="2">
+        <el-col :lg="2" :sm="3" :xs="3">
           <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
             <el-button size="small">
               选择
@@ -32,19 +32,19 @@
             </el-button>
           </el-upload>
         </el-col>
-        <el-col :lg="{span: 1, offset: 2}" :md="2">
+        <el-col :lg="{span: 1, offset: 2}" :sm="2" :xs="2">
           <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
         </el-col>
-        <el-col :lg="{span: 1, offset: 1}" :md="2">
+        <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
           <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
         </el-col>
-        <el-col :lg="{span: 1, offset: 1}" :md="2">
+        <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
           <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
         </el-col>
-        <el-col :lg="{span: 1, offset: 1}" :md="2">
+        <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
           <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
         </el-col>
-        <el-col :lg="{span: 2, offset: 6}" :md="2">
+        <el-col :lg="{span: 2, offset: 6}" :sm="2" :xs="2">
           <el-button type="primary" size="small" @click="uploadImg()">提 交</el-button>
         </el-col>
       </el-row>
@@ -56,6 +56,7 @@
 import store from "@/store";
 import { VueCropper } from "vue-cropper";
 import { uploadAvatar } from "@/api/system/user";
+import { debounce } from '@/utils'
 
 export default {
   components: { VueCropper },
@@ -80,7 +81,8 @@ export default {
         fixedBox: true, // 固定截图框大小 不允许改变
         filename: ''
       },
-      previews: {}
+      previews: {},
+      resizeHandler: null
     };
   },
   methods: {
@@ -91,6 +93,16 @@ export default {
     // 打开弹出层结束时的回调
     modalOpened() {
       this.visible = true;
+      if (!this.resizeHandler) {
+        this.resizeHandler = debounce(() => {
+          this.refresh()
+        }, 100)
+      }
+      window.addEventListener("resize", this.resizeHandler)
+    },
+    // 刷新组件
+    refresh() {
+      this.$refs.cropper.refresh();
     },
     // 覆盖默认的上传行为
     requestUpload() {
@@ -144,6 +156,7 @@ export default {
     closeDialog() {
       this.options.img = store.getters.avatar
       this.visible = false;
+      window.removeEventListener("resize", this.resizeHandler)
     }
   }
 };

+ 5 - 5
ruoyi-ui/src/views/tool/gen/editTable.vue

@@ -45,22 +45,22 @@
 
           <el-table-column label="插入" min-width="5%">
             <template slot-scope="scope">
-              <el-checkbox true-label="1" v-model="scope.row.isInsert"></el-checkbox>
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="编辑" min-width="5%">
             <template slot-scope="scope">
-              <el-checkbox true-label="1" v-model="scope.row.isEdit"></el-checkbox>
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="列表" min-width="5%">
             <template slot-scope="scope">
-              <el-checkbox true-label="1" v-model="scope.row.isList"></el-checkbox>
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="查询" min-width="5%">
             <template slot-scope="scope">
-              <el-checkbox true-label="1" v-model="scope.row.isQuery"></el-checkbox>
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="查询方式" min-width="10%">
@@ -79,7 +79,7 @@
           </el-table-column>
           <el-table-column label="必填" min-width="5%">
             <template slot-scope="scope">
-              <el-checkbox true-label="1" v-model="scope.row.isRequired"></el-checkbox>
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
             </template>
           </el-table-column>
           <el-table-column label="显示类型" min-width="12%">

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

@@ -29,7 +29,7 @@ services:
     network_mode: "host"
 
   nginx-web:
-    image: nginx:1.21.6
+    image: nginx:1.22.1
     container_name: nginx-web
     environment:
       # 时区上海
@@ -100,7 +100,7 @@ services:
     network_mode: "host"
 
   ruoyi-server1:
-    image: ruoyi/ruoyi-server:4.3.0
+    image: ruoyi/ruoyi-server:4.3.1
     container_name: ruoyi-server1
     environment:
       # 时区上海
@@ -113,7 +113,7 @@ services:
     network_mode: "host"
 
   ruoyi-server2:
-    image: "ruoyi/ruoyi-server:4.3.0"
+    image: "ruoyi/ruoyi-server:4.3.1"
     container_name: ruoyi-server2
     environment:
       # 时区上海
@@ -126,7 +126,7 @@ services:
     network_mode: "host"
 
   ruoyi-monitor-admin:
-    image: ruoyi/ruoyi-monitor-admin:4.3.0
+    image: ruoyi/ruoyi-monitor-admin:4.3.1
     container_name: ruoyi-monitor-admin
     environment:
       # 时区上海
@@ -138,7 +138,7 @@ services:
     network_mode: "host"
 
   ruoyi-xxl-job-admin:
-    image: ruoyi/ruoyi-xxl-job-admin:4.3.0
+    image: ruoyi/ruoyi-xxl-job-admin:4.3.1
     container_name: ruoyi-xxl-job-admin
     environment:
       # 时区上海

+ 1 - 1
script/sql/update/oracle/update-4.2-4.3.sql

@@ -2,7 +2,7 @@ insert into sys_menu values('112',  '缓存列表', '2',   '6', 'cacheList',  'm
 
 delete from sys_menu WHERE menu_id = 116;
 
-update sys_config set config_key = 'sys.account.captchaEnabled' where config_id = 4
+update sys_config set config_key = 'sys.account.captchaEnabled' where config_id = 4;
 
 insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock',  '#', 'admin', sysdate, '', null, '');
 

+ 1 - 1
script/sql/update/postgres/update-4.2-4.3.sql

@@ -2,7 +2,7 @@ insert into sys_menu values('112',  '缓存列表', '2',   '6', 'cacheList',  'm
 
 delete from sys_menu WHERE menu_id = 116;
 
-update sys_config set config_key = 'sys.account.captchaEnabled' where config_id = 4
+update sys_config set config_key = 'sys.account.captchaEnabled' where config_id = 4;
 
 insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:unlock',  '#', 'admin', now(), '', null, '');
 

+ 1 - 1
script/sql/update/update-4.2-4.3.sql

@@ -2,7 +2,7 @@ insert into sys_menu values('112',  '缓存列表', '2',   '6', 'cacheList',  'm
 
 delete from sys_menu WHERE menu_id = 116;
 
-update sys_config set config_key = 'sys.account.captchaEnabled' where config_id = 4
+update sys_config set config_key = 'sys.account.captchaEnabled' where config_id = 4;
 
 insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock',  '#', 'admin', sysdate(), '', null, '');