Conflicts:
	pom.xml
	ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
	ruoyi-admin/src/main/resources/application.yml
	ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
	ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
	ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
	ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
	ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
	ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
	ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
	ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
	ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
	ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
	ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java
	ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
	ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
	ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
	ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
	ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
	ruoyi-ui/babel.config.js
	ruoyi-ui/package.json
	ruoyi-ui/src/api/tool/gen.js
	ruoyi-ui/src/assets/styles/ruoyi.scss
	ruoyi-ui/src/components/HeaderSearch/index.vue
	ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
	ruoyi-ui/src/main.js
	ruoyi-ui/src/utils/ruoyi.js
	ruoyi-ui/src/views/login.vue
	ruoyi-ui/src/views/monitor/job/index.vue
	ruoyi-ui/src/views/monitor/logininfor/index.vue
	ruoyi-ui/src/views/monitor/online/index.vue
	ruoyi-ui/src/views/monitor/operlog/index.vue
	ruoyi-ui/src/views/system/config/index.vue
	ruoyi-ui/src/views/system/dept/index.vue
	ruoyi-ui/src/views/system/dict/data.vue
	ruoyi-ui/src/views/system/dict/index.vue
	ruoyi-ui/src/views/system/menu/index.vue
	ruoyi-ui/src/views/system/notice/index.vue
	ruoyi-ui/src/views/system/post/index.vue
	ruoyi-ui/src/views/system/role/index.vue
	ruoyi-ui/src/views/system/user/index.vue
	ruoyi-ui/src/views/tool/gen/genInfoForm.vue
	ruoyi-ui/src/views/tool/gen/index.vue
	ruoyi-ui/vue.config.js
	sql/ry_20200724.sql
This commit is contained in:
疯狂的狮子li 2020-08-02 18:31:47 +08:00
commit c966d9bada
56 changed files with 1058 additions and 311 deletions

View File

@ -21,6 +21,7 @@
<druid.version>1.1.14</druid.version>
<bitwalker.version>1.19</bitwalker.version>
<swagger.version>2.9.2</swagger.version>
<kaptcha.version>2.3.2</kaptcha.version>
<pagehelper.boot.version>1.2.5</pagehelper.boot.version>
<fastjson.version>1.2.70</fastjson.version>
<oshi.version>3.9.1</oshi.version>
@ -146,6 +147,13 @@
<version>${jwt.version}</version>
</dependency>
<!--验证码 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>

View File

@ -1,16 +1,20 @@
package com.ruoyi.web.controller.common;
import java.io.ByteArrayOutputStream;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Producer;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.VerifyCodeUtils;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.common.utils.uuid.IdUtils;
@ -22,41 +26,61 @@ import com.ruoyi.common.utils.uuid.IdUtils;
@RestController
public class CaptchaController
{
@Resource(name = "captchaProducer")
private Producer captchaProducer;
@Resource(name = "captchaProducerMath")
private Producer captchaProducerMath;
@Autowired
private RedisCache redisCache;
// 验证码类型
@Value("${ruoyi.captchaType}")
private String captchaType;
/**
* 生成验证码
*/
@GetMapping("/captchaImage")
public AjaxResult getCode(HttpServletResponse response) throws IOException
{
// 生成随机字串
String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
// 唯一标识
// 保存验证码信息
String uuid = IdUtils.simpleUUID();
String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
redisCache.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 生成图片
int w = 111, h = 36;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
String capStr = null, code = null;
BufferedImage image = null;
// 生成验证码
if ("math".equals(captchaType))
{
String capText = captchaProducerMath.createText();
capStr = capText.substring(0, capText.lastIndexOf("@"));
code = capText.substring(capText.lastIndexOf("@") + 1);
image = captchaProducerMath.createImage(capStr);
}
else if ("char".equals(captchaType))
{
capStr = code = captchaProducer.createText();
image = captchaProducer.createImage(capStr);
}
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try
{
AjaxResult ajax = AjaxResult.success();
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(stream.toByteArray()));
return ajax;
ImageIO.write(image, "jpg", os);
}
catch (Exception e)
catch (IOException e)
{
e.printStackTrace();
return AjaxResult.error(e.getMessage());
}
finally
{
stream.close();
}
AjaxResult ajax = AjaxResult.success();
ajax.put("uuid", uuid);
ajax.put("img", Base64.encode(os.toByteArray()));
return ajax;
}
}

View File

@ -12,6 +12,8 @@ ruoyi:
profile: D:/ruoyi/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数组计算 char 字符验证
captchaType: math
# 开发环境配置
server:

View File

@ -39,6 +39,11 @@ public @interface Excel
*/
public String readConverterExp() default "";
/**
* 分隔符读取字符串组内容
*/
public String separator() default ",";
/**
* 导出类型0数字 1字符串
*/

View File

@ -109,7 +109,7 @@ public class RedisCache
* 缓存List数据
*
* @param key 缓存的键值
* @param values 待缓存的List数据
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList)

View File

