1
0
forked from ruoyi/RuoYi-Vue

Compare commits

..

150 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
RuoYi
6a811d9824 若依 3.8.6 2023-06-30 08:43:54 +08:00
RuoYi
1c9c076280 升级oshi到最新版本6.4.3 2023-06-29 08:50:27 +08:00
RuoYi
918f94d8da 升级fastjson到最新版2.0.34 2023-06-29 08:38:33 +08:00
RuoYi
5db610d16f optimized code 2023-06-28 21:31:25 +08:00
RuoYi
cc6f983ee3 升级spring-boot到最新版本2.5.15 2023-06-24 14:49:03 +08:00
RuoYi
afe2852bbb update banner.txt 2023-06-24 14:48:54 +08:00
RuoYi
9c7d302b94 升级element-ui到最新版本2.15.13 2023-06-24 10:57:40 +08:00
RuoYi
9e66ada9c1 优化代码 2023-06-24 10:57:05 +08:00
若依
a63eec3be4 !714 修改侧边栏的平台标题内容与process.env.VUE_APP_TITLE保持同步
Merge pull request !714 from Yakov/N/A
2023-06-24 02:16:00 +00:00
若依
51990695f5 !729 update ruoyi-admin/src/main/resources/application.yml.
Merge pull request !729 from WhiskyZulu/N/A
2023-06-24 02:15:34 +00:00
若依
a7b8f2ee90 !722 update ruoyi-admin/src/main/resources/banner.txt.
Merge pull request !722 from 万河/N/A
2023-06-24 02:13:44 +00:00
WhiskyZulu
67ba621db6 update ruoyi-admin/src/main/resources/application.yml.
注释不太对,“数组计算”改为“数字计算”

Signed-off-by: WhiskyZulu <a913681304@qq.com>
2023-06-05 01:44:12 +00:00
万河
05feef34c7 update ruoyi-admin/src/main/resources/banner.txt.
线条填歪了,看着难受

Signed-off-by: 万河 <12894283+science-01@user.noreply.gitee.com>
2023-05-18 08:53:14 +00:00
yangfanao
be0b36f6b9 update ruoyi-ui/src/layout/components/Sidebar/Logo.vue.
修改了第38行的/* title: '若依后台管理系统',  */ 为/* title: process.env.VUE_APP_TITLE, */,使得侧边栏的平台标题内容可以和vue.config.js里面的process.env.VUE_APP_TITLE保持同步。

Signed-off-by: yangfanao <2364917935@qq.com>
2023-04-25 09:35:36 +00:00
RuoYi
69bbccbd76 添加新群号:136919097 2023-04-23 15:46:53 +08:00
若依
1eb7b3a03f !713 缓存列表:多次清除操作,提示不变的问题
Merge pull request !713 from 刘立伟/master
2023-04-23 06:57:17 +00:00
若依
4661edf7f0 !712 修复路由跳转被阻止时vue-router内部产生报错信息问题
Merge pull request !712 from 爱吃猫的鱼/master
2023-04-23 06:55:46 +00:00
若依
8485605145 !710 修复代码生成表字段注释不全问题
Merge pull request !710 from zouhuu/dev
2023-04-23 06:54:34 +00:00
若依
a4fe88ca61 !707 恢复翻页/切换路由滚动功能
Merge pull request !707 from 也曾为你像超人/master
2023-04-23 06:53:45 +00:00
若依
af15a3b274 !704 Vue的DictTag组件,当value没有匹配的值时,展示value
Merge pull request !704 from Aurora/master
2023-04-23 06:53:11 +00:00
刘立伟
571393c32c 缓存列表:多次清除操作,提示不变的问题; 2023-04-20 15:18:17 +08:00
loren-li
eff06c110f 修复路由跳转被阻止时vue-router内部产生报错信息问题 2023-04-20 15:02:38 +08:00
刘元博
6a18e06339 去除element滚动条 2023-04-17 18:52:46 +08:00
zouhuu
f04ca57f7a update ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml.
修复生成列字段注释显示不全问题

Signed-off-by: zouhuu <zouhugz@163.com>
2023-04-17 08:08:44 +00:00
刘元博
b4f2a4f7dd 恢复翻页/切换路由滚动功能 2023-04-15 17:01:18 +08:00
zouhuu
de0a43285f update pom.xml.
去除多余代码

Signed-off-by: zouhuu <zouhugz@163.com>
2023-04-14 07:31:50 +00:00
刘鹏飞
4952ac0a3d 修改DictTag组件,当value没有匹配的值时,展示value 2023-04-12 15:14:09 +08:00
RuoYi
6ad345331d 修复开启TopNav后一级菜单路由参数设置无效问题(I6T1DK) 2023-04-11 16:51:55 +08:00
RuoYi
5a634a4ecd 修复导入用户时无法更新存在用户数据的问题 2023-04-10 18:03:34 +08:00
RuoYi
f5b865a2e1 优化用户导入更新时需获取用户编号问题 2023-04-10 17:58:03 +08:00
若依
f7595e4998 !700 newInstance() 已弃用,使用clazz.getDeclaredConstructor().newInstance()
Merge pull request !700 from Nymph2333/N/A
2023-04-10 09:32:01 +00:00
若依
64e71302e4 !699 修改注释中不存在的参数 set
Merge pull request !699 from bell/N/A
2023-04-10 09:26:01 +00:00
若依
2e99c68ed0 !695 下拉图标选择组件优化:1.已选择图标高亮回显 2.滚动条采用el-scrollbar
Merge pull request !695 from 绿色心情/icon-select
2023-04-10 09:09:43 +00:00
Nymph2333
af0e0a110e newInstance() 已弃用,使用clazz.getDeclaredConstructor().newInstance()
This method propagates any exception thrown by the nullary constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler. The Constructor.newInstance method avoids this problem by wrapping any exception thrown by the constructor in a (checked) InvocationTargetException.
The call
 clazz.newInstance()
can be replaced by
 clazz.getDeclaredConstructor().newInstance()
The latter sequence of calls is inferred to be able to throw the additional exception types InvocationTargetException and NoSuchMethodException. Both of these exception types are subclasses of ReflectiveOperationException.

