From c2a179e9dd0bcc0b7f0607b0220d1264dae46461 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 20 Oct 2021 11:18:20 +0800
Subject: [PATCH 01/74] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=AE=A4=E8=AF=81?=
 =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E7=AE=80=E5=8C=96=E6=9D=83=E9=99=90=E9=AA=8C?=
 =?UTF-8?q?=E8=AF=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/plugins/auth.js  | 60 +++++++++++++++++++++++++++++++++++
 ruoyi-ui/src/plugins/index.js |  3 ++
 2 files changed, 63 insertions(+)
 create mode 100644 ruoyi-ui/src/plugins/auth.js

diff --git a/ruoyi-ui/src/plugins/auth.js b/ruoyi-ui/src/plugins/auth.js
new file mode 100644
index 000000000..af740aaef
--- /dev/null
+++ b/ruoyi-ui/src/plugins/auth.js
@@ -0,0 +1,60 @@
+import store from '@/store'
+
+function authPermission(permission) {
+  const all_permission = "*:*:*";
+  const permissions = store.getters && store.getters.permissions
+  if (permission && permission.length > 0) {
+    return permissions.some(v => {
+      return all_permission === v || v === permission
+    })
+  } else {
+    return false
+  }
+}
+
+function authRole(role) {
+  const super_admin = "admin";
+  const roles = store.getters && store.getters.roles
+  if (role && role.length > 0) {
+    return roles.some(v => {
+      return super_admin === v || v === role
+    })
+  } else {
+    return false
+  }
+}
+
+export default {
+  // 验证用户是否具备某权限
+  hasPermi(permission) {
+    return authPermission(permission);
+  },
+  // 验证用户是否含有指定权限,只需包含其中一个
+  hasPermiOr(permissions) {
+    return permissions.some(item => {
+      return authPermission(item)
+    })
+  },
+  // 验证用户是否含有指定权限,必须全部拥有
+  hasPermiAnd(permissions) {
+    return permissions.every(item => {
+      return authPermission(item)
+    })
+  },
+  // 验证用户是否具备某角色
+  hasRole(role) {
+    return authRole(role);
+  },
+  // 验证用户是否含有指定角色,只需包含其中一个
+  hasRoleOr(roles) {
+    return roles.some(item => {
+      return authRole(item)
+    })
+  },
+  // 验证用户是否含有指定角色,必须全部拥有
+  hasRoleAnd(roles) {
+    return roles.every(item => {
+      return authRole(item)
+    })
+  }
+}
diff --git a/ruoyi-ui/src/plugins/index.js b/ruoyi-ui/src/plugins/index.js
index a138e6d6f..7cc83a4c8 100644
--- a/ruoyi-ui/src/plugins/index.js
+++ b/ruoyi-ui/src/plugins/index.js
@@ -1,9 +1,12 @@
+import auth from './auth'
 import cache from './cache'
 import modal from './modal'
 import download from './download'
 
 export default {
   install(Vue) {
+    // 认证对象
+    Vue.prototype.$auth = auth
     // 缓存对象
     Vue.prototype.$cache = cache
     // 模态框对象

From 2d7d137abd0eb54a632ca2e18424348eab96cdd8 Mon Sep 17 00:00:00 2001
From: abbfun <819589789@qq.com>
Date: Fri, 22 Oct 2021 03:09:54 +0000
Subject: [PATCH 02/74] =?UTF-8?q?update=20ruoyi-common/src/main/java/com/r?=
 =?UTF-8?q?uoyi/common/core/domain/AjaxResult.java.=20AjaxResult=E9=93=BE?=
 =?UTF-8?q?=E5=BC=8F=E8=B0=83=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/ruoyi/common/core/domain/AjaxResult.java     | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
index b26e066ab..472afc868 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
@@ -145,4 +145,16 @@ public class AjaxResult extends HashMap<String, Object>
     {
         return new AjaxResult(code, msg, null);
     }
+
+	/**
+	 * 链式调用
+	 * 
+	 * @param key   键
+	 * @param value 内容
+	 * @return 警告消息
+	 */
+	public AjaxResult put(String key, Object value) {
+		super.put(key, value);
+		return this;
+	}
 }

From 3dbbc6a22360fa65c66609285f10bffc3a32334d Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Fri, 22 Oct 2021 16:23:08 +0800
Subject: [PATCH 03/74] =?UTF-8?q?AjaxResult=E9=87=8D=E5=86=99put=E6=96=B9?=
 =?UTF-8?q?=E6=B3=95=EF=BC=8C=E4=BB=A5=E6=96=B9=E4=BE=BF=E9=93=BE=E5=BC=8F?=
 =?UTF-8?q?=E8=B0=83=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ruoyi/common/core/domain/AjaxResult.java  | 24 ++++++++++---------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
index 472afc868..8ca1b9b11 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
@@ -146,15 +146,17 @@ public class AjaxResult extends HashMap<String, Object>
         return new AjaxResult(code, msg, null);
     }
 
-	/**
-	 * 链式调用
-	 * 
-	 * @param key   键
-	 * @param value 内容
-	 * @return 警告消息
-	 */
-	public AjaxResult put(String key, Object value) {
-		super.put(key, value);
-		return this;
-	}
+    /**
+     * 方便链式调用
+     *
+     * @param key 键
+     * @param value 值
+     * @return 数据对象
+     */
+    @Override
+    public AjaxResult put(String key, Object value)
+    {
+        super.put(key, value);
+        return this;
+    }
 }

From ef4fef3d56f569d151ef71a9288e9973a19f4f6d Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sat, 23 Oct 2021 10:21:02 +0800
Subject: [PATCH 04/74] update ry.sh.

---
 ry.bat | 26 +++++++++++++-------------
 ry.sh  | 12 ++++--------
 2 files changed, 17 insertions(+), 21 deletions(-)

diff --git a/ry.bat b/ry.bat
index 5de3e1503..9f16232b2 100644
--- a/ry.bat
+++ b/ry.bat
@@ -4,36 +4,36 @@ rem jarƽ
 set AppName=ruoyi-admin.jar
 
 rem JVM����
-set JVM_OPTS="-Dname=%AppName%  -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
+set JVM_OPTS="-Dname=%AppName%  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
 
 
-ECHO. 
+ECHO.
 	ECHO.  [1] ����%AppName%
 	ECHO.  [2] �ر�%AppName%
 	ECHO.  [3] ����%AppName%
 	ECHO.  [4] ����״̬ %AppName%
-	ECHO.  [5] �� �� 
-ECHO. 
+	ECHO.  [5] �� ��
+ECHO.
 
 ECHO.������ѡ����Ŀ�����:
 set /p ID=
-	IF "%id%"=="1" GOTO start 
-	IF "%id%"=="2" GOTO stop 
-	IF "%id%"=="3" GOTO restart 
+	IF "%id%"=="1" GOTO start
+	IF "%id%"=="2" GOTO stop
+	IF "%id%"=="3" GOTO restart
 	IF "%id%"=="4" GOTO status
 	IF "%id%"=="5" EXIT
-PAUSE 
+PAUSE
 :start
     for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do (
 		set pid=%%a
 		set image_name=%%b
 	)
 	if  defined pid (
-		echo %%is running 
-		PAUSE 
-	) 
+		echo %%is running
+		PAUSE
+	)
 
-start javaw -jar %JAVA_OPTS% ruoyi-admin.jar
+start javaw %JAVA_OPTS% -jar %AppName%
 
 echo  starting����
 echo  Start %AppName% success...
@@ -64,4 +64,4 @@ goto:eof
 	if not defined pid (echo process %AppName% is dead ) else (
 		echo %image_name% is running
 	)
-goto:eof
\ No newline at end of file
+goto:eof
diff --git a/ry.sh b/ry.sh
index 7c4f50385..d6a9cf33a 100644
--- a/ry.sh
+++ b/ry.sh
@@ -1,13 +1,9 @@
 #!/bin/sh
-# author ruoyi
-# ./ry.sh start 启动
-# ./ry.sh stop 停止
-# ./ry.sh restart 重启
-# ./ry.sh status 状态
+# ./ry.sh start 启动 stop 停止 restart 重启 status 状态
 AppName=ruoyi-admin.jar
 
 # JVM参数
-JVM_OPTS="-Dname=$AppName  -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
+JVM_OPTS="-Dname=$AppName  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
 APP_HOME=`pwd`
 LOG_PATH=$APP_HOME/logs/$AppName.log
 
@@ -30,7 +26,7 @@ function start()
 	if [ x"$PID" != x"" ]; then
 	    echo "$AppName is running..."
 	else
-		nohup java -jar  $JVM_OPTS target/$AppName > /dev/null 2>&1 &
+		nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 &
 		echo "Start $AppName success..."
 	fi
 }
@@ -38,7 +34,7 @@ function start()
 function stop()
 {
     echo "Stop $AppName"
-	
+
 	PID=""
 	query(){
 		PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`

From a4558c32b2b7630236f9f4323c79033879c1378b Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sat, 23 Oct 2021 10:23:32 +0800
Subject: [PATCH 05/74] =?UTF-8?q?=E8=A7=A3=E6=9E=90blob=E5=93=8D=E5=BA=94?=
 =?UTF-8?q?=E6=98=AF=E5=90=A6=E7=99=BB=E5=BD=95=E5=A4=B1=E6=95=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/plugins/download.js | 45 +++++++++++++++++++++++++-------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/ruoyi-ui/src/plugins/download.js b/ruoyi-ui/src/plugins/download.js
index cb10ab0e4..2aa81229a 100644
--- a/ruoyi-ui/src/plugins/download.js
+++ b/ruoyi-ui/src/plugins/download.js
@@ -1,6 +1,7 @@
 import { saveAs } from 'file-saver'
 import axios from 'axios'
 import { getToken } from '@/utils/auth'
+import { Message } from 'element-ui'
 
 const baseURL = process.env.VUE_APP_BASE_API
 
@@ -12,9 +13,14 @@ export default {
       url: url,
       responseType: 'blob',
       headers: { 'Authorization': 'Bearer ' + getToken() }
-    }).then(res => {
-      const blob = new Blob([res.data])
-      this.saveAs(blob, decodeURI(res.headers['download-filename']))
+    }).then(async (res) => {
+      const isLogin = await this.blobValidate(res.data);
+      if (isLogin) {
+        const blob = new Blob([res.data])
+        this.saveAs(blob, decodeURI(res.headers['download-filename']))
+      } else {
+        Message.error('无效的会话,或者会话已过期,请重新登录。');
+      }
     })
   },
   resource(resource) {
@@ -24,9 +30,14 @@ export default {
       url: url,
       responseType: 'blob',
       headers: { 'Authorization': 'Bearer ' + getToken() }
-    }).then(res => {
-      const blob = new Blob([res.data])
-      this.saveAs(blob, decodeURI(res.headers['download-filename']))
+    }).then(async (res) => {
+      const isLogin = await this.blobValidate(res.data);
+      if (isLogin) {
+        const blob = new Blob([res.data])
+        this.saveAs(blob, decodeURI(res.headers['download-filename']))
+      } else {
+        Message.error('无效的会话,或者会话已过期,请重新登录。');
+      }
     })
   },
   zip(url, name) {
@@ -36,13 +47,27 @@ export default {
       url: url,
       responseType: 'blob',
       headers: { 'Authorization': 'Bearer ' + getToken() }
-    }).then(res => {
-      const blob = new Blob([res.data], { type: 'application/zip' })
-      this.saveAs(blob, name)
+    }).then(async (res) => {
+      const isLogin = await this.blobValidate(res.data);
+      if (isLogin) {
+        const blob = new Blob([res.data], { type: 'application/zip' })
+        this.saveAs(blob, name)
+      } else {
+        Message.error('无效的会话,或者会话已过期,请重新登录。');
+      }
     })
   },
   saveAs(text, name, opts) {
     saveAs(text, name, opts);
-  }
+  },
+  async blobValidate(data) {
+    try {
+      const text = await data.text();
+      JSON.parse(text);
+      return false;
+    } catch (error) {
+      return true;
+    }
+  },
 }
 

From 17550a5f4bd152bb67a0de2c1284e2eef243777c Mon Sep 17 00:00:00 2001
From: Remenber_Ray <343509740@qq.com>
Date: Sun, 24 Oct 2021 02:34:25 +0000
Subject: [PATCH 06/74] =?UTF-8?q?update=20ruoyi-common/src/main/java/com/r?=
 =?UTF-8?q?uoyi/common/utils/Threads.java.=20=E4=BF=AE=E5=A4=8D=E6=8F=8F?=
 =?UTF-8?q?=E8=BF=B0=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
index 395920a24..f34935284 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
@@ -36,7 +36,7 @@ public class Threads
      * 停止线程池
      * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
      * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
-     * 如果仍人超時,則強制退出.
+     * 如果仍然超時,則強制退出.
      * 另对在shutdown时线程本身被调用中断做了处理.
      */
     public static void shutdownAndAwaitTermination(ExecutorService pool)

From 4583787759c30499cfb756615f9a10b4f7bbe281 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?=
 <15040126243@163.com>
Date: Sun, 24 Oct 2021 17:13:04 +0800
Subject: [PATCH 07/74] =?UTF-8?q?fix=20=20=E8=B7=A8=E5=9F=9F=E8=AE=BF?=
 =?UTF-8?q?=E9=97=AE=E4=B9=8B=E5=90=8E=20=E4=B8=8B=E8=BD=BD=E6=97=A0?=
 =?UTF-8?q?=E6=B3=95=E8=8E=B7=E5=8F=96=20download-filename?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/ruoyi/common/utils/file/FileUtils.java    | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
index 8d8f5a6a3..dd1bcc46f 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
@@ -210,6 +210,8 @@ public class FileUtils
                 .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);
     }

From 8a7dcf8a80583eb5710a336c89be63541c3054f0 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 25 Oct 2021 10:26:00 +0800
Subject: [PATCH 08/74] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=94=99=E5=88=AB?=
 =?UTF-8?q?=E5=AD=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/ruoyi/common/annotation/RepeatSubmit.java   | 2 +-
 .../java/com/ruoyi/framework/aspectj/RateLimiterAspect.java   | 4 ++--
 ruoyi-ui/src/layout/components/Settings/index.vue             | 4 ++--
 ruoyi-ui/src/views/index.vue                                  | 2 +-
 ruoyi-ui/src/views/monitor/cache/index.vue                    | 2 +-
 ruoyi-ui/src/views/monitor/server/index.vue                   | 2 +-
 ruoyi-ui/src/views/system/role/index.vue                      | 4 ++--
 7 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
index 408300525..1e2774350 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
@@ -27,5 +27,5 @@ public @interface RepeatSubmit
     /**
      * 提示消息
      */
-    public String message() default "不允许重复提交,请稍后再试";
+    public String message() default "不允许重复提交,请稍候再试";
 }
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
index 5020d000b..7b8ccf1d3 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
@@ -61,7 +61,7 @@ public class RateLimiterAspect
             Long number = redisTemplate.execute(limitScript, keys, count, time);
             if (StringUtils.isNull(number) || number.intValue() > count)
             {
-                throw new ServiceException("访问过于频繁,请稍后再试");
+                throw new ServiceException("访问过于频繁,请稍候再试");
             }
             log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), key);
         }
@@ -71,7 +71,7 @@ public class RateLimiterAspect
         }
         catch (Exception e)
         {
-            throw new RuntimeException("服务器限流异常,请稍后再试");
+            throw new RuntimeException("服务器限流异常,请稍候再试");
         }
     }
 
diff --git a/ruoyi-ui/src/layout/components/Settings/index.vue b/ruoyi-ui/src/layout/components/Settings/index.vue
index 4dff1d0c5..bd2f553cf 100644
--- a/ruoyi-ui/src/layout/components/Settings/index.vue
+++ b/ruoyi-ui/src/layout/components/Settings/index.vue
@@ -162,7 +162,7 @@ export default {
       this.sideTheme = val;
     },
     saveSetting() {
-      this.$modal.loading("正在保存到本地,请稍后...");
+      this.$modal.loading("正在保存到本地,请稍候...");
       this.$cache.local.set(
         "layout-setting",
         `{
@@ -178,7 +178,7 @@ export default {
       setTimeout(this.$modal.closeLoading(), 1000)
     },
     resetSetting() {
-      this.$modal.loading("正在清除设置缓存并刷新,请稍后...");
+      this.$modal.loading("正在清除设置缓存并刷新,请稍候...");
       this.$cache.local.remove("layout-setting")
       setTimeout("window.location.reload()", 1000)
     }
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index 00379e5aa..46811841b 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -590,7 +590,7 @@
                 <li>修复表格时间为空出现的异常</li>
                 <li>添加Jackson日期反序列化时区配置</li>
                 <li>调整根据用户权限加载菜单数据树形结构</li>
-                <li>调整成功登陆不恢复按钮,防止多次点击</li>
+                <li>调整成功登录不恢复按钮,防止多次点击</li>
                 <li>修改用户个人资料同步缓存信息</li>
                 <li>修复页面同时出现el-upload和Editor不显示处理</li>
                 <li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
diff --git a/ruoyi-ui/src/views/monitor/cache/index.vue b/ruoyi-ui/src/views/monitor/cache/index.vue
index 22501dc34..cafa28cfb 100644
--- a/ruoyi-ui/src/views/monitor/cache/index.vue
+++ b/ruoyi-ui/src/views/monitor/cache/index.vue
@@ -139,7 +139,7 @@ export default {
     },
     // 打开加载层
     openLoading() {
-      this.$modal.loading("正在加载缓存监控数据,请稍后!");
+      this.$modal.loading("正在加载缓存监控数据,请稍候!");
     },
   },
 };
diff --git a/ruoyi-ui/src/views/monitor/server/index.vue b/ruoyi-ui/src/views/monitor/server/index.vue
index 503bf9b61..3eaaea0e1 100644
--- a/ruoyi-ui/src/views/monitor/server/index.vue
+++ b/ruoyi-ui/src/views/monitor/server/index.vue
@@ -196,7 +196,7 @@ export default {
     },
     // 打开加载层
     openLoading() {
-      this.$modal.loading("正在加载服务监控数据,请稍后!");
+      this.$modal.loading("正在加载服务监控数据,请稍候!");
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue
index 6e5855863..5110834d4 100644
--- a/ruoyi-ui/src/views/system/role/index.vue
+++ b/ruoyi-ui/src/views/system/role/index.vue
@@ -200,7 +200,7 @@
             ref="menu"
             node-key="id"
             :check-strictly="!form.menuCheckStrictly"
-            empty-text="加载中,请稍后"
+            empty-text="加载中,请稍候"
             :props="defaultProps"
           ></el-tree>
         </el-form-item>
@@ -245,7 +245,7 @@
             ref="dept"
             node-key="id"
             :check-strictly="!form.deptCheckStrictly"
-            empty-text="加载中,请稍后"
+            empty-text="加载中,请稍候"
             :props="defaultProps"
           ></el-tree>
         </el-form-item>

From 790aa0d24bee0036d9a697a18c130d531649213b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=9B=AA=E4=B8=9B?=
 <8461269+ouwei2020@user.noreply.gitee.com>
Date: Tue, 26 Oct 2021 01:42:12 +0000
Subject: [PATCH 09/74] =?UTF-8?q?update=20ruoyi-common/src/main/java/com/r?=
 =?UTF-8?q?uoyi/common/core/redis/RedisCache.java.=20=E5=A2=9E=E5=8A=A0?=
 =?UTF-8?q?=E5=88=A0=E9=99=A4Hash=E4=B8=AD=E7=9A=84=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/ruoyi/common/core/redis/RedisCache.java | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
index 238753359..3246b7731 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
@@ -209,6 +209,18 @@ public class RedisCache
         return opsForHash.get(key, hKey);
     }
 
+    /**
+     * 删除Hash中的数据
+     * 
+     * @param key
+     * @param mapkey
+     */
+    public void delCacheMapValue(final String key, final String hkey)
+    {
+        HashOperations hashOperations = redisTemplate.opsForHash();
+        hashOperations.delete(key, hkey);
+    }
+
     /**
      * 获取多个Hash中的数据
      *

From 0628dc9b2f175602e9d4cc921986318d331abc23 Mon Sep 17 00:00:00 2001
From: Remenber_Ray <343509740@qq.com>
Date: Tue, 26 Oct 2021 08:02:48 +0000
Subject: [PATCH 10/74] update
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java.

---
 .../java/com/ruoyi/system/service/impl/SysUserServiceImpl.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
index b3febada9..7e8443c0f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -179,7 +179,7 @@ public class SysUserServiceImpl implements ISysUserService
     }
 
     /**
-     * 校验用户名称是否唯一
+     * 校验手机号码是否唯一
      *
      * @param user 用户信息
      * @return

From b6596d021b6216bd7750614e5588b319b4a5ce83 Mon Sep 17 00:00:00 2001
From: Ricky <hk_ricky@163.com>
Date: Tue, 26 Oct 2021 17:22:20 +0800
Subject: [PATCH 11/74] =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E8=87=AA=E5=AE=9A?=
 =?UTF-8?q?=E4=B9=89=E9=AA=8C=E8=AF=81=E6=B3=A8=E8=A7=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-common/pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 486d39f8c..eb84d30ce 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -43,8 +43,8 @@
 
         <!-- 自定义验证注解 -->
         <dependency>
-            <groupId>javax.validation</groupId>
-            <artifactId>validation-api</artifactId>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
         </dependency>
 
         <!--常用工具类 -->

From 839f631d6ba36b1e2c5cbfcd7d414f62d3afd840 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 27 Oct 2021 16:22:57 +0800
Subject: [PATCH 12/74] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Jaxb=E4=BE=9D=E8=B5=96?=
 =?UTF-8?q?=EF=BC=8C=E9=98=B2=E6=AD=A2jdk8=E4=BB=A5=E4=B8=8A=E5=87=BA?=
 =?UTF-8?q?=E7=8E=B0=E7=9A=84=E5=85=BC=E5=AE=B9=E9=94=99=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-common/pom.xml | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index eb84d30ce..278434bbe 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -89,12 +89,18 @@
             <artifactId>snakeyaml</artifactId>
         </dependency>
 
-        <!--Token生成与解析-->
+        <!-- Token生成与解析-->
         <dependency>
             <groupId>io.jsonwebtoken</groupId>
             <artifactId>jjwt</artifactId>
         </dependency>
 
+        <!-- Jaxb -->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+        </dependency>
+
         <!-- redis 缓存操作 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>

From 2eb55528ec9e736f9754c86d5984f5dc8ea819d8 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 27 Oct 2021 16:23:35 +0800
Subject: [PATCH 13/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7spring-boot=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC2.5.6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 6feb0ee79..2f3dd728d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -43,7 +43,7 @@
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-dependencies</artifactId>
-                <version>2.5.5</version>
+                <version>2.5.6</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>

From 13c770b6beedaee905d99d44bcd5c3378eeda0da Mon Sep 17 00:00:00 2001
From: Awen <39176130+yu1183688986@users.noreply.github.com>
Date: Wed, 27 Oct 2021 19:03:29 +0800
Subject: [PATCH 14/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=80=E4=BA=9B?=
 =?UTF-8?q?=E5=B8=83=E5=B0=94=E5=88=A4=E6=96=AD=E8=AF=AD=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/ruoyi/common/utils/html/HTMLFilter.java | 2 +-
 .../src/main/java/com/ruoyi/common/utils/uuid/UUID.java   | 8 ++++----
 .../com/ruoyi/system/service/impl/SysDeptServiceImpl.java | 6 +++---
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
index 415acbab2..d3b211a48 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
@@ -332,7 +332,7 @@ public final class HTMLFilter
             final String name = m.group(1).toLowerCase();
             if (allowed(name))
             {
-                if (false == inArray(name, vSelfClosingTags))
+                if (!inArray(name, vSelfClosingTags))
                 {
                     if (vTagCounts.containsKey(name))
                     {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
index eef72ee0b..c0c18af01 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
@@ -343,25 +343,25 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
         final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
         // time_low
         builder.append(digits(mostSigBits >> 32, 8));
-        if (false == isSimple)
+        if (!isSimple)
         {
             builder.append('-');
         }
         // time_mid
         builder.append(digits(mostSigBits >> 16, 4));
-        if (false == isSimple)
+        if (!isSimple)
         {
             builder.append('-');
         }
         // time_high_and_version
         builder.append(digits(mostSigBits, 4));
-        if (false == isSimple)
+        if (!isSimple)
         {
             builder.append('-');
         }
         // variant_and_sequence
         builder.append(digits(leastSigBits >> 48, 4));
-        if (false == isSimple)
+        if (!isSimple)
         {
             builder.append('-');
         }
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
index a2c3b5b1e..9bf8fe0e1 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -140,7 +140,7 @@ public class SysDeptServiceImpl implements ISysDeptService
     public boolean hasChildByDeptId(Long deptId)
     {
         int result = deptMapper.hasChildByDeptId(deptId);
-        return result > 0 ? true : false;
+        return result > 0;
     }
 
     /**
@@ -153,7 +153,7 @@ public class SysDeptServiceImpl implements ISysDeptService
     public boolean checkDeptExistUser(Long deptId)
     {
         int result = deptMapper.checkDeptExistUser(deptId);
-        return result > 0 ? true : false;
+        return result > 0;
     }
 
     /**
@@ -325,6 +325,6 @@ public class SysDeptServiceImpl implements ISysDeptService
      */
     private boolean hasChild(List<SysDept> list, SysDept t)
     {
-        return getChildList(list, t).size() > 0 ? true : false;
+        return getChildList(list, t).size() > 0;
     }
 }

From 3ae5ec92a530e5f14720a8b7d490959430399b11 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 1 Nov 2021 13:29:27 +0800
Subject: [PATCH 15/74] =?UTF-8?q?=E7=99=BB=E5=BD=95/=E9=AA=8C=E8=AF=81?=
 =?UTF-8?q?=E7=A0=81=E8=AF=B7=E6=B1=82headers=E4=B8=8D=E8=AE=BE=E7=BD=AEto?=
 =?UTF-8?q?ken?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/api/login.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ruoyi-ui/src/api/login.js b/ruoyi-ui/src/api/login.js
index 224561606..26742e79c 100644
--- a/ruoyi-ui/src/api/login.js
+++ b/ruoyi-ui/src/api/login.js
@@ -10,6 +10,9 @@ export function login(username, password, code, uuid) {
   }
   return request({
     url: '/login',
+    headers: {
+      isToken: false
+    },
     method: 'post',
     data: data
   })
@@ -47,6 +50,9 @@ export function logout() {
 export function getCodeImg() {
   return request({
     url: '/captchaImage',
+    headers: {
+      isToken: false
+    },
     method: 'get',
     timeout: 20000
   })

From 181f62c15ead24c5e56b77dde3bbf443430691bf Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 1 Nov 2021 14:40:00 +0800
Subject: [PATCH 16/74] =?UTF-8?q?=E5=9B=9E=E6=98=BE=E6=95=B0=E6=8D=AE?=
 =?UTF-8?q?=E5=AD=97=E5=85=B8=E9=94=AE=E5=80=BC=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/utils/ruoyi.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js
index 63bd379b7..440bf4cd8 100644
--- a/ruoyi-ui/src/utils/ruoyi.js
+++ b/ruoyi-ui/src/utils/ruoyi.js
@@ -85,8 +85,8 @@ export function selectDictLabels(datas, value, separator) {
 	var temp = value.split(currentSeparator);
 	Object.keys(value.split(currentSeparator)).some((val) => {
 		Object.keys(datas).some((key) => {
-			if (datas[key].dictValue == ('' + temp[val])) {
-				actions.push(datas[key].dictLabel + currentSeparator);
+			if (datas[key].value == ('' + temp[val])) {
+				actions.push(datas[key].label + currentSeparator);
 			}
 		})
 	})

From bd09e5b11ccb425d2b280c96b98dc110b1bb2c59 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 1 Nov 2021 15:02:47 +0800
Subject: [PATCH 17/74] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AD=97=E7=AC=A6?=
 =?UTF-8?q?=E4=B8=B2=E6=97=A0=E6=B3=95=E8=A2=AB=E5=8F=8D=E8=BD=AC=E4=B9=89?=
 =?UTF-8?q?=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ruoyi/common/utils/html/EscapeUtil.java   | 34 +++++++++++++------
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
index 65fd7920f..dda96c32f 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
@@ -69,26 +69,37 @@ public class EscapeUtil
      */
     private static String encode(String text)
     {
-        int len;
-        if ((text == null) || ((len = text.length()) == 0))
+        if (StringUtils.isEmpty(text))
         {
             return StringUtils.EMPTY;
         }
-        StringBuilder buffer = new StringBuilder(len + (len >> 2));
+
+        final StringBuilder tmp = new StringBuilder(text.length() * 6);
         char c;
-        for (int i = 0; i < len; i++)
+        for (int i = 0; i < text.length(); i++)
         {
             c = text.charAt(i);
-            if (c < 64)
+            if (c < 256)
             {
-                buffer.append(TEXT[c]);
+                tmp.append("%");
+                if (c < 16)
+                {
+                    tmp.append("0");
+                }
+                tmp.append(Integer.toString(c, 16));
             }
             else
             {
-                buffer.append(c);
+                tmp.append("%u");
+                if (c <= 0xfff)
+                {
+                    // issue#I49JU8@Gitee
+                    tmp.append("0");
+                }
+                tmp.append(Integer.toString(c, 16));
             }
         }
-        return buffer.toString();
+        return tmp.toString();
     }
 
     /**
@@ -145,11 +156,12 @@ public class EscapeUtil
     public static void main(String[] args)
     {
         String html = "<script>alert(1);</script>";
+        String escape = EscapeUtil.escape(html);
         // String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
         // String html = "<123";
         // String html = "123>";
-        System.out.println(EscapeUtil.clean(html));
-        System.out.println(EscapeUtil.escape(html));
-        System.out.println(EscapeUtil.unescape(html));
+        System.out.println("clean: " + EscapeUtil.clean(html));
+        System.out.println("escape: " + escape);
+        System.out.println("unescape: " + EscapeUtil.unescape(escape));
     }
 }

From cc4c52c998f5ffd6adc63d62d870ce76ffa9ae61 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 1 Nov 2021 15:03:06 +0800
Subject: [PATCH 18/74] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=B1=8F=E8=94=BD?=
 =?UTF-8?q?=E8=BF=9D=E8=A7=84=E5=AD=97=E7=AC=A6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../main/java/com/ruoyi/common/constant/Constants.java    | 8 +++++++-
 .../com/ruoyi/quartz/controller/SysJobController.java     | 8 ++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
index 9f55771bf..9e770c812 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -148,4 +148,10 @@ public class Constants
      * LDAP 远程方法调用
      */
     public static final String LOOKUP_LDAP = "ldap://";
-}
+
+    /**
+     * 定时任务违规的字符
+     */
+    public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+            "org.springframework.jndi" };
+}
\ No newline at end of file
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
index c9616c2f6..2f3ddab6f 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
@@ -96,6 +96,10 @@ public class SysJobController extends BaseController
         {
             return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用");
         }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+        {
+            return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        }
         job.setCreateBy(getUsername());
         return toAjax(jobService.insertJob(job));
     }
