This commit is contained in:
liqiang-fit2cloud 2022-12-21 18:20:03 +08:00
commit 232a659656
22 changed files with 770 additions and 803 deletions

View File

@ -29,7 +29,7 @@ public interface ExtApiDefinitionExecResultMapper {
long countByTestCaseIDInProject(String projectId); long countByTestCaseIDInProject(String projectId);
List<ExecutedCaseInfoResult> findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("version") String version, @Param("selectFunctionCase") boolean selectFunctionCase, @Param("startTimestamp") long startTimestamp, @Param("limitNumber") int limitNumber); List<ExecutedCaseInfoResult> findFailureCaseInTestPlanByProjectIDAndExecuteTimeAndLimitNumber(@Param("projectId") String projectId, @Param("versionId") String version, @Param("selectFunctionCase") boolean selectFunctionCase, @Param("startTimestamp") long startTimestamp, @Param("limitNumber") int limitNumber);
String selectExecResult(String resourceId); String selectExecResult(String resourceId);

View File

@ -383,7 +383,6 @@
</if> </if>
AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp} AND create_time BETWEEN #{firstDayTimestamp} AND #{lastDayTimestamp}
</select> </select>
<select id="countByProjectIdGroupByExecuteResult" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult"> <select id="countByProjectIdGroupByExecuteResult" resultType="io.metersphere.api.dto.datacount.ApiDataCountResult">
SELECT count(id) AS countNumber, result AS groupField SELECT count(id) AS countNumber, result AS groupField
FROM scenario_execution_info FROM scenario_execution_info

View File

@ -32,8 +32,7 @@ public class MockApiController {
public String postRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) { public String postRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) {
Project project = baseProjectService.findBySystemId(projectSystemId); Project project = baseProjectService.findBySystemId(projectSystemId);
Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request); Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request);
String returnStr = mockConfigService.checkReturnWithMockExpectByBodyParam("POST", requestHeaderMap, project, request, response); return mockConfigService.checkReturnWithMockExpectByBodyParam("POST", requestHeaderMap, project, request, response);
return returnStr;
} }
@GetMapping("/{projectSystemId}/**") @GetMapping("/{projectSystemId}/**")
@ -41,8 +40,7 @@ public class MockApiController {
public String getRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) { public String getRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) {
Project project = baseProjectService.findBySystemId(projectSystemId); Project project = baseProjectService.findBySystemId(projectSystemId);
Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request); Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request);
String returnStr = mockConfigService.checkReturnWithMockExpectByUrlParam("GET", requestHeaderMap, project, request, response); return mockConfigService.checkReturnWithMockExpectByUrlParam("GET", requestHeaderMap, project, request, response);
return returnStr;
} }
@PutMapping("/{projectSystemId}/**") @PutMapping("/{projectSystemId}/**")
@ -50,8 +48,7 @@ public class MockApiController {
public String putRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) { public String putRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) {
Project project = baseProjectService.findBySystemId(projectSystemId); Project project = baseProjectService.findBySystemId(projectSystemId);
Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request); Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request);
String returnStr = mockConfigService.checkReturnWithMockExpectByBodyParam("PUT", requestHeaderMap, project, request, response); return mockConfigService.checkReturnWithMockExpectByBodyParam("PUT", requestHeaderMap, project, request, response);
return returnStr;
} }
@PatchMapping("/{projectSystemId}/**") @PatchMapping("/{projectSystemId}/**")
@ -59,8 +56,7 @@ public class MockApiController {
public String patchRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) { public String patchRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) {
Project project = baseProjectService.findBySystemId(projectSystemId); Project project = baseProjectService.findBySystemId(projectSystemId);
Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request); Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request);
String returnStr = mockConfigService.checkReturnWithMockExpectByBodyParam("PATCH", requestHeaderMap, project, request, response); return mockConfigService.checkReturnWithMockExpectByBodyParam("PATCH", requestHeaderMap, project, request, response);
return returnStr;
} }
@DeleteMapping("/{projectSystemId}/**") @DeleteMapping("/{projectSystemId}/**")
@ -68,8 +64,7 @@ public class MockApiController {
public String deleteRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) { public String deleteRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) {
Project project = baseProjectService.findBySystemId(projectSystemId); Project project = baseProjectService.findBySystemId(projectSystemId);
Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request); Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request);
String returnStr = mockConfigService.checkReturnWithMockExpectByUrlParam("DELETE", requestHeaderMap, project, request, response); return mockConfigService.checkReturnWithMockExpectByUrlParam("DELETE", requestHeaderMap, project, request, response);
return returnStr;
} }
@RequestMapping(value = "/{projectSystemId}/**", method = RequestMethod.OPTIONS) @RequestMapping(value = "/{projectSystemId}/**", method = RequestMethod.OPTIONS)
@ -77,8 +72,7 @@ public class MockApiController {
public String optionsRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) { public String optionsRequest(@PathVariable String projectSystemId, HttpServletRequest request, HttpServletResponse response) {
Project project = baseProjectService.findBySystemId(projectSystemId); Project project = baseProjectService.findBySystemId(projectSystemId);
Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request); Map<String, String> requestHeaderMap = MockApiUtils.getHttpRequestHeader(request);
String returnStr = mockConfigService.checkReturnWithMockExpectByUrlParam("OPTIONS", requestHeaderMap, project, request, response); return mockConfigService.checkReturnWithMockExpectByUrlParam("OPTIONS", requestHeaderMap, project, request, response);
return returnStr;
} }
@RequestMapping(value = "/{projectSystemId}/**", method = RequestMethod.HEAD) @RequestMapping(value = "/{projectSystemId}/**", method = RequestMethod.HEAD)

View File

@ -127,11 +127,17 @@ public class MockConfigService {
} }
} }
/**
* 这个接口是生成用的
* 如果没数据就生成有数据就返回一套数据结构
* 所有入参都没有必填项
* 如果为了查询请写一个新的接口
*
* @param request
* @return
*/
public MockConfigResponse genMockConfig(MockConfigRequest request) { public MockConfigResponse genMockConfig(MockConfigRequest request) {
MockConfigResponse returnRsp; MockConfigResponse returnRsp;
if (StringUtils.isEmpty(request.getId())) {
return new MockConfigResponse(null, new ArrayList<>());
}
MockConfigExample example = new MockConfigExample(); MockConfigExample example = new MockConfigExample();
MockConfigExample.Criteria criteria = example.createCriteria(); MockConfigExample.Criteria criteria = example.createCriteria();
if (request.getId() != null) { if (request.getId() != null) {
@ -139,6 +145,8 @@ public class MockConfigService {
} }
if (request.getApiId() != null) { if (request.getApiId() != null) {
criteria.andApiIdEqualTo(request.getApiId()); criteria.andApiIdEqualTo(request.getApiId());
} else if (StringUtils.isEmpty(request.getId())) {
return new MockConfigResponse(null, new ArrayList<>());
} }
if (request.getProjectId() != null) { if (request.getProjectId() != null) {
criteria.andProjectIdEqualTo(request.getProjectId()); criteria.andProjectIdEqualTo(request.getProjectId());

View File

@ -1095,6 +1095,12 @@ public class ApiDefinitionService {
} }
apiDefinitionRequest.setVersionId(api.getVersionId()); apiDefinitionRequest.setVersionId(api.getVersionId());
checkNameExist(apiDefinitionRequest, false); checkNameExist(apiDefinitionRequest, false);
//同步修改所有版本的模块路径
if (StringUtils.isNotEmpty(request.getModuleId()) && StringUtils.isNotEmpty(request.getModulePath())) {
api.setModuleId(request.getModuleId());
api.setModulePath(request.getModulePath());
updateOtherVersionModule(api);
}
}); });
if (StringUtils.isNotEmpty(request.getFollow())) { if (StringUtils.isNotEmpty(request.getFollow())) {
if (StringUtils.equals(request.getFollow(), "cancel")) { if (StringUtils.equals(request.getFollow(), "cancel")) {

View File

@ -1139,6 +1139,11 @@ public class ApiScenarioService {
scenarioRequest.setModulePath(request.getModulePath()); scenarioRequest.setModulePath(request.getModulePath());
scenarioRequest.setVersionId(scenario.getVersionId()); scenarioRequest.setVersionId(scenario.getVersionId());
checkNameExist(scenarioRequest, false); checkNameExist(scenarioRequest, false);
if (StringUtils.isNotEmpty(request.getApiScenarioModuleId()) && StringUtils.isNotEmpty(request.getModulePath())) {
scenario.setApiScenarioModuleId(request.getApiScenarioModuleId());
scenario.setModulePath(request.getModulePath());
updateOtherVersionModule(scenario.getRefId(), scenario);
}
}); });
} }
apiScenarioMapper.updateByExampleSelective(apiScenarioWithBLOBs, apiScenarioExample); apiScenarioMapper.updateByExampleSelective(apiScenarioWithBLOBs, apiScenarioExample);

View File

