88 Commits

Author SHA1 Message Date
0b5c7f4c96 若依 3.4.0 2021-02-22 09:40:28 +08:00
265e3010aa 升级SpringBoot到最新版本2.2.13 2021-02-21 11:01:56 +08:00
b7a36bfe8a 修改ip字段长度防止ipv6地址长度不够 2021-02-10 12:48:52 +08:00
3a51c53823 角色非自定义权限范围清空选择值 2021-02-06 10:34:12 +08:00
df504c5c14 修复四级菜单无法显示问题 2021-02-06 09:29:50 +08:00
baeed2e8d3 修复角色管理-编辑角色-功能权限显示异常 2021-02-02 16:25:37 +08:00
2903de1561 升级element-ui到最新版本2.15.0 2021-01-24 12:06:19 +08:00
cca2f5c62d update README.md 2021-01-14 13:20:08 +08:00
ce54416e4f 升级fastjson到最新版1.2.75 2021-01-13 16:20:39 +08:00
bd19892aff 修复生成树表代码异常 2021-01-13 16:19:23 +08:00
14a859899c 代码生成模板支持主子表 2021-01-08 10:47:36 +08:00
f3cb18c836 !161 修复导入数据为负浮点数时,导入结果会丢失精度问题
Merge pull request !161 from 嘿白熊/master
2021-01-08 10:46:36 +08:00
7d0eb3b8c7 用户显隐列添加不同key防止被复用 2021-01-07 13:28:16 +08:00
654aa6b30c 表格右侧工具栏组件支持显隐列 2021-01-06 17:30:39 +08:00
b7cdd10f9f 修复导入数据为负浮点数时丢失精度问题 2021-01-06 11:11:11 +08:00
9bd35cb7be 升级druid到最新版本v1.2.4 2021-01-06 11:00:20 +08:00
7a86c714fc 代码生成支持文件上传组件 2021-01-06 11:00:09 +08:00
edd090a098 代码生成支持文件上传组件 2021-01-05 20:59:14 +08:00
3cd886785b 图片组件添加预览功能 2021-01-05 20:33:41 +08:00
ae5a0f9774 新增文件上传组件 2021-01-05 20:11:09 +08:00
074b3c735d 设置单图上传控件 2021-01-05 16:17:41 +08:00
a118738d0f 单图上传组件添加移除 2021-01-05 16:13:22 +08:00
56fa3912ae 修复IE11浏览器报错问题 2021-01-05 09:44:08 +08:00
2116ee1822 Update copyright 2021-01-04 17:49:52 +08:00
57a2eb4217 操作按钮组调整为朴素按钮样式 2021-01-04 17:48:46 +08:00
647af5b485 菜单组件修改允许空字符串 2020-12-29 17:27:48 +08:00
3f33219134 !156 修复 用户管理 -> 修改用户 手机号码 和 邮箱 不能清空
Merge pull request !156 from li_oxen/N/A
2020-12-29 17:14:31 +08:00
a04bb71777 修复 用户管理 -> 修改用户 手机号码 和 邮箱 不能清空 2020-12-29 13:51:15 +08:00
63992ac906 代码生成数据库文本类型生成表单文本域 2020-12-29 11:14:48 +08:00
0187344798 Excel注解支持Image图片导出 2020-12-27 10:04:45 +08:00
a9c6ba12e6 代码生成日期控件区分范围 2020-12-25 09:35:20 +08:00
ba068eae65 修正侧边栏静态路由丢失问题 2020-12-24 19:32:18 +08:00
1a87ee7c19 防止get请求参数值为false或0等特殊值会导致无法正确的传参
Merge pull request !146 from wugh/hotfix/gitee-issue_I2A5FU
2020-12-22 16:19:51 +08:00
3c4b01ab83 权限工具类增加admin判断 2020-12-21 19:43:57 +08:00
886ce995af [bug修复] 解决get请求,如果参数值为false或0等特殊值会导致无法正确传参 2020-12-21 11:58:15 +08:00
52264b6e2a 优化多级菜单之间切换无法缓存的问题 2020-12-21 10:50:48 +08:00
fd7e88a518 配置文件新增redis数据库索引属性 2020-12-21 10:26:54 +08:00
854a6f805f !145 redis 增加 database配置项,设置不同的库
Merge pull request !145 from li_oxen/N/A
2020-12-21 10:13:47 +08:00
1caec85f46 redis 增加 database配置项,设置不同的库 2020-12-19 10:08:09 +08:00
c86dc20743 移除path-to-regexp正则匹配插件 2020-12-17 12:05:29 +08:00
ecc7a8be46 优化多级菜单之间切换无法缓存的问题 2020-12-16 20:57:48 +08:00
e23ad20186 README 2020-12-16 10:20:02 +08:00
6cf2a8edeb 升级SpringBoot到最新版本2.2.12 提升启动速度 2020-12-16 10:05:53 +08:00
67198aede9 README 2020-12-15 10:06:12 +08:00
4f33da2a3f 登录后push添加catch防止出现检查错误 2020-12-15 10:04:09 +08:00
8988d0b4ab 若依 3.3.0 2020-12-14 09:02:10 +08:00
ceefa20aa2 调整代码生成页列宽 2020-12-13 16:05:49 +08:00
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
e8f63b2994 修改Set可能导致嵌套的问题 2020-12-11 18:16:57 +08:00
ecfe7006e2 代码生成预览支持高亮显示 2020-12-11 17:04:54 +08:00
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
d6eac2dc8d 前端更新插件版本 2020-12-11 09:27:12 +08:00
b368ad764f 升级core-js到最新版本3.8.1 2020-12-10 12:08:18 +08:00
ffd5f0ce5d 升级vue-router到最新版本3.4.9 2020-12-10 11:14:44 +08:00
a50beae599 代码生成预览提供滚动机制 2020-12-10 11:13:39 +08:00
cf7f51a633 解决多文件上传Log报错 2020-12-09 16:05:09 +08:00
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
fbc071a573 关闭页签清理缓存数据 2020-12-08 16:43:26 +08:00
6cfff90b4a 缓存仪表图设置默认大小 2020-12-08 16:13:21 +08:00
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
c01eeb8521 update ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java. 2020-12-08 11:11:34 +08:00
f90899d72a 支持主题风格配置 2020-12-07 14:13:02 +08:00
7e78a9167f 修改用户头像预览宽高 2020-12-06 16:22:45 +08:00
563e11d9c1 get请求params添加null值判断 2020-12-06 11:05:02 +08:00
ef92ad4d8c 支持get请求映射params参数 2020-12-04 10:52:20 +08:00
d8b006c15f 升级bitwalker到最新版本1.21 2020-12-04 10:51:20 +08:00
0e2b97a886 升级poi到最新版本4.1.2 2020-12-03 13:28:04 +08:00
1c7a5faae8 Excel支持注解align对齐方式 2020-12-03 13:26:46 +08:00
23868c4fad 防止安全扫描YUI出现的风险提示 2020-12-03 10:26:22 +08:00
3b2669d148 修改缓存监控内存单位 2020-11-30 19:27:03 +08:00
1147ea5f8a 设置用户头像悬停高度 2020-11-30 11:10:27 +08:00
a1bf5aaf8e 升级element-ui版本到2.14.1 2020-11-30 10:37:48 +08:00
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
01861f0aae update pom.xml. 2020-11-29 16:16:54 +08:00
a69cc94f35 三级菜单自动配置组件 2020-11-28 20:39:03 +08:00
c666faed66 修复三级菜单之间切换页面无法缓存的问题 2020-11-28 20:31:45 +08:00
6072239a40 修改缓存监控内存单位 2020-11-28 13:57:19 +08:00
a3b86d6f6d 代码生成删除多余的数字float类型 2020-11-28 12:09:24 +08:00
fd831d5a90 Excel支持导入Boolean型数据 2020-11-28 12:08:55 +08:00
e83412b9a5 升级oshi到最新版本v5.3.6 2020-11-24 16:17:33 +08:00
90ac416e02 新增缓存监控功能 2020-11-23 10:02:50 +08:00
5b63f0cab9 优化头像样式,鼠标移入悬停遮罩 2020-11-19 09:33:10 +08:00
117 changed files with 2423 additions and 519 deletions

View File

@ -1,13 +1,15 @@
## 平台简介 ## 平台简介
若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
* 前端采用Vue、Element UI。 * 前端采用Vue、Element UI。
* 后端采用Spring Boot、Spring Security、Redis & Jwt。 * 后端采用Spring Boot、Spring Security、Redis & Jwt。
* 权限认证使用Jwt支持多终端认证系统。 * 权限认证使用Jwt支持多终端认证系统。
* 支持加载动态权限菜单,多方式轻松权限控制。 * 支持加载动态权限菜单,多方式轻松权限控制。
* 高效率开发,使用代码生成器可以一键生成前后端代码。 * 高效率开发,使用代码生成器可以一键生成前后端代码。
* 提供了一个Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。 * 提供了单应用版本[RuoYi-Vue-fast](https://github.com/yangzongzhuan/RuoYi-Vue-fast)Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) * 不分离版本,请移步[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)。 * 特别鸣谢:[element](https://github.com/ElemeFE/element)[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)[eladmin-web](https://github.com/elunez/eladmin-web)。
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)   * 阿里云折扣场:[点我进入](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)   * 阿里云优惠券:[点我领取](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)  
@ -28,8 +30,9 @@
13. 代码生成前后端代码的生成java、html、xml、sql支持CRUD下载 。 13. 代码生成前后端代码的生成java、html、xml、sql支持CRUD下载 。
14. 系统接口根据业务代码自动生成相关的api接口文档。 14. 系统接口根据业务代码自动生成相关的api接口文档。
15. 服务监控监视当前系统CPU、内存、磁盘、堆栈等相关信息。 15. 服务监控监视当前系统CPU、内存、磁盘、堆栈等相关信息。
16. 在线构建器拖动表单元素生成相应的HTML代码 16. 缓存监控:对系统的缓存信息查询,命令统计等
17. 连接池监视监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈 17. 在线构建器拖动表单元素生成相应的HTML代码
18. 连接池监视监视当前系统数据库连接池状态可进行分析SQL找出系统性能瓶颈。
## 在线体验 ## 在线体验
@ -72,7 +75,7 @@
</tr> </tr>
<tr> <tr>
<td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td> <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
<td><img src="https://oscimg.oschina.net/oscnet/up-6d73c2140ce694e3de4c05035fdc1868d4c.png"/></td> <td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
</tr> </tr>
</table> </table>

18
pom.xml
View File

@ -6,29 +6,29 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.2.1</version> <version>3.4.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.2.1</ruoyi.version> <ruoyi.version>3.4.0</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<druid.version>1.2.2</druid.version> <druid.version>1.2.4</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.3.0</pagehelper.boot.version> <pagehelper.boot.version>1.3.0</pagehelper.boot.version>
<fastjson.version>1.2.74</fastjson.version> <fastjson.version>1.2.75</fastjson.version>
<oshi.version>5.2.5</oshi.version> <oshi.version>5.3.6</oshi.version>
<jna.version>5.5.0</jna.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.1</jwt.version> <jwt.version>0.9.1</jwt.version>
</properties> </properties>
@ -41,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.17.RELEASE</version> <version>2.2.13.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</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.2.1</version> <version>3.4.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

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