@@ -124,6 +128,10 @@ public class SysJobController extends BaseController
         {
             return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)//'调用");
         }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+        {
+            return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        }
         job.setUpdateBy(getUsername());
         return toAjax(jobService.updateJob(job));
     }

From bbbe83b737bb39804967a23502cbf9af135db164 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 2 Nov 2021 14:40:21 +0800
Subject: [PATCH 19/74] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=BE=A4?=
 =?UTF-8?q?=E5=8F=B7=EF=BC=9A101539465?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md                    | 2 +-
 ruoyi-ui/src/views/index.vue | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index f1ec311a8..0c10287a4 100644
--- a/README.md
+++ b/README.md
@@ -82,4 +82,4 @@
 
 ## 若依前后端分离交流群
 
-QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) 点击按钮入群。
\ No newline at end of file
+QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) 点击按钮入群。
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index 46811841b..4609c136e 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -120,9 +120,9 @@
             <p>
               <i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>
               <s>满887144332</s> <s>满180251782</s> <s>满104180207</s>
-              <s>满186866453</s> <s>满201396349</s>
-              <a href="https://jq.qq.com/?_wv=1027&k=TULPgzYe" target="_blank">
-                101456076</a
+              <s>满186866453</s> <s>满201396349</s> <s>满101456076</s>
+              <a href="https://jq.qq.com/?_wv=1027&k=KmQbXyJ6" target="_blank">
+                101539465</a
               >
             </p>
             <p>

From d185d4e4ccaba6480bedf7a497cb7d5b633576cb Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 10 Nov 2021 11:13:27 +0800
Subject: [PATCH 20/74] =?UTF-8?q?=E5=A2=9E=E5=8A=A0sendGet=E6=97=A0?=
 =?UTF-8?q?=E5=8F=82=E8=AF=B7=E6=B1=82=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/ruoyi/common/utils/http/HttpUtils.java   | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
index c920f5b12..f57baf0fc 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
@@ -30,6 +30,17 @@ public class HttpUtils
 {
     private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
 
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url)
+    {
+        return sendGet(url, StringUtils.EMPTY);
+    }
+
     /**
      * 向指定 URL 发送GET方法的请求
      *

From 4e817a11092343ff0bac1e80cbbb486e189075fe Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 10 Nov 2021 11:14:50 +0800
Subject: [PATCH 21/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7axios=E5=88=B0=E6=9C=80?=
 =?UTF-8?q?=E6=96=B0=E7=89=88=E6=9C=AC0.24.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 034e0642d..fd8630ddc 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -37,7 +37,7 @@
   },
   "dependencies": {
     "@riophae/vue-treeselect": "0.4.0",
-    "axios": "0.21.0",
+    "axios": "0.24.0",
     "clipboard": "2.0.6",
     "core-js": "3.8.1",
     "echarts": "4.9.0",

From b00171366ff27099133675f8bd66464b5e037867 Mon Sep 17 00:00:00 2001
From: XTvLi <948038320@qq.com>
Date: Wed, 10 Nov 2021 18:17:43 +0800
Subject: [PATCH 22/74] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=85=A8=E5=B1=80?=
 =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=86=85=E5=AE=B9,=20=E5=88=A0=E9=99=A4?=
 =?UTF-8?q?=E4=B8=B4=E6=97=B6=E8=B0=83=E7=94=A8=E9=85=8D=E7=BD=AE=E6=96=87?=
 =?UTF-8?q?=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../web/controller/common/CaptchaController.java      |  7 ++-----
 .../java/com/ruoyi/common/config/RuoYiConfig.java     | 11 +++++++++++
 2 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
index 649fd115e..955c78436 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
@@ -6,8 +6,8 @@ import java.util.concurrent.TimeUnit;
 import javax.annotation.Resource;
 import javax.imageio.ImageIO;
 import javax.servlet.http.HttpServletResponse;
+import com.ruoyi.common.config.RuoYiConfig;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.util.FastByteArrayOutputStream;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -36,10 +36,6 @@ public class CaptchaController
     @Autowired
     private RedisCache redisCache;
     
-    // 验证码类型
-    @Value("${ruoyi.captchaType}")
-    private String captchaType;
-    
     @Autowired
     private ISysConfigService configService;
     /**
@@ -64,6 +60,7 @@ public class CaptchaController
         BufferedImage image = null;
 
         // 生成验证码
+        String captchaType = RuoYiConfig.getCaptchaType();
         if ("math".equals(captchaType))
         {
             String capText = captchaProducerMath.createText();
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
index 843b91912..84c0029db 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
@@ -30,6 +30,9 @@ public class RuoYiConfig
     /** 获取地址开关 */
     private static boolean addressEnabled;
 
+    /** 验证码类型 */
+    private static String captchaType;
+
     public String getName()
     {
         return name;
@@ -90,6 +93,14 @@ public class RuoYiConfig
         RuoYiConfig.addressEnabled = addressEnabled;
     }
 
+    public static String getCaptchaType() {
+        return captchaType;
+    }
+
+    public void setCaptchaType(String captchaType) {
+        RuoYiConfig.captchaType = captchaType;
+    }
+
     /**
      * 获取导入上传路径
      */

From cb9c0e79ebadd5d219f60a2830e36e50868354cb Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 16 Nov 2021 14:15:17 +0800
Subject: [PATCH 23/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7core-js=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC3.19.1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index fd8630ddc..45f5508e6 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -39,7 +39,7 @@
     "@riophae/vue-treeselect": "0.4.0",
     "axios": "0.24.0",
     "clipboard": "2.0.6",
-    "core-js": "3.8.1",
+    "core-js": "3.19.1",
     "echarts": "4.9.0",
     "element-ui": "2.15.6",
     "file-saver": "2.0.5",

From 2ab96587ef8a2fab5e22ed786ff11953d2f2b0e2 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 16 Nov 2021 16:05:15 +0800
Subject: [PATCH 24/74] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E5=8F=82=E6=95=B0?=
 =?UTF-8?q?=E5=BF=BD=E7=95=A5=E5=8F=8C=E5=BC=95=E5=8F=B7=E4=B8=AD=E7=9A=84?=
 =?UTF-8?q?=E9=80=97=E5=8F=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
index 5519c672f..4cde0ec44 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
@@ -110,7 +110,7 @@ public class JobInvokeUtil
         {
             return null;
         }
-        String[] methodParams = methodStr.split(",");
+        String[] methodParams = methodStr.split(",(?=(?:[^\']*\"[^\']*\')*[^\']*$)");
         List<Object[]> classs = new LinkedList<>();
         for (int i = 0; i < methodParams.length; i++)
         {

From cedd2d1daf444c0f74ca2a7844e769d524877279 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 17 Nov 2021 11:57:17 +0800
Subject: [PATCH 25/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=BC=E5=87=BA?=
 =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=93=8D=E4=BD=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../monitor/SysLogininforController.java      |  8 ++-
 .../monitor/SysOperlogController.java         |  8 ++-
 .../system/SysConfigController.java           |  9 ++-
 .../system/SysDictDataController.java         |  7 +-
 .../system/SysDictTypeController.java         |  7 +-
 .../controller/system/SysPostController.java  |  7 +-
 .../controller/system/SysRoleController.java  |  7 +-
 .../controller/system/SysUserController.java  | 13 ++--
 .../com/ruoyi/common/utils/poi/ExcelUtil.java | 17 +++--
 .../main/resources/vm/java/controller.java.vm |  7 +-
 .../src/main/resources/vm/vue/index.vue.vm    | 16 ++---
 .../quartz/controller/SysJobController.java   |  7 +-
 .../controller/SysJobLogController.java       |  8 ++-
 ruoyi-ui/src/api/monitor/job.js               |  9 ---
 ruoyi-ui/src/api/monitor/jobLog.js            |  9 ---
 ruoyi-ui/src/api/monitor/logininfor.js        |  9 ---
 ruoyi-ui/src/api/monitor/operlog.js           |  9 ---
 ruoyi-ui/src/api/system/config.js             |  9 ---
 ruoyi-ui/src/api/system/dict/data.js          |  9 ---
 ruoyi-ui/src/api/system/dict/type.js          |  9 ---
 ruoyi-ui/src/api/system/post.js               |  9 ---
 ruoyi-ui/src/api/system/role.js               |  9 ---
 ruoyi-ui/src/api/system/user.js               | 17 -----
 ruoyi-ui/src/main.js                          |  2 +
 ruoyi-ui/src/plugins/download.js              | 18 ++---
 ruoyi-ui/src/utils/request.js                 | 68 ++++++++++++-------
 ruoyi-ui/src/utils/ruoyi.js                   | 37 ++++++++++
 ruoyi-ui/src/views/monitor/job/index.vue      | 16 ++---
 ruoyi-ui/src/views/monitor/job/log.vue        | 16 ++---
 .../src/views/monitor/logininfor/index.vue    | 16 ++---
 ruoyi-ui/src/views/monitor/operlog/index.vue  | 16 ++---
 ruoyi-ui/src/views/system/config/index.vue    | 16 ++---
 ruoyi-ui/src/views/system/dict/data.vue       | 16 ++---
 ruoyi-ui/src/views/system/dict/index.vue      | 16 ++---
 ruoyi-ui/src/views/system/post/index.vue      | 16 ++---
 ruoyi-ui/src/views/system/role/index.vue      | 16 ++---
 ruoyi-ui/src/views/system/user/index.vue      | 22 ++----
 37 files changed, 192 insertions(+), 318 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
index 14f57fdaf..5bd40baed 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
@@ -1,11 +1,13 @@
 package com.ruoyi.web.controller.monitor;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.annotation.Log;
@@ -40,12 +42,12 @@ public class SysLogininforController extends BaseController
 
     @Log(title = "登录日志", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysLogininfor logininfor)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysLogininfor logininfor)
     {
         List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
         ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
-        return util.exportExcel(list, "登录日志");
+        util.exportExcel(response, list, "登录日志");
     }
 
     @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
index 75bf12682..4ce126a54 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
@@ -1,11 +1,13 @@
 package com.ruoyi.web.controller.monitor;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.annotation.Log;
@@ -40,12 +42,12 @@ public class SysOperlogController extends BaseController
 
     @Log(title = "操作日志", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysOperLog operLog)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysOperLog operLog)
     {
         List<SysOperLog> list = operLogService.selectOperLogList(operLog);
         ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
-        return util.exportExcel(list, "操作日志");
+        util.exportExcel(response, list, "操作日志");
     }
 
     @Log(title = "操作日志", businessType = BusinessType.DELETE)
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
index dc2532fbc..04f71629a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
@@ -1,6 +1,7 @@
 package com.ruoyi.web.controller.system;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -13,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
@@ -49,12 +49,12 @@ public class SysConfigController extends BaseController
 
     @Log(title = "参数管理", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:config:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysConfig config)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysConfig config)
     {
         List<SysConfig> list = configService.selectConfigList(config);
         ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
-        return util.exportExcel(list, "参数数据");
+        util.exportExcel(response, list, "参数数据");
     }
 
     /**
@@ -82,7 +82,6 @@ public class SysConfigController extends BaseController
     @PreAuthorize("@ss.hasPermi('system:config:add')")
     @Log(title = "参数管理", businessType = BusinessType.INSERT)
     @PostMapping
-    @RepeatSubmit
     public AjaxResult add(@Validated @RequestBody SysConfig config)
     {
         if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
index b9e3dc3b1..eea89fd0d 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
@@ -2,6 +2,7 @@ package com.ruoyi.web.controller.system;
 
 import java.util.ArrayList;
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -50,12 +51,12 @@ public class SysDictDataController extends BaseController
 
     @Log(title = "字典数据", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:dict:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysDictData dictData)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysDictData dictData)
     {
         List<SysDictData> list = dictDataService.selectDictDataList(dictData);
         ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
-        return util.exportExcel(list, "字典数据");
+        util.exportExcel(response, list, "字典数据");
     }
 
     /**
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
index acad00e26..0dd3474cf 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
@@ -1,6 +1,7 @@
 package com.ruoyi.web.controller.system;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -45,12 +46,12 @@ public class SysDictTypeController extends BaseController
 
     @Log(title = "字典类型", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:dict:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysDictType dictType)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysDictType dictType)
     {
         List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
         ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
-        return util.exportExcel(list, "字典类型");
+        util.exportExcel(response, list, "字典类型");
     }
 
     /**
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
index 30a87616c..1a2b408ed 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
@@ -1,6 +1,7 @@
 package com.ruoyi.web.controller.system;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -48,12 +49,12 @@ public class SysPostController extends BaseController
     
     @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:post:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysPost post)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysPost post)
     {
         List<SysPost> list = postService.selectPostList(post);
         ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
-        return util.exportExcel(list, "岗位数据");
+        util.exportExcel(response, list, "岗位数据");
     }
 
     /**
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
index d73749086..d70fa8158 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -1,6 +1,7 @@
 package com.ruoyi.web.controller.system;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
@@ -61,12 +62,12 @@ public class SysRoleController extends BaseController
 
     @Log(title = "角色管理", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:role:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysRole role)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysRole role)
     {
         List<SysRole> list = roleService.selectRoleList(role);
         ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
-        return util.exportExcel(list, "角色数据");
+        util.exportExcel(response, list, "角色数据");
     }
 
     /**
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
index 6cfbfb8d7..9aacc3be0 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -2,6 +2,7 @@ package com.ruoyi.web.controller.system;
 
 import java.util.List;
 import java.util.stream.Collectors;
+import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.ArrayUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -62,12 +63,12 @@ public class SysUserController extends BaseController
 
     @Log(title = "用户管理", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('system:user:export')")
-    @GetMapping("/export")
-    public AjaxResult export(SysUser user)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysUser user)
     {
         List<SysUser> list = userService.selectUserList(user);
         ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        return util.exportExcel(list, "用户数据");
+        util.exportExcel(response, list, "用户数据");
     }
 
     @Log(title = "用户管理", businessType = BusinessType.IMPORT)
@@ -82,11 +83,11 @@ public class SysUserController extends BaseController
         return AjaxResult.success(message);
     }
 
-    @GetMapping("/importTemplate")
-    public AjaxResult importTemplate()
+    @PostMapping("/importTemplate")
+    public void importTemplate(HttpServletResponse response)
     {
         ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        return util.importTemplateExcel("用户数据");
+        util.importTemplateExcel(response, "用户数据");
     }
 
     /**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
index 4169360a1..93a19e870 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -431,7 +431,7 @@ public class ExcelUtil<T>
      * @return 结果
      * @throws IOException
      */
-    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)throws IOException
+    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
     {
         exportExcel(response, list, sheetName, StringUtils.EMPTY);
     }
@@ -446,12 +446,12 @@ public class ExcelUtil<T>
      * @return 结果
      * @throws IOException
      */
-    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title) throws IOException
+    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)
     {
         response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
         response.setCharacterEncoding("utf-8");
         this.init(list, sheetName, title, Type.EXPORT);
-        exportExcel(response.getOutputStream());
+        exportExcel(response);
     }
 
     /**
@@ -484,7 +484,7 @@ public class ExcelUtil<T>
      * @param sheetName 工作表的名称
      * @return 结果
      */
-    public void importTemplateExcel(HttpServletResponse response, String sheetName) throws IOException
+    public void importTemplateExcel(HttpServletResponse response, String sheetName)
     {
         importTemplateExcel(response, sheetName, StringUtils.EMPTY);
     }
@@ -496,12 +496,12 @@ public class ExcelUtil<T>
      * @param title 标题
      * @return 结果
      */
-    public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) throws IOException
+    public void importTemplateExcel(HttpServletResponse response, String sheetName, String title)
     {
         response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
         response.setCharacterEncoding("utf-8");
         this.init(null, sheetName, title, Type.IMPORT);
-        exportExcel(response.getOutputStream());
+        exportExcel(response);
     }
 
     /**
@@ -509,12 +509,12 @@ public class ExcelUtil<T>
      * 
      * @return 结果
      */
-    public void exportExcel(OutputStream out)
+    public void exportExcel(HttpServletResponse response)
     {
         try
         {
             writeSheet();
-            wb.write(out);
+            wb.write(response.getOutputStream());
         }
         catch (Exception e)
         {
@@ -523,7 +523,6 @@ public class ExcelUtil<T>
         finally
         {
             IOUtils.closeQuietly(wb);
-            IOUtils.closeQuietly(out);
         }
     }
 
diff --git a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
index 56ff5e66a..ab19cf51f 100644
--- a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
+++ b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
@@ -1,6 +1,7 @@
 package ${packageName}.controller;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
@@ -61,12 +62,12 @@ public class ${ClassName}Controller extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
     @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(${ClassName} ${className})
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ${ClassName} ${className})
     {
         List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
         ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
-        return util.exportExcel(list, "${functionName}数据");
+        util.exportExcel(response, list, "${functionName}数据");
     }
 
     /**
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
index 867225aba..729a9dafe 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -108,7 +108,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['${moduleName}:${businessName}:export']"
         >导出</el-button>
@@ -313,7 +312,7 @@
 </template>
 
 <script>
-import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
 
 export default {
   name: "${BusinessName}",
@@ -324,8 +323,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
 #if($table.sub)
@@ -562,14 +559,9 @@ export default {
 #end
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.#[[$modal]]#.confirm('是否确认导出所有${functionName}数据项?').then(() => {
-        this.exportLoading = true;
-        return export${BusinessName}(queryParams);
-      }).then(response => {
-        this.#[[$download]]#.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('${moduleName}/${businessName}/export', {
+        ...this.queryParams
+      }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
     }
   }
 };
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
index 2f3ddab6f..2512bf16f 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
@@ -1,6 +1,7 @@
 package com.ruoyi.quartz.controller;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.quartz.SchedulerException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -54,12 +55,12 @@ public class SysJobController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('monitor:job:export')")
     @Log(title = "定时任务", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(SysJob sysJob)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysJob sysJob)
     {
         List<SysJob> list = jobService.selectJobList(sysJob);
         ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
-        return util.exportExcel(list, "定时任务");
+        util.exportExcel(response, list, "定时任务");
     }
 
     /**
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
index 10a842b6d..fff959ada 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
@@ -1,11 +1,13 @@
 package com.ruoyi.quartz.controller;
 
 import java.util.List;
+import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.DeleteMapping;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.annotation.Log;
@@ -46,12 +48,12 @@ public class SysJobLogController extends BaseController
      */
     @PreAuthorize("@ss.hasPermi('monitor:job:export')")
     @Log(title = "任务调度日志", businessType = BusinessType.EXPORT)
-    @GetMapping("/export")
-    public AjaxResult export(SysJobLog sysJobLog)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysJobLog sysJobLog)
     {
         List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
         ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
-        return util.exportExcel(list, "调度日志");
+        util.exportExcel(response, list, "调度日志");
     }
     
     /**
diff --git a/ruoyi-ui/src/api/monitor/job.js b/ruoyi-ui/src/api/monitor/job.js
index 58c43434a..38155693a 100644
--- a/ruoyi-ui/src/api/monitor/job.js
+++ b/ruoyi-ui/src/api/monitor/job.js
@@ -43,15 +43,6 @@ export function delJob(jobId) {
   })
 }
 
-// 导出定时任务调度
-export function exportJob(query) {
-  return request({
-    url: '/monitor/job/export',
-    method: 'get',
-    params: query
-  })
-}
-
 // 任务状态修改
 export function changeJobStatus(jobId, status) {
   const data = {
diff --git a/ruoyi-ui/src/api/monitor/jobLog.js b/ruoyi-ui/src/api/monitor/jobLog.js
index be1fffdfa..6e0be6166 100644
--- a/ruoyi-ui/src/api/monitor/jobLog.js
+++ b/ruoyi-ui/src/api/monitor/jobLog.js
@@ -24,12 +24,3 @@ export function cleanJobLog() {
     method: 'delete'
   })
 }
-
-// 导出调度日志
-export function exportJobLog(query) {
-  return request({
-    url: '/monitor/jobLog/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/logininfor.js b/ruoyi-ui/src/api/monitor/logininfor.js
index 0b89cdc6e..cd7815172 100644
--- a/ruoyi-ui/src/api/monitor/logininfor.js
+++ b/ruoyi-ui/src/api/monitor/logininfor.js
@@ -24,12 +24,3 @@ export function cleanLogininfor() {
     method: 'delete'
   })
 }
-
-// 导出登录日志
-export function exportLogininfor(query) {
-  return request({
-    url: '/monitor/logininfor/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/operlog.js b/ruoyi-ui/src/api/monitor/operlog.js
index c519355ef..6e881dfe8 100644
--- a/ruoyi-ui/src/api/monitor/operlog.js
+++ b/ruoyi-ui/src/api/monitor/operlog.js
@@ -24,12 +24,3 @@ export function cleanOperlog() {
     method: 'delete'
   })
 }
-
-// 导出操作日志
-export function exportOperlog(query) {
-  return request({
-    url: '/monitor/operlog/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/config.js b/ruoyi-ui/src/api/system/config.js
index f1f872757..7858c6928 100644
--- a/ruoyi-ui/src/api/system/config.js
+++ b/ruoyi-ui/src/api/system/config.js
@@ -58,12 +58,3 @@ export function refreshCache() {
     method: 'delete'
   })
 }
-
-// 导出参数
-export function exportConfig(query) {
-  return request({
-    url: '/system/config/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dict/data.js b/ruoyi-ui/src/api/system/dict/data.js
index d3f8c2f20..2a6e48112 100644
--- a/ruoyi-ui/src/api/system/dict/data.js
+++ b/ruoyi-ui/src/api/system/dict/data.js
@@ -50,12 +50,3 @@ export function delData(dictCode) {
     method: 'delete'
   })
 }
-
-// 导出字典数据
-export function exportData(query) {
-  return request({
-    url: '/system/dict/data/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dict/type.js b/ruoyi-ui/src/api/system/dict/type.js
index 2c66bd5fb..526977d36 100644
--- a/ruoyi-ui/src/api/system/dict/type.js
+++ b/ruoyi-ui/src/api/system/dict/type.js
@@ -51,15 +51,6 @@ export function refreshCache() {
   })
 }
 
-// 导出字典类型
-export function exportType(query) {
-  return request({
-    url: '/system/dict/type/export',
-    method: 'get',
-    params: query
-  })
-}
-
 // 获取字典选择框列表
 export function optionselect() {
   return request({
diff --git a/ruoyi-ui/src/api/system/post.js b/ruoyi-ui/src/api/system/post.js
index fb124d961..8faa2669f 100644
--- a/ruoyi-ui/src/api/system/post.js
+++ b/ruoyi-ui/src/api/system/post.js
@@ -42,12 +42,3 @@ export function delPost(postId) {
     method: 'delete'
   })
 }
-
-// 导出岗位
-export function exportPost(query) {
-  return request({
-    url: '/system/post/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/role.js b/ruoyi-ui/src/api/system/role.js
index aa426df76..b5ebdf6c0 100644
--- a/ruoyi-ui/src/api/system/role.js
+++ b/ruoyi-ui/src/api/system/role.js
@@ -65,15 +65,6 @@ export function delRole(roleId) {
   })
 }
 
-// 导出角色
-export function exportRole(query) {
-  return request({
-    url: '/system/role/export',
-    method: 'get',
-    params: query
-  })
-}
-
 // 查询角色已授权用户列表
 export function allocatedUserList(query) {
   return request({
diff --git a/ruoyi-ui/src/api/system/user.js b/ruoyi-ui/src/api/system/user.js
index 85bdc19cf..577bea24c 100644
--- a/ruoyi-ui/src/api/system/user.js
+++ b/ruoyi-ui/src/api/system/user.js
@@ -44,15 +44,6 @@ export function delUser(userId) {
   })
 }
 
-// 导出用户
-export function exportUser(query) {
-  return request({
-    url: '/system/user/export',
-    method: 'get',
-    params: query
-  })
-}
-
 // 用户密码重置
 export function resetUserPwd(userId, password) {
   const data = {
@@ -118,14 +109,6 @@ export function uploadAvatar(data) {
   })
 }
 
-// 下载用户导入模板
-export function importTemplate() {
-  return request({
-    url: '/system/user/importTemplate',
-    method: 'get'
-  })
-}
-
 // 查询授权角色
 export function getAuthRole(userId) {
   return request({
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index 489600aa4..83b079101 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -12,6 +12,7 @@ import store from './store'
 import router from './router'
 import directive from './directive' //directive
 import plugins from './plugins' // plugins
+import { download } from '@/utils/request'
 
 import './assets/icons' // icon
 import './permission' // permission control
@@ -43,6 +44,7 @@ Vue.prototype.resetForm = resetForm
 Vue.prototype.addDateRange = addDateRange
 Vue.prototype.selectDictLabel = selectDictLabel
 Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.download = download
 Vue.prototype.handleTree = handleTree
 
 // 全局组件挂载
diff --git a/ruoyi-ui/src/plugins/download.js b/ruoyi-ui/src/plugins/download.js
index 2aa81229a..e1c664057 100644
--- a/ruoyi-ui/src/plugins/download.js
+++ b/ruoyi-ui/src/plugins/download.js
@@ -1,7 +1,8 @@
-import { saveAs } from 'file-saver'
 import axios from 'axios'
-import { getToken } from '@/utils/auth'
 import { Message } from 'element-ui'
+import { saveAs } from 'file-saver'
+import { getToken } from '@/utils/auth'
+import { blobValidate } from "@/utils/ruoyi";
 
 const baseURL = process.env.VUE_APP_BASE_API
 
@@ -48,7 +49,7 @@ export default {
       responseType: 'blob',
       headers: { 'Authorization': 'Bearer ' + getToken() }
     }).then(async (res) => {
-      const isLogin = await this.blobValidate(res.data);
+      const isLogin = await blobValidate(res.data);
       if (isLogin) {
         const blob = new Blob([res.data], { type: 'application/zip' })
         this.saveAs(blob, name)
@@ -59,15 +60,6 @@ export default {
   },
   saveAs(text, name, opts) {
     saveAs(text, name, opts);
-  },
-  async blobValidate(data) {
-    try {
-      const text = await data.text();
-      JSON.parse(text);
-      return false;
-    } catch (error) {
-      return true;
-    }
-  },
+  }
 }
 
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
index 9b40b4acb..78a20a2f1 100644
--- a/ruoyi-ui/src/utils/request.js
+++ b/ruoyi-ui/src/utils/request.js
@@ -1,8 +1,12 @@
 import axios from 'axios'
-import { Notification, MessageBox, Message } from 'element-ui'
+import { Notification, MessageBox, Message, Loading } from 'element-ui'
 import store from '@/store'
 import { getToken } from '@/utils/auth'
 import errorCode from '@/utils/errorCode'
+import { tansParams, blobValidate } from "@/utils/ruoyi";
+import { saveAs } from 'file-saver'
+
+let downloadLoadingInstance;
 
 axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
 // 创建axios实例
@@ -12,6 +16,7 @@ const service = axios.create({
   // 超时
   timeout: 10000
 })
+
 // request拦截器
 service.interceptors.request.use(config => {
   // 是否需要设置 token
@@ -21,24 +26,7 @@ service.interceptors.request.use(config => {
   }
   // get请求映射params参数
   if (config.method === 'get' && config.params) {
-    let url = config.url + '?';
-    for (const propName of Object.keys(config.params)) {
-      const value = config.params[propName];
-      var part = encodeURIComponent(propName) + "=";
-      if (value !== null && typeof(value) !== "undefined") {
-        if (typeof value === 'object') {
-          for (const key of Object.keys(value)) {
-            if (value[key] !== null && typeof (value[key]) !== 'undefined') {
-              let params = propName + '[' + key + ']';
-              let subPart = encodeURIComponent(params) + '=';
-              url += subPart + encodeURIComponent(value[key]) + '&';
-            }
-          }
-        } else {
-          url += part + encodeURIComponent(value) + "&";
-        }
-      }
-    }
+    let url = config.url + '?' + tansParams(config.params);
     url = url.slice(0, -1);
     config.params = {};
     config.url = url;
@@ -55,17 +43,24 @@ service.interceptors.response.use(res => {
     const code = res.data.code || 200;
     // 获取错误信息
     const msg = errorCode[code] || res.data.msg || errorCode['default']
+    // 二进制数据则直接返回
+    if(res.request.responseType ===  'blob' || res.request.responseType ===  'arraybuffer'){
+      return res.data
+    }
     if (code === 401) {
-      MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
+      let doms = document.getElementsByClassName('el-message-box')[0]
+      if(doms === undefined){
+        MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
           confirmButtonText: '重新登录',
           cancelButtonText: '取消',
           type: 'warning'
         }
-      ).then(() => {
-        store.dispatch('LogOut').then(() => {
-          location.href = '/index';
-        })
-      }).catch(() => {});
+        ).then(() => {
+          store.dispatch('LogOut').then(() => {
+            location.href = '/index';
+          })
+        }).catch(() => {});
+      }
       return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
     } else if (code === 500) {
       Message({
@@ -103,4 +98,27 @@ service.interceptors.response.use(res => {
   }
 )
 
+// 通用下载方法
+export function download(url, params, filename) {
+  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'
+  }).then(async (data) => {
+    const isLogin = await blobValidate(data);
+    if (isLogin) {
+      const blob = new Blob([data])
+      saveAs(blob, filename)
+    } else {
+      Message.error('无效的会话,或者会话已过期,请重新登录。');
+    }
+    downloadLoadingInstance.close();
+  }).catch((r) => {
+    console.error(r)
+    Message.error('下载文件出现错误,请联系管理员!')
+    downloadLoadingInstance.close();
+  })
+}
+
 export default service
diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js
index 440bf4cd8..4cc5e24ea 100644
--- a/ruoyi-ui/src/utils/ruoyi.js
+++ b/ruoyi-ui/src/utils/ruoyi.js
@@ -181,3 +181,40 @@ export function handleTree(data, id, parentId, children) {
 	}
 	return tree;
 }
+
+/**
+* 参数处理
+* @param {*} params  参数
+*/
+export function tansParams(params) {
+	let result = ''
+	for (const propName of Object.keys(params)) {
+		const value = params[propName];
+		var part = encodeURIComponent(propName) + "=";
+		if (value !== null && typeof (value) !== "undefined") {
+			if (typeof value === 'object') {
+				for (const key of Object.keys(value)) {
+					if (value[key] !== null && typeof (value[key]) !== 'undefined') {
+						let params = propName + '[' + key + ']';
+						var subPart = encodeURIComponent(params) + "=";
+						result += subPart + encodeURIComponent(value[key]) + "&";
+					}
+				}
+			} else {
+				result += part + encodeURIComponent(value) + "&";
+			}
+		}
+	}
+	return result
+}
+
+// 验证是否为blob格式
+export async function blobValidate(data) {
+    try {
+      const text = await data.text();
+      JSON.parse(text);
+      return false;
+    } catch (error) {
+      return true;
+    }
+}
diff --git a/ruoyi-ui/src/views/monitor/job/index.vue b/ruoyi-ui/src/views/monitor/job/index.vue
index 06b939d85..b8284ab91 100644
--- a/ruoyi-ui/src/views/monitor/job/index.vue
+++ b/ruoyi-ui/src/views/monitor/job/index.vue
@@ -75,7 +75,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['monitor:job:export']"
         >导出</el-button>
