38 Commits

Author SHA1 Message Date
RuoYi
8aca11c2a2 若依 3.6.6 2025-05-30 08:03:00 +08:00
RuoYi
725033e361 升级fastjson到最新版2.0.57 2025-05-26 11:14:45 +08:00
RuoYi
d29e49e23b 注册账号设置默认密码最后更新时间 2025-05-26 11:14:06 +08:00
RuoYi
706c3bb69b 添加底部版权信息及开关 2025-05-24 14:33:51 +08:00
RuoYi
cd0ee95b9c 添加页签图标显示开关功能 2025-05-23 14:57:49 +08:00
RuoYi
3293e2fb56 账号密码支持自定义更新周期 2025-05-23 10:19:47 +08:00
RuoYi
924ec0eb6e 初始密码支持自定义修改策略 2025-05-23 09:58:23 +08:00
RuoYi
135b1204a9 升级tomcat到最新版本9.0.105 2025-05-15 10:55:18 +08:00
RuoYi
cb566a704b 升级commons.io到最新版本2.19.0 2025-05-15 10:23:50 +08:00
RuoYi
aadba0382e delete vue-meta 2025-05-15 10:23:34 +08:00
RuoYi
a0ce1cf33b delete eslint 2025-05-15 10:22:46 +08:00
RuoYi
3915c77391 优化导航栏显示昵称&设置 2025-05-09 14:02:09 +08:00
RuoYi
b80932ceb4 菜单搜索支持键盘选择&悬浮主题背景 2025-05-07 13:27:13 +08:00
RuoYi
056cf94082 图片上传组件新增disabled属性 2025-05-06 19:14:54 +08:00
RuoYi
0dcd3e6183 add columnName Drag 2025-05-06 14:54:44 +08:00
RuoYi
07be5ceb26 修复上传组件被多次引用拖动仅对第一个有效的问题 2025-05-06 13:46:21 +08:00
RuoYi
cc59502d7c update icon 2025-05-05 11:22:35 +08:00
RuoYi
98738f23ad 上传组件新增拖动排序属性 2025-04-30 10:31:03 +08:00
RuoYi
57fe1c663e 优化Excel匹配数值型.0结尾 2025-04-28 11:20:48 +08:00
RuoYi
7b6fdb3a89 remove all semicolons 2025-04-27 11:56:21 +08:00
RuoYi
79c885decb 使用Gateway CacheRequestBody代替CacheRequestFilter 2025-04-25 15:11:17 +08:00
RuoYi
1a0f37a2dc 富文本复制粘贴图片上传至url 2025-04-24 18:19:16 +08:00
RuoYi
02de344d8c update package.json 2025-04-24 18:18:44 +08:00
RuoYi
189100f74e 优化低版本node无法启动的问题 2025-04-22 12:07:07 +08:00
RuoYi
e29284e687 优化代码 2025-04-22 12:06:59 +08:00
RuoYi
d4af286f41 显隐列组件支持全选/全不选 2025-04-21 15:30:32 +08:00
RuoYi
60e2d55a23 优化菜单搜索查询页 2025-04-21 13:28:32 +08:00
RuoYi
bbd112d5a3 支持文件&图片组件自定义地址&参数 2025-04-18 13:25:28 +08:00
RuoYi
90922844ea 优化角色禁用不允许分配 2025-04-17 15:36:18 +08:00
RuoYi
3a9f56f04b update status name 2025-04-17 15:35:58 +08:00
RuoYi
a1ec1d57d4 remove dev runjs 2025-03-18 16:01:46 +08:00
RuoYi
060959a7c5 登录页和注册页表头使用VUE_APP_TITLE配置值 2025-03-18 16:01:20 +08:00
RuoYi
43e1d8d573 升级tomcat到最新版本9.0.102 2025-03-14 16:12:40 +08:00
RuoYi
67cf51ba77 update handleTree 2025-03-14 16:12:29 +08:00
RuoYi
a256618d5d 优化代码 2025-03-11 12:52:17 +08:00
若依
a6bcebb62b !397 修复actuator暴漏问题
Merge pull request !397 from 威士忌的纯度/N/A
2025-03-10 03:45:34 +00:00
威士忌的纯度
1cb262daa3 修复actuator暴漏问题
Signed-off-by: 威士忌的纯度 <whr888888@vip.qq.com>
2025-03-07 10:22:52 +00:00
RuoYi
8c096cba8d 优化isAdmin方法,避免脱敏模块security依赖 2025-03-07 12:56:31 +08:00
145 changed files with 2784 additions and 2741 deletions

View File

@@ -1,11 +1,11 @@
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-b99b286755aef70355a7084753f89cdb7c9.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.5</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.6</h1>
<h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi-Cloud/stargazers"><img src="https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.5-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.6-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>

View File

@@ -9,7 +9,7 @@ usage() {
# copy sql
echo "begin copy sql "
cp ../sql/ry_20240629.sql ./mysql/db
cp ../sql/ry_20250523.sql ./mysql/db
cp ../sql/ry_config_20250224.sql ./mysql/db
# copy html

View File

@@ -29,7 +29,7 @@ http {
}
# 避免actuator暴露
if ($request_uri ~ "/actuator") {
if ($uri ~ "/actuator") {
return 403;
}

11
pom.xml
View File

@@ -6,14 +6,14 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依微服务系统</description>
<properties>
<ruoyi.version>3.6.5</ruoyi.version>
<ruoyi.version>3.6.6</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
@@ -26,17 +26,16 @@
<pagehelper.boot.version>2.0.0</pagehelper.boot.version>
<druid.version>1.2.23</druid.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<commons.io.version>2.13.0</commons.io.version>
<commons.io.version>2.19.0</commons.io.version>
<velocity.version>2.3</velocity.version>
<fastjson.version>2.0.53</fastjson.version>
<fastjson.version>2.0.57</fastjson.version>
<jjwt.version>0.9.1</jjwt.version>
<minio.version>8.2.2</minio.version>
<poi.version>4.1.2</poi.version>
<springdoc.version>1.6.9</springdoc.version>
<transmittable-thread-local.version>2.14.4</transmittable-thread-local.version>
<!-- override dependency version -->
<tomcat.version>9.0.98</tomcat.version>
<tomcat.version>9.0.105</tomcat.version>
<logback.version>1.2.13</logback.version>
<spring-framework.version>5.3.39</spring-framework.version>
</properties>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-api</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -8,6 +8,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.annotation.Excel.ColumnType;
import com.ruoyi.common.core.annotation.Excel.Type;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.annotation.Excels;
import com.ruoyi.common.core.web.domain.BaseEntity;
import com.ruoyi.common.core.xss.Xss;
@@ -55,8 +56,8 @@ public class SysUser extends BaseEntity
/** 密码 */
private String password;
/** 号状态0正常 1停用 */
@Excel(name = "号状态", readConverterExp = "0=正常,1=停用")
/** 号状态0正常 1停用 */
@Excel(name = "号状态", readConverterExp = "0=正常,1=停用")
private String status;
/** 删除标志0代表存在 2代表删除 */
@@ -70,6 +71,9 @@ public class SysUser extends BaseEntity
@Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
private Date loginDate;
/** 密码最后更新时间 */
private Date pwdUpdateDate;
/** 部门对象 */
@Excels({
@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
@@ -116,7 +120,7 @@ public class SysUser extends BaseEntity
public static boolean isAdmin(Long userId)
{
return userId != null && 1L == userId;
return UserConstants.isAdmin(userId);
}
public Long getDeptId()
@@ -247,6 +251,16 @@ public class SysUser extends BaseEntity
this.loginDate = loginDate;
}
public Date getPwdUpdateDate()
{
return pwdUpdateDate;
}
public void setPwdUpdateDate(Date pwdUpdateDate)
{
this.pwdUpdateDate = pwdUpdateDate;
}
public SysDept getDept()
{
return dept;
@@ -296,6 +310,7 @@ public class SysUser extends BaseEntity
{
this.roleId = roleId;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -312,6 +327,7 @@ public class SysUser extends BaseEntity
.append("delFlag", getDelFlag())
.append("loginIp", getLoginIp())
.append("loginDate", getLoginDate())
.append("pwdUpdateDate", getPwdUpdateDate())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -143,6 +143,7 @@ public class SysLoginService
SysUser sysUser = new SysUser();
sysUser.setUserName(username);
sysUser.setNickName(username);
sysUser.setPwdUpdateDate(DateUtils.getNowDate());
sysUser.setPassword(SecurityUtils.encryptPassword(password));
R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -80,4 +80,9 @@ public class UserConstants
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
public static boolean isAdmin(Long userId)
{
return userId != null && 1L == userId;
}
}

View File

@@ -136,6 +136,14 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return new Date(time);
}
/**
* 计算相差天数
*/
public static int differentDaysByMillisecond(Date date1, Date date2)
{
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
}
/**
* 计算时间差
*

View File

@@ -390,7 +390,7 @@ public class ExcelUtil<T>
if (String.class == fieldType)
{
String s = Convert.toStr(val);
if (StringUtils.endsWith(s, ".0"))
if (s.matches("^\\d+\\.0$"))
{
val = StringUtils.substringBefore(s, ".0");
}

View File

@@ -343,25 +343,25 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
// time_low
builder.append(digits(mostSigBits >> 32, 8));
if (false == isSimple)
if (!isSimple)
{
builder.append('-');
}
// time_mid
builder.append(digits(mostSigBits >> 16, 4));
if (false == isSimple)
if (!isSimple)
{
builder.append('-');
}
// time_high_and_version
builder.append(digits(mostSigBits, 4));
if (false == isSimple)
if (!isSimple)
{
builder.append('-');
}
// variant_and_sequence
builder.append(digits(leastSigBits >> 48, 4));
if (false == isSimple)
if (!isSimple)
{
builder.append('-');
}

View File

@@ -7,12 +7,17 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.PageUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.sql.SqlUtil;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageDomain;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.core.web.page.TableSupport;
/**
* web层通用数据处理
@@ -48,6 +53,19 @@ public class BaseController
PageUtils.startPage();
}
/**
* 设置请求排序数据
*/
protected void startOrderBy()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
PageHelper.orderBy(orderBy);
}
}
/**
* 清理分页的线程变量
*/

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -56,16 +56,8 @@ public class PreAuthorizeAspect
// 注解鉴权
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
checkMethodAnnotation(signature.getMethod());
try
{
// 执行原有逻辑
Object obj = joinPoint.proceed();
return obj;
}
catch (Throwable e)
{
throw e;
}
// 执行原有逻辑
return joinPoint.proceed();
}
/**

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -17,10 +17,10 @@
<dependencies>
<!-- RuoYi Common Security -->
<!-- RuoYi Common Core -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-security</artifactId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
</dependencies>

View File

@@ -8,10 +8,10 @@ import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.context.SecurityContextHolder;
import com.ruoyi.common.sensitive.annotation.Sensitive;
import com.ruoyi.common.sensitive.enums.DesensitizedType;
import com.ruoyi.system.api.model.LoginUser;
/**
* 数据脱敏序列化过滤
@@ -55,9 +55,9 @@ public class SensitiveJsonSerializer extends JsonSerializer<String> implements C
{
try
{
LoginUser securityUser = SecurityUtils.getLoginUser();
Long userId = SecurityContextHolder.getUserId();
// 管理员不脱敏
return !securityUser.getSysUser().isAdmin();
return !UserConstants.isAdmin(userId);
}
catch (Exception e)
{

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,87 +0,0 @@
package com.ruoyi.gateway.filter;
import java.util.Collections;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 获取body请求数据解决流不能重复读取问题
*
* @author ruoyi
*/
@Component
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
{
public CacheRequestFilter()
{
super(Config.class);
}
@Override
public String name()
{
return "CacheRequestFilter";
}
@Override
public GatewayFilter apply(Config config)
{
CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
Integer order = config.getOrder();
if (order == null)
{
return cacheRequestGatewayFilter;
}
return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
}
public static class CacheRequestGatewayFilter implements GatewayFilter
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
// GET DELETE 不过滤
HttpMethod method = exchange.getRequest().getMethod();
if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE)
{
return chain.filter(exchange);
}
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> {
if (serverHttpRequest == exchange.getRequest())
{
return chain.filter(exchange);
}
return chain.filter(exchange.mutate().request(serverHttpRequest).build());
});
}
}
@Override
public List<String> shortcutFieldOrder()
{
return Collections.singletonList("order");
}
static class Config
{
private Integer order;
public Integer getOrder()
{
return order;
}
public void setOrder(Integer order)
{
this.order = order;
}
}
}

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -57,7 +57,7 @@ public class GenController extends BaseController
}
/**
* 修改代码生成业务
* 获取代码生成信息
*/
@RequiresPermissions("tool:gen:query")
@GetMapping(value = "/{tableId}")

View File

@@ -283,9 +283,9 @@
</template>
<script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
export default {
name: "${BusinessName}",
@@ -346,18 +346,18 @@ export default {
#end
#end
}
};
}
},
created() {
this.getList();
this.getList()
},
methods: {
/** 查询${functionName}列表 */
getList() {
this.loading = true;
this.loading = true
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {};
this.queryParams.params = {}
#break
#end
#end
@@ -365,40 +365,40 @@ export default {
#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];
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 => {
this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
this.loading = false;
});
this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
this.loading = false
})
},
/** 转换${functionName}数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
delete node.children
}
return {
id: node.${treeCode},
label: node.${treeName},
children: node.children
};
}
},
/** 查询${functionName}下拉树结构 */
getTreeselect() {
list${BusinessName}().then(response => {
this.${businessName}Options = [];
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
this.${businessName}Options.push(data);
});
this.${businessName}Options = []
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
this.${businessName}Options.push(data)
})
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
this.open = false
this.reset()
},
// 表单重置
reset() {
@@ -410,61 +410,61 @@ export default {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
};
this.resetForm("form");
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.getList();
this.getList()
},
/** 重置按钮操作 */
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} = [];
this.daterange${AttrName} = []
#end
#end
this.resetForm("queryForm");
this.handleQuery();
this.resetForm("queryForm")
this.handleQuery()
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset();
this.getTreeselect();
this.reset()
this.getTreeselect()
if (row != null && row.${treeCode}) {
this.form.${treeParentCode} = row.${treeCode};
this.form.${treeParentCode} = row.${treeCode}
} else {
this.form.${treeParentCode} = 0;
this.form.${treeParentCode} = 0
}
this.open = true;
this.title = "添加${functionName}";
this.open = true
this.title = "添加${functionName}"
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.refreshTable = false
this.isExpandAll = !this.isExpandAll
this.$nextTick(() => {
this.refreshTable = true;
});
this.refreshTable = true
})
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.getTreeselect();
this.reset()
this.getTreeselect()
if (row != null) {
this.form.${treeParentCode} = row.${treeParentCode};
this.form.${treeParentCode} = row.${treeParentCode}
}
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
this.form = response.data;
this.form = response.data
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
this.form.$column.javaField = this.form.${column.javaField}.split(",")
#end
#end
this.open = true;
this.title = "修改${functionName}";
});
this.open = true
this.title = "修改${functionName}"
})
},
/** 提交按钮 */
submitForm() {
@@ -472,34 +472,34 @@ export default {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
this.form.$column.javaField = this.form.${column.javaField}.join(",")
#end
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("修改成功");
this.open = false;
this.getList();
});
this.#[[$modal]]#.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
add${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("新增成功");
this.open = false;
this.getList();
});
this.#[[$modal]]#.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
});
})
},
/** 删除按钮操作 */
handleDelete(row) {
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
return del${BusinessName}(row.${pkColumn.javaField});
return del${BusinessName}(row.${pkColumn.javaField})
}).then(() => {
this.getList();
this.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
this.getList()
this.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
}
}
};
}
</script>

View File

@@ -11,7 +11,7 @@
#else
#set($comment=$column.columnComment)
#end
#if($column.htmlType == "input" || $column.htmlType == "textarea")
#if($column.htmlType == "input")
<el-form-item label="${comment}" prop="${column.javaField}">
<el-input
v-model="queryParams.${column.javaField}"
@@ -353,7 +353,7 @@
</template>
<script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
export default {
name: "${BusinessName}",
@@ -423,18 +423,18 @@ export default {
#end
#end
}
};
}
},
created() {
this.getList();
this.getList()
},
methods: {
/** 查询${functionName}列表 */
getList() {
this.loading = true;
this.loading = true
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {};
this.queryParams.params = {}
#break
#end
#end
@@ -442,21 +442,21 @@ export default {
#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];
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 => {
this.${businessName}List = response.rows;
this.total = response.total;
this.loading = false;
});
this.${businessName}List = response.rows
this.total = response.total
this.loading = false
})
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
this.open = false
this.reset()
},
// 表单重置
reset() {
@@ -468,27 +468,27 @@ export default {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
};
}
#if($table.sub)
this.${subclassName}List = [];
this.${subclassName}List = []
#end
this.resetForm("form");
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
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} = [];
this.daterange${AttrName} = []
#end
#end
this.resetForm("queryForm");
this.handleQuery();
this.resetForm("queryForm")
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
@@ -498,27 +498,27 @@ export default {
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.open = true;
this.title = "添加${functionName}";
this.reset()
this.open = true
this.title = "添加${functionName}"
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.reset()
const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
get${BusinessName}(${pkColumn.javaField}).then(response => {
this.form = response.data;
this.form = response.data
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
this.form.$column.javaField = this.form.${column.javaField}.split(",")
#end
#end
#if($table.sub)
this.${subclassName}List = response.data.${subclassName}List;
this.${subclassName}List = response.data.${subclassName}List
#end
this.open = true;
this.title = "修改${functionName}";
});
this.open = true
this.title = "修改${functionName}"
})
},
/** 提交按钮 */
submitForm() {
@@ -526,64 +526,64 @@ export default {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
this.form.$column.javaField = this.form.${column.javaField}.join(",")
#end
#end
#if($table.sub)
this.form.${subclassName}List = this.${subclassName}List;
this.form.${subclassName}List = this.${subclassName}List
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("修改成功");
this.open = false;
this.getList();
});
this.#[[$modal]]#.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
add${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("新增成功");
this.open = false;
this.getList();
});
this.#[[$modal]]#.msgSuccess("新增成功")
this.open = false
this.getList()
})
}
}
});
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids;
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
return del${BusinessName}(${pkColumn.javaField}s);
return del${BusinessName}(${pkColumn.javaField}s)
}).then(() => {
this.getList();
this.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
this.getList()
this.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
},
#if($table.sub)
/** ${subTable.functionName}序号 */
row${subClassName}Index({ row, rowIndex }) {
row.index = rowIndex + 1;
row.index = rowIndex + 1
},
/** ${subTable.functionName}添加按钮操作 */
handleAdd${subClassName}() {
let obj = {};
let obj = {}
#foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
obj.$column.javaField = "";
obj.$column.javaField = ""
#end
#end
this.${subclassName}List.push(obj);
this.${subclassName}List.push(obj)
},
/** ${subTable.functionName}删除按钮操作 */
handleDelete${subClassName}() {
if (this.checked${subClassName}.length == 0) {
this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
} else {
const ${subclassName}List = this.${subclassName}List;
const checked${subClassName} = this.checked${subClassName};
const ${subclassName}List = this.${subclassName}List
const checked${subClassName} = this.checked${subClassName}
this.${subclassName}List = ${subclassName}List.filter(function(item) {
return checked${subClassName}.indexOf(item.index) == -1
});
})
}
},
/** 复选框选中数据 */
@@ -598,5 +598,5 @@ export default {
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
}
}
};
}
</script>

