Merge remote-tracking branch 'origin/master' into master

# Conflicts:
#	ruoyi-admin/src/main/resources/application-dev.yml
#	ruoyi-admin/src/main/resources/application-prod.yml
This commit is contained in:
czx 2020-12-31 17:17:36 +08:00
commit 57e016d0f1
42 changed files with 550 additions and 306 deletions

View File

@ -9,6 +9,10 @@
* 查看ruoyi-framework模块的pom.xml文件,根据注释更改依赖 * 查看ruoyi-framework模块的pom.xml文件,根据注释更改依赖
* 查看ruoyi-admin模块中的application.yml文件,根据注释更改配置 * 查看ruoyi-admin模块中的application.yml文件,根据注释更改配置
关于如何创建新模块
* 参考ruoyi-demo模块
* 需要改动: 父pom 与 admin模块pom
## 修改RuoYi功能 ## 修改RuoYi功能
* ORM框架 使用 Mybatis-Plus 简化CRUD * ORM框架 使用 Mybatis-Plus 简化CRUD
@ -17,16 +21,19 @@
* 代码生成模板 改为适配 Mybatis-Plus 的代码 * 代码生成模板 改为适配 Mybatis-Plus 的代码
* 项目修改为 maven多环境配置 * 项目修改为 maven多环境配置
* 重磅更新 升级MybatisPlus 3.4.1 重写配置文件详细注释 更新所有插件 * 重磅更新 升级MybatisPlus 3.4.1 重写配置文件详细注释 更新所有插件
* 增加demo模块示例(给不会增加模块的小伙伴做参考)
* 同步升级 3.3 * 同步升级 3.3
## 平台简介 ## 平台简介
若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
* 前端采用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)
## 内置功能 ## 内置功能

10
pom.xml
View File