@ -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

@ -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() + "'失败,邮箱账号已存在");
} }

View File

@ -3,9 +3,9 @@ ruoyi:
# 名称 # 名称
name: RuoYi name: RuoYi
# 版本 # 版本
version: 3.2.1 version: 3.4.0
# 版权年份 # 版权年份
copyrightYear: 2020 copyrightYear: 2021
# 实例演示开关 # 实例演示开关
demoEnabled: true demoEnabled: true
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath # 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
@ -62,6 +62,8 @@ spring:
host: localhost host: localhost
# 端口默认为6379 # 端口默认为6379
port: 6379 port: 6379
# 数据库索引
database: 0
# 密码 # 密码
password: password:
# 连接超时时间 # 连接超时时间

View File

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

View File

@ -105,6 +105,27 @@ public @interface Excel
*/ */
public boolean isStatistics() default false; 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仅导入
*/ */
@ -128,7 +149,7 @@ public @interface Excel
public enum ColumnType public enum ColumnType
{ {
NUMERIC(0), STRING(1); NUMERIC(0), STRING(1), IMAGE(2);
private final int value; private final int value;
ColumnType(int value) ColumnType(int value)

View File

@ -13,6 +13,9 @@ public class GenConstants
/** 树表(增删改查) */ /** 树表(增删改查) */
public static final String TPL_TREE = "tree"; public static final String TPL_TREE = "tree";
/** 主子表(增删改查) */
public static final String TPL_SUB = "sub";
/** 树编码字段 */ /** 树编码字段 */
public static final String TREE_CODE = "treeCode"; public static final String TREE_CODE = "treeCode";
@ -29,15 +32,17 @@ 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", "nvarchar", "varchar2", "tinytext", "text", public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
"mediumtext", "longtext" };
/** 数据库文本类型 */
public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
/** 数据库时间类型 */ /** 数据库时间类型 */
public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" }; public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
/** 数据库数字类型 */ /** 数据库数字类型 */
public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer", public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
"bit", "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,8 +79,11 @@ 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_IMAGE_UPLOAD = "imageUpload";
/** 文件上传控件 */
public static final String HTML_FILE_UPLOAD = "fileUpload";
/** 富文本控件 */ /** 富文本控件 */
public static final String HTML_EDITOR = "editor"; public static final String HTML_EDITOR = "editor";

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

@ -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

@ -29,8 +29,8 @@ public class RepeatableFilter implements Filter
throws IOException, ServletException throws IOException, ServletException
{ {
ServletRequest requestWrapper = null; ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest && StringUtils.equalsAnyIgnoreCase(request.getContentType(), if (request instanceof HttpServletRequest
MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_JSON_UTF8_VALUE)) && StringUtils.equalsAnyIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE))
{ {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
} }

View File

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

View File

@ -44,4 +44,33 @@ public class FileTypeUtils
} }
return fileName.substring(separatorIndex + 1).toLowerCase(); return fileName.substring(separatorIndex + 1).toLowerCase();
} }
/**
* 获取文件类型
*
* @param photoByte 文件字节码
* @return 后缀(不含".")
*/
public static String getFileExtendName(byte[] photoByte)
{
String strFileExtendName = "JPG";
if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
&& ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
{
strFileExtendName = "GIF";
}
else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
{
strFileExtendName = "JPG";
}
else if ((photoByte[0] == 66) && (photoByte[1] == 77))
{
strFileExtendName = "BMP";
}
else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
{
strFileExtendName = "PNG";
}
return strFileExtendName;
}
} }

View File

@ -0,0 +1,100 @@
package com.ruoyi.common.utils.file;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.StringUtils;
/**
* 图片处理工具类
*
* @author ruoyi
*/
public class ImageUtils
{
private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
public static byte[] getImage(String imagePath)
{
InputStream is = getFile(imagePath);
try
{
return IOUtils.toByteArray(is);
}
catch (Exception e)
{
log.error("图片加载异常 {}", e);
return null;
}
finally
{
IOUtils.closeQuietly(is);
}
}
public static InputStream getFile(String imagePath)
{
try
{
byte[] result = readFile(imagePath);
result = Arrays.copyOf(result, result.length);
return new ByteArrayInputStream(result);
}
catch (Exception e)
{
log.error("获取图片异常 {}", e);
}
return null;
}
/**
* 读取文件为字节数据
*
* @param key 地址
* @return 字节数据
*/
public static byte[] readFile(String url)
{
InputStream in = null;
ByteArrayOutputStream baos = null;
try
{
if (url.startsWith("http"))
{
// 网络地址
URL urlObj = new URL(url);
URLConnection urlConnection = urlObj.openConnection();
urlConnection.setConnectTimeout(30 * 1000);
urlConnection.setReadTimeout(60 * 1000);
urlConnection.setDoInput(true);
in = urlConnection.getInputStream();
}
else
{
// 本机地址
String localPath = RuoYiConfig.getProfile();
String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
in = new FileInputStream(downloadPath);
}
return IOUtils.toByteArray(in);
}
catch (Exception e)
{
log.error("获取文件路径异常 {}", e);
return null;
}
finally
{
IOUtils.closeQuietly(baos);
}
}
}

View File

