Browse Source

vue-element-admin

master
zhizhi wu 4 years ago
parent
commit
41a4c8faf6
  1. 29
      .gitignore
  2. 12
      scheduler/pom.xml
  3. 2
      scheduler/src/main/java/com/ccsens/scheduler/SchedulerApplication.java
  4. 2
      scheduler/src/main/java/com/ccsens/scheduler/api/DebugController.java
  5. 5
      scheduler/src/main/java/com/ccsens/scheduler/api/JobController.java
  6. 42
      scheduler/src/main/java/com/ccsens/scheduler/bean/dto/QuartzJob.java
  7. 11
      scheduler/src/main/java/com/ccsens/scheduler/bean/po/Task.java
  8. 70
      scheduler/src/main/java/com/ccsens/scheduler/bean/po/TaskExample.java
  9. 16
      scheduler/src/main/java/com/ccsens/scheduler/config/BeanConfig.java
  10. 146
      scheduler/src/main/java/com/ccsens/scheduler/config/ControllerExceptionHandler.java
  11. 764
      scheduler/src/main/java/com/ccsens/scheduler/config/DruidProps.java
  12. 48
      scheduler/src/main/java/com/ccsens/scheduler/config/MyPropertySourceFactory.java
  13. 76
      scheduler/src/main/java/com/ccsens/scheduler/config/RedisConfig.java
  14. 154
      scheduler/src/main/java/com/ccsens/scheduler/config/ServletConfig.java
  15. 3
      scheduler/src/main/java/com/ccsens/scheduler/config/SpringConfig.java
  16. 110
      scheduler/src/main/java/com/ccsens/scheduler/config/SwaggerConfigure.java
  17. 21
      scheduler/src/main/java/com/ccsens/scheduler/intercept/MybatisInterceptor.java
  18. 52
      scheduler/src/main/java/com/ccsens/scheduler/service/CoreJobService.java
  19. 31
      scheduler/src/main/java/com/ccsens/scheduler/service/JobService.java
  20. 2
      scheduler/src/main/java/com/ccsens/scheduler/util/CodeEnum.java
  21. 11
      scheduler/src/main/java/com/ccsens/scheduler/util/Constant.java
  22. 204
      scheduler/src/main/java/com/ccsens/scheduler/util/JsonResponse.java
  23. 46
      scheduler/src/main/java/com/ccsens/scheduler/util/PropUtil.java
  24. 25
      scheduler/src/main/java/com/ccsens/scheduler/util/QuartzJobUtil.java
  25. 1500
      scheduler/src/main/java/com/ccsens/scheduler/util/RedisUtil.java
  26. 312
      scheduler/src/main/java/com/ccsens/scheduler/util/RestTemplateUtil.java
  27. 59
      scheduler/src/main/java/com/ccsens/scheduler/util/SmsUtil.java
  28. 4
      scheduler/src/main/resources/application-dev.yml
  29. 4
      scheduler/src/main/resources/config/mail.setting
  30. 31
      scheduler/src/main/resources/mapper_raw/TaskMapper.xml
  31. 13
      scheduler/src/main/resources/notice/notice.yml
  32. 14
      scheduler/vue-element-admin-master/.editorconfig
  33. 5
      scheduler/vue-element-admin-master/.env.development
  34. 6
      scheduler/vue-element-admin-master/.env.production
  35. 8
      scheduler/vue-element-admin-master/.env.staging
  36. 4
      scheduler/vue-element-admin-master/.eslintignore
  37. 198
      scheduler/vue-element-admin-master/.eslintrc.js
  38. 23
      scheduler/vue-element-admin-master/.gitignore
  39. 5
      scheduler/vue-element-admin-master/.travis.yml
  40. 21
      scheduler/vue-element-admin-master/LICENSE
  41. 228
      scheduler/vue-element-admin-master/README.es.md
  42. 224
      scheduler/vue-element-admin-master/README.ja.md
  43. 250
      scheduler/vue-element-admin-master/README.md
  44. 273
      scheduler/vue-element-admin-master/README.zh-CN.md
  45. 14
      scheduler/vue-element-admin-master/babel.config.js
  46. 35
      scheduler/vue-element-admin-master/build/index.js
  47. 24
      scheduler/vue-element-admin-master/jest.config.js
  48. 9
      scheduler/vue-element-admin-master/jsconfig.json
  49. 116
      scheduler/vue-element-admin-master/mock/article.js
  50. 60
      scheduler/vue-element-admin-master/mock/index.js
  51. 81
      scheduler/vue-element-admin-master/mock/mock-server.js
  52. 51
      scheduler/vue-element-admin-master/mock/remote-search.js
  53. 98
      scheduler/vue-element-admin-master/mock/role/index.js
  54. 530
      scheduler/vue-element-admin-master/mock/role/routes.js
  55. 84
      scheduler/vue-element-admin-master/mock/user.js
  56. 48
      scheduler/vue-element-admin-master/mock/utils.js
  57. 111
      scheduler/vue-element-admin-master/package.json
  58. 26
      scheduler/vue-element-admin-master/plop-templates/component/index.hbs
  59. 55
      scheduler/vue-element-admin-master/plop-templates/component/prompt.js
  60. 16
      scheduler/vue-element-admin-master/plop-templates/store/index.hbs
  61. 62
      scheduler/vue-element-admin-master/plop-templates/store/prompt.js
  62. 2
      scheduler/vue-element-admin-master/plop-templates/utils.js
  63. 26
      scheduler/vue-element-admin-master/plop-templates/view/index.hbs
  64. 55
      scheduler/vue-element-admin-master/plop-templates/view/prompt.js
  65. 9
      scheduler/vue-element-admin-master/plopfile.js
  66. 5
      scheduler/vue-element-admin-master/postcss.config.js
  67. BIN
      scheduler/vue-element-admin-master/public/favicon.ico
  68. 15
      scheduler/vue-element-admin-master/public/index.html
  69. 11
      scheduler/vue-element-admin-master/src/App.vue
  70. 41
      scheduler/vue-element-admin-master/src/api/article.js
  71. 8
      scheduler/vue-element-admin-master/src/api/qiniu.js
  72. 17
      scheduler/vue-element-admin-master/src/api/remote-search.js
  73. 38
      scheduler/vue-element-admin-master/src/api/role.js
  74. 24
      scheduler/vue-element-admin-master/src/api/user.js
  75. BIN
      scheduler/vue-element-admin-master/src/assets/401_images/401.gif
  76. BIN
      scheduler/vue-element-admin-master/src/assets/404_images/404.png
  77. BIN
      scheduler/vue-element-admin-master/src/assets/404_images/404_cloud.png
  78. BIN
      scheduler/vue-element-admin-master/src/assets/custom-theme/fonts/element-icons.ttf
  79. BIN
      scheduler/vue-element-admin-master/src/assets/custom-theme/fonts/element-icons.woff
  80. 1
      scheduler/vue-element-admin-master/src/assets/custom-theme/index.css
  81. 111
      scheduler/vue-element-admin-master/src/components/BackToTop/index.vue
  82. 82
      scheduler/vue-element-admin-master/src/components/Breadcrumb/index.vue
  83. 155
      scheduler/vue-element-admin-master/src/components/Charts/Keyboard.vue
  84. 227
      scheduler/vue-element-admin-master/src/components/Charts/LineMarker.vue
  85. 271
      scheduler/vue-element-admin-master/src/components/Charts/MixChart.vue
  86. 56
      scheduler/vue-element-admin-master/src/components/Charts/mixins/resize.js
  87. 166
      scheduler/vue-element-admin-master/src/components/DndList/index.vue
  88. 65
      scheduler/vue-element-admin-master/src/components/DragSelect/index.vue
  89. 297
      scheduler/vue-element-admin-master/src/components/Dropzone/index.vue
  90. 78
      scheduler/vue-element-admin-master/src/components/ErrorLog/index.vue
  91. 54
      scheduler/vue-element-admin-master/src/components/GithubCorner/index.vue
  92. 44
      scheduler/vue-element-admin-master/src/components/Hamburger/index.vue
  93. 180
      scheduler/vue-element-admin-master/src/components/HeaderSearch/index.vue
  94. 1779
      scheduler/vue-element-admin-master/src/components/ImageCropper/index.vue
  95. 19
      scheduler/vue-element-admin-master/src/components/ImageCropper/utils/data2blob.js
  96. 39
      scheduler/vue-element-admin-master/src/components/ImageCropper/utils/effectRipple.js
  97. 232
      scheduler/vue-element-admin-master/src/components/ImageCropper/utils/language.js
  98. 7
      scheduler/vue-element-admin-master/src/components/ImageCropper/utils/mimes.js
  99. 77
      scheduler/vue-element-admin-master/src/components/JsonEditor/index.vue
  100. 99
      scheduler/vue-element-admin-master/src/components/Kanban/index.vue

29
.gitignore

@ -29,4 +29,33 @@ target/*
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
src/main/resources/static/
src/main/resources/static/*
# vue
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

12
scheduler/pom.xml

@ -12,6 +12,12 @@
<artifactId>scheduler</artifactId>
<dependencies>
<!--util-->
<dependency>
<artifactId>util</artifactId>
<groupId>com.ccsens</groupId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--引入quartz定时框架-->
<dependency>
<groupId>org.springframework.boot</groupId>
@ -176,11 +182,7 @@
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.5.0-b01</version>
</dependency>
</dependencies>
<build>

2
scheduler/src/main/java/com/ccsens/scheduler/SchedulerApplication.java

@ -16,7 +16,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@MapperScan(basePackages = {"com.ccsens.scheduler.persist.*"})
@ServletComponentScan
@EnableAsync
@SpringBootApplication(scanBasePackages = "com.ccsens.scheduler")
@SpringBootApplication(scanBasePackages = "com.ccsens")
public class SchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);

2
scheduler/src/main/java/com/ccsens/scheduler/api/DebugController.java

@ -1,6 +1,7 @@
package com.ccsens.scheduler.api;
import com.ccsens.util.JsonResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
@ -10,7 +11,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import com.ccsens.scheduler.util.JsonResponse;
@Api(tags = "DEBUG" , description = "DebugController | ")
@RestController

5
scheduler/src/main/java/com/ccsens/scheduler/api/JobController.java

@ -4,8 +4,7 @@ import com.ccsens.scheduler.bean.dto.QuartzJob;
import com.ccsens.scheduler.bean.dto.QueryDto;
import com.ccsens.scheduler.service.IJobService;
import com.ccsens.scheduler.util.CodeEnum;
import com.ccsens.scheduler.util.JsonResponse;
import com.ccsens.scheduler.util.QuartzJobUtil;
import com.ccsens.util.JsonResponse;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
@ -49,7 +48,7 @@ public class JobController {
log.info("修改任务:{}", dto);
CodeEnum codeEnum = jobService.modify(dto.getParam(), dto.getUserId());
log.info("修改任务结果:{}", codeEnum);
return JsonResponse.newInstance().ok();
return JsonResponse.newInstance().ok(codeEnum);
}
@ApiOperation(value = "/停止任务",notes = "")

42
scheduler/src/main/java/com/ccsens/scheduler/bean/dto/QuartzJob.java

@ -11,6 +11,8 @@ import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.springframework.util.ClassUtils;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import java.util.Date;
@ -39,15 +41,30 @@ public class QuartzJob {
private long startTime;
@ApiModelProperty("触发器结束时间")
private long endTime;
@ApiModelProperty("执行定时任务的具体操作")
private byte job = 0;
@ApiModelProperty("自动迁移 0:不自动迁移 1:自动迁移")
private byte autoMove = 1;
@NotEmpty
@ApiModelProperty("cron表达式")
private String cron;
@ApiModelProperty("misfire对应的处理规则")
private String misfirePolicy = "withMisfireHandlingInstructionDoNothing";
@Min(0)
@Max(0)
@ApiModelProperty("执行定时任务的具体操作,0:任务通知")
private byte job = 0;
@Min(0)
@Max(1)
@ApiModelProperty("自动迁移 0:不自动迁移 1:自动迁移")
private byte autoMove = 1;
@Min(0)
@Max(3)
@ApiModelProperty("通知方式0:http 1:mq 2:邮件 3:短信")
private byte notifyWay = 0;
@ApiModelProperty("通知路径/mq/收件人/手机号")
private String notifyUrl;
@ApiModelProperty("通知内容:http:body+json, mq:字符串")
private String notifyParam;
@ApiModelProperty("job的附加信息")
private JobDataMap jobDataMap = new JobDataMap();
/**
@ -60,7 +77,6 @@ public class QuartzJob {
|| StrUtil.isEmpty(triggerName)
|| StrUtil.isEmpty(triggerGroupName)
|| StrUtil.isEmpty(cron)
|| !ClassUtils.hasMethod(Job.class, "execute", JobExecutionContext.class)
);
}
}
@ -80,6 +96,22 @@ public class QuartzJob {
private long startTime;
@ApiModelProperty("触发器结束时间")
private long endTime;
@Min(0)
@Max(0)
@ApiModelProperty("执行定时任务的具体操作,0:任务通知")
private byte job = 0;
@Min(0)
@Max(1)
@ApiModelProperty("自动迁移 0:不自动迁移 1:自动迁移")
private byte autoMove = 1;
@Min(0)
@Max(3)
@ApiModelProperty("通知方式0:http 1:mq 2:邮件 3:短信")
private byte notifyWay = 0;
@ApiModelProperty("通知路径/mq/收件人/手机号")
private String notifyUrl;
@ApiModelProperty("通知内容:http:body+json, mq:字符串")
private String notifyParam;
}
@Data

11
scheduler/src/main/java/com/ccsens/scheduler/bean/po/Task.java

@ -28,6 +28,8 @@ public class Task implements Serializable {
private Byte notifyWay;
private String notifier;
private String notifyUrl;
private String notifyParam;
@ -138,6 +140,14 @@ public class Task implements Serializable {
this.notifyWay = notifyWay;
}
public String getNotifier() {
return notifier;
}
public void setNotifier(String notifier) {
this.notifier = notifier == null ? null : notifier.trim();
}
public String getNotifyUrl() {
return notifyUrl;
}
@ -204,6 +214,7 @@ public class Task implements Serializable {
sb.append(", endTime=").append(endTime);
sb.append(", autoMove=").append(autoMove);
sb.append(", notifyWay=").append(notifyWay);
sb.append(", notifier=").append(notifier);
sb.append(", notifyUrl=").append(notifyUrl);
sb.append(", notifyParam=").append(notifyParam);
sb.append(", appId=").append(appId);

70
scheduler/src/main/java/com/ccsens/scheduler/bean/po/TaskExample.java

@ -885,6 +885,76 @@ public class TaskExample {
return (Criteria) this;
}
public Criteria andNotifierIsNull() {
addCriterion("notifier is null");
return (Criteria) this;
}
public Criteria andNotifierIsNotNull() {
addCriterion("notifier is not null");
return (Criteria) this;
}
public Criteria andNotifierEqualTo(String value) {
addCriterion("notifier =", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierNotEqualTo(String value) {
addCriterion("notifier <>", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierGreaterThan(String value) {
addCriterion("notifier >", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierGreaterThanOrEqualTo(String value) {
addCriterion("notifier >=", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierLessThan(String value) {
addCriterion("notifier <", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierLessThanOrEqualTo(String value) {
addCriterion("notifier <=", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierLike(String value) {
addCriterion("notifier like", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierNotLike(String value) {
addCriterion("notifier not like", value, "notifier");
return (Criteria) this;
}
public Criteria andNotifierIn(List<String> values) {
addCriterion("notifier in", values, "notifier");
return (Criteria) this;
}
public Criteria andNotifierNotIn(List<String> values) {
addCriterion("notifier not in", values, "notifier");
return (Criteria) this;
}
public Criteria andNotifierBetween(String value1, String value2) {
addCriterion("notifier between", value1, value2, "notifier");
return (Criteria) this;
}
public Criteria andNotifierNotBetween(String value1, String value2) {
addCriterion("notifier not between", value1, value2, "notifier");
return (Criteria) this;
}
public Criteria andNotifyUrlIsNull() {
addCriterion("notify_url is null");
return (Criteria) this;

16
scheduler/src/main/java/com/ccsens/scheduler/config/BeanConfig.java

@ -3,6 +3,9 @@ package com.ccsens.scheduler.config;
import com.ccsens.scheduler.intercept.MybatisInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @description:
@ -20,4 +23,17 @@ public class BeanConfig {
MybatisInterceptor interceptor = new MybatisInterceptor();
return interceptor;
}
// @Bean
// public RestTemplate restTemplate(ClientHttpRequestFactory factory){
// return new RestTemplate(factory);
// }
//
// @Bean
// public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
// SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// factory.setReadTimeout(10000);
// factory.setConnectTimeout(10000);
// return factory;
// }
}

146
scheduler/src/main/java/com/ccsens/scheduler/config/ControllerExceptionHandler.java

@ -1,73 +1,73 @@
package com.ccsens.scheduler.config;
import com.ccsens.scheduler.exception.BaseException;
import com.ccsens.scheduler.util.CodeEnum;
import com.ccsens.scheduler.util.JsonResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
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;
/**
* @author wu
*/
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
@ResponseBody
public JsonResponse validateExceptionHandler(MethodArgumentNotValidException e){
BindingResult bindingResult = e.getBindingResult();
log.error("MethodArgumentNotValidException",e);
return JsonResponse.newInstance().fail(CodeEnum.PARAM_NULL.getCode(),bindingResult.getFieldError().getDefaultMessage());
}
@ExceptionHandler(value = BindException.class)
@ResponseBody
public JsonResponse handleBindException(BindException e) {
// ex.getFieldError():随机返回一个对象属性的异常信息。如果要一次性返回所有对象属性异常信息,则调用ex.getAllErrors()
FieldError fieldError = e.getFieldError();
StringBuilder sb = new StringBuilder();
sb.append(fieldError.getField()).append("=[").append(fieldError.getRejectedValue()).append("]")
.append(fieldError.getDefaultMessage());
e.printStackTrace();
log.error("BindException", e);
return JsonResponse.newInstance().fail(-11,sb.toString());
}
@ExceptionHandler(value = HttpMessageNotReadableException.class)
@ResponseBody
public JsonResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
e.printStackTrace();
log.error("HttpMessageNotReadableException", e);
return JsonResponse.newInstance().fail(-12,e.getMessage());
}
@ExceptionHandler(value = BaseException.class)
@ResponseBody
public JsonResponse jsonBaseExceptionHandler(HttpServletRequest req, BaseException e) {
e.printStackTrace();
log.error("BaseException",e);
if (e.getCodeEnum() != null) {
return JsonResponse.newInstance().ok(e.getCodeEnum());
}
return JsonResponse.newInstance().fail(e.getCode(),e.getMessage());
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public JsonResponse jsonExceptionHandler(HttpServletRequest req, Exception e) {
e.printStackTrace();
log.error("Exception",e);
return JsonResponse.newInstance().fail(-1,e.getMessage());
}
}
//package com.ccsens.scheduler.config;
//
//import com.ccsens.scheduler.exception.BaseException;
//import com.ccsens.scheduler.util.CodeEnum;
//import com.ccsens.scheduler.util.JsonResponse;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.http.converter.HttpMessageNotReadableException;
//import org.springframework.validation.BindException;
//import org.springframework.validation.BindingResult;
//import org.springframework.validation.FieldError;
//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;
//
///**
// * @author wu
// */
//@Slf4j
//@ControllerAdvice
//public class ControllerExceptionHandler {
//
//
// @ExceptionHandler(value = MethodArgumentNotValidException.class)
// @ResponseBody
// public JsonResponse validateExceptionHandler(MethodArgumentNotValidException e){
// BindingResult bindingResult = e.getBindingResult();
// log.error("MethodArgumentNotValidException",e);
// return JsonResponse.newInstance().fail(CodeEnum.PARAM_NULL.getCode(),bindingResult.getFieldError().getDefaultMessage());
// }
//
// @ExceptionHandler(value = BindException.class)
// @ResponseBody
// public JsonResponse handleBindException(BindException e) {
// // ex.getFieldError():随机返回一个对象属性的异常信息。如果要一次性返回所有对象属性异常信息,则调用ex.getAllErrors()
// FieldError fieldError = e.getFieldError();
// StringBuilder sb = new StringBuilder();
// sb.append(fieldError.getField()).append("=[").append(fieldError.getRejectedValue()).append("]")
// .append(fieldError.getDefaultMessage());
// e.printStackTrace();
// log.error("BindException", e);
// return JsonResponse.newInstance().fail(-11,sb.toString());
// }
//
// @ExceptionHandler(value = HttpMessageNotReadableException.class)
// @ResponseBody
// public JsonResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
// e.printStackTrace();
// log.error("HttpMessageNotReadableException", e);
// return JsonResponse.newInstance().fail(-12,e.getMessage());
// }
//
// @ExceptionHandler(value = BaseException.class)
// @ResponseBody
// public JsonResponse jsonBaseExceptionHandler(HttpServletRequest req, BaseException e) {
// e.printStackTrace();
// log.error("BaseException",e);
// if (e.getCodeEnum() != null) {
// return JsonResponse.newInstance().ok(e.getCodeEnum());
// }
// return JsonResponse.newInstance().fail(e.getCode(),e.getMessage());
// }
//
// @ExceptionHandler(value = Exception.class)
// @ResponseBody
// public JsonResponse jsonExceptionHandler(HttpServletRequest req, Exception e) {
// e.printStackTrace();
// log.error("Exception",e);
// return JsonResponse.newInstance().fail(-1,e.getMessage());
// }
//}

764
scheduler/src/main/java/com/ccsens/scheduler/config/DruidProps.java

