Эх сурвалжийг харах

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

疯狂的狮子li 3 жил өмнө
parent
commit
ca085b9aaa
54 өөрчлөгдсөн 381 нэмэгдсэн , 144 устгасан
  1. 2 2
      README.md
  2. 6 6
      pom.xml
  3. 1 1
      ruoyi-admin/pom.xml
  4. 1 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
  5. 0 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysOssController.java
  6. 3 2
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
  7. 1 1
      ruoyi-common/pom.xml
  8. 7 7
      ruoyi-common/src/main/java/com/ruoyi/common/captcha/UnsignedMathGenerator.java
  9. 6 0
      ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
  10. 4 4
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
  11. 2 5
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
  12. 2 5
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
  13. 3 3
      ruoyi-common/src/main/java/com/ruoyi/common/helper/LoginHelper.java
  14. 30 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
  15. 40 1
      ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
  16. 0 2
      ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
  17. 1 1
      ruoyi-demo/pom.xml
  18. 1 1
      ruoyi-extend/pom.xml
  19. 1 1
      ruoyi-extend/ruoyi-monitor-admin/pom.xml
  20. 1 1
      ruoyi-extend/ruoyi-xxl-job-admin/pom.xml
  21. 1 1
      ruoyi-framework/pom.xml
  22. 54 0
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java
  23. 1 1
      ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java
  24. 1 1
      ruoyi-generator/pom.xml
  25. 2 3
      ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
  26. 16 2
      ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
  27. 4 4
      ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
  28. 1 1
      ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
  29. 31 4
      ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
  30. 36 4
      ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
  31. 1 1
      ruoyi-job/pom.xml
  32. 1 1
      ruoyi-oss/pom.xml
  33. 1 1
      ruoyi-system/pom.xml
  34. 7 4
      ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java
  35. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
  36. 1 2
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
  37. 1 2
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
  38. 1 1
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
  39. 1 1
      ruoyi-ui/package.json
  40. 21 10
      ruoyi-ui/src/components/FileUpload/index.vue
  41. 21 21
      ruoyi-ui/src/components/ImageUpload/index.vue
  42. 1 6
      ruoyi-ui/src/components/Pagination/index.vue
  43. 3 0
      ruoyi-ui/src/permission.js
  44. 6 9
      ruoyi-ui/src/utils/request.js
  45. 12 1
      ruoyi-ui/src/utils/ruoyi.js
  46. 24 1
      ruoyi-ui/src/views/index.vue
  47. 2 1
      ruoyi-ui/src/views/register.vue
  48. 1 1
      ruoyi-ui/src/views/system/dept/index.vue
  49. 2 2
      ruoyi-ui/src/views/system/menu/index.vue
  50. 1 1
      ruoyi-ui/src/views/system/notice/index.vue
  51. 4 4
      ruoyi-ui/src/views/system/user/index.vue
  52. 1 1
      ruoyi-ui/src/views/system/user/profile/userInfo.vue
  53. 7 5
      script/docker/docker-compose.yml
  54. 1 1
      script/sql/ry_vue_4.0.sql

