90 Commits

Author SHA1 Message Date
5e64a93d11 若依 3.5.0 2021-05-25 09:37:55 +08:00
4aabf5d8be Redis设置HashKey序列化 2021-05-24 15:10:55 +08:00
cf6254a8d5 用户登录后记录最后登录IP&时间 2021-05-24 14:21:29 +08:00
883cff5de9 新增IE浏览器版本过低提示页面 2021-05-24 14:15:41 +08:00
7e79c4f249 生成vue模板导出按钮点击后添加遮罩 2021-05-24 11:34:03 +08:00
504638eb41 !234 【轻量级 PR】:删去两处冗余代码
Merge pull request !234 from xivLi/master
2021-05-24 11:30:21 +08:00
2adac4a899 升级fastjson到最新版1.2.76 2021-05-24 11:25:17 +08:00
56a943bf48 升级druid到最新版本v1.2.6 2021-05-24 11:24:54 +08:00
77ebca264a 修复请求形参未传值记录日志异常问题 2021-05-23 19:22:30 +08:00
7b94ae3a9a xss校验json条件优化 2021-05-23 19:20:36 +08:00
bd1edc6dcc !233 修正方法名单词拼写错误
Merge pull request !233 from lyqwer/N/A
2021-05-23 17:15:18 +08:00
09d166e97d !231 修正注释
Merge pull request !231 from 刘立伟/N/A
2021-05-23 17:14:52 +08:00
f3e5d908d6 quartz模块下 domain包中的 SysJob类不需要实现Serializable接口 2021-05-22 16:05:12 +08:00
9651a7d7fc 删去utils.uuid下 IdUtils类中 多余的import(同包下的UUID类) 2021-05-22 15:52:19 +08:00
b2914cbcb1 修正方法名单词拼写错误 2021-05-21 17:24:48 +08:00
d0a4d6b111 修正注释 2021-05-18 10:21:48 +08:00
b431703262 导出按钮点击之后添加遮罩 2021-05-17 15:37:58 +08:00
99726be9ac 修正导入表权限标识 2021-05-11 14:26:20 +08:00
32f333a00e 删除操作日志记录日志 2021-05-11 14:25:39 +08:00
be5c19b764 树级结构更新子节点使用replaceFirst 2021-05-11 14:25:25 +08:00
dd384e4a31 上传媒体类型添加视频格式 2021-05-11 14:25:08 +08:00
bdde195e2b !225 【bug修复】文件上传时出现java.nio.file.FileAlreadyExistsException
Merge pull request !225 from CANYON/master
2021-05-11 14:19:53 +08:00
14ea071306 修复文件上传时java.nio.file.FileAlreadyExistsException 2021-05-08 15:31:16 +08:00
50034301ac 添加新群号:201396349 2021-05-06 20:40:25 +08:00
85ed712c50 !222 update ruoyi-ui/src/assets/styles/element-ui.scss.
Merge pull request !222 from leizhuogogo/N/A
2021-05-06 20:39:36 +08:00
f67d682345 !221 update ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java.
Merge pull request !221 from phper08/N/A
2021-05-06 20:39:26 +08:00
3f1427eef9 update ruoyi-ui/src/assets/styles/element-ui.scss. 2021-05-06 17:50:28 +08:00
7d0f5e94ef update ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java. 2021-05-03 13:18:33 +08:00
62081aebb9 修复开启TopNav后,左侧打开外链问题 2021-04-21 16:34:44 +08:00
3f07632cd4 修复一级菜单包屑显示重复问题 2021-04-21 15:14:36 +08:00
2c94587263 优化ExcelUtil空值处理 2021-04-21 09:53:14 +08:00
2575c17f47 主题颜色保存配置 2021-04-19 16:59:56 +08:00
b6f13c546b 过滤BindingResult对象,防止异常 2021-04-18 21:54:53 +08:00
e60a69b670 兼容顶部栏一级菜单内部跳转 2021-04-18 18:33:13 +08:00
cb18eec802 修正模板字符编码 2021-04-18 15:45:49 +08:00
bef080c60a 升级mybatis到最新版3.5.6 阻止远程代码执行漏洞 2021-04-18 15:45:37 +08:00
de73cf300b 优化树表代码生成模板 2021-04-15 10:39:09 +08:00
cbcee86d2c 优化树表代码生成模板 2021-04-15 10:37:22 +08:00
cc50224d90 固定顶部导航栏&窗口大小改变实时更新栏数 2021-04-14 11:01:16 +08:00
ff09e1cf55 数据监控默认地址修改 2021-04-13 18:15:11 +08:00
fe2ccbdc1b 优化代码生成导出模板名称 2021-04-13 14:49:42 +08:00
c8df1f5e1f 布局设置支持保存&重置配置 2021-04-13 09:47:28 +08:00
e71c00e6fa 富文本编辑器支持自定义上传地址 2021-04-13 09:38:32 +08:00
dcb9839596 !209 导出 Excel 工作表的名称 由 ${businessName} 更改为 ${functionName}
Merge pull request !209 from lihy2021/N/A
2021-04-13 09:36:49 +08:00
f13b6d92d2 !205 富文本编辑器自定义上传地址
Merge pull request !205 from hechieh/N/A
2021-04-13 09:36:42 +08:00
6595c68df1 导出 Excel 工作表的名称 由 ${businessName} 更改为 ${functionName} 2021-04-12 14:52:14 +08:00
5a2a0c09b6 优化主子表代码生成 2021-04-12 13:26:54 +08:00
9aac65ff32 新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单) 2021-04-12 09:54:08 +08:00
5f2350569a 页签新增关闭右侧 2021-04-10 21:15:45 +08:00
ccf05b697d 富文本编辑器自定义上传地址 2021-04-10 17:08:49 +08:00
6810243ab7 修复树表数据显示不全&加载慢问题 2021-04-09 08:31:13 +08:00
b56b8846d9 修改主题后mini类型按钮无效问题 2021-04-08 13:54:48 +08:00
8e1e4cd8fe 通用下载完成后删除节点 2021-04-08 13:46:22 +08:00
9fa5c79713 !200 update ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java.
Merge pull request !200 from yvan7123/N/A
2021-04-08 13:42:30 +08:00
40a72c2b7e !199 规范命名、用户角色单个逻辑删除、去除多余代码
Merge pull request !199 from fuzui/some_problems
2021-04-08 13:40:28 +08:00
6fe9a358b7 update ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java. 2021-04-06 11:47:27 +08:00
9f6bc13e64 🔥 去除多余代码 2021-04-02 23:06:48 +08:00
ba5ab4b091 用户、角色单条删除时,使其逻辑删除 2021-04-02 22:49:19 +08:00
17407d0127 调整cache_repeat_key为驼峰格式 2021-04-02 22:40:15 +08:00
30f330f4a0 修复firefox下表单构建拖拽会新打卡一个选项卡 2021-03-30 17:45:35 +08:00
6ca7870393 修正注释 2021-03-30 15:30:18 +08:00
2a7342ec43 !195 读取excel增加非空判断
Merge pull request !195 from 叫我宏锅锅/yuhong
2021-03-30 15:23:04 +08:00
fc57e91b80 !196 RepeatedlyRequestWrapper.ServletInputStream 实现available方法
Merge pull request !196 from wangyang/master
2021-03-30 15:17:34 +08:00
347f36ceff fix:RepeatedlyRequestWrapper.ServletInputStream 实现available方法 2021-03-29 10:17:31 +08:00
9b9c1b999f 读取excel增加
if(row == null)
{
    continue;
}
判断。防止有时候Excel表中有空数据行,导致读取时出现空指针异常。
2021-03-29 09:00:44 +08:00
ec627704b2 取消 2021-03-29 08:58:46 +08:00
9e6b2a1265 读取excel增加
if(row == null)
{
    continue;
}
判断。防止有时候Excel表中有空数据行,导致读取时出现空指针异常。
2021-03-29 08:56:51 +08:00
266a5e844f !193 修复request.getInputStream() 重复读取错误问题
Merge pull request !193 from MccRay/master
2021-03-27 13:22:01 +08:00
0822680158 update ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java.
修复 getInputStream() has already been called for this request异常问题
2021-03-25 17:39:51 +08:00
090e258bf9 显隐列初始默认隐藏列 2021-03-24 15:46:37 +08:00
505fa06dc3 !192 update ruoyi-ui/src/views/system/user/profile/userAvatar.vue.
Merge pull request !192 from 谢凯/N/A
2021-03-24 15:32:24 +08:00
6cf53bfacb !191 update ruoyi-ui/src/views/system/user/profile/userAvatar.vue.
Merge pull request !191 from allworldg/N/A
2021-03-24 15:31:51 +08:00
881dc3fcf0 update ruoyi-ui/src/views/system/user/profile/userAvatar.vue. 2021-03-22 17:52:34 +08:00
b65c8d4512 update ruoyi-ui/src/views/system/user/profile/userAvatar.vue. 2021-03-21 21:20:23 +08:00
67371a9028 个人信息添加手机&邮箱重复验证 2021-03-21 08:53:11 +08:00
01b545e4ab 通用Controller添加响应返回消息 2021-03-16 14:43:55 +08:00
c2e9200626 数据监控默认账户密码防止越权访问 2021-03-14 16:37:34 +08:00
9502203bbe !187 【漏洞修复】升级commons-collections版本,解决3.2.1版本的反序列化漏洞问题
Merge pull request !187 from Delusive/master
2021-03-14 16:32:07 +08:00
c0f1569ad9 修复commons-collections引起的反序列化漏洞 2021-03-12 16:59:06 +08:00
61432480c8 删除多余的代码 2021-03-07 11:06:47 +08:00
78deee063d !180 富文本编辑组件支持只读
Merge pull request !180 from JOSWAY/master
2021-03-07 10:44:04 +08:00
4ad003649e !182 解决 Byte[] 类型 to string 死循环的问题
Merge pull request !182 from sproutcat/master
2021-03-07 10:39:41 +08:00
616f5a6aca !185 update ruoyi-ui/src/views/monitor/logininfor/index.vue.
Merge pull request !185 from asher/N/A
2021-03-07 10:39:30 +08:00
fea3ff7b2a !184 update ruoyi-ui/src/views/monitor/operlog/index.vue.
Merge pull request !184 from asher/N/A
2021-03-07 10:39:22 +08:00
f938a24df0 update ruoyi-ui/src/views/monitor/logininfor/index.vue. 2021-03-04 17:00:07 +08:00
45fa686a64 update ruoyi-ui/src/views/monitor/operlog/index.vue. 2021-03-04 16:58:18 +08:00
0d8c3b4940 升级oshi到最新版本v5.6.0 2021-03-03 13:53:03 +08:00
64e807f27b 添加新群号:186866453 2021-02-24 13:45:24 +08:00
tzg
9a384a2fc2 解决 Byte[] 类型 to string 死循环的问题 2021-02-23 16:30:14 +08:00
339b932a3d 富文本编辑组件支持只读 2021-02-22 17:49:17 +08:00
79 changed files with 1973 additions and 1258 deletions