@ -1,382 +1,382 @@
package com.ccsens.scheduler.config;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.druid.pool.DruidDataSource;
import com.ccsens.scheduler.util.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.SQLException;
@Component
@ConfigurationProperties(prefix="spring.datasource.druid")
@PropertySource(value = {"classpath:druid-${spring.profiles.active}.yml"}, factory = MyPropertySourceFactory.class)
public class DruidProps {
private Logger logger = LoggerFactory.getLogger(DruidProps.class);
private String dynamicUrl;
private String url;
private String username;
private String password;
private String driverClassName;
private int initialSize;
private int minIdle;
private int maxActive;
private int maxWait;
private int timeBetweenEvictionRunsMillis;
private int minEvictableIdleTimeMillis;
private String validationQuery;
private boolean testWhileIdle;
private boolean testOnBorrow;
private boolean testOnReturn;
private boolean poolPreparedStatements;
private int maxPoolPreparedStatementPerConnectionSize;
private String filters;
private String connectionProperties;
private String logSlowSql;
private String servletName;
private String servletUrlMapping;
private String servletLoginUsername;
private String servletLoginPassword;
private String servletLogSlowSql;
private String servletResetEnable;
private String filterName;
private String filterUrlPattern;
private String filterExclusions;
private String filterProfileEnable;
private String env;
public DataSource createDruidDataSource() {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(url);
datasource.setUsername(username);
if (StrUtil.isNotEmpty(password)) {
String key = System.getenv(env);
SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, Base64.decode(key));
String decryptStr = aes.decryptStr(password, CharsetUtil.CHARSET_UTF_8);
datasource.setPassword(decryptStr);
} else {
datasource.setPassword("");
}
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter : {0}", e);
e.printStackTrace();
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
public DataSource createDynamicDruidDataSource(String schema) {
DruidDataSource datasource = new DruidDataSource();
String url = dynamicUrl.replace(Constant.DYNAMIC_DATASOURCE_SCHEMA_KEY,schema);
datasource.setUrl(url);
datasource.setUsername(username);
datasource.setPassword(password);
datasource.setDriverClassName(driverClassName);
//configuration
datasource.setInitialSize(initialSize);
datasource.setMinIdle(minIdle);
datasource.setMaxActive(maxActive);
datasource.setMaxWait(maxWait);
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
datasource.setValidationQuery(validationQuery);
datasource.setTestWhileIdle(testWhileIdle);
datasource.setTestOnBorrow(testOnBorrow);
datasource.setTestOnReturn(testOnReturn);
datasource.setPoolPreparedStatements(poolPreparedStatements);
datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
try {
datasource.setFilters(filters);
} catch (SQLException e) {
logger.error("druid configuration initialization filter : {0}", e);
e.printStackTrace();
}
datasource.setConnectionProperties(connectionProperties);
return datasource;
}
//----------------------------------------------------
public String getDynamicUrl() {
return dynamicUrl;
}
public void setDynamicUrl(String dynamicUrl) {
this.dynamicUrl = dynamicUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
public int getInitialSize() {
return initialSize;
}
public void setInitialSize(int initialSize) {
this.initialSize = initialSize;
}
public int getMinIdle() {
return minIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public int getMaxActive() {
return maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public int getMaxWait() {
return maxWait;
}
public void setMaxWait(int maxWait) {
this.maxWait = maxWait;
}
public int getTimeBetweenEvictionRunsMillis() {
return timeBetweenEvictionRunsMillis;
}
public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
}
public int getMinEvictableIdleTimeMillis() {
return minEvictableIdleTimeMillis;
}
public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
}
public String getValidationQuery() {
return validationQuery;
}
public void setValidationQuery(String validationQuery) {
this.validationQuery = validationQuery;
}
public boolean isTestWhileIdle() {
return testWhileIdle;
}
public void setTestWhileIdle(boolean testWhileIdle) {
this.testWhileIdle = testWhileIdle;
}
public boolean isTestOnBorrow() {
return testOnBorrow;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public boolean isTestOnReturn() {
return testOnReturn;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public boolean isPoolPreparedStatements() {
return poolPreparedStatements;
}
public void setPoolPreparedStatements(boolean poolPreparedStatements) {
this.poolPreparedStatements = poolPreparedStatements;
}
public int getMaxPoolPreparedStatementPerConnectionSize() {
return maxPoolPreparedStatementPerConnectionSize;
}
public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
}
public String getFilters() {
return filters;
}
public void setFilters(String filters) {
this.filters = filters;
}
public String getConnectionProperties() {
return connectionProperties;
}
public void setConnectionProperties(String connectionProperties) {
this.connectionProperties = connectionProperties;
}
public String getLogSlowSql() {
return logSlowSql;
}
public void setLogSlowSql(String logSlowSql) {
this.logSlowSql = logSlowSql;
}
public String getServletUrlMapping() {
return servletUrlMapping;
}
public void setServletUrlMapping(String servletUrlMapping) {
this.servletUrlMapping = servletUrlMapping;
}
public String getServletLoginUsername() {
return servletLoginUsername;
}
public void setServletLoginUsername(String servletLoginUsername) {
this.servletLoginUsername = servletLoginUsername;
}
public String getServletLoginPassword() {
return servletLoginPassword;
}
public void setServletLoginPassword(String servletLoginPassword) {
this.servletLoginPassword = servletLoginPassword;
}
public String getServletLogSlowSql() {
return servletLogSlowSql;
}
public void setServletLogSlowSql(String servletLogSlowSql) {
this.servletLogSlowSql = servletLogSlowSql;
}
public String getServletResetEnable() {
return servletResetEnable;
}
public void setServletResetEnable(String servletResetEnable) {
this.servletResetEnable = servletResetEnable;
}
public String getServletName() {
return servletName;
}
public void setServletName(String servletName) {
this.servletName = servletName;
}
public String getFilterName() {
return filterName;
}
public void setFilterName(String filterName) {
this.filterName = filterName;
}
public String getFilterUrlPattern() {
return filterUrlPattern;
}
public void setFilterUrlPattern(String filterUrlPattern) {
this.filterUrlPattern = filterUrlPattern;
}
public String getFilterExclusions() {
return filterExclusions;
}
public void setFilterExclusions(String filterExclusions) {
this.filterExclusions = filterExclusions;
}
public String getFilterProfileEnable() {
return filterProfileEnable;
}
public void setFilterProfileEnable(String filterProfileEnable) {
this.filterProfileEnable = filterProfileEnable;
}
public String getEnv() {
return env;
}
public void setEnv(String env) {
this.env = env;
}
}
//package com.ccsens.scheduler.config;
//
//import cn.hutool.core.codec.Base64;
//import cn.hutool.core.util.CharsetUtil;
//import cn.hutool.core.util.StrUtil;
//import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
//import cn.hutool.crypto.symmetric.SymmetricCrypto;
//import com.alibaba.druid.pool.DruidDataSource;
//import com.ccsens.scheduler.util.Constant;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.boot.context.properties.ConfigurationProperties;
//import org.springframework.context.annotation.PropertySource;
//import org.springframework.stereotype.Component;
//
//import javax.sql.DataSource;
//import java.sql.SQLException;
//
//@Component
//@ConfigurationProperties(prefix="spring.datasource.druid")
//@PropertySource(value = {"classpath:druid-${spring.profiles.active}.yml"}, factory = MyPropertySourceFactory.class)
//public class DruidProps {
// private Logger logger = LoggerFactory.getLogger(DruidProps.class);
//
// private String dynamicUrl;
// private String url;
// private String username;
// private String password;
// private String driverClassName;
// private int initialSize;
// private int minIdle;
// private int maxActive;
// private int maxWait;
// private int timeBetweenEvictionRunsMillis;
// private int minEvictableIdleTimeMillis;
// private String validationQuery;
// private boolean testWhileIdle;
// private boolean testOnBorrow;
// private boolean testOnReturn;
// private boolean poolPreparedStatements;
// private int maxPoolPreparedStatementPerConnectionSize;
// private String filters;
// private String connectionProperties;
// private String logSlowSql;
//
// private String servletName;
// private String servletUrlMapping;
// private String servletLoginUsername;
// private String servletLoginPassword;
// private String servletLogSlowSql;
// private String servletResetEnable;
//
// private String filterName;
// private String filterUrlPattern;
// private String filterExclusions;
// private String filterProfileEnable;
//
// private String env;
//
// public DataSource createDruidDataSource() {
// DruidDataSource datasource = new DruidDataSource();
//
// datasource.setUrl(url);
// datasource.setUsername(username);
// if (StrUtil.isNotEmpty(password)) {
// String key = System.getenv(env);
// SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, Base64.decode(key));
// String decryptStr = aes.decryptStr(password, CharsetUtil.CHARSET_UTF_8);
// datasource.setPassword(decryptStr);
// } else {
// datasource.setPassword("");
// }
//
// datasource.setDriverClassName(driverClassName);
//
// //configuration
// datasource.setInitialSize(initialSize);
// datasource.setMinIdle(minIdle);
// datasource.setMaxActive(maxActive);
// datasource.setMaxWait(maxWait);
// datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// datasource.setValidationQuery(validationQuery);
// datasource.setTestWhileIdle(testWhileIdle);
// datasource.setTestOnBorrow(testOnBorrow);
// datasource.setTestOnReturn(testOnReturn);
// datasource.setPoolPreparedStatements(poolPreparedStatements);
// datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
// try {
// datasource.setFilters(filters);
// } catch (SQLException e) {
// logger.error("druid configuration initialization filter : {0}", e);
// e.printStackTrace();
// }
// datasource.setConnectionProperties(connectionProperties);
//
// return datasource;
// }
//
// public DataSource createDynamicDruidDataSource(String schema) {
// DruidDataSource datasource = new DruidDataSource();
//
// String url = dynamicUrl.replace(Constant.DYNAMIC_DATASOURCE_SCHEMA_KEY,schema);
// datasource.setUrl(url);
// datasource.setUsername(username);
// datasource.setPassword(password);
// datasource.setDriverClassName(driverClassName);
//
// //configuration
// datasource.setInitialSize(initialSize);
// datasource.setMinIdle(minIdle);
// datasource.setMaxActive(maxActive);
// datasource.setMaxWait(maxWait);
// datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// datasource.setValidationQuery(validationQuery);
// datasource.setTestWhileIdle(testWhileIdle);
// datasource.setTestOnBorrow(testOnBorrow);
// datasource.setTestOnReturn(testOnReturn);
// datasource.setPoolPreparedStatements(poolPreparedStatements);
// datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
// try {
// datasource.setFilters(filters);
// } catch (SQLException e) {
// logger.error("druid configuration initialization filter : {0}", e);
// e.printStackTrace();
// }
// datasource.setConnectionProperties(connectionProperties);
//
// return datasource;
// }
//
// //----------------------------------------------------
//
// public String getDynamicUrl() {
// return dynamicUrl;
// }
//
// public void setDynamicUrl(String dynamicUrl) {
// this.dynamicUrl = dynamicUrl;
// }
//
// public String getUrl() {
// return url;
// }
//
// public void setUrl(String url) {
// this.url = url;
// }
//
// public String getUsername() {
// return username;
// }
//
// public void setUsername(String username) {
// this.username = username;
// }
//
// public String getPassword() {
// return password;
// }
//
// public void setPassword(String password) {
// this.password = password;
// }
//
// public String getDriverClassName() {
// return driverClassName;
// }
//
// public void setDriverClassName(String driverClassName) {
// this.driverClassName = driverClassName;
// }
//
// public int getInitialSize() {
// return initialSize;
// }
//
// public void setInitialSize(int initialSize) {
// this.initialSize = initialSize;
// }
//
// public int getMinIdle() {
// return minIdle;
// }
//
// public void setMinIdle(int minIdle) {
// this.minIdle = minIdle;
// }
//
// public int getMaxActive() {
// return maxActive;
// }
//
// public void setMaxActive(int maxActive) {
// this.maxActive = maxActive;
// }
//
// public int getMaxWait() {
// return maxWait;
// }
//
// public void setMaxWait(int maxWait) {
// this.maxWait = maxWait;
// }
//
// public int getTimeBetweenEvictionRunsMillis() {
// return timeBetweenEvictionRunsMillis;
// }
//
// public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
// this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
// }
//
// public int getMinEvictableIdleTimeMillis() {
// return minEvictableIdleTimeMillis;
// }
//
// public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
// this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
// }
//
// public String getValidationQuery() {
// return validationQuery;
// }
//
// public void setValidationQuery(String validationQuery) {
// this.validationQuery = validationQuery;
// }
//
// public boolean isTestWhileIdle() {
// return testWhileIdle;
// }
//
// public void setTestWhileIdle(boolean testWhileIdle) {
// this.testWhileIdle = testWhileIdle;
// }
//
// public boolean isTestOnBorrow() {
// return testOnBorrow;
// }
//
// public void setTestOnBorrow(boolean testOnBorrow) {
// this.testOnBorrow = testOnBorrow;
// }
//
// public boolean isTestOnReturn() {
// return testOnReturn;
// }
//
// public void setTestOnReturn(boolean testOnReturn) {
// this.testOnReturn = testOnReturn;
// }
//
// public boolean isPoolPreparedStatements() {
// return poolPreparedStatements;
// }
//
// public void setPoolPreparedStatements(boolean poolPreparedStatements) {
// this.poolPreparedStatements = poolPreparedStatements;
// }
//
// public int getMaxPoolPreparedStatementPerConnectionSize() {
// return maxPoolPreparedStatementPerConnectionSize;
// }
//
// public void setMaxPoolPreparedStatementPerConnectionSize(int maxPoolPreparedStatementPerConnectionSize) {
// this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;
// }
//
// public String getFilters() {
// return filters;
// }
//
// public void setFilters(String filters) {
// this.filters = filters;
// }
//
// public String getConnectionProperties() {
// return connectionProperties;
// }
//
// public void setConnectionProperties(String connectionProperties) {
// this.connectionProperties = connectionProperties;
// }
//
// public String getLogSlowSql() {
// return logSlowSql;
// }
//
// public void setLogSlowSql(String logSlowSql) {
// this.logSlowSql = logSlowSql;
// }
//
// public String getServletUrlMapping() {
// return servletUrlMapping;
// }
//
// public void setServletUrlMapping(String servletUrlMapping) {
// this.servletUrlMapping = servletUrlMapping;
// }
//
// public String getServletLoginUsername() {
// return servletLoginUsername;
// }
//
// public void setServletLoginUsername(String servletLoginUsername) {
// this.servletLoginUsername = servletLoginUsername;
// }
//
// public String getServletLoginPassword() {
// return servletLoginPassword;
// }
//
// public void setServletLoginPassword(String servletLoginPassword) {
// this.servletLoginPassword = servletLoginPassword;
// }
//
// public String getServletLogSlowSql() {
// return servletLogSlowSql;
// }
//
// public void setServletLogSlowSql(String servletLogSlowSql) {
// this.servletLogSlowSql = servletLogSlowSql;
// }
//
// public String getServletResetEnable() {
// return servletResetEnable;
// }
//
// public void setServletResetEnable(String servletResetEnable) {
// this.servletResetEnable = servletResetEnable;
// }
//
// public String getServletName() {
// return servletName;
// }
//
// public void setServletName(String servletName) {
// this.servletName = servletName;
// }
//
// public String getFilterName() {
// return filterName;
// }
//
// public void setFilterName(String filterName) {
// this.filterName = filterName;
// }
//
// public String getFilterUrlPattern() {
// return filterUrlPattern;
// }
//
// public void setFilterUrlPattern(String filterUrlPattern) {
// this.filterUrlPattern = filterUrlPattern;
// }
//
// public String getFilterExclusions() {
// return filterExclusions;
// }
//
// public void setFilterExclusions(String filterExclusions) {
// this.filterExclusions = filterExclusions;
// }
//
// public String getFilterProfileEnable() {
// return filterProfileEnable;
// }
//
// public void setFilterProfileEnable(String filterProfileEnable) {
// this.filterProfileEnable = filterProfileEnable;
// }
//
// public String getEnv() {
// return env;
// }
//
// public void setEnv(String env) {
// this.env = env;
// }
//}

48
scheduler/src/main/java/com/ccsens/scheduler/config/MyPropertySourceFactory.java

@ -1,24 +1,24 @@
package com.ccsens.scheduler.config;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
/**
* @description:
* @author: wuHuiJuan
* @create: 2019/12/02 10:35
*/
public class MyPropertySourceFactory implements PropertySourceFactory {
public MyPropertySourceFactory() {
super();
}
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
return new YamlPropertySourceLoader().load(name, encodedResource.getResource()).get(0);
}
}
//package com.ccsens.scheduler.config;
//
//import org.springframework.boot.env.YamlPropertySourceLoader;
//import org.springframework.core.env.PropertySource;
//import org.springframework.core.io.support.EncodedResource;
//import org.springframework.core.io.support.PropertySourceFactory;
//
//import java.io.IOException;
//
///**
// * @description:
// * @author: wuHuiJuan
// * @create: 2019/12/02 10:35
// */
//public class MyPropertySourceFactory implements PropertySourceFactory {
// public MyPropertySourceFactory() {
// super();
// }
//
// @Override
// public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
// return new YamlPropertySourceLoader().load(name, encodedResource.getResource()).get(0);
// }
//}

76
scheduler/src/main/java/com/ccsens/scheduler/config/RedisConfig.java

@ -1,38 +1,38 @@
package com.ccsens.scheduler.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
//package com.ccsens.scheduler.config;
//
//import com.fasterxml.jackson.annotation.JsonAutoDetect;
//import com.fasterxml.jackson.annotation.PropertyAccessor;
//import com.fasterxml.jackson.databind.ObjectMapper;
//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.Jackson2JsonRedisSerializer;
//import org.springframework.data.redis.serializer.StringRedisSerializer;
//
//@Configuration
//public class RedisConfig {
//
// @Bean
// @SuppressWarnings("all")
// public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
// RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
// template.setConnectionFactory(factory);
// Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
// ObjectMapper om = new ObjectMapper();
// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// jackson2JsonRedisSerializer.setObjectMapper(om);
// StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// // key采用String的序列化方式
// template.setKeySerializer(stringRedisSerializer);
// // hash的key也采用String的序列化方式
// template.setHashKeySerializer(stringRedisSerializer);
// // value序列化方式采用jackson
// template.setValueSerializer(jackson2JsonRedisSerializer);
// // hash的value序列化方式采用jackson
// template.setHashValueSerializer(jackson2JsonRedisSerializer);
// template.afterPropertiesSet();
// return template;
// }
//}

154
scheduler/src/main/java/com/ccsens/scheduler/config/ServletConfig.java

@ -1,77 +1,77 @@
package com.ccsens.scheduler.config;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* 在springboot添加过滤器有两种方式
  1通过创建FilterRegistrationBean的方式
1.1 建议使用此种方式统一管理且通过注解的方式若不是本地调试
如果在filter中需要增加cookie可能会存在写不进前端情况
1.2 有多个filter就创建多个FilterRegistrationBean 若需注明filter的执行顺序
可通过registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE - 1)配置
值越大执行顺序越靠后 
2通过注解@WebFilter的方式
  2.1 在启动类上增加@ServletComponentScan注解自动扫描带有过滤器注解的包
2.2 在类上使用@WebFilter和@Order组合实现
3通过注解@WebFilter的方式
  3.1 在类上使用@WebFilter和@Order组合实现
3.2 在类上添加@Component注解
*/
/**
* 原生方案
* @WebServlet @WebListener@WebFilter
* 在启动类上增加@ServletComponentScan注解自动扫描带有Servlet原生方案注解的包
*
* SpringBoot方案
* SpringBoot提供了三种Bean
* FilterRegistrationBean
* ServletRegistrationBean
* ServletListenerRegistrationBean
* 分别对应配置原生的FilterServletListener
*/
/**
* 注册系统过滤器
*/
@Configuration
public class ServletConfig {
@Resource
private DruidProps druidConfig;
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.setName(druidConfig.getFilterName());
reg.addUrlMappings(druidConfig.getServletUrlMapping());
//白名单:
//reg.addInitParameter("allow","127.0.0.1");
//IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
//reg.addInitParameter("deny","192.168.1.73");
reg.addInitParameter("loginUsername", druidConfig.getServletLoginUsername());
reg.addInitParameter("loginPassword", druidConfig.getServletLoginPassword());
reg.addInitParameter("logSlowSql", druidConfig.getServletLogSlowSql());
//是否能够重置数据.
reg.addInitParameter("resetEnable",druidConfig.getServletResetEnable());
return reg;
}
@Bean
public FilterRegistrationBean druidFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.setName(druidConfig.getFilterName());
filterRegistrationBean.addUrlPatterns(druidConfig.getFilterUrlPattern());
filterRegistrationBean.addInitParameter("exclusions", druidConfig.getFilterExclusions());
filterRegistrationBean.addInitParameter("profileEnable", druidConfig.getFilterProfileEnable());
return filterRegistrationBean;
}
}
//package com.ccsens.scheduler.config;
//
//import com.alibaba.druid.support.http.StatViewServlet;
//import com.alibaba.druid.support.http.WebStatFilter;
//import org.springframework.boot.web.servlet.FilterRegistrationBean;
//import org.springframework.boot.web.servlet.ServletRegistrationBean;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//
//import javax.annotation.Resource;
//
///**
// * 在springboot添加过滤器有两种方式:
//   1、通过创建FilterRegistrationBean的方式
// 1.1 建议使用此种方式,统一管理,且通过注解的方式若不是本地调试,
// 如果在filter中需要增加cookie可能会存在写不进前端情况
// 1.2 有多个filter就创建多个FilterRegistrationBean ,若需注明filter的执行顺序,
// 可通过registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE - 1)配置,
// 值越大,执行顺序越靠后 
// 2、通过注解@WebFilter的方式
//   2.1 在启动类上增加@ServletComponentScan注解,自动扫描带有过滤器注解的包
// 2.2 在类上使用@WebFilter和@Order组合实现
// 3、通过注解@WebFilter的方式
//   3.1 在类上使用@WebFilter和@Order组合实现
// 3.2 在类上添加@Component注解
// */
//
///**
// * 原生方案
// * @WebServlet 、@WebListener、@WebFilter
// * 在启动类上增加@ServletComponentScan注解,自动扫描带有Servlet原生方案注解的包
// *
// * SpringBoot方案
// * SpringBoot提供了三种Bean
// * FilterRegistrationBean、
// * ServletRegistrationBean、
// * ServletListenerRegistrationBean
// * 分别对应配置原生的Filter、Servlet、Listener
// */
//
///**
// * 注册系统过滤器
// */
//@Configuration
//public class ServletConfig {
// @Resource
// private DruidProps druidConfig;
//
// @Bean
// public ServletRegistrationBean druidServlet() {
// ServletRegistrationBean reg = new ServletRegistrationBean();
// reg.setServlet(new StatViewServlet());
// reg.setName(druidConfig.getFilterName());
// reg.addUrlMappings(druidConfig.getServletUrlMapping());
// //白名单:
// //reg.addInitParameter("allow","127.0.0.1");
// //IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not permitted to view this page.
// //reg.addInitParameter("deny","192.168.1.73");
// reg.addInitParameter("loginUsername", druidConfig.getServletLoginUsername());
// reg.addInitParameter("loginPassword", druidConfig.getServletLoginPassword());
// reg.addInitParameter("logSlowSql", druidConfig.getServletLogSlowSql());
// //是否能够重置数据.
// reg.addInitParameter("resetEnable",druidConfig.getServletResetEnable());
// return reg;
// }
//
// @Bean
// public FilterRegistrationBean druidFilter() {
// FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
// filterRegistrationBean.setFilter(new WebStatFilter());
// filterRegistrationBean.setName(druidConfig.getFilterName());
// filterRegistrationBean.addUrlPatterns(druidConfig.getFilterUrlPattern());
// filterRegistrationBean.addInitParameter("exclusions", druidConfig.getFilterExclusions());
// filterRegistrationBean.addInitParameter("profileEnable", druidConfig.getFilterProfileEnable());
// return filterRegistrationBean;
// }
//}

3
scheduler/src/main/java/com/ccsens/scheduler/config/SpringConfig.java

@ -3,6 +3,7 @@ package com.ccsens.scheduler.config;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.ccsens.util.config.DruidProps;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
@ -99,6 +100,8 @@ public class SpringConfig implements WebMvcConfigurer {
registry.addResourceHandler("/uploads/**")
.addResourceLocations("file:///home/filedeal/uploads/");
registry.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static/");
}

110
scheduler/src/main/java/com/ccsens/scheduler/config/SwaggerConfigure.java

