This commit is contained in:
fit2-zhao 2020-12-30 11:27:22 +08:00
commit 4b975918e1
46 changed files with 1300 additions and 1840 deletions

View File

@ -41,6 +41,13 @@ public class ApiDefinitionController {
return PageUtils.setPageInfo(page, apiDefinitionService.list(request));
}
@PostMapping("/list/relevance/{goPage}/{pageSize}")
public Pager<List<ApiDefinitionResult>> listRelevance(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody ApiDefinitionRequest request) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
request.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
return PageUtils.setPageInfo(page, apiDefinitionService.listRelevance(request));
}
@PostMapping("/list/all")
public List<ApiDefinitionResult> list(@RequestBody ApiDefinitionRequest request) {
return apiDefinitionService.list(request);
@ -72,12 +79,23 @@ public class ApiDefinitionController {
apiDefinitionService.deleteBatch(ids);
}
@PostMapping("/deleteBatchByParams")
public void deleteBatchByParams(@RequestBody ApiDefinitionBatchProcessingRequest request) {
apiDefinitionService.deleteByParams(request);
}
@PostMapping("/removeToGc")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR)
public void removeToGc(@RequestBody List<String> ids) {
apiDefinitionService.removeToGc(ids);
}
@PostMapping("/removeToGcByParams")
@RequiresRoles(value = {RoleConstants.TEST_MANAGER, RoleConstants.TEST_USER}, logical = Logical.OR)
public void removeToGcByParams(@RequestBody ApiDefinitionBatchProcessingRequest request) {
apiDefinitionService.removeToGcByParams(request);
}
@PostMapping("/reduction")
public void reduction(@RequestBody List<SaveApiDefinitionRequest> requests) {
apiDefinitionService.reduction(requests);
@ -130,6 +148,12 @@ public class ApiDefinitionController {
apiDefinitionService.editApiBath(request);
}
@PostMapping("/batch/editByParams")
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
public void editByParams(@RequestBody ApiBatchRequest request) {
apiDefinitionService.editApiByParam(request);
}
@PostMapping("/relevance")
public void testPlanRelevance(@RequestBody ApiCaseRelevanceRequest request) {
apiDefinitionService.testPlanRelevance(request);

View File

@ -11,4 +11,24 @@ public class DeleteAPIReportRequest {
private String id;
private List<String> ids;
/**
* isSelectAllDate选择的数据是否是全部数据全部数据是不受分页影响的数据
* filters: 数据状态
* name如果是全部数据那么表格如果历经查询查询参数是什么
* moduleIds 哪些模块的数据
* unSelectIds是否在页面上有未勾选的数据有的话他们的ID是哪些
* filters/name/moduleIds/unSeelctIds 只在isSelectAllDate为true时需要为了让程序能明确批量的范围
*/
private boolean isSelectAllDate;
private List<String> filters;
private String name;
private String projectId;
private List<String> moduleIds;
private List<String> unSelectIds;
}

View File

@ -28,4 +28,23 @@ public class RunScenarioRequest {
private String reportUserID;
private List<String> scenarioIds;
/**
* isSelectAllDate选择的数据是否是全部数据全部数据是不受分页影响的数据
* filters: 数据状态
* name如果是全部数据那么表格如果历经查询查询参数是什么
* moduleIds 哪些模块的数据
* unSelectIds是否在页面上有未勾选的数据有的话他们的ID是哪些
* filters/name/moduleIds/unSeelctIds 只在isSelectAllDate为true时需要为了让程序能明确批量的范围
*/
private boolean isSelectAllDate;
private List<String> filters;
private String name;
private List<String> moduleIds;
private List<String> unSelectIds;
}

View File

@ -11,4 +11,26 @@ public class SaveApiPlanRequest {
private List<String> planIds;
private List<String> apiIds;
private List<String> scenarioIds;
/**
* isSelectAllDate选择的数据是否是全部数据全部数据是不受分页影响的数据
* filters: 数据状态
* name如果是全部数据那么表格如果历经查询查询参数是什么
* moduleIds 哪些模块的数据
* unSelectIds是否在页面上有未勾选的数据有的话他们的ID是哪些
* filters/name/moduleIds/unSeelctIds 只在isSelectAllDate为true时需要为了让程序能明确批量的范围
*/
private boolean isSelectAllDate;
private List<String> filters;
private String name;
private List<String> moduleIds;
private List<String> unSelectIds;
private String projectId;
}

View File

@ -13,4 +13,23 @@ public class ApiBatchRequest extends ApiDefinitionWithBLOBs {
private List<String> ids;
private List<OrderRequest> orders;
private String projectId;
/**
* isSelectAllDate选择的数据是否是全部数据全部数据是不受分页影响的数据
* filters: 数据状态
* name如果是全部数据那么表格如果历经查询查询参数是什么
* moduleIds 哪些模块的数据
* unSelectIds是否在页面上有未勾选的数据有的话他们的ID是哪些
* filters/name/moduleIds/unSeelctIds 只在isSelectAllDate为true时需要为了让程序能明确批量的范围
*/
private boolean isSelectAllDate;
private List<String> filters;
private String name;
private List<String> moduleIds;
private List<String> unSelectIds;
}

View File

@ -0,0 +1,39 @@
package io.metersphere.api.dto.definition;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* 接口定义模块-批量处理请求类
* @author song.tianyang
* @Date 2020/12/29 4:13 下午
* @Description
*/
@Getter
@Setter
public class ApiDefinitionBatchProcessingRequest {
/**
* isSelectAllDate选择的数据是否是全部数据全部数据是不受分页影响的数据
* filters: 数据状态
* name如果是全部数据那么表格如果历经查询查询参数是什么
* moduleIds 哪些模块的数据
* unSelectIds是否在页面上有未勾选的数据有的话他们的ID是哪些
* filters/name/moduleIds/unSeelctIds 只在isSelectAllDate为true时需要为了让程序能明确批量的范围
*/
private boolean isSelectAllDate;
private List<String> filters;
private String name;
private List<String> moduleIds;
private List<String> unSelectIds;
private String projectId;
private List<String> dataIds;
}

View File

@ -20,6 +20,7 @@ public class ApiDefinitionRequest {
private String name;
private String workspaceId;
private String userId;
private String planId;
private boolean recent = false;
private List<OrderRequest> orders;
private List<String> filters;

View File

@ -24,7 +24,6 @@ import io.metersphere.base.mapper.ext.ExtTestPlanScenarioCaseMapper;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
@ -303,13 +302,23 @@ public class ApiAutomationService {
* @return
*/
public String run(RunScenarioRequest request) {
List<ApiScenarioWithBLOBs> apiScenarios = extApiScenarioMapper.selectIds(request.getScenarioIds());
List<ApiScenarioWithBLOBs> apiScenarios = null;
List<String> ids = request.getScenarioIds();
if (request.isSelectAllDate()) {
ids = this.getAllScenarioIdsByFontedSelect(
request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds());
}
apiScenarios = extApiScenarioMapper.selectIds(ids);
MsTestPlan testPlan = new MsTestPlan();
testPlan.setHashTree(new LinkedList<>());
HashTree jmeterHashTree = new ListedHashTree();
try {
boolean isFirst = true;
for (ApiScenarioWithBLOBs item : apiScenarios) {
if (item.getStepTotal() == 0) {
MSException.throwException(item.getName() + "" + Translator.get("automation_exec_info"));
break;
}
MsThreadGroup group = new MsThreadGroup();
group.setLabel(item.getName());
group.setName(UUID.randomUUID().toString());
@ -347,7 +356,7 @@ public class ApiAutomationService {
}
} catch (Exception ex) {
LogUtil.error(ex.getMessage());
MSException.throwException(ex.getMessage());
}
testPlan.toHashTree(jmeterHashTree, testPlan.getHashTree(), new ParameterConfig());
@ -360,6 +369,27 @@ public class ApiAutomationService {
return request.getId();
}
/**
* 获取前台查询条件查询的所有(未经分页筛选)数据ID
*
* @param moduleIds 模块ID_前台查询时所选择的
* @param name 搜索条件_名称_前台查询时所输入的
* @param projectId 所属项目_前台查询时所在项目
* @param filters 过滤集合__前台查询时的过滤条件
* @param unSelectIds 未勾选ID_前台没有勾选的ID
* @return
*/
private List<String> getAllScenarioIdsByFontedSelect(List<String> moduleIds, String name, String projectId, List<String> filters, List<String> unSelectIds) {
ApiScenarioRequest selectRequest = new ApiScenarioRequest();
selectRequest.setModuleIds(moduleIds);
selectRequest.setName(name);
selectRequest.setProjectId(projectId);
selectRequest.setFilters(filters);
List<ApiScenarioDTO> list = extApiScenarioMapper.list(selectRequest);
List<String> allIds = list.stream().map(ApiScenarioDTO::getId).collect(Collectors.toList());
List<String> ids = allIds.stream().filter(id -> !unSelectIds.contains(id)).collect(Collectors.toList());
return ids;
}
/**
* 场景测试执行
@ -401,6 +431,11 @@ public class ApiAutomationService {
if (CollectionUtils.isEmpty(request.getPlanIds())) {
MSException.throwException(Translator.get("plan id is null "));
}
List<String> scenarioIds = request.getScenarioIds();
if (request.isSelectAllDate()) {
scenarioIds = this.getAllScenarioIdsByFontedSelect(
request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds());
}
List<TestPlanDTO> list = extTestPlanMapper.selectByIds(request.getPlanIds());
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
ExtTestPlanMapper mapper = sqlSession.getMapper(ExtTestPlanMapper.class);
@ -408,8 +443,8 @@ public class ApiAutomationService {
ExtTestPlanApiCaseMapper apiCaseBatchMapper = sqlSession.getMapper(ExtTestPlanApiCaseMapper.class);
for (TestPlanDTO testPlan : list) {
if (request.getScenarioIds() != null) {
for (String scenarioId : request.getScenarioIds()) {
if (scenarioIds != null) {
for (String scenarioId : scenarioIds) {
TestPlanApiScenario testPlanApiScenario = new TestPlanApiScenario();
testPlanApiScenario.setId(UUID.randomUUID().toString());
testPlanApiScenario.setApiScenarioId(scenarioId);

View File

@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.metersphere.api.dto.APIReportResult;
import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ApiScenarioDTO;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.ReferenceDTO;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
@ -78,23 +79,7 @@ public class ApiDefinitionService {
public List<ApiDefinitionResult> list(ApiDefinitionRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
List<ApiDefinitionResult> resList = extApiDefinitionMapper.list(request);
if (!resList.isEmpty()) {
List<String> ids = resList.stream().map(ApiDefinitionResult::getId).collect(Collectors.toList());
List<ApiComputeResult> results = extApiDefinitionMapper.selectByIds(ids);
Map<String, ApiComputeResult> resultMap = results.stream().collect(Collectors.toMap(ApiComputeResult::getApiDefinitionId, Function.identity()));
for (ApiDefinitionResult res : resList) {
ApiComputeResult compRes = resultMap.get(res.getId());
if (compRes != null) {
res.setCaseTotal(compRes.getCaseTotal());
res.setCasePassingRate(compRes.getPassRate());
res.setCaseStatus(compRes.getStatus());
} else {
res.setCaseTotal("-");
res.setCasePassingRate("-");
res.setCaseStatus("-");
}
}
}
calculateResult(resList);
return resList;
}
@ -420,6 +405,23 @@ public class ApiDefinitionService {
apiDefinitionMapper.updateByExampleSelective(definitionWithBLOBs, definitionExample);
}
public void editApiByParam(ApiBatchRequest request) {
List<String> ids = request.getIds();
if(request.isSelectAllDate()){
ids = this.getAllApiIdsByFontedSelect(request.getFilters(),request.getName(),request.getModuleIds(),request.getProjectId(),request.getUnSelectIds());
}
//name在这里只是查询参数
request.setName(null);
ApiDefinitionExample definitionExample = new ApiDefinitionExample();
definitionExample.createCriteria().andIdIn(ids);
ApiDefinitionWithBLOBs definitionWithBLOBs = new ApiDefinitionWithBLOBs();
BeanUtils.copyBean(definitionWithBLOBs, request);
definitionWithBLOBs.setUpdateTime(System.currentTimeMillis());
apiDefinitionMapper.updateByExampleSelective(definitionWithBLOBs, definitionExample);
}
public void testPlanRelevance(ApiCaseRelevanceRequest request) {
apiTestCaseService.relevanceByApi(request);
}
@ -466,4 +468,64 @@ public class ApiDefinitionService {
example.createCriteria().andIdIn(ids);
return apiDefinitionMapper.selectByExample(example);
}
public void deleteByParams(ApiDefinitionBatchProcessingRequest request) {
List<String> apiIds = request.getDataIds();
if(request.isSelectAllDate()){
apiIds = this.getAllApiIdsByFontedSelect(request.getFilters(),request.getName(),request.getModuleIds(),request.getProjectId(),request.getUnSelectIds());
}
ApiDefinitionExample example = new ApiDefinitionExample();
example.createCriteria().andIdIn(apiIds);
apiDefinitionMapper.deleteByExample(example);
}
private List<String> getAllApiIdsByFontedSelect(List<String> filter,String name,List<String> moduleIds,String projectId,List<String>unSelectIds) {
ApiDefinitionRequest request = new ApiDefinitionRequest();
request.setFilters(filter);
request.setName(name);
request.setModuleIds(moduleIds);
request.setProjectId(projectId);
List<ApiDefinitionResult> resList = extApiDefinitionMapper.list(request);
List<String> ids = new ArrayList<>(0);
if (!resList.isEmpty()) {
List<String> allIds = resList.stream().map(ApiDefinitionResult::getId).collect(Collectors.toList());
ids = allIds.stream().filter(id -> !unSelectIds.contains(id)).collect(Collectors.toList());
}
return ids;
}
public void removeToGcByParams(ApiDefinitionBatchProcessingRequest request) {
List<String> apiIds = request.getDataIds();
if(request.isSelectAllDate()){
apiIds = this.getAllApiIdsByFontedSelect(request.getFilters(),request.getName(),request.getModuleIds(),request.getProjectId(),request.getUnSelectIds());
}
extApiDefinitionMapper.removeToGc(apiIds);
}
public List<ApiDefinitionResult> listRelevance(ApiDefinitionRequest request) {
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
List<ApiDefinitionResult> resList = extApiDefinitionMapper.listRelevance(request);
calculateResult(resList);
return resList;
}
public void calculateResult(List<ApiDefinitionResult> resList) {
if (!resList.isEmpty()) {
List<String> ids = resList.stream().map(ApiDefinitionResult::getId).collect(Collectors.toList());
List<ApiComputeResult> results = extApiDefinitionMapper.selectByIds(ids);
Map<String, ApiComputeResult> resultMap = results.stream().collect(Collectors.toMap(ApiComputeResult::getApiDefinitionId, Function.identity()));
for (ApiDefinitionResult res : resList) {
ApiComputeResult compRes = resultMap.get(res.getId());
if (compRes != null) {
res.setCaseTotal(compRes.getCaseTotal());
res.setCasePassingRate(compRes.getPassRate());
res.setCaseStatus(compRes.getStatus());
} else {
res.setCaseTotal("-");
res.setCasePassingRate("-");
res.setCaseStatus("-");
}
}
}
}
}

View File

@ -3,9 +3,7 @@ package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import io.metersphere.api.dto.DeleteAPIReportRequest;
import io.metersphere.api.dto.QueryAPIReportRequest;
import io.metersphere.api.dto.automation.APIScenarioReportResult;
import io.metersphere.api.dto.automation.ExecuteType;
import io.metersphere.api.dto.automation.ScenarioStatus;
import io.metersphere.api.dto.automation.*;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.jmeter.ScenarioResult;
import io.metersphere.api.jmeter.TestResult;
@ -19,6 +17,7 @@ import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.DateUtils;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
@ -31,6 +30,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
@ -208,12 +208,23 @@ public class ApiScenarioReportService {
}
public void deleteAPIReportBatch(DeleteAPIReportRequest reportRequest) {
List<String> ids = reportRequest.getIds();
if (reportRequest.isSelectAllDate()) {
QueryAPIReportRequest selectRequest = new QueryAPIReportRequest();
selectRequest.setWorkspaceId(SessionUtils.getCurrentWorkspaceId());
selectRequest.setName(reportRequest.getName());
selectRequest.setProjectId(reportRequest.getProjectId());
List<APIScenarioReportResult> list = extApiScenarioReportMapper.list(selectRequest);
List<String> allIds = list.stream().map(APIScenarioReportResult::getId).collect(Collectors.toList());
ids = allIds.stream().filter(id -> !reportRequest.getUnSelectIds().contains(id)).collect(Collectors.toList());
}
ApiScenarioReportDetailExample detailExample = new ApiScenarioReportDetailExample();
detailExample.createCriteria().andReportIdIn(reportRequest.getIds());
detailExample.createCriteria().andReportIdIn(ids);
apiScenarioReportDetailMapper.deleteByExample(detailExample);
ApiScenarioReportExample apiTestReportExample = new ApiScenarioReportExample();
apiTestReportExample.createCriteria().andIdIn(reportRequest.getIds());
apiTestReportExample.createCriteria().andIdIn(ids);
apiScenarioReportMapper.deleteByExample(apiTestReportExample);
}

View File

@ -28,4 +28,6 @@ public interface ExtApiDefinitionMapper {
List<ApiDataCountResult> countApiCoverageByProjectID(String projectId);
ApiDefinition getNextNum(@Param("projectId") String projectId);
List<ApiDefinitionResult> listRelevance(@Param("request")ApiDefinitionRequest request);
}

View File

@ -295,4 +295,63 @@
<select id="getNextNum" resultType="io.metersphere.base.domain.ApiDefinition">
SELECT * FROM api_definition WHERE api_definition.project_id = #{projectId} ORDER BY num DESC LIMIT 1;
</select>
<select id="listRelevance" resultType="io.metersphere.api.dto.definition.ApiDefinitionResult">
select api_definition.id, api_definition.project_id, api_definition.num,
api_definition.name,api_definition.protocol,api_definition.path,api_definition.module_id,api_definition.module_path,api_definition.method,
api_definition.description,api_definition.request,api_definition.response,api_definition.environment_id,
api_definition.status, api_definition.user_id, api_definition.create_time, api_definition.update_time
from api_definition
inner join
api_test_case c
on c.api_definition_id = api_definition.id
and not exists (
select id
from test_plan_api_case t
where t.api_case_id = c.id
and t.test_plan_id = #{request.planId}
)
<where>
<if test="request.combine != null">
<include refid="combine">
<property name="condition" value="request.combine"/>
<property name="name" value="request.name"/>
</include>
</if>
<if test="request.name != null">
and api_definition.name like CONCAT('%', #{request.name},'%')
</if>
<if test="request.protocol != null">
AND api_definition.protocol = #{request.protocol}
</if>
<if test="request.id != null">
AND api_definition.id = #{request.id}
</if>
<if test="request.moduleId != null">
AND api_definition.module_id = #{request.moduleId}
</if>
<if test="request.projectId != null">
AND api_definition.project_id = #{request.projectId}
</if>
<if test="request.moduleIds != null and request.moduleIds.size() > 0">
AND api_definition.module_id in
<foreach collection="request.moduleIds" item="nodeId" separator="," open="(" close=")">
#{nodeId}
</foreach>
</if>
<if test="request.filters != null and request.filters.size() > 0">
and api_definition.status in
<foreach collection="request.filters" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</if>
</where>
<if test="request.orders != null and request.orders.size() > 0">
order by
<foreach collection="request.orders" separator="," item="order">
api_definition.${order.name} ${order.type}
</foreach>
</if>
</select>
</mapper>

View File

@ -19,7 +19,7 @@
select
t.id, t.environment_id, t.create_time, t.update_time,
c.id as case_id, c.project_id, c.name, c.api_definition_id, c.priority, c.description, c.create_user_id, c.update_user_id,
a.module_id, a.path, a.protocol, ader.status execResult
a.module_id, a.path, a.protocol, t.status execResult
from
test_plan_api_case t
inner join
@ -32,24 +32,6 @@
api_definition a
on
c.api_definition_id = a.id
left join (
select
e.status, e.id, e.resource_id
from
api_definition_exec_result e
left join (
select
max(start_time) start_time , resource_id
from
api_definition_exec_result
group by
resource_id
) as b
on e.resource_id = b.resource_id
where
e.start_time = b.start_time and e.type = 'API_PLAN'
) as ader
on t.id = ader.resource_id
<if test="request.protocol != null and request.protocol!=''">
and a.protocol = #{request.protocol}
</if>

View File

@ -100,7 +100,7 @@
parameterType="io.metersphere.track.request.testcase.QueryTestPlanRequest">
select DISTINCT test_plan.*, user.name as user_name from test_plan
LEFT JOIN user ON user.id = test_plan.principal
JOIN test_plan_project on test_plan.id = test_plan_id JOIN project on project.id = project_id
JOIN test_plan_project on test_plan.id = test_plan_project.test_plan_id JOIN project on project.id = test_plan_project.project_id
<where>
<if test="request.combine != null">
<include refid="combine">

View File

@ -17,6 +17,6 @@ public class Translator {
* 单Key翻译
*/
public static String get(String key) {
return messageSource.getMessage(key, null, "Not Support Key", LocaleContextHolder.getLocale());
return messageSource.getMessage(key, null, "Not Support Key: " + key, LocaleContextHolder.getLocale());
}
}

@ -1 +1 @@
Subproject commit f27d1609d77f7d6c988d37d709466e844d350e17
Subproject commit 068127ce59ea8b016434ed52a9de4a7a4b13bdb4

View File

@ -60,6 +60,7 @@ test_resource_pool_name_is_null=Test Resource Pool name cannot be null
test_resource_pool_name_already_exists=The test resource pool name already exists
load_test=Load Test
test_resource_pool_is_use=This resource pool is in use and cannot be deleted
only_one_k8s=Only one K8S can be added
#project
project_name_is_null=Project name cannot be null
project_name_already_exists=The project name already exists
@ -176,6 +177,6 @@ task_notification=Result notification
message_task_already_exists=Task recipient already exists
#automation
automation_name_already_exists=the scenario already exists in the project and the module
automation_exec_info=There are no test steps to execute

View File

@ -60,6 +60,7 @@ test_resource_pool_name_is_null=资源池名称不能为空
test_resource_pool_name_already_exists=资源池名称已存在
load_test=性能测试
test_resource_pool_is_use=正在使用此资源池,无法删除
only_one_k8s=只能添加一个 K8S
#project
project_name_is_null=项目名称不能为空
project_name_already_exists=项目名称已存在
@ -176,4 +177,5 @@ task_notification_jenkins=jenkins任务通知
task_notification=任务通知
message_task_already_exists=任务接收人已经存在
#automation
automation_name_already_exists=同一个项目和模块下,场景名称不能重复
automation_name_already_exists=同一个项目和模块下,场景名称不能重复
automation_exec_info=没有测试步骤,无法执行

View File

@ -60,6 +60,7 @@ test_resource_pool_name_is_null=資源池名稱不能為空
test_resource_pool_name_already_exists=資源池名稱已存在
load_test=性能測試
test_resource_pool_is_use=正在使用此資源池,無法刪除
only_one_k8s=只能添加一個 K8S
#project
project_name_is_null=項目名稱不能為空
project_name_already_exists=項目名稱已存在
@ -178,3 +179,4 @@ api_definition_url_not_repeating=接口請求地址已經存在
message_task_already_exists=任務接收人已經存在
#automation
automation_name_already_exists=同一個項目和模塊下,場景名稱不能重複
automation_exec_info=沒有測試步驟,無法執行

View File

@ -7,21 +7,35 @@
:title="$t('api_report.title')"
:show-create="false"/>
</template>
<el-table border :data="tableData" class="adjust-table table-content" @sort-change="sort"
<el-table ref="reportListTable" border :data="tableData" class="adjust-table table-content" @sort-change="sort"
@select-all="handleSelectAll"
@select="handleSelect"
@filter-change="filter" @row-click="handleView">
<el-table-column
type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<el-dropdown slot="header" style="width: 14px">
<span class="el-dropdown-link" style="width: 14px">
<i class="el-icon-arrow-down el-icon--right" style="margin-left: 0px"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native.stop="isSelectDataAll(true)">
{{ $t('api_test.batch_menus.select_all_data', [total]) }}
</el-dropdown-item>
<el-dropdown-item @click.native.stop="isSelectDataAll(false)">
{{ $t('api_test.batch_menus.select_show_data', [tableData.length]) }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template v-slot:default="scope">
<show-more-btn v-tester :is-show="scope.row.showMore" :buttons="buttons" :size="selectRows.size"/>
<show-more-btn v-tester :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/>
</template>
</el-table-column>
<el-table-column :label="$t('commons.name')" width="200" show-overflow-tooltip prop="name">
</el-table-column>
<el-table-column prop="scenarioName" :label="$t('api_test.automation.scenario_name')" width="150" show-overflow-tooltip/>
<el-table-column prop="scenarioName" :label="$t('api_test.automation.scenario_name')" width="150"
show-overflow-tooltip/>
<el-table-column prop="userName" :label="$t('api_test.creator')" width="150" show-overflow-tooltip/>
<el-table-column prop="createTime" width="250" :label="$t('commons.create_time')" sortable>
<template v-slot:default="scope">
@ -55,8 +69,10 @@
</el-card>
</ms-main-container>
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProjectId" :info-db="true" @refresh="search"/>
<el-drawer :visible.sync="debugVisible" :destroy-on-close="true" direction="ltr" :withHeader="false"
:title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-api-report-detail :report-id="reportId" :currentProjectId="currentProjectId" :info-db="true"
@refresh="search"/>
</el-drawer>
</ms-container>
</template>
@ -76,152 +92,190 @@ import ShowMoreBtn from "../../../track/case/components/ShowMoreBtn";
import MsApiReportDetail from "./ApiReportDetail";
export default {
components: {
ReportTriggerModeItem,
MsTableOperatorButton,
MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, ShowMoreBtn, MsApiReportDetail
},
data() {
return {
result: {},
reportId: "",
debugVisible: false,
condition: {
components: REPORT_CONFIGS
},
tableData: [],
multipleSelection: [],
currentPage: 1,
pageSize: 5,
total: 0,
loading: false,
currentProjectId: "",
statusFilters: [
{text: 'Saved', value: 'Saved'},
{text: 'Starting', value: 'Starting'},
{text: 'Running', value: 'Running'},
{text: 'Reporting', value: 'Reporting'},
{text: 'Completed', value: 'Completed'},
{text: 'Error', value: 'Error'},
{text: 'Success', value: 'Success'},
],
triggerFilters: [
{text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},
{text: this.$t('commons.trigger_mode.schedule'), value: 'SCHEDULE'},
{text: this.$t('commons.trigger_mode.api'), value: 'API'}
],
buttons: [
{
name: this.$t('api_report.batch_delete'), handleClick: this.handleBatchDelete
}
],
selectRows: new Set(),
}
},
watch: {
'$route': 'init',
},
methods: {
search() {
if (this.testId !== 'all') {
this.condition.testId = this.testId;
components: {
ReportTriggerModeItem,
MsTableOperatorButton,
MsApiReportStatus, MsMainContainer, MsContainer, MsTableHeader, MsTablePagination, ShowMoreBtn, MsApiReportDetail
},
data() {
return {
result: {},
reportId: "",
debugVisible: false,
condition: {
components: REPORT_CONFIGS
},
tableData: [],
multipleSelection: [],
currentPage: 1,
pageSize: 5,
total: 0,
loading: false,
currentProjectId: "",
statusFilters: [
{text: 'Saved', value: 'Saved'},
{text: 'Starting', value: 'Starting'},
{text: 'Running', value: 'Running'},
{text: 'Reporting', value: 'Reporting'},
{text: 'Completed', value: 'Completed'},
{text: 'Error', value: 'Error'},
{text: 'Success', value: 'Success'},
],
triggerFilters: [
{text: this.$t('commons.trigger_mode.manual'), value: 'MANUAL'},
{text: this.$t('commons.trigger_mode.schedule'), value: 'SCHEDULE'},
{text: this.$t('commons.trigger_mode.api'), value: 'API'}
],
buttons: [
{
name: this.$t('api_report.batch_delete'), handleClick: this.handleBatchDelete
}
this.condition.projectId = getCurrentProjectID();
let url = "/api/scenario/report/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.selectRows.clear();
});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleView(report) {
this.reportId = report.id;
this.currentProjectId = report.projectId;
this.debugVisible = true;
},
handleDelete(report) {
this.$alert(this.$t('api_report.delete_confirm') + report.name + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.result = this.$post("/api/scenario/report/delete", {id: report.id}, () => {
this.$success(this.$t('commons.delete_success'));
this.search();
// 广 head
ApiEvent.$emit(LIST_CHANGE);
});
}
}
});
},
init() {
this.testId = this.$route.params.testId;
this.search();
},
sort(column) {
_sort(column, this.condition);
this.init();
},
filter(filters) {
_filter(filters, this.condition);
this.init();
},
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);
}
},
handleSelectAll(selection) {
if (selection.length > 0) {
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('api_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.$post('/api/scenario/report/batch/delete', {ids: ids}, () => {
this.selectRows.clear();
this.$success(this.$t('commons.delete_success'));
this.search();
// 广 head
ApiEvent.$emit(LIST_CHANGE);
});
}
}
});
}
},
created() {
this.init();
],
selectRows: new Set(),
selectAll: false,
unSelection: [],
selectDataCounts: 0,
}
},
watch: {
'$route': 'init',
},
methods: {
search() {
if (this.testId !== 'all') {
this.condition.testId = this.testId;
}
this.condition.projectId = getCurrentProjectID();
this.selectAll = false;
this.unSelection = [];
this.selectDataCounts = 0;
let url = "/api/scenario/report/list/" + this.currentPage + "/" + this.pageSize;
this.result = this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.selectRows.clear();
this.unSelection = data.listObject.map(s => s.id);
});
},
handleSelectionChange(val) {
this.multipleSelection = val;
},
handleView(report) {
this.reportId = report.id;
this.currentProjectId = report.projectId;
this.debugVisible = true;
},
handleDelete(report) {
this.$alert(this.$t('api_report.delete_confirm') + report.name + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.result = this.$post("/api/scenario/report/delete", {id: report.id}, () => {
this.$success(this.$t('commons.delete_success'));
this.search();
// 广 head
ApiEvent.$emit(LIST_CHANGE);
});
}
}
});
},
init() {
this.testId = this.$route.params.testId;
this.search();
},
sort(column) {
_sort(column, this.condition);
this.init();
},
filter(filters) {
_filter(filters, this.condition);
this.init();
},
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);
}
this.selectRowsCount(this.selectRows)
},
handleSelectAll(selection) {
if (selection.length > 0) {
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);
})
}
this.selectRowsCount(this.selectRows)
},
handleBatchDelete() {
this.$alert(this.$t('api_report.delete_batch_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
let sendParam = {};
sendParam.ids = ids;
sendParam.selectAllDate = this.isSelectAllDate;
sendParam.unSelectIds = this.unSelection;
sendParam = Object.assign(sendParam, this.condition);
this.$post('/api/scenario/report/batch/delete', sendParam, () => {
this.selectRows.clear();
this.$success(this.$t('commons.delete_success'));
this.search();
// 广 head
ApiEvent.$emit(LIST_CHANGE);
});
}
}
});
},
selectRowsCount(selection) {
let selectedIDs = this.getIds(selection);
let allIDs = this.tableData.map(s => s.id);
this.unSelection = allIDs.filter(function (val) {
return selectedIDs.indexOf(val) === -1
});
if (this.isSelectAllDate) {
this.selectDataCounts = this.total - this.unSelection.length;
} else {
this.selectDataCounts = selection.size;
}
},
isSelectDataAll(dataType) {
this.isSelectAllDate = dataType;
this.selectRowsCount(this.selectRows)
//
if (this.selectRows.size != this.tableData.length) {
this.$refs.reportListTable.toggleAllSelection(true);
}
},
getIds(rowSets) {
let rowArray = Array.from(rowSets)
let ids = rowArray.map(s => s.id);
return ids;
}
},
created() {
this.init();
}
}
</script>
<style scoped>
.table-content {
width: 100%;
}
.table-content {
width: 100%;
}
</style>

