diff --git a/docker/copy.sh b/docker/copy.sh
new file mode 100644
index 00000000..4bb15410
--- /dev/null
+++ b/docker/copy.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+# 复制项目的文件到对应docker路径,便于一键生成镜像。
+usage() {
+ echo "Usage: sh copy.sh"
+ exit 1
+}
+
+
+# copy sql
+echo "begin copy sql "
+cp ../sql/ry_20210908.sql ./mysql/db
+cp ../sql/ry_config_20211118.sql ./mysql/db
+
+# copy html
+echo "begin copy html "
+cp -r ../ruoyi-ui/dist/** ./nginx/html/dist
+
+
+# copy jar
+echo "begin copy ruoyi-gateway "
+cp ../ruoyi-gateway/target/ruoyi-gateway.jar ./ruoyi/gateway/jar
+
+echo "begin copy ruoyi-auth "
+cp ../ruoyi-auth/target/ruoyi-auth.jar ./ruoyi/auth/jar
+
+echo "begin copy ruoyi-visual "
+cp ../ruoyi-visual/ruoyi-monitor/target/ruoyi-visual-monitor.jar ./ruoyi/visual/monitor/jar
+
+echo "begin copy ruoyi-modules-system "
+cp ../ruoyi-modules/ruoyi-system/target/ruoyi-modules-system.jar ./ruoyi/modules/system/jar
+
+echo "begin copy ruoyi-modules-file "
+cp ../ruoyi-modules/ruoyi-file/target/ruoyi-modules-file.jar ./ruoyi/modules/file/jar
+
+echo "begin copy ruoyi-modules-job "
+cp ../ruoyi-modules/ruoyi-job/target/ruoyi-modules-job.jar ./ruoyi/modules/job/jar
+
+echo "begin copy ruoyi-modules-gen "
+cp ../ruoyi-modules/ruoyi-gen/target/ruoyi-modules-gen.jar ./ruoyi/modules/gen/jar
+
diff --git a/docker/deploy.sh b/docker/deploy.sh
index 0ee4cd8a..02489092 100644
--- a/docker/deploy.sh
+++ b/docker/deploy.sh
@@ -26,12 +26,12 @@ port(){
# 启动基础环境(必须)
base(){
- docker-compose up -d ruoyi-mysql ruoyi-redis ruoyi-nacos ruoyi-nginx
+ docker-compose up -d ruoyi-mysql ruoyi-redis ruoyi-nacos
}
# 启动程序模块(必须)
modules(){
- docker-compose up -d ruoyi-gateway ruoyi-auth ruoyi-modules-system
+ docker-compose up -d ruoyi-nginx ruoyi-gateway ruoyi-auth ruoyi-modules-system
}
# 关闭所有环境/模块
diff --git a/pom.xml b/pom.xml
index 7248b6ee..d19b7801 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,7 @@
2.10.0
3.2.2
2.12.2
- 2.16.0
+ 2.17.0
diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java
index 87de3eca..f11f35fd 100644
--- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java
+++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/domain/SysUser.java
@@ -2,9 +2,7 @@ package com.ruoyi.system.api.domain;
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.JsonProperty;
@@ -13,6 +11,7 @@ import com.ruoyi.common.core.annotation.Excel.ColumnType;
import com.ruoyi.common.core.annotation.Excel.Type;
import com.ruoyi.common.core.annotation.Excels;
import com.ruoyi.common.core.web.domain.BaseEntity;
+import com.ruoyi.common.core.xss.Xss;
/**
* 用户对象 sys_user
@@ -131,6 +130,7 @@ public class SysUser extends BaseEntity
this.deptId = deptId;
}
+ @Xss(message = "用户昵称不能包含脚本字符")
@Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
public String getNickName()
{
@@ -142,6 +142,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/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java
new file mode 100644
index 00000000..f93d1f84
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java
@@ -0,0 +1,29 @@
+package com.ruoyi.common.core.utils;
+
+import com.github.pagehelper.PageHelper;
+import com.ruoyi.common.core.utils.sql.SqlUtil;
+import com.ruoyi.common.core.web.page.PageDomain;
+import com.ruoyi.common.core.web.page.TableSupport;
+
+/**
+ * 分页工具类
+ *
+ * @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);
+ }
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanValidators.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanValidators.java
new file mode 100644
index 00000000..75877262
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/bean/BeanValidators.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.core.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> constraintViolations = validator.validate(object, groups);
+ if (!constraintViolations.isEmpty())
+ {
+ throw new ConstraintViolationException(constraintViolations);
+ }
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/controller/BaseController.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/controller/BaseController.java
index 64169511..af52f172 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/controller/BaseController.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/web/controller/BaseController.java
@@ -7,16 +7,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
-import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.common.core.utils.sql.SqlUtil;
+import com.ruoyi.common.core.utils.PageUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
-import com.ruoyi.common.core.web.page.PageDomain;
import com.ruoyi.common.core.web.page.TableDataInfo;
-import com.ruoyi.common.core.web.page.TableSupport;
/**
* web层通用数据处理
@@ -49,15 +45,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/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/Xss.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/Xss.java
new file mode 100644
index 00000000..0a94d6b4
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/Xss.java
@@ -0,0 +1,27 @@
+package com.ruoyi.common.core.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/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/XssValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/XssValidator.java
new file mode 100644
index 00000000..c7dfde9b
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/xss/XssValidator.java
@@ -0,0 +1,29 @@
+package com.ruoyi.common.core.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
+{
+ 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-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm
index 95ac0ffe..62b12d98 100644
--- a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm
@@ -263,7 +263,7 @@
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm
new file mode 100644
index 00000000..6e7b41f1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/index.vue.vm
@@ -0,0 +1,567 @@
+
+
+
+#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")
+
+
+
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+
+
+
+
+
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+
+
+
+
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+
+
+
+#end
+#end
+#end
+
+ 搜索
+ 重置
+
+
+
+
+
+ 新增
+
+
+ 修改
+
+
+ 删除
+
+
+ 导出
+
+
+
+
+
+
+#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")
+
+
+ {{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}
+
+
+#elseif($column.list && "" != $column.dictType)
+
+
+#if($column.htmlType == "checkbox")
+
+#else
+
+#end
+
+
+#elseif($column.list && "" != $javaField)
+
+#end
+#end
+
+
+ 修改
+ 删除
+
+
+
+
+
+
+
+
+
+#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")
+
+
+
+#elseif($column.htmlType == "imageUpload")
+
+
+
+#elseif($column.htmlType == "fileUpload")
+
+
+
+#elseif($column.htmlType == "editor")
+
+
+
+#elseif($column.htmlType == "select" && "" != $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "select" && $dictType)
+
+
+
+
+
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+
+
+
+ {{dict.label}}
+
+
+
+#elseif($column.htmlType == "checkbox" && $dictType)
+
+
+ 请选择字典生成
+
+
+#elseif($column.htmlType == "radio" && "" != $dictType)
+
+
+ {{dict.label}}
+
+
+#elseif($column.htmlType == "radio" && $dictType)
+
+
+ 请选择字典生成
+
+
+#elseif($column.htmlType == "datetime")
+
+
+
+
+#elseif($column.htmlType == "textarea")
+
+
+
+#end
+#end
+#end
+#end
+#if($table.sub)
+ ${subTable.functionName}信息
+
+
+ 添加
+
+
+ 删除
+
+
+
+
+
+#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)
+
+
+
+
+
+#end
+#end
+
+#end
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/readme.txt b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/readme.txt
new file mode 100644
index 00000000..10362d62
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/v3/readme.txt
@@ -0,0 +1 @@
+ʹõRuoYi-Cloud-Vue3ǰˣôҪһ´Ŀ¼ģindex.vue.vmindex-tree.vue.vmļϼvueĿ¼
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
index 4e1c94c2..6e157638 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
@@ -4,8 +4,8 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
-
import com.ruoyi.common.core.web.domain.BaseEntity;
+import com.ruoyi.common.core.xss.Xss;
/**
* 通知公告表 sys_notice
@@ -46,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-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
index c397aa54..19d40a05 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ b/ruoyi-modules/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;
@@ -13,6 +14,7 @@ import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.SpringUtils;
import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.core.utils.bean.BeanValidators;
import com.ruoyi.common.datascope.annotation.DataScope;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysRole;
@@ -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++;
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
index a4961db2..4e209e16 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -55,8 +55,8 @@
"vue": "2.6.12",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
- "vue-router": "3.4.9",
"vue-meta": "2.4.0",
+ "vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
},
@@ -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/components/Crontab/index.vue b/ruoyi-ui/src/components/Crontab/index.vue
index bd863b1b..3963df28 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 ae389a7a..1cec700e 100644
--- a/ruoyi-ui/src/components/Crontab/week.vue
+++ b/ruoyi-ui/src/components/Crontab/week.vue
@@ -60,7 +60,7 @@
指定
- {{item.value}}
+ {{item.value}}
diff --git a/ruoyi-ui/src/components/ImagePreview/index.vue b/ruoyi-ui/src/components/ImagePreview/index.vue
new file mode 100644
index 00000000..44e27aac
--- /dev/null
+++ b/ruoyi-ui/src/components/ImagePreview/index.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
index 729467ae..ebd94b9d 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)
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
index c1fcfc14..65099a24 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' // 设定路由的名字,一定要填写不然使用时会出现各种问题
* query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
+ * roles: ['admin', 'common'] // 访问路由的角色权限
+ * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
* meta : {
noCache: true // 如果设置为true,则不会被 缓存(默认 false)
title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
@@ -35,28 +37,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 +68,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,20 +82,25 @@ 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' }
}
]
- },
+ }
+]
+
+// 动态路由,基于用户权限动态去加载
+export const dynamicRoutes = [
{
path: '/system/user-auth',
component: Layout,
hidden: true,
+ permissions: ['system:user:edit'],
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' }
}
@@ -103,10 +110,11 @@ export const constantRoutes = [
path: '/system/role-auth',
component: Layout,
hidden: true,
+ permissions: ['system:role:edit'],
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' }
}
@@ -116,10 +124,11 @@ export const constantRoutes = [
path: '/system/dict-data',
component: Layout,
hidden: true,
+ permissions: ['system:dict:list'],
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' }
}
@@ -129,10 +138,11 @@ export const constantRoutes = [
path: '/monitor/job-log',
component: Layout,
hidden: true,
+ permissions: ['monitor:job:list'],
children: [
{
path: 'index',
- component: (resolve) => require(['@/views/monitor/job/log'], resolve),
+ component: () => import('@/views/monitor/job/log'),
name: 'JobLog',
meta: { title: '调度日志', activeMenu: '/monitor/job' }
}
@@ -142,10 +152,11 @@ export const constantRoutes = [
path: '/tool/gen-edit',
component: Layout,
hidden: true,
+ permissions: ['tool:gen:edit'],
children: [
{
path: 'index',
- component: (resolve) => require(['@/views/tool/gen/editTable'], resolve),
+ component: () => import('@/views/tool/gen/editTable'),
name: 'GenEdit',
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
}
diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js
index 2c2120a8..8c3c3390 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)
diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue
index f203e692..7fb1c7b6 100644
--- a/ruoyi-ui/src/views/system/menu/index.vue
+++ b/ruoyi-ui/src/views/system/menu/index.vue
@@ -128,7 +128,7 @@
-
+
" + response.msg + "", "导入结果", { dangerouslyUseHTMLString: true });
this.getList();
},
// 提交上传文件
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
index 76707460..36cd2025 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: {
diff --git a/sql/ry_20210908.sql b/sql/ry_20210908.sql
index e1efcb45..d01ecea5 100644
--- a/sql/ry_20210908.sql
+++ b/sql/ry_20210908.sql
@@ -1,3 +1,5 @@
+SET NAMES utf8mb4;
+
-- ----------------------------
-- 1、部门表
-- ----------------------------