View File

@@ -271,26 +271,26 @@
</template>
<script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance()
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
const { ${dictsNoSymbol} } = proxy.useDict(${dicts})
#end
const ${businessName}List = ref([]);
const ${businessName}Options = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
const ${businessName}List = ref([])
const ${businessName}Options = ref([])
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const title = ref("")
const isExpandAll = ref(true)
const refreshTable = ref(true)
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([]);
const daterange${AttrName} = ref([])
#end
#end
@@ -318,16 +318,16 @@ const data = reactive({
#end
#end
}
});
})
const { queryParams, form, rules } = toRefs(data);
const { queryParams, form, rules } = toRefs(data)
/** 查询${functionName}列表 */
function getList() {
loading.value = true;
loading.value = true
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
queryParams.value.params = {};
queryParams.value.params = {}
#break
#end
#end
@@ -335,31 +335,31 @@ function getList() {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != daterange${AttrName} && '' != daterange${AttrName}) {
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]
}
#end
#end
list${BusinessName}(queryParams.value).then(response => {
${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
loading.value = false;
});
${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}")
loading.value = false
})
}
/** 查询${functionName}下拉树结构 */
function getTreeselect() {
list${BusinessName}().then(response => {
${businessName}Options.value = [];
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
${businessName}Options.value.push(data);
});
${businessName}Options.value = []
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}")
${businessName}Options.value.push(data)
})
}
// 取消按钮
function cancel() {
open.value = false;
reset();
open.value = false
reset()
}
// 表单重置
@@ -372,13 +372,13 @@ function reset() {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
};
proxy.resetForm("${businessName}Ref");
}
proxy.resetForm("${businessName}Ref")
}
/** 搜索按钮操作 */
function handleQuery() {
getList();
getList()
}
/** 重置按钮操作 */
@@ -386,52 +386,52 @@ function resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
daterange${AttrName}.value = [];
daterange${AttrName}.value = []
#end
#end
proxy.resetForm("queryRef");
handleQuery();
proxy.resetForm("queryRef")
handleQuery()
}
/** 新增按钮操作 */
function handleAdd(row) {
reset();
getTreeselect();
reset()
getTreeselect()
if (row != null && row.${treeCode}) {
form.value.${treeParentCode} = row.${treeCode};
form.value.${treeParentCode} = row.${treeCode}
} else {
form.value.${treeParentCode} = 0;
form.value.${treeParentCode} = 0
}
open.value = true;
title.value = "添加${functionName}";
open.value = true
title.value = "添加${functionName}"
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
refreshTable.value = false
isExpandAll.value = !isExpandAll.value
nextTick(() => {
refreshTable.value = true;
});
refreshTable.value = true
})
}
/** 修改按钮操作 */
async function handleUpdate(row) {
reset();
await getTreeselect();
reset()
await getTreeselect()
if (row != null) {
form.value.${treeParentCode} = row.${treeParentCode};
form.value.${treeParentCode} = row.${treeParentCode}
}
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
form.value = response.data;
form.value = response.data
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(",");
form.value.$column.javaField = form.value.${column.javaField}.split(",")
#end
#end
open.value = true;
title.value = "修改${functionName}";
});
open.value = true
title.value = "修改${functionName}"
})
}
/** 提交按钮 */
@@ -440,35 +440,35 @@ function submitForm() {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(",");
form.value.$column.javaField = form.value.${column.javaField}.join(",")
#end
#end
if (form.value.${pkColumn.javaField} != null) {
update${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("修改成功");
open.value = false;
getList();
});
proxy.#[[$modal]]#.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
add${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("新增成功");
open.value = false;
getList();
});
proxy.#[[$modal]]#.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
});
})
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
return del${BusinessName}(row.${pkColumn.javaField});
return del${BusinessName}(row.${pkColumn.javaField})
}).then(() => {
getList();
proxy.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
getList()
proxy.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
}
getList();
getList()
</script>

View File

@@ -343,33 +343,33 @@
</template>
<script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance()
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
const { ${dictsNoSymbol} } = proxy.useDict(${dicts})
#end
const ${businessName}List = ref([]);
const ${businessName}List = ref([])
#if($table.sub)
const ${subclassName}List = ref([]);
const ${subclassName}List = ref([])
#end
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
#if($table.sub)
const checked${subClassName} = ref([]);
const checked${subClassName} = ref([])
#end
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const title = ref("")
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([]);
const daterange${AttrName} = ref([])
#end
#end
@@ -399,16 +399,16 @@ const data = reactive({
#end
#end
}
});
})
const { queryParams, form, rules } = toRefs(data);
const { queryParams, form, rules } = toRefs(data)
/** 查询${functionName}列表 */
function getList() {
loading.value = true;
loading.value = true
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
queryParams.value.params = {};
queryParams.value.params = {}
#break
#end
#end
@@ -416,22 +416,22 @@ function getList() {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != daterange${AttrName} && '' != daterange${AttrName}) {
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]
}
#end
#end
list${BusinessName}(queryParams.value).then(response => {
${businessName}List.value = response.rows;
total.value = response.total;
loading.value = false;
});
${businessName}List.value = response.rows
total.value = response.total
loading.value = false
})
}
// 取消按钮
function cancel() {
open.value = false;
reset();
open.value = false
reset()
}
// 表单重置
@@ -444,17 +444,17 @@ function reset() {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
};
}
#if($table.sub)
${subclassName}List.value = [];
${subclassName}List.value = []
#end
proxy.resetForm("${businessName}Ref");
proxy.resetForm("${businessName}Ref")
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1;
getList();
queryParams.value.pageNum = 1
getList()
}
/** 重置按钮操作 */
@@ -462,44 +462,44 @@ function resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
daterange${AttrName}.value = [];
daterange${AttrName}.value = []
#end
#end
proxy.resetForm("queryRef");
handleQuery();
proxy.resetForm("queryRef")
handleQuery()
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.${pkColumn.javaField});
single.value = selection.length != 1;
multiple.value = !selection.length;
ids.value = selection.map(item => item.${pkColumn.javaField})
single.value = selection.length != 1
multiple.value = !selection.length
}
/** 新增按钮操作 */
function handleAdd() {
reset();
open.value = true;
title.value = "添加${functionName}";
reset()
open.value = true
title.value = "添加${functionName}"
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset();
reset()
const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
get${BusinessName}(_${pkColumn.javaField}).then(response => {
form.value = response.data;
form.value = response.data
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(",");
form.value.$column.javaField = form.value.${column.javaField}.split(",")
#end
#end
#if($table.sub)
${subclassName}List.value = response.data.${subclassName}List;
${subclassName}List.value = response.data.${subclassName}List
#end
open.value = true;
title.value = "修改${functionName}";
});
open.value = true
title.value = "修改${functionName}"
})
}
/** 提交按钮 */
@@ -508,68 +508,68 @@ function submitForm() {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(",");
form.value.$column.javaField = form.value.${column.javaField}.join(",")
#end
#end
#if($table.sub)
form.value.${subclassName}List = ${subclassName}List.value;
form.value.${subclassName}List = ${subclassName}List.value
#end
if (form.value.${pkColumn.javaField} != null) {
update${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("修改成功");
open.value = false;
getList();
});
proxy.#[[$modal]]#.msgSuccess("修改成功")
open.value = false
getList()
})
} else {
add${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("新增成功");
open.value = false;
getList();
});
proxy.#[[$modal]]#.msgSuccess("新增成功")
open.value = false
getList()
})
}
}
});
})
}
/** 删除按钮操作 */
function handleDelete(row) {
const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value;
const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value
proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?').then(function() {
return del${BusinessName}(_${pkColumn.javaField}s);
return del${BusinessName}(_${pkColumn.javaField}s)
}).then(() => {
getList();
proxy.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
getList()
proxy.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
}
#if($table.sub)
/** ${subTable.functionName}序号 */
function row${subClassName}Index({ row, rowIndex }) {
row.index = rowIndex + 1;
row.index = rowIndex + 1
}
/** ${subTable.functionName}添加按钮操作 */
function handleAdd${subClassName}() {
let obj = {};
let obj = {}
#foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
obj.$column.javaField = "";
obj.$column.javaField = ""
#end
#end
${subclassName}List.value.push(obj);
${subclassName}List.value.push(obj)
}
/** ${subTable.functionName}删除按钮操作 */
function handleDelete${subClassName}() {
if (checked${subClassName}.value.length == 0) {
proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
} else {
const ${subclassName}s = ${subclassName}List.value;
const checked${subClassName}s = checked${subClassName}.value;
const ${subclassName}s = ${subclassName}List.value
const checked${subClassName}s = checked${subClassName}.value
${subclassName}List.value = ${subclassName}s.filter(function(item) {
return checked${subClassName}s.indexOf(item.index) == -1
});
})
}
}
@@ -586,5 +586,5 @@ function handleExport() {
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
}
getList();
getList()
</script>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -178,7 +178,7 @@ public class SysJobController extends BaseController
@RequiresPermissions("monitor:job:remove")
@Log(title = "定时任务", businessType = BusinessType.DELETE)
@DeleteMapping("/{jobIds}")
public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException
public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException
{
jobService.deleteJobByIds(jobIds);
return success();

View File

@@ -3,7 +3,6 @@ package com.ruoyi.job.util;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.core.constant.ScheduleConstants;
@@ -30,7 +29,7 @@ public abstract class AbstractQuartzJob implements Job
private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
@Override
public void execute(JobExecutionContext context) throws JobExecutionException
public void execute(JobExecutionContext context)
{
SysJob sysJob = new SysJob();
BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.5</version>
<version>3.6.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.file.MimeTypeUtils;
@@ -112,7 +113,8 @@ public class SysProfileController extends BaseController
newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(userName, newPassword) > 0)
{
// 更新缓存用户密码
// 更新缓存用户密码&密码最后更新时间
loginUser.getSysUser().setPwdUpdateDate(DateUtils.getNowDate());
loginUser.getSysUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser);
return success();

View File

@@ -1,6 +1,7 @@
package com.ruoyi.system.controller;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -18,6 +19,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
@@ -186,9 +189,35 @@ public class SysUserController extends BaseController
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
return ajax;
}
// 检查初始密码是否提醒修改
public boolean initPasswordIsModify(Date pwdUpdateDate)
{
Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
}
// 检查密码是否过期
public boolean passwordIsExpiration(Date pwdUpdateDate)
{
Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
if (passwordValidateDays != null && passwordValidateDays > 0)
{
if (StringUtils.isNull(pwdUpdateDate))
{
// 如果从未修改过初始密码,直接提醒过期
return true;
}
Date nowDate = DateUtils.getNowDate();
return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
}
return false;
}
/**
* 根据用户编号获取详细信息
*/

View File