@ -323,6 +323,7 @@ export default {
}, },
mockSetting() { mockSetting() {
let mockParam = {}; let mockParam = {};
mockParam.projectId = this.projectId; mockParam.projectId = this.projectId;
if (this.currentApi.id) { if (this.currentApi.id) {
mockParam.apiId = this.currentApi.id; mockParam.apiId = this.currentApi.id;

View File

@ -3,7 +3,7 @@
<ms-container> <ms-container>
<ms-main-container style="padding: 0px"> <ms-main-container style="padding: 0px">
<div class="api-home-layout"> <div class="api-home-layout">
<el-row class="api-home-toolbar"> <el-row v-if="showVersionSelector" class="api-home-toolbar">
<el-select <el-select
clearable clearable
v-model="versionId" v-model="versionId"
@ -78,6 +78,7 @@ export default {
versionId: '', versionId: '',
projectId: getCurrentProjectID(), projectId: getCurrentProjectID(),
versions: [], versions: [],
showVersionSelector: false,
}; };
}, },
created() { created() {
@ -85,6 +86,7 @@ export default {
this.$nextTick(() => { this.$nextTick(() => {
this.refreshAllCard(); this.refreshAllCard();
}); });
this.showVersionSelector = hasLicense();
}, },
watch: { watch: {
versionId() { versionId() {

View File

@ -45,57 +45,11 @@
</el-input> </el-input>
</div> </div>
<!-- 接口测试配置 -->
<form-section :title="$t('commons.api')" :init-active=true>
<p>{{ $t('api_test.request.headers') }}</p> <p>{{ $t('api_test.request.headers') }}</p>
<el-row> <el-row>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ <el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}</el-link>
$t("commons.batch_add")
}}
</el-link>
</el-row> </el-row>
<ms-api-key-value :items="condition.headers" :isShowEnable="true" :suggestions="headerSuggestions"/> <ms-api-key-value :items="condition.headers" :isShowEnable="true" :suggestions="headerSuggestions"/>
</form-section>
<!-- UI 配置 -->
<form-section :title="$t('commons.ui_test')" :init-active=false v-if="condition.type !== 'MODULE'">
<el-row :gutter="10" style="padding-top: 10px;">
<el-col :span="6">
<!-- 浏览器驱动 -->
<span style="margin-right: 10px;">{{ $t("ui.browser") }}</span>
<el-select
size="mini"
v-model="httpConfig.browser"
style="width: 100px"
>
<el-option
v-for="b in browsers"
:key="b.value"
:value="b.value"
:label="b.label"
></el-option>
</el-select>
</el-col>
<el-col :span="6">
<!-- 性能模式 -->
<el-checkbox
v-model="httpConfig.headlessEnabled"
>
<span> {{ $t("ui.performance_mode") }}</span>
</el-checkbox>
<ms-instructions-icon size="10" :content="$t('ui.per_tip')"/>
</el-col>
</el-row>
<!-- 当前版本实现免登录是基于 cookie 的但是现在由于安全性问题绝大多数网站都不支持 cookie登录所以先屏蔽了-->
<!-- <el-row :gutter="10">-->
<!-- <el-col :span="24">-->
<!-- <ms-ui-scenario-cookie-table :items="httpConfig.cookie" ref="cookieTable"/>-->
<!-- </el-col>-->
<!-- </el-row>-->
</form-section>
<div style="margin-top: 20px"> <div style="margin-top: 20px">
<el-button v-if="!condition.id" type="primary" style="float: right" size="mini" @click="add"> <el-button v-if="!condition.id" type="primary" style="float: right" size="mini" @click="add">
{{ $t('commons.add') }} {{ $t('commons.add') }}
@ -167,12 +121,10 @@ import {getUUID} from "../../utils";
import {KeyValue} from "../../model/EnvTestModel"; import {KeyValue} from "../../model/EnvTestModel";
import Vue from "vue"; import Vue from "vue";
import BatchAddParameter from "./commons/BatchAddParameter"; import BatchAddParameter from "./commons/BatchAddParameter";
import FormSection from "metersphere-frontend/src/components/form/FormSection";
import MsInstructionsIcon from 'metersphere-frontend/src/components/MsInstructionsIcon';
export default { export default {
name: "MsEnvironmentHttpConfig", name: "MsEnvironmentHttpConfig",
components: {MsApiKeyValue, MsSelectTree, MsTableOperatorButton, BatchAddParameter, FormSection, MsInstructionsIcon}, components: {MsApiKeyValue, MsSelectTree, MsTableOperatorButton, BatchAddParameter},
props: { props: {
httpConfig: new HttpConfig(), httpConfig: new HttpConfig(),
projectId: String, projectId: String,
@ -213,21 +165,9 @@ export default {
socket: "", socket: "",
domain: "", domain: "",
port: 0, port: 0,
headers: [new KeyValue()], headers: [new KeyValue()]
headlessEnabled: true,
browser: 'CHROME'
}, },
beforeCondition: {}, beforeCondition: {}
browsers: [
{
label: this.$t("chrome"),
value: "CHROME",
},
{
label: this.$t("firefox"),
value: "FIREFOX",
},
],
}; };
}, },
watch: { watch: {

View File

@ -18,18 +18,12 @@
:content="$t('commons.import')" :content="$t('commons.import')"
@click="importJSON" @click="importJSON"
/> />
<el-dropdown @command="handleExportCommand" class="scenario-ext-btn" trigger="hover"
v-permission="['PROJECT_ENVIRONMENT:READ+EXPORT']">
<ms-table-button <ms-table-button
style="margin-left: 10px" v-permission="['PROJECT_ENVIRONMENT:READ+EXPORT']"
icon="el-icon-box" icon="el-icon-box"
:content="$t('commons.export')" :content="$t('commons.export')"
@click="exportJSON"
/> />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="exportApi">{{ $t('envrionment.export_variable_tip') }}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-link <el-link
style="margin-left: 10px" style="margin-left: 10px"
@click="batchAdd" @click="batchAdd"
@ -64,31 +58,6 @@
> >
<ms-table-column prop="num" sortable label="ID" min-width="60"> <ms-table-column prop="num" sortable label="ID" min-width="60">
</ms-table-column> </ms-table-column>
<ms-table-column
prop="scope"
sortable
:label="$t('commons.scope')"
:filters="scopeTypeFilters"
:filter-method="filterScope"
min-width="120">
<template slot-scope="scope">
<el-select
v-model="scope.row.scope"
:placeholder="$t('commons.please_select')"
size="mini"
@change="changeType(scope.row)"
>
<el-option
v-for="item in scopeTypeFilters"
:key="item.value"
:label="item.text"
:value="item.value"
/>
</el-select>
</template>
</ms-table-column>
<ms-table-column <ms-table-column
prop="name" prop="name"
:label="$t('api_test.variable_name')" :label="$t('api_test.variable_name')"
@ -115,9 +84,9 @@
<template slot-scope="scope"> <template slot-scope="scope">
<el-select <el-select
v-model="scope.row.type" v-model="scope.row.type"
v-if="!scope.row.scope || scope.row.scope == 'api'"
:placeholder="$t('commons.please_select')" :placeholder="$t('commons.please_select')"
size="mini" size="mini"
@change="changeType(scope.row)"
> >
<el-option <el-option
v-for="item in typeSelectOptions" v-for="item in typeSelectOptions"
@ -126,20 +95,6 @@
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
<el-select
v-else
v-model="scope.row.type"
:placeholder="$t('commons.please_select')"
size="mini"
>
<el-option
v-for="item in uiTypeSelectOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template> </template>
</ms-table-column> </ms-table-column>
@ -173,14 +128,14 @@
sortable sortable
> >
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.description" size="mini"/> <el-input v-model="scope.row.description" size="mini" />
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :label="$t('commons.operating')" width="150"> <ms-table-column :label="$t('commons.operating')" width="150">
<template v-slot:default="scope"> <template v-slot:default="scope">
<span> <span>
<el-switch v-model="scope.row.enable" size="mini"/> <el-switch v-model="scope.row.enable" size="mini" />
<el-tooltip <el-tooltip
effect="dark" effect="dark"
:content="$t('commons.remove')" :content="$t('commons.remove')"
@ -216,7 +171,7 @@
</ms-table-column> </ms-table-column>
</ms-table> </ms-table>
</div> </div>
<batch-add-parameter @batchSave="batchSave" ref="batchAdd"/> <batch-add-parameter @batchSave="batchSave" ref="batchAdd" />
<api-variable-setting ref="apiVariableSetting"></api-variable-setting> <api-variable-setting ref="apiVariableSetting"></api-variable-setting>
<variable-import <variable-import
ref="variableImport" ref="variableImport"
@ -226,7 +181,7 @@
</template> </template>
<script> <script>
import {KeyValue} from "../../../model/EnvTestModel"; import { KeyValue } from "../../../model/EnvTestModel";
import MsApiVariableInput from "./ApiVariableInput"; import MsApiVariableInput from "./ApiVariableInput";
import BatchAddParameter from "./BatchAddParameter"; import BatchAddParameter from "./BatchAddParameter";
import MsTableButton from "../../MsTableButton"; import MsTableButton from "../../MsTableButton";
@ -234,9 +189,8 @@ import MsTable from "../../table/MsTable";
import MsTableColumn from "../../table/MsTableColumn"; import MsTableColumn from "../../table/MsTableColumn";
import ApiVariableSetting from "./ApiVariableSetting"; import ApiVariableSetting from "./ApiVariableSetting";
import CsvFileUpload from "./variable/CsvFileUpload"; import CsvFileUpload from "./variable/CsvFileUpload";
import {downloadFile, getUUID, operationConfirm} from "../../../utils"; import { downloadFile, getUUID, operationConfirm } from "../../../utils";
import VariableImport from "./variable/VariableImport"; import VariableImport from "./variable/VariableImport";
import _ from "lodash";
export default { export default {
name: "MsApiScenarioVariables", name: "MsApiScenarioVariables",
@ -276,25 +230,15 @@ export default {
}, },
], ],
typeSelectOptions: [ typeSelectOptions: [
{value: "CONSTANT", label: this.$t("api_test.automation.constant")}, { value: "CONSTANT", label: this.$t("api_test.automation.constant") },
{value: "LIST", label: this.$t("test_track.case.list")}, { value: "LIST", label: this.$t("test_track.case.list") },
{value: "CSV", label: "CSV"}, { value: "CSV", label: "CSV" },
{value: "COUNTER", label: this.$t("api_test.automation.counter")}, { value: "COUNTER", label: this.$t("api_test.automation.counter") },
{value: "RANDOM", label: this.$t("api_test.automation.random")}, { value: "RANDOM", label: this.$t("api_test.automation.random") },
],
uiTypeSelectOptions: [
{value: "STRING", label: this.$t("api_test.automation.string")},
{value: "ARRAY", label: this.$t("api_test.automation.array")},
{value: "JSON", label: this.$t("api_test.automation.json")},
{value: "NUMBER", label: this.$t("api_test.automation.number")},
], ],
variables: {}, variables: {},
selectVariable: "", selectVariable: "",
editData: {}, editData: {},
scopeTypeFilters: [
{text: this.$t("commons.api"), value: "api"},
{text: this.$t("commons.ui_test"), value: "ui"},
]
}; };
}, },
watch: { watch: {
@ -343,7 +287,7 @@ export default {
} }
if (isNeedCreate) { if (isNeedCreate) {
this.variables.push( this.variables.push(
new KeyValue({enable: true, id: getUUID(), type: "CONSTANT", scope: "api"}) new KeyValue({ enable: true, id: getUUID(), type: "CONSTANT" })
); );
} }
this.$emit("change", this.variables); this.$emit("change", this.variables);
@ -360,10 +304,6 @@ export default {
data.files = []; data.files = [];
data.quotedData = "false"; data.quotedData = "false";
} }
if (!data.scope || data.scope == "ui") {
data.type = 'STRING';
}
}, },
valueText(data) { valueText(data) {
switch (data.type) { switch (data.type) {
@ -380,11 +320,11 @@ export default {
}, },
querySearch(queryString, cb) { querySearch(queryString, cb) {
let restaurants = [ let restaurants = [
{value: "UTF-8"}, { value: "UTF-8" },
{value: "UTF-16"}, { value: "UTF-16" },
{value: "GB2312"}, { value: "GB2312" },
{value: "ISO-8859-15"}, { value: "ISO-8859-15" },
{value: "US-ASCll"}, { value: "US-ASCll" },
]; ];
let results = queryString let results = queryString
? restaurants.filter(this.createFilter(queryString)) ? restaurants.filter(this.createFilter(queryString))
@ -406,9 +346,6 @@ export default {
this.$set(item, "description", item.remark); this.$set(item, "description", item.remark);
item.remark = undefined; item.remark = undefined;
} }
if (!item.scope) {
this.$set(item, "scope", "api");
}
index++; index++;
}); });
}, },
@ -432,7 +369,7 @@ export default {
} }
); );
}, },
filter(scope) { filter() {
let datas = []; let datas = [];
this.variables.forEach((item) => { this.variables.forEach((item) => {
if (this.selectVariable && this.selectVariable != "" && item.name) { if (this.selectVariable && this.selectVariable != "" && item.name) {
@ -452,12 +389,6 @@ export default {
}); });
this.variables = datas; this.variables = datas;
}, },
filterScope(value, row) {
if (value == "ui") {
return row.scope == "ui";
}
return !row.scope || row.scope == "api";
},
openSetting(data) { openSetting(data) {
this.$refs.apiVariableSetting.open(data); this.$refs.apiVariableSetting.open(data);
}, },
@ -518,15 +449,8 @@ export default {
this.sortParameters(); this.sortParameters();
}, },
exportJSON() { exportJSON() {
let apiVariable = []; if (this.$refs.variableTable.selectIds.length < 1) {
this.$refs.variableTable.selectRows.forEach((r) => { this.$warning(this.$t("api_test.environment.select_variable"));
if (!r.scope || r.scope != "ui") {
apiVariable.push(r);
}
});
if (apiVariable.length < 1) {
this.$warning(this.$t("api_test.environment.select_api_variable"));
return; return;
} }
let variablesJson = []; let variablesJson = [];
@ -536,7 +460,7 @@ export default {
if (row.type === "CSV") { if (row.type === "CSV") {
messages = this.$t("variables.csv_download"); messages = this.$t("variables.csv_download");
} }
if (row.name && (!row.scope || row.scope == "api")) { if (row.name) {
variablesJson.push(row); variablesJson.push(row);
} }
}); });
@ -569,21 +493,10 @@ export default {
} }
}); });
}, },
handleExportCommand(command){
this.exportJSON();
}
}, },
created() { created() {
if (this.items.length === 0) { if (this.items.length === 0) {
this.items.push(new KeyValue({enable: true, scope: "api"})); this.items.push(new KeyValue({ enable: true }));
} else {
// api
_.forEach(this.items, item => {
if (!item.scope) {
this.$set(item, "scope", "api");
}
})
this.variables = this.items;
} }
}, },
}; };

View File