View File

@ -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群 [![加入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) 点击按钮入群。

34
pom.xml
View File

@ -6,28 +6,30 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.4.0</version> <version>3.5.0</version>
<name>ruoyi</name> <name>ruoyi</name>
<url>http://www.ruoyi.vip</url> <url>http://www.ruoyi.vip</url>
<description>若依管理系统</description> <description>若依管理系统</description>
<properties> <properties>
<ruoyi.version>3.4.0</ruoyi.version> <ruoyi.version>3.5.0</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<druid.version>1.2.4</druid.version> <druid.version>1.2.6</druid.version>
<bitwalker.version>1.21</bitwalker.version> <bitwalker.version>1.21</bitwalker.version>
<swagger.version>2.9.2</swagger.version> <swagger.version>2.9.2</swagger.version>
<kaptcha.version>2.3.2</kaptcha.version> <kaptcha.version>2.3.2</kaptcha.version>
<mybatis-spring-boot.version>2.1.4</mybatis-spring-boot.version>
<pagehelper.boot.version>1.3.0</pagehelper.boot.version> <pagehelper.boot.version>1.3.0</pagehelper.boot.version>
<fastjson.version>1.2.75</fastjson.version> <fastjson.version>1.2.76</fastjson.version>
<oshi.version>5.3.6</oshi.version> <oshi.version>5.6.0</oshi.version>
<jna.version>5.6.0</jna.version> <jna.version>5.7.0</jna.version>
<commons.io.version>2.5</commons.io.version> <commons.io.version>2.5</commons.io.version>
<commons.fileupload.version>1.3.3</commons.fileupload.version> <commons.fileupload.version>1.3.3</commons.fileupload.version>
<commons.collections.version>3.2.2</commons.collections.version>
<poi.version>4.1.2</poi.version> <poi.version>4.1.2</poi.version>
<velocity.version>1.7</velocity.version> <velocity.version>1.7</velocity.version>
<jwt.version>0.9.1</jwt.version> <jwt.version>0.9.1</jwt.version>
@ -60,6 +62,13 @@
<version>${bitwalker.version}</version> <version>${bitwalker.version}</version>
</dependency> </dependency>
<!-- SpringBoot集成mybatis框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot.version}</version>
</dependency>
<!-- pagehelper 分页插件 --> <!-- pagehelper 分页插件 -->
<dependency> <dependency>
<groupId>com.github.pagehelper</groupId> <groupId>com.github.pagehelper</groupId>
@ -136,6 +145,19 @@
<groupId>org.apache.velocity</groupId> <groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId> <artifactId>velocity</artifactId>
<version>${velocity.version}</version> <version>${velocity.version}</version>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- collections工具类 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons.collections.version}</version>
</dependency> </dependency>
<!-- 阿里JSON解析器 --> <!-- 阿里JSON解析器 -->

View File

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

View File

@ -48,6 +48,7 @@ public class SysOperlogController extends BaseController
return util.exportExcel(list, "操作日志"); return util.exportExcel(list, "操作日志");
} }
@Log(title = "操作日志", businessType = BusinessType.DELETE)
@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')") @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
@DeleteMapping("/{operIds}") @DeleteMapping("/{operIds}")
public AjaxResult remove(@PathVariable Long[] operIds) public AjaxResult remove(@PathVariable Long[] operIds)

View File

