Merge branch 'v1.7'
# Conflicts: # backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java # backend/src/main/java/io/metersphere/track/service/TestPlanService.java # frontend/src/business/components/api/automation/scenario/common/ApiBaseComponent.vue # frontend/src/business/components/api/automation/scenario/variable/VariableList.vue # frontend/src/business/components/api/definition/components/case/ApiCaseItem.vue
This commit is contained in:
commit
683c533db0
|
@ -314,11 +314,7 @@ public class APITestController {
|
|||
apiCountResult.setThisWeekExecutedCount(executedInThisWeekCountNumber);
|
||||
|
||||
//统计 失败 成功 以及总数
|
||||
// List<ApiDataCountResult> api_allExecuteResult = apiReportService.countByProjectIdGroupByExecuteResult(projectId);
|
||||
List<ApiDataCountResult> allExecuteResult = apiScenarioReportService.countByProjectIdGroupByExecuteResult(projectId);
|
||||
// List<ApiDataCountResult> allExecuteResult = new ArrayList<>();
|
||||
// allExecuteResult.addAll(api_allExecuteResult);
|
||||
// allExecuteResult.addAll(scene_allExecuteResult);
|
||||
apiCountResult.countScheduleExecute(allExecuteResult);
|
||||
|
||||
long allCount = apiCountResult.getExecutedCount();
|
||||
|
|
|
@ -216,4 +216,6 @@ public class ApiDefinitionController {
|
|||
public String preview(@RequestBody String jsonSchema) {
|
||||
return JSONSchemaGenerator.getJson(jsonSchema);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -33,4 +33,6 @@ public class ApiBatchRequest extends ApiDefinitionWithBLOBs {
|
|||
|
||||
private List<String> unSelectIds;
|
||||
|
||||
private String moduleId;
|
||||
|
||||
}
|
||||
|
|
|
@ -98,6 +98,8 @@ public abstract class MsTestElement {
|
|||
private String refType;
|
||||
@JSONField(ordinal = 10)
|
||||
private LinkedList<MsTestElement> hashTree;
|
||||
@JSONField(ordinal = 11)
|
||||
private boolean customizeReq;
|
||||
|
||||
private MsTestElement parent;
|
||||
|
||||
|
@ -188,15 +190,14 @@ public abstract class MsTestElement {
|
|||
csvDataSet.setEnabled(true);
|
||||
csvDataSet.setProperty(TestElement.TEST_CLASS, CSVDataSet.class.getName());
|
||||
csvDataSet.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
|
||||
csvDataSet.setName(item.getName());
|
||||
csvDataSet.setProperty("fileEncoding", item.getEncoding());
|
||||
csvDataSet.setProperty("variableNames", item.getName());
|
||||
csvDataSet.setName(StringUtils.isEmpty(item.getName()) ? "CSVDataSet" : item.getName());
|
||||
csvDataSet.setProperty("fileEncoding", StringUtils.isEmpty(item.getEncoding()) ? "UTF-8" : item.getEncoding());
|
||||
if (CollectionUtils.isNotEmpty(item.getFiles())) {
|
||||
csvDataSet.setProperty("filename", BODY_FILE_DIR + "/" + item.getFiles().get(0).getId() + "_" + item.getFiles().get(0).getName());
|
||||
}
|
||||
csvDataSet.setIgnoreFirstLine(false);
|
||||
csvDataSet.setProperty("delimiter", item.getDelimiter());
|
||||
csvDataSet.setComment(item.getDescription());
|
||||
csvDataSet.setComment(StringUtils.isEmpty(item.getDescription()) ? "" : item.getDescription());
|
||||
tree.add(csvDataSet);
|
||||
});
|
||||
}
|
||||
|
@ -218,7 +219,7 @@ public abstract class MsTestElement {
|
|||
counterConfig.setVarName(item.getName());
|
||||
counterConfig.setIncrement(item.getIncrement());
|
||||
counterConfig.setFormat(item.getValue());
|
||||
counterConfig.setComment(item.getDescription());
|
||||
counterConfig.setComment(StringUtils.isEmpty(item.getDescription()) ? "" : item.getDescription());
|
||||
tree.add(counterConfig);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.api.dto.definition.request.ParameterConfig;
|
|||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.assertions.*;
|
||||
import org.apache.jmeter.save.SaveService;
|
||||
import org.apache.jmeter.testelement.TestElement;
|
||||
|
@ -89,7 +90,7 @@ public class MsAssertions extends MsTestElement {
|
|||
private JSONPathAssertion jsonPathAssertion(MsAssertionJsonPath assertionJsonPath) {
|
||||
JSONPathAssertion assertion = new JSONPathAssertion();
|
||||
assertion.setEnabled(true);
|
||||
assertion.setName(assertionJsonPath.getDescription());
|
||||
assertion.setName(StringUtils.isEmpty(assertionJsonPath.getDescription()) ? "JSONPathAssertion" : assertionJsonPath.getDescription());
|
||||
assertion.setProperty(TestElement.TEST_CLASS, JSONPathAssertion.class.getName());
|
||||
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("JSONPathAssertionGui"));
|
||||
assertion.setJsonPath(assertionJsonPath.getExpression());
|
||||
|
@ -104,7 +105,7 @@ public class MsAssertions extends MsTestElement {
|
|||
private XPath2Assertion xPath2Assertion(MsAssertionXPath2 assertionXPath2) {
|
||||
XPath2Assertion assertion = new XPath2Assertion();
|
||||
assertion.setEnabled(true);
|
||||
assertion.setName(assertionXPath2.getExpression());
|
||||
assertion.setName(StringUtils.isEmpty(assertionXPath2.getExpression()) ? "XPath2Assertion" : assertionXPath2.getExpression());
|
||||
assertion.setProperty(TestElement.TEST_CLASS, XPath2Assertion.class.getName());
|
||||
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("XPath2AssertionGui"));
|
||||
assertion.setXPathString(assertionXPath2.getExpression());
|
||||
|
@ -125,7 +126,7 @@ public class MsAssertions extends MsTestElement {
|
|||
private JSR223Assertion jsr223Assertion(MsAssertionJSR223 assertionJSR223) {
|
||||
JSR223Assertion assertion = new JSR223Assertion();
|
||||
assertion.setEnabled(true);
|
||||
assertion.setName(assertionJSR223.getDesc());
|
||||
assertion.setName(StringUtils.isEmpty(assertionJSR223.getDesc()) ? "JSR223Assertion" : assertionJSR223.getDesc());
|
||||
assertion.setProperty(TestElement.TEST_CLASS, JSR223Assertion.class.getName());
|
||||
assertion.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
|
||||
assertion.setProperty("cacheKey", "true");
|
||||
|
|
|
@ -42,10 +42,10 @@ public class MsIfController extends MsTestElement {
|
|||
private IfController ifController() {
|
||||
IfController ifController = new IfController();
|
||||
ifController.setEnabled(true);
|
||||
ifController.setName(this.getLabelName());
|
||||
ifController.setCondition(this.getCondition());
|
||||
ifController.setName(StringUtils.isEmpty(this.getName()) ? "IfController" : this.getName());
|
||||
ifController.setProperty(TestElement.TEST_CLASS, IfController.class.getName());
|
||||
ifController.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("IfControllerPanel"));
|
||||
ifController.setCondition(this.getCondition());
|
||||
ifController.setEvaluateAll(false);
|
||||
ifController.setUseExpression(true);
|
||||
return ifController;
|
||||
|
@ -79,13 +79,13 @@ public class MsIfController extends MsTestElement {
|
|||
}
|
||||
|
||||
if (StringUtils.equals(operator, "is empty")) {
|
||||
variable = "empty(" + variable + ")";
|
||||
variable = "!empty(" + variable + ")";
|
||||
operator = "";
|
||||
value = "";
|
||||
}
|
||||
|
||||
if (StringUtils.equals(operator, "is not empty")) {
|
||||
variable = "!empty(" + variable + ")";
|
||||
variable = "empty(" + variable + ")";
|
||||
operator = "";
|
||||
value = "";
|
||||
}
|
||||
|
|
|
@ -123,13 +123,13 @@ public class MsLoopController extends MsTestElement {
|
|||
}
|
||||
|
||||
if (StringUtils.equals(operator, "is empty")) {
|
||||
variable = "empty(" + variable + ")";
|
||||
variable = "!empty(" + variable + ")";
|
||||
operator = "";
|
||||
value = "";
|
||||
}
|
||||
|
||||
if (StringUtils.equals(operator, "is not empty")) {
|
||||
variable = "!empty(" + variable + ")";
|
||||
variable = "empty(" + variable + ")";
|
||||
operator = "";
|
||||
value = "";
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class MsExtract extends MsTestElement {
|
|||
if (Optional.ofNullable(extract).orElse(extract).length() > 0) {
|
||||
JSR223PostProcessor shell = new JSR223PostProcessor();
|
||||
shell.setEnabled(true);
|
||||
shell.setName(this.getName());
|
||||
shell.setName(StringUtils.isEmpty(this.getName()) ? "JSR223PostProcessor" : this.getName());
|
||||
shell.setProperty(TestElement.TEST_CLASS, JSR223PostProcessor.class.getName());
|
||||
shell.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("TestBeanGUI"));
|
||||
shell.setProperty("script", "io.metersphere.api.jmeter.JMeterVars.addVars(prev.hashCode(),vars," + "\"" + extract.toString() + "\"" + ");");
|
||||
|
|
|
@ -207,14 +207,17 @@ public class MsHTTPSamplerProxy extends MsTestElement {
|
|||
}
|
||||
|
||||
final HashTree httpSamplerTree = tree.add(sampler);
|
||||
|
||||
// 注意顺序,放在config前面,会优先于环境的请求头生效
|
||||
if (CollectionUtils.isNotEmpty(this.headers)) {
|
||||
setHeader(httpSamplerTree, this.headers);
|
||||
}
|
||||
|
||||
// 通用请求Headers
|
||||
if (config != null && config.getConfig() != null && config.getConfig().getHttpConfig() != null
|
||||
&& CollectionUtils.isNotEmpty(config.getConfig().getHttpConfig().getHeaders())) {
|
||||
setHeader(httpSamplerTree, config.getConfig().getHttpConfig().getHeaders());
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(this.headers)) {
|
||||
setHeader(httpSamplerTree, this.headers);
|
||||
}
|
||||
|
||||
//判断是否要开启DNS
|
||||
if (config != null && config.getConfig() != null && config.getConfig().getCommonConfig() != null
|
||||
|
|
|
@ -96,7 +96,7 @@ public class MsJDBCSampler extends MsTestElement {
|
|||
|
||||
private Arguments arguments(String name, List<KeyValue> variables) {
|
||||
Arguments arguments = new Arguments();
|
||||
if (!variables.isEmpty()) {
|
||||
if (CollectionUtils.isNotEmpty(variables)) {
|
||||
arguments.setEnabled(true);
|
||||
arguments.setName(name);
|
||||
arguments.setProperty(TestElement.TEST_CLASS, Arguments.class.getName());
|
||||
|
|
|
@ -12,6 +12,7 @@ import lombok.Data;
|
|||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jmeter.config.Arguments;
|
||||
import org.apache.jmeter.config.ConfigTestElement;
|
||||
import org.apache.jmeter.modifiers.UserParameters;
|
||||
import org.apache.jmeter.protocol.tcp.sampler.TCPSampler;
|
||||
|
@ -79,6 +80,13 @@ public class MsTCPSampler extends MsTestElement {
|
|||
}
|
||||
config.setConfig(getEnvironmentConfig(useEnvironment));
|
||||
parseEnvironment(config.getConfig());
|
||||
|
||||
// 添加环境中的公共变量
|
||||
Arguments arguments = this.addArguments(config);
|
||||
if (arguments != null) {
|
||||
tree.add(this.addArguments(config));
|
||||
}
|
||||
|
||||
final HashTree samplerHashTree = new ListedHashTree();
|
||||
samplerHashTree.add(tcpConfig());
|
||||
tree.set(tcpSampler(config), samplerHashTree);
|
||||
|
@ -94,7 +102,7 @@ public class MsTCPSampler extends MsTestElement {
|
|||
}
|
||||
|
||||
private void parseEnvironment(EnvironmentConfig config) {
|
||||
if (config != null && config.getTcpConfig() != null) {
|
||||
if (!isCustomizeReq() && config != null && config.getTcpConfig() != null) {
|
||||
this.server = config.getTcpConfig().getServer();
|
||||
this.port = config.getTcpConfig().getPort();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.metersphere.api.jmeter;
|
|||
|
||||
import io.metersphere.api.dto.scenario.request.RequestType;
|
||||
import io.metersphere.api.service.*;
|
||||
import io.metersphere.base.domain.ApiDefinitionExecResult;
|
||||
import io.metersphere.base.domain.ApiScenarioReport;
|
||||
import io.metersphere.base.domain.ApiTestReport;
|
||||
import io.metersphere.commons.constants.*;
|
||||
|
@ -177,10 +178,17 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
} else if (StringUtils.equals(this.runMode, ApiRunMode.JENKINS.name())) {
|
||||
apiDefinitionService.addResult(testResult);
|
||||
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.DEFINITION.name());
|
||||
apiTestService.changeStatus(testId, APITestStatus.Completed);
|
||||
report = apiReportService.getRunningReport(testResult.getTestId());
|
||||
apiReportService.complete(testResult, report);
|
||||
|
||||
} else if (StringUtils.equals(this.runMode, ApiRunMode.JENKINS_API_PLAN.name())) {
|
||||
apiDefinitionService.addResult(testResult);
|
||||
apiDefinitionExecResultService.saveApiResult(testResult, ApiRunMode.API_PLAN.name());
|
||||
ApiDefinitionExecResult result = new ApiDefinitionExecResult();
|
||||
result = apiDefinitionService.getResultByJenkins(debugReportId, ApiRunMode.API_PLAN.name());
|
||||
report = new ApiTestReport();
|
||||
report.setStatus(result.getStatus());
|
||||
report.setId(result.getId());
|
||||
report.setTriggerMode(ApiRunMode.API.name());
|
||||
report.setName(apiDefinitionService.getApiCaseInfo(testId).getName());
|
||||
} else if (StringUtils.equalsAny(this.runMode, ApiRunMode.API_PLAN.name(), ApiRunMode.SCHEDULE_API_PLAN.name())) {
|
||||
apiDefinitionService.addResult(testResult);
|
||||
|
||||
|
@ -264,9 +272,15 @@ public class APIBackendListenerClient extends AbstractBackendListenerClient impl
|
|||
if (StringUtils.equals("Success", report.getStatus())) {
|
||||
event = NoticeConstants.Event.EXECUTE_SUCCESSFUL;
|
||||
}
|
||||
if (StringUtils.equals("success", report.getStatus())) {
|
||||
event = NoticeConstants.Event.EXECUTE_SUCCESSFUL;
|
||||
}
|
||||
if (StringUtils.equals("Error", report.getStatus())) {
|
||||
event = NoticeConstants.Event.EXECUTE_FAILED;
|
||||
}
|
||||
if (StringUtils.equals("error", report.getStatus())) {
|
||||
event = NoticeConstants.Event.EXECUTE_FAILED;
|
||||
}
|
||||
Map<String, Object> paramMap = new HashMap<>();
|
||||
paramMap.put("testName", report.getName());
|
||||
paramMap.put("id", report.getId());
|
||||
|
|
|
@ -60,6 +60,18 @@ public class TestResult {
|
|||
item.getSubRequestResults().forEach(subItem -> {
|
||||
subItem.setName(item.getName());
|
||||
});
|
||||
} else {
|
||||
if (requestResultMap.containsKey(result.getName())) {
|
||||
requestResultMap.get(result.getName()).add(item);
|
||||
} else {
|
||||
List<RequestResult> requestResults = new LinkedList<>();
|
||||
requestResults.add(item);
|
||||
requestResultMap.put(result.getName(), requestResults);
|
||||
}
|
||||
item.getSubRequestResults().forEach(subItem -> {
|
||||
subItem.setName(item.getName());
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -86,23 +86,33 @@ public class ApiAutomationService {
|
|||
private TestPlanScenarioCaseService testPlanScenarioCaseService;
|
||||
|
||||
public List<ApiScenarioDTO> list(ApiScenarioRequest request) {
|
||||
request = this.initRequest(request,true,true);
|
||||
request = this.initRequest(request, true, true);
|
||||
List<ApiScenarioDTO> list = extApiScenarioMapper.list(request);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化部分参数
|
||||
*
|
||||
* @param request
|
||||
* @param setDefultOrders
|
||||
* @param checkThisWeekData
|
||||
* @return
|
||||
*/
|
||||
private ApiScenarioRequest initRequest(ApiScenarioRequest request,boolean setDefultOrders, boolean checkThisWeekData) {
|
||||
if(setDefultOrders){
|
||||
private ApiScenarioRequest initRequest(ApiScenarioRequest request, boolean setDefultOrders, boolean checkThisWeekData) {
|
||||
if (setDefultOrders) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
|
||||
}
|
||||
if(checkThisWeekData){
|
||||
if(StringUtils.isNotEmpty(request.getExecuteStatus())){
|
||||
Map<String,List<String>> statusFilter = new HashMap<>();
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add("Prepare");
|
||||
list.add("Underway");
|
||||
list.add("Completed");
|
||||
statusFilter.put("status",list);
|
||||
request.setFilters(statusFilter);
|
||||
}
|
||||
if (checkThisWeekData) {
|
||||
if (request.isSelectThisWeedData()) {
|
||||
Map<String, Date> weekFirstTimeAndLastTime = DateUtils.getWeedFirstTimeAndLastTime(new Date());
|
||||
Date weekFirstTime = weekFirstTimeAndLastTime.get("firstTime");
|
||||
|
@ -217,7 +227,7 @@ public class ApiAutomationService {
|
|||
ids.add(scenarioId);
|
||||
deleteApiScenarioReport(ids);
|
||||
|
||||
scheduleService.deleteScheduleAndJobByResourceId(scenarioId,ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
scheduleService.deleteScheduleAndJobByResourceId(scenarioId, ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
TestPlanApiScenarioExample example = new TestPlanApiScenarioExample();
|
||||
example.createCriteria().andApiScenarioIdEqualTo(scenarioId);
|
||||
List<TestPlanApiScenario> testPlanApiScenarioList = testPlanApiScenarioMapper.selectByExample(example);
|
||||
|
@ -284,7 +294,7 @@ public class ApiAutomationService {
|
|||
extApiScenarioMapper.removeToGc(apiIds);
|
||||
//将这些场景的定时任务删除掉
|
||||
for (String id : apiIds) {
|
||||
scheduleService.deleteScheduleAndJobByResourceId(id,ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
scheduleService.deleteScheduleAndJobByResourceId(id, ScheduleGroup.API_SCENARIO_TEST.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -372,7 +382,7 @@ public class ApiAutomationService {
|
|||
try {
|
||||
boolean isFirst = true;
|
||||
for (ApiScenarioWithBLOBs item : apiScenarios) {
|
||||
if (item.getStepTotal() == 0) {
|
||||
if (item.getStepTotal() == null || item.getStepTotal() == 0) {
|
||||
// 只有一个场景且没有测试步骤,则提示
|
||||
if (apiScenarios.size() == 1) {
|
||||
MSException.throwException((item.getName() + "," + Translator.get("automation_exec_info")));
|
||||
|
@ -412,14 +422,14 @@ public class ApiAutomationService {
|
|||
// 创建场景报告
|
||||
if (reportIds != null) {
|
||||
//如果是测试计划页面触发的执行方式,生成报告时createScenarioReport第二个参数需要特殊处理
|
||||
if(StringUtils.equals(request.getRunMode(),ApiRunMode.SCENARIO_PLAN.name())){
|
||||
if (StringUtils.equals(request.getRunMode(), ApiRunMode.SCENARIO_PLAN.name())) {
|
||||
String testPlanScenarioId = item.getId();
|
||||
if(request.getScenarioTestPlanIdMap()!=null&&request.getScenarioTestPlanIdMap().containsKey(item.getId())){
|
||||
if (request.getScenarioTestPlanIdMap() != null && request.getScenarioTestPlanIdMap().containsKey(item.getId())) {
|
||||
testPlanScenarioId = request.getScenarioTestPlanIdMap().get(item.getId());
|
||||
}
|
||||
createScenarioReport(group.getName(), testPlanScenarioId, item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID());
|
||||
}else{
|
||||
} else {
|
||||
createScenarioReport(group.getName(), item.getId(), item.getName(), request.getTriggerMode() == null ? ReportTriggerMode.MANUAL.name() : request.getTriggerMode(),
|
||||
request.getExecuteType(), item.getProjectId(), request.getReportUserID());
|
||||
}
|
||||
|
@ -449,6 +459,8 @@ public class ApiAutomationService {
|
|||
ids = this.getAllScenarioIdsByFontedSelect(
|
||||
request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds());
|
||||
}
|
||||
//检查是否有正在执行中的情景
|
||||
this.checkScenarioIsRunnng(ids);
|
||||
List<ApiScenarioWithBLOBs> apiScenarios = extApiScenarioMapper.selectIds(ids);
|
||||
|
||||
String runMode = ApiRunMode.SCENARIO.name();
|
||||
|
@ -465,6 +477,15 @@ public class ApiAutomationService {
|
|||
return request.getId();
|
||||
}
|
||||
|
||||
public void checkScenarioIsRunnng(List<String> ids) {
|
||||
List<ApiScenarioReport> lastReportStatusByIds = apiReportService.selectLastReportByIds(ids);
|
||||
for (ApiScenarioReport report : lastReportStatusByIds) {
|
||||
if(StringUtils.equals(report.getStatus(),APITestStatus.Running.name())){
|
||||
MSException.throwException(report.getName()+" Is Running!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取前台查询条件查询的所有(未经分页筛选)数据ID
|
||||
*
|
||||
|
@ -506,7 +527,6 @@ public class ApiAutomationService {
|
|||
ParameterConfig config = new ParameterConfig();
|
||||
config.setConfig(envConfig);
|
||||
HashTree hashTree = request.getTestElement().generateHashTree(config);
|
||||
|
||||
// 调用执行方法
|
||||
createScenarioReport(request.getId(), request.getScenarioId(), request.getScenarioName(), ReportTriggerMode.MANUAL.name(), request.getExecuteType(), request.getProjectId(),
|
||||
SessionUtils.getUserId());
|
||||
|
@ -635,10 +655,10 @@ public class ApiAutomationService {
|
|||
}
|
||||
|
||||
private void addOrUpdateApiScenarioCronJob(Schedule request) {
|
||||
if(StringUtils.equals(request.getGroup(),ScheduleGroup.TEST_PLAN_TEST.name())){
|
||||
if (StringUtils.equals(request.getGroup(), ScheduleGroup.TEST_PLAN_TEST.name())) {
|
||||
scheduleService.addOrUpdateCronJob(
|
||||
request, TestPlanTestJob.getJobKey(request.getResourceId()), TestPlanTestJob.getTriggerKey(request.getResourceId()), TestPlanTestJob.class);
|
||||
}else{
|
||||
} else {
|
||||
scheduleService.addOrUpdateCronJob(
|
||||
request, ApiScenarioTestJob.getJobKey(request.getResourceId()), ApiScenarioTestJob.getTriggerKey(request.getResourceId()), ApiScenarioTestJob.class);
|
||||
}
|
||||
|
@ -707,7 +727,9 @@ public class ApiAutomationService {
|
|||
apiScenarios.forEach(item -> {
|
||||
JSONObject object = JSONObject.parseObject(item.getScenarioDefinition());
|
||||
object.put("environmentId", request.getEnvironmentId());
|
||||
item.setScenarioDefinition(JSONObject.toJSONString(object));
|
||||
if (object != null) {
|
||||
item.setScenarioDefinition(JSONObject.toJSONString(object));
|
||||
}
|
||||
apiScenarioMapper.updateByPrimaryKeySelective(item);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -82,6 +82,8 @@ public class ApiDefinitionService {
|
|||
private ExtSwaggerUrlScheduleMapper extSwaggerUrlScheduleMapper;
|
||||
@Resource
|
||||
private ScheduleMapper scheduleMapper;
|
||||
@Resource
|
||||
private ApiTestCaseMapper apiTestCaseMapper;
|
||||
|
||||
private static Cache cache = Cache.newHardMemoryCache(0, 3600 * 24);
|
||||
|
||||
|
@ -348,7 +350,8 @@ public class ApiDefinitionService {
|
|||
private String setImportHashTree(ApiDefinitionWithBLOBs apiDefinition) {
|
||||
String request = apiDefinition.getRequest();
|
||||
MsHTTPSamplerProxy msHTTPSamplerProxy = JSONObject.parseObject(request, MsHTTPSamplerProxy.class);
|
||||
msHTTPSamplerProxy.setHashTree(null);
|
||||
msHTTPSamplerProxy.setId(apiDefinition.getId());
|
||||
msHTTPSamplerProxy.setHashTree(new LinkedList<>());
|
||||
apiDefinition.setRequest(JSONObject.toJSONString(msHTTPSamplerProxy));
|
||||
return request;
|
||||
}
|
||||
|
@ -468,6 +471,14 @@ public class ApiDefinitionService {
|
|||
return buildAPIReportResult(result);
|
||||
}
|
||||
|
||||
public ApiDefinitionExecResult getResultByJenkins(String testId, String type) {
|
||||
return extApiDefinitionExecResultMapper.selectMaxResultByResourceIdAndType(testId, type);
|
||||
}
|
||||
|
||||
public ApiTestCaseWithBLOBs getApiCaseInfo(String apiCaseId) {
|
||||
return apiTestCaseMapper.selectByPrimaryKey(apiCaseId);
|
||||
}
|
||||
|
||||
|
||||
public ApiDefinitionImport apiTestImport(MultipartFile file, ApiTestImportRequest request) {
|
||||
ApiImportParser apiImportParser = ApiImportParserFactory.getApiImportParser(request.getPlatform());
|
||||
|
|
|
@ -415,4 +415,12 @@ public class ApiScenarioReportService {
|
|||
public List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId) {
|
||||
return extApiScenarioReportMapper.countByProjectIdGroupByExecuteResult(projectId);
|
||||
}
|
||||
|
||||
public List<ApiScenarioReport> selectLastReportByIds(List<String> ids) {
|
||||
if(!ids.isEmpty()){
|
||||
return extApiScenarioReportMapper.selectLastReportByIds(ids);
|
||||
}else {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -473,7 +473,7 @@ public class ApiTestCaseService {
|
|||
String runMode = ApiRunMode.JENKINS.name();
|
||||
*/
|
||||
// 调用执行方法
|
||||
jMeterService.runDefinition(request.getReportId(), jmeterHashTree, request.getReportId(), request.getRunMode());
|
||||
jMeterService.runDefinition(request.getCaseId(), jmeterHashTree, request.getReportId(), request.getRunMode());
|
||||
|
||||
} catch (Exception ex) {
|
||||
LogUtil.error(ex.getMessage());
|
||||
|
|
|
@ -304,7 +304,7 @@
|
|||
|
||||
<select id="countRunResultByProjectID" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
|
||||
SELECT count(id) AS countNumber, if(last_result is null,"notRun",last_result) AS groupField FROM api_scenario
|
||||
WHERE project_id = #{0}
|
||||
WHERE project_id = #{0} AND status != 'Trash'
|
||||
GROUP BY groupField
|
||||
</select>
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.metersphere.base.mapper.ext;
|
|||
import io.metersphere.api.dto.QueryAPIReportRequest;
|
||||
import io.metersphere.api.dto.automation.APIScenarioReportResult;
|
||||
import io.metersphere.api.dto.datacount.ApiDataCountResult;
|
||||
import io.metersphere.base.domain.ApiScenarioReport;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
|
@ -20,4 +21,6 @@ public interface ExtApiScenarioReportMapper {
|
|||
long countByProjectIdAndCreateAndByScheduleInThisWeek(@Param("projectId") String projectId, @Param("firstDayTimestamp") long firstDayTimestamp, @Param("lastDayTimestamp") long lastDayTimestamp);
|
||||
|
||||
List<ApiDataCountResult> countByProjectIdGroupByExecuteResult(String projectId);
|
||||
|
||||
List<ApiScenarioReport> selectLastReportByIds(@Param("scenarioIdList") List<String> ids);
|
||||
}
|
|
@ -194,4 +194,26 @@
|
|||
WHERE acr.project_id = #{projectId} AND ar.trigger_mode = 'SCHEDULE'
|
||||
GROUP BY groupField;
|
||||
</select>
|
||||
<select id="selectLastReportByIds" resultType="io.metersphere.base.domain.ApiScenarioReport">
|
||||
SELECT report.* FROM api_scenario_report report
|
||||
INNER JOIN (
|
||||
SELECT a.id,a.createTime,a.scenario_id FROM
|
||||
(
|
||||
SELECT id AS id,create_time AS createTime, scenario_id AS scenario_id FROM api_scenario_report
|
||||
WHERE scenario_id in
|
||||
<foreach collection="scenarioIdList" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
UNION
|
||||
SELECT report.id AS id,report.create_time AS createTime,planScenario.api_scenario_id AS scenario_id FROM api_scenario_report report
|
||||
INNER JOIN test_plan_api_scenario planScenario ON report.scenario_id = planScenario.id
|
||||
WHERE planScenario.api_scenario_id in
|
||||
<foreach collection="scenarioIdList" item="value" separator="," open="(" close=")">
|
||||
#{value}
|
||||
</foreach>
|
||||
ORDER BY createTime DESC
|
||||
) a GROUP BY a.scenario_id
|
||||
) orderData ON orderData.id = report.id;
|
||||
</select>
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package io.metersphere.base.mapper.ext;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface ExtFileContentMapper {
|
||||
@Select(value = {
|
||||
"SELECT file ",
|
||||
"FROM file_content ",
|
||||
"WHERE file_id = #{id, jdbcType=VARCHAR}"
|
||||
})
|
||||
InputStream selectZipBytes(@Param("id") String id);
|
||||
}
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
<select id="list" resultType="io.metersphere.track.dto.TestPlanReportDTO"
|
||||
parameterType="io.metersphere.track.request.report.QueryTestPlanReportRequest">
|
||||
SELECT tpr.id AS id, tpr.`name` AS `name`, tp.`name` AS testPlanName, u.name AS creator, tpr.create_time AS createTime,tpr.trigger_Mode AS triggerMode,tpr.status AS status
|
||||
SELECT tpr.id AS id, tpr.`name` AS `name`, tp.`name` AS testPlanName,
|
||||
IF(u.name is null,tpr.creator,u.name)AS creator,
|
||||
tpr.create_time AS createTime,tpr.trigger_Mode AS triggerMode,tpr.status AS status
|
||||
FROM test_plan tp
|
||||
INNER JOIN test_plan_report tpr on tp.id = tpr.test_plan_id
|
||||
INNER JOIN user u on tpr.creator = u.id
|
||||
LEFT JOIN user u on tpr.creator = u.id
|
||||
<where>
|
||||
<if test="name != null">
|
||||
and tpr.name like CONCAT('%', #{name},'%')
|
||||
|
|
|
@ -339,7 +339,8 @@
|
|||
where plan_id = #{planId}
|
||||
</select>
|
||||
<select id="listByPlanId" resultType="io.metersphere.track.dto.TestPlanCaseDTO">
|
||||
SELECT test_plan_api_case.api_case_id as id,"definition" as type,api_test_case.name,test_plan_api_case.status
|
||||
SELECT test_plan_api_case.id as reportId,test_plan_api_case.api_case_id as id,"definition" as
|
||||
type,api_test_case.name,test_plan_api_case.status
|
||||
from test_plan_api_case left join api_test_case on test_plan_api_case.api_case_id=api_test_case.id
|
||||
inner join
|
||||
api_definition a
|
||||
|
@ -352,7 +353,7 @@
|
|||
</if>
|
||||
</where>
|
||||
UNION ALL
|
||||
SELECT test_plan_api_scenario.api_scenario_id as id,"scenario" as
|
||||
SELECT test_plan_api_scenario.id as reportId,test_plan_api_scenario.api_scenario_id as id,"scenario" as
|
||||
type,api_scenario.name,test_plan_api_scenario.status
|
||||
from test_plan_api_scenario
|
||||
left join
|
||||
|
@ -366,7 +367,8 @@
|
|||
</if>
|
||||
</where>
|
||||
UNION ALL
|
||||
select load_test.id as id,"perform" as type,load_test.name as name,test_plan_load_case.status from test_plan_load_case inner join
|
||||
select test_plan_load_case.id as reportId,load_test.id as id,"perform" as type,load_test.name as
|
||||
name,test_plan_load_case.status from test_plan_load_case inner join
|
||||
load_test on
|
||||
test_plan_load_case.load_case_id =load_test.id
|
||||
<where>
|
||||
|
@ -375,7 +377,8 @@
|
|||
</if>
|
||||
</where>
|
||||
UNION ALL
|
||||
SELECT test_case.test_id as id,test_case.type as type,test_case.name,test_plan_test_case.status
|
||||
SELECT test_case.id as reportId,test_case.test_id as id,test_case.type as
|
||||
type,test_case.name,test_plan_test_case.status
|
||||
from test_plan_test_case left join test_case on test_plan_test_case.case_id =test_case.id
|
||||
<where>
|
||||
<if test="request.planId != null">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
package io.metersphere.commons.constants;
|
||||
|
||||
public enum ApiRunMode {
|
||||
RUN, DEBUG, DEFINITION, SCENARIO, API_PLAN, JENKINS, SCENARIO_PLAN, API, SCHEDULE_API_PLAN, SCHEDULE_SCENARIO_PLAN, SCHEDULE_PERFORMANCE_TEST
|
||||
RUN, DEBUG, DEFINITION, SCENARIO, API_PLAN, JENKINS_API_PLAN, JENKINS, SCENARIO_PLAN, API, SCHEDULE_API_PLAN, SCHEDULE_SCENARIO_PLAN, SCHEDULE_PERFORMANCE_TEST
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@ import io.metersphere.performance.controller.request.ReportRequest;
|
|||
import io.metersphere.performance.service.ReportService;
|
||||
import org.apache.shiro.authz.annotation.Logical;
|
||||
import org.apache.shiro.authz.annotation.RequiresRoles;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -137,11 +134,7 @@ public class PerformanceReportController {
|
|||
}
|
||||
|
||||
@GetMapping("/jtl/download/{reportId}")
|
||||
public ResponseEntity<byte[]> downloadJtl(@PathVariable String reportId) {
|
||||
byte[] bytes = reportService.downloadJtl(reportId);
|
||||
return ResponseEntity.ok()
|
||||
.contentType(MediaType.parseMediaType("application/octet-stream"))
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + reportId + ".jtl\"")
|
||||
.body(bytes);
|
||||
public void downloadJtlZip(@PathVariable String reportId, HttpServletResponse response) {
|
||||
reportService.downloadJtlZip(reportId, response);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
|
|||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.metersphere.base.domain.*;
|
||||
import io.metersphere.base.mapper.*;
|
||||
import io.metersphere.base.mapper.ext.ExtFileContentMapper;
|
||||
import io.metersphere.base.mapper.ext.ExtLoadTestReportMapper;
|
||||
import io.metersphere.commons.constants.PerformanceTestStatus;
|
||||
import io.metersphere.commons.constants.ReportKeys;
|
||||
|
@ -23,11 +24,15 @@ import io.metersphere.performance.engine.EngineFactory;
|
|||
import io.metersphere.service.FileService;
|
||||
import io.metersphere.service.TestResourceService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -52,6 +57,8 @@ public class ReportService {
|
|||
private LoadTestReportDetailMapper loadTestReportDetailMapper;
|
||||
@Resource
|
||||
private FileService fileService;
|
||||
@Resource
|
||||
private SqlSessionFactory sqlSessionFactory;
|
||||
|
||||
public List<ReportDTO> getRecentReportList(ReportRequest request) {
|
||||
List<OrderRequest> orders = new ArrayList<>();
|
||||
|
@ -284,11 +291,28 @@ public class ReportService {
|
|||
return JSON.parseArray(content, ChartsData.class);
|
||||
}
|
||||
|
||||
public byte[] downloadJtl(String reportId) {
|
||||
/**
|
||||
* 流下载 jtl zip
|
||||
*/
|
||||
public void downloadJtlZip(String reportId, HttpServletResponse response) {
|
||||
LoadTestReportWithBLOBs report = getReport(reportId);
|
||||
if (StringUtils.isBlank(report.getFileId())) {
|
||||
throw new RuntimeException(Translator.get("load_test_report_file_not_exist"));
|
||||
}
|
||||
return fileService.loadFileAsBytes(report.getFileId());
|
||||
response.setHeader("Content-Disposition", "attachment;fileName=" + reportId + ".zip");
|
||||
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
|
||||
ExtFileContentMapper mapper = sqlSession.getMapper(ExtFileContentMapper.class);
|
||||
try (InputStream inputStream = mapper.selectZipBytes(report.getFileId())) {
|
||||
ServletOutputStream outputStream = response.getOutputStream();
|
||||
byte[] buffer = new byte[1024 * 4];
|
||||
int read;
|
||||
while ((read = inputStream.read(buffer)) > -1) {
|
||||
outputStream.write(buffer, 0, read);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
MSException.throwException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,14 @@ public class TestReviewTestCaseController {
|
|||
|
||||
@PostMapping("/batch/delete")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public void deleteTestCaseBath(@RequestBody TestReviewCaseBatchRequest request) {
|
||||
testReviewTestCaseService.deleteTestCaseBath(request);
|
||||
public void deleteTestCaseBatch(@RequestBody TestReviewCaseBatchRequest request) {
|
||||
testReviewTestCaseService.deleteTestCaseBatch(request);
|
||||
}
|
||||
|
||||
@PostMapping("/batch/edit/status")
|
||||
@RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR)
|
||||
public void editTestCaseBatch(@RequestBody TestReviewCaseBatchRequest request) {
|
||||
testReviewTestCaseService.editTestCaseBatchStatus(request);
|
||||
}
|
||||
|
||||
@PostMapping("/list/all")
|
||||
|
|
|
@ -39,7 +39,6 @@ import io.metersphere.track.request.testplan.LoadCaseRequest;
|
|||
import io.metersphere.track.request.testplan.RunTestPlanRequest;
|
||||
import io.metersphere.track.request.testplancase.QueryTestPlanCaseRequest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.session.ExecutorType;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
|
@ -179,8 +178,7 @@ public class TestPlanService {
|
|||
else if (res.getStatus().equals(TestPlanStatus.Completed.name())) {
|
||||
testPlan.setActualEndTime(null);
|
||||
} // 已完成->进行中,结束时间置空
|
||||
}
|
||||
else if (!res.getStatus().equals(TestPlanStatus.Prepare.name()) &&
|
||||
} else if (!res.getStatus().equals(TestPlanStatus.Prepare.name()) &&
|
||||
testPlan.getStatus().equals(TestPlanStatus.Prepare.name())) {
|
||||
testPlan.setActualStartTime(null);
|
||||
testPlan.setActualEndTime(null);
|
||||
|
@ -338,7 +336,7 @@ public class TestPlanService {
|
|||
testPlanScenarioCaseService.deleteByPlanId(planId);
|
||||
|
||||
//删除定时任务
|
||||
scheduleService.deleteScheduleAndJobByResourceId(planId,ScheduleGroup.TEST_PLAN_TEST.name());
|
||||
scheduleService.deleteScheduleAndJobByResourceId(planId, ScheduleGroup.TEST_PLAN_TEST.name());
|
||||
|
||||
int num = testPlanMapper.deleteByPrimaryKey(planId);
|
||||
List<String> relatedUsers = new ArrayList<>();
|
||||
|
@ -437,7 +435,7 @@ public class TestPlanService {
|
|||
}
|
||||
|
||||
public List<TestPlanDTOWithMetric> listTestPlanByProject(QueryTestPlanRequest request) {
|
||||
List<TestPlanDTOWithMetric> testPlans=extTestPlanMapper.list(request);
|
||||
List<TestPlanDTOWithMetric> testPlans = extTestPlanMapper.list(request);
|
||||
return testPlans;
|
||||
}
|
||||
|
||||
|
@ -784,12 +782,13 @@ public class TestPlanService {
|
|||
}
|
||||
return issues;
|
||||
}
|
||||
public List<TestPlanDTO> selectTestPlanByRelevancy(QueryTestPlanRequest params){
|
||||
return extTestPlanMapper.selectTestPlanByRelevancy(params);
|
||||
|
||||
public List<TestPlanDTO> selectTestPlanByRelevancy(QueryTestPlanRequest params) {
|
||||
return extTestPlanMapper.selectTestPlanByRelevancy(params);
|
||||
}
|
||||
|
||||
public String findTestProjectNameByTestPlanID(String testPlanId) {
|
||||
return extTestPlanMapper.findTestProjectNameByTestPlanID(testPlanId);
|
||||
return extTestPlanMapper.findTestProjectNameByTestPlanID(testPlanId);
|
||||
}
|
||||
|
||||
public String findScheduleCreateUserById(String testPlanId) {
|
||||
|
@ -877,23 +876,23 @@ public class TestPlanService {
|
|||
return request.getId();
|
||||
}
|
||||
|
||||
public void run(String testPlanID,String projectID,String userId,String triggerMode){
|
||||
Map<String,String> planScenarioIdMap;
|
||||
Map<String,String> apiTestCaseIdMap;
|
||||
Map<String,String> performanceIdMap;
|
||||
public void run(String testPlanID, String projectID, String userId, String triggerMode) {
|
||||
Map<String, String> planScenarioIdMap;
|
||||
Map<String, String> apiTestCaseIdMap;
|
||||
Map<String, String> performanceIdMap;
|
||||
|
||||
planScenarioIdMap = new LinkedHashMap<>();
|
||||
apiTestCaseIdMap = new LinkedHashMap<>();
|
||||
performanceIdMap = new LinkedHashMap<>();
|
||||
|
||||
List<TestPlanApiScenario> testPlanApiScenarioList = testPlanScenarioCaseService.getCasesByPlanId(testPlanID);
|
||||
for (TestPlanApiScenario model :testPlanApiScenarioList) {
|
||||
planScenarioIdMap.put(model.getApiScenarioId(),model.getId());
|
||||
for (TestPlanApiScenario model : testPlanApiScenarioList) {
|
||||
planScenarioIdMap.put(model.getApiScenarioId(), model.getId());
|
||||
}
|
||||
List<TestPlanApiCase> testPlanApiCaseList = testPlanApiCaseService.getCasesByPlanId(testPlanID);
|
||||
for (TestPlanApiCase model :
|
||||
testPlanApiCaseList) {
|
||||
apiTestCaseIdMap.put(model.getApiCaseId(),model.getId());
|
||||
apiTestCaseIdMap.put(model.getApiCaseId(), model.getId());
|
||||
}
|
||||
|
||||
LoadCaseRequest loadCaseRequest = new LoadCaseRequest();
|
||||
|
@ -901,24 +900,24 @@ public class TestPlanService {
|
|||
loadCaseRequest.setProjectId(projectID);
|
||||
List<TestPlanLoadCaseDTO> testPlanLoadCaseDTOList = testPlanLoadCaseService.list(loadCaseRequest);
|
||||
for (TestPlanLoadCaseDTO dto : testPlanLoadCaseDTOList) {
|
||||
performanceIdMap.put(dto.getId(),dto.getLoadCaseId());
|
||||
performanceIdMap.put(dto.getId(), dto.getLoadCaseId());
|
||||
}
|
||||
|
||||
LogUtil.info("-------------- start testplan schedule ----------");
|
||||
TestPlanReportService testPlanReportService = CommonBeanFactory.getBean(TestPlanReportService.class);
|
||||
//首先创建testPlanReport,然后返回的ID重新赋值为resourceID,作为后续的参数
|
||||
TestPlanReport testPlanReport = testPlanReportService.genTestPlanReport(testPlanID,userId,triggerMode);
|
||||
TestPlanReport testPlanReport = testPlanReportService.genTestPlanReport(testPlanID, userId, triggerMode);
|
||||
//执行接口案例任务
|
||||
for (Map.Entry<String,String> entry: apiTestCaseIdMap.entrySet()) {
|
||||
for (Map.Entry<String, String> entry : apiTestCaseIdMap.entrySet()) {
|
||||
String apiCaseID = entry.getKey();
|
||||
String planCaseID = entry.getValue();
|
||||
ApiTestCaseWithBLOBs blobs = apiTestCaseService.get(apiCaseID);
|
||||
//需要更新这里来保证PlanCase的状态能正常更改
|
||||
apiTestCaseService.run(blobs,UUID.randomUUID().toString(),testPlanReport.getId(),testPlanID,ApiRunMode.SCHEDULE_API_PLAN.name());
|
||||
apiTestCaseService.run(blobs, UUID.randomUUID().toString(), testPlanReport.getId(), testPlanID, ApiRunMode.SCHEDULE_API_PLAN.name());
|
||||
}
|
||||
|
||||
//执行场景执行任务
|
||||
if(!planScenarioIdMap.isEmpty()){
|
||||
if (!planScenarioIdMap.isEmpty()) {
|
||||
LogUtil.info("-------------- testplan schedule ---------- api case over -----------------");
|
||||
SchedulePlanScenarioExecuteRequest scenarioRequest = new SchedulePlanScenarioExecuteRequest();
|
||||
String senarionReportID = UUID.randomUUID().toString();
|
||||
|
@ -927,7 +926,7 @@ public class TestPlanService {
|
|||
scenarioRequest.setProjectId(projectID);
|
||||
scenarioRequest.setTriggerMode(ReportTriggerMode.SCHEDULE.name());
|
||||
scenarioRequest.setExecuteType(ExecuteType.Saved.name());
|
||||
Map<String, Map<String,String>> testPlanScenarioIdMap = new HashMap<>();
|
||||
Map<String, Map<String, String>> testPlanScenarioIdMap = new HashMap<>();
|
||||
testPlanScenarioIdMap.put(testPlanID, planScenarioIdMap);
|
||||
scenarioRequest.setTestPlanScenarioIDMap(testPlanScenarioIdMap);
|
||||
scenarioRequest.setReportUserID(userId);
|
||||
|
@ -939,7 +938,7 @@ public class TestPlanService {
|
|||
}
|
||||
//执行性能测试任务
|
||||
List<String> performaneReportIDList = new ArrayList<>();
|
||||
for (Map.Entry<String,String> entry: performanceIdMap.entrySet()) {
|
||||
for (Map.Entry<String, String> entry : performanceIdMap.entrySet()) {
|
||||
String id = entry.getKey();
|
||||
String caseID = entry.getValue();
|
||||
RunTestPlanRequest performanceRequest = new RunTestPlanRequest();
|
||||
|
@ -949,7 +948,7 @@ public class TestPlanService {
|
|||
String reportId = null;
|
||||
try {
|
||||
reportId = performanceTestService.run(performanceRequest);
|
||||
if(reportId!=null){
|
||||
if (reportId != null) {
|
||||
performaneReportIDList.add(reportId);
|
||||
|
||||
TestPlanLoadCase testPlanLoadCase = new TestPlanLoadCase();
|
||||
|
@ -957,7 +956,7 @@ public class TestPlanService {
|
|||
testPlanLoadCase.setLoadReportId(reportId);
|
||||
testPlanLoadCaseService.update(testPlanLoadCase);
|
||||
}
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//更新关联处的报告
|
||||
|
@ -967,9 +966,9 @@ public class TestPlanService {
|
|||
testPlanLoadCaseService.update(loadCase);
|
||||
}
|
||||
|
||||
if(!performaneReportIDList.isEmpty()){
|
||||
if (!performaneReportIDList.isEmpty()) {
|
||||
//性能测试时保存性能测试报告ID,在结果返回时用于捕捉并进行
|
||||
testPlanReportService.updatePerformanceInfo(testPlanReport,performaneReportIDList,ReportTriggerMode.SCHEDULE.name());
|
||||
testPlanReportService.updatePerformanceInfo(testPlanReport, performaneReportIDList, ReportTriggerMode.SCHEDULE.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import io.metersphere.track.request.testreview.QueryCaseReviewRequest;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
|
@ -97,7 +98,7 @@ public class TestReviewTestCaseService {
|
|||
}
|
||||
}
|
||||
|
||||
public void deleteTestCaseBath(TestReviewCaseBatchRequest request) {
|
||||
public void deleteTestCaseBatch(TestReviewCaseBatchRequest request) {
|
||||
checkReviewer(request.getReviewId());
|
||||
TestCaseReviewTestCaseExample example = new TestCaseReviewTestCaseExample();
|
||||
example.createCriteria().andIdIn(request.getIds());
|
||||
|
@ -105,15 +106,7 @@ public class TestReviewTestCaseService {
|
|||
}
|
||||
|
||||
public void editTestCase(TestCaseReviewTestCase testCaseReviewTestCase) {
|
||||
String currentUserId = SessionUtils.getUser().getId();
|
||||
String reviewId = testCaseReviewTestCase.getReviewId();
|
||||
TestCaseReviewUsersExample testCaseReviewUsersExample = new TestCaseReviewUsersExample();
|
||||
testCaseReviewUsersExample.createCriteria().andReviewIdEqualTo(reviewId);
|
||||
List<TestCaseReviewUsers> testCaseReviewUsers = testCaseReviewUsersMapper.selectByExample(testCaseReviewUsersExample);
|
||||
List<String> reviewIds = testCaseReviewUsers.stream().map(TestCaseReviewUsers::getUserId).collect(Collectors.toList());
|
||||
if (!reviewIds.contains(currentUserId)) {
|
||||
MSException.throwException("非此用例的评审人员!");
|
||||
}
|
||||
checkReviewCase(testCaseReviewTestCase.getReviewId());
|
||||
|
||||
// 记录测试用例评审状态变更
|
||||
testCaseReviewTestCase.setStatus(testCaseReviewTestCase.getStatus());
|
||||
|
@ -137,4 +130,37 @@ public class TestReviewTestCaseService {
|
|||
public TestReviewCaseDTO get(String reviewId) {
|
||||
return extTestReviewCaseMapper.get(reviewId);
|
||||
}
|
||||
|
||||
public void editTestCaseBatchStatus(TestReviewCaseBatchRequest request) {
|
||||
List<String> ids = request.getIds();
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(request.getReviewId())) {
|
||||
return;
|
||||
} else {
|
||||
checkReviewCase(request.getReviewId());
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
if (StringUtils.isNotBlank(request.getStatus())) {
|
||||
TestCaseExample example = new TestCaseExample();
|
||||
example.createCriteria().andIdIn(ids);
|
||||
TestCaseWithBLOBs testCase = new TestCaseWithBLOBs();
|
||||
testCase.setReviewStatus(request.getStatus());
|
||||
testCaseMapper.updateByExampleSelective(testCase, example);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkReviewCase(String reviewId) {
|
||||
String currentUserId = SessionUtils.getUser().getId();
|
||||
TestCaseReviewUsersExample testCaseReviewUsersExample = new TestCaseReviewUsersExample();
|
||||
testCaseReviewUsersExample.createCriteria().andReviewIdEqualTo(reviewId);
|
||||
List<TestCaseReviewUsers> testCaseReviewUsers = testCaseReviewUsersMapper.selectByExample(testCaseReviewUsersExample);
|
||||
List<String> reviewIds = testCaseReviewUsers.stream().map(TestCaseReviewUsers::getUserId).collect(Collectors.toList());
|
||||
if (!reviewIds.contains(currentUserId)) {
|
||||
MSException.throwException("非此用例的评审人员!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -273,5 +273,7 @@
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
/deep/ .el-tabs__header {
|
||||
margin: 0 0 0px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
rule: {
|
||||
name: [
|
||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
||||
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
|
||||
],
|
||||
principal: [{
|
||||
required: true,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -67,6 +67,19 @@
|
|||
});
|
||||
}
|
||||
}
|
||||
if (item && item.files) {
|
||||
item.files.forEach(fileItem => {
|
||||
if (fileItem.file) {
|
||||
if (!fileItem.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
fileItem.name = fileItem.file.name;
|
||||
fileItem.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(fileItem.id);
|
||||
bodyUploadFiles.push(fileItem.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
recursiveFile(arr, bodyUploadFiles, obj) {
|
||||
arr.forEach(item => {
|
||||
|
@ -86,6 +99,11 @@
|
|||
this.recursiveFile(item.hashTree, bodyUploadFiles, obj);
|
||||
}
|
||||
})
|
||||
if (request.variables) {
|
||||
request.variables.forEach(item => {
|
||||
this.setFiles(item, bodyUploadFiles, obj);
|
||||
})
|
||||
}
|
||||
return bodyUploadFiles;
|
||||
},
|
||||
run() {
|
||||
|
|
|
@ -250,7 +250,7 @@
|
|||
rules: {
|
||||
name: [
|
||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
||||
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
|
||||
],
|
||||
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
||||
apiScenarioModuleId: [{required: true, message: this.$t('test_track.case.input_module'), trigger: 'change'}],
|
||||
|
@ -567,6 +567,9 @@
|
|||
this.$error("不能引用或复制自身!");
|
||||
return;
|
||||
}
|
||||
if (!item.hashTree) {
|
||||
item.hashTree = [];
|
||||
}
|
||||
item.enable === undefined ? item.enable = true : item.enable;
|
||||
this.scenarioDefinition.push(item);
|
||||
})
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
if (response.data) {
|
||||
response.data.forEach(item => {
|
||||
let scenarioDefinition = JSON.parse(item.scenarioDefinition);
|
||||
let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition.hashTree};
|
||||
let obj = {id: item.id, name: item.name, type: "scenario", referenced: 'Copy', resourceId: getUUID(), hashTree: scenarioDefinition && scenarioDefinition.hashTree ? scenarioDefinition.hashTree : []};
|
||||
scenarios.push(obj);
|
||||
})
|
||||
this.$emit('addScenario', scenarios);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<relevance-dialog :title="'接口导入'" ref="relevanceDialog">
|
||||
<relevance-dialog :title="$t('api_test.definition.api_import')" ref="relevanceDialog">
|
||||
|
||||
<template v-slot:aside>
|
||||
<ms-api-module
|
||||
|
@ -28,32 +28,36 @@
|
|||
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>
|
||||
<el-button type="primary" @click="copy" @keydown.enter.native.prevent>{{ $t('commons.copy') }}</el-button>
|
||||
<el-button v-if="!isApiListEnable" type="primary" @click="reference" @keydown.enter.native.prevent>
|
||||
{{ $t('api_test.scenario.reference') }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
</relevance-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
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 "./RelevanceApiList";
|
||||
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
|
||||
export default {
|
||||
name: "ApiRelevance",
|
||||
components: {
|
||||
RelevanceDialog,
|
||||
ScenarioRelevanceApiList,
|
||||
MsMainContainer, MsAsideContainer, MsContainer, MsApiModule, ScenarioRelevanceCaseList},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
currentProtocol: null,
|
||||
selectNodeIds: [],
|
||||
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 "./RelevanceApiList";
|
||||
import RelevanceDialog from "../../../../track/plan/view/comonents/base/RelevanceDialog";
|
||||
|
||||
export default {
|
||||
name: "ApiRelevance",
|
||||
components: {
|
||||
RelevanceDialog,
|
||||
ScenarioRelevanceApiList,
|
||||
MsMainContainer, MsAsideContainer, MsContainer, MsApiModule, ScenarioRelevanceCaseList
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
result: {},
|
||||
currentProtocol: null,
|
||||
selectNodeIds: [],
|
||||
moduleOptions: {},
|
||||
isApiListEnable: true,
|
||||
}
|
||||
|
@ -118,4 +122,7 @@
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
/deep/ .filter-input {
|
||||
width: 140px !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
|
||||
<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-input :placeholder="$t('api_test.definition.request.select_case')" @blur="initTable"
|
||||
@keyup.enter.native="initTable" class="search-input" size="small" v-model="condition.name"/>
|
||||
|
||||
<el-table v-loading="result.loading"
|
||||
border
|
||||
|
@ -65,34 +66,33 @@
|
|||
|
||||
<script>
|
||||
|
||||
import MsTableOperator from "../../../../common/components/MsTableOperator";
|
||||
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
|
||||
import {LIST_CHANGE, TrackEvent} from "@/business/components/common/head/ListEvent";
|
||||
import MsTablePagination from "../../../../common/pagination/TablePagination";
|
||||
import MsTag from "../../../../common/components/MsTag";
|
||||
import MsBottomContainer from "../../../definition/components/BottomContainer";
|
||||
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
|
||||
import MsBatchEdit from "../../../definition/components/basis/BatchEdit";
|
||||
import {API_METHOD_COLOUR, CASE_PRIORITY} from "../../../definition/model/JsonData";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import ApiListContainer from "../../../definition/components/list/ApiListContainer";
|
||||
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";
|
||||
import TableSelectCountBar from "./TableSelectCountBar";
|
||||
import MsTableOperator from "../../../../common/components/MsTableOperator";
|
||||
import MsTableOperatorButton from "../../../../common/components/MsTableOperatorButton";
|
||||
import MsTablePagination from "../../../../common/pagination/TablePagination";
|
||||
import MsTag from "../../../../common/components/MsTag";
|
||||
import MsBottomContainer from "../../../definition/components/BottomContainer";
|
||||
import ShowMoreBtn from "../../../../track/case/components/ShowMoreBtn";
|
||||
import MsBatchEdit from "../../../definition/components/basis/BatchEdit";
|
||||
import {API_METHOD_COLOUR, CASE_PRIORITY} from "../../../definition/model/JsonData";
|
||||
import {getCurrentProjectID} from "@/common/js/utils";
|
||||
import ApiListContainer from "../../../definition/components/list/ApiListContainer";
|
||||
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";
|
||||
import TableSelectCountBar from "./TableSelectCountBar";
|
||||
|
||||
export default {
|
||||
name: "RelevanceCaseList",
|
||||
components: {
|
||||
TableSelectCountBar,
|
||||
MsEnvironmentSelect,
|
||||
PriorityTableItem,
|
||||
ApiListContainer,
|
||||
MsTableOperatorButton,
|
||||
MsTableOperator,
|
||||
MsTablePagination,
|
||||
MsTag,
|
||||
export default {
|
||||
name: "RelevanceCaseList",
|
||||
components: {
|
||||
TableSelectCountBar,
|
||||
MsEnvironmentSelect,
|
||||
PriorityTableItem,
|
||||
ApiListContainer,
|
||||
MsTableOperatorButton,
|
||||
MsTableOperator,
|
||||
MsTablePagination,
|
||||
MsTag,
|
||||
MsBottomContainer,
|
||||
ShowMoreBtn,
|
||||
MsBatchEdit
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
<template>
|
||||
<el-card class="api-component">
|
||||
|
||||
<div class="header" @click="active(data)">
|
||||
<div class="header" @click="active(data)">
|
||||
|
||||
<fieldset :disabled="data.disabled" class="ms-fieldset">
|
||||
<slot name="beforeHeaderLeft">
|
||||
<div v-if="data.index" class="el-step__icon is-text" style="margin-right: 10px;" :style="{'color': color, 'background-color': backgroundColor}">
|
||||
<div class="el-step__icon-inner">{{data.index}}</div>
|
||||
</div>
|
||||
<el-button class="ms-left-buttion" size="small" :style="{'color': color, 'background-color': backgroundColor}">{{title}}</el-button>
|
||||
</slot>
|
||||
</fieldset>
|
||||
<slot name="beforeHeaderLeft">
|
||||
<div v-if="data.index" class="el-step__icon is-text" style="margin-right: 10px;" :style="{'color': color, 'background-color': backgroundColor}">
|
||||
<div class="el-step__icon-inner">{{data.index}}</div>
|
||||
</div>
|
||||
<el-button class="ms-left-buttion" size="small" :style="{'color': color, 'background-color': backgroundColor}">{{title}}</el-button>
|
||||
</slot>
|
||||
|
||||
<span @click.stop>
|
||||
<span @click.stop>
|
||||
<slot name="headerLeft">
|
||||
<i class="icon el-icon-arrow-right" :class="{'is-active': data.active}"
|
||||
@click="active(data)" v-if="data.type!='scenario'"/>
|
||||
<el-input :draggable="draggable" v-if="isShowInput && isShowNameInput" size="small" v-model="data.name" class="name-input"
|
||||
@blur="isShowInput = false" :placeholder="$t('commons.input_name')" ref="nameEdit"/>
|
||||
@blur="isShowInput = false" :placeholder="$t('commons.input_name')" ref="nameEdit" :disabled="data.disabled"/>
|
||||
<span v-else>
|
||||
{{data.name}}
|
||||
<i class="el-icon-edit" style="cursor:pointer" @click="editName" v-tester v-if="data.referenced!='REF' && !data.disabled"/>
|
||||
|
@ -26,31 +24,31 @@
|
|||
<slot name="behindHeaderLeft"></slot>
|
||||
</span>
|
||||
|
||||
<div class="header-right" @click.stop>
|
||||
<slot name="message"></slot>
|
||||
<el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top">
|
||||
<el-switch v-model="data.enable" class="enable-switch"/>
|
||||
</el-tooltip>
|
||||
<slot name="button"></slot>
|
||||
<el-tooltip content="Copy" placement="top">
|
||||
<el-button size="mini" icon="el-icon-copy-document" circle @click="copyRow"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('commons.remove')" placement="top">
|
||||
<el-button size="mini" icon="el-icon-delete" type="danger" circle @click="remove"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div class="header-right" @click.stop>
|
||||
<slot name="message"></slot>
|
||||
<el-tooltip :content="$t('test_resource_pool.enable_disable')" placement="top">
|
||||
<el-switch v-model="data.enable" class="enable-switch"/>
|
||||
</el-tooltip>
|
||||
<slot name="button"></slot>
|
||||
<el-tooltip content="Copy" placement="top">
|
||||
<el-button size="mini" icon="el-icon-copy-document" circle @click="copyRow"/>
|
||||
</el-tooltip>
|
||||
<el-tooltip :content="$t('commons.remove')" placement="top">
|
||||
<el-button size="mini" icon="el-icon-delete" type="danger" circle @click="remove"/>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<fieldset :disabled="data.disabled" class="ms-fieldset">
|
||||
<div class="header">
|
||||
<el-collapse-transition>
|
||||
<div v-if="data.active && showCollapse" :draggable="draggable">
|
||||
<el-divider></el-divider>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="header">
|
||||
<fieldset :disabled="data.disabled" class="ms-fieldset">
|
||||
<el-collapse-transition>
|
||||
<div v-if="data.active && showCollapse" :draggable="draggable">
|
||||
<el-divider></el-divider>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</el-collapse-transition>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
</el-card>
|
||||
</template>
|
||||
|
@ -163,8 +161,4 @@
|
|||
border: 0px;
|
||||
}
|
||||
|
||||
.ms-fieldset {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="request.protocol === 'HTTP'">
|
||||
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-if="request.url" v-model="request.url" style="width: 85%;margin-top: 10px" size="small">
|
||||
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
|
||||
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-input>
|
||||
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-else v-model="request.path" style="width: 85%;margin-top: 10px" size="small">
|
||||
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
|
||||
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-input>
|
||||
</div>
|
||||
|
||||
<div v-if="request.protocol === 'TCP' && isCustomizeReq">
|
||||
<el-form>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="$t('api_test.request.tcp.server')" prop="server">
|
||||
<el-input class="server-input" v-model="request.server" maxlength="300" show-word-limit size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('api_test.request.tcp.port')" prop="port" label-width="60px">
|
||||
<el-input-number v-model="request.port" controls-position="right" :min="0" :max="65535" size="small"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
|
||||
|
||||
export default {
|
||||
name: "CustomizeReqInfo",
|
||||
props: ['request', 'isCustomizeReq'],
|
||||
data() {
|
||||
return {
|
||||
reqOptions: REQ_METHOD,
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.server-input {
|
||||
width: 50%;
|
||||
}
|
||||
</style>
|
|
@ -25,18 +25,8 @@
|
|||
</el-tooltip>
|
||||
</template>
|
||||
|
||||
<div v-if="request.protocol === 'HTTP'">
|
||||
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-if="request.url" v-model="request.url" style="width: 85%;margin-top: 10px" size="small">
|
||||
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
|
||||
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-input>
|
||||
<el-input :placeholder="$t('api_test.definition.request.path_all_info')" v-else v-model="request.path" style="width: 85%;margin-top: 10px" size="small">
|
||||
<el-select v-model="request.method" slot="prepend" style="width: 100px" size="small">
|
||||
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
|
||||
</el-select>
|
||||
</el-input>
|
||||
</div>
|
||||
<customize-req-info :is-customize-req="isCustomizeReq" :request="request"/>
|
||||
|
||||
<p class="tip">{{$t('api_test.definition.request.req_param')}} </p>
|
||||
<ms-api-request-form :isShowEnable="true" :referenced="true" :headers="request.headers " :request="request" v-if="request.protocol==='HTTP' || request.type==='HTTPSamplerProxy'"/>
|
||||
<ms-tcp-basis-parameters :request="request" v-if="request.protocol==='TCP'|| request.type==='TCPSampler'"/>
|
||||
|
@ -65,6 +55,7 @@
|
|||
import {getUUID} from "@/common/js/utils";
|
||||
import ApiBaseComponent from "../common/ApiBaseComponent";
|
||||
import ApiResponseComponent from "./ApiResponseComponent";
|
||||
import CustomizeReqInfo from "@/business/components/api/automation/scenario/common/CustomizeReqInfo";
|
||||
|
||||
export default {
|
||||
name: "MsApiComponent",
|
||||
|
@ -79,13 +70,13 @@
|
|||
currentEnvironmentId: String,
|
||||
},
|
||||
components: {
|
||||
CustomizeReqInfo,
|
||||
ApiBaseComponent, ApiResponseComponent,
|
||||
MsSqlBasisParameters, MsTcpBasisParameters, MsDubboBasisParameters, MsApiRequestForm, MsRequestResultTail, MsRun
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
reqOptions: REQ_METHOD,
|
||||
reportId: "",
|
||||
runData: [],
|
||||
isShowInput: false,
|
||||
|
@ -98,15 +89,8 @@
|
|||
// 加载引用对象数据
|
||||
this.getApiInfo();
|
||||
if (this.request.protocol === 'HTTP') {
|
||||
try {
|
||||
let urlObject = new URL(this.request.url);
|
||||
let url = urlObject.protocol + "//" + urlObject.host + "/";
|
||||
} catch (e) {
|
||||
if (this.request.url) {
|
||||
this.request.path = this.request.url;
|
||||
this.request.url = undefined;
|
||||
}
|
||||
}
|
||||
this.setUrl(this.request.url);
|
||||
this.setUrl(this.request.path);
|
||||
// 历史数据 auth 处理
|
||||
if (this.request.hashTree) {
|
||||
for (let index in this.request.hashTree) {
|
||||
|
@ -180,6 +164,17 @@
|
|||
copyRow() {
|
||||
this.$emit('copyRow', this.request, this.node);
|
||||
},
|
||||
setUrl(url) {
|
||||
try {
|
||||
new URL(url);
|
||||
this.request.url = url;
|
||||
} catch (e) {
|
||||
if (url) {
|
||||
this.request.path = url;
|
||||
this.request.url = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
getApiInfo() {
|
||||
if (this.request.id && this.request.referenced === 'REF') {
|
||||
let requestResult = this.request.requestResult;
|
||||
|
@ -192,7 +187,8 @@
|
|||
this.request.enable = enable;
|
||||
if (response.data.path && response.data.path != null) {
|
||||
this.request.path = response.data.path;
|
||||
this.request.url = response.data.path;
|
||||
this.request.url = response.data.url;
|
||||
this.setUrl(this.request.path);
|
||||
}
|
||||
if (response.data.method && response.data.method != null) {
|
||||
this.request.method = response.data.method;
|
||||
|
@ -239,6 +235,7 @@
|
|||
this.loading = true;
|
||||
this.runData = [];
|
||||
this.request.useEnvironment = this.currentEnvironmentId;
|
||||
this.request.customizeReq = this.isCustomizeReq;
|
||||
let debugData = {
|
||||
id: this.currentScenario.id, name: this.currentScenario.name, type: "scenario",
|
||||
variables: this.currentScenario.variables, referenced: 'Created', enableCookieShare: this.enableCookieShare,
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
import MsApiComponent from "./ApiComponent";
|
||||
import MsLoopController from "./LoopController";
|
||||
import MsApiScenarioComponent from "./ApiScenarioComponent";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "ComponentConfig",
|
||||
|
|
|
@ -127,7 +127,7 @@
|
|||
</ms-delete-confirm>
|
||||
|
||||
<ms-dialog-footer style="float: right;margin: 20px"
|
||||
@confirm="confirm">
|
||||
@confirm="confirm" @cancel="cancel">
|
||||
</ms-dialog-footer>
|
||||
|
||||
</el-card>
|
||||
|
@ -203,8 +203,12 @@
|
|||
confirm() {
|
||||
if (this.selection.length==0) {
|
||||
this.$warning(this.$t("api_test.definition.request.test_plan_select"));
|
||||
}else{
|
||||
this.$emit('addTestPlan', this.selection);
|
||||
}
|
||||
this.$emit('addTestPlan', this.selection);
|
||||
},
|
||||
cancel(){
|
||||
this.$emit('cancel');
|
||||
},
|
||||
select(selection) {
|
||||
this.selection = selection.map(s => s.id);
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
<template>
|
||||
<el-dialog :title="$t('api_test.scenario.variables')" :close-on-click-modal="false"
|
||||
:visible.sync="visible" class="environment-dialog" width="60%"
|
||||
@close="close">
|
||||
:visible.sync="visible" class="visible-dialog" width="60%"
|
||||
@close="close" v-loading="loading">
|
||||
<div>
|
||||
<el-input placeholder="变量名称搜索" style="width: 50%;margin: 0px 0px 10px" v-model="selectVariable" size="small" @change="filter" @keyup.enter="filter">
|
||||
<el-select v-model="searchType" slot="prepend" placeholder="类型" style="width: 90px" @change="filter">
|
||||
<el-option value="CONSTANT" label="常量"></el-option>
|
||||
<el-option value="LIST" label="列表"></el-option>
|
||||
<el-option value="CSV" label="CSV"></el-option>
|
||||
<el-option value="COUNTER" label="计数器"></el-option>
|
||||
<el-option value="RANDOM" label="随机数"></el-option>
|
||||
</el-select>
|
||||
</el-input>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<div style="border:1px #DCDFE6 solid; min-height: 400px;border-radius: 4px ;width: 100% ;">
|
||||
|
||||
<el-table ref="table" border :data="variables" class="adjust-table" @select-all="select" @select="select"
|
||||
v-loading="loading" @row-click="edit">
|
||||
v-loading="loading" @row-click="edit" height="400px" :row-class-name="tableRowClassName">
|
||||
<el-table-column type="selection" width="38"/>
|
||||
<el-table-column prop="num" label="ID" sortable/>
|
||||
<el-table-column prop="name" :label="$t('api_test.variable_name')" sortable show-overflow-tooltip/>
|
||||
|
@ -28,15 +36,12 @@
|
|||
<ms-edit-list-value v-if="editData.type=='LIST'" ref="listValue" :editData="editData"/>
|
||||
<ms-edit-csv v-if="editData.type=='CSV'" ref="csv" :editData.sync="editData"/>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
||||
</div>
|
||||
|
||||
<template v-slot:footer>
|
||||
<div style="margin:20px">
|
||||
<div>
|
||||
<el-button style="margin-right:10px" @click="deleteVariable">{{$t('commons.delete')}}</el-button>
|
||||
|
||||
<el-dropdown split-button type="primary" @command="handleClick" @click="handleClick('CONSTANT')" placement="top-end">
|
||||
{{$t('commons.add')}}
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
|
@ -49,8 +54,6 @@
|
|||
</el-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
|
@ -63,7 +66,7 @@
|
|||
import MsEditRandom from "./EditRandom";
|
||||
import MsEditListValue from "./EditListValue";
|
||||
import MsEditCsv from "./EditCsv";
|
||||
import {getUUID} from "@/common/js/utils";
|
||||
import {_filter, getUUID} from "@/common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsVariableList",
|
||||
|
@ -80,6 +83,9 @@
|
|||
data() {
|
||||
return {
|
||||
variables: [],
|
||||
searchType: "",
|
||||
selectVariable: "",
|
||||
condition: {},
|
||||
types: new Map([
|
||||
['CONSTANT', '常量'],
|
||||
['LIST', '列表'],
|
||||
|
@ -105,6 +111,12 @@
|
|||
edit(row) {
|
||||
this.editData = row;
|
||||
},
|
||||
tableRowClassName(row) {
|
||||
if (row.row.hidden) {
|
||||
return 'ms-variable-hidden-row';
|
||||
}
|
||||
return '';
|
||||
},
|
||||
addParameters(v) {
|
||||
v.id = getUUID();
|
||||
if (v.type === 'CSV') {
|
||||
|
@ -133,10 +145,13 @@
|
|||
this.visible = false;
|
||||
let saveVariables = [];
|
||||
this.variables.forEach(item => {
|
||||
item.hidden = undefined;
|
||||
if (item.name && item.name != "") {
|
||||
saveVariables.push(item);
|
||||
}
|
||||
})
|
||||
this.selectVariable = "";
|
||||
this.searchType = "";
|
||||
this.$emit('setVariables', saveVariables);
|
||||
},
|
||||
deleteVariable() {
|
||||
|
@ -150,11 +165,50 @@
|
|||
this.variables.splice(index, 1);
|
||||
})
|
||||
this.selection = [];
|
||||
}
|
||||
},
|
||||
filter() {
|
||||
let datas = [];
|
||||
this.variables.forEach(item => {
|
||||
if (this.searchType && this.searchType != "" && this.selectVariable && this.selectVariable != "") {
|
||||
if ((item.type && item.type.toLowerCase().indexOf(this.searchType.toLowerCase()) == -1) || (item.name && item.name.toLowerCase().indexOf(this.selectVariable.toLowerCase()) == -1)) {
|
||||
item.hidden = true;
|
||||
} else {
|
||||
item.hidden = undefined;
|
||||
}
|
||||
}
|
||||
else if (this.selectVariable && this.selectVariable != "") {
|
||||
if (item.name && item.name.toLowerCase().indexOf(this.selectVariable.toLowerCase()) == -1) {
|
||||
item.hidden = true;
|
||||
} else {
|
||||
item.hidden = undefined;
|
||||
}
|
||||
}
|
||||
else if (this.searchType && this.searchType != "") {
|
||||
if (item.type && item.type.toLowerCase().indexOf(this.searchType.toLowerCase()) == -1) {
|
||||
item.hidden = true;
|
||||
} else {
|
||||
item.hidden = undefined;
|
||||
}
|
||||
}
|
||||
datas.push(item);
|
||||
})
|
||||
this.variables = datas;
|
||||
},
|
||||
createFilter(queryString) {
|
||||
return item => {
|
||||
return (item.type && item.type.toLowerCase().indexOf(queryString.toLowerCase()) !== -1);
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ms-variable-hidden-row {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/deep/ .el-dialog__body {
|
||||
padding: 10px 10px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<ms-container v-if="renderComponent">
|
||||
<ms-aside-container>
|
||||
<ms-api-module
|
||||
|
@ -9,6 +10,7 @@
|
|||
@debug="debug"
|
||||
@saveAsEdit="editApi"
|
||||
@setModuleOptions="setModuleOptions"
|
||||
@setNodeTree="setNodeTree"
|
||||
@enableTrash="enableTrash"
|
||||
:type="'edit'"
|
||||
ref="nodeTree"/>
|
||||
|
@ -25,6 +27,8 @@
|
|||
<!-- 列表集合 -->
|
||||
<ms-api-list
|
||||
v-if="item.type === 'list' && isApiListEnable"
|
||||
:module-tree="nodeTree"
|
||||
:module-options="moduleOptions"
|
||||
:current-protocol="currentProtocol"
|
||||
:visible="visible"
|
||||
:currentRow="currentRow"
|
||||
|
@ -102,8 +106,12 @@
|
|||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
|
||||
</ms-main-container>
|
||||
</ms-container>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import MsApiList from './components/list/ApiList';
|
||||
|
@ -177,7 +185,7 @@
|
|||
currentModule: null,
|
||||
selectNodeIds: [],
|
||||
currentApi: {},
|
||||
moduleOptions: {},
|
||||
moduleOptions: [],
|
||||
trashEnable: false,
|
||||
apiTabs: [{
|
||||
title: this.$t('api_test.definition.api_title'),
|
||||
|
@ -187,7 +195,8 @@
|
|||
}],
|
||||
isApiListEnable: true,
|
||||
syncTabs: [],
|
||||
projectId: ""
|
||||
projectId: "",
|
||||
nodeTree: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -215,6 +224,7 @@
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
changeRedirectParam(redirectIDParam) {
|
||||
this.redirectID = redirectIDParam;
|
||||
},
|
||||
|
@ -394,6 +404,9 @@
|
|||
setModuleOptions(data) {
|
||||
this.moduleOptions = data;
|
||||
},
|
||||
setNodeTree(data) {
|
||||
this.nodeTree = data;
|
||||
},
|
||||
changeSelectDataRangeAll(tableType) {
|
||||
this.$route.params.dataSelectRange = 'all';
|
||||
},
|
||||
|
|
|
@ -127,6 +127,9 @@
|
|||
this.request = createComponent("JDBCSampler");
|
||||
this.currentApi.request = this.request;
|
||||
}
|
||||
if (!this.currentApi.request.variables) {
|
||||
this.currentApi.request.variables = [];
|
||||
}
|
||||
},
|
||||
initDubbo() {
|
||||
if (!this.setRequest()) {
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
rule: {
|
||||
name: [
|
||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
||||
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
|
||||
],
|
||||
path: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}, {validator: validateURL, trigger: 'blur'}],
|
||||
userId: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
<template>
|
||||
<div v-if="dialogVisible" class="batch-move" v-loading="result.loading">
|
||||
<el-dialog :title="this.$t('test_track.case.select_catalog')"
|
||||
:visible.sync="dialogVisible"
|
||||
:before-close="close"
|
||||
:destroy-on-close="true"
|
||||
width="20%"
|
||||
>
|
||||
<div>
|
||||
<el-input :placeholder="$t('test_track.module.search')" v-model="filterText" size="small"/>
|
||||
<el-tree
|
||||
class="filter-tree node-tree"
|
||||
:data="treeNodes"
|
||||
node-key="id"
|
||||
:filter-node-method="filterNode"
|
||||
:expand-on-click-node="false"
|
||||
highlight-current
|
||||
style="overflow: auto"
|
||||
@node-click="nodeClick"
|
||||
ref="tree"
|
||||
>
|
||||
<template v-slot:default="{node}">
|
||||
<span>
|
||||
<span class="node-icon">
|
||||
<i class="el-icon-folder"/>
|
||||
</span>
|
||||
<span class="node-title">{{node.label}}</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
<template v-slot:footer>
|
||||
<ms-dialog-footer
|
||||
@cancel="close"
|
||||
@confirm="save"/>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import MsDialogFooter from "@/business/components/common/components/MsDialogFooter";
|
||||
export default {
|
||||
name: "CaseBatchMove",
|
||||
components: {
|
||||
MsDialogFooter
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
treeNodes: [],
|
||||
selectIds: [],
|
||||
selectNode: {},
|
||||
dialogVisible: false,
|
||||
currentKey: "",
|
||||
moduleOptions: [],
|
||||
filterText: "",
|
||||
result: {},
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
filterText(val) {
|
||||
this.$refs.tree.filter(val);
|
||||
console.log( this.treeNodes)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
open(treeNodes, selectIds, moduleOptions) {
|
||||
|
||||
this.dialogVisible = true;
|
||||
this.treeNodes = treeNodes;
|
||||
this.selectIds = selectIds;
|
||||
this.moduleOptions = moduleOptions;
|
||||
|
||||
},
|
||||
save() {
|
||||
if (!this.currentKey) {
|
||||
this.$warning(this.$t('test_track.case.input_module'));
|
||||
return;
|
||||
}
|
||||
let param = {};
|
||||
param.nodeId = this.currentKey;
|
||||
if (this.moduleOptions) {
|
||||
this.moduleOptions.forEach(item => {
|
||||
if (item.id === this.currentKey) {
|
||||
param.nodePath = item.path;
|
||||
}
|
||||
});
|
||||
}
|
||||
param.ids = this.selectIds;
|
||||
this.$emit('moveSave', param);
|
||||
},
|
||||
refresh() {
|
||||
this.$emit("refresh");
|
||||
},
|
||||
close() {
|
||||
this.filterText = "";
|
||||
this.dialogVisible = false;
|
||||
this.selectNode = {};
|
||||
},
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.label.indexOf(value) !== -1;
|
||||
},
|
||||
nodeClick() {
|
||||
this.currentKey = this.$refs.tree.getCurrentKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.node-title {
|
||||
width: 0;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1 1 auto;
|
||||
padding: 0 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.batch-move {
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -288,6 +288,9 @@
|
|||
url = "/api/testcase/update";
|
||||
} else {
|
||||
tmp.request.path = this.api.path;
|
||||
if (tmp.request.protocol != "dubbo://" && tmp.request.protocol != "DUBBO") {
|
||||
tmp.request.method = this.api.method;
|
||||
}
|
||||
}
|
||||
if (tmp.tags instanceof Array) {
|
||||
tmp.tags = JSON.stringify(tmp.tags);
|
||||
|
|
|
@ -109,29 +109,29 @@
|
|||
|
||||
<script>
|
||||
|
||||
import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
|
||||
import MsResponseText from "../response/ResponseText";
|
||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||
import {API_STATUS, REQ_METHOD} from "../../model/JsonData";
|
||||
import {KeyValue} from "../../model/ApiTestModel";
|
||||
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
||||
import MsJsr233Processor from "../../../automation/scenario/component/Jsr233Processor";
|
||||
import MsApiRequestForm from "../request/http/ApiHttpRequestForm";
|
||||
import MsResponseText from "../response/ResponseText";
|
||||
import {WORKSPACE_ID} from '../../../../../../common/js/constants';
|
||||
import {API_STATUS, REQ_METHOD} from "../../model/JsonData";
|
||||
import {KeyValue} from "../../model/ApiTestModel";
|
||||
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
|
||||
import MsJsr233Processor from "../../../automation/scenario/component/Jsr233Processor";
|
||||
|
||||
export default {
|
||||
name: "MsAddCompleteHttpApi",
|
||||
components: {MsJsr233Processor, MsResponseText, MsApiRequestForm, MsInputTag},
|
||||
data() {
|
||||
let validateURL = (rule, value, callback) => {
|
||||
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
|
||||
callback(this.$t('api_test.definition.request.path_valid_info'));
|
||||
}
|
||||
callback();
|
||||
};
|
||||
return {
|
||||
export default {
|
||||
name: "MsAddCompleteHttpApi",
|
||||
components: {MsJsr233Processor, MsResponseText, MsApiRequestForm, MsInputTag},
|
||||
data() {
|
||||
let validateURL = (rule, value, callback) => {
|
||||
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
|
||||
callback(this.$t('api_test.definition.request.path_valid_info'));
|
||||
}
|
||||
callback();
|
||||
};
|
||||
return {
|
||||
rule: {
|
||||
name: [
|
||||
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
|
||||
{max: 50, message: this.$t('test_track.length_less_than') + '50', trigger: 'blur'}
|
||||
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
|
||||
],
|
||||
path: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}, {
|
||||
validator: validateURL,
|
||||
|
|
|
@ -147,8 +147,6 @@
|
|||
},
|
||||
saveAs() {
|
||||
let obj = {request: this.request};
|
||||
obj.request.server = this.debugForm.server;
|
||||
obj.request.port = this.debugForm.port;
|
||||
obj.server = this.debugForm.server;
|
||||
obj.port = this.debugForm.port;
|
||||
obj.request.id = getUUID();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
@select-all="handleSelectAll"
|
||||
@filter-change="filter"
|
||||
@sort-change="sort"
|
||||
@header-dragend="headerDragend"
|
||||
@select="handleSelect" :height="screenHeight">
|
||||
|
||||
<el-table-column type="selection" width="50"/>
|
||||
|
@ -25,25 +26,28 @@
|
|||
@selectPageAll="isSelectDataAll(false)"
|
||||
@selectAll="isSelectDataAll(true)"/>
|
||||
|
||||
<el-table-column width="30" :resizable="false" align="center">
|
||||
<el-table-column width="30" :resizable="false" min-width="30px" align="center">
|
||||
<template v-slot:default="scope">
|
||||
<show-more-btn :is-show="scope.row.showMore" :buttons="buttons" :size="selectDataCounts"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="num" label="ID" show-overflow-tooltip>
|
||||
<el-table-column prop="num" label="ID" min-width="120px" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip content="编辑">
|
||||
<a style="cursor:pointer" @click="handleTestCase(scope.row)"> {{ scope.row.num }} </a>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="name" :label="$t('test_track.case.name')" show-overflow-tooltip/>
|
||||
|
||||
<el-table-column prop="name" min-width="160px" :label="$t('test_track.case.name')" show-overflow-tooltip/>
|
||||
|
||||
<el-table-column
|
||||
prop="priority"
|
||||
:filters="priorityFilters"
|
||||
column-key="priority"
|
||||
min-width="120px"
|
||||
|
||||
:label="$t('test_track.case.priority')"
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
|
@ -54,10 +58,12 @@
|
|||
<el-table-column
|
||||
sortable="custom"
|
||||
prop="path"
|
||||
min-width="180px"
|
||||
:label="$t('api_test.definition.api_path')"
|
||||
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column prop="tags" :label="$t('commons.tag')">
|
||||
<el-table-column prop="tags" min-width="120px" :label="$t('commons.tag')">
|
||||
<template v-slot:default="scope">
|
||||
<div v-for="(itemName,index) in scope.row.tags" :key="index">
|
||||
<ms-tag type="success" effect="plain" :content="itemName"/>
|
||||
|
@ -68,12 +74,14 @@
|
|||
<el-table-column
|
||||
prop="createUser"
|
||||
:label="'创建人'"
|
||||
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column
|
||||
sortable="custom"
|
||||
width="160"
|
||||
min-width="160"
|
||||
:label="$t('api_test.definition.api_last_time')"
|
||||
|
||||
prop="updateTime">
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
|
@ -82,11 +90,6 @@
|
|||
|
||||
<el-table-column fixed="right" 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>-->
|
||||
<!-- <el-button type="text" @click="handleDelete(scope.row)" style="color: #F56C6C">{{ $t('commons.delete') }}-->
|
||||
<!-- </el-button>-->
|
||||
<ms-table-operator-button :tip="$t('commons.edit')" icon="el-icon-edit" @exec="handleTestCase(scope.row)" v-tester/>
|
||||
<ms-table-operator-button :tip="$t('commons.delete')" icon="el-icon-delete" @exec="handleDelete(scope.row)" type="danger" v-tester/>
|
||||
<ms-api-case-table-extend-btns @showCaseRef="showCaseRef" @showEnvironment="showEnvironment" @createPerformance="createPerformance" :row="scope.row" v-tester/>
|
||||
|
@ -505,6 +508,14 @@ export default {
|
|||
this.clickRow = row;
|
||||
this.$refs.setEnvironment.open(row);
|
||||
},
|
||||
headerDragend(newWidth,oldWidth,column,event){
|
||||
let finalWidth = newWidth;
|
||||
if(column.minWidth>finalWidth){
|
||||
finalWidth = column.minWidth;
|
||||
}
|
||||
column.width = finalWidth;
|
||||
column.realWidth = finalWidth;
|
||||
},
|
||||
createPerformance(row, environment) {
|
||||
/**
|
||||
* 思路:调用后台创建性能测试的方法,把当前案例的hashTree在后台转化为jmx并文件创建性能测试。
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -126,6 +126,7 @@
|
|||
buildNodePath(node, {path: ''}, moduleOptions);
|
||||
});
|
||||
this.$emit('setModuleOptions', moduleOptions);
|
||||
this.$emit('setNodeTree', this.data);
|
||||
if (this.$refs.nodeTree) {
|
||||
this.$refs.nodeTree.filter(this.condition.filterText);
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ export default {
|
|||
}
|
||||
|
||||
.filter-input {
|
||||
width: 175px;
|
||||
width: 174px;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-loading="isReloadData">
|
||||
<el-row>
|
||||
<el-col :span="21" style="padding-bottom: 20px">
|
||||
<div style="border:1px #DCDFE6 solid; height: 100%;border-radius: 4px ;width: 100% ;margin: 20px">
|
||||
|
@ -28,7 +28,7 @@
|
|||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="$t('api_test.request.sql.dataSource')" prop="dataSourceId" style="margin-left: 10px">
|
||||
<el-select v-model="request.dataSourceId" size="small">
|
||||
<el-select v-model="request.dataSourceId" size="small" @change="reload">
|
||||
<el-option v-for="(item, index) in databaseConfigsOptions" :key="index" :value="item.id" :label="item.name"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
@ -143,7 +143,7 @@
|
|||
activeName: "variables",
|
||||
rules: {
|
||||
environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
|
||||
dataSourceId: [{required: true, message: this.$t('api_test.request.sql.dataSource'), trigger: 'change'}],
|
||||
dataSourceId: [{required: true, message: this.$t('api_test.request.sql.dataSource'), trigger: 'blur'}],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
|
|
@ -63,23 +63,23 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import MsAssertionResults from "./AssertionResults";
|
||||
import MsCodeEdit from "../MsCodeEdit";
|
||||
import MsDropdown from "../../../../common/components/MsDropdown";
|
||||
import {BODY_FORMAT} from "../../model/ApiTestModel";
|
||||
import MsSqlResultTable from "./SqlResultTable";
|
||||
import MsAssertionResults from "./AssertionResults";
|
||||
import MsCodeEdit from "../MsCodeEdit";
|
||||
import MsDropdown from "../../../../common/components/MsDropdown";
|
||||
import {BODY_FORMAT} from "../../model/ApiTestModel";
|
||||
import MsSqlResultTable from "./SqlResultTable";
|
||||
|
||||
export default {
|
||||
name: "MsResponseResult",
|
||||
export default {
|
||||
name: "MsResponseResult",
|
||||
|
||||
components: {
|
||||
MsDropdown,
|
||||
MsCodeEdit,
|
||||
MsAssertionResults,
|
||||
MsSqlResultTable
|
||||
},
|
||||
components: {
|
||||
MsDropdown,
|
||||
MsCodeEdit,
|
||||
MsAssertionResults,
|
||||
MsSqlResultTable
|
||||
},
|
||||
|
||||
props: {
|
||||
props: {
|
||||
response: Object,
|
||||
currentProtocol: String,
|
||||
},
|
||||
|
@ -107,7 +107,7 @@
|
|||
this.mode = mode;
|
||||
},
|
||||
setBodyType() {
|
||||
if (!this.response.responseResult.headers) {
|
||||
if (!this.response.responseResult || !this.response.responseResult.headers) {
|
||||
return;
|
||||
}
|
||||
if (this.response.responseResult.headers.indexOf("Content-Type: application/json") > 0) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
title="选则模块"
|
||||
:title="$t('commons.module.select_module')"
|
||||
:visible.sync="oneClickOperationVisible"
|
||||
width="600px"
|
||||
left
|
||||
|
@ -11,7 +11,7 @@
|
|||
<ms-node-tree
|
||||
v-loading="result.loading"
|
||||
:tree-nodes="data"
|
||||
allLabel="默认模块"
|
||||
:allLabel="$t('commons.module.default_module')"
|
||||
@add="add"
|
||||
:type="'edit'"
|
||||
@edit="edit"
|
||||
|
|
|
@ -74,4 +74,9 @@
|
|||
|
||||
<style scoped>
|
||||
|
||||
.jar-config-list {
|
||||
max-height: 600px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -172,6 +172,22 @@ export const API_CASE_RESULT = {
|
|||
}
|
||||
}
|
||||
|
||||
export const API_SCENARIO_RESULT = {
|
||||
key: "status",
|
||||
name: 'MsTableSearchSelect',
|
||||
label: 'test_track.plan_view.execute_result',
|
||||
operator: {
|
||||
options: [OPERATORS.IN, OPERATORS.NOT_IN]
|
||||
},
|
||||
options: [
|
||||
{value: 'Success', label: 'api_test.automation.success'},
|
||||
{value: 'Fail', label: 'api_test.automation.fail'}
|
||||
],
|
||||
props: { // 尾部控件的props,一般为element ui控件的props
|
||||
multiple: true
|
||||
}
|
||||
}
|
||||
|
||||
export const API_METHOD = {
|
||||
key: "method",
|
||||
name: 'MsTableSearchSelect',
|
||||
|
@ -442,4 +458,6 @@ export const API_DEFINITION_CONFIGS = [NAME, API_METHOD, API_PATH, API_STATUS, A
|
|||
|
||||
export const API_CASE_CONFIGS = [NAME, API_CASE_PRIORITY, API_TAGS, API_CASE_RESULT, UPDATE_TIME, CREATE_TIME, CREATOR];
|
||||
|
||||
export const API_SCENARIO_CONFIGS = [NAME, API_CASE_PRIORITY, API_TAGS, API_SCENARIO_RESULT, UPDATE_TIME, CREATE_TIME, CREATOR];
|
||||
|
||||
export const TEST_PLAN_REPORT_CONFIGS = [NAME, TEST_PLAN_NAME,CREATOR, CREATE_TIME, TEST_PLAN_TRIGGER_MODE, TEST_PLAN_STATUS];
|
||||
|
|
|
@ -2,25 +2,41 @@
|
|||
<el-menu :unique-opened="true" mode="horizontal" router
|
||||
class="header-user-menu align-right"
|
||||
background-color="#2c2a48"
|
||||
active-text-color="#fff"
|
||||
default-active="1"
|
||||
text-color="#fff">
|
||||
<el-submenu index="1" popper-class="submenu"
|
||||
<el-menu-item index="1" v-show="false">Placeholder</el-menu-item>
|
||||
<el-submenu index="1" popper-class="org-ws-submenu"
|
||||
v-roles="['org_admin', 'test_manager', 'test_user', 'test_viewer']">
|
||||
<template v-slot:title>{{$t('commons.organization')}}: {{currentOrganizationName}}</template>
|
||||
<label v-for="(item,index) in organizationList" :key="index">
|
||||
<el-menu-item @click="changeOrg(item)">{{item.name}}
|
||||
<template v-slot:title>{{ $t('commons.organization') }}: {{ currentOrganizationName }}</template>
|
||||
<el-input :placeholder="$t('project.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
v-model="searchOrg"
|
||||
clearable
|
||||
class="search-input"
|
||||
size="small"/>
|
||||
<div class="org-ws-menu">
|
||||
<el-menu-item @click="changeOrg(item)" v-for="(item,index) in organizationList" :key="index">
|
||||
{{ item.name }}
|
||||
<i class="el-icon-check"
|
||||
v-if="item.id === currentUserInfo.lastOrganizationId"></i>
|
||||
</el-menu-item>
|
||||
</label>
|
||||
</div>
|
||||
</el-submenu>
|
||||
<el-submenu index="2" popper-class="submenu" v-roles="['test_manager', 'test_user', 'test_viewer']">
|
||||
<template v-slot:title>{{$t('commons.workspace')}}: {{currentWorkspaceName}}</template>
|
||||
<label v-for="(item,index) in workspaceList" :key="index">
|
||||
<el-menu-item @click="changeWs(item)">
|
||||
{{item.name}}
|
||||
<template v-slot:title>{{ $t('commons.workspace') }}: {{ currentWorkspaceName }}</template>
|
||||
<el-input :placeholder="$t('project.search_by_name')"
|
||||
prefix-icon="el-icon-search"
|
||||
v-model="searchWs"
|
||||
clearable
|
||||
class="search-input"
|
||||
size="small"/>
|
||||
<div class="org-ws-menu">
|
||||
<el-menu-item @click="changeWs(item)" v-for="(item,index) in workspaceList" :key="index">
|
||||
{{ item.name }}
|
||||
<i class="el-icon-check" v-if="item.id === currentUserInfo.lastWorkspaceId"></i>
|
||||
</el-menu-item>
|
||||
</label>
|
||||
</div>
|
||||
</el-submenu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
@ -34,107 +50,170 @@ import {
|
|||
ROLE_TEST_VIEWER,
|
||||
WORKSPACE_ID
|
||||
} from '../../../../common/js/constants';
|
||||
import {getCurrentUser, hasRoles, saveLocalStorage} from "../../../../common/js/utils";
|
||||
import {getCurrentUser, hasRoles, saveLocalStorage} from "../../../../common/js/utils";
|
||||
|
||||
export default {
|
||||
name: "MsHeaderOrgWs",
|
||||
created() {
|
||||
this.initMenuData();
|
||||
this.getCurrentUserInfo();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
organizationList: [
|
||||
{name: this.$t('organization.none')},
|
||||
],
|
||||
workspaceList: [
|
||||
{name: this.$t('workspace.none')},
|
||||
],
|
||||
currentUserInfo: {},
|
||||
currentUserId: getCurrentUser().id,
|
||||
workspaceIds: [],
|
||||
currentOrganizationName: '',
|
||||
currentWorkspaceName: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initMenuData() {
|
||||
if (hasRoles(ROLE_ORG_ADMIN, ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get("/organization/list/userorg/" + encodeURIComponent(this.currentUserId), response => {
|
||||
let data = response.data;
|
||||
this.organizationList = data;
|
||||
let org = data.filter(r => r.id === this.currentUser.lastOrganizationId);
|
||||
if (org.length > 0) {
|
||||
this.currentOrganizationName = org[0].name;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
if (!this.currentUser.lastOrganizationId) {
|
||||
return false;
|
||||
}
|
||||
this.$get("/workspace/list/orgworkspace/", response => {
|
||||
let data = response.data;
|
||||
if (data.length === 0) {
|
||||
this.workspaceList = [{name: this.$t('workspace.none')}]
|
||||
} else {
|
||||
this.workspaceList = data;
|
||||
let workspace = data.filter(r => r.id === this.currentUser.lastWorkspaceId);
|
||||
if (workspace.length > 0) {
|
||||
this.currentWorkspaceName = workspace[0].name;
|
||||
localStorage.setItem(WORKSPACE_ID, workspace[0].id);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getCurrentUserInfo() {
|
||||
this.$get("/user/info/" + encodeURIComponent(this.currentUserId), response => {
|
||||
this.currentUserInfo = response.data;
|
||||
})
|
||||
},
|
||||
changeOrg(data) {
|
||||
let orgId = data.id;
|
||||
if (!orgId) {
|
||||
return false;
|
||||
}
|
||||
this.$post("/user/switch/source/org/" + orgId, {}, response => {
|
||||
saveLocalStorage(response);
|
||||
if (response.data.workspaceId) {
|
||||
localStorage.setItem("workspace_id", response.data.workspaceId);
|
||||
}
|
||||
localStorage.removeItem(PROJECT_ID);
|
||||
this.$router.push('/').then(() => {
|
||||
window.location.reload();
|
||||
}).catch(err => err);
|
||||
});
|
||||
},
|
||||
changeWs(data) {
|
||||
let workspaceId = data.id;
|
||||
if (!workspaceId) {
|
||||
return false;
|
||||
}
|
||||
this.$post("/user/switch/source/ws/" + workspaceId, {}, response => {
|
||||
saveLocalStorage(response);
|
||||
localStorage.setItem("workspace_id", workspaceId);
|
||||
localStorage.removeItem(PROJECT_ID);
|
||||
this.$router.push('/').then(() => {
|
||||
window.location.reload();
|
||||
}).catch(err => err);
|
||||
})
|
||||
}
|
||||
export default {
|
||||
name: "MsHeaderOrgWs",
|
||||
created() {
|
||||
this.initMenuData();
|
||||
this.getCurrentUserInfo();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
organizationList: [
|
||||
{name: this.$t('organization.none')},
|
||||
],
|
||||
workspaceList: [
|
||||
{name: this.$t('workspace.none')},
|
||||
],
|
||||
currentUserInfo: {},
|
||||
currentUserId: getCurrentUser().id,
|
||||
workspaceIds: [],
|
||||
currentOrganizationName: '',
|
||||
currentWorkspaceName: '',
|
||||
searchOrg: '',
|
||||
searchWs: '',
|
||||
orgListCopy: [{name: this.$t('organization.none')}],
|
||||
wsListCopy: [{name: this.$t('workspace.none')}]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentUser: () => {
|
||||
return getCurrentUser();
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
searchOrg(val) {
|
||||
this.query('org', val);
|
||||
},
|
||||
searchWs(val) {
|
||||
this.query('ws', val);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initMenuData() {
|
||||
if (hasRoles(ROLE_ORG_ADMIN, ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
this.$get("/organization/list/userorg/" + encodeURIComponent(this.currentUserId), response => {
|
||||
let data = response.data;
|
||||
this.organizationList = data;
|
||||
this.orgListCopy = data;
|
||||
let org = data.filter(r => r.id === this.currentUser.lastOrganizationId);
|
||||
if (org.length > 0) {
|
||||
this.currentOrganizationName = org[0].name;
|
||||
}
|
||||
});
|
||||
}
|
||||
if (hasRoles(ROLE_TEST_VIEWER, ROLE_TEST_USER, ROLE_TEST_MANAGER)) {
|
||||
if (!this.currentUser.lastOrganizationId) {
|
||||
return false;
|
||||
}
|
||||
this.$get("/workspace/list/orgworkspace/", response => {
|
||||
let data = response.data;
|
||||
if (data.length === 0) {
|
||||
this.workspaceList = [{name: this.$t('workspace.none')}]
|
||||
} else {
|
||||
this.workspaceList = data;
|
||||
this.wsListCopy = data;
|
||||
let workspace = data.filter(r => r.id === this.currentUser.lastWorkspaceId);
|
||||
if (workspace.length > 0) {
|
||||
this.currentWorkspaceName = workspace[0].name;
|
||||
localStorage.setItem(WORKSPACE_ID, workspace[0].id);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getCurrentUserInfo() {
|
||||
this.$get("/user/info/" + encodeURIComponent(this.currentUserId), response => {
|
||||
this.currentUserInfo = response.data;
|
||||
})
|
||||
},
|
||||
changeOrg(data) {
|
||||
let orgId = data.id;
|
||||
if (!orgId) {
|
||||
return false;
|
||||
}
|
||||
this.$post("/user/switch/source/org/" + orgId, {}, response => {
|
||||
saveLocalStorage(response);
|
||||
if (response.data.workspaceId) {
|
||||
localStorage.setItem("workspace_id", response.data.workspaceId);
|
||||
}
|
||||
localStorage.removeItem(PROJECT_ID);
|
||||
this.$router.push('/').then(() => {
|
||||
window.location.reload();
|
||||
}).catch(err => err);
|
||||
});
|
||||
},
|
||||
changeWs(data) {
|
||||
let workspaceId = data.id;
|
||||
if (!workspaceId) {
|
||||
return false;
|
||||
}
|
||||
this.$post("/user/switch/source/ws/" + workspaceId, {}, response => {
|
||||
saveLocalStorage(response);
|
||||
localStorage.setItem("workspace_id", workspaceId);
|
||||
localStorage.removeItem(PROJECT_ID);
|
||||
this.$router.push('/').then(() => {
|
||||
window.location.reload();
|
||||
}).catch(err => err);
|
||||
})
|
||||
},
|
||||
query(sign, queryString) {
|
||||
if (sign === 'org') {
|
||||
this.organizationList = queryString ? this.orgListCopy.filter(this.createFilter(queryString)) : this.orgListCopy;
|
||||
}
|
||||
if (sign === 'ws') {
|
||||
this.workspaceList = queryString ? this.wsListCopy.filter(this.createFilter(queryString)) : this.wsListCopy;
|
||||
}
|
||||
},
|
||||
createFilter(queryString) {
|
||||
return item => {
|
||||
return (item.name.toLowerCase().indexOf(queryString.toLowerCase()) !== -1);
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-icon-check {
|
||||
color: #44b349;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.el-icon-check {
|
||||
color: #44b349;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 1em;
|
||||
background-color: #595591;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 1em;
|
||||
background-color: transparent;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.org-ws-menu {
|
||||
height: 180px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
padding: 0;
|
||||
margin-top: -4px;
|
||||
background-color: #595591;
|
||||
}
|
||||
|
||||
.search-input >>> .el-input__inner {
|
||||
border-radius: 0;
|
||||
background-color: #2d2a49;
|
||||
color: #d2ced8;
|
||||
border-color: #b4aebe;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
<el-row class="row" :gutter="20">
|
||||
<el-col :span="8" class="ms-col-name">
|
||||
<div :style="{marginLeft:`${10*deep}px`}" class="ms-col-name-c"/>
|
||||
<span v-if="pickValue.type==='object'" :class="hidden? 'el-tree-node__expand-icon el-icon-caret-right':
|
||||
'expanded el-tree-node__expand-icon el-icon-caret-right'" @click="hidden = !hidden"/>
|
||||
<span v-if="pickValue.type==='object'" :class="hidden? 'el-icon-caret-left ms-transform':
|
||||
'el-icon-caret-bottom'" @click="hidden = !hidden"/>
|
||||
<span v-else style="width:10px;display:inline-block"></span>
|
||||
<input class="el-input el-input__inner" style="height: 32px" :disabled="disabled || root" :value="pickKey" @blur="onInputName" size="small"/>
|
||||
|
||||
|
@ -393,4 +393,8 @@
|
|||
border-left: 4px solid #783887;
|
||||
margin: 0px 0px 10px;
|
||||
}
|
||||
.ms-transform {
|
||||
transform: rotate(-180deg);
|
||||
transition: 0ms;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -293,12 +293,12 @@ export default {
|
|||
};
|
||||
this.result = this.$request(config).then(response => {
|
||||
const content = response.data;
|
||||
const blob = new Blob([content]);
|
||||
const blob = new Blob([content], {type: "application/octet-stream"});
|
||||
if ("download" in document.createElement("a")) {
|
||||
// 非IE下载
|
||||
// chrome/firefox
|
||||
let aTag = document.createElement('a');
|
||||
aTag.download = this.reportId + ".jtl";
|
||||
aTag.download = this.reportId + ".zip";
|
||||
aTag.href = URL.createObjectURL(blob);
|
||||
aTag.click();
|
||||
URL.revokeObjectURL(aTag.href)
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
<el-table-column prop="description" :label="$t('commons.description')"/>
|
||||
<el-table-column :label="$t('commons.member')">
|
||||
<template v-slot:default="scope">
|
||||
<el-button type="text" class="member-size" @click="cellClick(scope.row)">{{scope.row.memberSize}}
|
||||
</el-button>
|
||||
<el-link type="primary" class="member-size" @click="cellClick(scope.row)">
|
||||
{{ scope.row.memberSize }}
|
||||
</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.operating')">
|
||||
|
@ -506,7 +507,6 @@
|
|||
|
||||
.member-size {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select-width {
|
||||
|
|
|
@ -114,9 +114,7 @@ export default {
|
|||
}
|
||||
],
|
||||
phone: [
|
||||
{required: true, message: this.$t('user.input_phone'), trigger: 'blur'},
|
||||
{
|
||||
required: false,
|
||||
pattern: PHONE_REGEX,
|
||||
message: this.$t('member.mobile_number_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
|
|
|
@ -399,9 +399,7 @@ export default {
|
|||
}
|
||||
],
|
||||
phone: [
|
||||
{required: true, message: this.$t('user.input_phone'), trigger: 'blur'},
|
||||
{
|
||||
required: true,
|
||||
pattern: PHONE_REGEX,
|
||||
message: this.$t('user.mobile_number_format_is_incorrect'),
|
||||
trigger: 'blur'
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
@filter-change="filter"
|
||||
@select-all="handleSelectAll"
|
||||
@select="handleSelect"
|
||||
@header-dragend="headerDragend"
|
||||
@cell-mouse-enter="showPopover"
|
||||
row-key="id"
|
||||
class="test-content adjust-table ms-select-all-fixed"
|
||||
|
@ -562,6 +563,14 @@ export default {
|
|||
this.selectDataCounts = this.selectRows.size;
|
||||
}
|
||||
},
|
||||
headerDragend(newWidth,oldWidth,column,event){
|
||||
let finalWidth = newWidth;
|
||||
if(column.minWidth>finalWidth){
|
||||
finalWidth = column.minWidth;
|
||||
}
|
||||
column.width = finalWidth;
|
||||
column.realWidth = finalWidth;
|
||||
},
|
||||
moveSave(param) {
|
||||
param.condition = this.condition;
|
||||
this.result = this.$post('/test/case/batch/edit', param, () => {
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
@select="handleSelectionChange"
|
||||
row-key="id"
|
||||
@row-click="showDetail"
|
||||
@header-dragend="headerDragend"
|
||||
:data="tableData">
|
||||
|
||||
<el-table-column
|
||||
|
@ -48,17 +49,23 @@
|
|||
prop="num"
|
||||
sortable="custom"
|
||||
:label="$t('commons.id')"
|
||||
min-width="120px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="name"
|
||||
:label="$t('commons.name')"
|
||||
min-width="120px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="priority"
|
||||
:filters="priorityFilters"
|
||||
column-key="priority"
|
||||
min-width="100px"
|
||||
|
||||
:label="$t('test_track.case.priority')">
|
||||
<template v-slot:default="scope">
|
||||
<priority-table-item :value="scope.row.priority" ref="priority"/>
|
||||
|
@ -70,13 +77,16 @@
|
|||
:filters="typeFilters"
|
||||
column-key="type"
|
||||
:label="$t('test_track.case.type')"
|
||||
min-width="80px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<type-table-item :value="scope.row.type"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="tags" :label="$t('commons.tag')">
|
||||
<el-table-column prop="tags" :label="$t('commons.tag')" min-width="120px"
|
||||
>
|
||||
<template v-slot:default="scope">
|
||||
<div v-for="(tag, index) in scope.row.showTags" :key="tag + '_' + index">
|
||||
<ms-tag type="success" effect="plain" :content="tag"/>
|
||||
|
@ -89,6 +99,8 @@
|
|||
:filters="methodFilters"
|
||||
column-key="method"
|
||||
:label="$t('test_track.case.method')"
|
||||
min-width="100px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<method-table-item :value="scope.row.method"/>
|
||||
|
@ -98,17 +110,23 @@
|
|||
<el-table-column
|
||||
prop="nodePath"
|
||||
:label="$t('test_track.case.module')"
|
||||
min-width="120px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="projectName"
|
||||
:label="$t('test_track.plan.plan_project')"
|
||||
min-width="120px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column
|
||||
:label="$t('test_track.issue.issue')"
|
||||
min-width="80px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<el-popover
|
||||
|
@ -141,6 +159,8 @@
|
|||
<el-table-column
|
||||
prop="executorName"
|
||||
:filters="executorFilters"
|
||||
min-width="100px"
|
||||
|
||||
column-key="executor"
|
||||
:label="$t('test_track.plan_view.executor')">
|
||||
</el-table-column>
|
||||
|
@ -149,6 +169,8 @@
|
|||
prop="status"
|
||||
:filters="statusFilters"
|
||||
column-key="status"
|
||||
min-width="100px"
|
||||
|
||||
:label="$t('test_track.plan_view.execute_result')">
|
||||
<template v-slot:default="scope">
|
||||
<span @click.stop="clickt = 'stop'">
|
||||
|
@ -181,6 +203,8 @@
|
|||
sortable
|
||||
prop="updateTime"
|
||||
:label="$t('commons.update_time')"
|
||||
min-width="120px"
|
||||
|
||||
show-overflow-tooltip>
|
||||
<template v-slot:default="scope">
|
||||
<span>{{ scope.row.updateTime | timestampFormatDate }}</span>
|
||||
|
@ -572,6 +596,14 @@ export default {
|
|||
_sort(column, this.condition);
|
||||
this.initTableData();
|
||||
},
|
||||
headerDragend(newWidth,oldWidth,column,event){
|
||||
let finalWidth = newWidth;
|
||||
if(column.minWidth>finalWidth){
|
||||
finalWidth = column.minWidth;
|
||||
}
|
||||
column.width = finalWidth;
|
||||
column.realWidth = finalWidth;
|
||||
},
|
||||
batchEdit(form) {
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
|
|
|
@ -57,11 +57,9 @@
|
|||
'redirectCharType',
|
||||
'clickType'
|
||||
],
|
||||
// activated() {
|
||||
// this.search();
|
||||
// this.checkTipsType();
|
||||
// },
|
||||
// mounted() {
|
||||
mounted() {
|
||||
this.initData();
|
||||
},
|
||||
activated(){
|
||||
this.initData();
|
||||
this.openTestCaseEdit(this.$route.path);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="failure-cases-list">
|
||||
<div class="failure-cases-list-header">
|
||||
接口测试用例
|
||||
{{$t('test_track.plan.api_case')}}
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
|
@ -28,7 +28,7 @@
|
|||
|
||||
<el-table-column
|
||||
prop="createUser"
|
||||
:label="'创建人'"
|
||||
:label="$t('api_test.automation.creator')"
|
||||
show-overflow-tooltip/>
|
||||
|
||||
<el-table-column prop="lastResult" :label="$t('api_test.automation.last_result')">
|
||||
|
@ -60,9 +60,23 @@
|
|||
name: "ApiFailureCasesList",
|
||||
components: {MsTag, PriorityTableItem, TypeTableItem, MethodTableItem, StatusTableItem},
|
||||
props: ['apiTestCases'],
|
||||
watch: {
|
||||
apiTestCases() {
|
||||
this.parseTags();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goFailureTestCase(row) {
|
||||
this.$emit("openFailureTestCase", row);
|
||||
},
|
||||
parseTags() {
|
||||
if (this.apiTestCases) {
|
||||
this.apiTestCases.forEach(item => {
|
||||
if (item.tags && item.tags.length > 0) {
|
||||
item.tags = JSON.parse(item.tags);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="failure-cases-list">
|
||||
<div class="failure-cases-list-header">
|
||||
场景测试用例
|
||||
{{$t('test_track.plan.scenario_case')}}
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
|
@ -64,9 +64,21 @@
|
|||
name: "ScenarioFailureCasesList",
|
||||
components: {MsTag, PriorityTableItem, TypeTableItem, MethodTableItem, StatusTableItem},
|
||||
props: ['scenarioTestCases'],
|
||||
watch: {
|
||||
scenarioTestCases() {
|
||||
this.parseTags();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goFailureTestCase(row) {
|
||||
this.$emit("openFailureTestCase", row);
|
||||
},
|
||||
parseTags() {
|
||||
this.scenarioTestCases.forEach(item => {
|
||||
if (item.tags && item.tags.length > 0) {
|
||||
item.tags = JSON.parse(item.tags);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,6 +146,9 @@
|
|||
@refreshTable="search"/>
|
||||
|
||||
</el-card>
|
||||
|
||||
<batch-edit ref="batchEdit" @batchEdit="batchEdit"
|
||||
:type-arr="typeArr" :value-arr="valueArr" :dialog-title="$t('test_track.case.batch_edit_case')"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -214,21 +217,21 @@ export default {
|
|||
],
|
||||
showMore: false,
|
||||
buttons: [
|
||||
{
|
||||
name: this.$t('test_track.case.batch_edit_case'), handleClick: this.handleEditBatch
|
||||
},
|
||||
{
|
||||
name: this.$t('test_track.case.batch_unlink'), handleClick: this.handleDeleteBatch
|
||||
}
|
||||
],
|
||||
typeArr: [
|
||||
{id: 'status', name: this.$t('test_track.plan_view.execute_result')},
|
||||
{id: 'executor', name: this.$t('test_track.plan_view.executor')},
|
||||
{id: 'status', name: this.$t('test_track.review_view.execute_result')},
|
||||
],
|
||||
valueArr: {
|
||||
executor: [],
|
||||
status: [
|
||||
{name: this.$t('test_track.plan_view.pass'), id: 'Pass'},
|
||||
{name: this.$t('test_track.plan_view.failure'), id: 'Failure'},
|
||||
{name: this.$t('test_track.plan_view.blocking'), id: 'Blocking'},
|
||||
{name: this.$t('test_track.plan_view.skip'), id: 'Skip'}
|
||||
{name: this.$t('test_track.case.status_prepare'), id: 'Prepare'},
|
||||
{name: this.$t('test_track.case.status_pass'), id: 'Pass'},
|
||||
{name: this.$t('test_track.case.status_un_pass'), id: 'UnPass'},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
@ -339,6 +342,23 @@ export default {
|
|||
this.$success(this.$t('test_track.cancel_relevance_success'));
|
||||
});
|
||||
},
|
||||
handleEditBatch() {
|
||||
this.$refs.batchEdit.open(this.selectRows.size);
|
||||
},
|
||||
batchEdit(form) {
|
||||
let reviewId = this.reviewId;
|
||||
let param = {};
|
||||
param[form.type] = form.value;
|
||||
param.ids = Array.from(this.selectRows).map(row => row.caseId);
|
||||
param.reviewId = reviewId;
|
||||
this.$post('/test/review/case/batch/edit/status', param, () => {
|
||||
this.selectRows.clear();
|
||||
this.status = '';
|
||||
this.$post('/test/case/review/edit/status/' + reviewId);
|
||||
this.$success(this.$t('commons.save_success'));
|
||||
this.$emit('refresh');
|
||||
});
|
||||
},
|
||||
handleSelectAll(selection) {
|
||||
if (selection.length > 0) {
|
||||
this.tableData.forEach(item => {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 53bd821bee65be3374f1ccc9a299cef9ac44b985
|
||||
Subproject commit a3d469fd18f663d11e5c1c49f71ced6e3e4b292f
|
|
@ -122,8 +122,8 @@ html,body {
|
|||
|
||||
/* 滚动条样式 */
|
||||
::-webkit-scrollbar{
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
position: fixed;
|
||||
}
|
||||
::-webkit-scrollbar-thumb{
|
||||
|
|
|
@ -322,21 +322,23 @@ export function _getBodyUploadFiles(request, bodyUploadFiles, obj) {
|
|||
body = request.body;
|
||||
}
|
||||
if (body) {
|
||||
body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
if (body.kvs) {
|
||||
body.kvs.forEach(param => {
|
||||
if (param.files) {
|
||||
param.files.forEach(item => {
|
||||
if (item.file) {
|
||||
if (!item.id) {
|
||||
let fileId = getUUID().substring(0, 12);
|
||||
item.name = item.file.name;
|
||||
item.id = fileId;
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
obj.bodyUploadIds.push(item.id);
|
||||
bodyUploadFiles.push(item.file);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (body.binary) {
|
||||
body.binary.forEach(param => {
|
||||
if (param.files) {
|
||||
|
|
|
@ -187,7 +187,11 @@ export default {
|
|||
review: "all"
|
||||
},
|
||||
image: 'Image',
|
||||
tag: 'Tag'
|
||||
tag: 'Tag',
|
||||
module: {
|
||||
select_module: "Select module",
|
||||
default_module: "Default module",
|
||||
}
|
||||
},
|
||||
license: {
|
||||
title: 'Authorization management',
|
||||
|
@ -208,8 +212,8 @@ export default {
|
|||
display: {
|
||||
title: 'Theme',
|
||||
logo: 'System LOGO',
|
||||
loginLogo: 'Picture on the right side of the login page',
|
||||
loginImage: 'Login page upper left corner LOGO',
|
||||
loginLogo: 'Login page upper left corner LOGO',
|
||||
loginImage: 'Picture on the right side of the login page',
|
||||
loginTitle: 'Login page prompt information',
|
||||
pageTitle: 'Page Title',
|
||||
},
|
||||
|
@ -528,6 +532,7 @@ export default {
|
|||
api_case_status: "Ise case status",
|
||||
api_case_passing_rate: "Use case pass rate",
|
||||
create_tip: "Note: Detailed interface information can be filled out on the edit page",
|
||||
api_import: "Api Import",
|
||||
select_comp: {
|
||||
no_data: "No Data",
|
||||
add_data: "Add Data"
|
||||
|
@ -586,6 +591,7 @@ export default {
|
|||
create_info: 'Create',
|
||||
update_info: 'Update',
|
||||
batch_edit: "Batch edit",
|
||||
batch_move:"Batch move",
|
||||
path_valid_info: "The request path is invalid",
|
||||
other_config: "Other Config",
|
||||
message_template: "Message Template",
|
||||
|
@ -1131,6 +1137,8 @@ export default {
|
|||
plan_delete_confirm: "All use cases under this plan will be deleted,confirm delete test plan: ",
|
||||
plan_delete_tip: "The test plan is under way, please confirm and delete it!",
|
||||
plan_delete: "Delete test plan",
|
||||
api_case: "Api case",
|
||||
scenario_case: "Scenario case",
|
||||
load_case: {
|
||||
case: "Load Case",
|
||||
execution_status: "Execution status",
|
||||
|
|
|
@ -188,7 +188,11 @@ export default {
|
|||
review: "全部评审"
|
||||
},
|
||||
image: '镜像',
|
||||
tag: '标签'
|
||||
tag: '标签',
|
||||
module: {
|
||||
select_module: "选择模块",
|
||||
default_module: "默认模块",
|
||||
}
|
||||
},
|
||||
license: {
|
||||
title: '授权管理',
|
||||
|
@ -209,8 +213,8 @@ export default {
|
|||
display: {
|
||||
title: '显示设置',
|
||||
logo: '系统 LOGO',
|
||||
loginLogo: '登陆页面右侧图片',
|
||||
loginImage: '登录页左上角 LOGO',
|
||||
loginLogo: '登录页左上角 LOGO',
|
||||
loginImage: '登陆页面右侧图片',
|
||||
loginTitle: '登陆页面提示信息',
|
||||
pageTitle: '页面 Title',
|
||||
},
|
||||
|
@ -528,6 +532,7 @@ export default {
|
|||
api_case_status: "用例状态",
|
||||
api_case_passing_rate: "用例通过率",
|
||||
create_tip: "注: 详细的接口信息可以在编辑页面填写",
|
||||
api_import: "接口导入",
|
||||
select_comp: {
|
||||
no_data: "无数据",
|
||||
add_data: "去添加"
|
||||
|
@ -587,6 +592,7 @@ export default {
|
|||
create_info: '创建',
|
||||
update_info: '更新',
|
||||
batch_edit: "批量编辑",
|
||||
batch_move:"批量移动",
|
||||
path_valid_info: "请求路径无效",
|
||||
other_config: "其他设置",
|
||||
message_template: "报文模版",
|
||||
|
@ -1135,6 +1141,8 @@ export default {
|
|||
plan_delete_confirm: "将删除该测试计划下所有用例,确认删除测试计划: ",
|
||||
plan_delete_tip: "该测试计划正在进行中,请确认再删除!",
|
||||
plan_delete: "删除计划",
|
||||
api_case: "接口测试用例",
|
||||
scenario_case: "场景测试用例",
|
||||
load_case: {
|
||||
case: "性能用例",
|
||||
execution_status: "执行状态",
|
||||
|
|
|
@ -188,7 +188,11 @@ export default {
|
|||
review: "全部評審"
|
||||
},
|
||||
image: '鏡像',
|
||||
tag: '標簽'
|
||||
tag: '標簽',
|
||||
module: {
|
||||
select_module: "選擇模塊",
|
||||
default_module: "默認模塊",
|
||||
}
|
||||
},
|
||||
license: {
|
||||
title: '授權管理',
|
||||
|
@ -209,8 +213,8 @@ export default {
|
|||
display: {
|
||||
title: '顯示設置',
|
||||
logo: '系統 LOGO',
|
||||
loginLogo: '登陸頁面右側圖片',
|
||||
loginImage: '登錄頁左上角 LOGO',
|
||||
loginLogo: '登錄頁左上角 LOGO',
|
||||
loginImage: '登陸頁面右側圖片',
|
||||
loginTitle: '登陸頁面提示信息',
|
||||
pageTitle: '頁面 Title',
|
||||
},
|
||||
|
@ -527,6 +531,7 @@ export default {
|
|||
api_case_status: "用例狀態",
|
||||
api_case_passing_rate: "用例通過率",
|
||||
create_tip: "註: 詳細的接口信息可以在編輯頁面填寫",
|
||||
api_import: "接口導入",
|
||||
select_comp: {
|
||||
no_data: "無數據",
|
||||
add_data: "去添加"
|
||||
|
@ -586,6 +591,7 @@ export default {
|
|||
create_info: '創建',
|
||||
update_info: '更新',
|
||||
batch_edit: "批量編輯",
|
||||
batch_move:"批量移動",
|
||||
path_valid_info: "請求路徑無效",
|
||||
other_config: "其他設置",
|
||||
message_template: "報文模版",
|
||||
|
@ -1133,6 +1139,8 @@ export default {
|
|||
plan_delete_confirm: "將刪除該測試計劃下所有用例,確認刪除測試計劃: ",
|
||||
plan_delete_tip: "該測試計劃正在進行中,請確認再刪除!",
|
||||
plan_delete: "刪除計劃",
|
||||
api_case: "接口測試用例",
|
||||
scenario_case: "場景測試用例",
|
||||
load_case: {
|
||||
case: "性能用例",
|
||||
execution_status: "執行狀態",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<img :src="'/display/file/loginLogo'" alt="">
|
||||
</div>
|
||||
<div class="welcome">
|
||||
<span>{{ $t('commons.welcome') }}</span>
|
||||
<span>{{ loginTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
|||
<div class="divider"/>
|
||||
|
||||
<el-col :span="12">
|
||||
<img class="login-image" :src="'/display/file/loginImage'">
|
||||
<img class="login-image" :src="'/display/file/loginImage'" alt="">
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
@ -85,7 +85,7 @@ export default {
|
|||
msg: '',
|
||||
ready: false,
|
||||
openLdap: false,
|
||||
loginTitle: this.$t("commons.login") + " MeterSphere",
|
||||
loginTitle: this.$t("commons.welcome"),
|
||||
authSources: [],
|
||||
loginUrl: 'signin',
|
||||
}
|
||||
|
@ -200,6 +200,7 @@ export default {
|
|||
|
||||
.title img {
|
||||
width: 293px;
|
||||
max-height: 60px;
|
||||
margin-top: 165px;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue