style(批量执行弹窗):批量执行弹窗样式修改

--user=郭雨琦
This commit is contained in:
guoyuqi 2022-11-10 18:49:41 +08:00 committed by xiaomeinvG
parent 2e9168535d
commit 5238a86e22
15 changed files with 607 additions and 324 deletions

View File

@ -92,6 +92,11 @@ public class ApiTestCaseController {
return apiTestCaseService.getApiCaseEnvironment(caseId); return apiTestCaseService.getApiCaseEnvironment(caseId);
} }
@PostMapping("/get/env")
public Map<String, String> getApiCaseEnvironments(@RequestBody List<String> caseIds) {
return apiTestCaseService.getApiCaseEnvironments(caseIds);
}
@PostMapping("/list-blobs") @PostMapping("/list-blobs")
public List<ApiTestCaseInfo> getCaseBLOBs(@RequestBody ApiTestCaseRequest request) { public List<ApiTestCaseInfo> getCaseBLOBs(@RequestBody ApiTestCaseRequest request) {
List<ApiTestCaseInfo> returnList = apiTestCaseService.findApiTestCaseBLOBs(request); List<ApiTestCaseInfo> returnList = apiTestCaseService.findApiTestCaseBLOBs(request);

View File

@ -36,6 +36,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
@RestController @RestController
@RequestMapping(value = "/api/automation") @RequestMapping(value = "/api/automation")
@ -417,6 +418,10 @@ public class ApiScenarioController {
public List<String> getEnvProjects(@RequestBody RunScenarioRequest request) { public List<String> getEnvProjects(@RequestBody RunScenarioRequest request) {
return apiAutomationService.getProjects(request); return apiAutomationService.getProjects(request);
} }
@PostMapping(value = "/env/map")
public Map<String, List<String>> getProjectEnvMap(@RequestBody RunScenarioRequest request) {
return apiAutomationService.getProjectEnvMap(request);
}
/** /**
* 统计场景用例 * 统计场景用例

View File

@ -1055,12 +1055,15 @@ public class ApiTestCaseService {
} }
public Map<String, String> getApiCaseEnvironments(List<String> caseIds) { public Map<String, String> getApiCaseEnvironments(List<String> caseIds) {
if (CollectionUtils.isEmpty(caseIds)){
return null;
}
List<ParamsDTO> environments = extApiTestCaseMapper.getApiCaseEnvironments(caseIds); List<ParamsDTO> environments = extApiTestCaseMapper.getApiCaseEnvironments(caseIds);
if (CollectionUtils.isEmpty(environments)) { if (CollectionUtils.isEmpty(environments)) {
return null; return null;
} }
try { try {
List<String> envIds = environments.stream().map(ParamsDTO::getValue).collect(Collectors.toList()); List<String> envIds = environments.stream().filter(t->StringUtils.isNotBlank(t.getValue()) && !StringUtils.equalsIgnoreCase(t.getValue(),"null")).map(ParamsDTO::getValue).collect(Collectors.toList());
ApiTestEnvironmentExample example = new ApiTestEnvironmentExample(); ApiTestEnvironmentExample example = new ApiTestEnvironmentExample();
example.createCriteria().andIdIn(envIds); example.createCriteria().andIdIn(envIds);
List<ApiTestEnvironment> environmentList = apiTestEnvironmentMapper.selectByExample(example); List<ApiTestEnvironment> environmentList = apiTestEnvironmentMapper.selectByExample(example);
@ -1069,7 +1072,7 @@ public class ApiTestCaseService {
} }
Map<String, String> envMap = environmentList.stream().collect(Collectors.toMap(ApiTestEnvironment::getId, ApiTestEnvironment::getName)); Map<String, String> envMap = environmentList.stream().collect(Collectors.toMap(ApiTestEnvironment::getId, ApiTestEnvironment::getName));
Map<String, String> caseEnvMap = environments.stream().collect(HashMap::new, (m, v) -> m.put(v.getId(), v.getValue()), HashMap::putAll); Map<String, String> caseEnvMap = environments.stream().filter(t->StringUtils.isNotBlank(t.getValue()) && !StringUtils.equalsIgnoreCase(t.getValue(),"null")).collect(HashMap::new, (m, v) -> m.put(v.getId(), v.getValue()), HashMap::putAll);
caseEnvMap.forEach((k, v) -> { caseEnvMap.forEach((k, v) -> {
if (envMap.containsKey(v)) { if (envMap.containsKey(v)) {
caseEnvMap.put(k, envMap.get(v)); caseEnvMap.put(k, envMap.get(v));

View File

@ -2219,4 +2219,36 @@ public class ApiScenarioService {
return extApiScenarioMapper.selectBaseCaseByProjectId(projectId); return extApiScenarioMapper.selectBaseCaseByProjectId(projectId);
} }
public Map<String, List<String>> getProjectEnvMap(RunScenarioRequest request) {
ServiceUtils.getSelectAllIds(request, request.getCondition(), (query) -> extApiScenarioMapper.selectIdsByQuery(query));
List<String> ids = request.getIds();
ApiScenarioExample example = new ApiScenarioExample();
example.createCriteria().andIdIn(ids);
List<ApiScenarioWithBLOBs> apiScenarios = apiScenarioMapper.selectByExampleWithBLOBs(example);
Map<String, List<String>> projectEnvMap = new HashMap<>();
apiScenarios.forEach(item -> {
if (StringUtils.isNotBlank(item.getEnvironmentJson())){
JSONObject jsonObject = JSONUtil.parseObject(item.getEnvironmentJson());
Map<String, Object> projectIdEnvMap = jsonObject.toMap();
if (MapUtils.isNotEmpty(projectIdEnvMap)) {
Set<String> projectIds = projectIdEnvMap.keySet();
projectIds.forEach(t->{
List<String> envIds = projectEnvMap.get(t);
if (CollectionUtils.isNotEmpty(envIds)) {
if (!envIds.contains(projectIdEnvMap.get(t).toString())) {
envIds.add(projectIdEnvMap.get(t).toString());
}
} else {
Object o = projectIdEnvMap.get(t);
List<String>envIdList = new ArrayList<>();
envIdList.add(o.toString());
projectEnvMap.put(t,envIdList);
}
});
}
}
});
return projectEnvMap;
}
} }

View File

@ -0,0 +1,7 @@
import {get, post} from "metersphere-frontend/src/plugins/request"
const BASE_URL = '/environment/';
export function getEnvironmentByProjectId(projectId) {
return get(BASE_URL + `list/${projectId}`);
}

View File

@ -85,3 +85,7 @@ export function editApiCase(url, file, files, params) {
export function apiTestCaseCount(param) { export function apiTestCaseCount(param) {
return post('/api/testcase/case-count',param); return post('/api/testcase/case-count',param);
} }
export function getApiCaseEnvironments(param) {
return post('/api/testcase/get/env',param);
}

View File

@ -74,6 +74,10 @@ export function apiScenarioEnv(params) {
return post('/api/automation/env', params); return post('/api/automation/env', params);
} }
export function apiScenarioEnvMap(params) {
return post('/api/automation/env/map', params);
}
export function getApiScenarioProjectIdByConditions(params) { export function getApiScenarioProjectIdByConditions(params) {
return post('/api/automation/list-project-ids', params); return post('/api/automation/list-project-ids', params);
} }

View File

@ -299,11 +299,12 @@
<batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr" <batch-edit ref="batchEdit" @batchEdit="batchEdit" :typeArr="typeArr" :value-arr="valueArr"
:dialog-title="$t('test_track.case.batch_edit_case')"/> :dialog-title="$t('test_track.case.batch_edit_case')"/>
<batch-move @refresh="search" @moveSave="moveSave" ref="testBatchMove"/> <batch-move @refresh="search" @moveSave="moveSave" ref="testBatchMove"/>
<ms-run-mode <ms-api-run-mode
:request="runRequest" :request="runRequest"
:project-id="projectId"
@close="search" @close="search"
@handleRunBatch="handleRunBatch" @handleRunBatch="handleRunBatch"
ref="runMode"/> ref="apiBatchRun"/>
<ms-run :debug="true" :environment="projectEnvMap" <ms-run :debug="true" :environment="projectEnvMap"
:reportId="reportId" :reportId="reportId"
:saved="true" :saved="true"
@ -377,6 +378,7 @@ import {REPORT_STATUS} from "@/business/commons/js/commons";
import {usePerformanceStore} from "@/store"; import {usePerformanceStore} from "@/store";
import {request} from "metersphere-frontend/src/plugins/request" import {request} from "metersphere-frontend/src/plugins/request"
import {parseEnvironment} from "@/business/environment/model/EnvironmentModel"; import {parseEnvironment} from "@/business/environment/model/EnvironmentModel";
import MsApiRunMode from "@/business/automation/scenario/common/ApiRunMode";
const performanceStore = usePerformanceStore(); const performanceStore = usePerformanceStore();
export default { export default {
@ -389,6 +391,7 @@ export default {
MsTableColumn, MsTableColumn,
HeaderLabelOperate, HeaderLabelOperate,
MsSearch, MsSearch,
MsApiRunMode,
MsApiReportStatus: () => import("../report/ApiReportStatus"), MsApiReportStatus: () => import("../report/ApiReportStatus"),
HeaderCustom: () => import("metersphere-frontend/src/components/head/HeaderCustom"), HeaderCustom: () => import("metersphere-frontend/src/components/head/HeaderCustom"),
BatchMove: () => import("@/business/commons/BatchMove"), BatchMove: () => import("@/business/commons/BatchMove"),
@ -407,7 +410,6 @@ export default {
MsScenarioExtendButtons: () => import("@/business/automation/scenario/ScenarioExtendBtns"), MsScenarioExtendButtons: () => import("@/business/automation/scenario/ScenarioExtendBtns"),
MsTestPlanList: () => import("./testplan/TestPlanList"), MsTestPlanList: () => import("./testplan/TestPlanList"),
MsTableOperatorButton: () => import("metersphere-frontend/src/components/MsTableOperatorButton"), MsTableOperatorButton: () => import("metersphere-frontend/src/components/MsTableOperatorButton"),
MsRunMode: () => import("./common/RunMode"),
MsTaskCenter: () => import("metersphere-frontend/src/components/task/TaskCenter"), MsTaskCenter: () => import("metersphere-frontend/src/components/task/TaskCenter"),
MsRun: () => import("./DebugRun"), MsRun: () => import("./DebugRun"),
MxRelationshipGraphDrawer: () => import("metersphere-frontend/src/components/graph/MxRelationshipGraphDrawer") MxRelationshipGraphDrawer: () => import("metersphere-frontend/src/components/graph/MxRelationshipGraphDrawer")
@ -1002,8 +1004,9 @@ export default {
run.projectId = this.projectId; run.projectId = this.projectId;
run.condition = this.condition; run.condition = this.condition;
this.runRequest = run; this.runRequest = run;
this.$refs.runMode.open(); this.$nextTick(() => {
this.$refs.apiBatchRun.open();
});
}, },
openSchedule(row) { openSchedule(row) {
let run = {}; let run = {};
@ -1393,9 +1396,6 @@ export default {
jmxObj.version = item.version; jmxObj.version = item.version;
jmxObjList.push(jmxObj); jmxObjList.push(jmxObj);
}); });
console.info("000000000");
console.info(jmxObjList);
console.info("000000000");
performanceStore.$patch({ performanceStore.$patch({
'scenarioJmxs': { 'scenarioJmxs': {
name: 'Scenarios', name: 'Scenarios',

View File

@ -0,0 +1,180 @@
<template>
<div>
<div v-for="(pe, pIndex) in eventData" :key="pe.id">
<el-card shadow="never" style="margin-top: 8px;background: #F5F6F7;border-radius: 4px;">
<i @click="expandCard(pIndex)" v-if="pe.expendStatus==='close'" class="el-icon-caret-right" style="color: var(--primary_color)"/>
<i @click="expandCard(pIndex)" v-else class="el-icon-caret-bottom" style="color: var(--primary_color)"/>
<span class="project-name" :title="getProjectName(pe.id)">
{{ getProjectName(pe.id) }}
</span><br/>
<div v-if="pe.expendStatus==='open'">
<el-radio-group v-model="pe.envRadio" style="width: 100%;" @change="envRadioChange(pe.envRadio,pIndex)" class="radio-change">
<el-radio label="DEFAULT_ENV" style="margin-top: 7px">{{$t('api_test.environment.default_environment') }}</el-radio>
<el-radio label="CUSTOMIZE_ENV" style="margin-top: 7px">{{$t('api_test.environment.choose_new_environment')}}</el-radio>
</el-radio-group>
<el-tag v-show="!pe.showEnvSelect" v-for="(itemName,index) in selectedEnvName.get(pe.id)" :key="index" size="mini"
style="margin-left: 0; margin-right: 2px;margin-top: 8px">{{ itemName }}</el-tag>
<el-select v-show="pe.showEnvSelect" v-model="pe['selectEnv']" :placeholder="$t('api_test.environment.select_environment')"
style="margin-top: 8px;width: 100%;" size="small" @change="chooseEnv">
<el-option v-for="(environment, index) in pe.envs" :key="index"
:label="environment.name"
:value="environment.id"/>
</el-select>
</div>
</el-card>
</div>
</div>
</template>
<script>
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
import {environmentGetALL} from "metersphere-frontend/src/api/environment";
import MsTag from "metersphere-frontend/src/components/MsTag";
import {parseEnvironment} from "metersphere-frontend/src/model/EnvironmentModel";
import {getEnvironmentByProjectId} from "@/api/api-environment";
export default {
name: "EnvSelectPopover",
components: {MsTag},
data(){
return {
radio:ENV_TYPE.JSON,
visible: false,
groups:[],
selectedEnvName:new Map(),
showEnvName:false,
eventData:[],
evnList:[],
selectEnvMap:new Map(),
}
},
computed: {
ENV_TYPE() {
return ENV_TYPE;
}
},
props:{
projectIds: Set,
projectList:Array,
projectEnvMap:Object,
caseIdEnvNameMap:Object,
envMap: Map,
groupId: {
type: String,
default() {
return "";
}
},
isScenario: {
type: Boolean,
default: true
}
},
methods: {
open(){
this.initDefaultEnv();
this.getgroups();
},
radioChange(val){
this.radio = val;
},
getProjectName(id) {
const project = this.projectList.find(p => p.id === id);
return project ? project.name : "";
},
envRadioChange(val,index){
this.eventData[index].envRadio = val
this.eventData[index].showEnvSelect = this.eventData[index].envRadio === "CUSTOMIZE_ENV";
},
viewGroup() {
this.visible = true;
},
getgroups(){
environmentGetALL().then(res => {
let data = res.data;
this.groups = data ? data : [];
})
},
chooseEnv(val){
let filter = this.evnList.filter(e => e.id === val);
this.selectEnvMap.set(filter[0].projectId,val);
this.$emit('setProjectEnvMap', this.selectEnvMap);
},
initDefaultEnv(){
this.selectedEnvName = new Map();
this.evnList = [];
this.projectIds.forEach(d => {
let item = {id: d, envs: [], selectEnv: "",envRadio:"DEFAULT_ENV",showEnvSelect:false,expendStatus:"open"};
this.eventData.push(item);
getEnvironmentByProjectId(d)
.then(res => {
let envs = res.data;
envs.forEach(environment => {
parseEnvironment(environment);
});
//
let temp = this.eventData.find(dt => dt.id === d);
temp.envs = envs;
envs.forEach(t=>{
this.evnList.push(t);
})
if (this.envMap && this.envMap.size > 0) {
let envId = this.envMap.get(id);
//
temp.selectEnv = envs.filter(e => e.id === envId).length === 0 ? null : envId;
}
if (this.isScenario){
if (this.projectEnvMap) {
let projectEnvMapElement = this.projectEnvMap[d];
if (projectEnvMapElement.length>0) {
projectEnvMapElement.forEach(envId => {
let filter = envs.filter(e => e.id === envId);
if (!this.selectedEnvName.has(d)) {
let name = [];
name.push(filter[0].name)
this.selectedEnvName.set(d,name);
} else {
this.selectedEnvName.get(d).push(filter[0].name);
}
});
}
}
} else {
if (this.caseIdEnvNameMap) {
let envName = new Set();
for (let key in this.caseIdEnvNameMap) {
envName.add(this.caseIdEnvNameMap[key])
}
this.selectedEnvName.set(d,envName);
}
}
});
})
},
expandCard(index){
if (this.eventData[index].expendStatus === "open") {
this.eventData[index].expendStatus = "close"
}else {
this.eventData[index].expendStatus = "open"
}
}
}
}
</script>
<style scoped>
.mode-span{
margin-left: 6px;
}
</style>
<style lang="scss" scoped>
.radio-change:deep(.el-radio__input.is-checked + .el-radio__label) {
color: #606266 !important;
}
</style>

View File

@ -0,0 +1,335 @@
<template>
<el-dialog
destroy-on-close
:title="$t('load_test.runtime_config')"
width="550px"
@close="close"
:visible.sync="runModeVisible">
<div class="env-container">
<div>
<div>{{ $t("commons.environment") }}</div>
<env-select-popover :project-ids="projectIds"
:project-list="projectList"
:case-id-env-name-map="caseIdEnvNameMap"
:is-scenario="isScenario"
:project-env-map="projectEnvListMap"
:group-id="runConfig.environmentGroupId"
@setProjectEnvMap="setProjectEnvMap"
@setEnvGroup="setEnvGroup"
ref="envSelectPopover"
class="mode-row"
></env-select-popover>
</div>
<div>
<div class="mode-row">{{ $t("run_mode.title") }}</div>
<div >
<el-radio-group
v-model="runConfig.mode"
@change="changeMode"
style="width: 100%"
class="radio-change mode-row"
>
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
</el-radio-group>
</div>
</div>
<!-- 资源池 -->
<div>
<div class="mode-row">{{ $t("run_mode.other_config") }}</div>
<div class="mode-row">
<el-radio-group v-model="runConfig.reportType">
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
</el-radio-group>
</div>
<div class="ms-mode-span-label" style="margin-top: 8px" v-if="runConfig.reportType === 'setReport'">{{ $t("run_mode.report_name") }}</div>
<div class="mode-row" v-if="runConfig.reportType === 'setReport'">
<el-input
v-model="runConfig.reportName"
:placeholder="$t('commons.input_content')"
size="small"
style="width: 100%"/>
</div>
<div >
<!-- 串行 -->
<div
class="mode-row"
v-if="runConfig.mode === 'serial' && testType === 'API'"
>
<el-checkbox
v-model="runConfig.runWithinResourcePool"
style="padding-right: 10px"
class="radio-change"
:disabled="runMode === 'POOL'"
>
{{ $t("run_mode.run_with_resource_pool") }}
</el-checkbox><br/>
<el-select
:disabled="!runConfig.runWithinResourcePool"
v-model="runConfig.resourcePoolId"
size="mini"
style="width:100%; margin-top: 8px"
>
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:value="item.id"
>
</el-option>
</el-select>
</div>
<!-- 并行 -->
<div
class="mode-row"
v-if="runConfig.mode === 'parallel' && testType === 'API'"
>
<el-checkbox
v-model="runConfig.runWithinResourcePool"
style="padding-right: 10px"
class="radio-change"
:disabled="runMode === 'POOL'"
>
{{ $t("run_mode.run_with_resource_pool") }}
</el-checkbox><br/>
<el-select
:disabled="!runConfig.runWithinResourcePool"
v-model="runConfig.resourcePoolId"
size="mini"
style="width:100%; margin-top: 8px"
>
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:disabled="!item.api"
:value="item.id"
>
</el-option>
</el-select>
</div>
<!-- 失败停止 -->
<div class="mode-row" v-if="runConfig.mode === 'serial'">
<el-checkbox v-model="runConfig.onSampleError" class="radio-change">{{
$t("api_test.fail_to_stop")
}}
</el-checkbox>
</div>
</div>
</div>
</div>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="handleRunBatch"/>
</template>
</el-dialog>
</template>
<script>
import {apiScenarioEnvMap} from "@/api/scenario";
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
import {strMapToObj} from "metersphere-frontend/src/utils";
import {getOwnerProjects, getProjectConfig} from "@/api/project";
import {getTestResourcePools} from "@/api/test-resource-pool";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
import EnvSelectPopover from "@/business/automation/scenario/EnvSelectPopover";
import {getApiCaseEnvironments} from "@/api/api-test-case";
export default {
name: "ApiRunMode",
components: {MsDialogFooter, EnvSelectPopover},
data() {
return {
runMode: "",
loading: false,
runModeVisible: false,
testType: null,
resourcePools: [],
runConfig: {
reportName: "",
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
},
projectEnvListMap: {},
projectList: [],
projectIds: new Set(),
caseIdEnvNameMap:{},
};
},
props: {
runCaseIds:Array,
request: Object,
isScenario: {
type: Boolean,
default: true
}
},
watch: {
'runConfig.runWithinResourcePool'() {
if (!this.runConfig.runWithinResourcePool) {
this.runConfig = {
mode: this.runConfig.mode,
reportType: "iddReport",
reportName: "",
runWithinResourcePool: false,
resourcePoolId: null,
};
}
}
},
methods: {
open() {
this.runModeVisible = true;
this.getResourcePools();
this.getWsProjects();
this.query();
this.showPopover();
this.runConfig.environmentType = ENV_TYPE.JSON;
},
changeMode() {
this.runConfig.reportType = "iddReport";
this.runConfig.reportName = "";
},
close() {
this.runConfig = {
mode: "serial",
reportType: "iddReport",
reportName: "",
environmentType: ENV_TYPE.JSON,
runWithinResourcePool: false,
resourcePoolId: null,
};
this.runModeVisible = false;
this.$emit('close');
},
getWsProjects() {
getOwnerProjects().then(res => {
this.projectList = res.data;
})
},
handleRunBatch() {
if ((this.runConfig.mode === 'serial' || this.runConfig.mode === 'parallel') && this.runConfig.reportType === 'setReport' && this.runConfig.reportName.trim() === "") {
this.$warning(this.$t('commons.input_name'));
return;
}
if (this.runConfig.runWithinResourcePool && this.runConfig.resourcePoolId == null) {
this.$warning(this.$t('workspace.env_group.please_select_run_within_resource_pool'));
return;
}
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
getResourcePools() {
this.result = getTestResourcePools().then(response => {
this.resourcePools = response.data;
});
},
query() {
this.loading = true;
this.result = getSystemBaseSetting().then(response => {
if (!response.data.runMode) {
response.data.runMode = 'LOCAL'
}
this.runMode = response.data.runMode;
if (this.runMode === 'POOL') {
this.runConfig.runWithinResourcePool = true;
this.getProjectApplication();
} else {
this.loading = false;
}
})
},
getProjectApplication() {
getProjectConfig(getCurrentProjectID(), "").then(res => {
if (res.data && res.data.poolEnable && res.data.resourcePoolId) {
this.runConfig.resourcePoolId = res.data.resourcePoolId;
}
this.loading = false;
});
},
setEnvGroup(id) {
this.runConfig.environmentGroupId = id;
},
setProjectEnvMap(projectEnvMap) {
this.runConfig.envMap = strMapToObj(projectEnvMap);
},
showPopover() {
if (this.isScenario) {
this.showScenarioPopover();
} else {
this.showApiPopover();
}
},
showApiPopover() {
let currentProjectID = getCurrentProjectID();
this.projectIds.clear();
getApiCaseEnvironments(this.runCaseIds).then((res) => {
let data = res.data;
if (data) {
this.caseIdEnvNameMap = data;
this.projectIds.add(currentProjectID);
}
this.$refs.envSelectPopover.open();
});
},
showScenarioPopover() {
this.projectIds.clear();
apiScenarioEnvMap(this.request).then(res => {
let data = res.data;
this.projectEnvListMap = data;
if (data) {
for (let d in data) {
this.projectIds.add(d);
}
}
this.$refs.envSelectPopover.open();
});
},
},
};
</script>
<style scoped>
.env-container .title {
width: 100px;
min-width: 100px;
text-align: right;
}
.env-container .content {
width: 163px;
}
:deep(.content .el-popover__reference) {
width: 100%;
}
.mode-row {
margin-top: 8px;
}
.ms-mode-span-label:before {
content: '*';
color: #F56C6C;
}
</style>
<style lang="scss" scoped>
.radio-change:deep(.el-radio__input.is-checked + .el-radio__label) {
color: #606266 !important;
}
</style>

View File

@ -1,261 +0,0 @@
<template>
<el-dialog
destroy-on-close
:title="$t('load_test.runtime_config')"
width="550px"
@close="close"
:visible.sync="runModeVisible">
<div v-loading="loading">
<div style="margin-bottom: 10px;">
<span class="ms-mode-span"> {{ $t("commons.environment") }} </span>
<env-popover
:project-ids="projectIds"
:placement="'bottom-start'"
:project-list="projectList"
:project-env-map="projectEnvListMap"
:environment-type.sync="runConfig.environmentType"
:group-id="runConfig.environmentGroupId"
:has-option-group="true"
:show-env-group="isScenario"
@setEnvGroup="setEnvGroup"
@setProjectEnvMap="setProjectEnvMap"
@showPopover="showPopover"
ref="envPopover" class="env-popover"/>
</div>
<div>
<span>{{ $t("run_mode.title") }}</span>
<el-radio-group v-model="runConfig.mode" @change="changeMode">
<el-radio label="serial">{{ $t("run_mode.serial") }}</el-radio>
<el-radio label="parallel">{{ $t("run_mode.parallel") }}</el-radio>
</el-radio-group>
</div>
<!-- 资源池 -->
<div class="ms-mode-div">
<span class="ms-mode-span">{{ $t("run_mode.other_config") }}</span>
<span>
<el-radio-group v-model="runConfig.reportType">
<el-radio label="iddReport">{{ $t("run_mode.idd_report") }}</el-radio>
<el-radio label="setReport">{{ $t("run_mode.set_report") }}</el-radio>
</el-radio-group>
</span>
<div style="padding:10px 90px">
<el-checkbox v-model="runConfig.runWithinResourcePool"
style="padding-right: 10px;" :disabled="runMode === 'POOL'">
{{ $t('run_mode.run_with_resource_pool') }}
</el-checkbox>
<el-select :disabled="!runConfig.runWithinResourcePool" v-model="runConfig.resourcePoolId" size="mini">
<el-option
v-for="item in resourcePools"
:key="item.id"
:label="item.name"
:disabled="!item.api"
:value="item.id">
</el-option>
</el-select>
</div>
</div>
<!--- 失败停止 -->
<div style="padding:0px 90px" v-if="runConfig.mode === 'serial'">
<el-checkbox v-model="runConfig.onSampleError">
{{ $t("api_test.fail_to_stop") }}
</el-checkbox>
</div>
<div class="ms-mode-div" v-if="runConfig.reportType === 'setReport'">
<span class="ms-mode-span-label">{{ $t("run_mode.report_name") }}</span>
<el-input
v-model="runConfig.reportName"
:placeholder="$t('commons.input_content')"
size="small"
style="width: 300px"/>
</div>
</div>
<template v-slot:footer>
<ms-dialog-footer @cancel="close" @confirm="handleRunBatch"/>
</template>
</el-dialog>
</template>
<script>
import {apiScenarioEnv} from "@/api/scenario";
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
import {strMapToObj} from "metersphere-frontend/src/utils";
import EnvPopover from "@/business/automation/scenario/EnvPopover";
import {getOwnerProjects, getProjectConfig} from "@/api/project";
import {getTestResourcePools} from "@/api/test-resource-pool";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {getSystemBaseSetting} from "metersphere-frontend/src/api/system";
export default {
name: "RunMode",
components: {MsDialogFooter, EnvPopover},
data() {
return {
runMode: "",
loading: false,
runModeVisible: false,
testType: null,
resourcePools: [],
runConfig: {
reportName: "",
mode: "serial",
reportType: "iddReport",
onSampleError: false,
runWithinResourcePool: false,
resourcePoolId: null,
envMap: new Map(),
environmentGroupId: "",
environmentType: ENV_TYPE.JSON
},
projectEnvListMap: {},
projectList: [],
projectIds: new Set(),
};
},
props: {
request: Object,
isScenario: {
type: Boolean,
default: true
}
},
watch: {
'runConfig.runWithinResourcePool'() {
if (!this.runConfig.runWithinResourcePool) {
this.runConfig = {
mode: this.runConfig.mode,
reportType: "iddReport",
reportName: "",
runWithinResourcePool: false,
resourcePoolId: null,
};
}
}
},
methods: {
open() {
this.runModeVisible = true;
this.getResourcePools();
this.getWsProjects();
this.query();
this.runConfig.environmentType = ENV_TYPE.JSON;
},
changeMode() {
this.runConfig.reportType = "iddReport";
this.runConfig.reportName = "";
},
close() {
this.runConfig = {
mode: "serial",
reportType: "iddReport",
reportName: "",
environmentType: ENV_TYPE.JSON,
runWithinResourcePool: false,
resourcePoolId: null,
};
this.runModeVisible = false;
this.$emit('close');
},
getWsProjects() {
getOwnerProjects().then(res => {
this.projectList = res.data;
})
},
handleRunBatch() {
if ((this.runConfig.mode === 'serial' || this.runConfig.mode === 'parallel') && this.runConfig.reportType === 'setReport' && this.runConfig.reportName.trim() === "") {
this.$warning(this.$t('commons.input_name'));
return;
}
if (this.runConfig.runWithinResourcePool && this.runConfig.resourcePoolId == null) {
this.$warning(this.$t('workspace.env_group.please_select_run_within_resource_pool'));
return;
}
this.$emit("handleRunBatch", this.runConfig);
this.close();
},
getResourcePools() {
this.result = getTestResourcePools().then(response => {
this.resourcePools = response.data;
});
},
query() {
this.loading = true;
this.result = getSystemBaseSetting().then(response => {
if (!response.data.runMode) {
response.data.runMode = 'LOCAL'
}
this.runMode = response.data.runMode;
if (this.runMode === 'POOL') {
this.runConfig.runWithinResourcePool = true;
this.getProjectApplication();
} else {
this.loading = false;
}
})
},
getProjectApplication() {
getProjectConfig(getCurrentProjectID(), "").then(res => {
if (res.data && res.data.poolEnable && res.data.resourcePoolId) {
this.runConfig.resourcePoolId = res.data.resourcePoolId;
}
this.loading = false;
});
},
setEnvGroup(id) {
this.runConfig.environmentGroupId = id;
},
setProjectEnvMap(projectEnvMap) {
this.runConfig.envMap = strMapToObj(projectEnvMap);
},
showPopover() {
if (this.isScenario) {
this.showScenarioPopover();
} else {
this.showApiPopover();
}
},
showApiPopover() {
this.projectIds.clear();
this.projectIds.add(getCurrentProjectID());
this.$refs.envPopover.openEnvSelect();
},
showScenarioPopover() {
this.projectIds.clear();
apiScenarioEnv(this.request).then(res => {
let data = res.data;
if (data) {
for (let d in data) {
this.projectIds.add(data[d]);
}
}
this.$refs.envPopover.openEnvSelect();
});
},
},
};
</script>
<style scoped>
.ms-mode-span {
margin-right: 10px;
display: -moz-inline-box;
display: inline-block;
width: 90px;
}
.ms-mode-div {
margin-top: 20px;
}
.ms-mode-span-label:before {
content: '*';
color: #F56C6C;
margin-right: 4px;
margin-left: 10px;
}
</style>

View File

@ -246,12 +246,13 @@
<ms-task-center ref="taskCenter" :show-menu="false"/> <ms-task-center ref="taskCenter" :show-menu="false"/>
<ms-api-case-run-mode-with-env <ms-api-run-mode
:is-scenario="false" :is-scenario="false"
:project-id="projectId" :project-id="projectId"
:run-case-ids="runCaseIds"
@handleRunBatch="runBatch" @handleRunBatch="runBatch"
@close="initTable" @close="initTable"
ref="batchRun"/> ref="apiBatchRun"/>
<el-dialog :close-on-click-modal="false" :title="$t('test_track.plan_view.test_result')" width="60%" <el-dialog :close-on-click-modal="false" :title="$t('test_track.plan_view.test_result')" width="60%"
:visible.sync="resVisible" class="api-import" destroy-on-close @close="resVisible=false"> :visible.sync="resVisible" class="api-import" destroy-on-close @close="resVisible=false">
@ -305,11 +306,8 @@ import MsContainer from "metersphere-frontend/src/components/MsContainer";
import MsBottomContainer from "../BottomContainer"; import MsBottomContainer from "../BottomContainer";
import ShowMoreBtn from "@/business/commons/ShowMoreBtn"; import ShowMoreBtn from "@/business/commons/ShowMoreBtn";
import MsBatchEdit from "../basis/BatchEdit"; import MsBatchEdit from "../basis/BatchEdit";
import MsApiCaseRunModeWithEnv from "@/business/automation/scenario/common/RunMode";
import {getUUID, operationConfirm} from "metersphere-frontend/src/utils"; import {getUUID, operationConfirm} from "metersphere-frontend/src/utils";
import {API_METHOD_COLOUR, CASE_PRIORITY, DUBBO_METHOD, REQ_METHOD, SQL_METHOD, TCP_METHOD} from "../../model/JsonData"; import {API_METHOD_COLOUR, CASE_PRIORITY, DUBBO_METHOD, REQ_METHOD, SQL_METHOD, TCP_METHOD} from "../../model/JsonData";
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token"; import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
import {hasLicense} from "metersphere-frontend/src/utils/permission"; import {hasLicense} from "metersphere-frontend/src/utils/permission";
import {getBodyUploadFiles} from "@/business/definition/api-definition"; import {getBodyUploadFiles} from "@/business/definition/api-definition";
@ -342,7 +340,7 @@ import SyncSetting from "@/business/definition/util/SyncSetting";
import {getEnvironmentByProjectId} from "metersphere-frontend/src/api/environment"; import {getEnvironmentByProjectId} from "metersphere-frontend/src/api/environment";
import {useApiStore, usePerformanceStore} from "@/store"; import {useApiStore, usePerformanceStore} from "@/store";
import {REPORT_STATUS} from "@/business/commons/js/commons"; import {REPORT_STATUS} from "@/business/commons/js/commons";
import MsApiRunMode from "@/business/automation/scenario/common/ApiRunMode";
const performanceStore = usePerformanceStore(); const performanceStore = usePerformanceStore();
const store = useApiStore(); const store = useApiStore();
@ -370,7 +368,7 @@ export default {
MsTable, MsTable,
MsTableColumn, MsTableColumn,
MsRequestResultTail, MsRequestResultTail,
MsApiCaseRunModeWithEnv, MsApiRunMode,
MsSearch, MsSearch,
SyncSetting, SyncSetting,
MsApiReportStatus: () => import("../../../automation/report/ApiReportStatus"), MsApiReportStatus: () => import("../../../automation/report/ApiReportStatus"),
@ -683,7 +681,10 @@ export default {
} }
}, },
handleRunBatch() { handleRunBatch() {
this.$refs.batchRun.open(); this.runCaseIds = Array.from(this.selectRows).map(row => row.id);
this.$nextTick(() => {
this.$refs.apiBatchRun.open();
});
}, },
runBatch(config) { runBatch(config) {
let obj = {}; let obj = {};
@ -696,7 +697,7 @@ export default {
obj.condition.status = ""; obj.condition.status = "";
testCaseBatchRun(obj).then(() => { testCaseBatchRun(obj).then(() => {
this.condition.ids = []; this.condition.ids = [];
this.$refs.batchRun.close(); this.$refs.apiBatchRun.close();
if (store.currentApiCase) { if (store.currentApiCase) {
store.currentApiCase.case = true; store.currentApiCase.case = true;
} else { } else {

View File

@ -434,12 +434,6 @@ export default {
width: 163px; width: 163px;
} }
.wrap {
display: flex;
align-items: center;
padding: 5px 10px 5px 10px;
}
:deep(.content .el-popover__reference) { :deep(.content .el-popover__reference) {
width: 100%; width: 100%;
} }
@ -448,28 +442,6 @@ export default {
margin-top: 8px; margin-top: 8px;
} }
.other-title {
height: 100%;
margin-top: 25px;
align-items: flex-start;
}
.other-content {
height: 100%;
}
.other-row {
height: 125px;
}
.project-name {
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 150px;
margin-left: 8px;
vertical-align: middle;
}
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
.radio-change:deep(.el-radio__input.is-checked + .el-radio__label) { .radio-change:deep(.el-radio__input.is-checked + .el-radio__label) {

View File

@ -166,12 +166,9 @@
:select-row="$refs.table ? $refs.table.selectRows : new Set()" ref="batchEdit" :select-row="$refs.table ? $refs.table.selectRows : new Set()" ref="batchEdit"
@batchEdit="batchEdit"/> @batchEdit="batchEdit"/>
<ms-plan-run-mode
:type="'apiCase'" <ms-test-plan-run-mode-with-env @handleRunBatch="handleRunBatch" ref="runMode" :plan-case-ids="testPlanCaseIds" :type="'apiCase'"
:plan-case-ids="testPlanCaseIds" @close="search" />
@close="search"
@handleRunBatch="handleRunBatch"
ref="runMode"/>
</el-card> </el-card>
<ms-task-center ref="taskCenter" :show-menu="false"/> <ms-task-center ref="taskCenter" :show-menu="false"/>
</div> </div>
@ -204,7 +201,6 @@ import HeaderLabelOperate from "metersphere-frontend/src/components/head/HeaderL
import MsTaskCenter from "metersphere-frontend/src/components/task/TaskCenter"; import MsTaskCenter from "metersphere-frontend/src/components/task/TaskCenter";
import MsTable from "metersphere-frontend/src/components/table/MsTable"; import MsTable from "metersphere-frontend/src/components/table/MsTable";
import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn"; import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn";
import MsPlanRunMode from "@/business/plan/common/PlanRunModeWithEnv";
import MsUpdateTimeColumn from "metersphere-frontend/src/components/table/MsUpdateTimeColumn"; import MsUpdateTimeColumn from "metersphere-frontend/src/components/table/MsUpdateTimeColumn";
import MsCreateTimeColumn from "metersphere-frontend/src/components/table/MsCreateTimeColumn"; import MsCreateTimeColumn from "metersphere-frontend/src/components/table/MsCreateTimeColumn";
import {editTestPlanApiCaseOrder, run, testPlanAutoCheck} from "@/api/remote/plan/test-plan"; import {editTestPlanApiCaseOrder, run, testPlanAutoCheck} from "@/api/remote/plan/test-plan";
@ -221,11 +217,11 @@ import {
import MsTestPlanApiStatus from "@/business/plan/view/comonents/api/TestPlanApiStatus"; import MsTestPlanApiStatus from "@/business/plan/view/comonents/api/TestPlanApiStatus";
import {getProjectVersions} from "@/business/utils/sdk-utils"; import {getProjectVersions} from "@/business/utils/sdk-utils";
import {TEST_PLAN_API_CASE_CONFIGS} from "metersphere-frontend/src/components/search/search-components"; import {TEST_PLAN_API_CASE_CONFIGS} from "metersphere-frontend/src/components/search/search-components";
import MsTestPlanRunModeWithEnv from "@/business/plan/common/TestPlanRunModeWithEnv";
export default { export default {
name: "TestPlanApiCaseList", name: "TestPlanApiCaseList",
components: { components: {
MsPlanRunMode,
MsCreateTimeColumn, MsCreateTimeColumn,
MsUpdateTimeColumn, MsUpdateTimeColumn,
MsTableColumn, MsTableColumn,
@ -241,7 +237,8 @@ export default {
MsContainer, MsContainer,
MsBottomContainer, MsBottomContainer,
MsTaskCenter, MsTaskCenter,
MsTestPlanApiStatus MsTestPlanApiStatus,
MsTestPlanRunModeWithEnv,
}, },
mounted() { mounted() {
this.getVersionOptions(); this.getVersionOptions();

View File

@ -189,12 +189,9 @@
<batch-edit :dialog-title="$t('test_track.case.batch_edit_case')" :type-arr="typeArr" :value-arr="valueArr" <batch-edit :dialog-title="$t('test_track.case.batch_edit_case')" :type-arr="typeArr" :value-arr="valueArr"
:select-row="this.$refs.table ? this.$refs.table.selectRows : new Set()" ref="batchEdit" :select-row="this.$refs.table ? this.$refs.table.selectRows : new Set()" ref="batchEdit"
@batchEdit="batchEdit"/> @batchEdit="batchEdit"/>
<ms-plan-run-mode <ms-test-plan-run-mode-with-env @handleRunBatch="handleRunBatch" ref="runMode" :plan-case-ids="planCaseIds" :type="'apiScenario'"
:type="'apiScenario'" @close="search" />
:plan-case-ids="planCaseIds"
@close="search"
@handleRunBatch="handleRunBatch"
ref="runMode"/>
<ms-task-center ref="taskCenter" :show-menu="false"/> <ms-task-center ref="taskCenter" :show-menu="false"/>
</div> </div>
@ -242,6 +239,7 @@ import MicroApp from "metersphere-frontend/src/components/MicroApp";
import MsTestPlanApiStatus from "@/business/plan/view/comonents/api/TestPlanApiStatus"; import MsTestPlanApiStatus from "@/business/plan/view/comonents/api/TestPlanApiStatus";
import {getVersionFilters} from "@/business/utils/sdk-utils"; import {getVersionFilters} from "@/business/utils/sdk-utils";
import {TEST_PLAN_API_SCENARIO_CONFIGS} from "metersphere-frontend/src/components/search/search-components"; import {TEST_PLAN_API_SCENARIO_CONFIGS} from "metersphere-frontend/src/components/search/search-components";
import MsTestPlanRunModeWithEnv from "@/business/plan/common/TestPlanRunModeWithEnv";
export default { export default {
name: "MsTestPlanApiScenarioList", name: "MsTestPlanApiScenarioList",
@ -261,7 +259,8 @@ export default {
BatchEdit, BatchEdit,
MsPlanRunMode, MsPlanRunMode,
MsTaskCenter, MsTaskCenter,
MsTestPlanApiStatus MsTestPlanApiStatus,
MsTestPlanRunModeWithEnv,
}, },
props: { props: {
referenced: { referenced: {