131 Commits
v3.1 ... v3.3.0

Author SHA1 Message Date
RuoYi
8988d0b4ab 若依 3.3.0 2020-12-14 09:02:10 +08:00
RuoYi
ceefa20aa2 调整代码生成页列宽 2020-12-13 16:05:49 +08:00
RuoYi
89e1f2a53f 修改Set可能导致嵌套的问题 2020-12-13 15:01:03 +08:00
若依
6800a12014 !138 修改Set可能导致嵌套的问题
Merge pull request !138 from BecomeDream/N/A
2020-12-13 14:54:17 +08:00
BecomeDream
e8f63b2994 修改Set可能导致嵌套的问题 2020-12-11 18:16:57 +08:00
RuoYi
ecfe7006e2 代码生成预览支持高亮显示 2020-12-11 17:04:54 +08:00
RuoYi
9e387dc447 去除用户手机邮箱部门必填验证 2020-12-11 13:26:14 +08:00
若依
231bbf6928 !135 增加日志记录过滤对象类型(解决多文件场景报错)
Merge pull request !135 from geruishi/master
2020-12-11 13:24:03 +08:00
RuoYi
d6eac2dc8d 前端更新插件版本 2020-12-11 09:27:12 +08:00
RuoYi
b368ad764f 升级core-js到最新版本3.8.1 2020-12-10 12:08:18 +08:00
RuoYi
ffd5f0ce5d 升级vue-router到最新版本3.4.9 2020-12-10 11:14:44 +08:00
RuoYi
a50beae599 代码生成预览提供滚动机制 2020-12-10 11:13:39 +08:00
葛瑞士
cf7f51a633 解决多文件上传Log报错 2020-12-09 16:05:09 +08:00
RuoYi
4d46f4c1b5 删除用户和角色解绑关联 2020-12-09 10:32:53 +08:00
若依
a941c1b488 !134 修改 代码生成 预览无法左右滑动
Merge pull request !134 from 〝走走停停/master
2020-12-09 10:27:34 +08:00
〝走走停停
d6b6151aea update ruoyi-ui/src/assets/styles/ruoyi.scss. 2020-12-08 17:49:51 +08:00
RuoYi
fbc071a573 关闭页签清理缓存数据 2020-12-08 16:43:26 +08:00
RuoYi
6cfff90b4a 缓存仪表图设置默认大小 2020-12-08 16:13:21 +08:00
RuoYi
474cca921e 回显数据字典防止空值报错 2020-12-08 16:12:00 +08:00
若依
1657e06be6 !132 update ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java.
Merge pull request !132 from abbfun/N/A
2020-12-08 16:03:51 +08:00
abbfun
c01eeb8521 update ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java. 2020-12-08 11:11:34 +08:00
RuoYi
f90899d72a 支持主题风格配置 2020-12-07 14:13:02 +08:00
RuoYi
7e78a9167f 修改用户头像预览宽高 2020-12-06 16:22:45 +08:00
RuoYi
563e11d9c1 get请求params添加null值判断 2020-12-06 11:05:02 +08:00
RuoYi
ef92ad4d8c 支持get请求映射params参数 2020-12-04 10:52:20 +08:00
RuoYi
d8b006c15f 升级bitwalker到最新版本1.21 2020-12-04 10:51:20 +08:00
RuoYi
0e2b97a886 升级poi到最新版本4.1.2 2020-12-03 13:28:04 +08:00
RuoYi
1c7a5faae8 Excel支持注解align对齐方式 2020-12-03 13:26:46 +08:00
RuoYi
23868c4fad 防止安全扫描YUI出现的风险提示 2020-12-03 10:26:22 +08:00
RuoYi
3b2669d148 修改缓存监控内存单位 2020-11-30 19:27:03 +08:00
RuoYi
1147ea5f8a 设置用户头像悬停高度 2020-11-30 11:10:27 +08:00
RuoYi
a1bf5aaf8e 升级element-ui版本到2.14.1 2020-11-30 10:37:48 +08:00
RuoYi
2797c1eb3a 修正转换字符串的目标字符集属性 2020-11-30 10:31:11 +08:00
若依
1791d7cf40 !126 update pom.xml.
Merge pull request !126 from abbfun/N/A
2020-11-30 10:07:08 +08:00
abbfun
01861f0aae update pom.xml. 2020-11-29 16:16:54 +08:00
RuoYi
a69cc94f35 三级菜单自动配置组件 2020-11-28 20:39:03 +08:00
RuoYi
c666faed66 修复三级菜单之间切换页面无法缓存的问题 2020-11-28 20:31:45 +08:00
RuoYi
6072239a40 修改缓存监控内存单位 2020-11-28 13:57:19 +08:00
RuoYi
a3b86d6f6d 代码生成删除多余的数字float类型 2020-11-28 12:09:24 +08:00
RuoYi
fd831d5a90 Excel支持导入Boolean型数据 2020-11-28 12:08:55 +08:00
RuoYi
e83412b9a5 升级oshi到最新版本v5.3.6 2020-11-24 16:17:33 +08:00
RuoYi
90ac416e02 新增缓存监控功能 2020-11-23 10:02:50 +08:00
RuoYi
5b63f0cab9 优化头像样式,鼠标移入悬停遮罩 2020-11-19 09:33:10 +08:00
RuoYi
8f145bba3a 若依 v3.2.1 2020-11-18 09:32:15 +08:00
RuoYi
6bb166b89f 阻止任意文件下载漏洞 2020-11-17 10:29:52 +08:00
RuoYi
823e95667e 代码生成支持上传控件 2020-11-16 16:20:17 +08:00
RuoYi
566053da0c 新增图片上传组件 2020-11-16 15:52:58 +08:00
RuoYi
0ef007240d 调整默认首页 2020-11-07 10:38:35 +08:00
RuoYi
0a75dcdd85 升级druid到最新版本v1.2.2 2020-11-05 13:58:36 +08:00
RuoYi
4c2626ffec 2020年双十一云服务器优惠,错过又要等一年 2020-11-04 16:58:28 +08:00
RuoYi
082b19e33a mapperLocations配置支持分隔符 2020-11-02 17:34:52 +08:00
若依
b779cf053d !112 未选择时,点击“确认”,出现必填验证提示。使用blur的话,选择之后验证消息不会自动消失,使用change会自动消失。
Merge pull request !112 from FlyFive/N/A
2020-11-02 17:30:06 +08:00
FlyFive
212012dc62 未选择时,点击“确认”,出现必填验证提示。使用blur的话,选择之后验证消息不会自动消失,使用change会自动消失。 2020-11-02 11:49:25 +08:00
若依
7de2cf77b4 !111 update ruoyi-ui/src/views/system/dept/index.vue.
Merge pull request !111 from FlyFive/N/A
2020-10-26 16:57:58 +08:00
FlyFive
2b9d46439f update ruoyi-ui/src/views/system/dept/index.vue.
验证的提示信息错了
2020-10-26 16:31:51 +08:00
若依
79265d59b7 !109 误修改,回退
Merge pull request !109 from tucke/master
2020-10-26 10:00:46 +08:00
tucke
093ba5b389 误修改,回退 2020-10-26 09:53:58 +08:00
RuoYi
3807b11290 权限调整 2020-10-23 17:27:20 +08:00
RuoYi
c9f25cb34e 调整sql默认时间 2020-10-21 11:30:37 +08:00
若依
203b54e5aa !106 update ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java.
Merge pull request !106 from abbfun/N/A
2020-10-14 17:12:57 +08:00
RuoYi
403f5c5dcf 解决代码生成没有bit类型的问题 2020-10-14 17:08:20 +08:00
abbfun
c6d0b9a9ae update ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java.
权限字符串修正
2020-10-14 16:21:43 +08:00
RuoYi
08df2c93a9 删除不必要的代码 2020-10-13 14:41:26 +08:00
若依
fbbdd94999 !105 update ruoyi-ui/src/views/system/role/index.vue.
Merge pull request !105 from FlyFive/N/A
2020-10-13 14:38:02 +08:00
FlyFive
0cae7d0058 update ruoyi-ui/src/views/system/role/index.vue.
getMenuAllCheckedKeys()方法中选中节点和半选节点获取的方法反了。
2020-10-12 13:50:25 +08:00
RuoYi
b0965653bf 删除不必要的代码 2020-10-10 17:54:30 +08:00
RuoYi
e472f62523 升级pagehelper到最新版1.3.0 2020-10-10 16:39:14 +08:00
RuoYi
69256940df 若依 3.2 2020-10-10 09:38:21 +08:00
RuoYi
b9f686be53 升级druid到最新版本v1.2.1 2020-10-09 11:45:33 +08:00
RuoYi
521ff51238 升级fastjson到最新版1.2.74 2020-10-09 11:45:06 +08:00
若依
f67c97e095 !102 rouyi.js中添加日期范围方法dateRange获取bug修复
Merge pull request !102 from zora/master
2020-10-09 11:37:18 +08:00
RuoYi
dd721ff894 修正定时任务执行一次权限标识 2020-10-07 13:36:55 +08:00
RuoYi
ae4290bdda 修复页签关闭所有固定标签路由不刷新问题 2020-10-03 20:05:24 +08:00
RuoYi
c19fec2cf8 格式化代码 2020-10-03 20:05:06 +08:00
RuoYi
669c42795a 表单构建布局型组件新增按钮 2020-10-03 17:47:24 +08:00
RuoYi
0d79f10c2f jna指定版本 2020-10-03 11:43:23 +08:00
RuoYi
d3595cd930 修正菜单提示信息错误 2020-10-03 11:15:18 +08:00
shizhenwei
5b0525d05c [修改]此工具类应使用参数dateRange而非bind在model上的dateRange 2020-09-27 13:22:23 +08:00
RuoYi
fb07677c32 左侧菜单文字过长显示省略号 2020-09-24 19:21:55 +08:00
RuoYi
a82a3d9465 升级oshi到最新版本v5.2.5 2020-09-22 18:25:58 +08:00
RuoYi
28bceda630 修正文字错误 2020-09-22 11:09:18 +08:00
RuoYi
69829827fe 菜单&数据权限新增(展开/折叠 全选/全不选 父子联动) 2020-09-21 14:10:01 +08:00
若依
89607fb028 !100 解决添加用户角色时报错问题
Merge pull request !100 from wensanpi/master
2020-09-21 10:31:59 +08:00
wensanpi
1aa18c523d update ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml. 2020-09-20 17:38:21 +08:00
RuoYi
abeb8d7fd8 菜单新增是否缓存keep-alive 2020-09-20 10:34:03 +08:00
RuoYi
478fae0d28 菜单&数据权限新增(展开/折叠 全选/全不选 父子联动) 2020-09-19 13:42:37 +08:00
RuoYi
0ecf27f8d6 去除多余的空格 2020-09-18 17:09:27 +08:00
RuoYi
0a5bb34fbf 升级springboot到2.1.17 提升安全性 2020-09-18 16:51:27 +08:00
RuoYi
9e38c7de2e 代码生成支持同步数据库 2020-09-18 10:24:21 +08:00
RuoYi
9ca28d6dbf 表格操作列间距调整 2020-09-18 10:23:31 +08:00
RuoYi
497f98ba90 导入excel整形值校验优化 2020-09-17 18:22:50 +08:00
RuoYi
a948affb2d 代码生成支持富文本控件 2020-09-15 15:53:27 +08:00
RuoYi
57b49dd5fa 限制系统内置参数不允许删除 2020-09-15 15:51:12 +08:00
RuoYi
9c0ed9c424 修复通知公告longblob类型乱码问题 2020-09-10 18:23:12 +08:00
RuoYi
70ab18052c 富文本工具栏样式对齐 2020-09-10 16:56:33 +08:00
RuoYi
aeb02c79d8 修正注释图标路径 2020-09-10 16:53:58 +08:00
RuoYi
33793d8eff Excel导出类型NUMERIC支持精度浮点类型 2020-09-09 11:30:34 +08:00
RuoYi
9652906954 降级druid到版本v1.1.22,防止出现一些错误 2020-09-09 10:08:31 +08:00
RuoYi
9fccc7de40 修正调用目标字符串最大长度 2020-09-07 16:40:38 +08:00
RuoYi
599be64fa8 升级jjwt到0.9.1 2020-09-07 16:40:21 +08:00
RuoYi
50ac363682 升级druid到最新版本v1.1.23 2020-09-04 14:47:07 +08:00
若依
f84b157419 !87 数据权限中的空值处理
Merge pull request !87 from sproutcat/master
2020-09-04 14:17:32 +08:00
若依
f4536d5d2e !86 数据字典缓存处理的一点小问题
Merge pull request !86 from 说一/master
2020-09-04 14:07:47 +08:00
若依
aed958b1be !82 修复Editor组件在传入内容为null时无法响应式更新其内容的bug
Merge pull request !82 from HaoRan/N/A
2020-09-04 14:04:08 +08:00
tzg
0a51f7d743 空值处理 2020-09-02 14:59:10 +08:00
dawn
3fd9147afb 解决“在只填加了字典类型,没有添加字典数据时,会出现缓存了空集合,即使后边添加了字典数据也没用,只能清空redis缓存。”的问题,小问题就是判断稍稍改了下,若依大大让我pr当个贡献者,很荣幸很欣慰。感谢! 2020-09-02 10:14:34 +08:00
RuoYi
4f86b6d9ca 修改公告内容字段类型 2020-09-01 18:07:59 +08:00
HaoRan
a65c287075 修复Editor组件无法对响应式更新null值问题 2020-08-31 02:10:01 +08:00
RuoYi
1af0d1665c 数据权限判断对象类型 2020-08-28 15:45:54 +08:00
RuoYi
4e32788b36 修正数据库字符串类型nvarchar 2020-08-28 14:11:32 +08:00
RuoYi
068c3e6f0d 优化递归子节点 2020-08-28 10:14:59 +08:00
RuoYi
dd6640086e 代码生成树模板去掉多余双引号 2020-08-27 17:34:06 +08:00
RuoYi
be54188ba6 导出Excel调整targetAttr获取值方法,防止get方法不规范 2020-08-26 15:39:46 +08:00
RuoYi
a4e2339f90 生成页面时不忽略remark属性 2020-08-26 14:24:37 +08:00
RuoYi
bf771ae5c8 Excel注解支持自动统计数据总和 2020-08-26 11:37:49 +08:00
RuoYi
fa5596bb20 Editor组件优化,支持自定义高度&图片冲突问题 2020-08-22 13:18:41 +08:00
RuoYi
eb30fc4b1a 修改公告内容字段类型 2020-08-22 13:11:40 +08:00
RuoYi
0446d211df 设置默认排序顺序 2020-08-19 17:02:23 +08:00
RuoYi
da146c2a70 Excel注解支持设置BigDecimal精度&舍入规则 2020-08-19 11:20:31 +08:00
RuoYi
7de5358dcd 升级fastjson到最新版1.2.73 2020-08-19 11:17:24 +08:00
RuoYi
549c7ee97a 代码生成添加select必填选项 2020-08-18 18:15:12 +08:00
RuoYi
5fcf342f5a 修改sass为node-sass,避免el-icon图标乱码 2020-08-18 17:36:20 +08:00
若依
c89722a7dd !74 update ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java.
Merge pull request !74 from Lyy/N/A
2020-08-18 17:30:18 +08:00
若依
61e10f2783 !73 代码生成:select的表单验证失效
Merge pull request !73 from sunshine/master
2020-08-18 17:30:03 +08:00
若依
c6912ca1d5 !64 修改sass为node-sass,避免el-icon图标乱码
Merge pull request !64 from 心悦李国楠/dev-心悦
2020-08-18 17:27:19 +08:00
若依
5c4f0c5503 !65 根节点为子部门时,树状结构显示问题
Merge pull request !65 from GSTong/master
2020-08-18 17:21:51 +08:00
Lyy
4f7702b22a update ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java.
修改注释,CRSF禁用
2020-08-17 17:05:33 +08:00
sunshine
04e294b3e5 代码生成:select的表单验证失效 2020-08-17 12:08:34 +08:00
RuoYi
d596d5bb8e 还原 addDateRange js 函数 2020-08-13 12:08:24 +08:00
gst
0070297fe1 根节点为子部门时,树状结构显示问题 2020-08-11 10:59:02 +08:00
liguonan
650359c357 修改sass为node-sass,避免el-icon图标乱码 2020-08-10 16:28:50 +08:00
133 changed files with 3172 additions and 1184 deletions