@ -1,55 +1,55 @@
package com.ccsens.scheduler.config;
import com.ccsens.scheduler.util.Constant;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableSwagger2
@ConditionalOnExpression("${swagger.enable}")
public class SwaggerConfigure {
@Bean
public Docket customDocket() {
//
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors
.basePackage("com.ccsens.scheduler.api"))
.build()
.globalOperationParameters(setHeaderToken());
}
private ApiInfo apiInfo() {
return new ApiInfo("Swagger scheduler",
"This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
"1.0.0",
"http://swagger.io/terms/",
"zhangsan",
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0.html"
);
}
private List<Parameter> setHeaderToken() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name(Constant.HEADER_KEY_TOKEN).description("token")
.defaultValue(Constant.HEADER_KEY_TOKEN_PREFIX)
.modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return pars;
}
}
//package com.ccsens.scheduler.config;
//
//import com.ccsens.scheduler.util.Constant;
//import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//import springfox.documentation.builders.ParameterBuilder;
//import springfox.documentation.builders.RequestHandlerSelectors;
//import springfox.documentation.schema.ModelRef;
//import springfox.documentation.service.ApiInfo;
//import springfox.documentation.service.Parameter;
//import springfox.documentation.spi.DocumentationType;
//import springfox.documentation.spring.web.plugins.Docket;
//import springfox.documentation.swagger2.annotations.EnableSwagger2;
//
//import java.util.ArrayList;
//import java.util.List;
//
//@Configuration
//@EnableSwagger2
//@ConditionalOnExpression("${swagger.enable}")
//public class SwaggerConfigure {
// @Bean
// public Docket customDocket() {
// //
// return new Docket(DocumentationType.SWAGGER_2)
// .apiInfo(apiInfo())
// .select()
// .apis(RequestHandlerSelectors
// .basePackage("com.ccsens.scheduler.api"))
// .build()
// .globalOperationParameters(setHeaderToken());
// }
//
// private ApiInfo apiInfo() {
// return new ApiInfo("Swagger scheduler",
// "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
// "1.0.0",
// "http://swagger.io/terms/",
// "zhangsan",
// "Apache 2.0",
// "http://www.apache.org/licenses/LICENSE-2.0.html"
// );
// }
//
// private List<Parameter> setHeaderToken() {
// ParameterBuilder tokenPar = new ParameterBuilder();
// List<Parameter> pars = new ArrayList<>();
// tokenPar.name(Constant.HEADER_KEY_TOKEN).description("token")
// .defaultValue(Constant.HEADER_KEY_TOKEN_PREFIX)
// .modelRef(new ModelRef("string")).parameterType("header").required(false).build();
// pars.add(tokenPar.build());
// return pars;
// }
//}

21
scheduler/src/main/java/com/ccsens/scheduler/intercept/MybatisInterceptor.java

@ -1,6 +1,7 @@
package com.ccsens.scheduler.intercept;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.ccsens.scheduler.util.Constant;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
@ -17,6 +18,7 @@ import org.apache.ibatis.session.RowBounds;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -58,7 +60,7 @@ public class MybatisInterceptor implements Interceptor {
} else if (statement.getId().endsWith(selectByPrimaryKey)) {
BoundSql boundSql = statement.getBoundSql(args[1]);
String sql = boundSql.getSql() + " and rec_status = 0";
String sql = boundSql.getSql() + " and rec_status in (0, 1)";
MappedStatement newStatement = newMappedStatement(statement, new BoundSqlSqlSource(boundSql));
MetaObject msObject = MetaObject.forObject(newStatement, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),new DefaultReflectorFactory());
msObject.setValue("sqlSource.boundSql.sql", sql);
@ -83,8 +85,11 @@ public class MybatisInterceptor implements Interceptor {
Object paramExample = Class.forName(exampleName).newInstance();
Method createCriteria = paramExample.getClass().getMethod("createCriteria");
Object criteria = createCriteria.invoke(paramExample);
Method andIsDelEqualTo = criteria.getClass().getMethod("andRecStatusEqualTo", Byte.class);
andIsDelEqualTo.invoke(criteria, Constant.REC_STATUS.Normal.value);
Method andIsDelEqualTo = criteria.getClass().getMethod("andRecStatusIn", List.class);
List<Byte> params = new ArrayList<>();
params.add(Constant.REC_STATUS.Normal.value);
params.add(Constant.REC_STATUS.Disabled.value);
andIsDelEqualTo.invoke(criteria, params);
list.add(criteria);
} else {
Object criteria = list.get(0);
@ -94,13 +99,17 @@ public class MybatisInterceptor implements Interceptor {
for (Object param : params) {
Method getCondition = param.getClass().getMethod("getCondition");
Object condition = getCondition.invoke(param);
if ("rec_status =".equals(condition)) {
if (condition instanceof String && ((String) condition).contains("rec_status ")) {
hasDel = true;
}
}
if (!hasDel) {
Method andIsDelEqualTo = criteria.getClass().getMethod("andRecStatusEqualTo", Byte.class);
andIsDelEqualTo.invoke(criteria, Constant.REC_STATUS.Normal.value);
Method andIsDelEqualTo = criteria.getClass().getMethod("andRecStatusIn", List.class);
List<Byte> recParams = new ArrayList<>();
recParams.add(Constant.REC_STATUS.Normal.value);
recParams.add(Constant.REC_STATUS.Disabled.value);
andIsDelEqualTo.invoke(criteria, recParams);
}
}

52
scheduler/src/main/java/com/ccsens/scheduler/service/CoreJobService.java

@ -2,12 +2,17 @@ package com.ccsens.scheduler.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.mail.Mail;
import cn.hutool.extra.mail.MailUtil;
import com.alibaba.fastjson.JSONObject;
import com.ccsens.scheduler.bean.po.Task;
import com.ccsens.scheduler.bean.po.TaskExample;
import com.ccsens.scheduler.persist.dao.TaskDao;
import com.ccsens.scheduler.util.Constant;
import com.ccsens.scheduler.util.RestTemplateUtil;
import com.ccsens.util.RestTemplateUtil;
import com.ccsens.util.notice.MailSendUtil;
import com.ccsens.util.notice.SmsSendUtil;
import com.ccsens.util.notice.dto.MailDto;
import com.ccsens.util.notice.dto.SmsDto;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
@ -18,7 +23,6 @@ import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.constraints.Email;
import java.util.List;
/**
@ -51,23 +55,33 @@ public class CoreJobService extends QuartzJobBean implements ICoreJobService {
Task task = tasks.get(0);
log.info("task:{}", task);
switch (task.getNotifyWay()) {
case Constant.NotifyWay.HTTP:
RestTemplateUtil.postBody(task.getNotifyUrl(), JSONObject.parse(task.getNotifyParam()));
break;
case Constant.NotifyWay.MQ:
rabbitTemplate.convertAndSend(task.getNotifyUrl(), task.getNotifyParam());
break;
case Constant.NotifyWay.EMAIL:
Mail.create().setContent()
break;
case Constant.NotifyWay.SMS:
break;
default:
break;
try {
switch (task.getNotifyWay()) {
case Constant.NotifyWay.HTTP:
RestTemplateUtil.postBody(task.getNotifyUrl(), JSONObject.parse(task.getNotifyParam()));
break;
case Constant.NotifyWay.MQ:
rabbitTemplate.convertAndSend(task.getNotifyUrl(), task.getNotifyParam());
break;
case Constant.NotifyWay.EMAIL:
MailDto.Receive receive = JSONObject.parseObject(task.getNotifyParam(), MailDto.Receive.class);
receive.setTos(task.getNotifyUrl());
MailSendUtil.sendMail(receive);
log.info("邮件已发送:{}", task);
break;
case Constant.NotifyWay.SMS:
String[] urls = task.getNotifyUrl().split(Constant.Split.NOTIFY_URL);
for (String url: urls) {
SmsDto.Receive smsReceive = JSONObject.parseObject(task.getNotifyParam(), SmsDto.Receive.class);
smsReceive.setPhone(url);
SmsSendUtil.sendSms(smsReceive);
}
break;
default:
break;
}
} catch (Exception e) {
log.error("通知异常:", e);
}
}
}

31
scheduler/src/main/java/com/ccsens/scheduler/service/JobService.java

@ -1,6 +1,7 @@
package com.ccsens.scheduler.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.ccsens.scheduler.bean.dto.QuartzJob;
import com.ccsens.scheduler.bean.po.Task;
@ -9,7 +10,7 @@ import com.ccsens.scheduler.persist.dao.TaskDao;
import com.ccsens.scheduler.util.CodeEnum;
import com.ccsens.scheduler.util.Constant;
import com.ccsens.scheduler.util.QuartzJobUtil;
import com.ccsens.scheduler.util.RedisUtil;
import com.ccsens.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@ -34,34 +35,50 @@ public class JobService implements IJobService {
@Resource
private RedisUtil redisUtil;
@Resource
private Snowflake snowflake;
@Resource
private TaskDao taskDao;
@Override
public CodeEnum add(QuartzJob.Job job, Long userId) {
// 写缓存,防重复
boolean writeSuc = redisUtil.setNx(Constant.Quartz.JOB_KEY_PREFIX + job.getJobName() + Constant.Quartz.JOB_KEY_SPLIT + job.getJobGroupName(), "", Constant.Quartz.JOB_KEY_EXPIRE_TIME);
String key = Constant.Quartz.JOB_KEY_PREFIX + job.getJobName() + Constant.Quartz.JOB_KEY_SPLIT + job.getJobGroupName();
boolean writeSuc = redisUtil.setNx(key, "", Constant.Quartz.JOB_KEY_EXPIRE_TIME);
log.info("缓存{}结果:{}", job.getJobName(), writeSuc);
if (!writeSuc) {
return CodeEnum.JOB_EXISTED;
}
// 查数据库
// 查询任务
TaskExample example = new TaskExample();
example.createCriteria().andTriggerNameEqualTo(job.getTriggerName()).andTriggerGroupNameEqualTo(job.getTriggerGroupName());
long count = taskDao.countByExample(example);
log.info("数据库中任务数量:{}", count);
if (count > 0) {
return CodeEnum.JOB_EXISTED;
}
// 添加任务
boolean suc = quartzJobUtil.addJob(job);
log.info("添加Quartz任务成功:{}", suc);
if (!suc) {
redisUtil.del(key);
return CodeEnum.JOB_ADD_FAIL;
}
Task task = new Task();
BeanUtils.copyProperties(job, task);
task.setId(snowflake.nextId());
taskDao.insertSelective(task);
log.info("添加任务成功");
redisUtil.del(key);
return CodeEnum.SUCCESS;
}
@Override
public CodeEnum modify(QuartzJob.Update job, Long userId) {
// 写缓存,防重复
boolean writeSuc = redisUtil.setNx(Constant.Quartz.JOB_KEY_PREFIX + job.getTriggerName() + Constant.Quartz.JOB_KEY_SPLIT + job.getTriggerGroupName(), "", Constant.Quartz.JOB_KEY_EXPIRE_TIME);
String key = Constant.Quartz.JOB_KEY_PREFIX + job.getTriggerName() + Constant.Quartz.JOB_KEY_SPLIT + job.getTriggerGroupName();
boolean writeSuc = redisUtil.setNx(key, "", Constant.Quartz.JOB_KEY_EXPIRE_TIME);
log.info("缓存{}结果:{}", job.getTriggerName() + Constant.Quartz.JOB_KEY_SPLIT + job.getTriggerGroupName(),writeSuc);
if (!writeSuc) {
return CodeEnum.JOB_EXISTED;
@ -72,21 +89,27 @@ public class JobService implements IJobService {
List<Task> tasks = taskDao.selectByExample(example);
log.info("tasks:{}", tasks);
if (CollectionUtil.isEmpty(tasks)) {
redisUtil.del(key);
return CodeEnum.JOB_NOT_EXISTED;
}
Task task = tasks.get(0);
boolean cronChange = (StrUtil.isNotBlank(job.getCron()) && !job.getCron().equals(task.getCron()))
|| ((StrUtil.isNotBlank(job.getMisfirePolicy()) && !job.getMisfirePolicy().equals(task.getMisfirePolicy())));
|| ((StrUtil.isNotBlank(job.getMisfirePolicy()) && !job.getMisfirePolicy().equals(task.getMisfirePolicy()))
|| job.getStartTime() != task.getStartTime() || job.getEndTime() != task.getEndTime()
);
if (cronChange) {
log.info("cron需要变更");
boolean modify = quartzJobUtil.modifyJobTime(job);
if (!modify) {
redisUtil.del(key);
return CodeEnum.JOB_MODIFY_FAIL;
}
}
Task updateTask = new Task();
BeanUtils.copyProperties(job, updateTask);
updateTask.setId(task.getId());
taskDao.updateByPrimaryKeySelective(updateTask);
redisUtil.del(key);
return CodeEnum.SUCCESS;
}

2
scheduler/src/main/java/com/ccsens/scheduler/util/CodeEnum.java

@ -12,7 +12,7 @@ public enum CodeEnum {
FILE_FORMAT_ERROR(1, "文件格式错误", true),
PARAM_NULL(2, "请检查您的参数是否填写完整。", true),
URL_ERROR(3, "请求路径转换异常", true),
JOB_EXISTED(4, "任务已经存在,请不要重复添加或修改任务名。", true),
JOB_EXISTED(4, "任务正在处理中,请不要重复添加或修改任务。", true),
JOB_ADD_FAIL(5, "任务添加失败,请检查参数后重试。", true),
JOB_NOT_EXISTED(6, "任务不存在。", true),
JOB_MODIFY_FAIL(7, "任务修改失败,请检查参数后重试。", true),

11
scheduler/src/main/java/com/ccsens/scheduler/util/Constant.java

@ -15,6 +15,8 @@ public class Constant {
public static final String HEADER_KEY_TOKEN_PREFIX = "Bearer ";
public static final String DYNAMIC_DATASOURCE_SCHEMA_KEY = "${schema}";
public enum REC_STATUS {
Normal((byte) 0,"正常"), Disabled((byte) 1,"已禁用"),Deleted((byte) 2,"已删除");
@ -30,7 +32,7 @@ public class Constant {
public static final String QZ_JOB_GROUP_NAME = "JOB_GROUP_NAME";
public static final String QZ_TRIGGER_GROUP_NAME = "TRIGGER_GROUP_NAME";
public static final String JOB_KEY_PREFIX = "scheduler:job:";
public static final long JOB_KEY_EXPIRE_TIME = 600;
public static final long JOB_KEY_EXPIRE_TIME = 60;
public static final String JOB_KEY_SPLIT = ":";
public static final Map<Byte, String> JOB = new HashMap<>();
static {
@ -45,7 +47,12 @@ public class Constant {
public static final byte SMS = 3;
}
public static class Split {
/**
* 多个通知路径分割符
*/
public static final String NOTIFY_URL = "[,;]";
}
// @SuppressWarnings("all")

204
scheduler/src/main/java/com/ccsens/scheduler/util/JsonResponse.java

@ -1,102 +1,102 @@
package com.ccsens.scheduler.util;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel
public class JsonResponse<T> {
/**
* Common Error Constant
*/
public static class RegularError {
public static final int ERRCODE_SUCCESS = 200;
public static final String ERRCODE_SUCCESS_PHASE = "ok";
public static final int ERRCODE_FAIL = -1;
public static final String ERRCODE_FAIL_PHASE = "error";
}
@ApiModelProperty(value="状态码")
private Integer code;
@ApiModelProperty(value="数据")
private T data;
@ApiModelProperty(value="消息")
private String msg;
@ApiModelProperty(value="成功与否")
private boolean success;
private JsonResponse() {
}
public static JsonResponse newInstance(){
return new JsonResponse();
}
public JsonResponse ok(){
this.code = CodeEnum.SUCCESS.getCode();
this.msg = CodeEnum.SUCCESS.getMsg();
this.success = CodeEnum.SUCCESS.isSuccess();
return this;
}
public JsonResponse<T> ok(T data){
ok();
this.data = data;
return this;
}
public JsonResponse ok(CodeEnum codeEnum){
this.code = codeEnum.getCode();
this.msg = codeEnum.getMsg();
this.success = codeEnum.isSuccess();
return this;
}
public JsonResponse ok(CodeEnum codeEnum, T data){
this.code = codeEnum.getCode();
this.msg = codeEnum.getMsg();
this.success = codeEnum.isSuccess();
this.data = data;
return this;
}
public JsonResponse fail(){
this.code = RegularError.ERRCODE_FAIL;
this.msg = RegularError.ERRCODE_FAIL_PHASE;
this.success = false;
return this;
}
public JsonResponse fail(String error){
fail();
this.msg = error;
return this;
}
public JsonResponse fail(int code){
fail();
this.code = code;
return this;
}
public JsonResponse fail(int code, String error){
fail();
this.code = code;
this.msg = error;
return this;
}
public JsonResponse fail(int code, String error, T obj){
fail();
this.code = code;
this.msg = error;
this.data = obj;
return this;
}
}
//package com.ccsens.scheduler.util;
//
//import io.swagger.annotations.ApiModel;
//import io.swagger.annotations.ApiModelProperty;
//import lombok.Data;
//
//@Data
//@ApiModel
//public class JsonResponse<T> {
//
// /**
// * Common Error Constant
// */
// public static class RegularError {
// public static final int ERRCODE_SUCCESS = 200;
// public static final String ERRCODE_SUCCESS_PHASE = "ok";
// public static final int ERRCODE_FAIL = -1;
// public static final String ERRCODE_FAIL_PHASE = "error";
// }
//
//
//
// @ApiModelProperty(value="状态码")
// private Integer code;
// @ApiModelProperty(value="数据")
// private T data;
// @ApiModelProperty(value="消息")
// private String msg;
// @ApiModelProperty(value="成功与否")
// private boolean success;
//
// private JsonResponse() {
// }
//
// public static JsonResponse newInstance(){
// return new JsonResponse();
// }
//
// public JsonResponse ok(){
// this.code = CodeEnum.SUCCESS.getCode();
// this.msg = CodeEnum.SUCCESS.getMsg();
// this.success = CodeEnum.SUCCESS.isSuccess();
// return this;
// }
//
// public JsonResponse<T> ok(T data){
// ok();
// this.data = data;
// return this;
// }
//
// public JsonResponse ok(CodeEnum codeEnum){
// this.code = codeEnum.getCode();
// this.msg = codeEnum.getMsg();
// this.success = codeEnum.isSuccess();
// return this;
// }
//
// public JsonResponse ok(CodeEnum codeEnum, T data){
// this.code = codeEnum.getCode();
// this.msg = codeEnum.getMsg();
// this.success = codeEnum.isSuccess();
// this.data = data;
// return this;
// }
//
// public JsonResponse fail(){
// this.code = RegularError.ERRCODE_FAIL;
// this.msg = RegularError.ERRCODE_FAIL_PHASE;
// this.success = false;
// return this;
// }
//
// public JsonResponse fail(String error){
// fail();
// this.msg = error;
// return this;
// }
//
// public JsonResponse fail(int code){
// fail();
// this.code = code;
// return this;
// }
//
// public JsonResponse fail(int code, String error){
// fail();
// this.code = code;
// this.msg = error;
// return this;
// }
//
// public JsonResponse fail(int code, String error, T obj){
// fail();
// this.code = code;
// this.msg = error;
// this.data = obj;
// return this;
// }
//
//
//}

46
scheduler/src/main/java/com/ccsens/scheduler/util/PropUtil.java

@ -1,23 +1,23 @@
package com.ccsens.scheduler.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @program: ptpro
* @description:
* @author: wu huijuan
* @create: 2019/10/21 10:37
*/
@Component
public class PropUtil {
public static String path;
@Value("${file.path:}")
public void setPath(String path) {
PropUtil.path = path;
}
}
//package com.ccsens.scheduler.util;
//
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.stereotype.Component;
//
///**
// * @program: ptpro
// * @description:
// * @author: wu huijuan
// * @create: 2019/10/21 10:37
// */
//@Component
//public class PropUtil {
//
// public static String path;
//
//
//
// @Value("${file.path:}")
// public void setPath(String path) {
// PropUtil.path = path;
// }
//}

25
scheduler/src/main/java/com/ccsens/scheduler/util/QuartzJobUtil.java

@ -48,8 +48,10 @@ public class QuartzJobUtil {
scheduler.start();
}
return true;
}
catch (Exception e) {
} catch (ObjectAlreadyExistsException e) {
log.error("任务已经存在", e);
return true;
} catch (Exception e) {
log.error("Add quartz job error, jobName = {}", jobModel.getJobName(), e);
}
@ -96,17 +98,14 @@ public class QuartzJobUtil {
if (trigger == null) {
return false;
}
String oldCron = trigger.getCronExpression();
if (!oldCron.equalsIgnoreCase(jobModel.getCron())) {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobModel.getCron());
handleCronScheduleMisfirePolicy(jobModel.getMisfirePolicy(), scheduleBuilder);
// 按新的cronExpression表达式重新构建trigger
TriggerBuilder<CronTrigger> builder = trigger.getTriggerBuilder().withIdentity(triggerKey);
setPeriod(builder, jobModel.getStartTime(), jobModel.getEndTime());
trigger = builder.withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
// 按新的cronExpression表达式重新构建trigger
TriggerBuilder<CronTrigger> builder = trigger.getTriggerBuilder().withIdentity(triggerKey);
setPeriod(builder, jobModel.getStartTime(), jobModel.getEndTime());
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(jobModel.getCron());
handleCronScheduleMisfirePolicy(jobModel.getMisfirePolicy(), scheduleBuilder);
trigger = builder.withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
return true;
}
catch (Exception e) {

1500
scheduler/src/main/java/com/ccsens/scheduler/util/RedisUtil.java

File diff suppressed because it is too large

312
scheduler/src/main/java/com/ccsens/scheduler/util/RestTemplateUtil.java

@ -1,156 +1,156 @@
package com.ccsens.scheduler.util;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ccsens.scheduler.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
public class RestTemplateUtil {
@Resource
private RestTemplate restTemplate;
private static RestTemplateUtil util;
@PostConstruct
public void init(){
util = this;
util.restTemplate = this.restTemplate;
}
public static Object getForEntity(String url, Map<String, Object> params, Class<?> returnClass) {
if (params != null && !params.isEmpty()) {
String questionMark = "?";
String assignMark = "=";
String andMark = "&";
if (!url.contains(questionMark)) {
url += questionMark;
}
for (String key : params.keySet()) {
if (url.endsWith(questionMark)) {
url += key + assignMark +params.get(key);
} else {
url += andMark + key + assignMark +params.get(key);
}
}
}
log.info("url:{}, params:{}", url, params);
ResponseEntity<String> entity = util.restTemplate.getForEntity(url, String.class);
log.info("entity:{}",entity);
return JSONObject.parseObject(entity.getBody(), returnClass);
}
public static String postBody(String url, Object params) {
log.info("路径:{}, 参数:{}", url, params);
HttpHeaders httpHeaders = new HttpHeaders();
MediaType type= MediaType.parseMediaType("application/json;charset=UTF-8");
httpHeaders.setContentType(type);
JSONObject json = JSON.parseObject(JSON.toJSONString(params));
HttpEntity<Map<String, Object>> objectHttpEntity = new HttpEntity<>(json,httpHeaders);
URI uri;
try {
uri = new URI(url);
}catch (URISyntaxException e) {
log.error("转换路径异常", e);
throw new BaseException(CodeEnum.URL_ERROR);
}
ResponseEntity<String> response = util.restTemplate.postForEntity(uri, objectHttpEntity, String.class);
log.info("返回:{}", response);
return response.getBody();
}
public static String postBody(String url, List<? extends Object> params) {
log.info("路径:{}, 参数:{}", url, params);
HttpHeaders httpHeaders = new HttpHeaders();
MediaType type= MediaType.parseMediaType("application/json;charset=UTF-8");
httpHeaders.setContentType(type);
HttpEntity<List<? extends Object>> objectHttpEntity = new HttpEntity<>(params,httpHeaders);
URI uri;
try {
uri = new URI(url);
}catch (URISyntaxException e) {
log.error("转换路径异常:{}", e);
throw new BaseException(CodeEnum.URL_ERROR);
}
ResponseEntity<String> response = util.restTemplate.postForEntity(uri, objectHttpEntity, String.class);
log.info("返回:{}", response);
return response.getBody();
}
public static String postUrlEncode(String url, Object params) {
log.info("请求路径:{},请求参数:{}", url, params);
MultiValueMap<String, Object> paramMap;
if (params == null) {
paramMap = new LinkedMultiValueMap<>();
} else {
JSONObject json = JSON.parseObject(JSON.toJSONString(params));
paramMap = transMultiValueMap(json);
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap> formEntity = new HttpEntity<>(paramMap, headers);
ResponseEntity<String> result = util.restTemplate.postForEntity(url, formEntity, String.class);
log.info("接口返回结果:{}", result);
return result.getBody();
}
/**
* 发送multipart/form-data
* @author whj
* @date 2019/8/20
* @param url 路径
* @param params 参数
* @return com.alibaba.fastjson.JSONObject
*/
public static JSONObject postImg(String url, JSONObject params) {
log.info("请求路径:{},请求参数:{}", url, params);
HttpHeaders headers = new HttpHeaders();
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> paramMap = transMultiValueMap(params);
HttpEntity<MultiValueMap> formEntity = new HttpEntity<>(paramMap, headers);
JSONObject result = util.restTemplate.postForObject(url, formEntity, JSONObject.class);
log.info("接口返回结果:{}", result);
return result;
}
/**
* 将参数封装成MultiValueMap对象
* @author whj
* @date 2019/8/20
* @param params 参数
* @return org.springframework.util.MultiValueMap<java.lang.String,java.lang.Object>
*/
private static MultiValueMap<String, Object> transMultiValueMap(JSONObject params) {
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
for (String key: params.keySet()) {
paramMap.add(key, params.get(key));
}
return paramMap;
}
}
//package com.ccsens.scheduler.util;
//
//import cn.hutool.core.util.StrUtil;
//import com.alibaba.fastjson.JSON;
//import com.alibaba.fastjson.JSONObject;
//import com.ccsens.scheduler.exception.BaseException;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.http.HttpEntity;
//import org.springframework.http.HttpHeaders;
//import org.springframework.http.MediaType;
//import org.springframework.http.ResponseEntity;
//import org.springframework.stereotype.Component;
//import org.springframework.util.LinkedMultiValueMap;
//import org.springframework.util.MultiValueMap;
//import org.springframework.web.client.RestTemplate;
//
//import javax.annotation.PostConstruct;
//import javax.annotation.Resource;
//import java.net.URI;
//import java.net.URISyntaxException;
//import java.util.List;
//import java.util.Map;
//
//@Slf4j
//@Component
//public class RestTemplateUtil {
//
// @Resource
// private RestTemplate restTemplate;
//
// private static RestTemplateUtil util;
//
// @PostConstruct
// public void init(){
// util = this;
// util.restTemplate = this.restTemplate;
// }
//
// public static Object getForEntity(String url, Map<String, Object> params, Class<?> returnClass) {
//
// if (params != null && !params.isEmpty()) {
// String questionMark = "?";
// String assignMark = "=";
// String andMark = "&";
// if (!url.contains(questionMark)) {
// url += questionMark;
// }
// for (String key : params.keySet()) {
// if (url.endsWith(questionMark)) {
// url += key + assignMark +params.get(key);
// } else {
// url += andMark + key + assignMark +params.get(key);
// }
// }
// }
// log.info("url:{}, params:{}", url, params);
// ResponseEntity<String> entity = util.restTemplate.getForEntity(url, String.class);
// log.info("entity:{}",entity);
// return JSONObject.parseObject(entity.getBody(), returnClass);
// }
//
// public static String postBody(String url, Object params) {
// log.info("路径:{}, 参数:{}", url, params);
// HttpHeaders httpHeaders = new HttpHeaders();
// MediaType type= MediaType.parseMediaType("application/json;charset=UTF-8");
// httpHeaders.setContentType(type);
//
// JSONObject json = JSON.parseObject(JSON.toJSONString(params));
// HttpEntity<Map<String, Object>> objectHttpEntity = new HttpEntity<>(json,httpHeaders);
// URI uri;
// try {
// uri = new URI(url);
// }catch (URISyntaxException e) {
// log.error("转换路径异常", e);
// throw new BaseException(CodeEnum.URL_ERROR);
// }
//
// ResponseEntity<String> response = util.restTemplate.postForEntity(uri, objectHttpEntity, String.class);
// log.info("返回:{}", response);
// return response.getBody();
// }
//
// public static String postBody(String url, List<? extends Object> params) {
// log.info("路径:{}, 参数:{}", url, params);
// HttpHeaders httpHeaders = new HttpHeaders();
// MediaType type= MediaType.parseMediaType("application/json;charset=UTF-8");
// httpHeaders.setContentType(type);
//
// HttpEntity<List<? extends Object>> objectHttpEntity = new HttpEntity<>(params,httpHeaders);
// URI uri;
// try {
// uri = new URI(url);
// }catch (URISyntaxException e) {
// log.error("转换路径异常:{}", e);
// throw new BaseException(CodeEnum.URL_ERROR);
// }
//
// ResponseEntity<String> response = util.restTemplate.postForEntity(uri, objectHttpEntity, String.class);
// log.info("返回:{}", response);
// return response.getBody();
// }
// public static String postUrlEncode(String url, Object params) {
// log.info("请求路径:{},请求参数:{}", url, params);
// MultiValueMap<String, Object> paramMap;
// if (params == null) {
// paramMap = new LinkedMultiValueMap<>();
// } else {
// JSONObject json = JSON.parseObject(JSON.toJSONString(params));
// paramMap = transMultiValueMap(json);
// }
//
// HttpHeaders headers = new HttpHeaders();
// headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// HttpEntity<MultiValueMap> formEntity = new HttpEntity<>(paramMap, headers);
// ResponseEntity<String> result = util.restTemplate.postForEntity(url, formEntity, String.class);
// log.info("接口返回结果:{}", result);
// return result.getBody();
// }
//
// /**
// * 发送multipart/form-data
// * @author whj
// * @date 2019/8/20
// * @param url 路径
// * @param params 参数
// * @return com.alibaba.fastjson.JSONObject
// */
// public static JSONObject postImg(String url, JSONObject params) {
// log.info("请求路径:{},请求参数:{}", url, params);
// HttpHeaders headers = new HttpHeaders();
// headers.add("Accept", MediaType.APPLICATION_JSON.toString());
// headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// MultiValueMap<String, Object> paramMap = transMultiValueMap(params);
// HttpEntity<MultiValueMap> formEntity = new HttpEntity<>(paramMap, headers);
// JSONObject result = util.restTemplate.postForObject(url, formEntity, JSONObject.class);
// log.info("接口返回结果:{}", result);
// return result;
// }
//
// /**
// * 将参数封装成MultiValueMap对象
// * @author whj
// * @date 2019/8/20
// * @param params 参数
// * @return org.springframework.util.MultiValueMap<java.lang.String,java.lang.Object>
// */
// private static MultiValueMap<String, Object> transMultiValueMap(JSONObject params) {
// MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
// for (String key: params.keySet()) {
// paramMap.add(key, params.get(key));
// }
// return paramMap;
// }
//
//
//}

59
scheduler/src/main/java/com/ccsens/scheduler/util/SmsUtil.java

@ -1,59 +0,0 @@
package com.ccsens.scheduler.util;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONException;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
@Component
public class SmsUtil {
// 1400开头
private static final int appid = 1400188778;
private static final String appkey = "c86ca104521ab2e28e1d4b558fdd665e";
/**
* {1} 验证码{1} 您正在通过{2}登录传控科技时物链条会议管理系统请与{3}分钟内填写如非本人操作请忽略本短信\
*/
private static final int templateId = 286731;
/**
* {1} 您正在通过{2}登录传控科技时物链条会议管理系统请与{2}分钟内填写如非本人操作请忽略本短信
*/
private static final int templateId1 = 286682;
/**验证码{1},{2}分钟内有效,如非本人操作请忽略
*
*/
private static final int templateId2 = 686476;
private static final String smsSign = "传控科技";
public static void sendSms(String phone,String code,String appName,Integer seconds){
String phoneNumbers[] = {phone};
Integer minutes = (seconds - 1) / 60 + 1;
try {
//数组具体的元素个数和模板中变量个数必须一致,例如事例中templateId:5678对应一个变量,参数数组中元素个数也必须是一个
String[] params = {code,String.valueOf(minutes)};
SmsSingleSender ssender = new SmsSingleSender(appid, appkey);
// 签名参数未提供或者为空时,会使用默认签名发送短信
SmsSingleSenderResult result = ssender.sendWithParam("86", phoneNumbers[0],
templateId2, params, smsSign, "", "");
log.info(String.valueOf(result));
} catch (HTTPException e) {
// HTTP响应码错误
e.printStackTrace();
} catch (JSONException e) {
// json解析错误
e.printStackTrace();
} catch (IOException e) {
// 网络IO错误
e.printStackTrace();
}
}
public static String generateRandomSmsCode(int length){
return RandomUtil.randomNumbers(4);
}
}

4
scheduler/src/main/resources/application-dev.yml

@ -1,5 +1,5 @@
server:
port: 8000
port: 8001
spring:
snowflake:
datacenterId: 1
@ -52,7 +52,7 @@ spring:
port: 6379
timeout: 1000ms
rabbitmq:
host: 192.168.4.113
host: dd.tall.wiki
password: 111111
port: 5672
username: admin

4
scheduler/src/main/resources/config/mail.setting

@ -1,4 +0,0 @@
host = smtp.ccsens.com
port = 25
from = admin@ccsens.com
pass = q1w2e3

31
scheduler/src/main/resources/mapper_raw/TaskMapper.xml

@ -14,6 +14,7 @@
<result column="end_time" jdbcType="BIGINT" property="endTime" />
<result column="auto_move" jdbcType="TINYINT" property="autoMove" />
<result column="notify_way" jdbcType="TINYINT" property="notifyWay" />
<result column="notifier" jdbcType="VARCHAR" property="notifier" />
<result column="notify_url" jdbcType="VARCHAR" property="notifyUrl" />
<result column="notify_param" jdbcType="VARCHAR" property="notifyParam" />
<result column="app_id" jdbcType="BIGINT" property="appId" />
@ -81,8 +82,8 @@
</sql>
<sql id="Base_Column_List">
id, job_name, job_group_name, trigger_name, trigger_group_name, cron, misfire_policy,
job, start_time, end_time, auto_move, notify_way, notify_url, notify_param, app_id,
created_at, updated_at, rec_status
job, start_time, end_time, auto_move, notify_way, notifier, notify_url, notify_param,
app_id, created_at, updated_at, rec_status
</sql>
<select id="selectByExample" parameterType="com.ccsens.scheduler.bean.po.TaskExample" resultMap="BaseResultMap">
select
@ -119,16 +120,16 @@
trigger_name, trigger_group_name, cron,
misfire_policy, job, start_time,
end_time, auto_move, notify_way,
notify_url, notify_param, app_id,
created_at, updated_at, rec_status
)
notifier, notify_url, notify_param,
app_id, created_at, updated_at,
rec_status)
values (#{id,jdbcType=BIGINT}, #{jobName,jdbcType=VARCHAR}, #{jobGroupName,jdbcType=VARCHAR},
#{triggerName,jdbcType=VARCHAR}, #{triggerGroupName,jdbcType=VARCHAR}, #{cron,jdbcType=VARCHAR},
#{misfirePolicy,jdbcType=VARCHAR}, #{job,jdbcType=TINYINT}, #{startTime,jdbcType=BIGINT},
#{endTime,jdbcType=BIGINT}, #{autoMove,jdbcType=TINYINT}, #{notifyWay,jdbcType=TINYINT},
#{notifyUrl,jdbcType=VARCHAR}, #{notifyParam,jdbcType=VARCHAR}, #{appId,jdbcType=BIGINT},
#{createdAt,jdbcType=TIMESTAMP}, #{updatedAt,jdbcType=TIMESTAMP}, #{recStatus,jdbcType=TINYINT}
)
#{notifier,jdbcType=VARCHAR}, #{notifyUrl,jdbcType=VARCHAR}, #{notifyParam,jdbcType=VARCHAR},
#{appId,jdbcType=BIGINT}, #{createdAt,jdbcType=TIMESTAMP}, #{updatedAt,jdbcType=TIMESTAMP},
#{recStatus,jdbcType=TINYINT})
</insert>
<insert id="insertSelective" parameterType="com.ccsens.scheduler.bean.po.Task">
insert into t_task
@ -169,6 +170,9 @@
<if test="notifyWay != null">
notify_way,
</if>
<if test="notifier != null">
notifier,
</if>
<if test="notifyUrl != null">
notify_url,
</if>
@ -225,6 +229,9 @@
<if test="notifyWay != null">
#{notifyWay,jdbcType=TINYINT},
</if>
<if test="notifier != null">
#{notifier,jdbcType=VARCHAR},
</if>
<if test="notifyUrl != null">
#{notifyUrl,jdbcType=VARCHAR},
</if>
@ -290,6 +297,9 @@
<if test="record.notifyWay != null">
notify_way = #{record.notifyWay,jdbcType=TINYINT},
</if>
<if test="record.notifier != null">
notifier = #{record.notifier,jdbcType=VARCHAR},
</if>
<if test="record.notifyUrl != null">
notify_url = #{record.notifyUrl,jdbcType=VARCHAR},
</if>
@ -327,6 +337,7 @@
end_time = #{record.endTime,jdbcType=BIGINT},
auto_move = #{record.autoMove,jdbcType=TINYINT},
notify_way = #{record.notifyWay,jdbcType=TINYINT},
notifier = #{record.notifier,jdbcType=VARCHAR},
notify_url = #{record.notifyUrl,jdbcType=VARCHAR},
notify_param = #{record.notifyParam,jdbcType=VARCHAR},
app_id = #{record.appId,jdbcType=BIGINT},
@ -373,6 +384,9 @@
<if test="notifyWay != null">
notify_way = #{notifyWay,jdbcType=TINYINT},
</if>
<if test="notifier != null">
notifier = #{notifier,jdbcType=VARCHAR},
</if>
<if test="notifyUrl != null">
notify_url = #{notifyUrl,jdbcType=VARCHAR},
</if>
@ -407,6 +421,7 @@
end_time = #{endTime,jdbcType=BIGINT},
auto_move = #{autoMove,jdbcType=TINYINT},
notify_way = #{notifyWay,jdbcType=TINYINT},
notifier = #{notifier,jdbcType=VARCHAR},
notify_url = #{notifyUrl,jdbcType=VARCHAR},
notify_param = #{notifyParam,jdbcType=VARCHAR},
app_id = #{appId,jdbcType=BIGINT},