@@ -5,24 +5,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.ruoyi.system.mapper.SysUserMapper">
<resultMap type="SysUser" id="SysUserResult">
<id property="userId" column="user_id" />
<result property="deptId" column="dept_id" />
<result property="userName" column="user_name" />
<result property="nickName" column="nick_name" />
<result property="email" column="email" />
<result property="phonenumber" column="phonenumber" />
<result property="sex" column="sex" />
<result property="avatar" column="avatar" />
<result property="password" column="password" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="loginIp" column="login_ip" />
<result property="loginDate" column="login_date" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<id property="userId" column="user_id" />
<result property="deptId" column="dept_id" />
<result property="userName" column="user_name" />
<result property="nickName" column="nick_name" />
<result property="email" column="email" />
<result property="phonenumber" column="phonenumber" />
<result property="sex" column="sex" />
<result property="avatar" column="avatar" />
<result property="password" column="password" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="loginIp" column="login_ip" />
<result property="loginDate" column="login_date" />
<result property="pwdUpdateDate" column="pwd_update_date" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<association property="dept" javaType="SysDept" resultMap="deptResult" />
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" />
</resultMap>
@@ -47,7 +48,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectUserVo">
select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.pwd_update_date, u.create_by, u.create_time, u.remark,
d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
from sys_user u
@@ -146,6 +147,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
insert into sys_user(
<if test="userId != null and userId != 0">user_id,</if>
<if test="deptId != null and deptId != 0">dept_id,</if>
<if test="userName != null and userName != ''">user_name,</if>
<if test="nickName != null and nickName != ''">nick_name,</if>
<if test="email != null and email != ''">email,</if>
<if test="avatar != null and avatar != ''">avatar,</if>
@@ -153,6 +155,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sex != null and sex != ''">sex,</if>
<if test="password != null and password != ''">password,</if>
<if test="status != null and status != ''">status,</if>
<if test="pwdUpdateDate != null">pwd_update_date,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
@@ -167,6 +170,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sex != null and sex != ''">#{sex},</if>
<if test="password != null and password != ''">#{password},</if>
<if test="status != null and status != ''">#{status},</if>
<if test="pwdUpdateDate != null">#{pwdUpdateDate},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
@@ -177,7 +181,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
update sys_user
<set>
<if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
<if test="userName != null and userName != ''">user_name = #{userName},</if>
<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
<if test="email != null ">email = #{email},</if>
<if test="phonenumber != null ">phonenumber = #{phonenumber},</if>
@@ -203,7 +206,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update>
<update id="resetUserPwd" parameterType="SysUser">
update sys_user set password = #{password} where user_name = #{userName}
update sys_user set pwd_update_date = sysdate(), password = #{password} where user_name = #{userName}
</update>
<delete id="deleteUserById" parameterType="Long">

View File

@@ -1,10 +0,0 @@
# 忽略build目录下类型为js的文件的语法检查
build/*.js
# 忽略src/assets目录下文件的语法检查
src/assets
# 忽略public目录下文件的语法检查
public
# 忽略当前目录下为js的文件的语法检查
*.js
# 忽略当前目录下为vue的文件的语法检查
*.vue

View File

@@ -1,199 +0,0 @@
// ESlint 检查配置
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true,
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
//it is base on https://github.com/vuejs/eslint-config-vue
rules: {
"vue/max-attributes-per-line": [2, {
"singleline": 10,
"multiline": {
"max": 1,
"allowFirstLine": false
}
}],
"vue/singleline-html-element-content-newline": "off",
"vue/multiline-html-element-content-newline":"off",
"vue/name-property-casing": ["error", "PascalCase"],
"vue/no-v-html": "off",
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
'after': true
}],
'block-spacing': [2, 'always'],
'brace-style': [2, '1tbs', {
'allowSingleLine': true
}],
'camelcase': [0, {
'properties': 'always'
}],
'comma-dangle': [2, 'never'],
'comma-spacing': [2, {
'before': false,
'after': true
}],
'comma-style': [2, 'last'],
'constructor-super': 2,
'curly': [2, 'multi-line'],
'dot-location': [2, 'property'],
'eol-last': 2,
'eqeqeq': ["error", "always", {"null": "ignore"}],
'generator-star-spacing': [2, {
'before': true,
'after': true
}],
'handle-callback-err': [2, '^(err|error)$'],
'indent': [2, 2, {
'SwitchCase': 1
}],
'jsx-quotes': [2, 'prefer-single'],
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true
}],
'keyword-spacing': [2, {
'before': true,
'after': true
}],
'new-cap': [2, {
'newIsCap': true,
'capIsNew': false
}],
'new-parens': 2,
'no-array-constructor': 2,
'no-caller': 2,
'no-console': 'off',
'no-class-assign': 2,
'no-cond-assign': 2,
'no-const-assign': 2,
'no-control-regex': 0,
'no-delete-var': 2,
'no-dupe-args': 2,
'no-dupe-class-members': 2,
'no-dupe-keys': 2,
'no-duplicate-case': 2,
'no-empty-character-class': 2,
'no-empty-pattern': 2,
'no-eval': 2,
'no-ex-assign': 2,
'no-extend-native': 2,
'no-extra-bind': 2,
'no-extra-boolean-cast': 2,
'no-extra-parens': [2, 'functions'],
'no-fallthrough': 2,
'no-floating-decimal': 2,
'no-func-assign': 2,
'no-implied-eval': 2,
'no-inner-declarations': [2, 'functions'],
'no-invalid-regexp': 2,
'no-irregular-whitespace': 2,
'no-iterator': 2,
'no-label-var': 2,
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false
}],
'no-lone-blocks': 2,
'no-mixed-spaces-and-tabs': 2,
'no-multi-spaces': 2,
'no-multi-str': 2,
'no-multiple-empty-lines': [2, {
'max': 1
}],
'no-native-reassign': 2,
'no-negated-in-lhs': 2,
'no-new-object': 2,
'no-new-require': 2,
'no-new-symbol': 2,
'no-new-wrappers': 2,
'no-obj-calls': 2,
'no-octal': 2,
'no-octal-escape': 2,
'no-path-concat': 2,
'no-proto': 2,
'no-redeclare': 2,
'no-regex-spaces': 2,
'no-return-assign': [2, 'except-parens'],
'no-self-assign': 2,
'no-self-compare': 2,
'no-sequences': 2,
'no-shadow-restricted-names': 2,
'no-spaced-func': 2,
'no-sparse-arrays': 2,
'no-this-before-super': 2,
'no-throw-literal': 2,
'no-trailing-spaces': 2,
'no-undef': 2,
'no-undef-init': 2,
'no-unexpected-multiline': 2,
'no-unmodified-loop-condition': 2,
'no-unneeded-ternary': [2, {
'defaultAssignment': false
}],
'no-unreachable': 2,
'no-unsafe-finally': 2,
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}],
'no-useless-call': 2,
'no-useless-computed-key': 2,
'no-useless-constructor': 2,
'no-useless-escape': 0,
'no-whitespace-before-property': 2,
'no-with': 2,
'one-var': [2, {
'initialized': 'never'
}],
'operator-linebreak': [2, 'after', {
'overrides': {
'?': 'before',
':': 'before'
}
}],
'padded-blocks': [2, 'never'],
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true
}],
'semi': [2, 'never'],
'semi-spacing': [2, {
'before': false,
'after': true
}],
'space-before-blocks': [2, 'always'],
'space-before-function-paren': [2, 'never'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [2, {
'words': true,
'nonwords': false
}],
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}],
'template-curly-spacing': [2, 'never'],
'use-isnan': 2,
'valid-typeof': 2,
'wrap-iife': [2, 'any'],
'yield-star-spacing': [2, 'both'],
'yoda': [2, 'never'],
'prefer-const': 2,
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'object-curly-spacing': [2, 'always', {
objectsInObjects: false
}],
'array-bracket-spacing': [2, 'never']
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "ruoyi",
"version": "3.6.5",
"version": "3.6.6",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
@@ -8,19 +8,7 @@
"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",
"lint": "eslint --ext .js,.vue src"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
"preview": "node build/index.js --preview"
},
"keywords": [
"vue",
@@ -56,24 +44,17 @@
"vue": "2.6.12",
"vue-count-to": "1.0.13",
"vue-cropper": "0.5.5",
"vue-meta": "2.4.0",
"vue-router": "3.4.9",
"vuedraggable": "2.24.3",
"vuex": "3.6.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.6",
"@vue/cli-plugin-eslint": "4.4.6",
"@vue/cli-service": "4.4.6",
"babel-eslint": "10.1.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "4.1.0",
"compression-webpack-plugin": "6.1.2",
"connect": "3.6.6",
"eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3",
"runjs": "4.4.2",
"sass": "1.32.13",
"sass-loader": "10.1.1",
"script-ext-html-webpack-plugin": "2.1.5",

View File

@@ -6,20 +6,12 @@
</template>
<script>
import ThemePicker from "@/components/ThemePicker";
import ThemePicker from "@/components/ThemePicker"
export default {
name: "App",
components: { ThemePicker },
metaInfo() {
return {
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
titleTemplate: title => {
return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
}
}
}
};
components: { ThemePicker }
}
</script>
<style scoped>
#app .theme-picker {

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746590936918" class="icon" viewBox="0 0 1194 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5378" xmlns:xlink="http://www.w3.org/1999/xlink" width="233.203125" height="200"><path d="M1151.9144 325.11999969V89.12a57.04000031 57.04000031 0 0 0-28.8-49.44 58.15999969 58.15999969 0 0 0-57.76000031 0 57.04000031 57.04000031 0 0 0-28.8 49.44v235.99999969c0.24 84.31999969-33.6 152.56000031-94.08 212.00000062-60.07999969 59.83999969-141.84 80.64-227.04 80.4H225.91440031L388.07439969 457.11999969a56.80000031 56.80000031 0 0 0 12.40000031-62.16 57.76000031 57.76000031 0 0 0-94.00000031-18.63999938L48.8744 631.20000031a56.88 56.88 0 0 0 0 80.79999938l264.96 262.56a58.08 58.08 0 0 0 96.55999969-25.59999938 56.80000031 56.80000031 0 0 0-14.95999969-55.2L232.07439969 731.67999969h483.44000062c116.56000031 0 226.15999969-32.08000031 308.64-113.76 82.15999969-80.80000031 128.23999969-178.15999969 127.83999938-292.87999969" p-id="5379"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746760911144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12537" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M395.21211 182.914448c0 62.669318 49.541323 113.472378 110.642936 113.472378 61.093427 0 110.652146-50.80306 110.65214601-113.472378 0-62.685691-49.559742-113.487727-110.65214601-113.487727C444.75241 69.426721 395.21211 120.22978 395.21211 182.914448zM395.21211 523.34693101c0 62.668295 49.541323 113.487727 110.642936 113.48772699 61.093427 0 110.652146-50.820456 110.652146-113.487727 0-62.669318-49.559742-113.472378-110.652146-113.472378C444.75241 409.874553 395.21211 460.67761301 395.21211 523.34693101zM395.21211 841.084529c0 62.686714 49.541323 113.488751 110.642936 113.488751 61.093427 0 110.652146-50.80203599 110.65214601-113.488751 0-62.669318-49.559742-113.471354-110.65214601-113.471354C444.75241 727.614198 395.21211 778.416234 395.21211 841.084529z" p-id="12538"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -25,7 +25,7 @@
z-index: 1001;
overflow: hidden;
-webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
box-shadow: 2px 0 6px rgba(0,21,41,.35);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
// reset element-ui css
.horizontal-collapse-transition {

View File

@@ -71,58 +71,58 @@ export default {
methods: {
// 单选按钮值变化时
radioChange() {
('day rachange');
('day rachange')
if (this.radioValue !== 2 && this.cron.week !== '?') {
this.$emit('update', 'week', '?', 'day')
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'day', '*');
break;
this.$emit('update', 'day', '*')
break
case 2:
this.$emit('update', 'day', '?');
break;
this.$emit('update', 'day', '?')
break
case 3:
this.$emit('update', 'day', this.cycleTotal);
break;
this.$emit('update', 'day', this.cycleTotal)
break
case 4:
this.$emit('update', 'day', this.averageTotal);
break;
this.$emit('update', 'day', this.averageTotal)
break
case 5:
this.$emit('update', 'day', this.workday + 'W');
break;
this.$emit('update', 'day', this.workday + 'W')
break
case 6:
this.$emit('update', 'day', 'L');
break;
this.$emit('update', 'day', 'L')
break
case 7:
this.$emit('update', 'day', this.checkboxString);
break;
this.$emit('update', 'day', this.checkboxString)
break
}
('day rachange end');
('day rachange end')
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'day', this.cycleTotal);
this.$emit('update', 'day', this.cycleTotal)
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'day', this.averageTotal);
this.$emit('update', 'day', this.averageTotal)
}
},
// 最近工作日值变化时
workdayChange() {
if (this.radioValue == '5') {
this.$emit('update', 'day', this.workdayCheck + 'W');
this.$emit('update', 'day', this.workdayCheck + 'W')
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '7') {
this.$emit('update', 'day', this.checkboxString);
this.$emit('update', 'day', this.checkboxString)
}
}
},
@@ -138,23 +138,23 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 1, 30)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 31, 31)
return cycle01 + '-' + cycle02;
return cycle01 + '-' + cycle02
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 1, 30)
const average02 = this.checkNum(this.average02, 1, 31 - average01 || 0)
return average01 + '/' + average02;
return average01 + '/' + average02
},
// 计算工作日格式
workdayCheck: function () {
const workday = this.checkNum(this.workday, 1, 31)
return workday;
return workday
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
let str = this.checkboxList.join()
return str == '' ? '*' : str
}
}
}

View File

@@ -51,37 +51,43 @@ export default {
methods: {
// 单选按钮值变化时
radioChange() {
if (this.cron.min === '*') {
this.$emit('update', 'min', '0', 'hour')
}
if (this.cron.second === '*') {
this.$emit('update', 'second', '0', 'hour')
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'hour', '*')
break;
this.$emit('update', 'hour', '*')
break
case 2:
this.$emit('update', 'hour', this.cycleTotal);
break;
this.$emit('update', 'hour', this.cycleTotal)
break
case 3:
this.$emit('update', 'hour', this.averageTotal);
break;
this.$emit('update', 'hour', this.averageTotal)
break
case 4:
this.$emit('update', 'hour', this.checkboxString);
break;
this.$emit('update', 'hour', this.checkboxString)
break
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'hour', this.cycleTotal);
this.$emit('update', 'hour', this.cycleTotal)
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'hour', this.averageTotal);
this.$emit('update', 'hour', this.averageTotal)
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'hour', this.checkboxString);
this.$emit('update', 'hour', this.checkboxString)
}
}
},
@@ -96,18 +102,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 0, 22)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 23)
return cycle01 + '-' + cycle02;
return cycle01 + '-' + cycle02
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 0, 22)
const average02 = this.checkNum(this.average02, 1, 23 - average01 || 0)
return average01 + '/' + average02;
return average01 + '/' + average02
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
let str = this.checkboxList.join()
return str == '' ? '*' : str
}
}
}

View File

@@ -113,14 +113,14 @@
</template>
<script>
import CrontabSecond from "./second.vue";
import CrontabMin from "./min.vue";
import CrontabHour from "./hour.vue";
import CrontabDay from "./day.vue";
import CrontabMonth from "./month.vue";
import CrontabWeek from "./week.vue";
import CrontabYear from "./year.vue";
import CrontabResult from "./result.vue";
import CrontabSecond from "./second.vue"
import CrontabMin from "./min.vue"
import CrontabHour from "./hour.vue"
import CrontabDay from "./day.vue"
import CrontabMonth from "./month.vue"
import CrontabWeek from "./week.vue"
import CrontabYear from "./year.vue"
import CrontabResult from "./result.vue"
export default {
data() {
@@ -137,19 +137,19 @@ export default {
week: "?",
year: "",
},
};
}
},
name: "vcrontab",
props: ["expression", "hideComponent"],
methods: {
shouldHide(key) {
if (this.hideComponent && this.hideComponent.includes(key)) return false;
return true;
if (this.hideComponent && this.hideComponent.includes(key)) return false
return true
},
resolveExp() {
// 反解析 表达式
if (this.expression) {
let arr = this.expression.split(" ");
let arr = this.expression.split(" ")
if (arr.length >= 6) {
//6 位以上是合法表达式
let obj = {
@@ -160,160 +160,160 @@ export default {
month: arr[4],
week: arr[5],
year: arr[6] ? arr[6] : "",
};
}
this.crontabValueObj = {
...obj,
};
}
for (let i in obj) {
if (obj[i]) this.changeRadio(i, obj[i]);
if (obj[i]) this.changeRadio(i, obj[i])
}
}
} else {
// 没有传入的表达式 则还原
this.clearCron();
this.clearCron()
}
},
// tab切换值
tabCheck(index) {
this.tabActive = index;
this.tabActive = index
},
// 由子组件触发,更改表达式组成的字段值
updateCrontabValue(name, value, from) {
"updateCrontabValue", name, value, from;
this.crontabValueObj[name] = value;
"updateCrontabValue", name, value, from
this.crontabValueObj[name] = value
if (from && from !== name) {
console.log(`来自组件 ${from} 改变了 ${name} ${value}`);
this.changeRadio(name, value);
console.log(`来自组件 ${from} 改变了 ${name} ${value}`)
this.changeRadio(name, value)
}
},
// 赋值到组件
changeRadio(name, value) {
let arr = ["second", "min", "hour", "month"],
refName = "cron" + name,
insValue;
insValue
if (!this.$refs[refName]) return;
if (!this.$refs[refName]) return
if (arr.includes(name)) {
if (value === "*") {
insValue = 1;
insValue = 1
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-");
let indexArr = value.split("-")
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insValue = 2;
: (this.$refs[refName].cycle01 = indexArr[0])
this.$refs[refName].cycle02 = indexArr[1]
insValue = 2
} else if (value.indexOf("/") > -1) {
let indexArr = value.split("/");
let indexArr = value.split("/")
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 0)
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insValue = 3;
: (this.$refs[refName].average01 = indexArr[0])
this.$refs[refName].average02 = indexArr[1]
insValue = 3
} else {
insValue = 4;
this.$refs[refName].checkboxList = value.split(",");
insValue = 4
this.$refs[refName].checkboxList = value.split(",")
}
} else if (name == "day") {
if (value === "*") {
insValue = 1;
insValue = 1
} else if (value == "?") {
insValue = 2;
insValue = 2
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-");
let indexArr = value.split("-")
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insValue = 3;
: (this.$refs[refName].cycle01 = indexArr[0])
this.$refs[refName].cycle02 = indexArr[1]
insValue = 3
} else if (value.indexOf("/") > -1) {
let indexArr = value.split("/");
let indexArr = value.split("/")
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 0)
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insValue = 4;
: (this.$refs[refName].average01 = indexArr[0])
this.$refs[refName].average02 = indexArr[1]
insValue = 4
} else if (value.indexOf("W") > -1) {
let indexArr = value.split("W");
let indexArr = value.split("W")
isNaN(indexArr[0])
? (this.$refs[refName].workday = 0)
: (this.$refs[refName].workday = indexArr[0]);
insValue = 5;
: (this.$refs[refName].workday = indexArr[0])
insValue = 5
} else if (value === "L") {
insValue = 6;
insValue = 6
} else {
this.$refs[refName].checkboxList = value.split(",");
insValue = 7;
this.$refs[refName].checkboxList = value.split(",")
insValue = 7
}
} else if (name == "week") {
if (value === "*") {
insValue = 1;
insValue = 1
} else if (value == "?") {
insValue = 2;
insValue = 2
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-");
let indexArr = value.split("-")
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insValue = 3;
: (this.$refs[refName].cycle01 = indexArr[0])
this.$refs[refName].cycle02 = indexArr[1]
insValue = 3
} else if (value.indexOf("#") > -1) {
let indexArr = value.split("#");
let indexArr = value.split("#")
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 1)
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insValue = 4;
: (this.$refs[refName].average01 = indexArr[0])
this.$refs[refName].average02 = indexArr[1]
insValue = 4
} else if (value.indexOf("L") > -1) {
let indexArr = value.split("L");
let indexArr = value.split("L")
isNaN(indexArr[0])
? (this.$refs[refName].weekday = 1)
: (this.$refs[refName].weekday = indexArr[0]);
insValue = 5;
: (this.$refs[refName].weekday = indexArr[0])
insValue = 5
} else {
this.$refs[refName].checkboxList = value.split(",");
insValue = 6;
this.$refs[refName].checkboxList = value.split(",")
insValue = 6
}
} else if (name == "year") {
if (value == "") {
insValue = 1;
insValue = 1
} else if (value == "*") {
insValue = 2;
insValue = 2
} else if (value.indexOf("-") > -1) {
insValue = 3;
insValue = 3
} else if (value.indexOf("/") > -1) {
insValue = 4;
insValue = 4
} else {
this.$refs[refName].checkboxList = value.split(",");
insValue = 5;
this.$refs[refName].checkboxList = value.split(",")
insValue = 5
}
}
this.$refs[refName].radioValue = insValue;
this.$refs[refName].radioValue = insValue
},
// 表单选项的子组件校验数字格式(通过-props传递
checkNumber(value, minLimit, maxLimit) {
// 检查必须为整数
value = Math.floor(value);
value = Math.floor(value)
if (value < minLimit) {
value = minLimit;
value = minLimit
} else if (value > maxLimit) {
value = maxLimit;
value = maxLimit
}
return value;
return value
},
// 隐藏弹窗
hidePopup() {
this.$emit("hide");
this.$emit("hide")
},
// 填充表达式
submitFill() {
this.$emit("fill", this.crontabValueString);
this.hidePopup();
this.$emit("fill", this.crontabValueString)
this.hidePopup()
},
clearCron() {
// 还原选择项
("准备还原");
("准备还原")
this.crontabValueObj = {
second: "*",
min: "*",
@@ -322,15 +322,15 @@ export default {
month: "*",
week: "?",
year: "",
};
}
for (let j in this.crontabValueObj) {
this.changeRadio(j, this.crontabValueObj[j]);
this.changeRadio(j, this.crontabValueObj[j])
}
},
},
computed: {
crontabValueString: function() {
let obj = this.crontabValueObj;
let obj = this.crontabValueObj
let str =
obj.second +
" " +
@@ -343,8 +343,8 @@ export default {
obj.month +
" " +
obj.week +
(obj.year == "" ? "" : " " + obj.year);
return str;
(obj.year == "" ? "" : " " + obj.year)
return str
},
},
components: {
@@ -364,9 +364,9 @@ export default {
},
},
mounted: function() {
this.resolveExp();
this.resolveExp()
},
};
}
</script>
<style scoped>
.pop_btn {

View File

@@ -54,35 +54,35 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'min', '*', 'min');
break;
this.$emit('update', 'min', '*', 'min')
break
case 2:
this.$emit('update', 'min', this.cycleTotal, 'min');
break;
this.$emit('update', 'min', this.cycleTotal, 'min')
break
case 3:
this.$emit('update', 'min', this.averageTotal, 'min');
break;
this.$emit('update', 'min', this.averageTotal, 'min')
break
case 4:
this.$emit('update', 'min', this.checkboxString, 'min');
break;
this.$emit('update', 'min', this.checkboxString, 'min')
break
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'min', this.cycleTotal, 'min');
this.$emit('update', 'min', this.cycleTotal, 'min')
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'min', this.averageTotal, 'min');
this.$emit('update', 'min', this.averageTotal, 'min')
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'min', this.checkboxString, 'min');
this.$emit('update', 'min', this.checkboxString, 'min')
}
},
@@ -98,18 +98,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 0, 58)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
return cycle01 + '-' + cycle02;
return cycle01 + '-' + cycle02
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 0, 58)
const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
return average01 + '/' + average02;
return average01 + '/' + average02
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
let str = this.checkboxList.join()
return str == '' ? '*' : str
}
}
}

View File

@@ -53,35 +53,35 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'month', '*');
break;
this.$emit('update', 'month', '*')
break
case 2:
this.$emit('update', 'month', this.cycleTotal);
break;
this.$emit('update', 'month', this.cycleTotal)
break
case 3:
this.$emit('update', 'month', this.averageTotal);
break;
this.$emit('update', 'month', this.averageTotal)
break
case 4:
this.$emit('update', 'month', this.checkboxString);
break;
this.$emit('update', 'month', this.checkboxString)
break
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'month', this.cycleTotal);
this.$emit('update', 'month', this.cycleTotal)
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'month', this.averageTotal);
this.$emit('update', 'month', this.averageTotal)
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'month', this.checkboxString);
this.$emit('update', 'month', this.checkboxString)
}
}
},
@@ -96,18 +96,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 1, 11)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12)
return cycle01 + '-' + cycle02;
return cycle01 + '-' + cycle02
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 1, 11)
const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0)
return average01 + '/' + average02;
return average01 + '/' + average02
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
let str = this.checkboxList.join()
return str == '' ? '*' : str
}
}
}

View File

@@ -27,135 +27,135 @@ export default {
expressionChange() {
// 计算开始-隐藏结果
this.isShow = false;
this.isShow = false
// 获取规则数组[0秒、1分、2时、3日、4月、5星期、6年]
let ruleArr = this.$options.propsData.ex.split(' ');
let ruleArr = this.$options.propsData.ex.split(' ')
// 用于记录进入循环的次数
let nums = 0;
let nums = 0
// 用于暂时存符号时间规则结果的数组
let resultArr = [];
let resultArr = []
// 获取当前时间精确至[年、月、日、时、分、秒]
let nTime = new Date();
let nYear = nTime.getFullYear();
let nMonth = nTime.getMonth() + 1;
let nDay = nTime.getDate();
let nHour = nTime.getHours();
let nMin = nTime.getMinutes();
let nSecond = nTime.getSeconds();
let nTime = new Date()
let nYear = nTime.getFullYear()
let nMonth = nTime.getMonth() + 1
let nDay = nTime.getDate()
let nHour = nTime.getHours()
let nMin = nTime.getMinutes()
let nSecond = nTime.getSeconds()
// 根据规则获取到近100年可能年数组、月数组等等
this.getSecondArr(ruleArr[0]);
this.getMinArr(ruleArr[1]);
this.getHourArr(ruleArr[2]);
this.getDayArr(ruleArr[3]);
this.getMonthArr(ruleArr[4]);
this.getWeekArr(ruleArr[5]);
this.getYearArr(ruleArr[6], nYear);
this.getSecondArr(ruleArr[0])
this.getMinArr(ruleArr[1])
this.getHourArr(ruleArr[2])
this.getDayArr(ruleArr[3])
this.getMonthArr(ruleArr[4])
this.getWeekArr(ruleArr[5])
this.getYearArr(ruleArr[6], nYear)
// 将获取到的数组赋值-方便使用
let sDate = this.dateArr[0];
let mDate = this.dateArr[1];
let hDate = this.dateArr[2];
let DDate = this.dateArr[3];
let MDate = this.dateArr[4];
let YDate = this.dateArr[5];
let sDate = this.dateArr[0]
let mDate = this.dateArr[1]
let hDate = this.dateArr[2]
let DDate = this.dateArr[3]
let MDate = this.dateArr[4]
let YDate = this.dateArr[5]
// 获取当前时间在数组中的索引
let sIdx = this.getIndex(sDate, nSecond);
let mIdx = this.getIndex(mDate, nMin);
let hIdx = this.getIndex(hDate, nHour);
let DIdx = this.getIndex(DDate, nDay);
let MIdx = this.getIndex(MDate, nMonth);
let YIdx = this.getIndex(YDate, nYear);
let sIdx = this.getIndex(sDate, nSecond)
let mIdx = this.getIndex(mDate, nMin)
let hIdx = this.getIndex(hDate, nHour)
let DIdx = this.getIndex(DDate, nDay)
let MIdx = this.getIndex(MDate, nMonth)
let YIdx = this.getIndex(YDate, nYear)
// 重置月日时分秒的函数(后面用的比较多)
const resetSecond = function () {
sIdx = 0;
sIdx = 0
nSecond = sDate[sIdx]
}
const resetMin = function () {
mIdx = 0;
mIdx = 0
nMin = mDate[mIdx]
resetSecond();
resetSecond()
}
const resetHour = function () {
hIdx = 0;
hIdx = 0
nHour = hDate[hIdx]
resetMin();
resetMin()
}
const resetDay = function () {
DIdx = 0;
DIdx = 0
nDay = DDate[DIdx]
resetHour();
resetHour()
}
const resetMonth = function () {
MIdx = 0;
MIdx = 0
nMonth = MDate[MIdx]
resetDay();
resetDay()
}
// 如果当前年份不为数组中当前值
if (nYear !== YDate[YIdx]) {
resetMonth();
resetMonth()
}
// 如果当前月份不为数组中当前值
if (nMonth !== MDate[MIdx]) {
resetDay();
resetDay()
}
// 如果当前“日”不为数组中当前值
if (nDay !== DDate[DIdx]) {
resetHour();
resetHour()
}
// 如果当前“时”不为数组中当前值
if (nHour !== hDate[hIdx]) {
resetMin();
resetMin()
}
// 如果当前“分”不为数组中当前值
if (nMin !== mDate[mIdx]) {
resetSecond();
resetSecond()
}
// 循环年份数组
goYear: for (let Yi = YIdx; Yi < YDate.length; Yi++) {
let YY = YDate[Yi];
let YY = YDate[Yi]
// 如果到达最大值时
if (nMonth > MDate[MDate.length - 1]) {
resetMonth();
continue;
resetMonth()
continue
}
// 循环月份数组
goMonth: for (let Mi = MIdx; Mi < MDate.length; Mi++) {
// 赋值、方便后面运算
let MM = MDate[Mi];
MM = MM < 10 ? '0' + MM : MM;
MM = MM < 10 ? '0' + MM : MM
// 如果到达最大值时
if (nDay > DDate[DDate.length - 1]) {
resetDay();
resetDay()
if (Mi == MDate.length - 1) {
resetMonth();
continue goYear;
resetMonth()
continue goYear
}
continue;
continue
}
// 循环日期数组
goDay: for (let Di = DIdx; Di < DDate.length; Di++) {
// 赋值、方便后面运算
let DD = DDate[Di];
let thisDD = DD < 10 ? '0' + DD : DD;
let DD = DDate[Di]
let thisDD = DD < 10 ? '0' + DD : DD
// 如果到达最大值时
if (nHour > hDate[hDate.length - 1]) {
resetHour();
resetHour()
if (Di == DDate.length - 1) {
resetDay();
resetDay()
if (Mi == MDate.length - 1) {
resetMonth();
continue goYear;
resetMonth()
continue goYear
}
continue goMonth;
continue goMonth
}
continue;
continue
}
// 判断日期的合法性,不合法的话也是跳出当前循环
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true && this.dayRule !== 'workDay' && this.dayRule !== 'lastWeek' && this.dayRule !== 'lastDay') {
resetDay();
continue goMonth;
resetDay()
continue goMonth
}
// 如果日期规则中有值时
if (this.dayRule == 'lastDay') {
@@ -163,84 +163,83 @@ export default {
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
DD--
thisDD = DD < 10 ? '0' + DD : DD
}
}
} else if (this.dayRule == 'workDay') {
// 校验并调整如果是2月30号这种日期传进来时需调整至正常月底
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
DD--
thisDD = DD < 10 ? '0' + DD : DD
}
}
// 获取达到条件的日期是星期X
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
// 当星期日时
if (thisWeek == 1) {
// 先找下一个日,并判断是否为月底
DD++;
thisDD = DD < 10 ? '0' + DD : DD;
DD++
thisDD = DD < 10 ? '0' + DD : DD
// 判断下一日已经不是合法日期
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD -= 3;
DD -= 3
}
} else if (thisWeek == 7) {
// 当星期6时只需判断不是1号就可进行操作
if (this.dayRuleSup !== 1) {
DD--;
DD--
} else {
DD += 2;
DD += 2
}
}
} else if (this.dayRule == 'weekDay') {
// 如果指定了是星期几
// 获取当前日期是属于星期几
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
// 校验当前星期是否在星期池dayRuleSup
if (this.dayRuleSup.indexOf(thisWeek) < 0) {
// 如果到达最大值时
if (Di == DDate.length - 1) {
resetDay();
resetDay()
if (Mi == MDate.length - 1) {
resetMonth();
continue goYear;
resetMonth()
continue goYear
}
continue goMonth;
continue goMonth
}
continue;
continue
}
} else if (this.dayRule == 'assWeek') {
// 如果指定了是第几周的星期几
// 获取每月1号是属于星期几
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
if (this.dayRuleSup[1] >= thisWeek) {
DD = (this.dayRuleSup[0] - 1) * 7 + this.dayRuleSup[1] - thisWeek + 1;
DD = (this.dayRuleSup[0] - 1) * 7 + this.dayRuleSup[1] - thisWeek + 1
} else {
DD = this.dayRuleSup[0] * 7 + this.dayRuleSup[1] - thisWeek + 1;
DD = this.dayRuleSup[0] * 7 + this.dayRuleSup[1] - thisWeek + 1
}
} else if (this.dayRule == 'lastWeek') {
// 如果指定了每月最后一个星期几
// 校验并调整如果是2月30号这种日期传进来时需调整至正常月底
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
DD--
thisDD = DD < 10 ? '0' + DD : DD
}
}
// 获取月末最后一天是星期几
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
// 找到要求中最近的那个星期几
if (this.dayRuleSup < thisWeek) {
DD -= thisWeek - this.dayRuleSup;
DD -= thisWeek - this.dayRuleSup
} else if (this.dayRuleSup > thisWeek) {
DD -= 7 - (this.dayRuleSup - thisWeek)
}
}
// 判断时间值是否小于10置换成“05”这种格式
DD = DD < 10 ? '0' + DD : DD;
DD = DD < 10 ? '0' + DD : DD
// 循环“时”数组
goHour: for (let hi = hIdx; hi < hDate.length; hi++) {
@@ -248,76 +247,76 @@ export default {
// 如果到达最大值时
if (nMin > mDate[mDate.length - 1]) {
resetMin();
resetMin()
if (hi == hDate.length - 1) {
resetHour();
resetHour()
if (Di == DDate.length - 1) {
resetDay();
resetDay()
if (Mi == MDate.length - 1) {
resetMonth();
continue goYear;
resetMonth()
continue goYear
}
continue goMonth;
continue goMonth
}
continue goDay;
continue goDay
}
continue;
continue
}
// 循环"分"数组
goMin: for (let mi = mIdx; mi < mDate.length; mi++) {
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi];
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi]
// 如果到达最大值时
if (nSecond > sDate[sDate.length - 1]) {
resetSecond();
resetSecond()
if (mi == mDate.length - 1) {
resetMin();
resetMin()
if (hi == hDate.length - 1) {
resetHour();
resetHour()
if (Di == DDate.length - 1) {
resetDay();
resetDay()
if (Mi == MDate.length - 1) {
resetMonth();
continue goYear;
resetMonth()
continue goYear
}
continue goMonth;
continue goMonth
}
continue goDay;
continue goDay
}
continue goHour;
continue goHour
}
continue;
continue
}
// 循环"秒"数组
goSecond: for (let si = sIdx; si <= sDate.length - 1; si++) {
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si];
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si]
// 添加当前时间(时间合法性在日期循环时已经判断)
if (MM !== '00' && DD !== '00') {
resultArr.push(YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss)
nums++;
nums++
}
// 如果条数满了就退出循环
if (nums == 5) break goYear;
if (nums == 5) break goYear
// 如果到达最大值时
if (si == sDate.length - 1) {
resetSecond();
resetSecond()
if (mi == mDate.length - 1) {
resetMin();
resetMin()
if (hi == hDate.length - 1) {
resetHour();
resetHour()
if (Di == DDate.length - 1) {
resetDay();
resetDay()
if (Mi == MDate.length - 1) {
resetMonth();
continue goYear;
resetMonth()
continue goYear
}
continue goMonth;
continue goMonth
}
continue goDay;
continue goDay
}
continue goHour;
continue goHour
}
continue goMin;
continue goMin
}
} //goSecond
} //goMin
@@ -327,33 +326,33 @@ export default {
}
// 判断100年内的结果条数
if (resultArr.length == 0) {
this.resultList = ['没有达到条件的结果!'];
this.resultList = ['没有达到条件的结果!']
} else {
this.resultList = resultArr;
this.resultList = resultArr
if (resultArr.length !== 5) {
this.resultList.push('最近100年内只有上面' + resultArr.length + '条结果!')
}
}
// 计算完成-显示结果
this.isShow = true;
this.isShow = true
},
// 用于计算某位数字在数组中的索引
getIndex(arr, value) {
if (value <= arr[0] || value > arr[arr.length - 1]) {
return 0;
return 0
} else {
for (let i = 0; i < arr.length - 1; i++) {
if (value > arr[i] && value <= arr[i + 1]) {
return i + 1;
return i + 1
}
}
}
},
// 获取"年"数组
getYearArr(rule, year) {
this.dateArr[5] = this.getOrderArr(year, year + 100);
this.dateArr[5] = this.getOrderArr(year, year + 100)
if (rule !== undefined) {
if (rule.indexOf('-') >= 0) {
this.dateArr[5] = this.getCycleArr(rule, year + 100, false)
@@ -366,7 +365,7 @@ export default {
},
// 获取"月"数组
getMonthArr(rule) {
this.dateArr[4] = this.getOrderArr(1, 12);
this.dateArr[4] = this.getOrderArr(1, 12)
if (rule.indexOf('-') >= 0) {
this.dateArr[4] = this.getCycleArr(rule, 12, false)
} else if (rule.indexOf('/') >= 0) {
@@ -380,58 +379,58 @@ export default {
// 只有当日期规则的两个值均为“”时则表达日期是有选项的
if (this.dayRule == '' && this.dayRuleSup == '') {
if (rule.indexOf('-') >= 0) {
this.dayRule = 'weekDay';
this.dayRule = 'weekDay'
this.dayRuleSup = this.getCycleArr(rule, 7, false)
} else if (rule.indexOf('#') >= 0) {
this.dayRule = 'assWeek';
let matchRule = rule.match(/[0-9]{1}/g);
this.dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])];
this.dateArr[3] = [1];
this.dayRule = 'assWeek'
let matchRule = rule.match(/[0-9]{1}/g)
this.dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])]
this.dateArr[3] = [1]
if (this.dayRuleSup[1] == 7) {
this.dayRuleSup[1] = 0;
this.dayRuleSup[1] = 0
}
} else if (rule.indexOf('L') >= 0) {
this.dayRule = 'lastWeek';
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
this.dateArr[3] = [31];
this.dayRule = 'lastWeek'
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0])
this.dateArr[3] = [31]
if (this.dayRuleSup == 7) {
this.dayRuleSup = 0;
this.dayRuleSup = 0
}
} else if (rule !== '*' && rule !== '?') {
this.dayRule = 'weekDay';
this.dayRule = 'weekDay'
this.dayRuleSup = this.getAssignArr(rule)
}
}
},
// 获取"日"数组-少量为日期规则
getDayArr(rule) {
this.dateArr[3] = this.getOrderArr(1, 31);
this.dayRule = '';
this.dayRuleSup = '';
this.dateArr[3] = this.getOrderArr(1, 31)
this.dayRule = ''
this.dayRuleSup = ''
if (rule.indexOf('-') >= 0) {
this.dateArr[3] = this.getCycleArr(rule, 31, false)
this.dayRuleSup = 'null';
this.dayRuleSup = 'null'
} else if (rule.indexOf('/') >= 0) {
this.dateArr[3] = this.getAverageArr(rule, 31)
this.dayRuleSup = 'null';
this.dayRuleSup = 'null'
} else if (rule.indexOf('W') >= 0) {
this.dayRule = 'workDay';
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
this.dateArr[3] = [this.dayRuleSup];
this.dayRule = 'workDay'
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0])
this.dateArr[3] = [this.dayRuleSup]
} else if (rule.indexOf('L') >= 0) {
this.dayRule = 'lastDay';
this.dayRuleSup = 'null';
this.dateArr[3] = [31];
this.dayRule = 'lastDay'
this.dayRuleSup = 'null'
this.dateArr[3] = [31]
} else if (rule !== '*' && rule !== '?') {
this.dateArr[3] = this.getAssignArr(rule)
this.dayRuleSup = 'null';
this.dayRuleSup = 'null'
} else if (rule == '*') {
this.dayRuleSup = 'null';
this.dayRuleSup = 'null'
}
},
// 获取"时"数组
getHourArr(rule) {
this.dateArr[2] = this.getOrderArr(0, 23);
this.dateArr[2] = this.getOrderArr(0, 23)
if (rule.indexOf('-') >= 0) {
this.dateArr[2] = this.getCycleArr(rule, 24, true)
} else if (rule.indexOf('/') >= 0) {
@@ -442,7 +441,7 @@ export default {
},
// 获取"分"数组
getMinArr(rule) {
this.dateArr[1] = this.getOrderArr(0, 59);
this.dateArr[1] = this.getOrderArr(0, 59)
if (rule.indexOf('-') >= 0) {
this.dateArr[1] = this.getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
@@ -453,7 +452,7 @@ export default {
},
// 获取"秒"数组
getSecondArr(rule) {
this.dateArr[0] = this.getOrderArr(0, 59);
this.dateArr[0] = this.getOrderArr(0, 59)
if (rule.indexOf('-') >= 0) {
this.dateArr[0] = this.getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
@@ -464,86 +463,86 @@ export default {
},
// 根据传进来的min-max返回一个顺序的数组
getOrderArr(min, max) {
let arr = [];
let arr = []
for (let i = min; i <= max; i++) {
arr.push(i);
arr.push(i)
}
return arr;
return arr
},
// 根据规则中指定的零散值返回一个数组
getAssignArr(rule) {
let arr = [];
let assiginArr = rule.split(',');
let arr = []
let assiginArr = rule.split(',')
for (let i = 0; i < assiginArr.length; i++) {
arr[i] = Number(assiginArr[i])
}
arr.sort(this.compare)
return arr;
return arr
},
// 根据一定算术规则计算返回一个数组
getAverageArr(rule, limit) {
let arr = [];
let agArr = rule.split('/');
let min = Number(agArr[0]);
let step = Number(agArr[1]);
let arr = []
let agArr = rule.split('/')
let min = Number(agArr[0])
let step = Number(agArr[1])
while (min <= limit) {
arr.push(min);
min += step;
arr.push(min)
min += step
}
return arr;
return arr
},
// 根据规则返回一个具有周期性的数组
getCycleArr(rule, limit, status) {
// status--表示是否从0开始则从1开始
let arr = [];
let cycleArr = rule.split('-');
let min = Number(cycleArr[0]);
let max = Number(cycleArr[1]);
let arr = []
let cycleArr = rule.split('-')
let min = Number(cycleArr[0])
let max = Number(cycleArr[1])
if (min > max) {
max += limit;
max += limit
}
for (let i = min; i <= max; i++) {
let add = 0;
let add = 0
if (status == false && i % limit == 0) {
add = limit;
add = limit
}
arr.push(Math.round(i % limit + add))
}
arr.sort(this.compare)
return arr;
return arr
},
// 比较数字大小用于Array.sort
compare(value1, value2) {
if (value2 - value1 > 0) {
return -1;
return -1
} else {
return 1;
return 1
}
},
// 格式化日期格式如2017-9-19 18:04:33
formatDate(value, type) {
// 计算日期相关值
let time = typeof value == 'number' ? new Date(value) : value;
let Y = time.getFullYear();
let M = time.getMonth() + 1;
let D = time.getDate();
let h = time.getHours();
let m = time.getMinutes();
let s = time.getSeconds();
let week = time.getDay();
let time = typeof value == 'number' ? new Date(value) : value
let Y = time.getFullYear()
let M = time.getMonth() + 1
let D = time.getDate()
let h = time.getHours()
let m = time.getMinutes()
let s = time.getSeconds()
let week = time.getDay()
// 如果传递了type的话
if (type == undefined) {
return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s)
} else if (type == 'week') {
// 在quartz中 1为星期日
return week + 1;
return week + 1
}
},
// 检查日期是否存在
checkDate(value) {
let time = new Date(value);
let time = new Date(value)
let format = this.formatDate(time)
return value === format;
return value === format
}
},
watch: {
@@ -552,7 +551,7 @@ export default {
props: ['ex'],
mounted: function () {
// 初始化 获取一次结果
this.expressionChange();
this.expressionChange()
}
}

View File

@@ -53,35 +53,35 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'second', '*', 'second');
break;
this.$emit('update', 'second', '*', 'second')
break
case 2:
this.$emit('update', 'second', this.cycleTotal);
break;
this.$emit('update', 'second', this.cycleTotal)
break
case 3:
this.$emit('update', 'second', this.averageTotal);
break;
this.$emit('update', 'second', this.averageTotal)
break
case 4:
this.$emit('update', 'second', this.checkboxString);
break;
this.$emit('update', 'second', this.checkboxString)
break
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'second', this.cycleTotal);
this.$emit('update', 'second', this.cycleTotal)
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'second', this.averageTotal);
this.$emit('update', 'second', this.averageTotal)
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'second', this.checkboxString);
this.$emit('update', 'second', this.checkboxString)
}
}
},
@@ -99,18 +99,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 0, 58)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
return cycle01 + '-' + cycle02;
return cycle01 + '-' + cycle02
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 0, 58)
const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
return average01 + '/' + average02;
return average01 + '/' + average02
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
let str = this.checkboxList.join()
return str == '' ? '*' : str
}
}
}

View File

@@ -118,52 +118,52 @@ export default {
// 单选按钮值变化时
radioChange() {
if (this.radioValue !== 2 && this.cron.day !== '?') {
this.$emit('update', 'day', '?', 'week');
this.$emit('update', 'day', '?', 'week')
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'week', '*');
break;
this.$emit('update', 'week', '*')
break
case 2:
this.$emit('update', 'week', '?');
break;
this.$emit('update', 'week', '?')
break
case 3:
this.$emit('update', 'week', this.cycleTotal);
break;
this.$emit('update', 'week', this.cycleTotal)
break
case 4:
this.$emit('update', 'week', this.averageTotal);
break;
this.$emit('update', 'week', this.averageTotal)
break
case 5:
this.$emit('update', 'week', this.weekdayCheck + 'L');
break;
this.$emit('update', 'week', this.weekdayCheck + 'L')
break
case 6:
this.$emit('update', 'week', this.checkboxString);
break;
this.$emit('update', 'week', this.checkboxString)
break
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'week', this.cycleTotal);
this.$emit('update', 'week', this.cycleTotal)
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'week', this.averageTotal);
this.$emit('update', 'week', this.averageTotal)
}
},
// 最近工作日值变化时
weekdayChange() {
if (this.radioValue == '5') {
this.$emit('update', 'week', this.weekday + 'L');
this.$emit('update', 'week', this.weekday + 'L')
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '6') {
this.$emit('update', 'week', this.checkboxString);
this.$emit('update', 'week', this.checkboxString)
}
},
},
@@ -179,23 +179,23 @@ export default {
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 1, 7)
this.cycle02 = this.checkNum(this.cycle02, 1, 7)
return this.cycle01 + '-' + this.cycle02;
return this.cycle01 + '-' + this.cycle02
},
// 计算平均用到的值
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 1, 4)
this.average02 = this.checkNum(this.average02, 1, 7)
return this.average02 + '#' + this.average01;
return this.average02 + '#' + this.average01
},
// 最近的工作日(格式)
weekdayCheck: function () {
this.weekday = this.checkNum(this.weekday, 1, 7)
return this.weekday;
return this.weekday
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
let str = this.checkboxList.join()
return str == '' ? '*' : str
}
}
}

View File

@@ -61,38 +61,38 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'year', '');
break;
this.$emit('update', 'year', '')
break
case 2:
this.$emit('update', 'year', '*');
break;
this.$emit('update', 'year', '*')
break
case 3:
this.$emit('update', 'year', this.cycleTotal);
break;
this.$emit('update', 'year', this.cycleTotal)
break
case 4:
this.$emit('update', 'year', this.averageTotal);
break;
this.$emit('update', 'year', this.averageTotal)
break
case 5:
this.$emit('update', 'year', this.checkboxString);
break;
this.$emit('update', 'year', this.checkboxString)
break
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'year', this.cycleTotal);
this.$emit('update', 'year', this.cycleTotal)
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'year', this.averageTotal);
this.$emit('update', 'year', this.averageTotal)
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '5') {
this.$emit('update', 'year', this.checkboxString);
this.$emit('update', 'year', this.checkboxString)
}
}
},
@@ -107,23 +107,23 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, this.fullYear, 2098)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : this.fullYear + 1, 2099)
return cycle01 + '-' + cycle02;
return cycle01 + '-' + cycle02
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, this.fullYear, 2098)
const average02 = this.checkNum(this.average02, 1, 2099 - average01 || this.fullYear)
return average01 + '/' + average02;
return average01 + '/' + average02
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join();
return str;
let str = this.checkboxList.join()
return str
}
},
mounted: function () {
// 仅获取当前年份
this.fullYear = Number(new Date().getFullYear());
this.fullYear = Number(new Date().getFullYear())
this.cycle01 = this.fullYear
this.average01 = this.fullYear
}

View File

@@ -74,13 +74,13 @@ export default {
},
filters: {
handleArray(array) {
if (array.length === 0) return '';
if (array.length === 0) return ''
return array.reduce((pre, cur) => {
return pre + ' ' + cur;
return pre + ' ' + cur
})
},
}
};
}
</script>
<style scoped>
.el-tag + .el-tag {

View File

@@ -18,11 +18,12 @@
</template>
<script>
import Quill from "quill";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { getToken } from "@/utils/auth";
import axios from "axios"
import Quill from "quill"
import "quill/dist/quill.core.css"
import "quill/dist/quill.snow.css"
import "quill/dist/quill.bubble.css"
import { getToken } from "@/utils/auth"
export default {
name: "Editor",
@@ -88,27 +89,27 @@ export default {
placeholder: "请输入内容",
readOnly: this.readOnly,
},
};
}
},
computed: {
styles() {
let style = {};
let style = {}
if (this.minHeight) {
style.minHeight = `${this.minHeight}px`;
style.minHeight = `${this.minHeight}px`
}
if (this.height) {
style.height = `${this.height}px`;
style.height = `${this.height}px`
}
return style;
},
return style
}
},
watch: {
value: {
handler(val) {
if (val !== this.currentValue) {
this.currentValue = val === null ? "" : val;
this.currentValue = val === null ? "" : val
if (this.Quill) {
this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue);
this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue)
}
}
},
@@ -116,84 +117,106 @@ export default {
},
},
mounted() {
this.init();
this.init()
},
beforeDestroy() {
this.Quill = null;
this.Quill = null
},
methods: {
init() {
const editor = this.$refs.editor;
this.Quill = new Quill(editor, this.options);
const editor = this.$refs.editor
this.Quill = new Quill(editor, this.options)
// 如果设置了上传地址则自定义图片上传事件
if (this.type == 'url') {
let toolbar = this.Quill.getModule("toolbar");
let toolbar = this.Quill.getModule("toolbar")
toolbar.addHandler("image", (value) => {
if (value) {
this.$refs.upload.$children[0].$refs.input.click();
this.$refs.upload.$children[0].$refs.input.click()
} else {
this.quill.format("image", false);
this.quill.format("image", false)
}
});
})
this.Quill.root.addEventListener('paste', this.handlePasteCapture, true)
}
this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue);
this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue)
this.Quill.on("text-change", (delta, oldDelta, source) => {
const html = this.$refs.editor.children[0].innerHTML;
const text = this.Quill.getText();
const quill = this.Quill;
this.currentValue = html;
this.$emit("input", html);
this.$emit("on-change", { html, text, quill });
});
const html = this.$refs.editor.children[0].innerHTML
const text = this.Quill.getText()
const quill = this.Quill
this.currentValue = html
this.$emit("input", html)
this.$emit("on-change", { html, text, quill })
})
this.Quill.on("text-change", (delta, oldDelta, source) => {
this.$emit("on-text-change", delta, oldDelta, source);
});
this.$emit("on-text-change", delta, oldDelta, source)
})
this.Quill.on("selection-change", (range, oldRange, source) => {
this.$emit("on-selection-change", range, oldRange, source);
});
this.$emit("on-selection-change", range, oldRange, source)
})
this.Quill.on("editor-change", (eventName, ...args) => {
this.$emit("on-editor-change", eventName, ...args);
});
this.$emit("on-editor-change", eventName, ...args)
})
},
// 上传前校检格式和大小
handleBeforeUpload(file) {
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
const isJPG = type.includes(file.type);
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"]
const isJPG = type.includes(file.type)
// 检验文件格式
if (!isJPG) {
this.$message.error(`图片格式错误!`);
return false;
this.$message.error(`图片格式错误!`)
return false
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
const isLt = file.size / 1024 / 1024 < this.fileSize
if (!isLt) {
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`);
return false;
this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`)
return false
}
}
return true;
return true
},
handleUploadSuccess(res, file) {
// 如果上传成功
if (res.code == 200) {
// 获取富文本组件实例
let quill = this.Quill;
let quill = this.Quill
// 获取光标所在位置
let length = quill.getSelection().index;
let length = quill.getSelection().index
// 插入图片 res.url为服务器返回的图片地址
quill.insertEmbed(length, "image", res.data.url);
quill.insertEmbed(length, "image", res.data.url)
// 调整光标到最后
quill.setSelection(length + 1);
quill.setSelection(length + 1)
} else {
this.$message.error("图片插入失败");
this.$message.error("图片插入失败")
}
},
handleUploadError() {
this.$message.error("图片插入失败");
this.$message.error("图片插入失败")
},
},
};
// 复制粘贴图片处理
handlePasteCapture(e) {
const clipboard = e.clipboardData || window.clipboardData
if (clipboard && clipboard.items) {
for (let i = 0; i < clipboard.items.length; i++) {
const item = clipboard.items[i]
if (item.type.indexOf('image') !== -1) {
e.preventDefault()
const file = item.getAsFile()
this.insertImage(file)
}
}
}
},
insertImage(file) {
const formData = new FormData()
formData.append("file", file)
axios.post(this.uploadUrl, formData, { headers: { "Content-Type": "multipart/form-data", Authorization: this.headers.Authorization } }).then(res => {
this.handleUploadSuccess(res.data)
})
}
}
}
</script>
<style>

View File

@@ -5,6 +5,7 @@
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:data="data"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
@@ -27,7 +28,7 @@
</el-upload>
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<transition-group ref="uploadFileList" class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
<el-link :href="file.url" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
@@ -41,13 +42,23 @@
</template>
<script>
import { getToken } from "@/utils/auth";
import { getToken } from "@/utils/auth"
import Sortable from 'sortablejs'
export default {
name: "FileUpload",
props: {
// 值
value: [String, Object, Array],
// 上传接口地址
action: {
type: String,
default: "/file/upload"
},
// 上传携带的参数
data: {
type: Object
},
// 数量限制
limit: {
type: Number,
@@ -72,37 +83,57 @@ export default {
disabled: {
type: Boolean,
default: false
},
// 拖动排序
drag: {
type: Boolean,
default: true
}
},
data() {
return {
number: 0,
uploadList: [],
uploadFileUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传文件服务器地址
uploadFileUrl: process.env.VUE_APP_BASE_API + this.action, // 上传文件服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
fileList: [],
};
fileList: []
}
},
mounted() {
if (this.drag && !this.disabled) {
this.$nextTick(() => {
const element = this.$refs.uploadFileList?.$el || this.$refs.uploadFileList
Sortable.create(element, {
ghostClass: 'file-upload-darg',
onEnd: (evt) => {
const movedItem = this.fileList.splice(evt.oldIndex, 1)[0]
this.fileList.splice(evt.newIndex, 0, movedItem)
this.$emit("input", this.listToString(this.fileList))
}
})
})
}
},
watch: {
value: {
handler(val) {
if (val) {
let temp = 1;
let temp = 1
// 首先将值转为数组
const list = Array.isArray(val) ? val : this.value.split(',');
const list = Array.isArray(val) ? val : this.value.split(',')
// 然后将数组转为对象数组
this.fileList = list.map(item => {
if (typeof item === "string") {
item = { name: item, url: item };
item = { name: item, url: item }
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
item.uid = item.uid || new Date().getTime() + temp++
return item
})
} else {
this.fileList = [];
return [];
this.fileList = []
return []
}
},
deep: true,
@@ -112,7 +143,7 @@ export default {
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
return this.isShowTip && (this.fileType || this.fileSize)
},
},
methods: {
@@ -120,91 +151,95 @@ export default {
handleBeforeUpload(file) {
// 校检文件类型
if (this.fileType) {
const fileName = file.name.split('.');
const fileExt = fileName[fileName.length - 1];
const isTypeOk = this.fileType.indexOf(fileExt) >= 0;
const fileName = file.name.split('.')
const fileExt = fileName[fileName.length - 1]
const isTypeOk = this.fileType.indexOf(fileExt) >= 0
if (!isTypeOk) {
this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}格式文件!`);
return false;
this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}格式文件!`)
return false
}
}
// 校检文件名是否包含特殊字符
if (file.name.includes(',')) {
this.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false;
this.$modal.msgError('文件名不正确,不能包含英文逗号!')
return false
}
// 校检文件大小
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
const isLt = file.size / 1024 / 1024 < this.fileSize
if (!isLt) {
this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`);
return false;
this.$modal.msgError(`上传文件大小不能超过 ${this.fileSize} MB!`)
return false
}
}
this.$modal.loading("正在上传文件,请稍候...");
this.number++;
return true;
this.$modal.loading("正在上传文件,请稍候...")
this.number++
return true
},
// 文件个数超出
handleExceed() {
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`)
},
// 上传失败
handleUploadError(err) {
this.$modal.msgError("上传文件失败,请重试");
this.$modal.msgError("上传文件失败,请重试")
this.$modal.closeLoading()
},
// 上传成功回调
handleUploadSuccess(res, file) {
if (res.code === 200) {
this.uploadList.push({ name: res.data.url, url: res.data.url });
this.uploadedSuccessfully();
this.uploadList.push({ name: res.data.url, url: res.data.url })
this.uploadedSuccessfully()
} else {
this.number--;
this.$modal.closeLoading();
this.$modal.msgError(res.msg);
this.$refs.fileUpload.handleRemove(file);
this.uploadedSuccessfully();
this.number--
this.$modal.closeLoading()
this.$modal.msgError(res.msg)
this.$refs.fileUpload.handleRemove(file)
this.uploadedSuccessfully()
}
},
// 删除文件
handleDelete(index) {
this.fileList.splice(index, 1);
this.$emit("input", this.listToString(this.fileList));
this.fileList.splice(index, 1)
this.$emit("input", this.listToString(this.fileList))
},
// 上传结束处理
uploadedSuccessfully() {
if (this.number > 0 && this.uploadList.length === this.number) {
this.fileList = this.fileList.concat(this.uploadList);
this.uploadList = [];
this.number = 0;
this.$emit("input", this.listToString(this.fileList));
this.$modal.closeLoading();
this.fileList = this.fileList.concat(this.uploadList)
this.uploadList = []
this.number = 0
this.$emit("input", this.listToString(this.fileList))
this.$modal.closeLoading()
}
},
// 获取文件名称
getFileName(name) {
// 如果是url那么取最后的名字 如果不是直接返回
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1);
return name.slice(name.lastIndexOf("/") + 1)
} else {
return name;
return name
}
},
// 对象转成指定字符串分隔
listToString(list, separator) {
let strs = "";
separator = separator || ",";
let strs = ""
separator = separator || ","
for (let i in list) {
strs += list[i].url + separator;
strs += list[i].url + separator
}
return strs != '' ? strs.substr(0, strs.length - 1) : '';
return strs != '' ? strs.substr(0, strs.length - 1) : ''
}
}
};
}
</script>
<style scoped lang="scss">
.file-upload-darg {
opacity: 0.5;
background: #c8ebfb;
}
.upload-file-uploader {
margin-bottom: 5px;
}

View File

@@ -1,25 +1,49 @@
<template>
<div :class="{'show':show}" class="header-search">
<div class="header-search">
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="Search"
class="header-search-select"
@change="change"
<el-dialog
:visible.sync="show"
width="600px"
@close="close"
:show-close="false"
append-to-body
>
<el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
</el-select>
<el-input
v-model="search"
ref="headerSearchSelectRef"
size="large"
@input="querySearch"
prefix-icon="el-icon-search"
placeholder="菜单搜索支持标题、URL模糊查询"
clearable
@keyup.enter.native="selectActiveResult"
@keydown.up.native="navigateResult('up')"
@keydown.down.native="navigateResult('down')"
>
</el-input>
<el-scrollbar wrap-class="right-scrollbar-wrapper">
<div class="result-wrap">
<div class="search-item" v-for="(item, index) in options" :key="item.path" :style="activeStyle(index)" @mouseenter="activeIndex = index" @mouseleave="activeIndex = -1">
<div class="left">
<svg-icon class="menu-icon" :icon-class="item.icon" />
</div>
<div class="search-info" @click="change(item)">
<div class="menu-title">
{{ item.title.join(" / ") }}
</div>
<div class="menu-path">
{{ item.path }}
</div>
</div>
<svg-icon icon-class="enter" v-show="index === activeIndex"/>
</div>
</div>
</el-scrollbar>
</el-dialog>
</div>
</template>
<script>
// fuse is a lightweight fuzzy-search module
// make search results more in line with expectations
import Fuse from 'fuse.js/dist/fuse.min.js'
import path from 'path'
import { isHttp } from '@/utils/validate'
@@ -31,11 +55,15 @@ export default {
search: '',
options: [],
searchPool: [],
activeIndex: -1,
show: false,
fuse: undefined
}
},
computed: {
theme() {
return this.$store.state.settings.theme
},
routes() {
return this.$store.getters.defaultRoutes
}
@@ -46,13 +74,6 @@ export default {
},
searchPool(list) {
this.initFuse(list)
},
show(value) {
if (value) {
document.body.addEventListener('click', this.close)
} else {
document.body.removeEventListener('click', this.close)
}
}
},
mounted() {
@@ -63,23 +84,26 @@ export default {
this.show = !this.show
if (this.show) {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
this.options = this.searchPool
}
},
close() {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
this.search = ''
this.options = []
this.show = false
this.activeIndex = -1
},
change(val) {
const path = val.path;
const query = val.query;
const path = val.path
const query = val.query
if(isHttp(val.path)) {
// http(s):// 路径新窗口打开
const pindex = path.indexOf("http");
window.open(path.substr(pindex, path.length), "_blank");
const pindex = path.indexOf("http")
window.open(path.substr(pindex, path.length), "_blank")
} else {
if (query) {
this.$router.push({ path: path, query: JSON.parse(query) });
this.$router.push({ path: path, query: JSON.parse(query) })
} else {
this.$router.push(path)
}
@@ -117,11 +141,13 @@ export default {
const data = {
path: !isHttp(router.path) ? path.resolve(basePath, router.path) : router.path,
title: [...prefixTitle]
title: [...prefixTitle],
icon: ''
}
if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title]
data.icon = router.meta.icon
if (router.redirect !== 'noRedirect') {
// only push the routes with title
@@ -145,52 +171,94 @@ export default {
return res
},
querySearch(query) {
this.activeIndex = -1
if (query !== '') {
this.options = this.fuse.search(query)
this.options = this.fuse.search(query).map((item) => item.item) ?? this.searchPool
} else {
this.options = []
this.options = this.searchPool
}
},
activeStyle(index) {
if (index !== this.activeIndex) return {}
return {
"background-color": this.theme,
"color": "#fff"
}
},
navigateResult(direction) {
if (direction === "up") {
this.activeIndex = this.activeIndex <= 0 ? this.options.length - 1 : this.activeIndex - 1
} else if (direction === "down") {
this.activeIndex = this.activeIndex >= this.options.length - 1 ? 0 : this.activeIndex + 1
}
},
selectActiveResult() {
if (this.options.length > 0 && this.activeIndex >= 0) {
this.change(this.options[this.activeIndex])
}
}
}
}
</script>
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
<style lang='scss' scoped>
::v-deep {
.el-dialog__header {
padding: 0 !important;
}
}
.header-search {
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
}
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
.result-wrap {
height: 280px;
margin: 6px 0;
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
.search-item {
display: flex;
height: 48px;
align-items: center;
padding-right: 10px;
.left {
width: 60px;
text-align: center;
.menu-icon {
width: 18px;
height: 18px;
}
}
.search-info {
padding-left: 5px;
margin-top: 10px;
width: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
flex: 1;
.menu-title,
.menu-path {
height: 20px;
}
.menu-path {
color: #ccc;
font-size: 10px;
}
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
}
.search-item:hover {
cursor: pointer;
}
}
</style>

View File

@@ -31,30 +31,30 @@ export default {
computed: {
realSrc() {
if (!this.src) {
return;
return
}
let real_src = this.src.split(",")[0];
return real_src;
let real_src = this.src.split(",")[0]
return real_src
},
realSrcList() {
if (!this.src) {
return;
return
}
let real_src_list = this.src.split(",");
let srcList = [];
let real_src_list = this.src.split(",")
let srcList = []
real_src_list.forEach(item => {
return srcList.push(item);
});
return srcList;
return srcList.push(item)
})
return srcList
},
realWidth() {
return typeof this.width == "string" ? this.width : `${this.width}px`;
return typeof this.width == "string" ? this.width : `${this.width}px`
},
realHeight() {
return typeof this.height == "string" ? this.height : `${this.height}px`;
return typeof this.height == "string" ? this.height : `${this.height}px`
}
},
};
}
</script>
<style lang="scss" scoped>

View File

@@ -2,10 +2,12 @@
<div class="component-upload-image">
<el-upload
multiple
:disabled="disabled"
:action="uploadImgUrl"
list-type="picture-card"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:data="data"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
@@ -21,7 +23,7 @@
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" slot="tip" v-if="showTip">
<div class="el-upload__tip" slot="tip" v-if="showTip && !disabled">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
@@ -43,30 +45,50 @@
</template>
<script>
import { getToken } from "@/utils/auth";
import { getToken } from "@/utils/auth"
import Sortable from 'sortablejs'
export default {
props: {
value: [String, Object, Array],
// 上传接口地址
action: {
type: String,
default: "/file/upload"
},
// 上传携带的参数
data: {
type: Object
},
// 图片数量限制
limit: {
type: Number,
default: 5,
default: 5
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
default: 5
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
default: () => ["png", "jpg", "jpeg"]
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
// 禁用组件(仅查看图片)
disabled: {
type: Boolean,
default: false
},
// 拖动排序
drag: {
type: Boolean,
default: true
}
},
data() {
@@ -76,29 +98,43 @@ export default {
dialogImageUrl: "",
dialogVisible: false,
hideUpload: false,
uploadImgUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
uploadImgUrl: process.env.VUE_APP_BASE_API + this.action, // 上传的图片服务器地址
headers: {
Authorization: "Bearer " + getToken(),
},
fileList: []
};
}
},
mounted() {
if (this.drag && !this.disabled) {
this.$nextTick(() => {
const element = this.$refs.imageUpload?.$el?.querySelector('.el-upload-list')
Sortable.create(element, {
onEnd: (evt) => {
const movedItem = this.fileList.splice(evt.oldIndex, 1)[0]
this.fileList.splice(evt.newIndex, 0, movedItem)
this.$emit("input", this.listToString(this.fileList))
}
})
})
}
},
watch: {
value: {
handler(val) {
if (val) {
// 首先将值转为数组
const list = Array.isArray(val) ? val : this.value.split(',');
const list = Array.isArray(val) ? val : this.value.split(',')
// 然后将数组转为对象数组
this.fileList = list.map(item => {
if (typeof item === "string") {
item = { name: item, url: item };
item = { name: item, url: item }
}
return item;
});
return item
})
} else {
this.fileList = [];
return [];
this.fileList = []
return []
}
},
deep: true,
@@ -108,113 +144,118 @@ export default {
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
return this.isShowTip && (this.fileType || this.fileSize)
},
},
methods: {
// 上传前loading加载
handleBeforeUpload(file) {
let isImg = false;
let isImg = false
if (this.fileType.length) {
let fileExtension = "";
let fileExtension = ""
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1)
}
isImg = this.fileType.some(type => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
if (file.type.indexOf(type) > -1) return true
if (fileExtension && fileExtension.indexOf(type) > -1) return true
return false
})
} else {
isImg = file.type.indexOf("image") > -1;
isImg = file.type.indexOf("image") > -1
}
if (!isImg) {
this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}图片格式文件!`);
return false;
this.$modal.msgError(`文件格式不正确,请上传${this.fileType.join("/")}图片格式文件!`)
return false
}
if (file.name.includes(',')) {
this.$modal.msgError('文件名不正确,不能包含英文逗号!');
return false;
this.$modal.msgError('文件名不正确,不能包含英文逗号!')
return false
}
if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize;
const isLt = file.size / 1024 / 1024 < this.fileSize
if (!isLt) {
this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`);
return false;
this.$modal.msgError(`上传头像图片大小不能超过 ${this.fileSize} MB!`)
return false
}
}
this.$modal.loading("正在上传图片,请稍候...");
this.number++;
this.$modal.loading("正在上传图片,请稍候...")
this.number++
},
// 文件个数超出
handleExceed() {
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`);
this.$modal.msgError(`上传文件数量不能超过 ${this.limit} 个!`)
},
// 上传成功回调
handleUploadSuccess(res, file) {
if (res.code === 200) {
this.uploadList.push({ name: res.data.url, url: res.data.url });
this.uploadedSuccessfully();
this.uploadList.push({ name: res.data.url, url: res.data.url })
this.uploadedSuccessfully()
} else {
this.number--;
this.$modal.closeLoading();
this.$modal.msgError(res.msg);
this.$refs.imageUpload.handleRemove(file);
this.uploadedSuccessfully();
this.number--
this.$modal.closeLoading()
this.$modal.msgError(res.msg)
this.$refs.imageUpload.handleRemove(file)
this.uploadedSuccessfully()
}
},
// 删除图片
handleDelete(file) {
const findex = this.fileList.map(f => f.name).indexOf(file.name);
const findex = this.fileList.map(f => f.name).indexOf(file.name)
if (findex > -1) {
this.fileList.splice(findex, 1);
this.$emit("input", this.listToString(this.fileList));
this.fileList.splice(findex, 1)
this.$emit("input", this.listToString(this.fileList))
}
},
// 上传失败
handleUploadError() {
this.$modal.msgError("上传图片失败,请重试");
this.$modal.closeLoading();
this.$modal.msgError("上传图片失败,请重试")
this.$modal.closeLoading()
},
// 上传结束处理
uploadedSuccessfully() {
if (this.number > 0 && this.uploadList.length === this.number) {
this.fileList = this.fileList.concat(this.uploadList);
this.uploadList = [];
this.number = 0;
this.$emit("input", this.listToString(this.fileList));
this.$modal.closeLoading();
this.fileList = this.fileList.concat(this.uploadList)
this.uploadList = []
this.number = 0
this.$emit("input", this.listToString(this.fileList))
this.$modal.closeLoading()
}
},
// 预览
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
this.dialogImageUrl = file.url
this.dialogVisible = true
},
// 对象转成指定字符串分隔
listToString(list, separator) {
let strs = "";
separator = separator || ",";
let strs = ""
separator = separator || ","
for (let i in list) {
if (list[i].url) {
strs += list[i].url.replace(this.baseUrl, "") + separator;
strs += list[i].url.replace(this.baseUrl, "") + separator
}
}
return strs != '' ? strs.substr(0, strs.length - 1) : '';
return strs != '' ? strs.substr(0, strs.length - 1) : ''
}
}
};
}
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
::v-deep.hide .el-upload--picture-card {
display: none;
display: none;
}
::v-deep .el-upload-list--picture-card.is-disabled + .el-upload--picture-card {
display: none !important;
}
// 去掉动画效果
::v-deep .el-list-enter-active,
::v-deep .el-list-leave-active {
transition: all 0s;
transition: all 0s;
}
::v-deep .el-list-enter, .el-list-leave-active {

View File

@@ -63,7 +63,7 @@ export default {
},
data() {
return {
};
}
},
computed: {
currentPage: {

View File

@@ -5,7 +5,6 @@
<slot />
</div>
</div>
<!-- eslint-disable-next-line -->
<div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
</div>
</template>

View File

@@ -1,106 +0,0 @@
<template>
<div ref="rightPanel" class="rightPanel-container">
<div class="rightPanel-background" />
<div class="rightPanel">
<div class="rightPanel-items">
<slot />
</div>
</div>
</div>
</template>
<script>
export default {
name: 'RightPanel',
props: {
clickNotClose: {
default: false,
type: Boolean
}
},
computed: {
show: {
get() {
return this.$store.state.settings.showSettings
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'showSettings',
value: val
})
}
}
},
watch: {
show(value) {
if (value && !this.clickNotClose) {
this.addEventClick()
}
}
},
mounted() {
this.addEventClick()
},
beforeDestroy() {
const elx = this.$refs.rightPanel
elx.remove()
},
methods: {
addEventClick() {
window.addEventListener('click', this.closeSidebar)
},
closeSidebar(evt) {
const parent = evt.target.closest('.el-drawer__body')
if (!parent) {
this.show = false
window.removeEventListener('click', this.closeSidebar)
}
}
}
}
</script>
<style lang="scss" scoped>
.rightPanel-background {
position: fixed;
top: 0;
left: 0;
opacity: 0;
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
background: rgba(0, 0, 0, .2);
z-index: -1;
}
.rightPanel {
width: 100%;
max-width: 260px;
height: 100vh;
position: fixed;
top: 0;
right: 0;
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
transition: all .25s cubic-bezier(.7, .3, .1, 1);
transform: translate(100%);
background: #fff;
z-index: 40000;
}
.handle-button {
width: 48px;
height: 48px;
position: absolute;
left: -48px;
text-align: center;
font-size: 24px;
border-radius: 6px 0 0 6px !important;
z-index: 0;
pointer-events: auto;
cursor: pointer;
color: #fff;
line-height: 48px;
i {
font-size: 24px;
line-height: 48px;
}
}
</style>

View File

@@ -12,9 +12,14 @@
<el-dropdown trigger="click" :hide-on-click="false" style="padding-left: 12px" v-if="showColumnsType == 'checkbox'">
<el-button size="mini" circle icon="el-icon-menu" />
<el-dropdown-menu slot="dropdown">
<!-- 全选/反选 按钮 -->
<el-dropdown-item>
<el-checkbox :indeterminate="isIndeterminate" v-model="isChecked" @change="toggleCheckAll"> 列展示 </el-checkbox>
</el-dropdown-item>
<div class="check-line"></div>
<template v-for="item in columns">
<el-dropdown-item :key="item.key">
<el-checkbox :checked="item.visible" @change="checkboxChange($event, item.label)" :label="item.label" />
<el-checkbox v-model="item.visible" @change="checkboxChange($event, item.label)" :label="item.label" />
</el-dropdown-item>
</template>
</el-dropdown-menu>
@@ -41,42 +46,51 @@ export default {
// 弹出层标题
title: "显示/隐藏",
// 是否显示弹出层
open: false,
};
open: false
}
},
props: {
/* 是否显示检索条件 */
showSearch: {
type: Boolean,
default: true,
default: true
},
/* 显隐列信息 */
columns: {
type: Array,
type: Array
},
/* 是否显示检索图标 */
search: {
type: Boolean,
default: true,
default: true
},
/* 显隐列类型transfer穿梭框、checkbox复选框 */
showColumnsType: {
type: String,
default: "checkbox",
default: "checkbox"
},
/* 右外边距 */
gutter: {
type: Number,
default: 10,
default: 10
},
},
computed: {
style() {
const ret = {};
const ret = {}
if (this.gutter) {
ret.marginRight = `${this.gutter / 2}px`;
ret.marginRight = `${this.gutter / 2}px`
}
return ret;
return ret
},
isChecked: {
get() {
return this.columns.every((col) => col.visible)
},
set() {}
},
isIndeterminate() {
return this.columns.some((col) => col.visible) && !this.isChecked
}
},
created() {
@@ -84,7 +98,7 @@ export default {
// 显隐列初始默认隐藏列
for (let item in this.columns) {
if (this.columns[item].visible === false) {
this.value.push(parseInt(item));
this.value.push(parseInt(item))
}
}
}
@@ -92,29 +106,34 @@ export default {
methods: {
// 搜索
toggleSearch() {
this.$emit("update:showSearch", !this.showSearch);
this.$emit("update:showSearch", !this.showSearch)
},
// 刷新
refresh() {
this.$emit("queryTable");
this.$emit("queryTable")
},
// 右侧列表元素变化
dataChange(data) {
for (let item in this.columns) {
const key = this.columns[item].key;
this.columns[item].visible = !data.includes(key);
const key = this.columns[item].key
this.columns[item].visible = !data.includes(key)
}
},
// 打开显隐列dialog
showColumn() {
this.open = true;
this.open = true
},
// 勾选
// 勾选
checkboxChange(event, label) {
this.columns.filter(item => item.label == label)[0].visible = event;
this.columns.filter(item => item.label == label)[0].visible = event
},
// 切换全选/反选
toggleCheckAll() {
const newValue = !this.isChecked
this.columns.forEach((col) => (col.visible = newValue))
}
},
};
}
</script>
<style lang="scss" scoped>
::v-deep .el-transfer__button {
@@ -126,4 +145,10 @@ export default {
::v-deep .el-transfer__button:first-child {
margin-bottom: 10px;
}
.check-line {
width: 90%;
height: 1px;
background-color: #ccc;
margin: 3px auto;
}
</style>

View File

@@ -51,6 +51,5 @@ export default {
})
}
}
}
</script>