@ -14,6 +14,11 @@ import com.ruoyi.common.utils.spring.SpringUtils;
*/
public class DictUtils
{
/**
* 分隔符
*/
public static final String SEPARATOR = ",";
/**
* 设置字典缓存
*
@ -36,8 +41,8 @@ public class DictUtils
Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
if (StringUtils.isNotNull(cacheObj))
{
List<SysDictData> DictDatas = StringUtils.cast(cacheObj);
return DictDatas;
List<SysDictData> dictDatas = StringUtils.cast(cacheObj);
return dictDatas;
}
return null;
}
@ -51,21 +56,7 @@ public class DictUtils
*/
public static String getDictLabel(String dictType, String dictValue)
{
if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotEmpty(dictValue))
{
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNotEmpty(datas))
{
for (SysDictData dict : datas)
{
if (dictValue.equals(dict.getDictValue()))
{
return dict.getDictLabel();
}
}
}
}
return dictValue;
return getDictLabel(dictType, dictValue, SEPARATOR);
}
/**
@ -77,10 +68,77 @@ public class DictUtils
*/
public static String getDictValue(String dictType, String dictLabel)
{
if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotEmpty(dictLabel))
return getDictValue(dictType, dictLabel, SEPARATOR);
}
/**
* 根据字典类型和字典值获取字典标签
*
* @param dictType 字典类型
* @param dictValue 字典值
* @param separator 分隔符
* @return 字典标签
*/
public static String getDictLabel(String dictType, String dictValue, String separator)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.isNotEmpty(datas))
if (StringUtils.containsAny(separator, dictValue) && StringUtils.isNotEmpty(datas))
{
for (SysDictData dict : datas)
{
for (String value : dictValue.split(separator))
{
if (value.equals(dict.getDictValue()))
{
propertyString.append(dict.getDictLabel() + separator);
break;
}
}
}
}
else
{
for (SysDictData dict : datas)
{
if (dictValue.equals(dict.getDictValue()))
{
return dict.getDictLabel();
}
}
}
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 根据字典类型和字典标签获取字典值
*
* @param dictType 字典类型
* @param dictLabel 字典标签
* @param separator 分隔符
* @return 字典值
*/
public static String getDictValue(String dictType, String dictLabel, String separator)
{
StringBuilder propertyString = new StringBuilder();
List<SysDictData> datas = getDictCache(dictType);
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
{
for (SysDictData dict : datas)
{
for (String label : dictLabel.split(separator))
{
if (label.equals(dict.getDictLabel()))
{
propertyString.append(dict.getDictValue() + separator);
break;
}
}
}
}
else
{
for (SysDictData dict : datas)
{
@ -90,8 +148,7 @@ public class DictUtils
}
}
}
}
return dictLabel;
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**

View File

@ -89,7 +89,7 @@ public class FileUploadUtils
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param extension 上传文件类型
* @param allowedExtension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws FileNameLengthLimitExceededException 文件名太长

View File

