Conflicts:
	backend/pom.xml
This commit is contained in:
shiziyuan9527 2020-06-22 18:26:02 +08:00
commit 8bcf1ebc4c
44 changed files with 5150 additions and 4 deletions

View File

@ -60,6 +60,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@ -75,6 +76,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- flyway -->
<dependency>
<groupId>org.flywaydb</groupId>
@ -153,6 +155,12 @@
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<!-- LDAP Module -->
<dependency>
<groupId>org.springframework.boot</groupId>

View File

@ -50,6 +50,11 @@ public class APITestController {
return apiTestService.getApiTestByProjectId(projectId);
}
@PostMapping(value = "/schedule/update")
public void updateSchedule(@RequestBody SaveAPITestRequest request) {
apiTestService.updateSchedule(request);
}
@PostMapping(value = "/create", consumes = {"multipart/form-data"})
public void create(@RequestPart("request") SaveAPITestRequest request, @RequestPart(value = "files") List<MultipartFile> files) {
apiTestService.create(request, files);

View File

@ -1,6 +1,7 @@
package io.metersphere.api.dto;
import io.metersphere.api.dto.scenario.Scenario;
import io.metersphere.dto.ScheduleDTO;
import lombok.Getter;
import lombok.Setter;
@ -17,4 +18,6 @@ public class SaveAPITestRequest {
private String name;
private List<Scenario> scenarioDefinition;
private ScheduleDTO schedule;
}

View File

@ -207,4 +207,14 @@ public class APITestService {
}
}
public void updateSchedule(SaveAPITestRequest request) {
// todo 开启调度线程
ApiTestWithBLOBs apiTest = new ApiTestWithBLOBs();
apiTest.setId(request.getId());
apiTest.setSchedule(JSONObject.toJSONString(request.getSchedule()));
apiTest.setUpdateTime(System.currentTimeMillis());
apiTestMapper.updateByPrimaryKeySelective(apiTest);
}
}

View File