@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
@ -19,6 +20,7 @@ import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUploadUtils; import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.framework.web.service.TokenService; import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysUserService; import com.ruoyi.system.service.ISysUserService;
@ -59,6 +61,16 @@ public class SysProfileController extends BaseController
@PutMapping @PutMapping
public AjaxResult updateProfile(@RequestBody SysUser user) public AjaxResult updateProfile(@RequestBody SysUser user)
{ {
if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
}
if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
if (userService.updateUserProfile(user) > 0) if (userService.updateUserProfile(user) > 0)
{ {
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());

View File

@ -43,8 +43,8 @@ spring:
allow: allow:
url-pattern: /druid/* url-pattern: /druid/*
# 控制台管理用户名和密码 # 控制台管理用户名和密码
login-username: login-username: ruoyi
login-password: login-password: 123456
filter: filter:
stat: stat:
enabled: true enabled: true

View File

@ -3,7 +3,7 @@ ruoyi:
# 名称 # 名称
name: RuoYi name: RuoYi
# 版本 # 版本
version: 3.4.0 version: 3.5.0
# 版权年份 # 版权年份
copyrightYear: 2021 copyrightYear: 2021
# 实例演示开关 # 实例演示开关

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.4.0</version> <version>3.5.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -25,7 +25,7 @@ import com.ruoyi.common.utils.sql.SqlUtil;
*/ */
public class BaseController public class BaseController
{ {
protected final Logger logger = LoggerFactory.getLogger(BaseController.class); protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/** /**
* 将前台传递过来的日期格式的字符串自动转化为Date类型 * 将前台传递过来的日期格式的字符串自动转化为Date类型
@ -84,6 +84,49 @@ public class BaseController
return rows > 0 ? AjaxResult.success() : AjaxResult.error(); return rows > 0 ? AjaxResult.success() : AjaxResult.error();
} }
/**
* 响应返回结果
*
* @param result 结果
* @return 操作结果
*/
protected AjaxResult toAjax(boolean result)
{
return result ? success() : error();
}
/**
* 返回成功
*/
public AjaxResult success()
{
return AjaxResult.success();
}
/**
* 返回失败消息
*/
public AjaxResult error()
{
return AjaxResult.error();
}
/**
* 返回成功消息
*/
public AjaxResult success(String message)
{
return AjaxResult.success(message);
}
/**
* 返回失败消息
*/
public AjaxResult error(String message)
{
return AjaxResult.error(message);
}
/** /**
* 页面跳转 * 页面跳转
*/ */

View File

@ -7,6 +7,7 @@ import java.nio.charset.Charset;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Set; import java.util.Set;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
/** /**
* 类型转换器 * 类型转换器
@ -795,9 +796,14 @@ public class Convert
{ {
return (String) obj; return (String) obj;
} }
else if (obj instanceof byte[] || obj instanceof Byte[]) else if (obj instanceof byte[])
{ {
return str((Byte[]) obj, charset); return str((byte[]) obj, charset);
}
else if (obj instanceof Byte[])
{
byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);
return str(bytes, charset);
} }
else if (obj instanceof ByteBuffer) else if (obj instanceof ByteBuffer)
{ {

View File

@ -68,4 +68,14 @@ public class InvalidExtensionException extends FileUploadException
super(allowedExtension, extension, filename); super(allowedExtension, extension, filename);
} }
} }
public static class InvalidVideoExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
} }

View File

@ -30,7 +30,7 @@ public class RepeatableFilter implements Filter
{ {
ServletRequest requestWrapper = null; ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest if (request instanceof HttpServletRequest
&& StringUtils.equalsAnyIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE))
{ {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
} }

View File

@ -38,18 +38,21 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
@Override @Override
public ServletInputStream getInputStream() throws IOException public ServletInputStream getInputStream() throws IOException
{ {
final ByteArrayInputStream bais = new ByteArrayInputStream(body); final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() return new ServletInputStream()
{ {
@Override @Override
public int read() throws IOException public int read() throws IOException
{ {
return bais.read(); return bais.read();
} }
@Override
public int available() throws IOException
{
return body.length;
}
@Override @Override
public boolean isFinished() public boolean isFinished()
{ {

View File

@ -99,6 +99,6 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
public boolean isJsonRequest() public boolean isJsonRequest()
{ {
String header = super.getHeader(HttpHeaders.CONTENT_TYPE); String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
return MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(header); return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
} }
} }

View File

@ -108,7 +108,7 @@ public class Arith
"The scale must be a positive integer or zero"); "The scale must be a positive integer or zero");
} }
BigDecimal b = new BigDecimal(Double.toString(v)); BigDecimal b = new BigDecimal(Double.toString(v));
BigDecimal one = new BigDecimal("1"); BigDecimal one = BigDecimal.ONE;
return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue(); return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
} }
} }

View File

@ -22,7 +22,7 @@ public class ExceptionUtil
return str; return str;
} }
public static String getRootErrorMseeage(Exception e) public static String getRootErrorMessage(Exception e)
{ {
Throwable root = ExceptionUtils.getRootCause(e); Throwable root = ExceptionUtils.getRootCause(e);
root = (root == null ? e : root); root = (root == null ? e : root);

View File

@ -312,7 +312,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
} }
/** /**
* 下划线转驼峰命名 * 驼峰转下划线命名
*/ */
public static String toUnderScoreCase(String str) public static String toUnderScoreCase(String str)
{ {

View File

@ -131,13 +131,12 @@ public class FileUploadUtils
{ {
File desc = new File(uploadDir + File.separator + fileName); File desc = new File(uploadDir + File.separator + fileName);
if (!desc.exists())
{
if (!desc.getParentFile().exists()) if (!desc.getParentFile().exists())
{ {
desc.getParentFile().mkdirs(); desc.getParentFile().mkdirs();
} }
if (!desc.exists())
{
desc.createNewFile();
} }
return desc; return desc;
} }
@ -186,6 +185,11 @@ public class FileUploadUtils
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
fileName); fileName);
} }
else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
{
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
fileName);
}
else else
{ {
throw new InvalidExtensionException(allowedExtension, extension, fileName); throw new InvalidExtensionException(allowedExtension, extension, fileName);

View File

@ -24,6 +24,8 @@ public class MimeTypeUtils
public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
"asf", "rm", "rmvb" }; "asf", "rm", "rmvb" };
public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" };
public static final String[] DEFAULT_ALLOWED_EXTENSION = { public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片 // 图片
"bmp", "gif", "jpg", "jpeg", "png", "bmp", "gif", "jpg", "jpeg", "png",
@ -31,6 +33,8 @@ public class MimeTypeUtils
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件 // 压缩文件
"rar", "zip", "gz", "bz2", "rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf // pdf
"pdf" }; "pdf" };

View File

@ -22,7 +22,7 @@ public class EscapeUtil
// special HTML characters // special HTML characters
TEXT['\''] = "&#039;".toCharArray(); // 单引号 TEXT['\''] = "&#039;".toCharArray(); // 单引号
TEXT['"'] = "&#34;".toCharArray(); // 引号 TEXT['"'] = "&#34;".toCharArray(); // 引号
TEXT['&'] = "&#38;".toCharArray(); // &符 TEXT['&'] = "&#38;".toCharArray(); // &符
TEXT['<'] = "&#60;".toCharArray(); // 小于号 TEXT['<'] = "&#60;".toCharArray(); // 小于号
TEXT['>'] = "&#62;".toCharArray(); // 大于号 TEXT['>'] = "&#62;".toCharArray(); // 大于号

View File

@ -229,6 +229,10 @@ public class ExcelUtil<T>
{ {
// 从第2行开始取数据,默认第一行是表头. // 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i); Row row = sheet.getRow(i);
if(row == null)
{
continue;
}
T entity = null; T entity = null;
for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet()) for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet())
{ {
@ -536,9 +540,12 @@ public class ExcelUtil<T>
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
} }
else if (ColumnType.NUMERIC == attr.cellType()) else if (ColumnType.NUMERIC == attr.cellType())
{
if (StringUtils.isNotNull(value))
{ {
cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
} }
}
else if (ColumnType.IMAGE == attr.cellType()) else if (ColumnType.IMAGE == attr.cellType())
{ {
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),

View File

@ -1,7 +1,5 @@
package com.ruoyi.common.utils.uuid; package com.ruoyi.common.utils.uuid;
import com.ruoyi.common.utils.uuid.UUID;
/** /**
* ID生成器工具类 * ID生成器工具类
* *

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.4.0</version> <version>3.5.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -16,6 +16,7 @@ import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
@ -196,7 +197,7 @@ public class LogAspect
{ {
for (int i = 0; i < paramsArray.length; i++) for (int i = 0; i < paramsArray.length; i++)
{ {
if (!isFilterObject(paramsArray[i])) if (StringUtils.isNotNull(paramsArray[i]) && !isFilterObject(paramsArray[i]))
{ {
Object jsonObj = JSON.toJSON(paramsArray[i]); Object jsonObj = JSON.toJSON(paramsArray[i]);
params += jsonObj.toString() + " "; params += jsonObj.toString() + " ";
@ -237,6 +238,7 @@ public class LogAspect
return entry.getValue() instanceof MultipartFile; return entry.getValue() instanceof MultipartFile;
} }
} }
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse; return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
|| o instanceof BindingResult;
} }
} }

View File

@ -36,9 +36,14 @@ public class RedisConfig extends CachingConfigurerSupport
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
serializer.setObjectMapper(mapper); serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
// 使用StringRedisSerializer来序列化和反序列化redis的key值 // 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer()); template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet(); template.afterPropertiesSet();
return template; return template;
} }

View File

@ -78,9 +78,9 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
} }
// 唯一标识指定key + 消息头) // 唯一标识指定key + 消息头)
String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey; String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + submitKey;
Object sessionObj = redisCache.getCacheObject(cache_repeat_key); Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
if (sessionObj != null) if (sessionObj != null)
{ {
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj; Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
@ -95,7 +95,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
} }
Map<String, Object> cacheMap = new HashMap<String, Object>(); Map<String, Object> cacheMap = new HashMap<String, Object>();
cacheMap.put(url, nowDataMap); cacheMap.put(url, nowDataMap);
redisCache.setCacheObject(cache_repeat_key, cacheMap, intervalTime, TimeUnit.SECONDS); redisCache.setCacheObject(cacheRepeatKey, cacheMap, intervalTime, TimeUnit.SECONDS);
return false; return false;
} }

View File

@ -8,15 +8,20 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.CustomException; import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.exception.user.CaptchaException; import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException; import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException; import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory; import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.system.service.ISysUserService;
/** /**
* 登录校验方法 * 登录校验方法
@ -35,6 +40,9 @@ public class SysLoginService
@Autowired @Autowired
private RedisCache redisCache; private RedisCache redisCache;
@Autowired
private ISysUserService userService;
/** /**
* 登录验证 * 登录验证
* *
@ -82,7 +90,18 @@ public class SysLoginService
} }
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
LoginUser loginUser = (LoginUser) authentication.getPrincipal(); LoginUser loginUser = (LoginUser) authentication.getPrincipal();
recordLoginInfo(loginUser.getUser());
// 生成token // 生成token
return tokenService.createToken(loginUser); return tokenService.createToken(loginUser);
} }
/**
* 记录登录信息
*/
public void recordLoginInfo(SysUser user)
{
user.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
user.setLoginDate(DateUtils.getNowDate());
userService.updateUserProfile(user);
}
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.4.0</version> <version>3.5.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -23,6 +23,12 @@
<artifactId>velocity</artifactId> <artifactId>velocity</artifactId>
</dependency> </dependency>
<!-- collections工具类 -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</dependency>
<!-- 通用工具--> <!-- 通用工具-->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>

View File

@ -101,7 +101,7 @@ public class GenController extends BaseController
/** /**
* 导入表结构(保存) * 导入表结构(保存)
*/ */
@PreAuthorize("@ss.hasPermi('tool:gen:list')") @PreAuthorize("@ss.hasPermi('tool:gen:import')")
@Log(title = "代码生成", businessType = BusinessType.IMPORT) @Log(title = "代码生成", businessType = BusinessType.IMPORT)
@PostMapping("/importTable") @PostMapping("/importTable")
public AjaxResult importTableSave(String tables) public AjaxResult importTableSave(String tables)

View File

@ -22,7 +22,7 @@ public class VelocityInitializer
// 加载classpath目录下的vm文件 // 加载classpath目录下的vm文件
p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
// 定义字符集 // 定义字符集
p.setProperty(Velocity.ENCODING_DEFAULT, Constants.UTF8); p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
p.setProperty(Velocity.OUTPUT_ENCODING, Constants.UTF8); p.setProperty(Velocity.OUTPUT_ENCODING, Constants.UTF8);
// 初始化Velocity引擎指定配置Properties // 初始化Velocity引擎指定配置Properties
Velocity.init(p); Velocity.init(p);

View File

@ -66,7 +66,7 @@ public class ${ClassName}Controller extends BaseController
{ {
List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
return util.exportExcel(list, "${businessName}"); return util.exportExcel(list, "${functionName}数据");
} }
/** /**

View File

@ -83,7 +83,7 @@ public interface ${ClassName}Mapper
/** /**
* 通过${functionName}ID删除${subTable.functionName}信息 * 通过${functionName}ID删除${subTable.functionName}信息
* *
* @param roleId 角色ID * @param ${pkColumn.javaField} ${functionName}ID
* @return 结果 * @return 结果
*/ */
public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField}); public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});