Signed-off-by: Nymph2333 <498092988@qq.com>
2023-04-10 06:27:40 +00:00
bell
bef86e041f 修改注释中不存在的参数 set
Signed-off-by: bell <bellaconly@qq.com>
2023-04-10 03:20:19 +00:00
尹志芳
1067567f1c 下拉图标选择组件优化:1.已选择图标高亮回显 2.滚动条采用el-scrollbar 2023-04-09 13:20:59 +08:00
e
0a670fdfd7 将el-scrollbar移动到main-container下,避免鼠标移出时无法隐藏的问题 2023-04-08 04:47:34 +08:00
RuoYi
a33090c90e 添加新群号:101046199 2023-04-05 17:52:27 +08:00
RuoYi
5061558e94 优化固定头部页签滚动条被隐藏的问题 2023-04-05 17:50:32 +08:00
若依
e7f088552f !686 导出Excel,提高导出效率
Merge pull request !686 from wzy1024/wzy1024
2023-04-05 09:36:45 +00:00
若依
5c4682e060 !683 修复tab栏“关闭其他”异常的问题
Merge pull request !683 from 也曾为你像超人/N/A
2023-04-05 09:35:24 +00:00
若依
5d5ebbec1a !682 解决表字段comment过长问题
Merge pull request !682 from baozhigang/column-comment
2023-04-05 09:35:04 +00:00
若依
23544bab5e !681 移除vue-multiselect样式
Merge pull request !681 from Jimi/master
2023-04-05 09:34:17 +00:00
若依
c5ef0336a4 !676 优化选择图标组件
Merge pull request !676 from 也曾为你像超人/master
2023-04-05 09:30:43 +00:00
wzy1024
a907f8485c 导出Excel,@Excel注解使用dictType属性时,如果有大量的字典数据,就会有大量的查询redis(打开、关闭),导致特别慢。于是使用map存储字典数据,相同的key就不需要再次去查询redis,大大提高了导出效率。 2023-04-04 11:58:26 +08:00
也曾为你像超人
66200c4203 修复tab栏”关闭其他“异常的问题
Signed-off-by: 也曾为你像超人 <1553592282@qq.com>
2023-04-01 03:17:47 +00:00
“baozhigang”
5a25212509 解决表字段comment过长问题 2023-03-30 20:10:22 +08:00
Jimi
95742bf5bd style:移除vue-multiselect样式(项目中并未安装vue-multiselect plugin) 2023-03-30 14:58:06 +08:00
刘元博
4eea8cdbb0 优化选择图标组件 2023-03-18 10:59:05 +08:00
RuoYi
cfce89be7d 升级fastjson到最新版2.0.25 2023-03-18 10:30:34 +08:00
RuoYi
ce7e12ec1d delete build style 2023-03-18 09:31:26 +08:00
RuoYi
4f02f3c6f7 支持自定义隐藏属性列过滤子对象(I6GKPE) 2023-03-17 14:13:39 +08:00
若依
5ca9bd6876 !673 $tab.closePage后存在非首页页签时不应该跳转首页
Merge pull request !673 from Giovanni/master
2023-03-17 06:11:24 +00:00
若依
020a2d4670 !671 优化弹窗后导航栏偏移的问题
Merge pull request !671 from 也曾为你像超人/master
2023-03-17 06:08:47 +00:00
若依
635d621b7b !670 修复页面切换时布局错乱的问题
Merge pull request !670 from 也曾为你像超人/N/A
2023-03-17 05:53:51 +00:00
若依
4cbd56cbd7 !669 用户多角色,数据权限切面处理时可能出现权限抬升的情况。
Merge pull request !669 from 0慕容雪0/master
2023-03-17 05:50:26 +00:00
刘元博
dcb9cb3d13 优化弹窗后导航栏偏移的问题 2023-03-11 14:42:02 +08:00
0慕容雪0
628bc94a9a update ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java.
Signed-off-by: 0慕容雪0 <ytu.mxh@163.com>
2023-03-11 04:31:55 +00:00
也曾为你像超人
38ddefe2e6 修复页面切换时布局错乱的问题
Signed-off-by: 也曾为你像超人 <1553592282@qq.com>
2023-03-11 02:19:57 +00:00
Giovanni
7a090bda1e 关闭当前tab页应跳转最右侧tab页而非首页 2023-03-10 18:04:56 +08:00
0慕容雪0
4e8dd706d5 update ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java.
DataScopeAspect,数据权限切面处理类中,用户多角色情况下,若所有角色都不包含传递过来的权限字符,这个时候sqlString也会为空,会导致用户拥有全部数据权限,所以要限制一下, 可以根据conditions集合是否为空,来判断循环时所有角色是否都是在判断权限字符时continue了。
复现方法: 在使用@DataScope注解时permission定义了值,这个值所有角色不包含。