View File

@@ -8,7 +8,8 @@
* 提供了一个Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。 * 提供了一个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) * 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
* 感谢[Vue-Element-Admin](https://github.com/PanJiaChen/vue-element-admin)[eladmin-web](https://gitee.com/elunez/eladmin-web?_from=gitee_search)。 * 感谢[Vue-Element-Admin](https://github.com/PanJiaChen/vue-element-admin)[eladmin-web](https://gitee.com/elunez/eladmin-web?_from=gitee_search)。
* 阿里云优惠券[点我进入](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)   * 阿里云折扣场[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场[点我进入](http://txy.ruoyi.vip)  
* 阿里云优惠券:[点我领取](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)  
## 内置功能 ## 内置功能

35
pom.xml
View File

@@ -6,30 +6,31 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.1.0</version> <version>3.3.0</version>
<name>ruoyi</name> <name>ruoyi</name>
<url>http://www.ruoyi.vip</url> <url>http://www.ruoyi.vip</url>
<description>若依管理系统</description> <description>若依管理系统</description>
<properties> <properties>
<ruoyi.version>3.1.0</ruoyi.version> <ruoyi.version>3.3.0</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<mybatis.boot.version>1.3.2</mybatis.boot.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<druid.version>1.1.14</druid.version> <druid.version>1.2.2</druid.version>
<bitwalker.version>1.19</bitwalker.version> <bitwalker.version>1.21</bitwalker.version>
<swagger.version>2.9.2</swagger.version> <swagger.version>2.9.2</swagger.version>
<kaptcha.version>2.3.2</kaptcha.version> <kaptcha.version>2.3.2</kaptcha.version>
<pagehelper.boot.version>1.2.5</pagehelper.boot.version> <pagehelper.boot.version>1.3.0</pagehelper.boot.version>
<fastjson.version>1.2.70</fastjson.version> <fastjson.version>1.2.74</fastjson.version>
<oshi.version>3.9.1</oshi.version> <oshi.version>5.3.6</oshi.version>
<jna.version>5.6.0</jna.version>
<commons.io.version>2.5</commons.io.version> <commons.io.version>2.5</commons.io.version>
<commons.fileupload.version>1.3.3</commons.fileupload.version> <commons.fileupload.version>1.3.3</commons.fileupload.version>
<poi.version>3.17</poi.version> <poi.version>4.1.2</poi.version>
<velocity.version>1.7</velocity.version> <velocity.version>1.7</velocity.version>
<jwt.version>0.9.0</jwt.version> <jwt.version>0.9.1</jwt.version>
</properties> </properties>
<!-- 依赖声明 --> <!-- 依赖声明 -->
@@ -40,7 +41,7 @@
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <artifactId>spring-boot-dependencies</artifactId>
<version>2.1.1.RELEASE</version> <version>2.1.18.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@@ -72,6 +73,18 @@
<artifactId>oshi-core</artifactId> <artifactId>oshi-core</artifactId>
<version>${oshi.version}</version> <version>${oshi.version}</version>
</dependency> </dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>${jna.version}</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>${jna.version}</version>
</dependency>
<!-- swagger2--> <!-- swagger2-->
<dependency> <dependency>

View File

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

View File

@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -41,17 +42,15 @@ public class CommonController
{ {
try try
{ {
if (!FileUtils.isValidFilename(fileName)) if (!FileUtils.checkAllowDownload(fileName))
{ {
throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
} }
String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
String filePath = RuoYiConfig.getDownloadPath() + fileName; String filePath = RuoYiConfig.getDownloadPath() + fileName;
response.setCharacterEncoding("utf-8"); response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setContentType("multipart/form-data"); FileUtils.setAttachmentResponseHeader(response, realFileName);
response.setHeader("Content-Disposition",
"attachment;fileName=" + FileUtils.setFileDownloadHeader(request, realFileName));
FileUtils.writeBytes(filePath, response.getOutputStream()); FileUtils.writeBytes(filePath, response.getOutputStream());
if (delete) if (delete)
{ {
@@ -92,18 +91,28 @@ public class CommonController
* 本地资源通用下载 * 本地资源通用下载
*/ */
@GetMapping("/common/download/resource") @GetMapping("/common/download/resource")
public void resourceDownload(String name, HttpServletRequest request, HttpServletResponse response) throws Exception public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
throws Exception
{ {
// 本地资源路径 try
String localPath = RuoYiConfig.getProfile(); {
// 数据库资源地址 if (!FileUtils.checkAllowDownload(resource))
String downloadPath = localPath + StringUtils.substringAfter(name, Constants.RESOURCE_PREFIX); {
// 下载名称 throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); }
response.setCharacterEncoding("utf-8"); // 本地资源路径
response.setContentType("multipart/form-data"); String localPath = RuoYiConfig.getProfile();
response.setHeader("Content-Disposition", // 数据库资源地址
"attachment;fileName=" + FileUtils.setFileDownloadHeader(request, downloadName)); String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
FileUtils.writeBytes(downloadPath, response.getOutputStream()); // 下载名称
String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
FileUtils.setAttachmentResponseHeader(response, downloadName);
FileUtils.writeBytes(downloadPath, response.getOutputStream());
}
catch (Exception e)
{
log.error("下载文件失败", e);
}
} }
} }

View File

@@ -0,0 +1,53 @@
package com.ruoyi.web.controller.monitor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
/**
* 缓存监控
*
* @author ruoyi
*/
@RestController
@RequestMapping("/monitor/cache")
public class CacheController
{
@Autowired
private RedisTemplate<String, String> redisTemplate;
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
@GetMapping()
public AjaxResult getInfo() throws Exception
{
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
Map<String, Object> result = new HashMap<>(3);
result.put("info", info);
result.put("dbSize", dbSize);
List<Map<String, String>> pieList = new ArrayList<>();
commandStats.stringPropertyNames().forEach(key -> {
Map<String, String> data = new HashMap<>(2);
String property = commandStats.getProperty(key);
data.put("name", StringUtils.removeStart(key, "cmdstat_"));
data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
pieList.add(data);
});
result.put("commandStats", pieList);
return AjaxResult.success(result);
}
}

View File

@@ -4,7 +4,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.framework.web.domain.Server; import com.ruoyi.framework.web.domain.Server;
@@ -15,7 +14,7 @@ import com.ruoyi.framework.web.domain.Server;
*/ */
@RestController @RestController
@RequestMapping("/monitor/server") @RequestMapping("/monitor/server")
public class ServerController extends BaseController public class ServerController
{ {
@PreAuthorize("@ss.hasPermi('monitor:server:list')") @PreAuthorize("@ss.hasPermi('monitor:server:list')")
@GetMapping() @GetMapping()

View File

@@ -38,18 +38,18 @@ public class SysLogininforController extends BaseController
return getDataTable(list); return getDataTable(list);
} }
@Log(title = "日志", businessType = BusinessType.EXPORT) @Log(title = "日志", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('monitor:logininfor:export')") @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
@GetMapping("/export") @GetMapping("/export")
public AjaxResult export(SysLogininfor logininfor) public AjaxResult export(SysLogininfor logininfor)
{ {
List<SysLogininfor> list = logininforService.selectLogininforList(logininfor); List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class); ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
return util.exportExcel(list, "日志"); return util.exportExcel(list, "日志");
} }
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
@Log(title = "日志", businessType = BusinessType.DELETE) @Log(title = "日志", businessType = BusinessType.DELETE)
@DeleteMapping("/{infoIds}") @DeleteMapping("/{infoIds}")
public AjaxResult remove(@PathVariable Long[] infoIds) public AjaxResult remove(@PathVariable Long[] infoIds)
{ {
@@ -57,7 +57,7 @@ public class SysLogininforController extends BaseController
} }
@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')") @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
@Log(title = "日志", businessType = BusinessType.CLEAN) @Log(title = "日志", businessType = BusinessType.CLEAN)
@DeleteMapping("/clean") @DeleteMapping("/clean")
public AjaxResult clean() public AjaxResult clean()
{ {

View File

@@ -1,5 +1,6 @@
package com.ruoyi.web.controller.system; package com.ruoyi.web.controller.system;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
@@ -19,6 +20,7 @@ import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.service.ISysDictDataService; import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.ISysDictTypeService; import com.ruoyi.system.service.ISysDictTypeService;
@@ -73,7 +75,12 @@ public class SysDictDataController extends BaseController
@GetMapping(value = "/type/{dictType}") @GetMapping(value = "/type/{dictType}")
public AjaxResult dictType(@PathVariable String dictType) public AjaxResult dictType(@PathVariable String dictType)
{ {
return AjaxResult.success(dictTypeService.selectDictDataByType(dictType)); List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
if (StringUtils.isNull(data))
{
data = new ArrayList<SysDictData>();
}
return AjaxResult.success(data);
} }
/** /**

View File

@@ -126,11 +126,11 @@ public class SysMenuController extends BaseController
else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) else if (UserConstants.YES_FRAME.equals(menu.getIsFrame())
&& !StringUtils.startsWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS)) && !StringUtils.startsWithAny(menu.getPath(), Constants.HTTP, Constants.HTTPS))
{ {
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头"); return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
} }
else if (menu.getMenuId().equals(menu.getParentId())) else if (menu.getMenuId().equals(menu.getParentId()))
{ {
return AjaxResult.error("新增菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); return AjaxResult.error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
} }
menu.setUpdateBy(SecurityUtils.getUsername()); menu.setUpdateBy(SecurityUtils.getUsername());
return toAjax(menuService.updateMenu(menu)); return toAjax(menuService.updateMenu(menu));

View File

@@ -127,11 +127,13 @@ public class SysUserController extends BaseController
{ {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) else if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return AjaxResult.error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
@@ -149,11 +151,13 @@ public class SysUserController extends BaseController
public AjaxResult edit(@Validated @RequestBody SysUser user) public AjaxResult edit(@Validated @RequestBody SysUser user)
{ {
userService.checkUserAllowed(user); userService.checkUserAllowed(user);
if (UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) if (StringUtils.isNotEmpty(user.getPhonenumber())
&& UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
{ {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
} }
else if (UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) else if (StringUtils.isNotEmpty(user.getEmail())
&& UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
{ {
return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); return AjaxResult.error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
} }
@@ -175,7 +179,7 @@ public class SysUserController extends BaseController
/** /**
* 重置密码 * 重置密码
*/ */
@PreAuthorize("@ss.hasPermi('system:user:edit')") @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
@Log(title = "用户管理", businessType = BusinessType.UPDATE) @Log(title = "用户管理", businessType = BusinessType.UPDATE)
@PutMapping("/resetPwd") @PutMapping("/resetPwd")
public AjaxResult resetPwd(@RequestBody SysUser user) public AjaxResult resetPwd(@RequestBody SysUser user)

View File

@@ -3,9 +3,9 @@ ruoyi:
# 名称 # 名称
name: RuoYi name: RuoYi
# 版本 # 版本
version: 3.1.0 version: 3.3.0
# 版权年份 # 版权年份
copyrightYear: 2019 copyrightYear: 2020
# 实例演示开关 # 实例演示开关
demoEnabled: true demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath # 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath

View File

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

View File

@@ -4,6 +4,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.math.BigDecimal;
/** /**
* 自定义导出Excel数据注解 * 自定义导出Excel数据注解
@@ -30,7 +31,7 @@ public @interface Excel
public String dateFormat() default ""; public String dateFormat() default "";
/** /**
* 如果是字典类型请设置字典的type值 * 如果是字典类型请设置字典的type值 (如: sys_user_sex)
*/ */
public String dictType() default ""; public String dictType() default "";
@@ -44,6 +45,16 @@ public @interface Excel
*/ */
public String separator() default ","; public String separator() default ",";
/**
* BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
*/
public int scale() default -1;
/**
* BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
*/
public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
/** /**
* 导出类型0数字 1字符串 * 导出类型0数字 1字符串
*/ */
@@ -89,6 +100,32 @@ public @interface Excel
*/ */
public String targetAttr() default ""; public String targetAttr() default "";
/**
* 是否自动统计数据,在最后追加一行统计数据总和
*/
public boolean isStatistics() default false;
/**
* 导出字段对齐方式0默认1靠左2居中3靠右
*/
Align align() default Align.AUTO;
public enum Align
{
AUTO(0), LEFT(1), CENTER(2), RIGHT(3);
private final int value;
Align(int value)
{
this.value = value;
}
public int value()
{
return this.value;
}
}
/** /**
* 字段类型0导出导入1仅导出2仅导入 * 字段类型0导出导入1仅导出2仅导入
*/ */

View File

@@ -29,7 +29,7 @@ public class GenConstants
public static final String PARENT_MENU_NAME = "parentMenuName"; public static final String PARENT_MENU_NAME = "parentMenuName";
/** 数据库字符串类型 */ /** 数据库字符串类型 */
public static final String[] COLUMNTYPE_STR = { "char", "varchar", "narchar", "varchar2", "tinytext", "text", public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2", "tinytext", "text",
"mediumtext", "longtext" }; "mediumtext", "longtext" };
/** 数据库时间类型 */ /** 数据库时间类型 */
@@ -37,7 +37,7 @@ public class GenConstants
/** 数据库数字类型 */ /** 数据库数字类型 */
public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer", public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
"bigint", "float", "float", "double", "decimal" }; "bit", "bigint", "float", "double", "decimal" };
/** 页面不需要编辑字段 */ /** 页面不需要编辑字段 */
public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" }; public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
@@ -74,6 +74,12 @@ public class GenConstants
/** 日期控件 */ /** 日期控件 */
public static final String HTML_DATETIME = "datetime"; public static final String HTML_DATETIME = "datetime";
/** 上传控件 */
public static final String HTML_UPLOAD_IMAGE = "uploadImage";
/** 富文本控件 */
public static final String HTML_EDITOR = "editor";
/** 字符串类型 */ /** 字符串类型 */
public static final String TYPE_STRING = "String"; public static final String TYPE_STRING = "String";

View File

@@ -54,6 +54,9 @@ public class UserConstants
/** Layout组件标识 */ /** Layout组件标识 */
public final static String LAYOUT = "Layout"; public final static String LAYOUT = "Layout";
/** ParentView组件标识 */
public final static String PARENT_VIEW = "ParentView";
/** 校验返回结果码 */ /** 校验返回结果码 */
public final static String UNIQUE = "0"; public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1"; public final static String NOT_UNIQUE = "1";

View File

@@ -5,7 +5,6 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
/** /**
* Entity基类 * Entity基类
@@ -36,14 +35,6 @@ public class BaseEntity implements Serializable
/** 备注 */ /** 备注 */
private String remark; private String remark;
/** 开始时间 */
@JsonIgnore
private String beginTime;
/** 结束时间 */
@JsonIgnore
private String endTime;
/** 请求参数 */ /** 请求参数 */
private Map<String, Object> params; private Map<String, Object> params;
@@ -107,26 +98,6 @@ public class BaseEntity implements Serializable
this.remark = remark; this.remark = remark;
} }
public String getBeginTime()
{
return beginTime;
}
public void setBeginTime(String beginTime)
{
this.beginTime = beginTime;
}
public String getEndTime()
{
return endTime;
}
public void setEndTime(String endTime)
{
this.endTime = endTime;
}
public Map<String, Object> getParams() public Map<String, Object> getParams()
{ {
if (params == null) if (params == null)

View File

@@ -41,6 +41,9 @@ public class SysMenu extends BaseEntity
/** 是否为外链0是 1否 */ /** 是否为外链0是 1否 */
private String isFrame; private String isFrame;
/** 是否缓存0缓存 1不缓存 */
private String isCache;
/** 类型M目录 C菜单 F按钮 */ /** 类型M目录 C菜单 F按钮 */
private String menuType; private String menuType;
@@ -144,6 +147,16 @@ public class SysMenu extends BaseEntity
this.isFrame = isFrame; this.isFrame = isFrame;
} }
public String getIsCache()
{
return isCache;
}
public void setIsCache(String isCache)
{
this.isCache = isCache;
}
@NotBlank(message = "菜单类型不能为空") @NotBlank(message = "菜单类型不能为空")
public String getMenuType() public String getMenuType()
{ {
@@ -216,6 +229,7 @@ public class SysMenu extends BaseEntity
.append("path", getPath()) .append("path", getPath())
.append("component", getComponent()) .append("component", getComponent())
.append("isFrame", getIsFrame()) .append("isFrame", getIsFrame())
.append("IsCache", getIsCache())
.append("menuType", getMenuType()) .append("menuType", getMenuType())
.append("visible", getVisible()) .append("visible", getVisible())
.append("status ", getStatus()) .append("status ", getStatus())

View File

@@ -37,6 +37,12 @@ public class SysRole extends BaseEntity
@Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限") @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限")
private String dataScope; private String dataScope;
/** 菜单树选择项是否关联显示( 0父子不互相关联显示 1父子互相关联显示 */
private boolean menuCheckStrictly;
/** 部门树选择项是否关联显示0父子不互相关联显示 1父子互相关联显示 */
private boolean deptCheckStrictly;
/** 角色状态0正常 1停用 */ /** 角色状态0正常 1停用 */
@Excel(name = "角色状态", readConverterExp = "0=正常,1=停用") @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
private String status; private String status;
@@ -128,6 +134,26 @@ public class SysRole extends BaseEntity
this.dataScope = dataScope; this.dataScope = dataScope;
} }
public boolean isMenuCheckStrictly()
{
return menuCheckStrictly;
}
public void setMenuCheckStrictly(boolean menuCheckStrictly)
{
this.menuCheckStrictly = menuCheckStrictly;
}
public boolean isDeptCheckStrictly()
{
return deptCheckStrictly;
}
public void setDeptCheckStrictly(boolean deptCheckStrictly)
{
this.deptCheckStrictly = deptCheckStrictly;
}
public String getStatus() public String getStatus()
{ {
return status; return status;
@@ -186,6 +212,8 @@ public class SysRole extends BaseEntity
.append("roleKey", getRoleKey()) .append("roleKey", getRoleKey())
.append("roleSort", getRoleSort()) .append("roleSort", getRoleSort())
.append("dataScope", getDataScope()) .append("dataScope", getDataScope())
.append("menuCheckStrictly", isMenuCheckStrictly())
.append("deptCheckStrictly", isDeptCheckStrictly())
.append("status", getStatus()) .append("status", getStatus())
.append("delFlag", getDelFlag()) .append("delFlag", getDelFlag())
.append("createBy", getCreateBy()) .append("createBy", getCreateBy())

View File

@@ -68,12 +68,12 @@ public class SysUser extends BaseEntity
/** 删除标志0代表存在 2代表删除 */ /** 删除标志0代表存在 2代表删除 */
private String delFlag; private String delFlag;
/** 最后登IP */ /** 最后登IP */
@Excel(name = "最后登IP", type = Type.EXPORT) @Excel(name = "最后登IP", type = Type.EXPORT)
private String loginIp; private String loginIp;
/** 最后登时间 */ /** 最后登时间 */
@Excel(name = "最后登时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) @Excel(name = "最后登时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
private Date loginDate; private Date loginDate;
/** 部门对象 */ /** 部门对象 */

View File

@@ -22,7 +22,7 @@ public class LoginUser implements UserDetails
private String token; private String token;
/** /**
* 登时间 * 登时间
*/ */
private Long loginTime; private Long loginTime;

View File

@@ -18,8 +18,8 @@ public class PageDomain
/** 排序列 */ /** 排序列 */
private String orderByColumn; private String orderByColumn;
/** 排序的方向 "desc" 或者 "asc". */ /** 排序的方向desc或者asc */
private String isAsc; private String isAsc = "asc";
public String getOrderBy() public String getOrderBy()
{ {

View File

@@ -1,11 +1,13 @@
package com.ruoyi.common.core.redis; package com.ruoyi.common.core.redis;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations; import org.springframework.data.redis.core.ValueOperations;
@@ -136,10 +138,15 @@ public class RedisCache
* @param dataSet 缓存的数据 * @param dataSet 缓存的数据
* @return 缓存数据的对象 * @return 缓存数据的对象
*/ */
public <T> long setCacheSet(final String key, final Set<T> dataSet) public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
{ {
Long count = redisTemplate.opsForSet().add(key, dataSet); BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
return count == null ? 0 : count; Iterator<T> it = dataSet.iterator();
while (it.hasNext())
{
setOperation.add(it.next());
}
return setOperation;
} }
/** /**

View File

@@ -66,7 +66,7 @@ public class CharsetKit
if (null == destCharset) if (null == destCharset)
{ {
srcCharset = StandardCharsets.UTF_8; destCharset = StandardCharsets.UTF_8;
} }
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))

View File

@@ -0,0 +1,47 @@
package com.ruoyi.common.utils.file;
import java.io.File;
import org.apache.commons.lang3.StringUtils;
/**
* 文件类型工具类
*
* @author ruoyi
*/
public class FileTypeUtils
{
/**
* 获取文件类型
* <p>
* 例如: ruoyi.txt, 返回: txt
*
* @param file 文件名
* @return 后缀(不含".")
*/
public static String getFileType(File file)
{
if (null == file)
{
return StringUtils.EMPTY;
}
return getFileType(file.getName());
}
/**
* 获取文件类型
* <p>
* 例如: ruoyi.txt, 返回: txt
*
* @param fileName 文件名
* @return 后缀(不含".")
*/
public static String getFileType(String fileName)
{
int separatorIndex = fileName.lastIndexOf(".");
if (separatorIndex < 0)
{
return "";
}
return fileName.substring(separatorIndex + 1).toLowerCase();
}
}

View File

@@ -7,7 +7,11 @@ import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import com.ruoyi.common.utils.StringUtils;
/** /**
* 文件处理工具类 * 文件处理工具类
@@ -104,6 +108,30 @@ public class FileUtils extends org.apache.commons.io.FileUtils
return filename.matches(FILENAME_PATTERN); return filename.matches(FILENAME_PATTERN);
} }
/**
* 检查文件是否可下载
*
* @param resource 需要下载的文件
* @return true 正常 false 非法
*/
public static boolean checkAllowDownload(String resource)
{
// 禁止目录上跳级别
if (StringUtils.contains(resource, ".."))
{
return false;
}
// 检查允许下载的文件规则
if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
{
return true;
}
// 不在允许下载的文件规则
return false;
}
/** /**
* 下载文件名重新编码 * 下载文件名重新编码
* *
@@ -111,8 +139,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
* @param fileName 文件名 * @param fileName 文件名
* @return 编码后的文件名 * @return 编码后的文件名
*/ */
public static String setFileDownloadHeader(HttpServletRequest request, String fileName) public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException
throws UnsupportedEncodingException
{ {
final String agent = request.getHeader("USER-AGENT"); final String agent = request.getHeader("USER-AGENT");
String filename = fileName; String filename = fileName;
@@ -139,4 +166,38 @@ public class FileUtils extends org.apache.commons.io.FileUtils
} }
return filename; return filename;
} }
/**
* 下载文件名重新编码
*
* @param response 响应对象
* @param realFileName 真实文件名
* @return
*/
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
{
String percentEncodedFileName = percentEncode(realFileName);
StringBuilder contentDispositionValue = new StringBuilder();
contentDispositionValue.append("attachment; filename=")
.append(percentEncodedFileName)
.append(";")
.append("filename*=")
.append("utf-8''")
.append(percentEncodedFileName);
response.setHeader("Content-disposition", contentDispositionValue.toString());
}
/**
* 百分号编码工具方法
*
* @param s 需要百分号编码的字符串
* @return 百分号编码后的字符串
*/
public static String percentEncode(String s) throws UnsupportedEncodingException
{
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
return encode.replaceAll("\\+", "%20");
}
} }

View File

@@ -6,8 +6,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
@@ -15,9 +15,9 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellStyle;
@@ -102,6 +102,16 @@ public class ExcelUtil<T>
*/ */
private List<Object[]> fields; private List<Object[]> fields;
/**
* 统计列表
*/
private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
/**
* 数字格式
*/
private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
/** /**
* 实体对象 * 实体对象
*/ */
@@ -232,19 +242,19 @@ public class ExcelUtil<T>
val = Convert.toStr(val); val = Convert.toStr(val);
} }
} }
else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
{ {
val = Convert.toInt(val); val = Convert.toInt(val);
} }
else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) else if (Long.TYPE == fieldType || Long.class == fieldType)
{ {
val = Convert.toLong(val); val = Convert.toLong(val);
} }
else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) else if (Double.TYPE == fieldType || Double.class == fieldType)
{ {
val = Convert.toDouble(val); val = Convert.toDouble(val);
} }
else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) else if (Float.TYPE == fieldType || Float.class == fieldType)
{ {
val = Convert.toFloat(val); val = Convert.toFloat(val);
} }
@@ -263,6 +273,10 @@ public class ExcelUtil<T>
val = DateUtil.getJavaDate((Double) val); val = DateUtil.getJavaDate((Double) val);
} }
} }
else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
{
val = Convert.toBool(val, false);
}
if (StringUtils.isNotNull(fieldType)) if (StringUtils.isNotNull(fieldType))
{ {
Excel attr = field.getAnnotation(Excel.class); Excel attr = field.getAnnotation(Excel.class);
@@ -341,6 +355,7 @@ public class ExcelUtil<T>
if (Type.EXPORT.equals(type)) if (Type.EXPORT.equals(type))
{ {
fillExcelData(index, row); fillExcelData(index, row);
addStatisticsRow();
} }
} }
String filename = encodingFilename(sheetName); String filename = encodingFilename(sheetName);
@@ -447,6 +462,30 @@ public class ExcelUtil<T>
headerFont.setColor(IndexedColors.WHITE.getIndex()); headerFont.setColor(IndexedColors.WHITE.getIndex());
style.setFont(headerFont); style.setFont(headerFont);
styles.put("header", style); styles.put("header", style);
style = wb.createCellStyle();
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
Font totalFont = wb.createFont();
totalFont.setFontName("Arial");
totalFont.setFontHeightInPoints((short) 10);
style.setFont(totalFont);
styles.put("total", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.LEFT);
styles.put("data1", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
styles.put("data2", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.RIGHT);
styles.put("data3", style);
return styles; return styles;
} }
@@ -476,13 +515,11 @@ public class ExcelUtil<T>
{ {
if (ColumnType.STRING == attr.cellType()) if (ColumnType.STRING == attr.cellType())
{ {
cell.setCellType(CellType.STRING);
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
} }
else if (ColumnType.NUMERIC == attr.cellType()) else if (ColumnType.NUMERIC == attr.cellType())
{ {
cell.setCellType(CellType.NUMERIC); cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
cell.setCellValue(Integer.parseInt(value + ""));
} }
} }
@@ -530,7 +567,8 @@ public class ExcelUtil<T>
{ {
// 创建cell // 创建cell
cell = row.createCell(column); cell = row.createCell(column);
cell.setCellStyle(styles.get("data")); int align = attr.align().value();
cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : "")));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@@ -546,15 +584,20 @@ public class ExcelUtil<T>
{ {
cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
} }
else if (StringUtils.isNotEmpty(dictType)) else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
{ {
cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator));
} }
else if (value instanceof BigDecimal && -1 != attr.scale())
{
cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString());
}
else else
{ {
// 设置列类型 // 设置列类型
setCellVo(value, attr, cell); setCellVo(value, attr, cell);
} }
addStatisticsData(column, Convert.toStr(value), attr);
} }
} }
catch (Exception e) catch (Exception e)
@@ -721,6 +764,53 @@ public class ExcelUtil<T>
return DictUtils.getDictValue(dictType, dictLabel, separator); return DictUtils.getDictValue(dictType, dictLabel, separator);
} }
/**
* 合计统计信息
*/
private void addStatisticsData(Integer index, String text, Excel entity)
{
if (entity != null && entity.isStatistics())
{
Double temp = 0D;
if (!statistics.containsKey(index))
{
statistics.put(index, temp);
}
try
{
temp = Double.valueOf(text);
}
catch (NumberFormatException e)
{
}
statistics.put(index, statistics.get(index) + temp);
}
}
/**
* 创建统计行
*/
public void addStatisticsRow()
{
if (statistics.size() > 0)
{
Cell cell = null;
Row row = sheet.createRow(sheet.getLastRowNum() + 1);
Set<Integer> keys = statistics.keySet();
cell = row.createCell(0);
cell.setCellStyle(styles.get("total"));
cell.setCellValue("合计");
for (Integer key : keys)
{
cell = row.createCell(key);
cell.setCellStyle(styles.get("total"));
cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key)));
}
statistics.clear();
}
}
/** /**
* 编码文件名 * 编码文件名
*/ */
@@ -787,12 +877,12 @@ public class ExcelUtil<T>
*/ */
private Object getValue(Object o, String name) throws Exception private Object getValue(Object o, String name) throws Exception
{ {
if (StringUtils.isNotEmpty(name)) if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name))
{ {
Class<?> clazz = o.getClass(); Class<?> clazz = o.getClass();
String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); Field field = clazz.getDeclaredField(name);
Method method = clazz.getMethod(methodName); field.setAccessible(true);
o = method.invoke(o); o = field.get(o);
} }
return o; return o;
} }
@@ -887,27 +977,34 @@ public class ExcelUtil<T>
Cell cell = row.getCell(column); Cell cell = row.getCell(column);
if (StringUtils.isNotNull(cell)) if (StringUtils.isNotNull(cell))
{ {
if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA)
{ {
val = cell.getNumericCellValue(); val = cell.getNumericCellValue();
if (HSSFDateUtil.isCellDateFormatted(cell)) if (DateUtil.isCellDateFormatted(cell))
{ {
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
} }
else else
{ {
val = new BigDecimal(val.toString()); // 浮点格式处理 if ((Double) val % 1 > 0)
{
val = new BigDecimal(val.toString());
}
else
{
val = new DecimalFormat("0").format(val);
}
} }
} }
else if (cell.getCellTypeEnum() == CellType.STRING) else if (cell.getCellType() == CellType.STRING)
{ {
val = cell.getStringCellValue(); val = cell.getStringCellValue();
} }
else if (cell.getCellTypeEnum() == CellType.BOOLEAN) else if (cell.getCellType() == CellType.BOOLEAN)
{ {
val = cell.getBooleanCellValue(); val = cell.getBooleanCellValue();
} }
else if (cell.getCellTypeEnum() == CellType.ERROR) else if (cell.getCellType() == CellType.ERROR)
{ {
val = cell.getErrorCellValue(); val = cell.getErrorCellValue();
} }

View File

@@ -204,6 +204,10 @@ public class ReflectUtils
args[i] = DateUtil.getJavaDate((Double) args[i]); args[i] = DateUtil.getJavaDate((Double) args[i]);
} }
} }
else if (cs[i] == boolean.class || cs[i] == Boolean.class)
{
args[i] = Convert.toBool(args[i]);
}
} }
} }
return (E) method.invoke(obj, args); return (E) method.invoke(obj, args);

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>3.1.0</version> <version>3.3.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -53,16 +53,6 @@
<artifactId>oshi-core</artifactId> <artifactId>oshi-core</artifactId>
</dependency> </dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
</dependency>
<!-- 系统模块--> <!-- 系统模块-->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>