13
scheduler/src/main/resources/notice/notice.yml

@ -0,0 +1,13 @@
util:
mail:
host: smtp.qiye.aliyun.com
port: 465
protocol: smtp
sender: wuhuijuan@ccsens.com
password: 111111aA!
ssl: true
sms:
appId: 1400188778
appKey: c86ca104521ab2e28e1d4b558fdd665e
sign: 传控科技
type: tx

14
scheduler/vue-element-admin-master/.editorconfig

@ -0,0 +1,14 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

5
scheduler/vue-element-admin-master/.env.development

@ -0,0 +1,5 @@
# just a flag
ENV = 'development'
# base api
VUE_APP_BASE_API = '/dev-api'

6
scheduler/vue-element-admin-master/.env.production

@ -0,0 +1,6 @@
# just a flag
ENV = 'production'
# base api
VUE_APP_BASE_API = '/prod-api'

8
scheduler/vue-element-admin-master/.env.staging

@ -0,0 +1,8 @@
NODE_ENV = production
# just a flag
ENV = 'staging'
# base api
VUE_APP_BASE_API = '/stage-api'

4
scheduler/vue-element-admin-master/.eslintignore

@ -0,0 +1,4 @@
build/*.js
src/assets
public
dist

198
scheduler/vue-element-admin-master/.eslintrc.js

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

23
scheduler/vue-element-admin-master/.gitignore

@ -0,0 +1,23 @@
.DS_Store
node_modules/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock

5
scheduler/vue-element-admin-master/.travis.yml

@ -0,0 +1,5 @@
language: node_js
node_js: 10
script: npm run test
notifications:
email: false

21
scheduler/vue-element-admin-master/LICENSE

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-present PanJiaChen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

228
scheduler/vue-element-admin-master/README.es.md

@ -0,0 +1,228 @@
<p align="center">
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
</p>
<p align="center">
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
</a>
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Estado de Construcción">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="Licencia">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="Liberación Github">
</a>
<a href="https://gitter.im/vue-element-admin/discuss">
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter">
</a>
<a href="https://panjiachen.github.io/vue-element-admin-site/donate">
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="Donación">
</a>
</p>
Español | [English](./README.md) | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md)
## Introducción
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) es una interfáz de administración preparada para producción. Está basada en [vue](https://github.com/vuejs/vue) y usa [element-ui](https://github.com/ElemeFE/element) como conjunto de herramientas de interfáz de usuario.
Vue Element Admin es una solución práctica basada en la nueva plataforma de desarrollo de vue, construida con soporte a i18 para el manejo de múltiples lenguajes, plantillas estándares para aplicaciones de negocio y un conjunto de asombrosas características. Esta herramienta ayuda a construir largas y complejas Aplicacones de una sola página (SPA). Creo que lo que necesites hacer, este proyecto te ayudará.
- [Vista Prévia de la Aplicación](https://panjiachen.github.io/vue-element-admin)
- [Documentación](https://panjiachen.github.io/vue-element-admin-site/)
- [Canal de Gitter](https://gitter.im/vue-element-admin/discuss)
- [Para Donaciones](https://panjiachen.github.io/vue-element-admin-site/donate/)
- [Enlace de Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [Canal de Gitee](https://panjiachen.gitee.io/vue-element-admin/)
- Plantilla base recomendada para usar: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- Aplicación de Escritorio: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Plantilla de Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Créditos: [@Armour](https://github.com/Armour))
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
**Después de la versión `v4.1.0+`, la rama por defecto master no tendrá soporte para i18n. Por favor utilice la rama [i18n](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), los cambios serán incluidos en la rama master**
**la versión actual es `v4.0+` construida con `vue-cli`. Si encuentra algún problema, por favor coloque un [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). Si desea usar la versión anterior, puede cambiar de rama a [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), no relacionado con `vue-cli`**
**Este proyecto no está soportado para versiones antigüas de navegadores (ej. IE).**
## Preparación
Necesita instalar [node](https://nodejs.org/) y [git](https://git-scm.com/) localmente. El proyecto es basado en [ES2015+](https://es6.ruanyifeng.com/), [vue](https://cn.vuejs.org/index.html), [vuex](https://vuex.vuejs.org/zh-cn/), [vue-router](https://router.vuejs.org/zh-cn/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), toda la solicitud de datos simulada se realiza a través de [Mock.js](https://github.com/nuysoft/Mock).
Entendiendo y aprendiendo esto pudiera ayudarle con su proyecto.
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p>
## Patrocinantes
Sea un patrocinante y coloque su logo en nuestro LEEME en GitHub con un enlace directo a su sitio web. [[Se un Patrocinante]](https://www.patreon.com/panjiachen)
### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Get Java backend for Vue admin with 20% discount for 39$ use coupon code SWB0RAZPZR1M
</p>
### Flatlogic
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
## Características
```
- Iniciar / Cerrar Sesión
- Permisos de Autenticación
- Página de Permisos
- Directivas de permisos
- Página de configuración de permisos
- Autenticación por dos pasos
- Construcción Multi-entorno
- Desarrollo (dev)
- sit
- Escenario de pruebas (stage),
- Producción (prod)
- Características Globales
- I18n
- Temas dinámicos
- Menu lateral dinámico (soporte a rutas multi-nivel)
- Barra de rutas dinámica
- Tags-view (Pestañas de página, Soporta operación de clic derecho)
- Svg Sprite
- Datos de simulación con Mock
- Pantalla completa
- Menu lateral responsivo
- Editor
- Editor de Texto Enriquecido
- Editor Markdown
- Editor JSON
- Excel
- Exportación a Excel
- Carga de Excel
- Visualización de Excel
- Exportación como ZIP
- Tabla
- Tabla Dinámica
- Tabla con Arrastrar y Soltar
- Tabla de edición en línea
- Páginas de Error
- 401
- 404
- Componentes
- Carga de Avatar
- Botón para subir al inicio
- Arrastrar y Soltar (Diaglogo)
- Arrastrar y Soltar (Seleccionar)
- Arrastrar y Soltar (Kanban)
- Arrastrar y Soltar (Lista)
- Panel de división
- Componente para soltar archivos
- Adhesión de objetos
- Contador hasta
- Ejemplo Avanzado
- Registro de Errores
- Tablero de indicadores
- Página de Guías
- ECharts (Gráficos)
- Portapapeles
- Convertidor de Markdown a HTML
```
## Iniciando
```bash
# clone el proyecto
git clone https://github.com/PanJiaChen/vue-element-admin.git
# vaya al directorio clonado
cd vue-element-admin
# instale las dependencias
npm install
# corra el proyecto como desarrollador
npm run dev
```
Automáticamente se abrirá el siguiente enlace en su navegador http://localhost:9527
## Construcción
```bash
# Construcción para entornos de prueba
npm run build:stage
# Construcción para entornos de producción
npm run build:prod
```
## Avanzado
```bash
# Vista previa con efectos de entorno
npm run preview
# Vista previa con efectos + análisis de recursos estáticos
npm run preview -- --report
# Chequeo de formato de código
npm run lint
# Chequeo de formato de código y auto-corrección
npm run lint -- --fix
```
Vaya a [Documentación](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) para mayor información
## Registro de Cambios
Los cambios detallados por cada liberación se encuentran en [notas de liberación](https://github.com/PanJiaChen/vue-element-admin/releases).
## Demostración en línea
[Vista Prévia de la Aplicación](https://panjiachen.github.io/vue-element-admin)
## Donación
Si este proyecto es de mucha ayuda para ti, puedes comprarle al autor un vaso de jugo :tropical_drink:
![Donar](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
[dona por Paypal](https://www.paypal.me/panfree23)
[Comprame un Café](https://www.buymeacoffee.com/Pan)
## Navegadores Soportados
Navegadores modernos e Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge | últimas 2 versiones | últimas 2 versiones | últimas 2 versiones |
## Licencia
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
Copyright (c) 2017-presente PanJiaChen

224
scheduler/vue-element-admin-master/README.ja.md

@ -0,0 +1,224 @@
<p align="center">
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
</p>
<p align="center">
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
</a>
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
</a>
<a href="https://gitter.im/vue-element-admin/discuss">
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="gitter">
</a>
<a href="https://panjiachen.gitee.io/vue-element-admin-site/zh/donate">
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
</a>
</p>
日本語 | [English](./README.md) | [简体中文](./README.zh-CN.md) | [Spanish](./README.es.md)
## 概要
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) は管理画面のフロントエンドのインタフェースで、[vue](https://github.com/vuejs/vue) と [element-ui](https://github.com/ElemeFE/element)を使っています。i18nの多言語対応、可変ルート、権限、典型的なビジネスアプリテンプレートであり、豊富なコンポーネントを提供しています。素早くビジネス用の管理画面の現型を構築に役立ちます。
- [デモページ](https://panjiachen.github.io/vue-element-admin)
- [ドキュメント](https://panjiachen.github.io/vue-element-admin-site/)
- [Gitter](https://gitter.im/vue-element-admin/discuss)
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- おすすめシンプルテンプレート: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- デスクトップバージョン: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescriptバージョン: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (感謝: [@Armour](https://github.com/Armour))
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
**バージョン`v4.1.0+`以降について、デフォルトのmasterブランチではi18nをサポートしていません。masterブランチと共にアップデートされる[i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n)を使用してください。 **
**現在のバージョン `v4.0+``vue-cli` で構築していて、バグ報告は[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)のissueでお願いします。旧バージョン[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0)もあります。こちらは`vue-cli`に依存しないです。**
**低いバージョンのブラウザはサーポートしないです(例えば ie),必要があれば polyfill を追加してください。 [詳細はこちら](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
## 前準備
ローカル環境に [node](http://nodejs.org/) と [git](https://git-scm.com/)のインストールが必要です。[ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) 、[vue-cli](https://github.com/vuejs/vue-cli) 、[axios](https://github.com/axios/axios) と [element-ui](https://github.com/ElemeFE/element)で開発しています。Requestは[Mock.js](https://github.com/nuysoft/Mock)のモックデータを使っています。
**バグ修正や新規機能追加のissue と pull requestは大歓迎です。**
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p>
## Sponsors
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen)
### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Get Java backend for Vue admin with 20% discount for 39$ use coupon code SWB0RAZPZR1M
</p>
### Flatlogic
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
## 機能一覧
```
- ログイン / ログアウト
- Auth認証
- ページ権限
- 権限パーミッション
- 権限設定
- 外部IDでログイン
- 複数環境デプロイ
- dev
- sit
- stage
- prod
- 共通機能
- 多言語切替
- テーマ切替
- サイトメニュー(ルートから生成)
- パンくずリストナビゲーション
- タブナビゲーション
- Svg Sprite アイコン
- ローカル/バックエンド モック データ
- Screenfull
- WYSIWYG
- TinyMCE
- Markdown
- JSON
- Excel
- エクスポート
- インポート
- リード
- Zip
- テーブル
- ダイナミックテーブル
- ドラッグアンドドロップテーブル
- インラインエディットテーブル
- エラーページ
- 401
- 404
- コンポーネント
- アバターアップロード
- トップに戻る
- ドラッグダイアログ
- ドラッグ選択
- ドラッグKanban
- ドラッグリスト
- ペインの分割
- Dropzone
- スティッキー
- CountTo
- 高度なサンプル
- エラーログ
- ダッシュボード
- ガイドページ
- ECharts
- クリップボード
- Markdown to html
```
## Getting started
```bash
# clone the project
git clone https://github.com/PanJiaChen/vue-element-admin.git
# enter the project directory
cd vue-element-admin
# install dependency
npm install
# develop
npm run dev
```
http://localhost:9527 が自動的に開きます。
## Build
```bash
# build for test environment
npm run build:stage
# build for production environment
npm run build:prod
```
## Advanced
```bash
# preview the release environment effect
npm run preview
# preview the release environment effect + static resource analysis
npm run preview -- --report
# code format check
npm run lint
# code format check and auto fix
npm run lint -- --fix
```
詳細は [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) を参照してください。
## Changelog
各リリースの詳細は [release notes](https://github.com/PanJiaChen/vue-element-admin/releases) にあります。
## Online Demo
[Preview](https://panjiachen.github.io/vue-element-admin)
## Donate
If you find this project useful, you can buy author a glass of juice :tropical_drink:
![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
[Paypal Me](https://www.paypal.me/panfree23)
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
## Browsers support
Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## License
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
Copyright (c) 2017-present PanJiaChen

250
scheduler/vue-element-admin-master/README.md

@ -0,0 +1,250 @@
<p align="center">
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
</p>
<p align="center">
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
</a>
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
</a>
<a href="https://gitter.im/vue-element-admin/discuss">
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="gitter">
</a>
<a href="https://panjiachen.github.io/vue-element-admin-site/donate">
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
</a>
</p>
English | [简体中文](./README.zh-CN.md) | [日本語](./README.ja.md) | [Spanish](./README.es.md)
<p align="center">
<b>SPONSORED BY</b>
</p>
<table align="center" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td align="center" valign="middle" width="250">
<a href="https://www.duohui.cn/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="多会" target="_blank">
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/duohui.png" title="多会 - 活动服务销售平台">
<p>活动服务销售平台</p>
</a>
</td>
<td align="center" valign="middle" width="250">
<a href="https://youke.co/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="有客" target="_blank">
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/youke.png" title="有客 - 客户消息直达工作群">
<p>客户消息直达工作群</p>
</a>
</td>
</tr>
</tbody>
</table>
## Introduction
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) is a production-ready front-end solution for admin interfaces. It is based on [vue](https://github.com/vuejs/vue) and uses the UI Toolkit [element-ui](https://github.com/ElemeFE/element).
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) is based on the newest development stack of vue and it has a built-in i18n solution, typical templates for enterprise applications, and lots of awesome features. It helps you build large and complex Single-Page Applications. I believe whatever your needs are, this project will help you.
- [Preview](https://panjiachen.github.io/vue-element-admin)
- [Documentation](https://panjiachen.github.io/vue-element-admin-site/)
- [Gitter](https://gitter.im/vue-element-admin/discuss)
- [Donate](https://panjiachen.github.io/vue-element-admin-site/donate/)
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 国内用户可访问该地址在线预览
- Base template recommends using: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- Desktop: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescript: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour))
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
**After the `v4.1.0+` version, the default master branch will not support i18n. Please use [i18n Branch](https://github.com/PanJiaChen/vue-element-admin/tree/i18n), it will keep up with the master update**
**The current version is `v4.0+` build on `vue-cli`. If you find a problem, please put [issue](https://github.com/PanJiaChen/vue-element-admin/issues/new). If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0), it does not rely on `vue-cli`**
**This project does not support low version browsers (e.g. IE). Please add polyfill by yourself.**
## Preparation
You need to install [node](https://nodejs.org/) and [git](https://git-scm.com/) locally. The project is based on [ES2015+](https://es6.ruanyifeng.com/), [vue](https://cn.vuejs.org/index.html), [vuex](https://vuex.vuejs.org/zh-cn/), [vue-router](https://router.vuejs.org/zh-cn/), [vue-cli](https://github.com/vuejs/vue-cli) , [axios](https://github.com/axios/axios) and [element-ui](https://github.com/ElemeFE/element), all request data is simulated using [Mock.js](https://github.com/nuysoft/Mock).
Understanding and learning this knowledge in advance will greatly help the use of this project.
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p>
## Sponsors
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen)
### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Get Java backend for Vue admin with 20% discount for 39$ use coupon code SWB0RAZPZR1M
</p>
### Flatlogic
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
## Features
```
- Login / Logout
- Permission Authentication
- Page permission
- Directive permission
- Permission configuration page
- Two-step login
- Multi-environment build
- Develop (dev)
- sit
- Stage Test (stage)
- Production (prod)
- Global Features
- I18n
- Multiple dynamic themes
- Dynamic sidebar (supports multi-level routing)
- Dynamic breadcrumb
- Tags-view (Tab page Support right-click operation)
- Svg Sprite
- Mock data
- Screenfull
- Responsive Sidebar
- Editor
- Rich Text Editor
- Markdown Editor
- JSON Editor
- Excel
- Export Excel
- Upload Excel
- Visualization Excel
- Export zip
- Table
- Dynamic Table
- Drag And Drop Table
- Inline Edit Table
- Error Page
- 401
- 404
- Components
- Avatar Upload
- Back To Top
- Drag Dialog
- Drag Select
- Drag Kanban
- Drag List
- SplitPane
- Dropzone
- Sticky
- CountTo
- Advanced Example
- Error Log
- Dashboard
- Guide Page
- ECharts
- Clipboard
- Markdown to html
```
## Getting started
```bash
# clone the project
git clone https://github.com/PanJiaChen/vue-element-admin.git
# enter the project directory
cd vue-element-admin
# install dependency
npm install
# develop
npm run dev
```
This will automatically open http://localhost:9527
## Build
```bash
# build for test environment
npm run build:stage
# build for production environment
npm run build:prod
```
## Advanced
```bash
# preview the release environment effect
npm run preview
# preview the release environment effect + static resource analysis
npm run preview -- --report
# code format check
npm run lint
# code format check and auto fix
npm run lint -- --fix
```
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information
## Changelog
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
## Online Demo
[Preview](https://panjiachen.github.io/vue-element-admin)
## Donate
If you find this project useful, you can buy author a glass of juice :tropical_drink:
![donate](https://wpimg.wallstcn.com/bd273f0d-83a0-4ef2-92e1-9ac8ed3746b9.png)
[Paypal Me](https://www.paypal.me/panfree23)
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
## Browsers support
Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## License
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
Copyright (c) 2017-present PanJiaChen

273
scheduler/vue-element-admin-master/README.zh-CN.md

@ -0,0 +1,273 @@
<p align="center">
<img width="320" src="https://wpimg.wallstcn.com/ecc53a42-d79b-42e2-8852-5126b810a4c8.svg">
</p>
<p align="center">
<a href="https://github.com/vuejs/vue">
<img src="https://img.shields.io/badge/vue-2.6.10-brightgreen.svg" alt="vue">
</a>
<a href="https://github.com/ElemeFE/element">
<img src="https://img.shields.io/badge/element--ui-2.7.0-brightgreen.svg" alt="element-ui">
</a>
<a href="https://travis-ci.org/PanJiaChen/vue-element-admin" rel="nofollow">
<img src="https://travis-ci.org/PanJiaChen/vue-element-admin.svg?branch=master" alt="Build Status">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/mashape/apistatus.svg" alt="license">
</a>
<a href="https://github.com/PanJiaChen/vue-element-admin/releases">
<img src="https://img.shields.io/github/release/PanJiaChen/vue-element-admin.svg" alt="GitHub release">
</a>
<a href="https://gitter.im/vue-element-admin/discuss">
<img src="https://badges.gitter.im/Join%20Chat.svg" alt="gitter">
</a>
<a href="https://panjiachen.gitee.io/vue-element-admin-site/zh/donate">
<img src="https://img.shields.io/badge/%24-donate-ff69b4.svg" alt="donate">
</a>
</p>
简体中文 | [English](./README.md) | [日本語](./README.ja.md) | [Spanish](./README.es.md)
<p align="center">
<b>SPONSORED BY</b>
</p>
<table align="center" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td align="center" valign="middle" width="250">
<a href="https://www.duohui.cn/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="多会" target="_blank">
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/duohui.png" title="多会 - 活动服务销售平台">
<p>活动服务销售平台</p>
</a>
</td>
<td align="center" valign="middle" width="250">
<a href="https://youke.co/?utm_source=vue-element-admin&utm_medium=web&utm_campaign=vue-element-admin_github" title="有客" target="_blank">
<img height="60px" src="https://qiniu.cdn.duohui.co/brand/youke.png" title="有客 - 客户消息直达工作群">
<p>客户消息直达工作群</p>
</a>
</td>
</tr>
</tbody>
</table>
## 简介
[vue-element-admin](https://panjiachen.github.io/vue-element-admin) 是一个后台前端解决方案,它基于 [vue](https://github.com/vuejs/vue) 和 [element-ui](https://github.com/ElemeFE/element)实现。它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
- [在线预览](https://panjiachen.github.io/vue-element-admin)
- [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
- [Gitter 讨论组](https://gitter.im/vue-element-admin/discuss)
- [Donate](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
- [Wiki](https://github.com/PanJiaChen/vue-element-admin/wiki)
- [Gitee](https://panjiachen.gitee.io/vue-element-admin/) 在线预览(国内用户可访问该地址)
- [国内访问文档](https://panjiachen.gitee.io/vue-element-admin-site/zh/) 文档(方便没翻墙的用户查看)
- 基础模板建议使用: [vue-admin-template](https://github.com/PanJiaChen/vue-admin-template)
- 桌面端: [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin)
- Typescript 版: [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (鸣谢: [@Armour](https://github.com/Armour))
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312)
**`v4.1.0+`版本之后默认 master 分支将不支持国际化,有需要的请使用[i18n](https://github.com/PanJiaChen/vue-element-admin/tree/i18n)分支,它会和 master 保持同步更新**
**该项目不支持低版本浏览器(如 ie),有需求请自行添加 polyfill [详情](https://github.com/PanJiaChen/vue-element-admin/wiki#babel-polyfill)**
**目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若发现问题,欢迎提[issue](https://github.com/PanJiaChen/vue-element-admin/issues/new)。若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-element-admin/tree/tag/3.11.0),它不依赖 `vue-cli`**
群主 **[圈子](https://jianshiapp.com/circles/1209)** 群主会经常分享一些技术相关的东西,或者加入 [qq 群](https://github.com/PanJiaChen/vue-element-admin/issues/602) 或者关注 [微博](https://weibo.com/u/3423485724?is_all=1)
## 前序准备
你需要在本地安装 [node](http://nodejs.org/) 和 [git](https://git-scm.com/)。本项目技术栈基于 [ES2015+](http://es6.ruanyifeng.com/)、[vue](https://cn.vuejs.org/index.html)、[vuex](https://vuex.vuejs.org/zh-cn/)、[vue-router](https://router.vuejs.org/zh-cn/) 、[vue-cli](https://github.com/vuejs/vue-cli) 、[axios](https://github.com/axios/axios) 和 [element-ui](https://github.com/ElemeFE/element),所有的请求数据都使用[Mock.js](https://github.com/nuysoft/Mock)进行模拟,提前了解和学习这些知识会对使用本项目有很大的帮助。
同时配套了系列教程文章,如何从零构建后一个完整的后台项目,建议大家先看完这些文章再来实践本项目
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2)
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac)
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35)
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板)](https://juejin.im/post/595b4d776fb9a06bbe7dba56)
- [手摸手,带你用vue撸后台 系列五(v4.0新版本)](https://juejin.im/post/5c92ff94f265da6128275a85)
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836)
- [手摸手,带你优雅的使用 icon](https://juejin.im/post/59bb864b5188257e7a427c09)
- [手摸手,带你用合理的姿势使用 webpack4(上)](https://juejin.im/post/5b56909a518825195f499806)
- [手摸手,带你用合理的姿势使用 webpack4(下)](https://juejin.im/post/5b5d6d6f6fb9a04fea58aabc)
**如有问题请先看上述使用文档和文章,若不能满足,欢迎 issue 和 pr**
[![Edit on CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/PanJiaChen/vue-element-admin/tree/CodeSandbox)
<p align="center">
<img width="900" src="https://wpimg.wallstcn.com/a5894c1b-f6af-456e-82df-1151da0839bf.png">
</p>
## Sponsors
Become a sponsor and get your logo on our README on GitHub with a link to your site. [[Become a sponsor]](https://www.patreon.com/panjiachen)
### Akveo
<a href="https://store.akveo.com/products/vue-java-admin-dashboard-spring?utm_campaign=akveo_store-Vue-Vue_demo%2Fgithub&utm_source=vue_admin&utm_medium=referral&utm_content=github_banner"><img width="500px" src="https://raw.githubusercontent.com/PanJiaChen/vue-element-admin-site/master/docs/.vuepress/public/images/vue-java-banner.png" /></a><p>Java 后端整合,可以使用优惠码:SWB0RAZPZR1M,获得20%的价格优化</p>
### Flatlogic
<a href="https://flatlogic.com/admin-dashboards?from=vue-element-admin"><img width="150px" src="https://wpimg.wallstcn.com/9c0b719b-5551-4c1e-b776-63994632d94a.png" /></a><p>Admin Dashboard Templates made with Vue, React and Angular.</p>
## 功能
```
- 登录 / 注销
- 权限验证
- 页面权限
- 指令权限
- 权限配置
- 二步登录
- 多环境发布
- dev
- sit
- stage
- prod
- 全局功能
- 国际化多语言
- 多种动态换肤
- 动态侧边栏(支持多级路由嵌套)
- 动态面包屑
- 快捷导航(标签页)
- Svg Sprite 图标
- 本地/后端 mock 数据
- Screenfull全屏
- 自适应收缩侧边栏
- 编辑器
- 富文本
- Markdown
- JSON 等多格式
- Excel
- 导出excel
- 导入excel
- 前端可视化excel
- 导出zip
- 表格
- 动态表格
- 拖拽表格
- 内联编辑
- 错误页面
- 401
- 404
- 組件
- 头像上传
- 返回顶部
- 拖拽Dialog
- 拖拽Select
- 拖拽看板
- 列表拖拽
- SplitPane
- Dropzone
- Sticky
- CountTo
- 综合实例
- 错误日志
- Dashboard
- 引导页
- ECharts 图表
- Clipboard(剪贴复制)
- Markdown2html
```
## 开发
```bash
# 克隆项目
git clone https://github.com/PanJiaChen/vue-element-admin.git
# 进入项目目录
cd vue-element-admin
# 安装依赖
npm install
# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
npm install --registry=https://registry.npm.taobao.org
# 启动服务
npm run dev
```
浏览器访问 http://localhost:9527
## 发布
```bash
# 构建测试环境
npm run build:stage
# 构建生产环境
npm run build:prod
```
## 其它
```bash
# 预览发布环境效果
npm run preview
# 预览发布环境效果 + 静态资源分析
npm run preview -- --report
# 代码格式检查
npm run lint
# 代码格式检查并自动修复
npm run lint -- --fix
```
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/)
## Changelog
Detailed changes for each release are documented in the [release notes](https://github.com/PanJiaChen/vue-element-admin/releases).
## Online Demo
[在线 Demo](https://panjiachen.github.io/vue-element-admin)
## Donate
如果你觉得这个项目帮助到了你,你可以帮作者买一杯果汁表示鼓励 :tropical_drink:
![donate](https://panjiachen.github.io/donate/donation.png)
[更多捐赠方式](https://panjiachen.gitee.io/vue-element-admin-site/zh/donate)
[Paypal Me](https://www.paypal.me/panfree23)
[Buy me a coffee](https://www.buymeacoffee.com/Pan)
## 购买贴纸
你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,本项目将获得 2 元的捐赠。
## Browsers support
Modern browsers and Internet Explorer 10+.
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](https://godban.github.io/browsers-support-badges/)</br>Safari |
| --------- | --------- | --------- | --------- |
| IE10, IE11, Edge | last 2 versions | last 2 versions | last 2 versions |
## License
[MIT](https://github.com/PanJiaChen/vue-element-admin/blob/master/LICENSE)
Copyright (c) 2017-present PanJiaChen

14
scheduler/vue-element-admin-master/babel.config.js

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

35
scheduler/vue-element-admin-master/build/index.js

@ -0,0 +1,35 @@
const { run } = require('runjs')
const chalk = require('chalk')
const config = require('../vue.config.js')
const rawArgv = process.argv.slice(2)
const args = rawArgv.join(' ')
if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
const report = rawArgv.includes('--report')
run(`vue-cli-service build ${args}`)
const port = 9526
const publicPath = config.publicPath
var connect = require('connect')
var serveStatic = require('serve-static')
const app = connect()
app.use(
publicPath,
serveStatic('./dist', {
index: ['index.html', '/']
})
)
app.listen(port, function () {
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`))
if (report) {
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`))
}
})
} else {
run(`vue-cli-service build ${args}`)
}

24
scheduler/vue-element-admin-master/jest.config.js

@ -0,0 +1,24 @@
module.exports = {
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
'jest-transform-stub',
'^.+\\.jsx?$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: ['jest-serializer-vue'],
testMatch: [
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'
],
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'],
coverageDirectory: '<rootDir>/tests/unit/coverage',
// 'collectCoverage': true,
'coverageReporters': [
'lcov',
'text-summary'
],
testURL: 'http://localhost/'
}

9
scheduler/vue-element-admin-master/jsconfig.json

@ -0,0 +1,9 @@
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

116
scheduler/vue-element-admin-master/mock/article.js

@ -0,0 +1,116 @@
const Mock = require('mockjs')
const List = []
const count = 100
const baseContent = '<p>I am testing data, I am testing data.</p><p><img src="https://wpimg.wallstcn.com/4c69009c-0fd4-4153-b112-6cb53d1cf943"></p>'
const image_uri = 'https://wpimg.wallstcn.com/e4558086-631c-425c-9430-56ffb46e70b3'
for (let i = 0; i < count; i++) {
List.push(Mock.mock({
id: '@increment',
timestamp: +Mock.Random.date('T'),
author: '@first',
reviewer: '@first',
title: '@title(5, 10)',
content_short: 'mock data',
content: baseContent,
forecast: '@float(0, 100, 2, 2)',
importance: '@integer(1, 3)',
'type|1': ['CN', 'US', 'JP', 'EU'],
'status|1': ['published', 'draft'],
display_time: '@datetime',
comment_disabled: true,
pageviews: '@integer(300, 5000)',
image_uri,
platforms: ['a-platform']
}))
}
module.exports = [
{
url: '/vue-element-admin/article/list',
type: 'get',
response: config => {
const { importance, type, title, page = 1, limit = 20, sort } = config.query
let mockList = List.filter(item => {
if (importance && item.importance !== +importance) return false
if (type && item.type !== type) return false
if (title && item.title.indexOf(title) < 0) return false
return true
})
if (sort === '-id') {
mockList = mockList.reverse()
}
const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
return {
code: 20000,
data: {
total: mockList.length,
items: pageList
}
}
}
},
{
url: '/vue-element-admin/article/detail',
type: 'get',
response: config => {
const { id } = config.query
for (const article of List) {
if (article.id === +id) {
return {
code: 20000,
data: article
}
}
}
}
},
{
url: '/vue-element-admin/article/pv',
type: 'get',
response: _ => {
return {
code: 20000,
data: {
pvData: [
{ key: 'PC', pv: 1024 },
{ key: 'mobile', pv: 1024 },
{ key: 'ios', pv: 1024 },
{ key: 'android', pv: 1024 }
]
}
}
}
},
{
url: '/vue-element-admin/article/create',
type: 'post',
response: _ => {
return {
code: 20000,
data: 'success'
}
}
},
{
url: '/vue-element-admin/article/update',
type: 'post',
response: _ => {
return {
code: 20000,
data: 'success'
}
}
}
]

60
scheduler/vue-element-admin-master/mock/index.js

@ -0,0 +1,60 @@
const Mock = require('mockjs')
const { param2Obj } = require('./utils')
const user = require('./user')
const role = require('./role')
const article = require('./article')
const search = require('./remote-search')
const mocks = [
...user,
...role,
...article,
...search
]
// for front mock
// please use it cautiously, it will redefine XMLHttpRequest,
// which will cause many of your third-party libraries to be invalidated(like progress event).
function mockXHR() {
// mock patch
// https://github.com/nuysoft/Mock/issues/300
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send
Mock.XHR.prototype.send = function() {
if (this.custom.xhr) {
this.custom.xhr.withCredentials = this.withCredentials || false
if (this.responseType) {
this.custom.xhr.responseType = this.responseType
}
}
this.proxy_send(...arguments)
}
function XHR2ExpressReqWrap(respond) {
return function(options) {
let result = null
if (respond instanceof Function) {
const { body, type, url } = options
// https://expressjs.com/en/4x/api.html#req
result = respond({
method: type,
body: JSON.parse(body),
query: param2Obj(url)
})
} else {
result = respond
}
return Mock.mock(result)
}
}
for (const i of mocks) {
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response))
}
}
module.exports = {
mocks,
mockXHR
}

81
scheduler/vue-element-admin-master/mock/mock-server.js

@ -0,0 +1,81 @@
const chokidar = require('chokidar')
const bodyParser = require('body-parser')
const chalk = require('chalk')
const path = require('path')
const Mock = require('mockjs')
const mockDir = path.join(process.cwd(), 'mock')
function registerRoutes(app) {
let mockLastIndex
const { mocks } = require('./index.js')
const mocksForServer = mocks.map(route => {
return responseFake(route.url, route.type, route.response)
})
for (const mock of mocksForServer) {
app[mock.type](mock.url, mock.response)
mockLastIndex = app._router.stack.length
}
const mockRoutesLength = Object.keys(mocksForServer).length
return {
mockRoutesLength: mockRoutesLength,
mockStartIndex: mockLastIndex - mockRoutesLength
}
}
function unregisterRoutes() {
Object.keys(require.cache).forEach(i => {
if (i.includes(mockDir)) {
delete require.cache[require.resolve(i)]
}
})
}
// for mock server
const responseFake = (url, type, respond) => {
return {
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`),
type: type || 'get',
response(req, res) {
console.log('request invoke:' + req.path)
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond))
}
}
}
module.exports = app => {
// parse app.body
// https://expressjs.com/en/4x/api.html#req.body
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
const mockRoutes = registerRoutes(app)
var mockRoutesLength = mockRoutes.mockRoutesLength
var mockStartIndex = mockRoutes.mockStartIndex
// watch files, hot reload mock server
chokidar.watch(mockDir, {
ignored: /mock-server/,
ignoreInitial: true
}).on('all', (event, path) => {
if (event === 'change' || event === 'add') {
try {
// remove mock routes stack
app._router.stack.splice(mockStartIndex, mockRoutesLength)
// clear routes cache
unregisterRoutes()
const mockRoutes = registerRoutes(app)
mockRoutesLength = mockRoutes.mockRoutesLength
mockStartIndex = mockRoutes.mockStartIndex
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`))
} catch (error) {
console.log(chalk.redBright(error))
}
}
})
}

51
scheduler/vue-element-admin-master/mock/remote-search.js

@ -0,0 +1,51 @@
const Mock = require('mockjs')
const NameList = []
const count = 100
for (let i = 0; i < count; i++) {
NameList.push(Mock.mock({
name: '@first'
}))
}
NameList.push({ name: 'mock-Pan' })
module.exports = [
// username search
{
url: '/vue-element-admin/search/user',
type: 'get',
response: config => {
const { name } = config.query
const mockNameList = NameList.filter(item => {
const lowerCaseName = item.name.toLowerCase()
return !(name && lowerCaseName.indexOf(name.toLowerCase()) < 0)
})
return {
code: 20000,
data: { items: mockNameList }
}
}
},
// transaction list
{
url: '/vue-element-admin/transaction/list',
type: 'get',
response: _ => {
return {
code: 20000,
data: {
total: 20,
'items|20': [{
order_no: '@guid()',
timestamp: +Mock.Random.date('T'),
username: '@name()',
price: '@float(1000, 15000, 0, 2)',
'status|1': ['success', 'pending']
}]
}
}
}
}
]

98
scheduler/vue-element-admin-master/mock/role/index.js

@ -0,0 +1,98 @@
const Mock = require('mockjs')
const { deepClone } = require('../utils')
const { asyncRoutes, constantRoutes } = require('./routes.js')
const routes = deepClone([...constantRoutes, ...asyncRoutes])
const roles = [
{
key: 'admin',
name: 'admin',
description: 'Super Administrator. Have access to view all pages.',
routes: routes
},
{
key: 'editor',
name: 'editor',
description: 'Normal Editor. Can see all pages except permission page',
routes: routes.filter(i => i.path !== '/permission')// just a mock
},
{
key: 'visitor',
name: 'visitor',
description: 'Just a visitor. Can only see the home page and the document page',
routes: [{
path: '',
redirect: 'dashboard',
children: [
{
path: 'dashboard',
name: 'Dashboard',
meta: { title: 'dashboard', icon: 'dashboard' }
}
]
}]
}
]
module.exports = [
// mock get all routes form server
{
url: '/vue-element-admin/routes',
type: 'get',
response: _ => {
return {
code: 20000,
data: routes
}
}
},
// mock get all roles form server
{
url: '/vue-element-admin/roles',
type: 'get',
response: _ => {
return {
code: 20000,
data: roles
}
}
},
// add role
{
url: '/vue-element-admin/role',
type: 'post',
response: {
code: 20000,
data: {
key: Mock.mock('@integer(300, 5000)')
}
}
},
// update role
{
url: '/vue-element-admin/role/[A-Za-z0-9]',
type: 'put',
response: {
code: 20000,
data: {
status: 'success'
}
}
},
// delete role
{
url: '/vue-element-admin/role/[A-Za-z0-9]',
type: 'delete',
response: {
code: 20000,
data: {
status: 'success'
}
}
}
]

530
scheduler/vue-element-admin-master/mock/role/routes.js

@ -0,0 +1,530 @@
// Just a mock data
const constantRoutes = [
{
path: '/redirect',
component: 'layout/Layout',
hidden: true,
children: [
{
path: '/redirect/:path*',
component: 'views/redirect/index'
}
]
},
{
path: '/login',
component: 'views/login/index',
hidden: true
},
{
path: '/auth-redirect',
component: 'views/login/auth-redirect',
hidden: true
},
{
path: '/404',
component: 'views/error-page/404',
hidden: true
},
{
path: '/401',
component: 'views/error-page/401',
hidden: true
},
{
path: '',
component: 'layout/Layout',
redirect: 'dashboard',
children: [
{
path: 'dashboard',
component: 'views/dashboard/index',
name: 'Dashboard',
meta: { title: 'Dashboard', icon: 'dashboard', affix: true }
}
]
},
{
path: '/documentation',
component: 'layout/Layout',
children: [
{
path: 'index',
component: 'views/documentation/index',
name: 'Documentation',
meta: { title: 'Documentation', icon: 'documentation', affix: true }
}
]
},
{
path: '/guide',
component: 'layout/Layout',
redirect: '/guide/index',
children: [
{
path: 'index',
component: 'views/guide/index',
name: 'Guide',
meta: { title: 'Guide', icon: 'guide', noCache: true }
}
]
}
]
const asyncRoutes = [
{
path: '/permission',
component: 'layout/Layout',
redirect: '/permission/index',
alwaysShow: true,
meta: {
title: 'Permission',
icon: 'lock',
roles: ['admin', 'editor']
},
children: [
{
path: 'page',
component: 'views/permission/page',
name: 'PagePermission',
meta: {
title: 'Page Permission',
roles: ['admin']
}
},
{
path: 'directive',
component: 'views/permission/directive',
name: 'DirectivePermission',
meta: {
title: 'Directive Permission'
}
},
{
path: 'role',
component: 'views/permission/role',
name: 'RolePermission',
meta: {
title: 'Role Permission',
roles: ['admin']
}
}
]
},
{
path: '/icon',
component: 'layout/Layout',
children: [
{
path: 'index',
component: 'views/icons/index',
name: 'Icons',
meta: { title: 'Icons', icon: 'icon', noCache: true }
}
]
},
{
path: '/components',
component: 'layout/Layout',
redirect: 'noRedirect',
name: 'ComponentDemo',
meta: {
title: 'Components',
icon: 'component'
},
children: [
{
path: 'tinymce',
component: 'views/components-demo/tinymce',
name: 'TinymceDemo',
meta: { title: 'Tinymce' }
},
{
path: 'markdown',
component: 'views/components-demo/markdown',
name: 'MarkdownDemo',
meta: { title: 'Markdown' }
},
{
path: 'json-editor',
component: 'views/components-demo/json-editor',
name: 'JsonEditorDemo',
meta: { title: 'Json Editor' }
},
{
path: 'split-pane',
component: 'views/components-demo/split-pane',
name: 'SplitpaneDemo',
meta: { title: 'SplitPane' }
},
{
path: 'avatar-upload',
component: 'views/components-demo/avatar-upload',
name: 'AvatarUploadDemo',
meta: { title: 'Avatar Upload' }
},
{
path: 'dropzone',
component: 'views/components-demo/dropzone',
name: 'DropzoneDemo',
meta: { title: 'Dropzone' }
},
{
path: 'sticky',
component: 'views/components-demo/sticky',
name: 'StickyDemo',
meta: { title: 'Sticky' }
},
{
path: 'count-to',
component: 'views/components-demo/count-to',
name: 'CountToDemo',
meta: { title: 'Count To' }
},
{
path: 'mixin',
component: 'views/components-demo/mixin',
name: 'ComponentMixinDemo',
meta: { title: 'componentMixin' }
},
{
path: 'back-to-top',
component: 'views/components-demo/back-to-top',
name: 'BackToTopDemo',
meta: { title: 'Back To Top' }
},
{
path: 'drag-dialog',
component: 'views/components-demo/drag-dialog',
name: 'DragDialogDemo',
meta: { title: 'Drag Dialog' }
},
{
path: 'drag-select',
component: 'views/components-demo/drag-select',
name: 'DragSelectDemo',
meta: { title: 'Drag Select' }
},
{
path: 'dnd-list',
component: 'views/components-demo/dnd-list',
name: 'DndListDemo',
meta: { title: 'Dnd List' }
},
{
path: 'drag-kanban',
component: 'views/components-demo/drag-kanban',
name: 'DragKanbanDemo',
meta: { title: 'Drag Kanban' }
}
]
},
{
path: '/charts',
component: 'layout/Layout',
redirect: 'noRedirect',
name: 'Charts',
meta: {
title: 'Charts',
icon: 'chart'
},
children: [
{
path: 'keyboard',
component: 'views/charts/keyboard',
name: 'KeyboardChart',
meta: { title: 'Keyboard Chart', noCache: true }
},
{
path: 'line',
component: 'views/charts/line',
name: 'LineChart',
meta: { title: 'Line Chart', noCache: true }
},
{
path: 'mixchart',
component: 'views/charts/mixChart',
name: 'MixChart',
meta: { title: 'Mix Chart', noCache: true }
}
]
},
{
path: '/nested',
component: 'layout/Layout',
redirect: '/nested/menu1/menu1-1',
name: 'Nested',
meta: {
title: 'Nested',
icon: 'nested'
},
children: [
{
path: 'menu1',
component: 'views/nested/menu1/index',
name: 'Menu1',
meta: { title: 'Menu1' },
redirect: '/nested/menu1/menu1-1',
children: [
{
path: 'menu1-1',
component: 'views/nested/menu1/menu1-1',
name: 'Menu1-1',
meta: { title: 'Menu1-1' }
},
{
path: 'menu1-2',
component: 'views/nested/menu1/menu1-2',
name: 'Menu1-2',
redirect: '/nested/menu1/menu1-2/menu1-2-1',
meta: { title: 'Menu1-2' },
children: [
{
path: 'menu1-2-1',
component: 'views/nested/menu1/menu1-2/menu1-2-1',
name: 'Menu1-2-1',
meta: { title: 'Menu1-2-1' }
},
{
path: 'menu1-2-2',
component: 'views/nested/menu1/menu1-2/menu1-2-2',
name: 'Menu1-2-2',
meta: { title: 'Menu1-2-2' }
}
]
},
{
path: 'menu1-3',
component: 'views/nested/menu1/menu1-3',
name: 'Menu1-3',
meta: { title: 'Menu1-3' }
}
]
},
{
path: 'menu2',
name: 'Menu2',
component: 'views/nested/menu2/index',
meta: { title: 'Menu2' }
}
]
},
{
path: '/example',
component: 'layout/Layout',
redirect: '/example/list',
name: 'Example',
meta: {
title: 'Example',
icon: 'example'
},
children: [
{
path: 'create',
component: 'views/example/create',
name: 'CreateArticle',
meta: { title: 'Create Article', icon: 'edit' }
},
{
path: 'edit/:id(\\d+)',
component: 'views/example/edit',
name: 'EditArticle',
meta: { title: 'Edit Article', noCache: true },
hidden: true
},
{
path: 'list',
component: 'views/example/list',
name: 'ArticleList',
meta: { title: 'Article List', icon: 'list' }
}
]
},
{
path: '/tab',
component: 'layout/Layout',
children: [
{
path: 'index',
component: 'views/tab/index',
name: 'Tab',
meta: { title: 'Tab', icon: 'tab' }
}
]
},
{
path: '/error',
component: 'layout/Layout',
redirect: 'noRedirect',
name: 'ErrorPages',
meta: {
title: 'Error Pages',
icon: '404'
},
children: [
{
path: '401',
component: 'views/error-page/401',
name: 'Page401',
meta: { title: 'Page 401', noCache: true }
},
{
path: '404',
component: 'views/error-page/404',
name: 'Page404',
meta: { title: 'Page 404', noCache: true }
}
]
},
{
path: '/error-log',
component: 'layout/Layout',
redirect: 'noRedirect',
children: [
{
path: 'log',
component: 'views/error-log/index',
name: 'ErrorLog',
meta: { title: 'Error Log', icon: 'bug' }
}
]
},
{
path: '/excel',
component: 'layout/Layout',
redirect: '/excel/export-excel',
name: 'Excel',
meta: {
title: 'Excel',
icon: 'excel'
},
children: [
{
path: 'export-excel',
component: 'views/excel/export-excel',
name: 'ExportExcel',
meta: { title: 'Export Excel' }
},
{
path: 'export-selected-excel',
component: 'views/excel/select-excel',
name: 'SelectExcel',
meta: { title: 'Select Excel' }
},
{
path: 'export-merge-header',
component: 'views/excel/merge-header',
name: 'MergeHeader',
meta: { title: 'Merge Header' }
},
{
path: 'upload-excel',
component: 'views/excel/upload-excel',
name: 'UploadExcel',
meta: { title: 'Upload Excel' }
}
]
},
{
path: '/zip',
component: 'layout/Layout',
redirect: '/zip/download',
alwaysShow: true,
meta: { title: 'Zip', icon: 'zip' },
children: [
{
path: 'download',
component: 'views/zip/index',
name: 'ExportZip',
meta: { title: 'Export Zip' }
}
]
},
{
path: '/pdf',
component: 'layout/Layout',
redirect: '/pdf/index',
children: [
{
path: 'index',
component: 'views/pdf/index',
name: 'PDF',
meta: { title: 'PDF', icon: 'pdf' }
}
]
},
{
path: '/pdf/download',
component: 'views/pdf/download',
hidden: true
},
{
path: '/theme',
component: 'layout/Layout',
redirect: 'noRedirect',
children: [
{
path: 'index',
component: 'views/theme/index',
name: 'Theme',
meta: { title: 'Theme', icon: 'theme' }
}
]
},
{
path: '/clipboard',
component: 'layout/Layout',
redirect: 'noRedirect',
children: [
{
path: 'index',
component: 'views/clipboard/index',
name: 'ClipboardDemo',
meta: { title: 'Clipboard Demo', icon: 'clipboard' }
}
]
},
{
path: '/i18n',
component: 'layout/Layout',
children: [
{
path: 'index',
component: 'views/i18n-demo/index',
name: 'I18n',
meta: { title: 'I18n', icon: 'international' }
}
]
},
{
path: 'external-link',
component: 'layout/Layout',
children: [
{
path: 'https://github.com/PanJiaChen/vue-element-admin',
meta: { title: 'External Link', icon: 'link' }
}
]
},
{ path: '*', redirect: '/404', hidden: true }
]
module.exports = {
constantRoutes,
asyncRoutes
}

84
scheduler/vue-element-admin-master/mock/user.js

@ -0,0 +1,84 @@
const tokens = {
admin: {
token: 'admin-token'
},
editor: {
token: 'editor-token'
}
}
const users = {
'admin-token': {
roles: ['admin'],
introduction: 'I am a super administrator',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Super Admin'
},
'editor-token': {
roles: ['editor'],
introduction: 'I am an editor',
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
name: 'Normal Editor'
}
}
module.exports = [
// user login
{
url: '/vue-element-admin/user/login',
type: 'post',
response: config => {
const { username } = config.body
const token = tokens[username]
// mock error
if (!token) {
return {
code: 60204,
message: 'Account and password are incorrect.'
}
}
return {
code: 20000,
data: token
}
}
},
// get user info
{
url: '/vue-element-admin/user/info\.*',
type: 'get',
response: config => {
const { token } = config.query
const info = users[token]
// mock error
if (!info) {
return {
code: 50008,
message: 'Login failed, unable to get user details.'
}
}
return {
code: 20000,
data: info
}
}
},
// user logout
{
url: '/vue-element-admin/user/logout',
type: 'post',
response: _ => {
return {
code: 20000,
data: 'success'
}
}
}
]

48
scheduler/vue-element-admin-master/mock/utils.js

@ -0,0 +1,48 @@
/**
* @param {string} url
* @returns {Object}
*/
function param2Obj(url) {
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
if (!search) {
return {}
}
const obj = {}
const searchArr = search.split('&')
searchArr.forEach(v => {
const index = v.indexOf('=')
if (index !== -1) {
const name = v.substring(0, index)
const val = v.substring(index + 1, v.length)
obj[name] = val
}
})
return obj
}
/**
* This is just a simple version of deep copy
* Has a lot of edge cases bug
* If you want to use a perfect deep copy, use lodash's _.cloneDeep
* @param {Object} source
* @returns {Object}
*/
function deepClone(source) {
if (!source && typeof source !== 'object') {
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach(keys => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepClone(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
module.exports = {
param2Obj,
deepClone
}

111
scheduler/vue-element-admin-master/package.json

@ -0,0 +1,111 @@
{
"name": "vue-element-admin",
"version": "4.4.0",
"description": "A magical vue admin. An out-of-box UI solution for enterprise applications. Newest development stack of vue. Lots of awesome features",
"author": "Pan <panfree23@gmail.com>",
"scripts": {
"dev": "vue-cli-service serve",
"lint": "eslint --ext .js,.vue src",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"new": "plop",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
"test:ci": "npm run lint && npm run test:unit"
},
"dependencies": {
"axios": "0.18.1",
"clipboard": "2.0.4",
"codemirror": "5.45.0",
"core-js": "3.6.5",
"driver.js": "0.9.5",
"dropzone": "5.5.1",
"echarts": "4.2.1",
"element-ui": "2.13.2",
"file-saver": "2.0.1",
"fuse.js": "3.4.4",
"js-cookie": "2.2.0",
"jsonlint": "1.6.3",
"jszip": "3.2.1",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"screenfull": "4.2.0",
"script-loader": "0.7.2",
"sortablejs": "1.8.4",
"tui-editor": "1.3.3",
"vue": "2.6.10",
"vue-count-to": "1.0.13",
"vue-router": "3.0.2",
"vue-splitpane": "1.0.4",
"vuedraggable": "2.20.0",
"vuex": "3.1.0",
"xlsx": "0.14.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "4.4.4",
"@vue/cli-plugin-eslint": "4.4.4",
"@vue/cli-plugin-unit-jest": "4.4.4",
"@vue/cli-service": "4.4.4",
"@vue/test-utils": "1.0.0-beta.29",
"autoprefixer": "9.5.1",
"babel-eslint": "10.1.0",
"babel-jest": "23.6.0",
"babel-plugin-dynamic-import-node": "2.3.3",
"chalk": "2.4.2",
"chokidar": "2.1.5",
"connect": "3.6.6",
"eslint": "6.7.2",
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0",
"husky": "1.3.1",
"lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3",
"plop": "2.3.0",
"runjs": "4.3.2",
"sass": "1.26.2",
"sass-loader": "8.0.2",
"script-ext-html-webpack-plugin": "2.1.3",
"serve-static": "1.13.2",
"svg-sprite-loader": "4.1.3",
"svgo": "1.2.0",
"vue-template-compiler": "2.6.10"
},
"browserslist": [
"> 1%",
"last 2 versions"
],
"bugs": {
"url": "https://github.com/PanJiaChen/vue-element-admin/issues"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
},
"keywords": [
"vue",
"admin",
"dashboard",
"element-ui",
"boilerplate",
"admin-template",
"management-system"
],
"license": "MIT",
"lint-staged": {
"src/**/*.{js,vue}": [
"eslint --fix",
"git add"
]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/PanJiaChen/vue-element-admin.git"
}
}

26
scheduler/vue-element-admin-master/plop-templates/component/index.hbs

@ -0,0 +1,26 @@
{{#if template}}
<template>
<div />
</template>
{{/if}}
{{#if script}}
<script>
export default {
name: '{{ properCase name }}',
props: {},
data() {
return {}
},
created() {},
mounted() {},
methods: {}
}
</script>
{{/if}}
{{#if style}}
<style lang="scss" scoped>
</style>
{{/if}}

55
scheduler/vue-element-admin-master/plop-templates/component/prompt.js

@ -0,0 +1,55 @@
const { notEmpty } = require('../utils.js')
module.exports = {
description: 'generate vue component',
prompts: [{
type: 'input',
name: 'name',
message: 'component name please',
validate: notEmpty('name')
},
{
type: 'checkbox',
name: 'blocks',
message: 'Blocks:',
choices: [{
name: '<template>',
value: 'template',
checked: true
},
{
name: '<script>',
value: 'script',
checked: true
},
{
name: 'style',
value: 'style',
checked: true
}
],
validate(value) {
if (value.indexOf('script') === -1 && value.indexOf('template') === -1) {
return 'Components require at least a <script> or <template> tag.'
}
return true
}
}
],
actions: data => {
const name = '{{properCase name}}'
const actions = [{
type: 'add',
path: `src/components/${name}/index.vue`,
templateFile: 'plop-templates/component/index.hbs',
data: {
name: name,
template: data.blocks.includes('template'),
script: data.blocks.includes('script'),
style: data.blocks.includes('style')
}
}]
return actions
}
}

16
scheduler/vue-element-admin-master/plop-templates/store/index.hbs

@ -0,0 +1,16 @@
{{#if state}}
const state = {}
{{/if}}
{{#if mutations}}
const mutations = {}
{{/if}}
{{#if actions}}
const actions = {}
{{/if}}
export default {
namespaced: true,
{{options}}
}

62
scheduler/vue-element-admin-master/plop-templates/store/prompt.js

@ -0,0 +1,62 @@
const { notEmpty } = require('../utils.js')
module.exports = {
description: 'generate store',
prompts: [{
type: 'input',
name: 'name',
message: 'store name please',
validate: notEmpty('name')
},
{
type: 'checkbox',
name: 'blocks',
message: 'Blocks:',
choices: [{
name: 'state',
value: 'state',
checked: true
},
{
name: 'mutations',
value: 'mutations',
checked: true
},
{
name: 'actions',
value: 'actions',
checked: true
}
],
validate(value) {
if (!value.includes('state') || !value.includes('mutations')) {
return 'store require at least state and mutations'
}
return true
}
}
],
actions(data) {
const name = '{{name}}'
const { blocks } = data
const options = ['state', 'mutations']
const joinFlag = `,
`
if (blocks.length === 3) {
options.push('actions')
}
const actions = [{
type: 'add',
path: `src/store/modules/${name}.js`,
templateFile: 'plop-templates/store/index.hbs',
data: {
options: options.join(joinFlag),
state: blocks.includes('state'),
mutations: blocks.includes('mutations'),
actions: blocks.includes('actions')
}
}]
return actions
}
}

2
scheduler/vue-element-admin-master/plop-templates/utils.js

@ -0,0 +1,2 @@
exports.notEmpty = name => v =>
!v || v.trim() === '' ? `${name} is required` : true

26
scheduler/vue-element-admin-master/plop-templates/view/index.hbs

@ -0,0 +1,26 @@
{{#if template}}
<template>
<div />
</template>
{{/if}}
{{#if script}}
<script>
export default {
name: '{{ properCase name }}',
props: {},
data() {
return {}
},
created() {},
mounted() {},
methods: {}
}
</script>
{{/if}}
{{#if style}}
<style lang="scss" scoped>
</style>
{{/if}}

55
scheduler/vue-element-admin-master/plop-templates/view/prompt.js

@ -0,0 +1,55 @@
const { notEmpty } = require('../utils.js')
module.exports = {
description: 'generate a view',
prompts: [{
type: 'input',
name: 'name',
message: 'view name please',
validate: notEmpty('name')
},
{
type: 'checkbox',
name: 'blocks',
message: 'Blocks:',
choices: [{
name: '<template>',
value: 'template',
checked: true
},
{
name: '<script>',
value: 'script',
checked: true
},
{
name: 'style',
value: 'style',
checked: true
}
],
validate(value) {
if (value.indexOf('script') === -1 && value.indexOf('template') === -1) {
return 'View require at least a <script> or <template> tag.'
}
return true
}
}
],
actions: data => {
const name = '{{name}}'
const actions = [{
type: 'add',
path: `src/views/${name}/index.vue`,
templateFile: 'plop-templates/view/index.hbs',
data: {
name: name,
template: data.blocks.includes('template'),
script: data.blocks.includes('script'),
style: data.blocks.includes('style')
}
}]
return actions
}
}

9
scheduler/vue-element-admin-master/plopfile.js

@ -0,0 +1,9 @@
const viewGenerator = require('./plop-templates/view/prompt')
const componentGenerator = require('./plop-templates/component/prompt')
const storeGenerator = require('./plop-templates/store/prompt.js')
module.exports = function(plop) {
plop.setGenerator('view', viewGenerator)
plop.setGenerator('component', componentGenerator)
plop.setGenerator('store', storeGenerator)
}

5
scheduler/vue-element-admin-master/postcss.config.js

@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

BIN
scheduler/vue-element-admin-master/public/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

15
scheduler/vue-element-admin-master/public/index.html

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="renderer" content="webkit">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= webpackConfig.name %></title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

11
scheduler/vue-element-admin-master/src/App.vue

@ -0,0 +1,11 @@
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
name: 'App'
}
</script>

41
scheduler/vue-element-admin-master/src/api/article.js

@ -0,0 +1,41 @@
import request from '@/utils/request'
export function fetchList(query) {
return request({
url: '/vue-element-admin/article/list',
method: 'get',
params: query
})
}
export function fetchArticle(id) {
return request({
url: '/vue-element-admin/article/detail',
method: 'get',
params: { id }
})
}
export function fetchPv(pv) {
return request({
url: '/vue-element-admin/article/pv',
method: 'get',
params: { pv }
})
}
export function createArticle(data) {
return request({
url: '/vue-element-admin/article/create',
method: 'post',
data
})
}
export function updateArticle(data) {
return request({
url: '/vue-element-admin/article/update',
method: 'post',
data
})
}

8
scheduler/vue-element-admin-master/src/api/qiniu.js

@ -0,0 +1,8 @@
import request from '@/utils/request'
export function getToken() {
return request({
url: '/qiniu/upload/token', // 假地址 自行替换
method: 'get'
})
}

17
scheduler/vue-element-admin-master/src/api/remote-search.js

@ -0,0 +1,17 @@
import request from '@/utils/request'
export function searchUser(name) {
return request({
url: '/vue-element-admin/search/user',
method: 'get',
params: { name }
})
}
export function transactionList(query) {
return request({
url: '/vue-element-admin/transaction/list',
method: 'get',
params: query
})
}

38
scheduler/vue-element-admin-master/src/api/role.js

@ -0,0 +1,38 @@
import request from '@/utils/request'
export function getRoutes() {
return request({
url: '/vue-element-admin/routes',
method: 'get'
})
}
export function getRoles() {
return request({
url: '/vue-element-admin/roles',
method: 'get'
})
}
export function addRole(data) {
return request({
url: '/vue-element-admin/role',
method: 'post',
data
})
}
export function updateRole(id, data) {
return request({
url: `/vue-element-admin/role/${id}`,
method: 'put',
data
})
}
export function deleteRole(id) {
return request({
url: `/vue-element-admin/role/${id}`,
method: 'delete'
})
}

24
scheduler/vue-element-admin-master/src/api/user.js

@ -0,0 +1,24 @@
import request from '@/utils/request'
export function login(data) {
return request({
url: '/vue-element-admin/user/login',
method: 'post',
data
})
}
export function getInfo(token) {
return request({
url: '/vue-element-admin/user/info',
method: 'get',
params: { token }
})
}
export function logout() {
return request({
url: '/vue-element-admin/user/logout',
method: 'post'
})
}

BIN
scheduler/vue-element-admin-master/src/assets/401_images/401.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

BIN
scheduler/vue-element-admin-master/src/assets/404_images/404.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

BIN
scheduler/vue-element-admin-master/src/assets/404_images/404_cloud.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
scheduler/vue-element-admin-master/src/assets/custom-theme/fonts/element-icons.ttf

Binary file not shown.

BIN
scheduler/vue-element-admin-master/src/assets/custom-theme/fonts/element-icons.woff

Binary file not shown.

1
scheduler/vue-element-admin-master/src/assets/custom-theme/index.css

File diff suppressed because one or more lines are too long

111
scheduler/vue-element-admin-master/src/components/BackToTop/index.vue

@ -0,0 +1,111 @@
<template>
<transition :name="transitionName">
<div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
<svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg" class="Icon Icon--backToTopArrow" aria-hidden="true" style="height:16px;width:16px"><path d="M12.036 15.59a1 1 0 0 1-.997.995H5.032a.996.996 0 0 1-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29a1.003 1.003 0 0 1 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z" /></svg>
</div>
</transition>
</template>
<script>
export default {
name: 'BackToTop',
props: {
visibilityHeight: {
type: Number,
default: 400
},
backPosition: {
type: Number,
default: 0
},
customStyle: {
type: Object,
default: function() {
return {
right: '50px',
bottom: '50px',
width: '40px',
height: '40px',
'border-radius': '4px',
'line-height': '45px',
background: '#e7eaf1'
}
}
},
transitionName: {
type: String,
default: 'fade'
}
},
data() {
return {
visible: false,
interval: null,
isMoving: false
}
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
},
beforeDestroy() {
window.removeEventListener('scroll', this.handleScroll)
if (this.interval) {
clearInterval(this.interval)
}
},
methods: {
handleScroll() {
this.visible = window.pageYOffset > this.visibilityHeight
},
backToTop() {
if (this.isMoving) return
const start = window.pageYOffset
let i = 0
this.isMoving = true
this.interval = setInterval(() => {
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
if (next <= this.backPosition) {
window.scrollTo(0, this.backPosition)
clearInterval(this.interval)
this.isMoving = false
} else {
window.scrollTo(0, next)
}
i++
}, 16.7)
},
easeInOutQuad(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b
return -c / 2 * (--t * (t - 2) - 1) + b
}
}
}
</script>
<style scoped>
.back-to-ceiling {
position: fixed;
display: inline-block;
text-align: center;
cursor: pointer;
}
.back-to-ceiling:hover {
background: #d5dbe7;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity .5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0
}
.back-to-ceiling .Icon {
fill: #9aaabf;
background: none;
}
</style>

82
scheduler/vue-element-admin-master/src/components/Breadcrumb/index.vue

@ -0,0 +1,82 @@
<template>
<el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group name="breadcrumb">
<el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
<span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
</el-breadcrumb-item>
</transition-group>
</el-breadcrumb>
</template>
<script>
import pathToRegexp from 'path-to-regexp'
export default {
data() {
return {
levelList: null
}
},
watch: {
$route(route) {
// if you go to the redirect page, do not update the breadcrumbs
if (route.path.startsWith('/redirect/')) {
return
}
this.getBreadcrumb()
}
},
created() {
this.getBreadcrumb()
},
methods: {
getBreadcrumb() {
// only show routes with meta.title
let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
const first = matched[0]
if (!this.isDashboard(first)) {
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched)
}
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
},
isDashboard(route) {
const name = route && route.name
if (!name) {
return false
}
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase()
},
pathCompile(path) {
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
const { params } = this.$route
var toPath = pathToRegexp.compile(path)
return toPath(params)
},
handleLink(item) {
const { redirect, path } = item
if (redirect) {
this.$router.push(redirect)
return
}
this.$router.push(this.pathCompile(path))
}
}
}
</script>
<style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb {
display: inline-block;
font-size: 14px;
line-height: 50px;
margin-left: 8px;
.no-redirect {
color: #97a8be;
cursor: text;
}
}
</style>

155
scheduler/vue-element-admin-master/src/components/Charts/Keyboard.vue

@ -0,0 +1,155 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
const xAxisData = []
const data = []
const data2 = []
for (let i = 0; i < 50; i++) {
xAxisData.push(i)
data.push((Math.sin(i / 5) * (i / 5 - 10) + i / 6) * 5)
data2.push((Math.sin(i / 5) * (i / 5 + 10) + i / 6) * 3)
}
this.chart.setOption({
backgroundColor: '#08263a',
grid: {
left: '5%',
right: '5%'
},
xAxis: [{
show: false,
data: xAxisData
}, {
show: false,
data: xAxisData
}],
visualMap: {
show: false,
min: 0,
max: 50,
dimension: 0,
inRange: {
color: ['#4a657a', '#308e92', '#b1cfa5', '#f5d69f', '#f5898b', '#ef5055']
}
},
yAxis: {
axisLine: {
show: false
},
axisLabel: {
textStyle: {
color: '#4a657a'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#08263f'
}
},
axisTick: {
show: false
}
},
series: [{
name: 'back',
type: 'bar',
data: data2,
z: 1,
itemStyle: {
normal: {
opacity: 0.4,
barBorderRadius: 5,
shadowBlur: 3,
shadowColor: '#111'
}
}
}, {
name: 'Simulate Shadow',
type: 'line',
data,
z: 2,
showSymbol: false,
animationDelay: 0,
animationEasing: 'linear',
animationDuration: 1200,
lineStyle: {
normal: {
color: 'transparent'
}
},
areaStyle: {
normal: {
color: '#08263a',
shadowBlur: 50,
shadowColor: '#000'
}
}
}, {
name: 'front',
type: 'bar',
data,
xAxisIndex: 1,
z: 3,
itemStyle: {
normal: {
barBorderRadius: 5
}
}
}],
animationEasing: 'elasticOut',
animationEasingUpdate: 'elasticOut',
animationDelay(idx) {
return idx * 20
},
animationDelayUpdate(idx) {
return idx * 20
}
})
}
}
}
</script>

227
scheduler/vue-element-admin-master/src/components/Charts/LineMarker.vue

@ -0,0 +1,227 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
this.chart.setOption({
backgroundColor: '#394056',
title: {
top: 20,
text: 'Requests',
textStyle: {
fontWeight: 'normal',
fontSize: 16,
color: '#F1F1F3'
},
left: '1%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#57617B'
}
}
},
legend: {
top: 20,
icon: 'rect',
itemWidth: 14,
itemHeight: 5,
itemGap: 13,
data: ['CMCC', 'CTCC', 'CUCC'],
right: '4%',
textStyle: {
fontSize: 12,
color: '#F1F1F3'
}
},
grid: {
top: 100,
left: '2%',
right: '2%',
bottom: '2%',
containLabel: true
},
xAxis: [{
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#57617B'
}
},
data: ['13:00', '13:05', '13:10', '13:15', '13:20', '13:25', '13:30', '13:35', '13:40', '13:45', '13:50', '13:55']
}],
yAxis: [{
type: 'value',
name: '(%)',
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: '#57617B'
}
},
axisLabel: {
margin: 10,
textStyle: {
fontSize: 14
}
},
splitLine: {
lineStyle: {
color: '#57617B'
}
}
}],
series: [{
name: 'CMCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(137, 189, 27, 0.3)'
}, {
offset: 0.8,
color: 'rgba(137, 189, 27, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(137,189,27)',
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12
}
},
data: [220, 182, 191, 134, 150, 120, 110, 125, 145, 122, 165, 122]
}, {
name: 'CTCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(0, 136, 212, 0.3)'
}, {
offset: 0.8,
color: 'rgba(0, 136, 212, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(0,136,212)',
borderColor: 'rgba(0,136,212,0.2)',
borderWidth: 12
}
},
data: [120, 110, 125, 145, 122, 165, 122, 220, 182, 191, 134, 150]
}, {
name: 'CUCC',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(219, 50, 51, 0.3)'
}, {
offset: 0.8,
color: 'rgba(219, 50, 51, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: 'rgb(219,50,51)',
borderColor: 'rgba(219,50,51,0.2)',
borderWidth: 12
}
},
data: [220, 182, 125, 145, 122, 191, 134, 150, 120, 110, 165, 122]
}]
})
}
}
}
</script>

271
scheduler/vue-element-admin-master/src/components/Charts/MixChart.vue

@ -0,0 +1,271 @@
<template>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
const xData = (function() {
const data = []
for (let i = 1; i < 13; i++) {
data.push(i + 'month')
}
return data
}())
this.chart.setOption({
backgroundColor: '#344b58',
title: {
text: 'statistics',
x: '20',
top: '20',
textStyle: {
color: '#fff',
fontSize: '22'
},
subtextStyle: {
color: '#90979c',
fontSize: '16'
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
textStyle: {
color: '#fff'
}
}
},
grid: {
left: '5%',
right: '5%',
borderWidth: 0,
top: 150,
bottom: 95,
textStyle: {
color: '#fff'
}
},
legend: {
x: '5%',
top: '10%',
textStyle: {
color: '#90979c'
},
data: ['female', 'male', 'average']
},
calculable: true,
xAxis: [{
type: 'category',
axisLine: {
lineStyle: {
color: '#90979c'
}
},
splitLine: {
show: false
},
axisTick: {
show: false
},
splitArea: {
show: false
},
axisLabel: {
interval: 0
},
data: xData
}],
yAxis: [{
type: 'value',
splitLine: {
show: false
},
axisLine: {
lineStyle: {
color: '#90979c'
}
},
axisTick: {
show: false
},
axisLabel: {
interval: 0
},
splitArea: {
show: false
}
}],
dataZoom: [{
show: true,
height: 30,
xAxisIndex: [
0
],
bottom: 30,
start: 10,
end: 80,
handleIcon: 'path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z',
handleSize: '110%',
handleStyle: {
color: '#d3dee5'
},
textStyle: {
color: '#fff' },
borderColor: '#90979c'
}, {
type: 'inside',
show: true,
height: 15,
start: 1,
end: 35
}],
series: [{
name: 'female',
type: 'bar',
stack: 'total',
barMaxWidth: 35,
barGap: '10%',
itemStyle: {
normal: {
color: 'rgba(255,144,128,1)',
label: {
show: true,
textStyle: {
color: '#fff'
},
position: 'insideTop',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
709,
1917,
2455,
2610,
1719,
1433,
1544,
3285,
5208,
3372,
2484,
4078
]
},
{
name: 'male',
type: 'bar',
stack: 'total',
itemStyle: {
normal: {
color: 'rgba(0,191,183,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
327,
1776,
507,
1200,
800,
482,
204,
1390,
1001,
951,
381,
220
]
}, {
name: 'average',
type: 'line',
stack: 'total',
symbolSize: 10,
symbol: 'circle',
itemStyle: {
normal: {
color: 'rgba(252,230,48,1)',
barBorderRadius: 0,
label: {
show: true,
position: 'top',
formatter(p) {
return p.value > 0 ? p.value : ''
}
}
}
},
data: [
1036,
3693,
2962,
3810,
2519,
1915,
1748,
4675,
6209,
4323,
2865,
4298
]
}
]
})
}
}
}
</script>

56
scheduler/vue-element-admin-master/src/components/Charts/mixins/resize.js

@ -0,0 +1,56 @@
import { debounce } from '@/utils'
export default {
data() {
return {
$_sidebarElm: null,
$_resizeHandler: null
}
},
mounted() {
this.initListener()
},
activated() {
if (!this.$_resizeHandler) {
// avoid duplication init
this.initListener()
}
// when keep-alive chart activated, auto resize
this.resize()
},
beforeDestroy() {
this.destroyListener()
},
deactivated() {
this.destroyListener()
},
methods: {
// use $_ for mixins properties
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
$_sidebarResizeHandler(e) {
if (e.propertyName === 'width') {
this.$_resizeHandler()
}
},
initListener() {
this.$_resizeHandler = debounce(() => {
this.resize()
}, 100)
window.addEventListener('resize', this.$_resizeHandler)
this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
},
destroyListener() {
window.removeEventListener('resize', this.$_resizeHandler)
this.$_resizeHandler = null
this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
},
resize() {
const { chart } = this
chart && chart.resize()
}
}
}

166
scheduler/vue-element-admin-master/src/components/DndList/index.vue

@ -0,0 +1,166 @@
<template>
<div class="dndList">
<div :style="{width:width1}" class="dndList-list">
<h3>{{ list1Title }}</h3>
<draggable :set-data="setData" :list="list1" group="article" class="dragArea">
<div v-for="element in list1" :key="element.id" class="list-complete-item">
<div class="list-complete-item-handle">
{{ element.id }}[{{ element.author }}] {{ element.title }}
</div>
<div style="position:absolute;right:0px;">
<span style="float: right ;margin-top: -20px;margin-right:5px;" @click="deleteEle(element)">
<i style="color:#ff4949" class="el-icon-delete" />
</span>
</div>
</div>
</draggable>
</div>
<div :style="{width:width2}" class="dndList-list">
<h3>{{ list2Title }}</h3>
<draggable :list="list2" group="article" class="dragArea">
<div v-for="element in list2" :key="element.id" class="list-complete-item">
<div class="list-complete-item-handle2" @click="pushEle(element)">
{{ element.id }} [{{ element.author }}] {{ element.title }}
</div>
</div>
</draggable>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
name: 'DndList',
components: { draggable },
props: {
list1: {
type: Array,
default() {
return []
}
},
list2: {
type: Array,
default() {
return []
}
},
list1Title: {
type: String,
default: 'list1'
},
list2Title: {
type: String,
default: 'list2'
},
width1: {
type: String,
default: '48%'
},
width2: {
type: String,
default: '48%'
}
},
methods: {
isNotInList1(v) {
return this.list1.every(k => v.id !== k.id)
},
isNotInList2(v) {
return this.list2.every(k => v.id !== k.id)
},
deleteEle(ele) {
for (const item of this.list1) {
if (item.id === ele.id) {
const index = this.list1.indexOf(item)
this.list1.splice(index, 1)
break
}
}
if (this.isNotInList2(ele)) {
this.list2.unshift(ele)
}
},
pushEle(ele) {
for (const item of this.list2) {
if (item.id === ele.id) {
const index = this.list2.indexOf(item)
this.list2.splice(index, 1)
break
}
}
if (this.isNotInList1(ele)) {
this.list1.push(ele)
}
},
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
}
}
}
</script>
<style lang="scss" scoped>
.dndList {
background: #fff;
padding-bottom: 40px;
&:after {
content: "";
display: table;
clear: both;
}
.dndList-list {
float: left;
padding-bottom: 30px;
&:first-of-type {
margin-right: 2%;
}
.dragArea {
margin-top: 15px;
min-height: 50px;
padding-bottom: 30px;
}
}
}
.list-complete-item {
cursor: pointer;
position: relative;
font-size: 14px;
padding: 5px 12px;
margin-top: 4px;
border: 1px solid #bfcbd9;
transition: all 1s;
}
.list-complete-item-handle {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 50px;
}
.list-complete-item-handle2 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 20px;
}
.list-complete-item.sortable-chosen {
background: #4AB7BD;
}
.list-complete-item.sortable-ghost {
background: #30B08F;
}
.list-complete-enter,
.list-complete-leave-active {
opacity: 0;
}
</style>