Signed-off-by: 0慕容雪0 <ytu.mxh@163.com>
2023-03-10 08:22:35 +00:00
RuoYi
641e550d7f 优化修改密码日志存储明文问题(I6ESO9) 2023-03-05 12:06:27 +08:00
RuoYi
81a01a1d9d 优化文件下载出现的异常(I6DLNU) 2023-02-28 13:33:12 +08:00
RuoYi
6523fe59a2 日志管理使用索引提升查询性能 2023-02-23 10:01:16 +08:00
RuoYi
90970eb9fe 修复isMatchedIp的参数判断产生空指针的问题 2023-02-22 10:29:28 +08:00
RuoYi
3402b69556 移除apache/commons-fileupload依赖 2023-02-21 18:06:28 +08:00
RuoYi
2c5e3e429f 升级druid到最新版本1.2.16 2023-02-21 18:05:22 +08:00
RuoYi
96ba768f50 优化代码 2023-02-21 18:02:00 +08:00
RuoYi
1268637e58 支持登录IP黑名单限制 2023-02-21 09:00:44 +08:00
RuoYi
61caa7966b 日志注解支持排除指定的请求参数 2023-02-20 16:25:40 +08:00
RuoYi
a5f95eddab 新增监控页面图标显示 2023-02-17 08:55:22 +08:00
RuoYi
ade70583e9 操作日志新增消耗时间属性 2023-02-16 10:22:39 +08:00
RuoYi
5676cf9ad4 修复匿名注解Anonymous空指针问题(I683DT) 2023-02-06 11:20:12 +08:00
RuoYi
c3d0cd5f8c update copyright 2023 2023-02-04 22:26:02 +08:00
RuoYi
eb96afee64 连接池Druid支持新的配置connectTimeout和socketTimeout 2023-02-04 22:25:49 +08:00
RuoYi
5873da87ae 屏蔽定时任务bean违规的字符 2023-02-04 22:25:33 +08:00
若依
4f1933e2e4 !656 tagsView右键选择框,只存在首页时,不应该存在关闭左侧选项
Merge pull request !656 from Giovanni/master
2023-02-04 14:21:28 +00:00
Giovanni
9926f73cd0 tagsView右选框,首页不应该存在关闭左侧选项 2023-02-01 15:58:40 +08:00
RuoYi
492919d4af 升级element-ui到最新版本2.15.12 2023-01-19 12:05:01 +08:00
RuoYi
a7ff50e695 升级fastjson到最新版2.0.23 2023-01-19 12:04:11 +08:00
RuoYi
71e7e1d6dd 字符未使用下划线不进行驼峰式处理 2023-01-19 12:02:48 +08:00
RuoYi
5073f95ccd 添加新群号:108482800 2023-01-11 12:55:29 +08:00
159 changed files with 2754 additions and 2067 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.5</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.5-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>
@@ -21,7 +21,6 @@
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
* 提供了单应用版本[RuoYi-Vue-fast](https://github.com/yangzongzhuan/RuoYi-Vue-fast)Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
* 特别鸣谢:[element](https://github.com/ElemeFE/element)[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)[eladmin-web](https://github.com/elunez/eladmin-web)。
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)&nbsp;&nbsp;
@@ -94,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群 [![加入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) 点击按钮入群。

31
pom.xml
View File

@@ -6,33 +6,32 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.8.5</version>
<version>3.8.7</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依管理系统</description>
<properties>
<ruoyi.version>3.8.5</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.15</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.20</fastjson.version>
<oshi.version>6.4.0</oshi.version>
<commons.io.version>2.11.0</commons.io.version>
<commons.fileupload.version>1.4</commons.fileupload.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>
@@ -41,7 +40,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.14</version>
<version>2.5.15</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@@ -94,13 +93,6 @@
<version>${commons.io.version}</version>
</dependency>
<!-- 文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons.fileupload.version}</version>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
@@ -191,11 +183,6 @@
</modules>
<packaging>pom</packaging>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.5</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

@@ -49,24 +49,15 @@ public class SysUserOnlineController extends BaseController
LoginUser user = redisCache.getCacheObject(key);
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
{
if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
{
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
}
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
}
else if (StringUtils.isNotEmpty(ipaddr))
{
if (StringUtils.equals(ipaddr, user.getIpaddr()))
{
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
}
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
}
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
{
if (StringUtils.equals(userName, user.getUsername()))
{
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
}
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
}
else
{

View File

@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -84,7 +83,7 @@ public class SysConfigController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody SysConfig config)
{
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
if (!configService.checkConfigKeyUnique(config))
{
return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
}
@@ -100,7 +99,7 @@ public class SysConfigController extends BaseController
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysConfig config)
{
if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
if (!configService.checkConfigKeyUnique(config))
{
return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
}

View File

@@ -76,7 +76,7 @@ public class SysDeptController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDept dept)
{
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
if (!deptService.checkDeptNameUnique(dept))
{
return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
@@ -94,7 +94,7 @@ public class SysDeptController extends BaseController
{
Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId);
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
if (!deptService.checkDeptNameUnique(dept))
{
return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}

View File

@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDictType;
@@ -72,7 +71,7 @@ public class SysDictTypeController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody SysDictType dict)
{
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
if (!dictTypeService.checkDictTypeUnique(dict))
{
return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
}
@@ -88,7 +87,7 @@ public class SysDictTypeController extends BaseController
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDictType dict)
{
if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
if (!dictTypeService.checkDictTypeUnique(dict))
{
return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
}

View File

@@ -85,7 +85,7 @@ public class SysMenuController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody SysMenu menu)
{
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
if (!menuService.checkMenuNameUnique(menu))
{
return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}
@@ -105,7 +105,7 @@ public class SysMenuController extends BaseController
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysMenu menu)
{
if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
if (!menuService.checkMenuNameUnique(menu))
{
return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
}

View File

@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -75,11 +74,11 @@ public class SysPostController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody SysPost post)
{
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
if (!postService.checkPostNameUnique(post))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
else if (!postService.checkPostCodeUnique(post))
{
return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}
@@ -95,11 +94,11 @@ public class SysPostController extends BaseController
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysPost post)
{
if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
if (!postService.checkPostNameUnique(post))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
else if (!postService.checkPostCodeUnique(post))
{
return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
}

View File

@@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
@@ -61,29 +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())
&& UserConstants.NOT_UNIQUE.equals(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())
&& UserConstants.NOT_UNIQUE.equals(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();
}
@@ -108,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

@@ -14,7 +14,6 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
@@ -94,11 +93,11 @@ public class SysRoleController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody SysRole role)
{
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
if (!roleService.checkRoleNameUnique(role))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
else if (!roleService.checkRoleKeyUnique(role))
{
return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
}
@@ -117,11 +116,11 @@ public class SysRoleController extends BaseController
{
roleService.checkRoleAllowed(role);
roleService.checkRoleDataScope(role.getRoleId());
if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
if (!roleService.checkRoleNameUnique(role))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
}
else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
else if (!roleService.checkRoleKeyUnique(role))
{
return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
}

View File

@@ -17,7 +17,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
@@ -125,17 +124,15 @@ public class SysUserController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user)
{
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user)))
if (!userService.checkUserNameUnique(user))
{
return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
}
else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
{
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
}
else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
{
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}
@@ -154,17 +151,15 @@ public class SysUserController extends BaseController
{
userService.checkUserAllowed(user);
userService.checkUserDataScope(user.getUserId());
if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user)))
if (!userService.checkUserNameUnique(user))
{
return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
}
else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
{
return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
}
else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
{
return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
}

View File

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

View File

@@ -24,6 +24,10 @@ spring:
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒

View File

@@ -3,16 +3,14 @@ ruoyi:
# 名称
name: RuoYi
# 版本
version: 3.8.5
version: 3.8.7
# 版权年份
copyrightYear: 2023
# 实例演示开关
demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:/ruoyi/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数计算 char 字符验证
# 验证码类型 math 数计算 char 字符验证
captchaType: math
# 开发环境配置
@@ -53,15 +51,15 @@ spring:
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
@@ -76,7 +74,7 @@ spring:
# 数据库索引
database: 0
# 密码
password:
password:
# 连接超时时间
timeout: 10s
lettuce:
@@ -92,27 +90,27 @@ spring:
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期默认30分钟
expireTime: 30
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期默认30分钟
expireTime: 30
# MyBatis配置
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
pagehelper:
helperDialect: mysql
supportMethodsArguments: true
params: count=countSql
params: count=countSql
# Swagger配置
swagger:
@@ -122,7 +120,7 @@ swagger:
pathMapping: /dev-api
# 防止XSS攻击
xss:
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)

View File

@@ -9,6 +9,7 @@ user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分
user.password.delete=对不起,您的账号已被删除
user.blocked=用户已封禁,请联系管理员
role.blocked=角色已封禁,请联系管理员
login.blocked=很遗憾访问IP已被列入系统黑名单
user.logout.success=退出成功
length.not.valid=长度必须在{min}到{max}个字符之间

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.5</version>
<version>3.8.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -78,12 +78,6 @@
<artifactId>commons-io</artifactId>
</dependency>
<!-- 文件上传工具类 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>

View File

@@ -59,12 +59,12 @@ public @interface Excel
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/**
* 导出时在excel中每个列的高度 单位为字符
* 导出时在excel中每个列的高度
*/
public double height() default 14;
/**
* 导出时在excel中每个列的宽 单位为字符
* 导出时在excel中每个列的宽
*/
public double width() default 16;
@@ -114,7 +114,7 @@ public @interface Excel
public ColumnType cellType() default ColumnType.STRING;
/**
* 导出列头背景色
* 导出列头背景
*/
public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
@@ -124,7 +124,7 @@ public @interface Excel
public IndexedColors headerColor() default IndexedColors.WHITE;
/**
* 导出单元格背景色
* 导出单元格背景
*/
public IndexedColors backgroundColor() default IndexedColors.WHITE;