View File

@ -108,8 +108,12 @@
#elseif($column.list && "" != $column.dictType) #elseif($column.list && "" != $column.dictType)
<el-table-column label="${comment}" align="center" prop="${javaField}" :formatter="${javaField}Format" /> <el-table-column label="${comment}" align="center" prop="${javaField}" :formatter="${javaField}Format" />
#elseif($column.list && "" != $javaField) #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}" /> <el-table-column label="${comment}" align="center" prop="${javaField}" />
#end #end
#end
#end #end
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope"> <template slot-scope="scope">
@ -120,6 +124,13 @@
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${moduleName}:${businessName}:edit']"
>修改</el-button> >修改</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-plus"
@click="handleAdd(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button>
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
@ -394,7 +405,7 @@ export default {
children: node.children children: node.children
}; };
}, },
/** 查询部门下拉树结构 */ /** 查询${functionName}下拉树结构 */
getTreeselect() { getTreeselect() {
list${BusinessName}().then(response => { list${BusinessName}().then(response => {
this.${businessName}Options = []; this.${businessName}Options = [];
@ -456,9 +467,14 @@ export default {
this.handleQuery(); this.handleQuery();
}, },
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd(row) {
this.reset(); this.reset();
this.getTreeselect(); this.getTreeselect();
if (row != null && row.${treeCode}) {
this.form.${treeParentCode} = row.${treeCode};
} else {
this.form.${treeParentCode} = 0;
}
this.open = true; this.open = true;
this.title = "添加${functionName}"; this.title = "添加${functionName}";
}, },

View File

@ -108,6 +108,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['${moduleName}:${businessName}:export']" v-hasPermi="['${moduleName}:${businessName}:export']"
>导出</el-button> >导出</el-button>
@ -354,6 +355,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
#if($table.sub) #if($table.sub)
@ -630,10 +633,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return export${BusinessName}(queryParams); return export${BusinessName}(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -12,12 +12,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#if($table.sub) #if($table.sub)
<resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result"> <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
<collection property="${subclassName}List" notNullColumn="${subTable.pkColumn.columnName}" javaType="java.util.List" resultMap="${subClassName}Result" /> <collection property="${subclassName}List" notNullColumn="sub_${subTable.pkColumn.columnName}" javaType="java.util.List" resultMap="${subClassName}Result" />
</resultMap> </resultMap>
<resultMap type="${subClassName}" id="${subClassName}Result"> <resultMap type="${subClassName}" id="${subClassName}Result">
#foreach ($column in $subTable.columns) #foreach ($column in $subTable.columns)
<result property="${column.javaField}" column="${column.columnName}" /> <result property="${column.javaField}" column="sub_${column.columnName}" />
#end #end
</resultMap> </resultMap>
#end #end
@ -64,7 +64,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where ${pkColumn.columnName} = #{${pkColumn.javaField}} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
#elseif($table.sub) #elseif($table.sub)
select#foreach($column in $columns) a.$column.columnName#if($velocityCount != $columns.size()),#end#end, select#foreach($column in $columns) a.$column.columnName#if($velocityCount != $columns.size()),#end#end,
#foreach($column in $subTable.columns) b.$column.columnName#if($velocityCount != $subTable.columns.size()),#end#end #foreach($column in $subTable.columns) b.$column.columnName as sub_$column.columnName#if($velocityCount != $subTable.columns.size()),#end#end
from ${tableName} a from ${tableName} a
left join ${subTableName} b on b.${subTableFkName} = a.${pkColumn.columnName} left join ${subTableName} b on b.${subTableFkName} = a.${pkColumn.columnName}

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.4.0</version> <version>3.5.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,6 +1,5 @@
package com.ruoyi.quartz.domain; package com.ruoyi.quartz.domain;
import java.io.Serializable;
import java.util.Date; import java.util.Date;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size; import javax.validation.constraints.Size;
@ -19,7 +18,7 @@ import com.ruoyi.quartz.util.CronUtils;
* *
* @author ruoyi * @author ruoyi
*/ */
public class SysJob extends BaseEntity implements Serializable public class SysJob extends BaseEntity
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.4.0</version> <version>3.5.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -241,7 +241,7 @@ public class SysDeptServiceImpl implements ISysDeptService
List<SysDept> children = deptMapper.selectChildrenDeptById(deptId); List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
for (SysDept child : children) for (SysDept child : children)
{ {
child.setAncestors(child.getAncestors().replace(oldAncestors, newAncestors)); child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
} }
if (children.size() > 0) if (children.size() > 0)
{ {

View File

@ -158,8 +158,9 @@ public class SysMenuServiceImpl implements ISysMenuService
router.setRedirect("noRedirect"); router.setRedirect("noRedirect");
router.setChildren(buildMenus(cMenus)); router.setChildren(buildMenus(cMenus));
} }
else if (isMeunFrame(menu)) else if (isMenuFrame(menu))
{ {
router.setMeta(null);
List<RouterVo> childrenList = new ArrayList<RouterVo>(); List<RouterVo> childrenList = new ArrayList<RouterVo>();
RouterVo children = new RouterVo(); RouterVo children = new RouterVo();
children.setPath(menu.getPath()); children.setPath(menu.getPath());
@ -321,7 +322,7 @@ public class SysMenuServiceImpl implements ISysMenuService
{ {
String routerName = StringUtils.capitalize(menu.getPath()); String routerName = StringUtils.capitalize(menu.getPath());
// 非外链并且是一级目录(类型为目录) // 非外链并且是一级目录(类型为目录)
if (isMeunFrame(menu)) if (isMenuFrame(menu))
{ {
routerName = StringUtils.EMPTY; routerName = StringUtils.EMPTY;
} }
@ -344,7 +345,7 @@ public class SysMenuServiceImpl implements ISysMenuService
routerPath = "/" + menu.getPath(); routerPath = "/" + menu.getPath();
} }
// 非外链并且是一级目录(类型为菜单) // 非外链并且是一级目录(类型为菜单)
else if (isMeunFrame(menu)) else if (isMenuFrame(menu))
{ {
routerPath = "/"; routerPath = "/";
} }
@ -360,7 +361,7 @@ public class SysMenuServiceImpl implements ISysMenuService
public String getComponent(SysMenu menu) public String getComponent(SysMenu menu)
{ {
String component = UserConstants.LAYOUT; String component = UserConstants.LAYOUT;
if (StringUtils.isNotEmpty(menu.getComponent()) && !isMeunFrame(menu)) if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu))
{ {
component = menu.getComponent(); component = menu.getComponent();
} }
@ -377,7 +378,7 @@ public class SysMenuServiceImpl implements ISysMenuService
* @param menu 菜单信息 * @param menu 菜单信息
* @return 结果 * @return 结果
*/ */
public boolean isMeunFrame(SysMenu menu) public boolean isMenuFrame(SysMenu menu)
{ {
return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType()) return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType())
&& menu.getIsFrame().equals(UserConstants.NO_FRAME); && menu.getIsFrame().equals(UserConstants.NO_FRAME);

View File

@ -135,12 +135,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where role_id = #{roleId} where role_id = #{roleId}
</update> </update>
<update id="updateRoleStatus" parameterType="SysRole">
update sys_user set status = #{status} where user_id = #{userId}
</update>
<delete id="deleteRoleById" parameterType="Long"> <delete id="deleteRoleById" parameterType="Long">
delete from sys_role where role_id = #{roleId} update sys_role set del_flag = '2' where role_id = #{roleId}
</delete> </delete>
<delete id="deleteRoleByIds" parameterType="Long"> <delete id="deleteRoleByIds" parameterType="Long">

View File

@ -169,7 +169,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update> </update>
<delete id="deleteUserById" parameterType="Long"> <delete id="deleteUserById" parameterType="Long">
delete from sys_user where user_id = #{userId} update sys_user set del_flag = '2' where user_id = #{userId}
</delete> </delete>
<delete id="deleteUserByIds" parameterType="Long"> <delete id="deleteUserByIds" parameterType="Long">

View File

@ -1,6 +1,6 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "3.4.0", "version": "3.5.0",
"description": "若依管理系统", "description": "若依管理系统",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title> <title><%= webpackConfig.name %></title>
<!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
<style> <style>
html, html,
body, body,

View File

@ -82,3 +82,11 @@
.el-range-separator { .el-range-separator {
box-sizing: content-box; box-sizing: content-box;
} }
.el-menu--collapse
> div
> .el-submenu
> .el-submenu__title
.el-submenu__icon-arrow {
display: none;
}

View File

@ -106,7 +106,6 @@
} }
.el-table .fixed-width .el-button--mini { .el-table .fixed-width .el-button--mini {
color: #409EFF;
padding-left: 0; padding-left: 0;
padding-right: 0; padding-right: 0;
width: inherit; width: inherit;

View File

@ -135,9 +135,6 @@
margin-left: 20px; margin-left: 20px;
} }
.el-submenu__icon-arrow {
display: none;
}
} }
} }

View File

@ -1,5 +1,19 @@
<template> <template>
<div>
<el-upload
:action="uploadUrl"
:on-success="handleUploadSuccess"
:on-error="handleUploadError"
name="file"
:show-file-list="false"
:headers="headers"
style="display: none"
ref="upload"
v-if="this.uploadUrl"
>
</el-upload>
<div class="editor" ref="editor" :style="styles"></div> <div class="editor" ref="editor" :style="styles"></div>
</div>
</template> </template>
<script> <script>
@ -7,6 +21,7 @@ import Quill from "quill";
import "quill/dist/quill.core.css"; import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css"; import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css"; import "quill/dist/quill.bubble.css";
import { getToken } from "@/utils/auth";
export default { export default {
name: "Editor", name: "Editor",
@ -26,9 +41,22 @@ export default {
type: Number, type: Number,
default: null, default: null,
}, },
/* 只读 */
readOnly: {
type: Boolean,
default: false,
},
/* 上传地址 */
uploadUrl: {
type: String,
default: "",
}
}, },
data() { data() {
return { return {
headers: {
Authorization: "Bearer " + getToken()
},
Quill: null, Quill: null,
currentValue: "", currentValue: "",
options: { options: {
@ -47,11 +75,11 @@ export default {
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色 [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ align: [] }], // 对齐方式 [{ align: [] }], // 对齐方式
["clean"], // 清除文本格式 ["clean"], // 清除文本格式
["link", "image", "video"] // 链接、图片、视频 ["link", "image"] // 链接、图片
], ],
}, },
placeholder: "请输入内容", placeholder: "请输入内容",
readOnly: false, readOnly: this.readOnly,
}, },
}; };
}, },
@ -90,6 +118,26 @@ export default {
init() { init() {
const editor = this.$refs.editor; const editor = this.$refs.editor;
this.Quill = new Quill(editor, this.options); this.Quill = new Quill(editor, this.options);
// 如果设置了上传地址则自定义图片上传事件
if (this.uploadUrl) {
let toolbar = this.Quill.getModule("toolbar");
toolbar.addHandler("image", (value) => {
this.uploadType = "image";
if (value) {
this.$refs.upload.$children[0].$refs.input.click();
} else {
this.quill.format("image", false);
}
});
toolbar.addHandler("video", (value) => {
this.uploadType = "video";
if (value) {
this.$refs.upload.$children[0].$refs.input.click();
} else {
this.quill.format("video", false);
}
});
}
this.Quill.pasteHTML(this.currentValue); this.Quill.pasteHTML(this.currentValue);
this.Quill.on("text-change", (delta, oldDelta, source) => { this.Quill.on("text-change", (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML; const html = this.$refs.editor.children[0].innerHTML;
@ -109,6 +157,24 @@ export default {
this.$emit("on-editor-change", eventName, ...args); this.$emit("on-editor-change", eventName, ...args);
}); });
}, },
handleUploadSuccess(res, file) {
// 获取富文本组件实例
let quill = this.Quill;
// 如果上传成功
if (res.code == 200) {
// 获取光标所在位置
let length = quill.getSelection().index;
// 插入图片 res.url为服务器返回的图片地址
quill.insertEmbed(length, "image", res.url);
// 调整光标到最后
quill.setSelection(length + 1);
} else {
this.$message.error("图片插入失败");
}
},
handleUploadError() {
this.$message.error("图片插入失败");
},
}, },
}; };
</script> </script>