@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest;
*
* @author ruoyi
*/
public class FileUtils
public class FileUtils extends org.apache.commons.io.FileUtils
{
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";

View File

@ -144,7 +144,10 @@ public class EscapeUtil
public static void main(String[] args)
{
String html = "alert('11111');";
String html = "<script>alert(1);</script>";
// String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
// String html = "<123";
// String html = "123>";
System.out.println(EscapeUtil.clean(html));
System.out.println(EscapeUtil.escape(html));
System.out.println(EscapeUtil.unescape(html));

View File

@ -131,7 +131,7 @@ public final class HTMLFilter
vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
stripComment = true;
encodeQuotes = true;
alwaysMakeTags = true;
alwaysMakeTags = false;
}
/**
@ -208,7 +208,7 @@ public final class HTMLFilter
s = processRemoveBlanks(s);
s = validateEntities(s);
// s = validateEntities(s);
return s;
}
@ -245,6 +245,7 @@ public final class HTMLFilter
// try and form html
//
s = regexReplace(P_END_ARROW, "", s);
// 不追加结束标签
s = regexReplace(P_BODY_TO_END, "<$1>", s);
s = regexReplace(P_XML_CONTENT, "$1<$2", s);

View File

@ -8,7 +8,6 @@ import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
@ -200,9 +199,12 @@ public class ExcelUtil<T>
// 设置类的私有字段属性可访问.
field.setAccessible(true);
Integer column = cellMap.get(attr.name());
if (column != null)
{
fieldsMap.put(column, field);
}
}
}
for (int i = 1; i < rows; i++)
{
// 从第2行开始取数据,默认第一行是表头.
@ -271,11 +273,11 @@ public class ExcelUtil<T>
}
else if (StringUtils.isNotEmpty(attr.readConverterExp()))
{
val = reverseByExp(Convert.toStr(val), attr.readConverterExp());
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
}
else if (StringUtils.isNotEmpty(attr.dictType()))
{
val = reverseDictByExp(attr.dictType(), Convert.toStr(val));
val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
}
ReflectUtils.invokeSetter(entity, propertyName, val);
}
@ -534,6 +536,7 @@ public class ExcelUtil<T>
Object value = getTargetValue(vo, field, attr);
String dateFormat = attr.dateFormat();
String readConverterExp = attr.readConverterExp();
String separator = attr.separator();
String dictType = attr.dictType();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{
@ -541,11 +544,11 @@ public class ExcelUtil<T>
}
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
{
cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp));
cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
}
else if (StringUtils.isNotEmpty(dictType))
{
cell.setCellValue(convertDictByExp(dictType, Convert.toStr(value)));
cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator));
}
else
{
@ -623,28 +626,36 @@ public class ExcelUtil<T>
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值
* @throws Exception
*/
public static String convertByExp(String propertyValue, String converterExp) throws Exception
{
try
public static String convertByExp(String propertyValue, String converterExp, String separator)
{
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue))
{
for (String value : propertyValue.split(separator))
{
if (itemArray[0].equals(value))
{
propertyString.append(itemArray[1] + separator);
break;
}
}
}
else
{
if (itemArray[0].equals(propertyValue))
{
return itemArray[1];
}
}
}
catch (Exception e)
{
throw e;
}
return propertyValue;
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
@ -652,52 +663,62 @@ public class ExcelUtil<T>
*
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
* @return 解析后值
* @throws Exception
*/
public static String reverseByExp(String propertyValue, String converterExp) throws Exception
{
try
public static String reverseByExp(String propertyValue, String converterExp, String separator)
{
StringBuilder propertyString = new StringBuilder();
String[] convertSource = converterExp.split(",");
for (String item : convertSource)
{
String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue))
{
for (String value : propertyValue.split(separator))
{
if (itemArray[1].equals(value))
{
propertyString.append(itemArray[0] + separator);
break;
}
}
}
else
{
if (itemArray[1].equals(propertyValue))
{
return itemArray[0];
}
}
}
catch (Exception e)
{
throw e;
}
return propertyValue;
return StringUtils.stripEnd(propertyString.toString(), separator);
}
/**
* 解析字典值
*
* @param dictType 字典类型
* @param dictValue 字典值
* @param dictType 字典类型
* @param separator 分隔符
* @return 字典标签
*/
public static String convertDictByExp(String dictType, String dictValue) throws Exception
public static String convertDictByExp(String dictValue, String dictType, String separator)
{
return DictUtils.getDictLabel(dictType, dictValue);
return DictUtils.getDictLabel(dictType, dictValue, separator);
}
/**
* 反向解析值字典值
*
* @param dictLabel 字典标签
* @param dictType 字典类型
* @param dictValue 字典标签
* @param separator 分隔符
* @return 字典值
*/
public static String reverseDictByExp(String dictType, String dictLabel) throws Exception
public static String reverseDictByExp(String dictLabel, String dictType, String separator)
{
return DictUtils.getDictValue(dictType, dictLabel);
return DictUtils.getDictValue(dictType, dictLabel, separator);
}
/**
@ -875,14 +896,7 @@ public class ExcelUtil<T>
}
else
{
if ((Double) val % 1 > 0)
{
val = new DecimalFormat("0.00").format(val);
}
else
{
val = new DecimalFormat("0").format(val);
}
val = new BigDecimal(val.toString()); // 浮点格式处理
}
}
else if (cell.getCellTypeEnum() == CellType.STRING)

View File

@ -1,5 +1,6 @@
package com.ruoyi.common.utils.sql;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.utils.StringUtils;
/**
@ -10,9 +11,9 @@ import com.ruoyi.common.utils.StringUtils;
public class SqlUtil
{
/**
* 仅支持字母数字下划线空格逗号支持多个字段排序
* 仅支持字母数字下划线空格逗号小数点支持多个字段排序
*/
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,]+";
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
/**
* 检查字符防止注入绕过
@ -21,7 +22,7 @@ public class SqlUtil
{
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
{
return StringUtils.EMPTY;
throw new BaseException("参数不符合规范,不能进行查询");
}
return value;
}

View File

@ -47,6 +47,18 @@
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- 验证码 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<exclusions>
<exclusion>
<artifactId>javax.servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>

View File

@ -96,7 +96,7 @@ public class DataScopeAspect
*
* @param joinPoint 切点
* @param user 用户
* @param alias 别名
* @param userAlias 别名
*/
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
{

View File

@ -0,0 +1,83 @@
package com.ruoyi.framework.config;
import java.util.Properties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import static com.google.code.kaptcha.Constants.*;
/**
* 验证码配置
*
* @author ruoyi
*/
@Configuration
public class CaptchaConfig
{
@Bean(name = "captchaProducer")
public DefaultKaptcha getKaptchaBean()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty(KAPTCHA_BORDER, "yes");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
// 验证码图片宽度 默认为200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
@Bean(name = "captchaProducerMath")
public DefaultKaptcha getKaptchaBeanMath()
{
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
Properties properties = new Properties();
// 是否有边框 默认为true 我们可以自己设置yesno
properties.setProperty(KAPTCHA_BORDER, "yes");
// 边框颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
// 验证码文本字符颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
// 验证码图片宽度 默认为200
properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
// 验证码图片高度 默认为50
properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
// 验证码文本字符大小 默认为40
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
// KAPTCHA_SESSION_KEY
properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
// 验证码文本生成器
properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.framework.config.KaptchaTextCreator");
// 验证码文本字符间距 默认为2
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
// 验证码文本字符长度 默认为5
properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
// 验证码文本字体样式 默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
// 验证码噪点颜色 默认为Color.BLACK
properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
// 干扰实现类
properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
// 图片样式 水纹com.google.code.kaptcha.impl.WaterRipple 鱼眼com.google.code.kaptcha.impl.FishEyeGimpy 阴影com.google.code.kaptcha.impl.ShadowGimpy
properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
Config config = new Config(properties);
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.framework.config;
import java.util.Random;
import com.google.code.kaptcha.text.impl.DefaultTextCreator;
/**
* 验证码文本生成器
*
* @author ruoyi
*/
public class KaptchaTextCreator extends DefaultTextCreator
{
private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
@Override
public String getText()
{
Integer result = 0;
Random random = new Random();
int x = random.nextInt(10);
int y = random.nextInt(10);
StringBuilder suChinese = new StringBuilder();
int randomoperands = (int) Math.round(Math.random() * 2);
if (randomoperands == 0)
{
result = x * y;
suChinese.append(CNUMBERS[x]);
suChinese.append("*");
suChinese.append(CNUMBERS[y]);
}
else if (randomoperands == 1)
{
if (!(x == 0) && y % x == 0)
{
result = y / x;
suChinese.append(CNUMBERS[y]);
suChinese.append("/");
suChinese.append(CNUMBERS[x]);
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
}
else if (randomoperands == 2)
{
if (x >= y)
{
result = x - y;
suChinese.append(CNUMBERS[x]);
suChinese.append("-");
suChinese.append(CNUMBERS[y]);
}
else
{
result = y - x;
suChinese.append(CNUMBERS[y]);
suChinese.append("-");
suChinese.append(CNUMBERS[x]);
}
}
else
{
result = x + y;
suChinese.append(CNUMBERS[x]);
suChinese.append("+");
suChinese.append(CNUMBERS[y]);
}
suChinese.append("=?@" + result);
return suChinese.toString();
}
}

View File

@ -47,7 +47,7 @@ public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
/**
* 验证是否重复提交由子类实现具体的防重复提交的规则
*
* @param httpServletRequest
* @param request
* @return
* @throws Exception
*/

View File

@ -114,7 +114,7 @@ public class TokenService
/**
* 验证令牌有效期相差不足20分钟自动刷新缓存
*
* @param token 令牌
* @param loginUser
* @return 令牌
*/
public void verifyToken(LoginUser loginUser)

View File

@ -148,15 +148,27 @@ public class GenController extends BaseController
}
/**
* 生成代码
* 生成代码下载方式
*/
@PreAuthorize("@ss.hasPermi('tool:gen:code')")
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/download/{tableName}")
public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
{
byte[] data = genTableService.downloadCode(tableName);
genCode(response, data);
}
/**
* 生成代码自定义路径
*/
@PreAuthorize("@ss.hasPermi('tool:gen:code')")
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/genCode/{tableName}")
public void genCode(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
public AjaxResult genCode(HttpServletResponse response, @PathVariable("tableName") String tableName)
{
byte[] data = genTableService.generatorCode(tableName);
genCode(response, data);
genTableService.generatorCode(tableName);
return AjaxResult.success();
}
/**
@ -168,7 +180,7 @@ public class GenController extends BaseController
public void batchGenCode(HttpServletResponse response, String tables) throws IOException
{
String[] tableNames = Convert.toStrArray(tables);
byte[] data = genTableService.generatorCode(tableNames);
byte[] data = genTableService.downloadCode(tableNames);
genCode(response, data);
}

View File

@ -55,6 +55,12 @@ public class GenTable extends BaseEntity
@NotBlank(message = "作者不能为空")
private String functionAuthor;
/** 生成代码方式0zip压缩包 1自定义路径 */
private String genType;
/** 生成路径(不填默认项目路径) */
private String genPath;
/** 主键信息 */
private GenTableColumn pkColumn;
@ -180,6 +186,26 @@ public class GenTable extends BaseEntity
this.functionAuthor = functionAuthor;
}
public String getGenType()
{
return genType;
}
public void setGenType(String genType)
{
this.genType = genType;
}
public String getGenPath()
{
return genPath;
}
public void setGenPath(String genPath)
{
this.genPath = genPath;
}
public GenTableColumn getPkColumn()
{
return pkColumn;

View File

@ -1,6 +1,7 @@
package com.ruoyi.generator.service;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.LinkedHashMap;
@ -21,9 +22,11 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.GenConstants;
import com.ruoyi.common.core.text.CharsetKit;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
import com.ruoyi.generator.mapper.GenTableColumnMapper;
@ -202,13 +205,13 @@ public class GenTableServiceImpl implements IGenTableService
}
/**
* 生成代码
* 生成代码下载方式
*
* @param tableName 表名称
* @return 数据
*/
@Override
public byte[] generatorCode(String tableName)
public byte[] downloadCode(String tableName)
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
@ -218,13 +221,55 @@ public class GenTableServiceImpl implements IGenTableService
}
/**
* 批量生成代码
* 生成代码自定义路径
*
* @param tableName 表名称
* @return 数据
*/
@Override
public void generatorCode(String tableName)
{
// 查询表信息
GenTable table = genTableMapper.selectGenTableByName(tableName);
// 查询列信息
List<GenTableColumn> columns = table.getColumns();
setPkColumn(table, columns);
VelocityInitializer.initVelocity();
VelocityContext context = VelocityUtils.prepareContext(table);
// 获取模板列表
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
for (String template : templates)
{
if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
{
// 渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
tpl.merge(context, sw);
try
{
String path = getGenPath(table, template);
FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
}
catch (IOException e)
{
throw new CustomException("渲染模板失败,表名:" + table.getTableName());
}
}
}
}
/**
* 批量生成代码下载方式
*
* @param tableNames 表数组
* @return 数据
*/
@Override
public byte[] generatorCode(String[] tableNames)
public byte[] downloadCode(String[] tableNames)
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
@ -347,4 +392,21 @@ public class GenTableServiceImpl implements IGenTableService
genTable.setParentMenuName(parentMenuName);
}
}
/**
* 获取代码生成地址
*
* @param table 业务表信息
* @param template 模板文件路径
* @return 生成地址
*/
public static String getGenPath(GenTable table, String template)
{
String genPath = table.getGenPath();
if (StringUtils.equals(genPath, "/"))
{
return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
}
return genPath + File.separator + VelocityUtils.getFileName(template, table);
}
}