View File

@@ -20,7 +20,7 @@ import com.ruoyi.common.enums.OperatorType;
public @interface Log
{
/**
* 模块
* 模块
*/
public String title() default "";
@@ -43,4 +43,9 @@ public @interface Log
* 是否保存响应的参数
*/
public boolean isSaveResponseData() default true;
/**
* 排除指定的请求参数
*/
public String[] excludeParamNames() default {};
}

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

@@ -60,9 +60,9 @@ public class UserConstants
/** InnerLink组件标识 */
public final static String INNER_LINK = "InnerLink";
/** 校验返回结果码 */
public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1";
/** 校验是否唯一的返回标识 */
public final static boolean UNIQUE = true;
public final static boolean NOT_UNIQUE = false;
/**
* 用户名长度限制

View File

@@ -1,6 +1,7 @@
package com.ruoyi.common.core.domain;
import java.util.HashMap;
import java.util.Objects;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.utils.StringUtils;
@@ -169,6 +170,36 @@ public class AjaxResult extends HashMap<String, Object>
return new AjaxResult(code, msg, null);
}
/**
* 是否为成功消息
*
* @return 结果
*/
public boolean isSuccess()
{
return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
}
/**
* 是否为警告消息
*
* @return 结果
*/
public boolean isWarn()
{
return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
}
/**
* 是否为错误消息
*
* @return 结果
*/
public boolean isError()
{
return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
}
/**
* 方便链式调用
*

View File

@@ -1,11 +1,11 @@
package com.ruoyi.common.core.domain.model;
import java.util.Collection;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.alibaba.fastjson2.annotation.JSONField;
import com.ruoyi.common.core.domain.entity.SysUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Set;
/**
* 登录用户身份权限
@@ -71,6 +71,24 @@ public class LoginUser implements UserDetails
*/
private SysUser user;
public LoginUser()
{
}
public LoginUser(SysUser user, Set<String> permissions)
{
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
public Long getUserId()
{
return userId;
@@ -101,24 +119,6 @@ public class LoginUser implements UserDetails
this.token = token;
}
public LoginUser()
{
}
public LoginUser(SysUser user, Set<String> permissions)
{
this.user = user;
this.permissions = permissions;
}
public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
{
this.userId = userId;
this.deptId = deptId;
this.user = user;
this.permissions = permissions;
}
@JSONField(serialize = false)
@Override
public String getPassword()

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

@@ -0,0 +1,61 @@
package com.ruoyi.common.exception.file;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* 文件上传异常类
*
* @author ruoyi
*/
public class FileUploadException extends Exception
{
private static final long serialVersionUID = 1L;
private final Throwable cause;
public FileUploadException()
{
this(null, null);
}
public FileUploadException(final String msg)
{
this(msg, null);
}
public FileUploadException(String msg, Throwable cause)
{
super(msg);
this.cause = cause;
}
@Override
public void printStackTrace(PrintStream stream)
{
super.printStackTrace(stream);
if (cause != null)
{
stream.println("Caused by:");
cause.printStackTrace(stream);
}
}
@Override
public void printStackTrace(PrintWriter writer)
{
super.printStackTrace(writer);
if (cause != null)
{
writer.println("Caused by:");
cause.printStackTrace(writer);
}
}
@Override
public Throwable getCause()
{
return cause;
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.common.exception.file;
import java.util.Arrays;
import org.apache.commons.fileupload.FileUploadException;
/**
* 文件上传 误异常类

View File

@@ -0,0 +1,16 @@
package com.ruoyi.common.exception.user;
/**
* 黑名单IP异常类
*
* @author ruoyi
*/
public class BlackListException extends UserException
{
private static final long serialVersionUID = 1L;
public BlackListException()
{
super("login.blocked", null);
}
}

View File

@@ -0,0 +1,16 @@
package com.ruoyi.common.exception.user;
/**
* 用户不存在异常类
*
* @author ruoyi
*/
public class UserNotExistsException extends UserException
{
private static final long serialVersionUID = 1L;
public UserNotExistsException()
{
super("user.not.exists", null);
}
}

View File

@@ -145,16 +145,20 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
}
/**
* 计算两个时间差
* 计算时间差
*
* @param endDate 最后时间
* @param startTime 开始时间
* @return 时间差(天/小时/分钟)
*/
public static String getDatePoor(Date endDate, Date nowDate)
public static String timeDistance(Date endDate, Date startTime)
{
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
// long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
long diff = endDate.getTime() - startTime.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时

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>
@@ -325,9 +349,9 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
}
/**
* 判断给定的set列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
* 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
*
* @param set 给定的集合
* @param collection 给定的集合
* @param array 给定的数组
* @return boolean 结果
*/
@@ -481,7 +505,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
}
/**
* 驼峰式命名法 例如user_name->userName
* 驼峰式命名法
* 例如user_name->userName
*/
public static String toCamelCase(String s)
{
@@ -489,6 +514,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
{
return null;
}
if (s.indexOf(SEPARATOR) == -1)
{
return s;
}
s = s.toLowerCase();
StringBuilder sb = new StringBuilder(s.length());
boolean upperCase = false;

View File

@@ -3,6 +3,7 @@ package com.ruoyi.common.utils.ip;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
/**
@@ -12,6 +13,23 @@ import com.ruoyi.common.utils.StringUtils;
*/
public class IpUtils
{
public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
// 匹配 ip
public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
// 匹配网段
public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
/**
* 获取客户端IP
*
* @return IP地址
*/
public static String getIpAddr()
{
return getIpAddr(ServletUtils.getRequest());
}
/**
* 获取客户端IP
*
@@ -248,7 +266,7 @@ public class IpUtils
}
}
}
return ip;
return StringUtils.substring(ip, 0, 255);
}
/**
@@ -261,4 +279,104 @@ public class IpUtils
{
return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
}
/**
* 是否为IP
*/
public static boolean isIP(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
}
/**
* 是否为IP或 *为间隔的通配符地址
*/
public static boolean isIpWildCard(String ip)
{
return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
}
/**
* 检测参数是否在ip通配符里
*/
public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
{
String[] s1 = ipWildCard.split("\\.");
String[] s2 = ip.split("\\.");
boolean isMatchedSeg = true;
for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
{
if (!s1[i].equals(s2[i]))
{
isMatchedSeg = false;
break;
}
}
return isMatchedSeg;
}
/**
* 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
*/
public static boolean isIPSegment(String ipSeg)
{
return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
}
/**
* 判断ip是否在指定网段中
*/
public static boolean ipIsInNetNoCheck(String iparea, String ip)
{
int idx = iparea.indexOf('-');
String[] sips = iparea.substring(0, idx).split("\\.");
String[] sipe = iparea.substring(idx + 1).split("\\.");
String[] sipt = ip.split("\\.");
long ips = 0L, ipe = 0L, ipt = 0L;
for (int i = 0; i < 4; ++i)
{
ips = ips << 8 | Integer.parseInt(sips[i]);
ipe = ipe << 8 | Integer.parseInt(sipe[i]);
ipt = ipt << 8 | Integer.parseInt(sipt[i]);
}
if (ips > ipe)
{
long t = ips;
ips = ipe;
ipe = t;
}
return ips <= ipt && ipt <= ipe;
}
/**
* 校验ip是否符合过滤串规则
*
* @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
* @param ip 校验IP地址
* @return boolean 结果
*/
public static boolean isMatchedIp(String filter, String ip)
{
if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
{
return false;
}
String[] ips = filter.split(";");
for (String iStr : ips)
{
if (isIP(iStr) && iStr.equals(ip))
{
return true;
}
else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
{
return true;
}
else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
{
return true;
}
}
return false;
}
}

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

@@ -98,6 +98,11 @@ public class ExcelUtil<T>
public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
/**
* 用于dictType属性数据存储避免重复查缓存
*/
public Map<String, String> sysDictMap = new HashMap<String, String>();
/**
* Excel sheet最大行数默认65536
*/
@@ -283,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;
}
/**
@@ -331,7 +350,6 @@ public class ExcelUtil<T>
}
// 获取最后一个非空行的行下标比如总行数为n则返回的为n-1
int rows = sheet.getLastRowNum();
if (rows > 0)
{
// 定义一个map用于存放excel列的序号和field.
@@ -446,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());
}
@@ -456,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))
{
@@ -1034,7 +1052,12 @@ public class ExcelUtil<T>
}
else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
{
cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator));
if (!sysDictMap.containsKey(dictType + value))
{
String lable = convertDictByExp(Convert.toStr(value), dictType, separator);
sysDictMap.put(dictType + value, lable);
}
cell.setCellValue(sysDictMap.get(dictType + value));
}
else if (value instanceof BigDecimal && -1 != attr.scale())
{
@@ -1042,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
{
@@ -1255,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)
{
@@ -1321,7 +1344,7 @@ public class ExcelUtil<T>
*/
public String encodingFilename(String filename)
{
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
filename = UUID.randomUUID() + "_" + filename + ".xlsx";
return filename;
}
@@ -1440,7 +1463,8 @@ public class ExcelUtil<T>
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
@@ -1598,7 +1622,7 @@ public class ExcelUtil<T>
HSSFPicture pic = (HSSFPicture) shape;
int pictureIndex = pic.getPictureIndex() - 1;
HSSFPictureData picData = pictures.get(pictureIndex);
String picIndex = String.valueOf(anchor.getRow1()) + "_" + String.valueOf(anchor.getCol1());
String picIndex = anchor.getRow1() + "_" + anchor.getCol1();
sheetIndexPicMap.put(picIndex, picData);
}
}

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