View File

@ -43,7 +43,14 @@ export default {
type: Array, type: Array,
}, },
}, },
created() {
// 显隐列初始默认隐藏列
for (let item in this.columns) {
if (this.columns[item].visible === false) {
this.value.push(parseInt(item));
}
}
},
methods: { methods: {
// 搜索 // 搜索
toggleSearch() { toggleSearch() {

View File

@ -35,7 +35,6 @@ export default {
if (typeof val !== 'string') return if (typeof val !== 'string') return
const themeCluster = this.getThemeCluster(val.replace('#', '')) const themeCluster = this.getThemeCluster(val.replace('#', ''))
const originalCluster = this.getThemeCluster(oldVal.replace('#', '')) const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
console.log(themeCluster, originalCluster)
const $message = this.$message({ const $message = this.$message({
message: ' Compiling the theme', message: ' Compiling the theme',

View File

@ -0,0 +1,182 @@
<template>
<el-menu
:default-active="activeMenu"
mode="horizontal"
@select="handleSelect"
>
<template v-for="(item, index) in topMenus">
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber"
><svg-icon :icon-class="item.meta.icon" />
{{ item.meta.title }}</el-menu-item
>
</template>
<!-- 顶部菜单超出数量折叠 -->
<el-submenu index="more" v-if="topMenus.length > visibleNumber">
<template slot="title">更多菜单</template>
<template v-for="(item, index) in topMenus">
<el-menu-item
:index="item.path"
:key="index"
v-if="index >= visibleNumber"
><svg-icon :icon-class="item.meta.icon" />
{{ item.meta.title }}</el-menu-item
>
</template>
</el-submenu>
</el-menu>
</template>
<script>
import { constantRoutes } from "@/router";
export default {
data() {
return {
// 顶部栏初始数
visibleNumber: 5,
// 是否为首次加载
isFrist: false,
// 当前激活菜单的 index
currentIndex: undefined
};
},
computed: {
theme() {
return this.$store.state.settings.theme;
},
// 顶部显示菜单
topMenus() {
let topMenus = [];
this.routers.map((menu) => {
if (menu.hidden !== true) {
// 兼容顶部栏一级菜单内部跳转
if (menu.path === "/") {
topMenus.push(menu.children[0]);
} else {
topMenus.push(menu);
}
}
});
return topMenus;
},
// 所有的路由信息
routers() {
return this.$store.state.permission.topbarRouters;
},
// 设置子路由
childrenMenus() {
var childrenMenus = [];
this.routers.map((router) => {
for (var item in router.children) {
if (router.children[item].parentPath === undefined) {
if(router.path === "/") {
router.children[item].path = "/redirect/" + router.children[item].path;
} else {
if(!this.ishttp(router.children[item].path)) {
router.children[item].path = router.path + "/" + router.children[item].path;
}
}
router.children[item].parentPath = router.path;
}
childrenMenus.push(router.children[item]);
}
});
return constantRoutes.concat(childrenMenus);
},
// 默认激活的菜单
activeMenu() {
const path = this.$route.path;
let activePath = this.routers[0].path;
if (path.lastIndexOf("/") > 0) {
const tmpPath = path.substring(1, path.length);
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
} else if ("/index" == path || "" == path) {
if (!this.isFrist) {
this.isFrist = true;
} else {
activePath = "index";
}
}
var routes = this.activeRoutes(activePath);
if (routes.length === 0) {
activePath = this.currentIndex || this.routers[0].path
this.activeRoutes(activePath);
}
return activePath;
},
},
beforeMount() {
window.addEventListener('resize', this.setVisibleNumber)
},
beforeDestroy() {
window.removeEventListener('resize', this.setVisibleNumber)
},
mounted() {
this.setVisibleNumber();
},
methods: {
// 根据宽度计算设置显示栏数
setVisibleNumber() {
const width = document.body.getBoundingClientRect().width / 3;
this.visibleNumber = parseInt(width / 85);
},
// 菜单选择事件
handleSelect(key, keyPath) {
this.currentIndex = key;
if (this.ishttp(key)) {
// http(s):// 路径新窗口打开
window.open(key, "_blank");
} else if (key.indexOf("/redirect") !== -1) {
// /redirect 路径内部打开
this.$router.push({ path: key.replace("/redirect", "") });
} else {
// 显示左侧联动菜单
this.activeRoutes(key);
}
},
// 当前激活的路由
activeRoutes(key) {
var routes = [];
if (this.childrenMenus && this.childrenMenus.length > 0) {
this.childrenMenus.map((item) => {
if (key == item.parentPath || (key == "index" && "" == item.path)) {
routes.push(item);
}
});
}
if(routes.length > 0) {
this.$store.commit("SET_SIDEBAR_ROUTERS", routes);
}
return routes;
},
ishttp(url) {
return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
}
},
};
</script>
<style lang="scss">
.el-menu--horizontal > .el-menu-item {
float: left;
height: 50px;
line-height: 50px;
margin: 0;
border-bottom: 3px solid transparent;
color: #999093;
padding: 0 5px;
margin: 0 10px;
}
.el-menu--horizontal > .el-menu-item.is-active {
border-bottom: 3px solid #{'var(--theme)'};
color: #303133;
}
/* submenu item */
.el-menu--horizontal > .el-submenu .el-submenu__title {
height: 50px !important;
line-height: 50px !important;
}
</style>

View File

@ -2,7 +2,8 @@
<div class="navbar"> <div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" /> <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
<top-nav id="topmenu-container" class="topmenu-container" v-if="topNav"/>
<div class="right-menu"> <div class="right-menu">
<template v-if="device!=='mobile'"> <template v-if="device!=='mobile'">
@ -48,6 +49,7 @@
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb' import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger' import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull' import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect' import SizeSelect from '@/components/SizeSelect'
@ -58,6 +60,7 @@ import RuoYiDoc from '@/components/RuoYi/Doc'
export default { export default {
components: { components: {
Breadcrumb, Breadcrumb,
TopNav,
Hamburger, Hamburger,
Screenfull, Screenfull,
SizeSelect, SizeSelect,
@ -81,6 +84,11 @@ export default {
value: val value: val
}) })
} }
},
topNav: {
get() {
return this.$store.state.settings.topNav
}
} }
}, },
methods: { methods: {
@ -127,6 +135,11 @@ export default {
float: left; float: left;
} }
.topmenu-container {
position: absolute;
left: 50px;
}
.errLog-container { .errLog-container {
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;

View File

@ -42,6 +42,11 @@
<h3 class="drawer-title">系统布局配置</h3> <h3 class="drawer-title">系统布局配置</h3>
<div class="drawer-item">
<span>开启 TopNav</span>
<el-switch v-model="topNav" class="drawer-switch" />
</div>
<div class="drawer-item"> <div class="drawer-item">
<span>开启 Tags-Views</span> <span>开启 Tags-Views</span>
<el-switch v-model="tagsView" class="drawer-switch" /> <el-switch v-model="tagsView" class="drawer-switch" />
@ -57,6 +62,10 @@
<el-switch v-model="sidebarLogo" class="drawer-switch" /> <el-switch v-model="sidebarLogo" class="drawer-switch" />
</div> </div>
<el-divider/>
<el-button size="small" type="primary" plain icon="el-icon-document-add" @click="saveSetting">保存配置</el-button>
<el-button size="small" plain icon="el-icon-refresh" @click="resetSetting">重置配置</el-button>
</div> </div>
</div> </div>
</template> </template>
@ -67,15 +76,12 @@ import ThemePicker from '@/components/ThemePicker'
export default { export default {
components: { ThemePicker }, components: { ThemePicker },
data() { data() {
return {} return {
theme: this.$store.state.settings.theme,
sideTheme: this.$store.state.settings.sideTheme
};
}, },
computed: { computed: {
theme() {
return this.$store.state.settings.theme
},
sideTheme() {
return this.$store.state.settings.sideTheme
},
fixedHeader: { fixedHeader: {
get() { get() {
return this.$store.state.settings.fixedHeader return this.$store.state.settings.fixedHeader
@ -87,6 +93,20 @@ export default {
}) })
} }
}, },
topNav: {
get() {
return this.$store.state.settings.topNav
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'topNav',
value: val
})
if (!val) {
this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes);
}
}
},
tagsView: { tagsView: {
get() { get() {
return this.$store.state.settings.tagsView return this.$store.state.settings.tagsView
@ -116,12 +136,46 @@ export default {
key: 'theme', key: 'theme',
value: val value: val
}) })
this.theme = val;
}, },
handleTheme(val) { handleTheme(val) {
this.$store.dispatch('settings/changeSetting', { this.$store.dispatch('settings/changeSetting', {
key: 'sideTheme', key: 'sideTheme',
value: val value: val
}) })
this.sideTheme = val;
},
saveSetting() {
const loading = this.$loading({
lock: true,
fullscreen: false,
text: "正在保存到本地,请稍后...",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
localStorage.setItem(
"layout-setting",
`{
"topNav":${this.topNav},
"tagsView":${this.tagsView},
"fixedHeader":${this.fixedHeader},
"sidebarLogo":${this.sidebarLogo},
"sideTheme":"${this.sideTheme}",
"theme":"${this.theme}"
}`
);
setTimeout(loading.close(), 1000)
},
resetSetting() {
this.$loading({
lock: true,
fullscreen: false,
text: "正在清除设置缓存并刷新,请稍后...",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)"
});
localStorage.removeItem("layout-setting")
setTimeout("window.location.reload()", 1000)
} }
} }
} }

View File

@ -21,6 +21,7 @@
<li @click="refreshSelectedTag(selectedTag)">刷新页面</li> <li @click="refreshSelectedTag(selectedTag)">刷新页面</li>
<li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前</li> <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">关闭当前</li>
<li @click="closeOthersTags">关闭其他</li> <li @click="closeOthersTags">关闭其他</li>
<li v-if="!isLastView()" @click="closeRightTags">关闭右侧</li>
<li @click="closeAllTags(selectedTag)">关闭所有</li> <li @click="closeAllTags(selectedTag)">关闭所有</li>
</ul> </ul>
</div> </div>
@ -83,6 +84,13 @@ export default {
isAffix(tag) { isAffix(tag) {
return tag.meta && tag.meta.affix return tag.meta && tag.meta.affix
}, },
isLastView() {
try {
return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath
} catch (err) {
return false
}
},
filterAffixTags(routes, basePath = '/') { filterAffixTags(routes, basePath = '/') {
let tags = [] let tags = []
routes.forEach(route => { routes.forEach(route => {
@ -152,6 +160,13 @@ export default {
} }
}) })
}, },
closeRightTags() {
this.$store.dispatch('tagsView/delRightTags', this.selectedTag).then(visitedViews => {
if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
this.toLastView(visitedViews)
}
})
},
closeOthersTags() { closeOthersTags() {
this.$router.push(this.selectedTag).catch(()=>{}); this.$router.push(this.selectedTag).catch(()=>{});
this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => { this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {

View File

@ -19,10 +19,8 @@ router.beforeEach((to, from, next) => {
} else { } else {
if (store.getters.roles.length === 0) { if (store.getters.roles.length === 0) {
// 判断当前用户是否已拉取完user_info信息 // 判断当前用户是否已拉取完user_info信息
store.dispatch('GetInfo').then(res => { store.dispatch('GetInfo').then(() => {
// 拉取user_info store.dispatch('GenerateRoutes').then(accessRoutes => {
const roles = res.roles
store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
// 根据roles权限生成可访问的路由表 // 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表 router.addRoutes(accessRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 next({ ...to, replace: true }) // hack方法 确保addRoutes已完成

View File

@ -11,6 +11,11 @@ module.exports = {
*/ */
showSettings: false, showSettings: false,
/**
* 是否显示顶部导航
*/
topNav: false,
/** /**
* 是否显示 tagsView * 是否显示 tagsView
*/ */

View File

@ -11,6 +11,8 @@ const getters = {
roles: state => state.user.roles, roles: state => state.user.roles,
permissions: state => state.user.permissions, permissions: state => state.user.permissions,
permission_routes: state => state.permission.routes, permission_routes: state => state.permission.routes,
topbarRouters:state => state.permission.topbarRouters,
defaultRoutes:state => state.permission.defaultRoutes,
sidebarRouters:state => state.permission.sidebarRouters, sidebarRouters:state => state.permission.sidebarRouters,
} }
export default getters export default getters

View File

@ -7,6 +7,8 @@ const permission = {
state: { state: {
routes: [], routes: [],
addRoutes: [], addRoutes: [],
defaultRoutes: [],
topbarRouters: [],
sidebarRouters: [] sidebarRouters: []
}, },
mutations: { mutations: {
@ -14,8 +16,19 @@ const permission = {
state.addRoutes = routes state.addRoutes = routes
state.routes = constantRoutes.concat(routes) state.routes = constantRoutes.concat(routes)
}, },
SET_SIDEBAR_ROUTERS: (state, routers) => { SET_DEFAULT_ROUTES: (state, routes) => {
state.sidebarRouters = constantRoutes.concat(routers) state.defaultRoutes = constantRoutes.concat(routes)
},
SET_TOPBAR_ROUTES: (state, routes) => {
// 顶部导航菜单默认添加统计报表栏指向首页
const index = [{
path: 'index',
meta: { title: '统计报表', icon: 'dashboard'}
}]
state.topbarRouters = routes.concat(index);
},
SET_SIDEBAR_ROUTERS: (state, routes) => {
state.sidebarRouters = routes
}, },
}, },
actions: { actions: {
@ -30,7 +43,9 @@ const permission = {
const rewriteRoutes = filterAsyncRouter(rdata, false, true) const rewriteRoutes = filterAsyncRouter(rdata, false, true)
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
commit('SET_ROUTES', rewriteRoutes) commit('SET_ROUTES', rewriteRoutes)
commit('SET_SIDEBAR_ROUTERS', sidebarRoutes) commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
commit('SET_DEFAULT_ROUTES', sidebarRoutes)
commit('SET_TOPBAR_ROUTES', sidebarRoutes)
resolve(rewriteRoutes) resolve(rewriteRoutes)
}) })
}) })

View File

@ -1,17 +1,18 @@
import variables from '@/assets/styles/element-variables.scss' import variables from '@/assets/styles/element-variables.scss'
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
const { sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo } = defaultSettings
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
const state = { const state = {
theme: variables.theme, theme: storageSetting.theme || variables.theme,
sideTheme: sideTheme, sideTheme: storageSetting.sideTheme || sideTheme,
showSettings: showSettings, showSettings: showSettings,
tagsView: tagsView, topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
fixedHeader: fixedHeader, tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
sidebarLogo: sidebarLogo fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo
} }
const mutations = { const mutations = {
CHANGE_SETTING: (state, { key, value }) => { CHANGE_SETTING: (state, { key, value }) => {
if (state.hasOwnProperty(key)) { if (state.hasOwnProperty(key)) {

View File

@ -62,6 +62,23 @@ const mutations = {
break break
} }
} }
},
DEL_RIGHT_VIEWS: (state, view) => {
const index = state.visitedViews.findIndex(v => v.path === view.path)
if (index === -1) {
return
}
state.visitedViews = state.visitedViews.filter((item, idx) => {
if (idx <= index || (item.meta && item.meta.affix)) {
return true
}
const i = state.cachedViews.indexOf(item.name)
if (i > -1) {
state.cachedViews.splice(i, 1)
}
return false
})
} }
} }
@ -148,6 +165,13 @@ const actions = {
updateVisitedView({ commit }, view) { updateVisitedView({ commit }, view) {
commit('UPDATE_VISITED_VIEW', view) commit('UPDATE_VISITED_VIEW', view)
},
delRightTags({ commit }, view) {
return new Promise(resolve => {
commit('DEL_RIGHT_VIEWS', view)
resolve([...state.visitedViews])
})
} }
} }

View File

@ -49,7 +49,7 @@ const user = {
// 获取用户信息 // 获取用户信息
GetInfo({ commit, state }) { GetInfo({ commit, state }) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo(state.token).then(res => { getInfo().then(res => {
const user = res.user const user = res.user
const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar; const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组

View File

@ -129,24 +129,47 @@ export function praseStrEmpty(str) {
* @param {*} id id字段 默认 'id' * @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId' * @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children' * @param {*} children 孩子节点字段 默认 'children'
* @param {*} rootId 根Id 默认 0
*/ */
export function handleTree(data, id, parentId, children, rootId) { export function handleTree(data, id, parentId, children) {
id = id || 'id' let config = {
parentId = parentId || 'parentId' id: id || 'id',
children = children || 'children' parentId: parentId || 'parentId',
rootId = rootId || Math.min.apply(Math, data.map(item => { return item[parentId] })) || 0 childrenList: children || 'children'
//对源数据深度克隆 };
const cloneData = JSON.parse(JSON.stringify(data))
//循环所有项 var childrenListMap = {};
const treeData = cloneData.filter(father => { var nodeIds = {};
let branchArr = cloneData.filter(child => { var tree = [];
//返回每一项的子级数组
return father[id] === child[parentId] for (let d of data) {
}); let parentId = d[config.parentId];
branchArr.length > 0 ? father.children = branchArr : ''; if (childrenListMap[parentId] == null) {
//返回第一层 childrenListMap[parentId] = [];
return father[parentId] === rootId; }
}); nodeIds[d[config.id]] = d;
return treeData != '' ? treeData : data; childrenListMap[parentId].push(d);
}
for (let d of data) {
let parentId = d[config.parentId];
if (nodeIds[parentId] == null) {
tree.push(d);
}
}
for (let t of tree) {
adaptToChildrenList(t);
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (let c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
}
return tree;
} }

View File

@ -36,5 +36,5 @@ export function resolveBlob(res, mimeType) {
aLink.setAttribute('download', fileName) // 设置下载文件名称 aLink.setAttribute('download', fileName) // 设置下载文件名称
document.body.appendChild(aLink) document.body.appendChild(aLink)
aLink.click() aLink.click()
document.body.appendChild(aLink) document.body.removeChild(aLink);
} }

View File

@ -119,9 +119,10 @@
</p> </p>
<p> <p>
<i class="el-icon-user-solid"></i> QQ群<s>满937441</s> <i class="el-icon-user-solid"></i> QQ群<s>满937441</s>
<s>满887144332</s> <s>满180251782</s> <s>满887144332</s> <s>满180251782</s> <s>满104180207</s>
<a href="https://jq.qq.com/?_wv=1027&k=4WWwqNxN" target="_blank" <s>满186866453</s>
> 104180207</a <a href="https://jq.qq.com/?_wv=1027&k=5vYAqA05" target="_blank">
201396349</a
> >
</p> </p>
<p> <p>
@ -146,6 +147,46 @@
<span>更新日志</span> <span>更新日志</span>
</div> </div>
<el-collapse accordion> <el-collapse accordion>
<el-collapse-item title="v3.5.0 - 2021-05-25">
<ol>
<li>新增菜单导航显示风格TopNavfalse为左侧导航菜单true为顶部导航菜单</li>
<li>布局设置支持保存&重置配置</li>
<li>修复树表数据显示不全&加载慢问题</li>
<li>新增IE浏览器版本过低提示页面</li>
<li>用户登录后记录最后登录IP&时间</li>
<li>页面导出按钮点击之后添加遮罩</li>
<li>富文本编辑器支持自定义上传地址</li>
<li>富文本编辑组件新增readOnly属性</li>
<li>页签TagsView新增关闭右侧功能</li>
<li>显隐列组件加载初始默认隐藏列</li>
<li>关闭头像上传窗口还原默认图片</li>
<li>个人信息添加手机&邮箱重复验证</li>
<li>代码生成模板导出按钮点击后添加遮罩</li>
<li>代码生成模板树表操作列添加新增按钮</li>
<li>代码生成模板修复主子表字段重名问题</li>
<li>升级fastjson到最新版1.2.76</li>
<li>升级druid到最新版本v1.2.6</li>
<li>升级mybatis到最新版3.5.6 阻止远程代码执行漏洞</li>
<li>升级oshi到最新版本v5.6.0</li>
<li>velocity剔除commons-collections版本防止3.2.1版本的反序列化漏洞</li>
<li>数据监控页默认账户密码防止越权访问</li>
<li>修复firefox下表单构建拖拽会新打卡一个选项卡</li>
<li>修正后端导入表权限标识</li>
<li>修正前端操作日志&登录日志权限标识</li>
<li>设置Redis配置HashKey序列化</li>
<li>删除操作日志记录信息</li>
<li>上传媒体类型添加视频格式</li>
<li>修复请求形参未传值记录日志异常问题</li>
<li>优化xss校验json请求条件</li>
<li>树级结构更新子节点使用replaceFirst</li>
<li>优化ExcelUtil空值处理</li>
<li>日志记录过滤BindingResult对象防止异常</li>
<li>修改主题后mini类型按钮无效问题</li>
<li>优化通用下载完成后删除节点</li>
<li>通用Controller添加响应返回消息</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.4.0 - 2021-02-22"> <el-collapse-item title="v3.4.0 - 2021-02-22">
<ol> <ol>
<li>代码生成模板支持主子表</li> <li>代码生成模板支持主子表</li>
@ -525,7 +566,7 @@ export default {
data() { data() {
return { return {
// 版本号 // 版本号
version: "3.4.0", version: "3.5.0",
}; };
}, },
methods: { methods: {

View File

@ -8,7 +8,7 @@ export default {
name: "Druid", name: "Druid",
data() { data() {
return { return {
src: process.env.VUE_APP_BASE_API + "/druid/index.html", src: process.env.VUE_APP_BASE_API + "/druid/login.html",
height: document.documentElement.clientHeight - 94.5 + "px;", height: document.documentElement.clientHeight - 94.5 + "px;",
loading: true loading: true
}; };

View File

@ -75,6 +75,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['monitor:job:export']" v-hasPermi="['monitor:job:export']"
>导出</el-button> >导出</el-button>
@ -274,6 +275,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非单个禁用 // 非单个禁用
@ -477,10 +480,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportJob(queryParams); return exportJob(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -89,6 +89,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['monitor:job:export']" v-hasPermi="['monitor:job:export']"
>导出</el-button> >导出</el-button>
@ -175,6 +176,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非多个禁用 // 非多个禁用
@ -288,10 +291,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportJobLog(queryParams); return exportJobLog(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -83,8 +83,9 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:logininfor:export']" v-hasPermi="['monitor:logininfor:export']"
>导出</el-button> >导出</el-button>
</el-col> </el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@ -126,6 +127,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非多个禁用 // 非多个禁用
@ -221,10 +224,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportLogininfor(queryParams); return exportLogininfor(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -99,8 +99,9 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:config:export']" v-hasPermi="['monitor:operlog:export']"
>导出</el-button> >导出</el-button>
</el-col> </el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@ -195,6 +196,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非多个禁用 // 非多个禁用
@ -309,10 +312,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportOperlog(queryParams); return exportOperlog(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -88,6 +88,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:config:export']" v-hasPermi="['system:config:export']"
>导出</el-button> >导出</el-button>
@ -188,6 +189,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非单个禁用 // 非单个禁用
@ -344,10 +347,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportConfig(queryParams); return exportConfig(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
}, },
/** 清理缓存按钮操作 */ /** 清理缓存按钮操作 */

View File

@ -75,6 +75,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:dict:export']" v-hasPermi="['system:dict:export']"
>导出</el-button> >导出</el-button>
@ -169,6 +170,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非单个禁用 // 非单个禁用
@ -343,10 +346,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportData(queryParams); return exportData(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -94,6 +94,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:dict:export']" v-hasPermi="['system:dict:export']"
>导出</el-button> >导出</el-button>
@ -196,6 +197,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非单个禁用 // 非单个禁用
@ -348,10 +351,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportType(queryParams); return exportType(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
}, },
/** 清理缓存按钮操作 */ /** 清理缓存按钮操作 */

View File

@ -176,7 +176,7 @@
</template> </template>
<script> <script>
import { listNotice, getNotice, delNotice, addNotice, updateNotice, exportNotice } from "@/api/system/notice"; import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
import Editor from '@/components/Editor'; import Editor from '@/components/Editor';
export default { export default {

View File

@ -74,6 +74,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:post:export']" v-hasPermi="['system:post:export']"
>导出</el-button> >导出</el-button>
@ -163,6 +164,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非单个禁用 // 非单个禁用
@ -315,10 +318,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportPost(queryParams); return exportPost(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -94,6 +94,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:role:export']" v-hasPermi="['system:role:export']"
>导出</el-button> >导出</el-button>
@ -258,6 +259,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非单个禁用 // 非单个禁用
@ -599,10 +602,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportRole(queryParams); return exportRole(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
} }
} }

View File

@ -131,6 +131,7 @@
plain plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
:loading="exportLoading"
@click="handleExport" @click="handleExport"
v-hasPermi="['system:user:export']" v-hasPermi="['system:user:export']"
>导出</el-button> >导出</el-button>
@ -356,6 +357,8 @@ export default {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 导出遮罩层
exportLoading: false,
// 选中数组 // 选中数组
ids: [], ids: [],
// 非单个禁用 // 非单个禁用
@ -637,10 +640,12 @@ export default {
confirmButtonText: "确定", confirmButtonText: "确定",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "warning" type: "warning"
}).then(function() { }).then(() => {
this.exportLoading = true;
return exportUser(queryParams); return exportUser(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
this.exportLoading = false;
}) })
}, },
/** 导入按钮操作 */ /** 导入按钮操作 */

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<div class="user-info-head" @click="editCropper()"><img v-bind:src="options.img" title="点击上传头像" class="img-circle img-lg" /></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"> <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened" @close="closeDialog()">
<el-row> <el-row>
<el-col :xs="24" :md="12" :style="{height: '350px'}"> <el-col :xs="24" :md="12" :style="{height: '350px'}">
<vue-cropper <vue-cropper
@ -136,6 +136,11 @@ export default {
// 实时预览 // 实时预览
realTime(data) { realTime(data) {
this.previews = data; this.previews = data;
},
// 关闭窗口
closeDialog() {
this.options.img = store.getters.avatar
this.visible = false;
} }
} }
}; };

View File

@ -193,7 +193,12 @@ export default {
activeData: drawingDefalut[0] activeData: drawingDefalut[0]
} }
}, },
computed: { created() {
// 防止 firefox 下 拖拽 会新打卡一个选项卡
document.body.ondrop = event => {
event.preventDefault()
event.stopPropagation()
}
}, },
watch: { watch: {
// eslint-disable-next-line func-names // eslint-disable-next-line func-names