334 changed files with 24133 additions and 1813 deletions
@ -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());
|
|||
// }
|
|||
//}
|
@ -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;
|
|||
// }
|
|||
//}
|
@ -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);
|
|||
// }
|
|||
//}
|
|||
|
@ -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;
|
|||
// }
|
|||
//}
|
@ -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 |
|||
* 分别对应配置原生的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; |
|||
} |
|||
} |
|||
//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;
|
|||
// }
|
|||
//}
|
|||
|
@ -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;
|
|||
// }
|
|||
//}
|
|||
|
@ -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;
|
|||
// }
|
|||
//
|
|||
//
|
|||
//}
|
|||
|
@ -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;
|
|||
// }
|
|||
//}
|
|||
|
File diff suppressed because it is too large
@ -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;
|
|||
// }
|
|||
//
|
|||
//
|
|||
//}
|
|||
|
@ -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); |
|||
} |
|||
} |
@ -1,4 +0,0 @@ |
|||
host = smtp.ccsens.com |
|||
port = 25 |
|||
from = admin@ccsens.com |
|||
pass = q1w2e3 |
@ -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 |
@ -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 |
@ -0,0 +1,5 @@ |
|||
# just a flag |
|||
ENV = 'development' |
|||
|
|||
# base api |
|||
VUE_APP_BASE_API = '/dev-api' |
@ -0,0 +1,6 @@ |
|||
# just a flag |
|||
ENV = 'production' |
|||
|
|||
# base api |
|||
VUE_APP_BASE_API = '/prod-api' |
|||
|
@ -0,0 +1,8 @@ |
|||
NODE_ENV = production |
|||
|
|||
# just a flag |
|||
ENV = 'staging' |
|||
|
|||
# base api |
|||
VUE_APP_BASE_API = '/stage-api' |
|||
|
@ -0,0 +1,4 @@ |
|||
build/*.js |
|||
src/assets |
|||
public |
|||
dist |
@ -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'] |
|||
} |
|||
} |
@ -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 |
@ -0,0 +1,5 @@ |
|||
language: node_js |
|||
node_js: 10 |
|||
script: npm run test |
|||
notifications: |
|||
email: false |
@ -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. |
@ -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. |
|||
|
|||
[](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: |
|||
|
|||
 |
|||
|
|||
[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 |
@ -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は大歓迎です。** |
|||
|
|||
[](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: |
|||
|
|||
 |
|||
|
|||
[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 |
@ -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. |
|||
|
|||
[](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: |
|||
|
|||
 |
|||
|
|||
[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 |
@ -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** |
|||
|
|||
[](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: |
|||
 |
|||
|
|||
[更多捐赠方式](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 |
@ -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'] |
|||
} |
|||
} |
|||
} |
@ -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}`) |
|||
} |
@ -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/' |
|||
} |
@ -0,0 +1,9 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"baseUrl": "./", |
|||
"paths": { |
|||
"@/*": ["src/*"] |
|||
} |
|||
}, |
|||
"exclude": ["node_modules", "dist"] |
|||
} |
@ -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' |
|||
} |
|||
} |
|||
} |
|||
] |
|||
|
@ -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 |
|||
} |
@ -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)) |
|||
} |
|||
} |
|||
}) |
|||
} |
@ -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'] |
|||
}] |
|||
} |
|||
} |
|||
} |
|||
} |
|||
] |
@ -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' |
|||
} |
|||
} |
|||
} |
|||
] |
@ -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 |
|||
} |
@ -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' |
|||
} |
|||
} |
|||
} |
|||
] |
@ -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 |
|||
} |
@ -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" |
|||
} |
|||
} |
@ -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}} |
@ -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 |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
{{#if state}} |
|||
const state = {} |
|||
{{/if}} |
|||
|
|||
{{#if mutations}} |
|||
const mutations = {} |
|||
{{/if}} |
|||
|
|||
{{#if actions}} |
|||
const actions = {} |
|||
{{/if}} |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
{{options}} |
|||
} |
@ -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 |
|||
} |
|||
} |
@ -0,0 +1,2 @@ |
|||
exports.notEmpty = name => v => |
|||
!v || v.trim() === '' ? `${name} is required` : true |
@ -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}} |
@ -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 |
|||
} |
|||
} |
@ -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) |
|||
} |
@ -0,0 +1,5 @@ |
|||
module.exports = { |
|||
plugins: { |
|||
autoprefixer: {} |
|||
} |
|||
} |
After Width: | Height: | Size: 66 KiB |
@ -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> |
@ -0,0 +1,11 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<router-view /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'App' |
|||
} |
|||
</script> |
@ -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 |
|||
}) |
|||
} |
@ -0,0 +1,8 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
export function getToken() { |
|||
return request({ |
|||
url: '/qiniu/upload/token', // 假地址 自行替换
|
|||
method: 'get' |
|||
}) |
|||
} |
@ -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 |
|||
}) |
|||
} |
@ -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' |
|||
}) |
|||
} |
@ -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' |
|||
}) |
|||
} |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 4.7 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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() |
|||
} |
|||
} |
|||
} |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
File diff suppressed because it is too large
@ -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 |
|||
}) |
|||
} |
@ -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 |
|||
} |
|||
} |
@ -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: '画像が小さすぎます。最小サイズ: ' |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
export default { |
|||
'jpg': 'image/jpeg', |
|||
'png': 'image/png', |
|||
'gif': 'image/gif', |
|||
'svg': 'image/svg+xml', |
|||
'psd': 'image/photoshop' |
|||
} |
@ -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> |
@ -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…
Reference in new issue