@@ -22,7 +22,7 @@ public class Seq
private static AtomicInteger uploadSeq = new AtomicInteger(1);
// 机器标识
private static String machineCode = "A";
private static final String machineCode = "A";
/**
* 获取通用序列号

View File

@@ -66,7 +66,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
}
/**
* 获取类型 4伪随机生成的UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
* 获取类型 4伪随机生成的UUID 的静态工厂。
*
* @return 随机生成的 {@code UUID}
*/

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.8.5</version>
<version>3.8.7</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -41,7 +41,7 @@
<artifactId>kaptcha</artifactId>
<exclusions>
<exclusion>
<artifactId>javax.servlet-api</artifactId>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>

View File

@@ -108,6 +108,7 @@ public class DataScopeAspect
if (DATA_SCOPE_ALL.equals(dataScope))
{
sqlString = new StringBuilder();
conditions.add(dataScope);
break;
}
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
@@ -141,6 +142,12 @@ public class DataScopeAspect
conditions.add(dataScope);
}
// 多角色情况下所有角色都不包含传递过来的权限字符这个时候sqlString也会为空所以要限制一下,不查询任何数据
if (StringUtils.isEmpty(conditions))
{
sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
}
if (StringUtils.isNotBlank(sqlString.toString()))
{
Object params = joinPoint.getArgs()[0];

View File

@@ -4,17 +4,21 @@ import java.util.Collection;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
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;
@@ -41,6 +45,18 @@ public class LogAspect
/** 排除敏感属性字段 */
public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
/** 计算操作消耗时间 */
private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
/**
* 处理请求前执行
*/
@Before(value = "@annotation(controllerLog)")
public void boBefore(JoinPoint joinPoint, Log controllerLog)
{
TIME_THREADLOCAL.set(System.currentTimeMillis());
}
/**
* 处理完请求后执行
*
@@ -75,12 +91,17 @@ public class LogAspect
SysOperLog operLog = new SysOperLog();
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
// 请求的地址
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
String ip = IpUtils.getIpAddr();
operLog.setOperIp(ip);
operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
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)
@@ -96,6 +117,8 @@ public class LogAspect
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 设置消耗时间
operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
// 保存数据库
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
}
@@ -105,6 +128,10 @@ public class LogAspect
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
finally
{
TIME_THREADLOCAL.remove();
}
}
/**
@@ -126,7 +153,7 @@ public class LogAspect
if (log.isSaveRequestData())
{
// 获取参数的信息,传入到数据库中。
setRequestValue(joinPoint, operLog);
setRequestValue(joinPoint, operLog, log.excludeParamNames());
}
// 是否需要保存response参数和值
if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
@@ -141,25 +168,26 @@ public class LogAspect
* @param operLog 操作日志
* @throws Exception 异常
*/
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
{
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod();
if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
if (StringUtils.isEmpty(paramsMap)
&& (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)))
{
String params = argsArrayToString(joinPoint.getArgs());
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
}
else
{
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter()), 0, 2000));
operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
}
}
/**
* 参数拼装
*/
private String argsArrayToString(Object[] paramsArray)
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
{
String params = "";
if (paramsArray != null && paramsArray.length > 0)
@@ -170,7 +198,7 @@ public class LogAspect
{
try
{
String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter());
String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
params += jsonObj.toString() + " ";
}
catch (Exception e)
@@ -185,9 +213,9 @@ public class LogAspect
/**
* 忽略敏感属性
*/
public PropertyPreExcludeFilter excludePropertyPreFilter()
public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
{
return new PropertyPreExcludeFilter().addExcludes(EXCLUDE_PROPERTIES);
return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
}
/**

View File

@@ -16,7 +16,6 @@ import org.springframework.stereotype.Component;
import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.enums.LimitType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
@@ -79,7 +78,7 @@ public class RateLimiterAspect
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
if (rateLimiter.limitType() == LimitType.IP)
{
stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
stringBuffer.append(IpUtils.getIpAddr()).append("-");
}
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();

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

@@ -24,6 +24,12 @@ public class DruidProperties
@Value("${spring.datasource.druid.maxWait}")
private int maxWait;
@Value("${spring.datasource.druid.connectTimeout}")
private int connectTimeout;
@Value("${spring.datasource.druid.socketTimeout}")
private int socketTimeout;
@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
private int timeBetweenEvictionRunsMillis;
@@ -54,6 +60,12 @@ public class DruidProperties
/** 配置获取连接等待超时的时间 */
datasource.setMaxWait(maxWait);
/** 配置驱动连接超时时间,检测数据库建立连接的超时时间,单位是毫秒 */
datasource.setConnectTimeout(connectTimeout);
/** 配置网络超时时间,等待数据库操作完成的网络超时时间,单位是毫秒 */
datasource.setSocketTimeout(socketTimeout);
/** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);

View File

@@ -3,6 +3,7 @@ package com.ruoyi.framework.config.properties;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
import org.apache.commons.lang3.RegExUtils;
@@ -44,12 +45,12 @@ public class PermitAllUrlProperties implements InitializingBean, ApplicationCont
// 获取方法上边的注解 替代path variable 为 *
Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
Optional.ofNullable(method).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
// 获取类上边的注解, 替代path variable 为 *
Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
Optional.ofNullable(controller).ifPresent(anonymous -> info.getPatternsCondition().getPatterns()
Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
.forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
});
}

View File

@@ -14,7 +14,7 @@ public class DynamicDataSourceContextHolder
/**
* 使用ThreadLocal维护变量ThreadLocal为每个使用该变量的线程提供独立的变量副本
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
*/
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

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

@@ -38,7 +38,7 @@ public class AsyncFactory
final Object... args)
{
final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
final String ip = IpUtils.getIpAddr();
return new TimerTask()
{
@Override

View File

@@ -117,7 +117,7 @@ public class Jvm
*/
public String getRunTime()
{
return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate());
return DateUtils.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate());
}
/**

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 = ",";
/**
* 验证用户是否具备某权限
*
@@ -62,7 +53,7 @@ public class PermissionService
/**
* 验证用户是否具有以下任意一个权限
*
* @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
* @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
* @return 用户是否具有以下任意一个权限
*/
public boolean hasAnyPermi(String permissions)
@@ -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

