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 db1b73d8f6..3a824bc6c1 100644 --- a/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java +++ b/backend/src/main/java/io/metersphere/api/controller/ApiAutomationController.java @@ -117,6 +117,12 @@ public class ApiAutomationController { apiAutomationService.bathEdit(request); } + @PostMapping("/batch/update/env") + @RequiresRoles(value = {RoleConstants.TEST_USER, RoleConstants.TEST_MANAGER}, logical = Logical.OR) + public void batchUpdateEnv(@RequestBody ApiScenarioBatchRequest request) { + apiAutomationService.batchUpdateEnv(request); + } + @PostMapping("/getReference") public ReferenceDTO getReference(@RequestBody ApiScenarioRequest request) { return apiAutomationService.getReference(request); 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 index 61466418c8..c1cde85378 100644 --- a/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioBatchRequest.java +++ b/backend/src/main/java/io/metersphere/api/dto/automation/ApiScenarioBatchRequest.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.Setter; import java.util.List; +import java.util.Map; @Getter @Setter @@ -15,4 +16,14 @@ public class ApiScenarioBatchRequest extends ApiScenarioWithBLOBs { private String environmentId; private ApiScenarioRequest condition; + + /** + * 环境和项目对应关系 + */ + private Map envMap; + + /** + * 场景用例跨项目的关系 + */ + private Map> mapping; } 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 e1e3f6ed8c..cc63e40754 100644 --- a/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java +++ b/backend/src/main/java/io/metersphere/api/service/ApiAutomationService.java @@ -90,9 +90,28 @@ public class ApiAutomationService { public List list(ApiScenarioRequest request) { request = this.initRequest(request, true, true); List list = extApiScenarioMapper.list(request); + setApiScenarioProjectIds(list); return list; } + private void setApiScenarioProjectIds(List list) { + // 如果场景步骤涉及多项目,则把涉及到的项目ID保存在projectIds属性 + list.forEach(data -> { + String definition = data.getScenarioDefinition(); + RunDefinitionRequest d = JSON.parseObject(definition, RunDefinitionRequest.class); + Map map = d.getEnvironmentMap(); + List idList = new ArrayList<>(); + if (map != null) { + Set set = d.getEnvironmentMap().keySet(); + idList = new ArrayList<>(set); + } else { + // 兼容历史数据,无EnvironmentMap直接赋值场景所属项目 + idList.add(data.getProjectId()); + } + data.setProjectIds(idList); + }); + } + /** * 初始化部分参数 * @@ -908,4 +927,28 @@ public class ApiAutomationService { return resList; } + public void batchUpdateEnv(ApiScenarioBatchRequest request) { + Map envMap = request.getEnvMap(); + Map> mapping = request.getMapping(); + Set set = mapping.keySet(); + if (set.isEmpty()) { return; } + set.forEach(id -> { + Map newEnvMap = new HashMap<>(16); + if (envMap != null && !envMap.isEmpty()) { + List list = mapping.get(id); + list.forEach(l -> { + newEnvMap.put(l, envMap.get(l)); + }); + } + if (!newEnvMap.isEmpty()) { + ApiScenarioWithBLOBs scenario = apiScenarioMapper.selectByPrimaryKey(id); + String definition = scenario.getScenarioDefinition(); + JSONObject object = JSON.parseObject(definition); + object.put("environmentMap", newEnvMap); + String newDefinition = JSON.toJSONString(object); + scenario.setScenarioDefinition(newDefinition); + apiScenarioMapper.updateByPrimaryKeySelective(scenario); + } + }); + } } 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 b9a23d4301..ae2cca7a78 100644 --- a/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java +++ b/backend/src/main/java/io/metersphere/track/service/TestPlanScenarioCaseService.java @@ -59,9 +59,8 @@ public class TestPlanScenarioCaseService { Set set = d.getEnvironmentMap().keySet(); idList = new ArrayList<>(set); } else { - if (org.apache.commons.lang3.StringUtils.isNotBlank(d.getEnvironmentId())) { - idList.add(d.getEnvironmentId()); - } + // 兼容历史数据,无EnvironmentMap直接赋值场景所属项目 + idList.add(data.getProjectId()); } data.setProjectIds(idList); }); diff --git a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue index 2e459cc76e..6bb9514153 100644 --- a/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue +++ b/frontend/src/business/components/api/automation/scenario/ApiScenarioList.vue @@ -151,9 +151,6 @@ - @@ -166,7 +163,7 @@ import MsTablePagination from "@/business/components/common/pagination/TablePagination"; import ShowMoreBtn from "@/business/components/track/case/components/ShowMoreBtn"; import MsTag from "../../../common/components/MsTag"; - import {downloadFile, getCurrentProjectID, getCurrentUser, getUUID} from "@/common/js/utils"; + import {downloadFile, getCurrentProjectID, getCurrentUser, getUUID, strMapToObj} from "@/common/js/utils"; import MsApiReportDetail from "../report/ApiReportDetail"; import MsTableMoreBtn from "./TableMoreBtn"; import MsScenarioExtendButtons from "@/business/components/api/automation/scenario/ScenarioExtendBtns"; @@ -288,7 +285,8 @@ {id: 'level', name: this.$t('test_track.case.priority')}, {id: 'status', name: this.$t('test_track.plan.plan_status')}, {id: 'principal', name: this.$t('api_test.definition.request.responsible'), optionMethod: this.getPrincipalOptions}, - {id: 'environmentId', name: this.$t('api_test.definition.request.run_env'), optionMethod: this.getEnvsOptions}, + // {id: 'environmentId', name: this.$t('api_test.definition.request.run_env'), optionMethod: this.getEnvsOptions}, + {id: 'projectEnv', name: this.$t('api_test.definition.request.run_env')}, ], statusFilters: [ {text: this.$t('test_track.plan.plan_status_prepare'), value: 'Prepare'}, @@ -319,7 +317,8 @@ {name: this.$t('test_track.plan.plan_status_completed'), id: 'Completed'} ], principal: [], - environmentId: [] + environmentId: [], + projectEnv: [] }, } }, @@ -432,6 +431,7 @@ }, handleBatchEdit() { this.$refs.batchEdit.open(this.selectDataCounts); + this.$refs.batchEdit.setScenarioSelectRows(this.selectRows); }, handleBatchMove() { this.$refs.testBatchMove.open(this.moduleTree, [], this.moduleOptions); @@ -446,13 +446,31 @@ }); }, batchEdit(form) { - let param = {}; - param[form.type] = form.value; - this.buildBatchParam(param); - this.$post('/api/automation/batch/edit', param, () => { - this.$success(this.$t('commons.save_success')); - this.search(); - }); + // 批量修改环境 + if (form.type === 'projectEnv') { + let param = {}; + let map = new Map(); + this.selectRows.forEach(row => { + map.set(row.id, row.projectIds); + }) + param.mapping = strMapToObj(map); + param.envMap = strMapToObj(form.projectEnvMap); + this.$post('/api/automation/batch/update/env', param, () => { + this.$success(this.$t('commons.save_success')); + this.search(); + }) + } else { + // 批量修改其它 + let param = {}; + param[form.type] = form.value; + this.buildBatchParam(param); + this.$post('/api/automation/batch/edit', param, () => { + this.$success(this.$t('commons.save_success')); + this.search(); + }); + } + + }, getPrincipalOptions(option) { let workspaceId = localStorage.getItem(WORKSPACE_ID); diff --git a/frontend/src/business/components/api/definition/components/document/ApiDocumentItem.vue b/frontend/src/business/components/api/definition/components/document/ApiDocumentItem.vue index 402ed5338a..bfd3dbb8de 100644 --- a/frontend/src/business/components/api/definition/components/document/ApiDocumentItem.vue +++ b/frontend/src/business/components/api/definition/components/document/ApiDocumentItem.vue @@ -24,7 +24,8 @@ - + +
@@ -300,6 +301,7 @@ export default { shareUrl:"", batchShareUrl:"", apiStepIndex: 0, + showXpackCompnent:false, apiInfoArray: [], modes: ['text', 'json', 'xml', 'html'], formParamTypes: ['form-data', 'x-www-from-urlencoded', 'BINARY'], @@ -349,6 +351,9 @@ export default { } }, created: function () { + if(requireComponent!=null && JSON.stringify(apiDocumentBatchShare) != '{}'){ + this.showXpackCompnent = true; + } this.initApiDocSimpleList(); this.clientHeight = `${document.documentElement.clientHeight}`;//获取浏览器可视区域高度 let that = this; @@ -601,7 +606,6 @@ export default { } if(apiInfo == null || !apiInfo.selectedFlag){ let apiId = apiInfo.id; - console.log(apiInfo.isSearching+":"+apiId); if(!apiInfo.isSearching){ apiInfo.isSearching = true; this.selectApiInfo(beforeIndex,apiId); @@ -616,7 +620,6 @@ export default { } if(apiInfo == null || !apiInfo.selectedFlag){ let apiId = apiInfo.id; - console.log(apiInfo.isSearching+":"+apiId); if(!apiInfo.isSearching) { apiInfo.isSearching = true; this.selectApiInfo(afterIndex,apiId); diff --git a/frontend/src/business/components/track/case/components/BatchEdit.vue b/frontend/src/business/components/track/case/components/BatchEdit.vue index 901e9f3dc1..89070b4556 100644 --- a/frontend/src/business/components/track/case/components/BatchEdit.vue +++ b/frontend/src/business/components/track/case/components/BatchEdit.vue @@ -97,6 +97,7 @@ }, open(size) { this.dialogVisible = true; + this.projectEnvMap.clear(); if (size) { this.size = size; } else {