View File

@@ -79,11 +79,11 @@ public class DataScopeAspect
} }
// 获取当前的用户 // 获取当前的用户
LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest()); LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
SysUser currentUser = loginUser.getUser(); if (StringUtils.isNotNull(loginUser))
if (currentUser != null)
{ {
SysUser currentUser = loginUser.getUser();
// 如果是超级管理员,则不过滤数据 // 如果是超级管理员,则不过滤数据
if (!currentUser.isAdmin()) if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{ {
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
controllerDataScope.userAlias()); controllerDataScope.userAlias());
@@ -142,8 +142,12 @@ public class DataScopeAspect
if (StringUtils.isNotBlank(sqlString.toString())) if (StringUtils.isNotBlank(sqlString.toString()))
{ {
BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0]; Object params = joinPoint.getArgs()[0];
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
{
BaseEntity baseEntity = (BaseEntity) params;
baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
}
} }
} }

View File

@@ -1,6 +1,8 @@
package com.ruoyi.framework.aspectj; package com.ruoyi.framework.aspectj;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@@ -210,8 +212,31 @@ public class LogAspect
* @param o 对象信息。 * @param o 对象信息。
* @return 如果是需要过滤的对象则返回true否则返回false。 * @return 如果是需要过滤的对象则返回true否则返回false。
*/ */
@SuppressWarnings("rawtypes")
public boolean isFilterObject(final Object o) public boolean isFilterObject(final Object o)
{ {
Class<?> clazz = o.getClass();
if (clazz.isArray())
{
return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
}
else if (Collection.class.isAssignableFrom(clazz))
{
Collection collection = (Collection) o;
for (Iterator iter = collection.iterator(); iter.hasNext();)
{
return iter.next() instanceof MultipartFile;
}
}
else if (Map.class.isAssignableFrom(clazz))
{
Map map = (Map) o;
for (Iterator iter = map.entrySet().iterator(); iter.hasNext();)
{
Map.Entry entry = (Map.Entry) iter.next();
return entry.getValue() instanceof MultipartFile;
}
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse; return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
} }
} }

