Merge remote-tracking branch 'origin/master'

This commit is contained in:
Captain.B 2021-03-05 17:43:48 +08:00
commit 0bd3d0355b
36 changed files with 516 additions and 187 deletions

View File

@ -13,4 +13,9 @@ public class ApiScenarioDTO extends ApiScenarioWithBLOBs {
private String projectName;
private String userName;
private List<String> tagNames;
/**
* 场景跨项目ID
*/
private List<String> projectIds;
}

View File

@ -15,6 +15,7 @@ import io.metersphere.api.service.ApiTestEnvironmentService;
import io.metersphere.base.domain.ApiScenarioWithBLOBs;
import io.metersphere.base.domain.ApiTestEnvironmentWithBLOBs;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.ScriptEngineUtils;
import io.metersphere.commons.utils.SessionUtils;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -132,7 +133,7 @@ public class MsScenario extends MsTestElement {
// 场景变量和环境变量
Arguments arguments = arguments(config);
if (arguments != null) {
tree.add(arguments);
tree.add(config.valueSupposeMock(arguments));
}
this.addCsvDataSet(tree, variables);
this.addCounter(tree, variables);

View File

@ -2,7 +2,9 @@ package io.metersphere.api.dto.definition.request;
import io.metersphere.api.dto.definition.request.variable.ScenarioVariable;
import io.metersphere.api.dto.scenario.environment.EnvironmentConfig;
import io.metersphere.commons.utils.ScriptEngineUtils;
import lombok.Data;
import org.apache.jmeter.config.Arguments;
import java.util.List;
import java.util.Map;
@ -37,4 +39,13 @@ public class ParameterConfig {
}
return false;
}
static public Arguments valueSupposeMock(Arguments arguments) {
for(int i = 0; i < arguments.getArguments().size(); ++i) {
String argValue = arguments.getArgument(i).getValue();
arguments.getArgument(i).setValue(ScriptEngineUtils.calculate(argValue));
}
return arguments;
}
}

View File