@@ -295,7 +294,7 @@
 </template>
 
 <script>
-import { listJob, getJob, delJob, addJob, updateJob, exportJob, runJob, changeJobStatus } from "@/api/monitor/job";
+import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job";
 import Crontab from '@/components/Crontab'
 
 export default {
@@ -306,8 +305,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -510,14 +507,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有定时任务数据项?').then(() => {
-        this.exportLoading = true;
-        return exportJob(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('monitor/job/export', {
+        ...this.queryParams
+      }, `job_${new Date().getTime()}.xlsx`)
     }
   }
 };
diff --git a/ruoyi-ui/src/views/monitor/job/log.vue b/ruoyi-ui/src/views/monitor/job/log.vue
index 44efe5f1e..35b778829 100644
--- a/ruoyi-ui/src/views/monitor/job/log.vue
+++ b/ruoyi-ui/src/views/monitor/job/log.vue
@@ -89,7 +89,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['monitor:job:export']"
         >导出</el-button>
@@ -186,7 +185,7 @@
 
 <script>
 import { getJob} from "@/api/monitor/job";
-import { listJobLog, delJobLog, exportJobLog, cleanJobLog } from "@/api/monitor/jobLog";
+import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog";
 
 export default {
   name: "JobLog",
@@ -195,8 +194,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非多个禁用
@@ -293,14 +290,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有调度日志数据项?').then(() => {
-        this.exportLoading = true;
-        return exportJobLog(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('/monitor/jobLog/export', {
+        ...this.queryParams
+      }, `log_${new Date().getTime()}.xlsx`)
     }
   }
 };
diff --git a/ruoyi-ui/src/views/monitor/logininfor/index.vue b/ruoyi-ui/src/views/monitor/logininfor/index.vue
index 634141997..0f4ecbba6 100644
--- a/ruoyi-ui/src/views/monitor/logininfor/index.vue
+++ b/ruoyi-ui/src/views/monitor/logininfor/index.vue
@@ -83,7 +83,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['monitor:logininfor:export']"
         >导出</el-button>
@@ -123,7 +122,7 @@
 </template>
 
 <script>
-import { list, delLogininfor, cleanLogininfor, exportLogininfor } from "@/api/monitor/logininfor";
+import { list, delLogininfor, cleanLogininfor } from "@/api/monitor/logininfor";
 
 export default {
   name: "Logininfor",
@@ -132,8 +131,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非多个禁用
@@ -216,14 +213,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有操作日志数据项?').then(() => {
-        this.exportLoading = true;
-        return exportLogininfor(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('monitor/logininfor/export', {
+        ...this.queryParams
+      }, `logininfor_${new Date().getTime()}.xlsx`)
     }
   }
 };
diff --git a/ruoyi-ui/src/views/monitor/operlog/index.vue b/ruoyi-ui/src/views/monitor/operlog/index.vue
index 0aee4a6a5..28f705b82 100644
--- a/ruoyi-ui/src/views/monitor/operlog/index.vue
+++ b/ruoyi-ui/src/views/monitor/operlog/index.vue
@@ -99,7 +99,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['monitor:operlog:export']"
         >导出</el-button>
@@ -196,7 +195,7 @@
 </template>
 
 <script>