@@ -9,16 +9,18 @@ import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.BlackListException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserNotExistsException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
@@ -61,12 +63,10 @@ public class SysLoginService
*/
public String login(String username, String password, String code, String uuid)
{
boolean captchaEnabled = configService.selectCaptchaEnabled();
// 验证码开关
if (captchaEnabled)
{
validateCaptcha(username, code, uuid);
}
// 验证码校验
validateCaptcha(username, code, uuid);
// 登录前置校验
loginPreCheck(username, password);
// 用户验证
Authentication authentication = null;
try
@@ -110,18 +110,58 @@ public class SysLoginService
*/
public void validateCaptcha(String username, String code, String uuid)
{
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey);
if (captcha == null)
boolean captchaEnabled = configService.selectCaptchaEnabled();
if (captchaEnabled)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
String captcha = redisCache.getCacheObject(verifyKey);
redisCache.deleteObject(verifyKey);
if (captcha == null)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
throw new CaptchaExpireException();
}
if (!code.equalsIgnoreCase(captcha))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
}
}
if (!code.equalsIgnoreCase(captcha))
}
/**
* 登录前置校验
* @param username 用户名
* @param password 用户密码
*/
public void loginPreCheck(String username, String password)
{
// 用户名或密码为空 错误
if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
throw new CaptchaException();
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
throw new UserNotExistsException();
}
// 密码如果不在指定范围内 错误
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// 用户名不在指定范围内 错误
if (username.length() < UserConstants.USERNAME_MIN_LENGTH
|| username.length() > UserConstants.USERNAME_MAX_LENGTH)
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
throw new UserPasswordNotMatchException();
}
// IP黑名单校验
String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
{
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
throw new BlackListException();
}
}
@@ -134,7 +174,7 @@ public class SysLoginService
{
SysUser sysUser = new SysUser();
sysUser.setUserId(userId);
sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
sysUser.setLoginIp(IpUtils.getIpAddr());
sysUser.setLoginDate(DateUtils.getNowDate());
userService.updateUserProfile(sysUser);
}

View File

@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.service.ISysMenuService;
@@ -62,7 +63,7 @@ public class SysPermissionService
else
{
List<SysRole> roles = user.getRoles();
if (!roles.isEmpty() && roles.size() > 1)
if (!CollectionUtils.isEmpty(roles))
{
// 多角色设置permissions属性以便数据权限匹配权限
for (SysRole role : roles)

View File

@@ -69,7 +69,7 @@ public class SysRegisterService
{
msg = "密码长度必须在5到20个字符之间";
}
else if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(sysUser)))
else if (!userService.checkUserNameUnique(sysUser))
{
msg = "保存用户'" + username + "'失败,注册账号已存在";
}

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;
@@ -156,7 +161,7 @@ public class TokenService
public void setUserAgent(LoginUser loginUser)
{
UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
String ip = IpUtils.getIpAddr();
loginUser.setIpaddr(ip);
loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
loginUser.setBrowser(userAgent.getBrowser().getName());

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.5</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

@@ -1,5 +1,5 @@
# 代码生成
gen:
gen:
# 作者
author: ruoyi
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool

View File

@@ -3,7 +3,7 @@
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.generator.mapper.GenTableColumnMapper">
<resultMap type="GenTableColumn" id="GenTableColumnResult">
<id property="columnId" column="column_id" />
<result property="tableId" column="table_id" />
@@ -28,23 +28,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectGenTableColumnVo">
select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column
</sql>
<select id="selectGenTableColumnListByTableId" parameterType="Long" resultMap="GenTableColumnResult">
<include refid="selectGenTableColumnVo"/>
where table_id = #{tableId}
order by sort
</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>
<insert id="insertGenTableColumn" parameterType="GenTableColumn" useGeneratedKeys="true" keyProperty="columnId">
insert into gen_table_column (
<if test="tableId != null and tableId != ''">table_id,</if>
@@ -88,7 +88,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
sysdate()
)
</insert>
<update id="updateGenTableColumn" parameterType="GenTableColumn">
update gen_table_column
<set>
@@ -111,14 +111,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update>
<delete id="deleteGenTableColumnByIds" parameterType="Long">
delete from gen_table_column where table_id in
delete from gen_table_column where table_id in
<foreach collection="array" item="tableId" open="(" separator="," close=")">
#{tableId}
</foreach>
</delete>
<delete id="deleteGenTableColumns">
delete from gen_table_column where column_id in
delete from gen_table_column where column_id in
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item.columnId}
</foreach>

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.5</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

