fix(环境管理): 修复环境更新或清除后选中数据无法回显问题 #1005471

--bug=1005471 --user=赵勇 【环境配置】选中环境... https://www.tapd.cn/55049933/s/1030097
This commit is contained in:
fit2-zhao 2021-07-28 14:19:53 +08:00 committed by fit2-zhao
parent 1ffbee6435
commit 861ddfec53
1 changed files with 285 additions and 283 deletions

View File

@ -3,7 +3,7 @@
<el-form :model="condition" :rules="rules" ref="httpConfig" class="ms-el-form-item__content" :disabled="isReadOnly"> <el-form :model="condition" :rules="rules" ref="httpConfig" class="ms-el-form-item__content" :disabled="isReadOnly">
<div class="ms-border"> <div class="ms-border">
<el-form-item prop="socket"> <el-form-item prop="socket">
<span class="ms-env-span">{{$t('api_test.environment.socket')}}</span> <span class="ms-env-span">{{ $t('api_test.environment.socket') }}</span>
<el-input v-model="condition.socket" style="width: 80%" :placeholder="$t('api_test.request.url_description')" clearable size="small"> <el-input v-model="condition.socket" style="width: 80%" :placeholder="$t('api_test.request.url_description')" clearable size="small">
<template slot="prepend"> <template slot="prepend">
<el-select v-model="condition.protocol" class="request-protocol-select" size="small"> <el-select v-model="condition.protocol" class="request-protocol-select" size="small">
@ -14,11 +14,11 @@
</el-input> </el-input>
</el-form-item> </el-form-item>
<el-form-item prop="enable"> <el-form-item prop="enable">
<span class="ms-env-span">{{$t('api_test.environment.condition_enable')}}</span> <span class="ms-env-span">{{ $t('api_test.environment.condition_enable') }}</span>
<el-radio-group v-model="condition.type" @change="typeChange"> <el-radio-group v-model="condition.type" @change="typeChange">
<el-radio label="NONE">{{ $t('api_test.definition.document.data_set.none') }}</el-radio> <el-radio label="NONE">{{ $t('api_test.definition.document.data_set.none') }}</el-radio>
<el-radio label="MODULE">{{$t('test_track.module.module')}}</el-radio> <el-radio label="MODULE">{{ $t('test_track.module.module') }}</el-radio>
<el-radio label="PATH">{{$t('api_test.definition.api_path')}}</el-radio> <el-radio label="PATH">{{ $t('api_test.definition.api_path') }}</el-radio>
</el-radio-group> </el-radio-group>
<div v-if="condition.type === 'MODULE'" style="margin-top: 6px"> <div v-if="condition.type === 'MODULE'" style="margin-top: 6px">
<ms-select-tree size="small" :data="moduleOptions" :default-key="condition.ids" @getValue="setModule" :obj="moduleObj" clearable checkStrictly multiple v-if="!loading"/> <ms-select-tree size="small" :data="moduleOptions" :default-key="condition.ids" @getValue="setModule" :obj="moduleObj" clearable checkStrictly multiple v-if="!loading"/>
@ -34,32 +34,32 @@
</el-input> </el-input>
</div> </div>
<p>{{$t('api_test.request.headers')}}</p> <p>{{ $t('api_test.request.headers') }}</p>
<ms-api-key-value :items="condition.headers" :isShowEnable="true" :suggestions="headerSuggestions"/> <ms-api-key-value :items="condition.headers" :isShowEnable="true" :suggestions="headerSuggestions"/>
<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">{{$t('commons.add')}}</el-button> <el-button v-if="!condition.id" type="primary" style="float: right" size="mini" @click="add">{{ $t('commons.add') }}</el-button>
<div v-else> <div v-else>
<el-button type="primary" style="float: right;margin-left: 10px" size="mini" @click="clear">{{$t('commons.clear')}}</el-button> <el-button type="primary" style="float: right;margin-left: 10px" size="mini" @click="clear">{{ $t('commons.clear') }}</el-button>
<el-button type="primary" style="float: right" size="mini" @click="update">{{$t('commons.update')}}</el-button> <el-button type="primary" style="float: right" size="mini" @click="update">{{ $t('commons.update') }}</el-button>
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
</div> </div>
<div class="ms-border"> <div class="ms-border">
<el-table :data="httpConfig.conditions" highlight-current-row @current-change="selectRow"> <el-table :data="httpConfig.conditions" highlight-current-row @current-change="selectRow" ref="envTable">
<el-table-column prop="socket" :label="$t('load_test.domain')" show-overflow-tooltip width="180"> <el-table-column prop="socket" :label="$t('load_test.domain')" show-overflow-tooltip width="180">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
{{getUrl(row)}} {{ getUrl(row) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="type" :label="$t('api_test.environment.condition_enable')" show-overflow-tooltip min-width="100px"> <el-table-column prop="type" :label="$t('api_test.environment.condition_enable')" show-overflow-tooltip min-width="100px">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
{{getName(row)}} {{ getName(row) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="details" show-overflow-tooltip min-width="120px" :label="$t('api_test.value')"> <el-table-column prop="details" show-overflow-tooltip min-width="120px" :label="$t('api_test.value')">
<template v-slot:default="{row}"> <template v-slot:default="{row}">
{{getDetails(row)}} {{ getDetails(row) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="createTime" show-overflow-tooltip min-width="120px" :label="$t('commons.create_time')"> <el-table-column prop="createTime" show-overflow-tooltip min-width="120px" :label="$t('commons.create_time')">
@ -83,292 +83,294 @@
</template> </template>
<script> <script>
import {HttpConfig} from "../../model/EnvironmentModel"; import {HttpConfig} from "../../model/EnvironmentModel";
import MsApiKeyValue from "../ApiKeyValue"; import MsApiKeyValue from "../ApiKeyValue";
import {REQUEST_HEADERS} from "@/common/js/constants"; import {REQUEST_HEADERS} from "@/common/js/constants";
import MsSelectTree from "../../../../common/select-tree/SelectTree"; import MsSelectTree from "../../../../common/select-tree/SelectTree";
import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton"; import MsTableOperatorButton from "@/business/components/common/components/MsTableOperatorButton";
import {getUUID} from "@/common/js/utils"; import {getUUID} from "@/common/js/utils";
import {KeyValue} from "../../../definition/model/ApiTestModel"; import {KeyValue} from "../../../definition/model/ApiTestModel";
import Vue from "vue"; import Vue from "vue";
export default { export default {
name: "MsEnvironmentHttpConfig", name: "MsEnvironmentHttpConfig",
components: {MsApiKeyValue, MsSelectTree, MsTableOperatorButton}, components: {MsApiKeyValue, MsSelectTree, MsTableOperatorButton},
props: { props: {
httpConfig: new HttpConfig(), httpConfig: new HttpConfig(),
projectId: String, projectId: String,
isReadOnly: { isReadOnly: {
type: Boolean, type: Boolean,
default: false default: false
},
}, },
created() { },
created() {
this.list();
},
data() {
let socketValidator = (rule, value, callback) => {
if (!this.validateSocket(value)) {
callback(new Error(this.$t("commons.formatErr")));
return false;
} else {
callback();
return true;
}
};
return {
headerSuggestions: REQUEST_HEADERS,
rules: {
socket: [{required: false, validator: socketValidator, trigger: "blur"}],
},
moduleOptions: [],
moduleObj: {
id: "id",
label: "name",
},
loading: false,
pathDetails: new KeyValue({name: "", value: "contains"}),
condition: {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]},
beforeCondition: {}
};
},
watch: {
projectId() {
this.list(); this.list();
}, },
data() { httpConfig: function (o) {
let socketValidator = (rule, value, callback) => { //
if (!this.validateSocket(value)) { if (this.httpConfig && this.httpConfig.socket && this.httpConfig.conditions && this.httpConfig.conditions.length === 0) {
callback(new Error(this.$t("commons.formatErr"))); this.condition.type = "NONE";
return false; this.condition.socket = this.httpConfig.socket;
} else { this.condition.protocol = this.httpConfig.protocol;
callback(); this.condition.port = this.httpConfig.port;
return true; this.condition.domain = this.httpConfig.domain;
} this.condition.time = new Date().getTime();
}; this.condition.headers = this.httpConfig.headers;
return { this.add();
headerSuggestions: REQUEST_HEADERS, }
rules: { this.condition = {id: undefined, type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]};
socket: [{required: false, validator: socketValidator, trigger: "blur"}],
},
moduleOptions: [],
moduleObj: {
id: "id",
label: "name",
},
loading: false,
pathDetails: new KeyValue({name: "", value: "contains"}),
condition: {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]},
beforeCondition: {}
};
}, },
watch: { },
projectId() { methods: {
this.list(); getUrl(row) {
}, return row.protocol + "://" + row.socket;
httpConfig: function (o) {
//
if (this.httpConfig && this.httpConfig.socket && this.httpConfig.conditions && this.httpConfig.conditions.length === 0) {
this.condition.type = "NONE";
this.condition.socket = this.httpConfig.socket;
this.condition.protocol = this.httpConfig.protocol;
this.condition.port = this.httpConfig.port;
this.condition.domain = this.httpConfig.domain;
this.condition.time = new Date().getTime();
this.condition.headers = this.httpConfig.headers;
this.add();
}
this.condition = {id: undefined, type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]};
},
}, },
methods: { getName(row) {
getUrl(row) { switch (row.type) {
return row.protocol + "://" + row.socket; case "NONE":
}, return this.$t("api_test.definition.document.data_set.none");
getName(row) { case "MODULE":
switch (row.type) { return this.$t("test_track.module.module");
case "NONE": case "PATH":
return this.$t("api_test.definition.document.data_set.none"); return this.$t("api_test.definition.api_path");
case "MODULE": }
return this.$t("test_track.module.module"); },
case "PATH": clearHisData() {
return this.$t("api_test.definition.api_path"); this.httpConfig.socket = undefined;
} this.httpConfig.protocol = undefined;
}, this.httpConfig.port = undefined;
clearHisData() { this.httpConfig.domain = undefined;
this.httpConfig.socket = undefined; },
this.httpConfig.protocol = undefined; getDetails(row) {
this.httpConfig.port = undefined; if (row && row.type === "MODULE") {
this.httpConfig.domain = undefined; if (row.details && row.details instanceof Array) {
}, let value = "";
getDetails(row) { row.details.forEach((item) => {
if (row && row.type === "MODULE") { value += item.name + ",";
if (row.details && row.details instanceof Array) {
let value = "";
row.details.forEach((item) => {
value += item.name + ",";
});
if (value.endsWith(",")) {
value = value.substr(0, value.length - 1);
}
return value;
}
} else if (row && row.type === "PATH" && row.details.length > 0 && row.details[0].name) {
return row.details[0].value === "equals" ? this.$t("commons.adv_search.operators.equals") + row.details[0].name : this.$t("api_test.request.assertions.contains") + row.details[0].name;
} else {
return "";
}
},
selectRow(row) {
this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]};
if (row) {
this.httpConfig.socket = row.socket;
this.httpConfig.protocol = row.protocol;
this.httpConfig.port = row.port;
this.condition = row;
if (!this.condition.headers) {
this.condition.headers = [new KeyValue()];
}
if (row.type === "PATH" && row.details.length > 0) {
this.pathDetails = JSON.parse(JSON.stringify(row.details[0]));
} else if (row.type === "MODULE" && row.details.length > 0) {
this.condition.ids = [];
row.details.forEach((item) => {
this.condition.ids.push(item.value);
});
}
}
this.beforeCondition = JSON.parse(JSON.stringify(this.condition));
this.reload();
},
typeChange() {
if (this.condition.type === "NONE" && this.condition.id && this.checkNode(this.condition.id)) {
this.condition.type = this.beforeCondition.type;
this.$warning("启用条件为 '无' 的域名已经存在!");
return;
}
switch (this.condition.type) {
case "NONE":
this.condition.details = [];
break;
case "MODULE":
this.condition.details = [];
break;
case "PATH":
this.pathDetails = new KeyValue({name: "", value: "contains"});
break;
}
},
list() {
if (this.projectId) {
let url = "/api/module/list/" + this.projectId + "/HTTP";
this.result = this.$get(url, (response) => {
if (response.data !== undefined && response.data !== null) {
this.moduleOptions = response.data;
}
}); });
} else { //projectId if (value.endsWith(",")) {
this.moduleOptions = []; value = value.substr(0, value.length - 1);
}
return value;
} }
}, } else if (row && row.type === "PATH" && row.details.length > 0 && row.details[0].name) {
setModule(id, data) { return row.details[0].value === "equals" ? this.$t("commons.adv_search.operators.equals") + row.details[0].name : this.$t("api_test.request.assertions.contains") + row.details[0].name;
if (data && data.length > 0) { } else {
this.condition.details = []; return "";
data.forEach((item) => { }
this.condition.details.push(new KeyValue({name: item.name, value: item.id})); },
}); selectRow(row) {
} else { this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", port: 0, headers: [new KeyValue()]};
if (row) {
this.httpConfig.socket = row.socket;
this.httpConfig.protocol = row.protocol;
this.httpConfig.port = row.port;
this.condition = row;
if (!this.condition.headers) {
this.condition.headers = [new KeyValue()];
}
if (row.type === "PATH" && row.details.length > 0) {
this.pathDetails = JSON.parse(JSON.stringify(row.details[0]));
} else if (row.type === "MODULE" && row.details.length > 0) {
this.condition.ids = []; this.condition.ids = [];
this.condition.details = []; row.details.forEach((item) => {
this.condition.ids.push(item.value);
});
} }
}, }
update() { this.beforeCondition = JSON.parse(JSON.stringify(this.condition));
const index = this.httpConfig.conditions.findIndex((d) => d.id === this.condition.id); this.reload();
this.validateSocket(this.condition.socket);
let obj = {
id: this.condition.id, type: this.condition.type, domain: this.condition.domain, socket: this.condition.socket, headers: this.condition.headers,
protocol: this.condition.protocol, details: this.condition.details, port: this.condition.port, time: this.condition.time
};
if (obj.type === "PATH") {
this.httpConfig.conditions[index].details = [this.pathDetails];
}
if (index !== -1) {
Vue.set(this.httpConfig.conditions[index], obj, 1);
this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", headers: [new KeyValue()]};
this.reload();
}
},
clear() {
this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", headers: [new KeyValue()]};
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
});
},
checkNode(id) {
let index = 1;
this.httpConfig.conditions.forEach(item => {
if (item.type === "NONE") {
if(!id || id !== item.id) {
index++;
}
}
})
return index > 1;
},
add() {
if (this.condition.type === "NONE" && this.checkNode()) {
this.$warning("启用条件为 '无' 的域名已经存在,请更新!");
return;
}
this.validateSocket();
let obj = {
id: getUUID(), type: this.condition.type, socket: this.condition.socket, protocol: this.condition.protocol, headers: this.condition.headers,
domain: this.condition.domain, port: this.condition.port, time: new Date().getTime()
};
if (this.condition.type === "PATH") {
obj.details = [JSON.parse(JSON.stringify(this.pathDetails))];
} else {
obj.details = this.condition.details ? JSON.parse(JSON.stringify(this.condition.details)) : this.condition.details;
}
this.httpConfig.conditions.unshift(obj);
this.clearHisData();
},
remove(row) {
const index = this.httpConfig.conditions.findIndex((d) => d.id === row.id);
this.httpConfig.conditions.splice(index, 1);
this.clearHisData();
},
copy(row) {
if (row.type === "NONE") {
this.$warning("启用条件为 '无' 的域名不支持复制!");
return;
}
const index = this.httpConfig.conditions.findIndex((d) => d.id === row.id);
let obj = {id: getUUID(), type: row.type, socket: row.socket, details: row.details, protocol: row.protocol, headers: JSON.parse(JSON.stringify(this.condition.headers)), domain: row.domain, time: new Date().getTime()};
if (index != -1) {
this.httpConfig.conditions.splice(index, 0, obj);
} else {
this.httpConfig.conditions.push(obj);
}
},
validateSocket(socket) {
if (!socket) return true;
let urlStr = this.condition.protocol + "://" + socket;
let url = {};
try {
url = new URL(urlStr);
} catch (e) {
return false;
}
this.condition.domain = decodeURIComponent(url.hostname);
this.condition.port = url.port;
let path = url.pathname === "/" ? "" : url.pathname;
if (url.port) {
this.condition.socket = this.condition.domain + ":" + url.port + path;
} else {
this.condition.socket = this.condition.domain + path;
}
return true;
},
validate() {
let isValidate = false;
this.$refs["httpConfig"].validate((valid) => {
isValidate = valid;
});
return isValidate;
},
}, },
}; typeChange() {
if (this.condition.type === "NONE" && this.condition.id && this.checkNode(this.condition.id)) {
this.condition.type = this.beforeCondition.type;
this.$warning("启用条件为 '无' 的域名已经存在!");
return;
}
switch (this.condition.type) {
case "NONE":
this.condition.details = [];
break;
case "MODULE":
this.condition.details = [];
break;
case "PATH":
this.pathDetails = new KeyValue({name: "", value: "contains"});
break;
}
},
list() {
if (this.projectId) {
let url = "/api/module/list/" + this.projectId + "/HTTP";
this.result = this.$get(url, (response) => {
if (response.data !== undefined && response.data !== null) {
this.moduleOptions = response.data;
}
});
} else { //projectId
this.moduleOptions = [];
}
},
setModule(id, data) {
if (data && data.length > 0) {
this.condition.details = [];
data.forEach((item) => {
this.condition.details.push(new KeyValue({name: item.name, value: item.id}));
});
} else {
this.condition.ids = [];
this.condition.details = [];
}
},
update() {
const index = this.httpConfig.conditions.findIndex((d) => d.id === this.condition.id);
this.validateSocket(this.condition.socket);
let obj = {
id: this.condition.id, type: this.condition.type, domain: this.condition.domain, socket: this.condition.socket, headers: this.condition.headers,
protocol: this.condition.protocol, details: this.condition.details, port: this.condition.port, time: this.condition.time
};
if (obj.type === "PATH") {
this.httpConfig.conditions[index].details = [this.pathDetails];
}
if (index !== -1) {
Vue.set(this.httpConfig.conditions[index], obj, 1);
this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", headers: [new KeyValue()]};
this.reload();
}
this.$refs.envTable.setCurrentRow(-1);
},
clear() {
this.condition = {type: "NONE", details: [new KeyValue({name: "", value: "contains"})], protocol: "http", socket: "", domain: "", headers: [new KeyValue()]};
this.$refs.envTable.setCurrentRow(-1);
},
reload() {
this.loading = true
this.$nextTick(() => {
this.loading = false
});
},
checkNode(id) {
let index = 1;
this.httpConfig.conditions.forEach(item => {
if (item.type === "NONE") {
if (!id || id !== item.id) {
index++;
}
}
})
return index > 1;
},
add() {
if (this.condition.type === "NONE" && this.checkNode()) {
this.$warning("启用条件为 '无' 的域名已经存在,请更新!");
return;
}
this.validateSocket();
let obj = {
id: getUUID(), type: this.condition.type, socket: this.condition.socket, protocol: this.condition.protocol, headers: this.condition.headers,
domain: this.condition.domain, port: this.condition.port, time: new Date().getTime()
};
if (this.condition.type === "PATH") {
obj.details = [JSON.parse(JSON.stringify(this.pathDetails))];
} else {
obj.details = this.condition.details ? JSON.parse(JSON.stringify(this.condition.details)) : this.condition.details;
}
this.httpConfig.conditions.unshift(obj);
this.clearHisData();
},
remove(row) {
const index = this.httpConfig.conditions.findIndex((d) => d.id === row.id);
this.httpConfig.conditions.splice(index, 1);
this.clearHisData();
},
copy(row) {
if (row.type === "NONE") {
this.$warning("启用条件为 '无' 的域名不支持复制!");
return;
}
const index = this.httpConfig.conditions.findIndex((d) => d.id === row.id);
let obj = {id: getUUID(), type: row.type, socket: row.socket, details: row.details, protocol: row.protocol, headers: JSON.parse(JSON.stringify(this.condition.headers)), domain: row.domain, time: new Date().getTime()};
if (index != -1) {
this.httpConfig.conditions.splice(index, 0, obj);
} else {
this.httpConfig.conditions.push(obj);
}
},
validateSocket(socket) {
if (!socket) return true;
let urlStr = this.condition.protocol + "://" + socket;
let url = {};
try {
url = new URL(urlStr);
} catch (e) {
return false;
}
this.condition.domain = decodeURIComponent(url.hostname);
this.condition.port = url.port;
let path = url.pathname === "/" ? "" : url.pathname;
if (url.port) {
this.condition.socket = this.condition.domain + ":" + url.port + path;
} else {
this.condition.socket = this.condition.domain + path;
}
return true;
},
validate() {
let isValidate = false;
this.$refs["httpConfig"].validate((valid) => {
isValidate = valid;
});
return isValidate;
},
},
};
</script> </script>
<style scoped> <style scoped>
.request-protocol-select { .request-protocol-select {
width: 90px; width: 90px;
} }
.ms-env-span { .ms-env-span {
margin-right: 10px; margin-right: 10px;
} }
/deep/ .el-form-item { /deep/ .el-form-item {
margin-bottom: 15px; margin-bottom: 15px;
} }
.ms-el-form-item__content >>> .el-form-item__content { .ms-el-form-item__content >>> .el-form-item__content {
line-height: 20px; line-height: 20px;
} }
</style> </style>