View File

@@ -2,6 +2,7 @@ package com.ruoyi.framework.config;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import javax.sql.DataSource; import javax.sql.DataSource;
@@ -21,6 +22,7 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import com.ruoyi.common.utils.StringUtils;
/** /**
* Mybatis支持*匹配扫描包 * Mybatis支持*匹配扫描包
@@ -89,6 +91,28 @@ public class MyBatisConfig
return typeAliasesPackage; return typeAliasesPackage;
} }
public Resource[] resolveMapperLocations(String[] mapperLocations)
{
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<Resource> resources = new ArrayList<Resource>();
if (mapperLocations != null)
{
for (String mapperLocation : mapperLocations)
{
try
{
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
}
catch (IOException e)
{
// ignore
}
}
}
return resources.toArray(new Resource[resources.size()]);
}
@Bean @Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
{ {
@@ -101,7 +125,7 @@ public class MyBatisConfig
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource); sessionFactory.setDataSource(dataSource);
sessionFactory.setTypeAliasesPackage(typeAliasesPackage); sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations)); sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
return sessionFactory.getObject(); return sessionFactory.getObject();
} }

View File

@@ -88,7 +88,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
protected void configure(HttpSecurity httpSecurity) throws Exception protected void configure(HttpSecurity httpSecurity) throws Exception
{ {
httpSecurity httpSecurity
// CRSF禁用因为不使用session // CSRF禁用因为不使用session
.csrf().disable() .csrf().disable()
// 认证失败处理类 // 认证失败处理类
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()

View File

@@ -25,7 +25,7 @@ public class AsyncFactory
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
/** /**
* 记录登信息 * 记录登信息
* *
* @param username 用户名 * @param username 用户名
* @param status 状态 * @param status 状态

View File

@@ -189,7 +189,7 @@ public class Server
private void setSysFiles(OperatingSystem os) private void setSysFiles(OperatingSystem os)
{ {
FileSystem fileSystem = os.getFileSystem(); FileSystem fileSystem = os.getFileSystem();
OSFileStore[] fsArray = fileSystem.getFileStores(); List<OSFileStore> fsArray = fileSystem.getFileStores();
for (OSFileStore fs : fsArray) for (OSFileStore fs : fsArray)
{ {
long free = fs.getUsableSpace(); long free = fs.getUsableSpace();

View File

@@ -109,7 +109,7 @@ public class PermissionService
for (SysRole sysRole : loginUser.getUser().getRoles()) for (SysRole sysRole : loginUser.getUser().getRoles())
{ {
String roleKey = sysRole.getRoleKey(); String roleKey = sysRole.getRoleKey();
if (SUPER_ADMIN.contains(roleKey) || roleKey.contains(StringUtils.trim(role))) if (SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
{ {
return true; return true;
} }

View File

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

View File

@@ -165,12 +165,24 @@ public class GenController extends BaseController
@PreAuthorize("@ss.hasPermi('tool:gen:code')") @PreAuthorize("@ss.hasPermi('tool:gen:code')")
@Log(title = "代码生成", businessType = BusinessType.GENCODE) @Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/genCode/{tableName}") @GetMapping("/genCode/{tableName}")
public AjaxResult genCode(HttpServletResponse response, @PathVariable("tableName") String tableName) public AjaxResult genCode(@PathVariable("tableName") String tableName)
{ {
genTableService.generatorCode(tableName); genTableService.generatorCode(tableName);
return AjaxResult.success(); return AjaxResult.success();
} }
/**
* 同步数据库
*/
@PreAuthorize("@ss.hasPermi('tool:gen:edit')")
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
@GetMapping("/synchDb/{tableName}")
public AjaxResult synchDb(@PathVariable("tableName") String tableName)
{
genTableService.synchDb(tableName);
return AjaxResult.success();
}
/** /**
* 批量生成代码 * 批量生成代码
*/ */

View File

@@ -59,7 +59,7 @@ public class GenTableColumn extends BaseEntity
/** 查询方式EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围 */ /** 查询方式EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围 */
private String queryType; private String queryType;
/** 显示类型input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件 */ /** 显示类型input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、upload上传控件、editor富文本控件 */
private String htmlType; private String htmlType;
/** 字典类型 */ /** 字典类型 */
@@ -340,7 +340,7 @@ public class GenTableColumn extends BaseEntity
public static boolean isUsableColumn(String javaField) public static boolean isUsableColumn(String javaField)
{ {
// isSuperColumn()中的名单用于避免生成多余Domain属性若某些属性在生成页面时需要用到不能忽略则放在此处白名单 // isSuperColumn()中的名单用于避免生成多余Domain属性若某些属性在生成页面时需要用到不能忽略则放在此处白名单
return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum"); return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
} }
public String readConverterExp() public String readConverterExp()

View File

@@ -17,7 +17,7 @@ public interface GenTableColumnMapper
* @return 列信息 * @return 列信息
*/ */
public List<GenTableColumn> selectDbTableColumnsByName(String tableName); public List<GenTableColumn> selectDbTableColumnsByName(String tableName);
/** /**
* 查询业务字段列表 * 查询业务字段列表
* *
@@ -42,6 +42,14 @@ public interface GenTableColumnMapper
*/ */
public int updateGenTableColumn(GenTableColumn genTableColumn); public int updateGenTableColumn(GenTableColumn genTableColumn);
/**
* 删除业务字段
*
* @param genTableColumns 列数据
* @return 结果
*/
public int deleteGenTableColumns(List<GenTableColumn> genTableColumns);
/** /**
* 批量删除业务字段 * 批量删除业务字段
* *

View File

@@ -7,6 +7,7 @@ import java.io.StringWriter;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@@ -224,7 +225,6 @@ public class GenTableServiceImpl implements IGenTableService
* 生成代码(自定义路径) * 生成代码(自定义路径)
* *
* @param tableName 表名称 * @param tableName 表名称
* @return 数据
*/ */
@Override @Override
public void generatorCode(String tableName) public void generatorCode(String tableName)
@@ -262,6 +262,37 @@ public class GenTableServiceImpl implements IGenTableService
} }
} }
/**
* 同步数据库
*
* @param tableName 表名称
*/
@Override
@Transactional
public void synchDb(String tableName)
{
GenTable table = genTableMapper.selectGenTableByName(tableName);
List<GenTableColumn> tableColumns = table.getColumns();
List<String> tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
dbTableColumns.forEach(column -> {
if (!tableColumnNames.contains(column.getColumnName()))
{
GenUtils.initColumnField(column, table);
genTableColumnMapper.insertGenTableColumn(column);
}
});
List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
if (StringUtils.isNotEmpty(delColumns))
{
genTableColumnMapper.deleteGenTableColumns(delColumns);
}
}
/** /**
* 批量生成代码(下载方式) * 批量生成代码(下载方式)
* *

View File

@@ -90,6 +90,13 @@ public interface IGenTableService
*/ */
public void generatorCode(String tableName); public void generatorCode(String tableName);
/**
* 同步数据库
*
* @param tableName 表名称
*/
public void synchDb(String tableName);
/** /**
* 批量生成代码(下载方式) * 批量生成代码(下载方式)
* *

View File

@@ -111,6 +111,16 @@ public class GenUtils
{ {
column.setHtmlType(GenConstants.HTML_SELECT); column.setHtmlType(GenConstants.HTML_SELECT);
} }
// 文件字段设置上传控件
else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
{
column.setHtmlType(GenConstants.HTML_UPLOAD_IMAGE);
}
// 内容字段设置富文本控件
else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
{
column.setHtmlType(GenConstants.HTML_EDITOR);
}
} }
/** /**

View File

@@ -117,4 +117,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
</delete> </delete>
<delete id="deleteGenTableColumns">
delete from gen_table_column where column_id in
<foreach collection="list" item="item" open="(" separator="," close=")">
#{item.columnId}
</foreach>
</delete>
</mapper> </mapper>

View File

@@ -64,11 +64,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="tableComment != null and tableComment != ''"> <if test="tableComment != null and tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d') AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if> </if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d') AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if> </if>
</where> </where>
</select> </select>
@@ -84,11 +84,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="tableComment != null and tableComment != ''"> <if test="tableComment != null and tableComment != ''">
AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d') AND date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if> </if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d') AND date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if> </if>
</select> </select>
@@ -186,4 +186,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach> </foreach>
</delete> </delete>
</mapper> </mapper>

View File

@@ -1,22 +1,22 @@
-- 菜单 SQL -- 菜单 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '${functionName}菜单'); values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');
-- 按钮父菜单ID -- 按钮父菜单ID
SELECT @parentId := LAST_INSERT_ID(); SELECT @parentId := LAST_INSERT_ID();
-- 按钮 SQL -- 按钮 SQL
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}查询', @parentId, '1', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); values('${functionName}查询', @parentId, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}新增', @parentId, '2', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); values('${functionName}新增', @parentId, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}修改', @parentId, '3', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); values('${functionName}修改', @parentId, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}删除', @parentId, '4', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); values('${functionName}删除', @parentId, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values('${functionName}导出', @parentId, '5', '#', '', 1, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); values('${functionName}导出', @parentId, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 'admin', sysdate(), '', null, '');

View File

@@ -66,7 +66,7 @@
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table <el-table
@@ -139,8 +139,16 @@
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-input v-model="form.${field}" placeholder="请输入${comment}" /> <el-input v-model="form.${field}" placeholder="请输入${comment}" />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType) #elseif($column.htmlType == "uploadImage")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<uploadImage v-model="form.${field}"/>
</el-form-item>
#elseif($column.htmlType == "editor")
<el-form-item label="${comment}">
<editor v-model="form.${field}" :min-height="192"/>
</el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}"> <el-select v-model="form.${field}" placeholder="请选择${comment}">
<el-option <el-option
v-for="dict in ${field}Options" v-for="dict in ${field}Options"
@@ -152,7 +160,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "select" && $dictType) #elseif($column.htmlType == "select" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}"> <el-select v-model="form.${field}" placeholder="请选择${comment}">
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
@@ -221,10 +229,36 @@
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}"; import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css";
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage")
import UploadImage from '@/components/UploadImage';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
import Editor from '@/components/Editor';
#break
#end
#end
export default { export default {
name: "${BusinessName}", name: "${BusinessName}",
components: { Treeselect }, components: {
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage")
UploadImage,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
Editor,
#break
#end
#end
Treeselect
},
data() { data() {
return { return {
// 遮罩层 // 遮罩层
@@ -272,9 +306,8 @@ export default {
#else #else
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
#set($comment=$column.columnComment)
$column.javaField: [ $column.javaField: [
{ required: true, message: "$comment不能为空", trigger: "blur" } { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
]#if($velocityCount != $columns.size()),#end ]#if($velocityCount != $columns.size()),#end
#end #end
@@ -403,19 +436,15 @@ export default {
#end #end
if (this.form.${pkColumn.javaField} != null) { if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => { update${BusinessName}(this.form).then(response => {
if (response.code === 200) { this.msgSuccess("修改成功");
this.msgSuccess("修改成功"); this.open = false;
this.open = false; this.getList();
this.getList();
}
}); });
} else { } else {
add${BusinessName}(this.form).then(response => { add${BusinessName}(this.form).then(response => {
if (response.code === 200) { this.msgSuccess("新增成功");
this.msgSuccess("新增成功"); this.open = false;
this.open = false; this.getList();
this.getList();
}
}); });
} }
} }
@@ -432,7 +461,7 @@ export default {
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); })
} }
} }
}; };

View File

@@ -168,8 +168,16 @@
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-input v-model="form.${field}" placeholder="请输入${comment}" /> <el-input v-model="form.${field}" placeholder="请输入${comment}" />
</el-form-item> </el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType) #elseif($column.htmlType == "uploadImage")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<uploadImage v-model="form.${field}"/>
</el-form-item>
#elseif($column.htmlType == "editor")
<el-form-item label="${comment}">
<editor v-model="form.${field}" :min-height="192"/>
</el-form-item>
#elseif($column.htmlType == "select" && "" != $dictType)
<el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}"> <el-select v-model="form.${field}" placeholder="请选择${comment}">
<el-option <el-option
v-for="dict in ${field}Options" v-for="dict in ${field}Options"
@@ -181,7 +189,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "select" && $dictType) #elseif($column.htmlType == "select" && $dictType)
<el-form-item label="${comment}"> <el-form-item label="${comment}" prop="${field}">
<el-select v-model="form.${field}" placeholder="请选择${comment}"> <el-select v-model="form.${field}" placeholder="请选择${comment}">
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
@@ -248,9 +256,35 @@
<script> <script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}"; import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName}, export${BusinessName} } from "@/api/${moduleName}/${businessName}";
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage")
import UploadImage from '@/components/UploadImage';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
import Editor from '@/components/Editor';
#break
#end
#end
export default { export default {
name: "${BusinessName}", name: "${BusinessName}",
components: {
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage")
UploadImage,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "editor")
Editor,
#break
#end
#end
},
data() { data() {
return { return {
// 遮罩层 // 遮罩层
@@ -306,9 +340,8 @@ export default {
#else #else
#set($comment=$column.columnComment) #set($comment=$column.columnComment)
#end #end
#set($comment=$column.columnComment)
$column.javaField: [ $column.javaField: [
{ required: true, message: "$comment不能为空", trigger: "blur" } { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select")"change"#else"blur"#end }
]#if($velocityCount != $columns.size()),#end ]#if($velocityCount != $columns.size()),#end
#end #end
@@ -421,19 +454,15 @@ export default {
#end #end
if (this.form.${pkColumn.javaField} != null) { if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => { update${BusinessName}(this.form).then(response => {
if (response.code === 200) { this.msgSuccess("修改成功");
this.msgSuccess("修改成功"); this.open = false;
this.open = false; this.getList();
this.getList();
}
}); });
} else { } else {
add${BusinessName}(this.form).then(response => { add${BusinessName}(this.form).then(response => {
if (response.code === 200) { this.msgSuccess("新增成功");
this.msgSuccess("新增成功"); this.open = false;
this.open = false; this.getList();
this.getList();
}
}); });
} }
} }
@@ -451,7 +480,7 @@ export default {
}).then(() => { }).then(() => {
this.getList(); this.getList();
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}).catch(function() {}); })
}, },
/** 导出按钮操作 */ /** 导出按钮操作 */
handleExport() { handleExport() {
@@ -464,7 +493,7 @@ export default {
return export${BusinessName}(queryParams); return export${BusinessName}(queryParams);
}).then(response => { }).then(response => {
this.download(response.msg); this.download(response.msg);
}).catch(function() {}); })
} }
} }
}; };