@ -18,15 +18,16 @@ import java.util.Map;
import java.util.Set; 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;
import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.DataValidation; import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint; import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper; import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.FillPatternType; import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.HorizontalAlignment;
@ -38,6 +39,7 @@ import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.streaming.SXSSFWorkbook; import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDataValidation; import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -52,6 +54,8 @@ import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils; import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileTypeUtils;
import com.ruoyi.common.utils.file.ImageUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils; import com.ruoyi.common.utils.reflect.ReflectUtils;
/** /**
@ -103,6 +107,11 @@ public class ExcelUtil<T>
*/ */
private List<Object[]> fields; private List<Object[]> fields;
/**
* 最大高度
*/
private short maxHeight;
/** /**
* 统计列表 * 统计列表
*/ */
@ -240,7 +249,15 @@ public class ExcelUtil<T>
} }
else else
{ {
val = Convert.toStr(val); String dateFormat = field.getAnnotation(Excel.class).dateFormat();
if (StringUtils.isNotEmpty(dateFormat))
{
val = DateUtils.parseDateToStr(dateFormat, (Date) val);
}
else
{
val = Convert.toStr(val);
}
} }
} }
else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
@ -274,6 +291,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);
@ -469,6 +490,21 @@ public class ExcelUtil<T>
style.setFont(totalFont); style.setFont(totalFont);
styles.put("total", style); 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;
} }
@ -497,14 +533,53 @@ 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(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
} }
else if (ColumnType.IMAGE == attr.cellType())
{
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1),
cell.getRow().getRowNum() + 1);
String imagePath = Convert.toStr(value);
if (StringUtils.isNotEmpty(imagePath))
{
byte[] data = ImageUtils.getImage(imagePath);
getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
}
}
}
/**
* 获取画布
*/
public static Drawing<?> getDrawingPatriarch(Sheet sheet)
{
if (sheet.getDrawingPatriarch() == null)
{
sheet.createDrawingPatriarch();
}
return sheet.getDrawingPatriarch();
}
/**
* 获取图片类型,设置图片插入类型
*/
public int getImageType(byte[] value)
{
String type = FileTypeUtils.getFileExtendName(value);
if ("JPG".equalsIgnoreCase(type))
{
return Workbook.PICTURE_TYPE_JPEG;
}
else if ("PNG".equalsIgnoreCase(type))
{
return Workbook.PICTURE_TYPE_PNG;
}
return Workbook.PICTURE_TYPE_JPEG;
} }
/** /**
@ -520,7 +595,6 @@ public class ExcelUtil<T>
{ {
// 设置列宽 // 设置列宽
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
row.setHeight((short) (attr.height() * 20));
} }
// 如果设置了提示信息则鼠标放上去提示. // 如果设置了提示信息则鼠标放上去提示.
if (StringUtils.isNotEmpty(attr.prompt())) if (StringUtils.isNotEmpty(attr.prompt()))
@ -545,13 +619,14 @@ public class ExcelUtil<T>
try try
{ {
// 设置行高 // 设置行高
row.setHeight((short) (attr.height() * 20)); row.setHeight(maxHeight);
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
if (attr.isExport()) if (attr.isExport())
{ {
// 创建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);
@ -860,7 +935,7 @@ 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();
Field field = clazz.getDeclaredField(name); Field field = clazz.getDeclaredField(name);
@ -899,6 +974,21 @@ public class ExcelUtil<T>
} }
} }
this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
this.maxHeight = getRowHeight();
}
/**
* 根据注解获取最大行高
*/
public short getRowHeight()
{
double maxHeight = 0;
for (Object[] os : this.fields)
{
Excel excel = (Excel) os[1];
maxHeight = maxHeight > excel.height() ? maxHeight : excel.height();
}
return (short) (maxHeight * 20);
} }
/** /**
@ -960,16 +1050,16 @@ 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
{ {
if ((Double) val % 1 > 0) if ((Double) val % 1 != 0)
{ {
val = new BigDecimal(val.toString()); val = new BigDecimal(val.toString());
} }
@ -979,15 +1069,15 @@ public class ExcelUtil<T>
} }
} }
} }
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.2.1</version> <version>3.4.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

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

@ -8,8 +8,10 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
/** /**
* redis配置 * redis配置
@ -31,7 +33,7 @@ public class RedisConfig extends CachingConfigurerSupport
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
serializer.setObjectMapper(mapper); serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer); template.setValueSerializer(serializer);

View File

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

View File

@ -63,10 +63,12 @@ public class GenController extends BaseController
public AjaxResult getInfo(@PathVariable Long talbleId) public AjaxResult getInfo(@PathVariable Long talbleId)
{ {
GenTable table = genTableService.selectGenTableById(talbleId); GenTable table = genTableService.selectGenTableById(talbleId);
List<GenTable> tables = genTableService.selectGenTableAll();
List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId); List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(talbleId);
Map<String, Object> map = new HashMap<String, Object>(); Map<String, Object> map = new HashMap<String, Object>();
map.put("info", table); map.put("info", table);
map.put("rows", list); map.put("rows", list);
map.put("tables", tables);
return AjaxResult.success(map); return AjaxResult.success(map);
} }

View File

@ -28,11 +28,17 @@ public class GenTable extends BaseEntity
@NotBlank(message = "表描述不能为空") @NotBlank(message = "表描述不能为空")
private String tableComment; private String tableComment;
/** 关联父表的表名 */
private String subTableName;
/** 本表关联父表的外键名 */
private String subTableFkName;
/** 实体类名称(首字母大写) */ /** 实体类名称(首字母大写) */
@NotBlank(message = "实体类名称不能为空") @NotBlank(message = "实体类名称不能为空")
private String className; private String className;
/** 使用的模板crud单表操作 tree树表操作 */ /** 使用的模板crud单表操作 tree树表操作 sub主子表操作 */
private String tplCategory; private String tplCategory;
/** 生成包路径 */ /** 生成包路径 */
@ -64,6 +70,9 @@ public class GenTable extends BaseEntity
/** 主键信息 */ /** 主键信息 */
private GenTableColumn pkColumn; private GenTableColumn pkColumn;
/** 子表信息 */
private GenTable subTable;
/** 表列信息 */ /** 表列信息 */
@Valid @Valid
private List<GenTableColumn> columns; private List<GenTableColumn> columns;
@ -116,6 +125,26 @@ public class GenTable extends BaseEntity
this.tableComment = tableComment; this.tableComment = tableComment;
} }
public String getSubTableName()
{
return subTableName;
}
public void setSubTableName(String subTableName)
{
this.subTableName = subTableName;
}
public String getSubTableFkName()
{
return subTableFkName;
}
public void setSubTableFkName(String subTableFkName)
{
this.subTableFkName = subTableFkName;
}
public String getClassName() public String getClassName()
{ {
return className; return className;
@ -216,6 +245,16 @@ public class GenTable extends BaseEntity
this.pkColumn = pkColumn; this.pkColumn = pkColumn;
} }
public GenTable getSubTable()
{
return subTable;
}
public void setSubTable(GenTable subTable)
{
this.subTable = subTable;
}
public List<GenTableColumn> getColumns() public List<GenTableColumn> getColumns()
{ {
return columns; return columns;
@ -286,6 +325,16 @@ public class GenTable extends BaseEntity
this.parentMenuName = parentMenuName; this.parentMenuName = parentMenuName;
} }
public boolean isSub()
{
return isSub(this.tplCategory);
}
public static boolean isSub(String tplCategory)
{
return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);
}
public boolean isTree() public boolean isTree()
{ {
return isTree(this.tplCategory); return isTree(this.tplCategory);

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日期控件、upload上传控件、editor富文本控件 */ /** 显示类型input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件 */
private String htmlType; private String htmlType;
/** 字典类型 */ /** 字典类型 */
@ -138,6 +138,11 @@ public class GenTableColumn extends BaseEntity
return javaField; return javaField;
} }
public String getCapJavaField()
{
return StringUtils.capitalize(javaField);
}
public void setIsPk(String isPk) public void setIsPk(String isPk)
{ {
this.isPk = isPk; this.isPk = isPk;

View File

@ -34,6 +34,13 @@ public interface GenTableMapper
*/ */
public List<GenTable> selectDbTableListByNames(String[] tableNames); public List<GenTable> selectDbTableListByNames(String[] tableNames);
/**
* 查询所有表信息
*
* @return 表信息集合
*/
public List<GenTable> selectGenTableAll();
/** /**
* 查询表ID业务信息 * 查询表ID业务信息
* *

View File

@ -102,6 +102,17 @@ public class GenTableServiceImpl implements IGenTableService
return genTableMapper.selectDbTableListByNames(tableNames); return genTableMapper.selectDbTableListByNames(tableNames);
} }
/**
* 查询所有表信息
*
* @return 表信息集合
*/
@Override
public List<GenTable> selectGenTableAll()
{
return genTableMapper.selectGenTableAll();
}
/** /**
* 修改业务 * 修改业务
* *
@ -185,9 +196,10 @@ public class GenTableServiceImpl implements IGenTableService
Map<String, String> dataMap = new LinkedHashMap<>(); Map<String, String> dataMap = new LinkedHashMap<>();
// 查询表信息 // 查询表信息
GenTable table = genTableMapper.selectGenTableById(tableId); GenTable table = genTableMapper.selectGenTableById(tableId);
// 查询列信息 // 设置主子表信息
List<GenTableColumn> columns = table.getColumns(); setSubTable(table);
setPkColumn(table, columns); // 设置主键列信息
setPkColumn(table);
VelocityInitializer.initVelocity(); VelocityInitializer.initVelocity();
VelocityContext context = VelocityUtils.prepareContext(table); VelocityContext context = VelocityUtils.prepareContext(table);
@ -231,9 +243,10 @@ public class GenTableServiceImpl implements IGenTableService
{ {
// 查询表信息 // 查询表信息
GenTable table = genTableMapper.selectGenTableByName(tableName); GenTable table = genTableMapper.selectGenTableByName(tableName);
// 查询列信息 // 设置主子表信息
List<GenTableColumn> columns = table.getColumns(); setSubTable(table);
setPkColumn(table, columns); // 设置主键列信息
setPkColumn(table);
VelocityInitializer.initVelocity(); VelocityInitializer.initVelocity();
@ -276,6 +289,10 @@ public class GenTableServiceImpl implements IGenTableService
List<String> tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); List<String> tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
if (StringUtils.isEmpty(dbTableColumns))
{
throw new CustomException("同步数据失败,原表结构不存在");
}
List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
dbTableColumns.forEach(column -> { dbTableColumns.forEach(column -> {
@ -319,9 +336,10 @@ public class GenTableServiceImpl implements IGenTableService
{ {
// 查询表信息 // 查询表信息
GenTable table = genTableMapper.selectGenTableByName(tableName); GenTable table = genTableMapper.selectGenTableByName(tableName);
// 查询列信息 // 设置主子表信息
List<GenTableColumn> columns = table.getColumns(); setSubTable(table);
setPkColumn(table, columns); // 设置主键列信息
setPkColumn(table);
VelocityInitializer.initVelocity(); VelocityInitializer.initVelocity();
@ -375,6 +393,17 @@ public class GenTableServiceImpl implements IGenTableService
{ {
throw new CustomException("树名称字段不能为空"); throw new CustomException("树名称字段不能为空");
} }
else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
{
if (StringUtils.isEmpty(genTable.getSubTableName()))
{
throw new CustomException("关联子表的表名不能为空");
}
else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
{
throw new CustomException("子表关联的外键名不能为空");
}
}
} }
} }
@ -382,11 +411,10 @@ public class GenTableServiceImpl implements IGenTableService
* 设置主键列信息 * 设置主键列信息
* *
* @param table 业务表信息 * @param table 业务表信息
* @param columns 业务字段列表
*/ */
public void setPkColumn(GenTable table, List<GenTableColumn> columns) public void setPkColumn(GenTable table)
{ {
for (GenTableColumn column : columns) for (GenTableColumn column : table.getColumns())
{ {
if (column.isPk()) if (column.isPk())
{ {
@ -396,7 +424,36 @@ public class GenTableServiceImpl implements IGenTableService
} }
if (StringUtils.isNull(table.getPkColumn())) if (StringUtils.isNull(table.getPkColumn()))
{ {
table.setPkColumn(columns.get(0)); table.setPkColumn(table.getColumns().get(0));
}
if (GenConstants.TPL_SUB.equals(table.getTplCategory()))
{
for (GenTableColumn column : table.getSubTable().getColumns())
{
if (column.isPk())
{
table.getSubTable().setPkColumn(column);
break;
}
}
if (StringUtils.isNull(table.getSubTable().getPkColumn()))
{
table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
}
}
}
/**
* 设置主子表信息
*
* @param table 业务表信息
*/
public void setSubTable(GenTable table)
{
String subTableName = table.getSubTableName();
if (StringUtils.isNotEmpty(subTableName))
{
table.setSubTable(genTableMapper.selectGenTableByName(subTableName));
} }
} }

View File

@ -35,6 +35,13 @@ public interface IGenTableService
*/ */
public List<GenTable> selectDbTableListByNames(String[] tableNames); public List<GenTable> selectDbTableListByNames(String[] tableNames);
/**
* 查询所有表信息
*
* @return 表信息集合
*/
public List<GenTable> selectGenTableAll();
/** /**
* 查询业务信息 * 查询业务信息
* *

View File

@ -40,13 +40,14 @@ public class GenUtils
column.setCreateBy(table.getCreateBy()); column.setCreateBy(table.getCreateBy());
// 设置java字段名 // 设置java字段名
column.setJavaField(StringUtils.toCamelCase(columnName)); column.setJavaField(StringUtils.toCamelCase(columnName));
// 设置默认类型
column.setJavaType(GenConstants.TYPE_STRING);
if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType)) if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
{ {
column.setJavaType(GenConstants.TYPE_STRING);
// 字符串长度超过500设置为文本域 // 字符串长度超过500设置为文本域
Integer columnLength = getColumnLength(column.getColumnType()); Integer columnLength = getColumnLength(column.getColumnType());
String htmlType = columnLength >= 500 ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
column.setHtmlType(htmlType); column.setHtmlType(htmlType);
} }
else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType))
@ -111,10 +112,15 @@ public class GenUtils
{ {
column.setHtmlType(GenConstants.HTML_SELECT); column.setHtmlType(GenConstants.HTML_SELECT);
} }
// 文件字段设置上传控件 // 图片字段设置图片上传控件
else if (StringUtils.endsWithIgnoreCase(columnName, "image")) else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
{ {
column.setHtmlType(GenConstants.HTML_UPLOAD_IMAGE); column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
}
// 文件字段设置文件上传控件
else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
{
column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
} }
// 内容字段设置富文本控件 // 内容字段设置富文本控件
else if (StringUtils.endsWithIgnoreCase(columnName, "content")) else if (StringUtils.endsWithIgnoreCase(columnName, "content"))

View File

@ -7,7 +7,7 @@ import com.ruoyi.common.constant.Constants;
/** /**
* VelocityEngine工厂 * VelocityEngine工厂
* *
* @author RuoYi * @author ruoyi
*/ */
public class VelocityInitializer public class VelocityInitializer
{ {

View File

@ -54,7 +54,7 @@ public class VelocityUtils
velocityContext.put("author", genTable.getFunctionAuthor()); velocityContext.put("author", genTable.getFunctionAuthor());
velocityContext.put("datetime", DateUtils.getDate()); velocityContext.put("datetime", DateUtils.getDate());
velocityContext.put("pkColumn", genTable.getPkColumn()); velocityContext.put("pkColumn", genTable.getPkColumn());
velocityContext.put("importList", getImportList(genTable.getColumns())); velocityContext.put("importList", getImportList(genTable));
velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
velocityContext.put("columns", genTable.getColumns()); velocityContext.put("columns", genTable.getColumns());
velocityContext.put("table", genTable); velocityContext.put("table", genTable);
@ -63,6 +63,10 @@ public class VelocityUtils
{ {
setTreeVelocityContext(velocityContext, genTable); setTreeVelocityContext(velocityContext, genTable);
} }
if (GenConstants.TPL_SUB.equals(tplCategory))
{
setSubVelocityContext(velocityContext, genTable);
}
return velocityContext; return velocityContext;
} }
@ -96,6 +100,24 @@ public class VelocityUtils
} }
} }
public static void setSubVelocityContext(VelocityContext context, GenTable genTable)
{
GenTable subTable = genTable.getSubTable();
String subTableName = genTable.getSubTableName();
String subTableFkName = genTable.getSubTableFkName();
String subClassName = genTable.getSubTable().getClassName();
String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
context.put("subTable", subTable);
context.put("subTableName", subTableName);
context.put("subTableFkName", subTableFkName);
context.put("subTableFkClassName", subTableFkClassName);
context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
context.put("subClassName", subClassName);
context.put("subclassName", StringUtils.uncapitalize(subClassName));
context.put("subImportList", getImportList(genTable.getSubTable()));
}
/** /**
* 获取模板信息 * 获取模板信息
* *
@ -120,6 +142,11 @@ public class VelocityUtils
{ {
templates.add("vm/vue/index-tree.vue.vm"); templates.add("vm/vue/index-tree.vue.vm");
} }
else if (GenConstants.TPL_SUB.equals(tplCategory))
{
templates.add("vm/vue/index.vue.vm");
templates.add("vm/java/sub-domain.java.vm");
}
return templates; return templates;
} }
@ -147,6 +174,10 @@ public class VelocityUtils
{ {
fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
} }
if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
{
fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
}
else if (template.contains("mapper.java.vm")) else if (template.contains("mapper.java.vm"))
{ {
fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
@ -202,12 +233,18 @@ public class VelocityUtils
/** /**
* 根据列类型获取导入包 * 根据列类型获取导入包
* *
* @param columns 列集合 * @param genTable 业务表对象
* @return 返回需要导入的包列表 * @return 返回需要导入的包列表
*/ */
public static HashSet<String> getImportList(List<GenTableColumn> columns) public static HashSet<String> getImportList(GenTable genTable)
{ {
List<GenTableColumn> columns = genTable.getColumns();
GenTable subGenTable = genTable.getSubTable();
HashSet<String> importList = new HashSet<String>(); HashSet<String> importList = new HashSet<String>();
if (StringUtils.isNotNull(subGenTable))
{
importList.add("java.util.List");
}
for (GenTableColumn column : columns) for (GenTableColumn column : columns)
{ {
if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType()))

View File

@ -5,24 +5,26 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.ruoyi.generator.mapper.GenTableMapper"> <mapper namespace="com.ruoyi.generator.mapper.GenTableMapper">
<resultMap type="GenTable" id="GenTableResult"> <resultMap type="GenTable" id="GenTableResult">
<id property="tableId" column="table_id" /> <id property="tableId" column="table_id" />
<result property="tableName" column="table_name" /> <result property="tableName" column="table_name" />
<result property="tableComment" column="table_comment" /> <result property="tableComment" column="table_comment" />
<result property="className" column="class_name" /> <result property="subTableName" column="sub_table_name" />
<result property="tplCategory" column="tpl_category" /> <result property="subTableFkName" column="sub_table_fk_name" />
<result property="packageName" column="package_name" /> <result property="className" column="class_name" />
<result property="moduleName" column="module_name" /> <result property="tplCategory" column="tpl_category" />
<result property="businessName" column="business_name" /> <result property="packageName" column="package_name" />
<result property="functionName" column="function_name" /> <result property="moduleName" column="module_name" />
<result property="functionAuthor" column="function_author" /> <result property="businessName" column="business_name" />
<result property="genType" column="gen_type" /> <result property="functionName" column="function_name" />
<result property="genPath" column="gen_path" /> <result property="functionAuthor" column="function_author" />
<result property="options" column="options" /> <result property="genType" column="gen_type" />
<result property="createBy" column="create_by" /> <result property="genPath" column="gen_path" />
<result property="createTime" column="create_time" /> <result property="options" column="options" />
<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" />
<collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" /> <collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" />
</resultMap> </resultMap>
@ -52,7 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectGenTableVo"> <sql id="selectGenTableVo">
select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
</sql> </sql>
<select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult"> <select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
@ -64,11 +66,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 +86,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>
@ -108,7 +110,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult"> <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark, SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@ -116,13 +118,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult"> <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark, SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id LEFT JOIN gen_table_column c ON t.table_id = c.table_id
where t.table_name = #{tableName} order by c.sort where t.table_name = #{tableName} order by c.sort
</select> </select>
<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
order by c.sort
</select>
<insert id="insertGenTable" parameterType="GenTable" useGeneratedKeys="true" keyProperty="tableId"> <insert id="insertGenTable" parameterType="GenTable" useGeneratedKeys="true" keyProperty="tableId">
insert into gen_table ( insert into gen_table (
<if test="tableName != null">table_name,</if> <if test="tableName != null">table_name,</if>
@ -162,6 +172,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<set> <set>
<if test="tableName != null">table_name = #{tableName},</if> <if test="tableName != null">table_name = #{tableName},</if>
<if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if> <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if>
<if test="subTableName != null">sub_table_name = #{subTableName},</if>
<if test="subTableFkName != null">sub_table_fk_name = #{subTableFkName},</if>
<if test="className != null and className != ''">class_name = #{className},</if> <if test="className != null and className != ''">class_name = #{className},</if>
<if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if> <if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if>
<if test="genType != null and genType != ''">gen_type = #{genType},</if> <if test="genType != null and genType != ''">gen_type = #{genType},</if>

View File

@ -18,7 +18,7 @@ import com.ruoyi.common.enums.BusinessType;
import ${packageName}.domain.${ClassName}; import ${packageName}.domain.${ClassName};
import ${packageName}.service.I${ClassName}Service; import ${packageName}.service.I${ClassName}Service;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
#if($table.crud) #if($table.crud || $table.sub)
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
#elseif($table.tree) #elseif($table.tree)
#end #end
@ -41,7 +41,7 @@ public class ${ClassName}Controller extends BaseController
*/ */
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')")
@GetMapping("/list") @GetMapping("/list")
#if($table.crud) #if($table.crud || $table.sub)
public TableDataInfo list(${ClassName} ${className}) public TableDataInfo list(${ClassName} ${className})
{ {
startPage(); startPage();

View File

@ -6,7 +6,7 @@ import ${import};
import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.annotation.Excel;
#if($table.crud) #if($table.crud || $table.sub)
import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.core.domain.BaseEntity;
#elseif($table.tree) #elseif($table.tree)
import com.ruoyi.common.core.domain.TreeEntity; import com.ruoyi.common.core.domain.TreeEntity;
@ -18,7 +18,7 @@ import com.ruoyi.common.core.domain.TreeEntity;
* @author ${author} * @author ${author}
* @date ${datetime} * @date ${datetime}
*/ */
#if($table.crud) #if($table.crud || $table.sub)
#set($Entity="BaseEntity") #set($Entity="BaseEntity")
#elseif($table.tree) #elseif($table.tree)
#set($Entity="TreeEntity") #set($Entity="TreeEntity")
@ -49,6 +49,11 @@ public class ${ClassName} extends ${Entity}
private $column.javaType $column.javaField; private $column.javaType $column.javaField;
#end #end
#end
#if($table.sub)
/** $table.subTable.functionName信息 */
private List<${subClassName}> ${subclassName}List;
#end #end
#foreach ($column in $columns) #foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField)) #if(!$table.isSuperColumn($column.javaField))
@ -69,6 +74,18 @@ public class ${ClassName} extends ${Entity}
#end #end
#end #end
#if($table.sub)
public List<${subClassName}> get${subClassName}List()
{
return ${subclassName}List;
}
public void set${subClassName}List(List<${subClassName}> ${subclassName}List)
{
this.${subclassName}List = ${subclassName}List;
}
#end
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@ -79,6 +96,9 @@ public class ${ClassName} extends ${Entity}
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#end #end
.append("${column.javaField}", get${AttrName}()) .append("${column.javaField}", get${AttrName}())
#end
#if($table.sub)
.append("${subclassName}List", get${subClassName}List())
#end #end
.toString(); .toString();
} }

View File

@ -2,6 +2,9 @@ package ${packageName}.mapper;
import java.util.List; import java.util.List;
import ${packageName}.domain.${ClassName}; import ${packageName}.domain.${ClassName};
#if($table.sub)
import ${packageName}.domain.${subClassName};
#end
/** /**
* ${functionName}Mapper接口 * ${functionName}Mapper接口
@ -58,4 +61,31 @@ public interface ${ClassName}Mapper
* @return 结果 * @return 结果
*/ */
public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s); public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s);
#if($table.sub)
/**
* 批量删除${subTable.functionName}
*
* @param customerIds 需要删除的数据ID
* @return 结果
*/
public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
/**
* 批量新增${subTable.functionName}
*
* @param ${subclassName}List ${subTable.functionName}列表
* @return 结果
*/
public int batch${subClassName}(List<${subClassName}> ${subclassName}List);
/**
* 通过${functionName}ID删除${subTable.functionName}信息
*
* @param roleId 角色ID
* @return 结果
*/
public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});
#end
} }