@ -43,7 +43,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.18.RELEASE</version> <version>2.2.12.RELEASE</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
@ -224,6 +224,13 @@
<version>${ruoyi.version}</version> <version>${ruoyi.version}</version>
</dependency> </dependency>
<!-- demo模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
<version>${ruoyi.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
@ -234,6 +241,7 @@
<module>ruoyi-quartz</module> <module>ruoyi-quartz</module>
<module>ruoyi-generator</module> <module>ruoyi-generator</module>
<module>ruoyi-common</module> <module>ruoyi-common</module>
<module>ruoyi-demo</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>

View File

@ -66,6 +66,12 @@
<artifactId>ruoyi-generator</artifactId> <artifactId>ruoyi-generator</artifactId>
</dependency> </dependency>
<!-- demo模块 -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

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

@ -29,8 +29,10 @@ 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" };

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

@ -22,10 +22,12 @@ 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;
@ -37,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;
@ -51,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;
/** /**
@ -102,16 +107,21 @@ public class ExcelUtil<T>
*/ */
private List<Object[]> fields; private List<Object[]> fields;
/**
* 最大高度
*/
private short maxHeight;
/** /**
* 统计列表 * 统计列表
*/ */
private Map<Integer, Double> statistics = new HashMap<Integer, Double>(); private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
/** /**
* 数字格式 * 数字格式
*/ */
private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
/** /**
* 实体对象 * 实体对象
*/ */
@ -239,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)))
@ -521,6 +539,47 @@ public class ExcelUtil<T>
{ {
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;
} }
/** /**
@ -536,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()))
@ -561,7 +619,7 @@ public class ExcelUtil<T>
try try
{ {
// 设置行高 // 设置行高
row.setHeight((short) (attr.height() * 20)); row.setHeight(maxHeight);
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
if (attr.isExport()) if (attr.isExport())
{ {
@ -737,7 +795,7 @@ public class ExcelUtil<T>
} }
return StringUtils.stripEnd(propertyString.toString(), separator); return StringUtils.stripEnd(propertyString.toString(), separator);
} }
/** /**
* 解析字典值 * 解析字典值
* *
@ -763,7 +821,7 @@ public class ExcelUtil<T>
{ {
return DictUtils.getDictValue(dictType, dictLabel, separator); return DictUtils.getDictValue(dictType, dictLabel, separator);
} }
/** /**
* 合计统计信息 * 合计统计信息
*/ */
@ -800,7 +858,7 @@ public class ExcelUtil<T>
cell = row.createCell(0); cell = row.createCell(0);
cell.setCellStyle(styles.get("total")); cell.setCellStyle(styles.get("total"));
cell.setCellValue("合计"); cell.setCellValue("合计");
for (Integer key : keys) for (Integer key : keys)
{ {
cell = row.createCell(key); cell = row.createCell(key);
@ -916,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);
} }
/** /**

28
ruoyi-demo/pom.xml Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ruoyi</artifactId>
<groupId>com.ruoyi</groupId>
<version>3.3.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-demo</artifactId>
<description>
demo模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1 @@
package com.ruoyi.demo.controller;

View File

@ -0,0 +1 @@
package com.ruoyi.demo.domain;

View File

@ -0,0 +1 @@
package com.ruoyi.demo.mapper;

View File

@ -0,0 +1 @@
package com.ruoyi.demo.service.impl;

View File

@ -0,0 +1 @@
package com.ruoyi.demo.service;

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

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

View File

@ -1,12 +1,8 @@
package ${packageName}.controller; package ${packageName}.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.util.List; import java.util.List;
import java.util.Arrays; import java.util.Arrays;
import com.ruoyi.common.utils.StringUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -49,98 +45,14 @@ 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)
public TableDataInfo list(${ClassName} ${className}) public TableDataInfo list(${ClassName} ${className}) {
{
startPage(); startPage();
LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery(${className}); List<${ClassName}> list = i${ClassName}Service.queryList(${className});
#foreach($column in $columns)
#set($queryType=$column.queryType)
#set($javaField=$column.javaField)
#set($javaType=$column.javaType)
#set($columnName=$column.columnName)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#if($column.query)
#if($column.queryType == "EQ")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.eq(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.eq(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "NE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.ne(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.ne(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "GT")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.gt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.gt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "GTE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.ge(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.ge(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "LT")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.lt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.lt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "LTE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.le(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.le(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "LIKE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.like(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.like(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "BETWEEN")
#end
#end
#end
List<${ClassName}> list = i${ClassName}Service.list(lqw);
return getDataTable(list); return getDataTable(list);
} }
#elseif($table.tree) #elseif($table.tree)
public AjaxResult list(${ClassName} ${className}) { public AjaxResult list(${ClassName} ${className}) {
LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery(${className}); List<${ClassName}> list = i${ClassName}Service.queryList(${className});
List<${ClassName}> list = i${ClassName}Service.list(lqw);
return AjaxResult.success(list); return AjaxResult.success(list);
} }
#end #end
@ -152,9 +64,8 @@ public class ${ClassName}Controller extends BaseController {
@Log(title = "${functionName}" , businessType = BusinessType.EXPORT) @Log(title = "${functionName}" , businessType = BusinessType.EXPORT)
@GetMapping("/export" ) @GetMapping("/export" )
public AjaxResult export(${ClassName} ${className}) { public AjaxResult export(${ClassName} ${className}) {
LambdaQueryWrapper<${ClassName}> lqw = new LambdaQueryWrapper<${ClassName}>(${className}); List<${ClassName}> list = i${ClassName}Service.queryList(${className});
List<${ClassName}> list = i${ClassName}Service.list(lqw); ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}. class);
return util.exportExcel(list, "${businessName}" ); return util.exportExcel(list, "${businessName}" );
} }

View File

@ -10,14 +10,12 @@ import com.ruoyi.common.annotation.Excel;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.math.BigDecimal; import java.math.BigDecimal;
#if($table.crud)
import com.ruoyi.common.core.domain.BaseEntity;
#elseif($table.tree)
import com.ruoyi.common.core.domain.TreeEntity;
#end
/** /**
* ${functionName}对象 ${tableName} * ${functionName}对象 ${tableName}
@ -25,11 +23,6 @@ import com.ruoyi.common.core.domain.TreeEntity;
* @author ${author} * @author ${author}
* @date ${datetime} * @date ${datetime}
*/ */
#if($table.crud)
#set($Entity="BaseEntity")
#elseif($table.tree)
#set($Entity="TreeEntity")
#end
@Data @Data
@ToString @ToString
@EqualsAndHashCode @EqualsAndHashCode
@ -66,4 +59,7 @@ private static final long serialVersionUID=1L;
private $column.javaType $column.javaField; private $column.javaType $column.javaField;
#end #end
#end #end
@TableField(exist = false)
private Map<String, Object> params = new HashMap<>();
} }