-import { list, delOperlog, cleanOperlog, exportOperlog } from "@/api/monitor/operlog";
+import { list, delOperlog, cleanOperlog } from "@/api/monitor/operlog";
 
 export default {
   name: "Operlog",
@@ -205,8 +204,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非多个禁用
@@ -303,14 +300,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有操作日志数据项?').then(() => {
-        this.exportLoading = true;
-        return exportOperlog(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('monitor/operlog/export', {
+        ...this.queryParams
+      }, `operlog_${new Date().getTime()}.xlsx`)
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/config/index.vue b/ruoyi-ui/src/views/system/config/index.vue
index efb69615b..9fde370f7 100644
--- a/ruoyi-ui/src/views/system/config/index.vue
+++ b/ruoyi-ui/src/views/system/config/index.vue
@@ -88,7 +88,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['system:config:export']"
         >导出</el-button>
@@ -185,7 +184,7 @@
 </template>
 
 <script>
-import { listConfig, getConfig, delConfig, addConfig, updateConfig, exportConfig, refreshCache } from "@/api/system/config";
+import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
 
 export default {
   name: "Config",
@@ -194,8 +193,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -334,14 +331,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有参数数据项?').then(() => {
-        this.exportLoading = true;
-        return exportConfig(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('system/config/export', {
+        ...this.queryParams
+      }, `config_${new Date().getTime()}.xlsx`)
     },
     /** 刷新缓存按钮操作 */
     handleRefreshCache() {
diff --git a/ruoyi-ui/src/views/system/dict/data.vue b/ruoyi-ui/src/views/system/dict/data.vue
index 36eb6afdb..45327c026 100644
--- a/ruoyi-ui/src/views/system/dict/data.vue
+++ b/ruoyi-ui/src/views/system/dict/data.vue
@@ -75,7 +75,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['system:dict:export']"
         >导出</el-button>
@@ -183,7 +182,7 @@
 </template>
 
 <script>
-import { listData, getData, delData, addData, updateData, exportData } from "@/api/system/dict/data";
+import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
 import { listType, getType } from "@/api/system/dict/type";
 
 export default {
@@ -193,8 +192,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -380,14 +377,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有数据项?').then(() => {
-        this.exportLoading = true;
-        return exportData(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('system/dict/data/export', {
+        ...this.queryParams
+      }, `data_${new Date().getTime()}.xlsx`)
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/dict/index.vue b/ruoyi-ui/src/views/system/dict/index.vue
index 37de40f3f..17cb5513e 100644
--- a/ruoyi-ui/src/views/system/dict/index.vue
+++ b/ruoyi-ui/src/views/system/dict/index.vue
@@ -94,7 +94,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['system:dict:export']"
         >导出</el-button>
@@ -193,7 +192,7 @@
 </template>
 
 <script>
-import { listType, getType, delType, addType, updateType, exportType, refreshCache } from "@/api/system/dict/type";
+import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
 
 export default {
   name: "Dict",
@@ -202,8 +201,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -338,14 +335,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有类型数据项?').then(() => {
-        this.exportLoading = true;
-        return exportType(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('system/dict/type/export', {
+        ...this.queryParams
+      }, `type_${new Date().getTime()}.xlsx`)
     },
     /** 刷新缓存按钮操作 */
     handleRefreshCache() {
diff --git a/ruoyi-ui/src/views/system/post/index.vue b/ruoyi-ui/src/views/system/post/index.vue
index e2069687d..02698da38 100644
--- a/ruoyi-ui/src/views/system/post/index.vue
+++ b/ruoyi-ui/src/views/system/post/index.vue
@@ -74,7 +74,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['system:post:export']"
         >导出</el-button>
@@ -160,7 +159,7 @@
 </template>
 
 <script>
-import { listPost, getPost, delPost, addPost, updatePost, exportPost } from "@/api/system/post";
+import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post";
 
 export default {
   name: "Post",
@@ -169,8 +168,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -305,14 +302,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有岗位数据项?').then(() => {
-        this.exportLoading = true;
-        return exportPost(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('system/post/export', {
+        ...this.queryParams
+      }, `post_${new Date().getTime()}.xlsx`)
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue
index 5110834d4..b2cfd6bf8 100644
--- a/ruoyi-ui/src/views/system/role/index.vue
+++ b/ruoyi-ui/src/views/system/role/index.vue
@@ -94,7 +94,6 @@
           plain
           icon="el-icon-download"
           size="mini"
-          :loading="exportLoading"
           @click="handleExport"
           v-hasPermi="['system:role:export']"
         >导出</el-button>
@@ -259,7 +258,7 @@
 </template>
 
 <script>
-import { listRole, getRole, delRole, addRole, updateRole, exportRole, dataScope, changeRoleStatus } from "@/api/system/role";
+import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus } from "@/api/system/role";
 import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu";
 import { treeselect as deptTreeselect, roleDeptTreeselect } from "@/api/system/dept";
 
@@ -270,8 +269,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -613,14 +610,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有用户数据项?').then(() => {
-        this.exportLoading = true;
-        return exportRole(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('system/role/export', {
+        ...this.queryParams
+      }, `role_${new Date().getTime()}.xlsx`)
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
index 4f20b0872..2b7283f9d 100644
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -131,7 +131,6 @@
               plain
               icon="el-icon-download"
               size="mini"
-              :loading="exportLoading"
               @click="handleExport"
               v-hasPermi="['system:user:export']"
             >导出</el-button>
@@ -346,7 +345,7 @@
 </template>
 
 <script>
-import { listUser, getUser, delUser, addUser, updateUser, exportUser, resetUserPwd, changeUserStatus, importTemplate } from "@/api/system/user";
+import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus } from "@/api/system/user";
 import { getToken } from "@/utils/auth";
 import { treeselect } from "@/api/system/dept";
 import Treeselect from "@riophae/vue-treeselect";
@@ -360,8 +359,6 @@ export default {
     return {
       // 遮罩层
       loading: true,
-      // 导出遮罩层
-      exportLoading: false,
       // 选中数组
       ids: [],
       // 非单个禁用
@@ -643,14 +640,9 @@ export default {
     },
     /** 导出按钮操作 */
     handleExport() {
-      const queryParams = this.queryParams;
-      this.$modal.confirm('是否确认导出所有用户数据项?').then(() => {
-        this.exportLoading = true;
-        return exportUser(queryParams);
-      }).then(response => {
-        this.$download.name(response.msg);
-        this.exportLoading = false;
-      }).catch(() => {});
+      this.download('system/user/export', {
+        ...this.queryParams
+      }, `user_${new Date().getTime()}.xlsx`)
     },
     /** 导入按钮操作 */
     handleImport() {
@@ -659,9 +651,9 @@ export default {
     },
     /** 下载模板操作 */
     importTemplate() {
-      importTemplate().then(response => {
-        this.$download.name(response.msg);
-      });
+      this.download('system/user/importTemplate', {
+        ...this.queryParams
+      }, `user_template_${new Date().getTime()}.xlsx`)
     },
     // 文件上传中处理
     handleFileUploadProgress(event, file, fileList) {

From 8de93d35ed15790d6963a1a26ff67c2989205702 Mon Sep 17 00:00:00 2001
From: lihy2021 <lihy2021@hotmail.com>
Date: Wed, 17 Nov 2021 07:56:24 +0000
Subject: [PATCH 26/74] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?=
 =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E7=BC=BA=E5=B0=91=E4=BA=8B=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
index 2fc79492e..116f6c544 100644
--- a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
+++ b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -129,6 +129,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
      * @param ${pkColumn.javaField} ${functionName}主键
      * @return 结果
      */
+#if($table.sub)
+    @Transactional
+#end
     @Override
     public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
     {

From fcf606acde83e67d050bc0758cce5960892f3904 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 18 Nov 2021 17:50:49 +0800
Subject: [PATCH 27/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7jsencrypt=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC3.2.1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json         |  2 +-
 ruoyi-ui/src/utils/request.js | 15 ++++++---------
 2 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 45f5508e6..a52059488 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -47,7 +47,7 @@
     "highlight.js": "9.18.5",
     "js-beautify": "1.13.0",
     "js-cookie": "2.2.1",
-    "jsencrypt": "3.0.0-rc.1",
+    "jsencrypt": "3.2.1",
     "nprogress": "0.2.0",
     "quill": "1.3.7",
     "screenfull": "5.0.2",
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
index 78a20a2f1..1acd94168 100644
--- a/ruoyi-ui/src/utils/request.js
+++ b/ruoyi-ui/src/utils/request.js
@@ -48,19 +48,16 @@ service.interceptors.response.use(res => {
       return res.data
     }
     if (code === 401) {
-      let doms = document.getElementsByClassName('el-message-box')[0]
-      if(doms === undefined){
-        MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
+      MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
           confirmButtonText: '重新登录',
           cancelButtonText: '取消',
           type: 'warning'
         }
-        ).then(() => {
-          store.dispatch('LogOut').then(() => {
-            location.href = '/index';
-          })
-        }).catch(() => {});
-      }
+      ).then(() => {
+        store.dispatch('LogOut').then(() => {
+          location.href = '/index';
+        })
+      }).catch(() => {});
       return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
     } else if (code === 500) {
       Message({

From 9a7bb81cd00526287b3f0efd8e78ae440e21906f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?=
 <15040126243@163.com>
Date: Fri, 19 Nov 2021 13:01:30 +0800
Subject: [PATCH 28/74] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=E5=85=B3?=
 =?UTF-8?q?=E9=97=AD=20xss=20=E5=8A=9F=E8=83=BD=E5=AF=BC=E8=87=B4=E5=8F=AF?=
 =?UTF-8?q?=E9=87=8D=E5=A4=8D=E8=AF=BB=20RepeatableFilter=20=E5=A4=B1?=
 =?UTF-8?q?=E6=95=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/ruoyi/framework/config/FilterConfig.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
index ab12e4164..610807a86 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
@@ -18,7 +18,6 @@ import com.ruoyi.common.utils.StringUtils;
  * @author ruoyi
  */
 @Configuration
-@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
 public class FilterConfig
 {
     @Value("${xss.excludes}")
@@ -29,6 +28,7 @@ public class FilterConfig
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @Bean
+    @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
     public FilterRegistrationBean xssFilterRegistration()
     {
         FilterRegistrationBean registration = new FilterRegistrationBean();

From d1eacc1d1c7ba17735ba5c0a59db9700ebabecc0 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Fri, 19 Nov 2021 14:53:40 +0800
Subject: [PATCH 29/74] =?UTF-8?q?=E6=96=B0=E5=A2=9Etab=E5=AF=B9=E8=B1=A1?=
 =?UTF-8?q?=E7=AE=80=E5=8C=96=E9=A1=B5=E7=AD=BE=E6=93=8D=E4=BD=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/layout/components/TagsView/index.vue  | 19 ++----
 ruoyi-ui/src/plugins/index.js                 |  3 +
 ruoyi-ui/src/plugins/tab.js                   | 68 +++++++++++++++++++
 ruoyi-ui/src/store/modules/tagsView.js        |  2 +-
 ruoyi-ui/src/views/monitor/job/log.vue        |  4 +-
 ruoyi-ui/src/views/system/dict/data.vue       | 14 ++++
 ruoyi-ui/src/views/system/role/authUser.vue   |  4 +-
 ruoyi-ui/src/views/system/user/authRole.vue   |  4 +-
 .../views/system/user/profile/resetPwd.vue    |  3 +-
 .../views/system/user/profile/userInfo.vue    |  3 +-
 ruoyi-ui/src/views/tool/gen/editTable.vue     |  4 +-
 11 files changed, 102 insertions(+), 26 deletions(-)
 create mode 100644 ruoyi-ui/src/plugins/tab.js

diff --git a/ruoyi-ui/src/layout/components/TagsView/index.vue b/ruoyi-ui/src/layout/components/TagsView/index.vue
index e43aa2e4a..2381d2e09 100644
--- a/ruoyi-ui/src/layout/components/TagsView/index.vue
+++ b/ruoyi-ui/src/layout/components/TagsView/index.vue
@@ -152,31 +152,24 @@ export default {
       })
     },
     refreshSelectedTag(view) {
-      this.$store.dispatch('tagsView/delCachedView', view).then(() => {
-        const { fullPath } = view
-        this.$nextTick(() => {
-          this.$router.replace({
-            path: '/redirect' + fullPath
-          })
-        })
-      })
+      this.$tab.refreshPage(view);
     },
     closeSelectedTag(view) {
-      this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
+      this.$tab.closePage(view).then(({ visitedViews }) => {
         if (this.isActive(view)) {
           this.toLastView(visitedViews, view)
         }
       })
     },
     closeRightTags() {
-      this.$store.dispatch('tagsView/delRightTags', this.selectedTag).then(visitedViews => {
+      this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
         if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
           this.toLastView(visitedViews)
         }
       })
     },
     closeLeftTags() {
-      this.$store.dispatch('tagsView/delLeftTags', this.selectedTag).then(visitedViews => {
+      this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
         if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
           this.toLastView(visitedViews)
         }
@@ -184,12 +177,12 @@ export default {
     },
     closeOthersTags() {
       this.$router.push(this.selectedTag).catch(()=>{});
-      this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
+      this.$tab.closeOtherPage(this.selectedTag).then(() => {
         this.moveToCurrentTag()
       })
     },
     closeAllTags(view) {
-      this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
+      this.$tab.closeAllPage().then(({ visitedViews }) => {
         if (this.affixTags.some(tag => tag.path === this.$route.path)) {
           return
         }
diff --git a/ruoyi-ui/src/plugins/index.js b/ruoyi-ui/src/plugins/index.js
index 7cc83a4c8..9bc6eacd3 100644
--- a/ruoyi-ui/src/plugins/index.js
+++ b/ruoyi-ui/src/plugins/index.js
@@ -1,3 +1,4 @@
+import tab from './tab'
 import auth from './auth'
 import cache from './cache'
 import modal from './modal'
@@ -5,6 +6,8 @@ import download from './download'
 
 export default {
   install(Vue) {
+    // 页签操作
+    Vue.prototype.$tab = tab
     // 认证对象
     Vue.prototype.$auth = auth
     // 缓存对象
diff --git a/ruoyi-ui/src/plugins/tab.js b/ruoyi-ui/src/plugins/tab.js
new file mode 100644
index 000000000..f2d7b22b8
--- /dev/null
+++ b/ruoyi-ui/src/plugins/tab.js
@@ -0,0 +1,68 @@
+import store from '@/store'
+import router from '@/router';
+
+export default {
+  // 刷新当前tab页签
+  refreshPage(obj) {
+    const { path, matched } = router.currentRoute;
+    if (obj === undefined) {
+      matched.forEach((m) => {
+        if (m.components && m.components.default && m.components.default.name) {
+          if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
+            obj = { name: m.components.default.name, path: path };
+          }
+        }
+      });
+    }
+    return store.dispatch('tagsView/delCachedView', obj).then(() => {
+      const { path } = obj
+      router.replace({
+        path: '/redirect' + path
+      })
+    })
+
+
+  },
+  // 关闭当前tab页签,打开新页签
+  closeOpenPage(obj) {
+    store.dispatch("tagsView/delView", router.currentRoute);
+    if (obj !== undefined) {
+      return router.push(obj);
+    }
+  },
+  // 关闭指定tab页签
+  closePage(obj) {
+    if (obj === undefined) {
+      return store.dispatch('tagsView/delView', router.currentRoute).then(({ lastPath }) => {
+        return router.push(lastPath || '/');
+      });
+    }
+    return store.dispatch('tagsView/delView', obj);
+  },
+  // 关闭所有tab页签
+  closeAllPage() {
+    return store.dispatch('tagsView/delAllViews');
+  },
+  // 关闭左侧tab页签
+  closeLeftPage(obj) {
+    return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute);
+  },
+  // 关闭右侧tab页签
+  closeRightPage(obj) {
+    return store.dispatch('tagsView/delRightTags', obj || router.currentRoute);
+  },
+  // 关闭其他tab页签
+  closeOtherPage(obj) {
+    return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute);
+  },
+  // 添加tab页签
+  addPage(title, url) {
+    var obj = { path: url, meta: { title: title } }
+    store.dispatch('tagsView/addView', obj);
+    return router.push(url);
+  },
+  // 修改tab页签
+  updatePage(obj) {
+    return store.dispatch('tagsView/updateVisitedView', obj);
+  }
+}
diff --git a/ruoyi-ui/src/store/modules/tagsView.js b/ruoyi-ui/src/store/modules/tagsView.js
index 93d44040d..9acf5dc54 100644
--- a/ruoyi-ui/src/store/modules/tagsView.js
+++ b/ruoyi-ui/src/store/modules/tagsView.js
@@ -14,7 +14,7 @@ const mutations = {
   },
   ADD_CACHED_VIEW: (state, view) => {
     if (state.cachedViews.includes(view.name)) return
-    if (!view.meta.noCache) {
+    if (view.meta && !view.meta.noCache) {
       state.cachedViews.push(view.name)
     }
   },
diff --git a/ruoyi-ui/src/views/monitor/job/log.vue b/ruoyi-ui/src/views/monitor/job/log.vue
index 35b778829..98b9ab3d5 100644
--- a/ruoyi-ui/src/views/monitor/job/log.vue
+++ b/ruoyi-ui/src/views/monitor/job/log.vue
@@ -245,8 +245,8 @@ export default {
     },
     // 返回按钮
     handleClose() {
-      this.$store.dispatch("tagsView/delView", this.$route);
-      this.$router.push({ path: "/monitor/job" });
+      const obj = { path: "/monitor/job" };
+      this.$tab.closeOpenPage(obj);
     },
     /** 搜索按钮操作 */
     handleQuery() {
diff --git a/ruoyi-ui/src/views/system/dict/data.vue b/ruoyi-ui/src/views/system/dict/data.vue
index 45327c026..aa878bdd8 100644
--- a/ruoyi-ui/src/views/system/dict/data.vue
+++ b/ruoyi-ui/src/views/system/dict/data.vue
@@ -79,6 +79,15 @@
           v-hasPermi="['system:dict:export']"
         >导出</el-button>
       </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-close"
+          size="mini"
+          @click="handleClose"
+        >关闭</el-button>
+      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
@@ -316,6 +325,11 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
+    // 返回按钮
+    handleClose() {
+      const obj = { path: "/system/dict" };
+      this.$tab.closeOpenPage(obj);
+    },
     /** 重置按钮操作 */
     resetQuery() {
       this.resetForm("queryForm");
diff --git a/ruoyi-ui/src/views/system/role/authUser.vue b/ruoyi-ui/src/views/system/role/authUser.vue
index e18ea8b31..dd1881252 100644
--- a/ruoyi-ui/src/views/system/role/authUser.vue
+++ b/ruoyi-ui/src/views/system/role/authUser.vue
@@ -153,8 +153,8 @@ export default {
     },
     // 返回按钮
     handleClose() {
-      this.$store.dispatch("tagsView/delView", this.$route);
-      this.$router.push({ path: "/system/role" });
+      const obj = { path: "/system/role" };
+      this.$tab.closeOpenPage(obj);
     },
     /** 搜索按钮操作 */
     handleQuery() {
diff --git a/ruoyi-ui/src/views/system/user/authRole.vue b/ruoyi-ui/src/views/system/user/authRole.vue
index a4bcbe3f4..b184de252 100644
--- a/ruoyi-ui/src/views/system/user/authRole.vue
+++ b/ruoyi-ui/src/views/system/user/authRole.vue
@@ -109,8 +109,8 @@ export default {
     },
     /** 关闭按钮 */
     close() {
-      this.$store.dispatch("tagsView/delView", this.$route);
-      this.$router.push({ path: "/system/user" });
+      const obj = { path: "/system/user" };
+      this.$tab.closeOpenPage(obj);
     },
   },
 };
diff --git a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
index e01926846..3437abca1 100644
--- a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
+++ b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
@@ -64,8 +64,7 @@ export default {
       });
     },
     close() {
-      this.$store.dispatch("tagsView/delView", this.$route);
-      this.$router.push({ path: "/index" });
+      this.$tab.closePage();
     }
   }
 };
diff --git a/ruoyi-ui/src/views/system/user/profile/userInfo.vue b/ruoyi-ui/src/views/system/user/profile/userInfo.vue
index 978cddf45..ac7c44a65 100644
--- a/ruoyi-ui/src/views/system/user/profile/userInfo.vue
+++ b/ruoyi-ui/src/views/system/user/profile/userInfo.vue
@@ -68,8 +68,7 @@ export default {
       });
     },
     close() {
-      this.$store.dispatch("tagsView/delView", this.$route);
-      this.$router.push({ path: "/index" });
+      this.$tab.closePage();
     }
   }
 };
diff --git a/ruoyi-ui/src/views/tool/gen/editTable.vue b/ruoyi-ui/src/views/tool/gen/editTable.vue
index a013cbbb0..b8f386e75 100644
--- a/ruoyi-ui/src/views/tool/gen/editTable.vue
+++ b/ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -211,8 +211,8 @@ export default {
     },
     /** 关闭按钮 */
     close() {
-      this.$store.dispatch("tagsView/delView", this.$route);
-      this.$router.push({ path: "/tool/gen", query: { t: Date.now(), pageNum: this.$route.query.pageNum } })
+      const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: this.$route.query.pageNum } };
+      this.$tab.closeOpenPage(obj);
     }
   },
   mounted() {

From 91ad85aec126ffabfd89afc410ef7049430742ca Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Fri, 19 Nov 2021 15:20:54 +0800
Subject: [PATCH 30/74] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=BE=A4?=
 =?UTF-8?q?=E5=8F=B7=EF=BC=9A264312783?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md                    | 2 +-
 ruoyi-ui/src/views/index.vue | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 0c10287a4..166974171 100644
--- a/README.md
+++ b/README.md
@@ -82,4 +82,4 @@
 
 ## 若依前后端分离交流群
 
-QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) 点击按钮入群。
\ No newline at end of file
+QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=lgBcot4o) 点击按钮入群。
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index 4609c136e..19e035f0a 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -121,8 +121,8 @@
               <i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>
               <s>满887144332</s> <s>满180251782</s> <s>满104180207</s>
               <s>满186866453</s> <s>满201396349</s> <s>满101456076</s>
-              <a href="https://jq.qq.com/?_wv=1027&k=KmQbXyJ6" target="_blank">
-                101539465</a
+              <a href="https://jq.qq.com/?_wv=1027&k=lgBcot4o" target="_blank">
+                264312783</a
               >
             </p>
             <p>

From 421593c0bac570b757ffa3eaf372928ebc5a73e1 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sat, 20 Nov 2021 12:09:53 +0800
Subject: [PATCH 31/74] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E7=BE=A4?=
 =?UTF-8?q?=E5=8F=B7=EF=BC=9A101539465?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md                    | 2 +-
 ruoyi-ui/src/views/index.vue | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index 166974171..0c10287a4 100644
--- a/README.md
+++ b/README.md
@@ -82,4 +82,4 @@
 
 ## 若依前后端分离交流群
 
-QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=lgBcot4o) 点击按钮入群。
\ No newline at end of file
+QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) 点击按钮入群。
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index 19e035f0a..4609c136e 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -121,8 +121,8 @@
               <i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>
               <s>满887144332</s> <s>满180251782</s> <s>满104180207</s>
               <s>满186866453</s> <s>满201396349</s> <s>满101456076</s>
-              <a href="https://jq.qq.com/?_wv=1027&k=lgBcot4o" target="_blank">
-                264312783</a
+              <a href="https://jq.qq.com/?_wv=1027&k=KmQbXyJ6" target="_blank">
+                101539465</a
               >
             </p>
             <p>

From ef4bfde4a8d43e012ade7c3e8946f4c121fc578d Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 22 Nov 2021 18:06:44 +0800
Subject: [PATCH 32/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8F=90=E7=A4=BA?=
 =?UTF-8?q?=E4=BF=A1=E6=81=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ruoyi/quartz/config/ScheduleConfig.java   |  2 +-
 ruoyi-ui/src/api/monitor/server.js            |  2 +-
 .../src/components/RightToolbar/index.vue     |  2 +-
 ruoyi-ui/src/plugins/tab.js                   |  4 +--
 ruoyi-ui/src/views/login.vue                  |  8 +++--
 .../src/views/monitor/logininfor/index.vue    |  4 +--
 ruoyi-ui/src/views/monitor/operlog/index.vue  |  4 +--
 ruoyi-ui/src/views/system/dept/index.vue      |  6 ++--
 ruoyi-ui/src/views/system/dict/data.vue       |  2 +-
 ruoyi-ui/src/views/system/menu/index.vue      | 35 ++++++++++---------
 ruoyi-ui/src/views/system/role/index.vue      |  3 +-
 ruoyi-ui/src/views/system/role/selectUser.vue |  4 +++
 ruoyi-ui/src/views/system/user/index.vue      |  3 +-
 .../views/system/user/profile/resetPwd.vue    |  9 ++---
 .../views/system/user/profile/userAvatar.vue  |  4 +--
 15 files changed, 46 insertions(+), 46 deletions(-)

diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
index e466ed057..e35eb26e4 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
@@ -7,7 +7,7 @@ import javax.sql.DataSource;
 import java.util.Properties;
 
 /**
- * 定时任务配置
+ * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效)
  * 
  * @author ruoyi
  */
diff --git a/ruoyi-ui/src/api/monitor/server.js b/ruoyi-ui/src/api/monitor/server.js
index 4991a4416..cac77916e 100644
--- a/ruoyi-ui/src/api/monitor/server.js
+++ b/ruoyi-ui/src/api/monitor/server.js
@@ -1,6 +1,6 @@
 import request from '@/utils/request'
 
-// 查询服务器详细
+// 获取服务信息
 export function getServer() {
   return request({
     url: '/monitor/server',
diff --git a/ruoyi-ui/src/components/RightToolbar/index.vue b/ruoyi-ui/src/components/RightToolbar/index.vue
index c7ab139d7..976974e4a 100644
--- a/ruoyi-ui/src/components/RightToolbar/index.vue
+++ b/ruoyi-ui/src/components/RightToolbar/index.vue
@@ -62,7 +62,7 @@ export default {
     },
     // 右侧列表元素变化
     dataChange(data) {
-      for (var item in this.columns) {
+      for (let item in this.columns) {
         const key = this.columns[item].key;
         this.columns[item].visible = !data.includes(key);
       }
diff --git a/ruoyi-ui/src/plugins/tab.js b/ruoyi-ui/src/plugins/tab.js
index f2d7b22b8..95a3848b6 100644
--- a/ruoyi-ui/src/plugins/tab.js
+++ b/ruoyi-ui/src/plugins/tab.js
@@ -20,8 +20,6 @@ export default {
         path: '/redirect' + path
       })
     })
-
-
   },
   // 关闭当前tab页签,打开新页签
   closeOpenPage(obj) {
@@ -56,7 +54,7 @@ export default {
     return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute);
   },
   // 添加tab页签
-  addPage(title, url) {
+  openPage(title, url) {
     var obj = { path: url, meta: { title: title } }
     store.dispatch('tagsView/addView', obj);
     return router.push(url);
diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue
index 255eafca0..3baaf2432 100644
--- a/ruoyi-ui/src/views/login.vue
+++ b/ruoyi-ui/src/views/login.vue
@@ -3,7 +3,12 @@
     <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
       <h3 class="title">若依后台管理系统</h3>
       <el-form-item prop="username">
-        <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号">
+        <el-input
+          v-model="loginForm.username"
+          type="text"
+          auto-complete="off"
+          placeholder="账号"
+        >
           <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
         </el-input>
       </el-form-item>
@@ -66,7 +71,6 @@ export default {
   data() {
     return {
       codeUrl: "",
-      cookiePassword: "",
       loginForm: {
         username: "admin",
         password: "admin123",
diff --git a/ruoyi-ui/src/views/monitor/logininfor/index.vue b/ruoyi-ui/src/views/monitor/logininfor/index.vue
index 0f4ecbba6..98bd74357 100644
--- a/ruoyi-ui/src/views/monitor/logininfor/index.vue
+++ b/ruoyi-ui/src/views/monitor/logininfor/index.vue
@@ -6,8 +6,8 @@
           v-model="queryParams.ipaddr"
           placeholder="请输入登录地址"
           clearable
+		  size="small"
           style="width: 240px;"
-          size="small"
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
@@ -16,8 +16,8 @@
           v-model="queryParams.userName"
           placeholder="请输入用户名称"
           clearable
+		  size="small"
           style="width: 240px;"
-          size="small"
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
diff --git a/ruoyi-ui/src/views/monitor/operlog/index.vue b/ruoyi-ui/src/views/monitor/operlog/index.vue
index 28f705b82..9b8b7856b 100644
--- a/ruoyi-ui/src/views/monitor/operlog/index.vue
+++ b/ruoyi-ui/src/views/monitor/operlog/index.vue
@@ -6,8 +6,8 @@
           v-model="queryParams.title"
           placeholder="请输入系统模块"
           clearable
-          style="width: 240px;"
           size="small"
+          style="width: 240px;"
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
@@ -16,8 +16,8 @@
           v-model="queryParams.operName"
           placeholder="请输入操作人员"
           clearable
-          style="width: 240px;"
           size="small"
+          style="width: 240px;"
           @keyup.enter.native="handleQuery"
         />
       </el-form-item>
diff --git a/ruoyi-ui/src/views/system/dept/index.vue b/ruoyi-ui/src/views/system/dept/index.vue
index f9c7741e5..e215b1c8e 100644
--- a/ruoyi-ui/src/views/system/dept/index.vue
+++ b/ruoyi-ui/src/views/system/dept/index.vue
@@ -179,8 +179,6 @@ export default {
       isExpandAll: true,
       // 重新渲染表格状态
       refreshTable: true,
-      // 是否展开
-      expand: false,
       // 查询参数
       queryParams: {
         deptName: undefined,
@@ -276,7 +274,7 @@ export default {
       this.open = true;
       this.title = "添加部门";
       listDept().then(response => {
-	        this.deptOptions = this.handleTree(response.data, "deptId");
+        this.deptOptions = this.handleTree(response.data, "deptId");
       });
     },
     /** 展开/折叠操作 */
@@ -296,7 +294,7 @@ export default {
         this.title = "修改部门";
       });
       listDeptExcludeChild(row.deptId).then(response => {
-	        this.deptOptions = this.handleTree(response.data, "deptId");
+        this.deptOptions = this.handleTree(response.data, "deptId");
       });
     },
     /** 提交按钮 */
diff --git a/ruoyi-ui/src/views/system/dict/data.vue b/ruoyi-ui/src/views/system/dict/data.vue
index aa878bdd8..c08c28a8d 100644
--- a/ruoyi-ui/src/views/system/dict/data.vue
+++ b/ruoyi-ui/src/views/system/dict/data.vue
@@ -325,7 +325,7 @@ export default {
       this.queryParams.pageNum = 1;
       this.getList();
     },
-    // 返回按钮
+    /** 返回按钮操作 */
     handleClose() {
       const obj = { path: "/system/dict" };
       this.$tab.closeOpenPage(obj);
diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue
index a89e1ee71..d65773ad2 100644
--- a/ruoyi-ui/src/views/system/menu/index.vue
+++ b/ruoyi-ui/src/views/system/menu/index.vue
@@ -78,7 +78,8 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button size="mini"
+          <el-button 
+            size="mini"
             type="text"
             icon="el-icon-edit"
             @click="handleUpdate(scope.row)"
@@ -126,8 +127,8 @@
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="24">
-            <el-form-item v-if="form.menuType != 'F'" label="菜单图标">
+          <el-col :span="24" v-if="form.menuType != 'F'">
+            <el-form-item label="菜单图标">
               <el-popover
                 placement="bottom-start"
                 width="460"
@@ -158,8 +159,8 @@
               <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.menuType != 'F'">
+          <el-col :span="12" v-if="form.menuType != 'F'">
+            <el-form-item>
               <span slot="label">
                 <el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
                 <i class="el-icon-question"></i>
@@ -172,8 +173,8 @@
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.menuType != 'F'" prop="path">
+          <el-col :span="12" v-if="form.menuType != 'F'">
+            <el-form-item prop="path">
               <span slot="label">
                 <el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
                 <i class="el-icon-question"></i>
@@ -194,8 +195,8 @@
               <el-input v-model="form.component" placeholder="请输入组件路径" />
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.menuType != 'M'">
+          <el-col :span="12" v-if="form.menuType != 'M'">
+            <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">
@@ -205,8 +206,8 @@
               </span>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.menuType == 'C'">
+          <el-col :span="12" v-if="form.menuType == 'C'">
+            <el-form-item>
               <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
               <span slot="label">
                 <el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
@@ -216,8 +217,8 @@
               </span>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.menuType == 'C'">
+          <el-col :span="12" v-if="form.menuType == 'C'">
+            <el-form-item>
               <span slot="label">
                 <el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
                 <i class="el-icon-question"></i>
@@ -230,8 +231,8 @@
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.menuType != 'F'">
+          <el-col :span="12" v-if="form.menuType != 'F'">
+            <el-form-item>
               <span slot="label">
                 <el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
                 <i class="el-icon-question"></i>
@@ -247,8 +248,8 @@
               </el-radio-group>
             </el-form-item>
           </el-col>
-          <el-col :span="12">
-            <el-form-item v-if="form.menuType != 'F'">
+          <el-col :span="12" v-if="form.menuType != 'F'">
+            <el-form-item>
               <span slot="label">
                 <el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
                 <i class="el-icon-question"></i>
diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue
index b2cfd6bf8..5b99d1797 100644
--- a/ruoyi-ui/src/views/system/role/index.vue
+++ b/ruoyi-ui/src/views/system/role/index.vue
@@ -355,8 +355,7 @@ export default {
     /** 查询角色列表 */
     getList() {
       this.loading = true;
-      listRole(this.addDateRange(this.queryParams, this.dateRange)).then(
-        response => {
+      listRole(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
           this.roleList = response.rows;
           this.total = response.total;
           this.loading = false;
diff --git a/ruoyi-ui/src/views/system/role/selectUser.vue b/ruoyi-ui/src/views/system/role/selectUser.vue
index a9e2ce0ff..02610d8ef 100644
--- a/ruoyi-ui/src/views/system/role/selectUser.vue
+++ b/ruoyi-ui/src/views/system/role/selectUser.vue
@@ -123,6 +123,10 @@ export default {
     handleSelectUser() {
       const roleId = this.queryParams.roleId;
       const userIds = this.userIds.join(",");
+      if (userIds == "") {
+        this.$modal.msgError("请选择要分配的用户");
+        return;
+      }
       authUserSelectAll({ roleId: roleId, userIds: userIds }).then(res => {
         this.$modal.msgSuccess(res.msg);
         if (res.code === 200) {
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
index 2b7283f9d..3525c9b3f 100644
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -206,7 +206,7 @@
       </el-col>
     </el-row>
 
-    <!-- 添加或修改参数配置对话框 -->
+    <!-- 添加或修改用户配置对话框 -->
     <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="80px">
         <el-row>
@@ -652,7 +652,6 @@ export default {
     /** 下载模板操作 */
     importTemplate() {
       this.download('system/user/importTemplate', {
-        ...this.queryParams
       }, `user_template_${new Date().getTime()}.xlsx`)
     },
     // 文件上传中处理
diff --git a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
index 3437abca1..06715e5cf 100644
--- a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
+++ b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
@@ -29,7 +29,6 @@ export default {
       }
     };
     return {
-      test: "1test",
       user: {
         oldPassword: undefined,
         newPassword: undefined,
@@ -55,11 +54,9 @@ export default {
     submit() {
       this.$refs["form"].validate(valid => {
         if (valid) {
-          updateUserPwd(this.user.oldPassword, this.user.newPassword).then(
-            response => {
-              this.$modal.msgSuccess("修改成功");
-            }
-          );
+          updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
+            this.$modal.msgSuccess("修改成功");
+          });
         }
       });
     },
diff --git a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
index 402d9cc93..63903a706 100644
--- a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
+++ b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
@@ -1,7 +1,7 @@
 <template>
   <div>
     <div class="user-info-head" @click="editCropper()"><img v-bind:src="options.img" title="点击上传头像" class="img-circle img-lg" /></div>
-    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened"  @close="closeDialog()">
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened"  @close="closeDialog">
       <el-row>
         <el-col :xs="24" :md="12" :style="{height: '350px'}">
           <vue-cropper
@@ -140,7 +140,7 @@ export default {
     // 关闭窗口
     closeDialog() {
       this.options.img = store.getters.avatar
-	  this.visible = false;
+      this.visible = false;
     }
   }
 };

From 4f194aa1010488644d99bf2c56fc62054c3fdf41 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 22 Nov 2021 18:07:33 +0800
Subject: [PATCH 33/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7js-cookie=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC3.0.1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index a52059488..25ff81391 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -46,7 +46,7 @@
     "fuse.js": "6.4.3",
     "highlight.js": "9.18.5",
     "js-beautify": "1.13.0",
-    "js-cookie": "2.2.1",
+    "js-cookie": "3.0.1",
     "jsencrypt": "3.2.1",
     "nprogress": "0.2.0",
     "quill": "1.3.7",

From b4f032fab4bb6719a278a2fe69243d58975f8cb2 Mon Sep 17 00:00:00 2001
From: fuzui <73400@163.com>
Date: Wed, 24 Nov 2021 02:48:35 +0800
Subject: [PATCH 34/74] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BB=A3=E7=A0=81?=
 =?UTF-8?q?=E7=94=9F=E6=88=90=E4=B8=AD=E5=86=97=E4=BD=99=E7=9A=84=E5=AF=BC?=
 =?UTF-8?q?=E5=87=BA=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-generator/src/main/resources/vm/js/api.js.vm       | 9 ---------
 .../src/main/resources/vm/vue/index-tree.vue.vm          | 2 +-
 2 files changed, 1 insertion(+), 10 deletions(-)

diff --git a/ruoyi-generator/src/main/resources/vm/js/api.js.vm b/ruoyi-generator/src/main/resources/vm/js/api.js.vm
index cd2403cc6..d78cd2f64 100644
--- a/ruoyi-generator/src/main/resources/vm/js/api.js.vm
+++ b/ruoyi-generator/src/main/resources/vm/js/api.js.vm
@@ -42,12 +42,3 @@ export function del${BusinessName}(${pkColumn.javaField}) {
     method: 'delete'
   })
 }
-
-// 导出${functionName}
-export function export${BusinessName}(query) {
-  return request({
-    url: '/${moduleName}/${businessName}/export',
-    method: 'get',
-    params: query
-  })
-}
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
index 19802cee8..a1c9ecf55 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -259,7 +259,7 @@
 </template>
 
 <script>
-import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 

From 026a4271030e12f43de7eb383c53c4aae17072fa Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 24 Nov 2021 14:47:24 +0800
Subject: [PATCH 35/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=89=8D=E7=AB=AF?=
 =?UTF-8?q?=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json                           |  2 +-
 ruoyi-ui/src/components/Breadcrumb/index.vue    |  2 +-
 ruoyi-ui/src/components/RuoYi/Doc/index.vue     |  2 +-
 ruoyi-ui/src/components/RuoYi/Git/index.vue     |  2 +-
 ruoyi-ui/src/components/SizeSelect/index.vue    |  3 +--
 ruoyi-ui/src/layout/components/Sidebar/Logo.vue |  2 +-
 ruoyi-ui/src/layout/index.vue                   |  2 +-
 ruoyi-ui/src/main.js                            |  2 +-
 ruoyi-ui/src/plugins/download.js                |  4 ++--
 ruoyi-ui/src/router/index.js                    | 10 +++++-----
 ruoyi-ui/src/store/modules/permission.js        |  4 ++--
 ruoyi-ui/src/store/modules/settings.js          |  2 +-
 ruoyi-ui/src/store/modules/user.js              |  2 +-
 13 files changed, 19 insertions(+), 20 deletions(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 25ff81391..5b3760977 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -55,7 +55,7 @@
     "vue": "2.6.12",
     "vue-count-to": "1.0.13",
     "vue-cropper": "0.5.5",
-    "vue-meta": "^2.4.0",
+    "vue-meta": "2.4.0",
     "vue-router": "3.4.9",
     "vuedraggable": "2.24.3",
     "vuex": "3.6.0"
diff --git a/ruoyi-ui/src/components/Breadcrumb/index.vue b/ruoyi-ui/src/components/Breadcrumb/index.vue
index 1fbae5f3c..1696f5471 100644
--- a/ruoyi-ui/src/components/Breadcrumb/index.vue
+++ b/ruoyi-ui/src/components/Breadcrumb/index.vue
@@ -2,7 +2,7 @@
   <el-breadcrumb class="app-breadcrumb" separator="/">
     <transition-group name="breadcrumb">
       <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
-        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
+        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
         <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
       </el-breadcrumb-item>
     </transition-group>
diff --git a/ruoyi-ui/src/components/RuoYi/Doc/index.vue b/ruoyi-ui/src/components/RuoYi/Doc/index.vue
index 3915c2965..cc829b243 100644
--- a/ruoyi-ui/src/components/RuoYi/Doc/index.vue
+++ b/ruoyi-ui/src/components/RuoYi/Doc/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <svg-icon icon-class="question" @click="goto"/>
+    <svg-icon icon-class="question" @click="goto" />
   </div>
 </template>
 
diff --git a/ruoyi-ui/src/components/RuoYi/Git/index.vue b/ruoyi-ui/src/components/RuoYi/Git/index.vue
index 2aab63c15..517c44865 100644
--- a/ruoyi-ui/src/components/RuoYi/Git/index.vue
+++ b/ruoyi-ui/src/components/RuoYi/Git/index.vue
@@ -1,6 +1,6 @@
 <template>
   <div>
-    <svg-icon icon-class="github" @click="goto"/>
+    <svg-icon icon-class="github" @click="goto" />
   </div>
 </template>
 
diff --git a/ruoyi-ui/src/components/SizeSelect/index.vue b/ruoyi-ui/src/components/SizeSelect/index.vue
index 5503b9712..00496f71d 100644
--- a/ruoyi-ui/src/components/SizeSelect/index.vue
+++ b/ruoyi-ui/src/components/SizeSelect/index.vue
@@ -5,8 +5,7 @@
     </div>
     <el-dropdown-menu slot="dropdown">
       <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
-        {{
-          item.label }}
+        {{ item.label }}
       </el-dropdown-item>
     </el-dropdown-menu>
   </el-dropdown>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
index 82f3d581b..c8401c519 100644
--- a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
+++ b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
@@ -29,7 +29,7 @@ export default {
     variables() {
       return variables;
     },
-	sideTheme() {
+    sideTheme() {
       return this.$store.state.settings.sideTheme
     }
   },
diff --git a/ruoyi-ui/src/layout/index.vue b/ruoyi-ui/src/layout/index.vue
index 718723ea4..4d6fe0244 100644
--- a/ruoyi-ui/src/layout/index.vue
+++ b/ruoyi-ui/src/layout/index.vue
@@ -98,7 +98,7 @@ export default {
   }
 
   .hideSidebar .fixed-header {
-    width: calc(100% - 54px)
+    width: calc(100% - 54px);
   }
 
   .mobile .fixed-header {
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index 83b079101..729467aee 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -10,7 +10,7 @@ import '@/assets/styles/ruoyi.scss' // ruoyi css
 import App from './App'
 import store from './store'
 import router from './router'
-import directive from './directive' //directive
+import directive from './directive' // directive
 import plugins from './plugins' // plugins
 import { download } from '@/utils/request'
 
diff --git a/ruoyi-ui/src/plugins/download.js b/ruoyi-ui/src/plugins/download.js
index e1c664057..103e10625 100644
--- a/ruoyi-ui/src/plugins/download.js
+++ b/ruoyi-ui/src/plugins/download.js
@@ -15,7 +15,7 @@ export default {
       responseType: 'blob',
       headers: { 'Authorization': 'Bearer ' + getToken() }
     }).then(async (res) => {
-      const isLogin = await this.blobValidate(res.data);
+      const isLogin = await blobValidate(res.data);
       if (isLogin) {
         const blob = new Blob([res.data])
         this.saveAs(blob, decodeURI(res.headers['download-filename']))
@@ -32,7 +32,7 @@ export default {
       responseType: 'blob',
       headers: { 'Authorization': 'Bearer ' + getToken() }
     }).then(async (res) => {
-      const isLogin = await this.blobValidate(res.data);
+      const isLogin = await blobValidate(res.data);
       if (isLogin) {
         const blob = new Blob([res.data])
         this.saveAs(blob, decodeURI(res.headers['download-filename']))
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index a826980f2..ccf886f73 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -95,7 +95,7 @@ export const constantRoutes = [
         path: 'role/:userId(\\d+)',
         component: (resolve) => require(['@/views/system/user/authRole'], resolve),
         name: 'AuthRole',
-        meta: { title: '分配角色', activeMenu: '/system/user'}
+        meta: { title: '分配角色', activeMenu: '/system/user' }
       }
     ]
   },
@@ -108,7 +108,7 @@ export const constantRoutes = [
         path: 'user/:roleId(\\d+)',
         component: (resolve) => require(['@/views/system/role/authUser'], resolve),
         name: 'AuthUser',
-        meta: { title: '分配用户', activeMenu: '/system/role'}
+        meta: { title: '分配用户', activeMenu: '/system/role' }
       }
     ]
   },
@@ -121,7 +121,7 @@ export const constantRoutes = [
         path: 'index/:dictId(\\d+)',
         component: (resolve) => require(['@/views/system/dict/data'], resolve),
         name: 'Data',
-        meta: { title: '字典数据', activeMenu: '/system/dict'}
+        meta: { title: '字典数据', activeMenu: '/system/dict' }
       }
     ]
   },
@@ -134,7 +134,7 @@ export const constantRoutes = [
         path: 'index',
         component: (resolve) => require(['@/views/monitor/job/log'], resolve),
         name: 'JobLog',
-        meta: { title: '调度日志', activeMenu: '/monitor/job'}
+        meta: { title: '调度日志', activeMenu: '/monitor/job' }
       }
     ]
   },
@@ -147,7 +147,7 @@ export const constantRoutes = [
         path: 'index',
         component: (resolve) => require(['@/views/tool/gen/editTable'], resolve),
         name: 'GenEdit',
-        meta: { title: '修改生成配置', activeMenu: '/tool/gen'}
+        meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
       }
     ]
   }
diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js
index 4c8ed023b..2c2120a8f 100644
--- a/ruoyi-ui/src/store/modules/permission.js
+++ b/ruoyi-ui/src/store/modules/permission.js
@@ -1,7 +1,7 @@
 import { constantRoutes } from '@/router'
 import { getRouters } from '@/api/menu'
 import Layout from '@/layout/index'
-import ParentView from '@/components/ParentView';
+import ParentView from '@/components/ParentView'
 import InnerLink from '@/layout/components/InnerLink'
 
 const permission = {
@@ -24,7 +24,7 @@ const permission = {
       // 顶部导航菜单默认添加统计报表栏指向首页
       const index = [{
         path: 'index',
-        meta: { title: '统计报表', icon: 'dashboard'}
+        meta: { title: '统计报表', icon: 'dashboard' }
       }]
       state.topbarRouters = routes.concat(index);
     },
diff --git a/ruoyi-ui/src/store/modules/settings.js b/ruoyi-ui/src/store/modules/settings.js
index 3277a60d9..d08d8c2cc 100644
--- a/ruoyi-ui/src/store/modules/settings.js
+++ b/ruoyi-ui/src/store/modules/settings.js
@@ -8,7 +8,7 @@ const state = {
   theme: storageSetting.theme || '#409EFF',
   sideTheme: storageSetting.sideTheme || sideTheme,
   showSettings: showSettings,
-  topNav:  storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
+  topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
   tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
   fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
   sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js
index 92bd8f76a..fce1a86b8 100644
--- a/ruoyi-ui/src/store/modules/user.js
+++ b/ruoyi-ui/src/store/modules/user.js
@@ -66,7 +66,7 @@ const user = {
         })
       })
     },
-    
+
     // 退出系统
     LogOut({ commit, state }) {
       return new Promise((resolve, reject) => {

From 31106c91fbf8a3b8ad5ab97e5bfd9263fa24c898 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 24 Nov 2021 15:00:51 +0800
Subject: [PATCH 36/74] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BD=BF=E7=94=A8=20th?=
 =?UTF-8?q?is.$options.data=20=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/utils/dict/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/src/utils/dict/index.js b/ruoyi-ui/src/utils/dict/index.js
index 66ddfef9e..d6fdb802c 100644
--- a/ruoyi-ui/src/utils/dict/index.js
+++ b/ruoyi-ui/src/utils/dict/index.js
@@ -5,7 +5,7 @@ export default function(Vue, options) {
   mergeOptions(options)
   Vue.mixin({
     data() {
-      if (this.$options.dicts === undefined || this.$options.dicts === null) {
+      if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
         return {}
       }
       const dict = new Dict()

From 16734b1d88bdab94516ec1f43833017d8cf8d821 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 24 Nov 2021 15:03:04 +0800
Subject: [PATCH 37/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7velocity=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC2.3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                                                | 10 ++--------
 ruoyi-generator/pom.xml                                |  2 +-
 .../com/ruoyi/generator/util/VelocityInitializer.java  |  3 +--
 3 files changed, 4 insertions(+), 11 deletions(-)

diff --git a/pom.xml b/pom.xml
index 2f3dd728d..7c0f8631c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
         <commons.fileupload.version>1.4</commons.fileupload.version>
         <commons.collections.version>3.2.2</commons.collections.version>
         <poi.version>4.1.2</poi.version>
-        <velocity.version>1.7</velocity.version>
+        <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
     </properties>
 	
@@ -132,14 +132,8 @@
             <!-- velocity代码生成使用模板 -->
             <dependency>
                 <groupId>org.apache.velocity</groupId>
-                <artifactId>velocity</artifactId>
+                <artifactId>velocity-engine-core</artifactId>
                 <version>${velocity.version}</version>
-                <exclusions>
-                    <exclusion>
-                        <groupId>commons-collections</groupId>
-                        <artifactId>commons-collections</artifactId>
-                    </exclusion>
-                </exclusions>
             </dependency>
 
             <!-- collections工具类 -->
diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml
index f68bbe984..89d921fb3 100644
--- a/ruoyi-generator/pom.xml
+++ b/ruoyi-generator/pom.xml
@@ -20,7 +20,7 @@
         <!--velocity代码生成使用模板 -->
         <dependency>
             <groupId>org.apache.velocity</groupId>
-            <artifactId>velocity</artifactId>
+            <artifactId>velocity-engine-core</artifactId>
         </dependency>
 
         <!-- collections工具类 -->
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
index 4be1eecbb..26456335e 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
@@ -20,10 +20,9 @@ public class VelocityInitializer
         try
         {
             // 加载classpath目录下的vm文件
-            p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
             // 定义字符集
             p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
-            p.setProperty(Velocity.OUTPUT_ENCODING, Constants.UTF8);
             // 初始化Velocity引擎,指定配置Properties
             Velocity.init(p);
         }

From 64f6a69d9a71d54e768e0e677aede973034a4026 Mon Sep 17 00:00:00 2001
From: Ricky <hk_ricky@163.com>
Date: Thu, 25 Nov 2021 13:54:49 +0800
Subject: [PATCH 38/74] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=A3=E7=A0=81?=
 =?UTF-8?q?=E7=94=9F=E6=88=90=E5=A4=8D=E9=80=89=E6=A1=86=E5=AD=97=E5=85=B8?=
 =?UTF-8?q?=E9=81=97=E6=BC=8F=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/ruoyi/generator/util/VelocityUtils.java | 3 ++-
 ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm   | 4 ++++
 ruoyi-generator/src/main/resources/vm/vue/index.vue.vm        | 4 ++++
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
index 2683ec8fd..1dadf2ced 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
@@ -274,7 +274,8 @@ public class VelocityUtils
         for (GenTableColumn column : columns)
         {
             if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
-                    column.getHtmlType(), new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO }))
+                    column.getHtmlType(),
+                    new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX }))
             {
                 dicts.add("'" + column.getDictType() + "'");
             }
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
index a1c9ecf55..fb9cef790 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -108,7 +108,11 @@
 #elseif($column.list && "" != $column.dictType)
       <el-table-column label="${comment}" align="center" prop="${javaField}">
         <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
           <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
         </template>
       </el-table-column>
 #elseif($column.list && "" != $javaField)
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
index 729a9dafe..10a1b91b0 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -136,7 +136,11 @@
 #elseif($column.list && "" != $column.dictType)
       <el-table-column label="${comment}" align="center" prop="${javaField}">
         <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
           <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
         </template>
       </el-table-column>
 #elseif($column.list && "" != $javaField)

From 9fc3e220a7d1789f54b20630c9858bd743d51408 Mon Sep 17 00:00:00 2001
From: Ricky <hk_ricky@163.com>
Date: Thu, 25 Nov 2021 14:00:27 +0800
Subject: [PATCH 39/74] =?UTF-8?q?=E9=98=B2=E6=AD=A2=E4=BF=AE=E6=94=B9?=
 =?UTF-8?q?=E7=94=A8=E6=88=B7=E4=B8=AA=E4=BA=BA=E4=BF=A1=E6=81=AF=E6=8E=A5?=
 =?UTF-8?q?=E5=8F=A3=E4=BF=AE=E6=94=B9=E7=94=A8=E6=88=B7=E5=90=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../ruoyi/web/controller/system/SysProfileController.java  | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
index 227ac872d..d764651c8 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -60,6 +60,9 @@ public class SysProfileController extends BaseController
     @PutMapping
     public AjaxResult updateProfile(@RequestBody SysUser user)
     {
+        LoginUser loginUser = getLoginUser();
+        SysUser sysUser = loginUser.getUser();
+        user.setUserName(sysUser.getUserName());
         if (StringUtils.isNotEmpty(user.getPhonenumber())
                 && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
         {
@@ -69,9 +72,7 @@ public class SysProfileController extends BaseController
                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
         {
             return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
-        }
-        LoginUser loginUser = getLoginUser();
-        SysUser sysUser = loginUser.getUser();
+        }       
         user.setUserId(sysUser.getUserId());
         user.setPassword(null);
         if (userService.updateUserProfile(user) > 0)

From 664192da0b746cc064a3b9b992083eb7b68253e9 Mon Sep 17 00:00:00 2001
From: Ricky <hk_ricky@163.com>
Date: Thu, 25 Nov 2021 15:18:02 +0800
Subject: [PATCH 40/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7velocity=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC2.3=EF=BC=88=E8=AF=AD?=
 =?UTF-8?q?=E6=B3=95=E5=8D=87=E7=BA=A7=EF=BC=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/resources/vm/vue/index-tree.vue.vm   | 14 +++++---------
 .../src/main/resources/vm/vue/index.vue.vm        | 15 +++++----------
 .../src/main/resources/vm/xml/mapper.xml.vm       | 10 +++++-----
 3 files changed, 15 insertions(+), 24 deletions(-)

diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
index fb9cef790..62b12d98d 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -300,8 +300,7 @@ export default {
       queryParams: {
 #foreach ($column in $columns)
 #if($column.query)
-        $column.javaField: null#if($velocityCount != $columns.size()),#end
-
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
 #end
 #end
       },
@@ -319,8 +318,7 @@ export default {
 #end
         $column.javaField: [
           { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
-        ]#if($velocityCount != $columns.size()),#end
-
+        ]#if($foreach.count != $columns.size()),#end
 #end
 #end
       }
@@ -383,14 +381,12 @@ export default {
       this.form = {
 #foreach ($column in $columns)
 #if($column.htmlType == "radio")
-        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
+        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
 
 #elseif($column.htmlType == "checkbox")
-        $column.javaField: []#if($velocityCount != $columns.size()),#end
-
+        $column.javaField: []#if($foreach.count != $columns.size()),#end
 #else
-        $column.javaField: null#if($velocityCount != $columns.size()),#end
-
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
 #end
 #end
       };
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
index 10a1b91b0..52adeaade 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -364,8 +364,7 @@ export default {
         pageSize: 10,
 #foreach ($column in $columns)
 #if($column.query)
-        $column.javaField: null#if($velocityCount != $columns.size()),#end
-
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
 #end
 #end
       },
@@ -383,8 +382,7 @@ export default {
 #end
         $column.javaField: [
           { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
-        ]#if($velocityCount != $columns.size()),#end
-
+        ]#if($foreach.count != $columns.size()),#end
 #end
 #end
       }
@@ -428,14 +426,11 @@ export default {
       this.form = {
 #foreach ($column in $columns)
 #if($column.htmlType == "radio")
-        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
-
+        $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
 #elseif($column.htmlType == "checkbox")
-        $column.javaField: []#if($velocityCount != $columns.size()),#end
-
+        $column.javaField: []#if($foreach.count != $columns.size()),#end
 #else
-        $column.javaField: null#if($velocityCount != $columns.size()),#end
-
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
 #end
 #end
       };
diff --git a/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
index 0c681d9cd..5b704e737 100644
--- a/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
+++ b/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
@@ -23,7 +23,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 #end
 
     <sql id="select${ClassName}Vo">
-        select#foreach($column in $columns) $column.columnName#if($velocityCount != $columns.size()),#end#end from ${tableName}
+        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName}
     </sql>
 
     <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result">
@@ -63,8 +63,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="select${ClassName}Vo"/>
         where ${pkColumn.columnName} = #{${pkColumn.javaField}}
 #elseif($table.sub)
-        select#foreach($column in $columns) a.$column.columnName#if($velocityCount != $columns.size()),#end#end,
-           #foreach($column in $subTable.columns) b.$column.columnName as sub_$column.columnName#if($velocityCount != $subTable.columns.size()),#end#end
+        select#foreach($column in $columns) a.$column.columnName#if($foreach.count != $columns.size()),#end#end,
+           #foreach($column in $subTable.columns) b.$column.columnName as sub_$column.columnName#if($foreach.count != $subTable.columns.size()),#end#end
 
         from ${tableName} a
         left join ${subTableName} b on b.${subTableFkName} = a.${pkColumn.columnName}
@@ -126,9 +126,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </delete>
 
     <insert id="batch${subClassName}">
-        insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($velocityCount != $subTable.columns.size()),#end#end) values
+        insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values
 		<foreach item="item" index="index" collection="list" separator=",">
-            (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($velocityCount != $subTable.columns.size()),#end#end)
+            (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end)
         </foreach>
     </insert>
 #end

From e5fd1f76db721443a0d2dc0cb6aac8cfcad5c32a Mon Sep 17 00:00:00 2001
From: khejing <khejing3@aliyun.com>
Date: Fri, 26 Nov 2021 08:26:45 +0000
Subject: [PATCH 41/74] =?UTF-8?q?camelCase=E4=B8=AD=E5=BA=94=E8=AF=A5?=
 =?UTF-8?q?=E6=98=AF=E4=B8=8B=E5=88=92=E7=BA=BF=EF=BC=8C=E8=80=8C=E4=B8=8D?=
 =?UTF-8?q?=E6=98=AF=E6=A8=AA=E6=9D=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/utils/index.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js
index 2893bc83a..9679e757a 100644
--- a/ruoyi-ui/src/utils/index.js
+++ b/ruoyi-ui/src/utils/index.js
@@ -381,7 +381,7 @@ export function titleCase(str) {
 
 // 下划转驼峰
 export function camelCase(str) {
-  return str.replace(/-[a-z]/g, str1 => str1.substr(-1).toUpperCase())
+  return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
 }
 
 export function isNumberStr(str) {

From 89e7cb19b9161fb2164fcfb61fe6da2de00f0004 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Fri, 26 Nov 2021 18:11:57 +0800
Subject: [PATCH 42/74] =?UTF-8?q?=E6=B3=A8=E5=86=8C=E6=88=90=E5=8A=9F?=
 =?UTF-8?q?=E6=8F=90=E7=A4=BA=E7=B1=BB=E5=9E=8Bsuccess?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/views/register.vue | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ruoyi-ui/src/views/register.vue b/ruoyi-ui/src/views/register.vue
index 7ee0a7973..476aa8196 100644
--- a/ruoyi-ui/src/views/register.vue
+++ b/ruoyi-ui/src/views/register.vue
@@ -127,7 +127,8 @@ export default {
           register(this.registerForm).then(res => {
             const username = this.registerForm.username;
             this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
-              dangerouslyUseHTMLString: true
+              dangerouslyUseHTMLString: true,
+              type: 'success'
             }).then(() => {
               this.$router.push("/login");
             }).catch(() => {});

From 34f2552cad396ce79a7cf4a50a15ff8bf5d817b6 Mon Sep 17 00:00:00 2001
From: fuzui <73400@163.com>
Date: Tue, 30 Nov 2021 00:17:12 +0800
Subject: [PATCH 43/74] =?UTF-8?q?fix:=20crontab=E7=BB=84=E4=BB=B6=E4=BA=92?=
 =?UTF-8?q?=E6=96=A5bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/components/Crontab/day.vue    | 19 +++++-----------
 ruoyi-ui/src/components/Crontab/hour.vue   | 14 +++---------
 ruoyi-ui/src/components/Crontab/index.vue  |  7 +++++-
 ruoyi-ui/src/components/Crontab/min.vue    |  4 ----
 ruoyi-ui/src/components/Crontab/month.vue  | 20 +++--------------
 ruoyi-ui/src/components/Crontab/second.vue |  1 -
 ruoyi-ui/src/components/Crontab/week.vue   | 25 +++++-----------------
 ruoyi-ui/src/components/Crontab/year.vue   | 15 -------------
 8 files changed, 22 insertions(+), 83 deletions(-)

diff --git a/ruoyi-ui/src/components/Crontab/day.vue b/ruoyi-ui/src/components/Crontab/day.vue
index bf9f5664e..bccd1d7a8 100644
--- a/ruoyi-ui/src/components/Crontab/day.vue
+++ b/ruoyi-ui/src/components/Crontab/day.vue
@@ -72,23 +72,14 @@ export default {
 		// 单选按钮值变化时
 		radioChange() {
 			('day rachange');
-			if (this.radioValue === 1) {
-				this.$emit('update', 'day', '*', 'day');
-				this.$emit('update', 'week', '?', 'day');
-				this.$emit('update', 'month', '*', 'day');
-			} else {
-				if (this.cron.hour === '*') {
-					this.$emit('update', 'hour', '0', 'day');
-				}
-				if (this.cron.min === '*') {
-					this.$emit('update', 'min', '0', 'day');
-				}
-				if (this.cron.second === '*') {
-					this.$emit('update', 'second', '0', 'day');
-				}
+			if (this.radioValue !== 2 && this.cron.week !== '?') {
+				this.$emit('update', 'week', '?', 'day')
 			}
 
 			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'day', '*');
+					break;
 				case 2:
 					this.$emit('update', 'day', '?');
 					break;
diff --git a/ruoyi-ui/src/components/Crontab/hour.vue b/ruoyi-ui/src/components/Crontab/hour.vue
index 5a1e14678..131edc9ce 100644
--- a/ruoyi-ui/src/components/Crontab/hour.vue
+++ b/ruoyi-ui/src/components/Crontab/hour.vue
@@ -51,18 +51,10 @@ export default {
 	methods: {
 		// 单选按钮值变化时
 		radioChange() {
-			if (this.radioValue === 1) {
-				this.$emit('update', 'hour', '*', 'hour');
-				this.$emit('update', 'day', '*', 'hour');
-			} else {
-				if (this.cron.min === '*') {
-					this.$emit('update', 'min', '0', 'hour');
-				}
-				if (this.cron.second === '*') {
-					this.$emit('update', 'second', '0', 'hour');
-				}
-			}
 			switch (this.radioValue) {
+				case 1:
+        	this.$emit('update', 'hour', '*')
+        	break;
 				case 2:
 					this.$emit('update', 'hour', this.cycle01 + '-' + this.cycle02);
 					break;
diff --git a/ruoyi-ui/src/components/Crontab/index.vue b/ruoyi-ui/src/components/Crontab/index.vue
index 27b4ab36c..bd863b1b6 100644
--- a/ruoyi-ui/src/components/Crontab/index.vue
+++ b/ruoyi-ui/src/components/Crontab/index.vue
@@ -2,7 +2,12 @@
   <div>
     <el-tabs type="border-card">
       <el-tab-pane label="秒" v-if="shouldHide('second')">
-        <CrontabSecond @update="updateCrontabValue" :check="checkNumber" ref="cronsecond" />
+        <CrontabSecond
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronsecond"
+        />
       </el-tab-pane>
 
       <el-tab-pane label="分钟" v-if="shouldHide('min')">
diff --git a/ruoyi-ui/src/components/Crontab/min.vue b/ruoyi-ui/src/components/Crontab/min.vue
index 980c4e768..79e435b0c 100644
--- a/ruoyi-ui/src/components/Crontab/min.vue
+++ b/ruoyi-ui/src/components/Crontab/min.vue
@@ -52,13 +52,9 @@ export default {
 	methods: {
 		// 单选按钮值变化时
 		radioChange() {
-			if (this.radioValue !== 1 && this.cron.second === '*') {
-				this.$emit('update', 'second', '0', 'min');
-			}
 			switch (this.radioValue) {
 				case 1:
 					this.$emit('update', 'min', '*', 'min');
-					this.$emit('update', 'hour', '*', 'min');
 					break;
 				case 2:
 					this.$emit('update', 'min', this.cycle01 + '-' + this.cycle02, 'min');
diff --git a/ruoyi-ui/src/components/Crontab/month.vue b/ruoyi-ui/src/components/Crontab/month.vue
index 619d1e791..a7e52e1f8 100644
--- a/ruoyi-ui/src/components/Crontab/month.vue
+++ b/ruoyi-ui/src/components/Crontab/month.vue
@@ -51,24 +51,10 @@ export default {
 	methods: {
 		// 单选按钮值变化时
 		radioChange() {
-			if (this.radioValue === 1) {
-				this.$emit('update', 'month', '*');
-				this.$emit('update', 'year', '*');
-			} else {
-				if (this.cron.day === '*') {
-					this.$emit('update', 'day', '0', 'month');
-				}
-				if (this.cron.hour === '*') {
-					this.$emit('update', 'hour', '0', 'month');
-				}
-				if (this.cron.min === '*') {
-					this.$emit('update', 'min', '0', 'month');
-				}
-				if (this.cron.second === '*') {
-					this.$emit('update', 'second', '0', 'month');
-				}
-			}
 			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'month', '*');
+					break;
 				case 2:
 					this.$emit('update', 'month', this.cycle01 + '-' + this.cycle02);
 					break;
diff --git a/ruoyi-ui/src/components/Crontab/second.vue b/ruoyi-ui/src/components/Crontab/second.vue
index 0fdf3386d..40815fb09 100644
--- a/ruoyi-ui/src/components/Crontab/second.vue
+++ b/ruoyi-ui/src/components/Crontab/second.vue
@@ -54,7 +54,6 @@ export default {
 			switch (this.radioValue) {
 				case 1:
 					this.$emit('update', 'second', '*', 'second');
-					this.$emit('update', 'min', '*', 'second');
 					break;
 				case 2:
 					this.$emit('update', 'second', this.cycle01 + '-' + this.cycle02);
diff --git a/ruoyi-ui/src/components/Crontab/week.vue b/ruoyi-ui/src/components/Crontab/week.vue
index 5ad949d6b..8cc82e208 100644
--- a/ruoyi-ui/src/components/Crontab/week.vue
+++ b/ruoyi-ui/src/components/Crontab/week.vue
@@ -67,27 +67,13 @@ export default {
 	methods: {
 		// 单选按钮值变化时
 		radioChange() {
-			if (this.radioValue === 1) {
-				this.$emit('update', 'week', '*');
-				this.$emit('update', 'year', '*');
-			} else {
-				if (this.cron.month === '*') {
-					this.$emit('update', 'month', '0', 'week');
-				}
-				if (this.cron.day === '*') {
-					this.$emit('update', 'day', '0', 'week');
-				}
-				if (this.cron.hour === '*') {
-					this.$emit('update', 'hour', '0', 'week');
-				}
-				if (this.cron.min === '*') {
-					this.$emit('update', 'min', '0', 'week');
-				}
-				if (this.cron.second === '*') {
-					this.$emit('update', 'second', '0', 'week');
-				}
+			if (this.radioValue !== 2 && this.cron.day !== '?') {
+				this.$emit('update', 'day', '?', 'week');
 			}
 			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'week', '*');
+					break;
 				case 2:
 					this.$emit('update', 'week', '?');
 					break;
@@ -105,7 +91,6 @@ export default {
 					break;
 			}
 		},
-		// 根据互斥事件,更改radio的值
 
 		// 周期两个值变化时
 		cycleChange() {
diff --git a/ruoyi-ui/src/components/Crontab/year.vue b/ruoyi-ui/src/components/Crontab/year.vue
index 800dfa522..16a2b04f3 100644
--- a/ruoyi-ui/src/components/Crontab/year.vue
+++ b/ruoyi-ui/src/components/Crontab/year.vue
@@ -59,21 +59,6 @@ export default {
 	methods: {
 		// 单选按钮值变化时
 		radioChange() {
-			if (this.cron.month === '*') {
-				this.$emit('update', 'month', '0', 'year');
-			}
-			if (this.cron.day === '*') {
-				this.$emit('update', 'day', '0', 'year');
-			}
-			if (this.cron.hour === '*') {
-				this.$emit('update', 'hour', '0', 'year');
-			}
-			if (this.cron.min === '*') {
-				this.$emit('update', 'min', '0', 'year');
-			}
-			if (this.cron.second === '*') {
-				this.$emit('update', 'second', '0', 'year');
-			}
 			switch (this.radioValue) {
 				case 1:
 					this.$emit('update', 'year', '');

From ca285f5e53aea0dae4fb1db8e46a0c0cb70afa29 Mon Sep 17 00:00:00 2001
From: fuzui <73400@163.com>
Date: Tue, 30 Nov 2021 00:22:23 +0800
Subject: [PATCH 44/74] =?UTF-8?q?fix:=20crontab=E7=BB=84=E4=BB=B6=E5=91=A8?=
 =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8F=8A=E8=AE=A1=E7=AE=97bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/components/Crontab/result.vue | 21 ++----
 ruoyi-ui/src/components/Crontab/week.vue   | 74 ++++++++++++++++++----
 2 files changed, 69 insertions(+), 26 deletions(-)

diff --git a/ruoyi-ui/src/components/Crontab/result.vue b/ruoyi-ui/src/components/Crontab/result.vue
index 07b963b79..aea6e0e46 100644
--- a/ruoyi-ui/src/components/Crontab/result.vue
+++ b/ruoyi-ui/src/components/Crontab/result.vue
@@ -179,7 +179,7 @@ export default {
 							// 获取达到条件的日期是星期X
 							let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
 							// 当星期日时
-							if (thisWeek == 0) {
+							if (thisWeek == 1) {
 								// 先找下一个日,并判断是否为月底
 								DD++;
 								thisDD = DD < 10 ? '0' + DD : DD;
@@ -187,7 +187,7 @@ export default {
 								if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
 									DD -= 3;
 								}
-							} else if (thisWeek == 6) {
+							} else if (thisWeek == 7) {
 								// 当星期6时只需判断不是1号就可进行操作
 								if (this.dayRuleSup !== 1) {
 									DD--;
@@ -200,7 +200,7 @@ export default {
 							// 获取当前日期是属于星期几
 							let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
 							// 校验当前星期是否在星期池(dayRuleSup)中
-							if (Array.indexOf(this.dayRuleSup, thisWeek) < 0) {
+							if (this.dayRuleSup.indexOf(thisWeek) < 0) {
 								// 如果到达最大值时
 								if (Di == DDate.length - 1) {
 									resetDay();
@@ -385,7 +385,7 @@ export default {
 				} else if (rule.indexOf('#') >= 0) {
 					this.dayRule = 'assWeek';
 					let matchRule = rule.match(/[0-9]{1}/g);
-					this.dayRuleSup = [Number(matchRule[0]), Number(matchRule[1])];
+					this.dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])];
 					this.dateArr[3] = [1];
 					if (this.dayRuleSup[1] == 7) {
 						this.dayRuleSup[1] = 0;
@@ -401,14 +401,6 @@ export default {
 					this.dayRule = 'weekDay';
 					this.dayRuleSup = this.getAssignArr(rule)
 				}
-				// 如果weekDay时将7调整为0【week值0即是星期日】
-				if (this.dayRule == 'weekDay') {
-					for (let i = 0; i < this.dayRuleSup.length; i++) {
-						if (this.dayRuleSup[i] == 7) {
-							this.dayRuleSup[i] = 0;
-						}
-					}
-				}
 			}
 		},
 		// 获取"日"数组-少量为日期规则
@@ -543,14 +535,15 @@ export default {
 			if (type == undefined) {
 				return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
 			} else if (type == 'week') {
-				return week;
+				// 在quartz中 1为星期日
+				return week + 1;
 			}
 		},
 		// 检查日期是否存在
 		checkDate(value) {
 			let time = new Date(value);
 			let format = this.formatDate(time)
-			return value == format ? true : false;
+			return value === format;
 		}
 	},
 	watch: {
diff --git a/ruoyi-ui/src/components/Crontab/week.vue b/ruoyi-ui/src/components/Crontab/week.vue
index 8cc82e208..4485bc4f6 100644
--- a/ruoyi-ui/src/components/Crontab/week.vue
+++ b/ruoyi-ui/src/components/Crontab/week.vue
@@ -15,8 +15,25 @@
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="3">
 				周期从星期
-				<el-input-number v-model='cycle01' :min="1" :max="7" /> -
-				<el-input-number v-model='cycle02' :min="1" :max="7" />
+				<el-select clearable v-model="cycle01">
+					<el-option
+						v-for="(item,index) of weekList"
+						:key="index"
+						:label="item.value"
+						:value="item.key"
+						:disabled="item.key === 1"
+					>{{item.value}}</el-option>
+				</el-select>
+				-
+				<el-select clearable v-model="cycle02">
+					<el-option
+						v-for="(item,index) of weekList"
+						:key="index"
+						:label="item.value"
+						:value="item.key"
+						:disabled="item.key < cycle01 && item.key !== 1"
+					>{{item.value}}</el-option>
+				</el-select>
 			</el-radio>
 		</el-form-item>
 
@@ -24,14 +41,18 @@
 			<el-radio v-model='radioValue' :label="4">
 				第
 				<el-input-number v-model='average01' :min="1" :max="4" /> 周的星期
-				<el-input-number v-model='average02' :min="1" :max="7" />
+				<el-select clearable v-model="average02">
+					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
+				</el-select>
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="5">
 				本月最后一个星期
-				<el-input-number v-model='weekday' :min="1" :max="7" />
+				<el-select clearable v-model="weekday">
+					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
+				</el-select>
 			</el-radio>
 		</el-form-item>
 
@@ -39,7 +60,7 @@
 			<el-radio v-model='radioValue' :label="6">
 				指定
 				<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
-					<el-option v-for="(item,index) of weekList" :key="index" :value="index+1">{{item}}</el-option>
+					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
 				</el-select>
 			</el-radio>
 		</el-form-item>
@@ -52,13 +73,42 @@ export default {
 	data() {
 		return {
 			radioValue: 2,
-			weekday: 1,
-			cycle01: 1,
-			cycle02: 2,
+			weekday: 2,
+			cycle01: 2,
+			cycle02: 3,
 			average01: 1,
-			average02: 1,
+			average02: 2,
 			checkboxList: [],
-			weekList: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
+			weekList: [
+				{
+					key: 2,
+					value: '星期一'
+				},
+				{
+					key: 3,
+					value: '星期二'
+				},
+				{
+					key: 4,
+					value: '星期三'
+				},
+				{
+					key: 5,
+					value: '星期四'
+				},
+				{
+					key: 6,
+					value: '星期五'
+				},
+				{
+					key: 7,
+					value: '星期六'
+				},
+				{
+					key: 1,
+					value: '星期日'
+				}
+			],
 			checkNum: this.$options.propsData.check
 		}
 	},
@@ -81,7 +131,7 @@ export default {
 					this.$emit('update', 'week', this.cycle01 + '-' + this.cycle02);
 					break;
 				case 4:
-					this.$emit('update', 'week', this.average01 + '#' + this.average02);
+					this.$emit('update', 'week', this.average02 + '#' + this.average01);
 					break;
 				case 5:
 					this.$emit('update', 'week', this.weekday + 'L');
@@ -135,7 +185,7 @@ export default {
 		averageTotal: function () {
 			this.average01 = this.checkNum(this.average01, 1, 4)
 			this.average02 = this.checkNum(this.average02, 1, 7)
-			return this.average01 + '#' + this.average02;
+			return this.average02 + '#' + this.average01;
 		},
 		// 最近的工作日(格式)
 		weekdayCheck: function () {

From f28a91969acd2c48423acc01973d4cf70e4f8d8c Mon Sep 17 00:00:00 2001
From: fuzui <73400@163.com>
Date: Tue, 30 Nov 2021 02:08:08 +0800
Subject: [PATCH 45/74] =?UTF-8?q?fix:=20crontab=E7=BB=84=E4=BB=B6=E4=B8=AD?=
 =?UTF-8?q?=E8=A7=84=E8=8C=83=E6=95=B0=E6=8D=AE=E8=8C=83=E5=9B=B4=E3=80=81?=
 =?UTF-8?q?=E5=86=97=E4=BD=99=E4=BB=A3=E7=A0=81=E5=8E=BB=E9=99=A4=E4=BB=A5?=
 =?UTF-8?q?=E5=8F=8A=E9=83=A8=E5=88=86=E9=80=9A=E9=85=8D=E7=AC=A6=E8=AF=B4?=
 =?UTF-8?q?=E6=98=8E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/components/Crontab/day.vue    | 47 +++++++++-------------
 ruoyi-ui/src/components/Crontab/hour.vue   | 26 ++++++------
 ruoyi-ui/src/components/Crontab/min.vue    | 26 ++++++------
 ruoyi-ui/src/components/Crontab/month.vue  | 26 ++++++------
 ruoyi-ui/src/components/Crontab/second.vue | 41 ++++++-------------
 ruoyi-ui/src/components/Crontab/week.vue   | 10 ++---
 ruoyi-ui/src/components/Crontab/year.vue   | 28 +++++++------
 7 files changed, 91 insertions(+), 113 deletions(-)

diff --git a/ruoyi-ui/src/components/Crontab/day.vue b/ruoyi-ui/src/components/Crontab/day.vue
index bccd1d7a8..fe3eaf0c4 100644
--- a/ruoyi-ui/src/components/Crontab/day.vue
+++ b/ruoyi-ui/src/components/Crontab/day.vue
@@ -2,7 +2,7 @@
 	<el-form size="small">
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="1">
-				日,允许的通配符[, - * / L M]
+				日,允许的通配符[, - * ? / L W]
 			</el-radio>
 		</el-form-item>
 
@@ -15,23 +15,23 @@
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="3">
 				周期从
-				<el-input-number v-model='cycle01' :min="0" :max="31" /> -
-				<el-input-number v-model='cycle02' :min="0" :max="31" /> 日
+				<el-input-number v-model='cycle01' :min="1" :max="30" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="31" /> 日
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="4">
 				从
-				<el-input-number v-model='average01' :min="0" :max="31" /> 号开始,每
-				<el-input-number v-model='average02' :min="0" :max="31" /> 日执行一次
+				<el-input-number v-model='average01' :min="1" :max="30" /> 号开始,每
+				<el-input-number v-model='average02' :min="1" :max="31 - average01 || 1" /> 日执行一次
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="5">
 				每月
-				<el-input-number v-model='workday' :min="0" :max="31" /> 号最近的那个工作日
+				<el-input-number v-model='workday' :min="1" :max="31" /> 号最近的那个工作日
 			</el-radio>
 		</el-form-item>
 
@@ -84,10 +84,10 @@ export default {
 					this.$emit('update', 'day', '?');
 					break;
 				case 3:
-					this.$emit('update', 'day', this.cycle01 + '-' + this.cycle02);
+					this.$emit('update', 'day', this.cycleTotal);
 					break;
 				case 4:
-					this.$emit('update', 'day', this.average01 + '/' + this.average02);
+					this.$emit('update', 'day', this.averageTotal);
 					break;
 				case 5:
 					this.$emit('update', 'day', this.workday + 'W');
@@ -116,7 +116,7 @@ export default {
 		// 最近工作日值变化时
 		workdayChange() {
 			if (this.radioValue == '5') {
-				this.$emit('update', 'day', this.workday + 'W');
+				this.$emit('update', 'day', this.workdayCheck + 'W');
 			}
 		},
 		// checkbox值变化时
@@ -124,19 +124,10 @@ export default {
 			if (this.radioValue == '7') {
 				this.$emit('update', 'day', this.checkboxString);
 			}
-		},
-		// 父组件传递的week发生变化触发
-		weekChange() {
-			//判断week值与day不能同时为“?”
-			if (this.cron.week == '?' && this.radioValue == '2') {
-				this.radioValue = '1';
-			} else if (this.cron.week !== '?' && this.radioValue != '2') {
-				this.radioValue = '2';
-			}
-		},
+		}
 	},
 	watch: {
-		"radioValue": "radioChange",
+		'radioValue': 'radioChange',
 		'cycleTotal': 'cycleChange',
 		'averageTotal': 'averageChange',
 		'workdayCheck': 'workdayChange',
@@ -145,20 +136,20 @@ export default {
 	computed: {
 		// 计算两个周期值
 		cycleTotal: function () {
-			this.cycle01 = this.checkNum(this.cycle01, 1, 31)
-			this.cycle02 = this.checkNum(this.cycle02, 1, 31)
-			return this.cycle01 + '-' + this.cycle02;
+			const cycle01 = this.checkNum(this.cycle01, 1, 30)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 31, 31)
+			return cycle01 + '-' + cycle02;
 		},
 		// 计算平均用到的值
 		averageTotal: function () {
-			this.average01 = this.checkNum(this.average01, 1, 31)
-			this.average02 = this.checkNum(this.average02, 1, 31)
-			return this.average01 + '/' + this.average02;
+			const average01 = this.checkNum(this.average01, 1, 30)
+			const average02 = this.checkNum(this.average02, 1, 31 - average01 || 0)
+			return average01 + '/' + average02;
 		},
 		// 计算工作日格式
 		workdayCheck: function () {
-			this.workday = this.checkNum(this.workday, 1, 31)
-			return this.workday;
+			const workday = this.checkNum(this.workday, 1, 31)
+			return workday;
 		},
 		// 计算勾选的checkbox值合集
 		checkboxString: function () {
diff --git a/ruoyi-ui/src/components/Crontab/hour.vue b/ruoyi-ui/src/components/Crontab/hour.vue
index 131edc9ce..29b88919f 100644
--- a/ruoyi-ui/src/components/Crontab/hour.vue
+++ b/ruoyi-ui/src/components/Crontab/hour.vue
@@ -9,16 +9,16 @@
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="2">
 				周期从
-				<el-input-number v-model='cycle01' :min="0" :max="60" /> -
-				<el-input-number v-model='cycle02' :min="0" :max="60" /> 小时
+				<el-input-number v-model='cycle01' :min="0" :max="22" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="23" /> 小时
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="3">
 				从
-				<el-input-number v-model='average01' :min="0" :max="60" /> 小时开始,每
-				<el-input-number v-model='average02' :min="0" :max="60" /> 小时执行一次
+				<el-input-number v-model='average01' :min="0" :max="22" /> 小时开始,每
+				<el-input-number v-model='average02' :min="1" :max="23 - average01 || 0" /> 小时执行一次
 			</el-radio>
 		</el-form-item>
 
@@ -56,10 +56,10 @@ export default {
         	this.$emit('update', 'hour', '*')
         	break;
 				case 2:
-					this.$emit('update', 'hour', this.cycle01 + '-' + this.cycle02);
+					this.$emit('update', 'hour', this.cycleTotal);
 					break;
 				case 3:
-					this.$emit('update', 'hour', this.average01 + '/' + this.average02);
+					this.$emit('update', 'hour', this.averageTotal);
 					break;
 				case 4:
 					this.$emit('update', 'hour', this.checkboxString);
@@ -86,7 +86,7 @@ export default {
 		}
 	},
 	watch: {
-		"radioValue": "radioChange",
+		'radioValue': 'radioChange',
 		'cycleTotal': 'cycleChange',
 		'averageTotal': 'averageChange',
 		'checkboxString': 'checkboxChange'
@@ -94,15 +94,15 @@ export default {
 	computed: {
 		// 计算两个周期值
 		cycleTotal: function () {
-			this.cycle01 = this.checkNum(this.cycle01, 0, 23)
-			this.cycle02 = this.checkNum(this.cycle02, 0, 23)
-			return this.cycle01 + '-' + this.cycle02;
+			const cycle01 = this.checkNum(this.cycle01, 0, 22)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 23)
+			return cycle01 + '-' + cycle02;
 		},
 		// 计算平均用到的值
 		averageTotal: function () {
-			this.average01 = this.checkNum(this.average01, 0, 23)
-			this.average02 = this.checkNum(this.average02, 1, 23)
-			return this.average01 + '/' + this.average02;
+			const average01 = this.checkNum(this.average01, 0, 22)
+			const average02 = this.checkNum(this.average02, 1, 23 - average01 || 0)
+			return average01 + '/' + average02;
 		},
 		// 计算勾选的checkbox值合集
 		checkboxString: function () {
diff --git a/ruoyi-ui/src/components/Crontab/min.vue b/ruoyi-ui/src/components/Crontab/min.vue
index 79e435b0c..0a106ce01 100644
--- a/ruoyi-ui/src/components/Crontab/min.vue
+++ b/ruoyi-ui/src/components/Crontab/min.vue
@@ -9,16 +9,16 @@
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="2">
 				周期从
-				<el-input-number v-model='cycle01' :min="0" :max="60" /> -
-				<el-input-number v-model='cycle02' :min="0" :max="60" /> 分钟
+				<el-input-number v-model='cycle01' :min="0" :max="58" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> 分钟
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="3">
 				从
-				<el-input-number v-model='average01' :min="0" :max="60" /> 分钟开始,每
-				<el-input-number v-model='average02' :min="0" :max="60" /> 分钟执行一次
+				<el-input-number v-model='average01' :min="0" :max="58" /> 分钟开始,每
+				<el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> 分钟执行一次
 			</el-radio>
 		</el-form-item>
 
@@ -57,10 +57,10 @@ export default {
 					this.$emit('update', 'min', '*', 'min');
 					break;
 				case 2:
-					this.$emit('update', 'min', this.cycle01 + '-' + this.cycle02, 'min');
+					this.$emit('update', 'min', this.cycleTotal, 'min');
 					break;
 				case 3:
-					this.$emit('update', 'min', this.average01 + '/' + this.average02, 'min');
+					this.$emit('update', 'min', this.averageTotal, 'min');
 					break;
 				case 4:
 					this.$emit('update', 'min', this.checkboxString, 'min');
@@ -88,7 +88,7 @@ export default {
 
 	},
 	watch: {
-		"radioValue": "radioChange",
+		'radioValue': 'radioChange',
 		'cycleTotal': 'cycleChange',
 		'averageTotal': 'averageChange',
 		'checkboxString': 'checkboxChange',
@@ -96,15 +96,15 @@ export default {
 	computed: {
 		// 计算两个周期值
 		cycleTotal: function () {
-			this.cycle01 = this.checkNum(this.cycle01, 0, 59)
-			this.cycle02 = this.checkNum(this.cycle02, 0, 59)
-			return this.cycle01 + '-' + this.cycle02;
+			const cycle01 = this.checkNum(this.cycle01, 0, 58)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
+			return cycle01 + '-' + cycle02;
 		},
 		// 计算平均用到的值
 		averageTotal: function () {
-			this.average01 = this.checkNum(this.average01, 0, 59)
-			this.average02 = this.checkNum(this.average02, 1, 59)
-			return this.average01 + '/' + this.average02;
+			const average01 = this.checkNum(this.average01, 0, 58)
+			const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
+			return average01 + '/' + average02;
 		},
 		// 计算勾选的checkbox值合集
 		checkboxString: function () {
diff --git a/ruoyi-ui/src/components/Crontab/month.vue b/ruoyi-ui/src/components/Crontab/month.vue
index a7e52e1f8..fd0ac384f 100644
--- a/ruoyi-ui/src/components/Crontab/month.vue
+++ b/ruoyi-ui/src/components/Crontab/month.vue
@@ -9,16 +9,16 @@
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="2">
 				周期从
-				<el-input-number v-model='cycle01' :min="1" :max="12" /> -
-				<el-input-number v-model='cycle02' :min="1" :max="12" /> 月
+				<el-input-number v-model='cycle01' :min="1" :max="11" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="12" /> 月
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="3">
 				从
-				<el-input-number v-model='average01' :min="1" :max="12" /> 月开始,每
-				<el-input-number v-model='average02' :min="1" :max="12" /> 月月执行一次
+				<el-input-number v-model='average01' :min="1" :max="11" /> 月开始,每
+				<el-input-number v-model='average02' :min="1" :max="12 - average01 || 0" /> 月月执行一次
 			</el-radio>
 		</el-form-item>
 
@@ -56,10 +56,10 @@ export default {
 					this.$emit('update', 'month', '*');
 					break;
 				case 2:
-					this.$emit('update', 'month', this.cycle01 + '-' + this.cycle02);
+					this.$emit('update', 'month', this.cycleTotal);
 					break;
 				case 3:
-					this.$emit('update', 'month', this.average01 + '/' + this.average02);
+					this.$emit('update', 'month', this.averageTotal);
 					break;
 				case 4:
 					this.$emit('update', 'month', this.checkboxString);
@@ -86,7 +86,7 @@ export default {
 		}
 	},
 	watch: {
-		"radioValue": "radioChange",
+		'radioValue': 'radioChange',
 		'cycleTotal': 'cycleChange',
 		'averageTotal': 'averageChange',
 		'checkboxString': 'checkboxChange'
@@ -94,15 +94,15 @@ export default {
 	computed: {
 		// 计算两个周期值
 		cycleTotal: function () {
-			this.cycle01 = this.checkNum(this.cycle01, 1, 12)
-			this.cycle02 = this.checkNum(this.cycle02, 1, 12)
-			return this.cycle01 + '-' + this.cycle02;
+			const cycle01 = this.checkNum(this.cycle01, 1, 11)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12)
+			return cycle01 + '-' + cycle02;
 		},
 		// 计算平均用到的值
 		averageTotal: function () {
-			this.average01 = this.checkNum(this.average01, 1, 12)
-			this.average02 = this.checkNum(this.average02, 1, 12)
-			return this.average01 + '/' + this.average02;
+			const average01 = this.checkNum(this.average01, 1, 11)
+			const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0)
+			return average01 + '/' + average02;
 		},
 		// 计算勾选的checkbox值合集
 		checkboxString: function () {
diff --git a/ruoyi-ui/src/components/Crontab/second.vue b/ruoyi-ui/src/components/Crontab/second.vue
index 40815fb09..e7b776171 100644
--- a/ruoyi-ui/src/components/Crontab/second.vue
+++ b/ruoyi-ui/src/components/Crontab/second.vue
@@ -9,16 +9,16 @@
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="2">
 				周期从
-				<el-input-number v-model='cycle01' :min="0" :max="60" /> -
-				<el-input-number v-model='cycle02' :min="0" :max="60" /> 秒
+				<el-input-number v-model='cycle01' :min="0" :max="58" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> 秒
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="3">
 				从
-				<el-input-number v-model='average01' :min="0" :max="60" /> 秒开始,每
-				<el-input-number v-model='average02' :min="0" :max="60" /> 秒执行一次
+				<el-input-number v-model='average01' :min="0" :max="58" /> 秒开始,每
+				<el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> 秒执行一次
 			</el-radio>
 		</el-form-item>
 
@@ -56,10 +56,10 @@ export default {
 					this.$emit('update', 'second', '*', 'second');
 					break;
 				case 2:
-					this.$emit('update', 'second', this.cycle01 + '-' + this.cycle02);
+					this.$emit('update', 'second', this.cycleTotal);
 					break;
 				case 3:
-					this.$emit('update', 'second', this.average01 + '/' + this.average02);
+					this.$emit('update', 'second', this.averageTotal);
 					break;
 				case 4:
 					this.$emit('update', 'second', this.checkboxString);
@@ -83,25 +83,10 @@ export default {
 			if (this.radioValue == '4') {
 				this.$emit('update', 'second', this.checkboxString);
 			}
-		},
-		othChange() {
-			// 反解析
-			let ins = this.cron.second
-			('反解析 second', ins);
-			if (ins === '*') {
-				this.radioValue = 1;
-			} else if (ins.indexOf('-') > -1) {
-				this.radioValue = 2
-			} else if (ins.indexOf('/') > -1) {
-				this.radioValue = 3
-			} else {
-				this.radioValue = 4
-				this.checkboxList = ins.split(',')
-			}
 		}
 	},
 	watch: {
-		"radioValue": "radioChange",
+		'radioValue': 'radioChange',
 		'cycleTotal': 'cycleChange',
 		'averageTotal': 'averageChange',
 		'checkboxString': 'checkboxChange',
@@ -112,15 +97,15 @@ export default {
 	computed: {
 		// 计算两个周期值
 		cycleTotal: function () {
-			this.cycle01 = this.checkNum(this.cycle01, 0, 59)
-			this.cycle02 = this.checkNum(this.cycle02, 0, 59)
-			return this.cycle01 + '-' + this.cycle02;
+			const cycle01 = this.checkNum(this.cycle01, 0, 58)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
+			return cycle01 + '-' + cycle02;
 		},
 		// 计算平均用到的值
 		averageTotal: function () {
-			this.average01 = this.checkNum(this.average01, 0, 59)
-			this.average02 = this.checkNum(this.average02, 1, 59)
-			return this.average01 + '/' + this.average02;
+			const average01 = this.checkNum(this.average01, 0, 58)
+			const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
+			return average01 + '/' + average02;
 		},
 		// 计算勾选的checkbox值合集
 		checkboxString: function () {
diff --git a/ruoyi-ui/src/components/Crontab/week.vue b/ruoyi-ui/src/components/Crontab/week.vue
index 4485bc4f6..ae389a7a5 100644
--- a/ruoyi-ui/src/components/Crontab/week.vue
+++ b/ruoyi-ui/src/components/Crontab/week.vue
@@ -2,7 +2,7 @@
 	<el-form size='small'>
 		<el-form-item>
 			<el-radio v-model='radioValue' :label="1">
-				周,允许的通配符[, - * / L #]
+				周,允许的通配符[, - * ? / L #]
 			</el-radio>
 		</el-form-item>
 
@@ -128,13 +128,13 @@ export default {
 					this.$emit('update', 'week', '?');
 					break;
 				case 3:
-					this.$emit('update', 'week', this.cycle01 + '-' + this.cycle02);
+					this.$emit('update', 'week', this.cycleTotal);
 					break;
 				case 4:
-					this.$emit('update', 'week', this.average02 + '#' + this.average01);
+					this.$emit('update', 'week', this.averageTotal);
 					break;
 				case 5:
-					this.$emit('update', 'week', this.weekday + 'L');
+					this.$emit('update', 'week', this.weekdayCheck + 'L');
 					break;
 				case 6:
 					this.$emit('update', 'week', this.checkboxString);
@@ -168,7 +168,7 @@ export default {
 		},
 	},
 	watch: {
-		"radioValue": "radioChange",
+		'radioValue': 'radioChange',
 		'cycleTotal': 'cycleChange',
 		'averageTotal': 'averageChange',
 		'weekdayCheck': 'weekdayChange',
diff --git a/ruoyi-ui/src/components/Crontab/year.vue b/ruoyi-ui/src/components/Crontab/year.vue
index 16a2b04f3..5487a6c7f 100644
--- a/ruoyi-ui/src/components/Crontab/year.vue
+++ b/ruoyi-ui/src/components/Crontab/year.vue
@@ -15,16 +15,16 @@
 		<el-form-item>
 			<el-radio :label="3" v-model='radioValue'>
 				周期从
-				<el-input-number v-model='cycle01' :min='fullYear' /> -
-				<el-input-number v-model='cycle02' :min='fullYear' />
+				<el-input-number v-model='cycle01' :min='fullYear' :max="2098" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : fullYear + 1" :max="2099" />
 			</el-radio>
 		</el-form-item>
 
 		<el-form-item>
 			<el-radio :label="4" v-model='radioValue'>
 				从
-				<el-input-number v-model='average01' :min='fullYear' /> 年开始,每
-				<el-input-number v-model='average02' :min='fullYear' /> 年执行一次
+				<el-input-number v-model='average01' :min='fullYear' :max="2098"/> 年开始,每
+				<el-input-number v-model='average02' :min="1" :max="2099 - average01 || fullYear" /> 年执行一次
 			</el-radio>
 
 		</el-form-item>
@@ -67,10 +67,10 @@ export default {
 					this.$emit('update', 'year', '*');
 					break;
 				case 3:
-					this.$emit('update', 'year', this.cycle01 + '-' + this.cycle02);
+					this.$emit('update', 'year', this.cycleTotal);
 					break;
 				case 4:
-					this.$emit('update', 'year', this.average01 + '/' + this.average02);
+					this.$emit('update', 'year', this.averageTotal);
 					break;
 				case 5:
 					this.$emit('update', 'year', this.checkboxString);
@@ -97,7 +97,7 @@ export default {
 		}
 	},
 	watch: {
-		"radioValue": "radioChange",
+		'radioValue': 'radioChange',
 		'cycleTotal': 'cycleChange',
 		'averageTotal': 'averageChange',
 		'checkboxString': 'checkboxChange'
@@ -105,15 +105,15 @@ export default {
 	computed: {
 		// 计算两个周期值
 		cycleTotal: function () {
-			this.cycle01 = this.checkNum(this.cycle01, this.fullYear, this.fullYear + 100)
-			this.cycle02 = this.checkNum(this.cycle02, this.fullYear + 1, this.fullYear + 101)
-			return this.cycle01 + '-' + this.cycle02;
+			const cycle01 = this.checkNum(this.cycle01, this.fullYear, 2098)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : this.fullYear + 1, 2099)
+			return cycle01 + '-' + cycle02;
 		},
 		// 计算平均用到的值
 		averageTotal: function () {
-			this.average01 = this.checkNum(this.average01, this.fullYear, this.fullYear + 100)
-			this.average02 = this.checkNum(this.average02, 1, 10)
-			return this.average01 + '/' + this.average02;
+			const average01 = this.checkNum(this.average01, this.fullYear, 2098)
+			const average02 = this.checkNum(this.average02, 1, 2099 - average01 || this.fullYear)
+			return average01 + '/' + average02;
 		},
 		// 计算勾选的checkbox值合集
 		checkboxString: function () {
@@ -124,6 +124,8 @@ export default {
 	mounted: function () {
 		// 仅获取当前年份
 		this.fullYear = Number(new Date().getFullYear());
+		this.cycle01 = this.fullYear
+		this.average01 = this.fullYear
 	}
 }
 </script>

From a2d3f987c04a2e5176a8686f1032f7f5bfee4af2 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 30 Nov 2021 11:15:17 +0800
Subject: [PATCH 46/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../controller/system/SysProfileController.java   |  2 +-
 .../system/service/impl/SysMenuServiceImpl.java   | 15 +++++++++++++--
 ruoyi-ui/src/plugins/modal.js                     |  8 ++++++++
 ruoyi-ui/src/views/monitor/online/index.vue       |  2 +-
 ruoyi-ui/src/views/system/user/index.vue          |  2 +-
 ruoyi-ui/src/views/tool/gen/basicInfoForm.vue     |  3 +--
 ruoyi-ui/src/views/tool/gen/editTable.vue         |  1 +
 ruoyi-ui/src/views/tool/gen/genInfoForm.vue       |  3 +--
 8 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
index d764651c8..be515fd61 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -72,7 +72,7 @@ public class SysProfileController extends BaseController
                 && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
         {
             return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
-        }       
+        }
         user.setUserId(sysUser.getUserId());
         user.setPassword(null);
         if (userService.updateUserProfile(user) > 0)
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
index af97f1492..d509da2b6 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -179,7 +179,7 @@ public class SysMenuServiceImpl implements ISysMenuService
                 router.setPath("/inner");
                 List<RouterVo> childrenList = new ArrayList<RouterVo>();
                 RouterVo children = new RouterVo();
-                String routerPath = StringUtils.replaceEach(menu.getPath(), new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" });
+                String routerPath = innerLinkReplaceEach(menu.getPath());
                 children.setPath(routerPath);
                 children.setComponent(UserConstants.INNER_LINK);
                 children.setName(StringUtils.capitalize(routerPath));
@@ -358,7 +358,7 @@ public class SysMenuServiceImpl implements ISysMenuService
         // 内链打开外网方式
         if (menu.getParentId().intValue() != 0 && isInnerLink(menu))
         {
-            routerPath = StringUtils.replaceEach(routerPath, new String[] { Constants.HTTP, Constants.HTTPS }, new String[] { "", "" });
+            routerPath = innerLinkReplaceEach(routerPath);
         }
         // 非外链并且是一级目录(类型为目录)
         if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
@@ -500,4 +500,15 @@ public class SysMenuServiceImpl implements ISysMenuService
     {
         return getChildList(list, t).size() > 0 ? true : false;
     }
+
+    /**
+     * 内链域名特殊字符替换
+     * 
+     * @return
+     */
+    public String innerLinkReplaceEach(String path)
+    {
+        return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS },
+                new String[] { "", "" });
+    }
 }
diff --git a/ruoyi-ui/src/plugins/modal.js b/ruoyi-ui/src/plugins/modal.js
index 7df61a890..503a16f46 100644
--- a/ruoyi-ui/src/plugins/modal.js
+++ b/ruoyi-ui/src/plugins/modal.js
@@ -59,6 +59,14 @@ export default {
       type: "warning",
     })
   },
+  // 提交内容
+  prompt(content) {
+    return MessageBox.prompt(content, "系统提示", {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: "warning",
+    })
+  },
   // 打开遮罩层
   loading(content) {
     loadingInstance = Loading.service({
diff --git a/ruoyi-ui/src/views/monitor/online/index.vue b/ruoyi-ui/src/views/monitor/online/index.vue
index ab66827b8..fedf08038 100644
--- a/ruoyi-ui/src/views/monitor/online/index.vue
+++ b/ruoyi-ui/src/views/monitor/online/index.vue
@@ -111,7 +111,7 @@ export default {
     },
     /** 强退按钮操作 */
     handleForceLogout(row) {
-      this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的数据项?').then(function() {
+      this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function() {
         return forceLogout(row.tokenId);
       }).then(() => {
         this.getList();
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
index 3525c9b3f..c538a6984 100644
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -596,7 +596,7 @@ export default {
         cancelButtonText: "取消",
         closeOnClickModal: false,
         inputPattern: /^.{5,20}$/,
-        inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
+        inputErrorMessage: "用户密码长度必须介于 5 和 20 之间"
       }).then(({ value }) => {
           resetUserPwd(row.userId, value).then(response => {
             this.$modal.msgSuccess("修改成功,新密码是:" + value);
diff --git a/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue b/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
index f3e87172b..75dc3bf3b 100644
--- a/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
+++ b/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
@@ -11,7 +11,6 @@
           <el-input placeholder="请输入" v-model="info.tableComment" />
         </el-form-item>
       </el-col>
-
       <el-col :span="12">
         <el-form-item label="实体类名称" prop="className">
           <el-input placeholder="请输入" v-model="info.className" />
@@ -30,9 +29,9 @@
     </el-row>
   </el-form>
 </template>
+
 <script>
 export default {
-  name: "BasicInfoForm",
   props: {
     info: {
       type: Object,
diff --git a/ruoyi-ui/src/views/tool/gen/editTable.vue b/ruoyi-ui/src/views/tool/gen/editTable.vue
index b8f386e75..5be5c5054 100644
--- a/ruoyi-ui/src/views/tool/gen/editTable.vue
+++ b/ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -124,6 +124,7 @@
     </el-form>
   </el-card>
 </template>
+
 <script>
 import { getGenTable, updateGenTable } from "@/api/tool/gen";
 import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
index 926376c96..bf6382d39 100644
--- a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
+++ b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
@@ -11,7 +11,6 @@
           </el-select>
         </el-form-item>
       </el-col>
-
       <el-col :span="12">
         <el-form-item prop="packageName">
           <span slot="label">
@@ -213,12 +212,12 @@
     </el-row>
   </el-form>
 </template>
+
 <script>
 import Treeselect from "@riophae/vue-treeselect";
 import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
 export default {
-  name: "BasicInfoForm",
   components: { Treeselect },
   props: {
     info: {

From 9bc730866f583847c33a944aa20d7ea5e3c0c7ac Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 30 Nov 2021 11:15:33 +0800
Subject: [PATCH 47/74] =?UTF-8?q?=F0=9F=8E=89=20RuoYi-Vue3=EF=BC=88Vue3=20?=
 =?UTF-8?q?Element=20Plus=20Vite=EF=BC=89=E7=89=88=E6=9C=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 0c10287a4..61938265c 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@
 * 权限认证使用Jwt,支持多终端认证系统。
 * 支持加载动态权限菜单,多方式轻松权限控制。
 * 高效率开发,使用代码生成器可以一键生成前后端代码。
+* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
 * 提供了单应用版本[RuoYi-Vue-fast](https://github.com/yangzongzhuan/RuoYi-Vue-fast),Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
 * 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
 * 特别鸣谢:[element](https://github.com/ElemeFE/element),[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin),[eladmin-web](https://github.com/elunez/eladmin-web)。

From 6bfae2652f63d1929cd0987655752214b84d2ec2 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 1 Dec 2021 08:53:11 +0800
Subject: [PATCH 48/74] =?UTF-8?q?=E8=8B=A5=E4=BE=9D=203.8.0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml                                       |  4 +-
 ruoyi-admin/pom.xml                           |  2 +-
 .../src/main/resources/application.yml        |  2 +-
 ruoyi-common/pom.xml                          |  2 +-
 ruoyi-framework/pom.xml                       |  2 +-
 ruoyi-generator/pom.xml                       |  2 +-
 ruoyi-quartz/pom.xml                          |  2 +-
 ruoyi-system/pom.xml                          |  2 +-
 ruoyi-ui/package.json                         |  2 +-
 ruoyi-ui/src/views/index.vue                  | 55 ++++++++++++++++++-
 10 files changed, 64 insertions(+), 11 deletions(-)

diff --git a/pom.xml b/pom.xml
index 7c0f8631c..b24166e70 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,14 +6,14 @@
 	
     <groupId>com.ruoyi</groupId>
     <artifactId>ruoyi</artifactId>
-    <version>3.7.0</version>
+    <version>3.8.0</version>
 
     <name>ruoyi</name>
     <url>http://www.ruoyi.vip</url>
     <description>若依管理系统</description>
     
     <properties>
-        <ruoyi.version>3.7.0</ruoyi.version>
+        <ruoyi.version>3.8.0</ruoyi.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 1d1d687b4..ca0631980 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>3.7.0</version>
+        <version>3.8.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index ae0ffbc9e..397548aa3 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -3,7 +3,7 @@ ruoyi:
   # 名称
   name: RuoYi
   # 版本
-  version: 3.7.0
+  version: 3.8.0
   # 版权年份
   copyrightYear: 2021
   # 实例演示开关
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 278434bbe..cbf4893a5 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>3.7.0</version>
+        <version>3.8.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml
index 0eea3ce11..2e8817bfa 100644
--- a/ruoyi-framework/pom.xml
+++ b/ruoyi-framework/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>3.7.0</version>
+        <version>3.8.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml
index 89d921fb3..8ec90ea0d 100644
--- a/ruoyi-generator/pom.xml
+++ b/ruoyi-generator/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>3.7.0</version>
+        <version>3.8.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-quartz/pom.xml b/ruoyi-quartz/pom.xml
index b1c1485f6..7d7a72631 100644
--- a/ruoyi-quartz/pom.xml
+++ b/ruoyi-quartz/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>3.7.0</version>
+        <version>3.8.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml
index 9d90f9976..a62fb550d 100644
--- a/ruoyi-system/pom.xml
+++ b/ruoyi-system/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>ruoyi</artifactId>
         <groupId>com.ruoyi</groupId>
-        <version>3.7.0</version>
+        <version>3.8.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 5b3760977..7576747b5 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -1,6 +1,6 @@
 {
   "name": "ruoyi",
-  "version": "3.7.0",
+  "version": "3.8.0",
   "description": "若依管理系统",
   "author": "若依",
   "license": "MIT",
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index 4609c136e..75761cb75 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -147,6 +147,59 @@
             <span>更新日志</span>
           </div>
           <el-collapse accordion>
+            <el-collapse-item title="v3.8.0 - 2021-12-01">
+              <ol>
+                <li>新增配套并同步的Vue3前端版本</li>
+                <li>新增通用方法简化模态/缓存/下载/权限/页签使用</li>
+                <li>优化导出数据/使用通用下载方法</li>
+                <li>Excel注解支持自定义数据处理器</li>
+                <li>Excel注解支持导入导出标题信息</li>
+                <li>Excel导入支持@Excels注解</li>
+                <li>新增组件data-dict,简化数据字典使用</li>
+                <li>新增Jaxb依赖,防止jdk8以上出现的兼容错误</li>
+                <li>生产环境使用路由懒加载提升页面响应速度</li>
+                <li>修复五级以上菜单出现的404问题</li>
+                <li>防重提交注解支持配置间隔时间/提示消息</li>
+                <li>日志注解新增是否保存响应参数</li>
+                <li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
+                <li>升级SpringBoot到最新版本2.5.6</li>
+                <li>升级pagehelper到最新版1.4.0</li>
+                <li>升级spring-boot-mybatis到最新版2.2.0</li>
+                <li>升级oshi到最新版本v5.8.2</li>
+                <li>升级druid到最新版1.2.8</li>
+                <li>升级velocity到最新版本2.3</li>
+                <li>升级fastjson到最新版1.2.78</li>
+                <li>升级axios到最新版本0.24.0</li>
+                <li>升级dart-sass到版本1.32.13</li>
+                <li>升级core-js到最新版本3.19.1</li>
+                <li>升级jsencrypt到最新版本3.2.1</li>
+                <li>升级js-cookie到最新版本3.0.1</li>
+                <li>升级file-saver到最新版本2.0.5</li>
+                <li>升级sass-loader到最新版本10.1.1</li>
+                <li>升级element-ui到最新版本2.15.6</li>
+                <li>新增sendGet无参请求方法</li>
+                <li>禁用el-tag组件的渐变动画</li>
+                <li>代码生成点击预览重置激活tab</li>
+                <li>AjaxResult重写put方法,以方便链式调用</li>
+                <li>优化登录/验证码请求headers不设置token</li>
+                <li>优化用户个人信息接口防止修改用户名</li>
+                <li>优化Cron表达式生成器关闭时销毁避免缓存</li>
+                <li>优化注册成功提示消息类型success</li>
+                <li>优化aop语法,使用spring自动注入注解</li>
+                <li>优化记录登录信息,移除不必要的修改</li>
+                <li>优化mybatis全局默认的执行器</li>
+                <li>优化Excel导入图片可能出现的异常</li>
+                <li>修复代码生成模板主子表删除缺少事务</li>
+                <li>修复日志记录可能出现的转换异常</li>
+                <li>修复代码生成复选框字典遗漏问题</li>
+                <li>修复关闭xss功能导致可重复读RepeatableFilter失效</li>
+                <li>修复字符串无法被反转义问题</li>
+                <li>修复后端主子表代码模板方法名生成错误问题</li>
+                <li>修复xss过滤后格式出现的异常</li>
+                <li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
             <el-collapse-item title="v3.7.0 - 2021-09-13">
               <ol>
                 <li>参数管理支持配置验证码开关</li>
@@ -664,7 +717,7 @@ export default {
   data() {
     return {
       // 版本号
-      version: "3.7.0",
+      version: "3.8.0",
     };
   },
   methods: {

From 2c3f1c28e520228c93fe360e0d848188976dd804 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 2 Dec 2021 16:31:51 +0800
Subject: [PATCH 49/74] tomcat update

---
 ruoyi-admin/src/main/resources/application.yml | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 397548aa3..557179b40 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -25,10 +25,13 @@ server:
   tomcat:
     # tomcat的URI编码
     uri-encoding: UTF-8
-    # tomcat最大线程数,默认为200
-    max-threads: 800
-    # Tomcat启动初始化的线程数,默认值25
-    min-spare-threads: 30
+    # 连接数满后的排队数,默认为100
+    accept-count: 1000
+    threads:
+      # tomcat最大线程数,默认为200
+      max: 800
+      # Tomcat启动初始化的线程数,默认值10
+      min-spare: 100
 
 # 日志配置
 logging:

From 965ebd0f0349196ede552c2a24a3e1aae36ce3f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?=
 <15040126243@163.com>
Date: Fri, 3 Dec 2021 11:11:43 +0800
Subject: [PATCH 50/74] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=E4=B8=BB?=
 =?UTF-8?q?=E9=94=AE=E6=BA=A2=E5=87=BA=E9=97=AE=E9=A2=98=20=E5=B0=86?=
 =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E8=BF=94=E5=9B=9E=E7=B1=BB=E5=9E=8B=E6=94=B9?=
 =?UTF-8?q?=E4=B8=BA=20Long?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java    | 2 +-
 .../src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java    | 2 +-
 .../src/main/java/com/ruoyi/system/mapper/SysPostMapper.java    | 2 +-
 .../src/main/java/com/ruoyi/system/service/ISysDeptService.java | 2 +-
 .../src/main/java/com/ruoyi/system/service/ISysMenuService.java | 2 +-
 .../src/main/java/com/ruoyi/system/service/ISysPostService.java | 2 +-
 .../java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java  | 2 +-
 .../java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java  | 2 +-
 .../java/com/ruoyi/system/service/impl/SysPostServiceImpl.java  | 2 +-
 ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml | 2 +-
 ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml | 2 +-
 ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml | 2 +-
 12 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
index a7088ca15..f3b58474e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
@@ -26,7 +26,7 @@ public interface SysDeptMapper
      * @param deptCheckStrictly 部门树选择项是否关联显示
      * @return 选中部门列表
      */
-    public List<Integer> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
+    public List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
 
     /**
      * 根据部门ID查询信息
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
index 773e6e8a6..f19d476da 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
@@ -64,7 +64,7 @@ public interface SysMenuMapper
      * @param menuCheckStrictly 菜单树选择项是否关联显示
      * @return 选中菜单列表
      */
-    public List<Integer> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
+    public List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
 
     /**
      * 根据菜单ID查询信息
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
index a98326f8b..8603d9aea 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
@@ -39,7 +39,7 @@ public interface SysPostMapper
      * @param userId 用户ID
      * @return 选中岗位ID列表
      */
-    public List<Integer> selectPostListByUserId(Long userId);
+    public List<Long> selectPostListByUserId(Long userId);
 
     /**
      * 查询用户所属岗位组
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
index fe5dd39d6..1ac8ccb27 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
@@ -41,7 +41,7 @@ public interface ISysDeptService
      * @param roleId 角色ID
      * @return 选中部门列表
      */
-    public List<Integer> selectDeptListByRoleId(Long roleId);
+    public List<Long> selectDeptListByRoleId(Long roleId);
 
     /**
      * 根据部门ID查询信息
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
index 78553d59d..59009be01 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
@@ -52,7 +52,7 @@ public interface ISysMenuService
      * @param roleId 角色ID
      * @return 选中菜单列表
      */
-    public List<Integer> selectMenuListByRoleId(Long roleId);
+    public List<Long> selectMenuListByRoleId(Long roleId);
 
     /**
      * 构建前端路由所需要的菜单
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
index 2fb9a540d..c7c3fc3f3 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
@@ -39,7 +39,7 @@ public interface ISysPostService
      * @param userId 用户ID
      * @return 选中岗位ID列表
      */
-    public List<Integer> selectPostListByUserId(Long userId);
+    public List<Long> selectPostListByUserId(Long userId);
 
     /**
      * 校验岗位名称
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
index 9bf8fe0e1..02288c56f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -100,7 +100,7 @@ public class SysDeptServiceImpl implements ISysDeptService
      * @return 选中部门列表
      */
     @Override
-    public List<Integer> selectDeptListByRoleId(Long roleId)
+    public List<Long> selectDeptListByRoleId(Long roleId)
     {
         SysRole role = roleMapper.selectRoleById(roleId);
         return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
index d509da2b6..d113cfe0e 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -128,7 +128,7 @@ public class SysMenuServiceImpl implements ISysMenuService
      * @return 选中菜单列表
      */
     @Override
-    public List<Integer> selectMenuListByRoleId(Long roleId)
+    public List<Long> selectMenuListByRoleId(Long roleId)
     {
         SysRole role = roleMapper.selectRoleById(roleId);
         return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
index a1b3d21ef..ec9d80ee6 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
@@ -67,7 +67,7 @@ public class SysPostServiceImpl implements ISysPostService
      * @return 选中岗位ID列表
      */
     @Override
-    public List<Integer> selectPostListByUserId(Long userId)
+    public List<Long> selectPostListByUserId(Long userId)
     {
         return postMapper.selectPostListByUserId(userId);
     }
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
index 3f40fb1b5..44bd8689a 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -47,7 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		order by d.parent_id, d.order_num
     </select>
     
-    <select id="selectDeptListByRoleId" resultType="Integer">
+    <select id="selectDeptListByRoleId" resultType="Long">
 		select d.dept_id
 		from sys_dept d
             left join sys_role_dept rd on d.dept_id = rd.dept_id
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
index 9f9fcb66a..144adb1b9 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -84,7 +84,7 @@
 		order by m.parent_id, m.order_num
 	</select>
 	
-	<select id="selectMenuListByRoleId" resultType="Integer">
+	<select id="selectMenuListByRoleId" resultType="Long">
 		select m.menu_id
 		from sys_menu m
             left join sys_role_menu rm on m.menu_id = rm.menu_id
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
index 6ac8e7c36..2425ae058 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
+++ b/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
@@ -46,7 +46,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		where post_id = #{postId}
 	</select>
 	
-	<select id="selectPostListByUserId" parameterType="Long" resultType="Integer">
+	<select id="selectPostListByUserId" parameterType="Long" resultType="Long">
 		select p.post_id
         from sys_post p
 	        left join sys_user_post up on up.post_id = p.post_id

From 4de4763bafb6fad4f3e219c9b4bcb0e8ac9d1c40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?=
 <15040126243@163.com>
Date: Mon, 6 Dec 2021 18:32:51 +0800
Subject: [PATCH 51/74] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=E6=9F=A5?=
 =?UTF-8?q?=E8=AF=A2=E7=94=A8=E6=88=B7=E7=9A=84=E8=A7=92=E8=89=B2=E7=BB=84?=
 =?UTF-8?q?=E3=80=81=E5=B2=97=E4=BD=8D=E7=BB=84=E4=BB=A3=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../service/impl/SysUserServiceImpl.java      | 25 +++++++------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
index 7e8443c0f..e80e7ae51 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -2,6 +2,8 @@ package com.ruoyi.system.service.impl;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -25,6 +27,7 @@ import com.ruoyi.system.mapper.SysUserPostMapper;
 import com.ruoyi.system.mapper.SysUserRoleMapper;
 import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysUserService;
+import org.springframework.util.CollectionUtils;
 
 /**
  * 用户 业务层处理
@@ -127,16 +130,11 @@ public class SysUserServiceImpl implements ISysUserService
     public String selectUserRoleGroup(String userName)
     {
         List<SysRole> list = roleMapper.selectRolesByUserName(userName);
-        StringBuffer idsStr = new StringBuffer();
-        for (SysRole role : list)
+        if (CollectionUtils.isEmpty(list))
         {
-            idsStr.append(role.getRoleName()).append(",");
+            return StringUtils.EMPTY;
         }
-        if (StringUtils.isNotEmpty(idsStr.toString()))
-        {
-            return idsStr.substring(0, idsStr.length() - 1);
-        }
-        return idsStr.toString();
+        return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(","));
     }
 
     /**
@@ -149,16 +147,11 @@ public class SysUserServiceImpl implements ISysUserService
     public String selectUserPostGroup(String userName)
     {
         List<SysPost> list = postMapper.selectPostsByUserName(userName);
-        StringBuffer idsStr = new StringBuffer();
-        for (SysPost post : list)
+        if (CollectionUtils.isEmpty(list))
         {
-            idsStr.append(post.getPostName()).append(",");
+            return StringUtils.EMPTY;
         }
-        if (StringUtils.isNotEmpty(idsStr.toString()))
-        {
-            return idsStr.substring(0, idsStr.length() - 1);
-        }
-        return idsStr.toString();
+        return list.stream().map(SysPost::getPostName).collect(Collectors.joining(","));
     }
 
     /**

From 850b98337b615d12a5dac0943a6737649bab6b17 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 6 Dec 2021 20:58:10 +0800
Subject: [PATCH 52/74] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E7=94=A8=E6=88=B7?=
 =?UTF-8?q?=E5=88=86=E9=85=8D=E8=A7=92=E8=89=B2=E5=B1=9E=E6=80=A7=E9=94=99?=
 =?UTF-8?q?=E8=AF=AF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../java/com/ruoyi/system/service/impl/SysUserServiceImpl.java | 3 +--
 ruoyi-ui/src/views/system/user/authRole.vue                    | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
index e80e7ae51..e40c8c85d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -3,12 +3,12 @@ package com.ruoyi.system.service.impl;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import com.ruoyi.common.annotation.DataScope;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.entity.SysRole;
@@ -27,7 +27,6 @@ import com.ruoyi.system.mapper.SysUserPostMapper;
 import com.ruoyi.system.mapper.SysUserRoleMapper;
 import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysUserService;
-import org.springframework.util.CollectionUtils;
 
 /**
  * 用户 业务层处理
diff --git a/ruoyi-ui/src/views/system/user/authRole.vue b/ruoyi-ui/src/views/system/user/authRole.vue
index b184de252..7655bdf62 100644
--- a/ruoyi-ui/src/views/system/user/authRole.vue
+++ b/ruoyi-ui/src/views/system/user/authRole.vue
@@ -9,7 +9,7 @@
           </el-form-item>
         </el-col>
         <el-col :span="8" :offset="2">
-          <el-form-item label="登录账号" prop="phonenumber">
+          <el-form-item label="登录账号" prop="userName">
             <el-input  v-model="form.userName" disabled />
           </el-form-item>
         </el-col>

From 4644176e26eca6c3ad6109e5adfdb60cab455246 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 9 Dec 2021 09:52:44 +0800
Subject: [PATCH 53/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7clipboard=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC2.0.8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 7576747b5..600e9ad12 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -38,7 +38,7 @@
   "dependencies": {
     "@riophae/vue-treeselect": "0.4.0",
     "axios": "0.24.0",
-    "clipboard": "2.0.6",
+    "clipboard": "2.0.8",
     "core-js": "3.19.1",
     "echarts": "4.9.0",
     "element-ui": "2.15.6",

From b911d7f78f7243ce5363511225441d6bd46f78fa Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 9 Dec 2021 09:56:11 +0800
Subject: [PATCH 54/74] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E6=96=87?=
 =?UTF-8?q?=E5=AD=97=E5=A4=8D=E5=88=B6=E5=89=AA=E8=B4=B4=E6=8C=87=E4=BB=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/directive/index.js            |  2 +
 ruoyi-ui/src/directive/module/clipboard.js | 54 ++++++++++++++++++++++
 2 files changed, 56 insertions(+)
 create mode 100644 ruoyi-ui/src/directive/module/clipboard.js

diff --git a/ruoyi-ui/src/directive/index.js b/ruoyi-ui/src/directive/index.js
index 030fd4fe2..b2901d7e2 100644
--- a/ruoyi-ui/src/directive/index.js
+++ b/ruoyi-ui/src/directive/index.js
@@ -3,10 +3,12 @@ import hasPermi from './permission/hasPermi'
 import dialogDrag from './dialog/drag'
 import dialogDragWidth from './dialog/dragWidth'
 import dialogDragHeight from './dialog/dragHeight'
+import clipboard from './module/clipboard'
 
 const install = function(Vue) {
   Vue.directive('hasRole', hasRole)
   Vue.directive('hasPermi', hasPermi)
+  Vue.directive('clipboard', clipboard)
   Vue.directive('dialogDrag', dialogDrag)
   Vue.directive('dialogDragWidth', dialogDragWidth)
   Vue.directive('dialogDragHeight', dialogDragHeight)
diff --git a/ruoyi-ui/src/directive/module/clipboard.js b/ruoyi-ui/src/directive/module/clipboard.js
new file mode 100644
index 000000000..635315a84
--- /dev/null
+++ b/ruoyi-ui/src/directive/module/clipboard.js
@@ -0,0 +1,54 @@
+/**
+* v-clipboard 文字复制剪贴
+* Copyright (c) 2021 ruoyi
+*/
+
+import Clipboard from 'clipboard'
+export default {
+  bind(el, binding, vnode) {
+    switch (binding.arg) {
+      case 'success':
+        el._vClipBoard_success = binding.value;
+        break;
+      case 'error':
+        el._vClipBoard_error = binding.value;
+        break;
+      default: {
+        const clipboard = new Clipboard(el, {
+          text: () => binding.value,
+          action: () => binding.arg === 'cut' ? 'cut' : 'copy'
+        });
+        clipboard.on('success', e => {
+          const callback = el._vClipBoard_success;
+          callback && callback(e);
+        });
+        clipboard.on('error', e => {
+          const callback = el._vClipBoard_error;
+          callback && callback(e);
+        });
+        el._vClipBoard = clipboard;
+      }
+    }
+  },
+  update(el, binding) {
+    if (binding.arg === 'success') {
+      el._vClipBoard_success = binding.value;
+    } else if (binding.arg === 'error') {
+      el._vClipBoard_error = binding.value;
+    } else {
+      el._vClipBoard.text = function () { return binding.value; };
+      el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy';
+    }
+  },
+  unbind(el, binding) {
+    if (!el._vClipboard) return
+    if (binding.arg === 'success') {
+      delete el._vClipBoard_success;
+    } else if (binding.arg === 'error') {
+      delete el._vClipBoard_error;
+    } else {
+      el._vClipBoard.destroy();
+      delete el._vClipBoard;
+    }
+  }
+}

From 44ce6774dc644b0b8bf994a1360dd8cd27465576 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 9 Dec 2021 09:57:02 +0800
Subject: [PATCH 55/74] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?=
 =?UTF-8?q?=E9=A2=84=E8=A7=88=E6=94=AF=E6=8C=81=E5=A4=8D=E5=88=B6=E5=86=85?=
 =?UTF-8?q?=E5=AE=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/views/tool/gen/index.vue | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/ruoyi-ui/src/views/tool/gen/index.vue b/ruoyi-ui/src/views/tool/gen/index.vue
index 646decf45..3b7c90230 100644
--- a/ruoyi-ui/src/views/tool/gen/index.vue
+++ b/ruoyi-ui/src/views/tool/gen/index.vue
@@ -169,7 +169,8 @@
           :name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
           :key="key"
         >
-        <pre><code class="hljs" v-html="highlightedCode(value, key)"></code></pre>
+          <el-link :underline="false" icon="el-icon-document-copy" v-clipboard:copy="value" v-clipboard:success="clipboardSuccess" style="float:right">复制</el-link>
+          <pre><code class="hljs" v-html="highlightedCode(value, key)"></code></pre>
         </el-tab-pane>
       </el-tabs>
     </el-dialog>
@@ -306,6 +307,10 @@ export default {
       const result = hljs.highlight(language, code || "", true);
       return result.value || '&nbsp;';
     },
+    /** 复制代码成功 */
+    clipboardSuccess(){
+      this.$modal.msgSuccess("复制成功");
+    },
     // 多选框选中数据
     handleSelectionChange(selection) {
       this.ids = selection.map(item => item.tableId);

From 2a235917dc8fa348f00cf9a030cef94dfd9a7d44 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Fri, 10 Dec 2021 10:03:25 +0800
Subject: [PATCH 56/74] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=8B=E8=BD=BD?=
 =?UTF-8?q?=E8=A7=A3=E6=9E=90blob=E5=BC=82=E5=B8=B8=E6=8F=90=E7=A4=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/plugins/download.js | 13 ++++++++++---
 ruoyi-ui/src/utils/request.js    |  5 ++++-
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/ruoyi-ui/src/plugins/download.js b/ruoyi-ui/src/plugins/download.js
index 103e10625..86e20311e 100644
--- a/ruoyi-ui/src/plugins/download.js
+++ b/ruoyi-ui/src/plugins/download.js
@@ -2,6 +2,7 @@ import axios from 'axios'
 import { Message } from 'element-ui'
 import { saveAs } from 'file-saver'
 import { getToken } from '@/utils/auth'
+import errorCode from '@/utils/errorCode'
 import { blobValidate } from "@/utils/ruoyi";
 
 const baseURL = process.env.VUE_APP_BASE_API
@@ -20,7 +21,7 @@ export default {
         const blob = new Blob([res.data])
         this.saveAs(blob, decodeURI(res.headers['download-filename']))
       } else {
-        Message.error('无效的会话,或者会话已过期,请重新登录。');
+        this.printErrMsg(res.data);
       }
     })
   },
@@ -37,7 +38,7 @@ export default {
         const blob = new Blob([res.data])
         this.saveAs(blob, decodeURI(res.headers['download-filename']))
       } else {
-        Message.error('无效的会话,或者会话已过期,请重新登录。');
+        this.printErrMsg(res.data);
       }
     })
   },
@@ -54,12 +55,18 @@ export default {
         const blob = new Blob([res.data], { type: 'application/zip' })
         this.saveAs(blob, name)
       } else {
-        Message.error('无效的会话,或者会话已过期,请重新登录。');
+        this.printErrMsg(res.data);
       }
     })
   },
   saveAs(text, name, opts) {
     saveAs(text, name, opts);
+  },
+  async printErrMsg(data) {
+    const resText = await data.text();
+    const rspObj = JSON.parse(resText);
+    const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+    Message.error(errMsg);
   }
 }
 
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
index 1acd94168..8ee43ccb4 100644
--- a/ruoyi-ui/src/utils/request.js
+++ b/ruoyi-ui/src/utils/request.js
@@ -108,7 +108,10 @@ export function download(url, params, filename) {
       const blob = new Blob([data])
       saveAs(blob, filename)
     } else {
-      Message.error('无效的会话,或者会话已过期,请重新登录。');
+      const resText = await data.text();
+      const rspObj = JSON.parse(resText);
+      const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+      Message.error(errMsg);
     }
     downloadLoadingInstance.close();
   }).catch((r) => {

From 2743785aafd8a9156b65f2a24a0dc388594233d0 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 13 Dec 2021 10:11:34 +0800
Subject: [PATCH 57/74] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E5=8F=82?=
 =?UTF-8?q?=E6=95=B0=E9=80=97=E5=8F=B7=E5=88=86=E9=9A=94=E7=9A=84=E9=97=AE?=
 =?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/ruoyi/quartz/util/JobInvokeUtil.java  | 24 +++++++++----------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
index 4cde0ec44..663b4a1f1 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
@@ -65,7 +65,7 @@ public class JobInvokeUtil
     /**
      * 校验是否为为class包名
      * 
-     * @param str 名称
+     * @param invokeTarget 名称
      * @return true是 false否
      */
     public static boolean isValidClassName(String invokeTarget)
@@ -110,30 +110,30 @@ public class JobInvokeUtil
         {
             return null;
         }
-        String[] methodParams = methodStr.split(",(?=(?:[^\']*\"[^\']*\')*[^\']*$)");
+        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
         List<Object[]> classs = new LinkedList<>();
         for (int i = 0; i < methodParams.length; i++)
         {
             String str = StringUtils.trimToEmpty(methodParams[i]);
-            // String字符串类型,包含'
-            if (StringUtils.contains(str, "'"))
+            // String字符串类型,以'或"开头
+            if (StringUtils.startsWithAny(str, "'", "\""))
             {
-                classs.add(new Object[] { StringUtils.replace(str, "'", ""), String.class });
+                classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class });
             }
             // boolean布尔类型,等于true或者false
-            else if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false"))
+            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str))
             {
                 classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
             }
-            // long长整形,包含L
-            else if (StringUtils.containsIgnoreCase(str, "L"))
+            // long长整形,以L结尾
+            else if (StringUtils.endsWith(str, "L"))
             {
-                classs.add(new Object[] { Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class });
+                classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });
             }
-            // double浮点类型,包含D
-            else if (StringUtils.containsIgnoreCase(str, "D"))
+            // double浮点类型,以D结尾
+            else if (StringUtils.endsWith(str, "D"))
             {
-                classs.add(new Object[] { Double.valueOf(StringUtils.replaceIgnoreCase(str, "D", "")), Double.class });
+                classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class });
             }
             // 其他类型归类为整形
             else

From bb4d75aff0027459e3ab99500a4539a3735a9022 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 14 Dec 2021 10:33:25 +0800
Subject: [PATCH 58/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7log4j2=E5=88=B0?=
 =?UTF-8?q?=E5=AE=89=E5=85=A8=E7=89=88=E6=9C=AC=EF=BC=8C=E9=98=B2=E6=AD=A2?=
 =?UTF-8?q?=E6=BC=8F=E6=B4=9E=E9=A3=8E=E9=99=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/pom.xml b/pom.xml
index b24166e70..c4586da67 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,6 +33,7 @@
         <poi.version>4.1.2</poi.version>
         <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
+        <log4j2.version>2.15.0</log4j2.version>
     </properties>
 	
     <!-- 依赖声明 -->
@@ -150,6 +151,19 @@
                 <version>${fastjson.version}</version>
             </dependency>
 
+            <!-- log4j日志组件 -->
+            <dependency>
+                <groupId>org.apache.logging.log4j</groupId>
+                <artifactId>log4j-api</artifactId>
+                <version>${log4j2.version}</version>
+            </dependency>
+            
+            <dependency>
+                <groupId>org.apache.logging.log4j</groupId>
+                <artifactId>log4j-to-slf4j</artifactId>
+                <version>${log4j2.version}</version>
+            </dependency>
+
             <!-- Token生成与解析-->
             <dependency>
                 <groupId>io.jsonwebtoken</groupId>

From e1c7115d8c08d188f2c6a49fd07ebb8d3de11ed0 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 14 Dec 2021 12:09:57 +0800
Subject: [PATCH 59/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7log4j2=E5=88=B0?=
 =?UTF-8?q?=E5=AE=89=E5=85=A8=E7=89=88=E6=9C=AC=EF=BC=8C=E9=98=B2=E6=AD=A2?=
 =?UTF-8?q?=E6=BC=8F=E6=B4=9E=E9=A3=8E=E9=99=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index c4586da67..df250e8fd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
         <poi.version>4.1.2</poi.version>
         <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
-        <log4j2.version>2.15.0</log4j2.version>
+        <log4j2.version>2.16.0</log4j2.version>
     </properties>
 	
     <!-- 依赖声明 -->

From d365a52cd6feaf4d118fafaa55104bf299d78bcb Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Wed, 15 Dec 2021 10:50:10 +0800
Subject: [PATCH 60/74] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89xss=E6=A0=A1?=
 =?UTF-8?q?=E9=AA=8C=E6=B3=A8=E8=A7=A3=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../common/core/domain/entity/SysUser.java    |  7 +++--
 .../common/utils/bean/BeanValidators.java     | 24 +++++++++++++++
 .../main/java/com/ruoyi/common/xss/Xss.java   | 27 +++++++++++++++++
 .../com/ruoyi/common/xss/XssValidator.java    | 29 +++++++++++++++++++
 .../com/ruoyi/system/domain/SysNotice.java    |  2 ++
 .../service/impl/SysUserServiceImpl.java      |  7 +++++
 6 files changed, 93 insertions(+), 3 deletions(-)
 create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java
 create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
 create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
index 08cf15142..4aa1d2b2d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -2,9 +2,7 @@ package com.ruoyi.common.core.domain.entity;
 
 import java.util.Date;
 import java.util.List;
-import javax.validation.constraints.Email;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Size;
+import javax.validation.constraints.*;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -14,6 +12,7 @@ import com.ruoyi.common.annotation.Excel.ColumnType;
 import com.ruoyi.common.annotation.Excel.Type;
 import com.ruoyi.common.annotation.Excels;
 import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.common.xss.Xss;
 
 /**
  * 用户对象 sys_user
@@ -135,6 +134,7 @@ public class SysUser extends BaseEntity
         this.deptId = deptId;
     }
 
+    @Xss(message = "用户昵称不能包含脚本字符")
     @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
     public String getNickName()
     {
@@ -146,6 +146,7 @@ public class SysUser extends BaseEntity
         this.nickName = nickName;
     }
 
+    @Xss(message = "用户账号不能包含脚本字符")
     @NotBlank(message = "用户账号不能为空")
     @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
     public String getUserName()
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java
new file mode 100644
index 000000000..d9821e0ec
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.utils.bean;
+
+import java.util.Set;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validator;
+
+/**
+ * bean对象属性验证
+ * 
+ * @author ruoyi
+ */
+public class BeanValidators
+{
+    public static void validateWithException(Validator validator, Object object, Class<?>... groups)
+            throws ConstraintViolationException
+    {
+        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
+        if (!constraintViolations.isEmpty())
+        {
+            throw new ConstraintViolationException(constraintViolations);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java b/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
new file mode 100644
index 000000000..14e43dc55
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
@@ -0,0 +1,27 @@
+package com.ruoyi.common.xss;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 自定义xss校验注解
+ * 
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
+@Constraint(validatedBy = { XssValidator.class })
+public @interface Xss
+{
+    String message()
+
+    default "不允许任何脚本运行";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java b/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
new file mode 100644
index 000000000..43163721d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
@@ -0,0 +1,29 @@
+package com.ruoyi.common.xss;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 自定义xss校验注解实现
+ * 
+ * @author ruoyi
+ */
+public class XssValidator implements ConstraintValidator<Xss, String>
+{
+    private final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
+    {
+        return !containsHtml(value);
+    }
+
+    public boolean containsHtml(String value)
+    {
+        Pattern pattern = Pattern.compile(HTML_PATTERN);
+        Matcher matcher = pattern.matcher(value);
+        return matcher.matches();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
index cb739dc41..b5c6187ba 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
@@ -5,6 +5,7 @@ import javax.validation.constraints.Size;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.common.xss.Xss;
 
 /**
  * 通知公告表 sys_notice
@@ -45,6 +46,7 @@ public class SysNotice extends BaseEntity
         this.noticeTitle = noticeTitle;
     }
 
+    @Xss(message = "公告标题不能包含脚本字符")
     @NotBlank(message = "公告标题不能为空")
     @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
     public String getNoticeTitle()
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
index e40c8c85d..8d33286fa 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -3,6 +3,7 @@ package com.ruoyi.system.service.impl;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
+import javax.validation.Validator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,6 +17,7 @@ import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.bean.BeanValidators;
 import com.ruoyi.common.utils.spring.SpringUtils;
 import com.ruoyi.system.domain.SysPost;
 import com.ruoyi.system.domain.SysUserPost;
@@ -56,6 +58,9 @@ public class SysUserServiceImpl implements ISysUserService
     @Autowired
     private ISysConfigService configService;
 
+    @Autowired
+    protected Validator validator;
+
     /**
      * 根据条件分页查询用户列表
      * 
@@ -513,6 +518,7 @@ public class SysUserServiceImpl implements ISysUserService
                 SysUser u = userMapper.selectUserByUserName(user.getUserName());
                 if (StringUtils.isNull(u))
                 {
+                    BeanValidators.validateWithException(validator, user);
                     user.setPassword(SecurityUtils.encryptPassword(password));
                     user.setCreateBy(operName);
                     this.insertUser(user);
@@ -521,6 +527,7 @@ public class SysUserServiceImpl implements ISysUserService
                 }
                 else if (isUpdateSupport)
                 {
+                    BeanValidators.validateWithException(validator, user);
                     user.setUpdateBy(operName);
                     this.updateUser(user);
                     successNum++;

From 43d76e599091dc6b79b51f89c79514b50e33ea35 Mon Sep 17 00:00:00 2001
From: fuzui <73400@163.com>
Date: Thu, 16 Dec 2021 02:18:48 +0800
Subject: [PATCH 61/74] =?UTF-8?q?fix:=20cron=E7=BB=84=E4=BB=B6=E4=B8=AD?=
 =?UTF-8?q?=E5=91=A8=E5=9B=9E=E6=98=BEbug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/components/Crontab/index.vue | 2 +-
 ruoyi-ui/src/components/Crontab/week.vue  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/ruoyi-ui/src/components/Crontab/index.vue b/ruoyi-ui/src/components/Crontab/index.vue
index bd863b1b6..3963df28e 100644
--- a/ruoyi-ui/src/components/Crontab/index.vue
+++ b/ruoyi-ui/src/components/Crontab/index.vue
@@ -273,7 +273,7 @@ export default {
           insValue = 5;
         } else {
           this.$refs[refName].checkboxList = value.split(",");
-          insValue = 7;
+          insValue = 6;
         }
       } else if (name == "year") {
         if (value == "") {
diff --git a/ruoyi-ui/src/components/Crontab/week.vue b/ruoyi-ui/src/components/Crontab/week.vue
index ae389a7a5..1cec700e8 100644
--- a/ruoyi-ui/src/components/Crontab/week.vue
+++ b/ruoyi-ui/src/components/Crontab/week.vue
@@ -60,7 +60,7 @@
 			<el-radio v-model='radioValue' :label="6">
 				指定
 				<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
-					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
+					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="String(item.key)">{{item.value}}</el-option>
 				</el-select>
 			</el-radio>
 		</el-form-item>

From 06aef0587aec1575ee2f33c7108c5949b769d829 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 16 Dec 2021 09:50:26 +0800
Subject: [PATCH 62/74] =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=AF=BC=E5=85=A5?=
 =?UTF-8?q?=E6=8F=90=E7=A4=BA=E6=BA=A2=E5=87=BA=E5=88=99=E6=98=BE=E7=A4=BA?=
 =?UTF-8?q?=E6=BB=9A=E5=8A=A8=E6=9D=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/views/system/user/index.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
index c538a6984..81a216179 100644
--- a/ruoyi-ui/src/views/system/user/index.vue
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -663,7 +663,7 @@ export default {
       this.upload.open = false;
       this.upload.isUploading = false;
       this.$refs.upload.clearFiles();
-      this.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
+      this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
       this.getList();
     },
     // 提交上传文件

From fef7ead0d5e7fc94b62662997f806898100fc6ef Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 16 Dec 2021 09:51:11 +0800
Subject: [PATCH 63/74] =?UTF-8?q?=E6=96=B0=E5=A2=9EVue3=E5=89=8D=E7=AB=AF?=
 =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E6=A8=A1=E6=9D=BF?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../resources/vm/vue/v3/index-tree.vue.vm     | 465 ++++++++++++++
 .../src/main/resources/vm/vue/v3/index.vue.vm | 567 ++++++++++++++++++
 .../src/main/resources/vm/vue/v3/readme.txt   |   1 +
 3 files changed, 1033 insertions(+)
 create mode 100644 ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
 create mode 100644 ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
 create mode 100644 ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt

diff --git a/ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
new file mode 100644
index 000000000..62fe2f11f
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
@@ -0,0 +1,465 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="请输入${comment}"
+          clearable
+          size="small"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
+          <el-option
+            v-for="dict in ${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="选择${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          size="small"
+          style="width: 240px"
+          value-format="YYYY-MM-DD"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+	    <el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >新增</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-loading="loading"
+      :data="${businessName}List"
+      row-key="${treeCode}"
+      default-expand-all
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template #default="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+      <el-table-column label="${comment}" prop="${javaField}" />
+#else
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="Edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="Plus"
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:add']"
+          >新增</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="Delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 添加或修改${functionName}对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+        <el-form-item label="${comment}" prop="${treeParentCode}">
+          <tree-select
+            v-model:value="form.${treeParentCode}"
+            :options="${businessName}Options"
+            :objMap="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
+            placeholder="请选择${comment}"
+          />
+        </el-form-item>
+#elseif($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}">
+          <imageUpload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}">
+          <fileUpload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
+
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>请选择字典生成</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
+
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable size="small"
+            v-model="form.${field}"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="选择${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+const { proxy } = getCurrentInstance();
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
+#end
+
+const ${businessName}List = ref([]);
+const ${businessName}Options = ref([]);
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const title = ref("");
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const daterange${AttrName} = ref([]);
+#end
+#end
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    #foreach ($column in $columns)
+#if($column.query)
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  },
+  rules: {
+    #foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+    $column.javaField: [
+      { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
+    ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询${functionName}列表 */
+function getList() {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
+    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
+    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
+  }
+#end
+#end
+  list${BusinessName}(queryParams.value).then(response => {
+    ${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+    loading.value = false;
+  });
+}
+
+/** 查询${functionName}下拉树结构 */
+async function getTreeselect() {
+  await list${BusinessName}().then(response => {
+    ${businessName}Options.value = [];
+    const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
+    data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+    ${businessName}Options.value.push(data);
+  });
+}
+	
+// 取消按钮
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+#foreach ($column in $columns)
+#if($column.htmlType == "radio")
+    $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
+
+#elseif($column.htmlType == "checkbox")
+    $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  };
+  proxy.resetForm("${businessName}Ref");
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  getList();
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  daterange${AttrName}.value = [];
+#end
+#end
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+/** 新增按钮操作 */
+async function handleAdd(row) {
+  reset();
+  await getTreeselect();
+  if (row != null && row.${treeCode}) {
+    form.value.${treeParentCode} = row.${treeCode};
+  } else {
+    form.value.${treeParentCode} = 0;
+  }
+  open.value = true;
+  title.value = "添加${functionName}";
+}
+
+/** 修改按钮操作 */
+async function handleUpdate(row) {
+  reset();
+  await getTreeselect();
+  if (row != null) {
+    form.value.${treeParentCode} = row.${treeCode};
+  }
+  get${BusinessName}(row.${pkColumn.javaField}).then(response => {
+    form.value = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+    open.value = true;
+    title.value = "修改${functionName}";
+  });
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
+    if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+      form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+      if (form.value.${pkColumn.javaField} != null) {
+        update${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("修改成功");
+          open.value = false;
+          getList();
+        });
+      } else {
+        add${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("新增成功");
+          open.value = false;
+          getList();
+        });
+      }
+    }
+  });
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
+    return del${BusinessName}(row.${pkColumn.javaField});
+  }).then(() => {
+    getList();
+    proxy.#[[$modal]]#.msgSuccess("删除成功");
+  }).catch(() => {});
+}
+
+getList();
+</script>
diff --git a/ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
new file mode 100644
index 000000000..6e7b41f1e
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
@@ -0,0 +1,567 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="请输入${comment}"
+          clearable
+          size="small"
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
+          <el-option
+            v-for="dict in ${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable size="small"
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="选择${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          size="small"
+          style="width: 240px"
+          value-format="YYYY-MM-DD"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+        <el-button type="primary" icon="Search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['${moduleName}:${businessName}:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['${moduleName}:${businessName}:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['${moduleName}:${businessName}:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template #default="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template #default="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="Edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="Delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:p:page="queryParams.pageNum"
+      v-model:p:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改${functionName}对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="${businessName}Ref" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}">
+          <imageUpload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}">
+          <fileUpload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
+
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>请选择字典生成</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
+
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable size="small"
+            v-model="form.${field}"
+            type="date"
+            value-format="YYYY-MM-DD"
+            placeholder="选择${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+#if($table.sub)
+        <el-divider content-position="center">${subTable.functionName}信息</el-divider>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" icon="Plus" size="mini" @click="handleAdd${subClassName}">添加</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" icon="Delete" size="mini" @click="handleDelete${subClassName}">删除</el-button>
+          </el-col>
+        </el-row>
+        <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="序号" align="center" prop="index" width="50"/>
+#foreach($column in $subTable.columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk || $javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $javaField)
+          <el-table-column label="$comment" prop="${javaField}">
+            <template #default="scope">
+              <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
+            </template>
+          </el-table-column>
+#end
+#end
+        </el-table>
+#end
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+const { proxy } = getCurrentInstance();
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
+#end
+
+const ${businessName}List = ref([]);
+#if($table.sub)
+const ${subclassName}List = ref([]);
+#end
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref([]);
+#if($table.sub)
+const checked${subClassName} = ref([]);
+#end
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const daterange${AttrName} = ref([]);
+#end
+#end
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    #foreach ($column in $columns)
+#if($column.query)
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  },
+  rules: {
+    #foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+    $column.javaField: [
+      { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
+    ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 查询${functionName}列表 */
+function getList() {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
+    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
+    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
+  }
+#end
+#end
+  list${BusinessName}(queryParams.value).then(response => {
+    ${businessName}List.value = response.rows;
+    total.value = response.total;
+    loading.value = false;
+  });
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+#foreach ($column in $columns)
+#if($column.htmlType == "radio")
+    $column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($foreach.count != $columns.size()),#end
+#elseif($column.htmlType == "checkbox")
+    $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  };
+#if($table.sub)
+  ${subclassName}List.value = [];
+#end
+  proxy.resetForm("${businessName}Ref");
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  daterange${AttrName}.value = [];
+#end
+#end
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.${pkColumn.javaField});
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "添加${functionName}";
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset();
+  const ${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
+  get${BusinessName}(${pkColumn.javaField}).then(response => {
+    form.value = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+#if($table.sub)
+    ${subclassName}List.value = response.data.${subclassName}List;
+#end
+    open.value = true;
+    title.value = "修改${functionName}";
+  });
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
+    if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+      form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+#if($table.sub)
+      form.value.${subclassName}List = ${subclassName}List.value;
+#end
+      if (form.value.${pkColumn.javaField} != null) {
+        update${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("修改成功");
+          open.value = false;
+          getList();
+        });
+      } else {
+        add${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("新增成功");
+          open.value = false;
+          getList();
+        });
+      }
+    }
+  });
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const ${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value;
+  proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
+    return del${BusinessName}(${pkColumn.javaField}s);
+  }).then(() => {
+    getList();
+    proxy.#[[$modal]]#.msgSuccess("删除成功");
+  }).catch(() => {});
+}
+
+#if($table.sub)
+/** ${subTable.functionName}序号 */
+function row${subClassName}Index({ row, rowIndex }) {
+  row.index = rowIndex + 1;
+}
+
+/** ${subTable.functionName}添加按钮操作 */
+function handleAdd${subClassName}() {
+  let obj = {};
+#foreach($column in $subTable.columns)
+#if($column.pk || $column.javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $javaField)
+  obj.$column.javaField = "";
+#end
+#end
+  ${subclassName}List.value.push(obj);
+}
+
+/** ${subTable.functionName}删除按钮操作 */
+function handleDelete${subClassName}() {
+  if (checked${subClassName}.value.length == 0) {
+    proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
+  } else {
+    const ${subclassName}s = ${subclassName}List.value;
+    const checked${subClassName}s = checked${subClassName}.value;
+    ${subclassName}List.value = ${subclassName}s.filter(function(item) {
+      return checked${subClassName}s.indexOf(item.index) == -1
+    });
+  }
+}
+
+/** 复选框选中数据 */
+function handle${subClassName}SelectionChange(selection) {
+  checked${subClassName}.value = selection.map(item => item.index)
+}
+
+#end
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('${moduleName}/${businessName}/export', {
+    ...queryParams.value
+  }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+}
+
+getList();
+</script>
diff --git a/ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt b/ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt
new file mode 100644
index 000000000..99239bb53
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/vue/v3/readme.txt
@@ -0,0 +1 @@
+���ʹ�õ���RuoYi-Vue3ǰ�ˣ���ô��Ҫ����һ�´�Ŀ¼��ģ��index.vue.vm��index-tree.vue.vm�ļ����ϼ�vueĿ¼��
\ No newline at end of file

From 6e14601c7cd8312a8dcb372b341ea05c7b965a23 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Thu, 16 Dec 2021 16:34:20 +0800
Subject: [PATCH 64/74] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=89=88=E6=9C=AC?=
 =?UTF-8?q?=E5=B7=AE=E5=BC=82=E5=AF=BC=E8=87=B4=E7=9A=84=E6=87=92=E5=8A=A0?=
 =?UTF-8?q?=E8=BD=BD=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json        |  1 +
 ruoyi-ui/src/router/index.js | 24 ++++++++++++------------
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 600e9ad12..6d33bdf57 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -65,6 +65,7 @@
     "@vue/cli-plugin-eslint": "4.4.6",
     "@vue/cli-service": "4.4.6",
     "babel-eslint": "10.1.0",
+    "babel-plugin-dynamic-import-node": "2.3.3",
     "chalk": "4.1.0",
     "connect": "3.6.6",
     "eslint": "7.15.0",
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index ccf886f73..6510ff708 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -35,28 +35,28 @@ export const constantRoutes = [
     children: [
       {
         path: '/redirect/:path(.*)',
-        component: (resolve) => require(['@/views/redirect'], resolve)
+        component: () => import('@/views/redirect')
       }
     ]
   },
   {
     path: '/login',
-    component: (resolve) => require(['@/views/login'], resolve),
+    component: () => import('@/views/login'),
     hidden: true
   },
   {
     path: '/register',
-    component: (resolve) => require(['@/views/register'], resolve),
+    component: () => import('@/views/register'),
     hidden: true
   },
   {
     path: '/404',
-    component: (resolve) => require(['@/views/error/404'], resolve),
+    component: () => import('@/views/error/404'),
     hidden: true
   },
   {
     path: '/401',
-    component: (resolve) => require(['@/views/error/401'], resolve),
+    component: () => import('@/views/error/401'),
     hidden: true
   },
   {
@@ -66,7 +66,7 @@ export const constantRoutes = [
     children: [
       {
         path: 'index',
-        component: (resolve) => require(['@/views/index'], resolve),
+        component: () => import('@/views/index'),
         name: 'Index',
         meta: { title: '首页', icon: 'dashboard', affix: true }
       }
@@ -80,7 +80,7 @@ export const constantRoutes = [
     children: [
       {
         path: 'profile',
-        component: (resolve) => require(['@/views/system/user/profile/index'], resolve),
+        component: () => import('@/views/system/user/profile/index'),
         name: 'Profile',
         meta: { title: '个人中心', icon: 'user' }
       }
@@ -93,7 +93,7 @@ export const constantRoutes = [
     children: [
       {
         path: 'role/:userId(\\d+)',
-        component: (resolve) => require(['@/views/system/user/authRole'], resolve),
+        component: () => import('@/views/system/user/authRole'),
         name: 'AuthRole',
         meta: { title: '分配角色', activeMenu: '/system/user' }
       }
@@ -106,7 +106,7 @@ export const constantRoutes = [
     children: [
       {
         path: 'user/:roleId(\\d+)',
-        component: (resolve) => require(['@/views/system/role/authUser'], resolve),
+        component: () => import('@/views/system/role/authUser'),
         name: 'AuthUser',
         meta: { title: '分配用户', activeMenu: '/system/role' }
       }
@@ -119,7 +119,7 @@ export const constantRoutes = [
     children: [
       {
         path: 'index/:dictId(\\d+)',
-        component: (resolve) => require(['@/views/system/dict/data'], resolve),
+        component: () => import('@/views/system/dict/data'),
         name: 'Data',
         meta: { title: '字典数据', activeMenu: '/system/dict' }
       }
@@ -132,7 +132,7 @@ export const constantRoutes = [
     children: [
       {
         path: 'index',
-        component: (resolve) => require(['@/views/monitor/job/log'], resolve),
+        component: () => import('@/views/monitor/job/log'),
         name: 'JobLog',
         meta: { title: '调度日志', activeMenu: '/monitor/job' }
       }
@@ -145,7 +145,7 @@ export const constantRoutes = [
     children: [
       {
         path: 'index',
-        component: (resolve) => require(['@/views/tool/gen/editTable'], resolve),
+        component: () => import('@/views/tool/gen/editTable'),
         name: 'GenEdit',
         meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
       }

From 47b67331d4197023189482763d9a9f01d6ece32e Mon Sep 17 00:00:00 2001
From: 18297093310 <18297093310@163.com>
Date: Fri, 17 Dec 2021 03:06:25 +0000
Subject: [PATCH 65/74] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=87=8D=E7=BD=AE?=
 =?UTF-8?q?=E8=A1=A8=E5=8D=95bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/views/system/menu/index.vue | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue
index d65773ad2..5c1f85a6f 100644
--- a/ruoyi-ui/src/views/system/menu/index.vue
+++ b/ruoyi-ui/src/views/system/menu/index.vue
@@ -128,7 +128,7 @@
             </el-form-item>
           </el-col>
           <el-col :span="24" v-if="form.menuType != 'F'">
-            <el-form-item label="菜单图标">
+            <el-form-item label="菜单图标" prop="icon">
               <el-popover
                 placement="bottom-start"
                 width="460"

From 8978012f9de8bf34e0de0e28998c3c71c3cb12c1 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Fri, 17 Dec 2021 11:36:15 +0800
Subject: [PATCH 66/74] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=89=93=E5=8C=85?=
 =?UTF-8?q?=E5=90=8E=E5=AD=97=E4=BD=93=E5=9B=BE=E6=A0=87=E5=81=B6=E7=8E=B0?=
 =?UTF-8?q?=E7=9A=84=E4=B9=B1=E7=A0=81=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/vue.config.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
index 76707460a..36cd2025e 100644
--- a/ruoyi-ui/vue.config.js
+++ b/ruoyi-ui/vue.config.js
@@ -42,6 +42,13 @@ module.exports = {
     },
     disableHostCheck: true
   },
+  css: {
+    loaderOptions: {
+      sass: {
+        sassOptions: { outputStyle: "expanded" }
+      }
+    }
+  },
   configureWebpack: {
     name: name,
     resolve: {

From 7492dcc9e6bf3e5dca48a14cf775c6c693bf32e5 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sat, 18 Dec 2021 12:22:41 +0800
Subject: [PATCH 67/74] =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=88=86=E9=A1=B5?=
 =?UTF-8?q?=E6=96=B9=E6=B3=95=E8=AE=BE=E7=BD=AE=E6=88=90=E9=80=9A=E7=94=A8?=
 =?UTF-8?q?=E6=96=B9=E4=BE=BF=E7=81=B5=E6=B4=BB=E8=B0=83=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../core/controller/BaseController.java       | 11 ++-----
 .../com/ruoyi/common/utils/PageUtils.java     | 29 +++++++++++++++++++
 2 files changed, 31 insertions(+), 9 deletions(-)
 create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
index 5b450cb87..2aeaf9bae 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
@@ -16,6 +16,7 @@ import com.ruoyi.common.core.page.PageDomain;
 import com.ruoyi.common.core.page.TableDataInfo;
 import com.ruoyi.common.core.page.TableSupport;
 import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.PageUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.sql.SqlUtil;
@@ -51,15 +52,7 @@ public class BaseController
      */
     protected void startPage()
     {
-        PageDomain pageDomain = TableSupport.buildPageRequest();
-        Integer pageNum = pageDomain.getPageNum();
-        Integer pageSize = pageDomain.getPageSize();
-        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
-        {
-            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
-            Boolean reasonable = pageDomain.getReasonable();
-            PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
-        }
+        PageUtils.startPage();
     }
 
     /**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
new file mode 100644
index 000000000..62a763277
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
@@ -0,0 +1,29 @@
+package com.ruoyi.common.utils;
+
+import com.github.pagehelper.PageHelper;
+import com.ruoyi.common.core.page.PageDomain;
+import com.ruoyi.common.core.page.TableSupport;
+import com.ruoyi.common.utils.sql.SqlUtil;
+
+/**
+ * 分页工具类
+ * 
+ * @author ruoyi
+ */
+public class PageUtils extends PageHelper
+{
+    /**
+     * 设置请求分页数据
+     */
+    public static void startPage()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
+        {
+            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+            PageHelper.startPage(pageNum, pageSize, orderBy);
+        }
+    }
+}

From 903b5aebca7951da979d703604c7f54159498157 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sat, 18 Dec 2021 12:23:59 +0800
Subject: [PATCH 68/74] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=9B=BE=E7=89=87?=
 =?UTF-8?q?=E9=A2=84=E8=A7=88=E7=BB=84=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/components/ImagePreview/index.vue     | 67 +++++++++++++++++++
 ruoyi-ui/src/main.js                          |  3 +
 2 files changed, 70 insertions(+)
 create mode 100644 ruoyi-ui/src/components/ImagePreview/index.vue

diff --git a/ruoyi-ui/src/components/ImagePreview/index.vue b/ruoyi-ui/src/components/ImagePreview/index.vue
new file mode 100644
index 000000000..44e27aac2
--- /dev/null
+++ b/ruoyi-ui/src/components/ImagePreview/index.vue
@@ -0,0 +1,67 @@
+<template>
+    <el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="[`${realSrc}`]">
+        <div slot="error" class="image-slot">
+          <i class="el-icon-picture-outline"></i>
+        </div>
+    </el-image>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+    name: 'ImagePreview',
+    props: {
+        src: {
+            type: String,
+            required: true
+        },
+        width: {
+            type: [Number, String],
+            default: ''
+        },
+        height: {
+            type: [Number, String],
+            default: ''
+        }
+    },
+    computed: {
+        realSrc() {
+            if (isExternal(this.src)) {
+                return this.src
+            }
+            return process.env.VUE_APP_BASE_API + this.src
+        },
+        realWidth() {
+            return typeof this.width == 'string' ? this.width : `${this.width}px`
+        },
+        realHeight() {
+            return typeof this.height == 'string' ? this.height : `${this.height}px`
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.el-image {
+    border-radius: 5px;
+    background-color: #ebeef5;
+    box-shadow: 0 0 5px 1px #ccc;
+    ::v-deep .el-image__inner {
+        transition: all 0.3s;
+        cursor: pointer;
+        &:hover {
+            transform: scale(1.2);
+        }
+    }
+    ::v-deep .image-slot {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        width: 100%;
+        height: 100%;
+        color: #909399;
+        font-size: 30px;
+    }
+}
+</style>
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index 729467aee..ebd94b9d8 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -29,6 +29,8 @@ import Editor from "@/components/Editor"
 import FileUpload from "@/components/FileUpload"
 // 图片上传组件
 import ImageUpload from "@/components/ImageUpload"
+// 图片预览组件
+import ImagePreview from "@/components/ImagePreview"
 // 字典标签组件
 import DictTag from '@/components/DictTag'
 // 头部标签组件
@@ -54,6 +56,7 @@ Vue.component('RightToolbar', RightToolbar)
 Vue.component('Editor', Editor)
 Vue.component('FileUpload', FileUpload)
 Vue.component('ImageUpload', ImageUpload)
+Vue.component('ImagePreview', ImagePreview)
 
 Vue.use(directive)
 Vue.use(plugins)

From e5647793ce650582787622aa8a9828356911dcc6 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sat, 18 Dec 2021 16:48:31 +0800
Subject: [PATCH 69/74] =?UTF-8?q?=E8=B7=AF=E7=94=B1=E6=94=AF=E6=8C=81?=
 =?UTF-8?q?=E5=8D=95=E7=8B=AC=E9=85=8D=E7=BD=AE=E8=8F=9C=E5=8D=95=E6=88=96?=
 =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/src/router/index.js             | 13 ++++++++++++-
 ruoyi-ui/src/store/modules/permission.js | 22 +++++++++++++++++++++-
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index 6510ff708..e4ccf19a6 100644
--- a/ruoyi-ui/src/router/index.js
+++ b/ruoyi-ui/src/router/index.js
@@ -17,6 +17,8 @@ import Layout from '@/layout'
  * redirect: noRedirect             // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
  * name:'router-name'               // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
  * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
+ * roles: ['admin', 'common']       // 访问路由的角色权限
+ * permissions: ['a:a:a', 'b:b:b']  // 访问路由的菜单权限
  * meta : {
     noCache: true                   // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
     title: 'title'                  // 设置该路由在侧边栏和面包屑中展示的名字
@@ -85,11 +87,16 @@ export const constantRoutes = [
         meta: { title: '个人中心', icon: 'user' }
       }
     ]
-  },
+  }
+]
+
+// 动态路由,基于用户权限动态去加载
+export const dynamicRoutes = [
   {
     path: '/system/user-auth',
     component: Layout,
     hidden: true,
+    permissions: ['system:user:edit'],
     children: [
       {
         path: 'role/:userId(\\d+)',
@@ -103,6 +110,7 @@ export const constantRoutes = [
     path: '/system/role-auth',
     component: Layout,
     hidden: true,
+    permissions: ['system:role:edit'],
     children: [
       {
         path: 'user/:roleId(\\d+)',
@@ -116,6 +124,7 @@ export const constantRoutes = [
     path: '/system/dict-data',
     component: Layout,
     hidden: true,
+    permissions: ['system:dict:list'],
     children: [
       {
         path: 'index/:dictId(\\d+)',
@@ -129,6 +138,7 @@ export const constantRoutes = [
     path: '/monitor/job-log',
     component: Layout,
     hidden: true,
+    permissions: ['monitor:job:list'],
     children: [
       {
         path: 'index',
@@ -142,6 +152,7 @@ export const constantRoutes = [
     path: '/tool/gen-edit',
     component: Layout,
     hidden: true,
+    permissions: ['tool:gen:edit'],
     children: [
       {
         path: 'index',
diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js
index 2c2120a8f..8c3c33909 100644
--- a/ruoyi-ui/src/store/modules/permission.js
+++ b/ruoyi-ui/src/store/modules/permission.js
@@ -1,4 +1,5 @@
-import { constantRoutes } from '@/router'
+import auth from '@/plugins/auth'
+import router, { constantRoutes, dynamicRoutes } from '@/router'
 import { getRouters } from '@/api/menu'
 import Layout from '@/layout/index'
 import ParentView from '@/components/ParentView'
@@ -42,7 +43,9 @@ const permission = {
           const rdata = JSON.parse(JSON.stringify(res.data))
           const sidebarRoutes = filterAsyncRouter(sdata)
           const rewriteRoutes = filterAsyncRouter(rdata, false, true)
+          const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
           rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
+          router.addRoutes(asyncRoutes);
           commit('SET_ROUTES', rewriteRoutes)
           commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
           commit('SET_DEFAULT_ROUTES', sidebarRoutes)
@@ -106,6 +109,23 @@ function filterChildren(childrenMap, lastRouter = false) {
   return children
 }
 
+// 动态路由遍历,验证是否具备权限
+export function filterDynamicRoutes(routes) {
+  const res = []
+  routes.forEach(route => {
+    if (route.permissions) {
+      if (auth.hasPermiOr(route.permissions)) {
+        res.push(route)
+      }
+    } else if (route.roles) {
+      if (auth.hasRoleOr(route.roles)) {
+        res.push(route)
+      }
+    }
+  })
+  return res
+}
+
 export const loadView = (view) => {
   if (process.env.NODE_ENV === 'development') {
     return (resolve) => require([`@/views/${view}`], resolve)

From ca2405c1040f204811dede20089a589f8b130bfe Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Sun, 19 Dec 2021 19:56:53 +0800
Subject: [PATCH 70/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7log4j2=E5=88=B0?=
 =?UTF-8?q?=E5=AE=89=E5=85=A8=E7=89=88=E6=9C=AC=EF=BC=8C=E9=98=B2=E6=AD=A2?=
 =?UTF-8?q?=E6=BC=8F=E6=B4=9E=E9=A3=8E=E9=99=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index df250e8fd..41994043d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
         <poi.version>4.1.2</poi.version>
         <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
-        <log4j2.version>2.16.0</log4j2.version>
+        <log4j2.version>2.17.0</log4j2.version>
     </properties>
 	
     <!-- 依赖声明 -->

From a028b566edf0546b75ec6483337480132b8fb6d6 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 20 Dec 2021 09:46:17 +0800
Subject: [PATCH 71/74] =?UTF-8?q?=E9=9B=86=E6=88=90compression-webpack-plu?=
 =?UTF-8?q?gin=E6=8F=92=E4=BB=B6=E5=AE=9E=E7=8E=B0=E6=89=93=E5=8C=85Gzip?=
 =?UTF-8?q?=E5=8E=8B=E7=BC=A9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/package.json  |  1 +
 ruoyi-ui/vue.config.js | 13 ++++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index 6d33bdf57..62f4bcee1 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -67,6 +67,7 @@
     "babel-eslint": "10.1.0",
     "babel-plugin-dynamic-import-node": "2.3.3",
     "chalk": "4.1.0",
+    "compression-webpack-plugin": "5.0.2",
     "connect": "3.6.6",
     "eslint": "7.15.0",
     "eslint-plugin-vue": "7.2.0",
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
index 36cd2025e..63bac6a51 100644
--- a/ruoyi-ui/vue.config.js
+++ b/ruoyi-ui/vue.config.js
@@ -5,6 +5,8 @@ function resolve(dir) {
   return path.join(__dirname, dir)
 }
 
+const CompressionPlugin = require('compression-webpack-plugin')
+
 const name = process.env.VUE_APP_TITLE || '若依管理系统' // 网页标题
 
 const port = process.env.port || process.env.npm_config_port || 80 // 端口
@@ -55,7 +57,16 @@ module.exports = {
       alias: {
         '@': resolve('src')
       }
-    }
+    },
+    plugins: [
+      new CompressionPlugin({
+        test: /\.(js|css|html)?$/i,     // 压缩文件格式
+        filename: '[path].gz[query]',   // 压缩后的文件名
+        algorithm: 'gzip',              // 使用gzip压缩
+        threshold: 10240,               // 对超过10K的数据压缩
+        minRatio: 0.8                   // 压缩率小于1才会压缩
+      })
+    ],
   },
   chainWebpack(config) {
     config.plugins.delete('preload') // TODO: need test

From c28aa299bd80df8611d7f83caf118f973d159f50 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Mon, 20 Dec 2021 14:25:52 +0800
Subject: [PATCH 72/74] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BD=BF=E7=94=A8Gzip?=
 =?UTF-8?q?=E8=A7=A3=E5=8E=8B=E7=BC=A9=E9=9D=99=E6=80=81=E6=96=87=E4=BB=B6?=
 =?UTF-8?q?=E5=9C=B0=E5=9D=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 ruoyi-ui/vue.config.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
index 63bac6a51..1a9e913df 100644
--- a/ruoyi-ui/vue.config.js
+++ b/ruoyi-ui/vue.config.js
@@ -59,11 +59,11 @@ module.exports = {
       }
     },
     plugins: [
+      // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
       new CompressionPlugin({
         test: /\.(js|css|html)?$/i,     // 压缩文件格式
         filename: '[path].gz[query]',   // 压缩后的文件名
         algorithm: 'gzip',              // 使用gzip压缩
-        threshold: 10240,               // 对超过10K的数据压缩
         minRatio: 0.8                   // 压缩率小于1才会压缩
       })
     ],

From fd3a699ad87f7c043658a18d9ffd298ae0b96a69 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 21 Dec 2021 13:32:28 +0800
Subject: [PATCH 73/74] =?UTF-8?q?SQL=E5=B7=A5=E5=85=B7=E7=B1=BB=E6=96=B0?=
 =?UTF-8?q?=E5=A2=9E=E6=A3=80=E6=9F=A5=E5=85=B3=E9=94=AE=E5=AD=97=E6=96=B9?=
 =?UTF-8?q?=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/ruoyi/common/utils/sql/SqlUtil.java   | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
index ceff84132..71a7ae10f 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
@@ -10,6 +10,11 @@ import com.ruoyi.common.utils.StringUtils;
  */
 public class SqlUtil
 {
+    /**
+     * 定义常用的 sql关键字
+     */
+    public static String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare ";
+
     /**
      * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
      */
@@ -34,4 +39,23 @@ public class SqlUtil
     {
         return value.matches(SQL_PATTERN);
     }
+
+    /**
+     * SQL关键字检查
+     */
+    public static void filterKeyword(String value)
+    {
+        if (StringUtils.isEmpty(value))
+        {
+            return;
+        }
+        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
+        for (int i = 0; i < sqlKeywords.length; i++)
+        {
+            if (StringUtils.indexOfIgnoreCase(value, sqlKeywords[i]) > -1)
+            {
+                throw new UtilException("参数存在SQL注入风险");
+            }
+        }
+    }
 }

From be412faf6c8bd8a815df0c7bbccf42b5e81ecd29 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: Tue, 21 Dec 2021 13:32:40 +0800
Subject: [PATCH 74/74] =?UTF-8?q?=E5=8D=87=E7=BA=A7fastjson=E5=88=B0?=
 =?UTF-8?q?=E6=9C=80=E6=96=B0=E7=89=881.2.79?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 41994043d..20e4b0b2e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
         <kaptcha.version>2.3.2</kaptcha.version>
         <mybatis-spring-boot.version>2.2.0</mybatis-spring-boot.version>
         <pagehelper.boot.version>1.4.0</pagehelper.boot.version>
-        <fastjson.version>1.2.78</fastjson.version>
+        <fastjson.version>1.2.79</fastjson.version>
         <oshi.version>5.8.2</oshi.version>
         <jna.version>5.9.0</jna.version>
         <commons.io.version>2.11.0</commons.io.version>