65
scheduler/vue-element-admin-master/src/components/DragSelect/index.vue

@ -0,0 +1,65 @@
<template>
<el-select ref="dragSelect" v-model="selectVal" v-bind="$attrs" class="drag-select" multiple v-on="$listeners">
<slot />
</el-select>
</template>
<script>
import Sortable from 'sortablejs'
export default {
name: 'DragSelect',
props: {
value: {
type: Array,
required: true
}
},
computed: {
selectVal: {
get() {
return [...this.value]
},
set(val) {
this.$emit('input', [...val])
}
}
},
mounted() {
this.setSort()
},
methods: {
setSort() {
const el = this.$refs.dragSelect.$el.querySelectorAll('.el-select__tags > span')[0]
this.sortable = Sortable.create(el, {
ghostClass: 'sortable-ghost', // Class name for the drop placeholder,
setData: function(dataTransfer) {
dataTransfer.setData('Text', '')
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
},
onEnd: evt => {
const targetRow = this.value.splice(evt.oldIndex, 1)[0]
this.value.splice(evt.newIndex, 0, targetRow)
}
})
}
}
}
</script>
<style lang="scss" scoped>
.drag-select {
::v-deep {
.sortable-ghost {
opacity: .8;
color: #fff !important;
background: #42b983 !important;
}
.el-tag {
cursor: pointer;
}
}
}
</style>