View File

@ -6,11 +6,26 @@
:show-create="false"/>
</template>
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="select" @select="select" v-loading="loading">
<el-table-column type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<el-table ref="scenarioTable" border :data="tableData" class="adjust-table" @select-all="select" @select="select"
v-loading="loading">
<el-table-column type="selection" width="38"/>
<el-table-column v-if="!referenced" width="40" :resizable="false" align="center">
<el-dropdown slot="header" style="width: 14px">
<span class="el-dropdown-link" style="width: 14px">
<i class="el-icon-arrow-down el-icon--right" style="margin-left: 0px"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native.stop="isSelectDataAll(true)">
{{$t('api_test.batch_menus.select_all_data',[total])}}
</el-dropdown-item>
<el-dropdown-item @click.native.stop="isSelectDataAll(false)">
{{$t('api_test.batch_menus.select_show_data',[tableData.length])}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template v-slot:default="{row}">
<show-more-btn :is-show="isSelect(row)" :buttons="buttons" :size="selection.length"/>
<show-more-btn :is-show="isSelect(row)" :buttons="buttons" :size="selectDataCounts"/>
</template>
</el-table-column>
<el-table-column prop="num" label="ID"
@ -25,7 +40,6 @@
<ms-tag v-if="scope.row.level == 'P2'" type="success" effect="plain" content="P2"/>
<ms-tag v-if="scope.row.level == 'P3'" type="danger" effect="plain" content="P3"/>
</template>
</el-table-column>
<el-table-column prop="tags" :label="$t('api_test.automation.tag')" width="200px">
<template v-slot:default="scope">
@ -43,8 +57,12 @@
<el-table-column prop="stepTotal" :label="$t('api_test.automation.step')" show-overflow-tooltip/>
<el-table-column prop="lastResult" :label="$t('api_test.automation.last_result')">
<template v-slot:default="{row}">
<el-link type="success" @click="showReport(row)" v-if="row.lastResult === 'Success'">{{ $t('api_test.automation.success') }}</el-link>
<el-link type="danger" @click="showReport(row)" v-if="row.lastResult === 'Fail'">{{ $t('api_test.automation.fail') }}</el-link>
<el-link type="success" @click="showReport(row)" v-if="row.lastResult === 'Success'">
{{ $t('api_test.automation.success') }}
</el-link>
<el-link type="danger" @click="showReport(row)" v-if="row.lastResult === 'Fail'">
{{ $t('api_test.automation.fail') }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="passRate" :label="$t('api_test.automation.passing_rate')"
@ -52,7 +70,7 @@
<el-table-column :label="$t('commons.operating')" width="200px" v-if="!referenced">
<template v-slot:default="{row}">
<div v-if="trashEnable">
<el-button type="text" @click="reductionApi(row)" v-tester>{{$t('commons.reduction')}}</el-button>
<el-button type="text" @click="reductionApi(row)" v-tester>{{ $t('commons.reduction') }}</el-button>
<el-button type="text" @click="remove(row)" v-tester>{{ $t('api_test.automation.remove') }}</el-button>
</div>
<div v-else>
@ -69,257 +87,313 @@
:total="total"/>
<div>
<!-- 执行结果 -->
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="true" :modal="false" size="90%">
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="true" :modal="false"
size="90%">
<ms-api-report-detail @refresh="search" :infoDb="infoDb" :report-id="reportId" :currentProjectId="projectId"/>
</el-drawer>
<!--测试计划-->
<el-drawer :visible.sync="planVisible" :destroy-on-close="true" direction="ltr" :withHeader="false" :title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<el-drawer :visible.sync="planVisible" :destroy-on-close="true" direction="ltr" :withHeader="false"
:title="$t('test_track.plan_view.test_result')" :modal="false" size="90%">
<ms-test-plan-list @addTestPlan="addTestPlan"/>
</el-drawer>
</div>
</el-card>
</div>
</template>
<script>
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} from "@/common/js/utils";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsTableMoreBtn from "./TableMoreBtn";
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
import MsTestPlanList from "./testplan/TestPlanList";
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} from "@/common/js/utils";
import MsApiReportDetail from "../report/ApiReportDetail";
import MsTableMoreBtn from "./TableMoreBtn";
import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns";
import MsTestPlanList from "./testplan/TestPlanList";
export default {
name: "MsApiScenarioList",
components: {MsTablePagination, MsTableMoreBtn, ShowMoreBtn, MsTableHeader, MsTag, MsApiReportDetail, MsScenarioExtendButtons, MsTestPlanList},
props: {
referenced: {
type: Boolean,
default: false,
},
selectNodeIds: Array,
trashEnable: {
type: Boolean,
default: false,
}
export default {
name: "MsApiScenarioList",
components: {
MsTablePagination,
MsTableMoreBtn,
ShowMoreBtn,
MsTableHeader,
MsTag,
MsApiReportDetail,
MsScenarioExtendButtons,
MsTestPlanList
},
props: {
referenced: {
type: Boolean,
default: false,
},
data() {
return {
loading: false,
condition: {},
currentScenario: {},
schedule: {},
selection: [],
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
reportId: "",
batchReportId: "",
content: {},
selectAll: false,
infoDb: false,
runVisible: false,
planVisible: false,
projectId: "",
runData: [],
report: {},
buttons: [
{
name: this.$t('api_test.automation.batch_add_plan'), handleClick: this.handleBatchAddCase
}, {
name: this.$t('api_test.automation.batch_execute'), handleClick: this.handleBatchExecute
}
],
}
},
created() {
this.projectId = getCurrentProjectID();
selectNodeIds: Array,
trashEnable: {
type: Boolean,
default: false,
}
},
data() {
return {
loading: false,
condition: {},
currentScenario: {},
schedule: {},
selection: [],
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
reportId: "",
batchReportId: "",
content: {},
infoDb: false,
runVisible: false,
planVisible: false,
projectId: "",
runData: [],
report: {},
selectDataSize: 0,
selectAll: false,
buttons: [
{
name: this.$t('api_test.automation.batch_add_plan'), handleClick: this.handleBatchAddCase
}, {
name: this.$t('api_test.automation.batch_execute'), handleClick: this.handleBatchExecute
}
],
isSelectAllDate: false,
unSelection: [],
selectDataCounts: 0,
}
},
created() {
this.projectId = getCurrentProjectID();
this.search();
},
watch: {
selectNodeIds() {
this.search();
},
watch: {
selectNodeIds() {
trashEnable() {
if (this.trashEnable) {
this.search();
},
trashEnable() {
if (this.trashEnable) {
this.search();
}
},
batchReportId() {
}
},
batchReportId() {
this.loading = true;
this.getReport();
}
},
computed: {
isNotRunning() {
return "Running" !== this.report.status;
}
},
methods: {
search() {
this.condition.filters = ["Prepare", "Underway", "Completed"];
this.condition.moduleIds = this.selectNodeIds;
if (this.trashEnable) {
this.condition.filters = ["Trash"];
this.condition.moduleIds = [];
}
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
this.selection = [];
this.selectAll = false;
this.unSelection = [];
this.selectDataCounts = 0;
let url = "/api/automation/list/" + this.currentPage + "/" + this.pageSize;
if (this.condition.projectId) {
this.loading = true;
this.getReport();
}
},
computed: {
isNotRunning() {
return "Running" !== this.report.status;
}
},
methods: {
search() {
this.condition.filters = ["Prepare", "Underway", "Completed"];
this.condition.moduleIds = this.selectNodeIds;
if (this.trashEnable) {
this.condition.filters = ["Trash"];
this.condition.moduleIds = [];
}
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
this.selection = [];
let url = "/api/automation/list/" + this.currentPage + "/" + this.pageSize;
if (this.condition.projectId) {
this.loading = true;
this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.tableData.forEach(item => {
if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags);
}
});
this.loading = false;
this.$post(url, this.condition, response => {
let data = response.data;
this.total = data.itemCount;
this.tableData = data.listObject;
this.tableData.forEach(item => {
if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags);
}
});
}
},
handleCommand(cmd) {
let table = this.$refs.scenarioTable;
switch (cmd) {
case "table":
this.selectAll = false;
table.toggleAllSelection();
break;
case "all":
this.selectAll = true;
break
}
},
handleBatchAddCase() {
this.planVisible = true;
},
addTestPlan(plans) {
let obj = {planIds: plans, scenarioIds: this.selection};
this.planVisible = false;
this.$post("/api/automation/scenario/plan", obj, response => {
this.$success(this.$t("commons.save_success"));
this.loading = false;
this.unSelection = data.listObject.map(s => s.id);
});
},
getReport() {
if (this.batchReportId) {
let url = "/api/scenario/report/get/" + this.batchReportId;
this.$get(url, response => {
this.report = response.data || {};
if (response.data) {
if (this.isNotRunning) {
try {
this.content = JSON.parse(this.report.content);
} catch (e) {
throw e;
}
this.loading = false;
this.$success("批量执行成功,请到报告页面查看详情!");
} else {
setTimeout(this.getReport, 2000)
}
},
handleCommand(cmd) {
let table = this.$refs.scenarioTable;
switch (cmd) {
case "table":
this.selectAll = false;
table.toggleAllSelection();
break;
case "all":
this.selectAll = true;
break
}
},
handleBatchAddCase() {
this.planVisible = true;
},
addTestPlan(plans) {
let obj = {planIds: plans, scenarioIds: this.selection};
obj.projectId = getCurrentProjectID();
obj.selectAllDate = this.isSelectAllDate;
obj.unSelectIds = this.unSelection;
obj = Object.assign(obj, this.condition);
this.planVisible = false;
this.$post("/api/automation/scenario/plan", obj, response => {
this.$success(this.$t("commons.save_success"));
});
},
getReport() {
if (this.batchReportId) {
let url = "/api/scenario/report/get/" + this.batchReportId;
this.$get(url, response => {
this.report = response.data || {};
if (response.data) {
if (this.isNotRunning) {
try {
this.content = JSON.parse(this.report.content);
} catch (e) {
throw e;
}
} else {
this.loading = false;
this.$error(this.$t('api_report.not_exist'));
}
});
}
},
handleBatchExecute() {
this.infoDb = false;
let url = "/api/automation/run/batch";
let run = {};
let scenarioIds = this.selection;
run.id = getUUID();
run.scenarioIds = scenarioIds;
run.projectId = getCurrentProjectID();
this.$post(url, run, response => {
let data = response.data;
this.runVisible = false;
this.batchReportId = run.id;
});
},
select(selection) {
this.selection = selection.map(s => s.id);
this.$emit('selection', selection);
},
isSelect(row) {
return this.selection.includes(row.id)
},
edit(row) {
this.$emit('edit', row);
},
reductionApi(row) {
row.scenarioDefinition = null;
row.tags = null;
let rows = [row];
this.$post("/api/automation/reduction", rows, response => {
this.$success(this.$t('commons.save_success'));
this.search();
})
},
execute(row) {
this.infoDb = false;
let url = "/api/automation/run";
let run = {};
let scenarioIds = [];
scenarioIds.push(row.id);
run.id = getUUID();
run.projectId = getCurrentProjectID();
run.scenarioIds = scenarioIds;
this.$post(url, run, response => {
let data = response.data;
this.runVisible = true;
this.reportId = run.id;
});
},
copy(row) {
row.copy = true;
this.$emit('edit', row);
},
showReport(row) {
this.runVisible = true;
this.infoDb = true;
this.reportId = row.reportId;
},
remove(row) {
if (this.trashEnable) {
this.$get('/api/automation/delete/' + row.id, () => {
this.$success(this.$t('commons.delete_success'));
this.search();
});
return;
}
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = [row.id];
this.$post('/api/automation/removeToGc/', ids, () => {
this.$success(this.$t('commons.delete_success'));
this.search();
});
this.$success("批量执行成功,请到报告页面查看详情!");
} else {
setTimeout(this.getReport, 2000)
}
} else {
this.loading = false;
this.$error(this.$t('api_report.not_exist'));
}
});
},
}
}
},
handleBatchExecute() {
this.infoDb = false;
let url = "/api/automation/run/batch";
let run = {};
let scenarioIds = this.selection;
run.id = getUUID();
run.scenarioIds = scenarioIds;
run.projectId = getCurrentProjectID();
run.selectAllDate = this.isSelectAllDate;
run.unSelectIds = this.unSelection;
run = Object.assign(run, this.condition);
this.$post(url, run, response => {
let data = response.data;
this.runVisible = false;
this.batchReportId = run.id;
});
},
select(selection) {
this.selection = selection.map(s => s.id);
//
this.selectRowsCount(this.selection)
this.$emit('selection', selection);
},
isSelect(row) {
return this.selection.includes(row.id)
},
edit(row) {
this.$emit('edit', row);
},
reductionApi(row) {
row.scenarioDefinition = null;
row.tags = null;
let rows = [row];
this.$post("/api/automation/reduction", rows, response => {
this.$success(this.$t('commons.save_success'));
this.search();
})
},
execute(row) {
this.infoDb = false;
let url = "/api/automation/run";
let run = {};
let scenarioIds = [];
scenarioIds.push(row.id);
run.id = getUUID();
run.projectId = getCurrentProjectID();
run.scenarioIds = scenarioIds;
this.$post(url, run, response => {
let data = response.data;
this.runVisible = true;
this.reportId = run.id;
});
},
copy(row) {
row.copy = true;
this.$emit('edit', row);
},
showReport(row) {
this.runVisible = true;
this.infoDb = true;
this.reportId = row.reportId;
},
//
isSelectDataAll(dataType) {
this.isSelectAllDate = dataType;
this.selectRowsCount(this.selection);
//
if (this.selection.length != this.tableData.length) {
this.$refs.scenarioTable.toggleAllSelection(true);
}
},
//
selectRowsCount(selection) {
let selectedIDs = selection;
let allIDs = this.tableData.map(s => s.id);
this.unSelection = allIDs.filter(function (val) {
return selectedIDs.indexOf(val) === -1
});
if (this.isSelectAllDate) {
this.selectDataCounts = this.total - this.unSelection.length;
} else {
this.selectDataCounts = this.selection.length;
}
},
remove(row) {
if (this.trashEnable) {
this.$get('/api/automation/delete/' + row.id, () => {
this.$success(this.$t('commons.delete_success'));
this.search();
});
return;
}
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = [row.id];
this.$post('/api/automation/removeToGc/', ids, () => {
this.$success(this.$t('commons.delete_success'));
this.search();
});
}
}
});
},
}
}
</script>
<style scoped>
/deep/ .el-drawer__header {
margin-bottom: 0px;
}
/deep/ .el-drawer__header {
margin-bottom: 0px;
}
</style>