View File

@ -75,20 +75,28 @@ public interface IGenTableService
public Map<String, String> previewCode(Long tableId);
/**
* 生成代码
* 生成代码下载方式
*
* @param tableName 表名称
* @return 数据
*/
public byte[] generatorCode(String tableName);
public byte[] downloadCode(String tableName);
/**
* 批量生成代码
* 生成代码自定义路径
*
* @param tableName 表名称
* @return 数据
*/
public void generatorCode(String tableName);
/**
* 批量生成代码下载方式
*
* @param tableNames 表数组
* @return 数据
*/
public byte[] generatorCode(String[] tableNames);
public byte[] downloadCode(String[] tableNames);
/**
* 修改保存参数校验

View File

@ -11,13 +11,18 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.GenTable;
import com.ruoyi.generator.domain.GenTableColumn;
/**
* 模板处理工具类
*
* @author ruoyi
*/
public class VelocityUtils
{
/** 项目空间路径 */
private static final String PROJECT_PATH = "main/java";
/** mybatis空间路径 */
private static final String MYBATIS_PATH = "main/resources/mybatis";
private static final String MYBATIS_PATH = "main/resources/mapper";
/** 默认上级菜单,系统工具 */
private static final String DEFAULT_PARENT_MENU_ID = "3";
@ -197,7 +202,7 @@ public class VelocityUtils
/**
* 根据列类型获取导入包
*
* @param column 列集合
* @param columns 列集合
* @return 返回需要导入的包列表
*/
public static HashSet<String> getImportList(List<GenTableColumn> columns)
@ -228,13 +233,12 @@ public class VelocityUtils
public static String getPermissionPrefix(String moduleName, String businessName)
{
return StringUtils.format("{}:{}", moduleName, businessName);
}
/**
* 获取上级菜单ID字段
*
* @param options 生成其他选项
* @param paramsObj 生成其他选项
* @return 上级菜单ID字段
*/
public static String getParentMenuId(JSONObject paramsObj)
@ -249,7 +253,7 @@ public class VelocityUtils
/**
* 获取树编码
*
* @param options 生成其他选项
* @param paramsObj 生成其他选项
* @return 树编码
*/
public static String getTreecode(JSONObject paramsObj)
@ -264,7 +268,7 @@ public class VelocityUtils
/**
* 获取树父编码
*
* @param options 生成其他选项
* @param paramsObj 生成其他选项
* @return 树父编码
*/
public static String getTreeParentCode(JSONObject paramsObj)
@ -279,7 +283,7 @@ public class VelocityUtils
/**
* 获取树名称
*
* @param options 生成其他选项
* @param paramsObj 生成其他选项
* @return 树名称
*/
public static String getTreeName(JSONObject paramsObj)

View File

@ -15,6 +15,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="businessName" column="business_name" />
<result property="functionName" column="function_name" />
<result property="functionAuthor" column="function_author" />
<result property="genType" column="gen_type" />
<result property="genPath" column="gen_path" />
<result property="options" column="options" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
@ -50,7 +52,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectGenTableVo">
select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, options, create_by, create_time, update_by, update_time, remark from gen_table
select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
</sql>
<select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
@ -106,7 +108,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@ -114,7 +116,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
FROM gen_table t
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
@ -132,6 +134,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessName != null and businessName != ''">business_name,</if>
<if test="functionName != null and functionName != ''">function_name,</if>
<if test="functionAuthor != null and functionAuthor != ''">function_author,</if>
<if test="genType != null and genType != ''">gen_type,</if>
<if test="genPath != null and genPath != ''">gen_path,</if>
<if test="remark != null and remark != ''">remark,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
create_time
@ -145,6 +149,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="businessName != null and businessName != ''">#{businessName},</if>
<if test="functionName != null and functionName != ''">#{functionName},</if>
<if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if>
<if test="genType != null and genType != ''">#{genType},</if>
<if test="genPath != null and genPath != ''">#{genPath},</if>
<if test="remark != null and remark != ''">#{remark},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
sysdate()
@ -158,6 +164,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if>
<if test="className != null and className != ''">class_name = #{className},</if>
<if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if>
<if test="genType != null and genType != ''">gen_type = #{genType},</if>
<if test="genPath != null and genPath != ''">gen_path = #{genPath},</if>
<if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if>
<if test="packageName != null and packageName != ''">package_name = #{packageName},</if>
<if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if>

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
@ -51,23 +51,30 @@
#end
#end
<el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索</el-button>
<el-button
class="filter-item"
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']"
>新增</el-button>
</el-form-item>
</el-form>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table
v-loading="loading"
@ -157,6 +164,23 @@
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox
v-for="dict in ${field}Options"
:key="dict.dictValue"
:label="dict.dictValue">
{{dict.dictLabel}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}">
<el-radio-group v-model="form.${field}">
@ -212,6 +236,8 @@ export default {
return {
// 遮罩层
loading: true,
// 显示搜索条件
showSearch: true,
// ${functionName}表格数据
${businessName}List: [],
// ${functionName}树选项
@ -236,7 +262,7 @@ export default {
queryParams: {
#foreach ($column in $columns)
#if($column.query)
$column.javaField: undefined#if($velocityCount != $columns.size()),#end
$column.javaField: null#if($velocityCount != $columns.size()),#end
#end
#end
@ -312,7 +338,7 @@ export default {
#end
// $comment字典翻译
${column.javaField}Format(row, column) {
return this.selectDictLabel(this.${column.javaField}Options, row.${column.javaField});
return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
},
#end
#end
@ -326,10 +352,13 @@ export default {
this.form = {
#foreach ($column in $columns)
#if($column.htmlType == "radio")
$column.javaField: "0"#if($velocityCount != $columns.size()),#end
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($velocityCount != $columns.size()),#end
#else
$column.javaField: undefined#if($velocityCount != $columns.size()),#end
$column.javaField: null#if($velocityCount != $columns.size()),#end
#end
#end
@ -356,20 +385,30 @@ export default {
handleUpdate(row) {
this.reset();
this.getTreeselect();
if (row != undefined) {
if (row != null) {
this.form.${treeParentCode} = row.${treeCode};
}
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
this.form = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
#end
#end
this.open = true;
this.title = "修改${functionName}";
});
},
/** 提交按钮 */
submitForm: function() {
submitForm() {
this.#[[$]]#refs["form"].validate(valid => {
if (valid) {
if (this.form.${pkColumn.javaField} != undefined) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
#end
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
if (response.code === 200) {
this.msgSuccess("修改成功");

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
@ -51,7 +51,7 @@
#end
#end
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -95,6 +95,14 @@
v-hasPermi="['${moduleName}:${businessName}:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
@ -185,6 +193,23 @@
<el-option label="请选择字典生成" value="" />
</el-select>
</el-form-item>
#elseif($column.htmlType == "checkbox" && "" != $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox
v-for="dict in ${field}Options"
:key="dict.dictValue"
:label="dict.dictValue">
{{dict.dictLabel}}
</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "checkbox" && $dictType)
<el-form-item label="${comment}">
<el-checkbox-group v-model="form.${field}">
<el-checkbox>请选择字典生成</el-checkbox>
</el-checkbox-group>
</el-form-item>
#elseif($column.htmlType == "radio" && "" != $dictType)
<el-form-item label="${comment}">
<el-radio-group v-model="form.${field}">
@ -243,6 +268,8 @@ export default {
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// ${functionName}表格数据
@ -269,7 +296,7 @@ export default {
pageSize: 10,
#foreach ($column in $columns)
#if($column.query)
$column.javaField: undefined#if($velocityCount != $columns.size()),#end
$column.javaField: null#if($velocityCount != $columns.size()),#end
#end
#end
@ -326,7 +353,7 @@ export default {
#end
// $comment字典翻译
${column.javaField}Format(row, column) {
return this.selectDictLabel(this.${column.javaField}Options, row.${column.javaField});
return this.selectDictLabel#if($column.htmlType == "checkbox")s#end(this.${column.javaField}Options, row.${column.javaField});
},
#end
#end
@ -340,10 +367,13 @@ export default {
this.form = {
#foreach ($column in $columns)
#if($column.htmlType == "radio")
$column.javaField: "0"#if($velocityCount != $columns.size()),#end
$column.javaField: #if($column.javaType == "Integer" || $column.javaType == "Long")0#else"0"#end#if($velocityCount != $columns.size()),#end
#elseif($column.htmlType == "checkbox")
$column.javaField: []#if($velocityCount != $columns.size()),#end
#else
$column.javaField: undefined#if($velocityCount != $columns.size()),#end
$column.javaField: null#if($velocityCount != $columns.size()),#end
#end
#end
@ -363,7 +393,7 @@ export default {
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.${pkColumn.javaField})
this.single = selection.length!=1
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
@ -378,15 +408,25 @@ export default {
const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
get${BusinessName}(${pkColumn.javaField}).then(response => {
this.form = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
#end
#end
this.open = true;
this.title = "修改${functionName}";
});
},
/** 提交按钮 */
submitForm: function() {
submitForm() {
this.#[[$]]#refs["form"].validate(valid => {
if (valid) {
if (this.form.${pkColumn.javaField} != undefined) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
#end
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
if (response.code === 200) {
this.msgSuccess("修改成功");

View File

@ -66,7 +66,7 @@ public abstract class AbstractQuartzJob implements Job
* 执行后
*
* @param context 工作执行上下文对象
* @param sysScheduleJob 系统计划任务
* @param sysJob 系统计划任务
*/
protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
{

View File

@ -52,7 +52,7 @@ public interface SysMenuMapper
/**
* 根据用户ID查询菜单
*
* @param username 用户ID
* @param userId 用户ID
* @return 菜单列表
*/
public List<SysMenu> selectMenuTreeByUserId(Long userId);

View File

@ -77,7 +77,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="checkDeptNameUnique" resultMap="SysDeptResult">
<include refid="selectDeptVo"/>
where dept_name=#{deptName} and parent_id = #{parentId}
where dept_name=#{deptName} and parent_id = #{parentId} limit 1
</select>
<insert id="insertDept" parameterType="SysDept">

View File

@ -1,5 +1,13 @@
module.exports = {
presets: [
'@vue/app'
]
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
'@vue/cli-plugin-babel/preset'
],
'env': {
'development': {
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
'plugins': ['dynamic-import-node']
}
}
}

View File

@ -5,7 +5,7 @@
"author": "若依",
"license": "MIT",
"scripts": {
"dev": "vue-cli-service serve --open",
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
@ -43,10 +43,11 @@
"@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",
"js-beautify": "1.10.2",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"jsencrypt": "3.0.0-rc.1",
@ -65,32 +66,31 @@
"vuex": "3.1.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "3.5.3",
"@vue/cli-plugin-eslint": "^3.9.1",
"@vue/cli-plugin-unit-jest": "3.5.3",
"@vue/cli-service": "3.5.3",
"@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",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.0.1",
"autoprefixer": "9.5.1",
"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",
"connect": "3.6.6",
"eslint": "5.15.3",
"eslint-plugin-vue": "5.2.2",
"eslint": "6.7.2",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0",
"http-proxy-middleware": "^0.19.1",
"husky": "1.3.1",
"lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3",
"node-sass": "^4.9.0",
"plop": "2.3.0",
"runjs": "^4.3.2",
"sass-loader": "^7.1.0",
"runjs": "4.3.2",
"sass": "1.26.10",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"script-loader": "0.7.2",
"serve-static": "^1.13.2",
"serve-static": "1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.0",
"vue-template-compiler": "2.6.10"

View File

@ -42,6 +42,7 @@ export function importTable(data) {
params: data
})
}
// 预览生成代码
export function previewTable(tableId) {
return request({
@ -49,6 +50,7 @@ export function previewTable(tableId) {
method: 'get'
})
}
// 删除表数据
export function delTable(tableId) {
return request({
@ -57,3 +59,11 @@ export function delTable(tableId) {
})
}
// 生成代码(自定义路径)
export function genCode(tableName) {
return request({
url: '/tool/gen/genCode/' + tableName,
method: 'get'
})
}

View File

@ -143,6 +143,27 @@
margin-bottom: 10px;
}
/* button color */
.el-button--cyan.is-active,
.el-button--cyan:active {
background: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
.el-button--cyan:focus,
.el-button--cyan:hover {
background: #48D1CC;
border-color: #48D1CC;
color: #FFFFFF;
}
.el-button--cyan {
background-color: #20B2AA;
border-color: #20B2AA;
color: #FFFFFF;
}
/* text color */
.text-navy {
color: #1ab394;
@ -199,3 +220,7 @@
color: #fff!important;
background: #42b983!important;
}
.top-right-btn {
float: right;
}

View File

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

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

View File

@ -18,7 +18,7 @@ import './assets/icons' // icon
import './permission' // permission control
import { getDicts } from "@/api/system/dict/data";
import { getConfigKey } from "@/api/system/config";
import { parseTime, resetForm, addDateRange, selectDictLabel, download, handleTree } from "@/utils/ruoyi";
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi";
import Pagination from "@/components/Pagination";
// 全局方法挂载
@ -28,6 +28,7 @@ Vue.prototype.parseTime = parseTime
Vue.prototype.resetForm = resetForm
Vue.prototype.addDateRange = addDateRange
Vue.prototype.selectDictLabel = selectDictLabel
Vue.prototype.selectDictLabels = selectDictLabels
Vue.prototype.download = download
Vue.prototype.handleTree = handleTree

View File

@ -77,6 +77,21 @@ export function selectDictLabel(datas, value) {
return actions.join('');
}
// 回显数据字典(字符串数组)
export function selectDictLabels(datas, value, separator) {
var actions = [];
var currentSeparator = undefined === separator ? "," : separator;
var temp = value.split(currentSeparator);
Object.keys(value.split(currentSeparator)).some((val) => {
Object.keys(datas).some((key) => {
if (datas[key].dictValue == ('' + temp[val])) {
actions.push(datas[key].dictLabel + currentSeparator);
}
})
})
return actions.join('').substring(0, actions.join('').length - 1);
}
// 通用下载方法
export function download(fileName) {
window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
@ -130,5 +145,5 @@ export function handleTree(data, id, parentId, children, rootId) {
return father[parentId] === rootId;
});
return treeData != '' ? treeData : data;
}
}

View File

@ -29,7 +29,7 @@
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" />
<img :src="codeUrl" @click="getCode" class="login-code-img"/>
</div>
</el-form-item>
<el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">记住密码</el-checkbox>
@ -200,4 +200,7 @@ export default {
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 38px;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
@ -31,7 +31,7 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -84,6 +84,14 @@
v-hasPermi="['monitor:job:query']"
>日志</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
@ -274,6 +282,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="任务名称" prop="jobName">
<el-input
v-model="queryParams.jobName"
@ -56,7 +56,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -90,6 +90,14 @@
v-hasPermi="['monitor:job:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
@ -175,6 +183,8 @@ export default {
ids: [],
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="登录地址" prop="ipaddr">
<el-input
v-model="queryParams.ipaddr"
@ -50,7 +50,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -84,6 +84,14 @@
v-hasPermi="['system:logininfor:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
@ -126,6 +134,8 @@ export default {
ids: [],
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -20,7 +20,7 @@
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="系统模块" prop="title">
<el-input
v-model="queryParams.title"
@ -66,7 +66,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -100,6 +100,14 @@
v-hasPermi="['system:config:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="list" @selection-change="handleSelectionChange">
@ -195,6 +203,8 @@ export default {
ids: [],
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="参数名称" prop="configName">
<el-input
v-model="queryParams.configName"
@ -44,7 +44,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -97,6 +97,14 @@
v-hasPermi="['system:config:remove']"
>清理缓存</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
@ -188,6 +196,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,7 +1,7 @@
<template>
<div class="app-container">
<el-form :inline="true">
<el-form-item label="部门名称">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
<el-form-item label="部门名称" prop="deptName">
<el-input
v-model="queryParams.deptName"
placeholder="请输入部门名称"
@ -10,7 +10,7 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态">
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="部门状态" clearable size="small">
<el-option
v-for="dict in statusOptions"
@ -21,23 +21,30 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索</el-button>
<el-button
class="filter-item"
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:dept:add']"
>新增</el-button>
</el-form-item>
</el-form>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table
v-loading="loading"
@ -149,6 +156,8 @@ export default {
return {
//
loading: true,
//
showSearch: true,
//
deptList: [],
//
@ -247,6 +256,11 @@ export default {
handleQuery() {
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset();

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
<el-form-item label="字典名称" prop="dictType">
<el-select v-model="queryParams.dictType" size="small">
<el-option
@ -31,7 +31,7 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -75,6 +75,14 @@
v-hasPermi="['system:dict:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
@ -170,6 +178,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="字典名称" prop="dictName">
<el-input
v-model="queryParams.dictName"
@ -50,7 +50,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -103,6 +103,14 @@
v-hasPermi="['system:dict:remove']"
>清理缓存</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
@ -196,6 +204,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,7 +1,7 @@
<template>
<div class="app-container">
<el-form :inline="true">
<el-form-item label="菜单名称">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch">
<el-form-item label="菜单名称" prop="menuName">
<el-input
v-model="queryParams.menuName"
placeholder="请输入菜单名称"
@ -10,7 +10,7 @@
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="状态">
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="菜单状态" clearable size="small">
<el-option
v-for="dict in statusOptions"
@ -21,11 +21,31 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:menu:add']">新增</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['system:menu:add']"
>新增</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table
v-loading="loading"
:data="menuList"
@ -197,6 +217,8 @@ export default {
return {
//
loading: true,
//
showSearch: true,
//
menuList: [],
//
@ -310,6 +332,11 @@ export default {
handleQuery() {
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset();

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="公告标题" prop="noticeTitle">
<el-input
v-model="queryParams.noticeTitle"
@ -30,7 +30,7 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -65,6 +65,14 @@
v-hasPermi="['system:notice:remove']"
>删除</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
@ -190,6 +198,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="岗位编码" prop="postCode">
<el-input
v-model="queryParams.postCode"
@ -30,7 +30,7 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -74,6 +74,14 @@
v-hasPermi="['system:post:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
@ -164,6 +172,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true">
<el-form :model="queryParams" ref="queryForm" v-show="showSearch" :inline="true">
<el-form-item label="角色名称" prop="roleName">
<el-input
v-model="queryParams.roleName"
@ -50,7 +50,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -91,9 +91,17 @@
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['system:post:export']"
v-hasPermi="['system:role:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
@ -249,6 +257,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -27,7 +27,7 @@
</el-col>
<!--用户数据-->
<el-col :span="20" :xs="24">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input
v-model="queryParams.userName"
@ -77,7 +77,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -130,6 +130,14 @@
v-hasPermi="['system:user:export']"
>导出</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
@ -356,6 +364,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//

View File

@ -6,7 +6,7 @@
<span slot="label">生成模板</span>
<el-select v-model="info.tplCategory">
<el-option label="单表(增删改查)" value="crud" />
<el-option label="树表(增删改查)" value="tree"/>
<el-option label="树表(增删改查)" value="tree" />
</el-select>
</el-form-item>
</el-col>
@ -60,14 +60,56 @@
</el-col>
<el-col :span="12">
<el-form-item prop="functionName">
<el-form-item>
<span slot="label">
上级菜单
<el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<treeselect :append-to-body="true" v-model="info.parentMenuId" :options="menus" :normalizer="normalizer" :show-count="true" placeholder="请选择系统菜单"/>
<treeselect
:append-to-body="true"
v-model="info.parentMenuId"
:options="menus"
:normalizer="normalizer"
:show-count="true"
placeholder="请选择系统菜单"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item prop="genType">
<span slot="label">
生成代码方式
<el-tooltip content="默认为zip压缩包下载也可以自定义生成路径" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
<el-radio v-model="info.genType" label="1">自定义路径</el-radio>
</el-form-item>
</el-col>
<el-col :span="24" v-if="info.genType == '1'">
<el-form-item prop="genPath">
<span slot="label">
自定义路径
<el-tooltip content="填写磁盘绝对路径若不填写则生成到当前Web项目下" placement="top">
<i class="el-icon-question"></i>
</el-tooltip>
</span>
<el-input v-model="info.genPath">
<el-dropdown slot="append">
<el-button type="primary">
最近路径快速选择
<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="info.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</el-input>
</el-form-item>
</el-col>
</el-row>
@ -165,7 +207,7 @@ export default {
],
functionName: [
{ required: true, message: "请输入生成功能名", trigger: "blur" }
]
],
}
};
},

View File

@ -1,6 +1,6 @@
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="表名称" prop="tableName">
<el-input
v-model="queryParams.tableName"
@ -32,7 +32,7 @@
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
@ -76,6 +76,14 @@
v-hasPermi="['tool:gen:remove']"
>删除</el-button>
</el-col>
<div class="top-right-btn">
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
<el-button size="mini" circle icon="el-icon-refresh" @click="handleQuery" />
</el-tooltip>
<el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
<el-button size="mini" circle icon="el-icon-search" @click="showSearch=!showSearch" />
</el-tooltip>
</div>
</el-row>
<el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange">
@ -166,7 +174,7 @@
</template>
<script>
import { listTable, previewTable, delTable } from "@/api/tool/gen";
import { listTable, previewTable, delTable, genCode } from "@/api/tool/gen";
import importTable from "./importTable";
import { downLoadZip } from "@/utils/zipdownload";
export default {
@ -186,6 +194,8 @@ export default {
single: true,
//
multiple: true,
//
showSearch: true,
//
total: 0,
//
@ -241,7 +251,13 @@ export default {
this.msgError("请选择要生成的数据");
return;
}
if(row.genType === "1") {
genCode(row.tableName).then(response => {
this.msgSuccess("成功生成到自定义路径:" + row.genPath);
});
} else {
downLoadZip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi");
}
},
/** 打开导入表弹窗 */
openImportTable() {

View File

@ -30,6 +30,7 @@ module.exports = {
devServer: {
host: '0.0.0.0',
port: port,
open: true,
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
@ -71,17 +72,6 @@ module.exports = {
})
.end()
// set preserveWhitespace
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
options.compilerOptions.preserveWhitespace = true
return options
})
.end()
config
.when(process.env.NODE_ENV !== 'development',
config => {

View File

@ -120,7 +120,7 @@ create table sys_role (
-- ----------------------------
-- 初始化-角色信息表数据
-- ----------------------------
insert into sys_role values('1', '系统管理员', 'admin', 1, 1, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统管理员');
insert into sys_role values('1', '超级管理员', 'admin', 1, 1, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '超级管理员');
insert into sys_role values('2', '普通角色', 'common', 2, 2, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '普通角色');
@ -635,6 +635,8 @@ create table gen_table (
business_name varchar(30) comment '生成业务名',
function_name varchar(50) comment '生成功能名',
function_author varchar(50) comment '生成功能作者',
gen_type char(1) default '0' comment '生成代码方式0zip压缩包 1自定义路径',
gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)',
options varchar(1000) comment '其它生成选项',
create_by varchar(64) default '' comment '创建者',
create_time datetime comment '创建时间',