@ -122,7 +122,7 @@ public class MsHTTPSamplerProxy extends MsTestElement {
// 添加环境中的公共变量
Arguments arguments = this.addArguments(config);
if (arguments != null) {
tree.add(arguments);
tree.add(config.valueSupposeMock(arguments));
}
try {
if (config.isEffective(this.getProjectId())) {

View File

@ -654,24 +654,29 @@ public class ApiAutomationService {
}
public void relevance(ApiCaseRelevanceRequest request) {
List<String> ids = request.getSelectIds();
if (CollectionUtils.isEmpty(ids)) {
Map<String, List<String>> mapping = request.getMapping();
Map<String, String> envMap = request.getEnvMap();
Set<String> set = mapping.keySet();
if (set.isEmpty()) {
return;
}
List<ApiScenario> apiScenarios = selectByIds(ids);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ExtTestPlanScenarioCaseMapper batchMapper = sqlSession.getMapper(ExtTestPlanScenarioCaseMapper.class);
apiScenarios.forEach(scenario -> {
set.forEach(id -> {
Map<String, String> newEnvMap = new HashMap<>(16);
if (envMap != null && !envMap.isEmpty()) {
List<String> list = mapping.get(id);
list.forEach(l -> {
newEnvMap.put(l, envMap.get(l));
});
}
TestPlanApiScenario testPlanApiScenario = new TestPlanApiScenario();
testPlanApiScenario.setId(UUID.randomUUID().toString());
testPlanApiScenario.setApiScenarioId(scenario.getId());
testPlanApiScenario.setApiScenarioId(id);
testPlanApiScenario.setTestPlanId(request.getPlanId());
testPlanApiScenario.setCreateTime(System.currentTimeMillis());
testPlanApiScenario.setUpdateTime(System.currentTimeMillis());
batchMapper.insertIfNotExists(testPlanApiScenario);
testPlanApiScenario.setEnvironment(JSON.toJSONString(newEnvMap));
testPlanApiScenarioMapper.insert(testPlanApiScenario);
});
sqlSession.flushStatements();
}
public List<ApiScenario> selectByIds(List<String> ids) {

View File

@ -22,6 +22,7 @@ import io.metersphere.base.mapper.ext.ExtApiDefinitionExecResultMapper;
import io.metersphere.base.mapper.ext.ExtApiTestCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanApiCaseMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper;
import io.metersphere.commons.constants.TestPlanStatus;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*;
import io.metersphere.i18n.Translator;
@ -49,6 +50,8 @@ import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class ApiTestCaseService {
@Resource
TestPlanMapper testPlanMapper;
@Resource
private ApiTestCaseMapper apiTestCaseMapper;
@Resource
@ -330,6 +333,14 @@ public class ApiTestCaseService {
testPlanApiCase.setUpdateTime(System.currentTimeMillis());
batchMapper.insertIfNotExists(testPlanApiCase);
});
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getPlanId());
if (StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Prepare.name())
|| StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Completed.name())) {
testPlan.setStatus(TestPlanStatus.Underway.name());
testPlan.setActualStartTime(System.currentTimeMillis()); // 将状态更新为进行中时开始时间也要更新
testPlan.setActualEndTime(null);
testPlanMapper.updateByPrimaryKey(testPlan);
}
sqlSession.flushStatements();
}

View File

@ -13,8 +13,6 @@ public class TestPlanApiScenario implements Serializable {
private String status;
private String environmentId;
private Long createTime;
private Long updateTime;
@ -25,5 +23,7 @@ public class TestPlanApiScenario implements Serializable {
private String reportId;
private String environment;
private static final long serialVersionUID = 1L;
}

View File

@ -384,76 +384,6 @@ public class TestPlanApiScenarioExample {
return (Criteria) this;
}
public Criteria andEnvironmentIdIsNull() {
addCriterion("environment_id is null");
return (Criteria) this;
}
public Criteria andEnvironmentIdIsNotNull() {
addCriterion("environment_id is not null");
return (Criteria) this;
}
public Criteria andEnvironmentIdEqualTo(String value) {
addCriterion("environment_id =", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdNotEqualTo(String value) {
addCriterion("environment_id <>", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdGreaterThan(String value) {
addCriterion("environment_id >", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdGreaterThanOrEqualTo(String value) {
addCriterion("environment_id >=", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdLessThan(String value) {
addCriterion("environment_id <", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdLessThanOrEqualTo(String value) {
addCriterion("environment_id <=", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdLike(String value) {
addCriterion("environment_id like", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdNotLike(String value) {
addCriterion("environment_id not like", value, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdIn(List<String> values) {
addCriterion("environment_id in", values, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdNotIn(List<String> values) {
addCriterion("environment_id not in", values, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdBetween(String value1, String value2) {
addCriterion("environment_id between", value1, value2, "environmentId");
return (Criteria) this;
}
public Criteria andEnvironmentIdNotBetween(String value1, String value2) {
addCriterion("environment_id not between", value1, value2, "environmentId");
return (Criteria) this;
}
public Criteria andCreateTimeIsNull() {
addCriterion("create_time is null");
return (Criteria) this;

View File

@ -16,15 +16,21 @@ public interface TestPlanApiScenarioMapper {
int insertSelective(TestPlanApiScenario record);
List<TestPlanApiScenario> selectByExampleWithBLOBs(TestPlanApiScenarioExample example);
List<TestPlanApiScenario> selectByExample(TestPlanApiScenarioExample example);
TestPlanApiScenario selectByPrimaryKey(String id);
int updateByExampleSelective(@Param("record") TestPlanApiScenario record, @Param("example") TestPlanApiScenarioExample example);
int updateByExampleWithBLOBs(@Param("record") TestPlanApiScenario record, @Param("example") TestPlanApiScenarioExample example);
int updateByExample(@Param("record") TestPlanApiScenario record, @Param("example") TestPlanApiScenarioExample example);
int updateByPrimaryKeySelective(TestPlanApiScenario record);
int updateByPrimaryKeyWithBLOBs(TestPlanApiScenario record);
int updateByPrimaryKey(TestPlanApiScenario record);
}

View File

@ -6,13 +6,15 @@
<result column="test_plan_id" jdbcType="VARCHAR" property="testPlanId" />
<result column="api_scenario_id" jdbcType="VARCHAR" property="apiScenarioId" />
<result column="status" jdbcType="VARCHAR" property="status" />
<result column="environment_id" jdbcType="VARCHAR" property="environmentId" />
<result column="create_time" jdbcType="BIGINT" property="createTime" />
<result column="update_time" jdbcType="BIGINT" property="updateTime" />
<result column="pass_rate" jdbcType="VARCHAR" property="passRate" />
<result column="last_result" jdbcType="VARCHAR" property="lastResult" />
<result column="report_id" jdbcType="VARCHAR" property="reportId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.base.domain.TestPlanApiScenario">
<result column="environment" jdbcType="LONGVARCHAR" property="environment" />
</resultMap>
<sql id="Example_Where_Clause">
<where>
<foreach collection="oredCriteria" item="criteria" separator="or">
@ -72,9 +74,28 @@
</where>
</sql>
<sql id="Base_Column_List">
id, test_plan_id, api_scenario_id, `status`, environment_id, create_time, update_time,
pass_rate, last_result, report_id
id, test_plan_id, api_scenario_id, `status`, create_time, update_time, pass_rate,
last_result, report_id
</sql>
<sql id="Blob_Column_List">
environment
</sql>
<select id="selectByExampleWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanApiScenarioExample" resultMap="ResultMapWithBLOBs">
select
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from test_plan_api_scenario
<if test="_parameter != null">
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
<select id="selectByExample" parameterType="io.metersphere.base.domain.TestPlanApiScenarioExample" resultMap="BaseResultMap">
select
<if test="distinct">
@ -89,9 +110,11 @@
order by ${orderByClause}
</if>
</select>
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
<select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="ResultMapWithBLOBs">
select
<include refid="Base_Column_List" />
,
<include refid="Blob_Column_List" />
from test_plan_api_scenario
where id = #{id,jdbcType=VARCHAR}
</select>
@ -107,13 +130,13 @@
</delete>
<insert id="insert" parameterType="io.metersphere.base.domain.TestPlanApiScenario">
insert into test_plan_api_scenario (id, test_plan_id, api_scenario_id,
`status`, environment_id, create_time,
update_time, pass_rate, last_result,
report_id)
`status`, create_time, update_time,
pass_rate, last_result, report_id,
environment)
values (#{id,jdbcType=VARCHAR}, #{testPlanId,jdbcType=VARCHAR}, #{apiScenarioId,jdbcType=VARCHAR},
#{status,jdbcType=VARCHAR}, #{environmentId,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT},
#{updateTime,jdbcType=BIGINT}, #{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR},
#{reportId,jdbcType=VARCHAR})
#{status,jdbcType=VARCHAR}, #{createTime,jdbcType=BIGINT}, #{updateTime,jdbcType=BIGINT},
#{passRate,jdbcType=VARCHAR}, #{lastResult,jdbcType=VARCHAR}, #{reportId,jdbcType=VARCHAR},
#{environment,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.base.domain.TestPlanApiScenario">
insert into test_plan_api_scenario
@ -130,9 +153,6 @@
<if test="status != null">
`status`,
</if>
<if test="environmentId != null">
environment_id,
</if>
<if test="createTime != null">
create_time,
</if>
@ -148,6 +168,9 @@
<if test="reportId != null">
report_id,
</if>
<if test="environment != null">
environment,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
@ -162,9 +185,6 @@
<if test="status != null">
#{status,jdbcType=VARCHAR},
</if>
<if test="environmentId != null">
#{environmentId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
#{createTime,jdbcType=BIGINT},
</if>
@ -180,6 +200,9 @@
<if test="reportId != null">
#{reportId,jdbcType=VARCHAR},
</if>
<if test="environment != null">
#{environment,jdbcType=LONGVARCHAR},
</if>
</trim>
</insert>
<select id="countByExample" parameterType="io.metersphere.base.domain.TestPlanApiScenarioExample" resultType="java.lang.Long">
@ -203,9 +226,6 @@
<if test="record.status != null">
`status` = #{record.status,jdbcType=VARCHAR},
</if>
<if test="record.environmentId != null">
environment_id = #{record.environmentId,jdbcType=VARCHAR},
</if>
<if test="record.createTime != null">
create_time = #{record.createTime,jdbcType=BIGINT},
</if>
@ -221,18 +241,36 @@
<if test="record.reportId != null">
report_id = #{record.reportId,jdbcType=VARCHAR},
</if>
<if test="record.environment != null">
environment = #{record.environment,jdbcType=LONGVARCHAR},
</if>
</set>
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExampleWithBLOBs" parameterType="map">
update test_plan_api_scenario
set id = #{record.id,jdbcType=VARCHAR},
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
api_scenario_id = #{record.apiScenarioId,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pass_rate = #{record.passRate,jdbcType=VARCHAR},
last_result = #{record.lastResult,jdbcType=VARCHAR},
report_id = #{record.reportId,jdbcType=VARCHAR},
environment = #{record.environment,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
</update>
<update id="updateByExample" parameterType="map">
update test_plan_api_scenario
set id = #{record.id,jdbcType=VARCHAR},
test_plan_id = #{record.testPlanId,jdbcType=VARCHAR},
api_scenario_id = #{record.apiScenarioId,jdbcType=VARCHAR},
`status` = #{record.status,jdbcType=VARCHAR},
environment_id = #{record.environmentId,jdbcType=VARCHAR},
create_time = #{record.createTime,jdbcType=BIGINT},
update_time = #{record.updateTime,jdbcType=BIGINT},
pass_rate = #{record.passRate,jdbcType=VARCHAR},
@ -254,9 +292,6 @@
<if test="status != null">
`status` = #{status,jdbcType=VARCHAR},
</if>
<if test="environmentId != null">
environment_id = #{environmentId,jdbcType=VARCHAR},
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=BIGINT},
</if>
@ -272,15 +307,30 @@
<if test="reportId != null">
report_id = #{reportId,jdbcType=VARCHAR},
</if>
<if test="environment != null">
environment = #{environment,jdbcType=LONGVARCHAR},
</if>
</set>
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKeyWithBLOBs" parameterType="io.metersphere.base.domain.TestPlanApiScenario">
update test_plan_api_scenario
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},
api_scenario_id = #{apiScenarioId,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pass_rate = #{passRate,jdbcType=VARCHAR},
last_result = #{lastResult,jdbcType=VARCHAR},
report_id = #{reportId,jdbcType=VARCHAR},
environment = #{environment,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<update id="updateByPrimaryKey" parameterType="io.metersphere.base.domain.TestPlanApiScenario">
update test_plan_api_scenario
set test_plan_id = #{testPlanId,jdbcType=VARCHAR},
api_scenario_id = #{apiScenarioId,jdbcType=VARCHAR},
`status` = #{status,jdbcType=VARCHAR},
environment_id = #{environmentId,jdbcType=VARCHAR},
create_time = #{createTime,jdbcType=BIGINT},
update_time = #{updateTime,jdbcType=BIGINT},
pass_rate = #{passRate,jdbcType=VARCHAR},

View File

@ -134,6 +134,7 @@
</sql>
<select id="list" resultMap="BaseResultMap">
select api_scenario.id, api_scenario.project_id, api_scenario.tags, api_scenario.user_id, api_scenario.num,
api_scenario.scenario_definition,
api_scenario.api_scenario_module_id,api_scenario.module_path, api_scenario.name, api_scenario.level,
api_scenario.status, api_scenario.principal, api_scenario.step_total, api_scenario.follow_people,
api_scenario.last_result,api_scenario.pass_rate,api_scenario.report_id,

View File

@ -17,7 +17,7 @@
<select id="list" resultType="io.metersphere.api.dto.automation.ApiScenarioDTO">
select
t.id, t.environment_id, t.create_time, t.update_time, t.last_result, t.pass_rate, t.report_id,
t.id, t.environment, t.create_time, t.update_time, t.last_result, t.pass_rate, t.report_id, c.scenario_definition,
c.id as case_id, c.project_id, c.user_id,c.api_scenario_module_id, c.module_path, c.name, c.level,
c.status, c.principal, c.step_total, c.follow_people, c.schedule, c.description, c.tags, c.num,
p.name as project_name, p.id as project_id, u.name as user_name

View File

@ -19,6 +19,8 @@ public class TestCaseExcelData {
@ExcelIgnore
private String priority;
@ExcelIgnore
private String tags;
@ExcelIgnore
private String method;
@ExcelIgnore
private String prerequisite;

View File

@ -38,6 +38,11 @@ public class TestCaseExcelDataCn extends TestCaseExcelData {
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}")
private String priority;
@ColumnWidth(50)
@ExcelProperty("标签")
@Length(min = 0, max = 1000)
private String tags;
@NotBlank(message = "{cannot_be_null}")
@ExcelProperty("测试方式")
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")

View File

@ -7,6 +7,7 @@ import io.metersphere.commons.constants.RoleConstants;
import io.metersphere.commons.utils.PageUtils;
import io.metersphere.commons.utils.Pager;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.track.dto.RelevanceScenarioRequest;
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
import io.metersphere.track.service.TestPlanScenarioCaseService;
import org.apache.shiro.authz.annotation.Logical;
@ -53,4 +54,10 @@ public class TestPlanScenarioCaseController {
request.setExecuteType(ExecuteType.Completed.name());
return testPlanScenarioCaseService.run(request);
}
@PostMapping("/batch/update/env")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void batchUpdateEnv(@RequestBody RelevanceScenarioRequest request) {
testPlanScenarioCaseService.batchUpdateEnv(request);
}
}

View File

@ -0,0 +1,23 @@
package io.metersphere.track.dto;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Map;
@Getter
@Setter
public class RelevanceScenarioRequest {
/**
* 环境和项目对应关系
*/
private Map<String, String> envMap;
/**
* 场景用例跨项目的关系
*/
private Map<String, List<String>> mapping;
}

View File

@ -5,6 +5,7 @@ import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Getter
@Setter
@ -25,4 +26,14 @@ public class ApiCaseRelevanceRequest {
* 具体要关联的用例
*/
private List<String> selectIds = new ArrayList<>();
/**
* 项目环境对应关系
*/
private Map<String, String> envMap;
/**
* 用例的环境的对应关系
*/
private Map<String, List<String>> mapping;
}

View File

@ -483,6 +483,7 @@ public class TestCaseService {
data.setType(t.getType());
data.setMethod(t.getMethod());
data.setPrerequisite(t.getPrerequisite());
data.setTags(t.getTags());
if (t.getMethod().equals("manual")) {
String steps = t.getSteps();
String setp = "";

View File

@ -4,7 +4,9 @@ import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.LoadTestMapper;
import io.metersphere.base.mapper.LoadTestReportMapper;
import io.metersphere.base.mapper.TestPlanLoadCaseMapper;
import io.metersphere.base.mapper.TestPlanMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanLoadCaseMapper;
import io.metersphere.commons.constants.TestPlanStatus;
import io.metersphere.controller.request.OrderRequest;
import io.metersphere.performance.request.RunTestPlanRequest;
import io.metersphere.performance.service.PerformanceTestService;
@ -28,7 +30,8 @@ import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class TestPlanLoadCaseService {
@Resource
TestPlanMapper testPlanMapper;
@Resource
private TestPlanLoadCaseMapper testPlanLoadCaseMapper;
@Resource
@ -78,6 +81,14 @@ public class TestPlanLoadCaseService {
t.setUpdateTime(System.currentTimeMillis());
testPlanLoadCaseMapper.insert(t);
});
TestPlan testPlan = testPlanMapper.selectByPrimaryKey(request.getTestPlanId());
if (org.apache.commons.lang3.StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Prepare.name())
|| org.apache.commons.lang3.StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Completed.name())) {
testPlan.setStatus(TestPlanStatus.Underway.name());
testPlan.setActualStartTime(System.currentTimeMillis()); // 将状态更新为进行中时开始时间也要更新
testPlan.setActualEndTime(null);
testPlanMapper.updateByPrimaryKey(testPlan);
}
sqlSession.flushStatements();
}

View File

@ -1,26 +1,25 @@
package io.metersphere.track.service;
import io.metersphere.api.dto.DeleteAPIReportRequest;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.RunScenarioRequest;
import io.metersphere.api.dto.automation.TestPlanScenarioRequest;
import io.metersphere.api.dto.definition.RunDefinitionRequest;
import io.metersphere.api.service.ApiAutomationService;
import io.metersphere.api.service.ApiScenarioReportService;
import io.metersphere.base.domain.TestPlanApiCase;
import io.metersphere.base.domain.TestPlanApiCaseExample;
import io.metersphere.base.domain.TestPlanApiScenario;
import io.metersphere.base.domain.TestPlanApiScenarioExample;
import io.metersphere.base.mapper.TestPlanApiScenarioMapper;
import io.metersphere.base.mapper.ext.ExtTestPlanScenarioCaseMapper;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.track.dto.RelevanceScenarioRequest;
import io.metersphere.track.request.testcase.TestPlanApiCaseBatchRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@ -42,20 +41,37 @@ public class TestPlanScenarioCaseService {
request.setProjectId(null);
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
List<ApiScenarioDTO> apiTestCases = extTestPlanScenarioCaseMapper.list(request);
setApiScenarioProjectIds(apiTestCases);
if (CollectionUtils.isEmpty(apiTestCases)) {
return apiTestCases;
}
return apiTestCases;
}
private void setApiScenarioProjectIds(List<ApiScenarioDTO> list) {
// 如果场景步骤涉及多项目则把涉及到的项目ID保存在projectIds属性
list.forEach(data -> {
String definition = data.getScenarioDefinition();
RunDefinitionRequest d = JSON.parseObject(definition, RunDefinitionRequest.class);
Map<String, String> map = d.getEnvironmentMap();
List<String> idList = new ArrayList<>();
if (map != null) {
Set<String> set = d.getEnvironmentMap().keySet();
idList = new ArrayList<>(set);
} else {
if (org.apache.commons.lang3.StringUtils.isNotBlank(d.getEnvironmentId())) {
idList.add(d.getEnvironmentId());
}
}
data.setProjectIds(idList);
});
}
public List<ApiScenarioDTO> relevanceList(ApiScenarioRequest request) {
// List<String> ids = apiAutomationService.selectIdsNotExistsInPlan(request.getProjectId(), request.getPlanId());
// if (CollectionUtils.isEmpty(ids)) {
// return new ArrayList<>();
// }
// request.setIds(ids);
request.setNotInTestPlan(true);
return apiAutomationService.list(request);
List<ApiScenarioDTO> list = apiAutomationService.list(request);
setApiScenarioProjectIds(list);
return list;
}
public int delete(String id) {
@ -137,4 +153,28 @@ public class TestPlanScenarioCaseService {
example.createCriteria().andApiScenarioIdEqualTo(id);
testPlanApiScenarioMapper.deleteByExample(example);
}
public void batchUpdateEnv(RelevanceScenarioRequest request) {
Map<String, String> envMap = request.getEnvMap();
Map<String, List<String>> mapping = request.getMapping();
Set<String> set = mapping.keySet();
if (set.isEmpty()) { return; }
set.forEach(id -> {
Map<String, String> newEnvMap = new HashMap<>(16);
if (envMap != null && !envMap.isEmpty()) {
List<String> list = mapping.get(id);
list.forEach(l -> {
newEnvMap.put(l, envMap.get(l));
});
}
if (!newEnvMap.isEmpty()) {
TestPlanApiScenario scenario = new TestPlanApiScenario();
scenario.setId(id);
scenario.setEnvironment(JSON.toJSONString(newEnvMap));
testPlanApiScenarioMapper.updateByPrimaryKeySelective(scenario);
}
});
}
}

View File

@ -159,8 +159,8 @@ public class TestPlanService {
public int editTestPlan(TestPlanDTO testPlan) {
checkTestPlanExist(testPlan);
TestPlan res = testPlanMapper.selectByPrimaryKey(testPlan.getId()); // 先查一次库
testPlan.setUpdateTime(System.currentTimeMillis());
if (!res.getStatus().equals(testPlan.getStatus())) { // 若有改变才更新时间
testPlan.setUpdateTime(System.currentTimeMillis());
if (TestPlanStatus.Underway.name().equals(testPlan.getStatus())) {
if (res.getStatus().equals(TestPlanStatus.Prepare.name())) {
testPlan.setActualStartTime(System.currentTimeMillis());
@ -183,7 +183,13 @@ public class TestPlanService {
List<String> userIds = new ArrayList<>();
userIds.add(testPlan.getPrincipal());
AddTestPlanRequest testPlans = new AddTestPlanRequest();
int i = testPlanMapper.updateByPrimaryKeySelective(testPlan); // 更新
int i;
if(testPlan.getName() == null) {// 若是点击该测试计划则仅更新了updateTime其它字段全为null使用updateByPrimaryKeySelective
i = testPlanMapper.updateByPrimaryKeySelective(testPlan);
}
else { // 有修改字段的调用为保证将某些时间置null的情况使用updateByPrimaryKey
i = testPlanMapper.updateByPrimaryKey(testPlan); // 更新
}
if (!StringUtils.isBlank(testPlan.getStatus())) {
BeanUtils.copyBean(testPlans, getTestPlan(testPlan.getId()));
String context = getTestPlanContext(testPlans, NoticeConstants.Event.UPDATE);
@ -412,6 +418,8 @@ public class TestPlanService {
if (StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Prepare.name())
|| StringUtils.equals(testPlan.getStatus(), TestPlanStatus.Completed.name())) {
testPlan.setStatus(TestPlanStatus.Underway.name());
testPlan.setActualStartTime(System.currentTimeMillis()); // 将状态更新为进行中时开始时间也要更新
testPlan.setActualEndTime(null);
testPlanMapper.updateByPrimaryKey(testPlan);
}
}

View File

@ -16,19 +16,16 @@ ALTER TABLE test_resource_pool ADD gc_algo VARCHAR(200) NULL;
-- create tale api_document_share
CREATE TABLE IF NOT EXISTS `api_document_share` (
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Api Document Share Info ID',
`create_time` BIGINT ( 13 ) NOT NULL COMMENT 'Create timestamp',
`create_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`update_time` BIGINT(13) NOT NULL COMMENT 'last visit timestamp',
`share_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'single or batch',
`share_api_id` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'APiDefinition.id (JSONArray format. Order by TreeSet)',
PRIMARY KEY (`id`) USING BTREE,
INDEX `share_type` (`share_type`) USING BTREE,
INDEX `share_api_id` (`share_api_id`(125)) USING BTREE
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci
ROW_FORMAT = Dynamic;
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Api Document Share Info ID',
`create_time` BIGINT ( 13 ) NOT NULL COMMENT 'Create timestamp',
`create_user_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`update_time` BIGINT ( 13 ) NOT NULL COMMENT 'last visit timestamp',
`share_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'single or batch',
`share_api_id` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'APiDefinition.id (JSONArray format. Order by TreeSet)',
PRIMARY KEY (`id`) USING BTREE,
INDEX `share_type`(`share_type`) USING BTREE,
INDEX `share_api_id`(`share_api_id`(125)) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- test_case_review add coloumn
ALTER TABLE test_case_review
@ -47,5 +44,8 @@ alter table test_case
-- test_case_review add column
ALTER TABLE test_case_review ADD tags VARCHAR(2000) NULL;
-- alter test_plan_api_scenario
alter table test_plan_api_scenario change environment_id environment longtext null comment 'Relevance environment';
-- file add sort column
alter table file_metadata add sort int default 0;

View File

@ -34,7 +34,7 @@ edit_load_test_not_found=无法编辑测试,未找到测试:
run_load_test_not_found=无法运行测试,未找到测试:
run_load_test_file_not_found=无法运行测试无法获取测试文件元信息测试ID
run_load_test_file_content_not_found=无法运行测试无法获取测试文件内容测试ID
run_load_test_file_init_error=无法运行测试,请检查当前站点配置
run_load_test_file_init_error=无法运行测试,请前往 [系统设置-系统-系统参数设置] 检查当前站点配置详情见https://metersphere.io/docs/faq/load_test/#url
load_test_is_running=测试正在运行, 请等待
load_test_kafka_invalid=Kafka 不可用,请检查配置
cannot_edit_load_test_running=不能修改正在运行的测试

View File

@ -662,7 +662,7 @@
}
const index = hashTree.findIndex(d => d.resourceId === row.resourceId);
if (index != -1) {
hashTree.splice(index, 0, obj);
hashTree.splice(index+1, 0, obj);
} else {
hashTree.push(obj);
}

View File

@ -1,30 +1,68 @@
<template>
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form">
<el-form-item :label="$t('api_test.variable_name')" prop="name">
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')" ref="nameInput"></el-input>
</el-form-item>
<div>
<el-form :model="editData" label-position="right" label-width="80px" size="small" ref="form">
<el-form-item :label="$t('api_test.variable_name')" prop="name">
<el-input v-model="editData.name" :placeholder="$t('api_test.variable_name')" ref="nameInput"></el-input>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="editData.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
<el-form-item :label="$t('commons.description')" prop="description">
<el-input class="ms-http-textarea"
v-model="editData.description"
type="textarea"
:autosize="{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
<el-form-item :label="$t('api_test.value')" prop="value">
<el-input v-model="editData.value" :placeholder="$t('api_test.value')"></el-input>
</el-form-item>
</el-form>
<el-form-item :label="$t('api_test.value')" prop="value">
<el-col class="item">
<el-autocomplete
size="small"
:placeholder="$t('api_test.value')"
style="width: 100%;"
v-model="editData.value"
value-key="name"
:fetch-suggestions="funcSearch"
highlight-first-item>
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced"></i>
</el-autocomplete>
</el-col>
</el-form-item>
</el-form>
<ms-api-variable-advance ref="variableAdvance"/>
</div>
</template>
<script>
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
import MsApiVariableAdvance from "../../../test/components/ApiVariableAdvance";
export default {
name: "MsEditConstant",
components: {},
components: {MsApiVariableAdvance},
props: {
editData: {},
},
methods: {
advanced() {
this.$refs.variableAdvance.open();
},
createFilter(queryString) {
return (variable) => {
return (variable.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
funcFilter(queryString) {
return (func) => {
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
};
},
funcSearch(queryString, cb) {
let funcs = MOCKJS_FUNC.concat(JMETER_FUNC);
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
// callback
cb(results);
},
},
created() {
this.$nextTick(() => {
this.$refs.nameInput.focus();

View File

@ -124,18 +124,22 @@ export default {
},
scheduleChange(){
let flag = this.schedule.enable;
this.$confirm(this.$t('api_test.home_page.running_task_list.confirm.close_title'), this.$t('commons.prompt'), {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
type: 'warning'
}).then(() => {
let param = {};
param.taskID = this.schedule.id;
param.enable = flag;
let param = {};
param.taskID = this.schedule.id;
param.enable = flag;
if(flag == false) {
this.$confirm(this.$t('api_test.home_page.running_task_list.confirm.close_title'), this.$t('commons.prompt'), {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
type: 'warning'
}).then(() => {
this.updateTask(param);
}).catch(() => {
});
}
else {
this.updateTask(param);
}).catch(() => {
});
}
},
updateTask(param){
this.result = this.$post('/api/schedule/updateEnableByPrimyKey', param, response => {

View File

@ -3,6 +3,15 @@
<span class="kv-description" v-if="description">
{{ description }}
</span>
<el-dropdown>
<span class="el-dropdown-link">
全选/反选<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="selectAll">全选</el-dropdown-item>
<el-dropdown-item @click.native="invertSelect">反选</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class="kv-row item" v-for="(item, index) in items" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col class="kv-checkbox" v-if="isShowEnable">
@ -19,7 +28,7 @@
<el-input v-if="!suggestions" :disabled="isReadOnly" v-model="item.name" size="small" maxlength="200"
@change="change"
:placeholder="keyText" show-word-limit/>
<el-autocomplete :disabled="isReadOnly" :maxlength="200" v-if="suggestions" v-model="item.name" size="small"
<el-autocomplete :disabled="isReadOnly" :maxlength="400" v-if="suggestions" v-model="item.name" size="small"
:fetch-suggestions="querySearch" @change="change" :placeholder="keyText"
show-word-limit/>
@ -138,6 +147,16 @@
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
selectAll() {
this.items.forEach(item => {
item.enable = true;
});
},
invertSelect() {
this.items.forEach(item => {
item.enable = !item.enable;
});
},
},
created() {
if (this.items.length === 0 || this.items[this.items.length - 1].name) {

View File

@ -15,8 +15,15 @@
:placeholder="$t('api_test.variable_name')" show-word-limit/>
</el-col>
<el-col>
<el-input :disabled="isReadOnly" v-model="item.value" size="small" @change="change"
:placeholder="$t('api_test.value')" show-word-limit/>
<el-autocomplete
size="small"
v-model="item.value"
:fetch-suggestions="funcSearch"
:placeholder="$t('api_test.value')"
value-key="name"
highlight-first-item>
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced"></i>
</el-autocomplete>
</el-col>
<el-col>
<el-input v-model="item.description" size="small" maxlength="200"
@ -33,16 +40,19 @@
</el-col>
</el-row>
</div>
<ms-api-variable-advance ref="variableAdvance"/>
</div>
</template>
<script>
import {KeyValue} from "../model/ApiTestModel";
import MsApiVariableInput from "./ApiVariableInput";
import {JMETER_FUNC, MOCKJS_FUNC} from "@/common/js/constants";
import MsApiVariableAdvance from "../../test/components/ApiVariableAdvance";
export default {
name: "MsApiScenarioVariables",
components: {MsApiVariableInput},
components: {MsApiVariableInput, MsApiVariableAdvance},
props: {
description: String,
items: Array,
@ -94,7 +104,26 @@
},
isDisable: function (index) {
return this.items.length - 1 === index;
}
},
advanced() {
this.$refs.variableAdvance.open();
},
createFilter(queryString) {
return (variable) => {
return (variable.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
};
},
funcFilter(queryString) {
return (func) => {
return (func.name.toLowerCase().indexOf(queryString.toLowerCase()) > -1);
};
},
funcSearch(queryString, cb) {
let funcs = MOCKJS_FUNC.concat(JMETER_FUNC);
let results = queryString ? funcs.filter(this.funcFilter(queryString)) : funcs;
// callback
cb(results);
},
},
created() {

View File

@ -3,7 +3,15 @@
<span class="kv-description" v-if="description">
{{ description }}
</span>
<el-dropdown>
<span class="el-dropdown-link">
全选/反选<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native="selectAll">全选</el-dropdown-item>
<el-dropdown-item @click.native="invertSelect">反选</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class="item kv-row" v-for="(item, index) in parameters" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col class="kv-checkbox" v-if="isShowEnable">
@ -220,6 +228,16 @@
item.contentType = 'text/plain';
}
},
selectAll() {
this.parameters.forEach(item => {
item.enable = true;
});
},
invertSelect() {
this.parameters.forEach(item => {
item.enable = !item.enable;
});
},
},
created() {
if (this.parameters.length === 0 || this.parameters[this.parameters.length - 1].name) {

View File

@ -1,6 +1,6 @@
<template>
<div class="variable-input">
<el-input class="el-input__inner_pd" :disabled="isReadOnly" :value="value" v-bind="$attrs" :size="size" @change="change" @input="input"/>
<el-input :disabled="isReadOnly" :value="value" v-bind="$attrs" :size="size" @change="change" @input="input"/>
<div :class="{'hidden': !showVariable}" class="variable-combine" v-if="value">
<div v-if="showCopy" class="variable">{{variable}}</div>
<el-tooltip v-if="showCopy" :content="$t('api_test.copied')" manual v-model="visible" placement="top" :visible-arrow="false">

View File

@ -473,9 +473,16 @@ export default {
},
handleDelete(apiCase) {
// if (this.trashEnable) {
this.$get('/api/testcase/delete/' + apiCase.id, () => {
this.$success(this.$t('commons.delete_success'));
this.initTable();
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + apiCase.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$get('/api/testcase/delete/' + apiCase.id, () => {
this.$success(this.$t('commons.delete_success'));
this.initTable();
});
}
}
});
return;
},

View File

@ -2,6 +2,7 @@
<el-dialog :title="$t('api_test.request.parameters_advance')"
:visible.sync="itemValueVisible"
class="advanced-item-value"
:append-to-body="true"
width="70%">
<el-tabs tab-position="top" style="height: 50vh;" @tab-click="selectTab">
<el-tab-pane :label="$t('api_test.request.parameters_advance_mock')">

View File

@ -112,6 +112,13 @@
this.projectIds.add(row.projectId)
})
},
setScenarioSelectRows(rows) {
this.selectRows = rows;
this.projectIds.clear();
this.selectRows.forEach(row => {
row.projectIds.forEach(id => this.projectIds.add(id));
})
},
handleClose() {
this.form = {};
this.options = [];

View File

@ -2,6 +2,9 @@
<div>
<el-card class="table-card" v-loading="result.loading">
<env-popover :env-map="projectEnvMap" :project-ids="projectIds" @setProjectEnvMap="setProjectEnvMap"
:project-list="projectList" ref="envPopover" class="env-popover"/>
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="handleSelectAll" @select="handleSelect">
<el-table-column type="selection"/>
@ -56,10 +59,12 @@
import MsTestPlanList from "../../../../../api/automation/scenario/testplan/TestPlanList";
import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader";
import {_handleSelect, _handleSelectAll} from "../../../../../../../common/js/tableUtils";
import EnvPopover from "@/business/components/api/automation/scenario/EnvPopover";
export default {
name: "RelevanceScenarioList",
components: {
EnvPopover,
TestPlanScenarioListHeader,
MsTablePagination, MsTableMoreBtn, ShowMoreBtn, MsTableHeader, MsTag, MsApiReportDetail, MsTestPlanList},
props: {
@ -84,7 +89,10 @@
total: 0,
reportId: "",
infoDb: false,
selectRows: new Set()
selectRows: new Set(),
projectEnvMap: new Map(),
projectList: [],
projectIds: new Set(),
}
},
watch: {
@ -95,8 +103,13 @@
this.search();
},
},
created() {
this.getWsProjects();
},
methods: {
search() {
this.projectEnvMap.clear();
this.projectIds.clear();
if (!this.projectId) {
return;
}
@ -129,10 +142,31 @@
},
handleSelectAll(selection) {
_handleSelectAll(this, selection, this.tableData, this.selectRows);
this.initProjectIds();
},
handleSelect(selection, row) {
_handleSelect(this, selection, row, this.selectRows);
this.initProjectIds();
},
setProjectEnvMap(projectEnvMap) {
this.projectEnvMap = projectEnvMap;
},
getWsProjects() {
this.$get("/project/listAll", res => {
this.projectList = res.data;
})
},
initProjectIds() {
this.projectIds.clear();
this.selectRows.forEach(row => {
row.projectIds.forEach(id => {
this.projectIds.add(id);
})
})
},
checkEnv() {
return this.$refs.envPopover.checkEnv();
}
}
}
</script>
@ -141,4 +175,9 @@
/deep/ .el-drawer__header {
margin-bottom: 0px;
}
.env-popover {
float: right;
margin-top: 4px;
}
</style>

View File

@ -31,7 +31,7 @@
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
import MsApiModule from "../../../../../api/definition/components/module/ApiModule";
import {getCurrentProjectID} from "../../../../../../../common/js/utils";
import {getCurrentProjectID, strMapToObj} from "../../../../../../../common/js/utils";
import ApiList from "../../../../../api/definition/components/list/ApiList";
import ApiCaseSimpleList from "../../../../../api/definition/components/list/ApiCaseSimpleList";
import MsApiScenarioList from "../../../../../api/automation/scenario/ApiScenarioList";
@ -98,13 +98,21 @@
},
saveCaseRelevance() {
const sign = this.$refs.apiScenarioList.checkEnv();
if (!sign) {
return false;
}
let param = {};
let url = '';
let selectIds = [];
url = '/api/automation/relevance';
selectIds = Array.from(this.$refs.apiScenarioList.selectRows).map(row => row.id);
let url = '/api/automation/relevance';
let rows = this.$refs.apiScenarioList.selectRows;
const envMap = this.$refs.apiScenarioList.projectEnvMap;
let map = new Map();
rows.forEach(row => {
map.set(row.id, row.projectIds);
})
param.planId = this.planId;
param.selectIds = selectIds;
param.mapping = strMapToObj(map);
param.envMap = strMapToObj(envMap);
this.result = this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));

View File

@ -37,7 +37,8 @@
<el-table-column v-if="item.id == 'tagNames'" prop="tagNames" :label="$t('api_test.automation.tag')"
width="200px" :key="index">
<template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" :content="itemName" style="margin-left: 5px"/>
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain"
:content="itemName" style="margin-left: 5px"/>
</template>
</el-table-column>
<el-table-column v-if="item.id == 'userId'" prop="userId" :label="$t('api_test.automation.creator')"
@ -90,6 +91,10 @@
</div>
</el-card>
<!-- 批量编辑 -->
<batch-edit :dialog-title="$t('test_track.case.batch_edit_case')" :type-arr="typeArr" :value-arr="valueArr"
:select-row="selectRows" ref="batchEdit" @batchEdit="batchEdit"/>
</div>
</template>
@ -98,7 +103,7 @@ import MsTableHeader from "@/business/components/common/components/MsTableHeader
import MsTablePagination from "@/business/components/common/pagination/TablePagination";
import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn";
import MsTag from "../../../../../common/components/MsTag";
import {getUUID, getCurrentProjectID, getCurrentUser} from "@/common/js/utils";
import {getUUID, getCurrentProjectID, getCurrentUser, strMapToObj} from "@/common/js/utils";
import MsApiReportDetail from "../../../../../api/automation/report/ApiReportDetail";
import MsTableMoreBtn from "../../../../../api/automation/scenario/TableMoreBtn";
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
@ -110,6 +115,7 @@ import HeaderCustom from "@/business/components/common/head/HeaderCustom";
import {TEST_CASE_LIST, TEST_PLAN_SCENARIO_CASE} from "@/common/js/constants";
import {Test_Plan_Scenario_Case, Track_Test_Case} from "@/business/components/common/model/JsonData";
import HeaderLabelOperate from "@/business/components/common/head/HeaderLabelOperate";
import BatchEdit from "@/business/components/track/case/components/BatchEdit";
export default {
name: "MsTestPlanApiScenarioList",
@ -125,7 +131,8 @@ export default {
MsTag,
MsApiReportDetail,
MsScenarioExtendButtons,
MsTestPlanList
MsTestPlanList,
BatchEdit
},
props: {
referenced: {
@ -162,9 +169,16 @@ export default {
},
{
name: this.$t('api_test.automation.batch_execute'), handleClick: this.handleBatchExecute
}
},
{name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleBatchEdit}
],
selectRows: new Set()
selectRows: new Set(),
typeArr: [
{id: 'projectEnv', name: this.$t('api_test.definition.request.run_env')},
],
valueArr: {
projectEnv: []
},
}
},
created() {
@ -284,7 +298,24 @@ export default {
}
}
});
}
},
handleBatchEdit() {
this.$refs.batchEdit.open(this.selectRows.size);
this.$refs.batchEdit.setScenarioSelectRows(this.selectRows);
},
batchEdit(form) {
let param = {};
let map = new Map();
this.selectRows.forEach(row => {
map.set(row.id, row.projectIds);
})
param.mapping = strMapToObj(map);
param.envMap = strMapToObj(form.projectEnvMap);
this.$post('/test/plan/scenario/case/batch/update/env', param, () => {
this.$success(this.$t('commons.save_success'));
this.search();
})
},
}
}
</script>