View File

@ -15,10 +15,9 @@
ref="nodeTree">
<template v-slot:header>
<el-input class="module-input" :placeholder="$t('test_track.module.search')" v-model="condition.filterText"
size="small">
<el-input :placeholder="$t('test_track.module.search')" v-model="condition.filterText" size="small">
<template v-slot:append>
<el-button icon="el-icon-folder-add" @click="addScenario" v-tester/>
<el-button v-if="!isReadOnly" icon="el-icon-folder-add" @click="addScenario" v-tester/>
</template>
</el-input>
<module-trash-button v-if="!isReadOnly" :condition="condition" :exe="enableTrash"/>
@ -247,7 +246,4 @@
width: 30px;
}
.module-input {
width: 275px;
}
</style>

View File

@ -115,7 +115,6 @@
<el-checkbox v-model="enableCookieShare">共享cookie</el-checkbox>
</el-col>
<el-col :span="7" class="ms-font">
{{$t('api_test.definition.request.run_env')}}
<el-select v-model="currentEnvironmentId" size="small" class="ms-htt-width"
:placeholder="$t('api_test.definition.request.run_env')"
clearable>
@ -177,19 +176,21 @@
</el-col>
<!-- 按钮列表 -->
<el-col :span="3">
<vue-fab id="fab" mainBtnColor="#783887" size="small" :global-options="globalOptions"
:click-auto-close="false" v-outside-click="outsideClick">
<fab-item
v-for="(item, index) in buttons"
:key="index"
:idx="getIdx(index)"
:title="item.title"
:title-bg-color="item.titleBgColor"
:title-color="item.titleColor"
:color="item.titleColor"
:icon="item.icon"
@clickItem="item.click"/>
</vue-fab>
<div @click="fabClick">
<vue-fab id="fab" mainBtnColor="#783887" size="small" :global-options="globalOptions"
:click-auto-close="false" v-outside-click="outsideClick">
<fab-item
v-for="(item, index) in buttons"
:key="index"
:idx="getIdx(index)"
:title="item.title"
:title-bg-color="item.titleBgColor"
:title-color="item.titleColor"
:color="item.titleColor"
:icon="item.icon"
@clickItem="item.click"/>
</vue-fab>
</div>
</el-col>
</el-row>
</div>
@ -248,7 +249,7 @@
import InputTag from 'vue-input-tag'
import "@/common/css/material-icons.css"
import OutsideClick from "@/common/js/outside-click";
import ScenarioApiRelevance from "./api/ScenarioApiRelevance";
import ScenarioApiRelevance from "./api/ApiRelevance";
import ScenarioRelevance from "./api/ScenarioRelevance";
export default {
@ -451,9 +452,14 @@
return false;
},
outsideClick(e) {
e.stopPropagation()
e.stopPropagation();
this.showAll();
},
fabClick() {
if (this.operatingElements.length < 1) {
this.$info("引用的场景或接口无法添加配置");
}
},
addComponent(type) {
switch (type) {
case ELEMENT_TYPE.IfController:

View File

@ -1,337 +0,0 @@
<template>
<div>
<el-container style="padding-bottom: 300px">
<el-header style="width: 100% ;padding: 0px">
<el-card>
<el-row>
<el-col :span="2" class="ms-api-col">
<el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
</el-col>
<el-col :span="api.protocol==='HTTP'? 3:6" class="ms-api-col">
<div class="variable-combine"> {{api.name}}</div>
</el-col>
<el-col :span="api.protocol==='HTTP'? 1:3" class="ms-api-col">
<el-tag size="mini" :style="{'background-color': getColor(true, api.method), border: getColor(true, api.method)}" class="api-el-tag">
{{ api.method}}
</el-tag>
</el-col>
<el-col :span="api.protocol==='HTTP'? 5:0" class="ms-api-col">
<div class="variable-combine" style="margin-left: 10px">{{api.path ===null ? " " : api.path}}</div>
</el-col>
<el-col :span="2" class="ms-api-col">
<div>{{$t('test_track.plan_view.case_count')}}{{apiCaseList.length}}</div>
</el-col>
<el-col :span="4">
<div>
<el-select size="small" :placeholder="$t('api_test.definition.request.grade_info')" v-model="priorityValue"
class="ms-api-header-select" @change="getApiTest">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</div>
</el-col>
<el-col :span="4">
<div class="ms-api-header-select">
<el-input size="small" :placeholder="$t('api_test.definition.request.select_case')"
v-model="name" @blur="getApiTest"/>
</div>
</el-col>
<el-col :span="2">
<button type="button" aria-label="Close" class="el-card-btn" @click="apiCaseClose()"><i
class="el-dialog__close el-icon el-icon-close"></i></button>
</el-col>
</el-row>
</el-card>
</el-header>
<!-- 用例部分 -->
<el-main v-loading="loading" style="overflow: auto;padding: 5px 10px 10px">
<el-checkbox-group v-model="checkedIndex" @change="handleCheckedChange">
<div v-for="(item,index) in apiCaseList" :key="index">
<el-card style="margin-top: 5px">
<el-row>
<el-col :span="1" class="ms-api-col">
<el-checkbox :key="item.id" :label="index+1"/>
</el-col>
<el-col :span="3">
<el-select size="small" v-model="item.priority" class="ms-api-select">
<el-option v-for="grd in priority" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</el-col>
<el-col :span="14">
<span v-if="item.type!='create'" style="color: #303132;font-size: 13px">
<i class="icon el-icon-arrow-right" :class="{'is-active': item.active}"
@click="active(item)"/>
{{item.name}}
</span>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span>
{{item.createTime | timestampFormatDate }}
{{item.createUser}} {{$t('api_test.definition.request.create_info')}}
</span>
<span>
{{item.updateTime | timestampFormatDate }}
{{item.updateUser}} {{$t('api_test.definition.request.update_info')}}
</span>
</div>
</el-col>
<el-col :span="6">
<div v-if="item.type!='create'">{{getResult(item.execResult)}}</div>
<div v-if="item.type!='create'" style="color: #999999;font-size: 12px">
<span> {{item.updateTime | timestampFormatDate }}</span>
{{item.updateUser}}
</div>
</el-col>
</el-row>
<!-- 请求参数-->
<el-collapse-transition>
<div v-if="item.active">
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
<ms-api-request-form :is-read-only="isReadOnly" :headers="item.request.headers " :request="item.request" v-if="api.protocol==='HTTP'"/>
<ms-tcp-basis-parameters :request="item.request" v-if="api.protocol==='TCP'"/>
<ms-sql-basis-parameters :request="item.request" v-if="api.protocol==='SQL'"/>
<ms-dubbo-basis-parameters :request="item.request" v-if="api.protocol==='DUBBO'"/>
<!-- 保存操作 -->
<el-button type="primary" size="small" style="margin: 20px; float: right" @click="saveTestCase(item)">
{{$t('commons.save')}}
</el-button>
</div>
</el-collapse-transition>
</el-card>
</div>
</el-checkbox-group>
</el-main>
</el-container>
</div>
</template>
<script>
import MsTag from "../../../../common/components/MsTag";
import MsTipButton from "../../../../common/components/MsTipButton";
import MsApiRequestForm from "../../../definition/components/request/http/ApiRequestForm";
import {downloadFile, getUUID, getCurrentProjectID} from "@/common/js/utils";
import {PRIORITY, RESULT_MAP} from "../../../definition/model/JsonData";
import MsApiAssertions from "../../../definition/components/assertion/ApiAssertions";
import MsSqlBasisParameters from "../../../definition/components/request/database/BasisParameters";
import MsTcpBasisParameters from "../../../definition/components/request/tcp/BasisParameters";
import MsDubboBasisParameters from "../../../definition/components/request/dubbo/BasisParameters";
import MsApiExtendBtns from "../../../definition/components/reference/ApiExtendBtns";
import {API_METHOD_COLOUR} from "../../../definition/model/JsonData";
export default {
name: 'ApiCaseList',
components: {
MsTag,
MsTipButton,
MsApiRequestForm,
MsApiAssertions,
MsSqlBasisParameters,
MsTcpBasisParameters,
MsDubboBasisParameters,
MsApiExtendBtns
},
props: {
api: {
type: Object
},
visible: {
type: String,
},
loaded: Boolean,
refreshSign: String,
currentRow: Object,
},
data() {
return {
grades: [],
environments: [],
environment: {},
name: "",
priorityValue: "",
isReadOnly: false,
selectedEvent: Object,
priority: PRIORITY,
apiCaseList: [],
loading: false,
runData: [],
reportId: "",
projectId: "",
methodColorMap: new Map(API_METHOD_COLOUR),
checkAll: false,
checkedIndex: [],
isIndeterminate: true
}
},
watch: {
//
api() {
this.getApiTest();
},
visible() {
this.getApiTest();
}
},
created() {
this.projectId = getCurrentProjectID();
this.getApiTest();
},
methods: {
getResult(data) {
if (RESULT_MAP.get(data)) {
return RESULT_MAP.get(data);
} else {
return RESULT_MAP.get("default");
}
},
showInput(row) {
row.type = "create";
row.active = true;
this.active(row);
},
apiCaseClose() {
this.apiCaseList = [];
this.$emit('apiCaseClose');
},
active(item) {
item.active = !item.active;
},
getApiTest() {
if (this.api) {
this.loading = true;
if (this.currentRow) {
this.currentRow.cases = [];
}
let condition = {};
condition.projectId = this.projectId;
condition.apiDefinitionId = this.api.id;
condition.priority = this.priorityValue;
condition.name = this.name;
this.$post("/api/testcase/list", condition, response => {
for (let index in response.data) {
let test = response.data[index];
test.checked = false;
test.request = JSON.parse(test.request);
}
this.loading = false;
this.apiCaseList = response.data;
});
}
},
validate(row) {
if (!row.name) {
this.$warning(this.$t('api_test.input_name'));
return true;
}
},
getColor(enable, method) {
if (enable) {
return this.methodColorMap.get(method);
}
},
handleCheckAllChange(val) {
this.currentRow.cases = [];
if (val) {
let index = 1;
this.apiCaseList.forEach(item => {
this.checkedIndex.push(index);
item.protocol = this.api.protocol;
item.hashTree = [];
this.currentRow.cases.push(item)
index++;
})
} else {
this.checkedIndex = [];
}
this.isIndeterminate = false;
},
handleCheckedChange(value) {
let checkedCount = value.length;
this.checkAll = checkedCount === this.apiCaseList.length;
this.isIndeterminate = checkedCount > 0 && checkedCount < this.apiCaseList.length;
this.currentRow.cases = [];
value.forEach(i => {
let index = i - 1;
let item = this.apiCaseList[index];
item.protocol = this.api.protocol;
item.hashTree = [];
this.currentRow.cases.push(item);
})
}
}
}
</script>
<style scoped>
.ms-api-select {
margin-left: 20px;
width: 80px;
}
.ms-api-header-select {
margin-left: 20px;
min-width: 100px;
}
.el-card-btn {
float: right;
top: 20px;
right: 0px;
padding: 0;
background: 0 0;
border: none;
outline: 0;
cursor: pointer;
font-size: 18px;
margin-left: 30px;
}
.ms-api-label {
/*color: #CCCCCC;*/
}
.ms-api-col {
margin-top: 5px;
}
.variable-combine {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 10px;
}
.icon.is-active {
transform: rotate(90deg);
}
.tip {
padding: 3px 5px;
font-size: 16px;
border-radius: 4px;
border-left: 4px solid #783887;
margin: 20px 0;
}
.environment-button {
margin-left: 20px;
padding: 7px;
}
.api-el-tag {
color: white;
}
.is-selected {
background: #EFF7FF;
}
</style>

View File

@ -1,150 +0,0 @@
<template>
<ms-container>
<ms-aside-container>
<ms-node-tree @nodeSelectEvent="selectModule" @getApiModuleTree="initTree" @protocolChange="changeProtocol"
@refresh="refresh" @saveAsEdit="editApi" @exportAPI="exportAPI"/>
</ms-aside-container>
<ms-main-container>
<!-- 主框架列表 -->
<el-tabs v-model="apiDefaultTab">
<el-tab-pane
:key="item.name"
v-for="(item) in apiTabs"
:label="item.title"
:closable="item.closable"
:name="item.name">
<!-- 列表集合 -->
<ms-api-list
v-if="item.type === 'list'"
:current-protocol="currentProtocol"
:current-module="currentModule"
@editApi="editApi"
@handleCase="handleCase"
:visible="visible"
:currentRow="currentRow"
ref="apiList"/>
</el-tab-pane>
</el-tabs>
</ms-main-container>
</ms-container>
</template>
<script>
import MsNodeTree from '../../../definition/components/module/ApiModule';
import MsApiList from './ApiList';
import MsContainer from "../../../../common/components/MsContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import {downloadFile, getCurrentUser, getUUID, getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiDefinition",
components: {
MsNodeTree,
MsApiList,
MsMainContainer,
MsContainer,
MsAsideContainer,
},
props: {
visible: {
type: String,
},
currentRow: {
type: Object,
}
},
data() {
return {
isHide: true,
apiDefaultTab: 'default',
currentProtocol: null,
currentModule: null,
currentApi: {},
moduleOptions: {},
runTestData: {},
apiTabs: [{
title: this.$t('api_test.definition.api_title'),
name: 'default',
type: "list",
closable: false
}],
}
},
methods: {
editApi(row) {
this.currentApi = row;
},
handleCase(testCase) {
this.currentApi = testCase;
this.isHide = false;
},
apiCaseClose() {
this.isHide = true;
},
selectModule(data) {
this.currentModule = data.data;
},
exportAPI() {
if (!this.$refs.apiList[0].tableData) {
return;
}
let obj = {projectName: getCurrentProjectID(), protocol: this.currentProtocol, data: this.$refs.apiList[0].tableData}
downloadFile("导出API.json", JSON.stringify(obj));
},
refresh(data) {
this.$refs.apiList[0].initApiTable(data);
},
setTabTitle(data) {
for (let index in this.apiTabs) {
let tab = this.apiTabs[index];
if (tab.name === this.apiDefaultTab) {
tab.title = this.$t('api_test.definition.request.edit_api') + "-" + data.name;
break;
}
}
this.runTestData = data;
},
saveApi(data) {
this.setTabTitle(data);
this.$refs.apiList[0].initApiTable(data);
},
initTree(data) {
this.moduleOptions = data;
},
changeProtocol(data) {
this.currentProtocol = data;
}
}
}
</script>
<style scoped>
.ms-api-buttion {
position: absolute;
top: 100px;
right: 4px;
padding: 0;
background: 0 0;
border: none;
outline: 0;
cursor: pointer;
margin-right: 10px;
font-size: 16px;
}
.ms-api-div {
overflow-y: auto;
height: calc(100vh - 155px)
}
/deep/ .el-tabs__header {
margin: 0 0 5px;
}
/deep/ .el-main {
overflow: hidden;
}
</style>

View File

@ -1,412 +0,0 @@
<template>
<div id="svgBox" style="overflow: auto">
<div id="svgTop" style="background-color: white">
<el-card class="card-content">
<el-input placeholder="搜索" @blur="search" style="float: right ;width: 300px;margin-bottom: 20px;margin-right: 20px" size="small" v-model="condition.name"/>
<el-table border :data="tableData" row-key="id" class="test-content adjust-table"
@select-all="handleSelectAll"
@select="handleSelect" :height="screenHeight">
<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('api_test.definition.api_name')" show-overflow-tooltip/>
<el-table-column
prop="status"
column-key="api_status"
:label="$t('api_test.definition.api_status')"
show-overflow-tooltip>
<template v-slot:default="scope">
<ms-tag v-if="scope.row.status == 'Prepare'" type="info" effect="plain" :content="$t('test_track.plan.plan_status_prepare')"/>
<ms-tag v-if="scope.row.status == 'Underway'" type="warning" effect="plain" :content="$t('test_track.plan.plan_status_running')"/>
<ms-tag v-if="scope.row.status == 'Completed'" type="success" effect="plain" :content="$t('test_track.plan.plan_status_completed')"/>
<ms-tag v-if="scope.row.status == 'Trash'" type="danger" effect="plain" content="废弃"/>
</template>
</el-table-column>
<el-table-column
prop="method"
:label="$t('api_test.definition.api_type')"
show-overflow-tooltip>
<template v-slot:default="scope" class="request-method">
<el-tag size="mini" :style="{'background-color': getColor(true, scope.row.method)}" class="api-el-tag">
{{ scope.row.method}}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="path"
:label="$t('api_test.definition.api_path')"
show-overflow-tooltip/>
<el-table-column
prop="userName"
:label="$t('api_test.definition.api_principal')"
show-overflow-tooltip/>
<el-table-column width="160" :label="$t('api_test.definition.api_last_time')" prop="updateTime">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
</template>
</el-table-column>
<el-table-column
prop="caseTotal"
:label="$t('api_test.definition.api_case_number')"
show-overflow-tooltip/>
<el-table-column
prop="caseStatus"
:label="$t('api_test.definition.api_case_status')"
show-overflow-tooltip/>
<!-- <el-table-column
prop="casePassingRate"
:label="$t('api_test.definition.api_case_passing_rate')"
show-overflow-tooltip/>-->
<el-table-column :label="$t('commons.operating')" min-width="80" align="center">
<template v-slot:default="scope">
<el-button type="text" @click="handleTestCase(scope.row)">用例</el-button>
</template>
</el-table-column>
</el-table>
<ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize"
:total="total"/>
</el-card>
</div>
<div id="svgResize"/>
<div id="svgDown">
<ms-bottom-container v-bind:enableAsideHidden="isHide">
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="initTable" :visible="visible" :currentRow="currentRow" :api="selectApi"/>
</ms-bottom-container>
</div>
</div>
</template>
<script>
import MsTableHeader from '../../../../../components/common/components/MsTableHeader';
import MsTableOperator from "../../../../common/components/MsTableOperator";
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
import MsTableButton from "../../../../common/components/MsTableButton";
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
import MsTablePagination from "../../../../common/pagination/TablePagination";
import MsTag from "../../../../common/components/MsTag";
import MsApiCaseList from "./ApiCaseList";
import MsContainer from "../../../../common/components/MsContainer";
import MsBottomContainer from "../../../definition/components/BottomContainer";
import ShowMoreBtn from "../../../../../components/track/case/components/ShowMoreBtn";
import {API_METHOD_COLOUR} from "../../../definition/model/JsonData";
import {getCurrentProjectID} from "@/common/js/utils";
export default {
name: "ApiList",
components: {
MsTableButton,
MsTableOperatorButton,
MsTableOperator,
MsTableHeader,
MsTablePagination,
MsTag,
MsApiCaseList,
MsContainer,
MsBottomContainer,
ShowMoreBtn
},
data() {
return {
condition: {},
isHide: true,
selectApi: {},
moduleId: "",
deletePath: "/test/case/delete",
selectRows: new Set(),
buttons: [{name: this.$t('api_test.definition.request.batch_delete'), handleClick: this.handleDeleteBatch}],
methodColorMap: new Map(API_METHOD_COLOUR),
tableData: [],
currentPage: 1,
pageSize: 10,
total: 0,
projectId: "",
screenHeight: document.documentElement.clientHeight - 330,//
}
},
props: {
currentProtocol: String,
currentModule: Object,
visible: {
type: String,
},
currentRow: {
type: Object,
}
},
created: function () {
this.projectId = getCurrentProjectID();
this.initTable();
},
mounted() {
this.dragControllerDiv();
},
watch: {
currentModule() {
this.initTable();
this.apiCaseClose();
},
visible() {
this.initTable();
this.apiCaseClose();
},
currentProtocol() {
this.initTable();
this.apiCaseClose();
},
},
methods: {
initTable() {
this.selectRows = new Set();
this.condition.filters = ["Prepare", "Underway", "Completed"];
if (this.currentModule) {
this.condition.moduleIds = [this.currentModule.id];
}
if (this.trashEnable) {
this.condition.filters = ["Trash"];
this.condition.moduleIds = [];
}
if (this.projectId != null) {
this.condition.projectId = this.projectId;
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
this.result = this.$post("/api/definition/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
});
},
handleSelect(selection, row) {
row.hashTree = [];
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);
if (this.currentRow) {
this.currentRow.apis = arr;
}
// 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) {
selection.hashTree = [];
this.selectRows.add(selection[0]);
} else {
this.tableData.forEach(item => {
item.hashTree = [];
this.$set(item, "showMore", true);
this.selectRows.add(item);
});
}
} else {
this.selectRows.clear();
this.tableData.forEach(row => {
this.$set(row, "showMore", false);
})
}
if (this.currentRow) {
let arr = Array.from(this.selectRows);
this.currentRow.apis = arr;
}
},
search() {
this.initTable();
},
buildPagePath(path) {
return path + "/" + this.currentPage + "/" + this.pageSize;
},
editApi(row) {
this.$emit('editApi', row);
},
reductionApi(row) {
row.status = 'Underway';
row.request = null;
row.response = null;
this.$fileUpload("/api/definition/update", null, [], row, () => {
this.$success(this.$t('commons.save_success'));
this.search();
});
},
handleDeleteBatch() {
if (this.currentModule != undefined && this.currentModule.id == "gc") {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/api/definition/deleteBatch/', ids, () => {
this.selectRows.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
});
}
}
});
} else {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + "", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/api/definition/removeToGc/', ids, () => {
this.selectRows.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
});
}
}
});
}
},
handleTestCase(testCase) {
let h = window.screen.height;
let svgTop = document.getElementById("svgTop");
svgTop.style.height = h / 2 - 200 + "px";
let svgDown = document.getElementById("svgDown");
svgDown.style.height = h / 2 + "px";
this.selectApi = testCase;
let request = JSON.parse(testCase.request);
this.selectApi.url = request.path;
this.isHide = false;
},
handleDelete(api) {
if (this.currentModule != undefined && this.currentModule.id == "gc") {
this.$get('/api/definition/delete/' + api.id, () => {
this.$success(this.$t('commons.delete_success'));
this.initTable();
});
return;
}
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + api.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let ids = [api.id];
this.$post('/api/definition/removeToGc/', ids, () => {
this.$success(this.$t('commons.delete_success'));
this.initTable();
});
}
}
});
},
apiCaseClose() {
this.selectApi = {};
let h = window.screen.height;
let svgTop = document.getElementById("svgTop");
svgTop.style.height = h - 200 + "px";
let svgDown = document.getElementById("svgDown");
svgDown.style.height = 0 + "px";
this.isHide = true;
},
getColor(enable, method) {
if (enable) {
return this.methodColorMap.get(method);
}
},
dragControllerDiv: function () {
let svgResize = document.getElementById("svgResize");
let svgTop = document.getElementById("svgTop");
let svgDown = document.getElementById("svgDown");
let svgBox = document.getElementById("svgBox");
svgResize.onmousedown = function (e) {
let startY = e.clientY;
svgResize.top = svgResize.offsetTop;
document.onmousemove = function (e) {
let endY = e.clientY;
let moveLen = svgResize.top + (endY - startY);
let maxT = svgBox.clientHeight - svgResize.offsetHeight;
if (moveLen < 30) moveLen = 30;
if (moveLen > maxT - 30) moveLen = maxT - 30;
svgResize.style.top = moveLen;
svgTop.style.height = moveLen + "px";
svgDown.style.height = (svgBox.clientHeight - moveLen - 5) + "px";
}
document.onmouseup = function (evt) {
document.onmousemove = null;
document.onmouseup = null;
svgResize.releaseCapture && svgResize.releaseCapture();
}
svgResize.setCapture && svgResize.setCapture();
return false;
}
},
}
}
</script>
<style scoped>
.operate-button > div {
display: inline-block;
margin-left: 10px;
}
.request-method {
padding: 0 5px;
color: #1E90FF;
}
.api-el-tag {
color: white;
}
#svgBox {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
#svgTop {
height: calc(30% - 5px);
width: 100%;
float: left;
overflow: auto;
}
#svgResize {
position: relative;
height: 5px;
width: 100%;
cursor: s-resize;
float: left;
}
#svgDown {
height: 70%;
width: 100%;
float: left;
overflow: hidden;
}
</style>