View File

@@ -32,11 +32,11 @@
</template>
<script>
import { constantRoutes } from "@/router";
import { isHttp } from "@/utils/validate";
import { constantRoutes } from "@/router"
import { isHttp } from "@/utils/validate"
// 隐藏侧边栏路由
const hideList = ['/index', '/user/profile'];
const hideList = ['/index', '/user/profile']
export default {
data() {
@@ -45,67 +45,67 @@ export default {
visibleNumber: 5,
// 当前激活菜单的 index
currentIndex: undefined
};
}
},
computed: {
theme() {
return this.$store.state.settings.theme;
return this.$store.state.settings.theme
},
// 顶部显示菜单
topMenus() {
let topMenus = [];
let topMenus = []
this.routers.map((menu) => {
if (menu.hidden !== true) {
// 兼容顶部栏一级菜单内部跳转
if (menu.path === "/") {
topMenus.push(menu.children[0]);
if (menu.path === '/' && menu.children) {
topMenus.push(menu.children[0])
} else {
topMenus.push(menu);
topMenus.push(menu)
}
}
});
return topMenus;
})
return topMenus
},
// 所有的路由信息
routers() {
return this.$store.state.permission.topbarRouters;
return this.$store.state.permission.topbarRouters
},
// 设置子路由
childrenMenus() {
var childrenMenus = [];
var childrenMenus = []
this.routers.map((router) => {
for (var item in router.children) {
if (router.children[item].parentPath === undefined) {
if(router.path === "/") {
router.children[item].path = "/" + router.children[item].path;
router.children[item].path = "/" + router.children[item].path
} else {
if(!isHttp(router.children[item].path)) {
router.children[item].path = router.path + "/" + router.children[item].path;
router.children[item].path = router.path + "/" + router.children[item].path
}
}
router.children[item].parentPath = router.path;
router.children[item].parentPath = router.path
}
childrenMenus.push(router.children[item]);
childrenMenus.push(router.children[item])
}
});
return constantRoutes.concat(childrenMenus);
})
return constantRoutes.concat(childrenMenus)
},
// 默认激活的菜单
activeMenu() {
const path = this.$route.path;
let activePath = path;
const path = this.$route.path
let activePath = path
if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
const tmpPath = path.substring(1, path.length);
const tmpPath = path.substring(1, path.length)
if (!this.$route.meta.link) {
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
this.$store.dispatch('app/toggleSideBarHide', false);
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"))
this.$store.dispatch('app/toggleSideBarHide', false)
}
} else if(!this.$route.children) {
activePath = path;
this.$store.dispatch('app/toggleSideBarHide', true);
activePath = path
this.$store.dispatch('app/toggleSideBarHide', true)
}
this.activeRoutes(activePath);
return activePath;
this.activeRoutes(activePath)
return activePath
},
},
beforeMount() {
@@ -115,55 +115,55 @@ export default {
window.removeEventListener('resize', this.setVisibleNumber)
},
mounted() {
this.setVisibleNumber();
this.setVisibleNumber()
},
methods: {
// 根据宽度计算设置显示栏数
setVisibleNumber() {
const width = document.body.getBoundingClientRect().width / 3;
this.visibleNumber = parseInt(width / 85);
const width = document.body.getBoundingClientRect().width / 3
this.visibleNumber = parseInt(width / 85)
},
// 菜单选择事件
handleSelect(key, keyPath) {
this.currentIndex = key;
const route = this.routers.find(item => item.path === key);
this.currentIndex = key
const route = this.routers.find(item => item.path === key)
if (isHttp(key)) {
// http(s):// 路径新窗口打开
window.open(key, "_blank");
window.open(key, "_blank")
} else if (!route || !route.children) {
// 没有子路由路径内部打开
const routeMenu = this.childrenMenus.find(item => item.path === key);
const routeMenu = this.childrenMenus.find(item => item.path === key)
if (routeMenu && routeMenu.query) {
let query = JSON.parse(routeMenu.query);
this.$router.push({ path: key, query: query });
let query = JSON.parse(routeMenu.query)
this.$router.push({ path: key, query: query })
} else {
this.$router.push({ path: key });
this.$router.push({ path: key })
}
this.$store.dispatch('app/toggleSideBarHide', true);
this.$store.dispatch('app/toggleSideBarHide', true)
} else {
// 显示左侧联动菜单
this.activeRoutes(key);
this.$store.dispatch('app/toggleSideBarHide', false);
this.activeRoutes(key)
this.$store.dispatch('app/toggleSideBarHide', false)
}
},
// 当前激活的路由
activeRoutes(key) {
var routes = [];
var routes = []
if (this.childrenMenus && this.childrenMenus.length > 0) {
this.childrenMenus.map((item) => {
if (key == item.parentPath || (key == "index" && "" == item.path)) {
routes.push(item);
routes.push(item)
}
});
})
}
if(routes.length > 0) {
this.$store.commit("SET_SIDEBAR_ROUTERS", routes);
this.$store.commit("SET_SIDEBAR_ROUTERS", routes)
} else {
this.$store.dispatch('app/toggleSideBarHide', true);
this.$store.dispatch('app/toggleSideBarHide', true)
}
}
},
};
}
</script>
<style lang="scss">

