43 Commits

Author SHA1 Message Date
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
76 changed files with 991 additions and 251 deletions

14
pom.xml
View File

@ -6,29 +6,29 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.2.1</version>
<version>3.3.0</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依管理系统</description>
<properties>
<ruoyi.version>3.2.1</ruoyi.version>
<ruoyi.version>3.3.0</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<druid.version>1.2.2</druid.version>
<bitwalker.version>1.19</bitwalker.version>
<bitwalker.version>1.21</bitwalker.version>
<swagger.version>2.9.2</swagger.version>
<kaptcha.version>2.3.2</kaptcha.version>
<pagehelper.boot.version>1.3.0</pagehelper.boot.version>
<fastjson.version>1.2.74</fastjson.version>
<oshi.version>5.2.5</oshi.version>
<jna.version>5.5.0</jna.version>
<oshi.version>5.3.6</oshi.version>
<jna.version>5.6.0</jna.version>
<commons.io.version>2.5</commons.io.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>
<jwt.version>0.9.1</jwt.version>
</properties>
@ -41,7 +41,7 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.17.RELEASE</version>
<version>2.1.18.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.2.1</version>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.framework.web.domain.Server;
@ -15,7 +14,7 @@ import com.ruoyi.framework.web.domain.Server;
*/
@RestController
@RequestMapping("/monitor/server")
public class ServerController extends BaseController
public class ServerController
{
@PreAuthorize("@ss.hasPermi('monitor:server:list')")
@GetMapping()

View File

@ -1,5 +1,6 @@
package com.ruoyi.web.controller.system;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
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.enums.BusinessType;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.service.ISysDictDataService;
import com.ruoyi.system.service.ISysDictTypeService;
@ -73,7 +75,12 @@ public class SysDictDataController extends BaseController
@GetMapping(value = "/type/{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() + "'失败,登录账号已存在");
}
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() + "'失败,手机号码已存在");
}
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() + "'失败,邮箱账号已存在");
}
@ -149,11 +151,13 @@ public class SysUserController extends BaseController
public AjaxResult edit(@Validated @RequestBody SysUser 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() + "'失败,手机号码已存在");
}
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() + "'失败,邮箱账号已存在");
}

View File

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

View File

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

View File

@ -105,6 +105,27 @@ public @interface Excel
*/
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仅导入
*/

View File

@ -37,7 +37,7 @@ public class GenConstants
/** 数据库数字类型 */
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" };

View File

@ -54,6 +54,9 @@ public class UserConstants
/** 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 NOT_UNIQUE = "1";

View File

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

View File

@ -1,11 +1,13 @@
package com.ruoyi.common.core.redis;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
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.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@ -136,10 +138,15 @@ public class RedisCache
* @param dataSet 缓存的数据
* @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);
return count == null ? 0 : count;
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
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)
{
srcCharset = StandardCharsets.UTF_8;
destCharset = StandardCharsets.UTF_8;
}
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))

View File

@ -18,7 +18,6 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
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.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
@ -274,6 +273,10 @@ public class ExcelUtil<T>
val = DateUtil.getJavaDate((Double) val);
}
}
else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
{
val = Convert.toBool(val, false);
}
if (StringUtils.isNotNull(fieldType))
{
Excel attr = field.getAnnotation(Excel.class);
@ -469,6 +472,21 @@ public class ExcelUtil<T>
style.setFont(totalFont);
styles.put("total", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.LEFT);
styles.put("data1", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.CENTER);
styles.put("data2", style);
style = wb.createCellStyle();
style.cloneStyleFrom(styles.get("data"));
style.setAlignment(HorizontalAlignment.RIGHT);
styles.put("data3", style);
return styles;
}
@ -497,12 +515,10 @@ public class ExcelUtil<T>
{
if (ColumnType.STRING == attr.cellType())
{
cell.setCellType(CellType.STRING);
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
}
else if (ColumnType.NUMERIC == attr.cellType())
{
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
}
}
@ -551,7 +567,8 @@ public class ExcelUtil<T>
{
// 创建cell
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);
@ -860,7 +877,7 @@ public class ExcelUtil<T>
*/
private Object getValue(Object o, String name) throws Exception
{
if (StringUtils.isNotEmpty(name))
if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name))
{
Class<?> clazz = o.getClass();
Field field = clazz.getDeclaredField(name);
@ -960,10 +977,10 @@ public class ExcelUtil<T>
Cell cell = row.getCell(column);
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();
if (HSSFDateUtil.isCellDateFormatted(cell))
if (DateUtil.isCellDateFormatted(cell))
{
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
}
@ -979,15 +996,15 @@ public class ExcelUtil<T>
}
}
}
else if (cell.getCellTypeEnum() == CellType.STRING)
else if (cell.getCellType() == CellType.STRING)
{
val = cell.getStringCellValue();
}
else if (cell.getCellTypeEnum() == CellType.BOOLEAN)
else if (cell.getCellType() == CellType.BOOLEAN)
{
val = cell.getBooleanCellValue();
}
else if (cell.getCellTypeEnum() == CellType.ERROR)
else if (cell.getCellType() == CellType.ERROR)
{
val = cell.getErrorCellValue();
}

