diff --git a/.gitignore b/.gitignore index 5d947ca8879f8a9072fe485c566204e3c2929e80..eccf09647d5edc926587cdfe3a1483369695c426 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ bin-release/ # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` # should NOT be excluded as they contain compiler settings and other important # information for Eclipse / Flash Builder. +/super-data-api.iml +/target/ diff --git a/README.md b/README.md index 0d503fa49f185346e796ec073cbd819ec1b9df3c..1034f2ac8f3ab6ea842f092e1ced0660c8f5ffc5 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,75 @@ -# 超级数据-api +# super-data-api -#### 介绍 -通过页面配置生成接口 +### 项目说明 + 通过页面配置动态生成在线接口。 +### 项目特点 +能够快速动态生成CRUD接口,减少重复工作 +可以在项目中扩展编写复自定义接口 +支持MySQL、ElasticSearch数据库 +Mysql支持关联查询 +支持报表导出接口 +支持自定义sql生成接口 + +#### 安装教程 +通过git下载源码 +执行db下initDataBase和v1.0.sql文件,初始化数据 +修改application.yml,更新MySQL账号和密码、数据库名称 +Linux环境运行sh文件下 ./run_super-data-api.sh start 脚本命令 +http://localhost:1001/home.html 打开主页面 #### 软件架构 -软件架构说明 +JDK1.8、Maven、IDEA、SpringBoot 2.2.4.RELEASE、ElasticSearch、Mybatis-Plus、Vue等 + +#### 使用说明 +1.新建数据源 +![img_1.png](img_1.png) -#### 安装教程 +2.新增接口 -1. xxxx -2. xxxx -3. xxxx + 2.1 Insert类型接口 + 2.1.1 Mysql数据源要先选择数据源,然后选择数据库,再选择想插入的表即可,接口配置中字段名称是数据库表字段名称, + 参数名称是请求的参数名称,参数类型是必须,分url传参和body传参 -#### 使用说明 +![img_2.png](img_2.png) + + 2.2.2 Es数据源只选择数据源和表即可,接口配置中信息同mysql数据源类型接口 +![img_3.png](img_3.png) + + 2.2 Delete类型接口 + 2.2.1 Delete类型接口就是根据条件删除指定表的数据,其中mysql要先选中数据库,接口配置中多了必选的条件类型字段 +![img_4.png](img_4.png) + + 2.3 Update类型接口 + 2.2.1 Update类型接口就是更新数据库,其中mysql要选中数据库,接口配置中多了必选的是否更新参数字段,意思是是 + 否是待更新的表字段 + +![img_5.png](img_5.png) + + 2.4 Select类型接口 + 2.4.1 Es数据源 + ElasticSearch数据源类型不支持关联查询,查询参数可以配置成url传参或者body传参。可以选择是否必传参数, + 和查询的条件类型。也可以配置返回参数名称,设置是否排序字段和顺序或者倒叙。若是导出接口最少配置一列导出数据。 + +![img_6.png](img_6.png) + + 2.4.2 Mysql数据源 + Mysql数据源类型在ElasticSearch功能基础上添加多表关联配置,选择好Mysql数据源可以通过接口获取获取下面的 + 表和表的字段信息,然后通过页面配置其关联关系和接口相关参数。 + +![img_7.png](img_7.png) -1. xxxx -2. xxxx -3. xxxx + 2.4.3 自定义sql接口配置 -#### 参与贡献 +![img_8.png](img_8.png) -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +3.查看、编辑、删除、调试接口 + 3.1查看接口详情 +![img_9.png](img_9.png) -#### 特技 + 3.2编辑接口 +![img_10.png](img_10.png) -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) + 3.3调试调用接口 +![img_11.png](img_11.png) diff --git a/img_1.png b/img_1.png new file mode 100644 index 0000000000000000000000000000000000000000..b3b25e42ad38b14cb1469f0b4780c5552d7a4d1c Binary files /dev/null and b/img_1.png differ diff --git a/img_10.png b/img_10.png new file mode 100644 index 0000000000000000000000000000000000000000..b88a9bc6ad0d40d28e0896a119d431011e9b1b0f Binary files /dev/null and b/img_10.png differ diff --git a/img_11.png b/img_11.png new file mode 100644 index 0000000000000000000000000000000000000000..17c0dcf75ea90393c5c862d15f433b7f42824e37 Binary files /dev/null and b/img_11.png differ diff --git a/img_2.png b/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..aebba0f9f7ff4fa6ffc153205dd4e16c9fa2b586 Binary files /dev/null and b/img_2.png differ diff --git a/img_3.png b/img_3.png new file mode 100644 index 0000000000000000000000000000000000000000..43f0f2ee211514a77d8f8b67ee9092bcfb689b4b Binary files /dev/null and b/img_3.png differ diff --git a/img_4.png b/img_4.png new file mode 100644 index 0000000000000000000000000000000000000000..bc59df787b4d7b96d5bf606edc702023c50ff8be Binary files /dev/null and b/img_4.png differ diff --git a/img_5.png b/img_5.png new file mode 100644 index 0000000000000000000000000000000000000000..fe30530abe50cae4a5d6ca0083100b879ac0f4e7 Binary files /dev/null and b/img_5.png differ diff --git a/img_6.png b/img_6.png new file mode 100644 index 0000000000000000000000000000000000000000..50665fbb81e6abaecbcf4fa83b813b4c5410191a Binary files /dev/null and b/img_6.png differ diff --git a/img_7.png b/img_7.png new file mode 100644 index 0000000000000000000000000000000000000000..f2e4f74840b4090605207c658f7b1a0e4eddbd02 Binary files /dev/null and b/img_7.png differ diff --git a/img_8.png b/img_8.png new file mode 100644 index 0000000000000000000000000000000000000000..88f48d2d5f88dba13297111a14325edac716dc7e Binary files /dev/null and b/img_8.png differ diff --git a/img_9.png b/img_9.png new file mode 100644 index 0000000000000000000000000000000000000000..ed571e1795081a9c5f3cb32ba1f8586acf922df1 Binary files /dev/null and b/img_9.png differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..4163e409959ac3383847ef1775dd3f6a5321ec8a --- /dev/null +++ b/pom.xml @@ -0,0 +1,181 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + com.xforwardai + super-data-api + 1.0-SNAPSHOT + + + 1.8 + 2.6.2 + 2.17.0 + 1.2.10 + 2.1.1 + 2.9.2 + 1.9.6 + 1.2.62 + 3.2.0 + 2.3.28 + 1.1.21 + 1.2.10 + 3.17 + 5.8.0 + 3.0 + + + + + + org.springframework.boot + spring-boot-starter-web + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + ${jasypt-spring-boot} + + + + org.springframework.boot + spring-boot-starter-data-redis + + + + io.springfox + springfox-swagger2 + ${springfox-swagger} + + + io.springfox + springfox-swagger-ui + ${springfox-swagger} + + + com.github.xiaoymin + swagger-bootstrap-ui + ${swagger-bootstrap-ui} + + + + org.springframework.boot + spring-boot-starter-data-elasticsearch + + + + com.alibaba + fastjson + ${com.alibaba} + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus} + + + org.freemarker + freemarker + ${org.freemarker} + + + + org.springframework.boot + spring-boot-starter-jdbc + + + + mysql + mysql-connector-java + + + + com.alibaba + druid + ${com.alibaba.version} + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.version} + + + org.mybatis + mybatis + + + org.mybatis + mybatis-spring + + + + + org.springframework.boot + spring-boot-starter-aop + + + org.apache.poi + poi + ${apache.poi.version} + + + org.apache.poi + poi-ooxml + ${apache.poi.version} + + + + cn.hutool + hutool-all + ${hutool.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${maven.plugin.version} + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/xforwardai/superdata/SuperDataApiApplication.java b/src/main/java/com/xforwardai/superdata/SuperDataApiApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..5e26c4d3cceec481db9e2f1b07f6f0f0c5172bba --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/SuperDataApiApplication.java @@ -0,0 +1,19 @@ +package com.xforwardai.superdata; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.annotation.EnableScheduling; + +@SpringBootApplication +@EnableAsync +@EnableScheduling +@MapperScan("com.xforwardai.superdata.mysql.mapper") +public class SuperDataApiApplication { + + public static void main(String[] args) { + SpringApplication.run(SuperDataApiApplication.class, args); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/annotation/MysqlCheckInject.java b/src/main/java/com/xforwardai/superdata/annotation/MysqlCheckInject.java new file mode 100644 index 0000000000000000000000000000000000000000..3b35b28b613fafd4262f299b53159eb2c96b0a59 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/annotation/MysqlCheckInject.java @@ -0,0 +1,30 @@ +package com.xforwardai.superdata.annotation; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +import java.lang.annotation.*; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.annotation.MysqlCheckInject.java + * @date: 2021/12/28 11:21 + * @author xujian + */ +@Documented +@Inherited +@Target(value = {ElementType.METHOD, ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface MysqlCheckInject { + + //字段唯一值判断 + String uniqueField() default ""; + + //字段唯一值条件 + String[] conditionUniqueField() default {}; + + //方法类型 add update + String method() default "add"; + + Class mapper() default BaseMapper.class; + +} diff --git a/src/main/java/com/xforwardai/superdata/annotation/aspect/MysqlCheckAspect.java b/src/main/java/com/xforwardai/superdata/annotation/aspect/MysqlCheckAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..41034a94f29e4cd221fd3bfb5454102c3a9d0d64 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/annotation/aspect/MysqlCheckAspect.java @@ -0,0 +1,33 @@ +package com.xforwardai.superdata.annotation.aspect; + +import com.xforwardai.superdata.annotation.MysqlCheckInject; +import com.xforwardai.superdata.util.MysqlCheckUtil; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.annotation.aspect.MysqlCheckAspect.java + * @date: 2021/12/28 15:17 + * @author xujian + */ +@Aspect +@Component +@Slf4j +@Order(2) +public class MysqlCheckAspect { + + @Around("@annotation(mysqlCheckInject)") + public Object around(ProceedingJoinPoint pjp, MysqlCheckInject mysqlCheckInject) throws Throwable { + Object[] args = pjp.getArgs(); + Object obj = args[0]; + String method = mysqlCheckInject.method(); + MysqlCheckUtil.check(obj, method); + return pjp.proceed(args); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/base/BaseDto.java b/src/main/java/com/xforwardai/superdata/base/BaseDto.java new file mode 100644 index 0000000000000000000000000000000000000000..ae44f10f01b58a6078901aeac9ae8f508343f7b8 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/base/BaseDto.java @@ -0,0 +1,30 @@ +package com.xforwardai.superdata.base; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.xforwardai.superdata.constants.CommonConstant; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.base.BaseDto.java + * @date: 2022/2/23 13:32 + * @author xujian + */ +@Data +public class BaseDto extends BasePageDto{ + + @ApiModelProperty(value = "主键") + private Integer id; + + @ApiModelProperty(value = "创建时间") + @JsonFormat(pattern = CommonConstant.CONSTANT_DATETIME_FORMAT) + private LocalDateTime createTime; + + @ApiModelProperty(value = "修改时间") + @JsonFormat(pattern = CommonConstant.CONSTANT_DATETIME_FORMAT) + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/xforwardai/superdata/base/BasePageDto.java b/src/main/java/com/xforwardai/superdata/base/BasePageDto.java new file mode 100644 index 0000000000000000000000000000000000000000..46f367132120531479a8f58aea14af2d6b78a79d --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/base/BasePageDto.java @@ -0,0 +1,17 @@ +package com.xforwardai.superdata.base; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class BasePageDto implements Serializable { + + @ApiModelProperty(value = "页码") + private int page; + + @ApiModelProperty(value = "页数") + private int size; + +} diff --git a/src/main/java/com/xforwardai/superdata/base/BasePageResultVo.java b/src/main/java/com/xforwardai/superdata/base/BasePageResultVo.java new file mode 100644 index 0000000000000000000000000000000000000000..17394480eca9d87b09706941a4efc3ce146e97ae --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/base/BasePageResultVo.java @@ -0,0 +1,23 @@ +package com.xforwardai.superdata.base; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; + +@Data +public class BasePageResultVo implements Serializable { + + @ApiModelProperty(value = "总数") + private long total; + + @ApiModelProperty(value = "页码") + private int page; + + @ApiModelProperty(value = "页数") + private int size; + + @ApiModelProperty(value = "业务数据") + private T content; + +} diff --git a/src/main/java/com/xforwardai/superdata/base/CommonResponse.java b/src/main/java/com/xforwardai/superdata/base/CommonResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..3606cb9efd2ad3d5ce8e347d364834e96a4450b7 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/base/CommonResponse.java @@ -0,0 +1,37 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package com.xforwardai.superdata.base; + +import com.xforwardai.superdata.constants.ResultCode; + +public class CommonResponse { + public CommonResponse() { + } + + public static CommonResult success(Object obj) { + return new CommonResult(ResultCode.SUCCEED_CODE, "成功", obj, (Object)null); + } + + public static CommonResult success(String msg, Object obj) { + return new CommonResult(ResultCode.SUCCEED_CODE, msg, obj, (Object)null); + } + + public static CommonResult success(String msg, Object obj, Object ext) { + return new CommonResult(ResultCode.SUCCEED_CODE, msg, obj, ext); + } + + public static CommonResult error(Object obj) { + return new CommonResult(ResultCode.ERROR_CODE, "失败", obj, (Object)null); + } + + public static CommonResult error(String msg, Object obj) { + return new CommonResult(ResultCode.ERROR_CODE, msg, obj, (Object)null); + } + + public static CommonResult error(String msg, Object obj, Object ext) { + return new CommonResult(ResultCode.ERROR_CODE, msg, obj, ext); + } +} diff --git a/src/main/java/com/xforwardai/superdata/base/CommonResult.java b/src/main/java/com/xforwardai/superdata/base/CommonResult.java new file mode 100644 index 0000000000000000000000000000000000000000..7cf3140954e4b49bb94e0ff8c551f70283011a58 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/base/CommonResult.java @@ -0,0 +1,150 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package com.xforwardai.superdata.base; + +import com.xforwardai.superdata.enums.ResultEnum; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.io.Serializable; + +@ApiModel("通用返回结构") +public class CommonResult implements Serializable { + private static final long serialVersionUID = 6116515098874945764L; + @ApiModelProperty("操作代码") + private int code; + @ApiModelProperty("操作信息") + private String message; + @ApiModelProperty("返回对象") + private T data; + @ApiModelProperty("附加对象") + private Object ext; + + public CommonResult() { + this.code = ResultEnum.SUCCEED.getCode(); + this.message = ResultEnum.SUCCEED.getMessage(); + } + + public CommonResult(Exception e) { + this.code = ResultEnum.ERROR.getCode(); + this.message = e.getMessage(); + } + + public CommonResult(T data) { + this.code = ResultEnum.SUCCEED.getCode(); + this.message = ResultEnum.SUCCEED.getMessage(); + this.data = data; + } + + public CommonResult(int code, String message, T data, Object ext) { + this.code = code; + this.message = message; + this.data = data; + this.ext = ext; + } + + public int getCode() { + return this.code; + } + + public String getMessage() { + return this.message; + } + + public T getData() { + return this.data; + } + + public Object getExt() { + return this.ext; + } + + public void setCode(final int code) { + this.code = code; + } + + public void setMessage(final String message) { + this.message = message; + } + + public void setData(final T data) { + this.data = data; + } + + public void setExt(final Object ext) { + this.ext = ext; + } + + public boolean equals(final Object o) { + if (o == this) { + return true; + } else if (!(o instanceof CommonResult)) { + return false; + } else { + CommonResult other = (CommonResult)o; + if (!other.canEqual(this)) { + return false; + } else if (this.getCode() != other.getCode()) { + return false; + } else { + label49: { + Object this$message = this.getMessage(); + Object other$message = other.getMessage(); + if (this$message == null) { + if (other$message == null) { + break label49; + } + } else if (this$message.equals(other$message)) { + break label49; + } + + return false; + } + + Object this$data = this.getData(); + Object other$data = other.getData(); + if (this$data == null) { + if (other$data != null) { + return false; + } + } else if (!this$data.equals(other$data)) { + return false; + } + + Object this$ext = this.getExt(); + Object other$ext = other.getExt(); + if (this$ext == null) { + if (other$ext != null) { + return false; + } + } else if (!this$ext.equals(other$ext)) { + return false; + } + + return true; + } + } + } + + protected boolean canEqual(final Object other) { + return other instanceof CommonResult; + } + + public int hashCode() { + int result = 1; + result = result * 59 + this.getCode(); + Object $message = this.getMessage(); + result = result * 59 + ($message == null ? 43 : $message.hashCode()); + Object $data = this.getData(); + result = result * 59 + ($data == null ? 43 : $data.hashCode()); + Object $ext = this.getExt(); + result = result * 59 + ($ext == null ? 43 : $ext.hashCode()); + return result; + } + + public String toString() { + return "CommonResult(code=" + this.getCode() + ", message=" + this.getMessage() + ", data=" + this.getData() + ", ext=" + this.getExt() + ")"; + } +} diff --git a/src/main/java/com/xforwardai/superdata/cache/ApiInfoCacheMap.java b/src/main/java/com/xforwardai/superdata/cache/ApiInfoCacheMap.java new file mode 100644 index 0000000000000000000000000000000000000000..7440480666b6166d3902795e8eeb0717a7979462 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/cache/ApiInfoCacheMap.java @@ -0,0 +1,18 @@ +package com.xforwardai.superdata.cache; + +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.cache.ApiInfoCacheMap.java + * @date: 2022/3/1 17:48 + * @author xujian + */ +public class ApiInfoCacheMap { + + public static Map API_INFO_MAP = new ConcurrentHashMap<>(); + +} diff --git a/src/main/java/com/xforwardai/superdata/config/HomeMvcConfigurer.java b/src/main/java/com/xforwardai/superdata/config/HomeMvcConfigurer.java new file mode 100644 index 0000000000000000000000000000000000000000..630e055e5ea01ae9a2b1d46bc0733b27935a9b65 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/config/HomeMvcConfigurer.java @@ -0,0 +1,21 @@ +package com.xforwardai.superdata.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class HomeMvcConfigurer { + + @Bean + public WebMvcConfigurer webMvcConfigurer() { + return new WebMvcConfigurer() { + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("home.html"); + } + }; + } + +} \ No newline at end of file diff --git a/src/main/java/com/xforwardai/superdata/config/RedisConfig.java b/src/main/java/com/xforwardai/superdata/config/RedisConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..175f2d58ace2a1929686408c60ae688daca35485 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/config/RedisConfig.java @@ -0,0 +1,26 @@ +package com.xforwardai.superdata.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.RedisSerializer; + +@Configuration +public class RedisConfig { + /** + * 默认redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, + * 使用所以自定义序列化类 将key和val设置为string + * @param redisConnectionFactory + * @return + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(RedisSerializer.string()); + redisTemplate.setValueSerializer(RedisSerializer.string()); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } +} diff --git a/src/main/java/com/xforwardai/superdata/config/SuperDataApiAutoConfiguration.java b/src/main/java/com/xforwardai/superdata/config/SuperDataApiAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..6246a3914672feda33d992c3776130304df03f06 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/config/SuperDataApiAutoConfiguration.java @@ -0,0 +1,29 @@ +package com.xforwardai.superdata.config; + +import com.xforwardai.superdata.handler.MappingHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import javax.annotation.PostConstruct; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.config.SuperDataApiAutoConfiguration.java + * @date: 2022/2/22 16:03 + * @author xujian + */ +@Configuration +public class SuperDataApiAutoConfiguration { + + @Autowired + private MappingHandler mappingHandler; + + @PostConstruct + public void initConfiguration() { + try { + mappingHandler.handlerAllApiMapping(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/xforwardai/superdata/config/SwaggerConfig.java b/src/main/java/com/xforwardai/superdata/config/SwaggerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..0c072ab9d7e733761f14a99041d01b3311f9c9bd --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/config/SwaggerConfig.java @@ -0,0 +1,99 @@ +package com.xforwardai.superdata.config; + +import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.service.ApiKey; +import springfox.documentation.service.AuthorizationScope; +import springfox.documentation.service.SecurityReference; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + +/** + * swagger 配置类 + */ +@EnableSwagger2 +@Configuration +@EnableSwaggerBootstrapUI +public class SwaggerConfig { + + @Value("${swagger.controller}") + private String controller; + @Value("${swagger.title}") + private String title; + @Value("${swagger.service-url}") + private String serviceUrl; + @Value("${info.description}") + private String des; + @Value("${info.version}") + private String ver; + + + @Bean + public Docket getDocket(){ + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .select() + .apis(RequestHandlerSelectors.basePackage(controller)) + .paths(PathSelectors.any()) + .build() + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()); + } + + private ApiInfo apiInfo(){ + return new ApiInfoBuilder() + .title(title) + .description(des) + .version(ver) + .termsOfServiceUrl(serviceUrl) + .build(); + } + + + /** + * 设置要验证的信息 + * + * @return + */ + private List securitySchemes() { + return newArrayList( + new ApiKey("Authorization", "Authorization", "header") + ); + } + + /** + * @return + */ + private List securityContexts() { + return newArrayList( + SecurityContext + .builder() + .securityReferences(defaultAuth()) + .forPaths(PathSelectors.regex("^(?!auth).*$")) + .build()); + } + + /** + * 配置验证范围 + * + * @return + */ + List defaultAuth() { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + return newArrayList(new SecurityReference("Authorization", authorizationScopes)); + } +} \ No newline at end of file diff --git a/src/main/java/com/xforwardai/superdata/constants/ActionConstants.java b/src/main/java/com/xforwardai/superdata/constants/ActionConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..0156849c420b48342b9bbc50d25b20e45aa75a5a --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/constants/ActionConstants.java @@ -0,0 +1,19 @@ +package com.xforwardai.superdata.constants; + +public class ActionConstants { + + public static final String MYSQL_URL_PREFIX = "jdbc:mysql://"; + + public static final String ORACLE_DRIVER = "oracle.jdbc.driver.OracleDriver"; + + public static final String ORACLE_URL_PREFIX = "jdbc:oracle:thin:@//"; + + public static final String HIVE_DRIVER = "org.apache.hive.jdbc.HiveDriver"; + + public static final String HIVE_URL_PREFIX = "jdbc:hive2://"; + + public static final String ORACLE_TYPE = "oracle"; + + public static final String HIVE_TYPE = "hive"; + +} diff --git a/src/main/java/com/xforwardai/superdata/constants/CommonConstant.java b/src/main/java/com/xforwardai/superdata/constants/CommonConstant.java new file mode 100644 index 0000000000000000000000000000000000000000..8d88f340a912a81a3c8d899a4446329e0a5aaddc --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/constants/CommonConstant.java @@ -0,0 +1,156 @@ +package com.xforwardai.superdata.constants; + +/** + * @author xujian + * @ClassName: CommonConstant + * @Description: (常量类) + * @date 2017年11月3日 + */ +public final class CommonConstant { + + /** + * 500:系统出错 + */ + public final static int CONSTANT_SERVER_ERROR = 500; + /** + * 403:没有权限 + */ + public final static int CONSTANT_NO_AUTHORITY = 403; + /** + * 400 请求参数有误 + */ + public final static int CONSTANT_ERROR_PARAMETER = 400; + /** + * 1002 参数非法 + */ + public final static int CONSTANT_ILLEGAL_PARAMETER = 1001; + /** + * 401:尚未登陆 + */ + public final static int CONSTANT_NO_PROMISSION = 401; + /** + * 200:正常返回 + */ + public final static int CONSTANT_REQUEST_SUCCESS = 200; + + /** + * 成功状态码 + */ + public final static Integer CONSTANT_CODE_SUCCESS = 0; + /** + * 新增标签 + */ + public final static Integer CONSTANT_TAG_ADD = 1; + /** + * 删除标签 + */ + public final static Integer CONSTANT_TAG_DEL = -1; + /** + * 标签串删除标注 + */ + public final static Integer CONSTANT_TAGSPLICE_DEL = 0; + + public final static String CONSTANT_STRING_SUCCESS = "200"; + + public final static String CONSTANT_VIAS_SUCCESS = "1000"; + + public final static String CONSTANT_CODE_STYLE = "UTF-8"; + + public final static String CONSTANT_REQUEST_OK = "OK"; + + /** + * date类型和string之间的转换格式 + */ + public final static String CONSTANT_DATE_FORMAT = "yyyy-MM-dd"; + /** + * date类型和string之间的转换格式 + */ + public final static String CONSTANT_DATE_NUM_FORMAT = "yyyyMMdd"; + /** + * date类型和string之间的转换格式 + */ + public final static String CONSTANT_DATE_FORMAT_MONTH = "yyyy-MM"; + /** + * date类型和string之间的转换格式 + */ + public final static String CONSTANT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + /** + * date类型和string之间的转换格式 + */ + public final static String CONSTANT_DATENUM_FORMAT = "yyyyMMddHHmmss"; + /** + * 默认日期格式(数据库存储格式) + */ + public static final String DEFAULT_DATE_FORMAT_SHORT_PATTERN = "yyyyMMdd"; + + public static final Integer CONSTANT_VALID_STATUS = 1; + + public static final Integer CONSTANT_UNVALID_STATUS = 0; + + public static final String CONSTANT_INSERT_SUCCESS = "新增成功"; + + public static final String CONSTANT_UPDATE_SUCCESS = "更新成功"; + + public static final String CONSTANT_DELETE_SUCCESS = "删除成功"; + /** + * mysql + */ + public static final Integer DATASOURCE_MYSQL = 1; + /** + * es + */ + public static final Integer DATASOURCE_ES = 2; + /** + * 返回数据类型 0:单条数据 + */ + public static final Integer API_DATA_RESULT_SINGLE = 0; + /** + * 返回数据类型 1:数组 + */ + public static final Integer API_DATA_RESULT_ARR = 1; + /** + * 返回数据类型 2:分页 + */ + public static final Integer API_DATA_RESULT_PAGE = 2; + /** + * 参数类型 0:url传参 + */ + public static final Integer API_PARAM_URL = 0; + /** + * 参数类型 1:请求体传参 + */ + public static final Integer API_PARAM_BODY = 1; + /** + * 必要参数 + */ + public static final Integer PARAM_REQUIRED = 1; + /** + * 导出接口 + */ + public static final Integer EXPORT_API = 1; + /** + * 自定义sql + */ + public static final Integer API_CUSTOMIZESQL = 1; + /** + * 字段集合拼接符号 + */ + public static final String FIELD_VALUE_SPLICE_LIST = "&&"; + /** + * "null" 字符串 + */ + public static final String NULL_STRING = "null"; + /** + * 自定义sql中boday传参识别 + */ + public static final String BODY_PARAM_STR = "#1"; + + public final static String ES_DOC = "_doc"; + + public final static String STRING_STR = "string"; + + public final static String DATE_STR = "date"; + + + +} diff --git a/src/main/java/com/xforwardai/superdata/constants/ResultCode.java b/src/main/java/com/xforwardai/superdata/constants/ResultCode.java new file mode 100644 index 0000000000000000000000000000000000000000..59db1eadc63fe47525f372d310739e9d0e625832 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/constants/ResultCode.java @@ -0,0 +1,17 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package com.xforwardai.superdata.constants; + +public class ResultCode { + public static final Integer SUCCEED_CODE = 0; + public static final Integer FAIL_CODE = -1; + public static final Integer ERROR_CODE = 1; + public static final String SUCCEED_MESSAGE = "成功"; + public static final String ERROR_MESSAGE = "失败"; + + public ResultCode() { + } +} diff --git a/src/main/java/com/xforwardai/superdata/controller/ApiDatasourceController.java b/src/main/java/com/xforwardai/superdata/controller/ApiDatasourceController.java new file mode 100644 index 0000000000000000000000000000000000000000..0ab7533bd87fa9c7bd88c2dd89fd6e6c07bb2e3a --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/controller/ApiDatasourceController.java @@ -0,0 +1,85 @@ +package com.xforwardai.superdata.controller; + +import com.xforwardai.superdata.annotation.MysqlCheckInject; +import com.xforwardai.superdata.base.CommonResponse; +import com.xforwardai.superdata.base.CommonResult; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.ApiDatasource; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.TableFieldDto; +import com.xforwardai.superdata.mysql.service.ApiDatasourceSerivce; +import io.swagger.annotations.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.controller.ApiDatasourceController.java + * @date: 2022/3/2 18:05 + * @author xujian + */ +@ApiSort(value = 2) +@Api(tags = "数据源接口") +@RestController +@RequestMapping("/api/datasource/") +public class ApiDatasourceController { + + @Autowired + private ApiDatasourceSerivce apiDatasourceSerivce; + + @ApiOperation(position = 1, value = "数据源测试链接") + @PostMapping("/connect") + @ApiImplicitParam(name = "apiDatasourceDto", value = "数据源实体", dataType = "ApiDatasourceDto") + public CommonResult connet(@RequestBody @Validated ApiDatasourceDto apiDatasourceDto) throws ApplicationException { + return CommonResponse.success(apiDatasourceSerivce.testSourceConnect(apiDatasourceDto)); + } + + @ApiOperation(position = 2, value = "新增数据源接口") + @PostMapping("") + @ApiImplicitParam(name = "apiDatasourceDto", value = "数据源实体", dataType = "ApiDatasourceDto") + @MysqlCheckInject + public CommonResult addDatasource(@RequestBody ApiDatasourceDto apiDatasourceDto) { + apiDatasourceSerivce.addDatasource(apiDatasourceDto); + return CommonResponse.success(CommonConstant.CONSTANT_INSERT_SUCCESS); + } + + @ApiOperation(position = 3, value = "数据源列表接口") + @GetMapping("") + @ApiImplicitParam(name = "type", value = "数据类型", dataType = "int", paramType = "query") + public CommonResult addDatasource(Integer type) { + return CommonResponse.success(apiDatasourceSerivce.getDatasourceList(type)); + } + + @ApiOperation(position = 4, value = "获取数据源下的所有的表") + @GetMapping("/tables") + @ApiImplicitParams({ + @ApiImplicitParam(name = "datasourceCode", value = "数据源code", dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "dataBaseName", value = "数据库名称", dataType = "String", paramType = "query")} + ) + public CommonResult getTables(String datasourceCode, String dataBaseName) { + return CommonResponse.success(apiDatasourceSerivce.getTables(datasourceCode, dataBaseName)); + } + + @ApiOperation(position = 5, value = "获取表下所有的字段") + @GetMapping("/table/field") + @ApiImplicitParams({ + @ApiImplicitParam(name = "datasourceCode", value = "数据源code", dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "dataBaseName", value = "数据库名称", dataType = "String", paramType = "query"), + @ApiImplicitParam(name = "tableName", value = "表名", dataType = "String", paramType = "query") + }) + public CommonResult> getTableFields(String datasourceCode, String dataBaseName, String tableName) { + return CommonResponse.success(apiDatasourceSerivce.getTableFields(datasourceCode, dataBaseName, tableName)); + } + + @ApiOperation(position = 6, value = "获取数据源下的所有的数据库") + @GetMapping("/database") + @ApiImplicitParam(name = "datasourceCode", value = "数据源code", dataType = "String", paramType = "query") + public CommonResult getDatabases(String datasourceCode) { + return CommonResponse.success(apiDatasourceSerivce.getDatabases(datasourceCode)); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/controller/ApiEnumController.java b/src/main/java/com/xforwardai/superdata/controller/ApiEnumController.java new file mode 100644 index 0000000000000000000000000000000000000000..2d2e2aebe25dd06b52742d3aa9f4822fde9a52eb --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/controller/ApiEnumController.java @@ -0,0 +1,56 @@ +package com.xforwardai.superdata.controller; + +import com.xforwardai.superdata.base.CommonResponse; +import com.xforwardai.superdata.base.CommonResult; +import com.xforwardai.superdata.enums.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiSort; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.controller.ApiEnumController.java + * @date: 2022/3/10 10:58 + * @author xujian + */ +@ApiSort(value = 1) +@Api(tags = "api枚举接口") +@RestController +@RequestMapping("/api/enum/") +public class ApiEnumController { + + @ApiOperation(position = 1, value = "数据源类型") + @GetMapping("/datasource") + public CommonResult getDatasourceTypeList() { + return CommonResponse.success(DatasourceType.getList()); + } + + @ApiOperation(position = 2, value = "条件类型") + @GetMapping("/condition") + public CommonResult getConditionTypeList() { + return CommonResponse.success(ConditionType.getList()); + } + + @ApiOperation(position = 3, value = "关系类型") + @GetMapping("/relation") + public CommonResult getRelationTypeList() { + return CommonResponse.success(RelationType.getList()); + } + + @ApiOperation(position = 4, value = "返回数据类型") + @GetMapping("/result-type") + public CommonResult getResutTypeList() { + return CommonResponse.success(ResutType.getList()); + } + + @ApiOperation(position = 5, value = "接口类型") + @GetMapping("/operate-type") + public CommonResult getOperateTypeList() { + return CommonResponse.success(OperateType.getList()); + } + + +} diff --git a/src/main/java/com/xforwardai/superdata/controller/ApiInfoController.java b/src/main/java/com/xforwardai/superdata/controller/ApiInfoController.java new file mode 100644 index 0000000000000000000000000000000000000000..2a57ed21fcd46b60494287beebb663eb6d8db47d --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/controller/ApiInfoController.java @@ -0,0 +1,111 @@ +package com.xforwardai.superdata.controller; + +import com.xforwardai.superdata.annotation.MysqlCheckInject; +import com.xforwardai.superdata.base.BasePageResultVo; +import com.xforwardai.superdata.base.CommonResponse; +import com.xforwardai.superdata.base.CommonResult; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.mysql.entity.dto.AddApiParamDto; +import com.xforwardai.superdata.mysql.entity.dto.AddApiResultDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDto; +import com.xforwardai.superdata.mysql.service.ApiInfoService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiSort; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.controller.ApiInfoController.java + * @date: 2022/3/3 11:03 + * @author xujian + */ +@ApiSort(3) +@Api(tags = "api相关接口") +@RestController +@RequestMapping("/api/info/") +public class ApiInfoController { + + @Autowired + private ApiInfoService apiInfoService; + + @ApiOperation(position = 1, value = "新增接口") + @PostMapping("") + @ApiImplicitParam(name = "apiInfoDetailDto", value = "接口实体", dataType = "ApiInfoDetailDto") + @MysqlCheckInject + public CommonResult addApiInfo(@Valid @RequestBody ApiInfoDetailDto apiInfoDetailDto) { + apiInfoService.addApiInfo(apiInfoDetailDto); + return CommonResponse.success(CommonConstant.CONSTANT_INSERT_SUCCESS); + } + + @ApiOperation(position = 2, value = "更新接口") + @PutMapping("") + @ApiImplicitParam(name = "apiInfoDetailDto", value = "接口实体", dataType = "ApiInfoDetailDto") + @MysqlCheckInject(method = "update") + public CommonResult updateApiInfo(@RequestBody ApiInfoDetailDto apiInfoDetailDto) { + apiInfoService.updateApiInfo(apiInfoDetailDto); + return CommonResponse.success(CommonConstant.CONSTANT_UPDATE_SUCCESS); + } + + @ApiOperation(position = 3, value = "删除接口") + @DeleteMapping("") + public CommonResult delete(Integer id) { + apiInfoService.delete(id); + return CommonResponse.success(CommonConstant.CONSTANT_DELETE_SUCCESS); + } + + @ApiOperation(position = 4, value = "新增接口参数") + @PostMapping("/param") + @ApiImplicitParam(name = "addApiParamDto", value = "接口实体", dataType = "AddApiParamDto") + public CommonResult addApiParam(@Valid @RequestBody AddApiParamDto addApiParamDto) { + apiInfoService.addApiParam(addApiParamDto); + return CommonResponse.success(CommonConstant.CONSTANT_INSERT_SUCCESS); + } + + @ApiOperation(position = 5, value = "删除接口参数") + @DeleteMapping("/param") + @ApiImplicitParam(name = "addApiParamDto", value = "接口实体", dataType = "AddApiParamDto") + public CommonResult deleteApiParam(@Valid @RequestBody AddApiParamDto addApiParamDto) { + apiInfoService.deleteApiParam(addApiParamDto); + return CommonResponse.success(CommonConstant.CONSTANT_DELETE_SUCCESS); + } + + @ApiOperation(position = 6, value = "新增接口返回") + @PostMapping("/result") + @ApiImplicitParam(name = "addApiResultDto", value = "接口实体", dataType = "AddApiResultDto") + public CommonResult addApiResult(@Valid @RequestBody AddApiResultDto addApiResultDto) { + apiInfoService.addApiResult(addApiResultDto); + return CommonResponse.success(CommonConstant.CONSTANT_INSERT_SUCCESS); + } + + @ApiOperation(position = 7, value = "删除接口返回") + @DeleteMapping("/result") + @ApiImplicitParam(name = "addApiResultDto", value = "接口实体", dataType = "AddApiResultDto") + public CommonResult deleteApiResutl(@RequestBody AddApiResultDto addApiResultDto) { + apiInfoService.deleteApiResutl(addApiResultDto); + return CommonResponse.success(CommonConstant.CONSTANT_DELETE_SUCCESS); + } + + @ApiOperation(position = 8, value = "接口分页查询") + @PostMapping("/page") + @ApiImplicitParam(name = "apiInfoDto", value = "接口实体", dataType = "ApiInfoDto") + public CommonResult>> getApiInfoPage(@RequestBody ApiInfoDto apiInfoDto) { + return CommonResponse.success(apiInfoService.getApiInfoPage(apiInfoDto)); + } + + @ApiOperation(position = 9, value = "新增或者更新接口") + @PutMapping("save-or-update") + @ApiImplicitParam(name = "apiInfoDetailDto", value = "接口实体", dataType = "ApiInfoDetailDto") + @MysqlCheckInject(method = "update") + public CommonResult saveOrUpdateApiInfo(@RequestBody ApiInfoDetailDto apiInfoDetailDto) { + apiInfoService.saveOrUpdateApiInfo(apiInfoDetailDto); + return CommonResponse.success(CommonConstant.CONSTANT_UPDATE_SUCCESS); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/controller/RequestHandlerController.java b/src/main/java/com/xforwardai/superdata/controller/RequestHandlerController.java new file mode 100644 index 0000000000000000000000000000000000000000..183323eba5679ba658bd86b4d3aad9255d4ee65a --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/controller/RequestHandlerController.java @@ -0,0 +1,144 @@ +package com.xforwardai.superdata.controller; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.xforwardai.superdata.base.CommonResponse; +import com.xforwardai.superdata.cache.ApiInfoCacheMap; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.handler.ExportHandler; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiParamDto; +import com.xforwardai.superdata.service.impl.SqlServiceImpl; +import com.xforwardai.superdata.util.JsonUtil; +import com.xforwardai.superdata.util.RequestUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiSort; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.controller.RequestHandlerController.java + * @date: 2022/2/22 17:01 + * @author xujian + */ +@Api(tags = "扩展Api") +@ApiSort(4) +@Slf4j +@Controller +public class RequestHandlerController { + + private final static String PAGE = "page"; + + private final static String SIZE = "size"; + + @Autowired + private SqlServiceImpl sqlService; + + @Autowired + private ExportHandler exportHandler; + + @ResponseBody + public Object invoke(HttpServletRequest request, HttpServletResponse response) throws ApplicationException { + String method = request.getMethod(); + String requestURI = request.getRequestURI(); + log.info("{}请求,uri:{}", method, requestURI); + ApiInfoDetailDto apiInfoDetailDto = ApiInfoCacheMap.API_INFO_MAP.get(method + ":" + requestURI); + if (null == apiInfoDetailDto) { + throw new ApplicationException(ResultCode.FAIL_CODE, "未找到" + method + "请求的" + requestURI + "接口"); + } + + //如果是分页设置分页值 + if (CommonConstant.API_DATA_RESULT_PAGE == apiInfoDetailDto.getResultType()) { + String page = request.getParameter(PAGE); + String size = request.getParameter(SIZE); + if (StringUtils.isEmpty(page) || Integer.valueOf(page) <= 0) { + apiInfoDetailDto.setPage(1); + } else { + apiInfoDetailDto.setPage(Integer.valueOf(page)); + } + if (StringUtils.isEmpty(size) || Integer.valueOf(size) <= 0) { + apiInfoDetailDto.setSize(10); + } else { + apiInfoDetailDto.setSize(Integer.valueOf(size)); + } + } + Object bodyParam = RequestUtil.getBodyParam(request); + List params = apiInfoDetailDto.getParams(); + //以下逻辑会删除前端没有传参的元素,新增一个集合保存原请求参数 + List newParams = new ArrayList<>(); + if (!CollectionUtils.isEmpty(params)) { + Iterator iterator = params.iterator(); + while (iterator.hasNext()) { + ApiParamDto param = iterator.next(); + newParams.add(param); + Integer paramBodyType = param.getParamBodyType(); + //url参数赋值 + if (CommonConstant.API_PARAM_URL == paramBodyType) { + String parameterValue = request.getParameter(param.getParamName()); + if (StringUtils.isEmpty(parameterValue)) { + iterator.remove(); + } else { + param.setParamValue(parameterValue); + } + } + //请求体参数赋值 + if (CommonConstant.API_PARAM_BODY == paramBodyType) { + if(null == bodyParam){ + iterator.remove(); + } + if (bodyParam instanceof JSONObject) { + String parameterValue = JsonUtil.getString(param.getParamName(), (JSONObject) bodyParam); + if (StringUtils.isEmpty(parameterValue)) { + iterator.remove(); + } else { + param.setParamValue(parameterValue); + } + } + + if (bodyParam instanceof JSONArray) { + List values = new ArrayList<>(); + ((JSONArray) bodyParam).forEach(item -> { + String parameterValue = JsonUtil.getString(param.getParamName(), (JSONObject) item); + parameterValue = StringUtils.isEmpty(parameterValue) ? CommonConstant.NULL_STRING : parameterValue; + values.add(parameterValue); + }); + + if (CollectionUtils.isEmpty(values)) { + iterator.remove(); + } else { + param.setParamValue(StringUtils.join(values, CommonConstant.FIELD_VALUE_SPLICE_LIST)); + } + } + } + } + + } + + Object execute = sqlService.execute(apiInfoDetailDto); + + apiInfoDetailDto.setParams(newParams); + + if (CommonConstant.EXPORT_API == apiInfoDetailDto.getIsExport()) { + exportHandler.export(response, apiInfoDetailDto, execute); + return null; + } + + return CommonResponse.success(execute); + } + + +} diff --git a/src/main/java/com/xforwardai/superdata/dds/DataSourceHelp.java b/src/main/java/com/xforwardai/superdata/dds/DataSourceHelp.java new file mode 100644 index 0000000000000000000000000000000000000000..f1cbd51a335c6f9afc9cdd74d2374a7f71ca44a8 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/DataSourceHelp.java @@ -0,0 +1,85 @@ +package com.xforwardai.superdata.dds; + +import com.xforwardai.superdata.dds.datasource.DBIdentifier; +import com.xforwardai.superdata.dds.datasource.DynamicDataSource; +import com.xforwardai.superdata.dds.datasource.ProjectDBMgr; +import com.xforwardai.superdata.dds.domain.DBVo; +import com.xforwardai.superdata.dds.esclient.ElasticsearchRestClientHolder; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.client.RestHighLevelClient; +import org.springframework.stereotype.Component; + +import java.sql.Connection; +import java.sql.Statement; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.dds.datasource.DataSourceHelp.java + * @date: 2022/3/2 18:25 + * @author xujian + */ +@Component +@Slf4j +public class DataSourceHelp { + + private volatile DynamicDataSource dynamicDataSource = null; + + public DynamicDataSource getDynamicDataSource() { + if (null == dynamicDataSource) { + synchronized (DynamicDataSource.class) { + if (null == dynamicDataSource) { + dynamicDataSource = new DynamicDataSource(); + } + } + } + return dynamicDataSource; + } + + public Connection getConnect(ApiDatasourceDto datasourceDto) { + String ip = datasourceDto.getIp(); + String port = datasourceDto.getPort(); + String dataSoureTypeName = DatasourceType.getNameByType(datasourceDto.getType()); + String projectCode = ip + "," + port + dataSoureTypeName + datasourceDto.getUsername() + datasourceDto.getPassword(); + //如果数据源信息map里面没有该数据源的信息需要加入数据源信息map中 + if (null == ProjectDBMgr.instance().getDBInfo(projectCode)) { + DBVo dbVo = new DBVo(); + dbVo.setIp(datasourceDto.getIp()); + dbVo.setPort(datasourceDto.getPort()); + dbVo.setUsername(datasourceDto.getUsername()); + dbVo.setPassword(datasourceDto.getPassword()); + ProjectDBMgr.instance().addDBInfo(projectCode, dbVo); + } + //以数据库ip为标识放入ThreadLocal中 + DBIdentifier.setProjectCode(projectCode); + return getDynamicDataSource().getConnection(); + } + + public RestHighLevelClient getRestHighLevelClient(ApiDatasourceDto datasourceDto) { + return getRestHighLevelClient(datasourceDto, Boolean.TRUE); + } + + public RestHighLevelClient getRestHighLevelClient(ApiDatasourceDto datasourceDto, Boolean isCache) { + DBVo dbVo = new DBVo(); + dbVo.setIp(datasourceDto.getIp()); + dbVo.setPort(datasourceDto.getPort()); + dbVo.setUsername(datasourceDto.getUsername()); + dbVo.setPassword(datasourceDto.getPassword()); + return ElasticsearchRestClientHolder.getInstance().getRestHighLevelClient(dbVo, isCache); + } + + public void close(Statement statement, Connection connection) { + try { + if (null != statement) { + statement.close(); + } + if (null != connection) { + connection.close(); + } + } catch (Exception e) { + log.error("关闭流异常 errMsg:{}", e.getMessage()); + } + } + +} diff --git a/src/main/java/com/xforwardai/superdata/dds/datasource/DBIdentifier.java b/src/main/java/com/xforwardai/superdata/dds/datasource/DBIdentifier.java new file mode 100644 index 0000000000000000000000000000000000000000..be1936dc154ad346539cd8e3f868eee6aff36dae --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/datasource/DBIdentifier.java @@ -0,0 +1,21 @@ +package com.xforwardai.superdata.dds.datasource; + +/** + * 数据库标识 + */ +public class DBIdentifier { + + private static ThreadLocal projectCode = new ThreadLocal<>(); + + public static String getProjectCode(){ + return projectCode.get(); + } + + public static void setProjectCode(String code){ + projectCode.set(code); + } + + public static void remove(){ + projectCode.remove(); + } +} diff --git a/src/main/java/com/xforwardai/superdata/dds/datasource/DDSHolder.java b/src/main/java/com/xforwardai/superdata/dds/datasource/DDSHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..f821a9f0218783f4775a0b627344b1627e3d2ed0 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/datasource/DDSHolder.java @@ -0,0 +1,81 @@ +package com.xforwardai.superdata.dds.datasource; + +import com.google.common.collect.Maps; +import com.zaxxer.hikari.HikariDataSource; +import lombok.extern.slf4j.Slf4j; + +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +/** + * 动态数据源操作类 + */ +@Slf4j +public class DDSHolder { + + /** + * 连接对象Map + */ + private Map ddsMap = Maps.newHashMap(); + + private DDSHolder() { + + } + + /** + * 单例构造器 + */ + private static class DDSHolderBuilder { + private static DDSHolder instance = new DDSHolder(); + } + + /** + * 创建单例对象 + * + * @return + */ + public static DDSHolder instance() { + return DDSHolderBuilder.instance; + } + + /** + * 添加数据源 + * @param projectCode + * @param dds + */ + public synchronized void addDDS(String projectCode, HikariDataSource dds) { + DDSTimer ddst = new DDSTimer(dds); + ddsMap.put(projectCode, ddst); + } + + /** + * 获取数据源 + * @param projectCode + * @return + */ + public synchronized HikariDataSource getDDS(String projectCode){ + DDSTimer result = Optional.ofNullable(ddsMap.get(projectCode)).orElse(null); + if(Objects.nonNull(result)){ + result.refreshTime(); + return result.getDataSource(); + } + return null; + } + + /** + * 检查并释放过期的数据库连接 + */ + public synchronized void checkIdelDataSource(){ + if(ddsMap.size() != 0){ + Iterator> it = ddsMap.entrySet().iterator(); + while(it.hasNext()){ + Map.Entry entry = it.next(); + if(entry.getValue().checkAndClose()){ + it.remove(); + } + } + } + } +} diff --git a/src/main/java/com/xforwardai/superdata/dds/datasource/DDSTimer.java b/src/main/java/com/xforwardai/superdata/dds/datasource/DDSTimer.java new file mode 100644 index 0000000000000000000000000000000000000000..fe01814da54825c43bb9d217fca6fe74c0f5c5bb --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/datasource/DDSTimer.java @@ -0,0 +1,58 @@ +package com.xforwardai.superdata.dds.datasource; + +import com.zaxxer.hikari.HikariDataSource; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * 数据源连接超时操作类 + */ +@Slf4j +@Data +public class DDSTimer { + /** + * 默认超时时间 + */ + private static long idel = 5 * 60 * 1000; + + private HikariDataSource dataSource; + private long lastUpdateTime = 0L; + + /** + * 构造函数 + * @param newDataSource + */ + public DDSTimer(HikariDataSource newDataSource) { + this.dataSource = newDataSource; + this.lastUpdateTime = System.currentTimeMillis(); + } + + /** + * 刷新更新时间 + */ + public void refreshTime() { + lastUpdateTime = System.currentTimeMillis(); + } + + /** + * 检查超时连接并关闭 + * @return + */ + public boolean checkAndClose() { + if (isTimeout()) { + dataSource.close(); + return true; + } + //清除ThreadLocal + DBIdentifier.remove(); + return false; + } + + /** + * 判断是否超时 + * @return + */ + private boolean isTimeout() { + return (System.currentTimeMillis() - lastUpdateTime) > idel; + } +} diff --git a/src/main/java/com/xforwardai/superdata/dds/datasource/DynamicDataSource.java b/src/main/java/com/xforwardai/superdata/dds/datasource/DynamicDataSource.java new file mode 100644 index 0000000000000000000000000000000000000000..f38a6b53f625f672d05f119c5570cc45f8857c1f --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/datasource/DynamicDataSource.java @@ -0,0 +1,89 @@ +package com.xforwardai.superdata.dds.datasource; + +import com.xforwardai.superdata.constants.ActionConstants; +import com.xforwardai.superdata.dds.domain.DBVo; +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringUtils; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Objects; + +/** + * 创建动态数据源 + */ +@Slf4j +public class DynamicDataSource extends HikariDataSource { + /** + * 创建数据库连接 + * + * @return + */ + @Override + public Connection getConnection() { + Connection result = null; + // 获取数据库标识 + String projectCode = DBIdentifier.getProjectCode(); + // 按照数据库标识获取数据源信息 + HikariDataSource dds = DDSHolder.instance().getDDS(projectCode); + if (dds == null) { + try { + dds = initDDS(projectCode); + DDSHolder.instance().addDDS(projectCode, dds); + } catch (IllegalArgumentException | IllegalAccessException e) { + log.error("Init data source fail. projectCode:" + projectCode); + } + } + try { + result = dds.getConnection(); + } catch (SQLException e) { + log.error("create connection fail. ex: {}", e.getMessage()); + } finally { + DDSHolder.instance().checkIdelDataSource(); + } + return result; + } + + /** + * 初始化数据源 + * + * @param projectCode + * @return + */ + private HikariDataSource initDDS(String projectCode) throws IllegalAccessException { + HikariConfig hikariConfig = new HikariConfig(); + DBVo dbVo = ProjectDBMgr.instance().getDBInfo(projectCode); + if (Objects.isNull(dbVo)) { + return null; + } + // 设置数据库连接信息 + String urlFormat = ActionConstants.MYSQL_URL_PREFIX; + //拼接url + String url = String.format(urlFormat + "%s%s%s?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=true", + dbVo.getIp() + ":", dbVo.getPort() + "/", StringUtils.isEmpty(dbVo.getDbname()) ? "" : dbVo.getDbname()); + if (ActionConstants.HIVE_TYPE.equals(dbVo.getDbType())) { + urlFormat = ActionConstants.HIVE_URL_PREFIX; + url = String.format(urlFormat + "%s%s", dbVo.getIp() + ":", dbVo.getPort()); + hikariConfig.setDriverClassName(ActionConstants.HIVE_DRIVER); + hikariConfig.setConnectionTestQuery("SELECT 1"); + } + if (ActionConstants.ORACLE_TYPE.equals(dbVo.getDbType())) { + urlFormat = ActionConstants.ORACLE_URL_PREFIX; + url = String.format(urlFormat + "%s%s" + "/orcl", dbVo.getIp() + ":", dbVo.getPort()); + hikariConfig.setDriverClassName(ActionConstants.ORACLE_DRIVER); + } + hikariConfig.setJdbcUrl(url); + hikariConfig.setUsername(dbVo.getUsername()); + hikariConfig.setPassword(dbVo.getPassword()); + hikariConfig.setMinimumIdle(5); + hikariConfig.setMaximumPoolSize(20); + hikariConfig.setIdleTimeout(10000); + // 30秒超时 + hikariConfig.setConnectionTimeout(30000); + HikariDataSource dds = new HikariDataSource(hikariConfig); + return dds; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/dds/datasource/ProjectDBMgr.java b/src/main/java/com/xforwardai/superdata/dds/datasource/ProjectDBMgr.java new file mode 100644 index 0000000000000000000000000000000000000000..eeddecf56ca70c16ca6d285f92765b0f987ee255 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/datasource/ProjectDBMgr.java @@ -0,0 +1,51 @@ +package com.xforwardai.superdata.dds.datasource; + +import com.google.common.collect.Maps; +import com.xforwardai.superdata.dds.domain.DBVo; + +import java.util.Map; +import java.util.Optional; + +/** + * 动态数据源操作类 + */ +public class ProjectDBMgr { + /** + * 存储code和对应的数据库信息对象 + */ + private Map dbNameMap = Maps.newHashMap(); + + /** + * 构建类 + */ + private static class ProjectDBMgrBuilder{ + private static ProjectDBMgr instance = new ProjectDBMgr(); + } + + private ProjectDBMgr(){ + + } + + public static ProjectDBMgr instance(){ + return ProjectDBMgrBuilder.instance; + } + + /** + * 按照code获取对应的数据库连接信息 + * @param projectCode + * @return + */ + public DBVo getDBInfo(String projectCode){ + DBVo result = Optional.ofNullable(dbNameMap.get(projectCode)).orElse(null); + return result; + } + + /** + * 添加数据库信息 + * @param projectCode + * @param dbVo + */ + public void addDBInfo(String projectCode,DBVo dbVo){ + dbNameMap.put(projectCode,dbVo); + } +} diff --git a/src/main/java/com/xforwardai/superdata/dds/domain/DBVo.java b/src/main/java/com/xforwardai/superdata/dds/domain/DBVo.java new file mode 100644 index 0000000000000000000000000000000000000000..b4c6c9c8a261a1ad4ebd1fcd39cdc2b7c7ce42a9 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/domain/DBVo.java @@ -0,0 +1,24 @@ +package com.xforwardai.superdata.dds.domain; + +import lombok.Data; + +@Data +public class DBVo { + + private String ip; + + private String port; + + private String dbname; + + private String username; + + private String password; + + private String dbType; + + public String getUrl(){ + return ip + ":" + port; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/dds/esclient/ElasticsearchRestClient.java b/src/main/java/com/xforwardai/superdata/dds/esclient/ElasticsearchRestClient.java new file mode 100644 index 0000000000000000000000000000000000000000..a9bd53cd8b572b6cd176343df395eb1ac4950d8a --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/esclient/ElasticsearchRestClient.java @@ -0,0 +1,49 @@ + package com.xforwardai.superdata.dds.esclient; + + + import com.xforwardai.superdata.dds.domain.DBVo; + import lombok.Data; + import org.apache.http.HttpHost; + import org.apache.http.auth.AuthScope; + import org.apache.http.auth.UsernamePasswordCredentials; + import org.apache.http.client.CredentialsProvider; + import org.apache.http.impl.client.BasicCredentialsProvider; + import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; + import org.apache.logging.log4j.util.Strings; + import org.elasticsearch.client.RestClient; + import org.elasticsearch.client.RestClientBuilder; + import org.elasticsearch.client.RestHighLevelClient; + + @Data + class ElasticsearchRestClient { + + private RestClientBuilder restClientBuilder; + + private RestHighLevelClient restHighLevelClient; + + public void restClientBuilder(DBVo dbDto) { + if(null == restClientBuilder){ + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + //es账号密码(默认用户名为elastic) + credentialsProvider.setCredentials(AuthScope.ANY, + new UsernamePasswordCredentials(dbDto.getUsername(), dbDto.getPassword())); + HttpHost httpHost = new HttpHost(dbDto.getIp(), Integer.valueOf(dbDto.getPort()), HttpHost.DEFAULT_SCHEME_NAME); + RestClientBuilder restClientBuilder = RestClient.builder(httpHost); + if(Strings.isNotBlank(dbDto.getUsername())){ + // 如果需要验证则需要获取用户名和密码 + restClientBuilder = restClientBuilder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { + @Override + public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) { + httpAsyncClientBuilder.disableAuthCaching(); + return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + } + }); + } + this.restClientBuilder = restClientBuilder; + this.restHighLevelClient = new RestHighLevelClient(restClientBuilder); + } + } + + + } + diff --git a/src/main/java/com/xforwardai/superdata/dds/esclient/ElasticsearchRestClientHolder.java b/src/main/java/com/xforwardai/superdata/dds/esclient/ElasticsearchRestClientHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..8e00fde6b39e116918f88dbbd765faa82ee2caff --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/esclient/ElasticsearchRestClientHolder.java @@ -0,0 +1,135 @@ +package com.xforwardai.superdata.dds.esclient; + +import com.google.common.collect.Maps; +import com.xforwardai.superdata.dds.domain.DBVo; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.client.RestClientBuilder; +import org.elasticsearch.client.RestHighLevelClient; +import org.springframework.util.StringUtils; + +import java.util.Iterator; +import java.util.Map; + +/** + * @Author xujian + * @Description 动态es连接,里面可以放不同host的es连接 + * @Date 9:23 2020/8/27 + **/ +@Slf4j +public class ElasticsearchRestClientHolder { + + private static volatile ElasticsearchRestClientHolder poll = null; + + private static Map ES_CLIENT = Maps.newHashMap(); + + /** + * @Author xujian + * @Description 双重校验锁的单例模式 + * @Date 9:24 2020/8/27 + * @return com.xforwardai.businesscenter.common.esclient.ElasticsearchRestClientPool + **/ + public static ElasticsearchRestClientHolder getInstance() { + if (null == poll) { + synchronized (ElasticsearchRestClientHolder.class) { + if (null == poll) { + poll = new ElasticsearchRestClientHolder(); + } + } + } + return poll; + } + + /** + * @Author xujian + * @Description 根据每个host+port获取每个es的连接 + * @Date 9:25 2020/8/27 + * @Param [dbDto] + * @return com.xforwardai.businesscenter.common.esclient.RestClientTimer + **/ + public RestClientTimer getRestClientTimer(DBVo dbDto, Boolean isCache) { + try { + if (StringUtils.isEmpty(dbDto.getIp()) || StringUtils.isEmpty(dbDto.getPort())) { + return null; + } + RestClientTimer restClient = ES_CLIENT.get(dbDto.getUrl()); + if (null == restClient || !isCache) { + ElasticsearchRestClient client = new ElasticsearchRestClient(); + client.restClientBuilder(dbDto); + RestClientTimer clientTimer = new RestClientTimer(client); + ES_CLIENT.put(dbDto.getUrl(), clientTimer); + return clientTimer; + } + restClient.refreshTime(); + return restClient; + } catch (Exception e) { + log.error("=========== 获取RestClienBuilder异常 errMsg:{} ==========", e.getMessage()); + } finally { + checkDelRestClient(); + } + return null; + } + + /** + * @Author xujian + * @Description 获取ElasticsearchRestClient + * @Date 9:26 2020/8/27 + * @Param [dbDto] + * @return com.xforwardai.businesscenter.common.esclient.ElasticsearchRestClient + **/ + public ElasticsearchRestClient getElasticsearchRestClient(DBVo dbDto, Boolean isCache) { + RestClientTimer restClientTimer = getRestClientTimer(dbDto, isCache); + if (null != restClientTimer) { + return restClientTimer.getRestClient(); + } + return null; + } + + /** + * @Author xujian + * @Description 获取RestClientBuilder + * @Date 9:26 2020/8/27 + * @Param [dbDto] + * @return org.elasticsearch.client.RestClientBuilder + **/ + public RestClientBuilder getRestClientBuilder(DBVo dbDto, Boolean isCache) { + ElasticsearchRestClient restClient = getElasticsearchRestClient(dbDto, isCache); + if (null != restClient) { + return restClient.getRestClientBuilder(); + } + return null; + } + + /** + * @Author xujian + * @Description 获取RestHighLevelClient + * @Date 9:26 2020/8/27 + * @Param [dbDto] + * @return org.elasticsearch.client.RestHighLevelClient + **/ + public RestHighLevelClient getRestHighLevelClient(DBVo dbDto, Boolean isCache) { + ElasticsearchRestClient restClient = getElasticsearchRestClient(dbDto, isCache); + if (null != restClient) { + return restClient.getRestHighLevelClient(); + } + return null; + } + + /** + * @Author xujian + * @Description 释放过期的连接 + * @Date 9:27 2020/8/27 + * @Param [] + * @return void + **/ + private synchronized void checkDelRestClient() { + if (ES_CLIENT.size() != 0) { + Iterator> it = ES_CLIENT.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + if (entry.getValue().checkAndClose()) { + it.remove(); + } + } + } + } +} diff --git a/src/main/java/com/xforwardai/superdata/dds/esclient/RestClientTimer.java b/src/main/java/com/xforwardai/superdata/dds/esclient/RestClientTimer.java new file mode 100644 index 0000000000000000000000000000000000000000..db59695a2063986dd3df632371a5268381f5d201 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/dds/esclient/RestClientTimer.java @@ -0,0 +1,65 @@ +package com.xforwardai.superdata.dds.esclient; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Data +@Slf4j +public class RestClientTimer { + + /** + * 默认超时时间 + */ + private static long idel = 5 * 60 * 1000; + + private ElasticsearchRestClient restClient; + + private long lastUpdateTime = 0L; + + /** + * 构造函数 + * + * @param restClient + */ + public RestClientTimer(ElasticsearchRestClient restClient) { + this.restClient = restClient; + this.lastUpdateTime = System.currentTimeMillis(); + } + + /** + * 刷新更新时间 + */ + public void refreshTime() { + lastUpdateTime = System.currentTimeMillis(); + } + + /** + * 检查超时连接并关闭 + * + * @return + */ + public boolean checkAndClose() { + try{ + if (isTimeout()) { + if(null != restClient.getRestHighLevelClient()){ + restClient.getRestHighLevelClient().close(); + restClient.setRestClientBuilder(null); + restClient = null; + } + return true; + } + }catch (Exception e){ + log.error("========== 关闭RestHighLevelClient异常 errMsg:{} =========",e.getMessage()); + } + return false; + } + + /** + * 判断是否超时 + * + * @return + */ + private boolean isTimeout() { + return (System.currentTimeMillis() - lastUpdateTime) > idel; + } +} diff --git a/src/main/java/com/xforwardai/superdata/enums/ConditionType.java b/src/main/java/com/xforwardai/superdata/enums/ConditionType.java new file mode 100644 index 0000000000000000000000000000000000000000..26953857f022642f65687c0d9fb4fcafc43ff180 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/ConditionType.java @@ -0,0 +1,85 @@ +package com.xforwardai.superdata.enums; + +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.enums.Method.java + * @date: 2022/2/23 17:08 + * @author xujian + */ +public enum ConditionType { + + EQ(1, " = "), + LE(2, " < "), + LEQ(3, " <= "), + GE(4, " > "), + GEQ(5," >= "), + LIKE(6," like "); + + private Integer type; + + private String name; + + ConditionType(Integer type, String name) { + this.type = type; + this.name = name; + } + + public static Integer getTypeByName(String name) { + ConditionType[] values = ConditionType.values(); + for (ConditionType item : values) { + if (item.name.equals(name)) { + return item.type; + } + } + return null; + } + + public static String getNameByType(Integer type) { + ConditionType[] values = ConditionType.values(); + for (ConditionType item : values) { + if (item.type.equals(type)) { + return item.name; + } + } + return null; + } + + private static List> LIST_RESULT = new ArrayList<>(); + + public static List> getList() { + if (CollectionUtils.isEmpty(LIST_RESULT)) { + ConditionType[] values = ConditionType.values(); + for (ConditionType value : values) { + Map map = new HashMap<>(); + map.put("type", value.type); + map.put("name", value.name); + LIST_RESULT.add(map); + } + } + return LIST_RESULT; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/enums/DatasourceType.java b/src/main/java/com/xforwardai/superdata/enums/DatasourceType.java new file mode 100644 index 0000000000000000000000000000000000000000..a804ee4ab6987e0dce418fa116987394f3b0c852 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/DatasourceType.java @@ -0,0 +1,87 @@ +package com.xforwardai.superdata.enums; + +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.enums.Method.java + * @date: 2022/2/23 17:08 + * @author xujian + */ +public enum DatasourceType { + + /*MYSQL(0, "MYSQL"), + HIVE(1, "HIVE"), + ES(3, "ES"), + KAFKA(4, "KAFKA"), + ORCALE(5, "ORCALE");*/ + + MYSQL(1, "MYSQL"), + ES(2, "ES"); + + private Integer type; + + private String name; + + DatasourceType(Integer type, String name) { + this.type = type; + this.name = name; + } + + public static Integer getTypeByName(String name) { + DatasourceType[] values = DatasourceType.values(); + for (DatasourceType item : values) { + if (item.name.equals(name)) { + return item.type; + } + } + return null; + } + + public static String getNameByType(Integer type) { + DatasourceType[] values = DatasourceType.values(); + for (DatasourceType item : values) { + if (item.type.equals(type)) { + return item.name; + } + } + return null; + } + + private static List> LIST_RESULT = new ArrayList<>(); + + public static List> getList() { + if (CollectionUtils.isEmpty(LIST_RESULT)) { + DatasourceType[] values = DatasourceType.values(); + for (DatasourceType value : values) { + Map map = new HashMap<>(); + map.put("type", value.type); + map.put("name", value.name); + LIST_RESULT.add(map); + } + } + return LIST_RESULT; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/enums/Method.java b/src/main/java/com/xforwardai/superdata/enums/Method.java new file mode 100644 index 0000000000000000000000000000000000000000..bd0a01195792180d1239f38b8cd8248e590856ba --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/Method.java @@ -0,0 +1,26 @@ +package com.xforwardai.superdata.enums; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.enums.Method.java + * @date: 2022/2/23 17:08 + * @author xujian + */ +public enum Method { + + GET("GET"), + PUT("PUT"), + DELETE("DELETE"), + POST("POST"); + + private String value; + + Method(String value){ + this.value = value; + } + + public String getValue(){ + return value; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/enums/OperateType.java b/src/main/java/com/xforwardai/superdata/enums/OperateType.java new file mode 100644 index 0000000000000000000000000000000000000000..8157ba9ba92a8508c215132dd48215b6d0c8cebf --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/OperateType.java @@ -0,0 +1,83 @@ +package com.xforwardai.superdata.enums; + +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.enums.OperateType.java + * @date: 2022/2/23 17:08 + * @author xujian + */ +public enum OperateType { + + QUERY(0, "QUERY"), + INSERT(1, "INSERT"), + UPDATE(2, "UPDATE"), + DELETE(3, "DELETE"); + + private Integer type; + + private String name; + + OperateType(Integer type, String name) { + this.type = type; + this.name = name; + } + + public static Integer getTypeByName(String name) { + OperateType[] values = OperateType.values(); + for (OperateType item : values) { + if (item.name.equals(name)) { + return item.type; + } + } + return null; + } + + public static String getNameByType(Integer type) { + OperateType[] values = OperateType.values(); + for (OperateType item : values) { + if (item.type.equals(type)) { + return item.name; + } + } + return null; + } + + private static List> LIST_RESULT = new ArrayList<>(); + + public static List> getList() { + if (CollectionUtils.isEmpty(LIST_RESULT)) { + OperateType[] values = OperateType.values(); + for (OperateType value : values) { + Map map = new HashMap<>(); + map.put("type", value.type); + map.put("name", value.name); + LIST_RESULT.add(map); + } + } + return LIST_RESULT; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/enums/RelationType.java b/src/main/java/com/xforwardai/superdata/enums/RelationType.java new file mode 100644 index 0000000000000000000000000000000000000000..5dacd6b4c7afee0549276f6045a607d91c430dc6 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/RelationType.java @@ -0,0 +1,82 @@ +package com.xforwardai.superdata.enums; + +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.enums.RelationType.java + * @date: 2022/2/23 17:08 + * @author xujian + */ +public enum RelationType { + + LEFT_JOIN(1, " LEFT JOIN "), + INNER_JOIN(2, " INNER JOIN "), + RIGHT_JOIN(3, " RIGHT JOIN "); + + private Integer type; + + private String name; + + RelationType(Integer type, String name) { + this.type = type; + this.name = name; + } + + public static Integer getTypeByName(String name) { + RelationType[] values = RelationType.values(); + for (RelationType item : values) { + if (item.name.equals(name)) { + return item.type; + } + } + return null; + } + + public static String getNameByType(Integer type) { + RelationType[] values = RelationType.values(); + for (RelationType item : values) { + if (item.type.equals(type)) { + return item.name; + } + } + return null; + } + + private static List> LIST_RESULT = new ArrayList<>(); + + public static List> getList() { + if (CollectionUtils.isEmpty(LIST_RESULT)) { + RelationType[] values = RelationType.values(); + for (RelationType value : values) { + Map map = new HashMap<>(); + map.put("type", value.type); + map.put("name", value.name); + LIST_RESULT.add(map); + } + } + return LIST_RESULT; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/enums/ResultEnum.java b/src/main/java/com/xforwardai/superdata/enums/ResultEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..6d59ff434aba3f524a1168c72b76e172b4b8524c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/ResultEnum.java @@ -0,0 +1,30 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by FernFlower decompiler) +// + +package com.xforwardai.superdata.enums; + +public enum ResultEnum { + SUCCEED(0, "ok"), + VALIDATED_ERROR(-1001, "参数校验失败"), + DOCKER_ERROR(-1002, "dockerAPI请求失败"), + FAIL(1, "fail"), + ERROR(-1, "error"); + + private int code; + private String message; + + private ResultEnum(int code, String message) { + this.code = code; + this.message = message; + } + + public int getCode() { + return this.code; + } + + public String getMessage() { + return this.message; + } +} diff --git a/src/main/java/com/xforwardai/superdata/enums/ResutType.java b/src/main/java/com/xforwardai/superdata/enums/ResutType.java new file mode 100644 index 0000000000000000000000000000000000000000..e65427213dd3ec19290e91113d8e189875b1f178 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/ResutType.java @@ -0,0 +1,83 @@ +package com.xforwardai.superdata.enums; + +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author xujian + * @Description: + * @ClassName: com.xforwardai.superdata.enums.ResutType.java + * @date: 2022/2/23 17:08 + */ +public enum ResutType { + + //返回数据类型 0:单条 1:数组 2:分页 + SINGLE(0, "单条"), + ARRAY(1, "数组"), + PAGE(2, "分页"); + + private Integer type; + + private String name; + + ResutType(Integer type, String name) { + this.type = type; + this.name = name; + } + + public static Integer getTypeByName(String name) { + ResutType[] values = ResutType.values(); + for (ResutType item : values) { + if (item.name.equals(name)) { + return item.type; + } + } + return null; + } + + public static String getNameByType(Integer type) { + ResutType[] values = ResutType.values(); + for (ResutType item : values) { + if (item.type.equals(type)) { + return item.name; + } + } + return null; + } + + private static List> LIST_RESULT = new ArrayList<>(); + + public static List> getList() { + if (CollectionUtils.isEmpty(LIST_RESULT)) { + ResutType[] values = ResutType.values(); + for (ResutType value : values) { + Map map = new HashMap<>(); + map.put("type", value.type); + map.put("name", value.name); + LIST_RESULT.add(map); + } + } + return LIST_RESULT; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/enums/SortType.java b/src/main/java/com/xforwardai/superdata/enums/SortType.java new file mode 100644 index 0000000000000000000000000000000000000000..2f9cde938a04489f304bdad353045dae02a2f008 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/enums/SortType.java @@ -0,0 +1,82 @@ +package com.xforwardai.superdata.enums; + +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.enums.SortType.java + * @date: 2022/2/23 17:08 + * @author xujian + */ +public enum SortType { + + NONE(0,"NO"), + DESC(1, "DESC"), + ASC(2, "ASC"); + + private Integer type; + + private String name; + + SortType(Integer type, String name) { + this.type = type; + this.name = name; + } + + public static Integer getTypeByName(String name) { + SortType[] values = SortType.values(); + for (SortType item : values) { + if (item.name.equals(name)) { + return item.type; + } + } + return null; + } + + public static String getNameByType(Integer type) { + SortType[] values = SortType.values(); + for (SortType item : values) { + if (item.type.equals(type)) { + return item.name; + } + } + return null; + } + + private static List> LIST_RESULT = new ArrayList<>(); + + public static List> getList() { + if (CollectionUtils.isEmpty(LIST_RESULT)) { + SortType[] values = SortType.values(); + for (SortType value : values) { + Map map = new HashMap<>(); + map.put("type", value.type); + map.put("name", value.name); + LIST_RESULT.add(map); + } + } + return LIST_RESULT; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/exceptionhandler/ApplicationException.java b/src/main/java/com/xforwardai/superdata/exceptionhandler/ApplicationException.java new file mode 100644 index 0000000000000000000000000000000000000000..f4d520537ca021335f8586b4057a46addcee50f2 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/exceptionhandler/ApplicationException.java @@ -0,0 +1,34 @@ +package com.xforwardai.superdata.exceptionhandler; + +import lombok.Data; + +/** + * @Author xujian + * @Description 自定义异常类 + * @Date 9:41 2020/8/27 + * @Param + * @return + **/ +@Data +public class ApplicationException extends RuntimeException { + + /** + * 异常编码 + */ + private int code; + + /** + * 异常消息 + */ + private String message; + + public ApplicationException() { + } + + public ApplicationException(int code, String message) { + super(); + this.code = code; + this.message = message; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/exceptionhandler/GlobalExceptionHandler.java b/src/main/java/com/xforwardai/superdata/exceptionhandler/GlobalExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..3284133bc6f7fc27d8c76139137bca5cb339db96 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/exceptionhandler/GlobalExceptionHandler.java @@ -0,0 +1,44 @@ +package com.xforwardai.superdata.exceptionhandler; + +import com.xforwardai.superdata.base.CommonResult; +import com.xforwardai.superdata.constants.ResultCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; + +/** + * 全局异常处理 + * 如果由于参数原因,没进处理的controller类,那么就会在这里进行处理 + */ +@ControllerAdvice +@ResponseBody +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(value = Exception.class) + public CommonResult customerErrorHandler(HttpServletRequest req, Exception e) { + log.error("全局异常处理 : {} 调用 {} 发生 {} 错误{}",req.getRemoteHost(),req.getMethod(),e.getMessage(),e); + //异常,写入日志 + return new CommonResult(ResultCode.FAIL_CODE, e.getMessage(), e.getClass().getName(), null); + } + + @ExceptionHandler(value = MethodArgumentNotValidException.class) + public CommonResult notNullFieldErrorHandler(HttpServletRequest req, MethodArgumentNotValidException ex) { + // 记录日志信息 + log.error("全局异常捕获: ip - {} req - {} error - {}", req.getRemoteHost(), req.getServletPath(), "请求字段有非空验证"); + BindingResult errors = ex.getBindingResult(); + String msg = ""; + if (errors.hasErrors()) { + //打印错误 + msg = errors.getFieldError().getDefaultMessage(); + } + // 返回通用数据结构 附加异常信息 + return new CommonResult(ResultCode.FAIL_CODE, String.format(msg), null, null); + } + +} \ No newline at end of file diff --git a/src/main/java/com/xforwardai/superdata/filter/BaseFilter.java b/src/main/java/com/xforwardai/superdata/filter/BaseFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..883b401033b15c986c6b0a113c2518a418e4a184 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/filter/BaseFilter.java @@ -0,0 +1,50 @@ +package com.xforwardai.superdata.filter; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Order(1) +@Component +@Slf4j +@WebFilter(filterName = "baseFilter", urlPatterns = "/*") +public class BaseFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + /** + * 处理跨域问题 + * @param servletRequest + * @param servletResponse + * @param filterChain + * @throws IOException + * @throws ServletException + */ + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest)servletRequest; + HttpServletResponse response = (HttpServletResponse)servletResponse; + String url=request.getRequestURL().toString(); + log.info("request url is [{}]",url); + //添加跨域CORS + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Headers", "*"); + response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH"); + filterChain.doFilter(servletRequest, servletResponse); + } + + @Override + public void destroy() { + + } + +} diff --git a/src/main/java/com/xforwardai/superdata/handler/EsHandler.java b/src/main/java/com/xforwardai/superdata/handler/EsHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..89892348223befc0be53d37d3dedbbc663baaea6 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/handler/EsHandler.java @@ -0,0 +1,23 @@ +package com.xforwardai.superdata.handler; + +import com.xforwardai.superdata.constants.CommonConstant; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.action.update.UpdateRequest; +import org.elasticsearch.common.xcontent.XContentType; +import org.springframework.stereotype.Component; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.handler.EsHandler.java + * @date: 2022/6/24 17:15 + * @author xujian + */ +@Component +@Slf4j +public class EsHandler { + + public UpdateRequest toUpdateIndexRequest(String jsonStr, String indexName, String id) { + return new UpdateRequest(indexName, CommonConstant.ES_DOC, id).doc(jsonStr, XContentType.JSON); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/handler/ExportHandler.java b/src/main/java/com/xforwardai/superdata/handler/ExportHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..5d49847b657fd6835cb78ea9139e396d2ed81c8c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/handler/ExportHandler.java @@ -0,0 +1,120 @@ +package com.xforwardai.superdata.handler; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.xforwardai.superdata.base.BasePageResultVo; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiResultDto; +import com.xforwardai.superdata.mysql.entity.dto.ExcelDataDto; +import com.xforwardai.superdata.util.DateUtils; +import com.xforwardai.superdata.util.ExcelUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.handler.ExportHandler.java + * @date: 2022/3/10 14:51 + * @author xujian + */ +@Component +@Slf4j +public class ExportHandler { + + public void export(HttpServletResponse response, ApiInfoDetailDto apiInfoDetailDto, Object data) { + List titles = apiInfoDetailDto.getResults().stream().filter(item -> + StringUtils.isNotBlank(item.getExportName()) + ).map(ApiResultDto::getExportName).collect(Collectors.toList()); + + List titleNames = apiInfoDetailDto.getResults().stream().filter(item -> + StringUtils.isNotBlank(item.getExportName()) + ).map(ApiResultDto::getResultName).collect(Collectors.toList()); + + if (CollectionUtils.isEmpty(titles)) { + throw new ApplicationException(ResultCode.FAIL_CODE, "导出列不能为空"); + } + + ExcelDataDto excelDataDto = new ExcelDataDto(); + List> rows = new ArrayList<>(); + if (data instanceof JSONObject) { + List row = handlerRow(data, titleNames); + rows.add(row); + } else if (data instanceof JSONArray) { + ((JSONArray) data).forEach(item -> { + List row = handlerRow(item, titleNames); + rows.add(row); + }); + } else if (data instanceof BasePageResultVo) { + Object content = ((BasePageResultVo) data).getContent(); + if (content instanceof List) { + ((List) content).forEach(item -> { + List row = handlerRow(item, titleNames); + rows.add(row); + }); + } + } + + excelDataDto.setRows(rows); + excelDataDto.setTitles(titles); + + XSSFWorkbook wb = ExcelUtil.generateWb(excelDataDto); + String dateTime = DateUtils.convertDateToString(new Date(), CommonConstant.CONSTANT_DATENUM_FORMAT); + String fileName = dateTime + "-file.xlsx"; + response.setContentType("application/vnd.ms-excel"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Content-disposition", "attachment;filename=" + fileName); + + OutputStream outputStream = null; + BufferedOutputStream bufferedOutputStream = null; + try { + outputStream = response.getOutputStream(); + bufferedOutputStream = new BufferedOutputStream(outputStream); + bufferedOutputStream.flush(); + wb.write(bufferedOutputStream); + } catch (Exception e) { + log.error("导出文件异常 errMsg:{}", e.getMessage()); + } finally { + try { + if (null != bufferedOutputStream) { + bufferedOutputStream.close(); + } + if (null != outputStream) { + outputStream.close(); + } + if (null != wb) { + wb.close(); + } + } catch (IOException e) { + log.error("导出文件关流异常 errMsg:{}", e.getMessage()); + } + } + } + + private List handlerRow(Object item, List titles) { + List row = new ArrayList<>(); + Set keys = ((JSONObject) item).keySet(); + titles.forEach(title -> { + keys.forEach(key -> { + if (title.equals(key)) { + row.add(((JSONObject) item).get(key)); + } + }); + }); + + return row; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/handler/MappingHandler.java b/src/main/java/com/xforwardai/superdata/handler/MappingHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..2fe291b91855c344431149a9caa776a46bb0eae9 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/handler/MappingHandler.java @@ -0,0 +1,112 @@ +package com.xforwardai.superdata.handler; + +import com.xforwardai.superdata.cache.ApiInfoCacheMap; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.controller.RequestHandlerController; +import com.xforwardai.superdata.enums.Method; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiParamDto; +import com.xforwardai.superdata.mysql.service.ApiInfoService; +import com.xforwardai.superdata.util.ApiUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.handler.MappingHandler.java + * @date: 2022/2/23 16:50 + * @author xujian + */ +@Component +@Slf4j +public class MappingHandler { + + @Autowired + private RequestHandlerController requestHandlerController; + + @Autowired + @Lazy + private RequestMappingHandlerMapping requestMappingHandlerMapping; + + @Autowired + private ApiInfoService apiInfoService; + + public void handlerAllApiMapping() { + List apiInfoList = apiInfoService.getApiInfoList(null); + if (!CollectionUtils.isEmpty(apiInfoList)) { + apiInfoList.forEach(apiInfo -> { + handlerApi(apiInfo); + }); + } + } + + private RequestMethod getRequestMethod(String method) { + if (Method.GET.getValue().equals(method)) { + return RequestMethod.GET; + } else if (Method.POST.getValue().equals(method)) { + return RequestMethod.POST; + } else if (Method.PUT.getValue().equals(method)) { + return RequestMethod.PUT; + } else if (Method.DELETE.getValue().equals(method)) { + return RequestMethod.DELETE; + } + return null; + } + + public void handlerApi(ApiInfoDetailDto apiInfoDetailDto) { + try { + apiInfoDetailDto.setDatasourceType(apiInfoDetailDto.getDatasourceDto().getType()); + List params = apiInfoDetailDto.getParams(); + //必传url的参数 + List paramNames = params.stream().filter(item -> + CommonConstant.PARAM_REQUIRED == item.getIsRequired() && CommonConstant.API_PARAM_BODY != item.getParamBodyType() + ).map(ApiParamDto::getParamName).collect(Collectors.toList()); + RequestMappingInfo.Builder paths = paths(apiInfoDetailDto.getUrl(), getRequestMethod(apiInfoDetailDto.getMethod()), + paramNames.toArray(new String[paramNames.size()])); + requestMappingHandlerMapping.registerMapping(paths.build(), requestHandlerController, RequestHandlerController.class.getDeclaredMethod("invoke", + HttpServletRequest.class, HttpServletResponse.class)); + log.info("{} {} 接口注册成功", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl()); + ApiInfoCacheMap.API_INFO_MAP.put(ApiUtil.getApiUrl(apiInfoDetailDto), apiInfoDetailDto); + } catch (Exception e) { + e.printStackTrace(); + log.info("{} {} 接口注册失败,errMsg:{}", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl(), e.getMessage()); + } + } + + public void handlerRemoveApi(ApiInfoDetailDto apiInfoDetailDto) { + try { + List params = apiInfoDetailDto.getParams(); + //必传url的参数 + List paramNames = params.stream().filter(item -> + CommonConstant.PARAM_REQUIRED == item.getIsRequired() && CommonConstant.API_PARAM_BODY != item.getParamBodyType() + ).map(ApiParamDto::getParamName).collect(Collectors.toList()); + RequestMappingInfo.Builder paths = paths(apiInfoDetailDto.getUrl(), getRequestMethod(apiInfoDetailDto.getMethod()), + paramNames.toArray(new String[paramNames.size()])); + requestMappingHandlerMapping.unregisterMapping(paths.build()); + log.info("{} {} 接口取消成功", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl()); + ApiInfoCacheMap.API_INFO_MAP.remove(ApiUtil.getApiUrl(apiInfoDetailDto)); + } catch (Exception e) { + e.printStackTrace(); + log.info("{} {} 接口取消成失败,errMsg:{}", apiInfoDetailDto.getMethod(), apiInfoDetailDto.getUrl(), e.getMessage()); + } + } + + private RequestMappingInfo.Builder paths(String name, RequestMethod method, String... params) { + RequestMappingInfo.Builder builder = RequestMappingInfo.paths(name); + builder.methods(method); + builder.params(params); + return builder; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/handler/SqlHandler.java b/src/main/java/com/xforwardai/superdata/handler/SqlHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..4e64e64d3729b8ea5e4d6397d8f19e9b83cbbf0d --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/handler/SqlHandler.java @@ -0,0 +1,249 @@ +package com.xforwardai.superdata.handler; + +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.enums.ConditionType; +import com.xforwardai.superdata.enums.RelationType; +import com.xforwardai.superdata.enums.SortType; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiParamDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiResultDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiTableRelationDto; +import com.xforwardai.superdata.util.CommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.handler.SqlHandler.java + * @date: 2022/2/23 17:31 + * @author xujian + */ +@Component +@Slf4j +public class SqlHandler { + + public String generateSql(ApiInfoDetailDto apiInfoDetailDto) { + StringBuffer from = generateFrom(apiInfoDetailDto); + StringBuffer query = generateQuerySql(apiInfoDetailDto.getResults()); + StringBuffer whereCondition = generateWhereCondition(apiInfoDetailDto.getParams()); + StringBuffer limitSql = limitSql(apiInfoDetailDto); + StringBuffer sql = query.append(from).append(whereCondition); + generateSortSql(apiInfoDetailDto, sql); + sql.append(limitSql); + log.info("generateSql : {}", sql); + return sql.toString(); + } + + public String generateCountSql(ApiInfoDetailDto apiInfoDetailDto) { + StringBuffer query = new StringBuffer(" select count(1) "); + StringBuffer from = generateFrom(apiInfoDetailDto); + StringBuffer whereCondition = generateWhereCondition(apiInfoDetailDto.getParams()); + StringBuffer sql = query.append(from).append(whereCondition); + log.info("generateCountSql : {}", sql); + return sql.toString(); + } + + public StringBuffer generateFrom(ApiInfoDetailDto apiInfoDetailDto) { + String fromTable = apiInfoDetailDto.getMainTableName(); + StringBuffer sb = new StringBuffer(" from "); + //自定义sql已输入别名 + if (CommonConstant.API_CUSTOMIZESQL.equals(apiInfoDetailDto.getIsCustomizeSql())) { + sb.append(fromTable).append(" "); + } else { + //配置接口别名默认表名 + sb.append(fromTable).append(" ").append(fromTable).append(" "); + } + List tableRelations = apiInfoDetailDto.getTableRelations(); + if (!CollectionUtils.isEmpty(tableRelations)) { + tableRelations.forEach(relation -> { + sb.append(RelationType.getNameByType(relation.getRelationType())).append(" "). + append(relation.getAssociationTableName()).append(" ").append(relation.getAssociationTableName()). + append(" on ").append(relation.getAssociationCondition()); + }); + } + + //自定义sql关联查询sql拼接 + if (CommonConstant.API_CUSTOMIZESQL.equals(apiInfoDetailDto.getIsCustomizeSql()) && null != apiInfoDetailDto.getApiCustomizeSqlDto() + && StringUtils.isNotBlank(apiInfoDetailDto.getApiCustomizeSqlDto().getAssociationSql())) { + sb.append(" ").append(apiInfoDetailDto.getApiCustomizeSqlDto().getAssociationSql()).append(" "); + } + + return sb; + } + + private void generateSortSql(ApiInfoDetailDto apiInfoDetailDto, StringBuffer sql) { + List collect = apiInfoDetailDto.getResults().stream(). + filter(item -> SortType.NONE.getType() != item.getSortType()). + collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(collect)) { + StringBuffer sort = new StringBuffer(" ORDER BY "); + for (int i = 0; i < collect.size(); i++) { + if (SortType.DESC.getType() == collect.get(i).getSortType()) { + sort.append(collect.get(i).getResultTableFieldName()).append(" ").append(SortType.DESC.getName()); + } else if (SortType.ASC.getType() == collect.get(i).getSortType()) { + sort.append(collect.get(i).getResultTableFieldName()).append(" ").append(SortType.ASC.getName()); + } + if (i != collect.size() - 1) { + sort.append(" , "); + } + } + sql.append(sort); + } + } + + private StringBuffer generateWhereCondition(List params) { + StringBuffer sb = new StringBuffer(" where 1=1 and "); + params.forEach(param -> { + String conditionTypeName = ConditionType.getNameByType(param.getConditionType()); + if (ConditionType.LIKE.getType().equals(param.getConditionType())) { + sb.append(param.getParamTableFieldName()).append(conditionTypeName).append("'%"). + append(param.getParamValue()).append("%'").append(" and "); + } else { + if (CommonUtil.hasCastString(param.getParamJavaType())) { + sb.append(param.getParamTableFieldName()).append(conditionTypeName). + append("'").append(param.getParamValue()).append("'").append(" and "); + } else { + sb.append(param.getParamTableFieldName()).append(conditionTypeName). + append(param.getParamValue()).append(" and "); + } + } + }); + + int lastAndIndex = sb.lastIndexOf("and"); + if (-1 != lastAndIndex) { + sb.delete(lastAndIndex, lastAndIndex + 3); + } + return sb; + } + + private StringBuffer generateQuerySql(List results) { + StringBuffer sb = new StringBuffer("select "); + results.forEach(result -> { + sb.append(result.getResultTableFieldName()).append(" "). + append(result.getResultName()).append(","); + }); + if (-1 != sb.lastIndexOf(",")) { + sb.deleteCharAt(sb.lastIndexOf(",")); + } + return sb; + } + + private StringBuffer limitSql(ApiInfoDetailDto apiInfoDetailDto) { + StringBuffer sb = new StringBuffer(); + Integer resultType = apiInfoDetailDto.getResultType(); + if (0 == resultType) { + sb.append(" limit 1 "); + } + //如果mysql数据库分页码可以直接limit + if (CommonConstant.API_DATA_RESULT_PAGE == resultType + && CommonConstant.DATASOURCE_MYSQL == apiInfoDetailDto.getDatasourceType()) { + int page = apiInfoDetailDto.getPage(); + int size = apiInfoDetailDto.getSize(); + sb.append(" limit ").append(size * (page - 1)).append(",").append(size); + } + return sb; + } + + public String generateInsertSql(ApiInfoDetailDto apiInfoDetailDto) { + StringBuffer sb = new StringBuffer(" insert into "); + String mainTableName = apiInfoDetailDto.getMainTableName(); + sb.append(mainTableName).append(" ("); + + StringBuffer fileds = new StringBuffer(); + + StringBuffer vaules = new StringBuffer(" values "); + List params = apiInfoDetailDto.getParams(); + + String[] fieldValue = params.get(0).getParamValue().toString().split(CommonConstant.FIELD_VALUE_SPLICE_LIST); + for (int i = 0; i < params.size(); i++) { + if (i != params.size() - 1) { + fileds.append(params.get(i).getParamTableFieldName().split("\\.")[1]).append(","); + } else { + fileds.append(params.get(i).getParamTableFieldName().split("\\.")[1]); + } + } + + for (int i = 0; i < fieldValue.length; i++) { + for (int j = 0; j < params.size(); j++) { + StringBuffer filedValues = new StringBuffer(); + String value = params.get(j).getParamValue().toString().split(CommonConstant.FIELD_VALUE_SPLICE_LIST)[i]; + value = (StringUtils.isBlank(value) || CommonConstant.NULL_STRING.equals(value)) ? null : "'" + value + "'"; + if (j == 0) { + filedValues.append("("); + } + + if ((j == params.size() - 1) && i != fieldValue.length - 1) { + filedValues.append(value).append("),"); + } else if ((j == params.size() - 1) && i == fieldValue.length - 1) { + filedValues.append(value).append(")"); + } else { + filedValues.append(value).append(","); + } + + vaules.append(filedValues); + } + } + + fileds.append(")"); + + String insertSql = sb.append(fileds).append(vaules).toString(); + log.info("mysql inserSql : {}", insertSql); + return insertSql; + } + + public String generateUpdateSql(ApiInfoDetailDto apiInfoDetailDto) { + StringBuffer sb = new StringBuffer(" update "); + String mainTableName = apiInfoDetailDto.getMainTableName(); + sb.append(mainTableName); + + List params = apiInfoDetailDto.getParams(); + List updateParam = params.stream().filter(item -> 1 == item.getIsUpdate()). + collect(Collectors.toList()); + + StringBuffer setSb = new StringBuffer(" set "); + for (int i = 0; i < updateParam.size(); i++) { + if (CommonUtil.hasCastString(updateParam.get(i).getParamJavaType())) { + setSb.append(updateParam.get(i).getParamTableFieldName().split("\\.")[1]).append("=").append("'").append(updateParam.get(i).getParamValue()).append("'"); + } else { + setSb.append(updateParam.get(i).getParamTableFieldName().split("\\.")[1]).append("=").append(updateParam.get(i).getParamValue()); + } + if (i != updateParam.size() - 1) { + setSb.append(","); + } + } + sb.append(setSb); + + List conditionParam = params.stream().filter(item -> 0 == item.getIsUpdate()).collect(Collectors.toList()); + + if (!CollectionUtils.isEmpty(conditionParam)) { + StringBuffer condition = generateWhereCondition(conditionParam); + sb.append(condition); + + } + + String result = sb.toString(); + log.info("mysql updateSql : {}", result); + return result; + } + + public String generateDeleteSql(ApiInfoDetailDto apiInfoDetailDto) { + StringBuffer sb = new StringBuffer(" delete from "); + String mainTableName = apiInfoDetailDto.getMainTableName(); + sb.append(mainTableName); + List params = apiInfoDetailDto.getParams(); + if (!CollectionUtils.isEmpty(params)) { + StringBuffer condition = generateWhereCondition(params); + sb.append(condition); + } + + String result = sb.toString(); + log.info("mysql deleteSql : {}", result); + return result; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/init/BeanInit.java b/src/main/java/com/xforwardai/superdata/init/BeanInit.java new file mode 100644 index 0000000000000000000000000000000000000000..e5bc1b6ec5dbb73fcaa9b9a82990040fc3d5034e --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/init/BeanInit.java @@ -0,0 +1,10 @@ +package com.xforwardai.superdata.init; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.init.BeanInit.java + * @date: 2022/2/22 15:53 + * @author xujian + */ +public class BeanInit { +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/ApiCustomizeSql.java b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiCustomizeSql.java new file mode 100644 index 0000000000000000000000000000000000000000..1242617c6a94b34e5065b7f496f992895c7fc9c6 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiCustomizeSql.java @@ -0,0 +1,20 @@ +package com.xforwardai.superdata.mysql.entity; + +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.ApiCustomizeSql.java + * @date: 2022/8/30 17:42 + * @author xujian + */ +@Data +public class ApiCustomizeSql extends Entity { + + private Integer apiId; + + private String customizeSql; + + private String associationSql; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/ApiDatasource.java b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiDatasource.java new file mode 100644 index 0000000000000000000000000000000000000000..23eed85e1c258e0e29ea5701e91ec9e507a6cce9 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiDatasource.java @@ -0,0 +1,36 @@ +package com.xforwardai.superdata.mysql.entity; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.ApiDatasource.java + * @date: 2022/3/2 18:06 + * @author xujian + */ +@Data +public class ApiDatasource extends Entity { + + @ApiModelProperty(value = "数据源唯一编码") + private String datasourceCode; + + @ApiModelProperty(value = "数据源名称") + private String datasourceName; + + @ApiModelProperty(value = "数据源类型 1-mysql 2-es") + private Integer type; + + @ApiModelProperty(value = "数据源ip") + private String ip; + + @ApiModelProperty(value = "数据源端口") + private String port; + + @ApiModelProperty(value = "数据源账号") + private String username; + + @ApiModelProperty(value = "数据源密码") + private String password; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/ApiInfo.java b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..96e2d354e0f6fbdde0de88c0120b37128561982d --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiInfo.java @@ -0,0 +1,35 @@ +package com.xforwardai.superdata.mysql.entity; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.entity.ApiInfo.java + * @date: 2022/2/23 10:20 + * @author xujian + */ +@Data +public class ApiInfo extends Entity { + + private String name; + + private String method; + + private String url; + + private String datasourceCode; + + private String databaseName; + + private String mainTableName; + + private Integer resultType; + + private Integer isExport; + + private Integer operateType; + + private Integer isCustomizeSql; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/ApiParam.java b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiParam.java new file mode 100644 index 0000000000000000000000000000000000000000..513a2fdbf9e98912d8de3ec40bce965f5acc47e3 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiParam.java @@ -0,0 +1,32 @@ +package com.xforwardai.superdata.mysql.entity; + +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.entity.ApiParam.java + * @date: 2022/2/23 10:39 + * @author xujian + */ +@Data +public class ApiParam extends Entity { + + private Integer apiId; + + private String paramName; + + private String paramTableFieldName; + + private String paramJavaType; + + private String paramTableFieldType; + + private Integer paramBodyType; + + private Integer isRequired; + + private Integer conditionType; + + private Integer isUpdate; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/ApiResult.java b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiResult.java new file mode 100644 index 0000000000000000000000000000000000000000..cbe0c69ffa44cb9b2ef241c6075187d6f1f4c0a5 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiResult.java @@ -0,0 +1,30 @@ +package com.xforwardai.superdata.mysql.entity; + +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.entity.ApiResult.java + * @date: 2022/2/23 10:43 + * @author xujian + */ +@Data +public class ApiResult extends Entity { + + private Integer apiId; + + private String resultName; + + private String resultTableFieldName; + + private String resultJavaType; + + private String resultTableFieldType; + + private String exportName; + + private Integer sortType; + +} + + diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/ApiTableRelation.java b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiTableRelation.java new file mode 100644 index 0000000000000000000000000000000000000000..4d60094b0bed917a8e8829de8400b5e30ad07931 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/ApiTableRelation.java @@ -0,0 +1,24 @@ +package com.xforwardai.superdata.mysql.entity; + +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.ApiTableRelation.java + * @date: 2022/3/8 18:08 + * @author xujian + */ +@Data +public class ApiTableRelation extends Entity { + + private Integer apiId; + + private String mainTableName; + + private String associationTableName; + + private String associationCondition; + + private Integer relationType; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/Entity.java b/src/main/java/com/xforwardai/superdata/mysql/entity/Entity.java new file mode 100644 index 0000000000000000000000000000000000000000..7f4b36fb29b4143273f5ce2bb7fc67ca815156d7 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/Entity.java @@ -0,0 +1,26 @@ +package com.xforwardai.superdata.mysql.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.xforwardai.superdata.constants.CommonConstant; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +public abstract class Entity implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @JsonFormat(pattern = CommonConstant.CONSTANT_DATETIME_FORMAT) + private LocalDateTime createTime; + + @JsonFormat(pattern = CommonConstant.CONSTANT_DATETIME_FORMAT) + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/AddApiParamDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/AddApiParamDto.java new file mode 100644 index 0000000000000000000000000000000000000000..6746e7e2ede8bafcdf65aa2095eb6fc2a671ff22 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/AddApiParamDto.java @@ -0,0 +1,24 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.dto.AddApiParamDto.java + * @date: 2022/3/8 9:57 + * @author xujian + */ +@Data +public class AddApiParamDto { + + @NotNull(message = "appId不能为空") + private Integer apiId; + + @NotEmpty(message = "参数集合不能为空") + private List list; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/AddApiResultDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/AddApiResultDto.java new file mode 100644 index 0000000000000000000000000000000000000000..0ff9600771b24a17c4ed5dc43d88c29f10b3abb5 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/AddApiResultDto.java @@ -0,0 +1,24 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.dto.AddApiResultDto.java + * @date: 2022/3/8 10:13 + * @author xujian + */ +@Data +public class AddApiResultDto { + + @NotNull(message = "appId不能为空") + private Integer apiId; + + @NotEmpty(message = "参数集合不能为空") + private List list; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiCustomizeSqlDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiCustomizeSqlDto.java new file mode 100644 index 0000000000000000000000000000000000000000..b5197542f440d7e1b6a2006d0848b976c3fc486a --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiCustomizeSqlDto.java @@ -0,0 +1,20 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.dto.ApiCustomizeSqlDto.java + * @date: 2022/8/31 15:04 + * @author xujian + */ +@Data +public class ApiCustomizeSqlDto { + + private Integer apiId; + + private String customizeSql; + + private String associationSql; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiDatasourceDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiDatasourceDto.java new file mode 100644 index 0000000000000000000000000000000000000000..98fcc0288272bf2ead2c7c626eac76157d3bccef --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiDatasourceDto.java @@ -0,0 +1,53 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import com.xforwardai.superdata.annotation.MysqlCheckInject; +import com.xforwardai.superdata.base.BaseDto; +import com.xforwardai.superdata.mysql.mapper.ApiDatasourceMapper; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto.java + * @date: 2022/3/2 16:19 + * @author xujian + */ +@Data +@MysqlCheckInject(mapper = ApiDatasourceMapper.class) +public class ApiDatasourceDto extends BaseDto { + + @MysqlCheckInject(uniqueField = "datasource_code") + @NotBlank(message = "数据源唯一编码不能为空") + @ApiModelProperty(value = "数据源唯一编码") + private String datasourceCode; + + @NotBlank(message = "数据源名称不能为空") + @ApiModelProperty(value = "数据源名称") + private String datasourceName; + + @ApiModelProperty(value = "数据库名称") + private String databaseName; + + @MysqlCheckInject(conditionUniqueField = {"ip", "port", "type", "database_name"}) + @ApiModelProperty(value = "数据源类型 1-mysql 2-es") + @NotNull(message = "数据源类型不能为空") + private Integer type; + + @ApiModelProperty(value = "数据源ip") + @NotBlank(message = "数据源ip不能为空") + private String ip; + + @ApiModelProperty(value = "数据源端口") + @NotBlank(message = "数据源端口不能为空") + private String port; + + @ApiModelProperty(value = "数据源账号") + private String username; + + @ApiModelProperty(value = "数据源密码") + private String password; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiInfoDetailDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiInfoDetailDto.java new file mode 100644 index 0000000000000000000000000000000000000000..641a5ad5d41e93d66935363f6eb1cf29a257824c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiInfoDetailDto.java @@ -0,0 +1,30 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import lombok.Data; + +import javax.validation.Valid; +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.entity.dto.ApiInfoDetailDto.java + * @date: 2022/2/23 13:56 + * @author xujian + */ +@Data +public class ApiInfoDetailDto extends ApiInfoDto { + + @Valid + private List params; + + //@Valid + //@NotEmpty(message = "返回字段不能为空") + private List results; + + private List tableRelations; + + private ApiDatasourceDto datasourceDto; + + private ApiCustomizeSqlDto apiCustomizeSqlDto; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiInfoDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiInfoDto.java new file mode 100644 index 0000000000000000000000000000000000000000..dc10367bd92170bfd949b3b49ca1cee4f36af7dc --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiInfoDto.java @@ -0,0 +1,66 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import com.xforwardai.superdata.annotation.MysqlCheckInject; +import com.xforwardai.superdata.base.BaseDto; +import com.xforwardai.superdata.mysql.mapper.ApiInfoMapper; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.entity.ApiInfo.java + * @date: 2022/2/23 10:20 + * @author xujian + */ +@Data +@MysqlCheckInject(mapper = ApiInfoMapper.class) +public class ApiInfoDto extends BaseDto { + + @NotBlank(message = "接口名称不能为空") + @ApiModelProperty(value = "接口名称") + @MysqlCheckInject(uniqueField = "name") + private String name; + + @NotBlank(message = "接口请求类型不能为空") + @ApiModelProperty(value = "接口请求类型") + @MysqlCheckInject(conditionUniqueField = {"method", "url"}) + private String method; + + @NotBlank(message = "请求url不能为空") + @ApiModelProperty(value = "请求url") + private String url; + + @ApiModelProperty(value = "数据源类型 1:mysql 2:es") + private Integer datasourceType; + + @ApiModelProperty(value = "接口类型 0:查询 1:新增 2:更新 3:删除") + private Integer operateType; + + @NotBlank(message = "数据源code不能为空") + @ApiModelProperty(value = "数据源code") + private String datasourceCode; + + @NotBlank(message = "数据库名称不能为空") + @ApiModelProperty(value = "数据库名称") + private String databaseName; + + //@NotBlank(message = "主表不能为空") + @ApiModelProperty(value = "主表名称") + private String mainTableName; + + @NotNull(message = "返回数据类型不能为空") + @ApiModelProperty(value = "返回数据类型 0:单条数据 1:数组 2:分页") + private Integer resultType; + + @NotNull(message = "是否导出接口类型不能为空") + @ApiModelProperty(value = "是否导出接口 1:是 0:否") + private Integer isExport; + + @NotNull(message = "是否自定义sql不能为空") + @ApiModelProperty(value = "是否导出接口 1:是 0:否") + private Integer isCustomizeSql; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiParamDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiParamDto.java new file mode 100644 index 0000000000000000000000000000000000000000..aeb1189791d4fbaf637db0582a57cadc26686f78 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiParamDto.java @@ -0,0 +1,57 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import com.xforwardai.superdata.base.BaseDto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.entity.dto.ApiParamDto.java + * @date: 2022/2/23 10:39 + * @author xujian + */ +@Data +public class ApiParamDto extends BaseDto { + + @ApiModelProperty(value = "接口id") + private Integer apiId; + + @NotBlank(message = "参数名称不能为空") + @ApiModelProperty(value = "参数名称") + private String paramName; + + //@NotBlank(message = "参数类型不能为空") + @ApiModelProperty(value = "参数类型") + private String paramJavaType; + + @NotBlank(message = "对应表字段类型不能为空") + @ApiModelProperty(value = "对应表字段类型") + private String paramTableFieldType; + + @NotBlank(message = "对应表字段不能为空") + @ApiModelProperty(value = "对应表字段") + private String paramTableFieldName; + + @NotNull(message = "请求类型不能为空") + @ApiModelProperty(value = "请求类型 0:url传参 1:请求体传参") + private Integer paramBodyType; + + @NotNull(message = "是否必须要的参数不能为空") + @ApiModelProperty(value = "是否必须要的参数 1:是 0:否") + private Integer isRequired; + + @ApiModelProperty(value = "请求参数对应的值") + private Object paramValue; + + @NotNull(message = "条件类型不能为空") + @ApiModelProperty(value = "条件类型 1:等于 2:小于 3:小于等于 4:大于 5:大于等于 6:模糊") + private Integer conditionType; + + @NotNull(message = "是否更新参数不能为空") + @ApiModelProperty(value = "是否更新参数 1:是 0:否") + private Integer isUpdate; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiResultDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiResultDto.java new file mode 100644 index 0000000000000000000000000000000000000000..4385df64e65cce7f748b84f1b862a747c41af26f --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiResultDto.java @@ -0,0 +1,46 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import com.xforwardai.superdata.base.BaseDto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.entity.dto.ApiResultDto.java + * @date: 2022/2/23 10:43 + * @author xujian + */ +@Data +public class ApiResultDto extends BaseDto { + + @ApiModelProperty(value = "接口id") + private Integer apiId; + + @ApiModelProperty(value = "返回字段名称") + @NotBlank(message = "返回字段名称不能为空") + private String resultName; + + @ApiModelProperty(value = "返回字段类型") + //@NotBlank(message = "返回字段类型不能为空") + private String resultJavaType; + + @ApiModelProperty(value = "返回对应表字段") + @NotBlank(message = "返回对应表字段不能为空") + private String resultTableFieldName; + + @ApiModelProperty(value = "返回对应表字段类型") + @NotBlank(message = "返回对应表字段类型不能为空") + private String resultTableFieldType; + + @ApiModelProperty(value = "导出表列名称") + private String exportName; + + @ApiModelProperty(value = "排序类型 0:无排序 1:倒序 2:升序") + private Integer sortType; + +} + + diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiTableRelationDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiTableRelationDto.java new file mode 100644 index 0000000000000000000000000000000000000000..fbb7de2d707f82b82a9bf77c054a7def2402fef1 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ApiTableRelationDto.java @@ -0,0 +1,31 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import com.xforwardai.superdata.base.BaseDto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.dto.ApiTableRelationDto.java + * @date: 2022/3/8 18:09 + * @author xujian + */ +@Data +public class ApiTableRelationDto extends BaseDto { + + @ApiModelProperty(value = "接口id") + private Integer apiId; + + @ApiModelProperty(value = "主表名称") + private String mainTableName; + + @ApiModelProperty(value = "关联表名称") + private String associationTableName; + + @ApiModelProperty(value = "关联条件 如: a.id=b.id") + private String associationCondition; + + @ApiModelProperty(value = "关联类型 1:LEFT JOIN 2:INNER JOIN 3:RIGHT JOIN") + private Integer relationType; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ExcelDataDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ExcelDataDto.java new file mode 100644 index 0000000000000000000000000000000000000000..a31b9f11ccae040f2b80bfe9e337127b3d265832 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/ExcelDataDto.java @@ -0,0 +1,31 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +public class ExcelDataDto { + /** + * 表头 + */ + private List titles; + /** + * 数据 + */ + private List> rows = new ArrayList<>(); + /** + * 页签名称 + */ + private String name; + /** + * excle名称 + */ + private String fileName; + /** + * sheetName + */ + private String sheetName; + +} \ No newline at end of file diff --git a/src/main/java/com/xforwardai/superdata/mysql/entity/dto/TableFieldDto.java b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/TableFieldDto.java new file mode 100644 index 0000000000000000000000000000000000000000..a1587f58e0ba6b514e1c2038f0f00910d813a61c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/entity/dto/TableFieldDto.java @@ -0,0 +1,18 @@ +package com.xforwardai.superdata.mysql.entity.dto; + +import lombok.Data; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.entity.dto.TableFieldDto.java + * @date: 2022/3/7 14:05 + * @author xujian + */ +@Data +public class TableFieldDto { + + private String fieldName; + + private String fieldType; + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiCustomizeSqlMapper.java b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiCustomizeSqlMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..e7d2e173d4de1526b84bd622d0b66f1070a3a1e1 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiCustomizeSqlMapper.java @@ -0,0 +1,13 @@ +package com.xforwardai.superdata.mysql.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xforwardai.superdata.mysql.entity.ApiCustomizeSql; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.mapper.ApiCustomizeSqlMapper.java + * @date: 2022/8/30 17:44 + * @author xujian + */ +public interface ApiCustomizeSqlMapper extends BaseMapper { +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiDatasourceMapper.java b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiDatasourceMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..787e6d1e0c05798ae94b2bcb38fd04018b927446 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiDatasourceMapper.java @@ -0,0 +1,14 @@ +package com.xforwardai.superdata.mysql.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xforwardai.superdata.mysql.entity.ApiDatasource; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.mapper.ApiDatasourceMapper.java + * @date: 2022/3/2 18:07 + * @author xujian + */ +public interface ApiDatasourceMapper extends BaseMapper { + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiInfoMapper.java b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiInfoMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..119e353440b019f5e887b6429aab0fb34fbfd540 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiInfoMapper.java @@ -0,0 +1,22 @@ +package com.xforwardai.superdata.mysql.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xforwardai.superdata.mysql.entity.ApiInfo; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDto; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.mapper.ApiInfoMapper.java + * @date: 2022/2/23 10:23 + * @author xujian + */ +public interface ApiInfoMapper extends BaseMapper { + + List getApiInfoList(Integer id); + + List getApiInfoByParam(ApiInfoDto apiInfoDto); + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiParamMapper.java b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiParamMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..aa6bdf49aec77447abd33a806340531c0a3e0e88 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiParamMapper.java @@ -0,0 +1,13 @@ +package com.xforwardai.superdata.mysql.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xforwardai.superdata.mysql.entity.ApiParam; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.mapper.ApiParamMapper.java + * @date: 2022/2/23 10:41 + * @author xujian + */ +public interface ApiParamMapper extends BaseMapper { +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiResultMapper.java b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiResultMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..e71bb8d8b9ccd0aa56ea51d8afcf1f5ba41dc3ac --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiResultMapper.java @@ -0,0 +1,13 @@ +package com.xforwardai.superdata.mysql.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xforwardai.superdata.mysql.entity.ApiResult; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.mapper.ApiResultMapper.java + * @date: 2022/2/23 10:46 + * @author xujian + */ +public interface ApiResultMapper extends BaseMapper { +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiTableRelationMapper.java b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiTableRelationMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..18a76a5559978cf01002e2eccabc2902044f8103 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/mapper/ApiTableRelationMapper.java @@ -0,0 +1,13 @@ +package com.xforwardai.superdata.mysql.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.xforwardai.superdata.mysql.entity.ApiTableRelation; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.mapper.ApiTableRelationMapper.java + * @date: 2022/6/21 19:31 + * @author xujian + */ +public interface ApiTableRelationMapper extends BaseMapper { +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/ApiCustomizeSqlService.java b/src/main/java/com/xforwardai/superdata/mysql/service/ApiCustomizeSqlService.java new file mode 100644 index 0000000000000000000000000000000000000000..3ebe457d3400ee3fe1284523edff7ab168b88606 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/ApiCustomizeSqlService.java @@ -0,0 +1,13 @@ +package com.xforwardai.superdata.mysql.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.xforwardai.superdata.mysql.entity.ApiCustomizeSql; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.service.ApiCustomizeSqlService.java + * @date: 2022/8/30 17:44 + * @author xujian + */ +public interface ApiCustomizeSqlService extends IService { +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/ApiDatasourceSerivce.java b/src/main/java/com/xforwardai/superdata/mysql/service/ApiDatasourceSerivce.java new file mode 100644 index 0000000000000000000000000000000000000000..e33a515d9e109efa35886a4b9c41459dbe80edca --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/ApiDatasourceSerivce.java @@ -0,0 +1,33 @@ +package com.xforwardai.superdata.mysql.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.ApiDatasource; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.TableFieldDto; + +import java.util.List; +import java.util.Set; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.service.ApiDatasourceSerivce.java + * @date: 2022/3/2 18:08 + * @author xujian + */ +public interface ApiDatasourceSerivce extends IService { + + List testSourceConnect(ApiDatasourceDto apiDatasourceDto) throws ApplicationException; + + void addDatasource(ApiDatasourceDto apiDatasourceDto); + + List getDatasourceList(Integer type); + + Set getTables(String datasourceCode, String dataBaseName); + + List getDatabases(String datasourceCode); + + List getTableFields(String datasourceCode, String dataBaseName, String tableName); + + ApiDatasource checkApiDatasource(String datasourceCode); +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/ApiInfoService.java b/src/main/java/com/xforwardai/superdata/mysql/service/ApiInfoService.java new file mode 100644 index 0000000000000000000000000000000000000000..ac4d47362edc014f6dcd9a593385b5db3ca64d1c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/ApiInfoService.java @@ -0,0 +1,41 @@ +package com.xforwardai.superdata.mysql.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.xforwardai.superdata.base.BasePageResultVo; +import com.xforwardai.superdata.mysql.entity.ApiInfo; +import com.xforwardai.superdata.mysql.entity.dto.AddApiParamDto; +import com.xforwardai.superdata.mysql.entity.dto.AddApiResultDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDto; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.service.impl.ApiInfoService.java + * @date: 2022/2/23 10:23 + * @author xujian + */ +public interface ApiInfoService extends IService { + + List getApiInfoList(Integer id); + + void addApiInfo(ApiInfoDetailDto apiInfoDetailDto); + + void updateApiInfo(ApiInfoDetailDto apiInfoDetailDto); + + void delete(Integer id); + + void addApiParam(AddApiParamDto addApiParamDto); + + void deleteApiParam(AddApiParamDto addApiParamDto); + + void addApiResult(AddApiResultDto addApiResultDto); + + void deleteApiResutl(AddApiResultDto addApiResultDto); + + BasePageResultVo> getApiInfoPage(ApiInfoDto apiInfoDto); + + void saveOrUpdateApiInfo(ApiInfoDetailDto apiInfoDetailDto); +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/ApiParamService.java b/src/main/java/com/xforwardai/superdata/mysql/service/ApiParamService.java new file mode 100644 index 0000000000000000000000000000000000000000..16c21183b54118786d0fbc427aa10b7e4d830b73 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/ApiParamService.java @@ -0,0 +1,18 @@ +package com.xforwardai.superdata.mysql.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.xforwardai.superdata.mysql.entity.ApiParam; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.service.ApiParamService.java + * @date: 2022/2/23 10:42 + * @author xujian + */ +public interface ApiParamService extends IService { + void deleteByApiId(Integer apiId); + + void addList(Integer apiId, List list); +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/ApiResultService.java b/src/main/java/com/xforwardai/superdata/mysql/service/ApiResultService.java new file mode 100644 index 0000000000000000000000000000000000000000..13712b1842973da71f2f3e859b2c40e1814ed35f --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/ApiResultService.java @@ -0,0 +1,18 @@ +package com.xforwardai.superdata.mysql.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.xforwardai.superdata.mysql.entity.ApiResult; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.service.ApiResultService.java + * @date: 2022/2/23 10:45 + * @author xujian + */ +public interface ApiResultService extends IService { + void deleteByApiId(Integer apiId); + + void addList(Integer apiId, List list); +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/ApiTableRelationService.java b/src/main/java/com/xforwardai/superdata/mysql/service/ApiTableRelationService.java new file mode 100644 index 0000000000000000000000000000000000000000..5e12d53563297c91b59d276eb2120ecb5fa0085e --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/ApiTableRelationService.java @@ -0,0 +1,19 @@ +package com.xforwardai.superdata.mysql.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.xforwardai.superdata.mysql.entity.ApiTableRelation; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.service.ApiTableRelationService.java + * @date: 2022/6/21 19:31 + * @author xujian + */ +public interface ApiTableRelationService extends IService { + + void addList(List list); + + void deleteByApiId(Integer apiId); +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiCustomizeSqlServiceImpl.java b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiCustomizeSqlServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..5a2da878c1a3cbe35393bcdd0112245d44b70fcc --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiCustomizeSqlServiceImpl.java @@ -0,0 +1,20 @@ +package com.xforwardai.superdata.mysql.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.xforwardai.superdata.mysql.entity.ApiCustomizeSql; +import com.xforwardai.superdata.mysql.mapper.ApiCustomizeSqlMapper; +import com.xforwardai.superdata.mysql.service.ApiCustomizeSqlService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.service.impl.ApiCustomizeSqlServiceImpl.java + * @date: 2022/8/30 17:47 + * @author xujian + */ +@Service +@Slf4j +public class ApiCustomizeSqlServiceImpl extends ServiceImpl implements ApiCustomizeSqlService { + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiDatasourceImpl.java b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiDatasourceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..2b24c47f37bb1fcf9c35345c3d6988c2465d354f --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiDatasourceImpl.java @@ -0,0 +1,108 @@ +package com.xforwardai.superdata.mysql.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.ApiDatasource; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.TableFieldDto; +import com.xforwardai.superdata.mysql.mapper.ApiDatasourceMapper; +import com.xforwardai.superdata.mysql.service.ApiDatasourceSerivce; +import com.xforwardai.superdata.service.impl.QuerySqlServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.service.impl.ApiDatasourceImpl.java + * @date: 2022/3/2 18:08 + * @author xujian + */ +@Slf4j +@Service +public class ApiDatasourceImpl extends ServiceImpl implements ApiDatasourceSerivce { + + @Autowired + private QuerySqlServiceImpl sqlService; + + @Override + public List testSourceConnect(ApiDatasourceDto apiDatasourceDto) throws ApplicationException { + return sqlService.testSourceConnect(apiDatasourceDto); + } + + @Override + public void addDatasource(ApiDatasourceDto apiDatasourceDto) { + ApiDatasource apiDatasource = new ApiDatasource(); + BeanUtils.copyProperties(apiDatasourceDto, apiDatasource); + this.save(apiDatasource); + } + + @Override + public List getDatasourceList(Integer type) { + QueryWrapper queryWrapper = new QueryWrapper(); + if (null != type) { + queryWrapper.eq("type", type); + } + return this.list(queryWrapper); + } + + @Override + public Set getTables(String datasourceCode, String dataBaseName) { + if (StringUtils.isBlank(datasourceCode) ) { + throw new ApplicationException(ResultCode.FAIL_CODE, "datasourceCode不能为空"); + } + + ApiDatasource apiDatesource = checkApiDatasource(datasourceCode); + ApiDatasourceDto apiDatasourceDto = new ApiDatasourceDto(); + BeanUtils.copyProperties(apiDatesource, apiDatasourceDto); + apiDatasourceDto.setDatabaseName(dataBaseName); + + return sqlService.getTables(apiDatasourceDto); + } + + @Override + public List getDatabases(String datasourceCode) { + if (StringUtils.isBlank(datasourceCode)) { + throw new ApplicationException(ResultCode.FAIL_CODE, "datasourceCode不能为空"); + } + + ApiDatasource apiDatesource = checkApiDatasource(datasourceCode); + ApiDatasourceDto apiDatasourceDto = new ApiDatasourceDto(); + BeanUtils.copyProperties(apiDatesource, apiDatasourceDto); + + return sqlService.testSourceConnect(apiDatasourceDto); + } + + + + @Override + public List getTableFields(String datasourceCode, String dataBaseName, String tableName) { + if (StringUtils.isBlank(datasourceCode) || StringUtils.isBlank(tableName)) { + throw new ApplicationException(ResultCode.FAIL_CODE, "datasourceCode,tableName不能为空"); + } + ApiDatasource apiDatesource = checkApiDatasource(datasourceCode); + ApiDatasourceDto apiDatasourceDto = new ApiDatasourceDto(); + BeanUtils.copyProperties(apiDatesource, apiDatasourceDto); + apiDatasourceDto.setDatabaseName(dataBaseName); + return sqlService.getTableFields(apiDatasourceDto, tableName); + } + + @Override + public ApiDatasource checkApiDatasource(String datasourceCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("datasource_code", datasourceCode); + ApiDatasource apiDatesource = this.getOne(queryWrapper); + if (null == apiDatesource) { + throw new ApplicationException(ResultCode.FAIL_CODE, "datasourceCode输入有误"); + } + return apiDatesource; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiInfoServiceImpl.java b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiInfoServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..2aec4c50966d62de11a87694acc18520ce2d954f --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiInfoServiceImpl.java @@ -0,0 +1,521 @@ +package com.xforwardai.superdata.mysql.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import com.xforwardai.superdata.base.BasePageResultVo; +import com.xforwardai.superdata.cache.ApiInfoCacheMap; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.enums.ConditionType; +import com.xforwardai.superdata.enums.SortType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.handler.MappingHandler; +import com.xforwardai.superdata.mysql.entity.*; +import com.xforwardai.superdata.mysql.entity.dto.*; +import com.xforwardai.superdata.mysql.mapper.ApiInfoMapper; +import com.xforwardai.superdata.mysql.service.*; +import com.xforwardai.superdata.util.ApiUtil; +import com.xforwardai.superdata.util.PropertiesUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.service.impl.ApiInfoServiceImpl.java + * @date: 2022/2/23 10:24 + * @author xujian + */ +@Service +@Slf4j +public class ApiInfoServiceImpl extends ServiceImpl implements ApiInfoService { + + @Autowired + private ApiParamService apiParamService; + + @Autowired + private ApiResultService apiResultService; + + @Autowired + private ApiDatasourceSerivce apiDatasourceSerivce; + + @Autowired + private ApiTableRelationService apiTableRelationService; + + @Autowired + private ApiCustomizeSqlService apiCustomizeSqlService; + + @Autowired + private PropertiesUtil propertiesUtil; + + @Autowired + private MappingHandler mappingHandler; + + @Override + public List getApiInfoList(Integer id) { + return this.getBaseMapper().getApiInfoList(id); + } + + private void before(ApiInfoDetailDto apiInfoDetailDto) { + ApiDatasource apiDatasource = apiDatasourceSerivce. + checkApiDatasource(apiInfoDetailDto.getDatasourceCode()); + ApiDatasourceDto apiDatasourceDto = new ApiDatasourceDto(); + BeanUtils.copyProperties(apiDatasource, apiDatasourceDto); + apiInfoDetailDto.setDatasourceDto(apiDatasourceDto); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void addApiInfo(ApiInfoDetailDto apiInfoDetailDto) { + before(apiInfoDetailDto); + if (CommonConstant.API_CUSTOMIZESQL.equals(apiInfoDetailDto.getIsCustomizeSql())) { + parseCustomizeSql(apiInfoDetailDto); + } + + ApiInfo apiInfo = new ApiInfo(); + BeanUtils.copyProperties(apiInfoDetailDto, apiInfo); + + this.save(apiInfo); + + if (CommonConstant.API_CUSTOMIZESQL.equals(apiInfoDetailDto.getIsCustomizeSql())) { + ApiCustomizeSql apiCustomizeSql = new ApiCustomizeSql(); + BeanUtils.copyProperties(apiInfoDetailDto.getApiCustomizeSqlDto(), apiCustomizeSql); + apiCustomizeSql.setApiId(apiInfo.getId()); + apiCustomizeSqlService.save(apiCustomizeSql); + } + + List apiParams = new ArrayList<>(); + apiInfoDetailDto.getParams().forEach(param -> { + if (StringUtils.isNotBlank(param.getParamTableFieldType())) { + String javaType = propertiesUtil.getJavaTypeByFieldType(param.getParamTableFieldType()); + param.setParamJavaType(javaType); + } + ApiParam apiParam = new ApiParam(); + BeanUtils.copyProperties(param, apiParam); + apiParam.setApiId(apiInfo.getId()); + + apiParams.add(apiParam); + }); + apiParamService.addList(apiInfo.getId(), apiParams); + + List apiResults = new ArrayList<>(); + apiInfoDetailDto.getResults().forEach(result -> { + if (StringUtils.isNotBlank(result.getResultTableFieldType())) { + String javaType = propertiesUtil.getJavaTypeByFieldType(result.getResultTableFieldType()); + result.setResultJavaType(javaType); + } + ApiResult apiResult = new ApiResult(); + BeanUtils.copyProperties(result, apiResult); + apiResult.setApiId(apiInfo.getId()); + apiResults.add(apiResult); + }); + apiResultService.addList(apiInfo.getId(), apiResults); + + List apiTableRelations = new ArrayList<>(); + if (!CollectionUtils.isEmpty(apiInfoDetailDto.getTableRelations())) { + apiInfoDetailDto.getTableRelations().forEach(item -> { + ApiTableRelation apiTableRelation = new ApiTableRelation(); + BeanUtils.copyProperties(item, apiTableRelation); + apiTableRelation.setApiId(apiInfo.getId()); + apiTableRelations.add(apiTableRelation); + }); + } + apiTableRelationService.addList(apiTableRelations); + + mappingHandler.handlerApi(apiInfoDetailDto); + } + + @Override + public void updateApiInfo(ApiInfoDetailDto apiInfoDetailDto) { + if (null == apiInfoDetailDto.getId()) { + throw new ApplicationException(ResultCode.FAIL_CODE, "id不能为空"); + } + mappingHandler.handlerRemoveApi(apiInfoDetailDto); + + before(apiInfoDetailDto); + ApiInfo apiInfo = new ApiInfo(); + BeanUtils.copyProperties(apiInfoDetailDto, apiInfo); + this.updateById(apiInfo); + + mappingHandler.handlerApi(apiInfoDetailDto); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(Integer id) { + if (null == id) { + throw new ApplicationException(ResultCode.FAIL_CODE, "id不能为空"); + } + + ApiInfo apiInfo = this.getById(id); + if (null == apiInfo) { + throw new ApplicationException(ResultCode.FAIL_CODE, "该接口已被删除"); + } + + ApiInfoDetailDto apiInfoDetailDto = new ApiInfoDetailDto(); + apiInfoDetailDto.setUrl(apiInfo.getUrl()); + apiInfoDetailDto.setMethod(apiInfo.getMethod()); + ApiInfoDetailDto cache = ApiInfoCacheMap.API_INFO_MAP.get(ApiUtil.getApiUrl(apiInfoDetailDto)); + if (null != cache) { + mappingHandler.handlerRemoveApi(cache); + } + + this.removeById(id); + apiParamService.deleteByApiId(id); + apiResultService.deleteByApiId(id); + apiTableRelationService.deleteByApiId(id); + } + + @Override + public void addApiParam(AddApiParamDto addApiParamDto) { + if (!CollectionUtils.isEmpty(addApiParamDto.getList())) { + List saveList = new ArrayList<>(); + addApiParamDto.getList().forEach(item -> { + ApiParam apiParam = new ApiParam(); + BeanUtils.copyProperties(item, apiParam); + apiParam.setApiId(addApiParamDto.getApiId()); + saveList.add(apiParam); + }); + + apiParamService.saveBatch(saveList); + refreshApi(addApiParamDto.getApiId()); + } + } + + @Override + public void deleteApiParam(AddApiParamDto addApiParamDto) { + if (!CollectionUtils.isEmpty(addApiParamDto.getList())) { + apiParamService.removeByIds(addApiParamDto.getList().stream().map + (ApiParamDto::getId).collect(Collectors.toList())); + refreshApi(addApiParamDto.getApiId()); + } + } + + @Override + public void addApiResult(AddApiResultDto addApiResultDto) { + if (!CollectionUtils.isEmpty(addApiResultDto.getList())) { + List saveList = new ArrayList<>(); + addApiResultDto.getList().forEach(item -> { + ApiResult apiResult = new ApiResult(); + BeanUtils.copyProperties(item, apiResult); + apiResult.setApiId(addApiResultDto.getApiId()); + saveList.add(apiResult); + }); + apiResultService.saveBatch(saveList); + + refreshApiMap(addApiResultDto.getApiId()); + } + } + + @Override + public void deleteApiResutl(AddApiResultDto addApiResultDto) { + if (!CollectionUtils.isEmpty(addApiResultDto.getList())) { + apiResultService.removeByIds(addApiResultDto.getList().stream().map + (ApiResultDto::getId).collect(Collectors.toList())); + refreshApiMap(addApiResultDto.getApiId()); + } + } + + @Override + public BasePageResultVo> getApiInfoPage(ApiInfoDto apiInfoDto) { + if (apiInfoDto.getPage() <= 0 || apiInfoDto.getSize() <= 0) { + throw new ApplicationException(ResultCode.FAIL_CODE, "page和size不能为空"); + } + BasePageResultVo result = new BasePageResultVo(); + Page page = PageHelper.startPage(apiInfoDto.getPage(), apiInfoDto.getSize()); + List apiInfoByParam = this.getBaseMapper().getApiInfoByParam(apiInfoDto); + if (!CollectionUtils.isEmpty(apiInfoByParam)) { + apiInfoByParam.stream().forEach(item -> { + item.setDatasourceType(item.getDatasourceDto().getType()); + }); + } + result.setContent(apiInfoByParam); + result.setPage(apiInfoDto.getPage()); + result.setSize(apiInfoDto.getSize()); + result.setTotal(page.getTotal()); + return result; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrUpdateApiInfo(ApiInfoDetailDto apiInfoDetailDto) { + if (null == apiInfoDetailDto.getId()) { + addApiInfo(apiInfoDetailDto); + } else { + delete(apiInfoDetailDto.getId()); + addApiInfo(apiInfoDetailDto); + } + } + + private String formatAllAssociation(String sql) { + sql = handlerEveryAssociation(sql, "LEFT"); + sql = handlerEveryAssociation(sql, "RIGHT"); + sql = handlerEveryAssociation(sql, "INNER"); + return sql; + } + + private String handlerEveryAssociation(String sql, String association) { + int leftIndex = sql.indexOf(" " + association + " "); + if (leftIndex != -1) { + char[] chars = sql.toCharArray(); + int leftEndIndex = leftIndex + association.length() + 1; + for (int i = leftEndIndex; leftEndIndex < chars.length; leftEndIndex++) { + if (chars[leftEndIndex] != ' ') { + break; + } + } + sql = sql.substring(0, leftIndex + association.length() + 2) + sql.substring(leftEndIndex, sql.length()); + } + return sql; + } + + /*** + * @description: 解析自定义sql + * @param: apiInfo + * @return: void + * @author xujian + * @date: 2022/8/31 18:28 + */ + public void parseCustomizeSql(ApiInfoDetailDto apiInfo) { + if (apiInfo.getApiCustomizeSqlDto() == null || + StringUtils.isBlank(apiInfo.getApiCustomizeSqlDto().getCustomizeSql())) { + throw new ApplicationException(ResultCode.FAIL_CODE, "自定义sql不能为空"); + } + String sql = apiInfo.getApiCustomizeSqlDto(). + getCustomizeSql().replaceAll("\n", " ").replaceAll("\t", " "); + String upCaseSql = sql.toUpperCase(); + //去除left join 等中间的空格(只保留一个空格,好为后面切割准备) + // upCaseSql = formatAllAssociation(upCaseSql); + + ApiCustomizeSqlDto apiCustomizeSqlDto = new ApiCustomizeSqlDto(); + apiCustomizeSqlDto.setCustomizeSql(apiInfo.getApiCustomizeSqlDto().getCustomizeSql()); + apiInfo.setApiCustomizeSqlDto(apiCustomizeSqlDto); + + //是否有where条件 + int whereIndex = upCaseSql.toUpperCase().indexOf(" WHERE "); + //是否有order 排序 + int orderIndex = upCaseSql.toUpperCase().indexOf(" ORDER "); + + String mainTable = null; + if(upCaseSql.contains(" LEFT ") || upCaseSql.contains(" RIGHT ") || upCaseSql.contains(" INNER ")){ + int mainTableStartIndex = 6 + upCaseSql.indexOf(" FROM "); + int mainTableEndIndex = 0; + String tempMainTable = null; + List values = Arrays.asList(new String[]{" LEFT ", " RIGHT ", " INNER "}); + for (String value : values) { + if (upCaseSql.indexOf(value) != -1) { + mainTableEndIndex = upCaseSql.indexOf(value); + tempMainTable = upCaseSql.substring(mainTableStartIndex, mainTableEndIndex); + if (!tempMainTable.contains(" LEFT ") + && !tempMainTable.contains(" RIGHT ") + && !tempMainTable.contains(" INNER ")) { + break; + } + } + } + mainTable = sql.substring(mainTableStartIndex, mainTableEndIndex); + + String association = null; + int mainIndex = upCaseSql.indexOf(tempMainTable) + tempMainTable.length(); + if (whereIndex != -1) { + association = sql.substring(mainIndex, whereIndex); + } else if (orderIndex != -1) { + association = sql.substring(mainIndex, orderIndex); + } + + log.info("association :{}", association); + apiCustomizeSqlDto.setAssociationSql(association); + }else { + int mainTableStartIndex = 5 + upCaseSql.indexOf(" FROM "); + int mainTableEndIndex = 0; + if (whereIndex != -1) { + mainTableEndIndex = upCaseSql.indexOf(" WHERE "); + } else if (orderIndex != -1) { + mainTableEndIndex = upCaseSql.indexOf(" ORDER "); + } + + mainTable = sql.substring(mainTableStartIndex, mainTableEndIndex); + } + + log.info("mainTable :{}", mainTable); + apiInfo.setMainTableName(mainTable); + + Set descSort = new HashSet<>(); + Set ascSort = new HashSet<>(); + if (orderIndex != -1) { + String sort = sql.substring(orderIndex + 6).replaceAll("BY ",""). + replaceAll("By ",""). + replaceAll("bY ",""). + replaceAll("by ",""); + + String[] sortFields = sort.split(","); + for (String sortField : sortFields) { + String[] fieldItem = sortField.trim().split(" "); + if (sortField.toUpperCase().contains(" DESC")) { + descSort.add(fieldItem[0].replaceAll(" ", "")); + } + if (sortField.toUpperCase().contains(" ASC")) { + ascSort.add(fieldItem[0].replaceAll(" ", "")); + } + } + } + + String resultSql = sql.substring(upCaseSql.indexOf("SELECT") + 7, upCaseSql.indexOf(" FROM ")); + String[] resultFields = resultSql.split(","); + if (null == resultFields || resultFields.length == 0) { + throw new ApplicationException(ResultCode.FAIL_CODE, "自定义sql没有查询字段"); + } + + List apiResults = new ArrayList<>(); + for (String field : resultFields) { + ApiResultDto apiResult = new ApiResultDto(); + String[] fieldSplit = field.split(" "); + Boolean isFirst = Boolean.TRUE; + for (String fieldName : fieldSplit) { + if (StringUtils.isNotBlank(fieldName)) { + if (isFirst) { + apiResult.setResultTableFieldName(fieldName.replaceAll(" ", "")); + isFirst = Boolean.FALSE; + } else { + apiResult.setResultName(fieldName.replaceAll(" ", "")); + apiResult.setExportName(fieldName.replaceAll(" ", "")); + } + apiResult.setResultTableFieldType("varchar(64)"); + apiResult.setResultJavaType("string"); + apiResult.setSortType(SortType.NONE.getType()); + } + } + apiResults.add(apiResult); + } + + apiInfo.setResults(apiResults); + + int paramStartIndex = 6; + int paramEndIndex = 0; + + if (whereIndex != -1) { + paramStartIndex = paramStartIndex + upCaseSql.indexOf(" WHERE "); + if (orderIndex != -1) { + paramEndIndex = upCaseSql.indexOf(" ORDER "); + } else { + paramEndIndex = upCaseSql.length(); + } + + List apiParams = new ArrayList<>(); + String paramSql = sql.substring(paramStartIndex, paramEndIndex); + String[] paramFields = null; + + paramSql = paramSql.replaceAll(" and ", " AND "); + if (paramSql.contains(" AND ")) { + paramFields = paramSql.split(" AND "); + } + + for (String paramField : paramFields) { + ApiParamDto apiParam = new ApiParamDto(); + String coditionName = null; + for (ConditionType value : ConditionType.values()) { + if (paramField.contains(value.getName().replaceAll(" ", ""))) { + apiParam.setConditionType(value.getType()); + coditionName = value.getName().replaceAll(" ", ""); + } + } + + String[] splitParam = paramField.split(coditionName); + String paramName = splitParam[1].replaceAll(" ", ""); + if (paramName.contains(CommonConstant.BODY_PARAM_STR)) { + apiParam.setParamBodyType(CommonConstant.API_PARAM_BODY); + apiParam.setParamName(paramName.replaceAll(CommonConstant.BODY_PARAM_STR, "")); + } else { + apiParam.setParamBodyType(CommonConstant.API_PARAM_URL); + apiParam.setParamName(paramName); + } + + apiParam.setParamTableFieldName(splitParam[0].replaceAll(" ", "")); + apiParam.setParamJavaType("string"); + apiParam.setParamTableFieldType("varchar(64)"); + apiParams.add(apiParam); + } + apiInfo.setParams(apiParams); + } + + //排序字段处理 + for (String descFeild : descSort) { + Boolean isExist = Boolean.FALSE; + for (ApiResultDto apiResult : apiResults) { + if (descFeild.equals(apiResult.getResultTableFieldType())) { + apiResult.setSortType(SortType.DESC.getType()); + isExist = Boolean.TRUE; + } + } + if (!isExist) { + ApiResultDto apiResult = new ApiResultDto(); + apiResult.setSortType(SortType.DESC.getType()); + if(descFeild.contains(".")){ + apiResult.setResultName(descFeild.split("\\.")[1]); + }else{ + apiResult.setResultName(descFeild); + } + apiResult.setResultTableFieldName(descFeild); + apiResult.setResultTableFieldType("varchar(64)"); + apiResult.setResultJavaType("string"); + apiResults.add(apiResult); + } + } + + for (String ascFeild : ascSort) { + Boolean isExist = Boolean.FALSE; + for (ApiResultDto apiResult : apiResults) { + if (ascFeild.equals(apiResult.getResultTableFieldType())) { + apiResult.setSortType(SortType.ASC.getType()); + isExist = Boolean.TRUE; + } + } + if (!isExist) { + ApiResultDto apiResult = new ApiResultDto(); + apiResult.setSortType(SortType.ASC.getType()); + if(ascFeild.contains(".")){ + apiResult.setResultName(ascFeild.split("\\.")[1]); + }else{ + apiResult.setResultName(ascFeild); + } + apiResult.setResultTableFieldName(ascFeild); + apiResult.setResultTableFieldType("varchar(64)"); + apiResult.setResultJavaType("string"); + apiResults.add(apiResult); + } + } + + } + + private void refreshApi(Integer apiId) { + List apiInfoList = this.getBaseMapper().getApiInfoList(apiId); + if (CollectionUtils.isEmpty(apiInfoList) || apiInfoList.size() > 1) { + throw new ApplicationException(ResultCode.FAIL_CODE, "id有误"); + } + + ApiInfoDetailDto apiInfoDetailDto = apiInfoList.get(0); + mappingHandler.handlerRemoveApi(apiInfoDetailDto); + mappingHandler.handlerApi(apiInfoDetailDto); + } + + private void refreshApiMap(Integer apiId) { + List apiInfoList = this.getBaseMapper().getApiInfoList(apiId); + if (CollectionUtils.isEmpty(apiInfoList) || apiInfoList.size() > 1) { + throw new ApplicationException(ResultCode.FAIL_CODE, "id有误"); + } + + ApiInfoDetailDto apiInfoDetailDto = apiInfoList.get(0); + + ApiInfoCacheMap.API_INFO_MAP.put(ApiUtil.getApiUrl(apiInfoDetailDto), apiInfoDetailDto); + } + + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiParamServiceImpl.java b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiParamServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f2c10278dc47bb0daa0dfc50e64267c7bef5f859 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiParamServiceImpl.java @@ -0,0 +1,54 @@ +package com.xforwardai.superdata.mysql.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.ApiParam; +import com.xforwardai.superdata.mysql.mapper.ApiParamMapper; +import com.xforwardai.superdata.mysql.service.ApiParamService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.service.impl.ApiParamServiceImpl.java + * @date: 2022/2/23 10:42 + * @author xujian + */ +@Service +@Slf4j +public class ApiParamServiceImpl extends ServiceImpl implements ApiParamService { + + @Override + public void deleteByApiId(Integer apiId) { + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("api_id", apiId); + this.remove(queryWrapper); + } + + @Override + public void addList(Integer apiId, List list){ + if(null != apiId && !CollectionUtils.isEmpty(list)){ + Set paramNames = list.stream().map(ApiParam::getParamName).collect(Collectors.toSet()); + if(list.size() != paramNames.size()){ + throw new ApplicationException(ResultCode.FAIL_CODE, "参数名称有重复"); + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("api_id", apiId).in("param_name", paramNames); + List datasourceDatas = this.list(queryWrapper); + if (!CollectionUtils.isEmpty(datasourceDatas)) { + throw new ApplicationException(ResultCode.FAIL_CODE, "参数名称有重复"); + } + + this.saveBatch(list); + } + } + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiResultServiceImpl.java b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiResultServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..b9ebfc45d92315299b24c844a9b73c1bcd2218b9 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiResultServiceImpl.java @@ -0,0 +1,54 @@ +package com.xforwardai.superdata.mysql.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.ApiResult; +import com.xforwardai.superdata.mysql.mapper.ApiResultMapper; +import com.xforwardai.superdata.mysql.service.ApiResultService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.mysql.service.impl.ApiResultServiceImpl.java + * @date: 2022/2/23 10:46 + * @author xujian + */ +@Service +@Slf4j +public class ApiResultServiceImpl extends ServiceImpl implements ApiResultService { + + @Override + public void deleteByApiId(Integer apiId) { + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("api_id", apiId); + this.remove(queryWrapper); + } + + @Override + public void addList(Integer apiId, List list) { + if (null != apiId && !CollectionUtils.isEmpty(list)) { + Set paramNames = list.stream().map(ApiResult::getResultName).collect(Collectors.toSet()); + if (list.size() != paramNames.size()) { + throw new ApplicationException(ResultCode.FAIL_CODE, "返回字段名称有重复"); + } + + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("api_id", apiId).in("result_name", paramNames); + List datasourceDatas = this.list(queryWrapper); + if (!CollectionUtils.isEmpty(datasourceDatas)) { + throw new ApplicationException(ResultCode.FAIL_CODE, "返回字段名称有重复"); + } + + this.saveBatch(list); + } + } + +} diff --git a/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiTableRelationServiceImpl.java b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiTableRelationServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..0cb2e20878ff1c4bd9008b98e3a9a1dcf48403fd --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/mysql/service/impl/ApiTableRelationServiceImpl.java @@ -0,0 +1,46 @@ +package com.xforwardai.superdata.mysql.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.ApiTableRelation; +import com.xforwardai.superdata.mysql.mapper.ApiTableRelationMapper; +import com.xforwardai.superdata.mysql.service.ApiTableRelationService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.mysql.service.impl.ApiTableRelationServiceImpl.java + * @date: 2022/6/21 19:32 + * @author xujian + */ +@Service +@Slf4j +public class ApiTableRelationServiceImpl extends ServiceImpl implements ApiTableRelationService { + + @Override + public void addList(List list) { + if (!CollectionUtils.isEmpty(list)) { + Set associationTableNames = list.stream().map(ApiTableRelation::getAssociationTableName).collect(Collectors.toSet()); + if (list.size() != associationTableNames.size()) { + throw new ApplicationException(ResultCode.FAIL_CODE, "关联表有重复"); + } + this.saveBatch(list); + } + } + + @Override + public void deleteByApiId(Integer apiId) { + QueryWrapper queryWrapper = new QueryWrapper(); + queryWrapper.eq("api_id", apiId); + this.remove(queryWrapper); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/service/DeleteSqlService.java b/src/main/java/com/xforwardai/superdata/service/DeleteSqlService.java new file mode 100644 index 0000000000000000000000000000000000000000..1360ee43e2ec190fc4041033b4726ab012905f45 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/DeleteSqlService.java @@ -0,0 +1,10 @@ +package com.xforwardai.superdata.service; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.DeleteSqlService.java + * @date: 2022/6/23 14:22 + * @author xujian + */ +public interface DeleteSqlService extends SqlService{ +} diff --git a/src/main/java/com/xforwardai/superdata/service/InsertSqlService.java b/src/main/java/com/xforwardai/superdata/service/InsertSqlService.java new file mode 100644 index 0000000000000000000000000000000000000000..d37c6b11985495c3969f5d6f6bffa2c255ac5b29 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/InsertSqlService.java @@ -0,0 +1,10 @@ +package com.xforwardai.superdata.service; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.InsertSqlService.java + * @date: 2022/3/10 17:30 + * @author xujian + */ +public interface InsertSqlService extends SqlService{ +} diff --git a/src/main/java/com/xforwardai/superdata/service/QuerySqlService.java b/src/main/java/com/xforwardai/superdata/service/QuerySqlService.java new file mode 100644 index 0000000000000000000000000000000000000000..c24c0e7204000cfdb6ffa18713cf218164082bee --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/QuerySqlService.java @@ -0,0 +1,24 @@ +package com.xforwardai.superdata.service; + +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.TableFieldDto; + +import java.util.List; +import java.util.Set; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.QuerySqlService.java + * @date: 2022/3/2 15:01 + * @author xujian + */ +public interface QuerySqlService extends SqlService{ + + List testSourceConnect(ApiDatasourceDto apiDatasourceDto) throws ApplicationException; + + Set getTables(ApiDatasourceDto apiDatasourceDto); + + List getTableFields(ApiDatasourceDto apiDatasourceDto, String tableName); + +} diff --git a/src/main/java/com/xforwardai/superdata/service/SqlService.java b/src/main/java/com/xforwardai/superdata/service/SqlService.java new file mode 100644 index 0000000000000000000000000000000000000000..398fcff0983ae81832bb502642aff12d3a05308c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/SqlService.java @@ -0,0 +1,19 @@ +package com.xforwardai.superdata.service; + +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.SqlService.java + * @date: 2022/3/10 17:23 + * @author xujian + */ +public interface SqlService { + + String getDatasourceType(); + + String getOperateType(); + + Object execute(ApiInfoDetailDto apiInfoDetailDto); + +} diff --git a/src/main/java/com/xforwardai/superdata/service/UpdateSqlService.java b/src/main/java/com/xforwardai/superdata/service/UpdateSqlService.java new file mode 100644 index 0000000000000000000000000000000000000000..1839d985f3fb96db18a9ee0a165b53d4bf3dd8bf --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/UpdateSqlService.java @@ -0,0 +1,10 @@ +package com.xforwardai.superdata.service; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.UpdateSqlService.java + * @date: 2022/6/23 11:05 + * @author xujian + */ +public interface UpdateSqlService extends SqlService{ +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/EsDeleteServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/EsDeleteServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..7042272e3cb53f90c8cd3b2387817aa806bc437d --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/EsDeleteServiceImpl.java @@ -0,0 +1,56 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.service.DeleteSqlService; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.reindex.BulkByScrollResponse; +import org.elasticsearch.index.reindex.DeleteByQueryRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.EsDeleteServiceImpl.java + * @date: 2022/6/28 14:29 + * @author xujian + */ +@Service +@Slf4j +public class EsDeleteServiceImpl implements DeleteSqlService { + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Override + public String getDatasourceType() { + return DatasourceType.ES.getName(); + } + + @Override + public String getOperateType() { + return OperateType.DELETE.getName(); + } + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) { + Long result = 0l; + try { + DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(apiInfoDetailDto.getMainTableName()); + BoolQueryBuilder boolQueryBuilder = EsQueryHelpService.generateQuery(apiInfoDetailDto.getParams()); + deleteByQueryRequest.setQuery(boolQueryBuilder); + BulkByScrollResponse bulkByScrollResponse = dataSourceHelp.getRestHighLevelClient(apiInfoDetailDto.getDatasourceDto()). + deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT); + result = bulkByScrollResponse.getTotal(); + } catch (Exception e) { + log.error("es delete异常 errMsg:{}", e.getMessage()); + } + return result; + } +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/EsInsertServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/EsInsertServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..08a2310a5bbe76607d97723caa96f9679dbd746c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/EsInsertServiceImpl.java @@ -0,0 +1,70 @@ +package com.xforwardai.superdata.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiParamDto; +import com.xforwardai.superdata.service.InsertSqlService; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.action.bulk.BulkRequest; +import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.index.IndexRequest; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.xcontent.XContentType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.EsInsertServiceImpl.java + * @date: 2022/3/10 18:13 + * @author xujian + */ +@Service +@Slf4j +public class EsInsertServiceImpl implements InsertSqlService { + + @Override + public String getDatasourceType() { + return DatasourceType.ES.getName(); + } + + @Override + public String getOperateType() { + return OperateType.INSERT.getName(); + } + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) { + Integer result = 0; + List params = apiInfoDetailDto.getParams(); + String[] fieldValue = params.get(0).getParamValue().toString().split(CommonConstant.FIELD_VALUE_SPLICE_LIST); + BulkRequest request = new BulkRequest(); + for (int i = 0; i < fieldValue.length; i++) { + JSONObject jsonObject = new JSONObject(); + for (ApiParamDto param : params) { + String[] split = param.getParamValue().toString().split(CommonConstant.FIELD_VALUE_SPLICE_LIST); + jsonObject.put(param.getParamTableFieldName().split("\\.")[1], split[i]); + } + IndexRequest indexRequest = new IndexRequest(apiInfoDetailDto.getMainTableName(), CommonConstant.ES_DOC).source(jsonObject, XContentType.JSON); + request.add(indexRequest); + } + + try { + RestHighLevelClient restHighLevelClient = dataSourceHelp.getRestHighLevelClient(apiInfoDetailDto.getDatasourceDto()); + BulkResponse bulk = restHighLevelClient.bulk(request); + result = bulk.getItems() == null ? 0 : bulk.getItems().length; + } catch (Exception e) { + log.error("es insert异常 errMsg:{}", e.getMessage()); + } + return result; + } +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/EsQueryHelpService.java b/src/main/java/com/xforwardai/superdata/service/impl/EsQueryHelpService.java new file mode 100644 index 0000000000000000000000000000000000000000..a561a09cfb55660b8d43ef02e1a13777d44022e5 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/EsQueryHelpService.java @@ -0,0 +1,44 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.enums.ConditionType; +import com.xforwardai.superdata.mysql.entity.dto.ApiParamDto; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.EsQueryHelpService.java + * @date: 2022/6/28 14:40 + * @author xujian + */ +public class EsQueryHelpService { + + public static BoolQueryBuilder generateQuery(List params) { + BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); + if (!CollectionUtils.isEmpty(params)) { + params.forEach(param -> { + if (null == param.getIsUpdate() || 1 != param.getIsUpdate()) { + String paraTableField = param.getParamTableFieldName().split("\\.")[1]; + if (ConditionType.EQ.getType() == param.getConditionType()) { + boolQueryBuilder.must(QueryBuilders.termQuery(paraTableField, param.getParamValue())); + } else if (ConditionType.GE.getType() == param.getConditionType()) { + boolQueryBuilder.must(QueryBuilders.rangeQuery(paraTableField).gt(param.getParamValue())); + } else if (ConditionType.GEQ.getType() == param.getConditionType()) { + boolQueryBuilder.must(QueryBuilders.rangeQuery(paraTableField).gte(param.getParamValue())); + } else if (ConditionType.LE.getType() == param.getConditionType()) { + boolQueryBuilder.must(QueryBuilders.rangeQuery(paraTableField).lt(param.getParamValue())); + } else if (ConditionType.LEQ.getType() == param.getConditionType()) { + boolQueryBuilder.must(QueryBuilders.rangeQuery(paraTableField).lte(param.getParamValue())); + } else if (ConditionType.LIKE.getType() == param.getConditionType()) { + boolQueryBuilder.must(QueryBuilders.wildcardQuery(paraTableField, "*" + param.getParamValue() + "*")); + } + } + }); + } + return boolQueryBuilder; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/EsQueryServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/EsQueryServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a4fb417985b2d29bc8398a1dc79225e7b9e7cdc8 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/EsQueryServiceImpl.java @@ -0,0 +1,208 @@ +package com.xforwardai.superdata.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.carrotsearch.hppc.cursors.ObjectObjectCursor; +import com.xforwardai.superdata.base.BasePageResultVo; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.handler.SqlHandler; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiResultDto; +import com.xforwardai.superdata.mysql.entity.dto.TableFieldDto; +import com.xforwardai.superdata.service.QuerySqlService; +import com.xforwardai.superdata.util.EsSqlUtil; +import com.xforwardai.superdata.util.PageUtil; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; +import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; +import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; +import org.elasticsearch.client.*; +import org.elasticsearch.cluster.metadata.AliasMetaData; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.EsQueryServiceImpl.java + * @date: 2022/3/2 15:11 + * @author xujian + */ +@Service +@Slf4j +public class EsQueryServiceImpl implements QuerySqlService { + + private final static String ES_MAPPING_PROPERTIES = "properties"; + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Autowired + private SqlHandler sqlHandler; + + @Override + public String getDatasourceType() { + return DatasourceType.ES.getName(); + } + + @Override + public String getOperateType() { + return OperateType.QUERY.getName(); + } + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) throws ApplicationException { + Object executeResult = null; + + String sql = sqlHandler.generateSql(apiInfoDetailDto); + + ApiDatasourceDto datasourceDto = apiInfoDetailDto.getDatasourceDto(); + if (null == datasourceDto) { + throw new ApplicationException(ResultCode.FAIL_CODE, "数据源获取异常"); + } + RestHighLevelClient restHighLevelClient = dataSourceHelp.getRestHighLevelClient(datasourceDto); + JSONObject jsonObject = new JSONObject(); + jsonObject.put("query", sql); + int fetchSize = 1; + if (0 != apiInfoDetailDto.getResultType()) { + fetchSize = 10000; + } + jsonObject.put("fetch_size", fetchSize); + Request request = new Request("GET", "_sql"); + request.setJsonEntity(jsonObject.toJSONString()); + + try { + Response response = restHighLevelClient.getLowLevelClient().performRequest(request); + InputStream inputStream = response.getEntity().getContent(); + String result = new BufferedReader(new InputStreamReader(inputStream)) + .lines().collect(Collectors.joining(System.lineSeparator())); + JSONObject apiResultObj = JSONObject.parseObject(result); + + JSONArray rows = apiResultObj.getJSONArray("rows"); + List results = apiInfoDetailDto.getResults(); + if (CommonConstant.API_DATA_RESULT_ARR == apiInfoDetailDto.getResultType()) { + JSONArray array = new JSONArray(); + rows.forEach(item -> { + JSONObject obj = handlerEsRow(item, results); + array.add(obj); + }); + executeResult = array; + } else if (CommonConstant.API_DATA_RESULT_PAGE == apiInfoDetailDto.getResultType()) { + BasePageResultVo pageResultVo = new BasePageResultVo(); + JSONArray array = new JSONArray(); + rows.forEach(item -> { + JSONObject obj = handlerEsRow(item, results); + array.add(obj); + }); + pageResultVo.setPage(apiInfoDetailDto.getPage()); + pageResultVo.setSize(apiInfoDetailDto.getSize()); + List page = PageUtil.page(array, apiInfoDetailDto.getPage(), apiInfoDetailDto.getSize()); + pageResultVo.setContent(page); + executeResult = pageResultVo; + } else if (CommonConstant.API_DATA_RESULT_SINGLE == apiInfoDetailDto.getResultType() && rows.size() > 0) { + executeResult = handlerEsRow(rows.get(0), results); + } + } catch (Exception e) { + log.error("es executeQuery执行异常 errMsg:{}", e.getMessage()); + } + return executeResult; + } + + private JSONObject handlerEsRow(Object item, List results) { + JSONObject obj = new JSONObject(); + for (int i = 0; i < results.size(); i++) { + obj.put(results.get(i).getResultName(), ((JSONArray) item).get(i)); + } + return obj; + } + + @Override + public List testSourceConnect(ApiDatasourceDto apiDatasourceDto) { + try { + RestHighLevelClient restHighLevelClient = dataSourceHelp.getRestHighLevelClient(apiDatasourceDto, Boolean.FALSE); + GetAliasesResponse alias = restHighLevelClient.indices().getAlias(new GetAliasesRequest(), RequestOptions.DEFAULT); + System.out.println(alias); + } catch (Exception e) { + throw new ApplicationException(ResultCode.FAIL_CODE, "数据库连接异常 msg:" + e.getMessage()); + } + return null; + } + + @Override + public Set getTables(ApiDatasourceDto apiDatasourceDto) { + Set result = new LinkedHashSet<>(); + try { + RestHighLevelClient restHighLevelClient = dataSourceHelp.getRestHighLevelClient(apiDatasourceDto); + GetAliasesResponse alias = restHighLevelClient.indices().getAlias(new GetAliasesRequest(), RequestOptions.DEFAULT); + Map> aliases = alias.getAliases(); + if (null != aliases && aliases.size() > 0) { + aliases.keySet().forEach(key -> { + if (!CollectionUtils.isEmpty(aliases.get(key))) { + aliases.get(key).forEach(s -> { + result.add(s.alias()); + }); + } else { + result.add(key); + } + }); + } + } catch (Exception e) { + log.error("获取表列表异常 errMsg:{}", e.getMessage()); + } + return result; + } + + @Override + public List getTableFields(ApiDatasourceDto apiDatasourceDto, String tableName) { + List result = new ArrayList<>(); + try { + RestHighLevelClient restHighLevelClient = dataSourceHelp.getRestHighLevelClient(apiDatasourceDto); + GetMappingsRequest getMappingsRequest = new GetMappingsRequest(); + getMappingsRequest.indices(tableName).types(new String[0]); + IndicesClient index = restHighLevelClient.indices(); + GetMappingsResponse response = index.getMapping(getMappingsRequest, RequestOptions.DEFAULT); + + ImmutableOpenMap> mappingsByIndex = response.getMappings(); + for (ObjectObjectCursor> indexEntry : mappingsByIndex) { + if (indexEntry.value.isEmpty()) { + continue; + } + log.info("es索引名称:{}", indexEntry.key); + LinkedHashMap properties = (LinkedHashMap) indexEntry.value.get(CommonConstant.ES_DOC).getSourceAsMap().get(ES_MAPPING_PROPERTIES); + properties.keySet().forEach(key -> { + TableFieldDto tableFieldDto = new TableFieldDto(); + tableFieldDto.setFieldName(String.valueOf(key)); + LinkedHashMap o = (LinkedHashMap) properties.get(key); + Object type = o.get("type"); + if (ObjectUtil.isNotNull(type)) { + tableFieldDto.setFieldType(String.valueOf(type)); + } else { + tableFieldDto.setFieldType(String.valueOf(properties.get(key))); + } + result.add(tableFieldDto); + }); + break; + } + } catch (Exception e) { + log.error("获取es表字段异常异常 errMsg:{}", e.getMessage()); + } + return result; + } + + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/EsUpdateServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/EsUpdateServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..62e940f4356d4bb7c1f18b941696fe94a9be9c54 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/EsUpdateServiceImpl.java @@ -0,0 +1,81 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiParamDto; +import com.xforwardai.superdata.service.UpdateSqlService; +import com.xforwardai.superdata.util.CommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.elasticsearch.client.RequestOptions; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.QueryBuilders; +import org.elasticsearch.index.reindex.BulkByScrollResponse; +import org.elasticsearch.index.reindex.BulkByScrollTask; +import org.elasticsearch.index.reindex.UpdateByQueryRequest; +import org.elasticsearch.script.Script; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.EsUpdateServiceImpl.java + * @date: 2022/6/24 17:10 + * @author xujian + */ +@Service +@Slf4j +public class EsUpdateServiceImpl implements UpdateSqlService { + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Override + public String getDatasourceType() { + return DatasourceType.ES.getName(); + } + + @Override + public String getOperateType() { + return OperateType.UPDATE.getName(); + } + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) { + Long result = 0l; + try { + UpdateByQueryRequest updateQuery = new UpdateByQueryRequest(apiInfoDetailDto.getMainTableName()); + List params = apiInfoDetailDto.getParams(); + BoolQueryBuilder boolQueryBuilder = EsQueryHelpService.generateQuery(apiInfoDetailDto.getParams()); + StringBuffer sb = new StringBuffer(); + params.forEach(item -> { + String fieldName = item.getParamTableFieldName().split("\\.")[1]; + if (1 == item.getIsUpdate()) { + if (CommonUtil.hasCastString(item.getParamJavaType())) { + sb.append("ctx._source.").append(fieldName).append("=").append("'").append(item.getParamValue()).append("'").append(";"); + } else { + sb.append("ctx._source.").append(fieldName).append("=").append(item.getParamValue()).append(";"); + } + } + }); + updateQuery.setQuery(boolQueryBuilder); + updateQuery.setScript(new Script(sb.toString())); + RestHighLevelClient restHighLevelClient = dataSourceHelp.getRestHighLevelClient(apiInfoDetailDto.getDatasourceDto()); + BulkByScrollResponse response = restHighLevelClient.updateByQuery(updateQuery, RequestOptions.DEFAULT); + BulkByScrollTask.Status status = response.getStatus(); + result = status.getTotal(); + } catch (Exception e) { + log.error("es更新异常 errMsg:{}", e.getMessage()); + } + + log.info("es update {} 条数据", result); + return result; + } + + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/MysqlDeleteSqlServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/MysqlDeleteSqlServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..314627cb7d19cde573581efd8e5b4059252ce73f --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/MysqlDeleteSqlServiceImpl.java @@ -0,0 +1,78 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.handler.SqlHandler; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.service.DeleteSqlService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.Statement; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.MysqlDeleteSqlServiceImpl.java + * @date: 2022/6/23 14:22 + * @author xujian + */ +@Service +@Slf4j +public class MysqlDeleteSqlServiceImpl implements DeleteSqlService { + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Autowired + private SqlHandler sqlHandler; + + @Override + public String getDatasourceType() { + return DatasourceType.MYSQL.getName(); + } + + @Override + public String getOperateType() { + return OperateType.DELETE.getName(); + } + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) { + Integer updateNum = 0; + ApiDatasourceDto datasourceDto = apiInfoDetailDto.getDatasourceDto(); + if (null == datasourceDto) { + throw new ApplicationException(ResultCode.FAIL_CODE, "数据源获取异常"); + } + Connection connect = dataSourceHelp.getConnect(datasourceDto); + Statement statement = null; + String deleteSql = sqlHandler.generateDeleteSql(apiInfoDetailDto); + try { + statement = connect.createStatement(); + statement.execute("use " + apiInfoDetailDto.getDatabaseName()); + statement.execute(deleteSql); + updateNum = statement.getUpdateCount(); + } catch (Exception e) { + log.error("mysql delete异常 errMsg:{}", e.getMessage()); + } finally { + try { + if (null != statement) { + statement.close(); + } + if (null != connect) { + connect.close(); + } + } catch (Exception e) { + log.error("关流异常 errMsg:{}", e.getMessage()); + } + } + log.info("mysql delete {} 条数据", updateNum); + return updateNum; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/MysqlInsertSqlServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/MysqlInsertSqlServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..3d36eba82b72312160071ac80b37c5a5e798018e --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/MysqlInsertSqlServiceImpl.java @@ -0,0 +1,82 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.handler.SqlHandler; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiParamDto; +import com.xforwardai.superdata.service.InsertSqlService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.Statement; +import java.util.List; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.MysqlInsertSqlServiceImpl.java + * @date: 2022/3/10 18:13 + * @author xujian + */ +@Service +@Slf4j +public class MysqlInsertSqlServiceImpl implements InsertSqlService { + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Autowired + private SqlHandler sqlHandler; + + @Override + public String getDatasourceType() { + return DatasourceType.MYSQL.getName(); + } + + @Override + public String getOperateType() { + return OperateType.INSERT.getName(); + } + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) { + Integer result = 0; + ApiDatasourceDto datasourceDto = apiInfoDetailDto.getDatasourceDto(); + if (null == datasourceDto) { + throw new ApplicationException(ResultCode.FAIL_CODE, "数据源获取异常"); + } + Connection connect = dataSourceHelp.getConnect(datasourceDto); + Statement statement = null; + String insertSql = sqlHandler.generateInsertSql(apiInfoDetailDto); + try { + statement = connect.createStatement(); + statement.execute("use " + apiInfoDetailDto.getDatabaseName()); + statement.execute(insertSql); + result = statement.getUpdateCount(); + } catch (Exception e) { + log.error("mysql insert异常 errMsg:{}", e.getMessage()); + } finally { + try { + if (null != statement) { + statement.close(); + } + if (null != connect) { + connect.close(); + } + } catch (Exception e) { + log.error("关流异常 errMsg:{}", e.getMessage()); + } + } + log.info("mysql insert {} 条数据", result); + return result; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/MysqlQuerySqlServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/MysqlQuerySqlServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..e45e641856bb31f613768aaf3fd2d00f2a6b3ee0 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/MysqlQuerySqlServiceImpl.java @@ -0,0 +1,187 @@ +package com.xforwardai.superdata.service.impl; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.xforwardai.superdata.base.BasePageResultVo; +import com.xforwardai.superdata.constants.CommonConstant; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.handler.SqlHandler; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiResultDto; +import com.xforwardai.superdata.mysql.entity.dto.TableFieldDto; +import com.xforwardai.superdata.service.QuerySqlService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.MysqlExecuteSqlServiceImpl.java + * @date: 2022/3/2 15:02 + * @author xujian + */ +@Service +@Slf4j +public class MysqlQuerySqlServiceImpl implements QuerySqlService { + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Autowired + private SqlHandler sqlHandler; + + @Override + public String getDatasourceType() { + return DatasourceType.MYSQL.getName(); + } + + @Override + public String getOperateType() { + return OperateType.QUERY.getName(); + } + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) throws ApplicationException { + String sql = sqlHandler.generateSql(apiInfoDetailDto); + + ApiDatasourceDto datasourceDto = apiInfoDetailDto.getDatasourceDto(); + if (null == datasourceDto) { + throw new ApplicationException(ResultCode.FAIL_CODE, "数据源获取异常"); + } + Connection connect = dataSourceHelp.getConnect(datasourceDto); + Statement statement = null; + JSONArray result = new JSONArray(); + BasePageResultVo pageResultVo = new BasePageResultVo(); + try { + statement = connect.createStatement(); + statement.execute("use " + apiInfoDetailDto.getDatabaseName()); + if (CommonConstant.API_DATA_RESULT_PAGE == apiInfoDetailDto.getResultType()) { + String countSql = sqlHandler.generateCountSql(apiInfoDetailDto); + ResultSet countResult = statement.executeQuery(countSql); + while (countResult.next()) { + int count = countResult.getInt(1); + pageResultVo.setTotal(count); + pageResultVo.setPage(apiInfoDetailDto.getPage()); + pageResultVo.setSize(apiInfoDetailDto.getSize()); + } + } + ResultSet resultSet = statement.executeQuery(sql); + while (resultSet.next()) { + JSONObject jsonObject = new JSONObject(); + List results = apiInfoDetailDto.getResults(); + results.forEach(r -> { + try { + String value = resultSet.getString(r.getResultName()); + jsonObject.put(r.getResultName(), value); + } catch (Exception e) { + log.error("字段赋值异常 errMsg:{}", e.getMessage()); + } + }); + result.add(jsonObject); + } + } catch (Exception e) { + log.error("mysql执行sql异常 errMsg:{}", e.getMessage()); + } finally { + try { + if (null != statement) { + statement.close(); + } + if (null != connect) { + connect.close(); + } + } catch (Exception e) { + log.error("关流异常 errMsg:{}", e.getMessage()); + } + } + if (CommonConstant.API_DATA_RESULT_ARR == apiInfoDetailDto.getResultType()) { + return result; + } else if (CommonConstant.API_DATA_RESULT_PAGE == apiInfoDetailDto.getResultType()) { + pageResultVo.setContent(result); + return pageResultVo; + } else if (CommonConstant.API_DATA_RESULT_SINGLE == apiInfoDetailDto.getResultType() + && result.size() > 0) { + return result.get(0); + } + return null; + } + + @Override + public List testSourceConnect(ApiDatasourceDto apiDatasourceDto) throws ApplicationException { + List result = new ArrayList<>(); + Connection connect = null; + Statement statement = null; + try { + connect = dataSourceHelp.getConnect(apiDatasourceDto); + statement = connect.createStatement(); + ResultSet resultSet = statement.executeQuery("show databases"); + while (resultSet.next()) { + String databaseName = resultSet.getString("Database"); + result.add(databaseName); + } + } catch (Exception e) { + throw new ApplicationException(ResultCode.FAIL_CODE, "数据库连接异常 msg:" + e.getMessage()); + } finally { + dataSourceHelp.close(statement, connect); + } + return result; + } + + @Override + public Set getTables(ApiDatasourceDto apiDatasourceDto) { + Set result = new LinkedHashSet<>(); + Statement statement = null; + Connection connect = null; + try { + connect = dataSourceHelp.getConnect(apiDatasourceDto); + statement = connect.createStatement(); + statement.execute("use " + apiDatasourceDto.getDatabaseName()); + ResultSet resultSet = statement.executeQuery("show tables"); + while (resultSet.next()) { + String databaseName = resultSet.getString("tables_in_" + apiDatasourceDto.getDatabaseName()); + result.add(databaseName); + } + } catch (Exception e) { + log.error("获取表列表异常 errMsg:{}", e.getMessage()); + } finally { + dataSourceHelp.close(statement, connect); + } + return result; + } + + public List getTableFields(ApiDatasourceDto apiDatasourceDto, String tableName) { + List result = new ArrayList<>(); + Statement statement = null; + Connection connect = null; + try { + connect = dataSourceHelp.getConnect(apiDatasourceDto); + statement = connect.createStatement(); + statement.execute("use " + apiDatasourceDto.getDatabaseName()); + ResultSet resultSet = statement.executeQuery("show full columns from " + tableName); + while (resultSet.next()) { + TableFieldDto fieldDto = new TableFieldDto(); + String fieldName = resultSet.getString("Field"); + String fieldType = resultSet.getString("Type"); + fieldDto.setFieldName(fieldName); + fieldDto.setFieldType(fieldType); + result.add(fieldDto); + } + } catch (Exception e) { + log.error("获取字段列表异常 errMsg:{}", e.getMessage()); + } + return result; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/MysqlUpdateSqlServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/MysqlUpdateSqlServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..5400d969f75111ea6c654d5308fd1ee804090ebd --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/MysqlUpdateSqlServiceImpl.java @@ -0,0 +1,78 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.dds.DataSourceHelp; +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.handler.SqlHandler; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.service.UpdateSqlService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.sql.Connection; +import java.sql.Statement; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.MysqlUpdateSqlServiceImpl.java + * @date: 2022/6/23 11:06 + * @author xujian + */ +@Service +@Slf4j +public class MysqlUpdateSqlServiceImpl implements UpdateSqlService { + + @Autowired + private DataSourceHelp dataSourceHelp; + + @Autowired + private SqlHandler sqlHandler; + + @Override + public String getDatasourceType() { + return DatasourceType.MYSQL.getName(); + } + + @Override + public String getOperateType() { + return OperateType.UPDATE.getName(); + } + + @Override + public Object execute(ApiInfoDetailDto apiInfoDetailDto) { + Integer updateNum = 0; + ApiDatasourceDto datasourceDto = apiInfoDetailDto.getDatasourceDto(); + if (null == datasourceDto) { + throw new ApplicationException(ResultCode.FAIL_CODE, "数据源获取异常"); + } + Connection connect = dataSourceHelp.getConnect(datasourceDto); + Statement statement = null; + String updateSql = sqlHandler.generateUpdateSql(apiInfoDetailDto); + try { + statement = connect.createStatement(); + statement.execute("use " + apiInfoDetailDto.getDatabaseName()); + statement.execute(updateSql); + updateNum = statement.getUpdateCount(); + } catch (Exception e) { + log.error("mysql update异常 errMsg:{}", e.getMessage()); + } finally { + try { + if (null != statement) { + statement.close(); + } + if (null != connect) { + connect.close(); + } + } catch (Exception e) { + log.error("关流异常 errMsg:{}", e.getMessage()); + } + } + log.info("mysql update{}条数据", updateNum); + return updateNum; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/QuerySqlServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/QuerySqlServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..fb2f96d76063ee7114e7806d6523724a4d94f3e0 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/QuerySqlServiceImpl.java @@ -0,0 +1,44 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.dto.ApiDatasourceDto; +import com.xforwardai.superdata.mysql.entity.dto.TableFieldDto; +import com.xforwardai.superdata.service.QuerySqlService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @Description: 环境策略类 + * @ClassName: com.xforwardai.superdata.service.impl.SqlServiceImpl.java + * @date: 2022/3/7 10:51 + * @author xujian + */ +@Service +public class QuerySqlServiceImpl { + + Map executeSqlServiceMap = new HashMap<>(); + + @Autowired + public QuerySqlServiceImpl(List executeSqlServiceList) { + executeSqlServiceList.forEach(item -> executeSqlServiceMap.put(item.getDatasourceType(), item)); + } + + public List testSourceConnect(ApiDatasourceDto apiDatasourceDto) throws ApplicationException { + return executeSqlServiceMap.get(DatasourceType.getNameByType(apiDatasourceDto.getType())).testSourceConnect(apiDatasourceDto); + } + + public Set getTables(ApiDatasourceDto apiDatasourceDto) { + return executeSqlServiceMap.get(DatasourceType.getNameByType(apiDatasourceDto.getType())).getTables(apiDatasourceDto); + } + + public List getTableFields(ApiDatasourceDto apiDatasourceDto, String tableName) { + return executeSqlServiceMap.get(DatasourceType.getNameByType(apiDatasourceDto.getType())).getTableFields(apiDatasourceDto, tableName); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/service/impl/SqlServiceImpl.java b/src/main/java/com/xforwardai/superdata/service/impl/SqlServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..369fa0dc46c2fc05bb3d3090968110fb3a4c0361 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/service/impl/SqlServiceImpl.java @@ -0,0 +1,36 @@ +package com.xforwardai.superdata.service.impl; + +import com.xforwardai.superdata.enums.DatasourceType; +import com.xforwardai.superdata.enums.OperateType; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; +import com.xforwardai.superdata.service.SqlService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.service.impl.SqlServiceImpl.java + * @date: 2022/3/10 17:40 + * @author xujian + */ +@Service +public class SqlServiceImpl { + + Map sqlServiceMap = new HashMap<>(); + + @Autowired + public SqlServiceImpl(List executeSqlServiceList) { + executeSqlServiceList.forEach(item -> sqlServiceMap.put(item.getOperateType() + item.getDatasourceType(), item)); + } + + public Object execute(ApiInfoDetailDto apiInfoDetailDto) throws ApplicationException { + return sqlServiceMap.get(OperateType.getNameByType(apiInfoDetailDto.getOperateType()) + + DatasourceType.getNameByType(apiInfoDetailDto.getDatasourceType())).execute(apiInfoDetailDto); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/ApiUtil.java b/src/main/java/com/xforwardai/superdata/util/ApiUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..95dd57ea2f0fa214ff81a5113315288e4fd80b61 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/ApiUtil.java @@ -0,0 +1,19 @@ +package com.xforwardai.superdata.util; + +import com.xforwardai.superdata.mysql.entity.dto.ApiInfoDetailDto; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.util.ApiUtil.java + * @date: 2022/3/7 16:31 + * @author xujian + */ +public class ApiUtil { + + private final static String COLON = ":"; + + public static String getApiUrl(ApiInfoDetailDto apiInfoDetailDto) { + return apiInfoDetailDto.getMethod() + COLON + apiInfoDetailDto.getUrl(); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/BeanHelper.java b/src/main/java/com/xforwardai/superdata/util/BeanHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..9e3d6ff2b94c578cc060ca720aa8ec8c441b89bd --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/BeanHelper.java @@ -0,0 +1,111 @@ +package com.xforwardai.superdata.util; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeanUtils; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author Francis.Yang + */ +@Slf4j +public class BeanHelper { + + public static T copyProperties(Object source, Class target){ + try { + T t = target.newInstance(); + BeanUtils.copyProperties(source, t); + return t; + } catch (Exception e) { + log.error("【数据转换】数据转换出错,目标对象{}构造函数异常", target.getName(), e); + throw new RuntimeException("数据转换出错"); + } + } + + public static List copyWithCollection(List sourceList, Class target){ + try { + return sourceList.stream().map(s -> copyProperties(s, target)).collect(Collectors.toList()); + } catch (Exception e) { + log.error("【数据转换】数据转换出错,目标对象{}构造函数异常", target.getName(), e); + throw new RuntimeException("数据转换出错"); } + } + + public static Set copyWithCollection(Set sourceList, Class target){ + try { + return sourceList.stream().map(s -> copyProperties(s, target)).collect(Collectors.toSet()); + } catch (Exception e) { + log.error("【数据转换】数据转换出错,目标对象{}构造函数异常", target.getName(), e); + throw new RuntimeException("数据转换出错"); } + } + + + public static Map convertToMap(Object obj){ + if(obj == null) + return null; + Map map = new HashMap(); + try + { + BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); + PropertyDescriptor propertyDescriptors[] = beanInfo.getPropertyDescriptors(); + PropertyDescriptor apropertydescriptor[] = propertyDescriptors; + int i = apropertydescriptor.length; + for(int j = 0; j < i; j++){ + PropertyDescriptor property = apropertydescriptor[j]; + String key = property.getName(); + if(!key.equals("class")){ + Method getter = property.getReadMethod(); + Object value = getter.invoke(obj, new Object[0]); + map.put(key, value); + } + } + + } + catch(Exception e) + { + System.out.println((new StringBuilder()).append("transBean2Map Error ").append(e).toString()); + } + return map; + } + + + /** + * list的深拷贝 + * @param src + * @param + * @return + * @throws ClassNotFoundException + */ + public static List deepCopy(List src) { + try { + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(byteOut); + out.writeObject(src); + + ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); + ObjectInputStream in = new ObjectInputStream(byteIn); + @SuppressWarnings("unchecked") + List dest = (List) in.readObject(); + return dest; + } + catch (Exception e){ + e.printStackTrace(); + log.error("[{}]",e); + return null; + } + } + + +} diff --git a/src/main/java/com/xforwardai/superdata/util/BeanUtils.java b/src/main/java/com/xforwardai/superdata/util/BeanUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..35ab2453b63b8f069aae7ac3bc7e11a5fe14e6bf --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/BeanUtils.java @@ -0,0 +1,283 @@ +package com.xforwardai.superdata.util; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; + +/** + * @ClassName: BeanUtils + * @Description:(实体类赋值方法) + * @author: xujian + * @date: 2017年10月31日 下午2:46:58 + * @Copyright: 2017 + */ +@Slf4j +public class BeanUtils { + + /** + * @Title: toBean + * @Description: (反射实体类赋值targetMap里面可以互相转化的字段对应关系) + * @param @param filterBean + * @param @param targetBean + * @param @param paramMap + * @param @throws Exception 参数 + * @author xujian + * @return void 返回类型 + * @throws + */ + /*@SuppressWarnings("rawtypes") + public static void toBean(Object filterBean, Object targetBean, Map paramMap) throws Exception { + Class filterClass = Class.forName(filterBean.getClass().getName()); + Class targetClass = Class.forName(targetBean.getClass().getName()); + Field[] fields1 = filterClass.getDeclaredFields(); + Field[] fields2 = targetClass.getDeclaredFields(); + for (Field f1 : fields1) { + Object value = invokeGetMethod(filterBean, f1.getName(), null); + for (Field f2 : fields2) { + String f1GetName = paramMap.get(f1.getName()); + + if (StringUtils.isNotBlank(f1GetName)) { + if (f1GetName.equals(f2.getName())) { + Object[] obj = new Object[1]; + obj[0] = value; + if ("class java.util.Date".equals(f2.getType().toString())) { + Object[] obj2 = new Object[1]; + obj2[0] = DateUtil.convertStringToDate((String) value, CommonStatus.CONSTANT_DATE_FORMAT); + invokeSetMethod(targetBean, f2.getName(), obj2); + continue; + } + invokeSetMethod(targetBean, f2.getName(), obj); + } + } else { + if (f1.getName().equals(f2.getName())) { + Object[] obj = new Object[1]; + obj[0] = value; + if ("class java.util.Date".equals(f2.getType().toString()) + && "class java.lang.String".equals(f1.getType().toString())) { + Object[] obj2 = new Object[1]; + obj2[0] = DateUtil.convertStringToDate((String) value, CommonStatus.CONSTANT_DATE_FORMAT); + invokeSetMethod(targetBean, f2.getName(), obj2); + continue; + } + if ("class java.util.Date".equals(f1.getType().toString()) + && "class java.lang.String".equals(f2.getType().toString())) { + Object[] obj2 = new Object[1]; + obj2[0] = DateUtil.convertDateToString((Date) value, CommonStatus.CONSTANT_DATE_FORMAT); + invokeSetMethod(targetBean, f2.getName(), obj2); + continue; + } + invokeSetMethod(targetBean, f2.getName(), obj); + } + } + } + } + }*/ + + /** + * @Title: invokeGetMethod + * @Description: (执行某个Field的getField方法) + * @param @param filterBean + * @param @param fieldName + * @param @param args + * @param @return 参数 + * @author xujian + * @return Object 返回类型 + * @throws + */ + public static Object invokeGetMethod(Object filterBean, String fieldName, Object... args) { + String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); + Method method = null; + try { + Class[] parameterTypes = new Class[1]; + Class targetClass = Class.forName(filterBean.getClass().getName()); + Field field = null; + Boolean isParentFiled = false; + Class parentClass = null; + try { + field = targetClass.getDeclaredField(fieldName); + } catch (Exception e) { + log.warn("【{}未找到{}字段,去父类找】", targetClass.getName(), fieldName); + Class tempClass = targetClass; + while (tempClass != null) { + Field[] declaredFields = tempClass.getDeclaredFields(); + for (Field fieldItem : declaredFields) { + if (fieldName.equals(fieldItem.getName())) { + field = fieldItem; + isParentFiled = true; + parentClass = tempClass; + break; + } + } + tempClass = tempClass.getSuperclass(); + } + } + parameterTypes[0] = field.getType(); + if (isParentFiled && null != parentClass) { + method = parentClass.getDeclaredMethod("get" + methodName); + } else { + method = targetClass.getDeclaredMethod("get" + methodName); + } + return method.invoke(filterBean, args); + } catch (Exception e) { + log.error("【invokeGetMethod异常 errMsg:{}】", e.getMessage()); + } + return null; + } + + /** + * @Author xujian + * @Description 执行对象的某个方法 + * @Date 16:31 2021/3/23 + * @Param [bean, aClass, methodName, paramTypes, args] + * bean 对象, aClass 对象的Class,methodName 执行的方法名称,paramTypes 参数名称,args 具体参数 + * @return java.lang.Object + **/ + public static Object invokeGetMethod(Object bean, Class aClass, String methodName, Class paramTypes, Object... args) { + Method method = null; + try { + method = aClass.getDeclaredMethod(methodName, paramTypes); + return method.invoke(bean, args); + } catch (Exception e) { + e.printStackTrace(); + } + return method; + } + + /** + * @Title: invokeSetMethod + * @Description: (执行某个Field的setField方法) + * @param @param targetBean + * @param @param fieldName + * @param @param args 参数 + * @author xujian + * @return void 返回类型 + * @throws + */ + public static void invokeSetMethod(Object targetBean, String fieldName, Object... args) { + String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); + Method method = null; + try { + Class[] parameterTypes = new Class[1]; + Class targetClass = Class.forName(targetBean.getClass().getName()); + Field field = null; + Boolean isParentFiled = false; + Class parentClass = null; + try { + field = targetClass.getDeclaredField(fieldName); + } catch (Exception e) { + log.warn("【{}未找到{}字段,去父类找】", targetClass.getName(), fieldName); + Class tempClass = targetClass; + while (tempClass != null) { + Field[] declaredFields = tempClass.getDeclaredFields(); + for (Field fieldItem : declaredFields) { + if (fieldName.equals(fieldItem.getName())) { + field = fieldItem; + isParentFiled = true; + parentClass = tempClass; + break; + } + } + tempClass = tempClass.getSuperclass(); + } + } + + parameterTypes[0] = field.getType(); + if (isParentFiled && null != parentClass) { + method = parentClass.getDeclaredMethod("set" + methodName, parameterTypes); + } else { + method = targetClass.getDeclaredMethod("set" + methodName, parameterTypes); + } + if (null == args) { + if (parameterTypes[0].getName().equals("java.lang.String")) { + method.invoke(targetBean, ""); + } + if (parameterTypes[0].getName().equals("java.util.List")) { + method.invoke(targetBean, new ArrayList()); + } + } else { + method.invoke(targetBean, args); + } + } catch (Exception e) { + log.error("【invokeSetMethod异常 errMsg:{}】", e.getMessage()); + } + } + + /** + * @Title: invokeExampleEqualToSetMethod + * @Description: (执行某个Field的andFieldEqualTo方法) + * @param @param targetBean + * @param @param fieldName + * @param @param args 参数 + * @author xujian + * @return void 返回类型 + * @throws + */ + private static void invokeExampleEqualToSetMethod(Object targetBean, Field field, Object[] args) { + String fieldName = field.getName(); + String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); + Method method = null; + try { + Class[] parameterTypes = new Class[1]; + Class targetClass = Class.forName(targetBean.getClass().getName()); + parameterTypes[0] = field.getType(); + method = targetClass.getMethod("and" + methodName + "EqualTo", parameterTypes); + method.invoke(targetBean, args); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 将JSONObject转换成相应的实体工具类 + * @param bean + * @param obj + * @return 该实体类Object + * @throws Exception + * @author 叶森 + * @time 2018-01-27 + */ + public static T convertBeamByJSONObject(T bean, JSONObject obj) throws Exception { + Class c = Class.forName(bean.getClass().getName()); + Field[] field = c.getDeclaredFields(); + Object object = c.newInstance(); + for (Field f : field) { + String name = f.getName(); + String val = JsonUtil.getString(name, obj); + String methodStr = "set" + name.toUpperCase().substring(0, 1) + name.substring(1); + Method method = c.getMethod(methodStr, new Class[]{f.getType()}); + if ("String".equals(f.getType().getSimpleName())) { + method.invoke(object, val); + } else if ("Integer".equals(f.getType().getSimpleName())) { + method.invoke(object, Integer.parseInt(val)); + } + } + return (T) object; + } + + /** + * 实体类转换成example类(全是EqualTo条件) + * @param filterBean + * @param targetBean + * @author xujian + */ + public static void toBeanExampleEqualTo(Object filterBean, Object targetBean) { + try { + Class filterClass = Class.forName(filterBean.getClass().getName()); + Field[] fields1 = filterClass.getDeclaredFields(); + for (Field f1 : fields1) { + Object value = invokeGetMethod(filterBean, f1.getName(), null); + if (null != value) { + Object[] obj = new Object[1]; + obj[0] = value; + invokeExampleEqualToSetMethod(targetBean, f1, obj); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/BigDecimalUtil.java b/src/main/java/com/xforwardai/superdata/util/BigDecimalUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..7b5724a22542094a89fa9bb15f75084815425e02 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/BigDecimalUtil.java @@ -0,0 +1,27 @@ +package com.xforwardai.superdata.util; + +import java.math.BigDecimal; + +/** + * @ClassName com.xforwardai.operation.monitor.util.BigDecimalUtil.java + * @Author xujian + * @Description + * @CreateTime 2021年04月01日 13:59:00 + */ +public class BigDecimalUtil { + + public static BigDecimal divide(BigDecimal var1, BigDecimal divisor, int scale, int roundingMode) { + if(null != divisor && 0 != divisor.intValue()){ + return var1.divide(divisor,scale,roundingMode); + } + return BigDecimal.ZERO; + } + + public static BigDecimal dividePercent(BigDecimal var1, BigDecimal divisor, int scale, int roundingMode) { + if(null != divisor && 0 != divisor.intValue()){ + return var1.multiply(new BigDecimal(100)).divide(divisor,scale,roundingMode); + } + return BigDecimal.ZERO; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/CommonUtil.java b/src/main/java/com/xforwardai/superdata/util/CommonUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..823834234ad30ed9a02c7e31c0416861d0feb61c --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/CommonUtil.java @@ -0,0 +1,318 @@ +package com.xforwardai.superdata.util; + +import com.alibaba.fastjson.JSONObject; +import com.xforwardai.superdata.constants.CommonConstant; +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.util.StringUtils; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.TimeUnit; + +@Slf4j +public class CommonUtil { + + private final static char UNDERLINE = '_'; + + private static final String FORMAT_TIME_SHORT = "yyyy-MM-dd"; + + private static final String DATE_TIME_FOMART = "yyyy-MM-dd HH:mm:ss"; + + /** + * 校验关键字是否为18位身份证号 + * + * @param q + * @return + */ + public static Boolean matchQ(String q) { + String regex = "^[1-9]\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$"; + return q.matches(regex); + } + + /** + * 将驼峰转为下横线 + * 比如createBy ---> create_by + * + * @param param + * @return + */ + public static String camelToUnderline(String param) { + if (param == null || "".equals(param.trim())) { + return ""; + } + int len = param.length(); + StringBuilder sb = new StringBuilder(len); + for (int i = 0; i < len; i++) { + char c = param.charAt(i); + if (Character.isUpperCase(c)) { + sb.append(UNDERLINE); + sb.append(Character.toLowerCase(c)); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + + /** + * 第一个为大写 + * + * @param param + * @return + */ + public static String camelToUnderlineU(String param) { + if (param == null || "".equals(param.trim())) { + return ""; + } + int len = param.length(); + StringBuilder sb = new StringBuilder(len); + for (int i = 0; i < len; i++) { + char c = param.charAt(i); + if (Character.isUpperCase(c)) { + sb.append(UNDERLINE); + sb.append(Character.toLowerCase(c)); + } else { + sb.append(c); + } + } + return sb.toString().substring(1); + } + + + public static TimeUnit getTimeUtil(String type) { + if (StringUtils.isEmpty(type)) { + return TimeUnit.SECONDS; + } + TimeUnit result = null; + switch (type) { + case "S": + result = TimeUnit.SECONDS; + break; + case "M": + result = TimeUnit.MINUTES; + break; + case "H": + result = TimeUnit.HOURS; + break; + case "D": + result = TimeUnit.DAYS; + break; + default: + result = TimeUnit.SECONDS; + } + return result; + } + + /** + * 创建UUID + * + * @param withBreak + * @return + */ + public static String createUUID(boolean withBreak) { + String result = UUID.randomUUID().toString(); + if (!withBreak) { + result = result.replace("-", ""); + } + return result; + } + + + /** + * 时间调整 比如 输入 2020-05-01 5 结果是 2020-05-06 + * + * @param dataStr + * @param date + * @return + */ + public static String addDay(String dataStr, int date) { + if (StringUtils.isEmpty(dataStr)) { + return null; + } + SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_TIME_SHORT); + try { + Date dt = sdf.parse(dataStr); + Calendar rightNow = Calendar.getInstance(); + rightNow.setTime(dt); + rightNow.add(Calendar.DATE, date); + Date dt1 = rightNow.getTime(); + return sdf.format(dt1); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + + /** + * LocalDateTime 转 字符串 + * + * @param localDateTime + * @param formatString + * @return + */ + public static String localDateTimeToString(LocalDateTime localDateTime, String formatString) { + if (localDateTime == null) { + return null; + } + formatString = Strings.isBlank(formatString) ? DATE_TIME_FOMART : formatString; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatString); + return dateTimeFormatter.format(localDateTime); + } + + public static String localDateTimeToString(LocalDateTime localDateTime) { + if (localDateTime == null) { + return null; + } + String formatString = DATE_TIME_FOMART; + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatString); + return dateTimeFormatter.format(localDateTime); + } + + + public static String getYear(LocalDateTime localDateTime) { + if (Objects.nonNull(localDateTime)) { + return String.valueOf(localDateTime.getYear()); + } + return String.valueOf(LocalDateTime.now().getYear()); + } + + public static String getYear(String strTime) { + if (StringUtils.isEmpty(strTime)) { + return null; + } + return strTime.substring(0, 4); + } + + public static String getCurrentTimeStr() { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_FOMART); + return dateTimeFormatter.format(LocalDateTime.now()); + } + + public static String getCurrentShortTimeStr() { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(FORMAT_TIME_SHORT); + return dateTimeFormatter.format(LocalDateTime.now()); + } + + /** + * String 转 LocalDatetime + * + * @param timeStr + * @param formatString + * @return + */ + public static LocalDateTime stringToLocalDateTime(String timeStr, String formatString) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(Strings.isBlank(formatString) ? DATE_TIME_FOMART : formatString); + LocalDateTime result = LocalDateTime.parse(timeStr, dateTimeFormatter); + return result; + } + + /** + * localDateTime 转 时间戳 + * + * @param localDateTime + * @return + */ + public static long localDateTimeToTimestamp(LocalDateTime localDateTime) { + return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); + } + + public static String long2Str(Long timeStamp) { + SimpleDateFormat format = new SimpleDateFormat(DATE_TIME_FOMART); //设置格式 + return format.format(timeStamp); + } + + public static String long2Str(Date timeStamp) { + SimpleDateFormat format = new SimpleDateFormat(DATE_TIME_FOMART); //设置格式 + return format.format(timeStamp); + } + + + public static String contactObjs(Object... args) { + StringBuilder sb = new StringBuilder(); + for (Object obj : args) { + if (obj == null || StringUtils.isEmpty(obj.toString())) { + sb.append(":"); + } else { + sb.append(obj.toString()).append(":"); + } + } + String str = sb.toString(); + return str.length() > 0 ? str.substring(0, str.length() - 1) : str; + } + + public static V cloneFather(T from, V to, Class vClass) { + try { + return JSONObject.parseObject(JSONObject.toJSONString(from), vClass); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + + public static String upperHeadChar(String in) { + String head = in.substring(0, 1); + String out = head.toUpperCase() + in.substring(1, in.length()); + return out; + } + + public static Map convertBeanToMap(Object bean) { + try { + Class type = bean.getClass(); + Map returnMap = new HashMap(); + BeanInfo beanInfo = Introspector.getBeanInfo(type); + + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + for (int i = 0; i < propertyDescriptors.length; i++) { + PropertyDescriptor descriptor = propertyDescriptors[i]; + String propertyName = descriptor.getName(); + if (!propertyName.equals("class")) { + Method readMethod = descriptor.getReadMethod(); + Object result = readMethod.invoke(bean, new Object[0]); + if (result != null) { + returnMap.put(propertyName, result); + } else { + returnMap.put(propertyName, ""); + } + } + } + return returnMap; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static String getIpAddress() { + try { + // node7 服务器会报错 + String hostAddress = InetAddress.getLocalHost().getHostAddress(); + log.info("ip is :{}",hostAddress); + return hostAddress; + } catch (Exception e) { + log.error("IP地址获取失败" + e.toString()); + } + return ""; + } + + public static Boolean hasCastString(String param){ + Boolean result = Boolean.FALSE; + if(CommonConstant.STRING_STR.equalsIgnoreCase(param) || CommonConstant.DATE_STR.equalsIgnoreCase(param) ){ + result = Boolean.TRUE; + } + return result; + } + +} + diff --git a/src/main/java/com/xforwardai/superdata/util/DateUtils.java b/src/main/java/com/xforwardai/superdata/util/DateUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..94bec20b0f06542465f97fd1e259d1f4feb4e9d3 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/DateUtils.java @@ -0,0 +1,123 @@ +package com.xforwardai.superdata.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; +import org.springframework.util.StringUtils; + +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +@Slf4j +public class DateUtils { + + private final static String CONSTANT_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + public final static String CONSTANT_DATETIME_FORMAT_DAY = "yyyy-MM-dd"; + + public static String addDay(int num, String formatString) { + formatString = Strings.isBlank(formatString) ? "yyyy-MM-dd HH:mm:ss" : formatString; + SimpleDateFormat format = new SimpleDateFormat(formatString); + try { + Calendar c = Calendar.getInstance(); + c.add(Calendar.DATE, -num); + Date date = c.getTime(); + return format.format(date); + } catch (Exception e) { + log.error("时间解析异常"); + return null; + } + } + + public static String addDay(int num, int type, String formatString) { + formatString = Strings.isBlank(formatString) ? "yyyy-MM-dd HH:mm:ss" : formatString; + SimpleDateFormat format = new SimpleDateFormat(formatString); + try { + Calendar c = Calendar.getInstance(); + c.add(type, num); + Date date = c.getTime(); + return format.format(date); + } catch (Exception e) { + log.error("时间解析异常"); + return null; + } + } + + + /** + * date类型转换成String类型 + * + * @param date + * @param format + * @return + */ + public static String convertDateToString(Date date, String format) { + if (null == date) { + return null; + } + try { + if (StringUtils.isEmpty(format)) { + format = CONSTANT_DATETIME_FORMAT; + } + SimpleDateFormat dateFormat = new SimpleDateFormat(format); + return dateFormat.format(date); + } catch (Exception e) { + log.error("======= Date 转换 String异常 msg:{} =======",e.getMessage()); + return null; + } + } + + public static Date convertStringToDate(String time, String format){ + try { + if (StringUtils.isEmpty(format)) { + format = CONSTANT_DATETIME_FORMAT; + } + SimpleDateFormat dateFormat = new SimpleDateFormat(format); + return dateFormat.parse(time); + } catch (Exception e) { + log.error("======= String 转换 Date异常 msg:{} =======",e.getMessage()); + return null; + } + } + + /** + * @Author xujian + * @Description String 类型时间转换成LocalDataTime + * @Date 10:08 2020/9/4 + * @Param [time, format] + * @return java.time.LocalDateTime + **/ + public static LocalDateTime convertStringToDataTime(String time, String format){ + if (StringUtils.isEmpty(time)) { + return null; + } + try { + if (StringUtils.isEmpty(format)) { + format = CONSTANT_DATETIME_FORMAT; + } + + DateTimeFormatter df = DateTimeFormatter.ofPattern(format); + return LocalDateTime.parse(time,df); + } catch (Exception e) { + log.error("======= String 转换LocalDateTime异常 msg:{} =======",e.getMessage()); + return null; + } + } + + + public static List getRecentDayAsc(int day) { + Date now = new Date(); + Calendar instance = Calendar.getInstance(); + List result = new ArrayList<>(); + for (int i = day; i >= 1; i--) { + instance.setTime(now); + instance.add(Calendar.DAY_OF_MONTH, -i); + result.add(convertDateToString(instance.getTime(), CONSTANT_DATETIME_FORMAT_DAY)); + } + return result; + } +} diff --git a/src/main/java/com/xforwardai/superdata/util/EsSqlUtil.java b/src/main/java/com/xforwardai/superdata/util/EsSqlUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..67471c841cff032da7db7e458ef61dbf40a7f380 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/EsSqlUtil.java @@ -0,0 +1,30 @@ +package com.xforwardai.superdata.util; + + +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; +import org.elasticsearch.client.RestClient; + +import java.io.IOException; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.util.EsSqlUtil.java + * @date: 2022/3/3 15:00 + * @author xujian + */ +public class EsSqlUtil { + + public static JSONArray getListQuery(RestClient restClient, String sql) throws IOException { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("query", sql); + Request request = new Request("GET", "_sql"); + request.setJsonEntity(jsonObject.toJSONString(0)); + Response response = restClient.performRequest(request); + JSONObject apiResultObj = JSONUtil.parseObj(response); + return apiResultObj.getJSONArray("rows"); + } +} diff --git a/src/main/java/com/xforwardai/superdata/util/ExcelUtil.java b/src/main/java/com/xforwardai/superdata/util/ExcelUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..47717f15b8745003098f7ddf804f91fafb3a5cd7 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/ExcelUtil.java @@ -0,0 +1,662 @@ +package com.xforwardai.superdata.util; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.xforwardai.superdata.mysql.entity.dto.ExcelDataDto; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.*; +import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder; +import org.springframework.web.multipart.MultipartFile; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +@Slf4j +public class ExcelUtil { + + public static final String OFFICE_EXCEL_2003_POSTFIX = "xls"; + + public static final String OFFICE_EXCEL_2010_POSTFIX = "xlsx"; + + /** + * 获取合并单元格的值 + * + * @param sheet + * @param row + * @param column + * @return + */ + public String getMergedRegionValue(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress ca = sheet.getMergedRegion(i); + int firstColumn = ca.getFirstColumn(); + int lastColumn = ca.getLastColumn(); + int firstRow = ca.getFirstRow(); + int lastRow = ca.getLastRow(); + if (row >= firstRow && row <= lastRow) { + if (column >= firstColumn && column <= lastColumn) { + Row fRow = sheet.getRow(firstRow); + Cell fCell = fRow.getCell(firstColumn); + return getCellValue(fCell); + } + } + } + return null; + } + + /** + * 判断合并了行 + * + * @param sheet + * @param row + * @param column + * @return + */ + private boolean isMergedRow(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if (row == firstRow && row == lastRow) { + if (column >= firstColumn && column <= lastColumn) { + return true; + } + } + } + return false; + } + + /** + * 判断指定的单元格是否是合并单元格 + * + * @param sheet + * @param row 行下标 + * @param column 列下标 + * @return + */ + private boolean isMergedRegion(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if (row >= firstRow && row <= lastRow) { + if (column >= firstColumn && column <= lastColumn) { + return true; + } + } + } + return false; + } + + /** + * 判断sheet页中是否含有合并单元格 + * + * @param sheet + * @return + */ + private boolean hasMerged(Sheet sheet) { + return sheet.getNumMergedRegions() > 0 ? true : false; + } + + /** + * 合并单元格 + * + * @param sheet + * @param firstRow 开始行 + * @param lastRow 结束行 + * @param firstCol 开始列 + * @param lastCol 结束列 + */ + private void mergeRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) { + sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); + } + + /** + * 获取单元格的值 + * + * @param cell + * @return + */ + public String getCellValue(Cell cell) { + + if (cell == null) { + return ""; + } + + if (cell.getCellType() == Cell.CELL_TYPE_STRING) { + + return cell.getStringCellValue(); + + } else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) { + + return String.valueOf(cell.getBooleanCellValue()); + + } else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) { + + return cell.getCellFormula(); + + } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) { + + return String.valueOf(cell.getNumericCellValue()); + + } + return ""; + } + + /** + * 从excel读取内容 + */ + public static void readContent(String fileName) { + boolean isE2007 = false; //判断是否是excel2007格式 + if (fileName.endsWith("xlsx")) { + isE2007 = true; + } + try { + InputStream input = new FileInputStream(fileName); //建立输入流 + Workbook wb = null; + //根据文件格式(2003或者2007)来初始化 + if (isE2007) { + wb = new XSSFWorkbook(input); + } else { + wb = new HSSFWorkbook(input); + } + Sheet sheet = wb.getSheetAt(0); //获得第一个表单 + Iterator rows = sheet.rowIterator(); //获得第一个表单的迭代器 + while (rows.hasNext()) { + Row row = rows.next(); //获得行数据 + System.out.println("Row #" + row.getRowNum()); //获得行号从0开始 + Iterator cells = row.cellIterator(); //获得第一行的迭代器 + while (cells.hasNext()) { + Cell cell = cells.next(); + System.out.println("Cell #" + cell.getColumnIndex()); + switch (cell.getCellType()) { //根据cell中的类型来输出数据 + case HSSFCell.CELL_TYPE_NUMERIC: + System.out.println(cell.getNumericCellValue()); + break; + case HSSFCell.CELL_TYPE_STRING: + System.out.println(cell.getStringCellValue()); + break; + case HSSFCell.CELL_TYPE_BOOLEAN: + System.out.println(cell.getBooleanCellValue()); + break; + case HSSFCell.CELL_TYPE_FORMULA: + System.out.println(cell.getCellFormula()); + break; + default: + System.out.println("unsuported sell type=======" + cell.getCellType()); + break; + } + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + /** + * read the Excel .xlsx,.xls + * + * @param file jsp中的上传文件 + * @return + * @throws IOException + */ + public static List> readExcel(MultipartFile file, boolean readFirstSheet) throws IOException { + if (file == null || "".equals(file.getOriginalFilename().trim())) { + return null; + } else { + String postfix = getPostfix(file.getOriginalFilename()); + if (StringUtils.isNotEmpty(postfix)) { + if (OFFICE_EXCEL_2003_POSTFIX.equals(postfix)) { + return readXls(file, readFirstSheet); + } else if (OFFICE_EXCEL_2010_POSTFIX.equals(postfix)) { + return readXlsx(file, readFirstSheet); + } else { + return null; + } + } + } + return null; + } + + public static List> readExcel(MultipartFile file, Integer sheetNum) throws IOException { + if (file == null || "".equals(file.getOriginalFilename().trim())) { + return null; + } else { + String postfix = getPostfix(file.getOriginalFilename()); + if (StringUtils.isNotEmpty(postfix)) { + if (OFFICE_EXCEL_2003_POSTFIX.equals(postfix)) { + return readXls(file, sheetNum); + } else if (OFFICE_EXCEL_2010_POSTFIX.equals(postfix)) { + return readXlsx(file, sheetNum); + } else { + return null; + } + } + } + return null; + } + + public static List> readXls(MultipartFile file, Integer sheetNum) { + List> list = new ArrayList<>(); + // IO流读取文件 + InputStream input = null; + HSSFWorkbook wb = null; + ArrayList rowList = null; + try { + input = file.getInputStream(); + // 创建文档 + wb = new HSSFWorkbook(input); + sheetNum = sheetNum == null ? 1 : sheetNum; + //读取sheet(页) + HSSFSheet hssfSheet = wb.getSheetAt(sheetNum); + if (hssfSheet == null) { + return list; + } + int totalRows = hssfSheet.getLastRowNum(); + //读取Row,从第二行开始 + for (int rowNum = 1; rowNum <= totalRows; rowNum++) { + HSSFRow hssfRow = hssfSheet.getRow(rowNum); + if (hssfRow != null) { + rowList = new ArrayList<>(); + int totalCells = hssfRow.getLastCellNum(); + //读取列,从第一列开始 + for (short c = 0; c <= totalCells + 1; c++) { + HSSFCell cell = hssfRow.getCell(c); + if (cell == null) { + rowList.add(""); + continue; + } + rowList.add(getHValue(cell).trim()); + } + list.add(rowList); + } + } + } catch (IOException e) { + log.error("========== 导入xls文件出错 msg:{} ============", e.getMessage()); + e.printStackTrace(); + } finally { + try { + if (null != input) { + input.close(); + } + } catch (IOException e) { + log.error("========== 导入xls文件流关闭异常 msg:{} ============", e.getMessage()); + } + } + return list; + } + + /** + * read the Excel 2003-2007 .xls + * + * @param file + * @return + * @throws IOException + */ + public static List> readXls(MultipartFile file, boolean readFirstSheet) { + List> list = new ArrayList<>(); + // IO流读取文件 + InputStream input = null; + HSSFWorkbook wb = null; + ArrayList rowList = null; + try { + input = file.getInputStream(); + // 创建文档 + wb = new HSSFWorkbook(input); + int sheetNum = 1; + if (!readFirstSheet) { + sheetNum = wb.getNumberOfSheets(); + } + //读取sheet(页) + for (int numSheet = 0; numSheet < sheetNum; numSheet++) { + HSSFSheet hssfSheet = wb.getSheetAt(numSheet); + if (hssfSheet == null) { + continue; + } + int totalRows = hssfSheet.getLastRowNum(); + //读取Row,从第二行开始 + for (int rowNum = 1; rowNum <= totalRows; rowNum++) { + HSSFRow hssfRow = hssfSheet.getRow(rowNum); + if (hssfRow != null) { + rowList = new ArrayList<>(); + int totalCells = hssfRow.getLastCellNum(); + //读取列,从第一列开始 + for (short c = 0; c <= totalCells + 1; c++) { + HSSFCell cell = hssfRow.getCell(c); + if (cell == null) { + rowList.add(""); + continue; + } + rowList.add(getHValue(cell).trim()); + } + list.add(rowList); + } + } + } + + } catch (IOException e) { + log.error("========== 导入xls文件出错 msg:{} ============", e.getMessage()); + e.printStackTrace(); + } finally { + try { + if (null != input) { + input.close(); + } + } catch (IOException e) { + log.error("========== 导入xls文件流关闭异常 msg:{} ============", e.getMessage()); + } + } + return list; + } + + public static List> readXlsx(MultipartFile file, Integer sheetNum) { + List> list = new ArrayList<>(); + // IO流读取文件 + InputStream input = null; + XSSFWorkbook wb = null; + ArrayList rowList = null; + try { + input = file.getInputStream(); + // 创建文档 + wb = new XSSFWorkbook(input); + sheetNum = sheetNum == null ? 1 : sheetNum; + //读取sheet(页) + XSSFSheet xssfSheet = wb.getSheetAt(sheetNum); + if (xssfSheet == null) { + return list; + } + int totalRows = xssfSheet.getLastRowNum(); + //读取Row,从第二行开始 + for (int rowNum = 1; rowNum <= totalRows; rowNum++) { + XSSFRow xssfRow = xssfSheet.getRow(rowNum); + if (xssfRow != null) { + rowList = new ArrayList(); + int totalCells = xssfRow.getLastCellNum(); + //读取列,从第一列开始 + for (int c = 0; c <= totalCells + 1; c++) { + XSSFCell cell = xssfRow.getCell(c); + if (cell == null) { + rowList.add(""); + continue; + } + rowList.add(getXValue(cell).trim()); + } + list.add(rowList); + } else { + break; + } + } + } catch (IOException e) { + log.error("========== 导入xlsx文件出错 msg:{} ============", e.getMessage()); + } finally { + try { + if (null != input) { + input.close(); + } + } catch (IOException e) { + log.error("========== 导入xlsx文件流关闭异常 msg:{} ============", e.getMessage()); + } + } + return list; + } + + + /** + * read the Excel 2010 .xlsx + * + * @param file + * @return + * @throws IOException + */ + public static List> readXlsx(MultipartFile file, boolean readFirstSheet) { + List> list = new ArrayList<>(); + // IO流读取文件 + InputStream input = null; + XSSFWorkbook wb = null; + ArrayList rowList = null; + try { + input = file.getInputStream(); + // 创建文档 + wb = new XSSFWorkbook(input); + int sheetNum = 1; + if (!readFirstSheet) { + sheetNum = wb.getNumberOfSheets(); + } + + //读取sheet(页) + for (int numSheet = 0; numSheet < sheetNum; numSheet++) { + XSSFSheet xssfSheet = wb.getSheetAt(numSheet); + if (xssfSheet == null) { + continue; + } + int totalRows = xssfSheet.getLastRowNum(); + //读取Row,从第二行开始 + for (int rowNum = 1; rowNum <= totalRows; rowNum++) { + XSSFRow xssfRow = xssfSheet.getRow(rowNum); + if (xssfRow != null) { + rowList = new ArrayList(); + int totalCells = xssfRow.getLastCellNum(); + //读取列,从第一列开始 + for (int c = 0; c <= totalCells + 1; c++) { + XSSFCell cell = xssfRow.getCell(c); + if (cell == null) { + rowList.add(""); + continue; + } + rowList.add(getXValue(cell).trim()); + } + list.add(rowList); + } else { + break; + } + } + } + } catch (IOException e) { + log.error("========== 导入xlsx文件出错 msg:{} ============", e.getMessage()); + } finally { + try { + if (null != input) { + input.close(); + } + } catch (IOException e) { + log.error("========== 导入xlsx文件流关闭异常 msg:{} ============", e.getMessage()); + } + } + return list; + } + + public static String getHValue(HSSFCell hssfCell) { + if (hssfCell.getCellType() == HSSFCell.CELL_TYPE_BOOLEAN) { + return String.valueOf(hssfCell.getBooleanCellValue()); + } else if (hssfCell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) { + String cellValue = ""; + DecimalFormat df = new DecimalFormat("#.##"); + cellValue = df.format(hssfCell.getNumericCellValue()); + String strArr = cellValue.substring(cellValue.lastIndexOf(".") + 1, cellValue.length()); + if (strArr.equals("00")) { + cellValue = cellValue.substring(0, cellValue.lastIndexOf(".")); + } + return cellValue; + } else { + return String.valueOf(hssfCell.getStringCellValue()); + } + } + + /** + * 单元格格式 + * + * @param xssfCell + * @return + */ + public static String getXValue(XSSFCell xssfCell) { + if (xssfCell.getCellType() == Cell.CELL_TYPE_BOOLEAN) { + return String.valueOf(xssfCell.getBooleanCellValue()); + } else if (xssfCell.getCellType() == Cell.CELL_TYPE_NUMERIC) { + String cellValue = ""; + DecimalFormat df = new DecimalFormat("#.##"); + cellValue = df.format(xssfCell.getNumericCellValue()); + String strArr = cellValue.substring(cellValue.lastIndexOf(".") + 1, cellValue.length()); + if (strArr.equals("00")) { + cellValue = cellValue.substring(0, cellValue.lastIndexOf(".")); + } + return cellValue; + } else { + return String.valueOf(xssfCell.getStringCellValue()); + } + } + + public static String getPostfix(String path) { + if (StringUtils.isNotEmpty(path) && path.contains(".")) { + return path.substring(path.lastIndexOf(".") + 1, path.length()); + } + return ""; + } + + public static String exportExcel(ExcelDataDto data, String filePath) { + XSSFWorkbook wb = null; + FileOutputStream fileOutputStream = null; + try { + String sheetName = data.getName(); + if (null == sheetName) { + sheetName = "Sheet1"; + } + String filename = data.getFileName(); + wb = new XSSFWorkbook(); + XSSFSheet sheet = wb.createSheet(sheetName); + writeExcel(wb, sheet, data); + fileOutputStream = new FileOutputStream(filePath + "/" + filename); + wb.write(fileOutputStream); + } catch (Exception e) { + log.error("======= 报表导出异常 -> data:{},msg:{} =======", data, e.toString()); + } finally { + try { + if (null != fileOutputStream) { + fileOutputStream.close(); + } + if (null != wb) { + wb.close(); + } + } catch (Exception e) { + log.error("关流异常 errMsg:{}", e.getMessage()); + } + } + return filePath; + } + + public static XSSFWorkbook generateWb(ExcelDataDto data) { + XSSFWorkbook wb = null; + try { + String sheetName = data.getName(); + if (null == sheetName) { + sheetName = "Sheet1"; + } + wb = new XSSFWorkbook(); + XSSFSheet sheet = wb.createSheet(sheetName); + writeExcel(wb, sheet, data); + } catch (Exception e) { + log.error("获取wb异常 errMsg:{}", e.getMessage()); + } + return wb; + } + + public static void writeExcel(XSSFWorkbook wb, Sheet sheet, ExcelDataDto data) { + int rowIndex = 0; + rowIndex = writeTitlesToExcel(wb, sheet, data.getTitles(), rowIndex); + writeRowsToExcel(wb, sheet, data.getRows(), rowIndex); + autoSizeColumns(sheet, data.getTitles().size() + 1); + } + + private static void autoSizeColumns(Sheet sheet, int columnNumber) { + for (int i = 0; i < columnNumber; i++) { + int orgWidth = sheet.getColumnWidth(i); + sheet.autoSizeColumn(i, true); + int colWidth = sheet.getColumnWidth(i) * 2; + + sheet.setColumnWidth(i, 3500); + } + } + + private static int writeTitlesToExcel(XSSFWorkbook wb, Sheet sheet, List titles, int rowIndex) { + Font titleFont = wb.createFont(); + titleFont.setFontName("simsun"); + titleFont.setFontHeightInPoints((short) 14); + titleFont.setColor(IndexedColors.BLACK.index); + + XSSFCellStyle titleStyle = wb.createCellStyle(); + titleStyle.setFont(titleFont); + setBorder(titleStyle, BorderStyle.THIN, new XSSFColor(new java.awt.Color(0, 0, 0))); + Row titleRow = sheet.createRow(rowIndex); + int colIndex = 0; + for (String field : titles) { + Cell cell = titleRow.createCell(colIndex); + cell.setCellValue(field); + cell.setCellStyle(titleStyle); + colIndex++; + } + rowIndex++; + return rowIndex; + } + + private static int writeRowsToExcel(XSSFWorkbook wb, Sheet sheet, List> rows, int rowIndex) { + int colIndex = 0; + Font dataFont = wb.createFont(); + dataFont.setFontName("simsun"); + dataFont.setFontHeightInPoints((short) 14); + dataFont.setColor(IndexedColors.BLACK.index); + XSSFCellStyle dataStyle = wb.createCellStyle(); + dataStyle.setFont(dataFont); + setBorder(dataStyle, BorderStyle.THIN, new XSSFColor(new java.awt.Color(0, 0, 0))); + for (List rowData : rows) { + Row dataRow = sheet.createRow(rowIndex); + colIndex = 0; + for (Object cellData : rowData) { + Cell cell = dataRow.createCell(colIndex); + if (cellData != null) { + if (cellData instanceof Double) { + cell.setCellValue(((Double) cellData).doubleValue()); + } else { + cell.setCellValue(cellData.toString()); + } + + } else { + cell.setCellValue(""); + } + + cell.setCellStyle(dataStyle); + colIndex++; + } + rowIndex++; + } + return rowIndex; + } + + private static void setBorder(XSSFCellStyle style, BorderStyle border, XSSFColor color) { + style.setBorderTop(border); + style.setBorderLeft(border); + style.setBorderRight(border); + style.setBorderBottom(border); + style.setBorderColor(XSSFCellBorder.BorderSide.TOP, color); + style.setBorderColor(XSSFCellBorder.BorderSide.LEFT, color); + style.setBorderColor(XSSFCellBorder.BorderSide.RIGHT, color); + style.setBorderColor(XSSFCellBorder.BorderSide.BOTTOM, color); + } + +} \ No newline at end of file diff --git a/src/main/java/com/xforwardai/superdata/util/HttpClientUtil.java b/src/main/java/com/xforwardai/superdata/util/HttpClientUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..9baab713d843d755e2b030608859474e89f43838 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/HttpClientUtil.java @@ -0,0 +1,708 @@ +package com.xforwardai.superdata.util; + +/** + * Created by chenzy on 2017/7/15. + */ + +import com.alibaba.druid.util.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.*; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustSelfSignedStrategy; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.*; + +/** + * @author H__D + * @date 2016年10月19日 上午11:27:25 + * + */ +public class HttpClientUtil { + + // utf-8字符编码 + public static final String CHARSET_UTF_8 = "utf-8"; + + // HTTP内容类型。 + public static final String CONTENT_TYPE_TEXT_HTML = "text/xml"; + + // HTTP内容类型。相当于form表单的形式,提交数据 + public static final String CONTENT_TYPE_FORM_URL = "application/x-www-form-urlencoded"; + + // HTTP内容类型。相当于form表单的形式,提交数据 + public static final String CONTENT_TYPE_JSON_URL = "application/json;charset=utf-8"; + + // 连接管理器 + private static PoolingHttpClientConnectionManager pool; + + // 请求配置 + private static RequestConfig requestConfig; + + // 因为请求groupService的接口返回状态码大于300的时候没有返回信息,所以在这里定义一个失败的常量; + private static String Fail_Request = "{'request':'fail'}"; + + protected final static Logger log = LoggerFactory + .getLogger(HttpClientUtil.class); + + static { + + try { + SSLContextBuilder builder = new SSLContextBuilder(); + builder.loadTrustMaterial(null, new TrustSelfSignedStrategy()); + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory( + builder.build()); + // 配置同时支持 HTTP 和 HTPPS + Registry socketFactoryRegistry = RegistryBuilder + . create() + .register("http", + PlainConnectionSocketFactory.getSocketFactory()) + .register("https", sslsf).build(); + // 初始化连接管理器 + pool = new PoolingHttpClientConnectionManager(socketFactoryRegistry); + // 将最大连接数增加到200,实际项目最好从配置文件中读取这个值 + pool.setMaxTotal(200); + // 设置最大路由 + pool.setDefaultMaxPerRoute(2); + // 根据默认超时限制初始化requestConfig + int socketTimeout = 300000; + int connectTimeout = 300000; + int connectionRequestTimeout = 300000; + requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(connectionRequestTimeout) + .setSocketTimeout(socketTimeout) + .setConnectTimeout(connectTimeout).build(); + + } catch (NoSuchAlgorithmException e) { + log.error("The exception is:", e); + } catch (KeyStoreException e) { + log.error("The exception is:", e); + } catch (KeyManagementException e) { + log.error("The exception is:", e); + } + + // 设置请求超时时间 + requestConfig = RequestConfig.custom().setSocketTimeout(300000) + .setConnectTimeout(300000).setConnectionRequestTimeout(300000) + .build(); + } + + public static CloseableHttpClient getHttpClient() { + + CloseableHttpClient httpClient = HttpClients.custom() + // 设置连接池管理 + .setConnectionManager(pool) + // 设置请求配置 + .setDefaultRequestConfig(requestConfig) + // 设置重试次数 + .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false)) + .build(); + + return httpClient; + } + + /** + * 发送Post请求 + * + * @param httpPost + * @return + */ + private static String sendHttpPost(HttpPost httpPost) { + + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + // 响应内容 + String responseContent = null; + // 判断响应状态 + try { + // 创建默认的httpClient实例. + httpClient = getHttpClient(); + // 配置请求信息 + httpPost.setConfig(requestConfig); + // 执行请求 + response = httpClient.execute(httpPost); + // 得到响应实例 + HttpEntity entity = response.getEntity(); + + // 可以获得响应头 + // Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE); + // for (Header header : headers) { + // } + + // 得到响应类型 + responseContent = EntityUtils.toString(entity, CHARSET_UTF_8); + // 判断响应状态 + if (response.getStatusLine().getStatusCode() >= 300) { + log.error("======= httpclent返回的状态码大于等于300 ======="); + if (StringUtils.isEmpty(responseContent)){ + return Fail_Request; + } + } + if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) { + EntityUtils.consume(entity); + } + + } catch (Exception e) { + log.error("The exception is:", e); + } finally { + try { + // 释放资源 + if (response != null) { + response.close(); + } + } catch (IOException e) { + log.error("The exception is:", e); + } + } + return responseContent; + } + + /** + * 发送put请求 + * @param httpPut + * @return + */ + private static String sendHttpPut(HttpPut httpPut) { + + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + // 响应内容 + String responseContent = null; + try { + // 创建默认的httpClient实例. + httpClient = getHttpClient(); + // 配置请求信息 + httpPut.setConfig(requestConfig); + // 执行请求 + response = httpClient.execute(httpPut); + // 得到响应实例 + HttpEntity entity = response.getEntity(); + + // 可以获得响应头 + // Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE); + // for (Header header : headers) { + // } + + responseContent = EntityUtils.toString(entity, CHARSET_UTF_8); + // 判断响应状态 + if (response.getStatusLine().getStatusCode() >= 300) { + log.error("====== httpclent返回的状态码大于等于300 ======"); + if (StringUtils.isEmpty(responseContent)) { + return Fail_Request; + } + } + + if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) { + EntityUtils.consume(entity); + } + + } catch (Exception e) { + log.error("The exception is:", e); + } finally { + try { + // 释放资源 + if (response != null) { + response.close(); + } + } catch (IOException e) { + log.error("The exception is:", e); + } + } + return responseContent; + } + + /** + * 发送Get请求 + * + * @param httpGet + * @return + */ + private static String sendHttpGet(HttpGet httpGet) { + + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + // 响应内容 + String responseContent = null; + try { + // 创建默认的httpClient实例. + httpClient = getHttpClient(); + // 配置请求信息 + httpGet.setConfig(requestConfig); + // 执行请求 + response = httpClient.execute(httpGet); + // 得到响应实例 + HttpEntity entity = response.getEntity(); + + // 可以获得响应头 + // Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE); + // for (Header header : headers) { + // } + + responseContent = EntityUtils.toString(entity, CHARSET_UTF_8); + // 判断响应状态 + if (response.getStatusLine().getStatusCode() >= 300) { + throw new Exception( + "HTTP Request is not success, Response code is " + + response.getStatusLine().getStatusCode()); + } + + if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) { + EntityUtils.consume(entity); + } + + } catch (Exception e) { + log.error("The exception is:", e); + } finally { + try { + // 释放资源 + if (response != null) { + response.close(); + } + } catch (IOException e) { + log.error("The exception is:", e); + } + } + return responseContent; + } + + + /** + * 发送Delete请求 + * + * @param httpDelete + * @return + */ + private static String sendHttpDelete(HttpDelete httpDelete) { + + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + // 响应内容 + String responseContent = null; + try { + // 创建默认的httpClient实例. + httpClient = getHttpClient(); + // 配置请求信息 + httpDelete.setConfig(requestConfig); + // 执行请求 + response = httpClient.execute(httpDelete); + // 得到响应实例 + HttpEntity entity = response.getEntity(); + + // 可以获得响应头 + // Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE); + // for (Header header : headers) { + // } + + responseContent = EntityUtils.toString(entity, CHARSET_UTF_8); + // 判断响应状态 + + if (response.getStatusLine().getStatusCode() >= 300) { + log.error("======= httpclent返回的状态码大于等于300 ======="); + if (StringUtils.isEmpty(responseContent)) { + return Fail_Request; + } + } + if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) { + EntityUtils.consume(entity); + } + } catch (Exception e) { + log.error("The exception is:", e); + } finally { + try { + // 释放资源 + if (response != null) { + response.close(); + } + } catch (IOException e) { + log.error("The exception is:", e); + } + } + return responseContent; + } + + /** + * 发送 post请求 + * + * @param httpUrl + * 地址 + */ + public static String sendHttpPost(String httpUrl) { + // 创建httpPost + HttpPost httpPost = new HttpPost(httpUrl); + return sendHttpPost(httpPost); + } + + /** + * 发送 get请求 + * + * @param httpUrl + */ + public static String sendHttpGet(String httpUrl, Map headers) { + // 创建get请求 + HttpGet httpGet = new HttpGet(httpUrl); + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpGet.addHeader(key, headers.get(key)); + } + } + return sendHttpGet(httpGet); + } + + /** + * 发送delete请求 + * + * @param httpUrl + */ + public static String sendHttpDelete(String httpUrl, Map headers) { + // 创建get请求 + HttpDelete httpDelete = new HttpDelete(httpUrl); + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpDelete.addHeader(key, headers.get(key)); + } + } + return sendHttpDelete(httpDelete); + } + + /** + * 发送 get请求 + * + * @param httpUrl + */ + public static InputStream sendHttpGetStream(String httpUrl, + Map headers) { + // 创建get请求 + HttpGet httpGet = new HttpGet(httpUrl); + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpGet.addHeader(key, headers.get(key)); + } + } + return sendHttpGetStream(httpGet); + } + + /** + * 发送Get请求 + * + * @param httpGet + * @return + */ + private static InputStream sendHttpGetStream(HttpGet httpGet) { + + CloseableHttpClient httpClient = null; + CloseableHttpResponse response = null; + // 响应内容 + HttpEntity entity = null; + // 储存的流对象 + InputStream inputStream = null; + try { + // 创建默认的httpClient实例. + httpClient = getHttpClient(); + // 配置请求信息 + httpGet.setConfig(requestConfig); + // 执行请求 + response = httpClient.execute(httpGet); + // 得到响应实例 + entity = response.getEntity(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + InputStream input = entity.getContent(); + byte[] buffer = new byte[1024]; + int len; + while ((len = input.read(buffer)) != -1) { + baos.write(buffer, 0, len); + } + input.close(); + baos.flush(); + inputStream = new ByteArrayInputStream(baos.toByteArray()); + // 判断响应状态 + if (response.getStatusLine().getStatusCode() >= 300) { + throw new Exception( + "HTTP Request is not success, Response code is " + + response.getStatusLine().getStatusCode()); + } + if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) { + EntityUtils.consume(entity); + } + } catch (Exception e) { + log.error("The exception is:", e); + } finally { + try { + // 释放资源 + if (response != null) { + response.close(); + } + } catch (IOException e) { + log.error("The exception is:", e); + } + } + try { + return inputStream; + } catch (Exception e) { + log.error("The exception is:", e); + } + return null; + } + + /** + * 发送 post请求 + * + * @param httpUrl + * 地址 + * @param params + * 参数(格式:key1=value1&key2=value2) + * @param headers + * http header 请求头 + * + */ + public static String sendHttpPost(String httpUrl, String params, + Map headers) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + try { + // 设置参数 + if (params != null && params.trim().length() > 0) { + StringEntity stringEntity = new StringEntity(params, "UTF-8"); + stringEntity.setContentType(CONTENT_TYPE_FORM_URL); + httpPost.setEntity(stringEntity); + } + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpPost.addHeader(key, headers.get(key)); + } + } + } catch (Exception e) { + log.error("The exception is:", e); + } + return sendHttpPost(httpPost); + } + + /** + * 发送 post请求 + * + * @param maps + * 参数 + * @param headers + * http 请求头 + */ + public static String sendHttpPost(String httpUrl, Map maps, + Map headers) { + String parem = convertStringParamter(maps); + return sendHttpPost(httpUrl, parem, headers); + } + + /** + * 发送 post请求 发送json数据 + * + * @param httpUrl + * 地址 + * @param paramsJson + * 参数(格式 json) + * @param headers + * http 请求头 + */ + public static String sendHttpPostJson(String httpUrl, String paramsJson, + Map headers) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + try { + // 设置参数 + if (paramsJson != null && paramsJson.trim().length() > 0) { + StringEntity stringEntity = new StringEntity(paramsJson, + "UTF-8"); + stringEntity.setContentType(CONTENT_TYPE_JSON_URL); + httpPost.setEntity(stringEntity); + } + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpPost.addHeader(key, headers.get(key)); + } + } + } catch (Exception e) { + log.error("The exception is:", e); + } + return sendHttpPost(httpPost); + } + + /** + * 发送 put请求 发送json数据 + * + * @param httpUrl + * 地址 + * @param paramsJson + * 参数(格式 json) + * @param headers + * http 请求头 + */ + public static String sendHttpPutJson(String httpUrl, String paramsJson, + Map headers) { + HttpPut httpPut = new HttpPut(httpUrl);// 创建httpPost + try { + // 设置参数 + if (paramsJson != null && paramsJson.trim().length() > 0) { + StringEntity stringEntity = new StringEntity(paramsJson, + "UTF-8"); + stringEntity.setContentType(CONTENT_TYPE_JSON_URL); + httpPut.setEntity(stringEntity); + } + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpPut.addHeader(key, headers.get(key)); + } + } + } catch (Exception e) { + log.error("The exception is:", e); + } + return sendHttpPut(httpPut); + } + + /** + * 发送 delete请求 发送json数据 + * + * @param httpUrl + * 地址 + * @param paramsJson + * 参数(格式 json) + * @param headers + * http 请求头 + */ + public static String sendHttpDeleteJson(String httpUrl, Map paramsJson, + Map headers) { + if (paramsJson != null) { + httpUrl = httpUrl + "?" + convertStringParamter(paramsJson); + } + HttpDelete httpDelete = new HttpDelete(httpUrl);// 创建httpPost + try { + // 设置参数 + /* + * if (paramsJson != null && paramsJson.trim().length() > 0) { + * StringEntity stringEntity = new StringEntity(paramsJson, + * "UTF-8"); stringEntity.setContentType(CONTENT_TYPE_JSON_URL); + * ((HttpResponse) httpDelete).setEntity(stringEntity); } + */ + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpDelete.addHeader(key, headers.get(key)); + } + } + } catch (Exception e) { + log.error("The exception is:", e); + } + return sendHttpDelete(httpDelete); + } + + + /** + * 发送 post请求 发送xml数据 + * + * @param httpUrl + * 地址 + * @param paramsXml + * 参数(格式 Xml) + * @param headers + * http 请求头 + */ + public static String sendHttpPostXml(String httpUrl, String paramsXml, + Map headers) { + HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost + try { + // 设置参数 + if (paramsXml != null && paramsXml.trim().length() > 0) { + StringEntity stringEntity = new StringEntity(paramsXml, "UTF-8"); + stringEntity.setContentType(CONTENT_TYPE_TEXT_HTML); + httpPost.setEntity(stringEntity); + } + if (headers != null) { + Set keys = headers.keySet(); + for (Iterator i = keys.iterator(); i.hasNext();) { + String key = (String) i.next(); + httpPost.addHeader(key, headers.get(key)); + } + } + } catch (Exception e) { + log.error("The exception is:", e); + } + return sendHttpPost(httpPost); + } + + /** + * 将map集合的键值对转化成:key1=value1&key2=value2 的形式 + * + * @param parameterMap + * 需要转化的键值对集合 + * @return 字符串 + */ + public static String convertStringParamter(Map parameterMap) { + StringBuffer parameterBuffer = new StringBuffer(); + if (parameterMap != null) { + Iterator iterator = parameterMap.keySet().iterator(); + String key = null; + String value = null; + List list = new ArrayList(); + while (iterator.hasNext()) { + key = (String) iterator.next(); + if (!key.contains("List") && parameterMap.get(key) != null) { + value = (String) parameterMap.get(key) == null ? "" + : (String) parameterMap.get(key); + } else { + list = (List) parameterMap.get(key); + /* + * if(list != null && list.size()>0){ for (String string : + * list) { value = value + string + ","; } value = + * value.substring(0, value.length()-1); }else{ value = ""; + * } + */ + if (list != null && list.size() > 0) { + for (String string : list) { + parameterBuffer.append(key).append("=") + .append(string); + if (iterator.hasNext()) { + parameterBuffer.append("&"); + } + } + } else { + value = ""; + } + continue; + } + parameterBuffer.append(key).append("=").append(value); + if (iterator.hasNext()) { + parameterBuffer.append("&"); + } + } + } + return parameterBuffer.toString(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/xforwardai/superdata/util/JsonHelper.java b/src/main/java/com/xforwardai/superdata/util/JsonHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..3beb99ee7016962d2c764cd23956ea7a3561d18d --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/JsonHelper.java @@ -0,0 +1,48 @@ +package com.xforwardai.superdata.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Charsets; +import lombok.Data; + +import java.io.*; + +@Data +public class JsonHelper { + private String properties_File_Path; + + public JsonHelper(String properties_File_Path) { + this.properties_File_Path = properties_File_Path; + } + + public JSONObject getJson(){ + try { + InputStream inputStream = this.getClass() + .getResourceAsStream(getProperties_File_Path()); + byte[] bytes = new byte[inputStream.available()]; + inputStream.read(bytes); + String resultStr = new String(bytes, Charsets.UTF_8); + return JSONObject.parseObject(resultStr); + } + catch (Exception e){ + e.printStackTrace(); + } + return null; + } + + public JSONArray getJsonArr(){ + try { + InputStream inputStream = this.getClass() + .getResourceAsStream(getProperties_File_Path()); + byte[] bytes = new byte[inputStream.available()]; + inputStream.read(bytes); + String resultStr = new String(bytes, Charsets.UTF_8); + return JSONArray.parseArray(resultStr); + } + catch (Exception e){ + e.printStackTrace(); + } + return null; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/JsonReader.java b/src/main/java/com/xforwardai/superdata/util/JsonReader.java new file mode 100644 index 0000000000000000000000000000000000000000..4280755dd3ec0e949bf8c98cbe90f7d03a45cb97 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/JsonReader.java @@ -0,0 +1,20 @@ +package com.xforwardai.superdata.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.stereotype.Component; + +@Component +public class JsonReader { + + public JSONObject getJson(String path) { + JsonHelper jsonHelper = new JsonHelper(path); + return jsonHelper.getJson(); + } + + public JSONArray getJsonArr(String path) { + JsonHelper jsonHelper = new JsonHelper(path); + return jsonHelper.getJsonArr(); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/JsonUtil.java b/src/main/java/com/xforwardai/superdata/util/JsonUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..8c3b9087179d95602ad88da879705ac322b412b3 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/JsonUtil.java @@ -0,0 +1,160 @@ +package com.xforwardai.superdata.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; + +/** + * @ClassName: JsonUtils + * @Description: (操作json的工具类) + * @author xujian + * @date 2017年12月27日 + */ +public class JsonUtil { + + + /** + * @Title: getInteger + * @Description: (从JSONObject中获取指定Integer类型的字符串) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return String 返回类型 + * @throws + */ + public static Integer getInteger(String str, JSONObject json) { + if (determine(str, json)) { + return json.getInteger(str); + } + return 0; + } + + /** + * @Title: getInteger + * @Description: (从JSONObject中获取指定Long类型的字符串) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return String 返回类型 + * @throws + */ + public static Long getLong(String str, JSONObject json) { + if (determine(str, json)) { + return json.getLong(str); + } + return 0l; + } + + /** + * @Title: getInteger + * @Description: (从JSONObject中获取指定Double类型的字符串) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return String 返回类型 + * @throws + */ + public static Double getDouble(String str, JSONObject json) { + if (determine(str, json)) { + return json.getDouble(str); + } + return 0d; + } + + /** + * @Title: getString + * @Description: (从JSONObject中获取指定String类型的字符串) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return String 返回类型 + * @throws + */ + public static String getString(String str, JSONObject json) { + if (determine(str, json)) { + return json.getString(str); + } + return ""; + } + + /** + * @Title: getJsonArray + * @Description: (从JSONObject中获取指定JSONArray) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return JSONArray 返回类型 + * @throws + */ + public static JSONArray getJsonArray(String str, JSONObject json) { + if (determine(str, json)) { + return json.getJSONArray(str); + } + return null; + } + + /** + * @Title: getJsonObject + * @Description: (从JSONObject中获取指定JSONObject) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return JSONObject 返回类型 + * @throws + */ + public static JSONObject getJsonObject(String str, JSONObject json) { + if (determine(str, json)) { + return json.getJSONObject(str); + } + return null; + } + + /** + * @throws Exception + * @Title: getStringObject + * @Description: (获取JsonObject里面data数组中第n个对象的某个key对应的value) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return JSONObject 返回类型 + * @throws + */ + public static String getStringFromArray(String str, JSONObject json, int index) throws Exception { + if (null != json && json.containsKey("data") && !"null".equalsIgnoreCase(json.getString(str))) { + JSONArray jsonArray = json.getJSONArray("data"); + if (index + 1 > jsonArray.size()) { + return ""; + } + JSONObject jb = (JSONObject) jsonArray.get(index); + return getString(str, jb); + } + return ""; + } + + /** + * @Title: determine + * @Description: (一些公共的判断) + * @param @param str + * @param @param json + * @param @return 参数 + * @author xujian + * @return Boolean 返回类型 + * @throws + */ + protected static Boolean determine(String str, JSONObject json) { + if (null != json && json.containsKey(str) && !"null".equalsIgnoreCase(json.getString(str)) + && StringUtils.isNotEmpty(json.getString(str))) { + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/Mapping.java b/src/main/java/com/xforwardai/superdata/util/Mapping.java new file mode 100644 index 0000000000000000000000000000000000000000..2333225fe01f98eeb924250df7f182d1eb38d727 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/Mapping.java @@ -0,0 +1,52 @@ +package com.xforwardai.superdata.util; + +import java.lang.reflect.Method; +import java.util.Map; + +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo.Builder; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo.BuilderConfiguration; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +public class Mapping { + private final AbstractHandlerMethodMapping methodMapping; + private final BuilderConfiguration config; + + private Mapping(AbstractHandlerMethodMapping methodMapping, BuilderConfiguration config) { + this.methodMapping = methodMapping; + this.config = config; + } + + public static Mapping create(RequestMappingHandlerMapping mapping) { + return new Mapping(mapping, (BuilderConfiguration) null); + } + + public Builder paths(String... paths) { + Builder builder = RequestMappingInfo.paths(paths); + return this.config != null ? builder.options(this.config) : builder; + } + + public Builder paths(String name, RequestMethod method, String... params){ + Builder builder = RequestMappingInfo.paths(name); + builder.methods(method); + builder.params(params); + return builder; + } + + public Mapping register(RequestMappingInfo requestMappingInfo, Object handler, Method method) { + this.methodMapping.registerMapping(requestMappingInfo, handler, method); + return this; + } + + public Map getHandlerMethods() { + return this.methodMapping.getHandlerMethods(); + } + + public Mapping unregister(RequestMappingInfo requestMappingInfo) { + this.methodMapping.unregisterMapping(requestMappingInfo); + return this; + } +} diff --git a/src/main/java/com/xforwardai/superdata/util/MysqlCheckUtil.java b/src/main/java/com/xforwardai/superdata/util/MysqlCheckUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..88c11e57f1d549000c7411827b411dd6cefbdf79 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/MysqlCheckUtil.java @@ -0,0 +1,131 @@ +package com.xforwardai.superdata.util; + +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.xforwardai.superdata.annotation.MysqlCheckInject; +import com.xforwardai.superdata.constants.ResultCode; +import com.xforwardai.superdata.exceptionhandler.ApplicationException; +import io.swagger.annotations.ApiModelProperty; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @Description: + * @ClassName: com.xforwardai.wisdom.machine.room.util.MysqlCheckUtil.java + * @date: 2021/12/28 16:32 + * @author xujian + */ +@Slf4j +public class MysqlCheckUtil { + + private final static String COLON = ":"; + + private final static String METHOD_ADD = "add"; + + private final static String METHOD_UPDATE = "update"; + + private final static String PRIMARY_KEY = "id"; + + private static List getAllFields(Object obj) { + List fieldList = new ArrayList<>(); + Class className = obj.getClass(); + for (; className != Object.class; className = className.getSuperclass()) {//获取自己和父级对象 + Field[] fields = className.getDeclaredFields();//获取全部私有字段 + for (Field field : fields) { + field.setAccessible(true); + fieldList.add(field); + } + } + return fieldList; + } + + public static void check(Object obj, String method) throws ApplicationException { + Class aClass = obj.getClass(); + QueryWrapper queryWrapper = new QueryWrapper<>(); + List fields = getAllFields(obj); + Set uniqueFields = new HashSet<>(); + Map conditionUniqueValues = new HashMap<>(); + for (Field filed : fields) { + try { + filed.setAccessible(true); + MysqlCheckInject fieldAnnotation = filed.getAnnotation(MysqlCheckInject.class); + ApiModelProperty apiModelProperty = filed.getAnnotation(ApiModelProperty.class); + if (null != fieldAnnotation) { + String uniqueField = fieldAnnotation.uniqueField(); + String[] conditionUniqueFields = fieldAnnotation.conditionUniqueField(); + if (null != conditionUniqueFields) { + for (String conditionUniqueField : conditionUniqueFields) { + Object value = BeanUtils.invokeGetMethod(obj, lineToHump(conditionUniqueField), null); + if (null != value) { + conditionUniqueValues.put(conditionUniqueField, value); + } + } + } + Object value = BeanUtils.invokeGetMethod(obj, filed.getName(), null); + if (StringUtils.isNotEmpty(uniqueField)) { + uniqueFields.add(apiModelProperty.value() + COLON + value); + queryWrapper.or().eq(uniqueField, value); + } + } + } catch (Exception e) { + log.error("【sql组装异常 msg:{}】", e.getMessage()); + } + } + + if (conditionUniqueValues.size() > 0) { + queryWrapper.or(wrapper -> { + conditionUniqueValues.keySet().forEach(key -> { + wrapper.eq(key, conditionUniqueValues.get(key)); + }); + }); + } + MysqlCheckInject annotation = aClass.getAnnotation(MysqlCheckInject.class); + Class mapper = annotation.mapper(); + BaseMapper bean = (BaseMapper) SpringUtil.getBean(mapper); + List list = bean.selectList(queryWrapper); + + //新增参数验证 + if (METHOD_ADD.equals(method)) { + if (!CollectionUtils.isEmpty(uniqueFields) && !CollectionUtils.isEmpty(list)) { + throw new ApplicationException(ResultCode.FAIL_CODE, uniqueFields + "或" + conditionUniqueValues + "不能重复"); + } + } + + //编辑参数验证 + if (METHOD_UPDATE.equals(method)) { + if (!CollectionUtils.isEmpty(list) && list.size() > 1) { + throw new ApplicationException(ResultCode.FAIL_CODE, uniqueFields + "或" + conditionUniqueValues + "不能重复"); + } else if (!CollectionUtils.isEmpty(list) && list.size() == 1) { + Object o = list.get(0); + //比较id + Object id = BeanUtils.invokeGetMethod(o, PRIMARY_KEY, null); + Object paramsId = BeanUtils.invokeGetMethod(obj, PRIMARY_KEY, null); + if (!ObjectUtil.equals(id, paramsId)) { + throw new ApplicationException(ResultCode.FAIL_CODE, uniqueFields + "不能重复"); + } + } + } + } + + private static final Pattern linePattern = Pattern.compile("_(\\w)"); + + /** 下划线转驼峰 */ + public static String lineToHump(String str) { + str = str.toLowerCase(); + Matcher matcher = linePattern.matcher(str); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, matcher.group(1).toUpperCase()); + } + matcher.appendTail(sb); + return sb.toString(); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/PageUtil.java b/src/main/java/com/xforwardai/superdata/util/PageUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..1f53ebe7651c9c95f5894a0c410d723d4d1779cd --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/PageUtil.java @@ -0,0 +1,33 @@ +package com.xforwardai.superdata.util; + +import com.alibaba.fastjson.JSONArray; + +import java.util.ArrayList; +import java.util.List; + +/** + * @description: 分页工具类 + * @author: weiqiao.qu + * @create: 2021/03/19 18:21 + **/ +public class PageUtil { + + public static List page(List result, Integer page, Integer pageSize) { + Integer start = (page - 1) * pageSize; + Integer end = page * pageSize; + if (start < result.size()) { + return result.subList(start, Math.min(end, result.size())); + } + return new ArrayList(); + } + + public static List page(JSONArray result, Integer page, Integer pageSize) { + Integer start = (page - 1) * pageSize; + Integer end = page * pageSize; + if (start < result.size()) { + return result.subList(start, Math.min(end, result.size())); + } + return new ArrayList(); + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/Pair.java b/src/main/java/com/xforwardai/superdata/util/Pair.java new file mode 100644 index 0000000000000000000000000000000000000000..125806fc94f058b0e9a33c08b3cec40f1ff6ff9f --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/Pair.java @@ -0,0 +1,43 @@ +package com.xforwardai.superdata.util; + + +import java.io.Serializable; + +public class Pair implements Serializable { + + /** + * Key of this Pair. + */ + private K key; + + /** + * Gets the key for this pair. + * @return key for this pair + */ + public K getKey() { return key; } + + /** + * Value of this this Pair. + */ + private V value; + + /** + * Gets the value for this pair. + * @return value for this pair + */ + public V getValue() { return value; } + + /** + * Creates a new pair + * @param key The key for this pair + * @param value The value to use for this pair + */ + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + @Override + public String toString() { + return key + "=" + value; + } +} diff --git a/src/main/java/com/xforwardai/superdata/util/PathUtils.java b/src/main/java/com/xforwardai/superdata/util/PathUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..ccdc919213d55fb220d12e9d2089e7389cc17dbe --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/PathUtils.java @@ -0,0 +1,14 @@ +package com.xforwardai.superdata.util; + +import java.util.regex.Pattern; + +public class PathUtils { + private static final Pattern REPLACE_SLASH_REGX = Pattern.compile("/+"); + + public PathUtils() { + } + + public static String replaceSlash(String path) { + return REPLACE_SLASH_REGX.matcher(path).replaceAll("/"); + } +} diff --git a/src/main/java/com/xforwardai/superdata/util/PropertiesUtil.java b/src/main/java/com/xforwardai/superdata/util/PropertiesUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..cb8a4d9aab2d558333ed56c023f68bea0fd67a28 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/PropertiesUtil.java @@ -0,0 +1,45 @@ +package com.xforwardai.superdata.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Controller; + +import java.io.IOException; +import java.util.Objects; +import java.util.Properties; + +@Component +@Slf4j +public class PropertiesUtil { + + + public Properties properties; + + /** + * 读取 application-dataType.yaml 配置文件信息 + */ + public PropertiesUtil() { + // application-datatype.yaml配置文件信息 + ClassPathResource resource = new ClassPathResource("/application-datatype.yaml"); + try { + properties = PropertiesLoaderUtils.loadProperties(resource); + } catch (IOException e) { + log.error("获取application-datatype配置文件异常 errMsg:{}", e.getMessage()); + + } + } + + public String getJavaTypeByFieldType(String fieldType) { + String javaType = properties.getProperty(fieldType); + if ((javaType == null || Objects.equals(javaType, "")) && fieldType.indexOf("char") > -1) { + javaType = properties.getProperty("varchar"); + } + if ((javaType == null || Objects.equals(javaType, "")) && fieldType.indexOf("decimal") > -1) { + javaType = properties.getProperty("decimal"); + } + return javaType; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/RedisUtils.java b/src/main/java/com/xforwardai/superdata/util/RedisUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..b7dca41cf48ca453c450a254f738f99af0de8492 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/RedisUtils.java @@ -0,0 +1,197 @@ +package com.xforwardai.superdata.util; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@Component +public class RedisUtils { + + private static final Logger log = LoggerFactory.getLogger(RedisUtils.class); + + @Resource + private RedisTemplate redisTemplate; + + public void convertAndSend(String channel, String message) { + log.info("redis convertAndSend channel [{}],message [{}]", channel, message); + redisTemplate.convertAndSend(channel, message); + } + + /** + * 删除keys值 + * @param keys + */ + public void delKeys(String... keys) { + if (keys != null && keys.length > 0) { + if (keys.length == 1) { + redisTemplate.delete(keys[0]); + } else { + redisTemplate.delete(CollectionUtils.arrayToList(keys)); + } + + } + } + + + /** + * 删除缓存, 匹配删除,效率低 + * @param patners + */ + public void delKeysPatners(String... patners) { + if (patners != null && patners.length > 0) { + for (String item : patners) { + redisTemplate.delete(redisTemplate.keys(item + "*")); + } + } + } + + + public List getObjPatners(String patners) { + String pt = String.format("0%s*", patners); + + Set keys = redisTemplate.keys(pt); + List result = new ArrayList<>(50); + for (String item : keys) { + result.add(this.getObj(item)); + } + return result; + } + + + /** + * 查询key值 + * @param key + * @return + */ + public Object getObj(String key) { + return redisTemplate.boundValueOps(key).get(); + } + + + /** + * 获取key值 and delete it by left + * @param key + * @param left + * @return + */ + public Object getObj(String key, Boolean left) { + Object object = redisTemplate.boundValueOps(key).get(); + if (!left) { + redisTemplate.delete(key); + } + return object; + } + + + /** + * 添加缓存 + * @param key + * @param value + */ + public void setObj(String key, Object value, Long expTimeSeconds) { + //添加缓存 + redisTemplate.opsForValue().set(key, value, expTimeSeconds, TimeUnit.SECONDS); + } + + // 对list 对相关操作 + public void addLList(String key, Object value) { + Long l = redisTemplate.opsForList().size(key); + if (l == null || Long.compare(l, 0L) == 0) { + redisTemplate.opsForList().set(key, 0, value); + } else { + redisTemplate.opsForList().leftPush(key, value); + } + } + + public void addRList(String key, Object value) { + Long l = redisTemplate.opsForList().size(key); + if (l == null || Long.compare(l, 0L) == 0) { + redisTemplate.opsForList().set(key, 0, value); + } else { + redisTemplate.opsForList().rightPush(key, value); + } + } + + public void setList(String key, List value) { + int index = 0; + redisTemplate.delete(key); + redisTemplate.opsForList().rightPushAll(key, value); +// for(Object item:value){ +// redisTemplate.opsForList().set(key,index++,item); +// } + } + + public List getList(String key) { + return redisTemplate.opsForList().range(key, 0, redisTemplate.opsForList().size(key)); + } + + + public void setStrList(String key, List list) { + redisTemplate.delete(key); + redisTemplate.opsForList().rightPushAll(key, list); + } + + public List getStrList(String key) { + return redisTemplate.opsForList().range(key, 0, redisTemplate.opsForList().size(key)); + } + + //set op + public void setSet(String key, List value) { + redisTemplate.opsForSet().add(key, value.toArray()); + } + + public Set getSet(String key) { + return redisTemplate.opsForSet().members(key); + } + + public Set getStrSet(String key) { + return redisTemplate.opsForSet().members(key); + } + + public void setStrSet(String key, Set values) { + redisTemplate.opsForSet().add(key, values.toArray()); + } + + public void setStrSet(String key, Set values, Long expTimeSeconds) { + redisTemplate.opsForSet().add(key, values.toArray()); + redisTemplate.expire(key, expTimeSeconds, TimeUnit.SECONDS); + } + + public void setStringSet(String key, List values) { + redisTemplate.opsForSet().add(key, values.toArray()); + } + + // public Set getStringSet(String key){ +// return redisTemplate.opsForSet().members(key).stream().map(p->{return p.toString();}).collect(Collectors.toSet()); +// } + public void addStringSet(String key, String value) { + redisTemplate.opsForSet().add(key, value); + } + + public void delStringSet(String key, String value) { + redisTemplate.opsForSet().remove(key, value); + } + + //hash op + public void setHash(String key, Map map) { + redisTemplate.opsForHash().putAll(key, map); + } + + public Map getHash(String key) { + return redisTemplate.opsForHash().entries(key); + } + + public Boolean setIfAbsent(String key, String value) { + return redisTemplate.opsForValue().setIfAbsent(key, value); + } +} diff --git a/src/main/java/com/xforwardai/superdata/util/RequestUtil.java b/src/main/java/com/xforwardai/superdata/util/RequestUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..fd4c86d480828cec7b9548de109e9fd2e1aa747a --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/RequestUtil.java @@ -0,0 +1,60 @@ +package com.xforwardai.superdata.util; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.util.Enumeration; + +/** + * @Description: + * @ClassName: com.xforwardai.superdata.util.RequestUtil.java + * @date: 2022/8/30 15:30 + * @author xujian + */ +@Slf4j +public class RequestUtil { + + public static Object getBodyParam(HttpServletRequest request) { + Object result = new JSONObject(); + StringBuffer sb = new StringBuffer(); + BufferedReader bufferReader = null; + String line = null; + try { + bufferReader = new BufferedReader(request.getReader()); + while ((line = bufferReader.readLine()) != null) { + sb.append(line); + } + try { + result = JSONObject.parseObject(sb.toString()); + } catch (Exception e) { + log.warn("请求参数为Lit"); + result = JSONArray.parseArray(sb.toString()); + } + } catch (Exception e) { + log.error("获取body参数异常 errMsg:{}", e.getMessage()); + } finally { + if (null != bufferReader) { + try { + bufferReader.close(); + } catch (Exception e) { + log.error("关流异常", e.getMessage()); + } + } + } + return result; + } + + public static Object getUrlParam(HttpServletRequest request) { + JSONObject jsonObject = new JSONObject(); + Enumeration enu = request.getParameterNames(); + while (enu.hasMoreElements()) { + String paraName = (String) enu.nextElement(); + jsonObject.put(paraName, request.getParameter(paraName)); + } + return jsonObject; + } + +} diff --git a/src/main/java/com/xforwardai/superdata/util/Sort.java b/src/main/java/com/xforwardai/superdata/util/Sort.java new file mode 100644 index 0000000000000000000000000000000000000000..72ff6137cf3fdcf6f806df932e6bd64bc6ff02f6 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/Sort.java @@ -0,0 +1,16 @@ +package com.xforwardai.superdata.util; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +public class Sort implements Serializable { + + private K key; + + private V sort; + +} diff --git a/src/main/java/com/xforwardai/superdata/util/SpringUtil.java b/src/main/java/com/xforwardai/superdata/util/SpringUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..aaa1d3b0945644f47819f46723bcbad310fb5be6 --- /dev/null +++ b/src/main/java/com/xforwardai/superdata/util/SpringUtil.java @@ -0,0 +1,40 @@ +package com.xforwardai.superdata.util; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class SpringUtil implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if (SpringUtil.applicationContext == null) { + SpringUtil.applicationContext = applicationContext; + } + } + + //获取applicationContext + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + //通过name获取 Bean. + public static Object getBean(String name) { + return getApplicationContext().getBean(name); + } + + //通过class获取Bean. + public static T getBean(Class clazz) { + return getApplicationContext().getBean(clazz); + } + + //通过name,以及Clazz返回指定的Bean + public static T getBean(String name, Class clazz) { + return getApplicationContext().getBean(name, clazz); + } + +} \ No newline at end of file diff --git a/src/main/resources/application-datatype.yaml b/src/main/resources/application-datatype.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2dbdeeb8a4a5c07b71be40bae5a317a27e72ff17 --- /dev/null +++ b/src/main/resources/application-datatype.yaml @@ -0,0 +1,43 @@ +# mysql中数据类型对应的java数据类型配置 mysql的数据类型:java的数据类型 +blob: byte +bit: boolean +tinyint: int +int: int +integer: long +bigint: long +float: float +double: double +smallint: int +char: string +text: string +tinytext: string +varchar: string +date: date +datetime: date +decimal: long +year: int +time: date +timestamp: date +string: string +keyword: string +_keyword: string +n_keyword: string +long: long +object: object +byte: byte +short: short +boolean: boolean +enum: string +longblob: byte +longtext: string +mediumblob: string +mediumtext: string +set: string +# hive库表树结构跳过的库名配置 +schemaName: ('sys','information_schema') +NUMBER: int +DATE: date +CHAR: string +VARCHAR2: string +ROWID: string +TIMESTAMP: date \ No newline at end of file diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0a189a704172aa39824dbf9cf45d644e2bfc4563 --- /dev/null +++ b/src/main/resources/application.yaml @@ -0,0 +1,81 @@ +spring: + servlet: + multipart: + max-file-size: 10MB + max-request-size: 10MB + resources: + static-locations: classpath:/public + profiles: + active: datatype + # redis配置 选择性打开 优先使用哨兵集群的方式 + redis: + database: 0 + password: ENC(euPZW4NJYT5Bob3LMZBgOTjzK1HAnSC/) + sentinel: + master: mymaster + nodes: sentinel1.xforwardai.com:36379,sentinel2.xforwardai.com:36380,sentinel3.xforwardai.com:36381 + # mysql数据库配置 + datasource: + url: jdbc:mysql://10.18.1.150:33306/super_data_api?useSSL=false&allowMultiQueries=true&characterEncoding=utf-8&serverTimezone=Hongkong&zeroDateTimeBehavior=convertToNull&allowPublicKeyRetrieval=true + username: root + #password: ENC(N0kFXrCrYwMHkBGW0nATcg==) + password: root + driver-class-name: com.mysql.cj.jdbc.Driver + druid: + max-active: 100 + initial-size: 10 + min-idle: 10 + max-wait: 60000 + # 间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + time-between-evictionrunsmillis: 60000 + # 连接在池中最小生存的时间,单位是毫秒 + min-evictable-idleiimemillis: 30000 + elasticsearch: + rest: + #username: elastic + #password: xforwardai@123 + uris: + - http://es1.xforwardai.com:39200 +server: + port: 1001 +#日志格式统一输出 +logging: + file: + max-size: 100MB + max-history: 7 + name: /opt/logs/super-data-api/super-data-api.log + level: + com.xforwardai.superdata.remote: DEBUG + root: info + com.xforwardai.superdata.mysql.mapper: DEBUG +management: + health: + elasticsearch: + enabled: false #取消es 的健康检查 + endpoint: + health: + show-details: always + endpoints: + web: + exposure: + include: ["*"] +jwt: + secret-key: xforwardai@2018 + ttl-min: 43200 +aop: + show-header: false +#数据库加密配置 +jasypt: + encryptor: + #这里可以理解成是加解密的时候使用的密钥 + password: xforwardai@2018 +info: + server-name: super-data-api + instance-id: super-data-api + description: 超级数据-api + version: v1.0.0 + module: 芯翌-超级数据-api +swagger: + title: 超级数据-api + controller: 'com.xforwardai.superdata.controller' + service-url: http://localhost:10001/swagger-ui.html \ No newline at end of file diff --git a/src/main/resources/db/initDataBase.sql b/src/main/resources/db/initDataBase.sql new file mode 100644 index 0000000000000000000000000000000000000000..ab185a019161a576867c79c7b88f23b223b364d0 --- /dev/null +++ b/src/main/resources/db/initDataBase.sql @@ -0,0 +1,2 @@ +CREATE +DATABASE IF NOT EXISTS `super_data_api` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; \ No newline at end of file diff --git a/src/main/resources/db/v1.0.sql b/src/main/resources/db/v1.0.sql new file mode 100644 index 0000000000000000000000000000000000000000..3f61ea817ce73adcbb551e61e627827832441d4d --- /dev/null +++ b/src/main/resources/db/v1.0.sql @@ -0,0 +1,108 @@ +/* +Navicat MySQL Data Transfer + +Source Server : 10.18.1.150 +Source Server Version : 80026 +Source Host : 10.18.1.150:33306 +Source Database : super_data + +Target Server Type : MYSQL +Target Server Version : 80026 +File Encoding : 65001 + +Date: 2022-07-21 16:22:47 +*/ + +SET FOREIGN_KEY_CHECKS=0; + +-- ---------------------------- +-- Table structure for api_datasource +-- ---------------------------- +DROP TABLE IF EXISTS `super_data_api`; +CREATE TABLE `api_datasource` ( + `id` int NOT NULL AUTO_INCREMENT COMMENT '编号,主键', + `datasource_code` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '唯一编号', + `type` int NOT NULL DEFAULT '0' COMMENT '数据源类型 0-mysql 1-opaq 2-hive 3-es 4-kafka 5-orcale', + `ip` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'IP', + `port` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '端口', + `username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '用户名', + `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '密码 加密存储', + `datasource_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '数据源名称', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for api_info +-- ---------------------------- +DROP TABLE IF EXISTS `api_info`; +CREATE TABLE `api_info` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '接口名称', + `method` varchar(16) DEFAULT NULL COMMENT '请求类型 GET,POST,PUT,DELETE', + `url` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL, + `operate_type` tinyint DEFAULT '0' COMMENT '接口操作类型 0:查询 1:新增 2:更新 3:删除', + `result_type` tinyint DEFAULT '0' COMMENT '返回数据类型 0:单条数据 1:数组 2:分页', + `main_table_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '主表名称', + `is_export` tinyint DEFAULT '0' COMMENT '是否导出接口 1:是 0:否', + `datasource_code` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '数据源id', + `database_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '数据库名称', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for api_param +-- ---------------------------- +DROP TABLE IF EXISTS `api_param`; +CREATE TABLE `api_param` ( + `id` int NOT NULL AUTO_INCREMENT, + `api_id` int NOT NULL COMMENT 'apiId', + `param_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '参数名称', + `param_table_field_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '表字段名称', + `param_java_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '参数java类型', + `param_table_field_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '参数表字段类型', + `param_body_type` tinyint DEFAULT '0' COMMENT '0:url传参 1:请求体传参 ', + `is_required` tinyint DEFAULT NULL COMMENT '是否必须要的参数 1:是 0:否', + `is_update` tinyint DEFAULT '0' COMMENT '是否更新参数 1:是 0:否', + `condition_type` tinyint DEFAULT '1' COMMENT '条件类型 1:等于 2:小于 3:小于等于 4:大于 5:大于等于 6:模糊', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for api_result +-- ---------------------------- +DROP TABLE IF EXISTS `api_result`; +CREATE TABLE `api_result` ( + `id` int NOT NULL AUTO_INCREMENT, + `api_id` int NOT NULL COMMENT 'apiId', + `result_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '字段名称', + `result_table_field_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '表字段名称', + `result_table_field_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '参数表字段类型', + `result_java_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '参数java类型', + `export_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '导出字段名称', + `sort_type` tinyint DEFAULT '0' COMMENT '排序类型 0:无排序 1:倒序 2:升序', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- ---------------------------- +-- Table structure for api_table_relation +-- ---------------------------- +DROP TABLE IF EXISTS `api_table_relation`; +CREATE TABLE `api_table_relation` ( + `id` int NOT NULL AUTO_INCREMENT, + `api_id` int NOT NULL, + `main_table_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '主表名称', + `association_table_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '关联表名称', + `association_condition` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '关联条件 如: a.id=b.id', + `relation_type` tinyint DEFAULT '1' COMMENT '关联类型 1:LEFT JOIN 2:INNER JOIN 3:RIGHT JOIN', + `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; diff --git a/src/main/resources/mapper/mysql/ApiInfoMapper.xml b/src/main/resources/mapper/mysql/ApiInfoMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..f78116ce274ce8c796856ef2d312ec889cdcb8d6 --- /dev/null +++ b/src/main/resources/mapper/mysql/ApiInfoMapper.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/public/datasource.html b/src/main/resources/public/datasource.html new file mode 100644 index 0000000000000000000000000000000000000000..a356bde0efa542d0255472c5839acd717ca03586 --- /dev/null +++ b/src/main/resources/public/datasource.html @@ -0,0 +1,255 @@ + + + + + 数据源管理 + + + + + + + + + + + + + +
+ +
+
+ +
+
+ 新增 +
+
+ 查询 +
+
+ +
+ +
+ + + +
+ + + + + + +
+
+ + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ +
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/public/home.html b/src/main/resources/public/home.html new file mode 100644 index 0000000000000000000000000000000000000000..b957a21a19acc580ce834de2645d9d5cb416b071 --- /dev/null +++ b/src/main/resources/public/home.html @@ -0,0 +1,68 @@ + + + + + super-data-api + + + + + + + + + + + + + +
+
+ +
数据库配置
+
接口
+
+
+ + +
+
+ + + diff --git a/src/main/resources/public/interface.html b/src/main/resources/public/interface.html new file mode 100644 index 0000000000000000000000000000000000000000..8700ee1128e0c9f3aac8b8d3c18bff3e277219c3 --- /dev/null +++ b/src/main/resources/public/interface.html @@ -0,0 +1,1727 @@ + + + + + 接口管理 + + + + + + + + + + + + + + +
+ +
+ +
+ 接口名称: + +
+ +
+ 接口url: + +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ 新增 +
+ +
+ 查询 +
+ +
+ +
+ + +
+ + +
+ 请求参数 +
+ + + + + + + + + + + + + + + +
+ +
+ +
+ 返回结果 +
+ + + + + + + + + +
+ +
+ +
+ 数据源信息 +
+ + + + + + + + +
+ +
+ +
+ 关联关系 +
+ + + + + + + + +
+
+ +
+ 自定义sql +
+ + +
+
+ +
+ + +
+ 接口信息 +
+ +
+
+ 接口名称: + +
+ +
+ 请求url: + +
+ +
+ +
+
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ +
+
+ +
+
+ + +
+ 数据源和表选择 +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ +
+ 关联表选择 +
+ +
+
+ 添加关联表: +
+ 添加 +
+
+ +
+
+
+ 主表: + + + + +
+ +
+ 关联表: + + + + +
+ +
+ 关联关系: + + + + +
+ +
+ 主表关联条件字段: + + + + +
+ +
+ 关联表条件字段: + + + + +
+ +
+ 删除 +
+ +
+
+ +
+ +
+ 自定义sql +
+ + +
+
+ +
+ 接口配置 +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + +
+ url参数: +
+ + + + + + + + + + + + +
+
+
+ body参数: +
+ + + + + + + + + + + + +
+
+ + + +
+ 调用结果: +
+ + + +
+
+
+ +
+ + + +
+ +
+ + + + + + + \ No newline at end of file diff --git a/src/main/resources/public/static/css/element-ui.css b/src/main/resources/public/static/css/element-ui.css new file mode 100644 index 0000000000000000000000000000000000000000..12b718f0e720b8cecdf779fbd50482da6fb6d3b5 --- /dev/null +++ b/src/main/resources/public/static/css/element-ui.css @@ -0,0 +1 @@ +@charset "UTF-8";@font-face{font-family:element-icons;src:url(fonts/element-icons.woff) format("woff"),url(fonts/element-icons.ttf) format("truetype");font-weight:400;font-display:"auto";font-style:normal}[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.el-icon-news:before{content:"\e73e"}.el-icon-price-tag:before{content:"\e744"}.el-icon-discount:before{content:"\e745"}.el-icon-wallet:before{content:"\e747"}.el-icon-coin:before{content:"\e748"}.el-icon-money:before{content:"\e749"}.el-icon-bank-card:before{content:"\e74a"}.el-icon-box:before{content:"\e74b"}.el-icon-present:before{content:"\e74c"}.el-icon-sell:before{content:"\e6d5"}.el-icon-sold-out:before{content:"\e6d6"}.el-icon-shopping-bag-2:before{content:"\e74d"}.el-icon-shopping-bag-1:before{content:"\e74e"}.el-icon-shopping-cart-2:before{content:"\e74f"}.el-icon-shopping-cart-1:before{content:"\e750"}.el-icon-shopping-cart-full:before{content:"\e751"}.el-icon-smoking:before{content:"\e752"}.el-icon-no-smoking:before{content:"\e753"}.el-icon-house:before{content:"\e754"}.el-icon-table-lamp:before{content:"\e755"}.el-icon-school:before{content:"\e756"}.el-icon-office-building:before{content:"\e757"}.el-icon-toilet-paper:before{content:"\e758"}.el-icon-notebook-2:before{content:"\e759"}.el-icon-notebook-1:before{content:"\e75a"}.el-icon-files:before{content:"\e75b"}.el-icon-collection:before{content:"\e75c"}.el-icon-receiving:before{content:"\e75d"}.el-icon-suitcase-1:before{content:"\e760"}.el-icon-suitcase:before{content:"\e761"}.el-icon-film:before{content:"\e763"}.el-icon-collection-tag:before{content:"\e765"}.el-icon-data-analysis:before{content:"\e766"}.el-icon-pie-chart:before{content:"\e767"}.el-icon-data-board:before{content:"\e768"}.el-icon-data-line:before{content:"\e76d"}.el-icon-reading:before{content:"\e769"}.el-icon-magic-stick:before{content:"\e76a"}.el-icon-coordinate:before{content:"\e76b"}.el-icon-mouse:before{content:"\e76c"}.el-icon-brush:before{content:"\e76e"}.el-icon-headset:before{content:"\e76f"}.el-icon-umbrella:before{content:"\e770"}.el-icon-scissors:before{content:"\e771"}.el-icon-mobile:before{content:"\e773"}.el-icon-attract:before{content:"\e774"}.el-icon-monitor:before{content:"\e775"}.el-icon-search:before{content:"\e778"}.el-icon-takeaway-box:before{content:"\e77a"}.el-icon-paperclip:before{content:"\e77d"}.el-icon-printer:before{content:"\e77e"}.el-icon-document-add:before{content:"\e782"}.el-icon-document:before{content:"\e785"}.el-icon-document-checked:before{content:"\e786"}.el-icon-document-copy:before{content:"\e787"}.el-icon-document-delete:before{content:"\e788"}.el-icon-document-remove:before{content:"\e789"}.el-icon-tickets:before{content:"\e78b"}.el-icon-folder-checked:before{content:"\e77f"}.el-icon-folder-delete:before{content:"\e780"}.el-icon-folder-remove:before{content:"\e781"}.el-icon-folder-add:before{content:"\e783"}.el-icon-folder-opened:before{content:"\e784"}.el-icon-folder:before{content:"\e78a"}.el-icon-edit-outline:before{content:"\e764"}.el-icon-edit:before{content:"\e78c"}.el-icon-date:before{content:"\e78e"}.el-icon-c-scale-to-original:before{content:"\e7c6"}.el-icon-view:before{content:"\e6ce"}.el-icon-loading:before{content:"\e6cf"}.el-icon-rank:before{content:"\e6d1"}.el-icon-sort-down:before{content:"\e7c4"}.el-icon-sort-up:before{content:"\e7c5"}.el-icon-sort:before{content:"\e6d2"}.el-icon-finished:before{content:"\e6cd"}.el-icon-refresh-left:before{content:"\e6c7"}.el-icon-refresh-right:before{content:"\e6c8"}.el-icon-refresh:before{content:"\e6d0"}.el-icon-video-play:before{content:"\e7c0"}.el-icon-video-pause:before{content:"\e7c1"}.el-icon-d-arrow-right:before{content:"\e6dc"}.el-icon-d-arrow-left:before{content:"\e6dd"}.el-icon-arrow-up:before{content:"\e6e1"}.el-icon-arrow-down:before{content:"\e6df"}.el-icon-arrow-right:before{content:"\e6e0"}.el-icon-arrow-left:before{content:"\e6de"}.el-icon-top-right:before{content:"\e6e7"}.el-icon-top-left:before{content:"\e6e8"}.el-icon-top:before{content:"\e6e6"}.el-icon-bottom:before{content:"\e6eb"}.el-icon-right:before{content:"\e6e9"}.el-icon-back:before{content:"\e6ea"}.el-icon-bottom-right:before{content:"\e6ec"}.el-icon-bottom-left:before{content:"\e6ed"}.el-icon-caret-top:before{content:"\e78f"}.el-icon-caret-bottom:before{content:"\e790"}.el-icon-caret-right:before{content:"\e791"}.el-icon-caret-left:before{content:"\e792"}.el-icon-d-caret:before{content:"\e79a"}.el-icon-share:before{content:"\e793"}.el-icon-menu:before{content:"\e798"}.el-icon-s-grid:before{content:"\e7a6"}.el-icon-s-check:before{content:"\e7a7"}.el-icon-s-data:before{content:"\e7a8"}.el-icon-s-opportunity:before{content:"\e7aa"}.el-icon-s-custom:before{content:"\e7ab"}.el-icon-s-claim:before{content:"\e7ad"}.el-icon-s-finance:before{content:"\e7ae"}.el-icon-s-comment:before{content:"\e7af"}.el-icon-s-flag:before{content:"\e7b0"}.el-icon-s-marketing:before{content:"\e7b1"}.el-icon-s-shop:before{content:"\e7b4"}.el-icon-s-open:before{content:"\e7b5"}.el-icon-s-management:before{content:"\e7b6"}.el-icon-s-ticket:before{content:"\e7b7"}.el-icon-s-release:before{content:"\e7b8"}.el-icon-s-home:before{content:"\e7b9"}.el-icon-s-promotion:before{content:"\e7ba"}.el-icon-s-operation:before{content:"\e7bb"}.el-icon-s-unfold:before{content:"\e7bc"}.el-icon-s-fold:before{content:"\e7a9"}.el-icon-s-platform:before{content:"\e7bd"}.el-icon-s-order:before{content:"\e7be"}.el-icon-s-cooperation:before{content:"\e7bf"}.el-icon-bell:before{content:"\e725"}.el-icon-message-solid:before{content:"\e799"}.el-icon-video-camera:before{content:"\e772"}.el-icon-video-camera-solid:before{content:"\e796"}.el-icon-camera:before{content:"\e779"}.el-icon-camera-solid:before{content:"\e79b"}.el-icon-download:before{content:"\e77c"}.el-icon-upload2:before{content:"\e77b"}.el-icon-upload:before{content:"\e7c3"}.el-icon-picture-outline-round:before{content:"\e75f"}.el-icon-picture-outline:before{content:"\e75e"}.el-icon-picture:before{content:"\e79f"}.el-icon-close:before{content:"\e6db"}.el-icon-check:before{content:"\e6da"}.el-icon-plus:before{content:"\e6d9"}.el-icon-minus:before{content:"\e6d8"}.el-icon-help:before{content:"\e73d"}.el-icon-s-help:before{content:"\e7b3"}.el-icon-circle-close:before{content:"\e78d"}.el-icon-circle-check:before{content:"\e720"}.el-icon-circle-plus-outline:before{content:"\e723"}.el-icon-remove-outline:before{content:"\e722"}.el-icon-zoom-out:before{content:"\e776"}.el-icon-zoom-in:before{content:"\e777"}.el-icon-error:before{content:"\e79d"}.el-icon-success:before{content:"\e79c"}.el-icon-circle-plus:before{content:"\e7a0"}.el-icon-remove:before{content:"\e7a2"}.el-icon-info:before{content:"\e7a1"}.el-icon-question:before{content:"\e7a4"}.el-icon-warning-outline:before{content:"\e6c9"}.el-icon-warning:before{content:"\e7a3"}.el-icon-goods:before{content:"\e7c2"}.el-icon-s-goods:before{content:"\e7b2"}.el-icon-star-off:before{content:"\e717"}.el-icon-star-on:before{content:"\e797"}.el-icon-more-outline:before{content:"\e6cc"}.el-icon-more:before{content:"\e794"}.el-icon-phone-outline:before{content:"\e6cb"}.el-icon-phone:before{content:"\e795"}.el-icon-user:before{content:"\e6e3"}.el-icon-user-solid:before{content:"\e7a5"}.el-icon-setting:before{content:"\e6ca"}.el-icon-s-tools:before{content:"\e7ac"}.el-icon-delete:before{content:"\e6d7"}.el-icon-delete-solid:before{content:"\e7c9"}.el-icon-eleme:before{content:"\e7c7"}.el-icon-platform-eleme:before{content:"\e7ca"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination::after,.el-pagination::before{display:table;content:""}.el-pagination::after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pager li,.el-pagination__editor{-webkit-box-sizing:border-box;text-align:center}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409EFF}.el-pagination button:disabled{color:#C0C4CC;background-color:#FFF;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:center center no-repeat #FFF;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#C0C4CC;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .arrow.disabled{visibility:hidden}.el-pagination--small .more::before,.el-pagination--small li.more::before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409EFF}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;margin:0 2px;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#C0C4CC}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409EFF}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409EFF;color:#FFF}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-pager .more::before{line-height:30px}.el-pager li{padding:0 4px;background:#FFF;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#C0C4CC}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409EFF}.el-pager li.active{color:#409EFF;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;background:#FFF;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);-webkit-box-sizing:border-box;box-sizing:border-box;width:50%}.el-autocomplete-suggestion,.el-dropdown-menu,.el-menu--collapse .el-submenu .el-menu{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409EFF}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #E4E7ED;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#FFF}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#F5F7FA}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#FFF}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button::before{content:'';position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:rgba(255,255,255,.5)}.el-dropdown .el-dropdown__caret-button.el-button--default::before{background:rgba(220,223,230,.5)}.el-dropdown .el-dropdown__caret-button:hover:not(.is-disabled)::before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing){outline-width:0}.el-dropdown [disabled]{cursor:not-allowed;color:#bbb}.el-dropdown-menu{position:absolute;top:0;left:0;z-index:10;padding:10px 0;margin:5px 0;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item{list-style:none;line-height:36px;padding:0 20px;margin:0;font-size:14px;color:#606266;cursor:pointer;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #EBEEF5}.el-dropdown-menu__item--divided:before{content:'';height:6px;display:block;margin:0 -20px;background-color:#FFF}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:solid 1px #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0;background-color:#FFF}.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu::after,.el-menu::before{display:table;content:""}.el-menu::after{clear:both}.el-menu.el-menu--horizontal{border-bottom:solid 1px #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409EFF;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#FFF;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409EFF;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-menu .el-submenu{min-width:200px}.el-menu--collapse .el-submenu{position:relative}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;z-index:10;border:1px solid #E4E7ED;border-radius:2px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;min-width:200px;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{height:56px;line-height:56px;font-size:14px;color:#303133;padding:0 20px;list-style:none;cursor:pointer;position:relative;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409EFF}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{height:56px;line-height:56px;font-size:14px;color:#303133;padding:0 20px;list-style:none;cursor:pointer;position:relative;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409EFF}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{line-height:1;vertical-align:middle;display:inline-block}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{white-space:nowrap;background:#FFF;border:1px solid #DCDFE6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;position:relative;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409EFF}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-switch,.el-switch__core{position:relative;vertical-align:middle}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #409EFF;box-shadow:-1px 0 0 0 #409EFF}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#F2F6FC}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-picker-panel,.el-popover,.el-select-dropdown,.el-table-filter,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;line-height:20px;height:20px}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;display:inline-block;font-size:14px;font-weight:500;cursor:pointer;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409EFF}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;display:inline-block;width:40px;height:20px;border:1px solid #DCDFE6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#DCDFE6;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#FFF}.el-switch.is-checked .el-switch__core{border-color:#409EFF;background-color:#409EFF}.el-switch.is-checked .el-switch__core::after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #E4E7ED;border-radius:4px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item{padding-right:40px}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409EFF;background-color:#FFF}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#F5F7FA}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:"\e6da";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#FFF}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#F5F7FA}.el-select-dropdown__item.selected{color:#409EFF;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#E4E7ED}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#C0C4CC}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409EFF}.el-select .el-input .el-select__caret{color:#C0C4CC;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotateZ(0);transform:rotateZ(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);border-radius:100%;color:#C0C4CC;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#E4E7ED}.el-range-editor.is-active,.el-range-editor.is-active:hover,.el-select .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#C0C4CC;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select__tags-text{overflow:hidden;text-overflow:ellipsis}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5;display:-webkit-box;display:-ms-flexbox;display:flex;max-width:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-select .el-tag__close.el-icon-close{background-color:#C0C4CC;top:0;color:#FFF;-ms-flex-negative:0;flex-shrink:0}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#FFF}.el-select .el-tag__close.el-icon-close::before{display:block;-webkit-transform:translate(0,.5px);transform:translate(0,.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table__empty-block{min-height:60px;text-align:center;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;font-size:12px;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit .el-table__cell.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th.el-table__cell{background:#F5F7FA}.el-table .el-table__cell{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table .el-table__cell.is-center{text-align:center}.el-table .el-table__cell.is-right{text-align:right}.el-table .el-table__cell.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table .el-table__cell.is-hidden>*{visibility:hidden}.el-table--medium .el-table__cell{padding:10px 0}.el-table--small{font-size:12px}.el-table--small .el-table__cell{padding:8px 0}.el-table--mini{font-size:12px}.el-table--mini .el-table__cell{padding:6px 0}.el-table tr{background-color:#FFF}.el-table tr input[type=checkbox]{margin:0}.el-table td.el-table__cell,.el-table th.el-table__cell.is-leaf{border-bottom:1px solid #EBEEF5}.el-table th.el-table__cell.is-sortable{cursor:pointer}.el-table th.el-table__cell{overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#FFF}.el-table th.el-table__cell>.cell{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;vertical-align:middle;padding-left:10px;padding-right:10px;width:100%}.el-table th.el-table__cell>.cell.highlight{color:#409EFF}.el-table th.el-table__cell.required>div::before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td.el-table__cell div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-table td.el-table__cell.gutter{width:0}.el-table .cell{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;line-height:23px;padding-left:10px;padding-right:10px}.el-date-table td,.el-date-table td div,.el-table-filter{-webkit-box-sizing:border-box}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #EBEEF5}.el-table--border::after,.el-table--group::after,.el-table::before{content:'';position:absolute;background-color:#EBEEF5;z-index:1}.el-table--border::after,.el-table--group::after{top:0;right:0;width:1px;height:100%}.el-table::before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border .el-table__cell,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #EBEEF5}.el-table--border .el-table__cell:first-child .cell{padding-left:10px}.el-table--border th.el-table__cell.gutter:last-of-type{border-bottom:1px solid #EBEEF5;border-bottom-width:1px}.el-table--border th.el-table__cell,.el-table__fixed-right-patch{border-bottom:1px solid #EBEEF5}.el-table--hidden{visibility:hidden}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right::before,.el-table__fixed::before{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#EBEEF5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#FFF}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td.el-table__cell{border-top:1px solid #EBEEF5;background-color:#F5F7FA;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td.el-table__cell{border-top:1px solid #EBEEF5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td.el-table__cell,.el-table__header-wrapper tbody td.el-table__cell{background-color:#F5F7FA;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #EBEEF5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#C0C4CC;top:5px}.el-table .sort-caret.descending{border-top-color:#C0C4CC;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409EFF}.el-table .descending .sort-caret.descending{border-top-color:#409EFF}.el-table .hidden-columns{visibility:hidden;position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell{background:#FAFAFA}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td.el-table__cell{background-color:#ecf5ff}.el-table__body tr.hover-row.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped>td.el-table__cell,.el-table__body tr.hover-row>td.el-table__cell{background-color:#F5F7FA}.el-table__body tr.current-row>td.el-table__cell{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #EBEEF5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td.el-table__cell{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell{background-color:#F5F7FA}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #EBEEF5;border-radius:2px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-sizing:border-box;margin:2px 0}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409EFF;color:#FFF}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #EBEEF5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table td.in-range div,.el-date-table td.in-range div:hover,.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div{background-color:#F2F6FC}.el-table-filter__bottom button:hover{color:#409EFF}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;height:30px;padding:4px 0;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{height:30px;padding:3px 0;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#C0C4CC}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409EFF;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#FFF}.el-date-table td.available:hover{color:#409EFF}.el-date-table td.current:not(.disabled) span{color:#FFF;background-color:#409EFF}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#FFF}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409EFF}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#F5F7FA;opacity:1;cursor:not-allowed;color:#C0C4CC}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#F2F6FC;border-radius:15px}.el-date-table td.selected div:hover{background-color:#F2F6FC}.el-date-table td.selected span{background-color:#409EFF;color:#FFF;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:solid 1px #EBEEF5}.el-month-table{font-size:12px;margin:-1px;border-collapse:collapse}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#409EFF;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#FFF}.el-month-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-month-table td.disabled .cell:hover{color:#C0C4CC}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409EFF}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#F2F6FC}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#FFF}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#FFF;background-color:#409EFF}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409EFF}.el-year-table{font-size:12px;margin:-1px;border-collapse:collapse}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409EFF;font-weight:700}.el-year-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-year-table td.disabled .cell:hover{color:#C0C4CC}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409EFF}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#FFF}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:solid 1px #EBEEF5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409EFF}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409EFF;font-weight:700}.time-select-item.disabled{color:#E4E7ED;cursor:not-allowed}.time-select-item:hover{background-color:#F5F7FA;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#C0C4CC;float:left;line-height:32px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;display:inline-block;height:100%;margin:0;padding:0;width:39%;text-align:center;font-size:14px;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input:-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::placeholder{color:#C0C4CC}.el-date-editor .el-range-separator{display:inline-block;height:100%;padding:0 5px;margin:0;text-align:center;line-height:32px;font-size:14px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#C0C4CC;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#E4E7ED}.el-range-editor.is-disabled input{background-color:#F5F7FA;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::placeholder{color:#C0C4CC}.el-range-editor.is-disabled .el-range-separator{color:#C0C4CC}.el-picker-panel{color:#606266;border:1px solid #E4E7ED;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#FFF;border-radius:4px;line-height:30px;margin:5px 0}.el-picker-panel__body-wrapper::after,.el-picker-panel__body::after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#FFF;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409EFF}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409EFF}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409EFF}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#FFF;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#FFF;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409EFF}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list::after,.el-time-spinner__list::before{content:'';display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#F5F7FA;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#C0C4CC;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #E4E7ED;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content::after,.el-time-panel__content::before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #E4E7ED;border-bottom:1px solid #E4E7ED}.el-form-item__label,.el-tabs__item,.el-tabs__nav-wrap.is-scrollable,.el-time-panel__footer,.el-time-range-picker__cell{-webkit-box-sizing:border-box}.el-time-panel__content::after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content::before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds::after{left:calc(100% / 3 * 2)}.el-time-panel__content.has-seconds::before{padding-left:calc(100% / 3)}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409EFF}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #E4E7ED}.el-popover{position:absolute;background:#FFF;min-width:150px;border-radius:4px;border:1px solid #EBEEF5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover,.el-cascader__dropdown,.el-color-picker__panel,.el-message-box,.el-notification{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing){outline-width:0}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#FFF;border-radius:4px;border:1px solid #EBEEF5;font-size:18px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper::after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#F56C6C}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409EFF}.el-message-box__content{padding:10px 15px;color:#606266;font-size:14px}.el-message-box__container{position:relative}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status::before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67C23A}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#E6A23C}.el-message-box__status.el-icon-error{color:#F56C6C}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#F56C6C;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#C0C4CC}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#409EFF;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item::after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__content::after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#F56C6C;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#F56C6C;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#F56C6C}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409EFF;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8,.8);transform:scale(.8,.8)}.el-tabs__new-tab:hover{color:#409EFF}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#E4E7ED;z-index:1}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409EFF inset;box-shadow:0 0 2px 2px #409EFF inset;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs--card>.el-tabs__header .el-tabs__active-bar,.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs__item .el-icon-close:hover{background-color:#C0C4CC;color:#FFF}.el-tabs__item.is-active{color:#409EFF}.el-tabs__item:hover{color:#409EFF;cursor:pointer}.el-tabs__item.is-disabled{color:#C0C4CC;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #E4E7ED}.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #E4E7ED;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #E4E7ED;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#FFF}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close{width:14px}.el-tabs--border-card{background:#FFF;border:1px solid #DCDFE6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#F5F7FA;border-bottom:1px solid #E4E7ED;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-col-offset-0,.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409EFF;background-color:#FFF;border-right-color:#DCDFE6;border-left-color:#DCDFE6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409EFF}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#C0C4CC}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-cascader-menu:last-child .el-cascader-node,.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #DCDFE6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left::after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left::after,.el-tabs--left .el-tabs__nav-wrap.is-right::after,.el-tabs--right .el-tabs__nav-wrap.is-left::after,.el-tabs--right .el-tabs__nav-wrap.is-right::after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-button-group>.el-button:not(:last-child),.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #E4E7ED;border-bottom:none;border-top:1px solid #E4E7ED;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #E4E7ED;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #E4E7ED;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #E4E7ED;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right::after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #E4E7ED}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #E4E7ED;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #E4E7ED;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #E4E7ED;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#FFF;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399;font-size:14px}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409EFF}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#F5F7FA}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409EFF;color:#fff}.el-tree-node__content:hover,.el-upload-list__item:hover{background-color:#F5F7FA}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#C0C4CC;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#C0C4CC}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert,.el-notification,.el-slider__button,.el-slider__stop{background-color:#FFF}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#C0C4CC}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67C23A}.el-alert--success.is-light .el-alert__description{color:#67C23A}.el-alert--success.is-dark{background-color:#67C23A;color:#FFF}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#FFF}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#E6A23C}.el-alert--warning.is-light .el-alert__description{color:#E6A23C}.el-alert--warning.is-dark{background-color:#E6A23C;color:#FFF}.el-alert--error.is-light{background-color:#fef0f0;color:#F56C6C}.el-alert--error.is-light .el-alert__description{color:#F56C6C}.el-alert--error.is-dark{background-color:#F56C6C;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active,.el-upload iframe{opacity:0}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #EBEEF5;position:fixed;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.right{right:16px}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67C23A}.el-notification .el-icon-error{color:#F56C6C}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#E6A23C}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#F5F7FA;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409EFF}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409EFF}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #DCDFE6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #DCDFE6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#E4E7ED;color:#E4E7ED}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#E4E7ED;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #DCDFE6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #DCDFE6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing){outline-width:0}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:" ";border-width:5px}.el-button-group::after,.el-button-group::before,.el-color-dropdown__main-wrapper::after,.el-link.is-underline:hover:after,.el-page-header__left::after,.el-progress-bar__inner::after,.el-row::after,.el-row::before,.el-slider::after,.el-slider::before,.el-slider__button-wrapper::after,.el-transfer-panel .el-transfer-panel__footer::after,.el-upload-cover::after,.el-upload-list--picture-card .el-upload-list__item-actions::after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#FFF}.el-tooltip__popper.is-light{background:#FFF;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#FFF}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#FFF}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#FFF}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#FFF}.el-slider::after,.el-slider::before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper::after{display:inline-block;vertical-align:middle}.el-slider::after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#E4E7ED;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button{border-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409EFF;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;position:absolute;z-index:1001;top:-15px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:transparent;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:normal}.el-button,.el-checkbox,.el-checkbox-button__inner,.el-empty__image img,.el-image-viewer__btn,.el-radio,.el-slider__button,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-slider__button-wrapper::after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409EFF;border-radius:50%;-webkit-transition:.2s;transition:.2s;-webkit-user-select:none;user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{position:absolute;height:6px;width:6px;border-radius:100%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #DCDFE6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#C0C4CC}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409EFF}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-10,.el-col-pull-11,.el-col-pull-12,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-2,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-push-0,.el-col-push-1,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-2,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-row,.el-upload-dragger,.el-upload-list__item{position:relative}.el-loading-spinner .el-loading-text{color:#409EFF;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409EFF;stroke-linecap:round}.el-loading-spinner i{color:#409EFF}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-top{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-col-0{width:0%}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0%}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0%}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0%}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0%}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0%}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;cursor:pointer;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409EFF;color:#409EFF}.el-upload:focus .el-upload-dragger{border-color:#409EFF}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:360px;height:180px;text-align:center;cursor:pointer;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#C0C4CC;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #DCDFE6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409EFF;font-style:normal}.el-upload-dragger:hover{border-color:#409EFF}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409EFF}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67C23A}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409EFF}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409EFF;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409EFF}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#FFF}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#FFF;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#FFF;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#FFF;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress-bar,.el-progress-bar__inner::after,.el-progress-bar__innerText,.el-spinner{display:inline-block;vertical-align:middle}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67C23A}.el-progress.is-success .el-progress__text{color:#67C23A}.el-progress.is-warning .el-progress-bar__inner{background-color:#E6A23C}.el-badge__content,.el-progress.is-exception .el-progress-bar__inner{background-color:#F56C6C}.el-progress.is-warning .el-progress__text{color:#E6A23C}.el-progress.is-exception .el-progress__text{color:#F56C6C}.el-progress-bar{padding-right:50px;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__header,.el-message,.el-step__icon{-webkit-box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#EBEEF5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409EFF;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-progress-bar__inner::after{height:100%}.el-progress-bar__innerText{color:#FFF;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;box-sizing:border-box;border-radius:4px;border-width:1px;border-style:solid;border-color:#EBEEF5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,transform .4s,top .4s;transition:opacity .3s,transform .4s,top .4s,-webkit-transform .4s;overflow:hidden;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67C23A}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#E6A23C}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#F56C6C}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__content:focus{outline-width:0}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#C0C4CC;font-size:16px}.el-message__closeBtn:focus{outline-width:0}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67C23A}.el-message .el-icon-error{color:#F56C6C}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#E6A23C}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409EFF}.el-badge__content--success{background-color:#67C23A}.el-badge__content--warning{background-color:#E6A23C}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#F56C6C}.el-card{border-radius:4px;border:1px solid #EBEEF5;background-color:#FFF;overflow:hidden;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;box-sizing:border-box}.el-card__body,.el-main{padding:20px}.el-rate{height:20px;line-height:1}.el-carousel__item,.el-carousel__mask{height:100%;position:absolute;width:100%}.el-rate:active,.el-rate:focus{outline-width:0}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#C0C4CC;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#F5F7FA}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#C0C4CC;border-color:#C0C4CC}.el-step__head.is-success{color:#67C23A;border-color:#67C23A}.el-step__head.is-error{color:#F56C6C;border-color:#F56C6C}.el-step__head.is-finish{color:#409EFF;border-color:#409EFF}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;box-sizing:border-box;background:#FFF;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step.is-horizontal,.el-step__icon-inner{display:inline-block}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{-webkit-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#C0C4CC}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#C0C4CC}.el-step__title.is-success{color:#67C23A}.el-step__title.is-error{color:#F56C6C}.el-step__title.is-finish{color:#409EFF}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#C0C4CC}.el-step__description.is-success{color:#67C23A}.el-step__description.is-error{color:#F56C6C}.el-step__description.is-finish{color:#409EFF}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#C0C4CC}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#C0C4CC;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{top:0;left:0;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{top:0;left:0;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active{opacity:0}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-fade-in-enter,.el-fade-in-leave-active{opacity:0}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #EBEEF5;border-bottom:1px solid #EBEEF5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#FFF;color:#303133;cursor:pointer;border-bottom:1px solid #EBEEF5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__header.focusing:focus:not(:hover),.el-tag{color:#409EFF}.el-collapse-item__arrow{margin:0 8px 0 auto;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#FFF;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #EBEEF5}.el-cascader__search-input,.el-cascader__tags,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-cascader,.el-tag{display:inline-block}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#EBEEF5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#FFF;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#EBEEF5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#FFF}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#EBEEF5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#FFF;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#EBEEF5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#FFF}.el-tag{background-color:#ecf5ff;border-color:#d9ecff;height:32px;padding:0 10px;line-height:30px;font-size:12px;border-width:1px;border-style:solid;border-radius:4px;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#409EFF}.el-tag .el-tag__close{color:#409eff}.el-tag .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67C23A}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close::before{display:block}.el-tag--dark{background-color:#409eff;border-color:#409eff;color:#fff}.el-tag--dark.is-hit{border-color:#409EFF}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#FFF;background-color:#66b1ff}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67C23A}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:#b3d8ff;color:#409eff}.el-tag--plain.is-hit{border-color:#409EFF}.el-tag--plain .el-tag__close{color:#409eff}.el-tag--plain .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67C23A}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-cascader{position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#C0C4CC}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#C0C4CC}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#FFF;border:1px solid #E4E7ED;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{-webkit-box-flex:0;-ms-flex:none;flex:none;background-color:#C0C4CC;color:#FFF}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#F5F7FA}.el-cascader__suggestion-item.is-checked{color:#409EFF;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#C0C4CC}.el-cascader__search-input{-webkit-box-flex:1;-ms-flex:1;flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;box-sizing:border-box}.el-cascader__search-input::-webkit-input-placeholder{color:#C0C4CC}.el-cascader__search-input:-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::placeholder{color:#C0C4CC}.el-color-predefine{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409EFF;box-shadow:0 0 3px 2px #409EFF}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(rgba(0,0,0,0)));background:linear-gradient(to top,#000,rgba(0,0,0,0))}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409EFF;border-color:#409EFF}.el-color-dropdown__link-btn{cursor:pointer;color:#409EFF;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409EFF,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color,.el-input__inner,.el-textarea__inner,.el-transfer-panel{-webkit-box-sizing:border-box}.el-color-picker__color{position:relative;display:block;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-input__inner,.el-textarea__inner{background-image:none;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty{font-size:12px;color:#999;position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{display:inline-block;position:absolute;width:100%;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#FFF;text-align:center;font-size:12px}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-textarea{position:relative;display:inline-block;width:100%;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#FFF;border:1px solid #DCDFE6;border-radius:4px;transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea__inner:hover{border-color:#C0C4CC}.el-textarea__inner:focus{outline:0;border-color:#409EFF}.el-textarea .el-input__count{color:#909399;background:#FFF;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea.is-exceed .el-textarea__inner{border-color:#F56C6C}.el-textarea.is-exceed .el-input__count{color:#F56C6C}.el-input{position:relative;font-size:14px;display:inline-block;width:100%}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#C0C4CC;font-size:14px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#909399;font-size:12px}.el-input .el-input__count .el-input__count-inner{background:#FFF;line-height:initial;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#FFF;border-radius:4px;border:1px solid #DCDFE6;box-sizing:border-box;color:#606266;display:inline-block;font-size:inherit;height:40px;line-height:40px;outline:0;padding:0 15px;transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__prefix,.el-input__suffix{position:absolute;top:0;-webkit-transition:all .3s;height:100%;color:#C0C4CC;text-align:center}.el-input__inner::-ms-reveal{display:none}.el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input__inner::placeholder{color:#C0C4CC}.el-input__inner:hover{border-color:#C0C4CC}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409EFF;outline:0}.el-input__suffix{right:5px;transition:all .3s;pointer-events:none}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-input.is-exceed .el-input__inner{border-color:#F56C6C}.el-input.is-exceed .el-input__suffix .el-input__count{color:#F56C6C}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#F5F7FA;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #DCDFE6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--prepend .el-input__inner,.el-input-group__append{border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-timeline-item__node--primary,.el-transfer__button{background-color:#409EFF}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input{font-size:inherit}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#FFF;font-size:0}.el-button-group>.el-button+.el-button,.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-timeline,.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #DCDFE6;background-color:#F5F7FA;color:#C0C4CC}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer-panel{border:1px solid #EBEEF5;border-radius:4px;overflow:hidden;background:#FFF;display:inline-block;vertical-align:middle;width:200px;max-height:100%;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block!important}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409EFF}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#F5F7FA;margin:0;padding-left:15px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-container,.el-header{-webkit-box-sizing:border-box}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#FFF;margin:0;padding:0;border-top:1px solid #EBEEF5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer::after{display:inline-block;height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner::after{height:6px;width:3px;left:4px}.el-container{display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;box-sizing:border-box;min-width:0}.el-container.is-vertical,.el-drawer,.el-empty,.el-result{-webkit-box-orient:vertical;-webkit-box-direction:normal}.el-container.is-vertical{-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside{overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-footer,.el-main{-webkit-box-sizing:border-box}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;overflow:auto;box-sizing:border-box}.el-footer{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #E4E7ED}.el-timeline-item__icon{color:#FFF;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#E4E7ED;border-radius:50%;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image__error,.el-timeline-item__dot{display:-webkit-box;display:-ms-flexbox;-webkit-box-pack:center}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--success{background-color:#67C23A}.el-timeline-item__node--warning{background-color:#E6A23C}.el-timeline-item__node--danger{background-color:#F56C6C}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:flex;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;cursor:pointer;padding:0;font-size:14px;font-weight:500}.el-link.is-underline:hover:after{position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #409EFF}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#409EFF}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#409EFF}.el-link.el-link--default.is-disabled{color:#C0C4CC}.el-link.el-link--primary{color:#409EFF}.el-link.el-link--primary:hover{color:#66b1ff}.el-link.el-link--primary.is-disabled{color:#a0cfff}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#F56C6C}.el-link.el-link--danger{color:#F56C6C}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67C23A}.el-link.el-link--success{color:#67C23A}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#E6A23C}.el-link.el-link--warning{color:#E6A23C}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#DCDFE6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#FFF;padding:0 20px;font-weight:500;color:#303133;font-size:14px}.el-image__error,.el-image__placeholder{background:#F5F7FA}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-image__error{display:flex;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;color:#C0C4CC;vertical-align:middle}.el-image__preview{cursor:pointer}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:50%;opacity:.8;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;user-select:none}.el-button,.el-checkbox,.el-checkbox-button__inner,.el-empty__image img,.el-radio{-webkit-user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:24px;color:#fff;background-color:#606266}.el-image-viewer__canvas{width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff;top:50%}.el-image-viewer__prev{-webkit-transform:translateY(-50%);transform:translateY(-50%);left:40px}.el-image-viewer__next{-webkit-transform:translateY(-50%);transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button,.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-button:focus,.el-button:hover{color:#409EFF;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#FFF;border-color:#409EFF;color:#409EFF}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#FFF;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#FFF;border-color:#EBEEF5;color:#C0C4CC}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:'';position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:rgba(255,255,255,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#FFF;background-color:#409EFF;border-color:#409EFF}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#FFF}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#FFF;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409EFF;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409EFF;border-color:#409EFF;color:#FFF}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#FFF;background-color:#67C23A;border-color:#67C23A}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#FFF}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#FFF}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#FFF;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67C23A;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67C23A;border-color:#67C23A;color:#FFF}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#FFF;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#FFF;background-color:#E6A23C;border-color:#E6A23C}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#FFF}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#FFF}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#FFF;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#E6A23C;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#E6A23C;border-color:#E6A23C;color:#FFF}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#FFF;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#FFF;background-color:#F56C6C;border-color:#F56C6C}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#FFF}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#FFF}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#FFF;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#F56C6C;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#F56C6C;border-color:#F56C6C;color:#FFF}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#FFF;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#FFF;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#FFF}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#FFF}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#FFF;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#FFF}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#FFF;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small{padding:9px 15px;font-size:12px;border-radius:3px}.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini{font-size:12px;border-radius:3px}.el-button--mini.is-circle{padding:7px}.el-button--text{border-color:transparent;color:#409EFF;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;border-color:transparent;background-color:transparent}.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover{border-color:transparent}.el-button-group .el-button--danger:last-child,.el-button-group .el-button--danger:not(:first-child):not(:last-child),.el-button-group .el-button--info:last-child,.el-button-group .el-button--info:not(:first-child):not(:last-child),.el-button-group .el-button--primary:last-child,.el-button-group .el-button--primary:not(:first-child):not(:last-child),.el-button-group .el-button--success:last-child,.el-button-group .el-button--success:not(:first-child):not(:last-child),.el-button-group .el-button--warning:last-child,.el-button-group .el-button--warning:not(:first-child):not(:last-child),.el-button-group>.el-dropdown>.el-button{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:first-child,.el-button-group .el-button--danger:not(:first-child):not(:last-child),.el-button-group .el-button--info:first-child,.el-button-group .el-button--info:not(:first-child):not(:last-child),.el-button-group .el-button--primary:first-child,.el-button-group .el-button--primary:not(:first-child):not(:last-child),.el-button-group .el-button--success:first-child,.el-button-group .el-button--success:not(:first-child):not(:last-child),.el-button-group .el-button--warning:first-child,.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-right-color:rgba(255,255,255,.5)}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group::after,.el-button-group::before{display:table}.el-button-group::after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button.is-disabled{z-index:1}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button.is-active,.el-button-group>.el-button:not(.is-disabled):active,.el-button-group>.el-button:not(.is-disabled):focus,.el-button-group>.el-button:not(.is-disabled):hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0}.el-calendar{background-color:#fff}.el-calendar__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #EBEEF5}.el-backtop,.el-page-header{display:-webkit-box;display:-ms-flexbox}.el-calendar__title{color:#000;-ms-flex-item-align:center;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#C0C4CC}.el-backtop,.el-calendar-table td.is-today{color:#409EFF}.el-calendar-table td{border-bottom:1px solid #EBEEF5;border-right:1px solid #EBEEF5;vertical-align:top;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#F2F8FE}.el-calendar-table tr:first-child td{border-top:1px solid #EBEEF5}.el-calendar-table tr td:first-child{border-left:1px solid #EBEEF5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#F2F8FE}.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}.el-page-header{display:flex;line-height:24px}.el-page-header__left{display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-right:40px;position:relative}.el-page-header__left::after{position:absolute;width:1px;height:16px;right:-20px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);background-color:#DCDFE6}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;-ms-flex-item-align:center;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409EFF}.el-checkbox.is-bordered.is-disabled{border-color:#EBEEF5;cursor:not-allowed}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#DCDFE6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#C0C4CC}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#C0C4CC}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#C0C4CC;border-color:#C0C4CC}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409EFF;border-color:#409EFF}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#C0C4CC;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409EFF}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409EFF}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#FFF;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #DCDFE6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#FFF;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409EFF}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #FFF;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-of-type{margin-right:0}.el-checkbox-button__inner{line-height:1;font-weight:500;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409EFF}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409EFF}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#EBEEF5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409EFF}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-avatar,.el-cascader-panel,.el-radio,.el-radio--medium.is-bordered .el-radio__label,.el-radio__label{font-size:14px}.el-radio{color:#606266;font-weight:500;line-height:1;cursor:pointer;white-space:nowrap;outline:0;margin-right:30px}.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-cascader-menu,.el-cascader-menu__list,.el-radio__inner{-webkit-box-sizing:border-box}.el-radio.is-bordered.is-checked{border-color:#409EFF}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#EBEEF5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#F5F7FA;border-color:#E4E7ED}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{white-space:nowrap;cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#F5F7FA}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#C0C4CC}.el-radio__input.is-disabled+span.el-radio__label{color:#C0C4CC;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409EFF;background:#409EFF}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409EFF}.el-radio__input.is-focus .el-radio__inner{border-color:#409EFF}.el-radio__inner{border:1px solid #DCDFE6;border-radius:100%;width:14px;height:14px;background-color:#FFF;cursor:pointer;box-sizing:border-box}.el-radio__inner:hover{border-color:#409EFF}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#FFF;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-radio__label{padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:-webkit-box;display:-ms-flexbox;display:flex;border-radius:4px}.el-cascader-panel.is-bordered{border:1px solid #E4E7ED;border-radius:4px}.el-cascader-menu{min-width:180px;box-sizing:border-box;color:#606266;border-right:solid 1px #E4E7ED}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;box-sizing:border-box}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-align:center;color:#C0C4CC}.el-cascader-node{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#409EFF;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#F5F7FA}.el-cascader-node.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{-webkit-box-flex:1;-ms-flex:1;flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px}.el-drawer,.el-drawer__body>*{-webkit-box-sizing:border-box}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-empty__image img,.el-empty__image svg{vertical-align:top;height:100%;width:100%}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}@-webkit-keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@-webkit-keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@-webkit-keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@-webkit-keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}@keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}.el-drawer{position:absolute;box-sizing:border-box;background-color:#FFF;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-webkit-box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);overflow:hidden;outline:0}.el-drawer.rtl{-webkit-animation:rtl-drawer-out .3s;animation:rtl-drawer-out .3s;right:0}.el-drawer__open .el-drawer.rtl{-webkit-animation:rtl-drawer-in .3s 1ms;animation:rtl-drawer-in .3s 1ms}.el-drawer.ltr{-webkit-animation:ltr-drawer-out .3s;animation:ltr-drawer-out .3s;left:0}.el-drawer__open .el-drawer.ltr{-webkit-animation:ltr-drawer-in .3s 1ms;animation:ltr-drawer-in .3s 1ms}.el-drawer.ttb{-webkit-animation:ttb-drawer-out .3s;animation:ttb-drawer-out .3s;top:0}.el-drawer__open .el-drawer.ttb{-webkit-animation:ttb-drawer-in .3s 1ms;animation:ttb-drawer-in .3s 1ms}.el-drawer.btt{-webkit-animation:btt-drawer-out .3s;animation:btt-drawer-out .3s;bottom:0}.el-drawer__open .el-drawer.btt{-webkit-animation:btt-drawer-in .3s 1ms;animation:btt-drawer-in .3s 1ms}.el-drawer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0}.el-drawer__header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#72767b;display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:32px;padding:20px 20px 0}.el-drawer__header>:first-child{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__title{margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;line-height:inherit;font-size:1rem}.el-drawer__close-btn{border:none;cursor:pointer;font-size:20px;color:inherit;background-color:transparent}.el-drawer__body{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:auto}.el-popconfirm__main,.el-skeleton__image{display:-ms-flexbox;-webkit-box-align:center;display:-webkit-box}.el-drawer__body>*{box-sizing:border-box}.el-drawer.ltr,.el-drawer.rtl{height:100%;top:0;bottom:0}.el-drawer.btt,.el-drawer.ttb{width:100%;left:0;right:0}.el-drawer__container{position:relative;left:0;right:0;top:0;bottom:0;height:100%;width:100%}.el-drawer-fade-enter-active{-webkit-animation:el-drawer-fade-in .3s;animation:el-drawer-fade-in .3s}.el-drawer-fade-leave-active{animation:el-drawer-fade-in .3s reverse}.el-popconfirm__main{display:flex;-ms-flex-align:center;align-items:center}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{text-align:right;margin:0}@-webkit-keyframes el-skeleton-loading{0%{background-position:100% 50%}100%{background-position:0 50%}}@keyframes el-skeleton-loading{0%{background-position:100% 50%}100%{background-position:0 50%}}.el-skeleton{width:100%}.el-skeleton__first-line,.el-skeleton__paragraph{height:16px;margin-top:16px;background:#f2f2f2}.el-skeleton.is-animated .el-skeleton__item{background:-webkit-gradient(linear,left top,right top,color-stop(25%,#f2f2f2),color-stop(37%,#e6e6e6),color-stop(63%,#f2f2f2));background:linear-gradient(90deg,#f2f2f2 25%,#e6e6e6 37%,#f2f2f2 63%);background-size:400% 100%;-webkit-animation:el-skeleton-loading 1.4s ease infinite;animation:el-skeleton-loading 1.4s ease infinite}.el-skeleton__item{background:#f2f2f2;display:inline-block;height:16px;border-radius:4px;width:100%}.el-skeleton__circle{border-radius:50%;width:36px;height:36px;line-height:36px}.el-skeleton__circle--lg{width:40px;height:40px;line-height:40px}.el-skeleton__circle--md{width:28px;height:28px;line-height:28px}.el-skeleton__button{height:40px;width:64px;border-radius:4px}.el-skeleton__p{width:100%}.el-skeleton__p.is-last{width:61%}.el-skeleton__p.is-first{width:33%}.el-skeleton__text{width:100%;height:13px}.el-skeleton__caption{height:12px}.el-skeleton__h1{height:20px}.el-skeleton__h3{height:18px}.el-skeleton__h5{height:16px}.el-skeleton__image{width:unset;display:flex;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:0}.el-skeleton__image svg{fill:#DCDDE0;width:22%;height:22%}.el-empty{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-direction:column;flex-direction:column;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;padding:40px 0}.el-empty__image{width:160px}.el-empty__image img{user-select:none;-o-object-fit:contain;object-fit:contain}.el-empty__image svg{fill:#DCDDE0}.el-empty__description{margin-top:20px}.el-empty__description p{margin:0;font-size:14px;color:#909399}.el-empty__bottom,.el-result__title{margin-top:20px}.el-descriptions{-webkit-box-sizing:border-box;box-sizing:border-box;font-size:14px;color:#303133}.el-descriptions__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:20px}.el-descriptions__title{font-size:16px;font-weight:700}.el-descriptions--mini,.el-descriptions--small{font-size:12px}.el-descriptions__body{color:#606266;background-color:#FFF}.el-descriptions__body .el-descriptions__table{border-collapse:collapse;width:100%;table-layout:fixed}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:left;font-weight:400;line-height:1.5}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-left{text-align:left}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-center{text-align:center}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-right{text-align:right}.el-descriptions .is-bordered{table-layout:auto}.el-descriptions .is-bordered .el-descriptions-item__cell{border:1px solid #EBEEF5;padding:12px 10px}.el-descriptions :not(.is-bordered) .el-descriptions-item__cell{padding-bottom:12px}.el-descriptions--medium.is-bordered .el-descriptions-item__cell{padding:10px}.el-descriptions--medium:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:10px}.el-descriptions--small.is-bordered .el-descriptions-item__cell{padding:8px 10px}.el-descriptions--small:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:8px}.el-descriptions--mini.is-bordered .el-descriptions-item__cell{padding:6px 10px}.el-descriptions--mini:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:6px}.el-descriptions-item{vertical-align:top}.el-descriptions-item__container{display:-webkit-box;display:-ms-flexbox;display:flex}.el-descriptions-item__container .el-descriptions-item__content,.el-descriptions-item__container .el-descriptions-item__label{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.el-descriptions-item__container .el-descriptions-item__content{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-descriptions-item__label.has-colon::after{content:':';position:relative;top:-.5px}.el-descriptions-item__label.is-bordered-label{font-weight:700;color:#909399;background:#fafafa}.el-descriptions-item__label:not(.is-bordered-label){margin-right:10px}.el-descriptions-item__content{word-break:break-word;overflow-wrap:break-word}.el-result{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-direction:column;flex-direction:column;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;padding:40px 30px}.el-result__icon svg{width:64px;height:64px}.el-result__title p{margin:0;font-size:20px;color:#303133;line-height:1.3}.el-result__subtitle{margin-top:10px}.el-result__subtitle p{margin:0;font-size:14px;color:#606266;line-height:1.3}.el-result__extra{margin-top:30px}.el-result .icon-success{fill:#67C23A}.el-result .icon-error{fill:#F56C6C}.el-result .icon-info{fill:#909399}.el-result .icon-warning{fill:#E6A23C} \ No newline at end of file diff --git a/src/main/resources/public/static/css/fonts/element-icons.woff b/src/main/resources/public/static/css/fonts/element-icons.woff new file mode 100644 index 0000000000000000000000000000000000000000..02b9a2539e425a7a8c244faba92527602be76212 Binary files /dev/null and b/src/main/resources/public/static/css/fonts/element-icons.woff differ diff --git a/src/main/resources/public/static/css/index.css b/src/main/resources/public/static/css/index.css new file mode 100644 index 0000000000000000000000000000000000000000..fc1dab6856091ad9cfec2686e758fe91a7174336 --- /dev/null +++ b/src/main/resources/public/static/css/index.css @@ -0,0 +1,146 @@ +.flexCenterDiv { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-around; +} + +.flexStartDiv { + display: flex; + align-items: flex-start; + justify-content: flex-start; +} + +.topFlexStartDiv { + display: flex; + align-items: flex-start; + justify-content: flex-start; + margin-top: 40px; + margin-left: 40px; +} + +.topTabDiv { + margin-top: 40px; + margin-left: 40px; + flex: 1; +} + +.flexLeftDivInput { + display: flex; + align-items: center; + justify-content: flex-start; + margin-left: 40px; + margin-top: 10px; +} + +.flexLeft100DivInput { + display: flex; + align-items: center; + justify-content: flex-start; + margin-left: 50px; + margin-top: 10px; +} + +.flexRightDivInput { + display: flex; + align-items: center; + justify-content: flex-start; + margin-right: 40px; + margin-top: 10px; +} + +.smallLexLeftDivInput { + display: flex; + align-items: center; + justify-content: flex-start; + margin-left: 11px; + margin-top: 10px; +} + +.flexLeftDivInput:first-child { + margin-left: 10px; +} + +.flexLeftDivInput .el-input { + width: auto; +} + +.flexLeftDivInput .el-input__inner { + width: 200px; +} + +.flexLeftDiv { + margin-left: 10px; +} + +.flexMarginLeftDiv { + margin-left: 20px; +} + +.flexMarginLeftDiv:first-child { + margin-left: 10px; +} + +.newlineStyle { + margin-left: 10px; + margin-top: 10px; +} + +.myInput { + width: 350px; +} + +.inputQuery { + margin-left: 40px; + margin-top: 12px; +} + +.topDiv { + margin-left: 10px; + margin-top: 10px; +} + +.marginLeft40px { + margin-left: 40px; +} + +.marginTop10px { + margin-top: 10px; +} + +.homeBtn { + height: 40px; + line-height: 40px; + cursor: pointer; + color: #303133; + text-align: center; + margin-bottom: 20px; + margin-top: 40px; + width: 50%; + margin-left: 60px; +} + +.homeLeft { + flex: 0 0 300px; + background: #f2f6fc; +} + +.homeRight { + flex: 1; + overflow: hidden; +} + +.superDataApiPic{ + width: 100%; +} + +.choseBtn{ + background: #13c2c2; +} + +.homeBox { + display: flex; + height: 100%; + width: 100%; +} + diff --git a/src/main/resources/public/static/js/axios.instance.utils.js b/src/main/resources/public/static/js/axios.instance.utils.js new file mode 100644 index 0000000000000000000000000000000000000000..3ed191e6fa604b3b4da120f7fd44e92e2e1e4b2b --- /dev/null +++ b/src/main/resources/public/static/js/axios.instance.utils.js @@ -0,0 +1,170 @@ +'use strict' + +function AxiosInstanceUtils (config) { + this._init(config) +} + +AxiosInstanceUtils.create = function (config) { + return new AxiosInstanceUtils(config) +} + +AxiosInstanceUtils.HEADER_KEY_CONTENT_TYPE = 'Content-Type' + +AxiosInstanceUtils.CONTENT_TYPE_APPLICATION_JSON = 'application/json' + +AxiosInstanceUtils.prototype = { + $instance: null, + REQUESTING: false, + REQUESTING_MARK: {}, + DEFAULT_HEADERS: {}, + HEADERS: {}, + _init (config) { + this.$instance = axios.create(config) + this.setDefaultHeader(AxiosInstanceUtils.HEADER_KEY_CONTENT_TYPE, AxiosInstanceUtils.CONTENT_TYPE_APPLICATION_JSON) + // 添加请求拦截器 + this.$instance.interceptors.request.use(config => { + this.REQUESTING = true + this.merge(this.DEFAULT_HEADERS, config.headers) + this.merge(this.HEADERS, config.headers) + this.clearHeader() + return config + }, function (error) { + this.REQUESTING = false + return Promise.reject(error) + }) + // 添加响应拦截器 + this.$instance.interceptors.response.use(response => { + this.REQUESTING = false + return response.data + }, error => { + this.REQUESTING = false + if (error.response) { + if (error.response.data && error.response.data.message) { + } else { + } + } else if (error.request) { + } else { + } + return Promise.reject(error) + }) + }, + get (url, params, success, error, flag) { + if (!this.checkRequesting(flag)) { + return false + } + this.$instance.get(url, { + params: params + }) + .then(responseData => { + this.REQUESTING_MARK[flag] = false + if (success) { + success(responseData) + } + }) + .catch(err => { + this.REQUESTING_MARK[flag] = false + if (error) { + error(err) + } + }) + }, + post (url, params, data, success, error, flag) { + if (!this.checkRequesting(flag)) { + return false + } + this.$instance.post(url, JSON.stringify(data), { + params: params + }) + .then(responseData => { + this.REQUESTING_MARK[flag] = false + if (success) { + success(responseData) + } + }) + .catch(err => { + this.REQUESTING_MARK[flag] = false + if (error) { + error(err) + } + }) + }, + delete (url, params, data, success, error, flag) { + if (!this.checkRequesting(flag)) { + return false + } + this.$instance.delete(url, { + params: params, + data: data + }) + .then(responseData => { + this.REQUESTING_MARK[flag] = false + if (success) { + success(responseData) + } + }) + .catch(err => { + this.REQUESTING_MARK[flag] = false + if (error) { + error(err) + } + }) + }, + put (url, params, data, success, error, flag) { + if (!this.checkRequesting(flag)) { + return false + } + this.$instance.put(url, JSON.stringify(data), { + params: params + }) + .then(responseData => { + this.REQUESTING_MARK[flag] = false + if (success) { + success(responseData) + } + }) + .catch(err => { + this.REQUESTING_MARK[flag] = false + if (error) { + error(err) + } + }) + }, + checkRequesting (flag) { + if (flag === true && this.REQUESTING) { + Message({ + message: '请等待上一个请求完成', + type: 'warning', + showClose: true + }) + return false + } else if (flag && flag !== false && flag !== true && this.REQUESTING_MARK[flag]) { + Message({ + message: '请勿重复请求', + type: 'warning', + showClose: true + }) + return false + } else if (flag && flag !== false && flag !== true) { + this.REQUESTING_MARK[flag] = true + } + return true + }, + setDefaultHeader (key, value) { + this.DEFAULT_HEADERS[key] = value + }, + clearDefaultHeader () { + this.DEFAULT_HEADERS = {} + }, + addHeader (key, value) { + this.HEADERS[key] = value + }, + clearHeader () { + this.HEADERS = {} + }, + merge (target, source) { + for (let key in target) { + source[key] = target[key] + } + return source + } +} diff --git a/src/main/resources/public/static/js/axios.min.js b/src/main/resources/public/static/js/axios.min.js new file mode 100644 index 0000000000000000000000000000000000000000..e8e4fc1603835b88f1fdb9c65a08d52fa0e90cc8 --- /dev/null +++ b/src/main/resources/public/static/js/axios.min.js @@ -0,0 +1,3 @@ +/* axios v0.27.2 | (c) 2022 by Matt Zabriskie */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=13)}([function(e,t,n){"use strict";var r,o=n(4),i=Object.prototype.toString,s=(r=Object.create(null),function(e){var t=i.call(e);return r[t]||(r[t]=t.slice(8,-1).toLowerCase())});function a(e){return e=e.toLowerCase(),function(t){return s(t)===e}}function u(e){return Array.isArray(e)}function c(e){return void 0===e}var f=a("ArrayBuffer");function l(e){return null!==e&&"object"==typeof e}function p(e){if("object"!==s(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}var d=a("Date"),h=a("File"),m=a("Blob"),v=a("FileList");function y(e){return"[object Function]"===i.call(e)}var g=a("URLSearchParams");function E(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),u(e))for(var n=0,r=e.length;n0;)s[i=r[o]]||(t[i]=e[i],s[i]=!0);e=Object.getPrototypeOf(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},kindOf:s,kindOfTest:a,endsWith:function(e,t,n){e=String(e),(void 0===n||n>e.length)&&(n=e.length),n-=t.length;var r=e.indexOf(t,n);return-1!==r&&r===n},toArray:function(e){if(!e)return null;var t=e.length;if(c(t))return null;for(var n=new Array(t);t-- >0;)n[t]=e[t];return n},isTypedArray:O,isFileList:v}},function(e,t,n){"use strict";var r=n(0);function o(e,t,n,r,o){Error.call(this),this.message=e,this.name="AxiosError",t&&(this.code=t),n&&(this.config=n),r&&(this.request=r),o&&(this.response=o)}r.inherits(o,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code,status:this.response&&this.response.status?this.response.status:null}}});var i=o.prototype,s={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED"].forEach((function(e){s[e]={value:e}})),Object.defineProperties(o,s),Object.defineProperty(i,"isAxiosError",{value:!0}),o.from=function(e,t,n,s,a,u){var c=Object.create(i);return r.toFlatObject(e,c,(function(e){return e!==Error.prototype})),o.call(c,e.message,t,n,s,a),c.name=e.name,u&&Object.assign(c,u),c},e.exports=o},function(e,t,n){"use strict";var r=n(1);function o(e){r.call(this,null==e?"canceled":e,r.ERR_CANCELED),this.name="CanceledError"}n(0).inherits(o,r,{__CANCEL__:!0}),e.exports=o},function(e,t,n){"use strict";var r=n(0),o=n(19),i=n(1),s=n(6),a=n(7),u={"Content-Type":"application/x-www-form-urlencoded"};function c(e,t){!r.isUndefined(e)&&r.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}var f,l={transitional:s,adapter:(("undefined"!=typeof XMLHttpRequest||"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process))&&(f=n(8)),f),transformRequest:[function(e,t){if(o(t,"Accept"),o(t,"Content-Type"),r.isFormData(e)||r.isArrayBuffer(e)||r.isBuffer(e)||r.isStream(e)||r.isFile(e)||r.isBlob(e))return e;if(r.isArrayBufferView(e))return e.buffer;if(r.isURLSearchParams(e))return c(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString();var n,i=r.isObject(e),s=t&&t["Content-Type"];if((n=r.isFileList(e))||i&&"multipart/form-data"===s){var u=this.env&&this.env.FormData;return a(n?{"files[]":e}:e,u&&new u)}return i||"application/json"===s?(c(t,"application/json"),function(e,t,n){if(r.isString(e))try{return(t||JSON.parse)(e),r.trim(e)}catch(e){if("SyntaxError"!==e.name)throw e}return(n||JSON.stringify)(e)}(e)):e}],transformResponse:[function(e){var t=this.transitional||l.transitional,n=t&&t.silentJSONParsing,o=t&&t.forcedJSONParsing,s=!n&&"json"===this.responseType;if(s||o&&r.isString(e)&&e.length)try{return JSON.parse(e)}catch(e){if(s){if("SyntaxError"===e.name)throw i.from(e,i.ERR_BAD_RESPONSE,this,null,this.response);throw e}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:n(27)},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],(function(e){l.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){l.headers[e]=r.merge(u)})),e.exports=l},function(e,t,n){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r=0)return;s[t]="set-cookie"===t?(s[t]?s[t]:[]).concat([n]):s[t]?s[t]+", "+n:n}})),s):s}},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?function(){var e,t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");function o(e){var r=e;return t&&(n.setAttribute("href",r),r=n.href),n.setAttribute("href",r),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:"/"===n.pathname.charAt(0)?n.pathname:"/"+n.pathname}}return e=o(window.location.href),function(t){var n=r.isString(t)?o(t):t;return n.protocol===e.protocol&&n.host===e.host}}():function(){return!0}},function(e,t,n){"use strict";e.exports=function(e){var t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}},function(e,t){e.exports=null},function(e,t,n){"use strict";var r=n(12).version,o=n(1),i={};["object","boolean","number","function","string","symbol"].forEach((function(e,t){i[e]=function(n){return typeof n===e||"a"+(t<1?"n ":" ")+e}}));var s={};i.transitional=function(e,t,n){function i(e,t){return"[Axios v"+r+"] Transitional option '"+e+"'"+t+(n?". "+n:"")}return function(n,r,a){if(!1===e)throw new o(i(r," has been removed"+(t?" in "+t:"")),o.ERR_DEPRECATED);return t&&!s[r]&&(s[r]=!0,console.warn(i(r," has been deprecated since v"+t+" and will be removed in the near future"))),!e||e(n,r,a)}},e.exports={assertOptions:function(e,t,n){if("object"!=typeof e)throw new o("options must be an object",o.ERR_BAD_OPTION_VALUE);for(var r=Object.keys(e),i=r.length;i-- >0;){var s=r[i],a=t[s];if(a){var u=e[s],c=void 0===u||a(u,s,e);if(!0!==c)throw new o("option "+s+" must be "+c,o.ERR_BAD_OPTION_VALUE)}else if(!0!==n)throw new o("Unknown option "+s,o.ERR_BAD_OPTION)}},validators:i}},function(e,t,n){"use strict";var r=n(2);function o(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise((function(e){t=e}));var n=this;this.promise.then((function(e){if(n._listeners){var t,r=n._listeners.length;for(t=0;t3?0:(e-e%10!=10)*e%10]}};var g={D:function(e){return e.getDay()},DD:function(e){return d(e.getDay())},Do:function(e,t){return t.DoFn(e.getDate())},d:function(e){return e.getDate()},dd:function(e){return d(e.getDate())},ddd:function(e,t){return t.dayNamesShort[e.getDay()]},dddd:function(e,t){return t.dayNames[e.getDay()]},M:function(e){return e.getMonth()+1},MM:function(e){return d(e.getMonth()+1)},MMM:function(e,t){return t.monthNamesShort[e.getMonth()]},MMMM:function(e,t){return t.monthNames[e.getMonth()]},yy:function(e){return d(String(e.getFullYear()),4).substr(2)},yyyy:function(e){return d(e.getFullYear(),4)},h:function(e){return e.getHours()%12||12},hh:function(e){return d(e.getHours()%12||12)},H:function(e){return e.getHours()},HH:function(e){return d(e.getHours())},m:function(e){return e.getMinutes()},mm:function(e){return d(e.getMinutes())},s:function(e){return e.getSeconds()},ss:function(e){return d(e.getSeconds())},S:function(e){return Math.round(e.getMilliseconds()/100)},SS:function(e){return d(Math.round(e.getMilliseconds()/10),2)},SSS:function(e){return d(e.getMilliseconds(),3)},a:function(e,t){return e.getHours()<12?t.amPm[0]:t.amPm[1]},A:function(e,t){return e.getHours()<12?t.amPm[0].toUpperCase():t.amPm[1].toUpperCase()},ZZ:function(e){var t=e.getTimezoneOffset();return(t>0?"-":"+")+d(100*Math.floor(Math.abs(t)/60)+Math.abs(t)%60,4)}},y={d:["\\d\\d?",function(e,t){e.day=t}],Do:["\\d\\d?"+o,function(e,t){e.day=parseInt(t,10)}],M:["\\d\\d?",function(e,t){e.month=t-1}],yy:["\\d\\d?",function(e,t){var i=+(""+(new Date).getFullYear()).substr(0,2);e.year=""+(t>68?i-1:i)+t}],h:["\\d\\d?",function(e,t){e.hour=t}],m:["\\d\\d?",function(e,t){e.minute=t}],s:["\\d\\d?",function(e,t){e.second=t}],yyyy:["\\d{4}",function(e,t){e.year=t}],S:["\\d",function(e,t){e.millisecond=100*t}],SS:["\\d{2}",function(e,t){e.millisecond=10*t}],SSS:["\\d{3}",function(e,t){e.millisecond=t}],D:["\\d\\d?",u],ddd:[o,u],MMM:[o,h("monthNamesShort")],MMMM:[o,h("monthNames")],a:[o,function(e,t,i){var n=t.toLowerCase();n===i.amPm[0]?e.isPm=!1:n===i.amPm[1]&&(e.isPm=!0)}],ZZ:["[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z",function(e,t){var i,n=(t+"").match(/([+-]|\d\d)/gi);n&&(i=60*n[1]+parseInt(n[2],10),e.timezoneOffset="+"===n[0]?i:-i)}]};y.dd=y.d,y.dddd=y.ddd,y.DD=y.D,y.mm=y.m,y.hh=y.H=y.HH=y.h,y.MM=y.M,y.ss=y.s,y.A=y.a,s.masks={default:"ddd MMM dd yyyy HH:mm:ss",shortDate:"M/D/yy",mediumDate:"MMM d, yyyy",longDate:"MMMM d, yyyy",fullDate:"dddd, MMMM d, yyyy",shortTime:"HH:mm",mediumTime:"HH:mm:ss",longTime:"HH:mm:ss.SSS"},s.format=function(e,t,i){var n=i||s.i18n;if("number"==typeof e&&(e=new Date(e)),"[object Date]"!==Object.prototype.toString.call(e)||isNaN(e.getTime()))throw new Error("Invalid Date in fecha.format");t=s.masks[t]||t||s.masks.default;var r=[];return(t=(t=t.replace(l,function(e,t){return r.push(t),"@@@"})).replace(a,function(t){return t in g?g[t](e,n):t.slice(1,t.length-1)})).replace(/@@@/g,function(){return r.shift()})},s.parse=function(e,t,i){var n=i||s.i18n;if("string"!=typeof t)throw new Error("Invalid format in fecha.parse");if(t=s.masks[t]||t,e.length>1e3)return null;var r={},o=[],u=[];t=t.replace(l,function(e,t){return u.push(t),"@@@"});var c,h=(c=t,c.replace(/[|\\{()[^$+*?.-]/g,"\\$&")).replace(a,function(e){if(y[e]){var t=y[e];return o.push(t[1]),"("+t[0]+")"}return e});h=h.replace(/@@@/g,function(){return u.shift()});var d=e.match(new RegExp(h,"i"));if(!d)return null;for(var p=1;pe?u():!0!==t&&(r=setTimeout(n?function(){r=void 0}:u,void 0===n?e-o:e))}}},function(e,t){var i=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=i)},function(e,t){var i=/^(attrs|props|on|nativeOn|class|style|hook)$/;function n(e,t){return function(){e&&e.apply(this,arguments),t&&t.apply(this,arguments)}}e.exports=function(e){return e.reduce(function(e,t){var r,s,a,o,l;for(a in t)if(r=e[a],s=t[a],r&&i.test(a))if("class"===a&&("string"==typeof r&&(l=r,e[a]=r={},r[l]=!0),"string"==typeof s&&(l=s,t[a]=s={},s[l]=!0)),"on"===a||"nativeOn"===a||"hook"===a)for(o in s)r[o]=n(r[o],s[o]);else if(Array.isArray(r))e[a]=r.concat(s);else if(Array.isArray(s))e[a]=[r].concat(s);else for(o in s)r[o]=s[o];else e[a]=t[a];return e},{})}},function(e,t){var i={}.hasOwnProperty;e.exports=function(e,t){return i.call(e,t)}},function(e,t,i){"use strict";t.__esModule=!0;var n,r=i(56),s=(n=r)&&n.__esModule?n:{default:n};t.default=s.default||function(e){for(var t=1;t0?n:i)(e)}},function(e,t,i){var n=i(29)("keys"),r=i(22);e.exports=function(e){return n[e]||(n[e]=r(e))}},function(e,t,i){var n=i(14),r=i(5),s=r["__core-js_shared__"]||(r["__core-js_shared__"]={});(e.exports=function(e,t){return s[e]||(s[e]=void 0!==t?t:{})})("versions",[]).push({version:n.version,mode:i(21)?"pure":"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t){e.exports={}},function(e,t,i){var n=i(10).f,r=i(7),s=i(13)("toStringTag");e.exports=function(e,t,i){e&&!r(e=i?e:e.prototype,s)&&n(e,s,{configurable:!0,value:t})}},function(e,t,i){t.f=i(13)},function(e,t,i){var n=i(5),r=i(14),s=i(21),a=i(34),o=i(10).f;e.exports=function(e){var t=r.Symbol||(r.Symbol=s?{}:n.Symbol||{});"_"==e.charAt(0)||e in t||o(t,e,{value:a.f(e)})}},function(e,t,i){e.exports=!i(11)&&!i(16)(function(){return 7!=Object.defineProperty(i(37)("div"),"a",{get:function(){return 7}}).a})},function(e,t,i){var n=i(15),r=i(5).document,s=n(r)&&n(r.createElement);e.exports=function(e){return s?r.createElement(e):{}}},function(e,t,i){var n=i(7),r=i(12),s=i(62)(!1),a=i(28)("IE_PROTO");e.exports=function(e,t){var i,o=r(e),l=0,u=[];for(i in o)i!=a&&n(o,i)&&u.push(i);for(;t.length>l;)n(o,i=t[l++])&&(~s(u,i)||u.push(i));return u}},function(e,t,i){var n=i(40);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==n(e)?e.split(""):Object(e)}},function(e,t){var i={}.toString;e.exports=function(e){return i.call(e).slice(8,-1)}},function(e,t,i){var n=i(26);e.exports=function(e){return Object(n(e))}},function(e,t,i){"use strict";var n=i(21),r=i(24),s=i(43),a=i(9),o=i(32),l=i(69),u=i(33),c=i(72),h=i(13)("iterator"),d=!([].keys&&"next"in[].keys()),p=function(){return this};e.exports=function(e,t,i,f,m,v,g){l(i,t,f);var y,b,w,_=function(e){if(!d&&e in S)return S[e];switch(e){case"keys":case"values":return function(){return new i(this,e)}}return function(){return new i(this,e)}},x=t+" Iterator",C="values"==m,k=!1,S=e.prototype,D=S[h]||S["@@iterator"]||m&&S[m],E=D||_(m),$=m?C?_("entries"):E:void 0,T="Array"==t&&S.entries||D;if(T&&(w=c(T.call(new e)))!==Object.prototype&&w.next&&(u(w,x,!0),n||"function"==typeof w[h]||a(w,h,p)),C&&D&&"values"!==D.name&&(k=!0,E=function(){return D.call(this)}),n&&!g||!d&&!k&&S[h]||a(S,h,E),o[t]=E,o[x]=p,m)if(y={values:C?E:_("values"),keys:v?E:_("keys"),entries:$},g)for(b in y)b in S||s(S,b,y[b]);else r(r.P+r.F*(d||k),t,y);return y}},function(e,t,i){e.exports=i(9)},function(e,t,i){var n=i(18),r=i(70),s=i(30),a=i(28)("IE_PROTO"),o=function(){},l=function(){var e,t=i(37)("iframe"),n=s.length;for(t.style.display="none",i(71).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("