68 Commits

Author SHA1 Message Date
RuoYi
36b900cef8 若依 3.8.7 2023-12-08 09:03:30 +08:00
RuoYi
ac9302e2a2 升级element-ui到最新版本2.15.14 2023-12-07 11:08:03 +08:00
RuoYi
0f7e3a744e 删除无用的代码 2023-12-07 11:07:30 +08:00
RuoYi
45656b271a 升级oshi到最新版本6.4.8 2023-12-05 11:28:42 +08:00
RuoYi
323e3b7371 升级pagehelper到最新版1.4.7 2023-12-05 11:28:18 +08:00
RuoYi
bfbaa9e7b5 升级druid到最新版本1.2.20 2023-12-05 11:28:05 +08:00
RuoYi
2253a146b3 update fastjson2 2023-12-05 10:48:22 +08:00
RuoYi
2070a9252a 操作日志记录部门名称 2023-12-05 10:47:39 +08:00
RuoYi
e231d78469 修复代码生成导入后必填项与数据库不匹配问题 2023-12-05 10:45:54 +08:00
RuoYi
f74454b61a 删除无用的实例演示开关配置 2023-12-05 10:44:50 +08:00
RuoYi
d71ee5dba1 显隐列组件支持复选框弹出类型 2023-12-01 11:20:12 +08:00
RuoYi
78b1ac4a60 代码生成支持选择前端模板类型 2023-11-30 09:38:07 +08:00
RuoYi
966a17123f 优化代码 2023-11-30 09:37:36 +08:00
RuoYi
42bb8f6445 优化头像上传参数新增文件名称 2023-11-29 12:41:04 +08:00
RuoYi
72e4cd9fb3 优化字典标签支持自定义分隔符 2023-11-29 12:40:47 +08:00
RuoYi
1525bd8b54 优化下载zip方法新增遮罩层 2023-11-29 12:40:01 +08:00
RuoYi
b8e2eeaaf8 优化缓存监控图表支持跟随屏幕大小自适应调整 2023-11-29 12:39:22 +08:00
RuoYi
cbcfabee2a 优化代码 2023-11-29 12:38:45 +08:00
RuoYi
e6d0599b25 优化个人中心/基本资料修改时数据显示问题 2023-11-28 12:36:30 +08:00
RuoYi
b224cebab7 防止高频率定时任务不执行问题 2023-11-28 12:35:04 +08:00
若依
f880dee7a4 !804 update ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java.
Merge pull request !804 from 刚刚好/N/A
2023-11-28 04:07:51 +00:00
若依
f16875c9af !799 update ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java.
Merge pull request !799 from 张利/N/A
2023-11-28 04:04:36 +00:00
若依
a90355eb5e !791 优化白名单页面放行逻辑
Merge pull request !791 from 也曾为你像超人/N/A
2023-11-28 03:54:05 +00:00
刚刚好
386f32a3b7 update ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java.
提交错别字

Signed-off-by: 刚刚好 <380862139@qq.com>
2023-11-12 02:38:46 +00:00
RuoYi
4ca30f08d6 修改权限字符匹配方式 2023-11-10 15:46:27 +08:00
RuoYi
73f881c7d3 修复五级路由缓存无效问题 2023-11-10 15:31:30 +08:00
RuoYi
b357aedaa3 修复内链iframe没有传递参数问题(I8DUOJ) 2023-11-10 11:13:16 +08:00
RuoYi
8cf8c8acd0 修复外链带端口出现的异常(I86J4B) 2023-11-07 11:38:19 +08:00
张利
fbab383bd7 update ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java.
此处新密码加密了两次,多余的操作,且会导致新生成的数据库密码与缓存中的密码不同,如果修改的不对还请讲解回复下,谢谢。

Signed-off-by: 张利 <zhangli_wei555@163.com>
2023-11-02 02:57:04 +00:00
RuoYi
d8255edf84 新增编程式判断资源访问权限 2023-11-01 16:02:53 +08:00
若依
eff42d8b0f !797 修复字典表详情页面搜索bug
Merge pull request !797 from 也曾为你像超人/N/A
2023-11-01 01:57:49 +00:00
也曾为你像超人
1f753e3d84 修复字典表详情页面搜索bug
Signed-off-by: 也曾为你像超人 <1553592282@qq.com>
2023-10-30 03:50:19 +00:00
RuoYi
72d4069537 优化数字金额大写转换精度丢失问题(I81IJA) 2023-10-27 12:25:54 +08:00
也曾为你像超人
76205588f0 update ruoyi-ui/src/permission.js.
Signed-off-by: 也曾为你像超人 <1553592282@qq.com>
2023-10-24 07:45:03 +00:00
RuoYi
7b4ba0146b 升级fastjson到最新版2.0.41 2023-10-21 14:44:02 +08:00
RuoYi
3963e86537 升级oshi到最新版本6.4.6 2023-10-21 14:34:05 +08:00
RuoYi
7098acc968 登录不做数据重复提交验证 2023-10-21 14:31:12 +08:00
RuoYi
079ac841f3 添加新群号:174951577 2023-10-09 21:27:00 +08:00
RuoYi
0434b4ca7a 去掉多余的参数 2023-10-09 21:26:40 +08:00
RuoYi
8873dc9b64 富文本Editor组件检验图片格式 2023-10-02 12:45:27 +08:00
RuoYi
078a3aad5a 修复HeaderSearch组件跳转query参数丢失问题 2023-09-28 22:24:25 +08:00
RuoYi
207a9ce855 操作日志列表新增IP地址查询 2023-09-27 15:21:59 +08:00
RuoYi
9ced1e9766 全局数据存储用户编号 2023-09-27 15:21:37 +08:00
RuoYi
1926840204 优化菜单管理类型为按钮状态可选 2023-09-18 15:04:34 +08:00
RuoYi
006d46ad07 修复自定义字典样式不生效的问题(I81F03) 2023-09-14 16:55:07 +08:00
RuoYi
f5a1b0c550 删除无用的传参 2023-09-01 09:37:16 +08:00
RuoYi
4a78fe116d 优化TopNav菜单没有图标svg不显示 2023-08-31 10:18:25 +08:00
若依
3e95dd21f2 !772 修改未登录访问需要登录的资源,在登录后重定向丢失请求参数问题
Merge pull request !772 from who's hu/pr
2023-08-31 02:17:32 +00:00
RuoYi
491b0f3db8 修复字典缓存删除方法参数错误问题(I7UDIR) 2023-08-23 14:54:20 +08:00
who's hu
16d8b71e21 update ruoyi-ui/src/permission.js.
由于重定向url存在 http://xxx.xx.xxx/{id}?param={a}&name={b} 的场景, 当未登录访问时, 通过改js封装登录后重定向参数, 会丢失?后的query params
如:
访问 http://localhost:1024/core/doc/doc?id=1683734914907807745&version=31
期望 http://localhost:1024/login?redirect=%2Fcore%2Fdoc%2Fdoc%3Fid%3D1683734914907807745%26version%3D31
实际通过 to.fullPath 封装后 获得 http://localhost:1024/login?redirect=%2Fcore%2Fdoc%2Fdoc%3Fid%3D1683734914907807745&version=31

登录成功跳转到重定向参数url后, 导致version参数丢失.
需要对 to.fullPath 进行一次编码, 以保证重定向前 to.fullPath 的完整性.
通过 ${encodeURIComponent(to.fullPath)} 获得 http://localhost:1024/login?redirect=%2Fcore%2Fdoc%2Fdoc%3Fid%3D1683734914907807745%26version%3D31 完整url



Signed-off-by: who's hu <hup_dev@outlook.com>
2023-08-22 09:25:19 +00:00
RuoYi
90260ce2f9 修复Excels导入时无法获取到dictType字典值问题(I7M4PW) 2023-08-21 15:52:30 +08:00
RuoYi
d58942c506 防重复提交数据大小限制(I7KZDA) 2023-08-21 11:57:14 +08:00
RuoYi
6a742e1d1b Excel导入数据临时文件无法删除问题(I7KIXX) 2023-08-19 15:43:57 +08:00
RuoYi
5b61aea064 修复树模板父级编码变量错误(I7JZ0L) 2023-08-19 14:34:30 +08:00
RuoYi
45ef542687 升级fastjson到最新版2.0.39 2023-08-15 12:17:27 +08:00
RuoYi
4ac7a1aa1f 升级commons.io到最新版本2.13.0 2023-08-15 11:31:38 +08:00
RuoYi
c5e4459bb8 优化代码 2023-08-15 11:30:49 +08:00
RuoYi
8f67bf416b 升级oshi到最新版本6.4.4 2023-08-14 19:11:46 +08:00
RuoYi
ab99a72b65 优化代码 2023-08-14 19:11:13 +08:00
RuoYi
7c9423657e Excel自定义数据处理器增加单元格/工作簿对象 2023-08-14 17:42:44 +08:00
RuoYi
128b186b8e 优化定时任务状态页面显示 2023-08-14 17:42:24 +08:00
RuoYi
68ac40eda9 update maven-plugin 2023-08-14 17:41:52 +08:00
RuoYi
5557433235 添加新群号:143961921 2023-07-28 11:12:09 +08:00
RuoYi
2517e9dddb 优化登录提示信息(I6ADCR) 2023-07-24 15:16:52 +08:00
RuoYi
a0595711ca 优化页签在Firefox浏览器被遮挡的问题 2023-07-06 22:09:16 +08:00
RuoYi
1ffb6379f7 排序属性orderBy参数限制长度 2023-07-06 22:09:02 +08:00
RuoYi
4d5c204b9a 优化代码 2023-07-06 22:08:47 +08:00
RuoYi
8ee740ef49 update sql 2023-07-06 22:07:00 +08:00
90 changed files with 1473 additions and 1235 deletions