View File

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

View File

@@ -88,7 +88,7 @@ public class SysJob extends BaseEntity implements Serializable
} }
@NotBlank(message = "调用目标字符串不能为空") @NotBlank(message = "调用目标字符串不能为空")
@Size(min = 0, max = 1000, message = "调用目标字符串长度不能超过500个字符") @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符")
public String getInvokeTarget() public String getInvokeTarget()
{ {
return invokeTarget; return invokeTarget;

View File

@@ -35,11 +35,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="invokeTarget != null and invokeTarget != ''"> <if test="invokeTarget != null and invokeTarget != ''">
AND invoke_target like concat('%', #{invokeTarget}, '%') AND invoke_target like concat('%', #{invokeTarget}, '%')
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d') and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if> </if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d') and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if> </if>
</where> </where>
</select> </select>

View File

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

View File

@@ -13,10 +13,15 @@ public class MetaVo
private String title; private String title;
/** /**
* 设置该路由的图标对应路径src/icons/svg * 设置该路由的图标对应路径src/assets/icons/svg
*/ */
private String icon; private String icon;
/**
* 设置为true则不会被 <keep-alive>缓存
*/
private boolean noCache;
public MetaVo() public MetaVo()
{ {
} }
@@ -27,6 +32,23 @@ public class MetaVo
this.icon = icon; this.icon = icon;
} }
public MetaVo(String title, String icon, boolean noCache)
{
this.title = title;
this.icon = icon;
this.noCache = noCache;
}
public boolean isNoCache()
{
return noCache;
}
public void setNoCache(boolean noCache)
{
this.noCache = noCache;
}
public String getTitle() public String getTitle()
{ {
return title; return title;

View File

@@ -23,9 +23,10 @@ public interface SysDeptMapper
* 根据角色ID查询部门树信息 * 根据角色ID查询部门树信息
* *
* @param roleId 角色ID * @param roleId 角色ID
* @param deptCheckStrictly 部门树选择项是否关联显示
* @return 选中部门列表 * @return 选中部门列表
*/ */
public List<Integer> selectDeptListByRoleId(Long roleId); public List<Integer> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
/** /**
* 根据部门ID查询信息 * 根据部门ID查询信息

View File

@@ -59,11 +59,12 @@ public interface SysMenuMapper
/** /**
* 根据角色ID查询菜单树信息 * 根据角色ID查询菜单树信息
* *
* @param roleId 角色ID * @param roleId 角色ID
* @param menuCheckStrictly 菜单树选择项是否关联显示
* @return 选中菜单列表 * @return 选中菜单列表
*/ */
public List<Integer> selectMenuListByRoleId(Long roleId); public List<Integer> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
/** /**
* 根据菜单ID查询信息 * 根据菜单ID查询信息

View File

@@ -26,6 +26,14 @@ public interface SysRoleMenuMapper
*/ */
public int deleteRoleMenuByRoleId(Long roleId); public int deleteRoleMenuByRoleId(Long roleId);
/**
* 批量删除角色菜单关联信息
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int deleteRoleMenu(Long[] ids);
/** /**
* 批量新增角色菜单信息 * 批量新增角色菜单信息
* *

View File

@@ -11,6 +11,7 @@ import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.enums.DataSourceType; import com.ruoyi.common.enums.DataSourceType;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper; import com.ruoyi.system.mapper.SysConfigMapper;
@@ -138,6 +139,14 @@ public class SysConfigServiceImpl implements ISysConfigService
@Override @Override
public int deleteConfigByIds(Long[] configIds) public int deleteConfigByIds(Long[] configIds)
{ {
for (Long configId : configIds)
{
SysConfig config = selectConfigById(configId);
if (StringUtils.equals(UserConstants.YES, config.getConfigType()))
{
throw new CustomException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
}
}
int count = configMapper.deleteConfigByIds(configIds); int count = configMapper.deleteConfigByIds(configIds);
if (count > 0) if (count > 0)
{ {

View File

@@ -10,9 +10,11 @@ import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.exception.CustomException; import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.mapper.SysDeptMapper; import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.system.service.ISysDeptService; import com.ruoyi.system.service.ISysDeptService;
/** /**
@@ -26,6 +28,9 @@ public class SysDeptServiceImpl implements ISysDeptService
@Autowired @Autowired
private SysDeptMapper deptMapper; private SysDeptMapper deptMapper;
@Autowired
private SysRoleMapper roleMapper;
/** /**
* 查询部门管理数据 * 查询部门管理数据
* *
@@ -93,7 +98,8 @@ public class SysDeptServiceImpl implements ISysDeptService
@Override @Override
public List<Integer> selectDeptListByRoleId(Long roleId) public List<Integer> selectDeptListByRoleId(Long roleId)
{ {
return deptMapper.selectDeptListByRoleId(roleId); SysRole role = roleMapper.selectRoleById(roleId);
return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
} }
/** /**
@@ -267,13 +273,7 @@ public class SysDeptServiceImpl implements ISysDeptService
{ {
if (hasChild(list, tChild)) if (hasChild(list, tChild))
{ {
// 判断是否有子节点 recursionFn(list, tChild);
Iterator<SysDept> it = childList.iterator();
while (it.hasNext())
{
SysDept n = (SysDept) it.next();
recursionFn(list, n);
}
} }
} }
} }

View File

@@ -76,12 +76,12 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService
public List<SysDictData> selectDictDataByType(String dictType) public List<SysDictData> selectDictDataByType(String dictType)
{ {
List<SysDictData> dictDatas = DictUtils.getDictCache(dictType); List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);
if (StringUtils.isNotNull(dictDatas)) if (StringUtils.isNotEmpty(dictDatas))
{ {
return dictDatas; return dictDatas;
} }
dictDatas = dictDataMapper.selectDictDataByType(dictType); dictDatas = dictDataMapper.selectDictDataByType(dictType);
if (StringUtils.isNotNull(dictDatas)) if (StringUtils.isNotEmpty(dictDatas))
{ {
DictUtils.setDictCache(dictType, dictDatas); DictUtils.setDictCache(dictType, dictDatas);
return dictDatas; return dictDatas;

View File

@@ -13,12 +13,14 @@ import org.springframework.stereotype.Service;
import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.vo.MetaVo; import com.ruoyi.system.domain.vo.MetaVo;
import com.ruoyi.system.domain.vo.RouterVo; import com.ruoyi.system.domain.vo.RouterVo;
import com.ruoyi.system.mapper.SysMenuMapper; import com.ruoyi.system.mapper.SysMenuMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.system.mapper.SysRoleMenuMapper; import com.ruoyi.system.mapper.SysRoleMenuMapper;
import com.ruoyi.system.service.ISysMenuService; import com.ruoyi.system.service.ISysMenuService;
@@ -35,6 +37,9 @@ public class SysMenuServiceImpl implements ISysMenuService
@Autowired @Autowired
private SysMenuMapper menuMapper; private SysMenuMapper menuMapper;
@Autowired
private SysRoleMapper roleMapper;
@Autowired @Autowired
private SysRoleMenuMapper roleMenuMapper; private SysRoleMenuMapper roleMenuMapper;
@@ -124,7 +129,8 @@ public class SysMenuServiceImpl implements ISysMenuService
@Override @Override
public List<Integer> selectMenuListByRoleId(Long roleId) public List<Integer> selectMenuListByRoleId(Long roleId)
{ {
return menuMapper.selectMenuListByRoleId(roleId); SysRole role = roleMapper.selectRoleById(roleId);
return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
} }
/** /**
@@ -144,7 +150,7 @@ public class SysMenuServiceImpl implements ISysMenuService
router.setName(getRouteName(menu)); router.setName(getRouteName(menu));
router.setPath(getRouterPath(menu)); router.setPath(getRouterPath(menu));
router.setComponent(getComponent(menu)); router.setComponent(getComponent(menu));
router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache())));
List<SysMenu> cMenus = menu.getChildren(); List<SysMenu> cMenus = menu.getChildren();
if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType())) if (!cMenus.isEmpty() && cMenus.size() > 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
{ {
@@ -159,7 +165,7 @@ public class SysMenuServiceImpl implements ISysMenuService
children.setPath(menu.getPath()); children.setPath(menu.getPath());
children.setComponent(menu.getComponent()); children.setComponent(menu.getComponent());
children.setName(StringUtils.capitalize(menu.getPath())); children.setName(StringUtils.capitalize(menu.getPath()));
children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon())); children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache())));
childrenList.add(children); childrenList.add(children);
router.setChildren(childrenList); router.setChildren(childrenList);
} }
@@ -178,14 +184,19 @@ public class SysMenuServiceImpl implements ISysMenuService
public List<SysMenu> buildMenuTree(List<SysMenu> menus) public List<SysMenu> buildMenuTree(List<SysMenu> menus)
{ {
List<SysMenu> returnList = new ArrayList<SysMenu>(); List<SysMenu> returnList = new ArrayList<SysMenu>();
List<Long> tempList = new ArrayList<Long>();
for (SysMenu dept : menus)
{
tempList.add(dept.getMenuId());
}
for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();) for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();)
{ {
SysMenu t = (SysMenu) iterator.next(); SysMenu menu = (SysMenu) iterator.next();
// 根据传入的某个父节点ID,遍历该父节点的所有子节点 // 如果是顶级节点, 遍历该父节点的所有子节点
if (t.getParentId() == 0) if (!tempList.contains(menu.getParentId()))
{ {
recursionFn(menus, t); recursionFn(menus, menu);
returnList.add(t); returnList.add(menu);
} }
} }
if (returnList.isEmpty()) if (returnList.isEmpty())
@@ -353,6 +364,10 @@ public class SysMenuServiceImpl implements ISysMenuService
{ {
component = menu.getComponent(); component = menu.getComponent();
} }
else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu))
{
component = UserConstants.PARENT_VIEW;
}
return component; return component;
} }
@@ -368,6 +383,17 @@ public class SysMenuServiceImpl implements ISysMenuService
&& menu.getIsFrame().equals(UserConstants.NO_FRAME); && menu.getIsFrame().equals(UserConstants.NO_FRAME);
} }
/**
* 是否为parent_view组件
*
* @param menu 菜单信息
* @return 结果
*/
public boolean isParentView(SysMenu menu)
{
return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType());
}
/** /**
* 根据父节点的ID获取所有子节点 * 根据父节点的ID获取所有子节点
* *
@@ -406,13 +432,7 @@ public class SysMenuServiceImpl implements ISysMenuService
{ {
if (hasChild(list, tChild)) if (hasChild(list, tChild))
{ {
// 判断是否有子节点 recursionFn(list, tChild);
Iterator<SysMenu> it = childList.iterator();
while (it.hasNext())
{
SysMenu n = (SysMenu) it.next();
recursionFn(list, n);
}
} }
} }
} }

View File

@@ -290,8 +290,13 @@ public class SysRoleServiceImpl implements ISysRoleService
* @return 结果 * @return 结果
*/ */
@Override @Override
@Transactional
public int deleteRoleById(Long roleId) public int deleteRoleById(Long roleId)
{ {
// 删除角色与菜单关联
roleMenuMapper.deleteRoleMenuByRoleId(roleId);
// 删除角色与部门关联
roleDeptMapper.deleteRoleDeptByRoleId(roleId);
return roleMapper.deleteRoleById(roleId); return roleMapper.deleteRoleById(roleId);
} }
@@ -302,6 +307,7 @@ public class SysRoleServiceImpl implements ISysRoleService
* @return 结果 * @return 结果
*/ */
@Override @Override
@Transactional
public int deleteRoleByIds(Long[] roleIds) public int deleteRoleByIds(Long[] roleIds)
{ {
for (Long roleId : roleIds) for (Long roleId : roleIds)
@@ -313,6 +319,10 @@ public class SysRoleServiceImpl implements ISysRoleService
throw new CustomException(String.format("%1$s已分配,不能删除", role.getRoleName())); throw new CustomException(String.format("%1$s已分配,不能删除", role.getRoleName()));
} }
} }
// 删除角色与菜单关联
roleMenuMapper.deleteRoleMenu(roleIds);
// 删除角色与部门关联
roleDeptMapper.deleteRoleDept(roleIds);
return roleMapper.deleteRoleByIds(roleIds); return roleMapper.deleteRoleByIds(roleIds);
} }
} }

View File

@@ -363,6 +363,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return 结果 * @return 结果
*/ */
@Override @Override
@Transactional
public int deleteUserById(Long userId) public int deleteUserById(Long userId)
{ {
// 删除用户与角色关联 // 删除用户与角色关联
@@ -379,12 +380,17 @@ public class SysUserServiceImpl implements ISysUserService
* @return 结果 * @return 结果
*/ */
@Override @Override
@Transactional
public int deleteUserByIds(Long[] userIds) public int deleteUserByIds(Long[] userIds)
{ {
for (Long userId : userIds) for (Long userId : userIds)
{ {
checkUserAllowed(new SysUser(userId)); checkUserAllowed(new SysUser(userId));
} }
// 删除用户与角色关联
userRoleMapper.deleteUserRole(userIds);
// 删除用户与岗位关联
userPostMapper.deleteUserPost(userIds);
return userMapper.deleteUserByIds(userIds); return userMapper.deleteUserByIds(userIds);
} }

View File

@@ -50,11 +50,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="configKey != null and configKey != ''"> <if test="configKey != null and configKey != ''">
AND config_key like concat('%', #{configKey}, '%') AND config_key like concat('%', #{configKey}, '%')
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d') and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if> </if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d') and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if> </if>
</where> </where>
</select> </select>

View File

@@ -44,12 +44,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
order by d.parent_id, d.order_num order by d.parent_id, d.order_num
</select> </select>
<select id="selectDeptListByRoleId" parameterType="Long" resultType="Integer"> <select id="selectDeptListByRoleId" resultType="Integer">
select d.dept_id, d.parent_id select d.dept_id
from sys_dept d from sys_dept d
left join sys_role_dept rd on d.dept_id = rd.dept_id left join sys_role_dept rd on d.dept_id = rd.dept_id
where rd.role_id = #{roleId} where rd.role_id = #{roleId}
and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId}) <if test="deptCheckStrictly">
and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId})
</if>
order by d.parent_id, d.order_num order by d.parent_id, d.order_num
</select> </select>

