refact: 解决冲突
This commit is contained in:
commit
5b750fe55f
|
@ -20,7 +20,7 @@ MeterSphere 是一站式的开源企业级持续测试平台,涵盖测试跟
|
|||
|
||||
## UI 展示
|
||||
|
||||
![UI](https://metersphere.io/images/screenshot/ss07.png)
|
||||
![UI](https://metersphere.io/images/screenshot/ss01.png)
|
||||
|
||||
## 在线体验
|
||||
- 环境地址:https://demo.metersphere.com/
|
||||
|
@ -49,6 +49,9 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu
|
|||
- [完整文档](https://metersphere.io/docs/)
|
||||
- [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4)
|
||||
|
||||
## MeterSphere 企业版
|
||||
[申请企业版使用](https://jinshuju.net/f/CzzAOe)
|
||||
|
||||
## 相关工具
|
||||
|
||||
- [Jenkins 插件](https://github.com/metersphere/jenkins-plugin)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TestPlanProject implements Serializable {
|
||||
private String testPlanId;
|
||||
|
||||
private String projectId;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,340 @@
|
|||
package io.metersphere.base.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TestPlanProjectExample {
|
||||
protected String orderByClause;
|
||||
|
||||
protected boolean distinct;
|
||||
|
||||
protected List<Criteria> oredCriteria;
|
||||
|
||||
public TestPlanProjectExample() {
|
||||
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 andTestPlanIdIsNull() {
|
||||
addCriterion("test_plan_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdIsNotNull() {
|
||||
addCriterion("test_plan_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdEqualTo(String value) {
|
||||
addCriterion("test_plan_id =", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdNotEqualTo(String value) {
|
||||
addCriterion("test_plan_id <>", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdGreaterThan(String value) {
|
||||
addCriterion("test_plan_id >", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("test_plan_id >=", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdLessThan(String value) {
|
||||
addCriterion("test_plan_id <", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("test_plan_id <=", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdLike(String value) {
|
||||
addCriterion("test_plan_id like", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdNotLike(String value) {
|
||||
addCriterion("test_plan_id not like", value, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdIn(List<String> values) {
|
||||
addCriterion("test_plan_id in", values, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdNotIn(List<String> values) {
|
||||
addCriterion("test_plan_id not in", values, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdBetween(String value1, String value2) {
|
||||
addCriterion("test_plan_id between", value1, value2, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andTestPlanIdNotBetween(String value1, String value2) {
|
||||
addCriterion("test_plan_id not between", value1, value2, "testPlanId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdIsNull() {
|
||||
addCriterion("project_id is null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdIsNotNull() {
|
||||
addCriterion("project_id is not null");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdEqualTo(String value) {
|
||||
addCriterion("project_id =", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdNotEqualTo(String value) {
|
||||
addCriterion("project_id <>", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdGreaterThan(String value) {
|
||||
addCriterion("project_id >", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
|
||||
addCriterion("project_id >=", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdLessThan(String value) {
|
||||
addCriterion("project_id <", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdLessThanOrEqualTo(String value) {
|
||||
addCriterion("project_id <=", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdLike(String value) {
|
||||
addCriterion("project_id like", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdNotLike(String value) {
|
||||
addCriterion("project_id not like", value, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdIn(List<String> values) {
|
||||
addCriterion("project_id in", values, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdNotIn(List<String> values) {
|
||||
addCriterion("project_id not in", values, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdBetween(String value1, String value2) {
|
||||
addCriterion("project_id between", value1, value2, "projectId");
|
||||
return (Criteria) this;
|
||||
}
|
||||
|
||||
public Criteria andProjectIdNotBetween(String value1, String value2) {
|
||||
addCriterion("project_id not between", value1, value2, "projectId");
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.metersphere.base.mapper;
|
||||
|
||||
import io.metersphere.base.domain.TestPlanProject;
|
||||
import io.metersphere.base.domain.TestPlanProjectExample;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
public interface TestPlanProjectMapper {
|
||||
long countByExample(TestPlanProjectExample example);
|
||||
|
||||
int deleteByExample(TestPlanProjectExample example);
|
||||
|
||||
int insert(TestPlanProject record);
|
||||
|
||||
int insertSelective(TestPlanProject record);
|
||||
|
||||
List<TestPlanProject> selectByExample(TestPlanProjectExample example);
|
||||
|
||||
int updateByExampleSelective(@Param("record") TestPlanProject record, @Param("example") TestPlanProjectExample example);
|
||||
|
||||
int updateByExample(@Param("record") TestPlanProject record, @Param("example") TestPlanProjectExample example);
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
<?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.TestPlanProjectMapper">
|
||||
<resultMap id="BaseResultMap" type="io.metersphere.base.domain.TestPlanProject">
|
||||
<result column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
|
||||
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
|
||||
</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">
|
||||
test_plan_id, project_id
|
||||
</sql>
|
||||
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestPlanProjectExample" resultMap="BaseResultMap">
|
||||
select
|
||||
<if test="distinct">
|
||||
distinct
|
||||
</if>
|
||||
<include refid="Base_Column_List" />
|
||||
from test_plan_project
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
<if test="orderByClause != null">
|
||||
order by ${orderByClause}
|
||||
</if>
|
||||
</select>
|
||||
<delete id="deleteByExample" parameterType="io.metersphere.base.domain.TestPlanProjectExample">
|
||||
delete from test_plan_project
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
</delete>
|
||||
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanProject">
|
||||
insert into test_plan_project (test_plan_id, project_id)
|
||||
values (#{testPlanId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR})
|
||||
</insert>
|
||||
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanProject">
|
||||
insert into test_plan_project
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="testPlanId != null">
|
||||
test_plan_id,
|
||||
</if>
|
||||
<if test="projectId != null">
|
||||
project_id,
|
||||
</if>
|
||||
</trim>
|
||||
<trim prefix="values (" suffix=")" suffixOverrides=",">
|
||||
<if test="testPlanId != null">
|
||||
#{testPlanId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="projectId != null">
|
||||
#{projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
</trim>
|
||||
</insert>
|
||||
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanProjectExample" resultType="java.lang.Long">
|
||||
select count(*) from test_plan_project
|
||||
<if test="_parameter != null">
|
||||
<include refid="Example_Where_Clause" />
|
||||
</if>
|
||||
</select>
|
||||
<update id="updateByExampleSelective" parameterType="map">
|
||||
update test_plan_project
|
||||
<set>
|
||||
<if test="record.testPlanId != null">
|
||||
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
<if test="record.projectId != null">
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR},
|
||||
</if>
|
||||
</set>
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
<update id="updateByExample" parameterType="map">
|
||||
update test_plan_project
|
||||
set test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
|
||||
project_id = #{record.projectId,jdbcType=VARCHAR}
|
||||
<if test="_parameter != null">
|
||||
<include refid="Update_By_Example_Where_Clause" />
|
||||
</if>
|
||||
</update>
|
||||
</mapper>
|
|
@ -11,6 +11,7 @@ import io.metersphere.commons.utils.SessionUtils;
|
|||
import io.metersphere.dto.LogDetailDTO;
|
||||
import io.metersphere.dto.ReportDTO;
|
||||
import io.metersphere.performance.base.*;
|
||||
import io.metersphere.performance.controller.request.DeleteReportRequest;
|
||||
import io.metersphere.performance.controller.request.ReportRequest;
|
||||
import io.metersphere.performance.service.ReportService;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
|
@ -113,4 +114,9 @@ public class PerformanceReportController {
|
|||
public void downloadLog(@PathVariable String reportId, @PathVariable String resourceId, HttpServletResponse response) throws Exception {
|
||||
reportService.downloadLog(response, reportId, resourceId);
|
||||
}
|
||||
|
||||
@PostMapping("/batch/delete")
|
||||
public void deleteReportBatch(@RequestBody DeleteReportRequest reportRequest) {
|
||||
reportService.deleteReportBatch(reportRequest);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package io.metersphere.performance.controller.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class DeleteReportRequest {
|
||||
|
||||
private List<String> ids;
|
||||
}
|
|
@ -14,6 +14,7 @@ import io.metersphere.controller.request.OrderRequest;
|
|||
import io.metersphere.dto.LogDetailDTO;
|
||||
import io.metersphere.dto.ReportDTO;
|
||||
import io.metersphere.performance.base.*;
|
||||
import io.metersphere.performance.controller.request.DeleteReportRequest;
|
||||
import io.metersphere.performance.controller.request.ReportRequest;
|
||||
import io.metersphere.performance.engine.Engine;
|
||||
import io.metersphere.performance.engine.EngineFactory;
|
||||
|
@ -72,18 +73,22 @@ public class ReportService {
|
|||
|
||||
LogUtil.info("Delete report started, report ID: %s" + reportId);
|
||||
|
||||
final Engine engine = EngineFactory.createEngine(loadTest);
|
||||
if (engine == null) {
|
||||
MSException.throwException(String.format("Delete report fail. create engine fail,report ID:%s", reportId));
|
||||
}
|
||||
try {
|
||||
final Engine engine = EngineFactory.createEngine(loadTest);
|
||||
if (engine == null) {
|
||||
MSException.throwException(String.format("Delete report fail. create engine fail,report ID:%s", reportId));
|
||||
}
|
||||
|
||||
String reportStatus = loadTestReport.getStatus();
|
||||
boolean isRunning = StringUtils.equals(reportStatus, PerformanceTestStatus.Running.name());
|
||||
boolean isStarting = StringUtils.equals(reportStatus, PerformanceTestStatus.Starting.name());
|
||||
boolean isError = StringUtils.equals(reportStatus, PerformanceTestStatus.Error.name());
|
||||
if (isRunning || isStarting || isError) {
|
||||
LogUtil.info("Start stop engine, report status: %s" + reportStatus);
|
||||
stopEngine(loadTest, engine);
|
||||
String reportStatus = loadTestReport.getStatus();
|
||||
boolean isRunning = StringUtils.equals(reportStatus, PerformanceTestStatus.Running.name());
|
||||
boolean isStarting = StringUtils.equals(reportStatus, PerformanceTestStatus.Starting.name());
|
||||
boolean isError = StringUtils.equals(reportStatus, PerformanceTestStatus.Error.name());
|
||||
if (isRunning || isStarting || isError) {
|
||||
LogUtil.info("Start stop engine, report status: %s" + reportStatus);
|
||||
stopEngine(loadTest, engine);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
// delete load_test_report_result
|
||||
|
@ -246,4 +251,9 @@ public class ReportService {
|
|||
report.setStatus(status);
|
||||
loadTestReportMapper.updateByPrimaryKeySelective(report);
|
||||
}
|
||||
|
||||
public void deleteReportBatch(DeleteReportRequest reportRequest) {
|
||||
List<String> ids = reportRequest.getIds();
|
||||
ids.forEach(this::deleteReport);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
create table if not exists test_plan_project
|
||||
(
|
||||
test_plan_id varchar(50) null,
|
||||
project_id varchar(50) null,
|
||||
constraint test_plan_project_pk
|
||||
unique (test_plan_id, project_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
insert into test_plan_project(test_plan_id, project_id) select id test_plan_id, project_id project_id from test_plan;
|
|
@ -1,104 +1,110 @@
|
|||
<template>
|
||||
<div class="schedule-config">
|
||||
<div>
|
||||
<div class="schedule-config">
|
||||
<div>
|
||||
<span class="cron-ico" @click="scheduleEdit">
|
||||
<i class="el-icon-date" size="small"></i>
|
||||
<span class="character">SCHEDULER</span>
|
||||
</span>
|
||||
<el-switch :disabled="!schedule.value || isReadOnly" v-model="schedule.enable" @change="scheduleChange"/>
|
||||
<ms-schedule-edit :is-read-only="isReadOnly" :schedule="schedule" :save="save" :custom-validate="customValidate" ref="scheduleEdit"/>
|
||||
<el-switch :disabled="!schedule.value || isReadOnly" v-model="schedule.enable" @change="scheduleChange"/>
|
||||
<ms-schedule-edit :is-read-only="isReadOnly" :schedule="schedule" :save="save" :custom-validate="customValidate"
|
||||
ref="scheduleEdit"/>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
<div>
|
||||
<span>
|
||||
{{$t('schedule.next_execution_time')}}:
|
||||
<span :class="{'disable-character': !schedule.enable}" v-if="!schedule.enable">{{$t('schedule.not_set')}}</span>
|
||||
{{ $t('schedule.next_execution_time') }}:
|
||||
<span :class="{'disable-character': !schedule.enable}"
|
||||
v-if="!schedule.enable">{{ $t('schedule.not_set') }}</span>
|
||||
<crontab-result v-if="schedule.enable" :enable-simple-mode="true" :ex="schedule.value" ref="crontabResult"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MsScheduleEdit from "./MsScheduleEdit";
|
||||
import CrontabResult from "../cron/CrontabResult";
|
||||
import MsScheduleEdit from "./MsScheduleEdit";
|
||||
import CrontabResult from "../cron/CrontabResult";
|
||||
|
||||
function defaultCustomValidate() {return {pass: true};}
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "MsScheduleConfig",
|
||||
components: {CrontabResult, MsScheduleEdit},
|
||||
data() {
|
||||
export default {
|
||||
name: "MsScheduleConfig",
|
||||
components: {CrontabResult, MsScheduleEdit},
|
||||
data() {
|
||||
return {
|
||||
recentList: [],
|
||||
}
|
||||
},
|
||||
props: {
|
||||
save: Function,
|
||||
schedule: {},
|
||||
checkOpen: {
|
||||
type: Function,
|
||||
default() {
|
||||
return {
|
||||
recentList: [],
|
||||
}
|
||||
},
|
||||
props: {
|
||||
save: Function,
|
||||
schedule: {},
|
||||
checkOpen: {
|
||||
type: Function,
|
||||
default() {
|
||||
return {
|
||||
checkOpen() {return true;}
|
||||
}
|
||||
checkOpen() {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scheduleEdit() {
|
||||
if (!this.checkOpen()) {
|
||||
return;
|
||||
}
|
||||
this.$refs.scheduleEdit.open();
|
||||
},
|
||||
scheduleChange() {
|
||||
this.$emit('scheduleChange');
|
||||
},
|
||||
flashResultList() {
|
||||
this.$refs.crontabResult.expressionChange();
|
||||
}
|
||||
}
|
||||
},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
scheduleEdit() {
|
||||
if (!this.checkOpen()) {
|
||||
return;
|
||||
}
|
||||
this.$refs.scheduleEdit.open();
|
||||
},
|
||||
scheduleChange() {
|
||||
this.$emit('scheduleChange');
|
||||
},
|
||||
flashResultList() {
|
||||
this.$refs.crontabResult.expressionChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.schedule-config {
|
||||
float: right;
|
||||
width: 250px;
|
||||
height: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
.schedule-config {
|
||||
float: right;
|
||||
width: 250px;
|
||||
height: 15px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.el-icon-date {
|
||||
font-size: 20px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.el-icon-date {
|
||||
font-size: 20px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.character {
|
||||
font-weight: bold;
|
||||
margin: 0 5px;
|
||||
}
|
||||
.character {
|
||||
font-weight: bold;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.disable-character {
|
||||
color: #cccccc;
|
||||
}
|
||||
.disable-character {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.el-switch {
|
||||
margin: 0 5px;
|
||||
}
|
||||
.el-switch {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.cron-ico {
|
||||
cursor: pointer;
|
||||
}
|
||||
.cron-ico {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -92,147 +92,147 @@
|
|||
|
||||
<script>
|
||||
|
||||
import Crontab from "../cron/Crontab";
|
||||
import CrontabResult from "../cron/CrontabResult";
|
||||
import {cronValidate} from "../../../../common/js/cron";
|
||||
import {listenGoBack, removeGoBackListener} from "../../../../common/js/utils";
|
||||
import Crontab from "../cron/Crontab";
|
||||
import CrontabResult from "../cron/CrontabResult";
|
||||
import {cronValidate} from "@/common/js/cron";
|
||||
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
|
||||
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
function defaultCustomValidate() {
|
||||
return {pass: true};
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "MsScheduleEdit",
|
||||
components: {CrontabResult, Crontab},
|
||||
props: {
|
||||
save: Function,
|
||||
schedule: {},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
export default {
|
||||
name: "MsScheduleEdit",
|
||||
components: {CrontabResult, Crontab},
|
||||
props: {
|
||||
save: Function,
|
||||
schedule: {},
|
||||
customValidate: {
|
||||
type: Function,
|
||||
default: defaultCustomValidate
|
||||
},
|
||||
watch: {
|
||||
'schedule.value'() {
|
||||
this.form.cronValue = this.schedule.value;
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'schedule.value'() {
|
||||
this.form.cronValue = this.schedule.value;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const validateCron = (rule, cronValue, callback) => {
|
||||
let customValidate = this.customValidate(this.getIntervalTime());
|
||||
if (!cronValue) {
|
||||
callback(new Error(this.$t('commons.input_content')));
|
||||
} else if (!cronValidate(cronValue)) {
|
||||
callback(new Error(this.$t('schedule.cron_expression_format_error')));
|
||||
}
|
||||
},
|
||||
data() {
|
||||
const validateCron = (rule, cronValue, callback) => {
|
||||
let customValidate = this.customValidate(this.getIntervalTime());
|
||||
if (!cronValue) {
|
||||
callback(new Error(this.$t('commons.input_content')));
|
||||
} else if (!cronValidate(cronValue)) {
|
||||
callback(new Error(this.$t('schedule.cron_expression_format_error')));
|
||||
}
|
||||
// else if(!this.intervalShortValidate()) {
|
||||
// callback(new Error(this.$t('schedule.cron_expression_interval_short_error')));
|
||||
// }
|
||||
else if (!customValidate.pass) {
|
||||
callback(new Error(customValidate.info));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
operation: true,
|
||||
dialogVisible: false,
|
||||
showCron: false,
|
||||
form: {
|
||||
cronValue: ""
|
||||
},
|
||||
tableData: [
|
||||
{
|
||||
event: '执行成功',
|
||||
receiver: '',
|
||||
email: '',
|
||||
operation: 1
|
||||
}, {
|
||||
event: '执行成功',
|
||||
receiver: '',
|
||||
email: '',
|
||||
operation: 2
|
||||
}
|
||||
],
|
||||
email: "",
|
||||
enable: true,
|
||||
activeName: 'first',
|
||||
rules: {
|
||||
cronValue: [{required: true, validator: validateCron, trigger: 'blur'}],
|
||||
}
|
||||
// else if(!this.intervalShortValidate()) {
|
||||
// callback(new Error(this.$t('schedule.cron_expression_interval_short_error')));
|
||||
// }
|
||||
else if (!customValidate.pass) {
|
||||
callback(new Error(customValidate.info));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
|
||||
};
|
||||
return {
|
||||
operation: true,
|
||||
dialogVisible: false,
|
||||
showCron: false,
|
||||
form: {
|
||||
cronValue: ""
|
||||
},
|
||||
open() {
|
||||
this.dialogVisible = true;
|
||||
this.form.cronValue = this.schedule.value;
|
||||
listenGoBack(this.close);
|
||||
},
|
||||
crontabFill(value, resultList) {
|
||||
//确定后回传的值
|
||||
this.form.cronValue = value;
|
||||
this.$refs.crontabResult.resultList = resultList;
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
showCronDialog() {
|
||||
this.showCron = true;
|
||||
},
|
||||
saveCron() {
|
||||
this.$refs['from'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.intervalShortValidate();
|
||||
this.save(this.form.cronValue);
|
||||
this.dialogVisible = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
close() {
|
||||
this.dialogVisible = false;
|
||||
this.form.cronValue = '';
|
||||
this.$refs['from'].resetFields();
|
||||
if (!this.schedule.value) {
|
||||
this.$refs.crontabResult.resultList = [];
|
||||
tableData: [
|
||||
{
|
||||
event: '执行成功',
|
||||
receiver: '',
|
||||
email: '',
|
||||
operation: 1
|
||||
}, {
|
||||
event: '执行成功',
|
||||
receiver: '',
|
||||
email: '',
|
||||
operation: 2
|
||||
}
|
||||
removeGoBackListener(this.close);
|
||||
},
|
||||
intervalShortValidate() {
|
||||
if (this.getIntervalTime() < 3 * 60 * 1000) {
|
||||
// return false;
|
||||
this.$info(this.$t('schedule.cron_expression_interval_short_error'));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
resultListChange() {
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
getIntervalTime() {
|
||||
let resultList = this.$refs.crontabResult.resultList;
|
||||
let time1 = new Date(resultList[0]);
|
||||
let time2 = new Date(resultList[1]);
|
||||
return time2 - time1;
|
||||
],
|
||||
email: "",
|
||||
enable: true,
|
||||
activeName: 'first',
|
||||
rules: {
|
||||
cronValue: [{required: true, validator: validateCron, trigger: 'blur'}],
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
|
||||
},
|
||||
open() {
|
||||
this.dialogVisible = true;
|
||||
this.form.cronValue = this.schedule.value;
|
||||
listenGoBack(this.close);
|
||||
},
|
||||
crontabFill(value, resultList) {
|
||||
//确定后回传的值
|
||||
this.form.cronValue = value;
|
||||
this.$refs.crontabResult.resultList = resultList;
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
showCronDialog() {
|
||||
this.showCron = true;
|
||||
},
|
||||
saveCron() {
|
||||
this.$refs['from'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.intervalShortValidate();
|
||||
this.save(this.form.cronValue);
|
||||
this.dialogVisible = false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
close() {
|
||||
this.dialogVisible = false;
|
||||
this.form.cronValue = '';
|
||||
this.$refs['from'].resetFields();
|
||||
if (!this.schedule.value) {
|
||||
this.$refs.crontabResult.resultList = [];
|
||||
}
|
||||
removeGoBackListener(this.close);
|
||||
},
|
||||
intervalShortValidate() {
|
||||
if (this.getIntervalTime() < 3 * 60 * 1000) {
|
||||
// return false;
|
||||
this.$info(this.$t('schedule.cron_expression_interval_short_error'));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
resultListChange() {
|
||||
this.$refs['from'].validate();
|
||||
},
|
||||
getIntervalTime() {
|
||||
let resultList = this.$refs.crontabResult.resultList;
|
||||
let time1 = new Date(resultList[0]);
|
||||
let time2 = new Date(resultList[1]);
|
||||
return time2 - time1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.inp {
|
||||
width: 50%;
|
||||
margin-right: 20px;
|
||||
}
|
||||
.inp {
|
||||
width: 50%;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.el-form-item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -9,9 +9,18 @@
|
|||
</template>
|
||||
|
||||
<el-table border :data="tableData" class="adjust-table test-content"
|
||||
@select-all="handleSelectAll"
|
||||
@select="handleSelect"
|
||||
@sort-change="sort"
|
||||
@filter-change="filter"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"/>
|
||||
<el-table-column width="40" :resizable="false" align="center">
|
||||
<template v-slot:default="scope">
|
||||
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
:label="$t('commons.name')"
|
||||
|
@ -89,13 +98,19 @@ import ReportTriggerModeItem from "../../common/tableItem/ReportTriggerModeItem"
|
|||
import {REPORT_CONFIGS} from "../../common/components/search/search-components";
|
||||
import MsTableHeader from "../../common/components/MsTableHeader";
|
||||
import {LIST_CHANGE, PerformanceEvent} from "@/business/components/common/head/ListEvent";
|
||||
import ShowMoreBtn from "../../track/case/components/ShowMoreBtn";
|
||||
|
||||
export default {
|
||||
name: "PerformanceTestReport",
|
||||
components: {
|
||||
MsTableHeader,
|
||||
ReportTriggerModeItem,
|
||||
MsTableOperatorButton, MsPerformanceReportStatus, MsTablePagination, MsContainer, MsMainContainer
|
||||
MsTableOperatorButton,
|
||||
MsPerformanceReportStatus,
|
||||
MsTablePagination,
|
||||
MsContainer,
|
||||
MsMainContainer,
|
||||
ShowMoreBtn,
|
||||
},
|
||||
created: function () {
|
||||
this.initTableData();
|
||||
|
@ -128,6 +143,12 @@ export default {
|
|||
{text: '定时任务', value: 'SCHEDULE'},
|
||||
{text: 'API', value: 'API'}
|
||||
],
|
||||
buttons: [
|
||||
{
|
||||
name: this.$t('report.batch_delete'), handleClick: this.handleBatchDelete
|
||||
}
|
||||
],
|
||||
selectRows: new Set(),
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
@ -194,6 +215,60 @@ export default {
|
|||
_filter(filters, this.condition);
|
||||
this.initTableData();
|
||||
},
|
||||
handleSelect(selection, row) {
|
||||
if (this.selectRows.has(row)) {
|
||||
this.$set(row, "showMore", false);
|
||||
this.selectRows.delete(row);
|
||||
} else {
|
||||
this.$set(row, "showMore", true);
|
||||
this.selectRows.add(row);
|
||||
}
|
||||
|
||||
let arr = Array.from(this.selectRows);
|
||||
|
||||
// 选中1个以上的用例时显示更多操作
|
||||
if (this.selectRows.size === 1) {
|
||||
this.$set(arr[0], "showMore", false);
|
||||
} else if (this.selectRows.size === 2) {
|
||||
arr.forEach(row => {
|
||||
this.$set(row, "showMore", true);
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSelectAll(selection) {
|
||||
if (selection.length > 0) {
|
||||
if (selection.length === 1) {
|
||||
this.selectRows.add(selection[0]);
|
||||
} else {
|
||||
this.tableData.forEach(item => {
|
||||
this.$set(item, "showMore", true);
|
||||
this.selectRows.add(item);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.selectRows.clear();
|
||||
this.tableData.forEach(row => {
|
||||
this.$set(row, "showMore", false);
|
||||
})
|
||||
}
|
||||
},
|
||||
handleBatchDelete() {
|
||||
this.$alert(this.$t('report.delete_batch_confirm') + "?", '', {
|
||||
confirmButtonText: this.$t('commons.confirm'),
|
||||
callback: (action) => {
|
||||
if (action === 'confirm') {
|
||||
let ids = Array.from(this.selectRows).map(row => row.id);
|
||||
this.result = this.$post('/performance/report/batch/delete', {ids: ids}, () => {
|
||||
this.selectRows.clear();
|
||||
this.$success(this.$t('commons.delete_success'));
|
||||
this.search();
|
||||
// 发送广播,刷新 head 上的最新列表
|
||||
PerformanceEvent.$emit(LIST_CHANGE);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -301,6 +301,8 @@ export default {
|
|||
force_stop_btn: 'Terminating',
|
||||
stop_btn: 'Graceful shutdown',
|
||||
not_exist: "Test report does not exist",
|
||||
batch_delete: "Delete reports in bulk",
|
||||
delete_batch_confirm: 'Confirm batch delete report',
|
||||
},
|
||||
load_test: {
|
||||
same_project_test: 'Only tests within the same project can be run',
|
||||
|
|
|
@ -301,6 +301,8 @@ export default {
|
|||
force_stop_btn: '强制停止',
|
||||
stop_btn: '停止',
|
||||
not_exist: "测试报告不存在",
|
||||
batch_delete: "批量删除报告",
|
||||
delete_batch_confirm: '确认批量删除报告',
|
||||
},
|
||||
load_test: {
|
||||
same_project_test: '只能运行同一项目内的测试',
|
||||
|
|
|
@ -300,6 +300,8 @@ export default {
|
|||
force_stop_btn: '強制停止',
|
||||
stop_btn: '停止',
|
||||
not_exist: "測試報告不存在",
|
||||
batch_delete: "批量刪除報告",
|
||||
delete_batch_confirm: '確認批量刪除報告',
|
||||
},
|
||||
load_test: {
|
||||
same_project_test: '只能運行同一項目內的測試',
|
||||
|
|
Loading…
Reference in New Issue