View File

@@ -1,11 +1,11 @@
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.6</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.7</h1>
<h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.6-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.7-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>
@@ -93,4 +93,4 @@
## 若依前后端分离交流群
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) 点击按钮入群。
QQ群 [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/已满-136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [![加入QQ群](https://img.shields.io/badge/已满-143961921-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [![加入QQ群](https://img.shields.io/badge/174951577-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) 点击按钮入群。

16
pom.xml
View File

@@ -6,32 +6,32 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.8.6</version>
<version>3.8.7</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依管理系统</description>
<properties>
<ruoyi.version>3.8.6</ruoyi.version>
<ruoyi.version>3.8.7</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<druid.version>1.2.16</druid.version>
<druid.version>1.2.20</druid.version>
<bitwalker.version>1.21</bitwalker.version>
<swagger.version>3.0.0</swagger.version>
<kaptcha.version>2.3.3</kaptcha.version>
<pagehelper.boot.version>1.4.6</pagehelper.boot.version>
<fastjson.version>2.0.34</fastjson.version>
<oshi.version>6.4.3</oshi.version>
<commons.io.version>2.11.0</commons.io.version>
<pagehelper.boot.version>1.4.7</pagehelper.boot.version>
<fastjson.version>2.0.43</fastjson.version>
<oshi.version>6.4.8</oshi.version>
<commons.io.version>2.13.0</commons.io.version>
<commons.collections.version>3.2.2</commons.collections.version>
<poi.version>4.1.2</poi.version>
<velocity.version>2.3</velocity.version>
<jwt.version>0.9.1</jwt.version>
</properties>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.6</version>
<version>3.8.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
@@ -68,7 +68,7 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<version>2.5.15</version>
<configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration>

View File

@@ -60,27 +60,22 @@ public class SysProfileController extends BaseController
public AjaxResult updateProfile(@RequestBody SysUser user)
{
LoginUser loginUser = getLoginUser();
SysUser sysUser = loginUser.getUser();
user.setUserName(sysUser.getUserName());
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
SysUser currentUser = loginUser.getUser();
currentUser.setNickName(user.getNickName());
currentUser.setEmail(user.getEmail());
currentUser.setPhonenumber(user.getPhonenumber());
currentUser.setSex(user.getSex());
if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
{
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
}
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
{
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
}
user.setUserId(sysUser.getUserId());
user.setPassword(null);
user.setAvatar(null);
user.setDeptId(null);
if (userService.updateUserProfile(user) > 0)
if (userService.updateUserProfile(currentUser) > 0)
{
// 更新缓存用户信息
sysUser.setNickName(user.getNickName());
sysUser.setPhonenumber(user.getPhonenumber());
sysUser.setEmail(user.getEmail());
sysUser.setSex(user.getSex());
tokenService.setLoginUser(loginUser);
return success();
}
@@ -105,10 +100,11 @@ public class SysProfileController extends BaseController
{
return error("新密码不能与旧密码相同");
}
if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0)
newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(userName, newPassword) > 0)
{
// 更新缓存用户密码
loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
loginUser.getUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser);
return success();
}

View File

@@ -1 +1 @@
restart.include.json=/com.alibaba.fastjson.*.jar
restart.include.json=/com.alibaba.fastjson2.*.jar

View File

@@ -3,11 +3,9 @@ ruoyi:
# 名称
name: RuoYi
# 版本
version: 3.8.6
version: 3.8.7
# 版权年份
copyrightYear: 2023
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:/ruoyi/uploadPath
# 获取ip地址开关

View File

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

View File

@@ -21,9 +21,6 @@ public class RuoYiConfig
/** 版权年份 */
private String copyrightYear;
/** 实例演示开关 */
private boolean demoEnabled;
/** 上传路径 */
private static String profile;
@@ -63,16 +60,6 @@ public class RuoYiConfig
this.copyrightYear = copyrightYear;
}
public boolean isDemoEnabled()
{
return demoEnabled;
}
public void setDemoEnabled(boolean demoEnabled)
{
this.demoEnabled = demoEnabled;
}
public static String getProfile()
{
return profile;

View File

@@ -63,7 +63,27 @@ public class Constants
* 登录失败
*/
public static final String LOGIN_FAIL = "Error";
/**
* 所有权限标识
*/
public static final String ALL_PERMISSION = "*:*:*";
/**
* 管理员角色权限标识
*/
public static final String SUPER_ADMIN = "admin";
/**
* 角色权限分隔符
*/
public static final String ROLE_DELIMETER = ",";
/**
* 权限标识分隔符
*/
public static final String PERMISSION_DELIMETER = ",";
/**
* 验证码有效期(分钟)
*/
@@ -129,6 +149,11 @@ public class Constants
*/
public static final String LOOKUP_LDAPS = "ldaps:";
/**
* 自动识别json对象白名单配置仅允许解析的包名范围越小越安全
*/
public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.ruoyi" };
/**
* 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
*/

View File

@@ -2,6 +2,7 @@ package com.ruoyi.common.core.text;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.text.NumberFormat;
@@ -977,7 +978,12 @@ public class Convert
String s = "";
for (int i = 0; i < fraction.length; i++)
{
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
// 优化double计算精度丢失问题
BigDecimal nNum = new BigDecimal(n);
BigDecimal decimal = new BigDecimal(10);
BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
double d = scale.doubleValue();
s += (digit[(int) (Math.floor(d * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
}
if (s.length() < 1)
{

View File

@@ -147,7 +147,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
/**
* 计算时间差
*
* @param endTime 最后时间
* @param endDate 最后时间
* @param startTime 开始时间
* @return 时间差(天/小时/分钟)
*/

View File

@@ -1,9 +1,15 @@
package com.ruoyi.common.utils;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.PatternMatchUtils;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
@@ -14,6 +20,7 @@ import com.ruoyi.common.exception.ServiceException;
*/
public class SecurityUtils
{
/**
* 用户ID
**/
@@ -43,7 +50,7 @@ public class SecurityUtils
throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
}
}
/**
* 获取用户账户
**/
@@ -117,4 +124,55 @@ public class SecurityUtils
{
return userId != null && 1L == userId;
}
/**
* 验证用户是否具备某权限
*
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(String permission)
{
return hasPermi(getLoginUser().getPermissions(), permission);
}
/**
* 判断是否包含权限
*
* @param authorities 权限列表
* @param permission 权限字符串
* @return 用户是否具备某权限
*/
public static boolean hasPermi(Collection<String> authorities, String permission)
{
return authorities.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
}
/**
* 验证用户是否拥有某个角色
*
* @param role 角色标识
* @return 用户是否具备某角色
*/
public static boolean hasRole(String role)
{
List<SysRole> roleList = getLoginUser().getUser().getRoles();
Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
return hasRole(roles, role);
}
/**
* 判断是否包含角色
*
* @param roles 角色列表
* @param role 角色
* @return 用户是否具备某角色权限
*/
public static boolean hasRole(Collection<String> roles, String role)
{
return roles.stream().filter(StringUtils::hasText)
.anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
}
}

View File

@@ -240,6 +240,30 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
return str.substring(start, end);
}
/**
* 判断是否为空,并且不是空白字符
*
* @param str 要判断的value
* @return 结果
*/
public static boolean hasText(String str)
{
return (str != null && !str.isEmpty() && containsText(str));
}
private static boolean containsText(CharSequence str)
{
int strLen = str.length();
for (int i = 0; i < strLen; i++)
{
if (!Character.isWhitespace(str.charAt(i)))
{
return true;
}
}
return false;
}
/**
* 格式化文本, {} 表示占位符<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>

View File

@@ -1,5 +1,8 @@
package com.ruoyi.common.utils.poi;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Workbook;
/**
* Excel数据格式处理适配器
*
@@ -12,8 +15,10 @@ public interface ExcelHandlerAdapter
*
* @param value 单元格数据值
* @param args excel注解args参数组
* @param cell 单元格对象
* @param wb 工作簿对象
*
* @return 处理后的值
*/
Object format(Object value, String[] args);
Object format(Object value, String[] args, Cell cell, Workbook wb);
}

View File

@@ -288,9 +288,23 @@ public class ExcelUtil<T>
* @param is 输入流
* @return 转换后集合
*/
public List<T> importExcel(InputStream is) throws Exception
public List<T> importExcel(InputStream is)
{
return importExcel(is, 0);
List<T> list = null;
try
{
list = importExcel(is, 0);
}
catch (Exception e)
{
log.error("导入Excel异常{}", e.getMessage());
throw new UtilException(e.getMessage());
}
finally
{
IOUtils.closeQuietly(is);
}
return list;
}
/**
@@ -336,7 +350,6 @@ public class ExcelUtil<T>
}
// 获取最后一个非空行的行下标比如总行数为n则返回的为n-1
int rows = sheet.getLastRowNum();
if (rows > 0)
{
// 定义一个map用于存放excel列的序号和field.
@@ -451,7 +464,7 @@ public class ExcelUtil<T>
{
propertyName = field.getName() + "." + attr.targetAttr();
}
else if (StringUtils.isNotEmpty(attr.readConverterExp()))
if (StringUtils.isNotEmpty(attr.readConverterExp()))
{
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
}
@@ -461,7 +474,7 @@ public class ExcelUtil<T>
}
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{
val = dataFormatHandlerAdapter(val, attr);
val = dataFormatHandlerAdapter(val, attr, null);
}
else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
{
@@ -1052,7 +1065,7 @@ public class ExcelUtil<T>
}
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{
cell.setCellValue(dataFormatHandlerAdapter(value, attr));
cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
}
else
{
@@ -1265,13 +1278,13 @@ public class ExcelUtil<T>
* @param excel 数据注解
* @return
*/
public String dataFormatHandlerAdapter(Object value, Excel excel)
public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell)
{
try
{
Object instance = excel.handler().newInstance();
Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class });
value = formatMethod.invoke(instance, value, excel.args());
Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class });
value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb);
}
catch (Exception e)
{

View File

@@ -20,6 +20,11 @@ public class SqlUtil
*/
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 限制orderBy最大长度
*/
private static final int ORDER_BY_MAX_LENGTH = 500;
/**
* 检查字符,防止注入绕过
*/
@@ -29,6 +34,10 @@ public class SqlUtil
{
throw new UtilException("参数不符合规范,不能进行查询");
}
if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
{
throw new UtilException("参数已超过最大限制,不能进行查询");
}
return value;
}