View File

@ -1,64 +1,56 @@
<template>
<el-dialog class="api-relevance" :title="'接口导入'"
:visible.sync="dialogVisible"
width="70%"
:close-on-click-modal="false"
top="50px">
<relevance-dialog :title="'接口导入'" ref="relevanceDialog">
<ms-container>
<ms-aside-container :enable-aside-hidden="false">
<ms-api-module
@nodeSelectEvent="nodeChange"
@protocolChange="handleProtocolChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
:is-read-only="true"
ref="nodeTree"/>
</ms-aside-container>
<template v-slot:aside>
<ms-api-module
@nodeSelectEvent="nodeChange"
@protocolChange="handleProtocolChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
:is-read-only="true"
ref="nodeTree"/>
</template>
<ms-main-container>
<scenario-relevance-api-list
v-if="isApiListEnable"
:current-protocol="currentProtocol"
:select-node-ids="selectNodeIds"
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange"
ref="apiList"
/>
<scenario-relevance-api-list
v-if="isApiListEnable"
:current-protocol="currentProtocol"
:select-node-ids="selectNodeIds"
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange"
ref="apiList"/>
<scenario-relevance-case-list
v-if="!isApiListEnable"
:current-protocol="currentProtocol"
:select-node-ids="selectNodeIds"
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange"
ref="apiCaseList"/>
</ms-main-container>
</ms-container>
<scenario-relevance-case-list
v-if="!isApiListEnable"
:current-protocol="currentProtocol"
:select-node-ids="selectNodeIds"
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange"
ref="apiCaseList"/>
<template v-slot:footer>
<el-button type="primary" @click="copy" @keydown.enter.native.prevent>复制</el-button>
<el-button v-if="!isApiListEnable" type="primary" @click="reference" @keydown.enter.native.prevent>引用</el-button>
</template>
</el-dialog>
</relevance-dialog>
</template>
<script>
import ScenarioRelevanceCaseList from "./ScenarioRelevanceCaseList";
import ScenarioRelevanceCaseList from "./RelevanceCaseList";
import MsApiModule from "../../../definition/components/module/ApiModule";
import MsContainer from "../../../../common/components/MsContainer";
import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import ScenarioRelevanceApiList from "./ScenarioRelevanceApiList";
import ScenarioRelevanceApiList from "./RelevanceApiList";
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
export default {
name: "ScenarioApiRelevance",
name: "ApiRelevance",
components: {
RelevanceDialog,
ScenarioRelevanceApiList,
MsMainContainer, MsAsideContainer, MsContainer, MsApiModule, ScenarioRelevanceCaseList},
data() {
return {
dialogVisible: false,
result: {},
currentProtocol: null,
selectNodeIds: [],
@ -91,10 +83,10 @@
},
close() {
this.refresh();
this.dialogVisible = false;
this.$refs.relevanceDialog.close();
},
open() {
this.dialogVisible = true;
this.$refs.relevanceDialog.open();
},
isApiListEnableChange(data) {
this.isApiListEnable = data;
@ -120,13 +112,4 @@
</script>
<style scoped>
.ms-aside-container {
border: 0px;
}
.api-relevance >>> .el-dialog__body {
padding: 10px 20px;
}
</style>

View File

@ -3,6 +3,8 @@
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange">
<ms-environment-select :project-id="projectId" v-if="isTestPlan" :is-read-only="isReadOnly" @setEnvironment="setEnvironment"/>
<el-input placeholder="搜索" @blur="initTable" class="search-input" size="small" @keyup.enter.native="initTable" v-model="condition.name"/>
<el-table v-loading="result.loading"
@ -43,11 +45,6 @@
:label="$t('api_test.definition.api_path')"
show-overflow-tooltip/>
<el-table-column
prop="userName"
:label="$t('api_test.definition.api_principal')"
show-overflow-tooltip/>
<el-table-column width="160" :label="$t('api_test.definition.api_last_time')" prop="updateTime">
<template v-slot:default="scope">
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
@ -90,10 +87,12 @@
import PriorityTableItem from "../../../../track/common/tableItems/planview/PriorityTableItem";
import {_filter, _sort} from "../../../../../../common/js/utils";
import {_handleSelect, _handleSelectAll} from "../../../../../../common/js/tableUtils";
import MsEnvironmentSelect from "../../../definition/components/case/MsEnvironmentSelect";
export default {
name: "ScenarioRelevanceApiList",
name: "RelevanceApiList",
components: {
MsEnvironmentSelect,
PriorityTableItem,
ApiListContainer,
MsTableOperatorButton,
@ -129,6 +128,7 @@
currentPage: 1,
pageSize: 10,
total: 0,
environmentId: ""
}
},
props: {
@ -150,8 +150,9 @@
type: Boolean,
default: false,
},
relevanceProjectId: String,
planId: String
projectId: String,
planId: String,
isTestPlan: Boolean
},
created: function () {
this.initTable();
@ -163,6 +164,9 @@
currentProtocol() {
this.initTable();
},
projectId() {
this.initTable();
}
},
computed: {},
methods: {
@ -179,12 +183,19 @@
}
if (this.projectId != null) {
this.condition.projectId = this.projectId;
} else {
this.condition.projectId = getCurrentProjectID();
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
this.condition.projectId = getCurrentProjectID();
this.result = this.$post("/api/definition/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
let url = '/api/definition/list/';
if (this.isTestPlan) {
url = '/api/definition/list/relevance/';
this.condition.planId = this.planId;
}
this.result = this.$post(url + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
});
@ -218,6 +229,9 @@
getColor(method) {
return this.methodColorMap.get(method);
},
setEnvironment(data) {
this.environmentId = data.id;
}
},
}
</script>

View File

@ -4,6 +4,8 @@
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange">
<ms-environment-select :project-id="projectId" v-if="isTestPlan" :is-read-only="isReadOnly" @setEnvironment="setEnvironment"/>
<el-input placeholder="搜索" @blur="initTable" @keyup.enter.native="initTable" class="search-input" size="small" v-model="condition.name"/>
<el-table v-loading="result.loading"
@ -73,10 +75,12 @@
import PriorityTableItem from "../../../../track/common/tableItems/planview/PriorityTableItem";
import {_filter, _sort} from "../../../../../../common/js/utils";
import {_handleSelect, _handleSelectAll} from "../../../../../../common/js/tableUtils";
import MsEnvironmentSelect from "../../../definition/components/case/MsEnvironmentSelect";
export default {
name: "ScenarioRelevanceCaseList",
name: "RelevanceCaseList",
components: {
MsEnvironmentSelect,
PriorityTableItem,
ApiListContainer,
MsTableOperatorButton,
@ -111,6 +115,7 @@
currentPage: 1,
pageSize: 10,
total: 0,
environmentId: ""
}
},
props: {
@ -132,8 +137,9 @@
type: Boolean,
default: false,
},
relevanceProjectId: String,
planId: String
projectId: String,
planId: String,
isTestPlan: Boolean
},
created: function () {
this.initTable();
@ -145,6 +151,9 @@
currentProtocol() {
this.initTable();
},
projectId() {
this.initTable();
}
},
computed: {
@ -157,11 +166,22 @@
this.selectRows = new Set();
this.condition.status = "";
this.condition.moduleIds = this.selectNodeIds;
if (this.projectId != null) {
this.condition.projectId = this.projectId;
} else {
this.condition.projectId = getCurrentProjectID();
}
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
this.condition.projectId = getCurrentProjectID();
this.result = this.$post("/api/testcase/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
let url = '/api/testcase/list/';
if (this.isTestPlan) {
url = '/test/plan/api/case/relevance/list/';
this.condition.planId = this.planId;
}
this.result = this.$post(url + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
});
@ -209,6 +229,9 @@
this.$refs.caseList.open(selectApi, testCase.id);
});
},
setEnvironment(data) {
this.environmentId = data.id;
}
},
}
</script>