297
scheduler/vue-element-admin-master/src/components/Dropzone/index.vue

@ -0,0 +1,297 @@
<template>
<div :id="id" :ref="id" :action="url" class="dropzone">
<input type="file" name="file">
</div>
</template>
<script>
import Dropzone from 'dropzone'
import 'dropzone/dist/dropzone.css'
// import { getToken } from 'api/qiniu';
Dropzone.autoDiscover = false
export default {
props: {
id: {
type: String,
required: true
},
url: {
type: String,
required: true
},
clickable: {
type: Boolean,
default: true
},
defaultMsg: {
type: String,
default: '上传图片'
},
acceptedFiles: {
type: String,
default: ''
},
thumbnailHeight: {
type: Number,
default: 200
},
thumbnailWidth: {
type: Number,
default: 200
},
showRemoveLink: {
type: Boolean,
default: true
},
maxFilesize: {
type: Number,
default: 2
},
maxFiles: {
type: Number,
default: 3
},
autoProcessQueue: {
type: Boolean,
default: true
},
useCustomDropzoneOptions: {
type: Boolean,
default: false
},
defaultImg: {
default: '',
type: [String, Array]
},
couldPaste: {
type: Boolean,
default: false
}
},
data() {
return {
dropzone: '',
initOnce: true
}
},
watch: {
defaultImg(val) {
if (val.length === 0) {
this.initOnce = false
return
}
if (!this.initOnce) return
this.initImages(val)
this.initOnce = false
}
},
mounted() {
const element = document.getElementById(this.id)
const vm = this
this.dropzone = new Dropzone(element, {
clickable: this.clickable,
thumbnailWidth: this.thumbnailWidth,
thumbnailHeight: this.thumbnailHeight,
maxFiles: this.maxFiles,
maxFilesize: this.maxFilesize,
dictRemoveFile: 'Remove',
addRemoveLinks: this.showRemoveLink,
acceptedFiles: this.acceptedFiles,
autoProcessQueue: this.autoProcessQueue,
dictDefaultMessage: '<i style="margin-top: 3em;display: inline-block" class="material-icons">' + this.defaultMsg + '</i><br>Drop files here to upload',
dictMaxFilesExceeded: '只能一个图',
previewTemplate: '<div class="dz-preview dz-file-preview"> <div class="dz-image" style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" ><img style="width:' + this.thumbnailWidth + 'px;height:' + this.thumbnailHeight + 'px" data-dz-thumbnail /></div> <div class="dz-details"><div class="dz-size"><span data-dz-size></span></div> <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div> <div class="dz-error-message"><span data-dz-errormessage></span></div> <div class="dz-success-mark"> <i class="material-icons">done</i> </div> <div class="dz-error-mark"><i class="material-icons">error</i></div></div>',
init() {
const val = vm.defaultImg
if (!val) return
if (Array.isArray(val)) {
if (val.length === 0) return
val.map((v, i) => {
const mockFile = { name: 'name' + i, size: 12345, url: v }
this.options.addedfile.call(this, mockFile)
this.options.thumbnail.call(this, mockFile, v)
mockFile.previewElement.classList.add('dz-success')
mockFile.previewElement.classList.add('dz-complete')
vm.initOnce = false
return true
})
} else {
const mockFile = { name: 'name', size: 12345, url: val }
this.options.addedfile.call(this, mockFile)
this.options.thumbnail.call(this, mockFile, val)
mockFile.previewElement.classList.add('dz-success')
mockFile.previewElement.classList.add('dz-complete')
vm.initOnce = false
}
},
accept: (file, done) => {
/* 七牛*/
// const token = this.$store.getters.token;
// getToken(token).then(response => {
// file.token = response.data.qiniu_token;
// file.key = response.data.qiniu_key;
// file.url = response.data.qiniu_url;
// done();
// })
done()
},
sending: (file, xhr, formData) => {
// formData.append('token', file.token);
// formData.append('key', file.key);
vm.initOnce = false
}
})
if (this.couldPaste) {
document.addEventListener('paste', this.pasteImg)
}
this.dropzone.on('success', file => {
vm.$emit('dropzone-success', file, vm.dropzone.element)
})
this.dropzone.on('addedfile', file => {
vm.$emit('dropzone-fileAdded', file)
})
this.dropzone.on('removedfile', file => {
vm.$emit('dropzone-removedFile', file)
})
this.dropzone.on('error', (file, error, xhr) => {
vm.$emit('dropzone-error', file, error, xhr)
})
this.dropzone.on('successmultiple', (file, error, xhr) => {
vm.$emit('dropzone-successmultiple', file, error, xhr)
})
},
destroyed() {
document.removeEventListener('paste', this.pasteImg)
this.dropzone.destroy()
},
methods: {
removeAllFiles() {
this.dropzone.removeAllFiles(true)
},
processQueue() {
this.dropzone.processQueue()
},
pasteImg(event) {
const items = (event.clipboardData || event.originalEvent.clipboardData).items
if (items[0].kind === 'file') {
this.dropzone.addFile(items[0].getAsFile())
}
},
initImages(val) {
if (!val) return
if (Array.isArray(val)) {
val.map((v, i) => {
const mockFile = { name: 'name' + i, size: 12345, url: v }
this.dropzone.options.addedfile.call(this.dropzone, mockFile)
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, v)
mockFile.previewElement.classList.add('dz-success')
mockFile.previewElement.classList.add('dz-complete')
return true
})
} else {
const mockFile = { name: 'name', size: 12345, url: val }
this.dropzone.options.addedfile.call(this.dropzone, mockFile)
this.dropzone.options.thumbnail.call(this.dropzone, mockFile, val)
mockFile.previewElement.classList.add('dz-success')
mockFile.previewElement.classList.add('dz-complete')
}
}
}
}
</script>
<style scoped>
.dropzone {
border: 2px solid #E5E5E5;
font-family: 'Roboto', sans-serif;
color: #777;
transition: background-color .2s linear;
padding: 5px;
}
.dropzone:hover {
background-color: #F6F6F6;
}
i {
color: #CCC;
}
.dropzone .dz-image img {
width: 100%;
height: 100%;
}
.dropzone input[name='file'] {
display: none;
}
.dropzone .dz-preview .dz-image {
border-radius: 0px;
}
.dropzone .dz-preview:hover .dz-image img {
transform: none;
filter: none;
width: 100%;
height: 100%;
}
.dropzone .dz-preview .dz-details {
bottom: 0px;
top: 0px;
color: white;
background-color: rgba(33, 150, 243, 0.8);
transition: opacity .2s linear;
text-align: left;
}
.dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span {
background-color: transparent;
}
.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span {
border: none;
}
.dropzone .dz-preview .dz-details .dz-filename:hover span {
background-color: transparent;
border: none;
}
.dropzone .dz-preview .dz-remove {
position: absolute;
z-index: 30;
color: white;
margin-left: 15px;
padding: 10px;
top: inherit;
bottom: 15px;
border: 2px white solid;
text-decoration: none;
text-transform: uppercase;
font-size: 0.8rem;
font-weight: 800;
letter-spacing: 1.1px;
opacity: 0;
}
.dropzone .dz-preview:hover .dz-remove {
opacity: 1;
}
.dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark {
margin-left: -40px;
margin-top: -50px;
}
.dropzone .dz-preview .dz-success-mark i, .dropzone .dz-preview .dz-error-mark i {
color: white;
font-size: 5rem;
}
</style>