@@ -34,7 +34,7 @@ public class JobInvokeUtil
}
else
{
Object bean = Class.forName(beanName).newInstance();
Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
invokeMethod(bean, methodName, methodParams);
}
}

View File

@@ -134,6 +134,8 @@ public class ScheduleUtils
return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
}
Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
return StringUtils.containsAnyIgnoreCase(obj.getClass().getPackage().getName(), Constants.JOB_WHITELIST_STR);
String beanPackageName = obj.getClass().getPackage().getName();
return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
&& !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
}
}

View File

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

View File

@@ -83,6 +83,10 @@ public class SysOperLog extends BaseEntity
@Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date operTime;
/** 消耗时间 */
@Excel(name = "消耗时间", suffix = "毫秒")
private Long costTime;
public Long getOperId()
{
return operId;
@@ -252,4 +256,14 @@ public class SysOperLog extends BaseEntity
{
this.operTime = operTime;
}
public Long getCostTime()
{
return costTime;
}
public void setCostTime(Long costTime)
{
this.costTime = costTime;
}
}

View File

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

View File

@@ -85,5 +85,5 @@ public interface ISysConfigService
* @param config 参数信息
* @return 结果
*/
public String checkConfigKeyUnique(SysConfig config);
public boolean checkConfigKeyUnique(SysConfig config);
}

View File

@@ -89,7 +89,7 @@ public interface ISysDeptService
* @param dept 部门信息
* @return 结果
*/
public String checkDeptNameUnique(SysDept dept);
public boolean checkDeptNameUnique(SysDept dept);
/**
* 校验部门是否有数据权限

View File

@@ -94,5 +94,5 @@ public interface ISysDictTypeService
* @param dictType 字典类型
* @return 结果
*/
public String checkDictTypeUnique(SysDictType dictType);
public boolean checkDictTypeUnique(SysDictType dictType);
}

View File

@@ -140,5 +140,5 @@ public interface ISysMenuService
* @param menu 菜单信息
* @return 结果
*/
public String checkMenuNameUnique(SysMenu menu);
public boolean checkMenuNameUnique(SysMenu menu);
}

View File

@@ -47,7 +47,7 @@ public interface ISysPostService
* @param post 岗位信息
* @return 结果
*/
public String checkPostNameUnique(SysPost post);
public boolean checkPostNameUnique(SysPost post);
/**
* 校验岗位编码
@@ -55,7 +55,7 @@ public interface ISysPostService
* @param post 岗位信息
* @return 结果
*/
public String checkPostCodeUnique(SysPost post);
public boolean checkPostCodeUnique(SysPost post);
/**
* 通过岗位ID查询岗位使用数量

View File

@@ -65,7 +65,7 @@ public interface ISysRoleService
* @param role 角色信息
* @return 结果
*/
public String checkRoleNameUnique(SysRole role);
public boolean checkRoleNameUnique(SysRole role);
/**
* 校验角色权限是否唯一
@@ -73,7 +73,7 @@ public interface ISysRoleService
* @param role 角色信息
* @return 结果
*/
public String checkRoleKeyUnique(SysRole role);
public boolean checkRoleKeyUnique(SysRole role);
/**
* 校验角色是否允许操作

View File

@@ -72,7 +72,7 @@ public interface ISysUserService
* @param user 用户信息
* @return 结果
*/
public String checkUserNameUnique(SysUser user);
public boolean checkUserNameUnique(SysUser user);
/**
* 校验手机号码是否唯一
@@ -80,7 +80,7 @@ public interface ISysUserService
* @param user 用户信息
* @return 结果
*/
public String checkPhoneUnique(SysUser user);
public boolean checkPhoneUnique(SysUser user);
/**
* 校验email是否唯一
@@ -88,7 +88,7 @@ public interface ISysUserService
* @param user 用户信息
* @return 结果
*/
public String checkEmailUnique(SysUser user);
public boolean checkEmailUnique(SysUser user);
/**
* 校验用户是否允许操作

View File

@@ -208,7 +208,7 @@ public class SysConfigServiceImpl implements ISysConfigService
* @return 结果
*/
@Override
public String checkConfigKeyUnique(SysConfig config)
public boolean checkConfigKeyUnique(SysConfig config)
{
Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId();
SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey());

View File

@@ -171,7 +171,7 @@ public class SysDeptServiceImpl implements ISysDeptService
* @return 结果
*/
@Override
public String checkDeptNameUnique(SysDept dept)
public boolean checkDeptNameUnique(SysDept dept)
{
Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());

View File

@@ -210,7 +210,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
* @return 结果
*/
@Override
public String checkDictTypeUnique(SysDictType dict)
public boolean checkDictTypeUnique(SysDictType dict)
{
Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType());

View File