View File

@@ -21,16 +21,16 @@ export default {
height: document.documentElement.clientHeight - 94.5 + "px;",
loading: true,
url: this.src
};
}
},
mounted: function () {
setTimeout(() => {
this.loading = false;
}, 300);
const that = this;
this.loading = false
}, 300)
const that = this
window.onresize = function temp() {
that.height = document.documentElement.clientHeight - 94.5 + "px;";
};
that.height = document.documentElement.clientHeight - 94.5 + "px;"
}
}
};
}
</script>

View File

@@ -8,57 +8,57 @@ export default {
const value = binding.value
if (value == false) return
// 获取拖拽内容头部
const dialogHeaderEl = el.querySelector('.el-dialog__header');
const dragDom = el.querySelector('.el-dialog');
dialogHeaderEl.style.cursor = 'move';
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
dragDom.style.position = 'absolute';
dragDom.style.marginTop = 0;
let width = dragDom.style.width;
const dialogHeaderEl = el.querySelector('.el-dialog__header')
const dragDom = el.querySelector('.el-dialog')
dialogHeaderEl.style.cursor = 'move'
// 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null)
const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null)
dragDom.style.position = 'absolute'
dragDom.style.marginTop = 0
let width = dragDom.style.width
if (width.includes('%')) {
width = +document.body.clientWidth * (+width.replace(/\%/g, '') / 100);
width = +document.body.clientWidth * (+width.replace(/\%/g, '') / 100)
} else {
width = +width.replace(/\px/g, '');
width = +width.replace(/\px/g, '')
}
dragDom.style.left = `${(document.body.clientWidth - width) / 2}px`;
dragDom.style.left = `${(document.body.clientWidth - width) / 2}px`
// 鼠标按下事件
dialogHeaderEl.onmousedown = (e) => {
// 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离)
const disX = e.clientX - dialogHeaderEl.offsetLeft;
const disY = e.clientY - dialogHeaderEl.offsetTop;
const disX = e.clientX - dialogHeaderEl.offsetLeft
const disY = e.clientY - dialogHeaderEl.offsetTop
// 获取到的值带px 正则匹配替换
let styL, styT;
let styL, styT
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
if (sty.left.includes('%')) {
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100);
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100);
styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100)
styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100)
} else {
styL = +sty.left.replace(/\px/g, '');
styT = +sty.top.replace(/\px/g, '');
};
styL = +sty.left.replace(/\px/g, '')
styT = +sty.top.replace(/\px/g, '')
}
// 鼠标拖拽事件
document.onmousemove = function (e) {
// 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离)
const l = e.clientX - disX;
const t = e.clientY - disY;
const l = e.clientX - disX
const t = e.clientY - disY
let finallyL = l + styL
let finallyT = t + styT
// 移动当前元素
dragDom.style.left = `${finallyL}px`;
dragDom.style.top = `${finallyT}px`;
dragDom.style.left = `${finallyL}px`
dragDom.style.top = `${finallyT}px`
};
}
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
document.onmousemove = null
document.onmouseup = null
}
}
}
};
}