View File

@ -9,6 +9,12 @@ import com.ruoyi.common.utils.DateUtils;
#end #end
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
#if($table.sub)
import java.util.ArrayList;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import ${packageName}.domain.${subClassName};
#end
import ${packageName}.mapper.${ClassName}Mapper; import ${packageName}.mapper.${ClassName}Mapper;
import ${packageName}.domain.${ClassName}; import ${packageName}.domain.${ClassName};
import ${packageName}.service.I${ClassName}Service; import ${packageName}.service.I${ClassName}Service;
@ -55,6 +61,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
* @param ${className} ${functionName} * @param ${className} ${functionName}
* @return 结果 * @return 结果
*/ */
#if($table.sub)
@Transactional
#end
@Override @Override
public int insert${ClassName}(${ClassName} ${className}) public int insert${ClassName}(${ClassName} ${className})
{ {
@ -63,7 +72,13 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
${className}.setCreateTime(DateUtils.getNowDate()); ${className}.setCreateTime(DateUtils.getNowDate());
#end #end
#end #end
#if($table.sub)
int rows = ${className}Mapper.insert${ClassName}(${className});
insert${subClassName}(${className});
return rows;
#else
return ${className}Mapper.insert${ClassName}(${className}); return ${className}Mapper.insert${ClassName}(${className});
#end
} }
/** /**
@ -72,6 +87,9 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
* @param ${className} ${functionName} * @param ${className} ${functionName}
* @return 结果 * @return 结果
*/ */
#if($table.sub)
@Transactional
#end
@Override @Override
public int update${ClassName}(${ClassName} ${className}) public int update${ClassName}(${ClassName} ${className})
{ {
@ -79,6 +97,10 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
#if($column.javaField == 'updateTime') #if($column.javaField == 'updateTime')
${className}.setUpdateTime(DateUtils.getNowDate()); ${className}.setUpdateTime(DateUtils.getNowDate());
#end #end
#end
#if($table.sub)
${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());
insert${subClassName}(${className});
#end #end
return ${className}Mapper.update${ClassName}(${className}); return ${className}Mapper.update${ClassName}(${className});
} }
@ -89,9 +111,15 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
* @param ${pkColumn.javaField}s 需要删除的${functionName}ID * @param ${pkColumn.javaField}s 需要删除的${functionName}ID
* @return 结果 * @return 结果
*/ */
#if($table.sub)
@Transactional
#end
@Override @Override
public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s) public int delete${ClassName}ByIds(${pkColumn.javaType}[] ${pkColumn.javaField}s)
{ {
#if($table.sub)
${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
#end
return ${className}Mapper.delete${ClassName}ByIds(${pkColumn.javaField}s); return ${className}Mapper.delete${ClassName}ByIds(${pkColumn.javaField}s);
} }
@ -104,6 +132,35 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service
@Override @Override
public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}) public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField})
{ {
#if($table.sub)
${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
#end
return ${className}Mapper.delete${ClassName}ById(${pkColumn.javaField}); return ${className}Mapper.delete${ClassName}ById(${pkColumn.javaField});
} }
#if($table.sub)
/**
* 新增${subTable.functionName}信息
*
* @param ${className} ${functionName}对象
*/
public void insert${subClassName}(${ClassName} ${className})
{
List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
Long ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
if (StringUtils.isNotNull(${subclassName}List))
{
List<${subClassName}> list = new ArrayList<${subClassName}>();
for (${subClassName} ${subclassName} : ${subclassName}List)
{
${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});
list.add(${subclassName});
}
if (list.size() > 0)
{
${className}Mapper.batch${subClassName}(list);
}
}
}
#end
} }