View File

@ -2,6 +2,7 @@ package ${packageName}.service;
import ${packageName}.domain.${ClassName}; import ${packageName}.domain.${ClassName};
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/** /**
* ${functionName}Service接口 * ${functionName}Service接口
@ -11,4 +12,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/ */
public interface I${ClassName}Service extends IService<${ClassName}> { public interface I${ClassName}Service extends IService<${ClassName}> {
/**
* 查询列表
*/
List<${ClassName}> queryList(${ClassName} ${className});
} }

View File

@ -2,10 +2,16 @@ package ${packageName}.service.impl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
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;
import java.util.List;
import java.util.Map;
/** /**
* ${functionName}Service业务层处理 * ${functionName}Service业务层处理
* *
@ -15,4 +21,94 @@ import ${packageName}.service.I${ClassName}Service;
@Service @Service
public class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}> implements I${ClassName}Service { public class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper, ${ClassName}> implements I${ClassName}Service {
@Override
public List<${ClassName}> queryList(${ClassName} ${className}) {
LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery();
#foreach($column in $columns)
#set($queryType=$column.queryType)
#set($javaField=$column.javaField)
#set($javaType=$column.javaType)
#set($columnName=$column.columnName)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#if($column.query)
#if($column.queryType == "EQ")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.eq(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.eq(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "NE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.ne(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.ne(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "GT")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.gt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.gt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "GTE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.ge(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.ge(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "LT")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.lt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.lt(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "LTE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.le(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.le(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "LIKE")
#if($javaType == 'String')
if (StringUtils.isNotBlank(${className}.get$AttrName())){
lqw.like(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#else
if (${className}.get$AttrName() != null){
lqw.like(${ClassName}::get$AttrName ,${className}.get$AttrName());
}
#end
#elseif($queryType == "BETWEEN")
Map<String, Object> params = ${className}.getParams();
if (params.get("begin$AttrName") != null && params.get("end$AttrName") != null) {
lqw.between(${ClassName}::get$AttrName ,params.get("begin$AttrName"),params.get("end$AttrName"));
}
#end
#end
#end
return this.list(lqw);
}
} }

View File

@ -38,15 +38,28 @@
<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
@ -201,7 +214,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"
@ -283,6 +296,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 +346,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 +429,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,15 +38,28 @@
<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
@ -95,7 +108,7 @@
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">
@ -230,7 +243,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"
@ -315,6 +328,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 +380,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;
@ -413,6 +445,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

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

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

@ -49,7 +49,6 @@
"js-cookie": "2.2.1", "js-cookie": "2.2.1",
"jsencrypt": "3.0.0-rc.1", "jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"path-to-regexp": "6.2.0",
"quill": "1.3.7", "quill": "1.3.7",
"screenfull": "5.0.2", "screenfull": "5.0.2",
"sortablejs": "1.10.2", "sortablejs": "1.10.2",

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

@ -1,8 +1,7 @@
<!-- @author ruoyi 20201128 支持三级以上菜单缓存 -->
<template> <template>
<section class="app-main"> <section class="app-main">
<transition name="fade-transform" mode="out-in"> <transition name="fade-transform" mode="out-in">
<keep-alive :max="20" :exclude="notCacheName"> <keep-alive :include="cachedViews">
<router-view :key="key" /> <router-view :key="key" />
</keep-alive> </keep-alive>
</transition> </transition>
@ -10,119 +9,17 @@
</template> </template>
<script> <script>
import Global from "@/layout/components/global.js";
export default { export default {
name: 'AppMain', name: 'AppMain',
computed: { computed: {
notCacheName() { cachedViews() {
var visitedViews = this.$store.state.tagsView.visitedViews; return this.$store.state.tagsView.cachedViews
var noCacheViews = [];
Object.keys(visitedViews).some((index) => {
if (visitedViews[index].meta.noCache) {
noCacheViews.push(visitedViews[index].name);
}
});
return noCacheViews;
}, },
key() { key() {
return this.$route.path; return this.$route.path
}, }
}, }
mounted() { }
//
Global.$on("removeCache", (name, view) => {
this.removeCache(name, view);
});
},
methods: {
// keep-aliveVnode
getVnode() {
//
if (this.$children.length == 0) return false;
let vnode;
for (let item of this.$children) {
// datakeykeep-alivekeyrouter-viewkey
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];
// keykey
componentInstance.keys.splice(index, 1);
}
});
},
//
closeAllTags({ componentInstance }) {
//
Object.keys(componentInstance.cache).forEach((key) => {
if (componentInstance.cache[key]) {
componentInstance.cache[key].componentInstance.$destroy();
}
});
//
componentInstance.cache = {};
// keykey
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];
// keykey
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 keykey
componentInstance.keys.splice(index, 1);
}
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -134,7 +31,7 @@ export default {
overflow: hidden; overflow: hidden;
} }
.fixed-header + .app-main { .fixed-header+.app-main {
padding-top: 50px; padding-top: 50px;
} }
@ -144,7 +41,7 @@ export default {
min-height: calc(100vh - 84px); min-height: calc(100vh - 84px);
} }
.fixed-header + .app-main { .fixed-header+.app-main {
padding-top: 84px; padding-top: 84px;
} }
} }

View File

@ -13,7 +13,7 @@
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

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

View File

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

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

@ -6,13 +6,17 @@ 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: {
// 生成路由 // 生成路由
@ -20,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, true)
rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
commit('SET_ROUTES', rewriteRoutes)
commit('SET_SIDEBAR_ROUTERS', sidebarRoutes)
resolve(rewriteRoutes)
}) })
}) })
} }
@ -31,8 +39,11 @@ const permission = {
} }
// 遍历后台传来的路由字符串,转换为组件对象 // 遍历后台传来的路由字符串,转换为组件对象
function filterAsyncRouter(asyncRouterMap) { function filterAsyncRouter(asyncRouterMap, isRewrite = false) {
return asyncRouterMap.filter(route => { return asyncRouterMap.filter(route => {
if (isRewrite && route.children) {
route.children = filterChildren(route.children)
}
if (route.component) { if (route.component) {
// Layout ParentView 组件特殊处理 // Layout ParentView 组件特殊处理
if (route.component === 'Layout') { if (route.component === 'Layout') {
@ -44,14 +55,35 @@ function filterAsyncRouter(asyncRouterMap) {
} }
} }
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, isRewrite)
} }
return true return true
}) })
} }
function filterChildren(childrenMap) {
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
}
}
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

@ -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) {
@ -46,4 +48,4 @@ export function checkRole(value) {
console.error(`need roles! Like checkRole="['admin','editor']"`) console.error(`need roles! Like checkRole="['admin','editor']"`)
return false return false
} }
} }

View File

@ -25,7 +25,7 @@ service.interceptors.request.use(config => {
for (const propName of Object.keys(config.params)) { for (const propName of Object.keys(config.params)) {
const value = config.params[propName]; const value = config.params[propName];
var part = encodeURIComponent(propName) + "="; var part = encodeURIComponent(propName) + "=";
if (value && typeof(value) !== "undefined") { if (value !== null && typeof(value) !== "undefined") {
if (typeof value === 'object') { if (typeof value === 'object') {
for (const key of Object.keys(value)) { for (const key of Object.keys(value)) {
let params = propName + '[' + key + ']'; let params = propName + '[' + key + ']';

View File

@ -62,8 +62,8 @@ export function addDateRange(params, dateRange, propName) {
search.params["beginTime"] = dateRange[0]; search.params["beginTime"] = dateRange[0];
search.params["endTime"] = dateRange[1]; search.params["endTime"] = dateRange[1];
} else { } else {
search.params[propName + "BeginTime"] = dateRange[0]; search.params["begin" + propName] = dateRange[0];
search.params[propName + "EndTime"] = dateRange[1]; search.params["end" + propName] = dateRange[1];
} }
} }
return search; return search;

View File

@ -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();
});
} }
}); });
} }

View File

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

View File

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

View File

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