View File

@@ -5,30 +5,30 @@
export default {
bind(el) {
const dragDom = el.querySelector('.el-dialog');
const lineEl = document.createElement('div');
lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;';
const dragDom = el.querySelector('.el-dialog')
const lineEl = document.createElement('div')
lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;'
lineEl.addEventListener('mousedown',
function(e) {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft;
const disY = e.clientY - el.offsetTop;
const disX = e.clientX - el.offsetLeft
const disY = e.clientY - el.offsetTop
// 当前宽度 高度
const curWidth = dragDom.offsetWidth;
const curHeight = dragDom.offsetHeight;
const curWidth = dragDom.offsetWidth
const curHeight = dragDom.offsetHeight
document.onmousemove = function(e) {
e.preventDefault(); // 移动时禁用默认事件
e.preventDefault() // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const xl = e.clientX - disX;
const xl = e.clientX - disX
const yl = e.clientY - disY
dragDom.style.width = `${curWidth + xl}px`;
dragDom.style.height = `${curHeight + yl}px`;
};
dragDom.style.width = `${curWidth + xl}px`
dragDom.style.height = `${curHeight + yl}px`
}
document.onmouseup = function(e) {
document.onmousemove = null;
document.onmouseup = null;
};
}, false);
dragDom.appendChild(lineEl);
document.onmousemove = null
document.onmouseup = null
}
}, false)
dragDom.appendChild(lineEl)
}
}