View File

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

View File

@@ -18,6 +18,7 @@ import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessStatus;
import com.ruoyi.common.enums.HttpMethod;
@@ -96,6 +97,11 @@ public class LogAspect
if (loginUser != null)
{
operLog.setOperName(loginUser.getUsername());
SysUser currentUser = loginUser.getUser();
if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept()))
{
operLog.setDeptName(currentUser.getDept().getDeptName());
}
}
if (e != null)

View File

@@ -6,6 +6,8 @@ import org.springframework.data.redis.serializer.SerializationException;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.Filter;
import com.ruoyi.common.constant.Constants;
/**
* Redis使用FastJson序列化
@@ -16,6 +18,8 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
{
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
private Class<T> clazz;
public FastJson2JsonRedisSerializer(Class<T> clazz)
@@ -43,6 +47,6 @@ public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
return JSON.parseObject(str, clazz, AUTO_TYPE_FILTER);
}
}

View File

@@ -47,8 +47,9 @@ public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
/**
* 验证是否重复提交由子类实现具体的防重复提交的规则
*
* @param request
* @return
* @param request 请求信息
* @param annotation 防重复注解参数
* @return 结果
* @throws Exception
*/
public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);

View File

@@ -7,8 +7,10 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.DemoModeException;
@@ -59,6 +61,28 @@ public class GlobalExceptionHandler
return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
}
/**
* 请求路径中缺少必需的路径变量
*/
@ExceptionHandler(MissingPathVariableException.class)
public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
}
/**
* 请求参数类型不匹配
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request)
{
String requestURI = request.getRequestURI();
log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
}
/**
* 拦截未知的运行时异常
*/

View File

@@ -3,6 +3,7 @@ package com.ruoyi.framework.web.service;
import java.util.Set;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
@@ -17,16 +18,6 @@ import com.ruoyi.framework.security.context.PermissionContextHolder;
@Service("ss")
public class PermissionService
{
/** 所有权限标识 */
private static final String ALL_PERMISSION = "*:*:*";
/** 管理员角色权限标识 */
private static final String SUPER_ADMIN = "admin";
private static final String ROLE_DELIMETER = ",";
private static final String PERMISSION_DELIMETER = ",";
/**
* 验证用户是否具备某权限
*
@@ -78,7 +69,7 @@ public class PermissionService
}
PermissionContextHolder.setContext(permissions);
Set<String> authorities = loginUser.getPermissions();
for (String permission : permissions.split(PERMISSION_DELIMETER))
for (String permission : permissions.split(Constants.PERMISSION_DELIMETER))
{
if (permission != null && hasPermissions(authorities, permission))
{
@@ -108,7 +99,7 @@ public class PermissionService
for (SysRole sysRole : loginUser.getUser().getRoles())
{
String roleKey = sysRole.getRoleKey();
if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
{
return true;
}
@@ -144,7 +135,7 @@ public class PermissionService
{
return false;
}
for (String role : roles.split(ROLE_DELIMETER))
for (String role : roles.split(Constants.ROLE_DELIMETER))
{
if (hasRole(role))
{
@@ -163,6 +154,6 @@ public class PermissionService
*/
private boolean hasPermissions(Set<String> permissions, String permission)
{
return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
return permissions.contains(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
}
}

View File

@@ -4,6 +4,8 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@@ -29,6 +31,8 @@ import io.jsonwebtoken.SignatureAlgorithm;
@Component
public class TokenService
{
private static final Logger log = LoggerFactory.getLogger(TokenService.class);
// 令牌自定义标识
@Value("${token.header}")
private String header;
@@ -72,6 +76,7 @@ public class TokenService
}
catch (Exception e)
{
log.error("获取用户信息异常'{}'", e.getMessage());
}
}
return null;

View File

@@ -11,6 +11,7 @@ import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
@@ -40,17 +41,17 @@ public class UserDetailsServiceImpl implements UserDetailsService
if (StringUtils.isNull(user))
{
log.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username + " 不存在");
throw new ServiceException(MessageUtils.message("user.not.exists"));
}
else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
{
log.info("登录用户:{} 已被删除.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已被删除");
throw new ServiceException(MessageUtils.message("user.password.delete"));
}
else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
{
log.info("登录用户:{} 已被停用.", username);
throw new ServiceException("对不起,您的账号:" + username + " 已停用");
throw new ServiceException(MessageUtils.message("user.blocked"));
}
passwordService.validate(user);

View File

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

View File