+ 2 - 2
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.0.0-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.0.1-success.svg)](https://gitee.com/JavaLionLi/RuoYi-Vue-Plus)
 [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.5-blue.svg)]()
 [![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]()
 [![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()
@@ -84,7 +84,7 @@
 
 ## 捐献作者
 作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭  
-<img src="https://images.gitee.com/uploads/images/2021/0525/101654_451e4523_1766278.jpeg" width="300px" height="450px" />
+<img src="https://images.gitee.com/uploads/images/2022/0218/213734_b1b8197f_1766278.jpeg" width="300px" height="450px" />
 <img src="https://images.gitee.com/uploads/images/2021/0525/101713_3d18b119_1766278.jpeg" width="300px" height="450px" />
 
 ## 业务功能

+ 6 - 6
pom.xml

@@ -6,15 +6,15 @@
 
     <groupId>com.ruoyi</groupId>
     <artifactId>ruoyi-vue-plus</artifactId>
-    <version>4.0.0</version>
+    <version>4.0.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.0.0</ruoyi-vue-plus.version>
-        <spring-boot.version>2.6.3</spring-boot.version>
+        <ruoyi-vue-plus.version>4.0.1</ruoyi-vue-plus.version>
+        <spring-boot.version>2.6.4</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>
@@ -29,7 +29,7 @@
         <satoken.version>1.29.0</satoken.version>
         <mybatis-plus.version>3.5.1</mybatis-plus.version>
         <p6spy.version>3.9.1</p6spy.version>
-        <hutool.version>5.7.20</hutool.version>
+        <hutool.version>5.7.21</hutool.version>
         <okhttp.version>4.9.2</okhttp.version>
         <spring-boot-admin.version>2.6.2</spring-boot-admin.version>
         <redisson.version>3.16.8</redisson.version>
@@ -42,10 +42,10 @@
         <jaxb.version>3.0.1</jaxb.version>
 
         <!-- OSS 配置 -->
-        <qiniu.version>7.9.2</qiniu.version>
+        <qiniu.version>7.9.3</qiniu.version>
         <aliyun.oss.version>3.14.0</aliyun.oss.version>
         <qcloud.cos.version>5.6.68</qcloud.cos.version>
-        <minio.version>8.3.5</minio.version>
+        <minio.version>8.3.7</minio.version>
 
         <!-- docker 配置 -->
         <docker.registry.url>localhost</docker.registry.url>

+ 1 - 1
ruoyi-admin/pom.xml

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

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

@@ -65,6 +65,7 @@ public class SysLoginController {
     public R<Void> logout() {
         try {
             StpUtil.logout();
+            loginService.logout(LoginHelper.getUsername());
         } catch (NotLoginException e) {
         }
         return R.ok("退出成功");

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

@@ -7,7 +7,6 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.http.HttpException;
 import cn.hutool.http.HttpUtil;
 import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.common.core.domain.R;
@@ -70,7 +69,6 @@ public class SysOssController extends BaseController {
     })
     @SaCheckPermission("system:oss:upload")
     @Log(title = "OSS对象存储", businessType = BusinessType.INSERT)
-    @RepeatSubmit
     @PostMapping("/upload")
     public R<Map<String, String>> upload(@RequestPart("file") MultipartFile file) {
         if (ObjectUtil.isNull(file)) {

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

@@ -16,6 +16,7 @@ import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.enums.BusinessType;
 import com.ruoyi.common.excel.ExcelResult;
+import com.ruoyi.common.helper.LoginHelper;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.poi.ExcelUtil;
 import com.ruoyi.system.domain.vo.SysUserExportVo;
@@ -109,7 +110,7 @@ public class SysUserController extends BaseController {
         userService.checkUserDataScope(userId);
         Map<String, Object> ajax = new HashMap<>();
         List<SysRole> roles = roleService.selectRoleAll();
-        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+        ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
         ajax.put("posts", postService.selectPostAll());
         if (ObjectUtil.isNotNull(userId)) {
             SysUser sysUser = userService.selectUserById(userId);
@@ -213,7 +214,7 @@ public class SysUserController extends BaseController {
         List<SysRole> roles = roleService.selectRolesByUserId(userId);
         Map<String, Object> ajax = new HashMap<>();
         ajax.put("user", user);
-        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+        ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
         return R.ok(ajax);
     }
 

+ 1 - 1
ruoyi-common/pom.xml

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

+ 7 - 7
ruoyi-common/src/main/java/com/ruoyi/common/captcha/UnsignedMathGenerator.java

@@ -41,14 +41,14 @@ public class UnsignedMathGenerator implements CodeGenerator {
     @Override
     public String generate() {
         final int limit = getLimit();
-        int min = RandomUtil.randomInt(limit);
-        int max = RandomUtil.randomInt(min, limit);
-        String number1 = Integer.toString(max);
-        String number2 = Integer.toString(min);
-        number1 = StringUtils.rightPad(number1, this.numberLength, CharUtil.SPACE);
-        number2 = StringUtils.rightPad(number2, this.numberLength, CharUtil.SPACE);
+        int a = RandomUtil.randomInt(limit);
+        int b = RandomUtil.randomInt(limit);
+        String max = Integer.toString(Math.max(a,b));
+        String min = Integer.toString(Math.min(a,b));
+        max = StringUtils.rightPad(max, this.numberLength, CharUtil.SPACE);
+        min = StringUtils.rightPad(min, this.numberLength, CharUtil.SPACE);
 
-        return number1 + RandomUtil.randomChar(OPERATORS) + number2 + '=';
+        return max + RandomUtil.randomChar(OPERATORS) + min + '=';
     }
 
     @Override

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

@@ -109,4 +109,10 @@ public interface UserConstants {
      */
     int PASSWORD_MIN_LENGTH = 5;
     int PASSWORD_MAX_LENGTH = 20;
+
+    /**
+     * 管理员ID
+     */
+    Long ADMIN_ID = 1L;
+
 }

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

@@ -38,11 +38,11 @@ public class R<T> implements Serializable {
     private T data;
 
     public static <T> R<T> ok() {
-        return restResult(null, SUCCESS, null);
+        return restResult(null, SUCCESS, "操作成功");
     }
 
     public static <T> R<T> ok(T data) {
-        return restResult(data, SUCCESS, null);
+        return restResult(data, SUCCESS, "操作成功");
     }
 
     public static <T> R<T> ok(String msg) {
@@ -54,7 +54,7 @@ public class R<T> implements Serializable {
     }
 
     public static <T> R<T> fail() {
-        return restResult(null, FAIL, null);
+        return restResult(null, FAIL, "操作失败");
     }
 
     public static <T> R<T> fail(String msg) {
@@ -62,7 +62,7 @@ public class R<T> implements Serializable {
     }
 
     public static <T> R<T> fail(T data) {
-        return restResult(data, FAIL, null);
+        return restResult(data, FAIL, "操作失败");
     }
 
     public static <T> R<T> fail(String msg, T data) {

+ 2 - 5
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.ruoyi.common.annotation.ExcelDictFormat;
+import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.convert.ExcelDictConvert;
 import com.ruoyi.common.core.domain.BaseEntity;
 import io.swagger.annotations.ApiModelProperty;
@@ -132,11 +133,7 @@ public class SysRole extends BaseEntity {
 
     @ApiModelProperty(value = "是否管理员")
     public boolean isAdmin() {
-        return isAdmin(this.roleId);
-    }
-
-    public static boolean isAdmin(Long roleId) {
-        return roleId != null && 1L == roleId;
+        return UserConstants.ADMIN_ID.equals(this.roleId);
     }
 
 }

+ 2 - 5
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.*;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.ruoyi.common.annotation.Sensitive;
+import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.BaseEntity;
 import com.ruoyi.common.enums.SensitiveStrategy;
 import com.ruoyi.common.xss.Xss;
@@ -185,11 +186,7 @@ public class SysUser extends BaseEntity {
 
     @ApiModelProperty(value = "是否管理员")
     public boolean isAdmin() {
-        return isAdmin(this.userId);
-    }
-
-    public static boolean isAdmin(Long userId) {
-        return userId != null && 1L == userId;
+        return UserConstants.ADMIN_ID.equals(this.userId);
     }
 
 }

+ 3 - 3
ruoyi-common/src/main/java/com/ruoyi/common/helper/LoginHelper.java

@@ -2,6 +2,7 @@ package com.ruoyi.common.helper;
 
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.util.ObjectUtil;
+import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.enums.DeviceType;
 import com.ruoyi.common.enums.UserType;
@@ -130,12 +131,11 @@ public class LoginHelper {
      * @return 结果
      */
     public static boolean isAdmin(Long userId) {
-        return userId != null && 1L == userId;
+        return UserConstants.ADMIN_ID.equals(userId);
     }
 
     public static boolean isAdmin() {
-        Long userId = getUserId();
-        return userId != null && 1L == userId;
+        return isAdmin(getUserId());
     }
 
 }

+ 30 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java

@@ -7,6 +7,11 @@ import org.apache.commons.lang3.time.DateFormatUtils;
 import java.lang.management.ManagementFactory;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Date;
 
 /**
@@ -117,6 +122,14 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
     }
 
     /**
+     * 计算相差天数
+     */
+    public static int differentDaysByMillisecond(Date date1, Date date2)
+    {
+        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
+    }
+
+    /**
      * 计算两个时间差
      */
     public static String getDatePoor(Date endDate, Date nowDate) {
@@ -136,4 +149,21 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
         // long sec = diff % nd % nh % nm / ns;
         return day + "天" + hour + "小时" + min + "分钟";
     }
+
+    /**
+     * 增加 LocalDateTime ==> Date
+     */
+    public static Date toDate(LocalDateTime temporalAccessor) {
+        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+
+    /**
+     * 增加 LocalDate ==> Date
+     */
+    public static Date toDate(LocalDate temporalAccessor) {
+        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
+        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
 }

+ 40 - 1
ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java

@@ -86,7 +86,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
      * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
      * 例:<br>
      * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
-     * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 转义{}: format("this is \\{} for {}", "a", "b") -> this is {} for a<br>
      * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
      *
      * @param template 文本模板,被替换的部分用 {} 表示
@@ -231,4 +231,43 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils {
         return matcher.match(pattern, url);
     }
 
+    /**
+     * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
+     *
+     * @param num 数字对象
+     * @param size 字符串指定长度
+     * @return 返回数字的字符串格式,该字符串为指定长度。
+     */
+    public static final String padl(final Number num, final int size) {
+        return padl(num.toString(), size, '0');
+    }
+
+    /**
+     * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
+     *
+     * @param s 原始字符串
+     * @param size 字符串指定长度
+     * @param c 用于补齐的字符
+     * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
+     */
+    public static final String padl(final String s, final int size, final char c) {
+        final StringBuilder sb = new StringBuilder(size);
+        if (s != null) {
+            final int len = s.length();
+            if (s.length() <= size) {
+                for (int i = size - len; i > 0; i--) {
+                    sb.append(c);
+                }
+                sb.append(s);
+            } else {
+                return s.substring(len - size, len);
+            }
+        } else {
+            for (int i = size; i > 0; i--) {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
 }

+ 0 - 2
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java

@@ -22,7 +22,6 @@ public class FileUtils extends FileUtil {
      *
      * @param response     响应对象
      * @param realFileName 真实文件名
-     * @return
      */
     public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
         String percentEncodedFileName = percentEncode(realFileName);
@@ -35,7 +34,6 @@ public class FileUtils extends FileUtil {
             .append("utf-8''")
             .append(percentEncodedFileName);
 
-        response.addHeader("Access-Control-Allow-Origin", "*");
         response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
         response.setHeader("Content-disposition", contentDispositionValue.toString());
         response.setHeader("download-filename", percentEncodedFileName);

+ 1 - 1
ruoyi-demo/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.0.0</version>
+        <version>4.0.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.0.0</version>
+        <version>4.0.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.0.0</version>
+        <version>4.0.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.0.0</version>
+        <version>4.0.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.0.0</version>
+        <version>4.0.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 54 - 0
ruoyi-framework/src/main/java/com/ruoyi/framework/config/AsyncConfig.java

@@ -0,0 +1,54 @@
+package com.ruoyi.framework.config;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.ruoyi.common.exception.ServiceException;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * 异步配置
+ *
+ * @author Lion Li
+ */
+@EnableAsync
+@Configuration
+public class AsyncConfig extends AsyncConfigurerSupport {
+
+    @Autowired
+    @Qualifier("scheduledExecutorService")
+    private ScheduledExecutorService scheduledExecutorService;
+
+    /**
+     * 自定义 @Async 注解使用系统线程池
+     */
+    @Override
+    public Executor getAsyncExecutor() {
+        return scheduledExecutorService;
+    }
+
+    /**
+     * 异步执行异常处理
+     */
+    @Override
+    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+        return (throwable, method, objects) -> {
+            throwable.printStackTrace();
+            StringBuilder sb = new StringBuilder();
+            sb.append("Exception message - ").append(throwable.getMessage())
+                .append(", Method name - ").append(method.getName());
+            if (ArrayUtil.isNotEmpty(objects)) {
+                sb.append(", Parameter value - ").append(Arrays.toString(objects));
+            }
+            throw new ServiceException(sb.toString());
+        };
+    }
+
+}

+ 1 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/handler/PlusDataPermissionHandler.java

@@ -79,7 +79,7 @@ public class PlusDataPermissionHandler {
             DataPermissionHelper.setVariable("user", currentUser);
         }
         // 如果是超级管理员,则不过滤数据
-        if (ObjectUtil.isNull(currentUser) || LoginHelper.isAdmin(currentUser.getUserId())) {
+        if (LoginHelper.isAdmin()) {
             return where;
         }
         String dataFilterSql = buildDataFilter(dataColumns, isSelect);

+ 1 - 1
ruoyi-generator/pom.xml

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

+ 2 - 3
ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java

@@ -1,8 +1,6 @@
 package com.ruoyi.generator.domain;
 
-import com.baomidou.mybatisplus.annotation.TableField;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.*;
 import com.ruoyi.common.constant.GenConstants;
 import com.ruoyi.common.core.domain.BaseEntity;
 import com.ruoyi.common.utils.StringUtils;
@@ -102,6 +100,7 @@ public class GenTable extends BaseEntity {
     /**
      * 生成路径(不填默认项目路径)
      */
+    @TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
     private String genPath;
 
     /**

+ 16 - 2
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java

@@ -244,14 +244,28 @@ public class VelocityUtils {
     public static String getDicts(GenTable genTable) {
         List<GenTableColumn> columns = genTable.getColumns();
         Set<String> dicts = new HashSet<String>();
+        addDicts(dicts, columns);
+        if (ObjectUtil.isNotNull(genTable.getSubTable())) {
+            List<GenTableColumn> subColumns = genTable.getSubTable().getColumns();
+            addDicts(dicts, subColumns);
+        }
+        return StringUtils.join(dicts, ", ");
+    }
+
+    /**
+     * 添加字典列表
+     *
+     * @param dicts 字典列表
+     * @param columns 列集合
+     */
+    public static void addDicts(Set<String> dicts, List<GenTableColumn> columns) {
         for (GenTableColumn column : columns) {
             if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
                 column.getHtmlType(),
-                new String[]{GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX})) {
+                new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) {
                 dicts.add("'" + column.getDictType() + "'");
             }
         }
-        return StringUtils.join(dicts, ", ");
     }
 
     /**

+ 4 - 4
ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm

@@ -48,7 +48,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
     /**
      * 查询${functionName}列表
      *
-     * @param ${className} ${functionName}
+     * @param bo ${functionName}
      * @return ${functionName}
      */
     @Override
@@ -62,7 +62,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
     /**
      * 查询${functionName}列表
      *
-     * @param ${className} ${functionName}
+     * @param bo ${functionName}
      * @return ${functionName}
      */
     @Override
@@ -101,7 +101,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
     /**
      * 新增${functionName}
      *
-     * @param ${className} ${functionName}
+     * @param bo ${functionName}
      * @return 结果
      */
     @Override
@@ -119,7 +119,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service {
     /**
      * 修改${functionName}
      *
-     * @param ${className} ${functionName}
+     * @param bo ${functionName}
      * @return 结果
      */
     @Override

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

@@ -306,7 +306,7 @@ export default {
       queryParams: {
 #foreach ($column in $columns)
 #if($column.query)
-        $column.javaField: null#if($foreach.count != $columns.size()),#end
+        $column.javaField: undefined#if($foreach.count != $columns.size()),#end
 #end
 #end
       },

+ 31 - 4
ruoyi-generator/src/main/resources/vm/vue/index.vue.vm

@@ -44,7 +44,7 @@
           v-model="queryParams.${column.javaField}"
           type="date"
           value-format="yyyy-MM-dd"
-          placeholder="选择${comment}">
+          placeholder="选择${comment}">
         </el-date-picker>
       </el-form-item>
 #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
@@ -268,7 +268,7 @@
             v-model="form.${field}"
             type="datetime"
             value-format="yyyy-MM-dd HH:mm:ss"
-            placeholder="选择${comment}">
+            placeholder="选择${comment}">
           </el-date-picker>
         </el-form-item>
 #elseif($column.htmlType == "textarea")
@@ -300,12 +300,39 @@
 #set($comment=$column.columnComment)
 #end
 #if($column.pk || $javaField == ${subTableFkclassName})
-#elseif($column.list && "" != $javaField)
-          <el-table-column label="$comment" prop="${javaField}">
+#elseif($column.list && $column.htmlType == "input")
+          <el-table-column label="$comment" prop="${javaField}" width="150">
             <template slot-scope="scope">
               <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
             </template>
           </el-table-column>
+#elseif($column.list && $column.htmlType == "datetime")
+          <el-table-column label="$comment" prop="${javaField}" width="240">
+            <template slot-scope="scope">
+              <el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" />
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+                <el-option
+                  v-for="dict in dict.type.$column.dictType"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+                <el-option label="请选择字典生成" value="" />
+              </el-select>
+            </template>
+          </el-table-column>
 #end
 #end
         </el-table>

+ 36 - 4
ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm

@@ -43,7 +43,7 @@
           v-model="queryParams.${column.javaField}"
           type="date"
           value-format="YYYY-MM-DD"
-          placeholder="选择${comment}">
+          placeholder="选择${comment}">
         </el-date-picker>
       </el-form-item>
 #elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
@@ -259,7 +259,7 @@
             v-model="form.${field}"
             type="datetime"
             value-format="YYYY-MM-DD HH:mm:ss"
-            placeholder="选择${comment}">
+            placeholder="选择${comment}">
           </el-date-picker>
         </el-form-item>
 #elseif($column.htmlType == "textarea")
@@ -291,12 +291,44 @@
 #set($comment=$column.columnComment)
 #end
 #if($column.pk || $javaField == ${subTableFkclassName})
-#elseif($column.list && "" != $javaField)
-          <el-table-column label="$comment" prop="${javaField}">
+#elseif($column.list && $column.htmlType == "input")
+          <el-table-column label="$comment" prop="${javaField}" width="150">
             <template #default="scope">
               <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
             </template>
           </el-table-column>
+#elseif($column.list && $column.htmlType == "datetime")
+          <el-table-column label="$comment" prop="${javaField}" width="240">
+            <template #default="scope">
+              <el-date-picker clearable
+                v-model="scope.row.$javaField"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="请选择$comment">
+              </el-date-picker>
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template #default="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+                <el-option
+                  v-for="dict in $column.dictType"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template #default="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+                <el-option label="请选择字典生成" value="" />
+              </el-select>
+            </template>
+          </el-table-column>
 #end
 #end
         </el-table>

+ 1 - 1
ruoyi-job/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi-vue-plus</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>4.0.0</version>
+        <version>4.0.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.0.0</version>
+        <version>4.0.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.0.0</version>
+        <version>4.0.1</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

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

@@ -87,16 +87,19 @@ public class SysLoginService {
 
         // 登录成功 清空错误次数
         RedisUtils.deleteObject(Constants.LOGIN_ERROR + username);
-        asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
-        recordLoginInfo(user.getUserId(), username);
-
         LoginUser loginUser = buildLoginUser(user);
-
         // 生成token
         LoginHelper.loginByDevice(loginUser, DeviceType.PC);
+
+        asyncService.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request);
+        recordLoginInfo(user.getUserId(), username);
         return StpUtil.getTokenValue();
     }
 
+    public void logout(String loginName) {
+        asyncService.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success"), ServletUtils.getRequest());
+    }
+
     /**
      * 校验验证码
      *

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

@@ -152,7 +152,7 @@ public class SysDeptServiceImpl implements ISysDeptService {
      */
     @Override
     public void checkDeptDataScope(Long deptId) {
-        if (!SysUser.isAdmin(LoginHelper.getUserId())) {
+        if (!LoginHelper.isAdmin()) {
             SysDept dept = new SysDept();
             dept.setDeptId(deptId);
             List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);

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

@@ -8,7 +8,6 @@ import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.entity.SysMenu;
 import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.helper.LoginHelper;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.TreeBuildUtils;
@@ -58,7 +57,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
     public List<SysMenu> selectMenuList(SysMenu menu, Long userId) {
         List<SysMenu> menuList = null;
         // 管理员显示所有菜单信息
-        if (SysUser.isAdmin(userId)) {
+        if (LoginHelper.isAdmin(userId)) {
             menuList = baseMapper.selectList(new LambdaQueryWrapper<SysMenu>()
                 .like(StringUtils.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName())
                 .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible())

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

@@ -7,7 +7,6 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.PageQuery;
 import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.helper.LoginHelper;
@@ -181,7 +180,7 @@ public class SysRoleServiceImpl implements ISysRoleService {
      */
     @Override
     public void checkRoleDataScope(Long roleId) {
-        if (!SysUser.isAdmin(LoginHelper.getUserId())) {
+        if (!LoginHelper.isAdmin()) {
             SysRole role = new SysRole();
             role.setRoleId(roleId);
             List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);

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

@@ -206,7 +206,7 @@ public class SysUserServiceImpl implements ISysUserService {
      */
     @Override
     public void checkUserDataScope(Long userId) {
-        if (!SysUser.isAdmin(LoginHelper.getUserId())) {
+        if (!LoginHelper.isAdmin()) {
             SysUser user = new SysUser();
             user.setUserId(userId);
             List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);

+ 1 - 1
ruoyi-ui/package.json

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

+ 21 - 10
ruoyi-ui/src/components/FileUpload/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="upload-file">
     <el-upload
+      multiple
       :action="uploadFileUrl"
       :before-upload="handleBeforeUpload"
       :file-list="fileList"
@@ -69,6 +70,8 @@ export default {
   },
   data() {
     return {
+      number: 0,
+      uploadList: [],
       baseUrl: process.env.VUE_APP_BASE_API,
       uploadFileUrl: process.env.VUE_APP_BASE_API + "/system/oss/upload", // 上传的图片服务器地址
       headers: {
@@ -122,7 +125,7 @@ export default {
           return false;
         });
         if (!isTypeOk) {
-          this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
+          this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
           return false;
         }
       }
@@ -130,29 +133,37 @@ export default {
       if (this.fileSize) {
         const isLt = file.size / 1024 / 1024 < this.fileSize;
         if (!isLt) {
-          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
+          this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`);
           return false;
         }
       }
+      this.$modal.loading("正在上传文件,请稍候...");
+      this.number++;
       return true;
     },
     // 文件个数超出
     handleExceed() {
-      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
+      this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
     },
     // 上传失败
     handleUploadError(err) {
-      this.$message.error("上传失败, 请重试");
+      this.$modal.msgError("上传图片失败,请重试");
+      this.$modal.closeLoading()
     },
     // 上传成功回调
     handleUploadSuccess(res, file) {
       if (res.code === 200) {
-        this.$message.success("上传成功");
-        this.fileList.push({ name: res.data.fileName, url: res.data.url });
-        this.$emit("input", this.listToString(this.fileList));
+        this.uploadList.push({ name: res.data.fileName, url: res.data.url });
+        if (this.uploadList.length === this.number) {
+          this.fileList = this.fileList.concat(this.uploadList);
+          this.uploadList = [];
+          this.number = 0;
+          this.$emit("input", this.listToString(this.fileList));
+          this.$modal.closeLoading();
+        }
       } else {
-        this.$message.error(res.msg);
-        this.loading.close();
+        this.$modal.msgError(res.msg);
+        this.$modal.closeLoading();
       }
     },
     // 删除文件
@@ -163,7 +174,7 @@ export default {
     // 获取文件名称
     getFileName(name) {
       if (name.lastIndexOf("/") > -1) {
-        return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
+        return name.slice(name.lastIndexOf("/") + 1);
       } else {
         return "";
       }

+ 21 - 21
ruoyi-ui/src/components/ImageUpload/index.vue

@@ -1,6 +1,7 @@
 <template>
   <div class="component-upload-image">
     <el-upload
+      multiple
       :action="uploadImgUrl"
       list-type="picture-card"
       :on-success="handleUploadSuccess"
@@ -18,7 +19,7 @@
     >
       <i class="el-icon-plus"></i>
     </el-upload>
-    
+
     <!-- 上传提示 -->
     <div class="el-upload__tip" slot="tip" v-if="showTip">
       请上传
@@ -70,6 +71,8 @@ export default {
   },
   data() {
     return {
+      number: 0,
+      uploadList: [],
       dialogImageUrl: "",
       dialogVisible: false,
       hideUpload: false,
@@ -121,12 +124,17 @@ export default {
     // 上传成功回调
     handleUploadSuccess(res) {
       if (res.code == 200) {
-        this.fileList.push({ name: res.data.fileName, url: res.data.url });
-        this.$emit("input", this.listToString(this.fileList));
-        this.loading.close();
+        this.uploadList.push({ name: res.data.fileName, url: res.data.url });
+        if (this.uploadList.length === this.number) {
+          this.fileList = this.fileList.concat(this.uploadList);
+          this.uploadList = [];
+          this.number = 0;
+          this.$emit("input", this.listToString(this.fileList));
+          this.$modal.closeLoading();
+        }
       } else {
-        this.$message.error(res.msg);
-        this.loading.close();
+        this.$modal.msgError(res.msg);
+        this.$modal.closeLoading();
       }
     },
     // 上传前loading加载
@@ -147,35 +155,27 @@ export default {
       }
 
       if (!isImg) {
-        this.$message.error(
-          `文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`
-        );
+        this.$modal.msgError(`文件格式不正确, 请上传${this.fileType.join("/")}图片格式文件!`);
         return false;
       }
       if (this.fileSize) {
         const isLt = file.size / 1024 / 1024 < this.fileSize;
         if (!isLt) {
-          this.$message.error(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
+          this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
           return false;
         }
       }
-      this.loading = this.$loading({
-        lock: true,
-        text: "上传中",
-        background: "rgba(0, 0, 0, 0.7)",
-      });
+      this.$modal.loading("正在上传图片,请稍候...");
+      this.number++;
     },
     // 文件个数超出
     handleExceed() {
-      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
+      this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
     },
     // 上传失败
     handleUploadError(res) {
-      this.$message({
-        type: "error",
-        message: "上传失败",
-      });
-      this.loading.close();
+      this.$modal.msgError("上传图片失败,请重试");
+      this.$modal.closeLoading();
     },
     // 预览
     handlePictureCardPreview(file) {

+ 1 - 6
ruoyi-ui/src/components/Pagination/index.vue

@@ -1,7 +1,6 @@
 <template>
   <div :class="{'hidden':hidden}" class="pagination-container">
     <el-pagination
-      v-if="pageShow"
       :background="background"
       :current-page.sync="currentPage"
       :page-size.sync="pageSize"
@@ -64,7 +63,6 @@ export default {
   },
   data() {
     return {
-      pageShow: true
     };
   },
   computed: {
@@ -88,10 +86,7 @@ export default {
   methods: {
     handleSizeChange(val) {
       if (this.currentPage * val > this.total) {
-        this.pageShow = false;
-        this.$nextTick(() => {
-          this.pageShow = true
-        })
+        this.currentPage = 1
       }
       this.$emit('pagination', { page: this.currentPage, limit: val })
       if (this.autoScroll) {

+ 3 - 0
ruoyi-ui/src/permission.js

@@ -4,6 +4,7 @@ import { Message } from 'element-ui'
 import NProgress from 'nprogress'
 import 'nprogress/nprogress.css'
 import { getToken } from '@/utils/auth'
+import { isRelogin } from '@/utils/request'
 
 NProgress.configure({ showSpinner: false })
 
@@ -19,8 +20,10 @@ router.beforeEach((to, from, next) => {
       NProgress.done()
     } else {
       if (store.getters.roles.length === 0) {
+        isRelogin.show = true
         // 判断当前用户是否已拉取完user_info信息
         store.dispatch('GetInfo').then(() => {
+          isRelogin.show = false
           store.dispatch('GenerateRoutes').then(accessRoutes => {
             // 根据roles权限生成可访问的路由表
             router.addRoutes(accessRoutes) // 动态添加可访问路由表

+ 6 - 9
ruoyi-ui/src/utils/request.js

@@ -9,7 +9,7 @@ import { saveAs } from 'file-saver'
 
 let downloadLoadingInstance;
 // 是否显示重新登录
-let isReloginShow;
+export let isRelogin = { show: false };
 
 axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
 // 对应国际化资源文件后缀
@@ -78,23 +78,20 @@ service.interceptors.response.use(res => {
       return res.data
     }
     if (code === 401) {
-      if (!isReloginShow) {
-        isReloginShow = true;
+      if (!isRelogin.show) {
+        isRelogin.show = true;
         MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
           confirmButtonText: '重新登录',
           cancelButtonText: '取消',
           type: 'warning'
         }
       ).then(() => {
-        isReloginShow = false;
+        isRelogin.show = false;
         store.dispatch('LogOut').then(() => {
-          // 如果是登录页面不需要重新加载
-          if (window.location.hash.indexOf("#/login") != 0) {
-            location.href = process.env.VUE_APP_CONTEXT_PATH + "index";
-          }
+          location.href = process.env.VUE_APP_CONTEXT_PATH + "index";
         })
       }).catch(() => {
-        isReloginShow = false;
+        isRelogin.show = false;
       });
     }
       return Promise.reject('无效的会话,或者会话已过期,请重新登录。')

+ 12 - 1
ruoyi-ui/src/utils/ruoyi.js

@@ -70,6 +70,9 @@ export function addDateRange(params, dateRange, propName) {
 
 // 回显数据字典 
 export function selectDictLabel(datas, value) {
+  if (value === undefined) {
+    return "";
+  }
   var actions = [];
   Object.keys(datas).some((key) => {
     if (datas[key].value == ('' + value)) {
@@ -77,23 +80,31 @@ export function selectDictLabel(datas, value) {
       return true;
     }
   })
+  if (actions.length === 0) {
+    actions.push(value);
+  }
   return actions.join('');
 }
 
 // 回显数据字典(字符串数组)
 export function selectDictLabels(datas, value, separator) {
-  if(value === undefined) {
+  if (value === undefined) {
     return "";
   }
   var actions = [];
   var currentSeparator = undefined === separator ? "," : separator;
   var temp = value.split(currentSeparator);
   Object.keys(value.split(currentSeparator)).some((val) => {
+    var match = false;
     Object.keys(datas).some((key) => {
       if (datas[key].value == ('' + temp[val])) {
         actions.push(datas[key].label + currentSeparator);
+        match = true;
       }
     })
+    if (!match) {
+      actions.push(temp[val] + currentSeparator);
+    }
   })
   return actions.join('').substring(0, actions.join('').length - 1);
 }

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

@@ -101,6 +101,29 @@
             <span>更新日志</span>
           </div>
           <el-collapse accordion>
+            <el-collapse-item title="v4.0.1 - 2022-03-01">
+              <ol>
+                <li>update 图片上传 文件上传 支持并发上传</li>
+                <li>update 组件ImageUpload支持多图同时选择上传</li>
+                <li>udpate 组件fileUpload支持多文件同时选择上传</li>
+                <li>update springboot 2.6.3 => 2.6.4</li>
+                <li>update hutool 5.7.20 => 5.7.21</li>
+                <li>update qiniu 7.9.2 => 7.9.3</li>
+                <li>update minio 8.3.5 => 8.3.7</li>
+                <li>update 优化 R 默认返回 msg</li>
+                <li>update 增加 用户注册 用户类型默认值</li>
+                <li>update 增加用户登出日志</li>
+                <li>update 更新 多用户多设备的注释说明</li>
+                <li>update 优化 是否为管理员的判断</li>
+                <li>update 优化 页面若未匹配到字典标签则返回原字典值</li>
+                <li>update 调整用户登录 将日志调整到最后 防止获取不到用户警告</li>
+                <li>update 优化随机数生成方式 避免容易生成两个相同随机数的问题</li>
+                <li>fix 修复代码生成 基于路径生成 路径为空问题</li>
+                <li>fix 恢复误删 @Async 注解线程池配置类</li>
+                <li>fix 修复 minio 适配 https 导致的问题</li>
+                <li>fix 修复分页组件请求两次问题</li>
+              </ol>
+            </el-collapse-item>
             <el-collapse-item title="v4.0.0 - 2022-02-18">
               <ol>
                 <li>[重大更新] 重写项目整体结构 数据处理下沉至Mapper符合MVC规范 减少循环依赖</li>
@@ -708,7 +731,7 @@ export default {
   data() {
     return {
       // 版本号
-      version: "4.0.0",
+      version: "4.0.1",
     };
   },
   methods: {

+ 2 - 1
ruoyi-ui/src/views/register.vue

@@ -86,7 +86,8 @@ export default {
         password: "",
         confirmPassword: "",
         code: "",
-        uuid: ""
+        uuid: "",
+        user_type: "sys_user"
       },
       registerRules: {
         username: [

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

@@ -206,7 +206,7 @@ export default {
         email: [
           {
             type: "email",
-            message: "'请输入正确的邮箱地址",
+            message: "请输入正确的邮箱地址",
             trigger: ["blur", "change"]
           }
         ],

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

@@ -78,7 +78,7 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button 
+          <el-button
             size="mini"
             type="text"
             icon="el-icon-edit"
@@ -199,7 +199,7 @@
             <el-form-item>
               <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
               <span slot="label">
-                <el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
+                <el-tooltip content="控制器中定义的权限字符,如:@SaCheckPermission('system:user:list')" placement="top">
                 <i class="el-icon-question"></i>
                 </el-tooltip>
                 权限字符

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

@@ -135,7 +135,7 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="公告类型" prop="noticeType">
-              <el-select v-model="form.noticeType" placeholder="请选择">
+              <el-select v-model="form.noticeType" placeholder="请选择公告类型">
                 <el-option
                   v-for="dict in dict.type.sys_notice_type"
                   :key="dict.value"

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

@@ -248,7 +248,7 @@
         <el-row>
           <el-col :span="12">
             <el-form-item label="用户性别">
-              <el-select v-model="form.sex" placeholder="请选择">
+              <el-select v-model="form.sex" placeholder="请选择性别">
                 <el-option
                   v-for="dict in dict.type.sys_user_sex"
                   :key="dict.value"
@@ -273,7 +273,7 @@
         <el-row>
           <el-col :span="12">
             <el-form-item label="岗位">
-              <el-select v-model="form.postIds" multiple placeholder="请选择">
+              <el-select v-model="form.postIds" multiple placeholder="请选择岗位">
                 <el-option
                   v-for="item in postOptions"
                   :key="item.postId"
@@ -286,7 +286,7 @@
           </el-col>
           <el-col :span="12">
             <el-form-item label="角色">
-              <el-select v-model="form.roleIds" multiple placeholder="请选择">
+              <el-select v-model="form.roleIds" multiple placeholder="请选择角色">
                 <el-option
                   v-for="item in roleOptions"
                   :key="item.roleId"
@@ -443,7 +443,7 @@ export default {
         email: [
           {
             type: "email",
-            message: "'请输入正确的邮箱地址",
+            message: "请输入正确的邮箱地址",
             trigger: ["blur", "change"]
           }
         ],

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

@@ -42,7 +42,7 @@ export default {
           { required: true, message: "邮箱地址不能为空", trigger: "blur" },
           {
             type: "email",
-            message: "'请输入正确的邮箱地址",
+            message: "请输入正确的邮箱地址",
             trigger: ["blur", "change"]
           }
         ],

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

@@ -89,12 +89,14 @@ services:
       MINIO_ACCESS_KEY: ruoyi
       # 管理后台密码,最小8个字符
       MINIO_SECRET_KEY: ruoyi123
+      # https需要指定域名
+      MINIO_SERVER_URL: ""
     volumes:
       # 映射当前目录下的data目录至容器内/data目录
       - /docker/minio/data:/data
       # 映射配置目录
       - /docker/minio/config:/root/.minio/
-    command: server --console-address ':9001' /data  # 指定容器中的目录 /data
+    command: server --address ':9000' --console-address ':9001' /data  # 指定容器中的目录 /data
     privileged: true
     restart: always
     networks:
@@ -102,7 +104,7 @@ services:
         ipv4_address: 172.30.0.54
 
   ruoyi-server1:
-    image: ruoyi/ruoyi-server:4.0.0
+    image: ruoyi/ruoyi-server:4.0.1
     container_name: ruoyi-server1
     environment:
       # 时区上海
@@ -117,7 +119,7 @@ services:
         ipv4_address: 172.30.0.60
 
   ruoyi-server2:
-    image: "ruoyi/ruoyi-server:4.0.0"
+    image: "ruoyi/ruoyi-server:4.0.1"
     container_name: ruoyi-server2
     environment:
       # 时区上海
@@ -132,7 +134,7 @@ services:
         ipv4_address: 172.30.0.61
 
   ruoyi-monitor-admin:
-    image: ruoyi/ruoyi-monitor-admin:4.0.0
+    image: ruoyi/ruoyi-monitor-admin:4.0.1
     container_name: ruoyi-monitor-admin
     environment:
       # 时区上海
@@ -147,7 +149,7 @@ services:
         ipv4_address: 172.30.0.90
 
   ruoyi-xxl-job-admin:
-    image: ruoyi/ruoyi-xxl-job-admin:4.0.0
+    image: ruoyi/ruoyi-xxl-job-admin:4.0.1
     container_name: ruoyi-xxl-job-admin
     environment:
       # 时区上海

+ 1 - 1
script/sql/ry_vue_4.0.sql

@@ -66,7 +66,7 @@ create table sys_user (
 -- 初始化-用户信息表数据
 -- ----------------------------
 insert into sys_user values(1,  103, 'admin', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '管理员');
-insert into sys_user values(2,  105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@163.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '测试员');
+insert into sys_user values(2,  105, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '测试员');
 
 
 -- ----------------------------