View File

@@ -5,26 +5,26 @@
export default {
bind(el) {
const dragDom = el.querySelector('.el-dialog');
const lineEl = document.createElement('div');
lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;';
const dragDom = el.querySelector('.el-dialog')
const lineEl = document.createElement('div')
lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;'
lineEl.addEventListener('mousedown',
function (e) {
// 鼠标按下,计算当前元素距离可视区的距离
const disX = e.clientX - el.offsetLeft;
const disX = e.clientX - el.offsetLeft
// 当前宽度
const curWidth = dragDom.offsetWidth;
const curWidth = dragDom.offsetWidth
document.onmousemove = function (e) {
e.preventDefault(); // 移动时禁用默认事件
e.preventDefault() // 移动时禁用默认事件
// 通过事件委托,计算移动的距离
const l = e.clientX - disX;
dragDom.style.width = `${curWidth + l}px`;
};
const l = e.clientX - disX
dragDom.style.width = `${curWidth + l}px`
}
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
}, false);
dragDom.appendChild(lineEl);
document.onmousemove = null
document.onmouseup = null
}
}, false)
dragDom.appendChild(lineEl)
}
}

View File

@@ -17,7 +17,7 @@ const install = function(Vue) {
if (window.Vue) {
window['hasRole'] = hasRole
window['hasPermi'] = hasPermi
Vue.use(install); // eslint-disable-line
Vue.use(install)
}
export default install

View File

@@ -8,47 +8,47 @@ export default {
bind(el, binding, vnode) {
switch (binding.arg) {
case 'success':
el._vClipBoard_success = binding.value;
break;
el._vClipBoard_success = binding.value
break
case 'error':
el._vClipBoard_error = binding.value;
break;
el._vClipBoard_error = binding.value
break
default: {
const clipboard = new Clipboard(el, {
text: () => binding.value,
action: () => binding.arg === 'cut' ? 'cut' : 'copy'
});
})
clipboard.on('success', e => {
const callback = el._vClipBoard_success;
callback && callback(e);
});
const callback = el._vClipBoard_success
callback && callback(e)
})
clipboard.on('error', e => {
const callback = el._vClipBoard_error;
callback && callback(e);
});
el._vClipBoard = clipboard;
const callback = el._vClipBoard_error
callback && callback(e)
})
el._vClipBoard = clipboard
}
}
},
update(el, binding) {
if (binding.arg === 'success') {
el._vClipBoard_success = binding.value;
el._vClipBoard_success = binding.value
} else if (binding.arg === 'error') {
el._vClipBoard_error = binding.value;
el._vClipBoard_error = binding.value
} else {
el._vClipBoard.text = function () { return binding.value; };
el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy';
el._vClipBoard.text = function () { return binding.value }
el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy'
}
},
unbind(el, binding) {
if (!el._vClipboard) return
if (binding.arg === 'success') {
delete el._vClipBoard_success;
delete el._vClipBoard_success
} else if (binding.arg === 'error') {
delete el._vClipBoard_error;
delete el._vClipBoard_error
} else {
el._vClipBoard.destroy();
delete el._vClipBoard;
el._vClipBoard.destroy()
delete el._vClipBoard
}
}
}

View File