View File

@ -204,6 +204,10 @@ public class ReflectUtils
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);

View File

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

View File

@ -1,6 +1,8 @@
package com.ruoyi.framework.aspectj;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -210,8 +212,31 @@ public class LogAspect
* @param o 对象信息。
* @return 如果是需要过滤的对象则返回true否则返回false。
*/
@SuppressWarnings("rawtypes")
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;
}
}

View File

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

View File

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

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.2.1</version>
<version>3.3.0</version>
</parent>
<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 != ''">
AND invoke_target like concat('%', #{invokeTarget}, '%')
</if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
</where>
</select>

View File

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

View File

@ -26,6 +26,14 @@ public interface SysRoleMenuMapper
*/
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();
}
else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu))
{
component = UserConstants.PARENT_VIEW;
}
return component;
}
@ -379,6 +383,17 @@ public class SysMenuServiceImpl implements ISysMenuService
&& 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获取所有子节点
*

View File

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

View File

@ -363,6 +363,7 @@ public class SysUserServiceImpl implements ISysUserService
* @return 结果
*/
@Override
@Transactional
public int deleteUserById(Long userId)
{
// 删除用户与角色关联
@ -379,12 +380,17 @@ public class SysUserServiceImpl implements ISysUserService
* @return 结果
*/
@Override
@Transactional
public int deleteUserByIds(Long[] userIds)
{
for (Long userId : userIds)
{
checkUserAllowed(new SysUser(userId));
}
// 删除用户与角色关联
userRoleMapper.deleteUserRole(userIds);
// 删除用户与岗位关联
userPostMapper.deleteUserPost(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 != ''">
AND config_key like concat('%', #{configKey}, '%')
</if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
</where>
</select>

View File

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

View File

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

View File

@ -54,11 +54,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="operName != null and operName != ''">
AND oper_name like concat('%', #{operName}, '%')
</if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
and date_format(oper_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(oper_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
and date_format(oper_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(oper_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
</where>
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 != ''">
AND r.role_key like concat('%', #{roleKey}, '%')
</if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
<!-- 数据范围过滤 -->
${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>
<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 into sys_role_menu(role_id, menu_id) values
<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 != ''">
AND u.phonenumber like concat('%', #{phonenumber}, '%')
</if>
<if test="beginTime != null and beginTime != ''"><!-- 开始时间检索 -->
AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{beginTime},'%y%m%d')
<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
</if>
<if test="endTime != null and endTime != ''"><!-- 结束时间检索 -->
AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{endTime},'%y%m%d')
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
<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) ))

View File

@ -1,6 +1,6 @@
{
"name": "ruoyi",
"version": "3.2.1",
"version": "3.3.0",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
@ -9,11 +9,7 @@
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"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"
"lint": "eslint --ext .js,.vue src"
},
"husky": {
"hooks": {
@ -41,59 +37,45 @@
},
"dependencies": {
"@riophae/vue-treeselect": "0.4.0",
"axios": "0.18.1",
"clipboard": "2.0.4",
"core-js": "3.6.5",
"echarts": "4.2.1",
"element-ui": "2.13.2",
"file-saver": "2.0.1",
"js-beautify": "1.10.2",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"axios": "0.21.0",
"clipboard": "2.0.6",
"core-js": "3.8.1",
"echarts": "4.9.0",
"element-ui": "2.14.1",
"file-saver": "2.0.4",
"fuse.js": "6.4.3",
"highlight.js": "10.4.1",
"js-beautify": "1.13.0",
"js-cookie": "2.2.1",
"jsencrypt": "3.0.0-rc.1",
"normalize.css": "7.0.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",
"path-to-regexp": "6.2.0",
"quill": "1.3.7",
"vue-cropper": "0.4.9",
"vue-router": "3.0.2",
"vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0",
"vuex": "3.1.0"
"screenfull": "5.0.2",
"sortablejs": "1.10.2",
"vue": "2.6.12",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.4",
"@vue/cli-plugin-eslint": "4.4.4",
"@vue/cli-plugin-unit-jest": "4.4.4",
"@vue/cli-service": "4.4.4",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "9.5.1",
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-service": "4.4.6",
"babel-eslint": "10.1.0",
"babel-jest": "23.6.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2",
"chokidar": "2.1.5",
"chalk": "4.1.0",
"connect": "3.6.6",
"eslint": "6.7.2",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0",
"husky": "1.3.1",
"lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3",
"plop": "2.3.0",
"runjs": "4.3.2",
"node-sass": "4.14.1",
"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"
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"sass": "1.30.0",
"runjs": "4.4.2",
"sass-loader": "10.1.0",
"script-ext-html-webpack-plugin": "2.1.5",
"svg-sprite-loader": "5.1.1",
"vue-template-compiler": "2.6.12"
},
"engines": {
"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;
top: 50%;
transform: translate(50%, -50%);
width: 180px;
height: 180px;
width: 200px;
height: 200px;
border-radius: 50%;
box-shadow: 0 0 4px #ccc;
overflow: hidden;

View File

@ -8,6 +8,7 @@
}
.sidebar-container {
-webkit-transition: width .28s;
transition: width 0.28s;
width: $sideBarWidth !important;
background-color: $menuBg;
@ -19,6 +20,8 @@
left: 0;
z-index: 1001;
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
.horizontal-collapse-transition {
@ -73,17 +76,25 @@
.submenu-title-noDropdown,
.el-submenu__title {
&: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;
}
& .nest-menu .el-submenu>.el-submenu__title,
& .el-submenu .el-menu-item {
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;
&:hover {
@ -190,7 +201,7 @@
.el-menu-item {
&:hover {
// 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;
$menuHover:#263445;
$sidebarTitle: #ffffff;
$menuLightBg:#ffffff;
$menuLightHover:#f0f1f5;
$sidebarLightTitle: #001529;
$subMenuBg:#1f2d3d;
$subMenuHover:#001528;
@ -29,7 +34,11 @@ $sideBarWidth: 200px;
subMenuActiveText: $subMenuActiveText;
menuBg: $menuBg;
menuHover: $menuHover;
menuLightBg: $menuLightBg;
menuLightHover: $menuLightHover;
subMenuBg: $subMenuBg;
subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth;
sidebarTitle: $sidebarTitle;
sidebarLightTitle: $sidebarLightTitle
}

View File

@ -12,7 +12,7 @@
class="header-search-select"
@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>
</div>
</template>
@ -167,7 +167,7 @@ export default {
display: inline-block;
vertical-align: middle;
/deep/ .el-input__inner {
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;

View File

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

View File

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

View File

@ -1,13 +1,47 @@
<template>
<div class="drawer-container">
<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">
<span>主题颜色</span>
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
<div class="drawer-item">
<span>主题颜色</span>
<theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
</div>
</div>
<el-divider/>
<h3 class="drawer-title">系统布局配置</h3>
<div class="drawer-item">
<span>开启 Tags-Views</span>
<el-switch v-model="tagsView" class="drawer-switch" />
@ -36,6 +70,12 @@ export default {
return {}
},
computed: {
theme() {
return this.$store.state.settings.theme
},
sideTheme() {
return this.$store.state.settings.sideTheme
},
fixedHeader: {
get() {
return this.$store.state.settings.fixedHeader
@ -76,33 +116,82 @@ export default {
key: 'theme',
value: val
})
},
handleTheme(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'sideTheme',
value: val
})
}
}
}
</script>
<style lang="scss" scoped>
.drawer-container {
padding: 24px;
font-size: 14px;
line-height: 1.5;
word-wrap: break-word;
.setting-drawer-content {
.setting-drawer-title {
margin-bottom: 12px;
color: rgba(0, 0, 0, .85);
font-size: 14px;
line-height: 22px;
font-weight: bold;
}
.drawer-title {
margin-bottom: 12px;
color: rgba(0, 0, 0, .85);
.setting-drawer-block-checbox {
display: flex;
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;
line-height: 22px;
}
line-height: 1.5;
word-wrap: break-word;
.drawer-item {
color: rgba(0, 0, 0, .65);
font-size: 14px;
padding: 12px 0;
}
.drawer-title {
margin-bottom: 12px;
color: rgba(0, 0, 0, .85);
font-size: 14px;
line-height: 22px;
}
.drawer-switch {
float: right
.drawer-item {
color: rgba(0, 0, 0, .65);
font-size: 14px;
padding: 12px 0;
}
.drawer-switch {
float: right
}
}
}
</style>

View File

@ -1,13 +1,13 @@
<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">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<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 v-else key="expand" class="sidebar-logo-link" to="/">
<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>
</transition>
</div>
@ -15,6 +15,7 @@
<script>
import logoImg from '@/assets/logo/logo.png'
import variables from '@/assets/styles/variables.scss'
export default {
name: 'SidebarLogo',
@ -24,6 +25,14 @@ export default {
required: true
}
},
computed: {
variables() {
return variables;
},
sideTheme() {
return this.$store.state.settings.sideTheme
}
},
data() {
return {
title: '若依管理系统',

View File

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

View File

@ -1,12 +1,12 @@
<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" />
<el-scrollbar wrap-class="scrollbar-wrapper">
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
<el-menu
:default-active="activeMenu"
:collapse="isCollapse"
:background-color="variables.menuBg"
:text-color="variables.menuText"
:background-color="settings.sideTheme === 'theme-dark' ? variables.menuBg : variables.menuLightBg"
:text-color="settings.sideTheme === 'theme-dark' ? variables.menuText : 'rgba(0,0,0,.65)'"
:unique-opened="true"
:active-text-color="settings.theme"
:collapse-transition="false"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@ Vue.use(Router)
/* Layout */
import Layout from '@/layout'
import ParentView from '@/components/ParentView';
/**
* Note: 路由配置项

View File

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

View File

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

View File

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

View File

@ -51,7 +51,7 @@ const user = {
return new Promise((resolve, reject) => {
getInfo(state.token).then(res => {
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是否是一个非空数组
commit('SET_ROLES', res.roles)
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

View File

@ -19,6 +19,28 @@ service.interceptors.request.use(config => {
if (getToken() && !isToken) {
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 && 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
}, 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;
search.beginTime = "";
search.endTime = "";
search.params = {};
if (null != dateRange && '' != dateRange) {
search.beginTime = dateRange[0];
search.endTime = dateRange[1];
if (typeof(propName) === "undefined") {
search.params["beginTime"] = dateRange[0];
search.params["endTime"] = dateRange[1];
} else {
search.params[propName + "BeginTime"] = dateRange[0];
search.params[propName + "EndTime"] = dateRange[1];
}
}
return search;
}

View File

@ -146,6 +146,64 @@
<span>更新日志</span>
</div>
<el-collapse accordion>
<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">
<ol>
<li>阻止任意文件下载漏洞</li>
@ -435,7 +493,7 @@ export default {
data() {
return {
// 版本号
version: "3.2.1",
version: "3.3.0",
};
},
methods: {

View File

@ -148,7 +148,7 @@ export default {
justify-content: center;
align-items: center;
height: 100%;
background-image: url("../assets/image/login-background.jpg");
background-image: url("../assets/images/login-background.jpg");
background-size: cover;
}
.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

@ -421,14 +421,10 @@ export default {
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
],
deptId: [
{ required: true, message: "归属部门不能为空", trigger: "change" }
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" }
],
email: [
{ required: true, message: "邮箱地址不能为空", trigger: "blur" },
{
type: "email",
message: "'请输入正确的邮箱地址",
@ -436,7 +432,6 @@ export default {
}
],
phonenumber: [
{ required: true, message: "手机号码不能为空", trigger: "blur" },
{
pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
message: "请输入正确的手机号码",

View File

@ -18,6 +18,7 @@
<script>
import { updateUserPwd } from "@/api/system/user";
import Global from "@/layout/components/global.js";
export default {
data() {
@ -64,6 +65,7 @@ export default {
});
},
close() {
Global.$emit("removeCache", "closeSelectedTag", this.$route);
this.$store.dispatch("tagsView/delView", this.$route);
this.$router.push({ path: "/index" });
}

View File

@ -1,6 +1,6 @@
<template>
<div>
<img v-bind:src="options.img" @click="editCropper()" title="点击上传头像" class="img-circle img-lg" />
<div class="user-info-head" @click="editCropper()"><img v-bind:src="options.img" title="点击上传头像" class="img-circle img-lg" /></div>
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened">
<el-row>
<el-col :xs="24" :md="12" :style="{height: '350px'}">
@ -27,7 +27,7 @@
<el-col :lg="2" :md="2">
<el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
<el-button size="small">
上传
选择
<i class="el-icon-upload el-icon--right"></i>
</el-button>
</el-upload>
@ -140,3 +140,28 @@ export default {
}
};
</script>
<style scoped lang="scss">
.user-info-head {
position: relative;
display: inline-block;
height: 120px;
}
.user-info-head:hover:after {
content: '+';
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
color: #eee;
background: rgba(0, 0, 0, 0.5);
font-size: 24px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
cursor: pointer;
line-height: 110px;
border-radius: 50%;
}
</style>

View File

@ -24,6 +24,7 @@
<script>
import { updateUserProfile } from "@/api/system/user";
import Global from "@/layout/components/global.js";
export default {
props: {
@ -68,6 +69,7 @@ export default {
});
},
close() {
Global.$emit("removeCache", "closeSelectedTag", this.$route);
this.$store.dispatch("tagsView/delView", this.$route);
this.$router.push({ path: "/index" });
}

View File

@ -127,6 +127,7 @@
import { getGenTable, updateGenTable } from "@/api/tool/gen";
import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
import { listMenu as getMenuTreeselect } from "@/api/system/menu";
import Global from "@/layout/components/global.js";
import basicInfoForm from "./basicInfoForm";
import genInfoForm from "./genInfoForm";
import Sortable from 'sortablejs'
@ -207,6 +208,7 @@ export default {
},
/** 关闭按钮 */
close() {
Global.$emit("removeCache", "closeSelectedTag", this.$route);
this.$store.dispatch("tagsView/delView", this.$route);
this.$router.push({ path: "/tool/gen", query: { t: Date.now()}})
}

View File

@ -91,21 +91,21 @@
align="center"
prop="tableName"
:show-overflow-tooltip="true"
width="130"
width="120"
/>
<el-table-column
label="表描述"
align="center"
prop="tableComment"
:show-overflow-tooltip="true"
width="130"
width="120"
/>
<el-table-column
label="实体"
align="center"
prop="className"
:show-overflow-tooltip="true"
width="130"
width="120"
/>
<el-table-column label="创建时间" align="center" prop="createTime" width="160" />
<el-table-column label="更新时间" align="center" prop="updateTime" width="160" />
@ -165,7 +165,7 @@
:name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
:key="key"
>
<pre>{{ value }}</pre>
<highlightjs autodetect :code="value" />
</el-tab-pane>
</el-tabs>
</el-dialog>
@ -177,6 +177,7 @@
import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen";
import importTable from "./importTable";
import { downLoadZip } from "@/utils/zipdownload";
export default {
name: "Gen",
components: { importTable },

View File

@ -109,8 +109,8 @@ module.exports = {
})
config.optimization.runtimeChunk('single'),
{
from: path.resolve(__dirname, './public/robots.txt'),//防爬虫文件
to:'./',//到根目录下
from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
to: './', //到根目录下
}
}
)

View File

@ -169,14 +169,15 @@ insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 's
insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', sysdate(), '', null, '字典管理菜单');
insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', sysdate(), '', null, '参数设置菜单');
insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', sysdate(), '', null, '通知公告菜单');
insert into sys_menu values('108', '日志管理', '1', '9', 'log', 'system/log/index', 1, 0, 'M', '0', '0', '', 'log', 'admin', sysdate(), '', null, '日志管理菜单');
insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', sysdate(), '', null, '日志管理菜单');
insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', sysdate(), '', null, '在线用户菜单');
insert into sys_menu values('110', '定时任务', '2', '2', 'job', 'monitor/job/index', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', sysdate(), '', null, '定时任务菜单');
insert into sys_menu values('111', '数据监控', '2', '3', 'druid', 'monitor/druid/index', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', sysdate(), '', null, '数据监控菜单');
insert into sys_menu values('112', '服务监控', '2', '4', 'server', 'monitor/server/index', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', sysdate(), '', null, '服务监控菜单');
insert into sys_menu values('113', '表单构建', '3', '1', 'build', 'tool/build/index', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', sysdate(), '', null, '表单构建菜单');
insert into sys_menu values('114', '代码生成', '3', '2', 'gen', 'tool/gen/index', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', sysdate(), '', null, '代码生成菜单');
insert into sys_menu values('115', '系统接口', '3', '3', 'swagger', 'tool/swagger/index', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', sysdate(), '', null, '系统接口菜单');
insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', sysdate(), '', null, '缓存监控菜单');
insert into sys_menu values('114', '表单构建', '3', '1', 'build', 'tool/build/index', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', sysdate(), '', null, '表单构建菜单');
insert into sys_menu values('115', '代码生成', '3', '2', 'gen', 'tool/gen/index', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', sysdate(), '', null, '代码生成菜单');
insert into sys_menu values('116', '系统接口', '3', '3', 'swagger', 'tool/swagger/index', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', sysdate(), '', null, '系统接口菜单');
-- 三级菜单
insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', sysdate(), '', null, '操作日志菜单');
insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', sysdate(), '', null, '登录日志菜单');
@ -247,12 +248,12 @@ insert into sys_menu values('1052', '任务删除', '110', '4', '#', '', 1, 0, '
insert into sys_menu values('1053', '状态修改', '110', '5', '#', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1054', '任务导出', '110', '7', '#', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', sysdate(), '', null, '');
-- 代码生成按钮
insert into sys_menu values('1055', '生成查询', '114', '1', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1056', '生成修改', '114', '2', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1057', '生成删除', '114', '3', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1058', '导入代码', '114', '2', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1059', '预览代码', '114', '4', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1060', '生成代码', '114', '5', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1055', '生成查询', '115', '1', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1056', '生成修改', '115', '2', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1057', '生成删除', '115', '3', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1058', '导入代码', '115', '2', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1059', '预览代码', '115', '4', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, '');
insert into sys_menu values('1060', '生成代码', '115', '5', '#', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, '');
-- ----------------------------
@ -305,6 +306,7 @@ insert into sys_role_menu values ('2', '112');
insert into sys_role_menu values ('2', '113');
insert into sys_role_menu values ('2', '114');
insert into sys_role_menu values ('2', '115');
insert into sys_role_menu values ('2', '116');
insert into sys_role_menu values ('2', '500');
insert into sys_role_menu values ('2', '501');
insert into sys_role_menu values ('2', '1000');