diff --git a/README.md b/README.md index d5de7e9ea9..e9cb840705 100755 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ curl -sSL https://github.com/metersphere/metersphere/releases/latest/download/qu 文档和演示视频: - [完整文档](https://metersphere.io/docs/) -- [演示视频](http://video.fit2cloud.com/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91202006%20MeterSphere%20v1.0%20%E5%8A%9F%E8%83%BD%E6%BC%94%E7%A4%BA.mp4) +- [演示视频](https://www.bilibili.com/video/BV1yp4y1p72C/) ## MeterSphere 企业版 diff --git a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java index c23f768f05..81404a7cce 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java @@ -2,9 +2,13 @@ package io.metersphere.api.controller; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; +import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.JmxInfoDTO; import io.metersphere.api.dto.automation.*; +import io.metersphere.api.dto.definition.ApiBatchRequest; +import io.metersphere.api.dto.definition.ApiExportResult; import io.metersphere.api.dto.definition.RunDefinitionRequest; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.api.service.ApiAutomationService; import io.metersphere.base.domain.ApiScenario; import io.metersphere.base.domain.ApiScenarioWithBLOBs; @@ -103,7 +107,7 @@ public class ApiAutomationController { @PostMapping("/batch/edit") @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) - public void bathEdit(@RequestBody SaveApiScenarioRequest request) { + public void bathEdit(@RequestBody ApiScenarioBatchRequest request) { apiAutomationService.bathEdit(request); } @@ -146,5 +150,18 @@ public class ApiAutomationController { .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileOperationRequest.getName() + "\"") .body(bytes); } + + @PostMapping(value = "/import", consumes = {"multipart/form-data"}) + @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) + public ApiDefinitionImport testCaseImport(@RequestPart(value = "file", required = false) MultipartFile file, @RequestPart("request") ApiTestImportRequest request) { + return apiAutomationService.scenarioImport(file, request); + } + + @PostMapping(value = "/export") + @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) + public ApiScenrioExportResult export(@RequestBody ApiScenarioBatchRequest request) { + return apiAutomationService.export(request); + } + } diff --git a/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java b/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java index 932c0ac674..e76fa7403e 100644 --- a/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java @@ -13,8 +13,6 @@ public class ApiTestImportRequest { private String projectId; private String platform; private Boolean useEnvironment; - // 来自场景的导入不需要存储 - private boolean saved = true; private String swaggerUrl; //导入策略 private String modeId; diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioBatchRequest.java b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioBatchRequest.java new file mode 100644 index 0000000000..61466418c8 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioBatchRequest.java @@ -0,0 +1,18 @@ +package io.metersphere.api.dto.automation; + + +import io.metersphere.base.domain.ApiScenarioWithBLOBs; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class ApiScenarioBatchRequest extends ApiScenarioWithBLOBs { + private List ids; + private String projectId; + private String environmentId; + + private ApiScenarioRequest condition; +} diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioRequest.java b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioRequest.java index 12b85d5a13..8034b6a573 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioRequest.java @@ -1,5 +1,6 @@ package io.metersphere.api.dto.automation; +import io.metersphere.controller.request.BaseQueryRequest; import io.metersphere.controller.request.OrderRequest; import lombok.Getter; import lombok.Setter; @@ -9,21 +10,14 @@ import java.util.Map; @Getter @Setter -public class ApiScenarioRequest { +public class ApiScenarioRequest extends BaseQueryRequest { private String id; private String excludeId; - private String projectId; private String moduleId; - private List moduleIds; private String name; - private String workspaceId; private String userId; private String planId; private boolean recent = false; - private List orders; - private Map> filters; - private Map combine; - private List ids; private boolean isSelectThisWeedData; private long createTime = 0; private String executeStatus; diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenrioExportResult.java b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenrioExportResult.java new file mode 100644 index 0000000000..8d9612d493 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenrioExportResult.java @@ -0,0 +1,15 @@ +package io.metersphere.api.dto.automation; + +import io.metersphere.base.domain.ApiScenarioWithBLOBs; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class ApiScenrioExportResult { + private String projectId; + private String version; + private List data; +} diff --git a/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java b/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java index 217787ffe0..4b1769eea2 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/RunScenarioRequest.java @@ -1,5 +1,6 @@ package io.metersphere.api.dto.automation; +import io.metersphere.base.domain.ApiScenarioWithBLOBs; import lombok.Getter; import lombok.Setter; @@ -8,14 +9,10 @@ import java.util.Map; @Setter @Getter -public class RunScenarioRequest { - - private String id; +public class RunScenarioRequest extends ApiScenarioWithBLOBs { private String reportId; - private String projectId; - private String environmentId; private String triggerMode; @@ -29,28 +26,12 @@ public class RunScenarioRequest { private List planCaseIds; - private String reportUserID; + private List ids; - private List scenarioIds; + private String reportUserID; private Map scenarioTestPlanIdMap; - /** - * isSelectAllDate:选择的数据是否是全部数据(全部数据是不受分页影响的数据) - * filters: 数据状态 - * name:如果是全部数据,那么表格如果历经查询,查询参数是什么 - * moduleIds: 哪些模块的数据 - * unSelectIds:是否在页面上有未勾选的数据,有的话他们的ID是哪些。 - * filters/name/moduleIds/unSeelctIds 只在isSelectAllDate为true时需要。为了让程序能明确批量的范围。 - */ - private boolean isSelectAllDate; - - private Map> filters; - - private String name; - - private List moduleIds; - - private List unSelectIds; + private ApiScenarioRequest condition; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java index 7a35339222..a92d0d1bf8 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java @@ -1,6 +1,8 @@ package io.metersphere.api.dto.definition.parse; +import io.metersphere.api.dto.definition.request.MsScenario; import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiScenarioWithBLOBs; import io.metersphere.base.domain.ApiTestCaseWithBLOBs; import lombok.Data; @@ -12,6 +14,10 @@ public class ApiDefinitionImport { private String protocol; private List data; + //导入场景 + private MsScenario scenarioDefinition; + private List scenarioDefinitionData; + // 新版本带用例导出 private List cases; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java index 3686898bde..6f56557fa4 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/MsScenario.java @@ -20,6 +20,8 @@ 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.protocol.http.control.Header; +import org.apache.jmeter.protocol.http.control.HeaderManager; import org.apache.jmeter.save.SaveService; import org.apache.jmeter.testelement.TestElement; import org.apache.jorphan.collections.HashTree; @@ -100,6 +102,9 @@ public class MsScenario extends MsTestElement { el.toHashTree(tree, el.getHashTree(), config); } } + if (CollectionUtils.isNotEmpty(this.headers)) { + setHeader(tree, this.headers); + } } public void setOldVariables(List oldVariables) { @@ -109,6 +114,20 @@ public class MsScenario extends MsTestElement { } } + public void setHeader(HashTree tree, List headers) { + if (CollectionUtils.isNotEmpty(headers)) { + HeaderManager headerManager = new HeaderManager(); + headerManager.setEnabled(true); + headerManager.setName(this.getName() + "场景Headers"); + headerManager.setProperty(TestElement.TEST_CLASS, HeaderManager.class.getName()); + headerManager.setProperty(TestElement.GUI_CLASS, SaveService.aliasToClass("HeaderPanel")); + headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> + headerManager.add(new Header(keyValue.getName(), keyValue.getValue())) + ); + tree.add(headerManager); + } + } + private Arguments arguments(ParameterConfig config) { Arguments arguments = new Arguments(); arguments.setEnabled(true); @@ -134,11 +153,6 @@ public class MsScenario extends MsTestElement { arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") ); } - if (CollectionUtils.isNotEmpty(this.headers)) { - this.headers.stream().filter(KeyValue::isValid).filter(KeyValue::isEnable).forEach(keyValue -> - arguments.addArgument(keyValue.getName(), keyValue.getValue(), "=") - ); - } return arguments; } diff --git a/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsLoopController.java b/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsLoopController.java index b22949ed2a..350db02e11 100644 --- a/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsLoopController.java +++ b/backend/src/main/java/io/metersphere/api/dto/definition/request/controller/MsLoopController.java @@ -102,7 +102,7 @@ public class MsLoopController extends MsTestElement { return counterConfig; } - private LoopController loopController() { + private LoopController initLoopController() { LoopController loopController = new LoopController(); loopController.setEnabled(true); loopController.setName("LoopController"); @@ -113,7 +113,7 @@ public class MsLoopController extends MsTestElement { return loopController; } - public String getCondition() { + private String getCondition() { String variable = "\"" + this.whileController.getVariable() + "\""; String operator = this.whileController.getOperator(); String value = "\"" + this.whileController.getValue() + "\""; @@ -136,7 +136,7 @@ public class MsLoopController extends MsTestElement { return "${__jexl3(" + variable + operator + value + ")}"; } - private WhileController whileController() { + private WhileController initWhileController() { String condition = getCondition(); if (StringUtils.isEmpty(condition)) { return null; @@ -150,7 +150,7 @@ public class MsLoopController extends MsTestElement { return controller; } - private ForeachController foreachController() { + private ForeachController initForeachController() { ForeachController controller = new ForeachController(); controller.setEnabled(true); controller.setName("ForeachController"); @@ -175,13 +175,13 @@ public class MsLoopController extends MsTestElement { runTime.setRuntime(timeout); // 添加超时处理,防止死循环 HashTree hashTree = tree.add(runTime); - return hashTree.add(whileController()); + return hashTree.add(initWhileController()); } if (StringUtils.equals(this.loopType, LoopConstants.FOREACH.name()) && this.forEachController != null) { - return tree.add(foreachController()); + return tree.add(initForeachController()); } if (StringUtils.equals(this.loopType, LoopConstants.LOOP_COUNT.name()) && this.countController != null) { - return tree.add(loopController()); + return tree.add(initLoopController()); } return null; } diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java index 12f7519ef9..e5d2729d8b 100644 --- a/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/ApiImportAbstractParser.java @@ -75,7 +75,7 @@ public abstract class ApiImportAbstractParser implements ApiImportParser { return null; } - protected ApiModule buildModule(ApiModule parentModule, String name, boolean isSaved) { + protected ApiModule buildModule(ApiModule parentModule, String name) { apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class); ApiModule module; if (parentModule != null) { @@ -84,9 +84,7 @@ public abstract class ApiImportAbstractParser implements ApiImportParser { } else { module = apiModuleService.getNewModule(name, this.projectId, 1); } - if (isSaved) { - createModule(module); - } + createModule(module); return module; } diff --git a/backend/src/main/java/io/metersphere/api/parse/ApiScenarioImportParserFactory.java b/backend/src/main/java/io/metersphere/api/parse/ApiScenarioImportParserFactory.java new file mode 100644 index 0000000000..8c9b5fc51b --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/ApiScenarioImportParserFactory.java @@ -0,0 +1,15 @@ +package io.metersphere.api.parse; + +import io.metersphere.commons.constants.ApiImportPlatform; +import org.apache.commons.lang3.StringUtils; + +public class ApiScenarioImportParserFactory { + public static ApiImportParser getApiImportParser(String platform) { + if (StringUtils.equals(ApiImportPlatform.Metersphere.name(), platform)) { + return new MsParser(); + } else if (StringUtils.equals(ApiImportPlatform.Postman.name(), platform)) { + return new ScenarioPostmanParser(); + } + return null; + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/MsParser.java b/backend/src/main/java/io/metersphere/api/parse/MsParser.java index 82f691a6c8..e8b69e112c 100644 --- a/backend/src/main/java/io/metersphere/api/parse/MsParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/MsParser.java @@ -39,7 +39,7 @@ public class MsParser extends ApiImportAbstractParser { return parseMsFormat(testStr, request); } else { request.setPlatform(ApiImportPlatform.Plugin.name()); - return parsePluginFormat(testObject, request); + return parsePluginFormat(testObject, request, true); } } @@ -65,17 +65,20 @@ public class MsParser extends ApiImportAbstractParser { apiDefinition.setRequest(JSONObject.toJSONString(requestObj)); } - private ApiDefinitionImport parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest) { + protected ApiDefinitionImport parsePluginFormat(JSONObject testObject, ApiTestImportRequest importRequest, Boolean isCreateModule) { List results = new ArrayList<>(); ApiDefinitionImport apiImport = new ApiDefinitionImport(); apiImport.setProtocol(RequestType.HTTP); apiImport.setData(results); testObject.keySet().forEach(tag -> { - ApiModule parentModule = getSelectModule(importRequest.getModuleId()); - ApiModule module = buildModule(parentModule, tag, importRequest.isSaved()); - + ApiModule module = null; + if (isCreateModule) { + module = buildModule(getSelectModule(importRequest.getModuleId()), tag); + } JSONObject requests = testObject.getJSONObject(tag); + String moduleId = module.getId(); + requests.keySet().forEach(requestName -> { JSONObject requestObject = requests.getJSONObject(requestName); @@ -84,7 +87,7 @@ public class MsParser extends ApiImportAbstractParser { MsHTTPSamplerProxy request = buildRequest(requestName, path, method); ApiDefinitionWithBLOBs apiDefinition = buildApiDefinition(request.getId(), requestName, path, method,importRequest); - apiDefinition.setModuleId(module.getId()); + apiDefinition.setModuleId(moduleId); apiDefinition.setProjectId(this.projectId); parseBody(requestObject, request.getBody()); parseHeader(requestObject, request.getHeaders()); @@ -181,7 +184,7 @@ public class MsParser extends ApiImportAbstractParser { Iterator iterator = modules.iterator(); while (iterator.hasNext()) { String item = iterator.next(); - parent = buildModule(parent, item, importRequest.isSaved()); + parent = buildModule(parent, item); if (!iterator.hasNext()) { apiDefinition.setModuleId(parent.getId()); } diff --git a/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java b/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java index 0b7d3d5862..393b07a3e3 100644 --- a/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/PostmanParser.java @@ -33,17 +33,20 @@ public class PostmanParser extends ApiImportAbstractParser { List variables = postmanCollection.getVariable(); ApiDefinitionImport apiImport = new ApiDefinitionImport(); List results = new ArrayList<>(); - parseItem(postmanCollection.getItem(), variables, results, buildModule(getSelectModule(request.getModuleId()), postmanCollection.getInfo().getName(), request.isSaved()), request.isSaved()); + parseItem(postmanCollection.getItem(), variables, results, buildModule(getSelectModule(request.getModuleId()), postmanCollection.getInfo().getName()), true); apiImport.setData(results); return apiImport; } - private void parseItem(List items, List variables, List results, ApiModule parentModule, boolean isSaved) { + protected void parseItem(List items, List variables, List results, ApiModule parentModule, Boolean isCreateModule) { for (PostmanItem item : items) { List childItems = item.getItem(); if (childItems != null) { - ApiModule module = buildModule(parentModule, item.getName() , isSaved); - parseItem(childItems, variables, results, module, isSaved); + ApiModule module = null; + if (isCreateModule) { + module = buildModule(parentModule, item.getName()); + } + parseItem(childItems, variables, results, module, isCreateModule); } else { ApiDefinitionWithBLOBs request = parsePostman(item); if (request != null) { diff --git a/backend/src/main/java/io/metersphere/api/parse/ScenarioMsParser.java b/backend/src/main/java/io/metersphere/api/parse/ScenarioMsParser.java new file mode 100644 index 0000000000..29a6f4c244 --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/ScenarioMsParser.java @@ -0,0 +1,71 @@ +package io.metersphere.api.parse; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.parser.Feature; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.automation.ApiScenrioExportResult; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; +import io.metersphere.api.dto.definition.request.MsScenario; +import io.metersphere.api.dto.definition.request.MsTestElement; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.service.ApiModuleService; +import io.metersphere.base.domain.ApiScenarioWithBLOBs; +import io.metersphere.commons.constants.ApiImportPlatform; +import io.metersphere.commons.utils.CommonBeanFactory; +import org.apache.commons.lang3.StringUtils; + +import java.io.InputStream; +import java.util.LinkedList; +import java.util.UUID; + +public class ScenarioMsParser extends MsParser { + + @Override + public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { + String testStr = getApiTestStr(source); + JSONObject testObject = JSONObject.parseObject(testStr, Feature.OrderedField); + apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class); + this.projectId = request.getProjectId(); + if (testObject.get("projectId") != null) { + return parseMsFormat(testStr, request); + } else { + request.setPlatform(ApiImportPlatform.Plugin.name()); + ApiDefinitionImport apiDefinitionImport = parsePluginFormat(testObject, request, false); + MsScenario msScenario = new MsScenario(); + LinkedList msHTTPSamplerProxies = new LinkedList<>(); + apiDefinitionImport.getData().forEach(res -> { + msHTTPSamplerProxies.add(JSONObject.parseObject(res.getRequest(), MsHTTPSamplerProxy.class)); + }); + msScenario.setHashTree(msHTTPSamplerProxies); + msScenario.setType("scenario"); + msScenario.setName("test"); + apiDefinitionImport.setScenarioDefinition(msScenario); + return apiDefinitionImport; + } + } + + private ApiDefinitionImport parseMsFormat(String testStr, ApiTestImportRequest importRequest) { + ApiScenrioExportResult apiScenrioExportResult = JSON.parseObject(testStr, ApiScenrioExportResult.class); + apiScenrioExportResult.getData().forEach(scenario -> { + parseApiDefinition(scenario, importRequest); + }); + ApiDefinitionImport apiDefinitionImport = new ApiDefinitionImport(); + apiDefinitionImport.setScenarioDefinitionData(apiScenrioExportResult.getData()); + return apiDefinitionImport; + } + + private void parseApiDefinition(ApiScenarioWithBLOBs scenario, ApiTestImportRequest importRequest) { + String id = UUID.randomUUID().toString(); + if (StringUtils.isBlank(scenario.getModulePath())) { + scenario.setApiScenarioModuleId(null); + } +// parseModule(scenario, importRequest); + scenario.setId(id); + scenario.setProjectId(this.projectId); + String scenarioDefinition = scenario.getScenarioDefinition(); + JSONObject scenarioDefinitionObj = JSONObject.parseObject(scenarioDefinition); + scenarioDefinitionObj.put("id", id); + scenario.setScenarioDefinition(JSONObject.toJSONString(scenarioDefinitionObj)); + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/ScenarioPostmanParser.java b/backend/src/main/java/io/metersphere/api/parse/ScenarioPostmanParser.java new file mode 100644 index 0000000000..cc45f434ee --- /dev/null +++ b/backend/src/main/java/io/metersphere/api/parse/ScenarioPostmanParser.java @@ -0,0 +1,40 @@ +package io.metersphere.api.parse; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import io.metersphere.api.dto.ApiTestImportRequest; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; +import io.metersphere.api.dto.definition.request.MsScenario; +import io.metersphere.api.dto.definition.request.MsTestElement; +import io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy; +import io.metersphere.api.dto.parse.postman.PostmanCollection; +import io.metersphere.base.domain.ApiDefinitionWithBLOBs; +import io.metersphere.base.domain.ApiModule; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class ScenarioPostmanParser extends PostmanParser { + + @Override + public ApiDefinitionImport parse(InputStream source, ApiTestImportRequest request) { + this.projectId = request.getProjectId(); + ApiDefinitionImport apiImport = new ApiDefinitionImport(); + List results = new ArrayList<>(); + PostmanCollection postmanCollection = JSON.parseObject(getApiTestStr(source), PostmanCollection.class); + parseItem(postmanCollection.getItem(), postmanCollection.getVariable(), results, null, false); + + MsScenario msScenario = new MsScenario(); + LinkedList msHTTPSamplerProxies = new LinkedList<>(); + results.forEach(res -> { + msHTTPSamplerProxies.add(JSONObject.parseObject(res.getRequest(), MsHTTPSamplerProxy.class)); + }); + msScenario.setHashTree(msHTTPSamplerProxies); + msScenario.setType("scenario"); + msScenario.setName(postmanCollection.getInfo().getName()); + apiImport.setScenarioDefinition(msScenario); + return apiImport; + } +} diff --git a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java index d2d2823dd2..00765494e9 100644 --- a/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java +++ b/backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java @@ -71,7 +71,7 @@ public class Swagger2Parser extends SwaggerAbstractParser { addBodyHeader(request); apiDefinition.setRequest(JSON.toJSONString(request)); apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation, operation.getResponses()))); - buildModule(parentNode, apiDefinition, operation.getTags(), importRequest.isSaved()); + buildModule(parentNode, apiDefinition, operation.getTags()); results.add(apiDefinition); } } diff --git a/backend/src/main/java/io/metersphere/api/parse/Swagger3Parser.java b/backend/src/main/java/io/metersphere/api/parse/Swagger3Parser.java index b189c89534..80b1b75684 100644 --- a/backend/src/main/java/io/metersphere/api/parse/Swagger3Parser.java +++ b/backend/src/main/java/io/metersphere/api/parse/Swagger3Parser.java @@ -103,7 +103,7 @@ public class Swagger3Parser extends SwaggerAbstractParser { addBodyHeader(request); apiDefinition.setRequest(JSON.toJSONString(request)); apiDefinition.setResponse(JSON.toJSONString(parseResponse(operation.getResponses()))); - buildModule(parentNode, apiDefinition, operation.getTags(), importRequest.isSaved()); + buildModule(parentNode, apiDefinition, operation.getTags()); results.add(apiDefinition); } } diff --git a/backend/src/main/java/io/metersphere/api/parse/SwaggerAbstractParser.java b/backend/src/main/java/io/metersphere/api/parse/SwaggerAbstractParser.java index 2a6fdf9f7a..187550d4eb 100644 --- a/backend/src/main/java/io/metersphere/api/parse/SwaggerAbstractParser.java +++ b/backend/src/main/java/io/metersphere/api/parse/SwaggerAbstractParser.java @@ -7,10 +7,10 @@ import java.util.List; public abstract class SwaggerAbstractParser extends ApiImportAbstractParser { - protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List tags, boolean isSaved) { + protected void buildModule(ApiModule parentModule, ApiDefinitionWithBLOBs apiDefinition, List tags) { if (tags != null) { tags.forEach(tag -> { - ApiModule module = buildModule(parentModule, tag, isSaved); + ApiModule module = buildModule(parentModule, tag); apiDefinition.setModuleId(module.getId()); }); } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java index 3de0a658c2..a82f7baa79 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -5,15 +5,19 @@ import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; +import io.metersphere.api.dto.ApiTestImportRequest; import io.metersphere.api.dto.DeleteAPIReportRequest; import io.metersphere.api.dto.JmxInfoDTO; import io.metersphere.api.dto.automation.*; import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.api.dto.definition.RunDefinitionRequest; +import io.metersphere.api.dto.definition.parse.ApiDefinitionImport; import io.metersphere.api.dto.definition.request.*; import io.metersphere.api.dto.definition.request.variable.ScenarioVariable; import io.metersphere.api.dto.scenario.environment.EnvironmentConfig; import io.metersphere.api.jmeter.JMeterService; +import io.metersphere.api.parse.ApiImportParser; +import io.metersphere.api.parse.ApiScenarioImportParserFactory; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ApiScenarioMapper; import io.metersphere.base.mapper.ApiScenarioReportMapper; @@ -143,32 +147,11 @@ public class ApiAutomationService { request.setId(UUID.randomUUID().toString()); checkNameExist(request); - final ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs(); - scenario.setId(request.getId()); - scenario.setName(request.getName()); - scenario.setProjectId(request.getProjectId()); - scenario.setTags(request.getTags()); - scenario.setApiScenarioModuleId(request.getApiScenarioModuleId()); - scenario.setModulePath(request.getModulePath()); - scenario.setLevel(request.getLevel()); - scenario.setFollowPeople(request.getFollowPeople()); - scenario.setPrincipal(request.getPrincipal()); - scenario.setStepTotal(request.getStepTotal()); - scenario.setScenarioDefinition(JSON.toJSONString(request.getScenarioDefinition())); + final ApiScenarioWithBLOBs scenario = buildSaveScenario(request); + scenario.setCreateTime(System.currentTimeMillis()); - scenario.setUpdateTime(System.currentTimeMillis()); scenario.setNum(getNextNum(request.getProjectId())); - if (StringUtils.isNotEmpty(request.getStatus())) { - scenario.setStatus(request.getStatus()); - } else { - scenario.setStatus(ScenarioStatus.Underway.name()); - } - if (request.getUserId() == null) { - scenario.setUserId(SessionUtils.getUserId()); - } else { - scenario.setUserId(request.getUserId()); - } - scenario.setDescription(request.getDescription()); + apiScenarioMapper.insert(scenario); List bodyUploadIds = request.getBodyUploadIds(); @@ -190,7 +173,12 @@ public class ApiAutomationService { List bodyUploadIds = request.getBodyUploadIds(); FileUtils.createBodyFiles(bodyUploadIds, bodyFiles); - final ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs(); + final ApiScenarioWithBLOBs scenario = buildSaveScenario(request); + apiScenarioMapper.updateByPrimaryKeySelective(scenario); + } + + public ApiScenarioWithBLOBs buildSaveScenario(SaveApiScenarioRequest request) { + ApiScenarioWithBLOBs scenario = new ApiScenarioWithBLOBs(); scenario.setId(request.getId()); scenario.setName(request.getName()); scenario.setProjectId(request.getProjectId()); @@ -201,16 +189,19 @@ public class ApiAutomationService { scenario.setFollowPeople(request.getFollowPeople()); scenario.setPrincipal(request.getPrincipal()); scenario.setStepTotal(request.getStepTotal()); - scenario.setScenarioDefinition(JSON.toJSONString(request.getScenarioDefinition())); scenario.setUpdateTime(System.currentTimeMillis()); + scenario.setScenarioDefinition(JSON.toJSONString(request.getScenarioDefinition())); if (StringUtils.isNotEmpty(request.getStatus())) { scenario.setStatus(request.getStatus()); } else { scenario.setStatus(ScenarioStatus.Underway.name()); } - scenario.setUserId(request.getUserId()); - scenario.setDescription(request.getDescription()); - apiScenarioMapper.updateByPrimaryKeySelective(scenario); + if (request.getUserId() == null) { + scenario.setUserId(SessionUtils.getUserId()); + } else { + scenario.setUserId(request.getUserId()); + } + return scenario; } public void delete(String id) { @@ -452,11 +443,11 @@ public class ApiAutomationService { * @return */ public String run(RunScenarioRequest request) { - List ids = request.getScenarioIds(); - if (request.isSelectAllDate()) { - ids = this.getAllScenarioIdsByFontedSelect( - request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds()); - } + + ServiceUtils.getSelectAllIds(request, request.getCondition(), + (query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query)); + + List ids = request.getIds(); //检查是否有正在执行中的情景 this.checkScenarioIsRunnng(ids); List apiScenarios = extApiScenarioMapper.selectIds(ids); @@ -665,11 +656,7 @@ public class ApiAutomationService { public JmxInfoDTO genPerformanceTestJmx(RunScenarioRequest request) throws Exception { List apiScenarios = null; - List ids = request.getScenarioIds(); - if (request.isSelectAllDate()) { - ids = this.getAllScenarioIdsByFontedSelect( - request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds()); - } + List ids = request.getIds(); apiScenarios = extApiScenarioMapper.selectIds(ids); String testName = ""; if (!apiScenarios.isEmpty()) { @@ -697,20 +684,17 @@ public class ApiAutomationService { return dto; } - public void bathEdit(SaveApiScenarioRequest request) { - if (CollectionUtils.isEmpty(request.getScenarioIds())) { - return; - } - if (request.isSelectAllDate()) { - request.setScenarioIds(this.getAllScenarioIdsByFontedSelect( - request.getModuleIds(), request.getName(), request.getProjectId(), request.getFilters(), request.getUnSelectIds())); - } + public void bathEdit(ApiScenarioBatchRequest request) { + + ServiceUtils.getSelectAllIds(request, request.getCondition(), + (query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query)); + if (StringUtils.isNotBlank(request.getEnvironmentId())) { bathEditEnv(request); return; } ApiScenarioExample apiScenarioExample = new ApiScenarioExample(); - apiScenarioExample.createCriteria().andIdIn(request.getScenarioIds()); + apiScenarioExample.createCriteria().andIdIn(request.getIds()); ApiScenarioWithBLOBs apiScenarioWithBLOBs = new ApiScenarioWithBLOBs(); BeanUtils.copyBean(apiScenarioWithBLOBs, request); apiScenarioWithBLOBs.setUpdateTime(System.currentTimeMillis()); @@ -719,9 +703,9 @@ public class ApiAutomationService { apiScenarioExample); } - public void bathEditEnv(SaveApiScenarioRequest request) { + public void bathEditEnv(ApiScenarioBatchRequest request) { if (StringUtils.isNotBlank(request.getEnvironmentId())) { - List apiScenarios = selectByIdsWithBLOBs(request.getScenarioIds()); + List apiScenarios = selectByIdsWithBLOBs(request.getIds()); apiScenarios.forEach(item -> { JSONObject object = JSONObject.parseObject(item.getScenarioDefinition()); object.put("environmentId", request.getEnvironmentId()); @@ -732,4 +716,40 @@ public class ApiAutomationService { }); } } + + public ApiDefinitionImport scenarioImport(MultipartFile file, ApiTestImportRequest request) { + ApiImportParser apiImportParser = ApiScenarioImportParserFactory.getApiImportParser(request.getPlatform()); + ApiDefinitionImport apiImport = null; + try { + apiImport = apiImportParser.parse(file == null ? null : file.getInputStream(), request); + } catch (Exception e) { + LogUtil.error(e.getMessage(), e); + MSException.throwException(Translator.get("parse_data_error")); + } + SaveApiScenarioRequest saveReq = new SaveApiScenarioRequest(); + saveReq.setScenarioDefinition(apiImport.getScenarioDefinition()); + saveReq.setName(saveReq.getScenarioDefinition().getName()); + saveReq.setProjectId(request.getProjectId()); + saveReq.setApiScenarioModuleId(request.getModuleId()); + if (StringUtils.isNotBlank(request.getUserId())) { + saveReq.setPrincipal(request.getUserId()); + } else { + saveReq.setPrincipal(SessionUtils.getUserId()); + } + create(saveReq, new ArrayList<>()); + return apiImport; + } + + public ApiScenrioExportResult export(ApiScenarioBatchRequest request) { + ServiceUtils.getSelectAllIds(request, request.getCondition(), + (query) -> extApiScenarioMapper.selectIdsByQuery((ApiScenarioRequest) query)); + ApiScenarioExample example = new ApiScenarioExample(); + example.createCriteria().andIdIn(request.getIds()); + List apiScenarioWithBLOBs = apiScenarioMapper.selectByExampleWithBLOBs(example); + ApiScenrioExportResult result = new ApiScenrioExportResult(); + result.setData(apiScenarioWithBLOBs); + result.setProjectId(request.getProjectId()); + result.setVersion(System.getenv("MS_VERSION")); + return result; + } } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java index d6d46b2ffa..6e1577576e 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java @@ -44,7 +44,7 @@ import org.springframework.web.multipart.MultipartFile; import sun.security.util.Cache; import javax.annotation.Resource; -import java.io.*; +import java.io.File; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -498,9 +498,7 @@ public class ApiDefinitionService { LogUtil.error(e.getMessage(), e); MSException.throwException(Translator.get("parse_data_error")); } - if (request.isSaved()) { - importApi(request, apiImport); - } + importApi(request, apiImport); return apiImport; } diff --git a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java index 6445f7d13a..ae8d9cb847 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiScenarioModuleService.java @@ -46,10 +46,6 @@ public class ApiScenarioModuleService extends NodeTreeService oredCriteria; + + public UserHeaderExample() { + oredCriteria = new ArrayList(); + } + + public void setOrderByClause(String orderByClause) { + this.orderByClause = orderByClause; + } + + public String getOrderByClause() { + return orderByClause; + } + + public void setDistinct(boolean distinct) { + this.distinct = distinct; + } + + public boolean isDistinct() { + return distinct; + } + + public List getOredCriteria() { + return oredCriteria; + } + + public void or(Criteria criteria) { + oredCriteria.add(criteria); + } + + public Criteria or() { + Criteria criteria = createCriteriaInternal(); + oredCriteria.add(criteria); + return criteria; + } + + public Criteria createCriteria() { + Criteria criteria = createCriteriaInternal(); + if (oredCriteria.size() == 0) { + oredCriteria.add(criteria); + } + return criteria; + } + + protected Criteria createCriteriaInternal() { + Criteria criteria = new Criteria(); + return criteria; + } + + public void clear() { + oredCriteria.clear(); + orderByClause = null; + distinct = false; + } + + protected abstract static class GeneratedCriteria { + protected List criteria; + + protected GeneratedCriteria() { + super(); + criteria = new ArrayList(); + } + + public boolean isValid() { + return criteria.size() > 0; + } + + public List getAllCriteria() { + return criteria; + } + + public List getCriteria() { + return criteria; + } + + protected void addCriterion(String condition) { + if (condition == null) { + throw new RuntimeException("Value for condition cannot be null"); + } + criteria.add(new Criterion(condition)); + } + + protected void addCriterion(String condition, Object value, String property) { + if (value == null) { + throw new RuntimeException("Value for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value)); + } + + protected void addCriterion(String condition, Object value1, Object value2, String property) { + if (value1 == null || value2 == null) { + throw new RuntimeException("Between values for " + property + " cannot be null"); + } + criteria.add(new Criterion(condition, value1, value2)); + } + + public Criteria andIdIsNull() { + addCriterion("id is null"); + return (Criteria) this; + } + + public Criteria andIdIsNotNull() { + addCriterion("id is not null"); + return (Criteria) this; + } + + public Criteria andIdEqualTo(String value) { + addCriterion("id =", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotEqualTo(String value) { + addCriterion("id <>", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThan(String value) { + addCriterion("id >", value, "id"); + return (Criteria) this; + } + + public Criteria andIdGreaterThanOrEqualTo(String value) { + addCriterion("id >=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThan(String value) { + addCriterion("id <", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLessThanOrEqualTo(String value) { + addCriterion("id <=", value, "id"); + return (Criteria) this; + } + + public Criteria andIdLike(String value) { + addCriterion("id like", value, "id"); + return (Criteria) this; + } + + public Criteria andIdNotLike(String value) { + addCriterion("id not like", value, "id"); + return (Criteria) this; + } + + public Criteria andIdIn(List values) { + addCriterion("id in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdNotIn(List values) { + addCriterion("id not in", values, "id"); + return (Criteria) this; + } + + public Criteria andIdBetween(String value1, String value2) { + addCriterion("id between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andIdNotBetween(String value1, String value2) { + addCriterion("id not between", value1, value2, "id"); + return (Criteria) this; + } + + public Criteria andUserIdIsNull() { + addCriterion("user_id is null"); + return (Criteria) this; + } + + public Criteria andUserIdIsNotNull() { + addCriterion("user_id is not null"); + return (Criteria) this; + } + + public Criteria andUserIdEqualTo(String value) { + addCriterion("user_id =", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdNotEqualTo(String value) { + addCriterion("user_id <>", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdGreaterThan(String value) { + addCriterion("user_id >", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdGreaterThanOrEqualTo(String value) { + addCriterion("user_id >=", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdLessThan(String value) { + addCriterion("user_id <", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdLessThanOrEqualTo(String value) { + addCriterion("user_id <=", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdLike(String value) { + addCriterion("user_id like", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdNotLike(String value) { + addCriterion("user_id not like", value, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdIn(List values) { + addCriterion("user_id in", values, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdNotIn(List values) { + addCriterion("user_id not in", values, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdBetween(String value1, String value2) { + addCriterion("user_id between", value1, value2, "userId"); + return (Criteria) this; + } + + public Criteria andUserIdNotBetween(String value1, String value2) { + addCriterion("user_id not between", value1, value2, "userId"); + return (Criteria) this; + } + + public Criteria andPropsIsNull() { + addCriterion("props is null"); + return (Criteria) this; + } + + public Criteria andPropsIsNotNull() { + addCriterion("props is not null"); + return (Criteria) this; + } + + public Criteria andPropsEqualTo(String value) { + addCriterion("props =", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsNotEqualTo(String value) { + addCriterion("props <>", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsGreaterThan(String value) { + addCriterion("props >", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsGreaterThanOrEqualTo(String value) { + addCriterion("props >=", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsLessThan(String value) { + addCriterion("props <", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsLessThanOrEqualTo(String value) { + addCriterion("props <=", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsLike(String value) { + addCriterion("props like", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsNotLike(String value) { + addCriterion("props not like", value, "props"); + return (Criteria) this; + } + + public Criteria andPropsIn(List values) { + addCriterion("props in", values, "props"); + return (Criteria) this; + } + + public Criteria andPropsNotIn(List values) { + addCriterion("props not in", values, "props"); + return (Criteria) this; + } + + public Criteria andPropsBetween(String value1, String value2) { + addCriterion("props between", value1, value2, "props"); + return (Criteria) this; + } + + public Criteria andPropsNotBetween(String value1, String value2) { + addCriterion("props not between", value1, value2, "props"); + return (Criteria) this; + } + + public Criteria andTypeIsNull() { + addCriterion("`type` is null"); + return (Criteria) this; + } + + public Criteria andTypeIsNotNull() { + addCriterion("`type` is not null"); + return (Criteria) this; + } + + public Criteria andTypeEqualTo(String value) { + addCriterion("`type` =", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotEqualTo(String value) { + addCriterion("`type` <>", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeGreaterThan(String value) { + addCriterion("`type` >", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeGreaterThanOrEqualTo(String value) { + addCriterion("`type` >=", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLessThan(String value) { + addCriterion("`type` <", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLessThanOrEqualTo(String value) { + addCriterion("`type` <=", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeLike(String value) { + addCriterion("`type` like", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotLike(String value) { + addCriterion("`type` not like", value, "type"); + return (Criteria) this; + } + + public Criteria andTypeIn(List values) { + addCriterion("`type` in", values, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotIn(List values) { + addCriterion("`type` not in", values, "type"); + return (Criteria) this; + } + + public Criteria andTypeBetween(String value1, String value2) { + addCriterion("`type` between", value1, value2, "type"); + return (Criteria) this; + } + + public Criteria andTypeNotBetween(String value1, String value2) { + addCriterion("`type` not between", value1, value2, "type"); + return (Criteria) this; + } + } + + public static class Criteria extends GeneratedCriteria { + + protected Criteria() { + super(); + } + } + + public static class Criterion { + private String condition; + + private Object value; + + private Object secondValue; + + private boolean noValue; + + private boolean singleValue; + + private boolean betweenValue; + + private boolean listValue; + + private String typeHandler; + + public String getCondition() { + return condition; + } + + public Object getValue() { + return value; + } + + public Object getSecondValue() { + return secondValue; + } + + public boolean isNoValue() { + return noValue; + } + + public boolean isSingleValue() { + return singleValue; + } + + public boolean isBetweenValue() { + return betweenValue; + } + + public boolean isListValue() { + return listValue; + } + + public String getTypeHandler() { + return typeHandler; + } + + protected Criterion(String condition) { + super(); + this.condition = condition; + this.typeHandler = null; + this.noValue = true; + } + + protected Criterion(String condition, Object value, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.typeHandler = typeHandler; + if (value instanceof List) { + this.listValue = true; + } else { + this.singleValue = true; + } + } + + protected Criterion(String condition, Object value) { + this(condition, value, null); + } + + protected Criterion(String condition, Object value, Object secondValue, String typeHandler) { + super(); + this.condition = condition; + this.value = value; + this.secondValue = secondValue; + this.typeHandler = typeHandler; + this.betweenValue = true; + } + + protected Criterion(String condition, Object value, Object secondValue) { + this(condition, value, secondValue, null); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/SwaggerUrlProjectMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/SwaggerUrlProjectMapper.xml index e520c74530..6fe4cf1452 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/SwaggerUrlProjectMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/SwaggerUrlProjectMapper.xml @@ -1,231 +1,229 @@ - - - - - - - - - - - - - - - - - and ${criterion.condition} - - - and ${criterion.condition} #{criterion.value} - - - and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} - - - and ${criterion.condition} - - #{listItem} - - - - - - + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + - - - - - - - - - - - and ${criterion.condition} - - - and ${criterion.condition} #{criterion.value} - - - and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} - - - and ${criterion.condition} - - #{listItem} - - - - - - + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + - - - - id, project_id, swagger_url, module_id, module_path, mode_id - - - - - delete - from swagger_url_project - where id = #{id,jdbcType=VARCHAR} - - - delete from swagger_url_project - - - - - - insert into swagger_url_project (id, project_id, swagger_url, - module_id, module_path, mode_id) - values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{swaggerUrl,jdbcType=VARCHAR}, - #{moduleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR}, #{modeId,jdbcType=VARCHAR}) - - - insert into swagger_url_project - - - id, - - - project_id, - - - swagger_url, - - - module_id, - - - module_path, - - - mode_id, - - - - - #{id,jdbcType=VARCHAR}, - - - #{projectId,jdbcType=VARCHAR}, - - - #{swaggerUrl,jdbcType=VARCHAR}, - - - #{moduleId,jdbcType=VARCHAR}, - - - #{modulePath,jdbcType=VARCHAR}, - - - #{modeId,jdbcType=VARCHAR}, - - - - - - update swagger_url_project - - - id = #{record.id,jdbcType=VARCHAR}, - - - project_id = #{record.projectId,jdbcType=VARCHAR}, - - - swagger_url = #{record.swaggerUrl,jdbcType=VARCHAR}, - - - module_id = #{record.moduleId,jdbcType=VARCHAR}, - - - module_path = #{record.modulePath,jdbcType=VARCHAR}, - - - mode_id = #{record.modeId,jdbcType=VARCHAR}, - - - - - - - - update swagger_url_project - set id = #{record.id,jdbcType=VARCHAR}, + + + + + id, project_id, swagger_url, module_id, module_path, mode_id + + + + + delete + from swagger_url_project + where id = #{id,jdbcType=VARCHAR} + + + delete from swagger_url_project + + + + + + insert into swagger_url_project (id, project_id, swagger_url, + module_id, module_path, mode_id) + values (#{id,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR}, #{swaggerUrl,jdbcType=VARCHAR}, + #{moduleId,jdbcType=VARCHAR}, #{modulePath,jdbcType=VARCHAR}, #{modeId,jdbcType=VARCHAR}) + + + insert into swagger_url_project + + + id, + + + project_id, + + + swagger_url, + + + module_id, + + + module_path, + + + mode_id, + + + + + #{id,jdbcType=VARCHAR}, + + + #{projectId,jdbcType=VARCHAR}, + + + #{swaggerUrl,jdbcType=VARCHAR}, + + + #{moduleId,jdbcType=VARCHAR}, + + + #{modulePath,jdbcType=VARCHAR}, + + + #{modeId,jdbcType=VARCHAR}, + + + + + + update swagger_url_project + + + id = #{record.id,jdbcType=VARCHAR}, + + project_id = #{record.projectId,jdbcType=VARCHAR}, + + swagger_url = #{record.swaggerUrl,jdbcType=VARCHAR}, + + module_id = #{record.moduleId,jdbcType=VARCHAR}, + + module_path = #{record.modulePath,jdbcType=VARCHAR}, - mode_id = #{record.modeId,jdbcType=VARCHAR} - - - - - - update swagger_url_project - - - project_id = #{projectId,jdbcType=VARCHAR}, - - - swagger_url = #{swaggerUrl,jdbcType=VARCHAR}, - - - module_id = #{moduleId,jdbcType=VARCHAR}, - - - module_path = #{modulePath,jdbcType=VARCHAR}, - - - mode_id = #{modeId,jdbcType=VARCHAR}, - - - where id = #{id,jdbcType=VARCHAR} - - - update swagger_url_project - set project_id = #{projectId,jdbcType=VARCHAR}, - swagger_url = #{swaggerUrl,jdbcType=VARCHAR}, - module_id = #{moduleId,jdbcType=VARCHAR}, - module_path = #{modulePath,jdbcType=VARCHAR}, - mode_id = #{modeId,jdbcType=VARCHAR} - where id = #{id,jdbcType=VARCHAR} - + + + mode_id = #{record.modeId,jdbcType=VARCHAR}, + + + + + + + + update swagger_url_project + set id = #{record.id,jdbcType=VARCHAR}, + project_id = #{record.projectId,jdbcType=VARCHAR}, + swagger_url = #{record.swaggerUrl,jdbcType=VARCHAR}, + module_id = #{record.moduleId,jdbcType=VARCHAR}, + module_path = #{record.modulePath,jdbcType=VARCHAR}, + mode_id = #{record.modeId,jdbcType=VARCHAR} + + + + + + update swagger_url_project + + + project_id = #{projectId,jdbcType=VARCHAR}, + + + swagger_url = #{swaggerUrl,jdbcType=VARCHAR}, + + + module_id = #{moduleId,jdbcType=VARCHAR}, + + + module_path = #{modulePath,jdbcType=VARCHAR}, + + + mode_id = #{modeId,jdbcType=VARCHAR}, + + + where id = #{id,jdbcType=VARCHAR} + + + update swagger_url_project + set project_id = #{projectId,jdbcType=VARCHAR}, + swagger_url = #{swaggerUrl,jdbcType=VARCHAR}, + module_id = #{moduleId,jdbcType=VARCHAR}, + module_path = #{modulePath,jdbcType=VARCHAR}, + mode_id = #{modeId,jdbcType=VARCHAR} + where id = #{id,jdbcType=VARCHAR} + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/UserHeaderMapper.java b/backend/src/main/java/io/metersphere/base/mapper/UserHeaderMapper.java new file mode 100644 index 0000000000..6851bfca79 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/UserHeaderMapper.java @@ -0,0 +1,30 @@ +package io.metersphere.base.mapper; + +import io.metersphere.base.domain.UserHeader; +import io.metersphere.base.domain.UserHeaderExample; +import java.util.List; +import org.apache.ibatis.annotations.Param; + +public interface UserHeaderMapper { + long countByExample(UserHeaderExample example); + + int deleteByExample(UserHeaderExample example); + + int deleteByPrimaryKey(String id); + + int insert(UserHeader record); + + int insertSelective(UserHeader record); + + List selectByExample(UserHeaderExample example); + + UserHeader selectByPrimaryKey(String id); + + int updateByExampleSelective(@Param("record") UserHeader record, @Param("example") UserHeaderExample example); + + int updateByExample(@Param("record") UserHeader record, @Param("example") UserHeaderExample example); + + int updateByPrimaryKeySelective(UserHeader record); + + int updateByPrimaryKey(UserHeader record); +} \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/UserHeaderMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/UserHeaderMapper.xml new file mode 100644 index 0000000000..5cb218d6e0 --- /dev/null +++ b/backend/src/main/java/io/metersphere/base/mapper/UserHeaderMapper.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + + + + + + + + and ${criterion.condition} + + + and ${criterion.condition} #{criterion.value} + + + and ${criterion.condition} #{criterion.value} and #{criterion.secondValue} + + + and ${criterion.condition} + + #{listItem} + + + + + + + + + + + id, user_id, props, `type` + + + + + delete from user_header + where id = #{id,jdbcType=VARCHAR} + + + delete from user_header + + + + + + insert into user_header (id, user_id, props, + `type`) + values (#{id,jdbcType=VARCHAR}, #{userId,jdbcType=VARCHAR}, #{props,jdbcType=VARCHAR}, + #{type,jdbcType=VARCHAR}) + + + insert into user_header + + + id, + + + user_id, + + + props, + + + `type`, + + + + + #{id,jdbcType=VARCHAR}, + + + #{userId,jdbcType=VARCHAR}, + + + #{props,jdbcType=VARCHAR}, + + + #{type,jdbcType=VARCHAR}, + + + + + + update user_header + + + id = #{record.id,jdbcType=VARCHAR}, + + + user_id = #{record.userId,jdbcType=VARCHAR}, + + + props = #{record.props,jdbcType=VARCHAR}, + + + `type` = #{record.type,jdbcType=VARCHAR}, + + + + + + + + update user_header + set id = #{record.id,jdbcType=VARCHAR}, + user_id = #{record.userId,jdbcType=VARCHAR}, + props = #{record.props,jdbcType=VARCHAR}, + `type` = #{record.type,jdbcType=VARCHAR} + + + + + + update user_header + + + user_id = #{userId,jdbcType=VARCHAR}, + + + props = #{props,jdbcType=VARCHAR}, + + + `type` = #{type,jdbcType=VARCHAR}, + + + where id = #{id,jdbcType=VARCHAR} + + + update user_header + set user_id = #{userId,jdbcType=VARCHAR}, + props = #{props,jdbcType=VARCHAR}, + `type` = #{type,jdbcType=VARCHAR} + where id = #{id,jdbcType=VARCHAR} + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java index 07ea9c380d..258706df46 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.java @@ -6,6 +6,7 @@ import io.metersphere.api.dto.datacount.ApiDataCountResult; import io.metersphere.base.domain.ApiScenario; import io.metersphere.base.domain.ApiScenarioExample; import io.metersphere.base.domain.ApiScenarioWithBLOBs; +import io.metersphere.controller.request.BaseQueryRequest; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -34,4 +35,6 @@ public interface ExtApiScenarioMapper { List selectIdsNotExistsInPlan(String projectId, String planId); ApiScenario getNextNum(@Param("projectId") String projectId); + + List selectIdsByQuery(@Param("request") ApiScenarioRequest request); } diff --git a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml index 7dce263d4f..3aa0322a8f 100644 --- a/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml +++ b/backend/src/main/java/io/metersphere/base/mapper/ext/ExtApiScenarioMapper.xml @@ -134,6 +134,11 @@ from api_scenario left join project on api_scenario.project_id = project.id left join user on api_scenario.user_id = user.id + + + + + @@ -144,8 +149,8 @@ and (api_scenario.name like CONCAT('%', #{request.name},'%') - or api_scenario.tags like CONCAT('%', #{request.name},'%') - or api_scenario.num like CONCAT('%', #{request.name},'%')) + or api_scenario.tags like CONCAT('%', #{request.name},'%') + or api_scenario.num like CONCAT('%', #{request.name},'%')) AND project.workspace_id = #{request.workspaceId} @@ -223,19 +228,13 @@ and api_scenario.id not in ( - select pc.api_scenario_id - from test_plan_api_scenario pc - where pc.test_plan_id = #{request.planId} + select pc.api_scenario_id + from test_plan_api_scenario pc + where pc.test_plan_id = #{request.planId} ) - - order by - - api_scenario.${order.name} ${order.type} - - - + + + \ No newline at end of file diff --git a/backend/src/main/java/io/metersphere/controller/SystemParameterController.java b/backend/src/main/java/io/metersphere/controller/SystemParameterController.java index 7f5dbfcf7a..8fd47d8dc0 100644 --- a/backend/src/main/java/io/metersphere/controller/SystemParameterController.java +++ b/backend/src/main/java/io/metersphere/controller/SystemParameterController.java @@ -1,8 +1,10 @@ package io.metersphere.controller; import io.metersphere.base.domain.SystemParameter; +import io.metersphere.base.domain.UserHeader; import io.metersphere.commons.constants.ParamConstants; import io.metersphere.commons.constants.RoleConstants; +import io.metersphere.controller.request.HeaderRequest; import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.ldap.domain.LdapInfo; import io.metersphere.notice.domain.MailInfo; @@ -67,4 +69,13 @@ public class SystemParameterController { return SystemParameterService.getLdapInfo(ParamConstants.Classify.LDAP.getValue()); } + @PostMapping("save/header") + public void saveHeader(@RequestBody UserHeader userHeader) { + SystemParameterService.saveHeader(userHeader); + } + + @PostMapping("/header/info") + public UserHeader getHeaderInfo(@RequestBody HeaderRequest headerRequest) { + return SystemParameterService.queryUserHeader(headerRequest); + } } diff --git a/backend/src/main/java/io/metersphere/controller/request/HeaderRequest.java b/backend/src/main/java/io/metersphere/controller/request/HeaderRequest.java new file mode 100644 index 0000000000..cee2348373 --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/request/HeaderRequest.java @@ -0,0 +1,11 @@ +package io.metersphere.controller.request; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class HeaderRequest { + private String userId; + private String type; +} diff --git a/backend/src/main/java/io/metersphere/job/sechedule/ApiScenarioTestJob.java b/backend/src/main/java/io/metersphere/job/sechedule/ApiScenarioTestJob.java index f238615e37..e118c90cf9 100644 --- a/backend/src/main/java/io/metersphere/job/sechedule/ApiScenarioTestJob.java +++ b/backend/src/main/java/io/metersphere/job/sechedule/ApiScenarioTestJob.java @@ -56,7 +56,7 @@ public class ApiScenarioTestJob extends MsScheduleJob { request.setProjectId(projectID); request.setTriggerMode(ReportTriggerMode.SCHEDULE.name()); request.setExecuteType(ExecuteType.Saved.name()); - request.setScenarioIds(this.scenarioIds); + request.setIds(this.scenarioIds); request.setReportUserID(this.userId); apiAutomationService.run(request); diff --git a/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java b/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java index ba8ab0c3ea..9c188e5ae9 100644 --- a/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java +++ b/backend/src/main/java/io/metersphere/job/sechedule/SwaggerUrlImportJob.java @@ -29,7 +29,6 @@ public class SwaggerUrlImportJob extends MsScheduleJob { request.setSwaggerUrl(swaggerUrlProject.getSwaggerUrl()); request.setModuleId(swaggerUrlProject.getModuleId()); request.setPlatform("Swagger2"); - request.setSaved(true); request.setUserId(jobDataMap.getString("userId")); request.setType("schedule"); apiDefinitionService.apiTestImport(null, request); diff --git a/backend/src/main/java/io/metersphere/service/SystemParameterService.java b/backend/src/main/java/io/metersphere/service/SystemParameterService.java index 8310c4baeb..70f1eaaa59 100644 --- a/backend/src/main/java/io/metersphere/service/SystemParameterService.java +++ b/backend/src/main/java/io/metersphere/service/SystemParameterService.java @@ -2,12 +2,16 @@ package io.metersphere.service; import io.metersphere.base.domain.SystemParameter; import io.metersphere.base.domain.SystemParameterExample; +import io.metersphere.base.domain.UserHeader; +import io.metersphere.base.domain.UserHeaderExample; import io.metersphere.base.mapper.SystemParameterMapper; +import io.metersphere.base.mapper.UserHeaderMapper; import io.metersphere.base.mapper.ext.ExtSystemParameterMapper; import io.metersphere.commons.constants.ParamConstants; import io.metersphere.commons.exception.MSException; import io.metersphere.commons.utils.EncryptUtils; import io.metersphere.commons.utils.LogUtil; +import io.metersphere.controller.request.HeaderRequest; import io.metersphere.dto.BaseSystemConfigDTO; import io.metersphere.i18n.Translator; import io.metersphere.ldap.domain.LdapInfo; @@ -29,7 +33,8 @@ import java.util.*; @Service @Transactional(rollbackFor = Exception.class) public class SystemParameterService { - + @Resource + private UserHeaderMapper userHeaderMapper; @Resource private SystemParameterMapper systemParameterMapper; @Resource @@ -233,4 +238,29 @@ public class SystemParameterService { example.clear(); }); } + + //保存表头 + public void saveHeader(UserHeader userHeader) { + UserHeaderExample example=new UserHeaderExample(); + example.createCriteria().andUserIdEqualTo(userHeader.getUserId()).andTypeEqualTo(userHeader.getType()); + if(userHeaderMapper.countByExample(example)>0){ + userHeaderMapper.deleteByExample(example); + userHeader.setId(UUID.randomUUID().toString()); + userHeaderMapper.insert(userHeader); + }else{ + userHeader.setId(UUID.randomUUID().toString()); + userHeaderMapper.insert(userHeader); + } + example.clear(); + } + + public UserHeader queryUserHeader(HeaderRequest headerRequest) { + UserHeaderExample example = new UserHeaderExample(); + example.createCriteria().andUserIdEqualTo(headerRequest.getUserId()).andTypeEqualTo(headerRequest.getType()); + List list = userHeaderMapper.selectByExample(example); + if (list.size() > 0) { + return list.get(0); + } + return null; + } } diff --git a/backend/src/main/java/io/metersphere/track/controller/TestCaseReviewController.java b/backend/src/main/java/io/metersphere/track/controller/TestCaseReviewController.java index d69cd5121e..ac3544d130 100644 --- a/backend/src/main/java/io/metersphere/track/controller/TestCaseReviewController.java +++ b/backend/src/main/java/io/metersphere/track/controller/TestCaseReviewController.java @@ -91,14 +91,14 @@ public class TestCaseReviewController { @PostMapping("/projects") public List getProjectByReviewId(@RequestBody TestReviewRelevanceRequest request) { - List projectIds = testReviewProjectService.getProjectIdsByReviewId(request.getReviewId()); + List projectIds = testReviewProjectService.getProjectIdsByReviewId(); request.setProjectIds(projectIds); return testReviewProjectService.getProject(request); } @PostMapping("/project/{goPage}/{pageSize}") public Pager> getProjectByReviewId(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody TestReviewRelevanceRequest request) { - List projectIds = testReviewProjectService.getProjectIdsByReviewId(request.getReviewId()); + List projectIds = testReviewProjectService.getProjectIdsByReviewId(); request.setProjectIds(projectIds); Page page = PageHelper.startPage(goPage, pageSize, true); return PageUtils.setPageInfo(page, testReviewProjectService.getProject(request)); diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java index fedd336094..6322147321 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseNodeService.java @@ -9,6 +9,7 @@ import io.metersphere.base.mapper.ext.ExtTestCaseNodeMapper; import io.metersphere.base.mapper.ext.ExtTestPlanTestCaseMapper; import io.metersphere.commons.constants.TestCaseConstants; import io.metersphere.commons.exception.MSException; +import io.metersphere.commons.utils.SessionUtils; import io.metersphere.exception.ExcelException; import io.metersphere.i18n.Translator; import io.metersphere.service.NodeTreeService; @@ -197,10 +198,11 @@ public class TestCaseNodeService extends NodeTreeService { public List getNodeByReviewId(String reviewId) { List list = new ArrayList<>(); - TestCaseReview testCaseReview = new TestCaseReview(); - testCaseReview.setId(reviewId); - List project = testCaseReviewService.getProjectByReviewId(testCaseReview); - List projectIds = project.stream().map(Project::getId).collect(Collectors.toList()); + ProjectExample example = new ProjectExample(); + example.createCriteria().andWorkspaceIdEqualTo(SessionUtils.getCurrentWorkspaceId()); + List projects = projectMapper.selectByExample(example); + List projectIds = projects.stream().map(Project::getId).collect(Collectors.toList()); + projectIds.forEach(id -> { String name = projectMapper.selectByPrimaryKey(id).getName(); @@ -405,6 +407,10 @@ public class TestCaseNodeService extends NodeTreeService { TestCaseNodeDTO nodeTree = request.getNodeTree(); + if (nodeTree == null) { + return; + } + List updateNodes = new ArrayList<>(); buildUpdateTestCase(nodeTree, testCases, updateNodes, "/", "0", 1); diff --git a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java index 9e59f6e02e..a5944ec526 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestCaseReviewService.java @@ -81,19 +81,7 @@ public class TestCaseReviewService { public void saveTestCaseReview(SaveTestCaseReviewRequest reviewRequest) { checkCaseReviewExist(reviewRequest); String reviewId = UUID.randomUUID().toString(); - List projectIds = reviewRequest.getProjectIds(); List userIds = reviewRequest.getUserIds();//执行人 - if (!CollectionUtils.isEmpty(projectIds)) { - List ids = projectIds.stream().distinct().collect(Collectors.toList()); - // 如果关联项目id中包含当前项目id进行移除 - ids.remove(SessionUtils.getCurrentProjectId()); - ids.forEach(projectId -> { - TestCaseReviewProject testCaseReviewProject = new TestCaseReviewProject(); - testCaseReviewProject.setProjectId(projectId); - testCaseReviewProject.setReviewId(reviewId); - testCaseReviewProjectMapper.insertSelective(testCaseReviewProject); - }); - } userIds.forEach(userId -> { TestCaseReviewUsers testCaseReviewUsers = new TestCaseReviewUsers(); @@ -216,7 +204,6 @@ public class TestCaseReviewService { public void editCaseReview(SaveTestCaseReviewRequest testCaseReview) { editCaseReviewer(testCaseReview); - editCaseReviewProject(testCaseReview); testCaseReview.setUpdateTime(System.currentTimeMillis()); checkCaseReviewExist(testCaseReview); testCaseReviewMapper.updateByPrimaryKeySelective(testCaseReview); @@ -259,56 +246,6 @@ public class TestCaseReviewService { testCaseReviewUsersMapper.deleteByExample(example); } - private void editCaseReviewProject(SaveTestCaseReviewRequest testCaseReview) { - List projectIds = testCaseReview.getProjectIds(); - if (!CollectionUtils.isEmpty(projectIds)) { - projectIds.remove(testCaseReview.getProjectId()); - } - String id = testCaseReview.getId(); - if (StringUtils.isNotBlank(testCaseReview.getProjectId())) { - TestCaseReviewProjectExample testCaseReviewProjectExample = new TestCaseReviewProjectExample(); - testCaseReviewProjectExample.createCriteria().andReviewIdEqualTo(id); - List testCaseReviewProjects = testCaseReviewProjectMapper.selectByExample(testCaseReviewProjectExample); - List dbProjectIds = testCaseReviewProjects.stream().map(TestCaseReviewProject::getProjectId).collect(Collectors.toList()); - projectIds.forEach(projectId -> { - if (!dbProjectIds.contains(projectId)) { - TestCaseReviewProject testCaseReviewProject = new TestCaseReviewProject(); - testCaseReviewProject.setReviewId(id); - testCaseReviewProject.setProjectId(projectId); - testCaseReviewProjectMapper.insert(testCaseReviewProject); - } - }); - - TestCaseReviewProjectExample example = new TestCaseReviewProjectExample(); - TestCaseReviewProjectExample.Criteria criteria1 = example.createCriteria().andReviewIdEqualTo(id); - if (!CollectionUtils.isEmpty(projectIds)) { - criteria1.andProjectIdNotIn(projectIds); - } - testCaseReviewProjectMapper.deleteByExample(example); - - - // 关联的项目下的用例idList - List caseIds = null; - // 测试计划所属项目下的用例不解除关联 - projectIds.add(testCaseReview.getProjectId()); - // 关联的项目下的用例idList - if (!CollectionUtils.isEmpty(projectIds)) { - TestCaseExample testCaseExample = new TestCaseExample(); - testCaseExample.createCriteria().andProjectIdIn(projectIds); - List caseList = testCaseMapper.selectByExample(testCaseExample); - caseIds = caseList.stream().map(TestCase::getId).collect(Collectors.toList()); - } - - TestCaseReviewTestCaseExample testCaseReviewTestCaseExample = new TestCaseReviewTestCaseExample(); - TestCaseReviewTestCaseExample.Criteria criteria = testCaseReviewTestCaseExample.createCriteria().andReviewIdEqualTo(id); - if (!CollectionUtils.isEmpty(caseIds)) { - criteria.andCaseIdNotIn(caseIds); - } - testCaseReviewTestCaseMapper.deleteByExample(testCaseReviewTestCaseExample); - } - - } - private void checkCaseReviewExist(TestCaseReview testCaseReview) { if (testCaseReview.getName() != null) { TestCaseReviewExample example = new TestCaseReviewExample(); diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanProjectService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanProjectService.java index bb8b69ee18..7d694b8767 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanProjectService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanProjectService.java @@ -11,6 +11,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -26,23 +27,15 @@ public class TestPlanProjectService { private TestPlanMapper testPlanMapper; public List getProjectIdsByPlanId(String planId) { - TestPlan testPlan = testPlanMapper.selectByPrimaryKey(planId); - TestPlanProjectExample example = new TestPlanProjectExample(); - example.createCriteria().andTestPlanIdEqualTo(planId); - List projectIds = testPlanProjectMapper.selectByExample(example) - .stream() - .map(TestPlanProject::getProjectId) - .collect(Collectors.toList()); - if (testPlan != null && StringUtils.isNotBlank(testPlan.getProjectId())) { - if (!projectIds.contains(testPlan.getProjectId())) { - projectIds.add(testPlan.getProjectId()); - } + TestPlan plan = testPlanMapper.selectByPrimaryKey(planId); + String workspaceId = plan.getWorkspaceId(); + if (StringUtils.isNotBlank(workspaceId)) { + ProjectExample example = new ProjectExample(); + example.createCriteria().andWorkspaceIdEqualTo(workspaceId); + List projects = projectMapper.selectByExample(example); + return projects.stream().map(Project::getId).collect(Collectors.toList()); } - if (projectIds.isEmpty()) { - return null; - } - - return projectIds; + return new ArrayList<>(); } public List getProjectByPlanId(TestCaseRelevanceRequest request) { diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java index 5a043becfa..3e8a534270 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java @@ -96,7 +96,7 @@ public class TestPlanScenarioCaseService { scenarioIds.add(apiScenario.getApiScenarioId()); scenarioIdApiScarionMap.put(apiScenario.getApiScenarioId(),apiScenario.getId()); } - request.setScenarioIds(scenarioIds); + request.setIds(scenarioIds); request.setScenarioTestPlanIdMap(scenarioIdApiScarionMap); request.setRunMode(ApiRunMode.SCENARIO_PLAN.name()); return apiAutomationService.run(request); diff --git a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java index 3618019da1..2e2589acfa 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanService.java @@ -119,15 +119,6 @@ public class TestPlanService { } String testPlanId = UUID.randomUUID().toString(); - - List projectIds = testPlan.getProjectIds(); - projectIds.forEach(id -> { - TestPlanProject testPlanProject = new TestPlanProject(); - testPlanProject.setProjectId(id); - testPlanProject.setTestPlanId(testPlanId); - testPlanProjectMapper.insertSelective(testPlanProject); - }); - testPlan.setId(testPlanId); testPlan.setStatus(TestPlanStatus.Prepare.name()); testPlan.setCreateTime(System.currentTimeMillis()); @@ -166,7 +157,6 @@ public class TestPlanService { } public int editTestPlan(TestPlanDTO testPlan) { - editTestPlanProject(testPlan); checkTestPlanExist(testPlan); TestPlan res = testPlanMapper.selectByPrimaryKey(testPlan.getId()); // 先查一次库 if (!res.getStatus().equals(testPlan.getStatus())) { // 若有改变才更新时间 @@ -213,70 +203,6 @@ public class TestPlanService { return i; } - private void editTestPlanProject(TestPlanDTO testPlan) { - // 将要进行关联的项目ID - List projectIds = testPlan.getProjectIds(); - // 如果将要关联的项目ID中包含测试计划所属ID则进行剔除 - if (!CollectionUtils.isEmpty(projectIds)) { - if (projectIds.contains(testPlan.getProjectId())) { - projectIds.remove(testPlan.getProjectId()); - } - } - // todo 优化; TestPlanList intoPlan 方法会触发此更新 - if (StringUtils.isNotBlank(testPlan.getProjectId())) { - TestPlanProjectExample testPlanProjectExample1 = new TestPlanProjectExample(); - testPlanProjectExample1.createCriteria().andTestPlanIdEqualTo(testPlan.getId()); - List testPlanProjects = testPlanProjectMapper.selectByExample(testPlanProjectExample1); - // 已经关联的项目idList - List dbProjectIds = testPlanProjects.stream().map(TestPlanProject::getProjectId).collect(Collectors.toList()); - // 修改后传过来的项目idList,如果还未关联,进行关联 - projectIds.forEach(projectId -> { - if (!dbProjectIds.contains(projectId)) { - TestPlanProject testPlanProject = new TestPlanProject(); - testPlanProject.setTestPlanId(testPlan.getId()); - testPlanProject.setProjectId(projectId); - testPlanProjectMapper.insert(testPlanProject); - } - }); - - TestPlanProjectExample testPlanProjectExample = new TestPlanProjectExample(); - TestPlanProjectExample.Criteria criteria1 = testPlanProjectExample.createCriteria(); - criteria1.andTestPlanIdEqualTo(testPlan.getId()); - if (!CollectionUtils.isEmpty(projectIds)) { - criteria1.andProjectIdNotIn(projectIds); - } - testPlanProjectMapper.deleteByExample(testPlanProjectExample); - - // 关联的项目下的用例idList - List caseIds = null; - // 测试计划所属项目下的用例不解除关联 - projectIds.add(testPlan.getProjectId()); - if (!CollectionUtils.isEmpty(projectIds)) { - TestCaseExample example = new TestCaseExample(); - example.createCriteria().andProjectIdIn(projectIds); - List caseList = testCaseMapper.selectByExample(example); - caseIds = caseList.stream().map(TestCase::getId).collect(Collectors.toList()); - } - - // 取消关联项目下的用例和计划的关系 - TestPlanTestCaseExample testPlanTestCaseExample = new TestPlanTestCaseExample(); - TestPlanTestCaseExample.Criteria criteria = testPlanTestCaseExample.createCriteria().andPlanIdEqualTo(testPlan.getId()); - if (!CollectionUtils.isEmpty(caseIds)) { - criteria.andCaseIdNotIn(caseIds); - } - testPlanTestCaseMapper.deleteByExample(testPlanTestCaseExample); - - List relevanceProjectIds = new ArrayList<>(); - relevanceProjectIds.add(testPlan.getProjectId()); - if (!CollectionUtils.isEmpty(testPlan.getProjectIds())) { - relevanceProjectIds.addAll(testPlan.getProjectIds()); - } - testPlanApiCaseService.deleteByRelevanceProjectIds(testPlan.getId(), relevanceProjectIds); - testPlanScenarioCaseService.deleteByRelevanceProjectIds(testPlan.getId(), relevanceProjectIds); - testPlanLoadCaseService.deleteByRelevanceProjectIds(testPlan.getId(), relevanceProjectIds); - } - } - //计划内容 private Map getTestPlanParamMap(TestPlan testPlan) { Long startTime = testPlan.getPlannedStartTime(); @@ -331,7 +257,6 @@ public class TestPlanService { public int deleteTestPlan(String planId) { TestPlan testPlan = getTestPlan(planId); deleteTestCaseByPlanId(planId); - testPlanProjectService.deleteTestPlanProjectByPlanId(planId); testPlanApiCaseService.deleteByPlanId(planId); testPlanScenarioCaseService.deleteByPlanId(planId); diff --git a/backend/src/main/java/io/metersphere/track/service/TestReviewProjectService.java b/backend/src/main/java/io/metersphere/track/service/TestReviewProjectService.java index 00f0259c8c..ecf1c92449 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestReviewProjectService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestReviewProjectService.java @@ -2,8 +2,7 @@ package io.metersphere.track.service; import io.metersphere.base.domain.*; import io.metersphere.base.mapper.ProjectMapper; -import io.metersphere.base.mapper.TestCaseReviewMapper; -import io.metersphere.base.mapper.TestCaseReviewProjectMapper; +import io.metersphere.commons.utils.SessionUtils; import io.metersphere.track.request.testreview.TestReviewRelevanceRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -19,32 +18,14 @@ public class TestReviewProjectService { @Resource private ProjectMapper projectMapper; - @Resource - private TestCaseReviewProjectMapper testCaseReviewProjectMapper; - @Resource - private TestCaseReviewMapper testCaseReviewMapper; - public List getProjectIdsByReviewId(String reviewId) { - TestCaseReviewProjectExample example = new TestCaseReviewProjectExample(); - example.createCriteria().andReviewIdEqualTo(reviewId); - List projectIds = testCaseReviewProjectMapper.selectByExample(example) - .stream() - .map(TestCaseReviewProject::getProjectId) - .collect(Collectors.toList()); - TestCaseReview caseReview = testCaseReviewMapper.selectByPrimaryKey(reviewId); - if (caseReview != null && StringUtils.isNotBlank(caseReview.getProjectId())) { - if (!projectIds.contains(caseReview.getProjectId())) { - projectIds.add(caseReview.getProjectId()); - } - } - if (projectIds.isEmpty()) { - return null; - } - - return projectIds; + public List getProjectIdsByReviewId() { + ProjectExample example = new ProjectExample(); + example.createCriteria().andWorkspaceIdEqualTo(SessionUtils.getCurrentWorkspaceId()); + List projects = projectMapper.selectByExample(example); + return projects.stream().map(Project::getId).collect(Collectors.toList()); } - public List getProject(TestReviewRelevanceRequest request) { ProjectExample projectExample = new ProjectExample(); ProjectExample.Criteria criteria = projectExample.createCriteria(); diff --git a/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java b/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java index a2e5645e8c..8829d61ba0 100644 --- a/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java +++ b/backend/src/main/java/io/metersphere/xmind/XmindCaseParser.java @@ -276,22 +276,19 @@ public class XmindCaseParser { testCase.setType("functional"); String tc = title.replace(":", ":"); - String[] tcArr = tc.split(":"); - if (tcArr.length < 1) { + String[] tcArrs = tc.split(":"); + if (tcArrs.length < 1) { process.add(Translator.get("test_case_name") + Translator.get("incorrect_format"), title); return; } // 用例名称 - StringBuffer name = new StringBuffer(); - for (int i = 1; i < tcArr.length; i++) { - name.append(tcArr[i]); - } - testCase.setName(name.toString()); + String name = title.replace(tcArrs[0] + ":", "").replace(tcArrs[0] + ":", ""); + testCase.setName(name); testCase.setNodePath(nodePath); // 用例等级和用例性质处理 - if (tcArr[0].indexOf("-") != -1) { - for (String item : tcArr[0].split("-")) { + if (tcArrs[0].indexOf("-") != -1) { + for (String item : tcArrs[0].split("-")) { if (isAvailable(item, TC_REGEX)) { continue; } else if (item.toUpperCase().startsWith("P")) { diff --git a/backend/src/main/java/io/metersphere/xpack b/backend/src/main/java/io/metersphere/xpack index b35af517d8..44bcc98930 160000 --- a/backend/src/main/java/io/metersphere/xpack +++ b/backend/src/main/java/io/metersphere/xpack @@ -1 +1 @@ -Subproject commit b35af517d888268abd3a8f2b58d6ea94335138a5 +Subproject commit 44bcc9893033900f95c99068cd4edec740465dfe diff --git a/backend/src/main/resources/db/migration/V74__modify_schedule_message_task.sql b/backend/src/main/resources/db/migration/V74__modify_schedule_message_task.sql index 0acb8fc2cd..695c6b2f11 100644 --- a/backend/src/main/resources/db/migration/V74__modify_schedule_message_task.sql +++ b/backend/src/main/resources/db/migration/V74__modify_schedule_message_task.sql @@ -1,4 +1,4 @@ ALTER TABLE schedule - MODIFY COLUMN id VARCHAR(255); + MODIFY COLUMN id VARCHAR (255); ALTER TABLE message_task - MODIFY COLUMN id VARCHAR(255); + MODIFY COLUMN id VARCHAR (255); diff --git a/backend/src/main/resources/db/migration/V75__modify_schedule_message_task_test_id.sql b/backend/src/main/resources/db/migration/V75__modify_schedule_message_task_test_id.sql index eaa6402348..b1092b7e3f 100644 --- a/backend/src/main/resources/db/migration/V75__modify_schedule_message_task_test_id.sql +++ b/backend/src/main/resources/db/migration/V75__modify_schedule_message_task_test_id.sql @@ -1,4 +1,4 @@ ALTER TABLE schedule - MODIFY COLUMN resource_id VARCHAR(255); + MODIFY COLUMN resource_id VARCHAR (255); ALTER TABLE message_task - MODIFY COLUMN test_id VARCHAR(255); + MODIFY COLUMN test_id VARCHAR (255); diff --git a/backend/src/main/resources/db/migration/V76__user_header.sql b/backend/src/main/resources/db/migration/V76__user_header.sql new file mode 100644 index 0000000000..65366058ec --- /dev/null +++ b/backend/src/main/resources/db/migration/V76__user_header.sql @@ -0,0 +1,10 @@ +create table user_header +( + id varchar(50) not null, + user_id varchar(50) null, + props varchar(1000) null, + type varchar(150) null, + constraint user_header_pk + primary key (id) +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 diff --git a/backend/src/main/resources/generatorConfig.xml b/backend/src/main/resources/generatorConfig.xml index afacb48f72..27511b8cc8 100644 --- a/backend/src/main/resources/generatorConfig.xml +++ b/backend/src/main/resources/generatorConfig.xml @@ -66,6 +66,7 @@
+
diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index 3ac43e7a11..5ea0284f71 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -184,4 +184,5 @@ automation_exec_info=There are no test steps to execute authsource_name_already_exists=Authentication source name already exists authsource_name_is_null=Authentication source name cannot be empty authsource_configuration_is_null=Authentication source configuration cannot be empty +mobile_phone_number_cannot_be_empty=When the receiving mode is pin and enterprise wechat: the user's mobile phone number cannot be empty diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index 4e9f9ffff4..485b69f6d6 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -185,4 +185,4 @@ automation_exec_info=沒有測試步驟,無法執行 #authsource authsource_name_already_exists=認證源名稱已經存在 authsource_name_is_null=認證源名稱不能為空 -authsource_configuration_is_null=認證源配置不能為空 \ No newline at end of file +authsource_configuration_is_null=認證源配置不能為空 diff --git a/frontend/src/business/components/api/automation/ApiAutomation.vue b/frontend/src/business/components/api/automation/ApiAutomation.vue index 8345b4a917..77ffbb9493 100644 --- a/frontend/src/business/components/api/automation/ApiAutomation.vue +++ b/frontend/src/business/components/api/automation/ApiAutomation.vue @@ -8,6 +8,7 @@ @setModuleOptions="setModuleOptions" @setNodeTree="setNodeTree" @enableTrash="enableTrash" + @exportAPI="exportAPI" :type="'edit'" ref="nodeTree"/> @@ -267,6 +268,9 @@ }, enableTrash(data) { this.trashEnable = data; + }, + exportAPI() { + this.$refs.apiScenarioList.exportApi(); } } } diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index 7f3f94c983..0a97efc9c9 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -9,7 +9,8 @@ @@ -24,95 +25,109 @@ + + diff --git a/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue b/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue index 8ddd33c4a4..e81879db47 100644 --- a/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue +++ b/frontend/src/business/components/api/automation/scenario/variable/VariableList.vue @@ -7,7 +7,8 @@
- + @@ -19,8 +20,9 @@ - - {{$t('commons.add')}} + + {{ $t('commons.add') }} 常量 列表 @@ -29,21 +31,23 @@ 随机数 - {{$t('commons.delete')}} + {{ $t('commons.delete') }} +
- @@ -64,15 +68,17 @@ - - {{$t('api_test.request.headers')}} + + {{ $t('api_test.request.headers') }}
-
{{headers.length-1}}
+
{{ headers.length - 1 }}
- {{$t("commons.batch_add")}} + {{ $t("commons.batch_add") }} +
@@ -82,40 +88,40 @@ diff --git a/frontend/src/business/components/api/definition/components/assertion/ApiAssertions.vue b/frontend/src/business/components/api/definition/components/assertion/ApiAssertions.vue index d825f5cb74..3bf78dbd8c 100644 --- a/frontend/src/business/components/api/definition/components/assertion/ApiAssertions.vue +++ b/frontend/src/business/components/api/definition/components/assertion/ApiAssertions.vue @@ -52,31 +52,31 @@ diff --git a/frontend/src/business/components/common/head/SearchList.vue b/frontend/src/business/components/common/head/SearchList.vue index 2b1b6f6cd5..ec087a2819 100644 --- a/frontend/src/business/components/common/head/SearchList.vue +++ b/frontend/src/business/components/common/head/SearchList.vue @@ -67,7 +67,11 @@ export default { if (userLastProjectId) { // id 是否存在 if (this.searchArray.length > 0 && this.searchArray.map(p => p.id).indexOf(userLastProjectId) !== -1) { - localStorage.setItem(PROJECT_ID, userLastProjectId); + let projectId = localStorage.getItem(PROJECT_ID); + if (!projectId || projectId != userLastProjectId) { + localStorage.setItem(PROJECT_ID, userLastProjectId); + window.location.reload(); + } } } let projectId = getCurrentProjectID(); diff --git a/frontend/src/business/components/common/model/JsonData.js b/frontend/src/business/components/common/model/JsonData.js new file mode 100644 index 0000000000..5ca60b233e --- /dev/null +++ b/frontend/src/business/components/common/model/JsonData.js @@ -0,0 +1,133 @@ +import i18n from '../../../../i18n/i18n' +//自定义默认表头 +//测试用例 +export const Track_Test_Case = [ + {prop: 'num', label: i18n.t('commons.id')}, + {prop: 'name', label: i18n.t('commons.name')}, + {prop: 'priority', label: i18n.t('test_track.case.priority')}, + {prop: 'type', label: i18n.t('test_track.case.type')}, + {prop: 'method', label: i18n.t('test_track.case.method')}, + {prop: 'reviewStatus', label: i18n.t('test_track.case.status')}, + {prop: 'tags', label: i18n.t('commons.tag')}, + {prop: 'nodePath', label: i18n.t('test_track.case.module')}, + {prop: 'updateTime', label: i18n.t('commons.update_time')}, +] +//用例评审-测试用例 +export const Test_Case_Review = [ + {prop: 'name', label: i18n.t('test_track.review.review_name')}, + {prop: 'reviewer', label: i18n.t('test_track.review.reviewer')}, + {prop: 'projectName', label: i18n.t('test_track.review.review_project')}, + {prop: 'creatorName', label: i18n.t('test_track.review.review_creator')}, + {prop: 'status', label: i18n.t('test_track.review.review_status')}, + {prop: 'createTime', label: i18n.t('commons.create_time')}, + {prop: 'endTime', label: i18n.t('test_track.review.end_time')}, +] +//测试计划-测试用例 +export const Test_Plan_List = [ + {prop: 'name', label: i18n.t('commons.name')}, + {prop: 'userName', label: i18n.t('test_track.plan.plan_principal')}, + {prop: 'status', label: i18n.t('test_track.plan.plan_status')}, + {prop: 'stage', label: i18n.t('test_track.plan.plan_stage')}, + {prop: 'testRate', label: i18n.t('test_track.home.test_rate')}, + {prop: 'projectName', label: i18n.t('test_track.plan.plan_project')}, + {prop: 'plannedStartTime', label: i18n.t('test_track.plan.planned_start_time')}, + {prop: 'plannedEndTime', label: i18n.t('test_track.plan.planned_end_time')}, + {prop: 'actualStartTime', label: i18n.t('test_track.plan.actual_start_time')}, + {prop: 'actualEndTime', label: i18n.t('test_track.plan.actual_end_time')}, +] +//接口定义-api列表 +export const Api_List = [ + {prop: 'num', label: "ID"}, + {prop: 'name', label: i18n.t('api_test.definition.api_name')}, + {prop: 'method', label: i18n.t('api_test.definition.api_type')}, + {prop: 'userName', label: i18n.t('api_test.definition.api_principal')}, + {prop: 'path', label: i18n.t('api_test.definition.api_path')}, + {prop: 'tags', label: i18n.t('commons.tag')}, + {prop: 'updateTime', label: i18n.t('api_test.definition.api_last_time')}, + {prop: 'caseTotal', label: i18n.t('api_test.definition.api_case_number')}, + {prop: 'caseStatus', label: i18n.t('api_test.definition.api_case_status')}, + {prop: 'casePassingRate', label: i18n.t('api_test.definition.api_case_passing_rate')}, +] +//接口定义-case列表 +export const Api_Case_List = [ + {prop: 'num', label: "ID"}, + {prop: 'name', label: i18n.t('test_track.case.name')}, + {prop: 'priority', label: i18n.t('test_track.case.priority')}, + {prop: 'path', label: i18n.t('api_test.definition.api_path')}, + {prop: 'tags', label: i18n.t('commons.tag')}, + {prop: 'createUser', label: "创建人"}, + {prop: 'updateTime', label: i18n.t('api_test.definition.api_last_time')}, +] +//接口自动化-场景列表 +export const Api_Scenario_List = [ + {prop: 'num', label: "ID"}, + {prop: 'name', label: i18n.t('test_track.case.name')}, + {prop: 'priority', label: i18n.t('test_track.case.priority')}, + {prop: 'path', label: i18n.t('api_test.definition.api_path')}, + {prop: 'tags', label: i18n.t('commons.tag')}, + {prop: 'createUser', label: '创建人'}, + {prop: 'updateTime', label: i18n.t('api_test.definition.api_last_time')}, +] +//测试评审-测试用例 +export const Test_Case_Review_Case_List = [ + {prop: 'num', label: i18n.t('commons.id')}, + {prop: 'name', label: i18n.t('commons.name')}, + {prop: 'priority', label: i18n.t('test_track.case.priority')}, + {prop: 'type', label: i18n.t('test_track.case.type')}, + {prop: 'method', label: i18n.t('test_track.case.method')}, + {prop: 'nodePath', label: i18n.t('test_track.case.module')}, + {prop: 'projectName', label: i18n.t('test_track.review.review_project')}, + {prop: 'reviewerName', label: i18n.t('test_track.review.reviewer')}, + {prop: 'reviewStatus', label: i18n.t('test_track.case.status')}, + {prop: 'updateTime', label: i18n.t('commons.update_time')}, +] +//测试计划-功能用例 +export const Test_Plan_Function_Test_Case = [ + {prop: 'num', label: i18n.t('commons.id')}, + {prop: 'name', label: i18n.t('commons.name')}, + {prop: 'priority', label: i18n.t('test_track.case.priority')}, + {prop: 'type', label: i18n.t('test_track.case.type')}, + {prop: 'tags', label: i18n.t('commons.tag')}, + {prop: 'method', label: i18n.t('test_track.case.method')}, + {prop: 'nodePath', label: i18n.t('test_track.case.module')}, + {prop: 'projectName', label: i18n.t('test_track.review.review_project')}, + {prop: 'issuesContent', label: i18n.t('test_track.issue.issue')}, + {prop: 'executorName', label: i18n.t('test_track.plan_view.executor')}, + {prop: 'status', label: i18n.t('test_track.plan_view.execute_result')}, + {prop: 'updateTime', label: i18n.t('commons.update_time')}, +] +//测试计划-api用例 +export const Test_Plan_Api_Case = [ + {prop: 'num', label: i18n.t('commons.id')}, + {prop: 'name', label: i18n.t('commons.name')}, + {prop: 'priority', label: i18n.t('test_track.case.priority')}, + {prop: 'path', label: i18n.t('api_test.definition.api_path')}, + {prop: 'createUser', label: '创建人'}, + {prop: 'custom', label: i18n.t('api_test.definition.api_last_time')}, + {prop: 'tags', label: i18n.t('commons.tag')}, + {prop: 'execResult', label: '执行状态'}, +] +//测试计划-性能用例 +export const Test_Plan_Load_Case = [ + {prop: 'num', label: i18n.t('commons.id')}, + {prop: 'caseName', label: i18n.t('commons.name')}, + {prop: 'projectName', label: i18n.t('load_test.project_name')}, + {prop: 'userName', label: i18n.t('load_test.user_name')}, + {prop: 'createTime', label: i18n.t('commons.create_time')}, + {prop: 'status', label: i18n.t('commons.status')}, + {prop: 'caseStatus', label: i18n.t('test_track.plan.load_case.execution_status')}, + {prop: 'loadReportId', label: i18n.t('test_track.plan.load_case.view_report')}, +] +//测试计划-场景用例 +export const Test_Plan_Scenario_Case = [ + {prop: 'num', label: i18n.t('commons.id')}, + {prop: 'name', label: i18n.t('commons.name')}, + {prop: 'level', label: i18n.t('api_test.automation.case_level')}, + {prop: 'tagNames', label: i18n.t('api_test.automation.tag')}, + {prop: 'userId', label: i18n.t('api_test.automation.creator')}, + {prop: 'updateTime', label: i18n.t('api_test.automation.update_time')}, + {prop: 'stepTotal', label: i18n.t('api_test.automation.success')}, + {prop: 'lastResult', label: i18n.t('api_test.automation.fail')}, + {prop: 'passRate', label: i18n.t('api_test.automation.passing_rate')}, +] + diff --git a/frontend/src/business/components/settings/organization/components/BugManageBtn.vue b/frontend/src/business/components/settings/organization/components/BugManageBtn.vue index 2b3e6d2156..691bb567b9 100644 --- a/frontend/src/business/components/settings/organization/components/BugManageBtn.vue +++ b/frontend/src/business/components/settings/organization/components/BugManageBtn.vue @@ -51,6 +51,7 @@ export default { this.showCancel = false; this.showSave = false; this.$emit("update:show", true); + this.$emit("reloadPassInput"); this.init(); }, init() { diff --git a/frontend/src/business/components/settings/organization/components/JiraSetting.vue b/frontend/src/business/components/settings/organization/components/JiraSetting.vue index f3b8145fef..3d99ec85a9 100644 --- a/frontend/src/business/components/settings/organization/components/JiraSetting.vue +++ b/frontend/src/business/components/settings/organization/components/JiraSetting.vue @@ -7,7 +7,7 @@ - @@ -23,6 +23,7 @@ @init="init" @testConnection="testConnection" @cancelIntegration="cancelIntegration" + @reloadPassInput="reloadPassInput" :form="form" :show.sync="show" ref="bugBtn"/> @@ -56,6 +57,7 @@ export default { data() { return { show: true, + showInput: true, form: {}, rules: { account: { @@ -123,6 +125,7 @@ export default { this.$refs.bugBtn.showEdit = true; this.$refs.bugBtn.showSave = false; this.$refs.bugBtn.showCancel = false; + this.reloadPassInput(); this.init(); this.$success(this.$t('commons.save_success')); }); @@ -170,6 +173,12 @@ export default { } else { this.$warning(this.$t('organization.integration.not_integrated')); } + }, + reloadPassInput() { + this.showInput = false; + this.$nextTick(function () { + this.showInput = true; + }); } } } diff --git a/frontend/src/business/components/settings/organization/components/TapdSetting.vue b/frontend/src/business/components/settings/organization/components/TapdSetting.vue index f3cde32739..cc4c757da7 100644 --- a/frontend/src/business/components/settings/organization/components/TapdSetting.vue +++ b/frontend/src/business/components/settings/organization/components/TapdSetting.vue @@ -7,7 +7,7 @@ - @@ -17,6 +17,7 @@ @init="init" @testConnection="testConnection" @cancelIntegration="cancelIntegration" + @reloadPassInput="reloadPassInput" :form="form" :show.sync="show" ref="bugBtn"/> @@ -52,6 +53,7 @@ export default { data() { return { show: true, + showInput: true, form: {}, rules: { account: { @@ -103,6 +105,7 @@ export default { this.$refs.bugBtn.showEdit = true; this.$refs.bugBtn.showSave = false; this.$refs.bugBtn.showCancel = false; + this.reloadPassInput(); this.init(); this.$success(this.$t('commons.save_success')); }); @@ -148,6 +151,12 @@ export default { } else { this.$warning(this.$t('organization.integration.not_integrated')); } + }, + reloadPassInput() { + this.showInput = false; + this.$nextTick(function () { + this.showInput = true; + }); } } } diff --git a/frontend/src/business/components/settings/organization/components/ZentaoSetting.vue b/frontend/src/business/components/settings/organization/components/ZentaoSetting.vue index bbb567b23f..30ee7593a8 100644 --- a/frontend/src/business/components/settings/organization/components/ZentaoSetting.vue +++ b/frontend/src/business/components/settings/organization/components/ZentaoSetting.vue @@ -7,7 +7,7 @@ - @@ -20,6 +20,7 @@ @init="init" @testConnection="testConnection" @cancelIntegration="cancelIntegration" + @reloadPassInput="reloadPassInput" :form="form" :show.sync="show" ref="bugBtn"/> @@ -55,6 +56,7 @@ export default { data() { return { show: true, + showInput: true, form: {}, rules: { account: { @@ -99,6 +101,7 @@ export default { this.$refs.bugBtn.showEdit = true; this.$refs.bugBtn.showSave = false; this.$refs.bugBtn.showCancel = false; + this.reloadPassInput(); this.init(); this.$success(this.$t('commons.save_success')); }); @@ -168,6 +171,12 @@ export default { } else { this.$warning(this.$t('organization.integration.not_integrated')); } + }, + reloadPassInput() { + this.showInput = false; + this.$nextTick(function () { + this.showInput = true; + }); } } } diff --git a/frontend/src/business/components/settings/system/EmailSetting.vue b/frontend/src/business/components/settings/system/EmailSetting.vue index 51c2bae52b..676257411e 100644 --- a/frontend/src/business/components/settings/system/EmailSetting.vue +++ b/frontend/src/business/components/settings/system/EmailSetting.vue @@ -124,7 +124,6 @@ export default { this.formInline = response.data; this.formInline.ssl = this.formInline.ssl === 'true'; this.formInline.tls = this.formInline.tls === 'true'; - console.log(this.formInline) this.$nextTick(() => { this.$refs.formInline.clearValidate(); }) diff --git a/frontend/src/business/components/settings/system/TestResourcePool.vue b/frontend/src/business/components/settings/system/TestResourcePool.vue index 958629e220..2daae39968 100644 --- a/frontend/src/business/components/settings/system/TestResourcePool.vue +++ b/frontend/src/business/components/settings/system/TestResourcePool.vue @@ -105,6 +105,13 @@ + + + + + + +
@@ -243,9 +250,9 @@ export default { if (this.infoList.length <= 0) { return {validate: false, msg: this.$t('test_resource_pool.cannot_empty')} } - + let resourcePoolType = this.form.type; let resultValidate = {validate: true, msg: this.$t('test_resource_pool.fill_the_data')}; - this.infoList.forEach(function (info) { + this.infoList.forEach(info => { for (let key in info) { if (info[key] != '0' && !info[key]) { resultValidate.validate = false @@ -257,6 +264,13 @@ export default { resultValidate.validate = false return false; } + if (resourcePoolType === 'K8S' && info.nodeSelector) { + let validate = this.isJsonString(info.nodeSelector); + if (!validate) { + resultValidate.validate = false; + resultValidate.msg = this.$t('test_resource_pool.node_selector_invalid'); + } + } }); return resultValidate; @@ -380,6 +394,16 @@ export default { row.status = 'INVALID'; this.result.loading = false; }) + }, + isJsonString(str) { + try { + if (typeof JSON.parse(str) == "object") { + return true; + } + } catch (e) { + console.log('json invalid'); + } + return false; } } } diff --git a/frontend/src/business/components/track/case/components/TestCaseList.vue b/frontend/src/business/components/track/case/components/TestCaseList.vue index 0ba9451af8..50770b40b2 100644 --- a/frontend/src/business/components/track/case/components/TestCaseList.vue +++ b/frontend/src/business/components/track/case/components/TestCaseList.vue @@ -34,135 +34,157 @@ row-key="id" class="test-content adjust-table ms-select-all-fixed" ref="table" @row-click="handleEdit"> - + :page-size="pageSize > total ? total : pageSize" + :total="total" + @selectPageAll="isSelectDataAll(false)" + @selectAll="isSelectDataAll(true)"/> - - - - - - - - - - - - - - + + + + + + - - -
+ diff --git a/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseList.vue b/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseList.vue index a4da33838a..f8172fc9d7 100644 --- a/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseList.vue +++ b/frontend/src/business/components/track/plan/view/comonents/functional/FunctionalTestCaseList.vue @@ -45,134 +45,146 @@
- + + + + + + + - show-overflow-tooltip> - - + + - show-overflow-tooltip> -
- + + - :label="$t('test_track.case.priority')"> - -
+ + + - + - show-overflow-tooltip> - -
+ + - - - - - - - - - - - - - - - - - + + + - + - column-key="executor" - :label="$t('test_track.plan_view.executor')"> - - - - + - - - + sortable + prop="updateTime" + :label="$t('commons.update_time')" + min-width="120px" + :key="index" + show-overflow-tooltip> + + + +
- + @@ -249,8 +270,15 @@ import MsTableHeader from '../../../../../common/components/MsTableHeader'; import MsTableButton from '../../../../../common/components/MsTableButton'; import NodeBreadcrumb from '../../../../common/NodeBreadcrumb'; -import {ROLE_TEST_MANAGER, ROLE_TEST_USER, TokenKey, WORKSPACE_ID} from "@/common/js/constants"; -import {checkoutTestManagerOrTestUser, hasRoles} from "@/common/js/utils"; +import { + ROLE_TEST_MANAGER, + ROLE_TEST_USER, + TEST_CASE_LIST, + TEST_PLAN_FUNCTION_TEST_CASE, + TokenKey, + WORKSPACE_ID +} from "@/common/js/constants"; +import {checkoutTestManagerOrTestUser, getCurrentUser, hasRoles} from "@/common/js/utils"; import PriorityTableItem from "../../../../common/tableItems/planview/PriorityTableItem"; import StatusTableItem from "../../../../common/tableItems/planview/StatusTableItem"; import TypeTableItem from "../../../../common/tableItems/planview/TypeTableItem"; @@ -264,11 +292,14 @@ import ClassicEditor from "@ckeditor/ckeditor5-build-classic"; import {hub} from "@/business/components/track/plan/event-bus"; import MsTag from "@/business/components/common/components/MsTag"; import {_filter, _sort} from "@/common/js/tableUtils"; +import HeaderCustom from "@/business/components/common/head/HeaderCustom"; +import {Test_Plan_Function_Test_Case} from "@/business/components/common/model/JsonData"; export default { name: "FunctionalTestCaseList", components: { + HeaderCustom, FunctionalTestCaseEdit, MsTableOperatorButton, MsTableOperator, @@ -281,6 +312,9 @@ export default { }, data() { return { + type: TEST_PLAN_FUNCTION_TEST_CASE, + headerItems: Test_Plan_Function_Test_Case, + tableLabel: Test_Plan_Function_Test_Case, result: {}, deletePath: "/test/case/delete", condition: { @@ -383,7 +417,12 @@ export default { hub.$off("openFailureTestCase"); }, methods: { + customHeader() { + this.$refs.headerCustom.open(this.tableLabel) + }, + initTableData() { + this.getLabel() if (this.planId) { // param.planId = this.planId; this.condition.planId = this.planId; @@ -428,6 +467,24 @@ export default { }); } }, + getLabel() { + let param = {} + param.userId = getCurrentUser().id; + param.type = TEST_PLAN_FUNCTION_TEST_CASE + this.result = this.$post('/system/header/info', param, response => { + if (response.data != null) { + let arry = eval(response.data.props); + let obj = {}; + for (let key in arry) { + obj[key] = arry[key]; + } + let newObj = Object.keys(obj).map(val => ({ + prop: obj[val] + })) + this.tableLabel = newObj + } + }) + }, showDetail(row, event, column) { this.isReadOnly = true; this.$refs.testPlanTestCaseEdit.openTestCaseEdit(row); @@ -596,9 +653,9 @@ export default { _sort(column, this.condition); this.initTableData(); }, - headerDragend(newWidth,oldWidth,column,event){ + headerDragend(newWidth, oldWidth, column, event) { let finalWidth = newWidth; - if(column.minWidth>finalWidth){ + if (column.minWidth > finalWidth) { finalWidth = column.minWidth; } column.width = finalWidth; diff --git a/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue b/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue index 199c8d4bb7..e6a7edda19 100644 --- a/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue +++ b/frontend/src/business/components/track/plan/view/comonents/load/TestPlanLoadCaseList.vue @@ -3,10 +3,10 @@ @@ -23,69 +23,89 @@ - - - - - - - - - - - - - - - - - - - - + + - - - - - - - + + :label="$t('commons.operating')" + > + + @@ -169,16 +202,24 @@ import MsTableButton from "../../../../common/components/MsTableButton"; import ShowMoreBtn from "../../../case/components/ShowMoreBtn"; import BatchEdit from "../../../case/components/BatchEdit"; import MsTablePagination from '../../../../common/pagination/TablePagination'; -import {checkoutTestManagerOrTestUser, hasRoles} from "../../../../../../common/js/utils"; +import {checkoutTestManagerOrTestUser, getCurrentUser, hasRoles} from "../../../../../../common/js/utils"; import {TEST_CASE_CONFIGS} from "../../../../common/components/search/search-components"; -import {ROLE_TEST_MANAGER, ROLE_TEST_USER} from "../../../../../../common/js/constants"; +import { + ROLE_TEST_MANAGER, + ROLE_TEST_USER, + TEST_CASE_LIST, + TEST_CASE_REVIEW_CASE_LIST, TEST_PLAN_LIST +} from "../../../../../../common/js/constants"; import TestReviewTestCaseEdit from "./TestReviewTestCaseEdit"; import ReviewStatus from "@/business/components/track/case/components/ReviewStatus"; import {_filter, _sort} from "@/common/js/tableUtils"; +import HeaderCustom from "@/business/components/common/head/HeaderCustom"; +import {Test_Case_Review_Case_List, Track_Test_Case} from "@/business/components/common/model/JsonData"; export default { name: "TestReviewTestCaseList", components: { + HeaderCustom, MsTableOperatorButton, MsTableOperator, MethodTableItem, TypeTableItem, StatusTableItem, PriorityTableItem, StatusEdit, ExecutorEdit, MsTipButton, TestReviewTestCaseEdit, MsTableHeader, @@ -186,6 +227,9 @@ export default { }, data() { return { + type: TEST_CASE_REVIEW_CASE_LIST, + headerItems: Test_Case_Review_Case_List, + tableLabel: Test_Case_Review_Case_List, result: {}, condition: {}, tableData: [], @@ -261,7 +305,11 @@ export default { this.isTestManagerOrTestUser = checkoutTestManagerOrTestUser(); }, methods: { + customHeader() { + this.$refs.headerCustom.open(this.tableLabel) + }, initTableData() { + this.getLabel() if (this.reviewId) { this.condition.reviewId = this.reviewId; } @@ -275,6 +323,24 @@ export default { }); } }, + getLabel() { + let param = {} + param.userId = getCurrentUser().id; + param.type = TEST_CASE_REVIEW_CASE_LIST + this.result = this.$post('/system/header/info', param, response => { + if (response.data != null) { + let arry = eval(response.data.props); + let obj = {}; + for (let key in arry) { + obj[key] = arry[key]; + } + let newObj = Object.keys(obj).map(val => ({ + prop: obj[val] + })) + this.tableLabel = newObj + } + }) + }, showDetail(row, event, column) { this.isReadOnly = true; this.$refs.testReviewTestCaseEdit.openTestCaseEdit(row); diff --git a/frontend/src/business/components/xpack b/frontend/src/business/components/xpack index a3d469fd18..4cc8926bad 160000 --- a/frontend/src/business/components/xpack +++ b/frontend/src/business/components/xpack @@ -1 +1 @@ -Subproject commit a3d469fd18f663d11e5c1c49f71ced6e3e4b292f +Subproject commit 4cc8926bad84083f675a262d6766a92bb09a890a diff --git a/frontend/src/common/js/constants.js b/frontend/src/common/js/constants.js index 33e7a474a3..ef3c5f4610 100644 --- a/frontend/src/common/js/constants.js +++ b/frontend/src/common/js/constants.js @@ -1,3 +1,15 @@ +export const TEST_CASE_LIST = 'test_case_list' +export const TEST_CASE_REVIEW_LIST = 'test_case_review_list' +export const API_LIST = 'api_list' +export const API_CASE_LIST = 'api_case_list' +export const API_SCENARIO_LIST = 'api_scenario_list' +export const TEST_CASE_REVIEW_CASE_LIST = 'test_case_review_case_list' +export const TEST_PLAN_LIST = 'test_plan_list' +export const TEST_PLAN_FUNCTION_TEST_CASE = 'test_plan_function_test_case' +export const TEST_PLAN_API_CASE = 'test_plan_api_case' +export const TEST_PLAN_LOAD_CASE = 'test_plan_load_case' +export const TEST_PLAN_SCENARIO_CASE = 'test_plan_scenario_case' + export const TokenKey = 'Admin-Token'; export const LicenseKey = 'License'; export const DEFAULT_LANGUAGE = 'default_language'; diff --git a/frontend/src/common/js/cron.js b/frontend/src/common/js/cron.js index 5d60e3dd18..0c8f6184b0 100644 --- a/frontend/src/common/js/cron.js +++ b/frontend/src/common/js/cron.js @@ -79,8 +79,8 @@ function checkField(secondsField, minimal, maximal) { try { var startVal = parseInt(startValue, 10); var endVal = parseInt(endValue, 10); - - return endVal > startVal; + //return endVal > startVal; + return true; } catch (e) { return false; } diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 0203ccccd9..806e4f0f80 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -674,7 +674,8 @@ export default { select_principal: "Select principal", follow_people: "Follow people", select_table: "Select table", - select_all: "Select all" + select_all: "Select all", + check_case: "Please check the Scene Use Case" }, report_name_info: 'Please enter the registration name', save_case_info: 'Please save the use case first', @@ -1353,6 +1354,7 @@ export default { status_change_success: 'Successfully changed the status!', status_change_failed: 'Failed to change the status, resource pool is invalid!', check_in: 'Check in', + node_selector_invalid: 'nodeSelector must be JSON' }, system_parameter_setting: { mailbox_service_settings: 'Mailbox Settings', diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index 2a10360dbe..d841583b0b 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -1,7 +1,7 @@ export default { commons: { - cover:'覆盖', - not_cover:'不覆盖', + cover: '覆盖', + not_cover: '不覆盖', import_mode: '导入模式', import_module: '导入模块', please_fill_in_the_template: '请填写模版内容', @@ -592,7 +592,7 @@ export default { create_info: '创建', update_info: '更新', batch_edit: "批量编辑", - batch_move:"批量移动", + batch_move: "批量移动", path_valid_info: "请求路径无效", other_config: "其他设置", message_template: "报文模版", @@ -675,7 +675,8 @@ export default { select_principal: "请选择责任人", follow_people: "关注人", select_table: "选择可见数据", - select_all: "选择全部数据" + select_all: "选择全部数据", + check_case: "请勾选场景用例" }, report_name_info: '请输入报告名称', save_case_info: '请先保存用例', @@ -1357,6 +1358,7 @@ export default { status_change_success: '状态修改成功!', status_change_failed: '状态修改失败, 校验不通过!', check_in: '校验中', + node_selector_invalid: 'nodeSelector 必须是有效的JSON' }, system_parameter_setting: { mailbox_service_settings: '邮件设置', diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index a27366c00c..790349838c 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -1,7 +1,7 @@ export default { commons: { - cover:'覆蓋', - not_cover:'不覆蓋', + cover: '覆蓋', + not_cover: '不覆蓋', import_mode: '導入模式', import_module: '導入模塊', please_fill_in_the_template: '請填寫模版內容', @@ -591,7 +591,7 @@ export default { create_info: '創建', update_info: '更新', batch_edit: "批量編輯", - batch_move:"批量移動", + batch_move: "批量移動", path_valid_info: "請求路徑無效", other_config: "其他設置", message_template: "報文模版", @@ -674,7 +674,8 @@ export default { select_principal: "請選擇責任人", follow_people: "關註人", select_table: "選擇可見數據", - select_all: "選擇全部數據" + select_all: "選擇全部數據", + check_case: "請勾選場景用例" }, report_name_info: '請輸入報告名稱', save_case_info: '請先保存用例', @@ -1355,6 +1356,7 @@ export default { status_change_success: '狀態修改成功!', status_change_failed: '狀態修改失敗, 校驗不通過!', check_in: '校驗中', + node_selector_invalid: 'nodeSelector 必須是有效的JSON' }, system_parameter_setting: { mailbox_service_settings: '郵件設置',