@ -0,0 +1,22 @@
package io.metersphere.base.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class UserKey implements Serializable {
private String id;
private String userId;
private String accessKey;
private String secretKey;
private Long createTime;
private String status;
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,610 @@
package io.metersphere.base.domain;
import java.util.ArrayList;
import java.util.List;
public class UserKeyExample {
protected String orderByClause;
protected boolean distinct;
protected List<Criteria> oredCriteria;
public UserKeyExample() {
oredCriteria = new ArrayList<Criteria>();
}
public void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}
public String getOrderByClause() {
return orderByClause;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public boolean isDistinct() {
return distinct;
}
public List<Criteria> getOredCriteria() {
return oredCriteria;
}
public void or(Criteria criteria) {
oredCriteria.add(criteria);
}
public Criteria or() {
Criteria criteria = createCriteriaInternal();
oredCriteria.add(criteria);
return criteria;
}
public Criteria createCriteria() {
Criteria criteria = createCriteriaInternal();
if (oredCriteria.size() == 0) {
oredCriteria.add(criteria);
}
return criteria;
}
protected Criteria createCriteriaInternal() {
Criteria criteria = new Criteria();
return criteria;
}
public void clear() {
oredCriteria.clear();
orderByClause = null;
distinct = false;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected GeneratedCriteria() {
super();
criteria = new ArrayList<Criterion>();
}
public boolean isValid() {
return criteria.size() > 0;
}
public List<Criterion> getAllCriteria() {
return criteria;
}
public List<Criterion> getCriteria() {
return criteria;
}
protected void addCriterion(String condition) {
if (condition == null) {
throw new RuntimeException("Value for condition cannot be null");
}
criteria.add(new Criterion(condition));
}
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
protected void addCriterion(String condition, Object value1, Object value2, String property) {
if (value1 == null || value2 == null) {
throw new RuntimeException("Between values for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value1, value2));
}
public Criteria andIdIsNull() {
addCriterion("id is null");
return (Criteria) this;
}
public Criteria andIdIsNotNull() {
addCriterion("id is not null");
return (Criteria) this;
}
public Criteria andIdEqualTo(String value) {
addCriterion("id =", value, "id");
return (Criteria) this;
}
public Criteria andIdNotEqualTo(String value) {
addCriterion("id <>", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThan(String value) {
addCriterion("id >", value, "id");
return (Criteria) this;
}
public Criteria andIdGreaterThanOrEqualTo(String value) {
addCriterion("id >=", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThan(String value) {
addCriterion("id <", value, "id");
return (Criteria) this;
}
public Criteria andIdLessThanOrEqualTo(String value) {
addCriterion("id <=", value, "id");
return (Criteria) this;
}
public Criteria andIdLike(String value) {
addCriterion("id like", value, "id");
return (Criteria) this;
}
public Criteria andIdNotLike(String value) {
addCriterion("id not like", value, "id");
return (Criteria) this;
}
public Criteria andIdIn(List<String> values) {
addCriterion("id in", values, "id");
return (Criteria) this;
}
public Criteria andIdNotIn(List<String> values) {
addCriterion("id not in", values, "id");
return (Criteria) this;
}
public Criteria andIdBetween(String value1, String value2) {
addCriterion("id between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andIdNotBetween(String value1, String value2) {
addCriterion("id not between", value1, value2, "id");
return (Criteria) this;
}
public Criteria andUserIdIsNull() {
addCriterion("user_id is null");
return (Criteria) this;
}
public Criteria andUserIdIsNotNull() {
addCriterion("user_id is not null");
return (Criteria) this;
}
public Criteria andUserIdEqualTo(String value) {
addCriterion("user_id =", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotEqualTo(String value) {
addCriterion("user_id <>", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThan(String value) {
addCriterion("user_id >", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdGreaterThanOrEqualTo(String value) {
addCriterion("user_id >=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThan(String value) {
addCriterion("user_id <", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLessThanOrEqualTo(String value) {
addCriterion("user_id <=", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdLike(String value) {
addCriterion("user_id like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotLike(String value) {
addCriterion("user_id not like", value, "userId");
return (Criteria) this;
}
public Criteria andUserIdIn(List<String> values) {
addCriterion("user_id in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotIn(List<String> values) {
addCriterion("user_id not in", values, "userId");
return (Criteria) this;
}
public Criteria andUserIdBetween(String value1, String value2) {
addCriterion("user_id between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andUserIdNotBetween(String value1, String value2) {
addCriterion("user_id not between", value1, value2, "userId");
return (Criteria) this;
}
public Criteria andAccessKeyIsNull() {
addCriterion("access_key is null");
return (Criteria) this;
}
public Criteria andAccessKeyIsNotNull() {
addCriterion("access_key is not null");
return (Criteria) this;
}
public Criteria andAccessKeyEqualTo(String value) {
addCriterion("access_key =", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyNotEqualTo(String value) {
addCriterion("access_key <>", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyGreaterThan(String value) {
addCriterion("access_key >", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyGreaterThanOrEqualTo(String value) {
addCriterion("access_key >=", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyLessThan(String value) {
addCriterion("access_key <", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyLessThanOrEqualTo(String value) {
addCriterion("access_key <=", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyLike(String value) {
addCriterion("access_key like", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyNotLike(String value) {
addCriterion("access_key not like", value, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyIn(List<String> values) {
addCriterion("access_key in", values, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyNotIn(List<String> values) {
addCriterion("access_key not in", values, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyBetween(String value1, String value2) {
addCriterion("access_key between", value1, value2, "accessKey");
return (Criteria) this;
}
public Criteria andAccessKeyNotBetween(String value1, String value2) {
addCriterion("access_key not between", value1, value2, "accessKey");
return (Criteria) this;
}
public Criteria andSecretKeyIsNull() {
addCriterion("secret_key is null");
return (Criteria) this;
}
public Criteria andSecretKeyIsNotNull() {
addCriterion("secret_key is not null");
return (Criteria) this;
}
public Criteria andSecretKeyEqualTo(String value) {
addCriterion("secret_key =", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyNotEqualTo(String value) {
addCriterion("secret_key <>", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyGreaterThan(String value) {
addCriterion("secret_key >", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyGreaterThanOrEqualTo(String value) {
addCriterion("secret_key >=", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyLessThan(String value) {
addCriterion("secret_key <", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyLessThanOrEqualTo(String value) {
addCriterion("secret_key <=", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyLike(String value) {
addCriterion("secret_key like", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyNotLike(String value) {
addCriterion("secret_key not like", value, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyIn(List<String> values) {
addCriterion("secret_key in", values, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyNotIn(List<String> values) {
addCriterion("secret_key not in", values, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyBetween(String value1, String value2) {
addCriterion("secret_key between", value1, value2, "secretKey");
return (Criteria) this;
}
public Criteria andSecretKeyNotBetween(String value1, String value2) {
addCriterion("secret_key not between", value1, value2, "secretKey");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;
}
public Criteria andCreateTimeIsNotNull() {
addCriterion("create_time is not null");
return (Criteria) this;
}
public Criteria andCreateTimeEqualTo(Long value) {
addCriterion("create_time =", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotEqualTo(Long value) {
addCriterion("create_time <>", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThan(Long value) {
addCriterion("create_time >", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeGreaterThanOrEqualTo(Long value) {
addCriterion("create_time >=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThan(Long value) {
addCriterion("create_time <", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeLessThanOrEqualTo(Long value) {
addCriterion("create_time <=", value, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeIn(List<Long> values) {
addCriterion("create_time in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotIn(List<Long> values) {
addCriterion("create_time not in", values, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeBetween(Long value1, Long value2) {
addCriterion("create_time between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andCreateTimeNotBetween(Long value1, Long value2) {
addCriterion("create_time not between", value1, value2, "createTime");
return (Criteria) this;
}
public Criteria andStatusIsNull() {
addCriterion("status is null");
return (Criteria) this;
}
public Criteria andStatusIsNotNull() {
addCriterion("status is not null");
return (Criteria) this;
}
public Criteria andStatusEqualTo(String value) {
addCriterion("status =", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotEqualTo(String value) {
addCriterion("status <>", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThan(String value) {
addCriterion("status >", value, "status");
return (Criteria) this;
}
public Criteria andStatusGreaterThanOrEqualTo(String value) {
addCriterion("status >=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThan(String value) {
addCriterion("status <", value, "status");
return (Criteria) this;
}
public Criteria andStatusLessThanOrEqualTo(String value) {
addCriterion("status <=", value, "status");
return (Criteria) this;
}
public Criteria andStatusLike(String value) {
addCriterion("status like", value, "status");
return (Criteria) this;
}
public Criteria andStatusNotLike(String value) {
addCriterion("status not like", value, "status");
return (Criteria) this;
}
public Criteria andStatusIn(List<String> values) {
addCriterion("status in", values, "status");
return (Criteria) this;
}
public Criteria andStatusNotIn(List<String> values) {
addCriterion("status not in", values, "status");
return (Criteria) this;
}
public Criteria andStatusBetween(String value1, String value2) {
addCriterion("status between", value1, value2, "status");
return (Criteria) this;
}
public Criteria andStatusNotBetween(String value1, String value2) {
addCriterion("status not between", value1, value2, "status");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {
protected Criteria() {
super();
}
}
public static class Criterion {
private String condition;
private Object value;
private Object secondValue;
private boolean noValue;
private boolean singleValue;
private boolean betweenValue;
private boolean listValue;
private String typeHandler;
public String getCondition() {
return condition;
}
public Object getValue() {
return value;
}
public Object getSecondValue() {
return secondValue;
}
public boolean isNoValue() {
return noValue;
}
public boolean isSingleValue() {
return singleValue;
}
public boolean isBetweenValue() {
return betweenValue;
}
public boolean isListValue() {
return listValue;
}
public String getTypeHandler() {
return typeHandler;
}
protected Criterion(String condition) {
super();
this.condition = condition;
this.typeHandler = null;
this.noValue = true;
}
protected Criterion(String condition, Object value, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.typeHandler = typeHandler;
if (value instanceof List<?>) {
this.listValue = true;
} else {
this.singleValue = true;
}
}
protected Criterion(String condition, Object value) {
this(condition, value, null);
}
protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
super();
this.condition = condition;
this.value = value;
this.secondValue = secondValue;
this.typeHandler = typeHandler;
this.betweenValue = true;
}
protected Criterion(String condition, Object value, Object secondValue) {
this(condition, value, secondValue, null);
}
}
}

View File

@ -0,0 +1,31 @@
package io.metersphere.base.mapper;
import io.metersphere.base.domain.UserKey;
import io.metersphere.base.domain.UserKeyExample;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface UserKeyMapper {
long countByExample(UserKeyExample example);
int deleteByExample(UserKeyExample example);
int deleteByPrimaryKey(String id);
int insert(UserKey record);
int insertSelective(UserKey record);
List<UserKey> selectByExample(UserKeyExample example);
UserKey selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") UserKey record, @Param("example") UserKeyExample example);
int updateByExample(@Param("record") UserKey record, @Param("example") UserKeyExample example);
int updateByPrimaryKeySelective(UserKey record);
int updateByPrimaryKey(UserKey record);
}

View File

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.base.mapper.UserKeyMapper">
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.UserKey">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="user_id" jdbcType="VARCHAR" property="userId" />
<result column="access_key" jdbcType="VARCHAR" property="accessKey" />
<result column="secret_key" jdbcType="VARCHAR" property="secretKey" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="status" jdbcType="VARCHAR" property="status" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
AND ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
AND ${criterion.condition} #{criterion.value} AND #{criterion.secondValue}
</when>
<when test="criterion.listValue">
AND ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Update_By_Example_Where_Clause">
<where>
<foreach collection="example.oredCriteria" item="criteria" separator="or">
<if test="criteria.valid">
<trim prefix="(" prefixOverrides="and" suffix=")">
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
AND ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
AND ${criterion.condition} #{criterion.value} AND #{criterion.secondValue}
</when>
<when test="criterion.listValue">
AND ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
</trim>
</if>
</foreach>
</where>
</sql>
<sql id="Base_Column_List">
id, user_id, access_key, secret_key, create_time, status
</sql>
<select id="selectByExample" parameterType="io.metersphere.base.domain.UserKeyExample" resultMap="BaseResultMap">
SELECT
<if test="distinct">
DISTINCT
</if>
<include refid="Base_Column_List" />
FROM user_key
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
ORDER BY ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
SELECT
<include refid="Base_Column_List" />
FROM user_key
WHERE id = #{id,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String">
DELETE FROM user_key
WHERE id = #{id,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.UserKeyExample">
DELETE FROM user_key
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.UserKey">
INSERT INTO user_key (id, user_id, access_key,
secret_key, create_time, status
)
VALUES (#{id,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{accessKey,jdbcType=VARCHAR},
#{secretKey,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{status,jdbcType=VARCHAR}
)
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.UserKey">
INSERT INTO user_key
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="userId != null">
user_id,
</if>
<if test="accessKey != null">
access_key,
</if>
<if test="secretKey != null">
secret_key,
</if>
<if test="createTime != null">
create_time,
</if>
<if test="status != null">
status,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=VARCHAR},
</if>
<if test="userId != null">
#{userId,jdbcType=VARCHAR},
</if>
<if test="accessKey != null">
#{accessKey,jdbcType=VARCHAR},
</if>
<if test="secretKey != null">
#{secretKey,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
<if test="status != null">
#{status,jdbcType=VARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.UserKeyExample" resultType="java.lang.Long">
SELECT count(*) FROM user_key
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
</select>
<update id="updateByExampleSelective" parameterType="map">
UPDATE user_key
<set>
<if test="record.id != null">
id = #{record.id,jdbcType=VARCHAR},
</if>
<if test="record.userId != null">
user_id = #{record.userId,jdbcType=VARCHAR},
</if>
<if test="record.accessKey != null">
access_key = #{record.accessKey,jdbcType=VARCHAR},
</if>
<if test="record.secretKey != null">
secret_key = #{record.secretKey,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
<if test="record.status != null">
status = #{record.status,jdbcType=VARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
UPDATE user_key
SET id = #{record.id,jdbcType=VARCHAR},
user_id = #{record.userId,jdbcType=VARCHAR},
access_key = #{record.accessKey,jdbcType=VARCHAR},
secret_key = #{record.secretKey,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
status = #{record.status,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByPrimaryKeySelective" parameterType="io.metersphere.base.domain.UserKey">
UPDATE user_key
<set>
<if test="userId != null">
user_id = #{userId,jdbcType=VARCHAR},
</if>
<if test="accessKey != null">
access_key = #{accessKey,jdbcType=VARCHAR},
</if>
<if test="secretKey != null">
secret_key = #{secretKey,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
<if test="status != null">
status = #{status,jdbcType=VARCHAR},
</if>
</set>
WHERE id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.UserKey">
UPDATE user_key
SET user_id = #{userId,jdbcType=VARCHAR},
access_key = #{accessKey,jdbcType=VARCHAR},
secret_key = #{secretKey,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
status = #{status,jdbcType=VARCHAR}
WHERE id = #{id,jdbcType=VARCHAR}
</update>
</mapper>

View File

@ -0,0 +1,5 @@
package io.metersphere.commons.constants;
public enum ApiKeyConstants {
ACTIVE, DISABLED
}

View File

@ -1,5 +1,6 @@
package io.metersphere.config;
import io.metersphere.security.ApiKeyFilter;
import io.metersphere.security.LoginFilter;
import io.metersphere.security.ShiroDBRealm;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
@ -37,6 +38,7 @@ public class ShiroConfig {
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setSuccessUrl("/");
shiroFilterFactoryBean.getFilters().put("apikey", new ApiKeyFilter());
Map<String, String> filterChainDefinitionMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
filterChainDefinitionMap.put("/resource/**", "anon");
@ -51,7 +53,7 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/api/**", "anon");
filterChainDefinitionMap.put("/403", "anon");
filterChainDefinitionMap.put("/anonymous/**", "anon");
filterChainDefinitionMap.put("/**", "authc");
filterChainDefinitionMap.put("/**", "apikey, authc");
return shiroFilterFactoryBean;
}

View File

@ -0,0 +1,47 @@
package io.metersphere.controller;
import io.metersphere.base.domain.UserKey;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.service.UserKeyService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("user/key")
public class UserKeysController {
@Resource
private UserKeyService userKeyService;
@GetMapping("info")
public List<UserKey> getUserKeysInfo() {
String userId = SessionUtils.getUser().getId();
return userKeyService.getUserKeysInfo(userId);
}
@GetMapping("generate")
public void generateUserKey() {
String userId = SessionUtils.getUser().getId();
userKeyService.generateUserKey(userId);
}
@GetMapping("delete/{id}")
public void deleteUserKey(@PathVariable String id) {
userKeyService.deleteUserKey(id);
}
@GetMapping("active/{id}")
public void activeUserKey(@PathVariable String id) {
userKeyService.activeUserKey(id);
}
@GetMapping("disable/{id}")
public void disabledUserKey(@PathVariable String id) {
userKeyService.disableUserKey(id);
}
}

View File

@ -0,0 +1,11 @@
package io.metersphere.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ScheduleDTO {
private Boolean enable;
private String cronExpression;
}

View File

@ -0,0 +1,21 @@
package io.metersphere.schedule.job;
import io.metersphere.api.service.APITestService;
import io.metersphere.commons.utils.CommonBeanFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class ApiTestJob implements Job {
private APITestService apiTestService;
public ApiTestJob() {
apiTestService = (APITestService) CommonBeanFactory.getBean("apiTestService");
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
}
}

View File

@ -0,0 +1,46 @@
package io.metersphere.security;
import io.metersphere.commons.utils.LogUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.filter.authc.AnonymousFilter;
import org.apache.shiro.web.util.WebUtils;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class ApiKeyFilter extends AnonymousFilter {
@Override
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) {
try {
if (!SecurityUtils.getSubject().isAuthenticated()) {
String userId = ApiKeyHandler.getUser(WebUtils.toHttp(request));
if (StringUtils.isNotBlank(userId)) {
if (LogUtil.getLogger().isDebugEnabled()) {
LogUtil.getLogger().debug("user auth: " + userId);
}
SecurityUtils.getSubject().login(new UsernamePasswordToken(userId, ApiKeySessionHandler.random));
}
} else {
if (ApiKeyHandler.isApiKeyCall(WebUtils.toHttp(request))) {
String userId = ApiKeyHandler.getUser(WebUtils.toHttp(request));
SecurityUtils.getSubject().login(new UsernamePasswordToken(userId, ApiKeySessionHandler.random));
}
}
if (!SecurityUtils.getSubject().isAuthenticated()) {
((HttpServletResponse) response).setHeader("Authentication-Status", "invalid");
}
} catch (Exception e) {
if (ApiKeyHandler.isApiKeyCall(WebUtils.toHttp(request))) {
throw e;
}
LogUtil.getLogger().error("failed to handle single sign on..", e);
}
return true;
}
}

View File

@ -0,0 +1,64 @@
package io.metersphere.security;
import io.metersphere.base.domain.UserKey;
import io.metersphere.commons.utils.CodingUtil;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.service.UserKeyService;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
public class ApiKeyHandler {
public static final String API_ACCESS_KEY = "accessKey";
public static final String API_SIGNATURE = "signature";
public static String getUser(HttpServletRequest request) {
if (request == null) {
return null;
}
return getUser(request.getHeader(API_ACCESS_KEY), request.getHeader(API_SIGNATURE));
}
public static Boolean isApiKeyCall(HttpServletRequest request) {
if (request == null) {
return false;
}
return !StringUtils.isBlank(request.getHeader(API_ACCESS_KEY)) && !StringUtils.isBlank(request.getHeader(API_SIGNATURE));
}
public static String getUser(String accessKey, String signature) {
if (StringUtils.isBlank(accessKey) || StringUtils.isBlank(signature)) {
return null;
}
UserKey userKey = CommonBeanFactory.getBean(UserKeyService.class).getUserKey(accessKey);
if (userKey == null) {
throw new RuntimeException("invalid accessKey");
}
String signatureDecrypt;
try {
signatureDecrypt = CodingUtil.aesDecrypt(signature, userKey.getSecretKey(), accessKey);
} catch (Throwable t) {
throw new RuntimeException("invalid signature");
}
String[] signatureArray = StringUtils.split(StringUtils.trimToNull(signatureDecrypt), "|");
if (signatureArray.length < 2) {
throw new RuntimeException("invalid signature");
}
if (!StringUtils.equals(accessKey, signatureArray[0])) {
throw new RuntimeException("invalid signature");
}
long signatureTime;
try {
signatureTime = Long.parseLong(signatureArray[signatureArray.length - 1]);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (Math.abs(System.currentTimeMillis() - signatureTime) > 1800000) {
//签名30分钟超时
throw new RuntimeException("expired signature");
}
return userKey.getUserId();
}
}

View File

@ -0,0 +1,59 @@
package io.metersphere.security;
import io.metersphere.commons.utils.EncryptUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;
public class ApiKeySessionHandler {
private static Logger logger = LoggerFactory.getLogger(ApiKeySessionHandler.class);
public static String random = UUID.randomUUID().toString() + UUID.randomUUID().toString();
public static String generateId(String authInfo) {
return SessionGenerator.generateId(authInfo);
}
public static String validate(HttpServletRequest request) {
try {
String v = request.getHeader(ApiKeyHandler.API_SIGNATURE);
if (StringUtils.isNotBlank(v)) {
return SessionGenerator.fromId(v);
}
} catch (Exception e) {
logger.error("failed to validate", e);
}
return null;
}
public static class SessionGenerator {
public SessionGenerator() {
}
public static String generateId(String authInfo) {
return EncryptUtils.aesEncrypt(parse2Str(authInfo)).toString();
}
public static String fromId(String sessionId) {
String authInfoString = EncryptUtils.aesDecrypt(sessionId).toString();
return fromStr(authInfoString);
}
private static String parse2Str(String authInfo) {
return UUID.randomUUID().toString() + "|" + authInfo + "|" + System.currentTimeMillis();
}
private static String fromStr(String authInfoString) {
String[] sp = authInfoString.split("\\|");
return sp[1];
}
}
}

View File

@ -83,6 +83,12 @@ public class ShiroDBRealm extends AuthorizingRealm {
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
// apikey 校验不验证密码
if (ApiKeySessionHandler.random.equalsIgnoreCase(password)) {
SessionUser sessionUser = SessionUser.fromUser(user);
SessionUtils.putUser(sessionUser);
return new SimpleAuthenticationInfo(userId, password, getName());
}
// 密码验证
if (!userService.checkUserPassword(userId, password)) {
throw new IncorrectCredentialsException(Translator.get("password_is_incorrect"));

View File

@ -0,0 +1,83 @@
package io.metersphere.service;
import io.metersphere.base.domain.UserKey;
import io.metersphere.base.domain.UserKeyExample;
import io.metersphere.base.mapper.UserKeyMapper;
import io.metersphere.commons.constants.ApiKeyConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.i18n.Translator;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
@Service
public class UserKeyService {
@Resource
private UserKeyMapper userKeyMapper;
@Resource
private UserService userService;
public List<UserKey> getUserKeysInfo(String userId) {
UserKeyExample userKeysExample = new UserKeyExample();
userKeysExample.createCriteria().andUserIdEqualTo(userId);
userKeysExample.setOrderByClause("create_time");
return userKeyMapper.selectByExample(userKeysExample);
}
public UserKey generateUserKey(String userId) {
if (userService.getUserDTO(userId) == null) {
MSException.throwException(Translator.get("user_not_exist") + userId);
}
UserKeyExample userKeysExample = new UserKeyExample();
userKeysExample.createCriteria().andUserIdEqualTo(userId);
List<UserKey> userKeysList = userKeyMapper.selectByExample(userKeysExample);
if (!CollectionUtils.isEmpty(userKeysList) && userKeysList.size() >= 5) {
MSException.throwException(Translator.get("user_apikey_limit"));
}
UserKey userKeys = new UserKey();
userKeys.setId(UUID.randomUUID().toString());
userKeys.setUserId(userId);
userKeys.setStatus(ApiKeyConstants.ACTIVE.name());
userKeys.setAccessKey(RandomStringUtils.randomAlphanumeric(16));
userKeys.setSecretKey(RandomStringUtils.randomAlphanumeric(16));
userKeys.setCreateTime(System.currentTimeMillis());
userKeyMapper.insert(userKeys);
return userKeyMapper.selectByPrimaryKey(userKeys.getId());
}
public void deleteUserKey(String id) {
userKeyMapper.deleteByPrimaryKey(id);
}
public void activeUserKey(String id) {
UserKey userKeys = new UserKey();
userKeys.setId(id);
userKeys.setStatus(ApiKeyConstants.ACTIVE.name());
userKeyMapper.updateByPrimaryKeySelective(userKeys);
}
public void disableUserKey(String id) {
UserKey userKeys = new UserKey();
userKeys.setId(id);
userKeys.setStatus(ApiKeyConstants.DISABLED.name());
userKeyMapper.updateByPrimaryKeySelective(userKeys);
}
public UserKey getUserKey(String accessKey) {
UserKeyExample userKeyExample = new UserKeyExample();
userKeyExample.createCriteria().andAccessKeyEqualTo(accessKey).andStatusEqualTo(ApiKeyConstants.ACTIVE.name());
List<UserKey> userKeysList = userKeyMapper.selectByExample(userKeyExample);
if (!CollectionUtils.isEmpty(userKeysList)) {
return userKeysList.get(0);
}
return null;
}
}

View File

@ -0,0 +1,14 @@
CREATE TABLE `user_key` (
`id` varchar(50) NOT NULL DEFAULT '' COMMENT 'user_key ID',
`user_id` varchar(50) NOT NULL COMMENT '用户ID',
`access_key` varchar(50) NOT NULL COMMENT 'access_key',
`secret_key` varchar(50) NOT NULL COMMENT 'secret key',
`create_time` bigint(13) NOT NULL COMMENT '创建时间',
`status` varchar(10) DEFAULT NULL COMMENT '状态',
PRIMARY KEY (`id`),
UNIQUE KEY `IDX_AK` (`access_key`),
KEY `IDX_USER_ID` (`user_id`)
)
ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4;

View File

@ -27,6 +27,7 @@ user_locked=the user has been locked.
user_expires=user expires.
not_authorized=not authorized.
login_fail=Login fail
user_apikey_limit=Can have up to 5 api keys
#load test
edit_load_test_not_found=Cannot edit test, test not found=
run_load_test_not_found=Cannot run test, test not found=

View File

@ -27,6 +27,7 @@ excessive_attempts=操作频繁
user_locked=用户被锁定
user_expires=用户过期
not_authorized=未经授权
user_apikey_limit=最多能有5个Api key
#load test
edit_load_test_not_found=无法编辑测试,未找到测试:
run_load_test_not_found=无法运行测试,未找到测试:

View File

@ -27,6 +27,7 @@ user_locked=用戶被鎖定
user_expires=用戶過期
not_authorized=未經授權。
login_fail=登入失敗
user_apikey_limit=最多能有5個Api key
#load test
edit_load_test_not_found=無法編輯測試,未找到測試:
run_load_test_not_found=無法運行測試,未找到測試:

1159
backend/tree.txt Normal file

File diff suppressed because one or more lines are too long

View File

@ -48,7 +48,9 @@
"rules": {
"vue/no-unused-components": "off",
"no-console": "off",
"no-unused-vars": "off"
"no-unused-vars": "off",
"no-unused-expressions": "off",
"no-unused-labels": "off"
},
"parserOptions": {
"parser": "babel-eslint"

View File

@ -4,7 +4,7 @@
<el-card>
<el-container class="test-container" v-loading="result.loading">
<el-header>
<el-row type="flex" align="middle">
<el-row>
<el-input :disabled="isReadOnly" class="test-name" v-model="test.name" maxlength="60"
:placeholder="$t('api_test.input_name')"
show-word-limit>
@ -46,6 +46,8 @@
</el-dropdown>
<ms-api-report-dialog :test-id="id" ref="reportDialog"/>
<ms-schedule-config :schedule="test.schedule" :save="saveCronExpression" @scheduleChange="saveSchedule" :check-open="checkScheduleEdit"/>
</el-row>
</el-header>
<ms-api-scenario-config :is-read-only="isReadOnly" :scenarios="test.scenarioDefinition" ref="config"/>
@ -61,11 +63,12 @@
import MsApiReportStatus from "../report/ApiReportStatus";
import MsApiReportDialog from "./ApiReportDialog";
import {checkoutTestManagerOrTestUser, downloadFile} from "../../../../common/js/utils";
import MsScheduleConfig from "../../common/components/MsScheduleConfig";
export default {
name: "MsApiTestConfig",
components: {MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig},
components: {MsScheduleConfig, MsApiReportDialog, MsApiReportStatus, MsApiScenarioConfig},
props: ["id"],
@ -126,6 +129,7 @@
name: item.name,
status: item.status,
scenarioDefinition: JSON.parse(item.scenarioDefinition),
schedule: item.schedule ? JSON.parse(item.schedule) : {},
});
this.$refs.config.reset();
}
@ -208,6 +212,31 @@
downloadFile(this.test.name + ".json", this.test.export());
break;
}
},
saveCronExpression(cronExpression) {
this.test.schedule.enable = true;
this.test.schedule.cronExpression = cronExpression;
this.saveSchedule();
},
saveSchedule() {
if (this.create) {
this.$message('请先保存测试,在设置定时任务');
return;
}
let param = {};
param.id = this.test.id;
param.schedule = this.test.schedule;
this.$post('/api/schedule/update', param, response => {
this.$success('保存成功');
this.getTest(this.test.id);
});
},
checkScheduleEdit() {
if (this.create) {
this.$message('请先保存测试');
return false;
}
return true;
}
},
@ -245,4 +274,8 @@
.test-container .more {
margin-left: 10px;
}
.schedule-config {
float: right;
}
</style>

View File

@ -100,6 +100,7 @@ export class Test extends BaseConfig {
this.name = undefined;
this.projectId = undefined;
this.scenarioDefinition = [];
this.schedule = {};
this.set(options);
this.sets({scenarioDefinition: Scenario}, options);

View File

@ -0,0 +1,101 @@
<template>
<div class="schedule-config">
<div>
<span class="cron-ico">
<i class="el-icon-date" size="small"></i>
<span class="character" @click="scheduleEdit">SCHEDULER</span>
</span>
<el-switch :disabled="!schedule.cronExpression" v-model="schedule.enable" @change="scheduleChange"/>
<ms-schedule-edit :schedule="schedule" :save="save" ref="scheduleEdit"/>
<crontab-result v-show="false" :ex="schedule.cronExpression" ref="crontabResult" @resultListChange="recentListChange"/>
</div>
<div>
<span :class="{'disable-character': !schedule.enable}"> 下次执行时间{{this.recentList.length > 0 ? this.recentList[0] : ''}} </span>
</div>
</div>
</template>
<script>
import MsScheduleEdit from "./MsScheduleEdit";
import CrontabResult from "../cron/CrontabResult";
export default {
name: "MsScheduleConfig",
components: {CrontabResult, MsScheduleEdit},
data() {
return {
recentList: [],
}
},
props: {
save: Function,
schedule: {},
checkOpen: {
type: Function,
default() {
return new Function()
}
},
},
// mounted() {
// console.log(this.schedule);
// // this.recentList = this.$refs.crontabResult.resultList;
// // console.log(this.recentList);
// console.log(this.recentList+ "====");
// },
// watch: {
// 'schedule.cronExpression'() {
// console.log(this.schedule);
// this.$refs.crontabResult.expressionChange();
// this.recentList = this.$refs.crontabResult.resultList;
// console.log(this.recentList);
// }
// },
methods: {
scheduleEdit() {
if (!this.checkOpen()) {
return;
}
this.$refs.scheduleEdit.open();
},
scheduleChange() {
this.$emit('scheduleChange');
},
recentListChange(resultList) {
this.recentList = resultList;
}
}
}
</script>
<style scoped>
.schedule-config {
float: right;
width: 250px;
height: 15px;
line-height: 25px;
}
.el-icon-date {
font-size: 20px;
margin-left: 5px;
}
.character {
font-weight: bold;
margin: 0 5px;
}
.disable-character {
color: #cccccc;
}
.el-switch {
margin: 0 5px;
}
.cron-ico {
cursor: pointer;
}
</style>

View File

@ -0,0 +1,97 @@
<template>
<el-dialog width="30%" class="schedule-edit" :title="'编辑定时任务'" :visible.sync="dialogVisible" @close="close">
<div id="app">
<el-form :model="form" :rules="rules" ref="from">
<el-form-item
:placeholder="'请输入 Cron 表达式'"
prop="cronValue">
<el-input v-model="form.cronValue" placeholder class="inp"/>
<el-button type="primary" @click="showCronDialog">生成 Cron</el-button>
<el-button type="primary" @click="saveCron">保存</el-button>
</el-form-item>
<crontab-result :ex="schedule.cronExpression" ref="crontabResult"/>
</el-form>
<el-dialog title="生成 cron" :visible.sync="showCron" :modal="false">
<crontab @hide="showCron=false" @fill="crontabFill" :expression="schedule.cronExpression"/>
</el-dialog>
</div>
</el-dialog>
</template>
<script>
import Crontab from "../cron/Crontab";
import CrontabResult from "../cron/CrontabResult";
import {cronValidate} from "../../../../common/js/cron";
export default {
name: "MsScheduleEdit",
components: {CrontabResult, Crontab},
props: {
save: Function,
schedule: {},
},
watch: {
'schedule.cronExpression'() {
this.form.cronValue = this.schedule.cronExpression;
}
},
data() {
const validateCron = (rule, cronValue, callback) => {
if (!cronValidate(cronValue)) {
callback(new Error('Cron 表达式格式错误'));
} else {
this.schedule.cronExpression = cronValue;
callback();
}
};
return {
dialogVisible: false,
showCron: false,
form: {
cronValue: ""
},
rules: {
cronValue :[{required: true, validator: validateCron, trigger: 'blur'}],
}
}
},
methods: {
open() {
this.dialogVisible = true;
},
crontabFill(value) {
//
this.schedule.cronExpression = value;
this.form.cronValue = value;
this.$refs['from'].validate();
},
showCronDialog() {
this.showCron = true;
},
saveCron () {
this.$refs['from'].validate((valid) => {
if (valid) {
this.save(this.form.cronValue);
this.dialogVisible = false;
} else {
return false;
}
});
},
close() {
this.$refs['from'].resetFields();
this.$refs.crontabResult.resultList = [];
}
}
}
</script>
<style scoped>
.inp {
width: 50%;
margin-right: 20px;
}
</style>

View File

@ -0,0 +1,422 @@
<template>
<div>
<el-tabs type="border-card">
<el-tab-pane label="秒" v-if="shouldHide('second')">
<crontab-second
@update="updateContabValue"
:check="checkNumber"
ref="cronsecond"
/>
</el-tab-pane>
<el-tab-pane label="分钟" v-if="shouldHide('min')">
<crontab-min
@update="updateContabValue"
:check="checkNumber"
:cron="contabValueObj"
ref="cronmin"
/>
</el-tab-pane>
<el-tab-pane label="小时" v-if="shouldHide('hour')">
<crontab-hour
@update="updateContabValue"
:check="checkNumber"
:cron="contabValueObj"
ref="cronhour"
/>
</el-tab-pane>
<el-tab-pane label="日" v-if="shouldHide('day')">
<crontab-day
@update="updateContabValue"
:check="checkNumber"
:cron="contabValueObj"
ref="cronday"
/>
</el-tab-pane>
<el-tab-pane label="月" v-if="shouldHide('mouth')">
<crontab-mouth
@update="updateContabValue"
:check="checkNumber"
:cron="contabValueObj"
ref="cronmouth"
/>
</el-tab-pane>
<el-tab-pane label="周" v-if="shouldHide('week')">
<crontab-week
@update="updateContabValue"
:check="checkNumber"
:cron="contabValueObj"
ref="cronweek"
/>
</el-tab-pane>
<el-tab-pane label="年" v-if="shouldHide('year')">
<crontab-year @update="updateContabValue"
:check="checkNumber"
:cron="contabValueObj"
ref="cronyear"/>
</el-tab-pane>
</el-tabs>
<div class="popup-main">
<div class="popup-result-container">
<p class="title">时间表达式</p>
<table>
<thead>
<th v-for="item of tabTitles" width="40" :key="item">{{item}}</th>
<th>crontab完整表达式</th>
</thead>
<tbody>
<td>
<span>{{contabValueObj.second}}</span>
</td>
<td>
<span>{{contabValueObj.min}}</span>
</td>
<td>
<span>{{contabValueObj.hour}}</span>
</td>
<td>
<span>{{contabValueObj.day}}</span>
</td>
<td>
<span>{{contabValueObj.mouth}}</span>
</td>
<td>
<span>{{contabValueObj.week}}</span>
</td>
<td>
<span>{{contabValueObj.year}}</span>
</td>
<td>
<span>{{contabValueString}}</span>
</td>
</tbody>
</table>
</div>
<crontab-result :ex="contabValueString"/>
<div class="pop_btn">
<el-button size="small" type="primary" @click="submitFill">确定</el-button>
<el-button size="small" type="warning" @click="clearCron">重置</el-button>
<el-button size="small" @click="hidePopup">取消</el-button>
</div>
</div>
</div>
</template>
<script>
import CrontabSecond from "./CrontabSecond.vue";
import CrontabMin from "./CrontabMin.vue";
import CrontabHour from "./CrontabHour.vue";
import CrontabDay from "./CrontabDay.vue";
import CrontabMouth from "./CrontabMouth.vue";
import CrontabWeek from "./CrontabWeek.vue";
import CrontabYear from "./CrontabYear.vue";
import CrontabResult from "./CrontabResult.vue";
export default {
name: "Crontab",
data() {
return {
tabTitles: ["秒", "分钟", "小时", "日", "月", "周", "年"],
tabActive: 0,
myindex: 0,
contabValueObj: {
second: "*",
min: "*",
hour: "*",
day: "*",
mouth: "*",
week: "?",
year: "",
},
};
},
props: ["expression", "hideComponent"],
methods: {
shouldHide(key) {
if (this.hideComponent && this.hideComponent.includes(key)) return false;
return true;
},
resolveExp() {
//
if (this.expression) {
let arr = this.expression.split(" ");
if (arr.length >= 6) {
//6
let obj = {
second: arr[0],
min: arr[1],
hour: arr[2],
day: arr[3],
mouth: arr[4],
week: arr[5],
year: arr[6] ? arr[6] : "",
};
this.contabValueObj = {
...obj,
};
for (let i in obj) {
if (obj[i]) this.changeRadio(i, obj[i]);
}
}
} else {
//
this.clearCron();
}
},
// tab
tabCheck(index) {
this.tabActive = index;
},
//
updateContabValue(name, value, from) {
"updateContabValue", name, value, from;
this.contabValueObj[name] = value;
if (from && from !== name) {
console.log(`来自组件 ${from} 改变了 ${name} ${value}`);
this.changeRadio(name, value);
}
},
//
changeRadio(name, value) {
let arr = ["second", "min", "hour", "mouth"],
refName = "cron" + name,
insVlaue;
if (!this.$refs[refName]) return;
if (arr.includes(name)) {
if (value === "*") {
insVlaue = 1;
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-");
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insVlaue = 2;
} else if (value.indexOf("/") > -1) {
let indexArr = value.split("/");
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 0)
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insVlaue = 3;
} else {
insVlaue = 4;
this.$refs[refName].checkboxList = value.split(",");
}
} else if (name == "day") {
if (value === "*") {
insVlaue = 1;
} else if (value == "?") {
insVlaue = 2;
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-");
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insVlaue = 3;
} else if (value.indexOf("/") > -1) {
let indexArr = value.split("/");
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 0)
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insVlaue = 4;
} else if (value.indexOf("W") > -1) {
let indexArr = value.split("W");
isNaN(indexArr[0])
? (this.$refs[refName].workday = 0)
: (this.$refs[refName].workday = indexArr[0]);
insVlaue = 5;
} else if (value === "L") {
insVlaue = 6;
} else {
this.$refs[refName].checkboxList = value.split(",");
insVlaue = 7;
}
} else if (name == "week") {
if (value === "*") {
insVlaue = 1;
} else if (value == "?") {
insVlaue = 2;
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-");
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insVlaue = 3;
} else if (value.indexOf("#") > -1) {
let indexArr = value.split("#");
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 1)
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insVlaue = 4;
} else if (value.indexOf("L") > -1) {
let indexArr = value.split("L");
isNaN(indexArr[0])
? (this.$refs[refName].weekday = 1)
: (this.$refs[refName].weekday = indexArr[0]);
insVlaue = 5;
} else {
this.$refs[refName].checkboxList = value.split(",");
insVlaue = 7;
}
} else if (name == "year") {
if (value == "") {
insVlaue = 1;
} else if (value == "*") {
insVlaue = 2;
} else if (value.indexOf("-") > -1) {
insVlaue = 3;
} else if (value.indexOf("/") > -1) {
insVlaue = 4;
} else {
this.$refs[refName].checkboxList = value.split(",");
insVlaue = 5;
}
}
this.$refs[refName].radioValue = insVlaue;
},
// -props
checkNumber(value, minLimit, maxLimit) {
//
value = Math.floor(value);
if (value < minLimit) {
value = minLimit;
} else if (value > maxLimit) {
value = maxLimit;
}
return value;
},
//
hidePopup() {
this.$emit("hide");
},
//
submitFill() {
this.$emit("fill", this.contabValueString);
this.hidePopup();
},
clearCron() {
//
("准备还原");
this.contabValueObj = {
second: "*",
min: "*",
hour: "*",
day: "*",
mouth: "*",
week: "?",
year: "",
};
for (let j in this.contabValueObj) {
this.changeRadio(j, this.contabValueObj[j]);
}
},
},
computed: {
contabValueString: function() {
let obj = this.contabValueObj;
let str =
obj.second +
" " +
obj.min +
" " +
obj.hour +
" " +
obj.day +
" " +
obj.mouth +
" " +
obj.week +
(obj.year == "" ? "" : " " + obj.year);
return str;
},
},
components: {
CrontabSecond,
CrontabMin,
CrontabHour,
CrontabDay,
CrontabMouth,
CrontabWeek,
CrontabYear,
CrontabResult,
},
watch: {
expression: "resolveExp",
hideComponent(value) {
//
},
},
mounted: function() {
this.resolveExp();
},
};
</script>
<style scoped>
.pop_btn {
text-align: center;
margin-top: 20px;
}
.popup-main {
position: relative;
margin: 10px auto;
background: #fff;
border-radius: 5px;
font-size: 12px;
overflow: hidden;
}
.popup-title {
overflow: hidden;
line-height: 34px;
padding-top: 6px;
background: #f2f2f2;
}
.popup-result-container {
box-sizing: border-box;
line-height: 24px;
margin: 25px auto;
padding: 15px 10px 10px;
border: 1px solid #ccc;
position: relative;
}
.popup-result-container .title {
position: absolute;
top: -28px;
left: 50%;
width: 140px;
font-size: 14px;
margin-left: -70px;
text-align: center;
line-height: 30px;
background: #fff;
}
.popup-result-container table {
text-align: center;
width: 100%;
margin: 0 auto;
}
.popup-result-container table span {
display: block;
width: 100%;
font-family: arial;
line-height: 30px;
height: 30px;
white-space: nowrap;
overflow: hidden;
border: 1px solid #e8e8e8;
}
</style>

View File

@ -0,0 +1,179 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model='radioValue' :label="1">
允许的通配符[, - * / L M]
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="2">
不指定
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="3">
周期从
<el-input-number v-model='cycle01' :min="0" :max="31" /> -
<el-input-number v-model='cycle02' :min="0" :max="31" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="4">
<el-input-number v-model='average01' :min="0" :max="31" /> 号开始
<el-input-number v-model='average02' :min="0" :max="31" /> 日执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="5">
每月
<el-input-number v-model='workday' :min="0" :max="31" /> 号最近的那个工作日
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="6">
本月最后一天
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="7">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
<el-option v-for="item in 31" :key="item" :value="item">{{item}}</el-option>
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
radioValue: 1,
workday: 1,
cycle01: 1,
cycle02: 2,
average01: 1,
average02: 1,
checkboxList: [],
checkNum: this.$options.propsData.check
}
},
name: 'CrontabDay',
props: ['check', 'cron'],
methods: {
//
radioChange() {
('day rachange');
if (this.radioValue === 1) {
this.$emit('update', 'day', '*', 'day');
this.$emit('update', 'week', '?', 'day');
this.$emit('update', 'mouth', '*', 'day');
} else {
if (this.cron.hour === '*') {
this.$emit('update', 'hour', '0', 'day');
}
if (this.cron.min === '*') {
this.$emit('update', 'min', '0', 'day');
}
if (this.cron.second === '*') {
this.$emit('update', 'second', '0', 'day');
}
}
switch (this.radioValue) {
case 2:
this.$emit('update', 'day', '?');
break;
case 3:
this.$emit('update', 'day', this.cycle01 + '-' + this.cycle02);
break;
case 4:
this.$emit('update', 'day', this.average01 + '/' + this.average02);
break;
case 5:
this.$emit('update', 'day', this.workday + 'W');
break;
case 6:
this.$emit('update', 'day', 'L');
break;
case 7:
this.$emit('update', 'day', this.checkboxString);
break;
}
('day rachange end');
},
//
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'day', this.cycleTotal);
}
},
//
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'day', this.averageTotal);
}
},
//
workdayChange() {
if (this.radioValue == '5') {
this.$emit('update', 'day', this.workday + 'W');
}
},
// checkbox
checkboxChange() {
if (this.radioValue == '7') {
this.$emit('update', 'day', this.checkboxString);
}
},
// week
weekChange() {
//weekday?
if (this.cron.week == '?' && this.radioValue == '2') {
this.radioValue = '1';
} else if (this.cron.week !== '?' && this.radioValue != '2') {
this.radioValue = '2';
}
},
},
watch: {
"radioValue": "radioChange",
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'workdayCheck': 'workdayChange',
'checkboxString': 'checkboxChange',
},
computed: {
//
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 1, 31)
this.cycle02 = this.checkNum(this.cycle02, 1, 31)
return this.cycle01 + '-' + this.cycle02;
},
//
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 1, 31)
this.average02 = this.checkNum(this.average02, 1, 31)
return this.average01 + '/' + this.average02;
},
//
workdayCheck: function () {
this.workday = this.checkNum(this.workday, 1, 31)
return this.workday;
},
// checkbox
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}
</script>

View File

@ -0,0 +1,122 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model='radioValue' :label="1">
小时允许的通配符[, - * /]
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="2">
周期从
<el-input-number v-model='cycle01' :min="0" :max="60" /> -
<el-input-number v-model='cycle02' :min="0" :max="60" /> 小时
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="3">
<el-input-number v-model='average01' :min="0" :max="60" /> 小时开始
<el-input-number v-model='average02' :min="0" :max="60" /> 小时执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
radioValue: 1,
cycle01: 0,
cycle02: 1,
average01: 0,
average02: 1,
checkboxList: [],
checkNum: this.$options.propsData.check
}
},
name: 'CrontabHour',
props: ['check', 'cron'],
methods: {
//
radioChange() {
if (this.radioValue === 1) {
this.$emit('update', 'hour', '*', 'hour');
this.$emit('update', 'day', '*', 'hour');
} else {
if (this.cron.min === '*') {
this.$emit('update', 'min', '0', 'hour');
}
if (this.cron.second === '*') {
this.$emit('update', 'second', '0', 'hour');
}
}
switch (this.radioValue) {
case 2:
this.$emit('update', 'hour', this.cycle01 + '-' + this.cycle02);
break;
case 3:
this.$emit('update', 'hour', this.average01 + '/' + this.average02);
break;
case 4:
this.$emit('update', 'hour', this.checkboxString);
break;
}
},
//
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'hour', this.cycleTotal);
}
},
//
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'hour', this.averageTotal);
}
},
// checkbox
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'hour', this.checkboxString);
}
}
},
watch: {
"radioValue": "radioChange",
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'checkboxString': 'checkboxChange'
},
computed: {
//
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 0, 23)
this.cycle02 = this.checkNum(this.cycle02, 0, 23)
return this.cycle01 + '-' + this.cycle02;
},
//
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 0, 23)
this.average02 = this.checkNum(this.average02, 1, 23)
return this.average01 + '/' + this.average02;
},
// checkbox
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}
</script>

View File

@ -0,0 +1,120 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model='radioValue' :label="1">
分钟允许的通配符[, - * /]
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="2">
周期从
<el-input-number v-model='cycle01' :min="0" :max="60" /> -
<el-input-number v-model='cycle02' :min="0" :max="60" /> 分钟
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="3">
<el-input-number v-model='average01' :min="0" :max="60" /> 分钟开始
<el-input-number v-model='average02' :min="0" :max="60" /> 分钟执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
radioValue: 1,
cycle01: 1,
cycle02: 2,
average01: 0,
average02: 1,
checkboxList: [],
checkNum: this.$options.propsData.check
}
},
name: 'CrontabMin',
props: ['check', 'cron'],
methods: {
//
radioChange() {
if (this.radioValue !== 1 && this.cron.second === '*') {
this.$emit('update', 'second', '0', 'min');
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'min', '*', 'min');
this.$emit('update', 'hour', '*', 'min');
break;
case 2:
this.$emit('update', 'min', this.cycle01 + '-' + this.cycle02, 'min');
break;
case 3:
this.$emit('update', 'min', this.average01 + '/' + this.average02, 'min');
break;
case 4:
this.$emit('update', 'min', this.checkboxString, 'min');
break;
}
},
//
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'min', this.cycleTotal, 'min');
}
},
//
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'min', this.averageTotal, 'min');
}
},
// checkbox
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'min', this.checkboxString, 'min');
}
},
},
watch: {
"radioValue": "radioChange",
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'checkboxString': 'checkboxChange',
},
computed: {
//
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 0, 59)
this.cycle02 = this.checkNum(this.cycle02, 0, 59)
return this.cycle01 + '-' + this.cycle02;
},
//
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 0, 59)
this.average02 = this.checkNum(this.average02, 1, 59)
return this.average01 + '/' + this.average02;
},
// checkbox
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}
</script>

View File

@ -0,0 +1,128 @@
<template>
<el-form size='small'>
<el-form-item>
<el-radio v-model='radioValue' :label="1">
允许的通配符[, - * /]
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="2">
周期从
<el-input-number v-model='cycle01' :min="1" :max="12" /> -
<el-input-number v-model='cycle02' :min="1" :max="12" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="3">
<el-input-number v-model='average01' :min="1" :max="12" /> 月开始
<el-input-number v-model='average02' :min="1" :max="12" /> 月月执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
<el-option v-for="item in 12" :key="item" :value="item">{{item}}</el-option>
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
radioValue: 1,
cycle01: 1,
cycle02: 2,
average01: 1,
average02: 1,
checkboxList: [],
checkNum: this.check
}
},
name: 'CrontabMouth',
props: ['check', 'cron'],
methods: {
//
radioChange() {
if (this.radioValue === 1) {
this.$emit('update', 'mouth', '*');
this.$emit('update', 'year', '*');
} else {
if (this.cron.day === '*') {
this.$emit('update', 'day', '1', 'mouth');
}
if (this.cron.hour === '*') {
this.$emit('update', 'hour', '0', 'mouth');
}
if (this.cron.min === '*') {
this.$emit('update', 'min', '0', 'mouth');
}
if (this.cron.second === '*') {
this.$emit('update', 'second', '0', 'mouth');
}
}
switch (this.radioValue) {
case 2:
this.$emit('update', 'mouth', this.cycle01 + '-' + this.cycle02);
break;
case 3:
this.$emit('update', 'mouth', this.average01 + '/' + this.average02);
break;
case 4:
this.$emit('update', 'mouth', this.checkboxString);
break;
}
},
//
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'mouth', this.cycleTotal);
}
},
//
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'mouth', this.averageTotal);
}
},
// checkbox
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'mouth', this.checkboxString);
}
}
},
watch: {
"radioValue": "radioChange",
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'checkboxString': 'checkboxChange'
},
computed: {
//
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 1, 12)
this.cycle02 = this.checkNum(this.cycle02, 1, 12)
return this.cycle01 + '-' + this.cycle02;
},
//
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 1, 12)
this.average02 = this.checkNum(this.average02, 1, 12)
return this.average01 + '/' + this.average02;
},
// checkbox
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}
</script>

View File

@ -0,0 +1,592 @@
<template>
<div class="popup-result">
<p class="title">最近5次运行时间</p>
<ul class="popup-result-scroll">
<template>
<li v-for='item in resultList' :key="item">{{item}}</li>
</template>
</ul>
</div>
</template>
<script>
export default {
name: 'CrontabResult',
data() {
return {
dayRule: '',
dayRuleSup: '',
dateArr: [],
resultList: [],
isShow: false
}
},
watch: {
'ex': 'expressionChange'
},
props: ['ex'],
mounted: function () {
//
this.expressionChange();
},
methods: {
//
expressionChange() {
// -
this.isShow = false;
if (!this.ex) {
this.resultList = [];
return;
}
// [0123456]
let ruleArr = this.$options.propsData.ex.split(' ');
//
let nums = 0;
//
let resultArr = [];
// []
let nTime = new Date();
let nYear = nTime.getFullYear();
let nMouth = nTime.getMonth() + 1;
let nDay = nTime.getDate();
let nHour = nTime.getHours();
let nMin = nTime.getMinutes();
let nSecond = nTime.getSeconds();
// 100
this.getSecondArr(ruleArr[0]);
this.getMinArr(ruleArr[1]);
this.getHourArr(ruleArr[2]);
this.getDayArr(ruleArr[3]);
this.getMouthArr(ruleArr[4]);
this.getWeekArr(ruleArr[5]);
this.getYearArr(ruleArr[6], nYear);
// -便使
let sDate = this.dateArr[0];
let mDate = this.dateArr[1];
let hDate = this.dateArr[2];
let DDate = this.dateArr[3];
let MDate = this.dateArr[4];
let YDate = this.dateArr[5];
//
let sIdx = this.getIndex(sDate, nSecond);
let mIdx = this.getIndex(mDate, nMin);
let hIdx = this.getIndex(hDate, nHour);
let DIdx = this.getIndex(DDate, nDay);
let MIdx = this.getIndex(MDate, nMouth);
let YIdx = this.getIndex(YDate, nYear);
// ()
const resetSecond = function () {
sIdx = 0;
nSecond = sDate[sIdx]
}
const resetMin = function () {
mIdx = 0;
nMin = mDate[mIdx]
resetSecond();
}
const resetHour = function () {
hIdx = 0;
nHour = hDate[hIdx]
resetMin();
}
const resetDay = function () {
DIdx = 0;
nDay = DDate[DIdx]
resetHour();
}
const resetMouth = function () {
MIdx = 0;
nMouth = MDate[MIdx]
resetDay();
}
//
if (nYear !== YDate[YIdx]) {
resetMouth();
}
//
if (nMouth !== MDate[MIdx]) {
resetDay();
}
//
if (nDay !== DDate[DIdx]) {
resetHour();
}
//
if (nHour !== hDate[hIdx]) {
resetMin();
}
//
if (nMin !== mDate[mIdx]) {
resetSecond();
}
//
goYear: for (let Yi = YIdx; Yi < YDate.length; Yi++) {
let YY = YDate[Yi];
//
if (nMouth > MDate[MDate.length - 1]) {
resetMouth();
continue;
}
//
goMouth: for (let Mi = MIdx; Mi < MDate.length; Mi++) {
// 便
let MM = MDate[Mi];
MM = MM < 10 ? '0' + MM : MM;
//
if (nDay > DDate[DDate.length - 1]) {
resetDay();
if (Mi == MDate.length - 1) {
resetMouth();
continue goYear;
}
continue;
}
//
goDay: for (let Di = DIdx; Di < DDate.length; Di++) {
// 便
let DD = DDate[Di];
let thisDD = DD < 10 ? '0' + DD : DD;
//
if (nHour > hDate[hDate.length - 1]) {
resetHour();
if (Di == DDate.length - 1) {
resetDay();
if (Mi == MDate.length - 1) {
resetMouth();
continue goYear;
}
continue goMouth;
}
continue;
}
//
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true && this.dayRule !== 'workDay' && this.dayRule !== 'lastWeek' && this.dayRule !== 'lastDay') {
resetDay();
continue goMouth;
}
//
if (this.dayRule == 'lastDay') {
//
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
}
}
} else if (this.dayRule == 'workDay') {
//230
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
}
}
// X
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
//
if (thisWeek == 0) {
//
DD++;
thisDD = DD < 10 ? '0' + DD : DD;
//
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD -= 3;
}
} else if (thisWeek == 6) {
//61
if (this.dayRuleSup !== 1) {
DD--;
} else {
DD += 2;
}
}
} else if (this.dayRule == 'weekDay') {
//
//
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
//dayRuleSup
if (Array.indexOf(this.dayRuleSup, thisWeek) < 0) {
//
if (Di == DDate.length - 1) {
resetDay();
if (Mi == MDate.length - 1) {
resetMouth();
continue goYear;
}
continue goMouth;
}
continue;
}
} else if (this.dayRule == 'assWeek') {
//
//1
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
if (this.dayRuleSup[1] >= thisWeek) {
DD = (this.dayRuleSup[0] - 1) * 7 + this.dayRuleSup[1] - thisWeek + 1;
} else {
DD = this.dayRuleSup[0] * 7 + this.dayRuleSup[1] - thisWeek + 1;
}
} else if (this.dayRule == 'lastWeek') {
//
//230
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
}
}
//
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
//
if (this.dayRuleSup < thisWeek) {
DD -= thisWeek - this.dayRuleSup;
} else if (this.dayRuleSup > thisWeek) {
DD -= 7 - (this.dayRuleSup - thisWeek)
}
}
// 1005
DD = DD < 10 ? '0' + DD : DD;
//
goHour: for (let hi = hIdx; hi < hDate.length; hi++) {
let hh = hDate[hi] < 10 ? '0' + hDate[hi] : hDate[hi]
//
if (nMin > mDate[mDate.length - 1]) {
resetMin();
if (hi == hDate.length - 1) {
resetHour();
if (Di == DDate.length - 1) {
resetDay();
if (Mi == MDate.length - 1) {
resetMouth();
continue goYear;
}
continue goMouth;
}
continue goDay;
}
continue;
}
// ""
goMin: for (let mi = mIdx; mi < mDate.length; mi++) {
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi];
//
if (nSecond > sDate[sDate.length - 1]) {
resetSecond();
if (mi == mDate.length - 1) {
resetMin();
if (hi == hDate.length - 1) {
resetHour();
if (Di == DDate.length - 1) {
resetDay();
if (Mi == MDate.length - 1) {
resetMouth();
continue goYear;
}
continue goMouth;
}
continue goDay;
}
continue goHour;
}
continue;
}
// ""
goSecond: for (let si = sIdx; si <= sDate.length - 1; si++) {
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si];
//
if (MM !== '00' && DD !== '00') {
resultArr.push(YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss)
nums++;
}
//退
if (nums == 5) break goYear;
//
if (si == sDate.length - 1) {
resetSecond();
if (mi == mDate.length - 1) {
resetMin();
if (hi == hDate.length - 1) {
resetHour();
if (Di == DDate.length - 1) {
resetDay();
if (Mi == MDate.length - 1) {
resetMouth();
continue goYear;
}
continue goMouth;
}
continue goDay;
}
continue goHour;
}
continue goMin;
}
} //goSecond
} //goMin
}//goHour
}//goDay
}//goMouth
}
// 100
if (resultArr.length == 0) {
this.resultList = ['没有达到条件的结果!'];
} else {
this.resultList = resultArr;
if (resultArr.length !== 5) {
this.resultList.push('最近100年内只有上面' + resultArr.length + '条结果!')
}
}
this.$emit("resultListChange", this.resultList);
// -
this.isShow = true;
},
//
getIndex(arr, value) {
if (value <= arr[0] || value > arr[arr.length - 1]) {
return 0;
} else {
for (let i = 0; i < arr.length - 1; i++) {
if (value > arr[i] && value <= arr[i + 1]) {
return i + 1;
}
}
}
},
// ""
getYearArr(rule, year) {
this.dateArr[5] = this.getOrderArr(year, year + 100);
if (rule !== undefined) {
if (rule.indexOf('-') >= 0) {
this.dateArr[5] = this.getCycleArr(rule, year + 100, false)
} else if (rule.indexOf('/') >= 0) {
this.dateArr[5] = this.getAverageArr(rule, year + 100)
} else if (rule !== '*') {
this.dateArr[5] = this.getAssignArr(rule)
}
}
},
// ""
getMouthArr(rule) {
this.dateArr[4] = this.getOrderArr(1, 12);
if (rule.indexOf('-') >= 0) {
this.dateArr[4] = this.getCycleArr(rule, 12, false)
} else if (rule.indexOf('/') >= 0) {
this.dateArr[4] = this.getAverageArr(rule, 12)
} else if (rule !== '*') {
this.dateArr[4] = this.getAssignArr(rule)
}
},
// ""-
getWeekArr(rule) {
//
if (this.dayRule == '' && this.dayRuleSup == '') {
if (rule.indexOf('-') >= 0) {
this.dayRule = 'weekDay';
this.dayRuleSup = this.getCycleArr(rule, 7, false)
} else if (rule.indexOf('#') >= 0) {
this.dayRule = 'assWeek';
let matchRule = rule.match(/[0-9]{1}/g);
this.dayRuleSup = [Number(matchRule[0]), Number(matchRule[1])];
this.dateArr[3] = [1];
if (this.dayRuleSup[1] == 7) {
this.dayRuleSup[1] = 0;
}
} else if (rule.indexOf('L') >= 0) {
this.dayRule = 'lastWeek';
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
this.dateArr[3] = [31];
if (this.dayRuleSup == 7) {
this.dayRuleSup = 0;
}
} else if (rule !== '*' && rule !== '?') {
this.dayRule = 'weekDay';
this.dayRuleSup = this.getAssignArr(rule)
}
//weekDay70week0
if (this.dayRule == 'weekDay') {
for (let i = 0; i < this.dayRuleSup.length; i++) {
if (this.dayRuleSup[i] == 7) {
this.dayRuleSup[i] = 0;
}
}
}
}
},
// ""-
getDayArr(rule) {
this.dateArr[3] = this.getOrderArr(1, 31);
this.dayRule = '';
this.dayRuleSup = '';
if (rule.indexOf('-') >= 0) {
this.dateArr[3] = this.getCycleArr(rule, 31, false)
this.dayRuleSup = 'null';
} else if (rule.indexOf('/') >= 0) {
this.dateArr[3] = this.getAverageArr(rule, 31)
this.dayRuleSup = 'null';
} else if (rule.indexOf('W') >= 0) {
this.dayRule = 'workDay';
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
this.dateArr[3] = [this.dayRuleSup];
} else if (rule.indexOf('L') >= 0) {
this.dayRule = 'lastDay';
this.dayRuleSup = 'null';
this.dateArr[3] = [31];
} else if (rule !== '*' && rule !== '?') {
this.dateArr[3] = this.getAssignArr(rule)
this.dayRuleSup = 'null';
} else if (rule == '*') {
this.dayRuleSup = 'null';
}
},
// ""
getHourArr(rule) {
this.dateArr[2] = this.getOrderArr(0, 23);
if (rule.indexOf('-') >= 0) {
this.dateArr[2] = this.getCycleArr(rule, 24, true)
} else if (rule.indexOf('/') >= 0) {
this.dateArr[2] = this.getAverageArr(rule, 23)
} else if (rule !== '*') {
this.dateArr[2] = this.getAssignArr(rule)
}
},
// ""
getMinArr(rule) {
this.dateArr[1] = this.getOrderArr(0, 59);
if (rule.indexOf('-') >= 0) {
this.dateArr[1] = this.getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
this.dateArr[1] = this.getAverageArr(rule, 59)
} else if (rule !== '*') {
this.dateArr[1] = this.getAssignArr(rule)
}
},
// ""
getSecondArr(rule) {
this.dateArr[0] = this.getOrderArr(0, 59);
if (rule.indexOf('-') >= 0) {
this.dateArr[0] = this.getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
this.dateArr[0] = this.getAverageArr(rule, 59)
} else if (rule !== '*') {
this.dateArr[0] = this.getAssignArr(rule)
}
},
// min-max
getOrderArr(min, max) {
let arr = [];
for (let i = min; i <= max; i++) {
arr.push(i);
}
return arr;
},
//
getAssignArr(rule) {
let arr = [];
let assiginArr = rule.split(',');
for (let i = 0; i < assiginArr.length; i++) {
arr[i] = Number(assiginArr[i])
}
arr.sort(this.compare)
return arr;
},
//
getAverageArr(rule, limit) {
let arr = [];
let agArr = rule.split('/');
let min = Number(agArr[0]);
let step = Number(agArr[1]);
while (min <= limit) {
arr.push(min);
min += step;
}
return arr;
},
//
getCycleArr(rule, limit, status) {
//status--01
let arr = [];
let cycleArr = rule.split('-');
let min = Number(cycleArr[0]);
let max = Number(cycleArr[1]);
if (min > max) {
max += limit;
}
for (let i = min; i <= max; i++) {
let add = 0;
if (status == false && i % limit == 0) {
add = limit;
}
arr.push(Math.round(i % limit + add))
}
arr.sort(this.compare)
return arr;
},
//Array.sort
compare(value1, value2) {
if (value2 - value1 > 0) {
return -1;
} else {
return 1;
}
},
// 2017-9-19 18:04:33
formatDate(value, type) {
//
let time = typeof value == 'number' ? new Date(value) : value;
let Y = time.getFullYear();
let M = time.getMonth() + 1;
let D = time.getDate();
let h = time.getHours();
let m = time.getMinutes();
let s = time.getSeconds();
let week = time.getDay();
// type
if (type == undefined) {
return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
} else if (type == 'week') {
return week;
}
},
//
checkDate(value) {
let time = new Date(value);
let format = this.formatDate(time)
return value == format ? true : false;
}
}
}
</script>
<style>
.title {
margin: 0;
}
.popup-result-scroll {
font-size: 12px;
line-height: 24px;
height: 10em;
overflow-y: auto;
}
.popup-result {
box-sizing: border-box;
line-height: 24px;
margin: 25px auto;
padding: 15px 10px 10px;
border: 1px solid #ccc;
position: relative;
}
</style>

View File

@ -0,0 +1,133 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio v-model='radioValue' :label="1">
允许的通配符[, - * /]
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="2">
周期从
<el-input-number v-model='cycle01' :min="0" :max="60" /> -
<el-input-number v-model='cycle02' :min="0" :max="60" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="3">
<el-input-number v-model='average01' :min="0" :max="60" /> 秒开始
<el-input-number v-model='average02' :min="0" :max="60" /> 秒执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="4">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
radioValue: 1,
cycle01: 1,
cycle02: 2,
average01: 0,
average02: 1,
checkboxList: [],
checkNum: this.$options.propsData.check
}
},
name: 'CrontabSecond',
props: ['check', 'radioParent'],
methods: {
//
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'second', '*', 'second');
this.$emit('update', 'min', '*', 'second');
break;
case 2:
this.$emit('update', 'second', this.cycle01 + '-' + this.cycle02);
break;
case 3:
this.$emit('update', 'second', this.average01 + '/' + this.average02);
break;
case 4:
this.$emit('update', 'second', this.checkboxString);
break;
}
},
//
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'second', this.cycleTotal);
}
},
//
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'second', this.averageTotal);
}
},
// checkbox
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'second', this.checkboxString);
}
},
othChange() {
//
let ins = this.cron.second
// (' second', ins);
if (ins === '*') {
this.radioValue = 1;
} else if (ins.indexOf('-') > -1) {
this.radioValue = 2
} else if (ins.indexOf('/') > -1) {
this.radioValue = 3
} else {
this.radioValue = 4
this.checkboxList = ins.split(',')
}
}
},
watch: {
"radioValue": "radioChange",
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'checkboxString': 'checkboxChange',
radioParent() {
this.radioValue = this.radioParent
}
},
computed: {
//
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 0, 59);
this.cycle02 = this.checkNum(this.cycle02, 0, 59);
return this.cycle01 + '-' + this.cycle02;
},
//
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 0, 59)
this.average02 = this.checkNum(this.average02, 1, 59)
return this.average01 + '/' + this.average02;
},
// checkbox
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}
</script>

View File

@ -0,0 +1,167 @@
<template>
<el-form size='small'>
<el-form-item>
<el-radio v-model='radioValue' :label="1">
允许的通配符[, - * / L #]
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="2">
不指定
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="3">
周期从星期
<el-input-number v-model='cycle01' :min="1" :max="7" /> -
<el-input-number v-model='cycle02' :min="1" :max="7" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="4">
<el-input-number v-model='average01' :min="1" :max="4" /> 周的星期
<el-input-number v-model='average02' :min="1" :max="7" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="5">
本月最后一个星期
<el-input-number v-model='weekday' :min="1" :max="7" />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio v-model='radioValue' :label="6">
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple style="width:100%">
<el-option v-for="(item,index) of weekList" :key="index" :value="index+1">{{item}}</el-option>
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
radioValue: 2,
weekday: 1,
cycle01: 1,
cycle02: 2,
average01: 1,
average02: 1,
checkboxList: [],
weekList: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
checkNum: this.$options.propsData.check
}
},
name: 'CrontabWeek',
props: ['check', 'cron'],
methods: {
//
radioChange() {
if (this.radioValue === 1) {
this.$emit('update', 'week', '*');
this.$emit('update', 'year', '*');
} else {
if (this.cron.mouth === '*') {
this.$emit('update', 'mouth', '1', 'week');
}
if (this.cron.day === '*') {
this.$emit('update', 'day', '1', 'week');
}
if (this.cron.hour === '*') {
this.$emit('update', 'hour', '0', 'week');
}
if (this.cron.min === '*') {
this.$emit('update', 'min', '0', 'week');
}
if (this.cron.second === '*') {
this.$emit('update', 'second', '0', 'week');
}
}
switch (this.radioValue) {
case 2:
this.$emit('update', 'week', '?');
break;
case 3:
this.$emit('update', 'week', this.cycle01 + '-' + this.cycle02);
break;
case 4:
this.$emit('update', 'week', this.average01 + '#' + this.average02);
break;
case 5:
this.$emit('update', 'week', this.weekday + 'L');
break;
case 6:
this.$emit('update', 'week', this.checkboxString);
break;
}
},
// radio
//
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'week', this.cycleTotal);
}
},
//
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'week', this.averageTotal);
}
},
//
weekdayChange() {
if (this.radioValue == '5') {
this.$emit('update', 'week', this.weekday + 'L');
}
},
// checkbox
checkboxChange() {
if (this.radioValue == '6') {
this.$emit('update', 'week', this.checkboxString);
}
},
},
watch: {
"radioValue": "radioChange",
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'weekdayCheck': 'weekdayChange',
'checkboxString': 'checkboxChange',
},
computed: {
//
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 1, 7)
this.cycle02 = this.checkNum(this.cycle02, 1, 7)
return this.cycle01 + '-' + this.cycle02;
},
//
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 1, 4)
this.average02 = this.checkNum(this.average02, 1, 7)
return this.average01 + '#' + this.average02;
},
//
weekdayCheck: function () {
this.weekday = this.checkNum(this.weekday, 1, 7)
return this.weekday;
},
// checkbox
checkboxString: function () {
let str = this.checkboxList.join();
return str == '' ? '?' : str;
}
}
}
</script>

View File

@ -0,0 +1,144 @@
<template>
<el-form size="small">
<el-form-item>
<el-radio :label="1" v-model='radioValue'>
不填允许的通配符[, - * /]
</el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="2" v-model='radioValue'>
每年
</el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="3" v-model='radioValue'>
周期从
<el-input-number v-model='cycle01' :min='fullYear' /> -
<el-input-number v-model='cycle02' :min='fullYear' />
</el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="4" v-model='radioValue'>
<el-input-number v-model='average01' :min='fullYear' /> 年开始
<el-input-number v-model='average02' :min='fullYear' /> 年执行一次
</el-radio>
</el-form-item>
<el-form-item>
<el-radio :label="5" v-model='radioValue'>
指定
<el-select clearable v-model="checkboxList" placeholder="可多选" multiple>
<el-option v-for="item in 9" :key="item" :value="item - 1 + fullYear" :label="item -1 + fullYear" />
</el-select>
</el-radio>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
fullYear: 0,
radioValue: 1,
cycle01: 0,
cycle02: 0,
average01: 0,
average02: 1,
checkboxList: [],
checkNum: this.$options.propsData.check
}
},
name: 'CrontabYear',
props: ['check', 'mouth', 'cron'],
methods: {
//
radioChange() {
if (this.cron.mouth === '*') {
this.$emit('update', 'mouth', '1', 'year');
}
if (this.cron.day === '*') {
this.$emit('update', 'day', '1', 'year');
}
if (this.cron.hour === '*') {
this.$emit('update', 'hour', '0', 'year');
}
if (this.cron.min === '*') {
this.$emit('update', 'min', '0', 'year');
}
if (this.cron.second === '*') {
this.$emit('update', 'second', '0', 'year');
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'year', '');
break;
case 2:
this.$emit('update', 'year', '*');
break;
case 3:
this.$emit('update', 'year', this.cycle01 + '-' + this.cycle02);
break;
case 4:
this.$emit('update', 'year', this.average01 + '/' + this.average02);
break;
case 5:
this.$emit('update', 'year', this.checkboxString);
break;
}
},
//
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'year', this.cycleTotal);
}
},
//
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'year', this.averageTotal);
}
},
// checkbox
checkboxChange() {
if (this.radioValue == '5') {
this.$emit('update', 'year', this.checkboxString);
}
}
},
watch: {
"radioValue": "radioChange",
'cycleTotal': 'cycleChange',
'averageTotal': 'averageChange',
'checkboxString': 'checkboxChange'
},
computed: {
//
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, this.fullYear, this.fullYear + 100)
this.cycle02 = this.checkNum(this.cycle02, this.fullYear + 1, this.fullYear + 101)
return this.cycle01 + '-' + this.cycle02;
},
//
averageTotal: function () {
this.average01 = this.checkNum(this.average01, this.fullYear, this.fullYear + 100)
this.average02 = this.checkNum(this.average02, 1, 10)
return this.average01 + '/' + this.average02;
},
// checkbox
checkboxString: function () {
let str = this.checkboxList.join();
return str;
}
},
mounted: function () {
//
this.fullYear = Number(new Date().getFullYear());
}
}
</script>

View File

@ -32,6 +32,7 @@ import TestCase from "../../track/case/TestCase";
import TestTrack from "../../track/TestTrack";
import ApiReportList from "../../api/report/ApiReportList";
import axios from "axios";
import ApiKeys from "../../settings/personal/ApiKeys";
Vue.use(VueRouter);
@ -70,6 +71,10 @@ const router = new VueRouter({
path: 'personsetting',
component: PersonSetting
},
{
path: 'apikeys',
component: ApiKeys
},
{
path: 'member',
component: Member

View File

@ -38,6 +38,7 @@
<span>{{$t('commons.personal_info')}}</span>
</template>
<el-menu-item index="/setting/personsetting">{{$t('commons.personal_setting')}}</el-menu-item>
<el-menu-item index="/setting/apikeys">API Keys</el-menu-item>
</el-submenu>
</el-menu>

View File

@ -0,0 +1,125 @@
<template>
<div v-loading="result.loading">
<el-card class="table-card">
<template v-slot:header>
<div>
<el-row class="table-title" type="flex" justify="space-between" align="middle">
<span class="title">API Keys</span>
</el-row>
<el-row type="flex" justify="space-between" align="middle">
<el-button @click="createApiKey()" plain type="el-icon-question" icon="el-icon-circle-plus-outline"
size="mini">
{{$t('commons.create')}}
</el-button>
</el-row>
</div>
</template>
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="accessKey" label="Access Key"/>
<el-table-column prop="secretKey" label="Secret Key"/>
<el-table-column prop="status" :label="$t('commons.status')">
<template v-slot:default="scope">
<el-switch v-model="scope.row.status"
active-color="#13ce66"
inactive-color="#ff4949"
active-value="ACTIVE"
inactive-value="DISABLED"
@change="changeSwitch(scope.row)"
/>
</template>
</el-table-column>
<el-table-column prop="createTime" :label="$t('commons.create_time')">
<template v-slot:default="scope">
<span>{{ scope.row.createTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('commons.operating')">
<template v-slot:default="scope">
<ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete"
type="danger" @exec="deleteApiKey(scope.row)"/>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import MsDialogFooter from "../../common/components/MsDialogFooter";
import {getCurrentUser} from "../../../../common/js/utils";
import MsTableOperatorButton from "../../common/components/MsTableOperatorButton";
import MsTableHeader from "../../common/components/MsTableHeader";
export default {
name: "MsApiKeys",
components: {MsDialogFooter, MsTableOperatorButton, MsTableHeader},
data() {
return {
result: {},
updateVisible: false,
editPasswordVisible: false,
apiKeysVisible: false,
condition: {},
tableData: [],
}
},
activated() {
this.search();
},
methods: {
currentUser: () => {
return getCurrentUser();
},
search() {
this.result = this.$get("/user/key/info", response => {
this.tableData = response.data;
this.tableData.forEach(d => d.show = false);
}
)
},
deleteApiKey(row) {
this.$confirm(this.$t('user.apikey_delete_confirm'), '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
type: 'warning'
}).then(() => {
this.result = this.$get("/user/key/delete/" + row.id, response => {
this.$success(this.$t('commons.delete_success'));
this.search();
})
}).catch(() => {
this.$info(this.$t('commons.delete_cancel'));
});
},
createApiKey() {
this.result = this.$get("/user/key/generate", response => {
this.$success(this.$t('commons.save_success'));
this.search();
})
},
changeSwitch(row) {
if (row.status === 'ACTIVE') {
this.result = this.$get("/user/key/active/" + row.id, response => {
this.$success(this.$t('commons.save_success'));
});
}
if (row.status === 'DISABLED') {
this.result = this.$get("/user/key/disable/" + row.id, response => {
this.$success(this.$t('commons.save_success'));
});
}
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,334 @@
/**
* Validates a cron expression.
*
* @param cronExpression The expression to validate
* @return True is expression is valid
*/
export function cronValidate(cronExpression ){
//alert("校验函数的开始!");
var cronParams = cronExpression.split(" ");
if (cronParams.length < 6 || cronParams.length > 7) {
return false;
}
//CronTrigger cronTrigger = new CronTrigger();
//cronTrigger.setCronExpression( cronExpression );
if (cronParams[3] == "?" || cronParams[5]=="?") {
//Check seconds param
if (!checkSecondsField(cronParams[0])) {
return false;
}
//Check minutes param
if (!checkMinutesField(cronParams[1])) {
return false;
}
//Check hours param
if (!checkHoursField(cronParams[2])) {
return false;
}
//Check day-of-month param
if (!checkDayOfMonthField(cronParams[3])) {
return false;
}
//Check months param
if (!checkMonthsField(cronParams[4])) {
return false;
}
//Check day-of-week param
if (!checkDayOfWeekField(cronParams[5])) {
return false;
}
//Check year param
if (cronParams.length == 7) {
if (!checkYearField(cronParams[6])) {
return false;
}
}
return true;
} else {
return false;
}
}
function checkSecondsField(secondsField) {
return checkField(secondsField, 0, 59);
}
function checkField(secondsField, minimal, maximal) {
if (secondsField.indexOf("-") > -1 ) {
var startValue = secondsField.substring(0, secondsField.indexOf( "-" ));
var endValue = secondsField.substring(secondsField.indexOf( "-" ) + 1);
if (!(checkIntValue(startValue, minimal, maximal, true) && checkIntValue(endValue, minimal, maximal, true))) {
return false;
}
try {
var startVal = parseInt(startValue, 10);
var endVal = parseInt(endValue, 10);
return endVal > startVal;
} catch (e) {
return false;
}
} else if (secondsField.indexOf(",") > -1) {
return checkListField(secondsField, minimal, maximal);
} else if (secondsField.indexOf( "/" ) > -1) {
return checkIncrementField( secondsField, minimal, maximal );
} else if (secondsField.indexOf( "*" ) != -1) {
return true;
} else {
return checkIntValue(secondsField, minimal, maximal);
}
}
function checkIntValue(value, minimal, maximal, checkExtremity) {
try {
var val = parseInt(value, 10);
//判断是否为整数
if (value == val) {
if (checkExtremity) {
if (val < minimal || val > maximal) {
return false;
}
}
return true;
}
return false;
} catch (e) {
return false;
}
}
function checkMinutesField(minutesField) {
return checkField(minutesField, 0, 59);
}
function checkHoursField(hoursField) {
return checkField(hoursField, 0, 23);
}
function checkDayOfMonthField(dayOfMonthField) {
if (dayOfMonthField == "?") {
return true;
}
if (dayOfMonthField.indexOf("L") >= 0) {
return checkFieldWithLetter(dayOfMonthField, "L", 1, 7, -1, -1);
} else if ( dayOfMonthField.indexOf("W") >= 0) {
return checkFieldWithLetter(dayOfMonthField, "W", 1, 31, -1, -1);
} else if (dayOfMonthField.indexOf("C") >= 0) {
return checkFieldWithLetter(dayOfMonthField, "C", 1, 31, -1, -1);
} else {
return checkField( dayOfMonthField, 1, 31 );
}
}
function checkMonthsField(monthsField) {
/* monthsField = StringUtils.replace( monthsField, "JAN", "1" );
monthsField = StringUtils.replace( monthsField, "FEB", "2" );
monthsField = StringUtils.replace( monthsField, "MAR", "3" );
monthsField = StringUtils.replace( monthsField, "APR", "4" );
monthsField = StringUtils.replace( monthsField, "MAY", "5" );
monthsField = StringUtils.replace( monthsField, "JUN", "6" );
monthsField = StringUtils.replace( monthsField, "JUL", "7" );
monthsField = StringUtils.replace( monthsField, "AUG", "8" );
monthsField = StringUtils.replace( monthsField, "SEP", "9" );
monthsField = StringUtils.replace( monthsField, "OCT", "10" );
monthsField = StringUtils.replace( monthsField, "NOV", "11" );
monthsField = StringUtils.replace( monthsField, "DEC", "12" );*/
monthsField.replace("JAN", "1");
monthsField.replace("FEB", "2");
monthsField.replace("MAR", "3");
monthsField.replace("APR", "4");
monthsField.replace("MAY", "5");
monthsField.replace("JUN", "6");
monthsField.replace("JUL", "7");
monthsField.replace("AUG", "8");
monthsField.replace("SEP", "9");
monthsField.replace("OCT", "10");
monthsField.replace("NOV", "11");
monthsField.replace("DEC", "12");
return checkField(monthsField, 1, 31);
}
function checkDayOfWeekField(dayOfWeekField) {
/* dayOfWeekField = StringUtils.replace( dayOfWeekField, "SUN", "1" );
dayOfWeekField = StringUtils.replace( dayOfWeekField, "MON", "2" );
dayOfWeekField = StringUtils.replace( dayOfWeekField, "TUE", "3" );
dayOfWeekField = StringUtils.replace( dayOfWeekField, "WED", "4" );
dayOfWeekField = StringUtils.replace( dayOfWeekField, "THU", "5" );
dayOfWeekField = StringUtils.replace( dayOfWeekField, "FRI", "6" );
dayOfWeekField = StringUtils.replace( dayOfWeekField, "SAT", "7" );*/
dayOfWeekField.replace("SUN", "1" );
dayOfWeekField.replace("MON", "2" );
dayOfWeekField.replace("TUE", "3" );
dayOfWeekField.replace("WED", "4" );
dayOfWeekField.replace("THU", "5" );
dayOfWeekField.replace("FRI", "6" );
dayOfWeekField.replace("SAT", "7" );
if (dayOfWeekField == "?") {
return true;
}
if (dayOfWeekField.indexOf("L") >= 0) {
return checkFieldWithLetter(dayOfWeekField, "L", 1, 7, -1, -1);
} else if (dayOfWeekField.indexOf("C") >= 0) {
return checkFieldWithLetter(dayOfWeekField, "C", 1, 7, -1, -1);
} else if (dayOfWeekField.indexOf("#") >= 0) {
return checkFieldWithLetter(dayOfWeekField, "#", 1, 7, 1, 5);
} else {
return checkField(dayOfWeekField, 1, 7);
}
}
function checkYearField(yearField) {
return checkField(yearField, 1970, 2099);
}
function checkFieldWithLetter(value, letter, minimalBefore, maximalBefore,
minimalAfter, maximalAfter) {
var canBeAlone = false;
var canHaveIntBefore = false;
var canHaveIntAfter = false;
var mustHaveIntBefore = false;
var mustHaveIntAfter = false;
if (letter == "L") {
canBeAlone = true;
canHaveIntBefore = true;
canHaveIntAfter = false;
mustHaveIntBefore = false;
mustHaveIntAfter = false;
}
if (letter == "W" || letter == "C") {
canBeAlone = false;
canHaveIntBefore = true;
canHaveIntAfter = false;
mustHaveIntBefore = true;
mustHaveIntAfter = false;
}
if (letter == "#") {
canBeAlone = false;
canHaveIntBefore = true;
canHaveIntAfter = true;
mustHaveIntBefore = true;
mustHaveIntAfter = true;
}
var beforeLetter = "";
var afterLetter = "";
if (value.indexOf(letter) >= 0 ) {
beforeLetter = value.substring( 0, value.indexOf(letter));
}
if (!value.endsWith(letter)) {
afterLetter = value.substring( value.indexOf( letter ) + 1 );
}
if (value.indexOf(letter) >= 0) {
if (letter == value) {
return canBeAlone;
}
if (canHaveIntBefore) {
if (mustHaveIntBefore && beforeLetter.length == 0) {
return false;
}
if (!checkIntValue(beforeLetter, minimalBefore, maximalBefore, true)){
return false;
}
} else {
if (beforeLetter.length > 0 ) {
return false;
}
}
if (canHaveIntAfter) {
if ( mustHaveIntAfter && afterLetter.length == 0 ) {
return false;
}
if (!checkIntValue(afterLetter, minimalAfter, maximalAfter, true)) {
return false;
}
} else {
if (afterLetter.length > 0) {
return false;
}
}
}
return true;
}
/* function checkIntValue(value, minimal, maximal) {
return checkIntValue(value, minimal, maximal, true);
} */
function checkIncrementField(value, minimal, maximal) {
var start = value.substring(0, value.indexOf("/"));
var increment = value.substring(value.indexOf("/") + 1);
if (!("*" == start)) {
return checkIntValue(start, minimal, maximal, true) && checkIntValue(increment, minimal, maximal, false);
} else {
return checkIntValue(increment, minimal, maximal, true);
}
}
function checkListField(value, minimal, maximal ) {
var st = value.split(",");
var values = new Array(st.length);
for(var j = 0; j < st.length; j++) {
values[j] = st[j];
}
var previousValue = -1;
for (var i= 0; i < values.length; i++) {
var currentValue = values[i];
if (!checkIntValue(currentValue, minimal, maximal, true)) {
return false;
}
try {
var val = parseInt(currentValue, 10);
if (val <= previousValue) {
return false;
} else {
previousValue = val;
}
} catch (e) {
// we have always an int
}
}
return true;
}

View File

@ -174,6 +174,7 @@ export default {
'mobile_number_format_is_incorrect': 'Mobile number format is incorrect',
'email_format_is_incorrect': 'Email format is incorrect',
'delete_confirm': 'Are you sure you want to delete this User?',
'apikey_delete_confirm': 'Are you sure you want to delete this API Key?',
'input_id_placeholder': 'Please enter ID (only supports numbers and English letters)'
},
role: {

View File

@ -173,6 +173,7 @@ export default {
'mobile_number_format_is_incorrect': '手机号码格式不正确',
'email_format_is_incorrect': '邮箱格式不正确',
'delete_confirm': '这个用户确定要删除吗?',
'apikey_delete_confirm': '这个 API Key 确定要删除吗?',
'input_id_placeholder': '请输入ID (只支持数字、英文字母)'
},
role: {

View File

@ -171,6 +171,7 @@ export default {
'mobile_number_format_is_incorrect': '手機號碼格式不正確',
'email_format_is_incorrect': '郵箱格式不正確',
'delete_confirm': '這個用戶確定要刪除嗎?',
'apikey_delete_confirm': '這個 API Key 確定要刪除嗎?',
'input_id_placeholder': '請輸入ID (只支持數字、英文字母)'
},
role: {