View File

@ -1,12 +1,7 @@
<template>
<el-dialog class="api-relevance" :title="'场景导入'"
:visible.sync="dialogVisible"
width="70%"
:close-on-click-modal="false"
top="50px">
<relevance-dialog :title="'场景导入'" ref="relevanceDialog">
<ms-container>
<ms-aside-container :enable-aside-hidden="false">
<template v-slot:aside>
<ms-api-scenario-module
@nodeSelectEvent="nodeChange"
@refreshTable="refresh"
@ -14,51 +9,48 @@
@enableTrash="false"
:is-read-only="true"
ref="nodeTree"/>
</ms-aside-container>
</template>
<ms-main-container>
<ms-api-scenario-list
:select-node-ids="selectNodeIds"
:referenced="true"
:trash-enable="false"
@selection="setData"
ref="apiScenarioList"/>
</ms-main-container>
</ms-container>
<ms-api-scenario-list
:select-node-ids="selectNodeIds"
:referenced="true"
:trash-enable="false"
@selection="setData"
ref="apiScenarioList"/>
<template v-slot:footer>
<el-button type="primary" @click="copy" @keydown.enter.native.prevent>复制</el-button>
<el-button type="primary" @click="reference" @keydown.enter.native.prevent>引用</el-button>
</template>
</el-dialog>
</relevance-dialog>
</template>
<script>
import ScenarioRelevanceCaseList from "./ScenarioRelevanceCaseList";
import ScenarioRelevanceCaseList from "./RelevanceCaseList";
import MsApiModule from "../../../definition/components/module/ApiModule";
import MsContainer from "../../../../common/components/MsContainer";
import MsAsideContainer from "../../../../common/components/MsAsideContainer";
import MsMainContainer from "../../../../common/components/MsMainContainer";
import ScenarioRelevanceApiList from "./ScenarioRelevanceApiList";
import ScenarioRelevanceApiList from "./RelevanceApiList";
import MsApiScenarioModule from "../ApiScenarioModule";
import MsApiScenarioList from "../ApiScenarioList";
import {getUUID} from "../../../../../../common/js/utils";
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
export default {
name: "ScenarioRelevance",
components: {
RelevanceDialog,
MsApiScenarioList,
MsApiScenarioModule,
MsMainContainer, MsAsideContainer, MsContainer},
data() {
return {
dialogVisible: false,
result: {},
currentProtocol: null,
selectNodeIds: [],
moduleOptions: {},
isApiListEnable: true,
currentScenario: [],
currentScenarioIds: [],
}
@ -97,10 +89,10 @@
},
close() {
this.refresh();
this.dialogVisible = false;
this.$refs.relevanceDialog.close();
},
open() {
this.dialogVisible = true;
this.$refs.relevanceDialog.open();
if (this.$refs.apiScenarioList) {
this.$refs.apiScenarioList.search();
}
@ -127,12 +119,4 @@
<style scoped>
.ms-aside-container {
border: 0px;
}
.api-relevance >>> .el-dialog__body {
padding: 10px 20px;
}
</style>

View File

@ -20,11 +20,20 @@
<div>
<el-select size="small" :placeholder="$t('api_test.definition.request.grade_info')" v-model="condition.priority"
:disabled="isCaseEdit"
class="ms-api-header-select" @change="getApiTest" clearable style="margin-right: 20px">
class="ms-api-header-select" @change="getApiTest" clearable>
<el-option v-for="grd in priorities" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</div>
</el-col>
<el-col :span="3">
<div class="ms-api-header-select" style="margin-right: 20px">
<el-input size="small" :placeholder="$t('api_test.definition.request.select_case')"
:disabled="isCaseEdit"
v-model="condition.name" @blur="getApiTest" @keyup.enter.native="getApiTest" />
</div>
</el-col>
<el-col :span="4">
<div>
<ms-environment-select
@ -33,13 +42,7 @@
@setEnvironment="setEnvironment"/>
</div>
</el-col>
<el-col :span="3">
<div class="ms-api-header-select">
<el-input size="small" :placeholder="$t('api_test.definition.request.select_case')"
:disabled="isCaseEdit"
v-model="condition.name" @blur="getApiTest" @keyup.enter.native="getApiTest"/>
</div>
</el-col>
<el-col :span="2" v-if="!(isReadOnly || isCaseEdit)">
<el-dropdown size="small" split-button type="primary" class="ms-api-header-select" @click="addCase"
@command="handleCommand" v-tester>
@ -56,17 +59,17 @@
<script>
import ApiEnvironmentConfig from "../../../test/components/ApiEnvironmentConfig";
import {parseEnvironment} from "../../../test/model/EnvironmentModel";
import MsTag from "../../../../common/components/MsTag";
import MsEnvironmentSelect from "./MsEnvironmentSelect";
import {API_METHOD_COLOUR} from "../../model/JsonData";
import ApiEnvironmentConfig from "../../../test/components/ApiEnvironmentConfig";
import {parseEnvironment} from "../../../test/model/EnvironmentModel";
import MsTag from "../../../../common/components/MsTag";
import MsEnvironmentSelect from "./MsEnvironmentSelect";
import {API_METHOD_COLOUR} from "../../model/JsonData";
export default {
name: "ApiCaseHeader",
components: {MsEnvironmentSelect, MsTag, ApiEnvironmentConfig},
data() {
return {
export default {
name: "ApiCaseHeader",
components: {MsEnvironmentSelect, MsTag, ApiEnvironmentConfig},
data() {
return {
environments: [],
environment: {},
methodColorMap: new Map(API_METHOD_COLOUR),
@ -171,7 +174,6 @@
font-size: 10px;
}
.el-col {
height: 32px;
line-height: 32px;

View File

@ -1,24 +1,10 @@
<template>
<div>
<api-list-container
:is-show-change-button="!isPlanModel"
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange">
<ms-environment-select v-if="isRelevanceModel" :project-id="relevanceProjectId" :is-read-only="isReadOnly" @setEnvironment="setEnvironment"/>
<el-input v-if="!isPlanModel" placeholder="搜索" @blur="search" @keyup.enter.native="search" class="search-input" size="small" v-model="condition.name"/>
<template v-slot:header>
<test-plan-case-list-header
:project-id="getProjectId()"
:condition="condition"
:plan-id="planId"
@refresh="initTable"
@relevanceCase="$emit('relevanceCase')"
@setEnvironment="setEnvironment"
v-if="isPlanModel"/>
</template>
<el-input placeholder="搜索" @blur="search" @keyup.enter.native="search" class="search-input" size="small" v-model="condition.name"/>
<el-table v-loading="result.loading"
border
@ -30,7 +16,7 @@
<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 && !isReadOnly && !isRelevanceModel" :buttons="buttons" :size="selectRows.size"/>
<show-more-btn :is-show="scope.row.showMore && !isReadOnly" :buttons="buttons" :size="selectRows.size"/>
</template>
</el-table-column>
@ -69,7 +55,7 @@
</template>
</el-table-column>
<el-table-column v-if="!isReadOnly && !isRelevanceModel" :label="$t('commons.operating')" min-width="130" align="center">
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" min-width="130" align="center">
<template v-slot:default="scope">
<!--<el-button type="text" @click="reductionApi(scope.row)" v-if="trashEnable">{{$t('commons.reduction')}}</el-button>-->
<el-button type="text" @click="handleTestCase(scope.row)" v-if="!trashEnable">{{$t('commons.edit')}}</el-button>
@ -82,9 +68,9 @@
:total="total"/>
</api-list-container>
<api-case-list v-if="!isRelevanceModel" @showExecResult="showExecResult" @refresh="initTable" :currentApi="selectCase" ref="caseList"/>
<api-case-list @showExecResult="showExecResult" @refresh="initTable" :currentApi="selectCase" ref="caseList"/>
<!--批量编辑-->
<ms-batch-edit v-if="!isRelevanceModel" ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr"/>
<ms-batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr"/>
</div>
</template>
@ -109,12 +95,11 @@
import {_filter, _sort} from "../../../../../../common/js/utils";
import TestPlanCaseListHeader from "../../../../track/plan/view/comonents/api/TestPlanCaseListHeader";
import MsEnvironmentSelect from "../case/MsEnvironmentSelect";
import {_handleSelect, _handleSelectAll} from "../../../../../../common/js/tableUtils";
export default {
name: "ApiCaseSimpleList",
components: {
MsEnvironmentSelect,
TestPlanCaseListHeader,
ApiCaseList,
PriorityTableItem,
ApiListContainer,
@ -213,14 +198,7 @@
}
},
computed: {
//
isRelevanceModel() {
return this.model === 'relevance'
},
//
isPlanModel() {
return this.model === 'plan'
},
//
isApiModel() {
return this.model === 'api'
@ -232,7 +210,6 @@
},
initTable() {
this.selectRows = new Set();
// this.condition.filters = ["Prepare", "Underway", "Completed"];
this.condition.status = "";
this.condition.moduleIds = this.selectNodeIds;
if (this.trashEnable) {
@ -240,46 +217,18 @@
this.condition.moduleIds = [];
}
this.buildCondition(this.condition);
this.condition.projectId = getCurrentProjectID();
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
if (this.condition.projectId) {
this.result = this.$post(this.getListUrl() + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.result = this.$post('/api/testcase/list/' + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
});
}
},
buildCondition(condition) {
if (this.isPlanModel) {
condition.planId = this.planId;
} else if (this.isRelevanceModel) {
condition.planId = this.planId;
condition.projectId = this.getProjectId();
} else {
condition.projectId = this.getProjectId();
}
},
getListUrl() {
if (this.isPlanModel) {
return '/test/plan/api/case/list/';
} else if (this.isRelevanceModel) {
return '/test/plan/api/case/relevance/list/';
} else {
return '/api/testcase/list/';
}
},
getDeleteUrl(apiCase) {
if (this.isPlanModel) {
return '/test/plan/api/case/delete/' + this.planId + '/' + apiCase.id;
} else if (this.isRelevanceModel) {
return '/api/testcase/delete/' + apiCase.id;
} else {
return '/api/testcase/delete/' + apiCase.id;
}
},
// getMaintainerOptions() {
// let workspaceId = localStorage.getItem(WORKSPACE_ID);
// this.$post('/user/ws/member/tester/list', {workspaceId: workspaceId}, response => {
@ -287,23 +236,7 @@
// });
// },
handleSelect(selection, row) {
row.hashTree = [];
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);
})
}
_handleSelect(this, selection, row, this.selectRows);
},
showExecResult(row) {
this.visible = false;
@ -322,23 +255,7 @@
this.initTable();
},
handleSelectAll(selection) {
if (selection.length > 0) {
if (selection.length === 1) {
selection.hashTree = [];
this.selectRows.add(selection[0]);
} else {
this.tableData.forEach(item => {
item.hashTree = [];
this.$set(item, "showMore", true);
this.selectRows.add(item);
});
}
} else {
this.selectRows.clear();
this.tableData.forEach(row => {
this.$set(row, "showMore", false);
})
}
_handleSelectAll(this, selection, this.tableData, this.selectRows);
},
search() {
this.initTable();
@ -377,7 +294,7 @@
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$post(this.getBatchDeleteParam(), this.buildBatchDeleteParam(), () => {
this.$post('/api/testcase/deleteBatch/', Array.from(this.selectRows).map(row => row.id), () => {
this.selectRows.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
@ -401,23 +318,6 @@
// });
// }
},
buildBatchDeleteParam() {
if (this.isPlanModel) {
let request = {};
request.ids = Array.from(this.selectRows).map(row => row.id);
request.planId = this.planId;
return request;
} else {
return Array.from(this.selectRows).map(row => row.id);
}
},
getBatchDeleteParam() {
if (this.isPlanModel) {
return '/test/plan/api/case/batch/delete';
} else {
return '/api/testcase/deleteBatch/';
}
},
handleEditBatch() {
this.$refs.batchEdit.open();
},
@ -434,7 +334,7 @@
},
handleDelete(apiCase) {
// if (this.trashEnable) {
this.$get(this.getDeleteUrl(apiCase), () => {
this.$get('/api/testcase/delete/' + apiCase.id, () => {
this.$success(this.$t('commons.delete_success'));
this.initTable();
});
@ -453,13 +353,6 @@
// }
// });
},
getProjectId() {
if (!this.isRelevanceModel) {
return getCurrentProjectID();
} else {
return this.relevanceProjectId;
}
},
setEnvironment(data) {
this.environmentId = data.id;
}

View File

@ -4,19 +4,31 @@
:is-api-list-enable="isApiListEnable"
@isApiListEnableChange="isApiListEnableChange">
<ms-environment-select :project-id="relevanceProjectId" v-if="isRelevance" :is-read-only="isReadOnly" @setEnvironment="setEnvironment"/>
<el-input placeholder="搜索" @blur="search" class="search-input" size="small" @keyup.enter.native="search" v-model="condition.name"/>
<el-table v-loading="result.loading"
ref="apiDefinitionTable"
border
:data="tableData" row-key="id" class="test-content adjust-table"
@select-all="handleSelectAll"
@select="handleSelect" :height="screenHeight">
<el-table-column type="selection"/>
<el-table-column width="40" :resizable="false" align="center">
<el-dropdown slot="header" style="width: 14px">
<span class="el-dropdown-link" style="width: 14px">
<i class="el-icon-arrow-down el-icon--right" style="margin-left: 0px"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item @click.native.stop="isSelectDataAll(true)">
{{$t('api_test.batch_menus.select_all_data',[total])}}
</el-dropdown-item>
<el-dropdown-item @click.native.stop="isSelectDataAll(false)">
{{$t('api_test.batch_menus.select_show_data',[tableData.length])}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<template v-slot:default="scope">
<show-more-btn :is-show="scope.row.showMore && !isReadOnly && !isRelevance" :buttons="buttons" :size="selectRows.size"/>
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/>
</template>
</el-table-column>
@ -77,7 +89,7 @@
:label="$t('api_test.definition.api_case_passing_rate')"
show-overflow-tooltip/>
<el-table-column v-if="!isReadOnly && !isRelevance" :label="$t('commons.operating')" min-width="130" align="center">
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" min-width="130" align="center">
<template v-slot:default="scope">
<el-button type="text" @click="reductionApi(scope.row)" v-if="trashEnable" v-tester>{{$t('commons.reduction')}}</el-button>
<el-button type="text" @click="editApi(scope.row)" v-else v-tester>{{$t('commons.edit')}}</el-button>
@ -114,12 +126,10 @@
import {getCurrentProjectID} from "@/common/js/utils";
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
import ApiListContainer from "./ApiListContainer";
import MsEnvironmentSelect from "../case/MsEnvironmentSelect";
export default {
name: "ApiList",
components: {
MsEnvironmentSelect,
ApiListContainer,
MsTableButton,
MsTableOperatorButton,
@ -161,7 +171,10 @@
pageSize: 10,
total: 0,
screenHeight: document.documentElement.clientHeight - 330,//,
environmentId: undefined
environmentId: undefined,
selectAll: false,
unSelection:[],
selectDataCounts:0,
}
},
props: {
@ -184,8 +197,6 @@
type: Boolean,
default: false
},
relevanceProjectId: String,
isRelevance: Boolean
},
created: function () {
this.initTable();
@ -202,9 +213,6 @@
if (this.trashEnable) {
this.initTable();
}
},
relevanceProjectId() {
this.initTable();
}
},
methods: {
@ -213,6 +221,11 @@
},
initTable() {
this.selectRows = new Set();
this.selectAll = false;
this.unSelection = [];
this.selectDataCounts = 0;
this.condition.filters = ["Prepare", "Underway", "Completed"];
this.condition.moduleIds = this.selectNodeIds;
@ -221,7 +234,7 @@
this.condition.moduleIds = [];
}
this.condition.projectId = this.getProjectId();
this.condition.projectId = getCurrentProjectID();
if (this.currentProtocol != null) {
this.condition.protocol = this.currentProtocol;
}
@ -229,6 +242,7 @@
this.result = this.$post("/api/definition/list/" + this.currentPage + "/" + this.pageSize, this.condition, response => {
this.total = response.data.itemCount;
this.tableData = response.data.listObject;
this.unSelection = response.data.listObject.map(s=>s.id);
});
}
},
@ -256,6 +270,7 @@
this.$set(row, "showMore", true);
})
}
this.selectRowsCount(this.selectRows)
},
handleSelectAll(selection) {
if (selection.length > 0) {
@ -275,6 +290,7 @@
this.$set(row, "showMore", false);
})
}
this.selectRowsCount(this.selectRows)
},
search() {
this.initTable();
@ -301,8 +317,14 @@
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
let deleteParam = {};
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/api/definition/deleteBatch/', ids, () => {
deleteParam.dataIds = ids;
deleteParam.projectId = getCurrentProjectID();
deleteParam.selectAllDate = this.isSelectAllDate;
deleteParam.unSelectIds = this.unSelection;
deleteParam = Object.assign(deleteParam, this.condition);
this.$post('/api/definition/deleteBatchByParams/', deleteParam, () => {
this.selectRows.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
@ -316,7 +338,13 @@
callback: (action) => {
if (action === 'confirm') {
let ids = Array.from(this.selectRows).map(row => row.id);
this.$post('/api/definition/removeToGc/', ids, () => {
let deleteParam = {};
deleteParam.dataIds = ids;
deleteParam.projectId = getCurrentProjectID();
deleteParam.selectAllDate = this.isSelectAllDate;
deleteParam.unSelectIds = this.unSelection;
deleteParam = Object.assign(deleteParam, this.condition);
this.$post('/api/definition/removeToGcByParams/', deleteParam, () => {
this.selectRows.clear();
this.initTable();
this.$success(this.$t('commons.delete_success'));
@ -336,7 +364,13 @@
let param = {};
param[form.type] = form.value;
param.ids = ids;
this.$post('/api/definition/batch/edit', param, () => {
param.projectId = getCurrentProjectID();
param.selectAllDate = this.isSelectAllDate;
param.unSelectIds = this.unSelection;
param = Object.assign(param, this.condition);
this.$post('/api/definition/batch/editByParams', param, () => {
this.$success(this.$t('commons.save_success'));
this.initTable();
});
@ -385,15 +419,30 @@
showExecResult(row) {
this.$emit('showExecResult', row);
},
getProjectId() {
if (!this.isCaseRelevance) {
return getCurrentProjectID();
} else {
return this.relevanceProjectId;
selectRowsCount(selection){
let selectedIDs = this.getIds(selection);
let allIDs = this.tableData.map(s=>s.id);
this.unSelection = allIDs.filter(function (val) {
return selectedIDs.indexOf(val) === -1
});
if(this.isSelectAllDate){
this.selectDataCounts =this.total - this.unSelection.length;
}else {
this.selectDataCounts =selection.size;
}
},
setEnvironment(data) {
this.environmentId = data.id;
isSelectDataAll(dataType) {
this.isSelectAllDate = dataType;
this.selectRowsCount(this.selectRows)
//
if (this.selectRows.size != this.tableData.length) {
this.$refs.apiDefinitionTable.toggleAllSelection(true);
}
},
getIds(rowSets){
let rowArray = Array.from(rowSets)
let ids = rowArray.map(s=>s.id);
return ids;
}
},
}

View File

@ -5,8 +5,6 @@
stripe
border
style="width: 100%"
show-summary
:summary-method="getSummaries"
>
<el-table-column label="Requests" fixed width="450" align="center">
<el-table-column
@ -91,93 +89,42 @@
</template>
<script>
export default {
name: "RequestStatistics",
data() {
return {
tableData: [],
id: ''
}
export default {
name: "RequestStatistics",
data() {
return {
tableData: [],
id: ''
}
},
methods: {
initTableData() {
this.$get("/performance/report/content/" + this.id).then(res => {
this.tableData = res.data.data;
}).catch(() => {
this.tableData = [];
})
},
methods: {
initTableData() {
this.$get("/performance/report/content/" + this.id).then(res => {
this.tableData = res.data.data;
}).catch(() => {
},
watch: {
report: {
handler(val) {
if (!val.status || !val.id) {
return;
}
let status = val.status;
this.id = val.id;
if (status === "Completed" || status === "Running") {
this.initTableData();
} else {
this.tableData = [];
})
}
},
getSummaries(param) {
const {data} = param;
const sums = [];
let allSamples = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.samples);
}, 0);
let failSize = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.ko);
}, 0);
let averageTimeTotal = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.average) * parseFloat(currentValue.samples);
}, 0);
let tp90Total = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.tp90) * parseFloat(currentValue.samples);
}, 0);
let tp95Total = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.tp95) * parseFloat(currentValue.samples);
}, 0);
let tp99Total = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.tp99) * parseFloat(currentValue.samples);
}, 0);
let transactions = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.transactions);
}, 0);
transactions = transactions.toFixed(2);
let received = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.received);
}, 0);
received = received.toFixed(2);
let sent = data.reduce(function (total, currentValue) {
return total + parseFloat(currentValue.sent);
}, 0);
sent = sent.toFixed(2);
let error = (Math.round(failSize / allSamples * 10000) / 100) + '%';
let averageTime = (averageTimeTotal / allSamples).toFixed(2);
let tp90 = (tp90Total / allSamples).toFixed(2);
let tp95 = (tp95Total / allSamples).toFixed(2);
let tp99 = (tp99Total / allSamples).toFixed(2);
let min = Math.min.apply(Math, data.map(function (o) {
return parseFloat(o.min)
}));
let max = Math.max.apply(Math, data.map(function (o) {
return parseFloat(o.max)
}));
sums.push('Total', allSamples, failSize, error, averageTime, min, max, tp90, tp95, tp99, transactions, received, sent);
return sums;
}
},
watch: {
report: {
handler(val){
if (!val.status || !val.id) {
return;
}
let status = val.status;
this.id = val.id;
if (status === "Completed" || status === "Running") {
this.initTableData();
} else {
this.tableData = [];
}
},
deep:true
}
},
props: ['report']
}
deep: true
}
},
props: ['report']
}
</script>
<style scoped>