View File

@@ -32,11 +32,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="dictType != null and dictType != ''"> <if test="dictType != null and dictType != ''">
AND dict_type like concat('%', #{dictType}, '%') AND dict_type like concat('%', #{dictType}, '%')
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d') and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if> </if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d') and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if> </if>
</where> </where>
</select> </select>

View File

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

View File

@@ -13,6 +13,7 @@
<result property="path" column="path" /> <result property="path" column="path" />
<result property="component" column="component" /> <result property="component" column="component" />
<result property="isFrame" column="is_frame" /> <result property="isFrame" column="is_frame" />
<result property="isCache" column="is_cache" />
<result property="menuType" column="menu_type" /> <result property="menuType" column="menu_type" />
<result property="visible" column="visible" /> <result property="visible" column="visible" />
<result property="status" column="status" /> <result property="status" column="status" />
@@ -26,7 +27,7 @@
</resultMap> </resultMap>
<sql id="selectMenuVo"> <sql id="selectMenuVo">
select menu_id, menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time select menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time
from sys_menu from sys_menu
</sql> </sql>
@@ -47,13 +48,13 @@
</select> </select>
<select id="selectMenuTreeAll" resultMap="SysMenuResult"> <select id="selectMenuTreeAll" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0 from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
order by m.parent_id, m.order_num order by m.parent_id, m.order_num
</select> </select>
<select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult"> <select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_role_menu rm on m.menu_id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id left join sys_user_role ur on rm.role_id = ur.role_id
@@ -72,7 +73,7 @@
</select> </select>
<select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult"> <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult">
select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
from sys_menu m from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_role_menu rm on m.menu_id = rm.menu_id
left join sys_user_role ur on rm.role_id = ur.role_id left join sys_user_role ur on rm.role_id = ur.role_id
@@ -82,12 +83,14 @@
order by m.parent_id, m.order_num order by m.parent_id, m.order_num
</select> </select>
<select id="selectMenuListByRoleId" parameterType="Long" resultType="Integer"> <select id="selectMenuListByRoleId" resultType="Integer">
select m.menu_id, m.parent_id select m.menu_id
from sys_menu m from sys_menu m
left join sys_role_menu rm on m.menu_id = rm.menu_id left join sys_role_menu rm on m.menu_id = rm.menu_id
where rm.role_id = #{roleId} where rm.role_id = #{roleId}
and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id = rm.menu_id and rm.role_id = #{roleId}) <if test="menuCheckStrictly">
and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id = rm.menu_id and rm.role_id = #{roleId})
</if>
order by m.parent_id, m.order_num order by m.parent_id, m.order_num
</select> </select>
@@ -130,6 +133,7 @@
<if test="path != null and path != ''">path = #{path},</if> <if test="path != null and path != ''">path = #{path},</if>
<if test="component != null and component != ''">component = #{component},</if> <if test="component != null and component != ''">component = #{component},</if>
<if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if> <if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if>
<if test="isCache != null and isCache != ''">is_cache = #{isCache},</if>
<if test="menuType != null and menuType != ''">menu_type = #{menuType},</if> <if test="menuType != null and menuType != ''">menu_type = #{menuType},</if>
<if test="visible != null">visible = #{visible},</if> <if test="visible != null">visible = #{visible},</if>
<if test="status != null">status = #{status},</if> <if test="status != null">status = #{status},</if>
@@ -151,6 +155,7 @@
<if test="path != null and path != ''">path,</if> <if test="path != null and path != ''">path,</if>
<if test="component != null and component != ''">component,</if> <if test="component != null and component != ''">component,</if>
<if test="isFrame != null and isFrame != ''">is_frame,</if> <if test="isFrame != null and isFrame != ''">is_frame,</if>
<if test="isCache != null and isCache != ''">is_cache,</if>
<if test="menuType != null and menuType != ''">menu_type,</if> <if test="menuType != null and menuType != ''">menu_type,</if>
<if test="visible != null">visible,</if> <if test="visible != null">visible,</if>
<if test="status != null">status,</if> <if test="status != null">status,</if>
@@ -167,6 +172,7 @@
<if test="path != null and path != ''">#{path},</if> <if test="path != null and path != ''">#{path},</if>
<if test="component != null and component != ''">#{component},</if> <if test="component != null and component != ''">#{component},</if>
<if test="isFrame != null and isFrame != ''">#{isFrame},</if> <if test="isFrame != null and isFrame != ''">#{isFrame},</if>
<if test="isCache != null and isCache != ''">#{isCache},</if>
<if test="menuType != null and menuType != ''">#{menuType},</if> <if test="menuType != null and menuType != ''">#{menuType},</if>
<if test="visible != null">#{visible},</if> <if test="visible != null">#{visible},</if>
<if test="status != null">#{status},</if> <if test="status != null">#{status},</if>

View File

@@ -18,7 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectNoticeVo"> <sql id="selectNoticeVo">
select notice_id, notice_title, notice_type, notice_content, status, create_by, create_time, update_by, update_time, remark select notice_id, notice_title, notice_type, cast(notice_content as char) as notice_content, status, create_by, create_time, update_by, update_time, remark
from sys_notice from sys_notice
</sql> </sql>

View File

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

View File

@@ -5,22 +5,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.ruoyi.system.mapper.SysRoleMapper"> <mapper namespace="com.ruoyi.system.mapper.SysRoleMapper">
<resultMap type="SysRole" id="SysRoleResult"> <resultMap type="SysRole" id="SysRoleResult">
<id property="roleId" column="role_id" /> <id property="roleId" column="role_id" />
<result property="roleName" column="role_name" /> <result property="roleName" column="role_name" />
<result property="roleKey" column="role_key" /> <result property="roleKey" column="role_key" />
<result property="roleSort" column="role_sort" /> <result property="roleSort" column="role_sort" />
<result property="dataScope" column="data_scope" /> <result property="dataScope" column="data_scope" />
<result property="status" column="status" /> <result property="menuCheckStrictly" column="menu_check_strictly" />
<result property="delFlag" column="del_flag" /> <result property="deptCheckStrictly" column="dept_check_strictly" />
<result property="createBy" column="create_by" /> <result property="status" column="status" />
<result property="createTime" column="create_time" /> <result property="delFlag" column="del_flag" />
<result property="updateBy" column="update_by" /> <result property="createBy" column="create_by" />
<result property="updateTime" column="update_time" /> <result property="createTime" column="create_time" />
<result property="remark" column="remark" /> <result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
</resultMap> </resultMap>
<sql id="selectRoleVo"> <sql id="selectRoleVo">
select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.menu_check_strictly, r.dept_check_strictly,
r.status, r.del_flag, r.create_time, r.remark r.status, r.del_flag, r.create_time, r.remark
from sys_role r from sys_role r
left join sys_user_role ur on ur.role_id = r.role_id left join sys_user_role ur on ur.role_id = r.role_id
@@ -40,11 +42,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="roleKey != null and roleKey != ''"> <if test="roleKey != null and roleKey != ''">
AND r.role_key like concat('%', #{roleKey}, '%') AND r.role_key like concat('%', #{roleKey}, '%')
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d') and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if> </if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d') and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if> </if>
<!-- 数据范围过滤 --> <!-- 数据范围过滤 -->
${params.dataScope} ${params.dataScope}
@@ -95,6 +97,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="roleKey != null and roleKey != ''">role_key,</if> <if test="roleKey != null and roleKey != ''">role_key,</if>
<if test="roleSort != null and roleSort != ''">role_sort,</if> <if test="roleSort != null and roleSort != ''">role_sort,</if>
<if test="dataScope != null and dataScope != ''">data_scope,</if> <if test="dataScope != null and dataScope != ''">data_scope,</if>
<if test="menuCheckStrictly != null">menu_check_strictly,</if>
<if test="deptCheckStrictly != null">dept_check_strictly,</if>
<if test="status != null and status != ''">status,</if> <if test="status != null and status != ''">status,</if>
<if test="remark != null and remark != ''">remark,</if> <if test="remark != null and remark != ''">remark,</if>
<if test="createBy != null and createBy != ''">create_by,</if> <if test="createBy != null and createBy != ''">create_by,</if>
@@ -105,6 +109,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="roleKey != null and roleKey != ''">#{roleKey},</if> <if test="roleKey != null and roleKey != ''">#{roleKey},</if>
<if test="roleSort != null and roleSort != ''">#{roleSort},</if> <if test="roleSort != null and roleSort != ''">#{roleSort},</if>
<if test="dataScope != null and dataScope != ''">#{dataScope},</if> <if test="dataScope != null and dataScope != ''">#{dataScope},</if>
<if test="menuCheckStrictly != null">#{menuCheckStrictly},</if>
<if test="deptCheckStrictly != null">#{deptCheckStrictly},</if>
<if test="status != null and status != ''">#{status},</if> <if test="status != null and status != ''">#{status},</if>
<if test="remark != null and remark != ''">#{remark},</if> <if test="remark != null and remark != ''">#{remark},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if> <if test="createBy != null and createBy != ''">#{createBy},</if>
@@ -119,6 +125,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="roleKey != null and roleKey != ''">role_key = #{roleKey},</if> <if test="roleKey != null and roleKey != ''">role_key = #{roleKey},</if>
<if test="roleSort != null and roleSort != ''">role_sort = #{roleSort},</if> <if test="roleSort != null and roleSort != ''">role_sort = #{roleSort},</if>
<if test="dataScope != null and dataScope != ''">data_scope = #{dataScope},</if> <if test="dataScope != null and dataScope != ''">data_scope = #{dataScope},</if>
<if test="menuCheckStrictly != null">menu_check_strictly = #{menuCheckStrictly},</if>
<if test="deptCheckStrictly != null">dept_check_strictly = #{deptCheckStrictly},</if>
<if test="status != null and status != ''">status = #{status},</if> <if test="status != null and status != ''">status = #{status},</if>
<if test="remark != null">remark = #{remark},</if> <if test="remark != null">remark = #{remark},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>

View File

@@ -17,6 +17,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
delete from sys_role_menu where role_id=#{roleId} delete from sys_role_menu where role_id=#{roleId}
</delete> </delete>
<delete id="deleteRoleMenu" parameterType="Long">
delete from sys_role_menu where role_id in
<foreach collection="array" item="roleId" open="(" separator="," close=")">
#{roleId}
</foreach>
</delete>
<insert id="batchRoleMenu"> <insert id="batchRoleMenu">
insert into sys_role_menu(role_id, menu_id) values insert into sys_role_menu(role_id, menu_id) values
<foreach item="item" index="index" collection="list" separator=","> <foreach item="item" index="index" collection="list" separator=",">

View File

@@ -68,14 +68,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="phonenumber != null and phonenumber != ''"> <if test="phonenumber != null and phonenumber != ''">
AND u.phonenumber like concat('%', #{phonenumber}, '%') AND u.phonenumber like concat('%', #{phonenumber}, '%')
</if> </if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 --> <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d') AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if> </if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 --> <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d') AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if> </if>
<if test="deptId != null and deptId != 0"> <if test="deptId != null and deptId != 0">
AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE FIND_IN_SET (#{deptId},ancestors) )) AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
</if> </if>
<!-- 数据范围过滤 --> <!-- 数据范围过滤 -->
${params.dataScope} ${params.dataScope}

View File

@@ -1,6 +1,6 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "3.1.0", "version": "3.3.0",
"description": "若依管理系统", "description": "若依管理系统",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
@@ -9,11 +9,7 @@
"build:prod": "vue-cli-service build", "build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging", "build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview", "preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src", "lint": "eslint --ext .js,.vue src"
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"new": "plop"
}, },
"husky": { "husky": {
"hooks": { "hooks": {
@@ -41,59 +37,45 @@
}, },
"dependencies": { "dependencies": {
"@riophae/vue-treeselect": "0.4.0", "@riophae/vue-treeselect": "0.4.0",
"axios": "0.18.1", "axios": "0.21.0",
"clipboard": "2.0.4", "clipboard": "2.0.6",
"core-js": "3.6.5", "core-js": "3.8.1",
"echarts": "4.2.1", "echarts": "4.9.0",
"element-ui": "2.13.2", "element-ui": "2.14.1",
"file-saver": "2.0.1", "file-saver": "2.0.4",
"js-beautify": "1.10.2", "fuse.js": "6.4.3",
"fuse.js": "3.4.4", "highlight.js": "10.4.1",
"js-cookie": "2.2.0", "js-beautify": "1.13.0",
"js-cookie": "2.2.1",
"jsencrypt": "3.0.0-rc.1", "jsencrypt": "3.0.0-rc.1",
"normalize.css": "7.0.0",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"path-to-regexp": "2.4.0", "path-to-regexp": "6.2.0",
"screenfull": "4.2.0", "quill": "1.3.7",
"sortablejs": "1.8.4", "screenfull": "5.0.2",
"vue": "2.6.10", "sortablejs": "1.10.2",
"vue": "2.6.12",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-quill-editor": "3.0.6", "vue-cropper": "0.5.5",
"vue-cropper": "0.4.9", "vue-router": "3.4.9",
"vue-router": "3.0.2", "vuedraggable": "2.24.3",
"vue-splitpane": "1.0.4", "vuex": "3.6.0"
"vuedraggable": "2.20.0",
"vuex": "3.1.0"
}, },
"devDependencies": { "devDependencies": {
"@vue/cli-plugin-babel": "4.4.4", "@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.4", "@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-plugin-unit-jest": "4.4.4", "@vue/cli-service": "4.4.6",
"@vue/cli-service": "4.4.4",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "9.5.1",
"babel-eslint": "10.1.0", "babel-eslint": "10.1.0",
"babel-jest": "23.6.0", "chalk": "4.1.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2",
"chokidar": "2.1.5",
"connect": "3.6.6", "connect": "3.6.6",
"eslint": "6.7.2", "eslint": "7.15.0",
"eslint-plugin-vue": "6.2.2", "eslint-plugin-vue": "7.2.0",
"html-webpack-plugin": "3.2.0", "lint-staged": "10.5.3",
"husky": "1.3.1", "sass": "1.30.0",
"lint-staged": "8.1.5", "runjs": "4.4.2",
"mockjs": "1.0.1-beta3", "sass-loader": "10.1.0",
"plop": "2.3.0", "script-ext-html-webpack-plugin": "2.1.5",
"runjs": "4.3.2", "svg-sprite-loader": "5.1.1",
"sass": "1.26.10", "vue-template-compiler": "2.6.12"
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.0",
"vue-template-compiler": "2.6.10"
}, },
"engines": { "engines": {
"node": ">=8.9", "node": ">=8.9",

View File

@@ -0,0 +1,9 @@
import request from '@/utils/request'
// 查询缓存详细
export function getCache() {
return request({
url: '/monitor/cache',
method: 'get'
})
}

View File

@@ -67,3 +67,10 @@ export function genCode(tableName) {
}) })
} }
// 同步数据库
export function synchDb(tableName) {
return request({
url: '/tool/gen/synchDb/' + tableName,
method: 'get'
})
}

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></path></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1605865043777" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="856" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1023.786667 611.84c-0.426667 9.770667-13.354667 20.693333-39.893334 34.56-54.613333 28.458667-337.749333 144.896-397.994666 176.298667-60.288 31.402667-93.738667 31.104-141.354667 8.32-47.616-22.741333-348.842667-144.469333-403.114667-170.368-27.093333-12.970667-40.917333-23.893333-41.386666-34.218667v103.509333c0 10.325333 14.250667 21.290667 41.386666 34.261334 54.272 25.941333 355.541333 147.626667 403.114667 170.368 47.616 22.784 81.066667 23.082667 141.354667-8.362667 60.245333-31.402667 343.338667-147.797333 397.994666-176.298667 27.776-14.464 40.106667-25.728 40.106667-35.925333v-102.058667l-0.213333-0.085333z m0-168.746667c-0.512 9.770667-13.397333 20.650667-39.893334 34.517334-54.613333 28.458667-337.749333 144.896-397.994666 176.298666-60.288 31.402667-93.738667 31.104-141.354667 8.362667-47.616-22.741333-348.842667-144.469333-403.114667-170.410667-27.093333-12.928-40.917333-23.893333-41.386666-34.176v103.509334c0 10.325333 14.250667 21.248 41.386666 34.218666 54.272 25.941333 355.498667 147.626667 403.114667 170.368 47.616 22.784 81.066667 23.082667 141.354667-8.32 60.245333-31.402667 343.338667-147.84 397.994666-176.298666 27.776-14.506667 40.106667-25.770667 40.106667-35.968v-102.058667l-0.256-0.042667z m0-175.018666c0.469333-10.410667-13.141333-19.541333-40.533334-29.610667-53.248-19.498667-334.634667-131.498667-388.522666-151.253333-53.888-19.712-75.818667-18.901333-139.093334 3.84C392.234667 113.706667 92.629333 231.253333 39.338667 252.074667c-26.666667 10.496-39.68 20.181333-39.253334 30.506666V386.133333c0 10.325333 14.250667 21.248 41.386667 34.218667 54.272 25.941333 355.498667 147.669333 403.114667 170.410667 47.616 22.741333 81.066667 23.04 141.354666-8.362667 60.245333-31.402667 343.338667-147.84 397.994667-176.298667 27.776-14.506667 40.106667-25.770667 40.106667-35.968V268.074667h-0.341334zM366.677333 366.08l237.269334-36.437333-71.68 105.088-165.546667-68.650667z m524.8-94.634667l-140.330666 55.466667-15.232 5.973333-140.245334-55.466666 155.392-61.44 140.373334 55.466666z m-411.989333-101.674666l-22.954667-42.325334 71.594667 27.989334 67.498667-22.101334-18.261334 43.733334 68.778667 25.770666-88.704 9.216-19.882667 47.786667-32.085333-53.290667-102.4-9.216 76.416-27.562666z m-176.768 59.733333c70.058667 0 126.805333 21.973333 126.805333 49.109333s-56.746667 49.152-126.805333 49.152-126.848-22.058667-126.848-49.152c0-27.136 56.789333-49.152 126.848-49.152z" p-id="857"></path></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
<g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
<g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
<rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
<g id="Group-8" transform="translate(1167.000000, 0.000000)">
<g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 509 KiB