View File

@ -0,0 +1,76 @@
package ${packageName}.domain;
#foreach ($import in $subImportList)
import ${import};
#end
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;
/**
* ${subTable.functionName}对象 ${subTableName}
*
* @author ${author}
* @date ${datetime}
*/
public class ${subClassName} extends BaseEntity
{
private static final long serialVersionUID = 1L;
#foreach ($column in $subTable.columns)
#if(!$table.isSuperColumn($column.javaField))
/** $column.columnComment */
#if($column.list)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($parentheseIndex != -1)
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
#elseif($column.javaType == 'Date')
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
#else
@Excel(name = "${comment}")
#end
#end
private $column.javaType $column.javaField;
#end
#end
#foreach ($column in $subTable.columns)
#if(!$table.isSuperColumn($column.javaField))
#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
#set($AttrName=$column.javaField)
#else
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#end
public void set${AttrName}($column.javaType $column.javaField)
{
this.$column.javaField = $column.javaField;
}
public $column.javaType get${AttrName}()
{
return $column.javaField;
}
#end
#end
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
#foreach ($column in $subTable.columns)
#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
#set($AttrName=$column.javaField)
#else
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#end
.append("${column.javaField}", get${AttrName}())
#end
.toString();
}
}

View File

@ -38,20 +38,33 @@
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" style="width: 200px" <el-date-picker clearable size="small"
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}">
<el-date-picker
v-model="daterange${AttrName}"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
#end #end
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -60,6 +73,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="primary" type="primary"
plain
icon="el-icon-plus" icon="el-icon-plus"
size="mini" size="mini"
@click="handleAdd" @click="handleAdd"
@ -139,9 +153,13 @@
<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 == "uploadImage") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<uploadImage v-model="form.${field}"/> <imageUpload v-model="form.${field}"/>
</el-form-item>
#elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -201,7 +219,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" style="width: 200px" <el-date-picker clearable size="small"
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -230,8 +248,14 @@ import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${Busin
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) #foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage") #if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
import UploadImage from '@/components/UploadImage'; import ImageUpload from '@/components/ImageUpload';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
import FileUpload from '@/components/FileUpload';
#break #break
#end #end
#end #end
@ -246,8 +270,14 @@ export default {
name: "${BusinessName}", name: "${BusinessName}",
components: { components: {
#foreach($column in $columns) #foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage") #if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
UploadImage, ImageUpload,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
FileUpload,
#break #break
#end #end
#end #end
@ -283,6 +313,10 @@ export default {
#if(${column.dictType} != '') #if(${column.dictType} != '')
// $comment字典 // $comment字典
${column.javaField}Options: [], ${column.javaField}Options: [],
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
// $comment时间范围
daterange${AttrName}: [],
#end #end
#end #end
// 查询参数 // 查询参数
@ -329,6 +363,21 @@ export default {
/** 查询${functionName}列表 */ /** 查询${functionName}列表 */
getList() { getList() {
this.loading = true; this.loading = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {};
#break
#end
#end
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
}
#end
#end
list${BusinessName}(this.queryParams).then(response => { list${BusinessName}(this.queryParams).then(response => {
this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}"); this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
this.loading = false; this.loading = false;
@ -397,6 +446,12 @@ export default {
}, },
/** 重置按钮操作 */ /** 重置按钮操作 */
resetQuery() { resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
this.daterange${AttrName} = [];
#end
#end
this.resetForm("queryForm"); this.resetForm("queryForm");
this.handleQuery(); this.handleQuery();
}, },

View File

@ -38,20 +38,33 @@
<el-option label="请选择字典生成" value="" /> <el-option label="请选择字典生成" value="" />
</el-select> </el-select>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
<el-form-item label="${comment}" prop="${column.javaField}"> <el-form-item label="${comment}" prop="${column.javaField}">
<el-date-picker clearable size="small" style="width: 200px" <el-date-picker clearable size="small"
v-model="queryParams.${column.javaField}" v-model="queryParams.${column.javaField}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
placeholder="选择${comment}"> placeholder="选择${comment}">
</el-date-picker> </el-date-picker>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
<el-form-item label="${comment}">
<el-date-picker
v-model="daterange${AttrName}"
size="small"
style="width: 240px"
value-format="yyyy-MM-dd"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
></el-date-picker>
</el-form-item>
#end #end
#end #end
#end #end
<el-form-item> <el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -60,6 +73,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="primary" type="primary"
plain
icon="el-icon-plus" icon="el-icon-plus"
size="mini" size="mini"
@click="handleAdd" @click="handleAdd"
@ -69,6 +83,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="success" type="success"
plain
icon="el-icon-edit" icon="el-icon-edit"
size="mini" size="mini"
:disabled="single" :disabled="single"
@ -79,6 +94,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="danger" type="danger"
plain
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
:disabled="multiple" :disabled="multiple"
@ -89,13 +105,14 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="warning" type="warning"
plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
@click="handleExport" @click="handleExport"
v-hasPermi="['${moduleName}:${businessName}:export']" v-hasPermi="['${moduleName}:${businessName}:export']"
>导出</el-button> >导出</el-button>
</el-col> </el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
@ -168,9 +185,13 @@
<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 == "uploadImage") #elseif($column.htmlType == "imageUpload")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
<uploadImage v-model="form.${field}"/> <imageUpload v-model="form.${field}"/>
</el-form-item>
#elseif($column.htmlType == "fileUpload")
<el-form-item label="${comment}">
<fileUpload v-model="form.${field}"/>
</el-form-item> </el-form-item>
#elseif($column.htmlType == "editor") #elseif($column.htmlType == "editor")
<el-form-item label="${comment}"> <el-form-item label="${comment}">
@ -230,7 +251,7 @@
</el-form-item> </el-form-item>
#elseif($column.htmlType == "datetime") #elseif($column.htmlType == "datetime")
<el-form-item label="${comment}" prop="${field}"> <el-form-item label="${comment}" prop="${field}">
<el-date-picker clearable size="small" style="width: 200px" <el-date-picker clearable size="small"
v-model="form.${field}" v-model="form.${field}"
type="date" type="date"
value-format="yyyy-MM-dd" value-format="yyyy-MM-dd"
@ -244,6 +265,38 @@
#end #end
#end #end
#end #end
#end
#if($table.sub)
<el-divider content-position="center">${subTable.functionName}信息</el-divider>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd${subClassName}">添加</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDelete${subClassName}">删除</el-button>
</el-col>
</el-row>
<el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="序号" align="center" prop="index" width="50"/>
#foreach($column in $subTable.columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf(""))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.pk || $javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
<el-table-column label="$comment" prop="${javaField}">
<template slot-scope="scope">
<el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
</template>
</el-table-column>
#end
#end
</el-table>
#end #end
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
@ -257,8 +310,14 @@
<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) #foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage") #if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
import UploadImage from '@/components/UploadImage'; import ImageUpload from '@/components/ImageUpload';
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
import FileUpload from '@/components/FileUpload';
#break #break
#end #end
#end #end
@ -273,8 +332,14 @@ export default {
name: "${BusinessName}", name: "${BusinessName}",
components: { components: {
#foreach($column in $columns) #foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "uploadImage") #if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "imageUpload")
UploadImage, ImageUpload,
#break
#end
#end
#foreach($column in $columns)
#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "fileUpload")
FileUpload,
#break #break
#end #end
#end #end
@ -291,6 +356,10 @@ export default {
loading: true, loading: true,
// 选中数组 // 选中数组
ids: [], ids: [],
#if($table.sub)
// 子表选中数据
checked${subClassName}: [],
#end
// 非单个禁用 // 非单个禁用
single: true, single: true,
// 非多个禁用 // 非多个禁用
@ -301,6 +370,10 @@ export default {
total: 0, total: 0,
// ${functionName}表格数据 // ${functionName}表格数据
${businessName}List: [], ${businessName}List: [],
#if($table.sub)
// ${subTable.functionName}表格数据
${subclassName}List: [],
#end
// 弹出层标题 // 弹出层标题
title: "", title: "",
// 是否显示弹出层 // 是否显示弹出层
@ -315,6 +388,10 @@ export default {
#if(${column.dictType} != '') #if(${column.dictType} != '')
// $comment字典 // $comment字典
${column.javaField}Options: [], ${column.javaField}Options: [],
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
// $comment时间范围
daterange${AttrName}: [],
#end #end
#end #end
// 查询参数 // 查询参数
@ -363,6 +440,21 @@ export default {
/** 查询${functionName}列表 */ /** 查询${functionName}列表 */
getList() { getList() {
this.loading = true; this.loading = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {};
#break
#end
#end
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
}
#end
#end
list${BusinessName}(this.queryParams).then(response => { list${BusinessName}(this.queryParams).then(response => {
this.${businessName}List = response.rows; this.${businessName}List = response.rows;
this.total = response.total; this.total = response.total;
@ -404,6 +496,9 @@ export default {
#end #end
#end #end
}; };
#if($table.sub)
this.${subclassName}List = [];
#end
this.resetForm("form"); this.resetForm("form");
}, },
/** 搜索按钮操作 */ /** 搜索按钮操作 */
@ -413,6 +508,12 @@ export default {
}, },
/** 重置按钮操作 */ /** 重置按钮操作 */
resetQuery() { resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
this.daterange${AttrName} = [];
#end
#end
this.resetForm("queryForm"); this.resetForm("queryForm");
this.handleQuery(); this.handleQuery();
}, },
@ -438,6 +539,9 @@ export default {
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(","); this.form.$column.javaField = this.form.${column.javaField}.split(",");
#end #end
#end
#if($table.sub)
this.${subclassName}List = response.data.${subclassName}List;
#end #end
this.open = true; this.open = true;
this.title = "修改${functionName}"; this.title = "修改${functionName}";
@ -451,6 +555,9 @@ export default {
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(","); this.form.$column.javaField = this.form.${column.javaField}.join(",");
#end #end
#end
#if($table.sub)
this.form.${subclassName}List = this.${subclassName}List;
#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 => {
@ -482,6 +589,40 @@ export default {
this.msgSuccess("删除成功"); this.msgSuccess("删除成功");
}) })
}, },
#if($table.sub)
/** ${subTable.functionName}序号 */
row${subClassName}Index({ row, rowIndex }) {
row.index = rowIndex + 1;
},
/** ${subTable.functionName}添加按钮操作 */
handleAdd${subClassName}() {
let obj = {};
#foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
obj.$column.javaField = "";
#end
#end
this.${subclassName}List.push(obj);
},
/** ${subTable.functionName}删除按钮操作 */
handleDelete${subClassName}() {
if (this.checked${subClassName}.length == 0) {
this.$alert("请先选择要删除的${subTable.functionName}数据", "提示", { confirmButtonText: "确定", });
} else {
this.${subclassName}List.splice(this.checked${subClassName}[0].index - 1, 1);
}
},
/** 单选框选中数据 */
handle${subClassName}SelectionChange(selection) {
if (selection.length > 1) {
this.$refs.${subclassName}.clearSelection();
this.$refs.${subclassName}.toggleRowSelection(selection.pop());
} else {
this.checked${subClassName} = selection;
}
},
#end
/** 导出按钮操作 */ /** 导出按钮操作 */
handleExport() { handleExport() {
const queryParams = this.queryParams; const queryParams = this.queryParams;

View File

@ -9,6 +9,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="${column.javaField}" column="${column.columnName}" /> <result property="${column.javaField}" column="${column.columnName}" />
#end #end
</resultMap> </resultMap>
#if($table.sub)
<resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
<collection property="${subclassName}List" notNullColumn="${subTable.pkColumn.columnName}" javaType="java.util.List" resultMap="${subClassName}Result" />
</resultMap>
<resultMap type="${subClassName}" id="${subClassName}Result">
#foreach ($column in $subTable.columns)
<result property="${column.javaField}" column="${column.columnName}" />
#end
</resultMap>
#end
<sql id="select${ClassName}Vo"> <sql id="select${ClassName}Vo">
select#foreach($column in $columns) $column.columnName#if($velocityCount != $columns.size()),#end#end from ${tableName} select#foreach($column in $columns) $column.columnName#if($velocityCount != $columns.size()),#end#end from ${tableName}
@ -46,9 +58,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where> </where>
</select> </select>
<select id="select${ClassName}ById" parameterType="${pkColumn.javaType}" resultMap="${ClassName}Result"> <select id="select${ClassName}ById" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
#if($table.crud || $table.tree)
<include refid="select${ClassName}Vo"/> <include refid="select${ClassName}Vo"/>
where ${pkColumn.columnName} = #{${pkColumn.javaField}} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
#elseif($table.sub)
select#foreach($column in $columns) a.$column.columnName#if($velocityCount != $columns.size()),#end#end,
#foreach($column in $subTable.columns) b.$column.columnName#if($velocityCount != $subTable.columns.size()),#end#end
from ${tableName} a
left join ${subTableName} b on b.${subTableFkName} = a.${pkColumn.columnName}
where a.${pkColumn.columnName} = #{${pkColumn.javaField}}
#end
</select> </select>
<insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end> <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end>
@ -91,5 +112,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
#{${pkColumn.javaField}} #{${pkColumn.javaField}}
</foreach> </foreach>
</delete> </delete>
#if($table.sub)
<delete id="delete${subClassName}By${subTableFkClassName}s" parameterType="String">
delete from ${subTableName} where ${subTableFkName} in
<foreach item="${subTableFkclassName}" collection="array" open="(" separator="," close=")">
#{${subTableFkclassName}}
</foreach>
</delete>
<delete id="delete${subClassName}By${subTableFkClassName}" parameterType="Long">
delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
</delete>
<insert id="batch${subClassName}">
insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($velocityCount != $subTable.columns.size()),#end#end) values
<foreach item="item" index="index" collection="list" separator=",">
(#foreach($column in $subTable.columns) #{item.$column.javaField}#if($velocityCount != $subTable.columns.size()),#end#end)
</foreach>
</insert>
#end
</mapper> </mapper>

View File

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

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.2.1</version> <version>3.4.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

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

@ -364,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;
} }
@ -379,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获取所有子节点
* *

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

@ -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

@ -131,7 +131,7 @@
<if test="parentId != null">parent_id = #{parentId},</if> <if test="parentId != null">parent_id = #{parentId},</if>
<if test="orderNum != null and orderNum != ''">order_num = #{orderNum},</if> <if test="orderNum != null and orderNum != ''">order_num = #{orderNum},</if>
<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">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="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>

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

@ -42,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}

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,11 +68,11 @@ 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) ))
@ -141,8 +141,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="deptId != null and deptId != 0">dept_id = #{deptId},</if> <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
<if test="userName != null and userName != ''">user_name = #{userName},</if> <if test="userName != null and userName != ''">user_name = #{userName},</if>
<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if> <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
<if test="email != null and email != ''">email = #{email},</if> <if test="email != null ">email = #{email},</if>
<if test="phonenumber != null and phonenumber != ''">phonenumber = #{phonenumber},</if> <if test="phonenumber != null ">phonenumber = #{phonenumber},</if>
<if test="sex != null and sex != ''">sex = #{sex},</if> <if test="sex != null and sex != ''">sex = #{sex},</if>
<if test="avatar != null and avatar != ''">avatar = #{avatar},</if> <if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
<if test="password != null and password != ''">password = #{password},</if> <if test="password != null and password != ''">password = #{password},</if>

View File

@ -1,6 +1,6 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "3.2.1", "version": "3.4.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,44 @@
}, },
"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.15.0",
"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": "9.18.5",
"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",
"screenfull": "4.2.0",
"sortablejs": "1.8.4",
"vue": "2.6.10",
"vue-count-to": "1.0.13",
"quill": "1.3.7", "quill": "1.3.7",
"vue-cropper": "0.4.9", "screenfull": "5.0.2",
"vue-router": "3.0.2", "sortablejs": "1.10.2",
"vue-splitpane": "1.0.4", "vue": "2.6.12",
"vuedraggable": "2.20.0", "vue-count-to": "1.0.13",
"vuex": "3.1.0" "vue-cropper": "0.5.5",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.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", "runjs": "4.4.2",
"lint-staged": "8.1.5", "sass": "1.32.0",
"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",
"node-sass": "4.14.1", "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

@ -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

@ -220,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;

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 {
@ -73,17 +76,25 @@
.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 {
@ -190,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

@ -10,8 +10,6 @@
</template> </template>
<script> <script>
import pathToRegexp from 'path-to-regexp'
export default { export default {
data() { data() {
return { return {
@ -49,18 +47,13 @@ export default {
} }
return name.trim() === '首页' return name.trim() === '首页'
}, },
pathCompile(path) {
const { params } = this.$route
var toPath = pathToRegexp.compile(path)
return toPath(params)
},
handleLink(item) { handleLink(item) {
const { redirect, path } = item const { redirect, path } = item
if (redirect) { if (redirect) {
this.$router.push(redirect) this.$router.push(redirect)
return return
} }
this.$router.push(this.pathCompile(path)) this.$router.push(path)
} }
} }
} }

View File

@ -0,0 +1,179 @@
<template>
<div class="upload-file">
<el-upload
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:limit="1"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:headers="headers"
class="upload-file-uploader"
ref="upload"
>
<!-- 上传按钮 -->
<el-button size="mini" type="primary">选取文件</el-button>
<!-- 上传提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
的文件
</div>
</el-upload>
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in list">
<el-link :href="file.url" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
<div class="ele-upload-list__item-content-action">
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
</div>
</li>
</transition-group>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
export default {
props: {
// 值
value: [String, Object, Array],
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
}
},
data() {
return {
uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
fileList: [],
};
},
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
// 列表
list() {
let temp = 1;
if (this.value) {
// 首先将值转为数组
const list = Array.isArray(this.value) ? this.value : [this.value];
// 然后将数组转为对象数组
return list.map((item) => {
if (typeof item === "string") {
item = { name: item, url: item };
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
this.fileList = [];
return [];
}
},
},
methods: {
// 上传前校检格式和大小
handleBeforeUpload(file) {
// 校检文件类型
if (this.fileType) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
const isTypeOk = this.fileType.some((type) => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
if (!isTypeOk) {
this.$message.error(`文件格式不正确, 请上传${this.fileType.join("/")}格式文件!`);
return false;
}
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
if (!isLt) {
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
return false;
}
}
return true;
},
// 文件个数超出
handleExceed() {
this.$message.error(`只允许上传单个文件`);
},
// 上传失败
handleUploadError(err) {
this.$message.error("上传失败, 请重试");
},
// 上传成功回调
handleUploadSuccess(res, file) {
this.$message.success("上传成功");
this.$emit("input", res.url);
},
// 删除文件
handleDelete(index) {
this.fileList.splice(index, 1);
this.$emit("input", '');
},
// 获取文件名称
getFileName(name) {
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
} else {
return "";
}
}
},
created() {
this.fileList = this.list;
},
};
</script>
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
}
</style>

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>
@ -20,7 +20,7 @@
<script> <script>
// fuse is a lightweight fuzzy-search module // fuse is a lightweight fuzzy-search module
// make search results more in line with expectations // make search results more in line with expectations
import Fuse from 'fuse.js' import Fuse from 'fuse.js/dist/fuse.min.js'
import path from 'path' import path from 'path'
export default { export default {
@ -167,7 +167,7 @@ export default {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
/deep/ .el-input__inner { ::v-deep .el-input__inner {
border-radius: 0; border-radius: 0;
border: 0; border: 0;
padding-left: 0; padding-left: 0;

View File

@ -11,9 +11,28 @@
:headers="headers" :headers="headers"
style="display: inline-block; vertical-align: top" style="display: inline-block; vertical-align: top"
> >
<img v-if="value" :src="value" class="avatar" /> <el-image v-if="!value" :src="value">
<i v-else class="el-icon-plus avatar-uploader-icon"></i> <div slot="error" class="image-slot">
<i class="el-icon-plus" />
</div>
</el-image>
<div v-else class="image">
<el-image :src="value" :style="`width:150px;height:150px;`" fit="fill"/>
<div class="mask">
<div class="actions">
<span title="预览" @click.stop="dialogVisible = true">
<i class="el-icon-zoom-in" />
</span>
<span title="移除" @click.stop="removeImage">
<i class="el-icon-delete" />
</span>
</div>
</div>
</div>
</el-upload> </el-upload>
<el-dialog :visible.sync="dialogVisible" title="预览" width="800" append-to-body>
<img :src="value" style="display: block; max-width: 100%; margin: 0 auto;">
</el-dialog>
</div> </div>
</template> </template>
@ -21,9 +40,9 @@
import { getToken } from "@/utils/auth"; import { getToken } from "@/utils/auth";
export default { export default {
components: {},
data() { data() {
return { return {
dialogVisible: false,
uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", //
headers: { headers: {
Authorization: "Bearer " + getToken(), Authorization: "Bearer " + getToken(),
@ -37,6 +56,9 @@ export default {
}, },
}, },
methods: { methods: {
removeImage() {
this.$emit("input", "");
},
handleUploadSuccess(res) { handleUploadSuccess(res) {
this.$emit("input", res.url); this.$emit("input", res.url);
this.loading.close(); this.loading.close();
@ -61,8 +83,18 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.avatar { .image {
width: 100%; position: relative;
height: 100%; .mask {
opacity: 0;
position: absolute;
top: 0;
width: 100%;
background-color: rgba(0, 0, 0, 0.5);
transition: all 0.3s;
}
&:hover .mask {
opacity: 1;
}
} }
</style> </style>

View File

@ -1,4 +1,3 @@
<!-- @author Shiyn/ huangmx 20200807优化-->
<template> <template>
<div class="top-right-btn"> <div class="top-right-btn">
<el-row> <el-row>
@ -8,31 +7,74 @@
<el-tooltip class="item" effect="dark" content="刷新" placement="top"> <el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" /> <el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
</el-tooltip> </el-tooltip>
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
<el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" />
</el-tooltip>
</el-row> </el-row>
<el-dialog :title="title" :visible.sync="open" append-to-body>
<el-transfer
:titles="['显示', '隐藏']"
v-model="value"
:data="columns"
@change="dataChange"
></el-transfer>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: "RightToolbar", name: "RightToolbar",
data() { data() {
return {}; return {
// 显隐数据
value: [],
// 弹出层标题
title: "显示/隐藏",
// 是否显示弹出层
open: false,
};
}, },
props: { props: {
showSearch: { showSearch: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
columns: {
type: Array,
},
}, },
methods: { methods: {
//搜索 // 搜索
toggleSearch() { toggleSearch() {
this.$emit("update:showSearch", !this.showSearch); this.$emit("update:showSearch", !this.showSearch);
}, },
//刷新 // 刷新
refresh() { refresh() {
this.$emit("queryTable"); this.$emit("queryTable");
}, },
// 右侧列表元素变化
dataChange(data) {
for (var item in this.columns) {
const key = this.columns[item].key;
this.columns[item].visible = !data.includes(key);
}
},
// 打开显隐列dialog
showColumn() {
this.open = true;
},
}, },
}; };
</script> </script>
<style lang="scss" scoped>
::v-deep .el-transfer__button {
border-radius: 50%;
padding: 12px;
display: block;
margin-left: 0px;
}
::v-deep .el-transfer__button:first-child {
margin-bottom: 10px;
}
</style>

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

@ -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,19 +1,19 @@
<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"
mode="vertical" mode="vertical"
> >
<sidebar-item <sidebar-item
v-for="(route, index) in permission_routes" v-for="(route, index) in sidebarRouters"
:key="route.path + index" :key="route.path + index"
:item="route" :item="route"
:base-path="route.path" :base-path="route.path"
@ -33,7 +33,7 @@ export default {
components: { SidebarItem, Logo }, components: { SidebarItem, Logo },
computed: { computed: {
...mapState(["settings"]), ...mapState(["settings"]),
...mapGetters(["permission_routes", "sidebar"]), ...mapGetters(["sidebarRouters", "sidebar"]),
activeMenu() { activeMenu() {
const route = this.$route; const route = this.$route;
const { meta, path } = route; const { meta, path } = route;

View File

@ -82,7 +82,7 @@ export default {
position: relative; position: relative;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
/deep/ { ::v-deep {
.el-scrollbar__bar { .el-scrollbar__bar {
bottom: 0px; bottom: 0px;
} }

View File

@ -153,7 +153,7 @@ export default {
}) })
}, },
closeOthersTags() { closeOthersTags() {
this.$router.push(this.selectedTag) this.$router.push(this.selectedTag).catch(()=>{});
this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => { this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
this.moveToCurrentTag() this.moveToCurrentTag()
}) })

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,7 +18,7 @@ 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"
// 全局方法挂载 // 全局方法挂载

View File

@ -23,28 +23,18 @@ router.beforeEach((to, from, next) => {
// 拉取user_info // 拉取user_info
const roles = res.roles const roles = res.roles
store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => { store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
// 测试 默认静态页面
// store.dispatch('permission/generateRoutes', { roles }).then(accessRoutes => {
// 根据roles权限生成可访问的路由表 // 根据roles权限生成可访问的路由表
router.addRoutes(accessRoutes) // 动态添加可访问路由表 router.addRoutes(accessRoutes) // 动态添加可访问路由表
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
}) })
}) }).catch(err => {
.catch(err => { store.dispatch('LogOut').then(() => {
store.dispatch('FedLogOut').then(() => {
Message.error(err) Message.error(err)
next({ path: '/' }) next({ path: '/' })
}) })
}) })
} else { } else {
next() next()
// 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
// if (hasPermission(store.getters.roles, to.meta.roles)) {
// next()
// } else {
// next({ path: '/401', replace: true, query: { noGoBack: true }})
// }
// 可删 ↑
} }
} }
} else { } else {

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: 路由配置项

View File

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

View File

@ -10,6 +10,7 @@ const getters = {
introduction: state => state.user.introduction, introduction: state => state.user.introduction,
roles: state => state.user.roles, roles: state => state.user.roles,
permissions: state => state.user.permissions, permissions: state => state.user.permissions,
permission_routes: state => state.permission.routes permission_routes: state => state.permission.routes,
sidebarRouters:state => state.permission.sidebarRouters,
} }
export default getters export default getters

View File

@ -1,17 +1,22 @@
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: {
routes: [], routes: [],
addRoutes: [] addRoutes: [],
sidebarRouters: []
}, },
mutations: { mutations: {
SET_ROUTES: (state, routes) => { SET_ROUTES: (state, routes) => {
state.addRoutes = routes state.addRoutes = routes
state.routes = constantRoutes.concat(routes) state.routes = constantRoutes.concat(routes)
} },
SET_SIDEBAR_ROUTERS: (state, routers) => {
state.sidebarRouters = constantRoutes.concat(routers)
},
}, },
actions: { actions: {
// 生成路由 // 生成路由
@ -19,10 +24,14 @@ const permission = {
return new Promise(resolve => { return new Promise(resolve => {
// 向后端请求路由数据 // 向后端请求路由数据
getRouters().then(res => { getRouters().then(res => {
const accessedRoutes = filterAsyncRouter(res.data) const sdata = JSON.parse(JSON.stringify(res.data))
accessedRoutes.push({ path: '*', redirect: '/404', hidden: true }) const rdata = JSON.parse(JSON.stringify(res.data))
commit('SET_ROUTES', accessedRoutes) const sidebarRoutes = filterAsyncRouter(sdata)
resolve(accessedRoutes) const rewriteRoutes = filterAsyncRouter(rdata, false, true)
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
commit('SET_ROUTES', rewriteRoutes)
commit('SET_SIDEBAR_ROUTERS', sidebarRoutes)
resolve(rewriteRoutes)
}) })
}) })
} }
@ -30,25 +39,57 @@ const permission = {
} }
// 遍历后台传来的路由字符串,转换为组件对象 // 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap) { function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
return asyncRouterMap.filter(route => { return asyncRouterMap.filter(route => {
if (type && route.children) {
route.children = filterChildren(route.children)
}
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)
} }
} }
if (route.children != null && route.children && route.children.length) { if (route.children != null && route.children && route.children.length) {
route.children = filterAsyncRouter(route.children) route.children = filterAsyncRouter(route.children, route, type)
} else {
delete route['children']
delete route['redirect']
} }
return true return true
}) })
} }
function filterChildren(childrenMap, lastRouter = false) {
var children = []
childrenMap.forEach((el, index) => {
if (el.children && el.children.length) {
if (el.component === 'ParentView') {
el.children.forEach(c => {
c.path = el.path + '/' + c.path
if (c.children && c.children.length) {
children = children.concat(filterChildren(c.children, c))
return
}
children.push(c)
})
return
}
}
if (lastRouter) {
el.path = lastRouter.path + '/' + el.path
}
children = children.concat(el)
})
return children
}
export const loadView = (view) => { // 路由懒加载 export const loadView = (view) => { // 路由懒加载
return (resolve) => require([`@/views/${view}`], resolve) return (resolve) => require([`@/views/${view}`], resolve)
} }
export default permission export default permission