78
scheduler/vue-element-admin-master/src/components/ErrorLog/index.vue

@ -0,0 +1,78 @@
<template>
<div v-if="errorLogs.length>0">
<el-badge :is-dot="true" style="line-height: 25px;margin-top: -5px;" @click.native="dialogTableVisible=true">
<el-button style="padding: 8px 10px;" size="small" type="danger">
<svg-icon icon-class="bug" />
</el-button>
</el-badge>
<el-dialog :visible.sync="dialogTableVisible" width="80%" append-to-body>
<div slot="title">
<span style="padding-right: 10px;">Error Log</span>
<el-button size="mini" type="primary" icon="el-icon-delete" @click="clearAll">Clear All</el-button>
</div>
<el-table :data="errorLogs" border>
<el-table-column label="Message">
<template slot-scope="{row}">
<div>
<span class="message-title">Msg:</span>
<el-tag type="danger">
{{ row.err.message }}
</el-tag>
</div>
<br>
<div>
<span class="message-title" style="padding-right: 10px;">Info: </span>
<el-tag type="warning">
{{ row.vm.$vnode.tag }} error in {{ row.info }}
</el-tag>
</div>
<br>
<div>
<span class="message-title" style="padding-right: 16px;">Url: </span>
<el-tag type="success">
{{ row.url }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="Stack">
<template slot-scope="scope">
{{ scope.row.err.stack }}
</template>
</el-table-column>
</el-table>
</el-dialog>
</div>
</template>
<script>
export default {
name: 'ErrorLog',
data() {
return {
dialogTableVisible: false
}
},
computed: {
errorLogs() {
return this.$store.getters.errorLogs
}
},
methods: {
clearAll() {
this.dialogTableVisible = false
this.$store.dispatch('errorLog/clearErrorLog')
}
}
}
</script>
<style scoped>
.message-title {
font-size: 16px;
color: #333;
font-weight: bold;
padding-right: 8px;
}
</style>

54
scheduler/vue-element-admin-master/src/components/GithubCorner/index.vue

@ -0,0 +1,54 @@
<template>
<a href="https://github.com/PanJiaChen/vue-element-admin" target="_blank" class="github-corner" aria-label="View source on Github">
<svg
width="80"
height="80"
viewBox="0 0 250 250"
style="fill:#40c9c6; color:#fff;"
aria-hidden="true"
>
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z" />
<path
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
fill="currentColor"
style="transform-origin: 130px 106px;"
class="octo-arm"
/>
<path
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
fill="currentColor"
class="octo-body"
/>
</svg>
</a>
</template>
<style scoped>
.github-corner:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
@keyframes octocat-wave {
0%,
100% {
transform: rotate(0)
}
20%,
60% {
transform: rotate(-25deg)
}
40%,
80% {
transform: rotate(10deg)
}
}
@media (max-width:500px) {
.github-corner:hover .octo-arm {
animation: none
}
.github-corner .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
}
</style>

44
scheduler/vue-element-admin-master/src/components/Hamburger/index.vue

@ -0,0 +1,44 @@
<template>
<div style="padding: 0 15px;" @click="toggleClick">
<svg
:class="{'is-active':isActive}"
class="hamburger"
viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg"
width="64"
height="64"
>
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
</div>
</template>
<script>
export default {
name: 'Hamburger',
props: {
isActive: {
type: Boolean,
default: false
}
},
methods: {
toggleClick() {
this.$emit('toggleClick')
}
}
}
</script>
<style scoped>
.hamburger {
display: inline-block;
vertical-align: middle;
width: 20px;
height: 20px;
}
.hamburger.is-active {
transform: rotate(180deg);
}
</style>

180
scheduler/vue-element-admin-master/src/components/HeaderSearch/index.vue

@ -0,0 +1,180 @@
<template>
<div :class="{'show':show}" class="header-search">
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
<el-select
ref="headerSearchSelect"
v-model="search"
:remote-method="querySearch"
filterable
default-first-option
remote
placeholder="Search"
class="header-search-select"
@change="change"
>
<el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
</el-select>
</div>
</template>
<script>
// fuse is a lightweight fuzzy-search module
// make search results more in line with expectations
import Fuse from 'fuse.js'
import path from 'path'
export default {
name: 'HeaderSearch',
data() {
return {
search: '',
options: [],
searchPool: [],
show: false,
fuse: undefined
}
},
computed: {
routes() {
return this.$store.getters.permission_routes
}
},
watch: {
routes() {
this.searchPool = this.generateRoutes(this.routes)
},
searchPool(list) {
this.initFuse(list)
},
show(value) {
if (value) {
document.body.addEventListener('click', this.close)
} else {
document.body.removeEventListener('click', this.close)
}
}
},
mounted() {
this.searchPool = this.generateRoutes(this.routes)
},
methods: {
click() {
this.show = !this.show
if (this.show) {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
}
},
close() {
this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
this.options = []
this.show = false
},
change(val) {
this.$router.push(val.path)
this.search = ''
this.options = []
this.$nextTick(() => {
this.show = false
})
},
initFuse(list) {
this.fuse = new Fuse(list, {
shouldSort: true,
threshold: 0.4,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [{
name: 'title',
weight: 0.7
}, {
name: 'path',
weight: 0.3
}]
})
},
// Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title
generateRoutes(routes, basePath = '/', prefixTitle = []) {
let res = []
for (const router of routes) {
// skip hidden router
if (router.hidden) { continue }
const data = {
path: path.resolve(basePath, router.path),
title: [...prefixTitle]
}
if (router.meta && router.meta.title) {
data.title = [...data.title, router.meta.title]
if (router.redirect !== 'noRedirect') {
// only push the routes with title
// special case: need to exclude parent router without redirect
res.push(data)
}
}
// recursive child routes
if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes]
}
}
}
return res
},
querySearch(query) {
if (query !== '') {
this.options = this.fuse.search(query)
} else {
this.options = []
}
}
}
}
</script>
<style lang="scss" scoped>
.header-search {
font-size: 0 !important;
.search-icon {
cursor: pointer;
font-size: 18px;
vertical-align: middle;
}
.header-search-select {
font-size: 18px;
transition: width 0.2s;
width: 0;
overflow: hidden;
background: transparent;
border-radius: 0;
display: inline-block;
vertical-align: middle;
::v-deep .el-input__inner {
border-radius: 0;
border: 0;
padding-left: 0;
padding-right: 0;
box-shadow: none !important;
border-bottom: 1px solid #d9d9d9;
vertical-align: middle;
}
}
&.show {
.header-search-select {
width: 210px;
margin-left: 10px;
}
}
}
</style>