@ -136,8 +136,8 @@ import MsTableOperator from "metersphere-frontend/src/components/MsTableOperator
import MsTableOperatorButton from "metersphere-frontend/src/components/MsTableOperatorButton"; import MsTableOperatorButton from "metersphere-frontend/src/components/MsTableOperatorButton";
import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination"; import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination";
import ApiEnvironmentConfig from "metersphere-frontend/src/components/environment/ApiEnvironmentConfig"; import ApiEnvironmentConfig from "metersphere-frontend/src/components/environment/ApiEnvironmentConfig";
import {Environment, parseEnvironment, HttpConfig} from "metersphere-frontend/src/model/EnvironmentModel"; import {Environment, parseEnvironment} from "metersphere-frontend/src/model/EnvironmentModel";
import EnvironmentEdit from "./components/EnvironmentEdit"; import EnvironmentEdit from "metersphere-frontend/src/components/environment/EnvironmentEdit";
import MsAsideItem from "metersphere-frontend/src/components/MsAsideItem"; import MsAsideItem from "metersphere-frontend/src/components/MsAsideItem";
import MsAsideContainer from "metersphere-frontend/src/components/MsAsideContainer"; import MsAsideContainer from "metersphere-frontend/src/components/MsAsideContainer";
import ProjectSwitch from "metersphere-frontend/src/components/head/ProjectSwitch"; import ProjectSwitch from "metersphere-frontend/src/components/head/ProjectSwitch";
@ -174,7 +174,7 @@ export default {
projectList: [], projectList: [],
condition: {}, // condition: {}, //
environments: [], environments: [],
currentEnvironment: new Environment({httpConfig: new HttpConfig()}), currentEnvironment: new Environment(),
result: {}, result: {},
loading: false, loading: false,
dialogVisible: false, dialogVisible: false,
@ -288,7 +288,7 @@ export default {
createEnv() { createEnv() {
this.dialogTitle = this.$t('api_test.environment.create'); this.dialogTitle = this.$t('api_test.environment.create');
this.dialogVisible = true; this.dialogVisible = true;
this.currentEnvironment = new Environment({httpConfig: new HttpConfig()}); this.currentEnvironment = new Environment();
this.currentEnvironment.projectId = this.currentProjectId; this.currentEnvironment.projectId = this.currentProjectId;
this.currentEnvironment.currentProjectId = this.currentProjectId; this.currentEnvironment.currentProjectId = this.currentProjectId;
this.ifCreate = true; this.ifCreate = true;

View File

@ -155,7 +155,7 @@ import {REQUEST_HEADERS} from "metersphere-frontend/src/utils/constants";
import {CommonConfig, Environment} from "metersphere-frontend/src/model/EnvironmentModel"; import {CommonConfig, Environment} from "metersphere-frontend/src/model/EnvironmentModel";
import MsApiHostTable from "metersphere-frontend/src/components/environment/commons/ApiHostTable"; import MsApiHostTable from "metersphere-frontend/src/components/environment/commons/ApiHostTable";
import MsDatabaseConfig from "metersphere-frontend/src/components/environment/database/DatabaseConfig"; import MsDatabaseConfig from "metersphere-frontend/src/components/environment/database/DatabaseConfig";
import MsEnvironmentHttpConfig from "./EnvironmentHttpConfig"; import MsEnvironmentHttpConfig from "metersphere-frontend/src/components/environment/EnvironmentHttpConfig";
import MsEnvironmentCommonConfig from "metersphere-frontend/src/components/environment/EnvironmentCommonConfig"; import MsEnvironmentCommonConfig from "metersphere-frontend/src/components/environment/EnvironmentCommonConfig";
import MsEnvironmentSSLConfig from "metersphere-frontend/src/components/environment/EnvironmentSSLConfig"; import MsEnvironmentSSLConfig from "metersphere-frontend/src/components/environment/EnvironmentSSLConfig";
import MsApiAuthConfig from "metersphere-frontend/src/components/environment/auth/ApiAuthConfig"; import MsApiAuthConfig from "metersphere-frontend/src/components/environment/auth/ApiAuthConfig";

View File

@ -65,6 +65,8 @@ import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.ServletOutputStream; import javax.servlet.ServletOutputStream;
@ -1548,10 +1550,6 @@ public class TestPlanService {
envMap = planTestPlanApiCaseService.getApiCaseEnv(planId); envMap = planTestPlanApiCaseService.getApiCaseEnv(planId);
Map<String, List<String>> scenarioEnv = planTestPlanScenarioCaseService.getApiScenarioEnv(planId); Map<String, List<String>> scenarioEnv = planTestPlanScenarioCaseService.getApiScenarioEnv(planId);
if (DiscoveryUtil.hasService(MicroServiceName.UI_TEST)) {
scenarioEnv = mergeUiScenarioEnv(planId, scenarioEnv);
}
Set<String> projectIds = scenarioEnv.keySet(); Set<String> projectIds = scenarioEnv.keySet();
for (String projectId : projectIds) { for (String projectId : projectIds) {
if (envMap.containsKey(projectId)) { if (envMap.containsKey(projectId)) {
@ -1574,32 +1572,6 @@ public class TestPlanService {
return envMap; return envMap;
} }
/**
* 合并ui场景的环境信息
* @param planId
* @param scenarioEnv
* @return
*/
private Map<String, List<String>> mergeUiScenarioEnv(String planId, Map<String, List<String>> scenarioEnv) {
Map<String, List<String>> uiScenarioEnv = planTestPlanUiScenarioCaseService.getUiScenarioEnv(planId);
if (MapUtils.isEmpty(scenarioEnv)) {
return uiScenarioEnv;
}
if (MapUtils.isNotEmpty(uiScenarioEnv)) {
uiScenarioEnv.entrySet().forEach(entry -> {
if (scenarioEnv.containsKey(entry.getKey())) {
List<String> environmentIds = scenarioEnv.get(entry.getKey());
entry.getValue().forEach(eId -> {
if (!environmentIds.contains(eId)) {
environmentIds.add(eId);
}
});
}
});
}
return scenarioEnv;
}
public String runPlan(TestPlanRunRequest testplanRunRequest) { public String runPlan(TestPlanRunRequest testplanRunRequest) {
//检查测试计划下有没有可以执行的用例 //检查测试计划下有没有可以执行的用例
if (!haveExecCase(testplanRunRequest.getTestPlanId(), false)) { if (!haveExecCase(testplanRunRequest.getTestPlanId(), false)) {

View File

@ -1857,6 +1857,22 @@ public class TestCaseService {
BeanUtils.copyBean(batchEdit, request); BeanUtils.copyBean(batchEdit, request);
batchEdit.setUpdateTime(System.currentTimeMillis()); batchEdit.setUpdateTime(System.currentTimeMillis());
bathUpdateByCondition(request, batchEdit); bathUpdateByCondition(request, batchEdit);
//批量修改选中数据其他版本的模块路径
if (request != null && (request.getIds() != null || !request.getIds().isEmpty())) {
request.getIds().forEach(testCaseId -> {
TestCaseWithBLOBs testCaseWithBLOBs = testCaseMapper.selectByPrimaryKey(testCaseId);
if (testCaseWithBLOBs == null) {
return;
}
if (StringUtils.isNotEmpty(request.getNodeId()) && StringUtils.isNotEmpty(request.getNodePath())) {
testCaseWithBLOBs.setNodeId(request.getNodeId());
testCaseWithBLOBs.setNodePath(request.getNodePath());
EditTestCaseRequest editTestCaseRequest = new EditTestCaseRequest();
BeanUtils.copyBean(editTestCaseRequest, testCaseWithBLOBs);
updateOtherVersionModule(editTestCaseRequest);
}
});
}
} }
} }

View File

@ -241,7 +241,12 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
if (endpoint.endsWith("/")) { if (endpoint.endsWith("/")) {
endpoint = endpoint.substring(0, endpoint.length() - 1); endpoint = endpoint.substring(0, endpoint.length() - 1);
} }
path = " <img src=\"" + endpoint + path + "\"/>"; String format = " <img src=\"%s\"/>";
if (path.trim().startsWith("http")) {
path = String.format(format, path);
} else {
path = String.format(format, endpoint + path);
}
result = matcher.replaceFirst(path); result = matcher.replaceFirst(path);
matcher = pattern.matcher(result); matcher = pattern.matcher(result);
} }

View File

@ -9,7 +9,8 @@
:plan-status="planStatus" :plan-status="planStatus"
@refresh="search" @refresh="search"
@relevanceCase="$emit('relevanceCase')" @relevanceCase="$emit('relevanceCase')"
v-if="isPlanModel"/> v-if="isPlanModel"
/>
</template> </template>
<ms-table <ms-table
v-loading="loading" v-loading="loading"
@ -29,17 +30,24 @@
:enable-order-drag="enableOrderDrag" :enable-order-drag="enableOrderDrag"
row-key="id" row-key="id"
@filter="search" @filter="search"
ref="table"> ref="table"
<span v-for="(item) in fields" :key="item.key"> >
<ms-table-column :field="item" <span v-for="item in fields" :key="item.key">
<ms-table-column
:field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
sortable sortable
label="ID" label="ID"
prop="num" prop="num"
min-width="80"> min-width="80"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span style="cursor:pointer" <span
v-if="!hasPermission('PROJECT_API_DEFINITION:READ+EDIT_CASE')"> {{ scope.row.num }} </span> style="cursor: pointer"
v-if="!hasPermission('PROJECT_API_DEFINITION:READ+EDIT_CASE')"
>
{{ scope.row.num }}
</span>
<el-link @click="openApiById(scope.row)" v-else> <el-link @click="openApiById(scope.row)" v-else>
<span> <span>
{{ scope.row.num }} {{ scope.row.num }}
@ -48,8 +56,14 @@
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :field="item" :fields-width="fieldsWidth" prop="name" sortable min-width="120" <ms-table-column
:label="$t('test_track.case.name')"/> :field="item"
:fields-width="fieldsWidth"
prop="name"
sortable
min-width="120"
:label="$t('test_track.case.name')"
/>
<ms-table-column <ms-table-column
v-if="versionEnable" v-if="versionEnable"
@ -58,7 +72,8 @@
:filters="versionFilters" :filters="versionFilters"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
:label="$t('commons.version')" :label="$t('commons.version')"
min-width="120px"> min-width="120px"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.versionName }}</span> <span>{{ scope.row.versionName }}</span>
</template> </template>
@ -71,9 +86,10 @@
:filters="priorityFilters" :filters="priorityFilters"
sortable sortable
:label="$t('test_track.case.priority')" :label="$t('test_track.case.priority')"
min-width="120px"> min-width="120px"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<priority-table-item :value="scope.row.priority"/> <priority-table-item :value="scope.row.priority" />
</template> </template>
</ms-table-column> </ms-table-column>
@ -82,7 +98,8 @@
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
min-width="100" min-width="100"
prop="path" prop="path"
:label="$t('api_test.definition.api_path')"/> :label="$t('api_test.definition.api_path')"
/>
<ms-table-column <ms-table-column
:field="item" :field="item"
@ -91,7 +108,8 @@
sortable sortable
min-width="100" min-width="100"
:filters="userFilters" :filters="userFilters"
:label="$t('commons.create_user')"> :label="$t('commons.create_user')"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
{{ scope.row.creatorName }} {{ scope.row.creatorName }}
</template> </template>
@ -103,9 +121,10 @@
prop="environmentName" prop="environmentName"
min-width="120" min-width="120"
show-overflow-tooltip show-overflow-tooltip
:label="$t('commons.environment')"> :label="$t('commons.environment')"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
{{ scope.row.environmentName || '-' }} {{ scope.row.environmentName || "-" }}
</template> </template>
</ms-table-column> </ms-table-column>
@ -114,39 +133,58 @@
prop="userId" prop="userId"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
:label="$t('custom_field.case_maintainer')" :label="$t('custom_field.case_maintainer')"
min-width="120"> min-width="120"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
{{ scope.row.principalName }} {{ scope.row.principalName }}
</template> </template>
</ms-table-column> </ms-table-column>
<ms-update-time-column :field="item" :fields-width="fieldsWidth"/> <ms-update-time-column :field="item" :fields-width="fieldsWidth" />
<ms-create-time-column :field="item" :fields-width="fieldsWidth"/> <ms-create-time-column :field="item" :fields-width="fieldsWidth" />
<ms-table-column <ms-table-column
:field="item" :field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="tags" prop="tags"
min-width="100" min-width="100"
:label="$t('commons.tag')"> :label="$t('commons.tag')"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" <ms-tag
:content="itemName" style="margin-left: 0px; margin-right: 2px"/> v-for="(itemName, index) in scope.row.tags"
:key="index"
type="success"
effect="plain"
:content="itemName"
style="margin-left: 0px; margin-right: 2px"
/>
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :field="item" <ms-table-column
:field="item"
prop="execResult" prop="execResult"
:filters="execResultFilters" :filters="execResultFilters"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
:label="$t('test_track.plan.execute_result')" min-width="150" align="center"> :label="$t('test_track.plan.execute_result')"
min-width="150"
align="center"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<div v-loading="rowLoading === scope.row.id"> <div v-loading="rowLoading === scope.row.id">
<el-link @click="getReportResult(scope.row)" <el-link
:disabled="!scope.row.execResult || scope.row.execResult==='PENDING'"> @click="getReportResult(scope.row)"
<ms-test-plan-api-status :status="scope.row.execResult"/> :disabled="
!scope.row.execResult || scope.row.execResult === 'PENDING'
"
>
<ms-test-plan-api-status :status="scope.row.execResult" />
</el-link> </el-link>
<div v-if="scope.row.id" style="color: #999999;font-size: 12px"> <div
v-if="scope.row.id"
style="color: #999999; font-size: 12px"
>
<span> {{ scope.row.updateTime | datetimeFormat }}</span> <span> {{ scope.row.updateTime | datetimeFormat }}</span>
{{ scope.row.updateUser }} {{ scope.row.updateUser }}
</div> </div>
@ -156,45 +194,66 @@
</span> </span>
</ms-table> </ms-table>
<ms-table-pagination :change="initTable" :current-page.sync="currentPage" :page-size.sync="pageSize" <ms-table-pagination
:total="total"/> :change="initTable"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:total="total"
/>
<test-plan-api-case-result ref="apiCaseResult"/> <test-plan-api-case-result ref="apiCaseResult" />
<!-- 批量编辑 --> <!-- 批量编辑 -->
<batch-edit :dialog-title="$t('test_track.case.batch_edit_case')" :type-arr="typeArr" :value-arr="valueArr" <batch-edit
:select-row="$refs.table ? $refs.table.selectRows : new Set()" ref="batchEdit" :dialog-title="$t('test_track.case.batch_edit_case')"
@batchEdit="batchEdit"/> :type-arr="typeArr"
:value-arr="valueArr"
:select-row="$refs.table ? $refs.table.selectRows : new Set()"
ref="batchEdit"
@batchEdit="batchEdit"
/>
<ms-test-plan-run-mode-with-env
<ms-test-plan-run-mode-with-env @handleRunBatch="handleRunBatch" ref="runMode" :plan-case-ids="testPlanCaseIds" :type="'apiCase'" @handleRunBatch="handleRunBatch"
@close="search" /> ref="runMode"
:plan-case-ids="testPlanCaseIds"
:type="'apiCase'"
@close="search"
/>
</el-card> </el-card>
<ms-task-center ref="taskCenter" :show-menu="false"/> <ms-task-center ref="taskCenter" :show-menu="false" />
</div> </div>
</template> </template>
<script> <script>
import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination"; import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination";
import MsTag from "metersphere-frontend/src/components/MsTag"; import MsTag from "metersphere-frontend/src/components/MsTag";
import MsContainer from "metersphere-frontend/src/components/MsContainer"; import MsContainer from "metersphere-frontend/src/components/MsContainer";
import MsBottomContainer from "metersphere-frontend/src/components/MsBottomContainer"; import MsBottomContainer from "metersphere-frontend/src/components/MsBottomContainer";
import BatchEdit from "@/business/case/components/BatchEdit"; import BatchEdit from "@/business/case/components/BatchEdit";
import {API_METHOD_COLOUR, CASE_PRIORITY, RESULT_MAP} from "metersphere-frontend/src/model/JsonData"; import {
import {getCurrentProjectID, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token"; API_METHOD_COLOUR,
import {hasLicense, hasPermission} from "metersphere-frontend/src/utils/permission"; CASE_PRIORITY,
import {getUUID, strMapToObj} from "metersphere-frontend/src/utils"; RESULT_MAP,
} from "metersphere-frontend/src/model/JsonData";
import {
getCurrentProjectID,
getCurrentWorkspaceId,
} from "metersphere-frontend/src/utils/token";
import {
hasLicense,
hasPermission,
} from "metersphere-frontend/src/utils/permission";
import { getUUID, strMapToObj } from "metersphere-frontend/src/utils";
import PriorityTableItem from "../../../../common/tableItems/planview/PriorityTableItem"; import PriorityTableItem from "../../../../common/tableItems/planview/PriorityTableItem";
import TestPlanCaseListHeader from "./TestPlanCaseListHeader"; import TestPlanCaseListHeader from "./TestPlanCaseListHeader";
import TestPlanApiCaseResult from "./TestPlanApiCaseResult"; import TestPlanApiCaseResult from "./TestPlanApiCaseResult";
import {TEST_PLAN_API_CASE} from "metersphere-frontend/src/utils/constants"; import { TEST_PLAN_API_CASE } from "metersphere-frontend/src/utils/constants";
import { import {
buildBatchParam, buildBatchParam,
deepClone, deepClone,
getCustomTableHeader, getCustomTableHeader,
getCustomTableWidth getCustomTableWidth,
} from "metersphere-frontend/src/utils/tableUtils"; } from "metersphere-frontend/src/utils/tableUtils";
import HeaderCustom from "metersphere-frontend/src/components/head/HeaderCustom"; import HeaderCustom from "metersphere-frontend/src/components/head/HeaderCustom";
import HeaderLabelOperate from "metersphere-frontend/src/components/head/HeaderLabelOperate"; import HeaderLabelOperate from "metersphere-frontend/src/components/head/HeaderLabelOperate";
@ -203,20 +262,27 @@ 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 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 {
import {getProjectMemberUserFilter} from "@/api/user"; editTestPlanApiCaseOrder,
import {apiTestCaseGet, apiTestCaseReduction} from "@/api/remote/api/api-case"; run,
testPlanAutoCheck,
} from "@/api/remote/plan/test-plan";
import { getProjectMemberUserFilter } from "@/api/user";
import {
apiTestCaseGet,
apiTestCaseReduction,
} from "@/api/remote/api/api-case";
import { import {
testPlanApiCaseBatchDelete, testPlanApiCaseBatchDelete,
testPlanApiCaseBatchUpdateEnv, testPlanApiCaseBatchUpdateEnv,
testPlanApiCaseDelete, testPlanApiCaseDelete,
testPlanApiCaseList, testPlanApiCaseList,
testPlanApiCaseRun, testPlanApiCaseRun,
testPlanApiCaseSelectAllTableRows testPlanApiCaseSelectAllTableRows,
} from "@/api/remote/plan/test-plan-api-case"; } from "@/api/remote/plan/test-plan-api-case";
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"; import MsTestPlanRunModeWithEnv from "@/business/plan/common/TestPlanRunModeWithEnv";
export default { export default {
@ -247,67 +313,72 @@ export default {
return { return {
type: TEST_PLAN_API_CASE, type: TEST_PLAN_API_CASE,
tableHeaderKey: "TEST_PLAN_API_CASE", tableHeaderKey: "TEST_PLAN_API_CASE",
fields: getCustomTableHeader('TEST_PLAN_API_CASE'), fields: getCustomTableHeader("TEST_PLAN_API_CASE"),
fieldsWidth: getCustomTableWidth('TEST_PLAN_API_CASE'), fieldsWidth: getCustomTableWidth("TEST_PLAN_API_CASE"),
tableLabel: [], tableLabel: [],
condition: { condition: {
components: TEST_PLAN_API_CASE_CONFIGS components: TEST_PLAN_API_CASE_CONFIGS,
}, },
selectCase: {}, selectCase: {},
loading: false, loading: false,
moduleId: "", moduleId: "",
status: 'default', status: "default",
deletePath: "/test/case/delete", deletePath: "/test/case/delete",
enableOrderDrag: true, enableOrderDrag: true,
operators: [ operators: [
{ {
tip: this.$t('api_test.run'), icon: "el-icon-video-play", tip: this.$t("api_test.run"),
icon: "el-icon-video-play",
exec: this.singleRun, exec: this.singleRun,
class: this.planStatus === 'Archived' ? 'disable-run' : 'run-button', class: this.planStatus === "Archived" ? "disable-run" : "run-button",
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+RUN'] permissions: ["PROJECT_TRACK_PLAN:READ+RUN"],
}, },
{ {
tip: this.$t('test_track.plan_view.cancel_relevance'), icon: "el-icon-unlock", tip: this.$t("test_track.plan_view.cancel_relevance"),
icon: "el-icon-unlock",
exec: this.handleDelete, exec: this.handleDelete,
type: 'danger', type: "danger",
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL'] permissions: ["PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL"],
} },
], ],
buttons: [ buttons: [
{ {
name: this.$t('test_track.case.batch_unlink'), name: this.$t("test_track.case.batch_unlink"),
handleClick: this.handleDeleteBatch, handleClick: this.handleDeleteBatch,
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_DELETE'] permissions: ["PROJECT_TRACK_PLAN:READ+CASE_BATCH_DELETE"],
}, },
{ {
name: this.$t('api_test.automation.batch_execute'), name: this.$t("api_test.automation.batch_execute"),
handleClick: this.handleBatchExecute, handleClick: this.handleBatchExecute,
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_RUN'] permissions: ["PROJECT_TRACK_PLAN:READ+CASE_BATCH_RUN"],
}, },
{ {
name: this.$t('test_track.case.batch_edit_case'), name: this.$t("test_track.case.batch_edit_case"),
handleClick: this.handleBatchEdit, handleClick: this.handleBatchEdit,
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_EDIT'] permissions: ["PROJECT_TRACK_PLAN:READ+CASE_BATCH_EDIT"],
} },
], ],
typeArr: [ typeArr: [
{id: 'projectEnv', name: this.$t('api_test.definition.request.run_env')}, {
id: "projectEnv",
name: this.$t("api_test.definition.request.run_env"),
},
], ],
priorityFilters: [ priorityFilters: [
{text: 'P0', value: 'P0'}, { text: "P0", value: "P0" },
{text: 'P1', value: 'P1'}, { text: "P1", value: "P1" },
{text: 'P2', value: 'P2'}, { text: "P2", value: "P2" },
{text: 'P3', value: 'P3'} { text: "P3", value: "P3" },
], ],
valueArr: { valueArr: {
priority: CASE_PRIORITY, priority: CASE_PRIORITY,
userId: [], userId: [],
projectEnv: [] projectEnv: [],
}, },
methodColorMap: new Map(API_METHOD_COLOUR), methodColorMap: new Map(API_METHOD_COLOUR),
tableData: [], tableData: [],
@ -315,7 +386,7 @@ export default {
pageSize: 10, pageSize: 10,
total: 0, total: 0,
selectDataCounts: 0, selectDataCounts: 0,
screenHeight: 'calc(100vh - 250px)',// screenHeight: "calc(100vh - 250px)", //
currentCaseProjectId: "", currentCaseProjectId: "",
runData: [], runData: [],
testPlanCaseIds: [], testPlanCaseIds: [],
@ -327,11 +398,11 @@ export default {
projectList: [], projectList: [],
versionFilters: [], versionFilters: [],
execResultFilters: [ execResultFilters: [
{text: 'Pending', value: 'PENDING'}, { text: "Pending", value: "PENDING" },
{text: 'Success', value: 'SUCCESS'}, { text: "Success", value: "SUCCESS" },
{text: 'Error', value: 'ERROR'}, { text: "Error", value: "ERROR" },
{text: "FakeError", value: 'FAKE_ERROR'}, { text: "FakeError", value: "FAKE_ERROR" },
] ],
}; };
}, },
props: { props: {
@ -347,7 +418,7 @@ export default {
}, },
isReadOnly: { isReadOnly: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
isCaseRelevance: { isCaseRelevance: {
type: Boolean, type: Boolean,
@ -356,8 +427,8 @@ export default {
model: { model: {
type: String, type: String,
default() { default() {
'api'; "api";
} },
}, },
planId: String, planId: String,
planStatus: String, planStatus: String,
@ -375,7 +446,7 @@ export default {
this.$EventBus.$off("API_TEST_END", this.handleTestEnd); this.$EventBus.$off("API_TEST_END", this.handleTestEnd);
}, },
activated() { activated() {
this.status = 'default'; this.status = "default";
}, },
watch: { watch: {
selectNodeIds() { selectNodeIds() {
@ -387,20 +458,20 @@ export default {
}, },
planId() { planId() {
this.initTable(); this.initTable();
} },
}, },
computed: { computed: {
// //
isRelevanceModel() { isRelevanceModel() {
return this.model === 'relevance'; return this.model === "relevance";
}, },
// //
isPlanModel() { isPlanModel() {
return this.model === 'plan'; return this.model === "plan";
}, },
// //
isApiModel() { isApiModel() {
return this.model === 'api'; return this.model === "api";
}, },
editTestPlanApiCaseOrder() { editTestPlanApiCaseOrder() {
return editTestPlanApiCaseOrder; return editTestPlanApiCaseOrder;
@ -418,7 +489,7 @@ export default {
}); });
}, },
isApiListEnableChange(data) { isApiListEnableChange(data) {
this.$emit('isApiListEnableChange', data); this.$emit("isApiListEnableChange", data);
}, },
initTable() { initTable() {
if (this.$refs.table) { if (this.$refs.table) {
@ -431,25 +502,30 @@ export default {
this.condition.protocol = this.currentProtocol; this.condition.protocol = this.currentProtocol;
} }
this.enableOrderDrag = (this.condition.orders && this.condition.orders.length) > 0 ? false : true; this.enableOrderDrag =
(this.condition.orders && this.condition.orders.length) > 0
? false
: true;
if (this.clickType) { if (this.clickType) {
if (this.status == 'default') { if (this.status == "default") {
this.condition.status = this.clickType; this.condition.status = this.clickType;
} else { } else {
this.condition.status = null; this.condition.status = null;
} }
this.status = 'all'; this.status = "all";
} }
if (this.planId) { if (this.planId) {
this.condition.planId = this.planId; this.condition.planId = this.planId;
this.loading = true; this.loading = true;
testPlanApiCaseList({pageNum: this.currentPage, pageSize: this.pageSize}, this.condition) testPlanApiCaseList(
.then(response => { { pageNum: this.currentPage, pageSize: this.pageSize },
this.condition
).then((response) => {
this.loading = false; this.loading = false;
this.total = response.data.itemCount; this.total = response.data.itemCount;
this.tableData = response.data.listObject; this.tableData = response.data.listObject;
this.tableData.forEach(item => { this.tableData.forEach((item) => {
if (item.tags && item.tags.length > 0) { if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags); item.tags = JSON.parse(item.tags);
} }
@ -466,34 +542,36 @@ export default {
}, },
reductionApi(row) { reductionApi(row) {
let ids = [row.id]; let ids = [row.id];
apiTestCaseReduction(ids) apiTestCaseReduction(ids).then(() => {
.then(() => { this.$success(this.$t("commons.save_success"));
this.$success(this.$t('commons.save_success'));
this.search(); this.search();
}); });
}, },
handleDeleteBatch() { handleDeleteBatch() {
this.$alert(this.$t('test_track.plan_view.confirm_cancel_relevance') + "", '', { this.$alert(
confirmButtonText: this.$t('commons.confirm'), this.$t("test_track.plan_view.confirm_cancel_relevance") + "",
"",
{
confirmButtonText: this.$t("commons.confirm"),
callback: (action) => { callback: (action) => {
if (action === 'confirm') { if (action === "confirm") {
let param = buildBatchParam(this); let param = buildBatchParam(this);
param.ids = this.$refs.table.selectIds; param.ids = this.$refs.table.selectIds;
if (this.planId) { if (this.planId) {
param.planId = this.planId; param.planId = this.planId;
testPlanApiCaseBatchDelete(param) testPlanApiCaseBatchDelete(param).then(() => {
.then(() => {
if (this.$refs.table) { if (this.$refs.table) {
this.$refs.table.clear(); this.$refs.table.clear();
} }
this.initTable(); this.initTable();
this.$emit('refresh'); this.$emit("refresh");
this.$success(this.$t('test_track.cancel_relevance_success')); this.$success(this.$t("test_track.cancel_relevance_success"));
}); });
} }
} }
},
} }
}); );
}, },
getResult(data) { getResult(data) {
if (RESULT_MAP.get(data)) { if (RESULT_MAP.get(data)) {
@ -503,8 +581,8 @@ export default {
} }
}, },
runRefresh() { runRefresh() {
this.rowLoading = ''; this.rowLoading = "";
this.$success(this.$t('schedule.event_success')); this.$success(this.$t("schedule.event_success"));
this.autoCheckStatus(); this.autoCheckStatus();
this.initTable(); this.initTable();
}, },
@ -524,7 +602,9 @@ export default {
} }
}, },
handleBatchEdit() { handleBatchEdit() {
this.$refs.batchEdit.open(this.condition.selectAll ? this.total : this.$refs.table.selectRows.size); this.$refs.batchEdit.open(
this.condition.selectAll ? this.total : this.$refs.table.selectRows.size
);
this.$refs.batchEdit.setSelectRows(this.$refs.table.selectRows); this.$refs.batchEdit.setSelectRows(this.$refs.table.selectRows);
}, },
getData() { getData() {
@ -535,14 +615,13 @@ export default {
if (this.condition != null && this.condition.selectAll) { if (this.condition != null && this.condition.selectAll) {
let selectAllRowParams = buildBatchParam(this); let selectAllRowParams = buildBatchParam(this);
selectAllRowParams.ids = this.$refs.table.selectIds; selectAllRowParams.ids = this.$refs.table.selectIds;
testPlanApiCaseSelectAllTableRows(selectAllRowParams) testPlanApiCaseSelectAllTableRows(selectAllRowParams).then(
.then(response => { (response) => {
let dataRows = response.data; let dataRows = response.data;
// //
this.orderBySelectRows(dataRows); this.orderBySelectRows(dataRows);
dataRows.forEach(row => { dataRows.forEach((row) => {
apiTestCaseGet(row.caseId) apiTestCaseGet(row.caseId).then((response) => {
.then((response) => {
let apiCase = response.data; let apiCase = response.data;
let request = JSON.parse(apiCase.request); let request = JSON.parse(apiCase.request);
request.name = row.id; request.name = row.id;
@ -556,13 +635,13 @@ export default {
index++; index++;
}); });
}); });
}); }
);
} else { } else {
// //
let dataRows = this.orderBySelectRows(this.$refs.table.selectRows); let dataRows = this.orderBySelectRows(this.$refs.table.selectRows);
dataRows.forEach(row => { dataRows.forEach((row) => {
apiTestCaseGet(row.caseId) apiTestCaseGet(row.caseId).then((response) => {
.then((response) => {
let apiCase = response.data; let apiCase = response.data;
let request = JSON.parse(apiCase.request); let request = JSON.parse(apiCase.request);
request.name = row.id; request.name = row.id;
@ -582,32 +661,32 @@ export default {
batchEdit(form) { batchEdit(form) {
let param = {}; let param = {};
// //
if (form.type === 'projectEnv') { if (form.type === "projectEnv") {
let selectAllRowParams = buildBatchParam(this); let selectAllRowParams = buildBatchParam(this);
selectAllRowParams.ids = this.$refs.table.selectIds; selectAllRowParams.ids = this.$refs.table.selectIds;
testPlanApiCaseSelectAllTableRows(selectAllRowParams) testPlanApiCaseSelectAllTableRows(selectAllRowParams).then(
.then(response => { (response) => {
let dataRows = response.data; let dataRows = response.data;
let map = new Map(); let map = new Map();
param.projectEnvMap = strMapToObj(form.projectEnvMap); param.projectEnvMap = strMapToObj(form.projectEnvMap);
param.environmentType = form.environmentType; param.environmentType = form.environmentType;
param.environmentGroupId = form.envGroupId; param.environmentGroupId = form.envGroupId;
dataRows.forEach(row => { dataRows.forEach((row) => {
map[row.id] = row.projectId; map[row.id] = row.projectId;
}); });
param.selectRows = map; param.selectRows = map;
testPlanApiCaseBatchUpdateEnv(param) testPlanApiCaseBatchUpdateEnv(param).then(() => {
.then(() => { this.$success(this.$t("commons.save_success"));
this.$success(this.$t('commons.save_success'));
this.initTable(); this.initTable();
}); });
}); }
);
} else { } else {
// //
} }
}, },
orderBySelectRows(rows) { orderBySelectRows(rows) {
let selectIds = Array.from(rows).map(row => row.id); let selectIds = Array.from(rows).map((row) => row.id);
let array = []; let array = [];
for (let i in this.tableData) { for (let i in this.tableData) {
if (selectIds.indexOf(this.tableData[i].id) !== -1) { if (selectIds.indexOf(this.tableData[i].id) !== -1) {
@ -619,21 +698,26 @@ export default {
handleBatchExecute() { handleBatchExecute() {
this.getData().then(() => { this.getData().then(() => {
if (this.runData && this.runData.length > 0) { if (this.runData && this.runData.length > 0) {
this.$refs.runMode.open('API'); this.$refs.runMode.open("API");
} }
}); });
}, },
handleRunBatch(config) { handleRunBatch(config) {
let obj = {planIds: this.testPlanCaseIds, config: config, triggerMode: "BATCH",projectId: getCurrentProjectID()}; let obj = {
planIds: this.testPlanCaseIds,
config: config,
triggerMode: "BATCH",
projectId: getCurrentProjectID(),
};
obj.config.envMap = strMapToObj(config.envMap); obj.config.envMap = strMapToObj(config.envMap);
testPlanApiCaseRun(obj) testPlanApiCaseRun(obj).then(() => {
.then(() => { this.$message(this.$t("commons.run_message"));
this.$message(this.$t('commons.run_message'));
this.$refs.taskCenter.open(); this.$refs.taskCenter.open();
this.search(); this.search();
}); });
}, },
autoCheckStatus() { // autoCheckStatus() {
//
if (!this.planId) { if (!this.planId) {
return; return;
} }
@ -641,10 +725,9 @@ export default {
}, },
handleDelete(apiCase) { handleDelete(apiCase) {
if (this.planId) { if (this.planId) {
testPlanApiCaseDelete(apiCase.id) testPlanApiCaseDelete(apiCase.id).then(() => {
.then(() => { this.$success(this.$t("test_track.cancel_relevance_success"));
this.$success(this.$t('test_track.cancel_relevance_success')); this.$emit("refresh");
this.$emit('refresh');
this.initTable(); this.initTable();
}); });
} }
@ -662,18 +745,28 @@ export default {
}, },
getVersionOptions() { getVersionOptions() {
if (hasLicense()) { if (hasLicense()) {
getProjectVersions(getCurrentProjectID()) getProjectVersions(getCurrentProjectID()).then((response) => {
.then(response => {
this.versionOptions = response.data; this.versionOptions = response.data;
this.versionFilters = response.data.map(u => { this.versionFilters = response.data.map((u) => {
return {text: u.name, value: u.id}; return { text: u.name, value: u.id };
}); });
}); });
} }
}, },
openApiById(item) { openApiById(item) {
let definitionData = this.$router.resolve('/api/definition/' + getUUID() + "/apiTestCase/single:" + item.caseId + "/" + getCurrentProjectID() + "/" + item.protocol + "/" + getCurrentWorkspaceId()); let definitionData = this.$router.resolve(
window.open(definitionData.href, '_blank'); "/api/definition/default/" +
getUUID() +
"/apiTestCase/single:" +
item.caseId +
"/" +
getCurrentProjectID() +
"/" +
item.protocol +
"/" +
getCurrentWorkspaceId()
);
window.open(definitionData.href, "_blank");
}, },
}, },
}; };
@ -687,7 +780,7 @@ export default {
.request-method { .request-method {
padding: 0 5px; padding: 0 5px;
color: #1E90FF; color: #1e90ff;
} }
.api-el-tag { .api-el-tag {
@ -700,5 +793,4 @@ export default {
/*margin-bottom: 20px;*/ /*margin-bottom: 20px;*/
margin-right: 20px; margin-right: 20px;
} }
</style> </style>

View File

@ -7,7 +7,8 @@
:projectId="projectId" :projectId="projectId"
:plan-status="planStatus" :plan-status="planStatus"
@refresh="filterSearch" @refresh="filterSearch"
@relevanceCase="$emit('relevanceCase', 'scenario')"/> @relevanceCase="$emit('relevanceCase', 'scenario')"
/>
</template> </template>
<ms-table <ms-table
@ -27,18 +28,24 @@
:row-order-group-id="planId" :row-order-group-id="planId"
@order="search" @order="search"
@filter="filterSearch" @filter="filterSearch"
ref="table"> ref="table"
<span v-for="(item) in fields" :key="item.key"> >
<span v-for="item in fields" :key="item.key">
<ms-table-column <ms-table-column
v-if="item.id == 'num'" v-if="item.id == 'num'"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
sortable sortable
prop="customNum" prop="customNum"
min-width="80px" min-width="80px"
label="ID"> label="ID"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span style="cursor:pointer" <span
v-if="!hasPermission('PROJECT_API_SCENARIO:READ+EDIT')"> {{ scope.row.num }} </span> style="cursor: pointer"
v-if="!hasPermission('PROJECT_API_SCENARIO:READ+EDIT')"
>
{{ scope.row.num }}
</span>
<el-link @click="openById(scope.row)" v-else> <el-link @click="openById(scope.row)" v-else>
<span> <span>
{{ scope.row.customNum }} {{ scope.row.customNum }}
@ -47,11 +54,14 @@
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :field="item" <ms-table-column
:field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="name" prop="name"
:label="$t('api_test.automation.scenario_name')" min-width="120px" :label="$t('api_test.automation.scenario_name')"
sortable/> min-width="120px"
sortable
/>
<ms-table-column <ms-table-column
:field="item" :field="item"
@ -59,20 +69,25 @@
prop="versionId" prop="versionId"
:filters="versionFilters" :filters="versionFilters"
:label="$t('commons.version')" :label="$t('commons.version')"
min-width="120px"> min-width="120px"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<span>{{ scope.row.versionName }}</span> <span>{{ scope.row.versionName }}</span>
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :field="item" <ms-table-column
:field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="level" :label="$t('api_test.automation.case_level')" min-width="120px" prop="level"
:label="$t('api_test.automation.case_level')"
min-width="120px"
column-key="level" column-key="level"
sortable sortable
:filters="apiscenariofilters.LEVEL_FILTERS"> :filters="apiscenariofilters.LEVEL_FILTERS"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<priority-table-item :value="scope.row.level" ref="level"/> <priority-table-item :value="scope.row.level" ref="level" />
</template> </template>
</ms-table-column> </ms-table-column>
@ -81,48 +96,68 @@
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="envs" prop="envs"
:label="$t('commons.environment')" :label="$t('commons.environment')"
min-width="150"> min-width="150"
<template v-slot:default="{row}"> >
<template v-slot:default="{ row }">
<div v-if="row.envs"> <div v-if="row.envs">
<span v-for="(k, v, index) in row.envs" :key="index"> <span v-for="(k, v, index) in row.envs" :key="index">
<span v-if="index===0 || index===1"> <span v-if="index === 0 || index === 1">
<span class="project-name" :title="v">{{ v }}</span>: <span class="project-name" :title="v">{{ v }}</span
>:
<el-tag type="success" size="mini" effect="plain"> <el-tag type="success" size="mini" effect="plain">
{{ k }} {{ k }}
</el-tag> </el-tag>
<br/> <br />
</span> </span>
<el-popover <el-popover placement="top" width="350" trigger="click">
placement="top"
width="350"
trigger="click">
<div v-for="(k, v, index) in row.envs" :key="index"> <div v-for="(k, v, index) in row.envs" :key="index">
<span class="plan-case-env">{{ v }}: <span class="plan-case-env"
<el-tag type="success" size="mini" effect="plain">{{ k }}</el-tag><br/> >{{ v }}:
<el-tag type="success" size="mini" effect="plain">{{
k
}}</el-tag
><br />
</span> </span>
</div> </div>
<el-link v-if="index === 2" slot="reference" type="info" :underline="false" icon="el-icon-more"/> <el-link
v-if="index === 2"
slot="reference"
type="info"
:underline="false"
icon="el-icon-more"
/>
</el-popover> </el-popover>
</span> </span>
</div> </div>
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :field="item" <ms-table-column
:field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="tagNames" :label="$t('api_test.automation.tag')" prop="tagNames"
min-width="100px"> :label="$t('api_test.automation.tag')"
min-width="100px"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<ms-tag v-for="(itemName,index) in scope.row.tags" :key="index" type="success" effect="plain" <ms-tag
:content="itemName" style="margin-left: 0px; margin-right: 2px"/> v-for="(itemName, index) in scope.row.tags"
:key="index"
type="success"
effect="plain"
:content="itemName"
style="margin-left: 0px; margin-right: 2px"
/>
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :field="item" <ms-table-column
:field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="createUser" prop="createUser"
:label="$t('api_test.automation.creator')" :label="$t('api_test.automation.creator')"
min-width="100px"> min-width="100px"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
{{ scope.row.creatorName }} {{ scope.row.creatorName }}
</template> </template>
@ -133,7 +168,8 @@
prop="userId" prop="userId"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
:label="$t('custom_field.case_maintainer')" :label="$t('custom_field.case_maintainer')"
min-width="120"> min-width="120"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
{{ scope.row.principalName }} {{ scope.row.principalName }}
</template> </template>
@ -144,56 +180,89 @@
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="principal" prop="principal"
:label="$t('custom_field.case_maintainer')" :label="$t('custom_field.case_maintainer')"
min-width="120"/> min-width="120"
/>
<ms-update-time-column :field="item" :fields-width="fieldsWidth"/> <ms-update-time-column :field="item" :fields-width="fieldsWidth" />
<ms-create-time-column :field="item" :fields-width="fieldsWidth"/> <ms-create-time-column :field="item" :fields-width="fieldsWidth" />
<ms-table-column
<ms-table-column :field="item" :field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="stepTotal" :label="$t('api_test.automation.step')" prop="stepTotal"
min-width="80px"/> :label="$t('api_test.automation.step')"
<ms-table-column :field="item" min-width="80px"
/>
<ms-table-column
:field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="lastResult" min-width="100px" prop="lastResult"
min-width="100px"
:filters="apiscenariofilters.RESULT_FILTERS" :filters="apiscenariofilters.RESULT_FILTERS"
:label="$t('api_test.automation.last_result')"> :label="$t('api_test.automation.last_result')"
<template v-slot:default="{row}"> >
<el-link @click="showReport(row)" :disabled="!row.lastResult || row.lastResult==='PENDING'"> <template v-slot:default="{ row }">
<ms-test-plan-api-status :status="row.lastResult"/> <el-link
@click="showReport(row)"
:disabled="!row.lastResult || row.lastResult === 'PENDING'"
>
<ms-test-plan-api-status :status="row.lastResult" />
</el-link> </el-link>
</template> </template>
</ms-table-column> </ms-table-column>
<ms-table-column :field="item" <ms-table-column
:field="item"
:fields-width="fieldsWidth" :fields-width="fieldsWidth"
prop="passRate" min-width="80px" prop="passRate"
:label="$t('api_test.automation.passing_rate')"/> min-width="80px"
:label="$t('api_test.automation.passing_rate')"
/>
</span> </span>
</ms-table> </ms-table>
<ms-table-pagination :change="search" :current-page.sync="currentPage" :page-size.sync="pageSize" <ms-table-pagination
:total="total"/> :change="search"
:current-page.sync="currentPage"
:page-size.sync="pageSize"
:total="total"
/>
<div> <div>
<!-- 执行结果 --> <!-- 执行结果 -->
<el-drawer :visible.sync="runVisible" :destroy-on-close="true" direction="ltr" :withHeader="true" :modal="false" <el-drawer
size="90%"> :visible.sync="runVisible"
:destroy-on-close="true"
direction="ltr"
:withHeader="true"
:modal="false"
size="90%"
>
<!-- 接口场景报告 --> <!-- 接口场景报告 -->
<micro-app :to="`/automation/report/view/${reportId}`" service="api"/> <micro-app
:to="`/automation/report/view/${reportId}`"
service="api"
/>
</el-drawer> </el-drawer>
</div> </div>
</el-card> </el-card>
<!-- 批量编辑 --> <!-- 批量编辑 -->
<batch-edit :dialog-title="$t('test_track.case.batch_edit_case')" :type-arr="typeArr" :value-arr="valueArr" <batch-edit
:select-row="this.$refs.table ? this.$refs.table.selectRows : new Set()" ref="batchEdit" :dialog-title="$t('test_track.case.batch_edit_case')"
@batchEdit="batchEdit"/> :type-arr="typeArr"
<ms-test-plan-run-mode-with-env @handleRunBatch="handleRunBatch" ref="runMode" :plan-case-ids="planCaseIds" :type="'apiScenario'" :value-arr="valueArr"
@close="search" /> :select-row="this.$refs.table ? this.$refs.table.selectRows : new Set()"
ref="batchEdit"
@batchEdit="batchEdit"
/>
<ms-test-plan-run-mode-with-env
@handleRunBatch="handleRunBatch"
ref="runMode"
:plan-case-ids="planCaseIds"
:type="'apiScenario'"
@close="search"
/>
<ms-task-center ref="taskCenter" :show-menu="false" />
<ms-task-center ref="taskCenter" :show-menu="false"/>
</div> </div>
</template> </template>
@ -201,29 +270,38 @@
import MsTableHeader from "metersphere-frontend/src/components/MsTableHeader"; import MsTableHeader from "metersphere-frontend/src/components/MsTableHeader";
import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination"; import MsTablePagination from "metersphere-frontend/src/components/pagination/TablePagination";
import MsTag from "metersphere-frontend/src/components/MsTag"; import MsTag from "metersphere-frontend/src/components/MsTag";
import {getCurrentProjectID, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token"; import {
import {getUUID, strMapToObj} from "metersphere-frontend/src/utils"; getCurrentProjectID,
import {hasLicense, hasPermission} from "metersphere-frontend/src/utils/permission"; getCurrentWorkspaceId,
} from "metersphere-frontend/src/utils/token";
import { getUUID, strMapToObj } from "metersphere-frontend/src/utils";
import {
hasLicense,
hasPermission,
} from "metersphere-frontend/src/utils/permission";
import MsTableMoreBtn from "metersphere-frontend/src/components/table/TableMoreBtn"; import MsTableMoreBtn from "metersphere-frontend/src/components/table/TableMoreBtn";
import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader"; import TestPlanScenarioListHeader from "./TestPlanScenarioListHeader";
import { import {
buildBatchParam, buildBatchParam,
getCustomTableHeader, getCustomTableHeader,
getCustomTableWidth, getCustomTableWidth,
initCondition initCondition,
} from "metersphere-frontend/src/utils/tableUtils"; } from "metersphere-frontend/src/utils/tableUtils";
import {ENV_TYPE, TEST_PLAN_SCENARIO_CASE} from "metersphere-frontend/src/utils/constants"; import {
ENV_TYPE,
TEST_PLAN_SCENARIO_CASE,
} from "metersphere-frontend/src/utils/constants";
import HeaderLabelOperate from "metersphere-frontend/src/components/head/HeaderLabelOperate"; import HeaderLabelOperate from "metersphere-frontend/src/components/head/HeaderLabelOperate";
import BatchEdit from "@/business/case/components/BatchEdit"; import BatchEdit from "@/business/case/components/BatchEdit";
import MsPlanRunMode from "@/business/plan/common/PlanRunModeWithEnv"; import MsPlanRunMode from "@/business/plan/common/PlanRunModeWithEnv";
import PriorityTableItem from "@/business/common/tableItems/planview/PriorityTableItem"; import PriorityTableItem from "@/business/common/tableItems/planview/PriorityTableItem";
import {API_SCENARIO_FILTERS} from "metersphere-frontend/src/utils/table-constants"; import { API_SCENARIO_FILTERS } from "metersphere-frontend/src/utils/table-constants";
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 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 {editTestPlanScenarioCaseOrder} from "@/api/remote/plan/test-plan"; import { editTestPlanScenarioCaseOrder } from "@/api/remote/plan/test-plan";
import { import {
testPlanScenarioCaseBatchDelete, testPlanScenarioCaseBatchDelete,
testPlanScenarioCaseBatchUpdateEnv, testPlanScenarioCaseBatchUpdateEnv,
@ -231,14 +309,14 @@ import {
testPlanScenarioCaseRun, testPlanScenarioCaseRun,
testPlanScenarioCaseSelectAllTableRows, testPlanScenarioCaseSelectAllTableRows,
testPlanScenarioEnv, testPlanScenarioEnv,
testPlanScenarioList testPlanScenarioList,
} from "@/api/remote/plan/test-plan-scenario"; } from "@/api/remote/plan/test-plan-scenario";
import {environmentGroupGetProjectMapName} from "@/api/environment-group"; import { environmentGroupGetProjectMapName } from "@/api/environment-group";
import {apiAutomationReduction} from "@/api/remote/api/api-automation"; import { apiAutomationReduction } from "@/api/remote/api/api-automation";
import MicroApp from "metersphere-frontend/src/components/MicroApp"; 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"; import MsTestPlanRunModeWithEnv from "@/business/plan/common/TestPlanRunModeWithEnv";
export default { export default {
@ -277,13 +355,13 @@ export default {
return { return {
type: TEST_PLAN_SCENARIO_CASE, type: TEST_PLAN_SCENARIO_CASE,
tableHeaderKey: "TEST_PLAN_SCENARIO_CASE", tableHeaderKey: "TEST_PLAN_SCENARIO_CASE",
fields: getCustomTableHeader('TEST_PLAN_SCENARIO_CASE'), fields: getCustomTableHeader("TEST_PLAN_SCENARIO_CASE"),
fieldsWidth: getCustomTableWidth('TEST_PLAN_SCENARIO_CASE'), fieldsWidth: getCustomTableWidth("TEST_PLAN_SCENARIO_CASE"),
screenHeight: 'calc(100vh - 250px)',// screenHeight: "calc(100vh - 250px)", //
tableLabel: [], tableLabel: [],
loading: false, loading: false,
condition: { condition: {
components: TEST_PLAN_API_SCENARIO_CONFIGS components: TEST_PLAN_API_SCENARIO_CONFIGS,
}, },
currentScenario: {}, currentScenario: {},
schedule: {}, schedule: {},
@ -294,57 +372,62 @@ export default {
pageSize: 10, pageSize: 10,
total: 0, total: 0,
reportId: "", reportId: "",
status: 'default', status: "default",
infoDb: false, infoDb: false,
runVisible: false, runVisible: false,
runData: [], runData: [],
enableOrderDrag: true, enableOrderDrag: true,
operators: [ operators: [
{ {
tip: this.$t('api_test.run'), icon: "el-icon-video-play", tip: this.$t("api_test.run"),
icon: "el-icon-video-play",
exec: this.execute, exec: this.execute,
class: this.planStatus === 'Archived' ? 'disable-run' : 'run-button', class: this.planStatus === "Archived" ? "disable-run" : "run-button",
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+RUN'] permissions: ["PROJECT_TRACK_PLAN:READ+RUN"],
}, },
{ {
tip: this.$t('test_track.plan_view.cancel_relevance'), icon: "el-icon-unlock", tip: this.$t("test_track.plan_view.cancel_relevance"),
icon: "el-icon-unlock",
exec: this.remove, exec: this.remove,
type: 'danger', type: "danger",
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL'] permissions: ["PROJECT_TRACK_PLAN:READ+RELEVANCE_OR_CANCEL"],
} },
], ],
buttons: [ buttons: [
{ {
name: this.$t('test_track.case.batch_unlink'), name: this.$t("test_track.case.batch_unlink"),
handleClick: this.handleDeleteBatch, handleClick: this.handleDeleteBatch,
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_DELETE'] permissions: ["PROJECT_TRACK_PLAN:READ+CASE_BATCH_DELETE"],
}, },
{ {
name: this.$t('api_test.automation.batch_execute'), name: this.$t("api_test.automation.batch_execute"),
handleClick: this.handleBatchExecute, handleClick: this.handleBatchExecute,
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_RUN'] permissions: ["PROJECT_TRACK_PLAN:READ+CASE_BATCH_RUN"],
}, },
{ {
name: this.$t('test_track.case.batch_edit_case'), name: this.$t("test_track.case.batch_edit_case"),
handleClick: this.handleBatchEdit, handleClick: this.handleBatchEdit,
isDisable: this.planStatus === 'Archived', isDisable: this.planStatus === "Archived",
permissions: ['PROJECT_TRACK_PLAN:READ+CASE_BATCH_EDIT'] permissions: ["PROJECT_TRACK_PLAN:READ+CASE_BATCH_EDIT"],
} },
], ],
typeArr: [ typeArr: [
{id: 'projectEnv', name: this.$t('api_test.definition.request.run_env')}, {
id: "projectEnv",
name: this.$t("api_test.definition.request.run_env"),
},
], ],
valueArr: { valueArr: {
projectEnv: [] projectEnv: [],
}, },
planCaseIds: [], planCaseIds: [],
apiscenariofilters: {}, apiscenariofilters: {},
versionFilters: [], versionFilters: [],
} };
}, },
computed: { computed: {
projectId() { projectId() {
@ -352,7 +435,7 @@ export default {
}, },
editTestPlanScenarioCaseOrder() { editTestPlanScenarioCaseOrder() {
return editTestPlanScenarioCaseOrder; return editTestPlanScenarioCaseOrder;
} },
}, },
created() { created() {
this.apiscenariofilters = API_SCENARIO_FILTERS(); this.apiscenariofilters = API_SCENARIO_FILTERS();
@ -366,7 +449,7 @@ export default {
}, },
planId() { planId() {
this.search(); this.search();
} },
}, },
methods: { methods: {
hasPermission, hasPermission,
@ -380,53 +463,58 @@ export default {
this.loading = true; this.loading = true;
this.condition.moduleIds = this.selectNodeIds; this.condition.moduleIds = this.selectNodeIds;
if (this.clickType) { if (this.clickType) {
if (this.status == 'default') { if (this.status == "default") {
this.condition.status = this.clickType; this.condition.status = this.clickType;
} else { } else {
this.condition.status = null; this.condition.status = null;
} }
this.status = 'all'; this.status = "all";
} }
this.enableOrderDrag = (this.condition.orders && this.condition.orders.length) > 0 ? false : true; this.enableOrderDrag =
(this.condition.orders && this.condition.orders.length) > 0
? false
: true;
if (this.planId) { if (this.planId) {
this.condition.planId = this.planId; this.condition.planId = this.planId;
testPlanScenarioList({pageNum: this.currentPage, pageSize: this.pageSize}, this.condition) testPlanScenarioList(
.then(response => { { pageNum: this.currentPage, pageSize: this.pageSize },
this.condition
).then((response) => {
let data = response.data; let data = response.data;
this.total = data.itemCount; this.total = data.itemCount;
this.tableData = data.listObject; this.tableData = data.listObject;
this.tableData.forEach(item => { this.tableData.forEach((item) => {
if (item.tags && item.tags.length > 0) { if (item.tags && item.tags.length > 0) {
item.tags = JSON.parse(item.tags); item.tags = JSON.parse(item.tags);
} }
}); });
this.tableData.forEach(item => { this.tableData.forEach((item) => {
try { try {
let envs; let envs;
const type = item.environmentType; const type = item.environmentType;
if (type === ENV_TYPE.GROUP && item.environmentGroupId) { if (type === ENV_TYPE.GROUP && item.environmentGroupId) {
environmentGroupGetProjectMapName(item.environmentGroupId) environmentGroupGetProjectMapName(item.environmentGroupId).then(
.then(res => { (res) => {
let data = res.data; let data = res.data;
if (data) { if (data) {
envs = new Map(Object.entries(data)); envs = new Map(Object.entries(data));
this.$set(item, 'envs', res.data); this.$set(item, "envs", res.data);
} }
}); }
);
} else if (type === ENV_TYPE.JSON) { } else if (type === ENV_TYPE.JSON) {
envs = JSON.parse(item.environment); envs = JSON.parse(item.environment);
if (envs) { if (envs) {
testPlanScenarioEnv(envs) testPlanScenarioEnv(envs).then((res) => {
.then(res => { this.$set(item, "envs", res.data);
this.$set(item, 'envs', res.data);
}); });
} }
} }
} catch (error) { } catch (error) {
this.$set(item, 'envs', {}); this.$set(item, "envs", {});
} }
}) });
this.loading = false; this.loading = false;
}); });
} }
@ -434,25 +522,24 @@ export default {
reductionApi(row) { reductionApi(row) {
row.scenarioDefinition = null; row.scenarioDefinition = null;
let rows = [row]; let rows = [row];
apiAutomationReduction(rows) apiAutomationReduction(rows).then((response) => {
.then(response => { this.$success(this.$t("commons.save_success"));
this.$success(this.$t('commons.save_success'));
this.search(); this.search();
}); });
}, },
handleBatchExecute() { handleBatchExecute() {
let rows = this.orderBySelectRows(this.$refs.table.selectRows); let rows = this.orderBySelectRows(this.$refs.table.selectRows);
this.planCaseIds = []; this.planCaseIds = [];
rows.forEach(row => { rows.forEach((row) => {
this.planCaseIds.push(row.id); this.planCaseIds.push(row.id);
}) });
//this.planCaseIds //this.planCaseIds
this.$nextTick(()=>{ this.$nextTick(() => {
this.$refs.runMode.open('API'); this.$refs.runMode.open("API");
}) });
}, },
orderBySelectRows(rows) { orderBySelectRows(rows) {
let selectIds = Array.from(rows).map(row => row.id); let selectIds = Array.from(rows).map((row) => row.id);
let array = []; let array = [];
for (let i in this.tableData) { for (let i in this.tableData) {
if (selectIds.indexOf(this.tableData[i].id) !== -1) { if (selectIds.indexOf(this.tableData[i].id) !== -1) {
@ -465,9 +552,9 @@ export default {
let rows = this.orderBySelectRows(this.$refs.table.selectRows); let rows = this.orderBySelectRows(this.$refs.table.selectRows);
if (this.planId) { if (this.planId) {
let selectParam = buildBatchParam(this); let selectParam = buildBatchParam(this);
let param = {config: config, planCaseIds: []}; let param = { config: config, planCaseIds: [] };
param.ids = rows.map(r => r.id); param.ids = rows.map((r) => r.id);
rows.forEach(row => { rows.forEach((row) => {
this.buildExecuteParam(param, row); this.buildExecuteParam(param, row);
}); });
param.config.envMap = strMapToObj(config.envMap); param.config.envMap = strMapToObj(config.envMap);
@ -475,9 +562,8 @@ export default {
param.triggerMode = "BATCH"; param.triggerMode = "BATCH";
param.requestOriginator = "TEST_PLAN"; param.requestOriginator = "TEST_PLAN";
param.projectId = this.projectId; param.projectId = this.projectId;
testPlanScenarioCaseRun(param) testPlanScenarioCaseRun(param).then(() => {
.then(() => { this.$message(this.$t("commons.run_message"));
this.$message(this.$t('commons.run_message'));
this.$refs.taskCenter.open(); this.$refs.taskCenter.open();
this.search(); this.search();
}); });
@ -485,14 +571,14 @@ export default {
}, },
execute(row) { execute(row) {
this.infoDb = false; this.infoDb = false;
let param = {planCaseIds: []}; let param = { planCaseIds: [] };
this.reportId = ""; this.reportId = "";
this.buildExecuteParam(param, row); this.buildExecuteParam(param, row);
param.triggerMode = "MANUAL"; param.triggerMode = "MANUAL";
param.requestOriginator = "TEST_PLAN"; param.requestOriginator = "TEST_PLAN";
param.projectId = this.projectId; param.projectId = this.projectId;
param.config = { param.config = {
mode: "serial" mode: "serial",
}; };
if (this.planId) { if (this.planId) {
this.loading = true; this.loading = true;
@ -505,8 +591,9 @@ export default {
this.reportId = response.data[0].reportId; this.reportId = response.data[0].reportId;
} }
this.search(); this.search();
}, 2000) }, 2000);
}).catch(() => { })
.catch(() => {
this.loading = false; this.loading = false;
}); });
} }
@ -526,48 +613,57 @@ export default {
}, },
remove(row) { remove(row) {
if (this.planId) { if (this.planId) {
testPlanScenarioCaseDelete(row.id) testPlanScenarioCaseDelete(row.id).then(() => {
.then(() => { this.$success(this.$t("test_track.cancel_relevance_success"));
this.$success(this.$t('test_track.cancel_relevance_success')); this.$emit("refresh");
this.$emit('refresh');
this.search(); this.search();
}); });
} }
}, },
handleDeleteBatch() { handleDeleteBatch() {
this.$alert(this.$t('test_track.plan_view.confirm_cancel_relevance') + "", '', { this.$alert(
confirmButtonText: this.$t('commons.confirm'), this.$t("test_track.plan_view.confirm_cancel_relevance") + "",
"",
{
confirmButtonText: this.$t("commons.confirm"),
callback: (action) => { callback: (action) => {
if (action === 'confirm') { if (action === "confirm") {
let param = buildBatchParam(this); let param = buildBatchParam(this);
param.ids = this.$refs.table.selectIds; param.ids = this.$refs.table.selectIds;
if (this.planId) { if (this.planId) {
param.planId = this.planId; param.planId = this.planId;
testPlanScenarioCaseBatchDelete(param) testPlanScenarioCaseBatchDelete(param).then(() => {
.then(() => {
this.$refs.table.selectRows.clear(); this.$refs.table.selectRows.clear();
this.search(); this.search();
this.$success(this.$t('test_track.cancel_relevance_success')); this.$success(this.$t("test_track.cancel_relevance_success"));
this.$emit('refresh'); this.$emit("refresh");
}); });
} }
} }
},
} }
}); );
}, },
handleBatchEdit() { handleBatchEdit() {
if (this.condition != null && this.condition.selectAll) { if (this.condition != null && this.condition.selectAll) {
let selectAllRowParams = buildBatchParam(this); let selectAllRowParams = buildBatchParam(this);
selectAllRowParams.ids = this.$refs.table.selectIds; selectAllRowParams.ids = this.$refs.table.selectIds;
testPlanScenarioCaseSelectAllTableRows(selectAllRowParams) testPlanScenarioCaseSelectAllTableRows(selectAllRowParams).then(
.then(response => { (response) => {
let dataRows = response.data; let dataRows = response.data;
this.$refs.batchEdit.open(dataRows.size); this.$refs.batchEdit.open(dataRows.size);
this.$refs.batchEdit.setScenarioSelectRows(dataRows, "planScenario"); this.$refs.batchEdit.setScenarioSelectRows(
}); dataRows,
"planScenario"
);
}
);
} else { } else {
this.$refs.batchEdit.open(this.$refs.table.selectRows.size); this.$refs.batchEdit.open(this.$refs.table.selectRows.size);
this.$refs.batchEdit.setScenarioSelectRows(this.$refs.table.selectRows, "planScenario"); this.$refs.batchEdit.setScenarioSelectRows(
this.$refs.table.selectRows,
"planScenario"
);
} }
}, },
batchEdit(form) { batchEdit(form) {
@ -577,29 +673,37 @@ export default {
param.environmentType = form.environmentType; param.environmentType = form.environmentType;
param.envGroupId = form.envGroupId; param.envGroupId = form.envGroupId;
if (this.planId) { if (this.planId) {
testPlanScenarioCaseBatchUpdateEnv(param) testPlanScenarioCaseBatchUpdateEnv(param).then(() => {
.then(() => { this.$success(this.$t("commons.save_success"));
this.$success(this.$t('commons.save_success'));
this.search(); this.search();
}); });
} }
}, },
getVersionOptions() { getVersionOptions() {
if (hasLicense()) { if (hasLicense()) {
getVersionFilters(getCurrentProjectID()) getVersionFilters(getCurrentProjectID()).then(
.then(r => this.versionFilters = r.data); (r) => (this.versionFilters = r.data)
);
} }
}, },
openById(item) { openById(item) {
let automationData = this.$router.resolve('/api/automation/' + getUUID() + "/scenario/edit:" + item.caseId + "/" + item.projectId + "/" + getCurrentWorkspaceId()); let automationData = this.$router.resolve(
window.open(automationData.href, '_blank'); "/api/automation/default/" +
getUUID() +
"/scenario/edit:" +
item.caseId +
"/" +
item.projectId +
"/" +
getCurrentWorkspaceId()
);
window.open(automationData.href, "_blank");
}, },
} },
} };
</script> </script>
<style scoped> <style scoped>
.plan-case-env { .plan-case-env {
display: inline-block; display: inline-block;
padding: 0 0; padding: 0 0;
@ -619,5 +723,4 @@ export default {
width: 80px; width: 80px;
vertical-align: middle; vertical-align: middle;
} }
</style> </style>

View File

@ -1,21 +1,5 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<env-group-popover
:env-map="projectEnvMap"
:project-ids="projectIds"
:show-env-group="false"
@setProjectEnvMap="setProjectEnvMap"
:environment-type.sync="environmentType"
:group-id="envGroupId"
:is-scenario="false"
@setEnvGroup="setEnvGroup"
:show-config-button-with-out-permission="
showConfigButtonWithOutPermission
"
:project-list="projectList"
ref="envPopover"
class="env-popover"
/>
<ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar" <ms-table-adv-search-bar :condition.sync="condition" class="adv-search-bar"
v-if="condition.components !== undefined && condition.components.length > 0" v-if="condition.components !== undefined && condition.components.length > 0"
@ -115,9 +99,6 @@ import {
getCustomTableWidth getCustomTableWidth
} from "metersphere-frontend/src/utils/tableUtils"; } from "metersphere-frontend/src/utils/tableUtils";
import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn"; import MsTableColumn from "metersphere-frontend/src/components/table/MsTableColumn";
import EnvGroupPopover from "@/business/plan/env/EnvGroupPopover";
import {getApiScenarioEnvByProjectId} from "@/api/remote/api/api-automation";
import {getUiScenarioEnvByProjectId} from "@/api/remote/ui/ui-automation";
export default { export default {
name: "RelevanceUiScenarioList", name: "RelevanceUiScenarioList",
@ -131,7 +112,6 @@ export default {
MsTag, MsTag,
MsTableAdvSearchBar, MsTableAdvSearchBar,
MsTableColumn, MsTableColumn,
EnvGroupPopover,
}, },
props: { props: {
referenced: { referenced: {
@ -167,7 +147,6 @@ export default {
envGroupId: "", envGroupId: "",
versionFilters: [], versionFilters: [],
fieldsWidth: getCustomTableWidth('TEST_PLAN_UI_SCENARIO_CASE'), fieldsWidth: getCustomTableWidth('TEST_PLAN_UI_SCENARIO_CASE'),
projectIds: new Set()
}; };
}, },
computed: { computed: {
@ -265,22 +244,10 @@ export default {
selectCountChange(data) { selectCountChange(data) {
this.selectRows = this.$refs.scenarioTable.selectRows; this.selectRows = this.$refs.scenarioTable.selectRows;
this.$emit("selectCountChange", data); this.$emit("selectCountChange", data);
this.initProjectIds();
}, },
showReport() { showReport() {
}, }
initProjectIds() {
this.projectIds.clear();
// this.map.clear();
this.selectRows.forEach((row) => {
getUiScenarioEnvByProjectId(row.id).then((res) => {
let data = res.data;
data.projectIds.forEach((d) => this.projectIds.add(d));
// this.map.set(row.id, data.projectIds);
});
});
},
} }
}; };
</script> </script>

View File

@ -148,10 +148,6 @@ export default {
let map = this.$refs.apiScenarioList.map; let map = this.$refs.apiScenarioList.map;
let envGroupId = this.$refs.apiScenarioList.envGroupId; let envGroupId = this.$refs.apiScenarioList.envGroupId;
if (!envMap || envMap.size == 0) {
this.$warning(this.$t('api_test.environment.select_environment'));
return;
}
selectRows.forEach(row => { selectRows.forEach(row => {
selectIds.push(row.id); selectIds.push(row.id);
}) })
@ -183,6 +179,8 @@ export default {
this.autoCheckStatus(); this.autoCheckStatus();
this.$refs.baseRelevance.close(); this.$refs.baseRelevance.close();
}); });
}, },
autoCheckStatus() { // autoCheckStatus() { //
if (!this.planId) { if (!this.planId) {

View File

@ -147,8 +147,7 @@
:filters="apiscenariofilters.RESULT_FILTERS" :filters="apiscenariofilters.RESULT_FILTERS"
:label="$t('api_test.automation.last_result')"> :label="$t('api_test.automation.last_result')">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
<el-link @click="showReport(row)" <el-link @click="showReport(row)" :disabled="!row.lastResult || row.lastResult==='PENDING' || row.lastResult==='UnExecute'">
:disabled="!row.lastResult || row.lastResult==='PENDING' || row.lastResult==='UnExecute'">
<ms-test-plan-api-status :status="row.lastResult==='UnExecute' ? 'PENDING' : row.lastResult"/> <ms-test-plan-api-status :status="row.lastResult==='UnExecute' ? 'PENDING' : row.lastResult"/>
</el-link> </el-link>
</template> </template>
@ -178,7 +177,7 @@
@batchEdit="batchEdit"/> @batchEdit="batchEdit"/>
<ui-run-mode @handleRunBatch="handleRunBatch" ref="runMode" :custom-run-mode="true" <ui-run-mode @handleRunBatch="handleRunBatch" ref="runMode" :custom-run-mode="true"
:custom-serial-on-sample-error="true" :request="conditionRequest"/> :custom-serial-on-sample-error="true"/>
<ms-task-center ref="taskCenter" :show-menu="false"/> <ms-task-center ref="taskCenter" :show-menu="false"/>
</div> </div>
@ -328,8 +327,6 @@ export default {
] ]
}, },
versionFilters: [], versionFilters: [],
//
conditionRequest: {}
} }
}, },
computed: { computed: {
@ -361,14 +358,14 @@ export default {
}, },
search() { search() {
initCondition(this.condition, this.condition.selectAll); initCondition(this.condition, this.condition.selectAll);
if (this.condition && this.condition.filters && this.condition.filters.last_result) { if(this.condition && this.condition.filters && this.condition.filters.last_result){
if (this.condition.filters.last_result.length > 0) { if(this.condition.filters.last_result.length > 0){
//PENDING //PENDING
if (this.condition.filters.last_result.includes("PENDING")) { if(this.condition.filters.last_result.includes("PENDING")){
this.condition.filters.last_result = [...this.condition.filters.last_result, "UnExecute"] this.condition.filters.last_result = [...this.condition.filters.last_result, "UnExecute"]
} }
//ERROR //ERROR
if (this.condition.filters.last_result.includes("ERROR")) { if(this.condition.filters.last_result.includes("ERROR")){
this.condition.filters.last_result = [...this.condition.filters.last_result, "FAIL"] this.condition.filters.last_result = [...this.condition.filters.last_result, "FAIL"]
} }
} }
@ -440,19 +437,12 @@ export default {
let rows = this.orderBySelectRows(this.$refs.table.selectRows); let rows = this.orderBySelectRows(this.$refs.table.selectRows);
this.planCaseIds = []; this.planCaseIds = [];
rows.forEach(row => { rows.forEach(row => {
this.planCaseIds.push(row.caseId); this.planCaseIds.push(row.id);
}) })
this.conditionRequest.id = getUUID();
this.conditionRequest.ids = this.planCaseIds;
this.conditionRequest.projectId = this.projectId;
this.conditionRequest.condition = this.condition;
this.$refs.runMode.open(); this.$refs.runMode.open();
}, },
orderBySelectRows(rows) { orderBySelectRows(rows) {
let selectIds = this.$refs.table.selectIds; let selectIds = Array.from(rows).map(row => row.id);
if (rows) {
selectIds = Array.from(rows).map(row => row.id);
}
let array = []; let array = [];
for (let i in this.tableData) { for (let i in this.tableData) {
if (selectIds.indexOf(this.tableData[i].id) !== -1) { if (selectIds.indexOf(this.tableData[i].id) !== -1) {

View File

@ -7,21 +7,6 @@
:visible.sync="runModeVisible" :visible.sync="runModeVisible"
> >
<div class="mode-container"> <div class="mode-container">
<div>
<div>{{ $t("commons.environment") }}</div>
<env-select-popover :project-ids="projectIds"
:project-list="projectList"
:project-env-map="projectEnvListMap"
:environment-type="'JSON'"
:has-option-group="false"
:group-id="runConfig.environmentGroupId"
@setProjectEnvMap="setProjectEnvMap"
ref="envSelectPopover"
class="mode-row"
></env-select-popover>
</div>
<!-- 浏览器 --> <!-- 浏览器 -->
<div class="browser-row wrap"> <div class="browser-row wrap">
<div class="title">{{ $t("ui.browser") }}</div> <div class="title">{{ $t("ui.browser") }}</div>
@ -190,13 +175,11 @@
<script> <script>
import MsDialogFooter from 'metersphere-frontend/src/components/MsDialogFooter' import MsDialogFooter from 'metersphere-frontend/src/components/MsDialogFooter'
import {getCurrentProjectID, getOwnerProjects, strMapToObj} from "@/business/utils/sdk-utils"; import {getOwnerProjects} from "@/business/utils/sdk-utils";
import {uiScenarioEnvMap} from "@/api/remote/ui/ui-automation";
import EnvSelectPopover from "@/business/plan/env/EnvSelectPopover";
export default { export default {
name: "UiRunMode", name: "UiRunMode",
components: {MsDialogFooter, EnvSelectPopover}, components: {MsDialogFooter},
data() { data() {
return { return {
runModeVisible: false, runModeVisible: false,
@ -224,8 +207,6 @@ export default {
}, },
projectList: [], projectList: [],
projectIds: new Set(), projectIds: new Set(),
projectEnvListMap: {},
caseIdEnvNameMap: {},
}; };
}, },
props: { props: {
@ -281,7 +262,6 @@ export default {
}; };
this.runModeVisible = true; this.runModeVisible = true;
this.getWsProjects(); this.getWsProjects();
this.showPopover();
}, },
changeMode() { changeMode() {
this.runConfig.runWithinResourcePool = false; this.runConfig.runWithinResourcePool = false;
@ -316,29 +296,6 @@ export default {
this.$emit("handleRunBatch", this.runConfig); this.$emit("handleRunBatch", this.runConfig);
this.close(); this.close();
}, },
setProjectEnvMap(projectEnvMap) {
this.runConfig.envMap = strMapToObj(projectEnvMap);
},
showPopover() {
this.showScenarioPopover();
},
showScenarioPopover() {
let currentProjectID = getCurrentProjectID();
this.projectIds.clear();
uiScenarioEnvMap(this.request).then((res) => {
let data = res.data;
this.projectEnvListMap = data;
if (data) {
for (let d in data) {
this.projectIds.add(d);
}
}
if (this.projectIds.size === 0) {
this.projectIds.add(currentProjectID);
}
this.$refs.envSelectPopover.open();
});
},
}, },
}; };
</script> </script>

View File

@ -88,7 +88,6 @@ const TRACK_HEADER = {
{id: 'name', key: '2', label: 'api_test.automation.scenario_name'}, {id: 'name', key: '2', label: 'api_test.automation.scenario_name'},
{id: 'versionId', key: 'd', label: 'commons.version'}, {id: 'versionId', key: 'd', label: 'commons.version'},
{id: 'level', key: '3', label: 'api_test.automation.case_level'}, {id: 'level', key: '3', label: 'api_test.automation.case_level'},
{id: 'envs', key: '8', label: 'commons.environment'},
{id: 'tagNames', key: '4', label: 'api_test.automation.tag'}, {id: 'tagNames', key: '4', label: 'api_test.automation.tag'},
{id: 'stepTotal', key: '7', label: 'api_test.automation.step'}, {id: 'stepTotal', key: '7', label: 'api_test.automation.step'},
{id: 'passRate', key: '9', label: 'api_test.automation.passing_rate'}, {id: 'passRate', key: '9', label: 'api_test.automation.passing_rate'},