@@ -8,7 +8,7 @@ import store from '@/store'
export default {
inserted(el, binding, vnode) {
const { value } = binding
const all_permission = "*:*:*";
const all_permission = "*:*:*"
const permissions = store.getters && store.getters.permissions
if (value && value instanceof Array && value.length > 0) {

View File

@@ -8,7 +8,7 @@ import store from '@/store'
export default {
inserted(el, binding, vnode) {
const { value } = binding
const super_admin = "admin";
const super_admin = "admin"
const roles = store.getters && store.getters.roles
if (value && value instanceof Array && value.length > 0) {

View File

@@ -6,15 +6,17 @@
</keep-alive>
</transition>
<iframe-toggle />
<copyright />
</section>
</template>
<script>
import copyright from "./Copyright/index"
import iframeToggle from "./IframeToggle/index"
export default {
name: 'AppMain',
components: { iframeToggle },
components: { iframeToggle, copyright },
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews
@@ -33,7 +35,7 @@ export default {
},
methods: {
addIframe() {
const {name} = this.$route
const { name } = this.$route
if (name && this.$route.meta.link) {
this.$store.dispatch('tagsView/addIframeView', this.$route)
}
@@ -51,6 +53,10 @@ export default {
overflow: hidden;
}
.app-main:has(.copyright) {
padding-bottom: 36px;
}
.fixed-header + .app-main {
padding-top: 50px;
}

View File

@@ -0,0 +1,35 @@
<template>
<footer v-if="visible" class="copyright">
<span>{{ content }}</span>
</footer>
</template>
<script>
export default {
computed: {
visible() {
return this.$store.state.settings.footerVisible
},
content() {
return this.$store.state.settings.footerContent
}
}
}
</script>
<style scoped>
.copyright {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 36px;
padding: 10px 20px;
text-align: right;
background-color: #f8f8f8;
color: #666;
font-size: 14px;
border-top: 1px solid #e7e7e7;
z-index: 999;
}
</style>

View File

@@ -11,22 +11,22 @@
</template>
<script>
import InnerLink from "../InnerLink/index";
import InnerLink from "../InnerLink/index"
export default {
components: { InnerLink },
computed: {
iframeViews() {
return this.$store.state.tagsView.iframeViews;
return this.$store.state.tagsView.iframeViews
}
},
methods: {
iframeUrl(url, query) {
if (Object.keys(query).length > 0) {
let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&");
return url + "?" + params;
let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&")
return url + "?" + params
}
return url;
return url
}
}
}

View File

@@ -24,24 +24,24 @@ export default {
return {
loading: false,
height: document.documentElement.clientHeight - 94.5 + "px;"
};
}
},
mounted() {
var _this = this;
const iframeId = ("#" + this.iframeId).replace(/\//g, "\\/");
const iframe = document.querySelector(iframeId);
var _this = this
const iframeId = ("#" + this.iframeId).replace(/\//g, "\\/")
const iframe = document.querySelector(iframeId)
// iframe页面loading控制
if (iframe.attachEvent) {
this.loading = true;
this.loading = true
iframe.attachEvent("onload", function () {
_this.loading = false;
});
_this.loading = false
})
} else {
this.loading = true;
this.loading = true
iframe.onload = function () {
_this.loading = false;
};
_this.loading = false
}
}
}
};
}
</script>

View File

@@ -25,23 +25,24 @@
</template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
<div class="avatar-wrapper">
<img :src="avatar" class="user-avatar">
<i class="el-icon-caret-bottom" />
<span class="user-nickname"> {{ nickName }} </span>
</div>
<el-dropdown-menu slot="dropdown">
<router-link to="/user/profile">
<el-dropdown-item>个人中心</el-dropdown-item>
</router-link>
<el-dropdown-item @click.native="setting = true">
<span>布局设置</span>
</el-dropdown-item>
<el-dropdown-item divided @click.native="logout">
<span>退出登录</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class="right-menu-item hover-effect setting" @click="setLayout" v-if="setting">
<svg-icon icon-class="more-up" />
</div>
</div>
</div>
</template>
@@ -58,6 +59,7 @@ import RuoYiGit from '@/components/RuoYi/Git'
import RuoYiDoc from '@/components/RuoYi/Doc'
export default {
emits: ['setLayout'],
components: {
Breadcrumb,
TopNav,
@@ -72,17 +74,12 @@ export default {
...mapGetters([
'sidebar',
'avatar',
'device'
'device',
'nickName'
]),
setting: {
get() {
return this.$store.state.settings.showSettings
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'showSettings',
value: val
})
}
},
topNav: {
@@ -95,16 +92,19 @@ export default {
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
async logout() {
setLayout(event) {
this.$emit('setLayout')
},
logout() {
this.$confirm('确定注销并退出系统吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$store.dispatch('LogOut').then(() => {
location.href = '/index';
location.href = '/index'
})
}).catch(() => {});
}).catch(() => {})
}
}
}
@@ -173,17 +173,25 @@ export default {
}
.avatar-container {
margin-right: 30px;
margin-right: 0px;
padding-right: 0px;
.avatar-wrapper {
margin-top: 5px;
margin-top: 10px;
position: relative;
.user-avatar {
cursor: pointer;
width: 40px;
height: 40px;
border-radius: 10px;
width: 30px;
height: 30px;
border-radius: 50%;
}
.user-nickname{
position: relative;
bottom: 10px;
font-size: 14px;
font-weight: bold;
}
.el-icon-caret-bottom {

View File

@@ -1,5 +1,5 @@
<template>
<el-drawer size="280px" :visible="visible" :with-header="false" :append-to-body="true" :show-close="false">
<el-drawer size="280px" :visible="showSettings" :with-header="false" :append-to-body="true" :before-close="closeSetting" :lock-scroll="false">
<div class="drawer-container">
<div>
<div class="setting-drawer-content">
@@ -49,6 +49,11 @@
<el-switch v-model="tagsView" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>显示页签图标</span>
<el-switch v-model="tagsIcon" :disabled="!tagsView" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>固定 Header</span>
<el-switch v-model="fixedHeader" class="drawer-switch" />
@@ -64,6 +69,11 @@
<el-switch v-model="dynamicTitle" class="drawer-switch" />
</div>
<div class="drawer-item">
<span>底部版权</span>
<el-switch v-model="footerVisible" class="drawer-switch" />
</div>
<el-divider/>
<el-button size="small" type="primary" plain icon="el-icon-document-add" @click="saveSetting">保存配置</el-button>
@@ -78,18 +88,15 @@ import ThemePicker from '@/components/ThemePicker'
export default {
components: { ThemePicker },
expose: ['openSetting'],
data() {
return {
theme: this.$store.state.settings.theme,
sideTheme: this.$store.state.settings.sideTheme
};
sideTheme: this.$store.state.settings.sideTheme,
showSettings: false
}
},
computed: {
visible: {
get() {
return this.$store.state.settings.showSettings
}
},
fixedHeader: {
get() {
return this.$store.state.settings.fixedHeader
@@ -111,8 +118,8 @@ export default {
value: val
})
if (!val) {
this.$store.dispatch('app/toggleSideBarHide', false);
this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes);
this.$store.dispatch('app/toggleSideBarHide', false)
this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes)
}
}
},
@@ -127,6 +134,17 @@ export default {
})
}
},
tagsIcon: {
get() {
return this.$store.state.settings.tagsIcon
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'tagsIcon',
value: val
})
}
},
sidebarLogo: {
get() {
return this.$store.state.settings.sidebarLogo
@@ -147,8 +165,20 @@ export default {
key: 'dynamicTitle',
value: val
})
this.$store.dispatch('settings/setTitle', this.$store.state.settings.title)
}
},
footerVisible: {
get() {
return this.$store.state.settings.footerVisible
},
set(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'footerVisible',
value: val
})
}
}
},
methods: {
themeChange(val) {
@@ -156,33 +186,41 @@ export default {
key: 'theme',
value: val
})
this.theme = val;
this.theme = val
},
handleTheme(val) {
this.$store.dispatch('settings/changeSetting', {
key: 'sideTheme',
value: val
})
this.sideTheme = val;
this.sideTheme = val
},
openSetting() {
this.showSettings = true
},
closeSetting(){
this.showSettings = false
},
saveSetting() {
this.$modal.loading("正在保存到本地,请稍候...");
this.$modal.loading("正在保存到本地,请稍候...")
this.$cache.local.set(
"layout-setting",
`{
"topNav":${this.topNav},
"tagsView":${this.tagsView},
"tagsIcon":${this.tagsIcon},
"fixedHeader":${this.fixedHeader},
"sidebarLogo":${this.sidebarLogo},
"dynamicTitle":${this.dynamicTitle},
"footerVisible":${this.footerVisible},
"sideTheme":"${this.sideTheme}",
"theme":"${this.theme}"
}`
);
)
setTimeout(this.$modal.closeLoading(), 1000)
},
resetSetting() {
this.$modal.loading("正在清除设置缓存并刷新,请稍候...");
this.$modal.loading("正在清除设置缓存并刷新,请稍候...")
this.$cache.local.remove("layout-setting")
setTimeout("window.location.reload()", 1000)
}

View File

@@ -27,7 +27,7 @@ export default {
},
computed: {
variables() {
return variables;
return variables
},
sideTheme() {
return this.$store.state.settings.sideTheme

View File

@@ -57,7 +57,7 @@ export default {
methods: {
hasOneShowingChild(children = [], parent) {
if (!children) {
children = [];
children = []
}
const showingChildren = children.filter(item => {
if (item.hidden) {
@@ -89,7 +89,7 @@ export default {
return this.basePath
}
if (routeQuery) {
let query = JSON.parse(routeQuery);
let query = JSON.parse(routeQuery)
return { path: path.resolve(this.basePath, routePath), query: query }
}
return path.resolve(this.basePath, routePath)

View File

@@ -24,10 +24,10 @@
</template>
<script>
import { mapGetters, mapState } from "vuex";
import Logo from "./Logo";
import SidebarItem from "./SidebarItem";
import variables from "@/assets/styles/variables.scss";
import { mapGetters, mapState } from "vuex"
import Logo from "./Logo"
import SidebarItem from "./SidebarItem"
import variables from "@/assets/styles/variables.scss"
export default {
components: { SidebarItem, Logo },
@@ -35,23 +35,23 @@ export default {
...mapState(["settings"]),
...mapGetters(["sidebarRouters", "sidebar"]),
activeMenu() {
const route = this.$route;
const { meta, path } = route;
const route = this.$route
const { meta, path } = route
// if set path, the sidebar will highlight the path you set
if (meta.activeMenu) {
return meta.activeMenu;
return meta.activeMenu
}
return path;
return path
},
showLogo() {
return this.$store.state.settings.sidebarLogo;
return this.$store.state.settings.sidebarLogo
},
variables() {
return variables;
return variables
},
isCollapse() {
return !this.sidebar.opened;
return !this.sidebar.opened
}
}
};
}
</script>

View File

@@ -5,7 +5,7 @@
v-for="tag in visitedViews"
ref="tag"
:key="tag.path"
:class="isActive(tag)?'active':''"
:class="{ 'active': isActive(tag), 'has-icon': tagsIcon }"
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
tag="span"
class="tags-view-item"
@@ -13,6 +13,7 @@
@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
@contextmenu.prevent.native="openMenu(tag,$event)"
>
<svg-icon v-if="tagsIcon && tag.meta && tag.meta.icon && tag.meta.icon !== '#'" :icon-class="tag.meta.icon" />
{{ tag.title }}
<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
</router-link>
@@ -51,7 +52,10 @@ export default {
return this.$store.state.permission.routes
},
theme() {
return this.$store.state.settings.theme;
return this.$store.state.settings.theme
},
tagsIcon() {
return this.$store.state.settings.tagsIcon
}
},
watch: {
@@ -76,11 +80,11 @@ export default {
return route.path === this.$route.path
},
activeStyle(tag) {
if (!this.isActive(tag)) return {};
if (!this.isActive(tag)) return {}
return {
"background-color": this.theme,
"border-color": this.theme
};
}
},
isAffix(tag) {
return tag.meta && tag.meta.affix
@@ -151,7 +155,7 @@ export default {
})
},
refreshSelectedTag(view) {
this.$tab.refreshPage(view);
this.$tab.refreshPage(view)
if (this.$route.meta.link) {
this.$store.dispatch('tagsView/delIframeView', this.$route)
}
@@ -178,7 +182,7 @@ export default {
})
},
closeOthersTags() {
this.$router.push(this.selectedTag.fullPath).catch(()=>{});
this.$router.push(this.selectedTag.fullPath).catch(()=>{})
this.$tab.closeOtherPage(this.selectedTag).then(() => {
this.moveToCurrentTag()
})
@@ -277,6 +281,11 @@ export default {
}
}
}
.tags-view-item.active.has-icon::before {
content: none !important;
}
.contextmenu {
margin: 0;
background: #fff;

View File

@@ -4,19 +4,16 @@
<sidebar v-if="!sidebar.hide" class="sidebar-container"/>
<div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar/>
<navbar @setLayout="setLayout"/>
<tags-view v-if="needTagsView"/>
</div>
<app-main/>
<right-panel>
<settings/>
</right-panel>
<settings ref="settingRef"/>
</div>
</div>
</template>
<script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'
@@ -27,7 +24,6 @@ export default {
components: {
AppMain,
Navbar,
RightPanel,
Settings,
Sidebar,
TagsView
@@ -51,12 +47,15 @@ export default {
}
},
variables() {
return variables;
return variables
}
},
methods: {
handleClickOutside() {
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
},
setLayout() {
this.$refs.settingRef.openSetting()
}
}
}

View File

@@ -16,11 +16,11 @@ import { download } from '@/utils/request'
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, selectDictLabels, handleTree } from "@/utils/ruoyi";
import { getDicts } from "@/api/system/dict/data"
import { getConfigKey } from "@/api/system/config"
import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi"
// 分页组件
import Pagination from "@/components/Pagination";
import Pagination from "@/components/Pagination"
// 自定义表格工具组件
import RightToolbar from "@/components/RightToolbar"
// 富文本组件
@@ -33,8 +33,6 @@ import ImageUpload from "@/components/ImageUpload"
import ImagePreview from "@/components/ImagePreview"
// 字典标签组件
import DictTag from '@/components/DictTag'
// 头部标签组件
import VueMeta from 'vue-meta'
// 字典数据组件
import DictData from '@/components/DictData'
@@ -60,7 +58,6 @@ Vue.component('ImagePreview', ImagePreview)
Vue.use(directive)
Vue.use(plugins)
Vue.use(VueMeta)
DictData.install()
/**

View File

@@ -1,7 +1,7 @@
import store from '@/store'
function authPermission(permission) {
const all_permission = "*:*:*";
const all_permission = "*:*:*"
const permissions = store.getters && store.getters.permissions
if (permission && permission.length > 0) {
return permissions.some(v => {
@@ -13,7 +13,7 @@ function authPermission(permission) {
}
function authRole(role) {
const super_admin = "admin";
const super_admin = "admin"
const roles = store.getters && store.getters.roles
if (role && role.length > 0) {
return roles.some(v => {
@@ -27,7 +27,7 @@ function authRole(role) {
export default {
// 验证用户是否具备某权限
hasPermi(permission) {
return authPermission(permission);
return authPermission(permission)
},
// 验证用户是否含有指定权限,只需包含其中一个
hasPermiOr(permissions) {
@@ -43,7 +43,7 @@ export default {
},
// 验证用户是否具备某角色
hasRole(role) {
return authRole(role);
return authRole(role)
},
// 验证用户是否含有指定角色,只需包含其中一个
hasRoleOr(roles) {

View File

@@ -29,7 +29,7 @@ const sessionCache = {
return null
},
remove (key) {
sessionStorage.removeItem(key);
sessionStorage.removeItem(key)
}
}
const localCache = {
@@ -63,7 +63,7 @@ const localCache = {
return null
},
remove (key) {
localStorage.removeItem(key);
localStorage.removeItem(key)
}
}

View File

@@ -3,10 +3,10 @@ import {Loading, Message} from 'element-ui'
import { saveAs } from 'file-saver'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { blobValidate } from "@/utils/ruoyi";
import { blobValidate } from "@/utils/ruoyi"
const baseURL = process.env.VUE_APP_BASE_API
let downloadLoadingInstance;
let downloadLoadingInstance
export default {
zip(url, name) {
@@ -18,28 +18,28 @@ export default {
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then((res) => {
const isBlob = blobValidate(res.data);
const isBlob = blobValidate(res.data)
if (isBlob) {
const blob = new Blob([res.data], { type: 'application/zip' })
this.saveAs(blob, name)
} else {
this.printErrMsg(res.data);
this.printErrMsg(res.data)
}
downloadLoadingInstance.close();
downloadLoadingInstance.close()
}).catch((r) => {
console.error(r)
Message.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close();
downloadLoadingInstance.close()
})
},
saveAs(text, name, opts) {
saveAs(text, name, opts);
saveAs(text, name, opts)
},
async printErrMsg(data) {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const resText = await data.text()
const rspObj = JSON.parse(resText)
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
Message.error(errMsg);
Message.error(errMsg)
}
}

View File

@@ -1,6 +1,6 @@
import { Message, MessageBox, Notification, Loading } from 'element-ui'
let loadingInstance;
let loadingInstance
export default {
// 消息提示
@@ -41,7 +41,7 @@ export default {
},
// 错误通知
notifyError(content) {
Notification.error(content);
Notification.error(content)
},
// 成功通知
notifySuccess(content) {
@@ -78,6 +78,6 @@ export default {
},
// 关闭遮罩层
closeLoading() {
loadingInstance.close();
loadingInstance.close()
}
}

View File

@@ -1,18 +1,18 @@
import store from '@/store'
import router from '@/router';
import router from '@/router'
export default {
// 刷新当前tab页签
refreshPage(obj) {
const { path, query, matched } = router.currentRoute;
const { path, query, matched } = router.currentRoute
if (obj === undefined) {
matched.forEach((m) => {
if (m.components && m.components.default && m.components.default.name) {
if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
obj = { name: m.components.default.name, path: path, query: query };
obj = { name: m.components.default.name, path: path, query: query }
}
}
});
})
}
return store.dispatch('tagsView/delCachedView', obj).then(() => {
const { path, query } = obj
@@ -24,9 +24,9 @@ export default {
},
// 关闭当前tab页签打开新页签
closeOpenPage(obj) {
store.dispatch("tagsView/delView", router.currentRoute);
store.dispatch("tagsView/delView", router.currentRoute)
if (obj !== undefined) {
return router.push(obj);
return router.push(obj)
}
},
// 关闭指定tab页签
@@ -37,35 +37,35 @@ export default {
if (latestView) {
return router.push(latestView.fullPath)
}
return router.push('/');
});
return router.push('/')
})
}
return store.dispatch('tagsView/delView', obj);
return store.dispatch('tagsView/delView', obj)
},
// 关闭所有tab页签
closeAllPage() {
return store.dispatch('tagsView/delAllViews');
return store.dispatch('tagsView/delAllViews')
},
// 关闭左侧tab页签
closeLeftPage(obj) {
return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute);
return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute)
},
// 关闭右侧tab页签
closeRightPage(obj) {
return store.dispatch('tagsView/delRightTags', obj || router.currentRoute);
return store.dispatch('tagsView/delRightTags', obj || router.currentRoute)
},
// 关闭其他tab页签
closeOtherPage(obj) {
return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute);
return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute)
},
// 添加tab页签
openPage(title, url, params) {
const obj = { path: url, meta: { title: title } }
store.dispatch('tagsView/addView', obj);
return router.push({ path: url, query: params });
store.dispatch('tagsView/addView', obj)
return router.push({ path: url, query: params })
},
// 修改tab页签
updatePage(obj) {
return store.dispatch('tagsView/updateVisitedView', obj);
return store.dispatch('tagsView/updateVisitedView', obj)
}
}

View File

@@ -165,8 +165,8 @@ export const dynamicRoutes = [
]
// 防止连续点击多次路由报错
let routerPush = Router.prototype.push;
let routerReplace = Router.prototype.replace;
let routerPush = Router.prototype.push
let routerReplace = Router.prototype.replace
// push
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch(err => err)

View File

@@ -1,13 +1,18 @@
module.exports = {
/**
* 网页标题
*/
title: process.env.VUE_APP_TITLE,
/**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/
sideTheme: 'theme-dark',
/**
* 是否系统布局配置
* 系统布局配置
*/
showSettings: false,
showSettings: true,
/**
* 是否显示顶部导航
@@ -18,6 +23,11 @@ module.exports = {
* 是否显示 tagsView
*/
tagsView: true,
/**
* 显示页签图标
*/
tagsIcon: false,
/**
* 是否固定头部
@@ -35,10 +45,12 @@ module.exports = {
dynamicTitle: false,
/**
* @type {string | array} 'production' | ['production', 'development']
* @description Need show err logs component.
* The default is only used in the production env
* If you want to also use it in dev, you can pass ['production', 'development']
* 是否显示底部版权
*/
errorLog: 'production'
footerVisible: false,
/**
* 底部版权文本内容
*/
footerContent: 'Copyright © 2018-2025 RuoYi. All Rights Reserved.'
}

View File

@@ -7,13 +7,15 @@ const getters = {
cachedViews: state => state.tagsView.cachedViews,
token: state => state.user.token,
avatar: state => state.user.avatar,
id: state => state.user.id,
name: state => state.user.name,
nickName: state => state.user.nickName,
introduction: state => state.user.introduction,
roles: state => state.user.roles,
permissions: state => state.user.permissions,
permission_routes: state => state.permission.routes,
topbarRouters:state => state.permission.topbarRouters,
defaultRoutes:state => state.permission.defaultRoutes,
sidebarRouters:state => state.permission.sidebarRouters,
topbarRouters: state => state.permission.topbarRouters,
defaultRoutes: state => state.permission.defaultRoutes,
sidebarRouters: state => state.permission.sidebarRouters
}
export default getters

View File

@@ -13,7 +13,7 @@ const state = {
const mutations = {
TOGGLE_SIDEBAR: state => {
if (state.sidebar.hide) {
return false;
return false
}
state.sidebar.opened = !state.sidebar.opened
state.sidebar.withoutAnimation = false

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