View File

@ -1,10 +1,11 @@
import variables from '@/assets/styles/element-variables.scss' import variables from '@/assets/styles/element-variables.scss'
import defaultSettings from '@/settings' import defaultSettings from '@/settings'
const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings const { sideTheme, showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
const state = { const state = {
theme: variables.theme, theme: variables.theme,
sideTheme: sideTheme,
showSettings: showSettings, showSettings: showSettings,
tagsView: tagsView, tagsView: tagsView,
fixedHeader: fixedHeader, fixedHeader: fixedHeader,

View File

@ -51,7 +51,7 @@ const user = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
getInfo(state.token).then(res => { getInfo(state.token).then(res => {
const user = res.user const user = res.user
const avatar = user.avatar == "" ? require("@/assets/image/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar; const avatar = user.avatar == "" ? require("@/assets/images/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组 if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
commit('SET_ROLES', res.roles) commit('SET_ROLES', res.roles)
commit('SET_PERMISSIONS', res.permissions) commit('SET_PERMISSIONS', res.permissions)

View File

@ -1,4 +1,4 @@
import JSEncrypt from 'jsencrypt/bin/jsencrypt' import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
// 密钥对生成 http://web.chacuo.net/netrsakeypair // 密钥对生成 http://web.chacuo.net/netrsakeypair

View File

@ -9,9 +9,10 @@ export function checkPermi(value) {
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const permissions = store.getters && store.getters.permissions const permissions = store.getters && store.getters.permissions
const permissionDatas = value const permissionDatas = value
const all_permission = "*:*:*";
const hasPermission = permissions.some(permission => { const hasPermission = permissions.some(permission => {
return permissionDatas.includes(permission) return all_permission === permission || permissionDatas.includes(permission)
}) })
if (!hasPermission) { if (!hasPermission) {
@ -33,9 +34,10 @@ export function checkRole(value) {
if (value && value instanceof Array && value.length > 0) { if (value && value instanceof Array && value.length > 0) {
const roles = store.getters && store.getters.roles const roles = store.getters && store.getters.roles
const permissionRoles = value const permissionRoles = value
const super_admin = "admin";
const hasRole = roles.some(role => { const hasRole = roles.some(role => {
return permissionRoles.includes(role) return super_admin === role || permissionRoles.includes(role)
}) })
if (!hasRole) { if (!hasRole) {

View File

@ -19,6 +19,28 @@ service.interceptors.request.use(config => {
if (getToken() && !isToken) { if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
} }
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?';
for (const propName of Object.keys(config.params)) {
const value = config.params[propName];
var part = encodeURIComponent(propName) + "=";
if (value !== null && typeof(value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
let params = propName + '[' + key + ']';
var subPart = encodeURIComponent(params) + "=";
url += subPart + encodeURIComponent(value[key]) + "&";
}
} else {
url += part + encodeURIComponent(value) + "&";
}
}
}
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
return config return config
}, error => { }, error => {
console.log(error) console.log(error)

View File

@ -54,13 +54,17 @@ export function resetForm(refName) {
} }
// 添加日期范围 // 添加日期范围
export function addDateRange(params, dateRange) { export function addDateRange(params, dateRange, propName) {
var search = params; var search = params;
search.beginTime = ""; search.params = {};
search.endTime = "";
if (null != dateRange && '' != dateRange) { if (null != dateRange && '' != dateRange) {
search.beginTime = dateRange[0]; if (typeof(propName) === "undefined") {
search.endTime = dateRange[1]; search.params["beginTime"] = dateRange[0];
search.params["endTime"] = dateRange[1];
} else {
search.params["begin" + propName] = dateRange[0];
search.params["end" + propName] = dateRange[1];
}
} }
return search; return search;
} }

View File

@ -146,6 +146,96 @@
<span>更新日志</span> <span>更新日志</span>
</div> </div>
<el-collapse accordion> <el-collapse accordion>
<el-collapse-item title="v3.4.0 - 2021-02-22">
<ol>
<li>代码生成模板支持主子表</li>
<li>表格右侧工具栏组件支持显隐列</li>
<li>图片组件添加预览&移除功能</li>
<li>Excel注解支持Image图片导出</li>
<li>操作按钮组调整为朴素按钮样式</li>
<li>代码生成支持文件上传组件</li>
<li>代码生成日期控件区分范围</li>
<li>代码生成数据库文本类型生成表单文本域</li>
<li>用户手机邮箱&菜单组件修改允许空字符串</li>
<li>升级SpringBoot到最新版本2.2.13 提升启动速度</li>
<li>升级druid到最新版本v1.2.4</li>
<li>升级fastjson到最新版1.2.75</li>
<li>升级element-ui到最新版本2.15.0</li>
<li>修复IE11浏览器报错问题</li>
<li>优化多级菜单之间切换无法缓存的问题</li>
<li>修复四级菜单无法显示问题</li>
<li>修正侧边栏静态路由丢失问题</li>
<li>修复角色管理-编辑角色-功能权限显示异常</li>
<li>配置文件新增redis数据库索引属性</li>
<li>权限工具类增加admin判断</li>
<li>角色非自定义权限范围清空选择值</li>
<li>修复导入数据为负浮点数时丢失精度问题</li>
<li>移除path-to-regexp正则匹配插件</li>
<li>修复生成树表代码异常</li>
<li>修改ip字段长度防止ipv6地址长度不够</li>
<li>防止get请求参数值为false或0等特殊值会导致无法正确的传参</li>
<li>登录后push添加catch防止出现检查错误</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.3.0 - 2020-12-14">
<ol>
<li>新增缓存监控功能</li>
<li>支持主题风格配置</li>
<li>修复多级菜单之间切换无法缓存的问题</li>
<li>多级菜单自动配置组件</li>
<li>代码生成预览支持高亮显示</li>
<li>支持Get请求映射Params参数</li>
<li>删除用户和角色解绑关联</li>
<li>去除用户手机邮箱部门必填验证</li>
<li>Excel支持注解align对齐方式</li>
<li>Excel支持导入Boolean型数据</li>
<li>优化头像样式鼠标移入悬停遮罩</li>
<li>代码生成预览提供滚动机制</li>
<li>代码生成删除多余的数字float类型</li>
<li>修正转换字符串的目标字符集属性</li>
<li>回显数据字典防止空值报错</li>
<li>日志记录增加过滤多文件场景</li>
<li>修改缓存Set方法可能导致嵌套的问题</li>
<li>移除前端一些多余的依赖</li>
<li>防止安全扫描YUI出现的风险提示</li>
<li>修改node-sass为dart-sass</li>
<li>升级SpringBoot到最新版本2.1.18</li>
<li>升级poi到最新版本4.1.2</li>
<li>升级oshi到最新版本v5.3.6</li>
<li>升级bitwalker到最新版本1.21</li>
<li>升级axios到最新版本0.21.0</li>
<li>升级element-ui到最新版本2.14.1</li>
<li>升级vue到最新版本2.6.12</li>
<li>升级vuex到最新版本3.6.0</li>
<li>升级vue-cli到版本4.5.9</li>
<li>升级vue-router到最新版本3.4.9</li>
<li>升级vue-cli到最新版本4.4.6</li>
<li>升级vue-cropper到最新版本0.5.5</li>
<li>升级clipboard到最新版本2.0.6</li>
<li>升级core-js到最新版本3.8.1</li>
<li>升级echarts到最新版本4.9.0</li>
<li>升级file-saver到最新版本2.0.4</li>
<li>升级fuse.js到最新版本6.4.3</li>
<li>升级js-beautify到最新版本1.13.0</li>
<li>升级js-cookie到最新版本2.2.1</li>
<li>升级path-to-regexp到最新版本6.2.0</li>
<li>升级quill到最新版本1.3.7</li>
<li>升级screenfull到最新版本5.0.2</li>
<li>升级sortablejs到最新版本1.10.2</li>
<li>升级vuedraggable到最新版本2.24.3</li>
<li>升级chalk到最新版本4.1.0</li>
<li>升级eslint到最新版本7.15.0</li>
<li>升级eslint-plugin-vue到最新版本7.2.0</li>
<li>升级lint-staged到最新版本10.5.3</li>
<li>升级runjs到最新版本4.4.2</li>
<li>升级sass-loader到最新版本10.1.0</li>
<li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
<li>升级svg-sprite-loader到最新版本5.1.1</li>
<li>升级vue-template-compiler到最新版本2.6.12</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.2.1 - 2020-11-18"> <el-collapse-item title="v3.2.1 - 2020-11-18">
<ol> <ol>
<li>阻止任意文件下载漏洞</li> <li>阻止任意文件下载漏洞</li>
@ -435,7 +525,7 @@ export default {
data() { data() {
return { return {
// 版本号 // 版本号
version: "3.2.1", version: "3.4.0",
}; };
}, },
methods: { methods: {

View File

@ -48,7 +48,7 @@
</el-form> </el-form>
<!-- 底部 --> <!-- 底部 -->
<div class="el-login-footer"> <div class="el-login-footer">
<span>Copyright © 2018-2020 ruoyi.vip All Rights Reserved.</span> <span>Copyright © 2018-2021 ruoyi.vip All Rights Reserved.</span>
</div> </div>
</div> </div>
</template> </template>
@ -126,15 +126,12 @@ export default {
Cookies.remove("password"); Cookies.remove("password");
Cookies.remove('rememberMe'); Cookies.remove('rememberMe');
} }
this.$store this.$store.dispatch("Login", this.loginForm).then(() => {
.dispatch("Login", this.loginForm) this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
.then(() => { }).catch(() => {
this.$router.push({ path: this.redirect || "/" }); this.loading = false;
}) this.getCode();
.catch(() => { });
this.loading = false;
this.getCode();
});
} }
}); });
} }
@ -148,7 +145,7 @@ export default {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
height: 100%; height: 100%;
background-image: url("../assets/image/login-background.jpg"); background-image: url("../assets/images/login-background.jpg");
background-size: cover; background-size: cover;
} }
.title { .title {

View File

@ -0,0 +1,153 @@
<template>
<div class="app-container">
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<div slot="header"><span>基本信息</span></div>
<div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%">
<tbody>
<tr>
<td><div class="cell">Redis版本</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
<td><div class="cell">运行模式</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
<td><div class="cell">端口</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
<td><div class="cell">客户端数</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
</tr>
<tr>
<td><div class="cell">运行时间()</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
<td><div class="cell">使用内存</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
<td><div class="cell">使用CPU</div></td>
<td><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
<td><div class="cell">内存配置</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
</tr>
<tr>
<td><div class="cell">AOF是否开启</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
<td><div class="cell">RDB是否成功</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
<td><div class="cell">Key数量</div></td>
<td><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
<td><div class="cell">网络入口/出口</div></td>
<td><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
</tr>
</tbody>
</table>
</div>
</el-card>
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<div slot="header"><span>命令统计</span></div>
<div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="commandstats" style="height: 420px" />
</div>
</el-card>
</el-col>
<el-col :span="12" class="card-box">
<el-card>
<div slot="header">
<span>内存信息</span>
</div>
<div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="usedmemory" style="height: 420px" />
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
import { getCache } from "@/api/monitor/cache";
import echarts from "echarts";
export default {
name: "Server",
data() {
return {
// 加载层信息
loading: [],
// 统计命令信息
commandstats: null,
// 使用内存
usedmemory: null,
// cache信息
cache: [],
};
},
created() {
this.getList();
this.openLoading();
},
methods: {
/** 查缓存询信息 */
getList() {
getCache().then((response) => {
this.cache = response.data;
this.loading.close();
this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
this.commandstats.setOption({
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)",
},
series: [
{
name: "命令",
type: "pie",
roseType: "radius",
radius: [15, 95],
center: ["50%", "38%"],
data: response.data.commandStats,
animationEasing: "cubicInOut",
animationDuration: 1000,
},
],
});
this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons");
this.usedmemory.setOption({
tooltip: {
formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human,
},
series: [
{
name: "峰值",
type: "gauge",
min: 0,
max: 1000,
detail: {
formatter: this.cache.info.used_memory_human,
},
data: [
{
value: parseFloat(this.cache.info.used_memory_human),
name: "内存消耗",
},
],
},
],
});
});
},
// 打开加载层
openLoading() {
this.loading = this.$loading({
lock: true,
text: "拼命读取中",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.7)",
});
},
},
};
</script>

View File

@ -31,7 +31,7 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -40,6 +40,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="primary" type="primary"
plain
icon="el-icon-plus" icon="el-icon-plus"
size="mini" size="mini"
@click="handleAdd" @click="handleAdd"
@ -49,6 +50,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="success" type="success"
plain
icon="el-icon-edit" icon="el-icon-edit"
size="mini" size="mini"
:disabled="single" :disabled="single"
@ -59,6 +61,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="danger" type="danger"
plain
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
:disabled="multiple" :disabled="multiple"
@ -69,6 +72,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="warning" type="warning"
plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
@click="handleExport" @click="handleExport"
@ -78,6 +82,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="info" type="info"
plain
icon="el-icon-s-operation" icon="el-icon-s-operation"
size="mini" size="mini"
@click="handleJobLog" @click="handleJobLog"

View File

@ -56,7 +56,7 @@
></el-date-picker> ></el-date-picker>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -65,6 +65,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="danger" type="danger"
plain
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
:disabled="multiple" :disabled="multiple"
@ -75,6 +76,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="danger" type="danger"
plain
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
@click="handleClean" @click="handleClean"
@ -84,6 +86,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="warning" type="warning"
plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
@click="handleExport" @click="handleExport"

View File

@ -50,7 +50,7 @@
></el-date-picker> ></el-date-picker>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@ -59,6 +59,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="danger" type="danger"
plain
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
:disabled="multiple" :disabled="multiple"
@ -69,6 +70,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="danger" type="danger"
plain
icon="el-icon-delete" icon="el-icon-delete"
size="mini" size="mini"
@click="handleClean" @click="handleClean"
@ -78,6 +80,7 @@
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
type="warning" type="warning"
plain
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
@click="handleExport" @click="handleExport"

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