1779
scheduler/vue-element-admin-master/src/components/ImageCropper/index.vue

File diff suppressed because it is too large

19
scheduler/vue-element-admin-master/src/components/ImageCropper/utils/data2blob.js

@ -0,0 +1,19 @@
/**
* database64文件格式转换为2进制
*
* @param {[String]} data dataURL 的格式为 data:image/png;base64,****,逗号之前都是一些说明性的文字我们只需要逗号之后的就行了
* @param {[String]} mime [description]
* @return {[blob]} [description]
*/
export default function(data, mime) {
data = data.split(',')[1]
data = window.atob(data)
var ia = new Uint8Array(data.length)
for (var i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i)
}
// canvas.toDataURL 返回的默认格式就是 image/png
return new Blob([ia], {
type: mime
})
}

39
scheduler/vue-element-admin-master/src/components/ImageCropper/utils/effectRipple.js

@ -0,0 +1,39 @@
/**
* 点击波纹效果
*
* @param {[event]} e [description]
* @param {[Object]} arg_opts [description]
* @return {[bollean]} [description]
*/
export default function(e, arg_opts) {
var opts = Object.assign({
ele: e.target, // 波纹作用元素
type: 'hit', // hit点击位置扩散center中心点扩展
bgc: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
}, arg_opts)
var target = opts.ele
if (target) {
var rect = target.getBoundingClientRect()
var ripple = target.querySelector('.e-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'e-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'e-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = (rect.height / 2 - ripple.offsetHeight / 2) + 'px'
ripple.style.left = (rect.width / 2 - ripple.offsetWidth / 2) + 'px'
break
default:
ripple.style.top = (e.pageY - rect.top - ripple.offsetHeight / 2 - document.body.scrollTop) + 'px'
ripple.style.left = (e.pageX - rect.left - ripple.offsetWidth / 2 - document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.bgc
ripple.className = 'e-ripple z-active'
return false
}
}

232
scheduler/vue-element-admin-master/src/components/ImageCropper/utils/language.js

@ -0,0 +1,232 @@
export default {
zh: {
hint: '点击,或拖动图片至此处',
loading: '正在上传……',
noSupported: '浏览器不支持该功能,请使用IE10以上或其他现在浏览器!',
success: '上传成功',
fail: '图片上传失败',
preview: '头像预览',
btn: {
off: '取消',
close: '关闭',
back: '上一步',
save: '保存'
},
error: {
onlyImg: '仅限图片格式',
outOfSize: '单文件大小不能超过 ',
lowestPx: '图片最低像素为(宽*高):'
}
},
'zh-tw': {
hint: '點擊,或拖動圖片至此處',
loading: '正在上傳……',
noSupported: '瀏覽器不支持該功能,請使用IE10以上或其他現代瀏覽器!',
success: '上傳成功',
fail: '圖片上傳失敗',
preview: '頭像預覽',
btn: {
off: '取消',
close: '關閉',
back: '上一步',
save: '保存'
},
error: {
onlyImg: '僅限圖片格式',
outOfSize: '單文件大小不能超過 ',
lowestPx: '圖片最低像素為(寬*高):'
}
},
en: {
hint: 'Click or drag the file here to upload',
loading: 'Uploading…',
noSupported: 'Browser is not supported, please use IE10+ or other browsers',
success: 'Upload success',
fail: 'Upload failed',
preview: 'Preview',
btn: {
off: 'Cancel',
close: 'Close',
back: 'Back',
save: 'Save'
},
error: {
onlyImg: 'Image only',
outOfSize: 'Image exceeds size limit: ',
lowestPx: 'Image\'s size is too low. Expected at least: '
}
},
ro: {
hint: 'Atinge sau trage fișierul aici',
loading: 'Se încarcă',
noSupported: 'Browser-ul tău nu suportă acest feature. Te rugăm încearcă cu alt browser.',
success: 'S-a încărcat cu succes',
fail: 'A apărut o problemă la încărcare',
preview: 'Previzualizează',
btn: {
off: 'Anulează',
close: 'Închide',
back: 'Înapoi',
save: 'Salvează'
},
error: {
onlyImg: 'Doar imagini',
outOfSize: 'Imaginea depășește limita de: ',
loewstPx: 'Imaginea este prea mică; Minim: '
}
},
ru: {
hint: 'Нажмите, или перетащите файл в это окно',
loading: 'Загружаю……',
noSupported: 'Ваш браузер не поддерживается, пожалуйста, используйте IE10 + или другие браузеры',
success: 'Загрузка выполнена успешно',
fail: 'Ошибка загрузки',
preview: 'Предпросмотр',
btn: {
off: 'Отменить',
close: 'Закрыть',
back: 'Назад',
save: 'Сохранить'
},
error: {
onlyImg: 'Только изображения',
outOfSize: 'Изображение превышает предельный размер: ',
lowestPx: 'Минимальный размер изображения: '
}
},
'pt-br': {
hint: 'Clique ou arraste o arquivo aqui para carregar',
loading: 'Carregando…',
noSupported: 'Browser não suportado, use o IE10+ ou outro browser',
success: 'Sucesso ao carregar imagem',
fail: 'Falha ao carregar imagem',
preview: 'Pré-visualizar',
btn: {
off: 'Cancelar',
close: 'Fechar',
back: 'Voltar',
save: 'Salvar'
},
error: {
onlyImg: 'Apenas imagens',
outOfSize: 'A imagem excede o limite de tamanho: ',
lowestPx: 'O tamanho da imagem é muito pequeno. Tamanho mínimo: '
}
},
fr: {
hint: 'Cliquez ou glissez le fichier ici.',
loading: 'Téléchargement…',
noSupported: 'Votre navigateur n\'est pas supporté. Utilisez IE10 + ou un autre navigateur s\'il vous plaît.',
success: 'Téléchargement réussit',
fail: 'Téléchargement echoué',
preview: 'Aperçu',
btn: {
off: 'Annuler',
close: 'Fermer',
back: 'Retour',
save: 'Enregistrer'
},
error: {
onlyImg: 'Image uniquement',
outOfSize: 'L\'image sélectionnée dépasse la taille maximum: ',
lowestPx: 'L\'image sélectionnée est trop petite. Dimensions attendues: '
}
},
nl: {
hint: 'Klik hier of sleep een afbeelding in dit vlak',
loading: 'Uploaden…',
noSupported: 'Je browser wordt helaas niet ondersteund. Gebruik IE10+ of een andere browser.',
success: 'Upload succesvol',
fail: 'Upload mislukt',
preview: 'Voorbeeld',
btn: {
off: 'Annuleren',
close: 'Sluiten',
back: 'Terug',
save: 'Opslaan'
},
error: {
onlyImg: 'Alleen afbeeldingen',
outOfSize: 'De afbeelding is groter dan: ',
lowestPx: 'De afbeelding is te klein! Minimale afmetingen: '
}
},
tr: {
hint: 'Tıkla veya yüklemek istediğini buraya sürükle',
loading: 'Yükleniyor…',
noSupported: 'Tarayıcı desteklenmiyor, lütfen IE10+ veya farklı tarayıcı kullanın',
success: 'Yükleme başarılı',
fail: 'Yüklemede hata oluştu',
preview: 'Önizle',
btn: {
off: 'İptal',
close: 'Kapat',
back: 'Geri',
save: 'Kaydet'
},
error: {
onlyImg: 'Sadece resim',
outOfSize: 'Resim yükleme limitini aşıyor: ',
lowestPx: 'Resmin boyutu çok küçük. En az olması gereken: '
}
},
'es-MX': {
hint: 'Selecciona o arrastra una imagen',
loading: 'Subiendo...',
noSupported: 'Tu navegador no es soportado, porfavor usa IE10+ u otros navegadores mas recientes',
success: 'Subido exitosamente',
fail: 'Sucedió un error',
preview: 'Vista previa',
btn: {
off: 'Cancelar',
close: 'Cerrar',
back: 'Atras',
save: 'Guardar'
},
error: {
onlyImg: 'Unicamente imagenes',
outOfSize: 'La imagen excede el tamaño maximo:',
lowestPx: 'La imagen es demasiado pequeño. Se espera por lo menos:'
}
},
de: {
hint: 'Klick hier oder zieh eine Datei hier rein zum Hochladen',
loading: 'Hochladen…',
noSupported: 'Browser wird nicht unterstützt, bitte verwende IE10+ oder andere Browser',
success: 'Upload erfolgreich',
fail: 'Upload fehlgeschlagen',
preview: 'Vorschau',
btn: {
off: 'Abbrechen',
close: 'Schließen',
back: 'Zurück',
save: 'Speichern'
},
error: {
onlyImg: 'Nur Bilder',
outOfSize: 'Das Bild ist zu groß: ',
lowestPx: 'Das Bild ist zu klein. Mindestens: '
}
},
ja: {
hint: 'クリック・ドラッグしてファイルをアップロード',
loading: 'アップロード中...',
noSupported: 'このブラウザは対応されていません。IE10+かその他の主要ブラウザをお使いください。',
success: 'アップロード成功',
fail: 'アップロード失敗',
preview: 'プレビュー',
btn: {
off: 'キャンセル',
close: '閉じる',
back: '戻る',
save: '保存'
},
error: {
onlyImg: '画像のみ',
outOfSize: '画像サイズが上限を超えています。上限: ',
lowestPx: '画像が小さすぎます。最小サイズ: '
}
}
}

7
scheduler/vue-element-admin-master/src/components/ImageCropper/utils/mimes.js

@ -0,0 +1,7 @@
export default {
'jpg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'svg': 'image/svg+xml',
'psd': 'image/photoshop'
}

77
scheduler/vue-element-admin-master/src/components/JsonEditor/index.vue

@ -0,0 +1,77 @@
<template>
<div class="json-editor">
<textarea ref="textarea" />
</div>
</template>
<script>
import CodeMirror from 'codemirror'
import 'codemirror/addon/lint/lint.css'
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/rubyblue.css'
require('script-loader!jsonlint')
import 'codemirror/mode/javascript/javascript'
import 'codemirror/addon/lint/lint'
import 'codemirror/addon/lint/json-lint'
export default {
name: 'JsonEditor',
/* eslint-disable vue/require-prop-types */
props: ['value'],
data() {
return {
jsonEditor: false
}
},
watch: {
value(value) {
const editorValue = this.jsonEditor.getValue()
if (value !== editorValue) {
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
}
}
},
mounted() {
this.jsonEditor = CodeMirror.fromTextArea(this.$refs.textarea, {
lineNumbers: true,
mode: 'application/json',
gutters: ['CodeMirror-lint-markers'],
theme: 'rubyblue',
lint: true
})
this.jsonEditor.setValue(JSON.stringify(this.value, null, 2))
this.jsonEditor.on('change', cm => {
this.$emit('changed', cm.getValue())
this.$emit('input', cm.getValue())
})
},
methods: {
getValue() {
return this.jsonEditor.getValue()
}
}
}
</script>
<style lang="scss" scoped>
.json-editor {
height: 100%;
position: relative;
::v-deep {
.CodeMirror {
height: auto;
min-height: 300px;
}
.CodeMirror-scroll {
min-height: 300px;
}
.cm-s-rubyblue span.cm-string {
color: #F08047;
}
}
}
</style>

99
scheduler/vue-element-admin-master/src/components/Kanban/index.vue

@ -0,0 +1,99 @@
<template>
<div class="board-column">
<div class="board-column-header">
{{ headerText }}
</div>
<draggable
:list="list"
v-bind="$attrs"
class="board-column-content"
:set-data="setData"
>
<div v-for="element in list" :key="element.id" class="board-item">
{{ element.name }} {{ element.id }}
</div>
</draggable>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
name: 'DragKanbanDemo',
components: {
draggable
},
props: {
headerText: {
type: String,
default: 'Header'
},
options: {
type: Object,
default() {
return {}
}
},
list: {
type: Array,
default() {
return []
}
}
},
methods: {
setData(dataTransfer) {
// to avoid Firefox bug
// Detail see : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData('Text', '')
}
}
}
</script>
<style lang="scss" scoped>
.board-column {
min-width: 300px;
min-height: 100px;
height: auto;
overflow: hidden;
background: #f0f0f0;
border-radius: 3px;
.board-column-header {
height: 50px;
line-height: 50px;
overflow: hidden;
padding: 0 20px;
text-align: center;
background: #333;
color: #fff;
border-radius: 3px 3px 0 0;
}
.board-column-content {
height: auto;
overflow: hidden;
border: 10px solid transparent;
min-height: 60px;
display: flex;
justify-content: flex-start;
flex-direction: column;
align-items: center;
.board-item {
cursor: pointer;
width: 100%;
height: 64px;
margin: 5px 0;
background-color: #fff;
text-align: left;
line-height: 54px;
padding: 5px 10px;
box-sizing: border-box;
box-shadow: 0px 1px 3px 0 rgba(0, 0, 0, 0.2);
}
}
}
</style>

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

Loading…
Cancel
Save