@@ -41,6 +41,9 @@ public class GenTable extends BaseEntity
/** 使用的模板crud单表操作 tree树表操作 sub主子表操作 */
private String tplCategory;
/** 前端类型element-ui模版 element-plus模版 */
private String tplWebType;
/** 生成包路径 */
@NotBlank(message = "生成包路径不能为空")
private String packageName;
@@ -165,6 +168,16 @@ public class GenTable extends BaseEntity
this.tplCategory = tplCategory;
}
public String getTplWebType()
{
return tplWebType;
}
public void setTplWebType(String tplWebType)
{
this.tplWebType = tplWebType;
}
public String getPackageName()
{
return packageName;

View File

@@ -206,7 +206,7 @@ public class GenTableServiceImpl implements IGenTableService
VelocityContext context = VelocityUtils.prepareContext(table);
// 获取模板列表
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
for (String template : templates)
{
// 渲染模板
@@ -254,7 +254,7 @@ public class GenTableServiceImpl implements IGenTableService
VelocityContext context = VelocityUtils.prepareContext(table);
// 获取模板列表
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
for (String template : templates)
{
if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
@@ -367,7 +367,7 @@ public class GenTableServiceImpl implements IGenTableService
VelocityContext context = VelocityUtils.prepareContext(table);
// 获取模板列表
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
for (String template : templates)
{
// 渲染模板

View File

@@ -123,11 +123,17 @@ public class VelocityUtils
/**
* 获取模板信息
*
* @param tplCategory 生成的模板
* @param tplWebType 前端类型
* @return 模板列表
*/
public static List<String> getTemplateList(String tplCategory)
public static List<String> getTemplateList(String tplCategory, String tplWebType)
{
String useWebType = "vm/vue";
if ("element-plus".equals(tplWebType))
{
useWebType = "vm/vue/v3";
}
List<String> templates = new ArrayList<String>();
templates.add("vm/java/domain.java.vm");
templates.add("vm/java/mapper.java.vm");
@@ -139,15 +145,15 @@ public class VelocityUtils
templates.add("vm/js/api.js.vm");
if (GenConstants.TPL_CRUD.equals(tplCategory))
{
templates.add("vm/vue/index.vue.vm");
templates.add(useWebType + "/index.vue.vm");
}
else if (GenConstants.TPL_TREE.equals(tplCategory))
{
templates.add("vm/vue/index-tree.vue.vm");
templates.add(useWebType + "/index-tree.vue.vm");
}
else if (GenConstants.TPL_SUB.equals(tplCategory))
{
templates.add("vm/vue/index.vue.vm");
templates.add(useWebType + "/index.vue.vm");
templates.add("vm/java/sub-domain.java.vm");
}
return templates;

View File

@@ -40,7 +40,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
order by ordinal_position
</select>

View File

@@ -12,6 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="subTableFkName" column="sub_table_fk_name" />
<result property="className" column="class_name" />
<result property="tplCategory" column="tpl_category" />
<result property="tplWebType" column="tpl_web_type" />
<result property="packageName" column="package_name" />
<result property="moduleName" column="module_name" />
<result property="businessName" column="business_name" />
@@ -54,7 +55,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectGenTableVo">
select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, tpl_web_type, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
</sql>
<select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
@@ -111,7 +112,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@@ -119,7 +120,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@@ -127,7 +128,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@@ -140,6 +141,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="tableComment != null and tableComment != ''">table_comment,</if>
<if test="className != null and className != ''">class_name,</if>
<if test="tplCategory != null and tplCategory != ''">tpl_category,</if>
<if test="tplWebType != null and tplWebType != ''">tpl_web_type,</if>
<if test="packageName != null and packageName != ''">package_name,</if>
<if test="moduleName != null and moduleName != ''">module_name,</if>
<if test="businessName != null and businessName != ''">business_name,</if>
@@ -155,6 +157,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="tableComment != null and tableComment != ''">#{tableComment},</if>
<if test="className != null and className != ''">#{className},</if>
<if test="tplCategory != null and tplCategory != ''">#{tplCategory},</if>
<if test="tplWebType != null and tplWebType != ''">#{tplWebType},</if>
<if test="packageName != null and packageName != ''">#{packageName},</if>
<if test="moduleName != null and moduleName != ''">#{moduleName},</if>
<if test="businessName != null and businessName != ''">#{businessName},</if>
@@ -180,6 +183,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="genType != null and genType != ''">gen_type = #{genType},</if>
<if test="genPath != null and genPath != ''">gen_path = #{genPath},</if>
<if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if>
<if test="tplWebType != null and tplWebType != ''">tpl_web_type = #{tplWebType},</if>
<if test="packageName != null and packageName != ''">package_name = #{packageName},</if>
<if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if>
<if test="businessName != null and businessName != ''">business_name = #{businessName},</if>

View File

@@ -453,7 +453,7 @@ export default {
this.reset();
this.getTreeselect();
if (row != null) {
this.form.${treeParentCode} = row.${treeCode};
this.form.${treeParentCode} = row.${treeParentCode};
}
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
this.form = response.data;

View File

@@ -420,7 +420,7 @@ async function handleUpdate(row) {
reset();
await getTreeselect();
if (row != null) {
form.value.${treeParentCode} = row.${treeCode};
form.value.${treeParentCode} = row.${treeParentCode};
}
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
form.value = response.data;

View File

@@ -1 +0,0 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD>RuoYi-Vue3ǰ<33>ˣ<EFBFBD><CBA3><EFBFBD>ô<EFBFBD><C3B4>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>һ<EFBFBD>´<EFBFBD>Ŀ¼<C4BF><C2BC>ģ<EFBFBD><C4A3>index.vue.vm<76><6D>index-tree.vue.vm<76>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ϼ<EFBFBD>vueĿ¼<C4BF><C2BC>

View File

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

View File

@@ -33,7 +33,7 @@
// // 集群配置
// prop.put("org.quartz.jobStore.isClustered", "true");
// prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
// prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
// prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10");
// prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
//
// // sqlserver 启用

View File

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

View File

@@ -37,7 +37,7 @@ public interface SysUserPostMapper
/**
* 批量新增用户岗位信息
*
* @param userPostList 用户角色列表
* @param userPostList 用户岗位列表
* @return 结果
*/
public int batchUserPost(List<SysUserPost> userPostList);

View File

@@ -525,7 +525,7 @@ public class SysMenuServiceImpl implements ISysMenuService
*/
public String innerLinkReplaceEach(String path)
{
return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, "." },
new String[] { "", "", "", "/" });
return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":" },
new String[] { "", "", "", "/", "/" });
}
}

View File

@@ -37,6 +37,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectOperLogList" parameterType="SysOperLog" resultMap="SysOperLogResult">
<include refid="selectOperLogVo"/>
<where>
<if test="operIp != null and operIp != ''">
AND oper_ip like concat('%', #{operIp}, '%')
</if>
<if test="title != null and title != ''">
AND title like concat('%', #{title}, '%')
</if>

View File

@@ -23,8 +23,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<association property="dept" column="dept_id" javaType="SysDept" resultMap="deptResult" />
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" />
<association property="dept" javaType="SysDept" resultMap="deptResult" />
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" />
</resultMap>
<resultMap id="deptResult" type="SysDept">
@@ -42,7 +42,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="roleName" column="role_name" />
<result property="roleKey" column="role_key" />
<result property="roleSort" column="role_sort" />
<result property="dataScope" column="data_scope" />
<result property="dataScope" column="data_scope" />
<result property="status" column="role_status" />
</resultMap>

View File

@@ -1,6 +1,6 @@
{
"name": "ruoyi",
"version": "3.8.6",
"version": "3.8.7",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
@@ -41,7 +41,7 @@
"clipboard": "2.0.8",
"core-js": "3.25.3",
"echarts": "5.4.0",
"element-ui": "2.15.13",
"element-ui": "2.15.14",
"file-saver": "2.0.5",
"fuse.js": "6.4.3",
"highlight.js": "9.18.5",

View File

@@ -11,14 +11,14 @@ import ThemePicker from "@/components/ThemePicker";
export default {
name: "App",
components: { ThemePicker },
metaInfo() {
return {
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
titleTemplate: title => {
return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
}
}
metaInfo() {
return {
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
titleTemplate: title => {
return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
}
}
}
};
</script>
<style scoped>

View File

@@ -11,7 +11,8 @@ export function login(username, password, code, uuid) {
return request({
url: '/login',
headers: {
isToken: false
isToken: false,
repeatSubmit: false
},
method: 'post',
data: data

View File

@@ -1,129 +1,143 @@
/**
* 通用css样式布局处理
* Copyright (c) 2019 ruoyi
*/
/**
* 通用css样式布局处理
* Copyright (c) 2019 ruoyi
*/
/** 基础通用 **/
/** 基础通用 **/
.pt5 {
padding-top: 5px;
padding-top: 5px;
}
.pr5 {
padding-right: 5px;
padding-right: 5px;
}
.pb5 {
padding-bottom: 5px;
padding-bottom: 5px;
}
.mt5 {
margin-top: 5px;
margin-top: 5px;
}
.mr5 {
margin-right: 5px;
margin-right: 5px;
}
.mb5 {
margin-bottom: 5px;
margin-bottom: 5px;
}
.mb8 {
margin-bottom: 8px;
margin-bottom: 8px;
}
.ml5 {
margin-left: 5px;
margin-left: 5px;
}
.mt10 {
margin-top: 10px;
margin-top: 10px;
}
.mr10 {
margin-right: 10px;
margin-right: 10px;
}
.mb10 {
margin-bottom: 10px;
margin-bottom: 10px;
}
.ml10 {
margin-left: 10px;
}
.mt20 {
margin-top: 20px;
margin-top: 20px;
}
.mr20 {
margin-right: 20px;
margin-right: 20px;
}
.mb20 {
margin-bottom: 20px;
margin-bottom: 20px;
}
.ml20 {
margin-left: 20px;
}
.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
font-family: inherit;
font-weight: 500;
line-height: 1.1;
color: inherit;
font-family: inherit;
font-weight: 500;
line-height: 1.1;
color: inherit;
}
.el-message-box__status + .el-message-box__message{
word-break: break-word;
word-break: break-word;
}
.el-dialog:not(.is-fullscreen) {
margin-top: 6vh !important;
margin-top: 6vh !important;
}
.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
overflow: auto;
overflow-x: hidden;
max-height: 70vh;
padding: 10px 20px 0;
overflow: auto;
overflow-x: hidden;
max-height: 70vh;
padding: 10px 20px 0;
}
.el-table {
.el-table__header-wrapper, .el-table__fixed-header-wrapper {
th {
word-break: break-word;
background-color: #f8f8f9;
color: #515a6e;
height: 40px;
font-size: 13px;
}
}
.el-table__body-wrapper {
.el-button [class*="el-icon-"] + span {
margin-left: 1px;
}
}
.el-table__header-wrapper, .el-table__fixed-header-wrapper {
th {
word-break: break-word;
background-color: #f8f8f9;
color: #515a6e;
height: 40px;
font-size: 13px;
}
}
.el-table__body-wrapper {
.el-button [class*="el-icon-"] + span {
margin-left: 1px;
}
}
}
/** 表单布局 **/
.form-header {
font-size:15px;
color:#6379bb;
border-bottom:1px solid #ddd;
margin:8px 10px 25px 10px;
padding-bottom:5px
font-size: 15px;
color: #6379bb;
border-bottom: 1px solid #ddd;
margin: 8px 10px 25px 10px;
padding-bottom: 5px
}
/** 表格布局 **/
.pagination-container {
position: relative;
height: 25px;
margin-bottom: 10px;
margin-top: 15px;
padding: 10px 20px !important;
position: relative;
height: 25px;
margin-bottom: 10px;
margin-top: 15px;
padding: 10px 20px !important;
}
/* tree border */
.tree-border {
margin-top: 5px;
border: 1px solid #e5e6e7;
background: #FFFFFF none;
border-radius:4px;
margin-top: 5px;
border: 1px solid #e5e6e7;
background: #FFFFFF none;
border-radius: 4px;
}
.pagination-container .el-pagination {
right: 0;
position: absolute;
right: 0;
position: absolute;
}
@media ( max-width : 768px) {
@media (max-width: 768px) {
.pagination-container .el-pagination > .el-pagination__jump {
display: none !important;
}
@@ -133,9 +147,9 @@
}
.el-table .fixed-width .el-button--mini {
padding-left: 0;
padding-right: 0;
width: inherit;
padding-left: 0;
padding-right: 0;
width: inherit;
}
/** 表格更多操作下拉样式 */
@@ -145,51 +159,51 @@
}
.el-table .el-dropdown, .el-icon-arrow-down {
font-size: 12px;
font-size: 12px;
}
.el-tree-node__content > .el-checkbox {
margin-right: 8px;
margin-right: 8px;
}
.list-group-striped > .list-group-item {
border-left: 0;
border-right: 0;
border-radius: 0;
padding-left: 0;
padding-right: 0;
border-left: 0;
border-right: 0;
border-radius: 0;
padding-left: 0;
padding-right: 0;
}
.list-group {
padding-left: 0px;
list-style: none;
padding-left: 0px;
list-style: none;
}
.list-group-item {
border-bottom: 1px solid #e7eaec;
border-top: 1px solid #e7eaec;
margin-bottom: -1px;
padding: 11px 0px;
font-size: 13px;
border-bottom: 1px solid #e7eaec;
border-top: 1px solid #e7eaec;
margin-bottom: -1px;
padding: 11px 0px;
font-size: 13px;
}
.pull-right {
float: right !important;
float: right !important;
}
.el-card__header {
padding: 14px 15px 7px;
min-height: 40px;
padding: 14px 15px 7px;
min-height: 40px;
}
.el-card__body {
padding: 15px 20px 20px 20px;
padding: 15px 20px 20px 20px;
}
.card-box {
padding-right: 15px;
padding-left: 15px;
margin-bottom: 10px;
padding-right: 15px;
padding-left: 15px;
margin-bottom: 10px;
}
/* button color */
@@ -215,63 +229,63 @@
/* text color */
.text-navy {
color: #1ab394;
color: #1ab394;
}
.text-primary {
color: inherit;
color: inherit;
}
.text-success {
color: #1c84c6;
color: #1c84c6;
}
.text-info {
color: #23c6c8;
color: #23c6c8;
}
.text-warning {
color: #f8ac59;
color: #f8ac59;
}
.text-danger {
color: #ed5565;
color: #ed5565;
}
.text-muted {
color: #888888;
color: #888888;
}
/* image */
.img-circle {
border-radius: 50%;
border-radius: 50%;
}
.img-lg {
width: 120px;
height: 120px;
width: 120px;
height: 120px;
}
.avatar-upload-preview {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;
}
/* 拖拽列样式 */
.sortable-ghost{
opacity: .8;
color: #fff!important;
background: #42b983!important;
.sortable-ghost {
opacity: .8;
color: #fff !important;
background: #42b983 !important;
}
.top-right-btn {
position: relative;
float: right;
position: relative;
float: right;
}

View File

@@ -3,11 +3,11 @@
<template v-for="(item, index) in options">
<template v-if="values.includes(item.value)">
<span
v-if="item.raw.listClass == 'default' || item.raw.listClass == ''"
v-if="(item.raw.listClass == 'default' || item.raw.listClass == '') && (item.raw.cssClass == '' || item.raw.cssClass == null)"
:key="item.value"
:index="index"
:class="item.raw.cssClass"
>{{ item.label + " " }}</span
>{{ item.label + ' ' }}</span
>
<el-tag
v-else
@@ -17,7 +17,7 @@
:type="item.raw.listClass == 'primary' ? '' : item.raw.listClass"
:class="item.raw.cssClass"
>
{{ item.label + " " }}
{{ item.label + ' ' }}
</el-tag>
</template>
</template>
@@ -40,6 +40,10 @@ export default {
showValue: {
type: Boolean,
default: true,
},
separator: {
type: String,
default: ","
}
},
data() {
@@ -49,39 +53,32 @@ export default {
},
computed: {
values() {
if (this.value !== null && typeof this.value !== "undefined") {
return Array.isArray(this.value) ? this.value : [String(this.value)];
} else {
return [];
}
if (this.value === null || typeof this.value === 'undefined' || this.value === '') return []
return Array.isArray(this.value) ? this.value.map(item => '' + item) : String(this.value).split(this.separator)
},
unmatch() {
this.unmatchArray = [];
if (this.value !== null && typeof this.value !== "undefined") {
// 传入值为非数组
if (!Array.isArray(this.value)) {
if (this.options.some((v) => v.value == this.value)) return false;
this.unmatchArray.push(this.value);
return true;
}
// 传入值为Array
this.value.forEach((item) => {
if (!this.options.some((v) => v.value == item))
this.unmatchArray.push(item);
});
return true;
}
this.unmatchArray = []
// 没有value不显示
return false;
if (this.value === null || typeof this.value === 'undefined' || this.value === '' || this.options.length === 0) return false
// 传入值为数组
let unmatch = false // 添加一个标志来判断是否有未匹配项
this.values.forEach(item => {
if (!this.options.some(v => v.value === item)) {
this.unmatchArray.push(item)
unmatch = true // 如果有未匹配项将标志设置为true
}
})
return unmatch // 返回标志的值
},
},
filters: {
handleArray(array) {
if (array.length === 0) return "";
if (array.length === 0) return '';
return array.reduce((pre, cur) => {
return pre + " " + cur;
return pre + ' ' + cur;
})
}
},
}
};
</script>

View File

@@ -47,7 +47,7 @@ export default {
type: Boolean,
default: false,
},
// 上传文件大小限制(MB)
/* 上传文件大小限制(MB) */
fileSize: {
type: Number,
default: 5,
@@ -129,7 +129,6 @@ export default {
if (this.type == 'url') {
let toolbar = this.Quill.getModule("toolbar");
toolbar.addHandler("image", (value) => {
this.uploadType = "image";
if (value) {
this.$refs.upload.$children[0].$refs.input.click();
} else {
@@ -158,6 +157,13 @@ export default {
},
// 上传前校检格式和大小
handleBeforeUpload(file) {
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
const isJPG = type.includes(file.type);
// 检验文件格式
if (!isJPG) {
this.$message.error(`图片格式错误!`);
return false;
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
@@ -169,10 +175,10 @@ export default {
return true;
},
handleUploadSuccess(res, file) {
// 获取富文本组件实例
let quill = this.Quill;
// 如果上传成功
if (res.code == 200) {
// 获取富文本组件实例
let quill = this.Quill;
// 获取光标所在位置
let length = quill.getSelection().index;
// 插入图片 res.url为服务器返回的图片地址
@@ -206,11 +212,9 @@ export default {
content: "保存";
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode="video"]::before {
content: "请输入视频地址:";
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: "14px";
@@ -227,7 +231,6 @@ export default {
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
content: "32px";
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: "文本";
@@ -256,7 +259,6 @@ export default {
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: "标题6";
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: "标准字体";

View File

@@ -142,7 +142,7 @@ export default {
// 上传失败
handleUploadError(err) {
this.$modal.msgError("上传文件失败,请重试");
this.$modal.closeLoading()
this.$modal.closeLoading();
},
// 上传成功回调
handleUploadSuccess(res, file) {
@@ -174,10 +174,11 @@ export default {
},
// 获取文件名称
getFileName(name) {
// 如果是url那么取最后的名字 如果不是直接返回
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1);
} else {
return "";
return name;
}
},
// 对象转成指定字符串分隔

View File

@@ -71,12 +71,17 @@ export default {
},
change(val) {
const path = val.path;
const query = val.query;
if(this.ishttp(val.path)) {
// http(s):// 路径新窗口打开
const pindex = path.indexOf("http");
window.open(path.substr(pindex, path.length), "_blank");
} else {
this.$router.push(val.path)
if (query) {
this.$router.push({ path: path, query: JSON.parse(query) });
} else {
this.$router.push(path)
}
}
this.search = ''
this.options = []
@@ -124,6 +129,10 @@ export default {
}
}
if (router.query) {
data.query = router.query
}
// recursive child routes
if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)

View File

@@ -19,7 +19,7 @@
>
<i class="el-icon-plus"></i>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
请上传
@@ -168,7 +168,7 @@ export default {
// 删除图片
handleDelete(file) {
const findex = this.fileList.map(f => f.name).indexOf(file.name);
if(findex > -1) {
if (findex > -1) {
this.fileList.splice(findex, 1);
this.$emit("input", this.listToString(this.fileList));
}
@@ -219,8 +219,8 @@ export default {
}
::v-deep .el-list-enter, .el-list-leave-active {
opacity: 0;
transform: translateY(0);
opacity: 0;
transform: translateY(0);
}
</style>

View File

@@ -8,7 +8,17 @@
<el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
</el-tooltip>
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
<el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" />
<el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" v-if="showColumnsType == 'transfer'"/>
<el-dropdown trigger="click" :hide-on-click="false" style="padding-left: 12px" v-if="showColumnsType == 'checkbox'">
<el-button size="mini" circle icon="el-icon-menu" />
<el-dropdown-menu slot="dropdown">
<template v-for="item in columns">
<el-dropdown-item :key="item.key">
<el-checkbox :checked="item.visible" @change="checkboxChange($event, item.label)" :label="item.label" />
</el-dropdown-item>
</template>
</el-dropdown-menu>
</el-dropdown>
</el-tooltip>
</el-row>
<el-dialog :title="title" :visible.sync="open" append-to-body>
@@ -35,17 +45,26 @@ export default {
};
},
props: {
/* 是否显示检索条件 */
showSearch: {
type: Boolean,
default: true,
},
/* 显隐列信息 */
columns: {
type: Array,
},
/* 是否显示检索图标 */
search: {
type: Boolean,
default: true,
},
/* 显隐列类型transfer穿梭框、checkbox复选框 */
showColumnsType: {
type: String,
default: "checkbox",
},
/* 右外边距 */
gutter: {
type: Number,
default: 10,
@@ -61,10 +80,12 @@ export default {
}
},
created() {
// 显隐列初始默认隐藏列
for (let item in this.columns) {
if (this.columns[item].visible === false) {
this.value.push(parseInt(item));
if (this.showColumnsType == 'transfer') {
// 显隐列初始默认隐藏列
for (let item in this.columns) {
if (this.columns[item].visible === false) {
this.value.push(parseInt(item));
}
}
}
},
@@ -88,6 +109,10 @@ export default {
showColumn() {
this.open = true;
},
// 勾选
checkboxChange(event, label) {
this.columns.filter(item => item.label == label)[0].visible = event;
}
},
};
</script>

View File

@@ -5,10 +5,12 @@
@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
>
<el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber">
<svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon"/>
{{ item.meta.title }}
</el-menu-item>
</template>
<!-- 顶部菜单超出数量折叠 -->
@@ -18,10 +20,12 @@
<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
>
v-if="index >= visibleNumber">
<svg-icon
v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
:icon-class="item.meta.icon"/>
{{ item.meta.title }}
</el-menu-item>
</template>
</el-submenu>
</el-menu>
@@ -53,9 +57,9 @@ export default {
if (menu.hidden !== true) {
// 兼容顶部栏一级菜单内部跳转
if (menu.path === "/") {
topMenus.push(menu.children[0]);
topMenus.push(menu.children[0]);
} else {
topMenus.push(menu);
topMenus.push(menu);
}
}
});

View File

@@ -1,34 +1,34 @@
/**
* v-dialogDragWidth 可拖动弹窗高度(右下角)
* Copyright (c) 2019 ruoyi
*/
* v-dialogDragWidth 可拖动弹窗高度(右下角)
* Copyright (c) 2019 ruoyi
*/
export default {
bind(el) {
const dragDom = el.querySelector('.el-dialog');
const lineEl = document.createElement('div');
lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;';
lineEl.addEventListener('mousedown',
function(e) {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft;
const disY = e.clientY - el.offsetTop;
// 当前宽度 高度
const curWidth = dragDom.offsetWidth;
const curHeight = dragDom.offsetHeight;
document.onmousemove = function(e) {
e.preventDefault(); // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const xl = e.clientX - disX;
const yl = e.clientY - disY
dragDom.style.width = `${curWidth + xl}px`;
dragDom.style.height = `${curHeight + yl}px`;
};
document.onmouseup = function(e) {
document.onmousemove = null;
document.onmouseup = null;
};
}, false);
dragDom.appendChild(lineEl);
}
}
bind(el) {
const dragDom = el.querySelector('.el-dialog');
const lineEl = document.createElement('div');
lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;';
lineEl.addEventListener('mousedown',
function(e) {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft;
const disY = e.clientY - el.offsetTop;
// 当前宽度 高度
const curWidth = dragDom.offsetWidth;
const curHeight = dragDom.offsetHeight;
document.onmousemove = function(e) {
e.preventDefault(); // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const xl = e.clientX - disX;
const yl = e.clientY - disY
dragDom.style.width = `${curWidth + xl}px`;
dragDom.style.height = `${curHeight + yl}px`;
};
document.onmouseup = function(e) {
document.onmousemove = null;
document.onmouseup = null;
};
}, false);
dragDom.appendChild(lineEl);
}
}

View File

@@ -1,30 +1,30 @@
/**
* v-dialogDragWidth 可拖动弹窗宽度(右侧边)
* Copyright (c) 2019 ruoyi
*/
* v-dialogDragWidth 可拖动弹窗宽度(右侧边)
* Copyright (c) 2019 ruoyi
*/
export default {
bind(el) {
const dragDom = el.querySelector('.el-dialog');
const lineEl = document.createElement('div');
lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;';
lineEl.addEventListener('mousedown',
function (e) {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft;
// 当前宽度
const curWidth = dragDom.offsetWidth;
document.onmousemove = function (e) {
e.preventDefault(); // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const l = e.clientX - disX;
dragDom.style.width = `${curWidth + l}px`;
};
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
}, false);
dragDom.appendChild(lineEl);
}
}
bind(el) {
const dragDom = el.querySelector('.el-dialog');
const lineEl = document.createElement('div');
lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;';
lineEl.addEventListener('mousedown',
function (e) {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft;
// 当前宽度
const curWidth = dragDom.offsetWidth;
document.onmousemove = function (e) {
e.preventDefault(); // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const l = e.clientX - disX;
dragDom.style.width = `${curWidth + l}px`;
};
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
}, false);
dragDom.appendChild(lineEl);
}
}

View File

@@ -2,7 +2,7 @@
* v-hasPermi 操作权限处理
* Copyright (c) 2019 ruoyi
*/
import store from '@/store'
export default {

View File

@@ -2,7 +2,7 @@
* v-hasRole 角色权限处理
* Copyright (c) 2019 ruoyi
*/
import store from '@/store'
export default {

View File

@@ -5,19 +5,28 @@
:key="item.path"
:iframeId="'iframe' + index"
v-show="$route.path === item.path"
:src="item.meta.link"
:src="iframeUrl(item.meta.link, item.query)"
></inner-link>
</transition-group>
</template>
<script>
import InnerLink from "../InnerLink/index"
import InnerLink from "../InnerLink/index";
export default {
components: { InnerLink },
computed: {
iframeViews() {
return this.$store.state.tagsView.iframeViews
return this.$store.state.tagsView.iframeViews;
}
},
methods: {
iframeUrl(url, query) {
if (Object.keys(query).length > 0) {
let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&");
return url + "?" + params;
}
return url;
}
}
}

View File

@@ -8,7 +8,7 @@
<div class="right-menu">
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>

View File

@@ -38,7 +38,7 @@
<el-divider/>
<h3 class="drawer-title">系统布局配置</h3>
<div class="drawer-item">
<span>开启 TopNav</span>
<el-switch v-model="topNav" class="drawer-switch" />

View File

@@ -13,8 +13,8 @@
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
v-for="(child, index) in item.children"
:key="child.path + index"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"

View File

@@ -87,7 +87,7 @@ export default {
bottom: 0px;
}
.el-scrollbar__wrap {
height: 39px;
height: 49px;
}
}
}

View File

@@ -18,6 +18,8 @@ router.beforeEach((to, from, next) => {
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
if (store.getters.roles.length === 0) {
isRelogin.show = true
@@ -45,7 +47,7 @@ router.beforeEach((to, from, next) => {
// 在免登录白名单,直接进入
next()
} else {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 否则全部重定向到登录页
NProgress.done()
}
}

View File

@@ -1,11 +1,12 @@
import axios from 'axios'
import { Message } from 'element-ui'
import {Loading, Message} from 'element-ui'
import { saveAs } from 'file-saver'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { blobValidate } from "@/utils/ruoyi";
const baseURL = process.env.VUE_APP_BASE_API
let downloadLoadingInstance;
export default {
name(name, isDelete = true) {
@@ -44,6 +45,7 @@ export default {
},
zip(url, name) {
var url = baseURL + url
downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
axios({
method: 'get',
url: url,
@@ -57,6 +59,11 @@ export default {
} else {
this.printErrMsg(res.data);
}
downloadLoadingInstance.close();
}).catch((r) => {
console.error(r)
Message.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close();
})
},
saveAs(text, name, opts) {

View File

@@ -35,7 +35,7 @@ export default {
return store.dispatch('tagsView/delView', router.currentRoute).then(({ visitedViews }) => {
const latestView = visitedViews.slice(-1)[0]
if (latestView) {
return router.push(latestView.fullPath)
return router.push(latestView.fullPath)
}
return router.push('/');
});
@@ -60,7 +60,7 @@ export default {
},
// 添加tab页签
openPage(title, url, params) {
var obj = { path: url, meta: { title: title } }
const obj = { path: url, meta: { title: title } }
store.dispatch('tagsView/addView', obj);
return router.push({ path: url, query: params });
},

View File

@@ -14,7 +14,7 @@ const mutations = {
try {
for (let i = 0; i < state.dict.length; i++) {
if (state.dict[i].key == key) {
state.dict.splice(i, i)
state.dict.splice(i, 1)
return true
}
}

View File

@@ -98,6 +98,10 @@ function filterChildren(childrenMap, lastRouter = false) {
}
if (lastRouter) {
el.path = lastRouter.path + '/' + el.path
if (el.children && el.children.length) {
children = children.concat(filterChildren(el.children, el))
return
}
}
children = children.concat(el)
})

View File

@@ -4,6 +4,7 @@ import { getToken, setToken, removeToken } from '@/utils/auth'
const user = {
state: {
token: getToken(),
id: '',
name: '',
avatar: '',
roles: [],
@@ -14,6 +15,9 @@ const user = {
SET_TOKEN: (state, token) => {
state.token = token
},
SET_ID: (state, id) => {
state.id = id
},
SET_NAME: (state, name) => {
state.name = name
},
@@ -58,6 +62,7 @@ const user = {
} else {
commit('SET_ROLES', ['ROLE_DEFAULT'])
}
commit('SET_ID', user.userId)
commit('SET_NAME', user.userName)
commit('SET_AVATAR', avatar)
resolve(res)

View File

@@ -5,12 +5,12 @@ import { parseTime } from './ruoyi'
*/
export function formatDate(cellValue) {
if (cellValue == null || cellValue == "") return "";
var date = new Date(cellValue)
var date = new Date(cellValue)
var year = date.getFullYear()
var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
}
@@ -330,7 +330,7 @@ export function makeMap(str, expectsLowerCase) {
? val => map[val.toLowerCase()]
: val => map[val]
}
export const exportDefault = 'export default '
export const beautifierConf = {
@@ -387,4 +387,4 @@ export function camelCase(str) {
export function isNumberStr(str) {
return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
}

View File

@@ -15,10 +15,8 @@ export function checkPermi(value) {
return all_permission === permission || permissionDatas.includes(permission)
})
if (!hasPermission) {
return false
}
return true
return hasPermission;
} else {
console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
return false
@@ -40,10 +38,8 @@ export function checkRole(value) {
return super_admin === role || permissionRoles.includes(role)
})
if (!hasRole) {
return false
}
return true
return hasRole;
} else {
console.error(`need roles! Like checkRole="['admin','editor']"`)
return false

View File

@@ -42,6 +42,12 @@ service.interceptors.request.use(config => {
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制无法进行防重复提交验证。')
return config;
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)

View File

@@ -65,10 +65,7 @@ export function validEmail(email) {
* @returns {Boolean}
*/
export function isString(str) {
if (typeof str === 'string' || str instanceof String) {
return true
}
return false
return typeof str === 'string' || str instanceof String;
}
/**

View File

@@ -1,3 +0,0 @@
const elementIcons = ['platform-eleme', 'eleme', 'delete-solid', 'delete', 's-tools', 'setting', 'user-solid', 'user', 'phone', 'phone-outline', 'more', 'more-outline', 'star-on', 'star-off', 's-goods', 'goods', 'warning', 'warning-outline', 'question', 'info', 'remove', 'circle-plus', 'success', 'error', 'zoom-in', 'zoom-out', 'remove-outline', 'circle-plus-outline', 'circle-check', 'circle-close', 's-help', 'help', 'minus', 'plus', 'check', 'close', 'picture', 'picture-outline', 'picture-outline-round', 'upload', 'upload2', 'download', 'camera-solid', 'camera', 'video-camera-solid', 'video-camera', 'message-solid', 'bell', 's-cooperation', 's-order', 's-platform', 's-fold', 's-unfold', 's-operation', 's-promotion', 's-home', 's-release', 's-ticket', 's-management', 's-open', 's-shop', 's-marketing', 's-flag', 's-comment', 's-finance', 's-claim', 's-custom', 's-opportunity', 's-data', 's-check', 's-grid', 'menu', 'share', 'd-caret', 'caret-left', 'caret-right', 'caret-bottom', 'caret-top', 'bottom-left', 'bottom-right', 'back', 'right', 'bottom', 'top', 'top-left', 'top-right', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'd-arrow-left', 'd-arrow-right', 'video-pause', 'video-play', 'refresh', 'refresh-right', 'refresh-left', 'finished', 'sort', 'sort-up', 'sort-down', 'rank', 'loading', 'view', 'c-scale-to-original', 'date', 'edit', 'edit-outline', 'folder', 'folder-opened', 'folder-add', 'folder-remove', 'folder-delete', 'folder-checked', 'tickets', 'document-remove', 'document-delete', 'document-copy', 'document-checked', 'document', 'document-add', 'printer', 'paperclip', 'takeaway-box', 'search', 'monitor', 'attract', 'mobile', 'scissors', 'umbrella', 'headset', 'brush', 'mouse', 'coordinate', 'magic-stick', 'reading', 'data-line', 'data-board', 'pie-chart', 'data-analysis', 'collection-tag', 'film', 'suitcase', 'suitcase-1', 'receiving', 'collection', 'files', 'notebook-1', 'notebook-2', 'toilet-paper', 'office-building', 'school', 'table-lamp', 'house', 'no-smoking', 'smoking', 'shopping-cart-full', 'shopping-cart-1', 'shopping-cart-2', 'shopping-bag-1', 'shopping-bag-2', 'sold-out', 'sell', 'present', 'box', 'bank-card', 'money', 'coin', 'wallet', 'discount', 'price-tag', 'news', 'guide', 'male', 'female', 'thumb', 'cpu', 'link', 'connection', 'open', 'turn-off', 'set-up', 'chat-round', 'chat-line-round', 'chat-square', 'chat-dot-round', 'chat-dot-square', 'chat-line-square', 'message', 'postcard', 'position', 'turn-off-microphone', 'microphone', 'close-notification', 'bangzhu', 'time', 'odometer', 'crop', 'aim', 'switch-button', 'full-screen', 'copy-document', 'mic', 'stopwatch', 'medal-1', 'medal', 'trophy', 'trophy-1', 'first-aid-kit', 'discover', 'place', 'location', 'location-outline', 'location-information', 'add-location', 'delete-location', 'map-location', 'alarm-clock', 'timer', 'watch-1', 'watch', 'lock', 'unlock', 'key', 'service', 'mobile-phone', 'bicycle', 'truck', 'ship', 'basketball', 'football', 'soccer', 'baseball', 'wind-power', 'light-rain', 'lightning', 'heavy-rain', 'sunrise', 'sunrise-1', 'sunset', 'sunny', 'cloudy', 'partly-cloudy', 'cloudy-and-sunny', 'moon', 'moon-night', 'dish', 'dish-1', 'food', 'chicken', 'fork-spoon', 'knife-fork', 'burger', 'tableware', 'sugar', 'dessert', 'ice-cream', 'hot-water', 'water-cup', 'coffee-cup', 'cold-drink', 'goblet', 'goblet-full', 'goblet-square', 'goblet-square-full', 'refrigerator', 'grape', 'watermelon', 'cherry', 'apple', 'pear', 'orange', 'coffee', 'ice-tea', 'ice-drink', 'milk-tea', 'potato-strips', 'lollipop', 'ice-cream-square', 'ice-cream-round']
export default elementIcons

View File

@@ -1,87 +0,0 @@
<template>
<div class="icons-container">
<aside>
<a href="#" target="_blank">Add and use
</a>
</aside>
<el-tabs type="border-card">
<el-tab-pane label="Icons">
<div v-for="item of svgIcons" :key="item">
<el-tooltip placement="top">
<div slot="content">
{{ generateIconCode(item) }}
</div>
<div class="icon-item">
<svg-icon :icon-class="item" class-name="disabled" />
<span>{{ item }}</span>
</div>
</el-tooltip>
</div>
</el-tab-pane>
<el-tab-pane label="Element-UI Icons">
<div v-for="item of elementIcons" :key="item">
<el-tooltip placement="top">
<div slot="content">
{{ generateElementIconCode(item) }}
</div>
<div class="icon-item">
<i :class="'el-icon-' + item" />
<span>{{ item }}</span>
</div>
</el-tooltip>
</div>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import svgIcons from './svg-icons'
import elementIcons from './element-icons'
export default {
name: 'Icons',
data() {
return {
svgIcons,
elementIcons
}
},
methods: {
generateIconCode(symbol) {
return `<svg-icon icon-class="${symbol}" />`
},
generateElementIconCode(symbol) {
return `<i class="el-icon-${symbol}" />`
}
}
}
</script>
<style lang="scss" scoped>
.icons-container {
margin: 10px 20px 0;
overflow: hidden;
.icon-item {
margin: 20px;
height: 85px;
text-align: center;
width: 100px;
float: left;
font-size: 30px;
color: #24292e;
cursor: pointer;
}
span {
display: block;
font-size: 16px;
margin-top: 10px;
}
.disabled {
pointer-events: none;
}
}
</style>

View File

@@ -1,10 +0,0 @@
const req = require.context('../../../assets/icons/svg', false, /\.svg$/)
const requireAll = requireContext => requireContext.keys()
const re = /\.\/(.*)\.svg/
const svgIcons = requireAll(req).map(i => {
return i.match(re)[1]
})
export default svgIcons

View File

@@ -3,7 +3,7 @@
</template>
<script>
import * as echarts from 'echarts';
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'

View File

@@ -3,7 +3,7 @@
</template>
<script>
import * as echarts from 'echarts';
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'

View File

@@ -3,7 +3,7 @@
</template>
<script>
import * as echarts from 'echarts';
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'

View File

@@ -3,7 +3,7 @@
</template>
<script>
import * as echarts from 'echarts';
import * as echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'

View File

@@ -122,7 +122,7 @@
<s> 满180251782 </s> <s> 满104180207 </s> <s> 满186866453 </s> <s> 满201396349 </s>
<s> 满101456076 </s> <s> 满101539465 </s> <s> 满264312783 </s> <s> 满167385320 </s>
<s> 满104748341 </s> <s> 满160110482 </s> <s> 满170801498 </s> <s> 满108482800 </s>
<s> 满101046199 </s> <a href="https://jq.qq.com/?_wv=1027&k=tKEt51dz" target="_blank">136919097</a>
<s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=1HmEGh7zKA_CKI2E-pGInPTlC5jS9mc_&authKey=XaiUf1wfbSTEecm4lDMtIMsc6g%2BoETxjBm1BbZPr6IfuMGRj7oG4GEeu7jtzNaw%2F&noverify=0&group_code=174951577" target="_blank">174951577</a>
</p>
<p>
<i class="el-icon-chat-dot-round"></i> 微信<a
@@ -146,6 +146,49 @@
<span>更新日志</span>
</div>
<el-collapse accordion>
<el-collapse-item title="v3.8.7 - 2023-12-08">
<ol>
<li>操作日志记录部门名称</li>
<li>全局数据存储用户编号</li>
<li>新增编程式判断资源访问权限</li>
<li>操作日志列表新增IP地址查询</li>
<li>定时任务新增页去除状态选项</li>
<li>代码生成支持选择前端模板类型</li>
<li>显隐列组件支持复选框弹出类型</li>
<li>通用排序属性orderBy参数限制长度</li>
<li>Excel自定义数据处理器增加单元格/工作簿对象</li>
<li>升级oshi到最新版本6.4.8</li>
<li>升级druid到最新版本1.2.20</li>
<li>升级fastjson到最新版2.0.43</li>
<li>升级pagehelper到最新版1.4.7</li>
<li>升级commons.io到最新版本2.13.0</li>
<li>升级element-ui到最新版本2.15.14</li>
<li>修复五级路由缓存无效问题</li>
<li>修复外链带端口出现的异常</li>
<li>修复树模板父级编码变量错误</li>
<li>修复字典表详情页面搜索问题</li>
<li>修复内链iframe没有传递参数问题</li>
<li>修复自定义字典样式不生效的问题</li>
<li>修复字典缓存删除方法参数错误问题</li>
<li>修复Excel导入数据临时文件无法删除问题</li>
<li>修复未登录带参数访问成功后参数丢失问题</li>
<li>修复HeaderSearch组件跳转query参数丢失问题</li>
<li>修复代码生成导入后必填项与数据库不匹配问题</li>
<li>修复Excels导入时无法获取到dictType字典值问题</li>
<li>优化下载zip方法新增遮罩层</li>
<li>优化头像上传参数新增文件名称</li>
<li>优化字典标签支持自定义分隔符</li>
<li>优化菜单管理类型为按钮状态可选</li>
<li>优化前端防重复提交数据大小限制</li>
<li>优化TopNav菜单没有图标svg不显示</li>
<li>优化数字金额大写转换精度丢失问题</li>
<li>优化富文本Editor组件检验图片格式</li>
<li>优化页签在Firefox浏览器被遮挡的问题</li>
<li>优化个人中心/基本资料修改时数据显示问题</li>
<li>优化缓存监控图表支持跟随屏幕大小自适应调整</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.6 - 2023-06-30">
<ol>
<li>支持登录IP黑名单限制</li>
@@ -946,7 +989,7 @@ export default {
data() {
return {
// 版本号
version: "3.8.6"
version: "3.8.7"
};
},
methods: {

View File

@@ -133,6 +133,10 @@ export default {
}
]
});
window.addEventListener("resize", () => {
this.commandstats.resize();
this.usedmemory.resize();
});
});
},
// 打开加载层

View File

@@ -200,7 +200,18 @@
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-col :span="24" v-if="form.jobId !== undefined">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in dict.type.sys_job_status"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="执行策略" prop="misfirePolicy">
<el-radio-group v-model="form.misfirePolicy" size="small">
<el-radio-button label="1">立即执行</el-radio-button>
@@ -217,17 +228,6 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio
v-for="dict in dict.type.sys_job_status"
:key="dict.value"
:label="dict.value"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
@@ -264,7 +264,7 @@
<el-col :span="12">
<el-form-item label="任务状态:">
<div v-if="form.status == 0">正常</div>
<div v-else-if="form.status == 1">失败</div>
<div v-else-if="form.status == 1">暂停</div>
</el-form-item>
</el-col>
<el-col :span="12">

View File

@@ -1,6 +1,15 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="操作地址" prop="operIp">
<el-input
v-model="queryParams.operIp"
placeholder="请输入操作地址"
clearable
style="width: 240px;"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="系统模块" prop="title">
<el-input
v-model="queryParams.title"
@@ -151,7 +160,7 @@
/>
<!-- 操作日志详细 -->
<el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body>
<el-dialog title="操作日志详细" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" label-width="100px" size="mini">
<el-row>
<el-col :span="12">
@@ -173,7 +182,7 @@
<el-col :span="24">
<el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
</el-col>
<el-col :span="6">
<el-col :span="8">
<el-form-item label="操作状态:">
<div v-if="form.status === 0">正常</div>
<div v-else-if="form.status === 1">失败</div>
@@ -182,7 +191,7 @@
<el-col :span="8">
<el-form-item label="消耗时间:">{{ form.costTime }}毫秒</el-form-item>
</el-col>
<el-col :span="10">
<el-col :span="8">
<el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
</el-col>
<el-col :span="24">
@@ -229,6 +238,7 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 10,
operIp: undefined,
title: undefined,
operName: undefined,
businessType: undefined,

View File

@@ -95,8 +95,8 @@
<el-table-column label="字典编码" align="center" prop="dictCode" />
<el-table-column label="字典标签" align="center" prop="dictLabel">
<template slot-scope="scope">
<span v-if="scope.row.listClass == '' || scope.row.listClass == 'default'">{{scope.row.dictLabel}}</span>
<el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass">{{scope.row.dictLabel}}</el-tag>
<span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
<el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
</template>
</el-table-column>
<el-table-column label="字典键值" align="center" prop="dictValue" />
@@ -251,8 +251,8 @@ export default {
queryParams: {
pageNum: 1,
pageSize: 10,
dictName: undefined,
dictType: undefined,
dictLabel: undefined,
status: undefined
},
// 表单参数

View File

@@ -246,7 +246,7 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.menuType != 'F'">
<el-col :span="12">
<el-form-item prop="status">
<span slot="label">
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">

View File

@@ -33,7 +33,7 @@
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
<el-form label-width="100px">

View File

@@ -8,7 +8,7 @@
</div>
<div>
<div class="text-center">
<userAvatar :user="user" />
<userAvatar />
</div>
<ul class="list-group list-group-striped">
<li class="list-group-item">

View File

@@ -61,11 +61,6 @@ import { debounce } from '@/utils'
export default {
components: { VueCropper },
props: {
user: {
type: Object
}
},
data() {
return {
// 是否显示弹出层
@@ -75,12 +70,13 @@ export default {
// 弹出层标题
title: "修改头像",
options: {
img: store.getters.avatar, //裁剪图片的地址
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
outputType:"png" // 默认生成截图为PNG格式
img: store.getters.avatar, //裁剪图片的地址
autoCrop: true, // 是否默认生成截图框
autoCropWidth: 200, // 默认生成截图框宽度
autoCropHeight: 200, // 默认生成截图框高度
fixedBox: true, // 固定截图框大小 不允许改变
outputType:"png", // 默认生成截图为PNG格式
filename: 'avatar' // 文件名称
},
previews: {},
resizeHandler: null
@@ -130,6 +126,7 @@ export default {
reader.readAsDataURL(file);
reader.onload = () => {
this.options.img = reader.result;
this.options.filename = file.name;
};
}
},
@@ -137,7 +134,7 @@ export default {
uploadImg() {
this.$refs.cropper.getCropBlob(data => {
let formData = new FormData();
formData.append("avatarfile", data);
formData.append("avatarfile", data, this.options.filename);
uploadAvatar(formData).then(response => {
this.open = false;
this.options.img = process.env.VUE_APP_BASE_API + response.imgUrl;

View File

@@ -1,16 +1,16 @@
<template>
<el-form ref="form" :model="user" :rules="rules" label-width="80px">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="user.nickName" maxlength="30" />
<el-input v-model="form.nickName" maxlength="30" />
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="user.phonenumber" maxlength="11" />
<el-input v-model="form.phonenumber" maxlength="11" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="user.email" maxlength="50" />
<el-input v-model="form.email" maxlength="50" />
</el-form-item>
<el-form-item label="性别">
<el-radio-group v-model="user.sex">
<el-radio-group v-model="form.sex">
<el-radio label="0"></el-radio>
<el-radio label="1"></el-radio>
</el-radio-group>
@@ -33,6 +33,7 @@ export default {
},
data() {
return {
form: {},
// 表单校验
rules: {
nickName: [
@@ -57,12 +58,24 @@ export default {
}
};
},
watch: {
user: {
handler(user) {
if (user) {
this.form = { nickName: user.nickName, phonenumber: user.phonenumber, email: user.email, sex: user.sex };
}
},
immediate: true
}
},
methods: {
submit() {
this.$refs["form"].validate(valid => {
if (valid) {
updateUserProfile(this.user).then(response => {
updateUserProfile(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.user.phonenumber = this.form.phonenumber;
this.user.email = this.form.email;
});
}
});

View File

@@ -11,6 +11,15 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="tplWebType">
<span slot="label">前端类型</span>
<el-select v-model="info.tplWebType">
<el-option label="Vue2 Element UI 模版" value="element-ui" />
<el-option label="Vue3 Element Plus 模版" value="element-plus" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="packageName">
<span slot="label">
@@ -59,6 +68,19 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="genType">
<span slot="label">
生成代码方式
<el-tooltip content="默认为zip压缩包下载也可以自定义生成路径" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
<el-radio v-model="info.genType" label="1">自定义路径</el-radio>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<span slot="label">
@@ -78,19 +100,6 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="genType">
<span slot="label">
生成代码方式
<el-tooltip content="默认为zip压缩包下载也可以自定义生成路径" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
<el-radio v-model="info.genType" label="1">自定义路径</el-radio>
</el-form-item>
</el-col>
<el-col :span="24" v-if="info.genType == '1'">
<el-form-item prop="genPath">
<span slot="label">
@@ -255,10 +264,14 @@ export default {
}
};
},
created() {},
watch: {
'info.subTableName': function(val) {
this.setSubTableColumns(val);
},
'info.tplWebType': function(val) {
if (val === '') {
this.info.tplWebType = "element-ui";
}
}
},
methods: {

View File

@@ -112,7 +112,7 @@ module.exports = {
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
},
commons: {
name: 'chunk-commons',

File diff suppressed because it is too large Load Diff