@@ -175,7 +175,7 @@ public class SysMenuServiceImpl implements ISysMenuService
router.setQuery(menu.getQuery());
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
List<SysMenu> cMenus = menu.getChildren();
if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
{
router.setAlwaysShow(true);
router.setRedirect("noRedirect");
@@ -335,7 +335,7 @@ public class SysMenuServiceImpl implements ISysMenuService
* @return 结果
*/
@Override
public String checkMenuNameUnique(SysMenu menu)
public boolean checkMenuNameUnique(SysMenu menu)
{
Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId());
@@ -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

@@ -79,7 +79,7 @@ public class SysPostServiceImpl implements ISysPostService
* @return 结果
*/
@Override
public String checkPostNameUnique(SysPost post)
public boolean checkPostNameUnique(SysPost post)
{
Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
SysPost info = postMapper.checkPostNameUnique(post.getPostName());
@@ -97,7 +97,7 @@ public class SysPostServiceImpl implements ISysPostService
* @return 结果
*/
@Override
public String checkPostCodeUnique(SysPost post)
public boolean checkPostCodeUnique(SysPost post)
{
Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
SysPost info = postMapper.checkPostCodeUnique(post.getPostCode());

View File

@@ -146,7 +146,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @return 结果
*/
@Override
public String checkRoleNameUnique(SysRole role)
public boolean checkRoleNameUnique(SysRole role)
{
Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName());
@@ -164,7 +164,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @return 结果
*/
@Override
public String checkRoleKeyUnique(SysRole role)
public boolean checkRoleKeyUnique(SysRole role)
{
Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey());

View File

@@ -165,7 +165,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return 结果
*/
@Override
public String checkUserNameUnique(SysUser user)
public boolean checkUserNameUnique(SysUser user)
{
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
SysUser info = userMapper.checkUserNameUnique(user.getUserName());
@@ -183,7 +183,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return
*/
@Override
public String checkPhoneUnique(SysUser user)
public boolean checkPhoneUnique(SysUser user)
{
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
@@ -201,7 +201,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return
*/
@Override
public String checkEmailUnique(SysUser user)
public boolean checkEmailUnique(SysUser user)
{
Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
SysUser info = userMapper.checkEmailUnique(user.getEmail());
@@ -501,17 +501,18 @@ public class SysUserServiceImpl implements ISysUserService
BeanValidators.validateWithException(validator, user);
user.setPassword(SecurityUtils.encryptPassword(password));
user.setCreateBy(operName);
this.insertUser(user);
userMapper.insertUser(user);
successNum++;
successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
}
else if (isUpdateSupport)
{
BeanValidators.validateWithException(validator, user);
checkUserAllowed(user);
checkUserDataScope(user.getUserId());
checkUserAllowed(u);
checkUserDataScope(u.getUserId());
user.setUserId(u.getUserId());
user.setUpdateBy(operName);
this.updateUser(user);
userMapper.updateUser(user);
successNum++;
successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
}

View File

@@ -34,10 +34,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND user_name like concat('%', #{userName}, '%')
</if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(login_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
AND login_time &gt;= #{params.beginTime}
</if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(login_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
AND login_time &lt;= #{params.endTime}
</if>
</where>
order by info_id desc

View File

@@ -21,21 +21,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="status" column="status" />
<result property="errorMsg" column="error_msg" />
<result property="operTime" column="oper_time" />
<result property="costTime" column="cost_time" />
</resultMap>
<sql id="selectOperLogVo">
select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time
select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time, cost_time
from sys_oper_log
</sql>
<insert id="insertOperlog" parameterType="SysOperLog">
insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time)
values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, sysdate())
insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, cost_time, oper_time)
values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate())
</insert>
<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>
@@ -55,10 +59,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND oper_name like concat('%', #{operName}, '%')
</if>
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(oper_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
AND oper_time &gt;= #{params.beginTime}
</if>
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(oper_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
AND oper_time &lt;= #{params.endTime}
</if>
</where>
order by oper_id desc

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.5",
"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.10",
"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

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -1,191 +1,182 @@
@import './variables.scss';
@import './mixin.scss';
@import './transition.scss';
@import './element-ui.scss';
@import './sidebar.scss';
@import './btn.scss';
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
}
label {
font-weight: 700;
}
html {
height: 100%;
box-sizing: border-box;
}
#app {
height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
.no-padding {
padding: 0px !important;
}
.padding-content {
padding: 4px 0;
}
a:focus,
a:active {
outline: none;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
div:focus {
outline: none;
}
.fr {
float: right;
}
.fl {
float: left;
}
.pr-5 {
padding-right: 5px;
}
.pl-5 {
padding-left: 5px;
}
.block {
display: block;
}
.pointer {
cursor: pointer;
}
.inlineBlock {
display: block;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
}
aside {
background: #eef1f6;
padding: 8px 24px;
margin-bottom: 20px;
border-radius: 2px;
display: block;
line-height: 32px;
font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
color: #2c3e50;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
a {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
}
//main-container全局样式
.app-container {
padding: 20px;
}
.components-container {
margin: 30px 50px;
position: relative;
}
.pagination-container {
margin-top: 30px;
}
.text-center {
text-align: center
}
.sub-navbar {
height: 50px;
line-height: 50px;
position: relative;
width: 100%;
text-align: right;
padding-right: 20px;
transition: 600ms ease position;
background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
.subtitle {
font-size: 20px;
color: #fff;
}
&.draft {
background: #d0d0d0;
}
&.deleted {
background: #d0d0d0;
}
}
.link-type,
.link-type:focus {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
.filter-container {
padding-bottom: 10px;
.filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
}
}
//refine vue-multiselect plugin
.multiselect {
line-height: 16px;
}
.multiselect--active {
z-index: 1000 !important;
}
@import './variables.scss';
@import './mixin.scss';
@import './transition.scss';
@import './element-ui.scss';
@import './sidebar.scss';
@import './btn.scss';
body {
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
}
label {
font-weight: 700;
}
html {
height: 100%;
box-sizing: border-box;
}
#app {
height: 100%;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
.no-padding {
padding: 0px !important;
}
.padding-content {
padding: 4px 0;
}
a:focus,
a:active {
outline: none;
}
a,
a:focus,
a:hover {
cursor: pointer;
color: inherit;
text-decoration: none;
}
div:focus {
outline: none;
}
.fr {
float: right;
}
.fl {
float: left;
}
.pr-5 {
padding-right: 5px;
}
.pl-5 {
padding-left: 5px;
}
.block {
display: block;
}
.pointer {
cursor: pointer;
}
.inlineBlock {
display: block;
}
.clearfix {
&:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
}
aside {
background: #eef1f6;
padding: 8px 24px;
margin-bottom: 20px;
border-radius: 2px;
display: block;
line-height: 32px;
font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
color: #2c3e50;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
a {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
}
//main-container全局样式
.app-container {
padding: 20px;
}
.components-container {
margin: 30px 50px;
position: relative;
}
.pagination-container {
margin-top: 30px;
}
.text-center {
text-align: center
}
.sub-navbar {
height: 50px;
line-height: 50px;
position: relative;
width: 100%;
text-align: right;
padding-right: 20px;
transition: 600ms ease position;
background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
.subtitle {
font-size: 20px;
color: #fff;
}
&.draft {
background: #d0d0d0;
}
&.deleted {
background: #d0d0d0;
}
}
.link-type,
.link-type:focus {
color: #337ab7;
cursor: pointer;
&:hover {
color: rgb(32, 160, 255);
}
}
.filter-container {
padding-bottom: 10px;
.filter-item {
display: inline-block;
vertical-align: middle;
margin-bottom: 10px;
}
}

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

@@ -1,7 +1,7 @@
#app {
.main-container {
min-height: 100%;
height: 100%;
transition: margin-left .28s;
margin-left: $base-sidebar-width;
position: relative;

View File

@@ -18,10 +18,6 @@
transition: all .5s;
}
.fade-transform-leave-active {
position: absolute;
}
.fade-transform-enter {
opacity: 0;
transform: translateX(-30px);

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,10 +17,13 @@
:type="item.raw.listClass == 'primary' ? '' : item.raw.listClass"
:class="item.raw.cssClass"
>
{{ item.label }}
{{ item.label + ' ' }}
</el-tag>
</template>
</template>
<template v-if="unmatch && showValue">
{{ unmatchArray | handleArray }}
</template>
</div>
</template>
@@ -33,20 +36,54 @@ export default {
default: null,
},
value: [Number, String, Array],
// 当未找到匹配的数据时显示value
showValue: {
type: Boolean,
default: true,
},
separator: {
type: String,
default: ","
}
},
data() {
return {
unmatchArray: [], // 记录未匹配的项
}
},
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 = []
// 没有value不显示
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 '';
return array.reduce((pre, cur) => {
return pre + ' ' + cur;
})
},
}
};
</script>
<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
</style>
</style>

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: "标准字体";

Some files were not shown because too many files have changed in this diff Show More