After

Width:  |  Height:  |  Size: 509 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -67,6 +67,11 @@
font-size: 13px; font-size: 13px;
} }
} }
.el-table__body-wrapper {
.el-button [class*="el-icon-"] + span {
margin-left: 1px;
}
}
} }
/** 表单布局 **/ /** 表单布局 **/
@@ -87,6 +92,14 @@
padding: 10px 20px !important; padding: 10px 20px !important;
} }
/* tree border */
.tree-border {
margin-top: 5px;
border: 1px solid #e5e6e7;
background: #FFFFFF none;
border-radius:4px;
}
.pagination-container .el-pagination { .pagination-container .el-pagination {
right: 0; right: 0;
position: absolute; position: absolute;
@@ -207,8 +220,8 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
transform: translate(50%, -50%); transform: translate(50%, -50%);
width: 180px; width: 200px;
height: 180px; height: 200px;
border-radius: 50%; border-radius: 50%;
box-shadow: 0 0 4px #ccc; box-shadow: 0 0 4px #ccc;
overflow: hidden; overflow: hidden;
@@ -224,4 +237,4 @@
.top-right-btn { .top-right-btn {
position: relative; position: relative;
float: right; float: right;
} }

View File

@@ -8,6 +8,7 @@
} }
.sidebar-container { .sidebar-container {
-webkit-transition: width .28s;
transition: width 0.28s; transition: width 0.28s;
width: $sideBarWidth !important; width: $sideBarWidth !important;
background-color: $menuBg; background-color: $menuBg;
@@ -19,6 +20,8 @@
left: 0; left: 0;
z-index: 1001; z-index: 1001;
overflow: hidden; overflow: hidden;
-webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
box-shadow: 2px 0 6px rgba(0,21,41,.35);
// reset element-ui css // reset element-ui css
.horizontal-collapse-transition { .horizontal-collapse-transition {
@@ -63,21 +66,35 @@
width: 100% !important; width: 100% !important;
} }
.el-menu-item, .el-submenu__title {
overflow: hidden !important;
text-overflow: ellipsis !important;
white-space: nowrap !important;
}
// menu hover // menu hover
.submenu-title-noDropdown, .submenu-title-noDropdown,
.el-submenu__title { .el-submenu__title {
&:hover { &:hover {
background-color: $menuHover !important; background-color: rgba(0, 0, 0, 0.06) !important;
} }
} }
.is-active>.el-submenu__title { & .theme-dark .is-active > .el-submenu__title {
color: $subMenuActiveText !important; color: $subMenuActiveText !important;
} }
& .nest-menu .el-submenu>.el-submenu__title, & .nest-menu .el-submenu>.el-submenu__title,
& .el-submenu .el-menu-item { & .el-submenu .el-menu-item {
min-width: $sideBarWidth !important; min-width: $sideBarWidth !important;
&:hover {
background-color: rgba(0, 0, 0, 0.06) !important;
}
}
& .theme-dark .nest-menu .el-submenu>.el-submenu__title,
& .theme-dark .el-submenu .el-menu-item {
background-color: $subMenuBg !important; background-color: $subMenuBg !important;
&:hover { &:hover {
@@ -184,7 +201,7 @@
.el-menu-item { .el-menu-item {
&:hover { &:hover {
// you can use $subMenuHover // you can use $subMenuHover
background-color: $menuHover !important; background-color: rgba(0, 0, 0, 0.06) !important;
} }
} }

View File

@@ -15,6 +15,11 @@ $subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
$menuBg:#304156; $menuBg:#304156;
$menuHover:#263445; $menuHover:#263445;
$sidebarTitle: #ffffff;
$menuLightBg:#ffffff;
$menuLightHover:#f0f1f5;
$sidebarLightTitle: #001529;
$subMenuBg:#1f2d3d; $subMenuBg:#1f2d3d;
$subMenuHover:#001528; $subMenuHover:#001528;
@@ -29,7 +34,11 @@ $sideBarWidth: 200px;
subMenuActiveText: $subMenuActiveText; subMenuActiveText: $subMenuActiveText;
menuBg: $menuBg; menuBg: $menuBg;
menuHover: $menuHover; menuHover: $menuHover;
menuLightBg: $menuLightBg;
menuLightHover: $menuLightHover;
subMenuBg: $subMenuBg; subMenuBg: $subMenuBg;
subMenuHover: $subMenuHover; subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth; sideBarWidth: $sideBarWidth;
sidebarTitle: $sidebarTitle;
sidebarLightTitle: $sidebarLightTitle
} }

View File

@@ -1,153 +1,122 @@
<template> <template>
<div> <div class="editor" ref="editor" :style="styles"></div>
<!-- 图片上传组件辅助 -->
<el-upload
class="avatar-uploader quill-img"
:action="uploadImgUrl"
name="file"
:headers="headers"
:show-file-list="false"
:on-success="quillImgSuccess"
:on-error="uploadError"
:before-upload="quillImgBefore"
accept='.jpg,.jpeg,.png,.gif'
></el-upload>
<!-- 富文本组件 -->
<quill-editor
class="editor"
v-model="content"
ref="quillEditor"
:options="editorOption"
@blur="onEditorBlur($event)"
@focus="onEditorFocus($event)"
@change="onEditorChange($event)"
></quill-editor>
</div>
</template> </template>
<script> <script>
import { getToken } from '@/utils/auth' import Quill from "quill";
// 工具栏配置
const toolbarOptions = [
["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
["blockquote", "code-block"], // 引用 代码块
[{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
[{ indent: "-1" }, { indent: "+1" }], // 缩进
[{ size: ["small", false, "large", "huge"] }], // 字体大小
[{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
[{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
[{ align: [] }], // 对齐方式
["clean"], // 清除文本格式
["link", "image", "video"] // 链接、图片、视频
];
import { quillEditor } from "vue-quill-editor";
import "quill/dist/quill.core.css"; import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css"; import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css"; import "quill/dist/quill.bubble.css";
export default { export default {
name: "Editor",
props: { props: {
/* 编辑器的内容 */ /* 编辑器的内容 */
value: { value: {
type: String type: String,
default: "",
}, },
/* 图片大小 */ /* 高度 */
maxSize: { height: {
type: Number, type: Number,
default: 4000 //kb default: null,
} },
/* 最小高度 */
minHeight: {
type: Number,
default: null,
},
}, },
components: { quillEditor },
data() { data() {
return { return {
content: this.value, Quill: null,
uploadImgUrl: "", currentValue: "",
editorOption: { options: {
theme: "snow", // or 'bubble' theme: "snow",
placeholder: "请输入内容", bounds: document.body,
debug: "warn",
modules: { modules: {
toolbar: { // 工具栏配置
container: toolbarOptions, toolbar: [
handlers: { ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
image: function(value) { ["blockquote", "code-block"], // 引用 代码块
if (value) { [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
// 触发input框选择图片文件 [{ indent: "-1" }, { indent: "+1" }], // 缩进
document.querySelector(".quill-img input").click(); [{ size: ["small", false, "large", "huge"] }], // 字体大小
} else { [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
this.quill.format("image", false); [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
} [{ align: [] }], // 对齐方式
} ["clean"], // 清除文本格式
} ["link", "image", "video"] // 链接、图片、视频
],
},
placeholder: "请输入内容",
readOnly: false,
},
};
},
computed: {
styles() {
let style = {};
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
}
if (this.height) {
style.height = `${this.height}px`;
}
return style;
},
},
watch: {
value: {
handler(val) {
if (val !== this.currentValue) {
this.currentValue = val === null ? "" : val;
if (this.Quill) {
this.Quill.pasteHTML(this.currentValue);
} }
} }
}, },
uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址 immediate: true,
headers: { },
Authorization: 'Bearer ' + getToken()
}
};
}, },
watch: { mounted() {
value: function() { this.init();
this.content = this.value; },
} beforeDestroy() {
this.Quill = null;
}, },
methods: { methods: {
onEditorBlur() { init() {
//失去焦点事件 const editor = this.$refs.editor;
this.Quill = new Quill(editor, this.options);
this.Quill.pasteHTML(this.currentValue);
this.Quill.on("text-change", (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText();
const quill = this.Quill;
this.currentValue = html;
this.$emit("input", html);
this.$emit("on-change", { html, text, quill });
});
this.Quill.on("text-change", (delta, oldDelta, source) => {
this.$emit("on-text-change", delta, oldDelta, source);
});
this.Quill.on("selection-change", (range, oldRange, source) => {
this.$emit("on-selection-change", range, oldRange, source);
});
this.Quill.on("editor-change", (eventName, ...args) => {
this.$emit("on-editor-change", eventName, ...args);
});
}, },
onEditorFocus() { },
//获得焦点事件
},
onEditorChange() {
//内容改变事件
this.$emit("input", this.content);
},
// 富文本图片上传前
quillImgBefore(file) {
let fileType = file.type;
if(fileType === 'image/jpeg' || fileType === 'image/png'){
return true;
}else {
this.$message.error('请插入图片类型文件(jpg/jpeg/png)');
return false;
}
},
quillImgSuccess(res, file) {
// res为图片服务器返回的数据
// 获取富文本组件实例
let quill = this.$refs.quillEditor.quill;
// 如果上传成功
if (res.code == 200) {
// 获取光标所在位置
let length = quill.getSelection().index;
// 插入图片 res.url为服务器返回的图片地址
quill.insertEmbed(length, "image", res.url);
// 调整光标到最后
quill.setSelection(length + 1);
} else {
this.$message.error("图片插入失败");
}
},
// 富文本图片上传失败
uploadError() {
// loading动画消失
this.$message.error("图片插入失败");
}
}
}; };
</script> </script>
<style> <style>
.editor { .editor, .ql-toolbar {
white-space: pre-wrap!important; white-space: pre-wrap!important;
line-height: normal !important; line-height: normal !important;
height: 192px;
} }
.quill-img { .quill-img {
display: none; display: none;

View File

@@ -12,7 +12,7 @@
class="header-search-select" class="header-search-select"
@change="change" @change="change"
> >
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" /> <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
</el-select> </el-select>
</div> </div>
</template> </template>

View File

@@ -1,3 +1,3 @@
<template > <template >
<router-view /> <router-view />
</template> </template>

View File

@@ -22,11 +22,8 @@ export default {
}, },
methods: { methods: {
click() { click() {
if (!screenfull.enabled) { if (!screenfull.isEnabled) {
this.$message({ this.$message({ message: '你的浏览器不支持全屏', type: 'warning' })
message: 'you browser can not work',
type: 'warning'
})
return false return false
} }
screenfull.toggle() screenfull.toggle()
@@ -35,12 +32,12 @@ export default {
this.isFullscreen = screenfull.isFullscreen this.isFullscreen = screenfull.isFullscreen
}, },
init() { init() {
if (screenfull.enabled) { if (screenfull.isEnabled) {
screenfull.on('change', this.change) screenfull.on('change', this.change)
} }
}, },
destroy() { destroy() {
if (screenfull.enabled) { if (screenfull.isEnabled) {
screenfull.off('change', this.change) screenfull.off('change', this.change)
} }
} }

View File

@@ -0,0 +1,68 @@
<template>
<div class="component-upload-image">
<el-upload
:action="uploadImgUrl"
list-type="picture-card"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:on-error="handleUploadError"
name="file"
:show-file-list="false"
:headers="headers"
style="display: inline-block; vertical-align: top"
>
<img v-if="value" :src="value" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
export default {
components: {},
data() {
return {
uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
};
},
props: {
value: {
type: String,
default: "",
},
},
methods: {
handleUploadSuccess(res) {
this.$emit("input", res.url);
this.loading.close();
},
handleBeforeUpload() {
this.loading = this.$loading({
lock: true,
text: "上传中",
background: "rgba(0, 0, 0, 0.7)",
});
},
handleUploadError() {
this.$message({
type: "error",
message: "上传失败",
});
this.loading.close();
},
},
watch: {},
};
</script>
<style scoped lang="scss">
.avatar {
width: 100%;
height: 100%;
}
</style>

View File

@@ -1,7 +1,8 @@
<!-- @author ruoyi 20201128 支持三级以上菜单缓存 -->
<template> <template>
<section class="app-main"> <section class="app-main">
<transition name="fade-transform" mode="out-in"> <transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews"> <keep-alive :max="20" :exclude="notCacheName">
<router-view :key="key" /> <router-view :key="key" />
</keep-alive> </keep-alive>
</transition> </transition>
@@ -9,17 +10,119 @@
</template> </template>
<script> <script>
import Global from "@/layout/components/global.js";
export default { export default {
name: 'AppMain', name: 'AppMain',
computed: { computed: {
cachedViews() { notCacheName() {
return this.$store.state.tagsView.cachedViews var visitedViews = this.$store.state.tagsView.visitedViews;
var noCacheViews = [];
Object.keys(visitedViews).some((index) => {
if (visitedViews[index].meta.noCache) {
noCacheViews.push(visitedViews[index].name);
}
});
return noCacheViews;
}, },
key() { key() {
return this.$route.path return this.$route.path;
} },
} },
} mounted() {
// 关闭标签触发
Global.$on("removeCache", (name, view) => {
this.removeCache(name, view);
});
},
methods: {
// 获取有keep-alive子节点的Vnode
getVnode() {
// 判断子集非空
if (this.$children.length == 0) return false;
let vnode;
for (let item of this.$children) {
// 如果data中有key则代表找到了keep-alive下面的子集这个key就是router-view上的key
if (item.$vnode.data.key) {
vnode = item.$vnode;
break;
}
}
return vnode ? vnode : false;
},
// 移除keep-alive缓存
removeCache(name, view = {}) {
let vnode = this.getVnode();
if (!vnode) return false;
let componentInstance = vnode.parent.componentInstance;
// 这个key是用来获取前缀用来后面正则匹配用的
let keyStart = vnode.key.split("/")[0];
let thisKey = `${keyStart}${view.fullPath}`;
let regKey = `${keyStart}${view.path}`;
this[name]({ componentInstance, thisKey, regKey });
},
// 移除其他
closeOthersTags({ componentInstance, thisKey }) {
Object.keys(componentInstance.cache).forEach((key, index) => {
if (key != thisKey) {
// 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断)
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
// 删除缓存
delete componentInstance.cache[key];
// 移除key中对应的key
componentInstance.keys.splice(index, 1);
}
});
},
// 移除所有缓存
closeAllTags({ componentInstance }) {
// 销毁实例
Object.keys(componentInstance.cache).forEach((key) => {
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
});
// 删除缓存
componentInstance.cache = {};
// 移除key中对应的key
componentInstance.keys = [];
},
// 移除单个缓存
closeSelectedTag({ componentInstance, regKey }) {
let reg = new RegExp(`^${regKey}`);
Object.keys(componentInstance.cache).forEach((key, i) => {
if (reg.test(key)) {
// 销毁实例
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
// 删除缓存
delete componentInstance.cache[key];
// 移除key中对应的key
componentInstance.keys.splice(i, 1);
}
});
},
// 刷新单个缓存
refreshSelectedTag({ componentInstance, thisKey }) {
Object.keys(componentInstance.cache).forEach((key, index) => {
if (null != thisKey && key.replace("/redirect", "") == thisKey) {
// 1 销毁实例(这里存在多个key指向一个缓存的情况可能前面一个已经清除掉了所有要加判断)
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
// 2 删除缓存
delete componentInstance.cache[key];
// 3 移除key中对应的key
componentInstance.keys.splice(index, 1);
}
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -31,7 +134,7 @@ export default {
overflow: hidden; overflow: hidden;
} }
.fixed-header+.app-main { .fixed-header + .app-main {
padding-top: 50px; padding-top: 50px;
} }
@@ -41,7 +144,7 @@ export default {
min-height: calc(100vh - 84px); min-height: calc(100vh - 84px);
} }
.fixed-header+.app-main { .fixed-header + .app-main {
padding-top: 84px; padding-top: 84px;
} }
} }

View File

@@ -1,13 +1,47 @@
<template> <template>
<div class="drawer-container"> <div class="drawer-container">
<div> <div>
<h3 class="drawer-title">系统布局配置</h3> <div class="setting-drawer-content">
<div class="setting-drawer-title">
<h3 class="drawer-title">主题风格设置</h3>
</div>
<div class="setting-drawer-block-checbox">
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
<img src="@/assets/images/dark.svg" alt="dark">
<div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
<i aria-label="图标: check" class="anticon anticon-check">
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
focusable="false" class="">
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
</svg>
</i>
</div>
</div>
<div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
<img src="@/assets/images/light.svg" alt="light">
<div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
<i aria-label="图标: check" class="anticon anticon-check">
<svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true"
focusable="false" class="">
<path
d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
</svg>
</i>
</div>
</div>
</div>
<div class="drawer-item"> <div class="drawer-item">
<span>主题颜色</span> <span>主题颜色</span>
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" /> <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
</div>
</div> </div>
<el-divider/>
<h3 class="drawer-title">系统布局配置</h3>
<div class="drawer-item"> <div class="drawer-item">
<span>开启 Tags-Views</span> <span>开启 Tags-Views</span>
<el-switch v-model="tagsView" class="drawer-switch" /> <el-switch v-model="tagsView" class="drawer-switch" />
@@ -36,6 +70,12 @@ export default {
return {} return {}
}, },
computed: { computed: {
theme() {
return this.$store.state.settings.theme
},
sideTheme() {
return this.$store.state.settings.sideTheme
},
fixedHeader: { fixedHeader: {
get() { get() {
return this.$store.state.settings.fixedHeader return this.$store.state.settings.fixedHeader
@@ -76,33 +116,82 @@ export default {
key: 'theme', key: 'theme',
value: val value: val
}) })
},
handleTheme(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'sideTheme',
value: val
})
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.drawer-container { .setting-drawer-content {
padding: 24px; .setting-drawer-title {
font-size: 14px; margin-bottom: 12px;
line-height: 1.5; color: rgba(0, 0, 0, .85);
word-wrap: break-word; font-size: 14px;
line-height: 22px;
font-weight: bold;
}
.drawer-title { .setting-drawer-block-checbox {
margin-bottom: 12px; display: flex;
color: rgba(0, 0, 0, .85); justify-content: flex-start;
align-items: center;
margin-top: 10px;
margin-bottom: 20px;
.setting-drawer-block-checbox-item {
position: relative;
margin-right: 16px;
border-radius: 2px;
cursor: pointer;
img {
width: 48px;
height: 48px;
}
.setting-drawer-block-checbox-selectIcon {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
padding-top: 15px;
padding-left: 24px;
color: #1890ff;
font-weight: 700;
font-size: 14px;
}
}
}
}
.drawer-container {
padding: 24px;
font-size: 14px; font-size: 14px;
line-height: 22px; line-height: 1.5;
} word-wrap: break-word;
.drawer-item { .drawer-title {
color: rgba(0, 0, 0, .65); margin-bottom: 12px;
font-size: 14px; color: rgba(0, 0, 0, .85);
padding: 12px 0; font-size: 14px;
} line-height: 22px;
}
.drawer-switch { .drawer-item {
float: right color: rgba(0, 0, 0, .65);
font-size: 14px;
padding: 12px 0;
}
.drawer-switch {
float: right
}
} }
}
</style> </style>

View File

@@ -1,13 +1,13 @@
<template> <template>
<div class="sidebar-logo-container" :class="{'collapse':collapse}"> <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }">
<transition name="sidebarLogoFade"> <transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo"> <img v-if="logo" :src="logo" class="sidebar-logo">
<h1 v-else class="sidebar-title">{{ title }} </h1> <h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
</router-link> </router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> <router-link v-else key="expand" class="sidebar-logo-link" to="/">
<img v-if="logo" :src="logo" class="sidebar-logo"> <img v-if="logo" :src="logo" class="sidebar-logo">
<h1 class="sidebar-title">{{ title }} </h1> <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.sidebarTitle : variables.sidebarLightTitle }">{{ title }} </h1>
</router-link> </router-link>
</transition> </transition>
</div> </div>
@@ -15,6 +15,7 @@
<script> <script>
import logoImg from '@/assets/logo/logo.png' import logoImg from '@/assets/logo/logo.png'
import variables from '@/assets/styles/variables.scss'
export default { export default {
name: 'SidebarLogo', name: 'SidebarLogo',
@@ -24,6 +25,14 @@ export default {
required: true required: true
} }
}, },
computed: {
variables() {
return variables;
},
sideTheme() {
return this.$store.state.settings.sideTheme
}
},
data() { data() {
return { return {
title: '若依管理系统', title: '若依管理系统',

View File

@@ -56,6 +56,9 @@ export default {
}, },
methods: { methods: {
hasOneShowingChild(children = [], parent) { hasOneShowingChild(children = [], parent) {
if (!children) {
children = [];
}
const showingChildren = children.filter(item => { const showingChildren = children.filter(item => {
if (item.hidden) { if (item.hidden) {
return false return false

View File

@@ -1,12 +1,12 @@
<template> <template>
<div :class="{'has-logo':showLogo}"> <div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }">
<logo v-if="showLogo" :collapse="isCollapse" /> <logo v-if="showLogo" :collapse="isCollapse" />
<el-scrollbar wrap-class="scrollbar-wrapper"> <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
<el-menu <el-menu
:default-active="activeMenu" :default-active="activeMenu"
:collapse="isCollapse" :collapse="isCollapse"
:background-color="variables.menuBg" :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg"
:text-color="variables.menuText" :text-color="settings.sideTheme === 'theme-dark' ? variables.menuText : 'rgba(0,0,0,.65)'"
:unique-opened="true" :unique-opened="true"
:active-text-color="settings.theme" :active-text-color="settings.theme"
:collapse-transition="false" :collapse-transition="false"

View File

@@ -29,6 +29,7 @@
<script> <script>
import ScrollPane from './ScrollPane' import ScrollPane from './ScrollPane'
import path from 'path' import path from 'path'
import Global from "@/layout/components/global.js";
export default { export default {
components: { ScrollPane }, components: { ScrollPane },
@@ -144,6 +145,7 @@ export default {
}) })
}) })
}) })
Global.$emit("removeCache", "refreshSelectedTag", this.selectedTag);
}, },
closeSelectedTag(view) { closeSelectedTag(view) {
this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => { this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
@@ -151,20 +153,23 @@ export default {
this.toLastView(visitedViews, view) this.toLastView(visitedViews, view)
} }
}) })
Global.$emit("removeCache", "closeSelectedTag", view);
}, },
closeOthersTags() { closeOthersTags() {
this.$router.push(this.selectedTag) this.$router.push(this.selectedTag)
this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => { this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
this.moveToCurrentTag() this.moveToCurrentTag()
}) })
Global.$emit("removeCache", "closeOthersTags", this.selectedTag);
}, },
closeAllTags(view) { closeAllTags(view) {
this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => { this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
if (this.affixTags.some(tag => tag.path === view.path)) { if (this.affixTags.some(tag => tag.path === this.$route.path)) {
return return
} }
this.toLastView(visitedViews, view) this.toLastView(visitedViews, view)
}) })
Global.$emit("removeCache", "closeAllTags");
}, },
toLastView(visitedViews, view) { toLastView(visitedViews, view) {
const latestView = visitedViews.slice(-1)[0] const latestView = visitedViews.slice(-1)[0]

View File

@@ -0,0 +1,3 @@
import Vue from 'vue'
const global = new Vue()
export default global

View File

@@ -1,7 +1,7 @@
<template> <template>
<div :class="classObj" class="app-wrapper"> <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
<sidebar class="sidebar-container" /> <sidebar class="sidebar-container" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg }" />
<div :class="{hasTagsView:needTagsView}" class="main-container"> <div :class="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}"> <div :class="{'fixed-header':fixedHeader}">
<navbar /> <navbar />
@@ -20,6 +20,7 @@ import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components' import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler' import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import variables from '@/assets/styles/variables.scss'
export default { export default {
name: 'Layout', name: 'Layout',
@@ -34,6 +35,8 @@ export default {
mixins: [ResizeMixin], mixins: [ResizeMixin],
computed: { computed: {
...mapState({ ...mapState({
theme: state => state.settings.theme,
sideTheme: state => state.settings.sideTheme,
sidebar: state => state.app.sidebar, sidebar: state => state.app.sidebar,
device: state => state.app.device, device: state => state.app.device,
showSettings: state => state.settings.showSettings, showSettings: state => state.settings.showSettings,
@@ -47,6 +50,9 @@ export default {
withoutAnimation: this.sidebar.withoutAnimation, withoutAnimation: this.sidebar.withoutAnimation,
mobile: this.device === 'mobile' mobile: this.device === 'mobile'
} }
},
variables() {
return variables;
} }
}, },
methods: { methods: {

View File

@@ -2,8 +2,6 @@ import Vue from 'vue'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
import 'normalize.css/normalize.css' // a modern alternative to CSS resets
import Element from 'element-ui' import Element from 'element-ui'
import './assets/styles/element-variables.scss' import './assets/styles/element-variables.scss'
@@ -20,8 +18,11 @@ import { getDicts } from "@/api/system/dict/data";
import { getConfigKey } from "@/api/system/config"; import { getConfigKey } from "@/api/system/config";
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi"; import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi";
import Pagination from "@/components/Pagination"; import Pagination from "@/components/Pagination";
//自定义表格工具扩展 // 自定义表格工具扩展
import RightToolbar from "@/components/RightToolbar" import RightToolbar from "@/components/RightToolbar"
// 代码高亮插件
import hljs from 'highlight.js'
import 'highlight.js/styles/github-gist.css'
// 全局方法挂载 // 全局方法挂载
Vue.prototype.getDicts = getDicts Vue.prototype.getDicts = getDicts
@@ -51,6 +52,7 @@ Vue.component('Pagination', Pagination)
Vue.component('RightToolbar', RightToolbar) Vue.component('RightToolbar', RightToolbar)
Vue.use(permission) Vue.use(permission)
Vue.use(hljs.vuePlugin);
/** /**
* If you don't want to use mock-server * If you don't want to use mock-server

View File

@@ -5,6 +5,7 @@ Vue.use(Router)
/* Layout */ /* Layout */
import Layout from '@/layout' import Layout from '@/layout'
import ParentView from '@/components/ParentView';
/** /**
* Note: 路由配置项 * Note: 路由配置项
@@ -17,9 +18,9 @@ import Layout from '@/layout'
* redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
* name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 * name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
* meta : { * meta : {
roles: ['admin','editor'] // 设置该路由进入的权限,支持多个权限叠加 noCache: true // 如果设置为true则不会被 <keep-alive> 缓存(默认 false)
title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
icon: 'svg-name' // 设置该路由的图标对应路径src/icons/svg icon: 'svg-name' // 设置该路由的图标对应路径src/assets/icons/svg
breadcrumb: false // 如果设置为false则不会在breadcrumb面包屑中显示 breadcrumb: false // 如果设置为false则不会在breadcrumb面包屑中显示
} }
*/ */

View File

@@ -1,6 +1,11 @@
module.exports = { module.exports = {
title: '若依管理系统', title: '若依管理系统',
/**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/
sideTheme: 'theme-dark',
/** /**
* 是否系统布局配置 * 是否系统布局配置
*/ */

View File

@@ -1,6 +1,7 @@
import { constantRoutes } from '@/router' import { constantRoutes } from '@/router'
import { getRouters } from '@/api/menu' import { getRouters } from '@/api/menu'
import Layout from '@/layout/index' import Layout from '@/layout/index'
import ParentView from '@/components/ParentView';
const permission = { const permission = {
state: { state: {
@@ -33,9 +34,11 @@ const permission = {
function filterAsyncRouter(asyncRouterMap) { function filterAsyncRouter(asyncRouterMap) {
return asyncRouterMap.filter(route => { return asyncRouterMap.filter(route => {
if (route.component) { if (route.component) {
// Layout组件特殊处理 // Layout ParentView 组件特殊处理
if (route.component === 'Layout') { if (route.component === 'Layout') {
route.component = Layout route.component = Layout
} else if (route.component === 'ParentView') {
route.component = ParentView
} else { } else {
route.component = loadView(route.component) route.component = loadView(route.component)
} }

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