View File

@ -66,7 +66,7 @@
</el-form-item>
<el-form-item :label="$t('test_resource_pool.type')" prop="type">
<el-select v-model="form.type" :placeholder="$t('test_resource_pool.select_pool_type')"
@change="changeResourceType()">
@change="changeResourceType(form.type)">
<el-option key="NODE" value="NODE" label="Node">Node</el-option>
<el-option key="K8S" value="K8S" label="Kubernetes" v-xpack>Kubernetes</el-option>
</el-select>
@ -89,6 +89,14 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item label="Namespace"
:rules="requiredRules">
<el-input v-model="item.namespace" type="text"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item :label="$t('test_resource_pool.max_threads')"
@ -205,9 +213,20 @@ export default {
this.total = data.itemCount;
})
},
changeResourceType() {
changeResourceType(type) {
this.infoList = [];
this.infoList.push({})
let info = {};
if (type === 'NODE') {
info.ip = '';
info.port = '8082';
}
if (type === 'K8S') {
info.masterUrl = '';
info.token = '';
info.namespace = '';
}
info.maxConcurrency = 100;
this.infoList.push(info);
},
addResourceInfo() {

View File

@ -12,42 +12,32 @@
@protocolChange="handleProtocolChange"
@refreshTable="refresh"
@setModuleOptions="setModuleOptions"
:relevance-project-id="projectId"
:is-read-only="true"
:type="'edit'"
ref="nodeTree"/>
</template>
<!-- 列表集合 -->
<api-list
<relevance-api-list
v-if="isApiListEnable"
:current-protocol="currentProtocol"
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="trashEnable"
:is-api-list-enable="isApiListEnable"
:is-case-relevance="true"
:relevance-project-id="projectId"
:is-relevance="true"
:project-id="projectId"
:is-test-plan="true"
:plan-id="planId"
@isApiListEnableChange="isApiListEnableChange"
ref="apiList"/>
<!--测试用例列表-->
<api-case-simple-list
<relevance-case-list
v-if="!isApiListEnable"
:current-protocol="currentProtocol"
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="trashEnable"
:is-api-list-enable="isApiListEnable"
:is-case-relevance="true"
:relevance-project-id="projectId"
:project-id="projectId"
:is-test-plan="true"
:plan-id="planId"
:model="'relevance'"
@isApiListEnableChange="isApiListEnableChange"
ref="apiCaseList"/>
</test-case-relevance-base>
</template>
@ -56,15 +46,14 @@
import TestCaseRelevanceBase from "../base/TestCaseRelevanceBase";
import MsApiModule from "../../../../../api/definition/components/module/ApiModule";
import {getCurrentProjectID} from "../../../../../../../common/js/utils";
import ApiList from "../../../../../api/definition/components/list/ApiList";
import ApiCaseSimpleList from "../../../../../api/definition/components/list/ApiCaseSimpleList";
import RelevanceApiList from "../../../../../api/automation/scenario/api/RelevanceApiList";
import RelevanceCaseList from "../../../../../api/automation/scenario/api/RelevanceCaseList";
export default {
name: "TestCaseApiRelevance",
components: {
ApiCaseSimpleList,
ApiList,
RelevanceCaseList,
RelevanceApiList,
MsApiModule,
TestCaseRelevanceBase,
},
@ -94,8 +83,20 @@
},
methods: {
open() {
this.init();
this.$refs.baseRelevance.open();
},
init() {
if (this.$refs.apiList) {
this.$refs.apiList.initTable();
}
if (this.$refs.apiCaseList) {
this.$refs.apiCaseList.initTable();
}
if (this.$refs.nodeTree) {
this.$refs.nodeTree.list();
}
},
setProject(projectId) {
this.projectId = projectId;
},
@ -145,11 +146,6 @@
param.planId = this.planId;
param.selectIds = selectIds;
param.environmentId = environmentId;
// param.request = this.condition;
//
// if (this.testCases.length === param.testCaseIds.length) {
// param.testCaseIds = ['all'];
// }
this.result = this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));

View File

@ -162,18 +162,6 @@
this.moduleOptions = data;
},
saveCaseRelevance() {
let url = '';
let selectIds = [];
let param = {};
param.planId = this.planId;
param.selectIds = selectIds;
this.result = this.$post(url, param, () => {
this.$success(this.$t('commons.save_success'));
this.refresh();
this.$refs.baseRelevance.close();
});
},
openTestCaseRelevanceDialog(model) {
if (model === 'scenario') {
this.$refs.scenarioCaseRelevance.open();
@ -194,4 +182,9 @@
margin: 5px 10px;
}
/deep/ .run-button {
background-color: #409EFF;
border-color: #409EFF;
}
</style>

View File

@ -81,8 +81,10 @@
<el-table-column v-if="!isReadOnly" :label="$t('commons.operating')" align="center">
<template v-slot:default="scope">
<el-button type="text" @click="singleRun(scope.row)">{{$t('api_test.run')}}</el-button>
<el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">{{$t('commons.delete')}}</el-button>
<ms-table-operator-button class="run-button" :is-tester-permission="true" :tip="$t('api_test.run')" icon="el-icon-video-play"
@exec="singleRun(scope.row)" v-tester/>
<ms-table-operator-button :is-tester-permission="true" :tip="$t('test_track.plan_view.cancel_relevance')"
icon="el-icon-unlock" type="danger" @exec="handleDelete(scope.row)" v-tester/>
</template>
</el-table-column>
@ -334,7 +336,7 @@
this.selectRows.clear();
this.initTable();
this.$emit('refresh');
this.$success(this.$t('commons.delete_success'));
this.$success(this.$t('test_track.cancel_relevance_success'));
});
}
}
@ -414,7 +416,7 @@
},
handleDelete(apiCase) {
this.$get('/test/plan/api/case/delete/' + this.planId + '/' + apiCase.id, () => {
this.$success(this.$t('commons.delete_success'));
this.$success(this.$t('test_track.cancel_relevance_success'));
this.$emit('refresh');
this.initTable();
});

View File

@ -51,8 +51,10 @@
show-overflow-tooltip/>
<el-table-column :label="$t('commons.operating')" width="200px" v-if="!referenced">
<template v-slot:default="{row}">
<el-button type="text" @click="execute(row)">{{ $t('api_test.automation.execute') }}</el-button>
<el-button type="text" @click="remove(row)">{{ $t('api_test.automation.remove') }}</el-button>
<ms-table-operator-button class="run-button" :is-tester-permission="true" :tip="$t('api_test.run')" icon="el-icon-video-play"
@exec="execute(row)" v-tester/>
<ms-table-operator-button :is-tester-permission="true" :tip="$t('test_track.plan_view.cancel_relevance')"
icon="el-icon-unlock" type="danger" @exec="remove(row)" v-tester/>
</template>
</el-table-column>
</el-table>
@ -81,10 +83,12 @@
import MsTestPlanList from "../../../../../api/automation/scenario/testplan/TestPlanList";
import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader";
import {_handleSelect, _handleSelectAll} from "../../../../../../../common/js/tableUtils";
import MsTableOperatorButton from "../../../../../common/components/MsTableOperatorButton";
export default {
name: "MsTestPlanApiScenarioList",
components: {
MsTableOperatorButton,
TestPlanScenarioListHeader,
MsTablePagination, MsTableMoreBtn, ShowMoreBtn, MsTableHeader, MsTag, MsApiReportDetail, MsScenarioExtendButtons, MsTestPlanList},
props: {
@ -189,7 +193,7 @@
},
remove(row) {
this.$get('/test/plan/scenario/case/delete/' + this.planId + '/' + row.id, () => {
this.$success(this.$t('commons.delete_success'));
this.$success(this.$t('test_track.cancel_relevance_success'));
this.$emit('refresh');
this.search();
});
@ -215,7 +219,7 @@
this.$post('/test/plan/scenario/case/batch/delete', param, () => {
this.selectRows.clear();
this.search();
this.$success(this.$t('commons.delete_success'));
this.$success(this.$t('test_track.cancel_relevance_success'));
this.$emit('refresh');
});
}

View File

@ -0,0 +1,69 @@
<template>
<el-dialog :title="title"
:visible.sync="dialogVisible"
@close="close"
width="60%" v-loading="result.loading"
:close-on-click-modal="false"
top="50px">
<el-container class="main-content">
<el-aside class="tree-aside" width="250px">
<slot name="aside"></slot>
</el-aside>
<el-container>
<el-main class="case-content">
<slot></slot>
</el-main>
</el-container>
</el-container>
<template v-slot:footer>
<slot name="footer"></slot>
</template>
</el-dialog>
</template>
<script>
import MsDialogFooter from '../../../../../common/components/MsDialogFooter'
import SelectMenu from "../../../../common/SelectMenu";
export default {
name: "RelevanceDialog",
components: {
SelectMenu,
MsDialogFooter,
},
data() {
return {
result: {},
dialogVisible: false,
};
},
props: ['title'],
methods: {
open() {
this.dialogVisible = true;
},
close() {
this.dialogVisible = false;
},
}
}
</script>
<style scoped>
.el-dialog {
min-height: 700px;
}
.el-dialog >>> .el-dialog__body {
padding: 10px 20px;
}
</style>

View File

@ -1,55 +1,45 @@
<template>
<div>
<el-dialog :title="$t('test_track.plan_view.relevance_test_case')"
:visible.sync="dialogVisible"
@close="close"
width="60%" v-loading="result.loading"
:close-on-click-modal="false"
top="50px">
<relevance-dialog :title="$t('test_track.plan_view.relevance_test_case')" ref="relevanceDialog">
<el-container class="main-content">
<el-aside class="tree-aside" width="250px">
<select-menu
:data="projects"
width="160px"
:current-data="currentProject"
:title="$t('test_track.switch_project')"
@dataChange="changeProject"/>
<slot name="aside"></slot>
</el-aside>
<template v-slot:aside>
<select-menu
:data="projects"
width="160px"
:current-data="currentProject"
:title="$t('test_track.switch_project')"
@dataChange="changeProject"/>
<slot name="aside"></slot>
</template>
<el-container>
<el-main class="case-content">
<slot></slot>
</el-main>
</el-container>
</el-container>
<slot></slot>
<template v-slot:footer>
<ms-dialog-footer @cancel="dialogVisible = false" @confirm="save"/>
</template>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="save"/>
</template>
</el-dialog>
</div>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="save"/>
</template>
</relevance-dialog>
</template>
<script>
import MsDialogFooter from '../../../../../common/components/MsDialogFooter'
import SelectMenu from "../../../../common/SelectMenu";
import RelevanceDialog from "./RelevanceDialog";
export default {
name: "TestCaseRelevanceBase",
components: {
RelevanceDialog,
SelectMenu,
MsDialogFooter,
},
data() {
return {
result: {},
dialogVisible: false,
currentProject: {},
projectId: '',
projectName: '',
@ -66,10 +56,6 @@
},
methods: {
open() {
this.getProject();
this.dialogVisible = true;
},
refreshNode() {
this.$emit('refresh');
@ -80,7 +66,12 @@
},
close() {
this.dialogVisible = false;
this.$refs.relevanceDialog.close();
},
open() {
this.getProject();
this.$refs.relevanceDialog.open();
},
getProject() {
@ -108,53 +99,4 @@
</script>
<style scoped>
.tb-edit .el-input {
display: none;
color: black;
}
.tb-edit .current-row .el-input {
display: block;
}
.tb-edit .current-row .el-input + span {
display: none;
}
.node-tree {
margin-right: 10px;
}
.el-header {
background-color: darkgrey;
color: #333;
line-height: 60px;
}
.case-content {
padding: 0px 20px;
height: 100%;
/*border: 1px solid #EBEEF5;*/
}
.tree-aside {
min-height: 300px;
max-height: 100%;
}
.main-content {
min-height: 300px;
height: 100%;
/*border: 1px solid #EBEEF5;*/
}
.project-link {
float: right;
margin-right: 12px;
margin-bottom: 10px;
}
</style>

View File

@ -364,12 +364,14 @@ export default {
for (let i = 0; i < this.tableData.length; i++) {
if (this.tableData[i]) {
this.$set(this.tableData[i], "issuesSize", 0);
this.$get("/issues/get/" + this.tableData[i].caseId, response => {
let issues = response.data;
this.$get("/issues/get/" + this.tableData[i].caseId).then(response => {
let issues = response.data.data;
if (this.tableData[i]) {
this.$set(this.tableData[i], "issuesSize", issues.length);
this.$set(this.tableData[i], "issuesContent", issues);
}
}).catch(() => {
this.$set(this.tableData[i], "issuesContent", [{title: '获取缺陷失败',description: '获取缺陷失败',platform: '获取缺陷失败' }]);
})
}
}

View File

@ -29,12 +29,7 @@ export function _handleSelect(component, selection, row, selectRows) {
selectRows.add(row);
}
let arr = Array.from(selectRows);
// 选中1个以上的用例时显示更多操作
if (selectRows.size === 1) {
component.$set(arr[0], "showMore", false);
} else if (selectRows.size === 2) {
arr.forEach(row => {
component.$set(row, "showMore", true);
})
}
arr.forEach(row => {
component.$set(row, "showMore", true);
})
}

View File

@ -489,6 +489,10 @@ export default {
file_exist: "The name already exists in the project",
upload_limit_size: "Upload file size cannot exceed 30MB!",
},
batch_menus:{
select_all_data: "Select all datas({0})",
select_show_data: "Select show datas({0})",
},
definition: {
api_title: "Api test",
api_name: "Api name",

View File

@ -487,6 +487,10 @@ export default {
file_exist: "该项目下已存在该jar包",
upload_limit_size: "上传文件大小不能超过 30MB!",
},
batch_menus:{
select_all_data: "选择所有数据(共{0}条)",
select_show_data: "选择可见数据(共{0}条)",
},
definition: {
api_title: "接口列表",
api_name: "接口名称",

View File

@ -487,6 +487,10 @@ export default {
file_exist: "該項目下已存在該jar包",
upload_limit_size: "上傳文件大小不能超過 30MB!",
},
batch_menus:{
select_all_data: "選擇所有數據(共{0}條)",
select_show_data: "選擇可見數據(共{0}條)",
},
definition: {
api_title: "接口列表",
api_name: "接口名稱",