feat(接口测试): HTTP部分参数列支持可配置

HTTP部分参数列支持可配置
This commit is contained in:
song-tianyang 2022-11-30 17:55:38 +08:00 committed by 建国
parent c40b2407e3
commit 087bcceca6
14 changed files with 1048 additions and 395 deletions

View File

@ -2,25 +2,38 @@
<div id="app" v-loading="loading"> <div id="app" v-loading="loading">
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tabs v-model="activeName" @tab-click="handleClick">
<el-tab-pane :label="$t('organization.message.template')" name="apiTemplate"> <el-tab-pane :label="$t('organization.message.template')" name="apiTemplate">
<el-button <div>
v-show="!jsonSchemaDisable" <el-button
type="primary" v-show="!jsonSchemaDisable"
size="mini" type="primary"
style="margin: 10px 10px 0px" size="mini"
@click="openOneClickOperation"> style="margin: 10px 10px 0px"
{{ this.$t('commons.import') }} @click="openOneClickOperation">
</el-button> {{ this.$t('commons.import') }}
</el-button>
<div style="float: right">
<api-params-config
v-if="apiJsonSchemaConfigFields"
:storage-key="storageKey"
@refresh="refreshApiParamsField"
:api-params-config-fields="apiJsonSchemaConfigFields" />
</div>
</div>
<div :style="jsonSchemaDisable ? '' : 'min-height: 200px'"> <div :style="jsonSchemaDisable ? '' : 'min-height: 200px'">
<json-schema-editor <div style="overflow: auto">
class="schema" <json-schema-editor
:disabled="jsonSchemaDisable" v-if="reloadedApiVariable"
:value="schema" class="schema"
:show-mock-vars="showMockVars" :disabled="jsonSchemaDisable"
:scenario-definition="scenarioDefinition" :value="schema"
@editScenarioAdvance="editScenarioAdvance" :show-mock-vars="showMockVars"
:need-mock="needMock" :scenario-definition="scenarioDefinition"
lang="zh_CN" @editScenarioAdvance="editScenarioAdvance"
custom /> :param-columns="apiJsonSchemaShowColumns"
:need-mock="needMock"
lang="zh_CN"
custom />
</div>
</div> </div>
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="showPreview" :label="$t('schema.preview')" name="preview"> <el-tab-pane v-if="showPreview" :label="$t('schema.preview')" name="preview">
@ -37,13 +50,15 @@
<script> <script>
import MsImportJson from './import/ImportJson'; import MsImportJson from './import/ImportJson';
import JsonSchemaEditor from '@/business/commons/json-schema/schema/editor/index'; import JsonSchemaEditor from '@/business/commons/json-schema/schema/editor/index';
import { getApiJsonSchemaConfigFields, getShowFields } from 'metersphere-frontend/src/utils/custom_field';
import ApiParamsConfig from '@/business/definition/components/request/components/ApiParamsConfig';
const Convert = require('./convert/convert.js'); const Convert = require('./convert/convert.js');
const MsConvert = new Convert(); const MsConvert = new Convert();
export default { export default {
name: 'App', name: 'App',
components: { MsImportJson, JsonSchemaEditor }, components: { MsImportJson, JsonSchemaEditor, ApiParamsConfig },
props: { props: {
body: {}, body: {},
showPreview: { showPreview: {
@ -76,6 +91,7 @@ export default {
this.schema = { root: this.body.jsonSchema }; this.schema = { root: this.body.jsonSchema };
} }
this.body.jsonSchema = this.schema.root; this.body.jsonSchema = this.schema.root;
this.apiJsonSchemaShowColumns = getShowFields(this.storageKey);
}, },
watch: { watch: {
schema: { schema: {
@ -106,11 +122,18 @@ export default {
}, },
}, },
loading: false, loading: false,
reloadedApiVariable: true,
preview: null, preview: null,
activeName: 'apiTemplate', activeName: 'apiTemplate',
storageKey: 'API_JSON_SCHEMA_SHOW_FIELD',
apiJsonSchemaConfigFields: getApiJsonSchemaConfigFields(this),
apiJsonSchemaShowColumns: [],
}; };
}, },
methods: { methods: {
refreshApiParamsField() {
this.apiJsonSchemaShowColumns = getShowFields(this.storageKey);
},
handleClick() { handleClick() {
if (this.activeName === 'preview') { if (this.activeName === 'preview') {
this.loading = true; this.loading = true;

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="json-schema-editor"> <div class="json-schema-editor" style="padding: 0 10px">
<el-row class="row" :gutter="20"> <el-row class="row" :gutter="10">
<el-col :span="8" class="ms-col-name"> <el-col :style="{ minWidth: `${200 - 10 * deep}px` }" class="ms-col-name">
<div :style="{ marginLeft: `${10 * deep}px` }" class="ms-col-name-c" /> <div :style="{ marginLeft: `${10 * deep}px` }" class="ms-col-name-c" />
<span <span
v-if="pickValue.type === 'object' || pickValue.type === 'array'" v-if="pickValue.type === 'object' || pickValue.type === 'array'"
@ -32,17 +32,19 @@
@change="onCheck" /> @change="onCheck" />
</el-tooltip> </el-tooltip>
</el-col> </el-col>
<el-col :span="4">
<el-col style="width: 120px; padding: 0 5px">
<el-select <el-select
v-model="pickValue.type" v-model="pickValue.type"
:disabled="disabled || disabledType" :disabled="disabled || disabledType"
class="ms-col-type" class="ms-col-type"
@change="onChangeType" @change="onChangeType"
style="width: 110px"
size="small"> size="small">
<el-option :key="t" :value="t" :label="t" v-for="t in types" /> <el-option :key="t" :value="t" :label="t" v-for="t in types" />
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="4"> <el-col style="min-width: 200px; padding: 0 5px">
<ms-mock <ms-mock
:disabled=" :disabled="
disabled || disabled ||
@ -55,9 +57,103 @@
:scenario-definition="scenarioDefinition" :scenario-definition="scenarioDefinition"
:show-mock-vars="showMockVars" :show-mock-vars="showMockVars"
:need-mock="needMock" :need-mock="needMock"
style="width: 100%"
@editScenarioAdvance="editScenarioAdvance" /> @editScenarioAdvance="editScenarioAdvance" />
</el-col> </el-col>
<el-col :span="4">
<el-col v-if="showColumns('MIX_LENGTH')" class="item kv-select" style="width: 150px; padding: 0 5px">
<el-input-number
:min="0"
v-model="pickValue.minLength"
:placeholder="$t('schema.minLength')"
size="small"
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
style="width: 140px" />
</el-col>
<el-col v-if="showColumns('MAX_LENGTH')" class="item kv-select" style="width: 150px; padding: 0 5px">
<el-input-number
:min="0"
v-model="pickValue.maxLength"
:placeholder="$t('schema.maxLength')"
size="small"
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
style="width: 140px" />
</el-col>
<el-col v-if="showColumns('DEFAULT')" class="item kv-select" style="min-width: 200px; padding: 0 5px">
<el-input
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
v-model="pickValue.default"
class="ms-col-title"
:placeholder="$t('schema.default')"
style="width: 100%"
size="small" />
</el-col>
<el-col v-if="showColumns('PATTERN')" style="min-width: 200px; padding: 0 5px">
<el-input
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
v-model="pickValue.pattern"
class="ms-col-title"
:placeholder="$t('schema.pattern')"
size="small" />
</el-col>
<el-col v-if="showColumns('FORMAT')" style="min-width: 120px; padding: 0 5px">
<div v-if="advancedAttr.format">
<el-select
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
v-model="pickValue.format"
style="width: 100%"
size="small">
<el-option value="" :label="$t('schema.nothing')"></el-option>
<el-option :key="t" :value="t" :label="t" v-for="t in advancedAttr.format.enums" />
</el-select>
</div>
<div v-else>
<el-input :disabled="true" size="small" :placeholder="$t('schema.format')"></el-input>
</div>
</el-col>
<el-col v-if="showColumns('ENUM')" style="min-width: 300px; padding: 0 5px">
<el-input
type="textarea"
autosize
:disabled="disabled"
v-model="pickValue.enum"
class="ms-col-title"
:placeholder="$t('schema.enum')"
size="small" />
</el-col>
<el-col v-if="showColumns('DESCRIPTION')" style="min-width: 300px; padding: 0 5px">
<el-input <el-input
:disabled="disabled" :disabled="disabled"
v-model="pickValue.description" v-model="pickValue.description"
@ -65,16 +161,19 @@
:placeholder="$t('schema.description')" :placeholder="$t('schema.description')"
size="small" /> size="small" />
</el-col> </el-col>
<el-col :span="4" class="col-item-setting" v-if="!disabled"> <!--其余操作-->
<el-tooltip class="item" effect="dark" :content="$t('schema.adv_setting')" placement="top"> <el-col style="width: 220px" class="col-item-setting" v-if="!disabled">
<i class="el-icon-setting" @click="onSetting" /> <div style="width: 80px">
</el-tooltip> <el-tooltip class="item" effect="dark" :content="$t('schema.adv_setting')" placement="top">
<el-tooltip v-if="isObject || isArray(pickValue)" :content="$t('schema.add_child_node')" placement="top"> <i class="el-icon-setting" @click="onSetting" />
<i class="el-icon-plus" @click="addChild" style="margin-left: 10px" /> </el-tooltip>
</el-tooltip> <el-tooltip v-if="isObject || isArray(pickValue)" :content="$t('schema.add_child_node')" placement="top">
<el-tooltip v-if="!root && !isItem" :content="$t('schema.remove_node')" placement="top"> <i class="el-icon-plus" @click="addChild" style="margin-left: 10px" />
<i class="el-icon-close" @click="removeNode" style="margin-left: 10px" /> </el-tooltip>
</el-tooltip> <el-tooltip v-if="!root && !isItem" :content="$t('schema.remove_node')" placement="top">
<i class="el-icon-close" @click="removeNode" style="margin-left: 10px" />
</el-tooltip>
</div>
</el-col> </el-col>
</el-row> </el-row>
@ -87,6 +186,7 @@
:deep="deep + 1" :deep="deep + 1"
:root="false" :root="false"
class="children" class="children"
:param-columns="paramColumns"
:scenario-definition="scenarioDefinition" :scenario-definition="scenarioDefinition"
:show-mock-vars="showMockVars" :show-mock-vars="showMockVars"
:disabled="disabled" :disabled="disabled"
@ -106,6 +206,7 @@
:deep="deep + 1" :deep="deep + 1"
:root="false" :root="false"
class="children" class="children"
:param-columns="paramColumns"
:scenario-definition="scenarioDefinition" :scenario-definition="scenarioDefinition"
:show-mock-vars="showMockVars" :show-mock-vars="showMockVars"
:disabled="disabled" :disabled="disabled"
@ -188,6 +289,7 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
paramColumns: Array,
showMockVars: { showMockVars: {
type: Boolean, type: Boolean,
default() { default() {
@ -302,6 +404,12 @@ export default {
} }
}, },
methods: { methods: {
showColumns(columns) {
if (!this.paramColumns) {
return false;
}
return this.paramColumns.indexOf(columns) >= 0;
},
isArray(data) { isArray(data) {
let isDataArray = data.type === 'array'; let isDataArray = data.type === 'array';
if (isDataArray) { if (isDataArray) {

View File

@ -3,6 +3,7 @@
<el-autocomplete <el-autocomplete
size="small" size="small"
class="input-with-autocomplete" class="input-with-autocomplete"
style="width: 100%"
v-model="mock.mock" v-model="mock.mock"
:fetch-suggestions="funcSearch" :fetch-suggestions="funcSearch"
:disabled="disabled" :disabled="disabled"

View File

@ -1,107 +1,175 @@
<template> <template>
<div style="margin-bottom: 20px"> <div style="margin-bottom: 20px">
<span class="kv-description" v-if="description"> <div style="overflow: auto; width: 100%">
{{ description }} <span class="kv-description" v-if="description">
</span> {{ description }}
<el-row> </span>
<el-checkbox v-model="isSelectAll" v-if="parameters.length > 1" /> <el-row>
</el-row> <el-checkbox v-model="isSelectAll" v-if="parameters.length > 1" />
<div class="item kv-row" v-for="(item, index) in parameters" :key="index">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col class="kv-checkbox" v-if="isShowEnable">
<el-checkbox v-if="!isDisable(index)" v-model="item.enable" :disabled="isReadOnly" />
</el-col>
<span style="margin-left: 10px" v-else></span>
<i class="el-icon-top" style="cursor: pointer" @click="moveTop(index)" />
<i class="el-icon-bottom" style="cursor: pointer" @click="moveBottom(index)" />
<el-col class="item">
<el-input
v-if="!suggestions"
:disabled="isReadOnly"
v-model="item.name"
size="small"
maxlength="200"
@change="change"
:placeholder="keyText"
show-word-limit>
<template v-slot:prepend>
<el-select
v-if="type === 'body'"
:disabled="isReadOnly"
class="kv-type"
v-model="item.type"
@change="typeChange(item)">
<el-option value="text" />
<el-option value="file" />
<el-option value="json" />
</el-select>
</template>
</el-input>
<el-autocomplete
:disabled="isReadOnly"
v-if="suggestions"
v-model="item.name"
size="small"
:fetch-suggestions="querySearch"
@change="change"
:placeholder="keyText"
show-word-limit />
</el-col>
<el-col class="item kv-select">
<el-select v-model="item.required" size="small">
<el-option v-for="req in requireds" :key="req.id" :label="req.name" :value="req.id" />
</el-select>
</el-col>
<el-col class="item" v-if="isActive && item.type !== 'file'">
<el-autocomplete
:disabled="isReadOnly"
size="small"
class="input-with-autocomplete"
v-model="item.value"
:fetch-suggestions="funcSearch"
:placeholder="valueText"
value-key="name"
highlight-first-item
@select="change">
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced(item)"></i>
</el-autocomplete>
</el-col>
<el-col v-if="isActive && item.type === 'file'" class="item">
<ms-api-body-file-upload :parameter="item" :id="id" :is-read-only="isReadOnly" />
</el-col>
<el-col v-if="type === 'body'" class="item kv-select">
<el-input
:disabled="isReadOnly"
v-model="item.contentType"
size="small"
@change="change"
:placeholder="$t('api_test.request.content_type')"
show-word-limit>
</el-input>
</el-col>
<el-col v-if="withMoreSetting" class="item kv-setting">
<el-tooltip effect="dark" :content="$t('schema.adv_setting')" placement="top">
<i class="el-icon-setting" @click="openApiVariableSetting(item)" />
</el-tooltip>
</el-col>
<el-col class="item kv-delete">
<el-button
size="mini"
class="el-icon-delete-solid"
circle
@click="remove(index)"
:disabled="isDisable(index) || isReadOnly" />
</el-col>
</el-row> </el-row>
<!-- 数据-->
<div class="item kv-row" v-for="(item, index) in parameters" :key="index" style="width: 99%">
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
<el-col class="kv-checkbox" v-if="isShowEnable">
<el-checkbox v-if="!isDisable(index)" v-model="item.enable" :disabled="isReadOnly" />
</el-col>
<span style="margin-left: 10px" v-else></span>
<i class="el-icon-top" style="cursor: pointer" @click="moveTop(index)" />
<i class="el-icon-bottom" style="cursor: pointer" @click="moveBottom(index)" />
<el-col class="item" style="min-width: 200px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ keyText }}</span>
</el-row>
<el-input
v-if="!suggestions"
:disabled="isReadOnly"
v-model="item.name"
size="small"
maxlength="200"
@change="change"
:placeholder="keyText"
show-word-limit>
<template v-slot:prepend>
<el-select
v-if="type === 'body'"
:disabled="isReadOnly"
class="kv-type"
v-model="item.type"
@change="typeChange(item)">
<el-option value="text" />
<el-option value="file" />
<el-option value="json" />
</el-select>
</template>
</el-input>
<el-autocomplete
:disabled="isReadOnly"
v-if="suggestions"
v-model="item.name"
size="small"
:fetch-suggestions="querySearch"
@change="change"
:placeholder="keyText"
show-word-limit />
</el-col>
<el-col class="item kv-select" style="width: 130px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0">
{{ $t('api_test.definition.document.table_coloum.is_required') }}</span
>
</el-row>
<el-select v-model="item.required" size="small" style="width: 120px">
<el-option v-for="req in requireds" :key="req.id" :label="req.name" :value="req.id" />
</el-select>
</el-col>
<el-col class="item" v-if="isActive && item.type !== 'file'" style="min-width: 200px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ valueText }}</span>
</el-row>
<el-autocomplete
:disabled="isReadOnly"
size="small"
class="input-with-autocomplete"
v-model="item.value"
:fetch-suggestions="funcSearch"
:placeholder="valueText"
value-key="name"
highlight-first-item
@select="change">
<i slot="suffix" class="el-input__icon el-icon-edit pointer" @click="advanced(item)"></i>
</el-autocomplete>
</el-col>
<el-col v-if="isActive && item.type === 'file'" class="item" style="min-width: 200px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ valueText }}</span>
</el-row>
<ms-api-body-file-upload :parameter="item" :id="id" :is-read-only="isReadOnly" />
</el-col>
<el-col v-if="type === 'body'" class="item kv-select" style="min-width: 160px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ $t('api_test.request.content_type') }}</span>
</el-row>
<el-input
:disabled="isReadOnly"
v-model="item.contentType"
size="small"
@change="change"
:placeholder="$t('api_test.request.content_type')"
show-word-limit>
</el-input>
</el-col>
<el-col v-if="showColumns('MIX_LENGTH')" class="item kv-select" style="width: 150px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ $t('schema.minLength') }}</span>
</el-row>
<el-input-number
:min="0"
v-model="item.min"
:placeholder="$t('schema.minLength')"
size="small"
style="width: 140px" />
</el-col>
<el-col v-if="showColumns('MAX_LENGTH')" class="item kv-select" style="width: 150px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ $t('schema.maxLength') }}</span>
</el-row>
<el-input-number
:min="0"
v-model="item.max"
:placeholder="$t('schema.maxLength')"
size="small"
style="width: 140px" />
</el-col>
<el-col v-if="showColumns('ENCODE')" class="item kv-select" style="width: 130px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ $t('commons.encode') }}</span>
</el-row>
<el-select v-model="item.urlEncode" size="small" clearable style="width: 100px">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-col>
<el-col class="item" v-if="showColumns('DESCRIPTION')" style="min-width: 300px; padding: 0 5px">
<el-row>
<span class="param-header-span" v-if="index === 0"> {{ $t('commons.description') }}</span>
</el-row>
<el-input
v-model="item.description"
size="small"
maxlength="200"
:placeholder="$t('commons.description')"
show-word-limit>
</el-input>
</el-col>
<el-col v-if="withMoreSetting" class="item kv-setting">
<el-tooltip effect="dark" :content="$t('schema.adv_setting')" placement="top">
<i class="el-icon-setting" @click="openApiVariableSetting(item)" />
</el-tooltip>
</el-col>
<el-col class="item kv-delete">
<el-button
size="mini"
class="el-icon-delete-solid"
circle
@click="remove(index)"
:disabled="isDisable(index) || isReadOnly" />
</el-col>
</el-row>
</div>
</div> </div>
<ms-api-variable-advance <ms-api-variable-advance
ref="variableAdvance" ref="variableAdvance"
:environment="environment" :environment="environment"
@ -126,6 +194,7 @@ import MsApiVariableJson from './ApiVariableJson';
import MsApiBodyFileUpload from './body/ApiBodyFileUpload'; import MsApiBodyFileUpload from './body/ApiBodyFileUpload';
import Vue from 'vue'; import Vue from 'vue';
import ApiVariableSetting from '@/business/definition/components/ApiVariableSetting'; import ApiVariableSetting from '@/business/definition/components/ApiVariableSetting';
import { getShowFields } from 'metersphere-frontend/src/utils/custom_field';
export default { export default {
name: 'MsApiVariable', name: 'MsApiVariable',
@ -184,6 +253,17 @@ export default {
], ],
isSelectAll: true, isSelectAll: true,
isActive: true, isActive: true,
paramColumns: [],
options: [
{
value: true,
label: this.$t('commons.yes'),
},
{
value: false,
label: this.$t('commons.no'),
},
],
}; };
}, },
watch: { watch: {
@ -194,6 +274,13 @@ export default {
this.invertSelect(); this.invertSelect();
} }
}, },
paramColumns: {
handler(val) {
this.reload();
},
deep: true,
},
}, },
computed: { computed: {
keyText() { keyText() {
@ -204,6 +291,9 @@ export default {
}, },
}, },
methods: { methods: {
showColumns(columns) {
return this.paramColumns.indexOf(columns) >= 0;
},
moveBottom(index) { moveBottom(index) {
if (this.parameters.length < 2 || index === this.parameters.length - 2) { if (this.parameters.length < 2 || index === this.parameters.length - 2) {
return; return;
@ -365,6 +455,10 @@ export default {
}) })
); );
} }
let savedApiParamsShowFields = getShowFields('API_PARAMS_SHOW_FIELD');
if (savedApiParamsShowFields) {
this.paramColumns = savedApiParamsShowFields;
}
}, },
}; };
</script> </script>
@ -416,4 +510,9 @@ export default {
width: 40px; width: 40px;
padding: 0px !important; padding: 0px !important;
} }
.param-header-span {
margin-bottom: 5px;
font-weight: 600;
}
</style> </style>

View File

@ -26,8 +26,12 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
<div v-if="body.type == 'Form Data' || body.type == 'WWW_FORM'"> <div v-if="body.type == 'Form Data' || body.type == 'WWW_FORM'">
<el-row v-if="body.type == 'Form Data' || body.type == 'WWW_FORM'"> <el-row v-if="body.type == 'Form Data' || body.type == 'WWW_FORM'" class="ms-el-link">
<el-link class="ms-el-link" @click="batchAdd"> {{ $t('commons.batch_add') }}</el-link> <el-link style="margin-right: 5px" @click="batchAdd"> {{ $t('commons.batch_add') }}</el-link>
<api-params-config
v-if="apiParamsConfigFields"
@refresh="refreshApiParamsField"
:api-params-config-fields="apiParamsConfigFields" />
</el-row> </el-row>
<ms-api-variable <ms-api-variable
:with-more-setting="true" :with-more-setting="true"
@ -38,6 +42,7 @@
:scenario-definition="scenarioDefinition" :scenario-definition="scenarioDefinition"
:id="id" :id="id"
@editScenarioAdvance="editScenarioAdvance" @editScenarioAdvance="editScenarioAdvance"
v-if="reloadedApiVariable"
type="body" /> type="body" />
</div> </div>
<div v-if="body.type == 'JSON'"> <div v-if="body.type == 'JSON'">
@ -89,6 +94,8 @@ import MsApiBinaryVariable from './ApiBinaryVariable';
import MsApiFromUrlVariable from './ApiFromUrlVariable'; import MsApiFromUrlVariable from './ApiFromUrlVariable';
import BatchAddParameter from '../basis/BatchAddParameter'; import BatchAddParameter from '../basis/BatchAddParameter';
import Convert from '@/business/commons/json-schema/convert/convert'; import Convert from '@/business/commons/json-schema/convert/convert';
import { getApiParamsConfigFields } from 'metersphere-frontend/src/utils/custom_field';
import ApiParamsConfig from '@/business/definition/components/request/components/ApiParamsConfig';
export default { export default {
name: 'MsApiBody', name: 'MsApiBody',
@ -101,6 +108,7 @@ export default {
MsApiFromUrlVariable, MsApiFromUrlVariable,
MsJsonCodeEdit, MsJsonCodeEdit,
BatchAddParameter, BatchAddParameter,
ApiParamsConfig,
}, },
props: { props: {
body: { body: {
@ -131,6 +139,8 @@ export default {
}, },
data() { data() {
return { return {
reloadedApiVariable: true,
apiParamsConfigFields: getApiParamsConfigFields(this),
type: BODY_TYPE, type: BODY_TYPE,
modes: ['text', 'json', 'xml', 'html'], modes: ['text', 'json', 'xml', 'html'],
jsonSchema: 'JSON', jsonSchema: 'JSON',
@ -146,6 +156,13 @@ export default {
}, },
}, },
methods: { methods: {
refreshApiParamsField() {
this.reloadedApiVariable = false;
this.$nextTick(() => {
this.reloadedApiVariable = true;
});
},
isObj(x) { isObj(x) {
let type = typeof x; let type = typeof x;
return x !== null && (type === 'object' || type === 'function'); return x !== null && (type === 'object' || type === 'function');

View File

@ -36,8 +36,17 @@
</div> </div>
</div> </div>
<div v-else> <div v-else>
<el-row v-if="tableType === 'rest' || tableType === 'query'">
<div style="float: right">
<api-params-config
v-if="apiParamsConfigFields"
@refresh="refreshApiParamsField"
:api-params-config-fields="apiParamsConfigFields" />
</div>
</el-row>
<el-table <el-table
border border
v-if="reloadedApiVariable"
:show-header="true" :show-header="true"
row-key="id" row-key="id"
:row-class-name="getRowClassName" :row-class-name="getRowClassName"
@ -78,37 +87,25 @@
<script> <script>
import { getCurrentUser } from 'metersphere-frontend/src/utils/token'; import { getCurrentUser } from 'metersphere-frontend/src/utils/token';
import { getUUID } from 'metersphere-frontend/src/utils'; import { getUUID } from 'metersphere-frontend/src/utils';
import tableAdvancedSetting from '@/business/definition/components/document/components/plugin/TableAdvancedSetting'; import TableAdvancedSetting from '@/business/definition/components/document/components/plugin/TableAdvancedSetting';
import ApiParamsConfig from '@/business/definition/components/request/components/ApiParamsConfig';
import { getApiParamsConfigFields, getShowFields } from 'metersphere-frontend/src/utils/custom_field';
export default { export default {
name: 'ApiInfoCollapse', name: 'ApiInfoCollapse',
components: { tableAdvancedSetting }, components: { TableAdvancedSetting, ApiParamsConfig },
data() { data() {
return { return {
active: true, active: true,
expandAllRow: false, expandAllRow: false,
language: 'zh_CN', language: 'zh_CN',
reloadedApiVariable: true,
tableData: [], tableData: [],
storageKey: 'API_PARAMS_SHOW_FIELD',
apiParamsConfigFields: getApiParamsConfigFields(this),
tableExpandButtonId: 'docTableExpandBtn' + getUUID(), tableExpandButtonId: 'docTableExpandBtn' + getUUID(),
expandTitle: this.$t('commons.expand_all'), expandTitle: this.$t('commons.expand_all'),
tableColumnArr: [ tableColumnArr: [],
{ id: 1, prop: 'name', label: this.$t('api_definition.document.name') },
{
id: 2,
prop: 'isRequired',
label: this.$t('api_definition.document.is_required'),
},
{
id: 3,
prop: 'value',
label: this.$t('api_definition.document.value'),
},
{
id: 4,
prop: 'description',
label: this.$t('api_definition.document.desc'),
},
],
}; };
}, },
props: { props: {
@ -116,6 +113,7 @@ export default {
tableColumnType: String, tableColumnType: String,
remarks: String, remarks: String,
isRequest: Boolean, isRequest: Boolean,
tableType: String,
isResponse: Boolean, isResponse: Boolean,
tableCanExpand: { tableCanExpand: {
type: Boolean, type: Boolean,
@ -138,6 +136,7 @@ export default {
this.language = user.language; this.language = user.language;
} }
this.tableData = this.getJsonArr(this.stringData); this.tableData = this.getJsonArr(this.stringData);
this.formatTableData();
}, },
created: function () { created: function () {
//language zh_CN/zh_TW/en_US //language zh_CN/zh_TW/en_US
@ -145,7 +144,9 @@ export default {
if (user) { if (user) {
this.language = user.language; this.language = user.language;
} }
this.initTableColumnArr();
this.tableData = this.getJsonArr(this.stringData); this.tableData = this.getJsonArr(this.stringData);
this.formatTableData();
}, },
mounted() { mounted() {
//language zh_CN/zh_TW/en_US //language zh_CN/zh_TW/en_US
@ -154,6 +155,7 @@ export default {
this.language = user.language; this.language = user.language;
} }
this.tableData = this.getJsonArr(this.stringData); this.tableData = this.getJsonArr(this.stringData);
this.formatTableData();
}, },
computed: { computed: {
showSlotComponent() { showSlotComponent() {
@ -163,6 +165,7 @@ export default {
watch: { watch: {
stringData() { stringData() {
this.tableData = this.getJsonArr(this.stringData); this.tableData = this.getJsonArr(this.stringData);
this.formatTableData();
}, },
expandAllRow() { expandAllRow() {
if (this.$refs.expandTable) { if (this.$refs.expandTable) {
@ -184,6 +187,71 @@ export default {
}, },
}, },
methods: { methods: {
formatTableData() {
if (this.tableData) {
this.tableData.forEach((item) => {
if (item.urlEncode !== null && item.urlEncode !== undefined) {
if (item.urlEncode === true) {
item.urlEncode = this.$t('commons.yes');
} else {
item.urlEncode = this.$t('commons.no');
}
}
});
}
},
refreshApiParamsField() {
this.initTableColumnArr();
this.reloadedApiVariable = false;
this.$nextTick(() => {
this.reloadedApiVariable = true;
});
},
initTableColumnArr() {
this.tableColumnArr = [
{ id: 1, prop: 'name', label: this.$t('api_definition.document.name') },
{
id: 2,
prop: 'isRequired',
label: this.$t('api_definition.document.is_required'),
},
{
id: 3,
prop: 'value',
label: this.$t('api_definition.document.value'),
},
];
if (this.tableType === 'rest' || this.tableType === 'query') {
let apiParamConfigArr = getShowFields(this.storageKey);
if (apiParamConfigArr) {
apiParamConfigArr.forEach((item) => {
let tableColumn = {};
if (item === 'MIX_LENGTH') {
tableColumn.id = 5;
tableColumn.prop = 'min';
tableColumn.label = this.$t('schema.minLength');
} else if (item === 'MAX_LENGTH') {
tableColumn.id = 6;
tableColumn.prop = 'max';
tableColumn.label = this.$t('schema.maxLength');
} else if (item === 'ENCODE') {
tableColumn.id = 7;
tableColumn.prop = 'urlEncode';
tableColumn.label = this.$t('commons.encode');
} else if (item === 'DESCRIPTION') {
tableColumn.id = 8;
tableColumn.prop = 'description';
tableColumn.label = this.$t('commons.description');
} else {
tableColumn = null;
}
if (tableColumn) {
this.tableColumnArr.push(tableColumn);
}
});
}
}
},
getRowClassName({ row, rowIndex }) { getRowClassName({ row, rowIndex }) {
let classname = 'autofix-table-row '; let classname = 'autofix-table-row ';
// //

View File

@ -50,12 +50,14 @@
<api-info-collapse <api-info-collapse
v-if="isArrayHasData(apiInfo.urlParams)" v-if="isArrayHasData(apiInfo.urlParams)"
table-column-type="simple" table-column-type="simple"
table-type="query"
:title="'QUERY' + $t('api_test.definition.document.request_param')" :title="'QUERY' + $t('api_test.definition.document.request_param')"
:string-data="apiInfo.urlParams" /> :string-data="apiInfo.urlParams" />
<!--REST参数--> <!--REST参数-->
<api-info-collapse <api-info-collapse
v-if="isArrayHasData(apiInfo.restParams)" v-if="isArrayHasData(apiInfo.restParams)"
table-column-type="simple" table-column-type="simple"
table-type="rest"
:title="'REST' + $t('api_test.definition.document.request_param')" :title="'REST' + $t('api_test.definition.document.request_param')"
:string-data="apiInfo.restParams" /> :string-data="apiInfo.restParams" />
<!--api请求体 以及表格--> <!--api请求体 以及表格-->

View File

@ -2,54 +2,44 @@
<div> <div>
<el-row class="apiInfoRow"> <el-row class="apiInfoRow">
<div> <div>
<el-table <div v-if="formParamTypes.includes(apiInfo.requestBodyParamType)">
border <el-row>
v-if="formParamTypes.includes(apiInfo.requestBodyParamType)" <div style="float: right">
:show-header="true" <api-params-config
row-key="id" v-if="apiParamsConfigFields"
:row-class-name="getRowClassName" @refresh="refreshApiParamsField"
:data="tableData" :api-params-config-fields="apiParamsConfigFields" />
:class="getTableClass()" </div>
ref="expandTable"> </el-row>
<el-table-column <el-table
prop="name" border
:label="$t('api_definition.document.name')" :show-header="true"
min-width="120px" row-key="id"
show-overflow-tooltip /> :row-class-name="getRowClassName"
<el-table-column :data="tableData"
prop="contentType" :class="getTableClass()"
:label="$t('api_definition.document.type')" ref="expandTable">
min-width="120px" <el-table-column
show-overflow-tooltip /> v-for="item in tableColumnArr"
<el-table-column :key="item.id"
prop="description" :prop="item.prop"
:label="$t('api_definition.document.desc')" :label="item.label"
min-width="280px" show-overflow-tooltip />
show-overflow-tooltip /> <el-table-column type="expand" :label="getCollapseOption()" width="80px">
<el-table-column <template slot="header">
prop="required" <el-button type="text" size="mini" @click="expandAllRows">
:label="$t('api_definition.document.is_required')" <span :id="tableExpandButtonId">
:formatter="formatBoolean" {{ expandTitle }}
min-width="80px" </span>
show-overflow-tooltip /> </el-button>
<el-table-column </template>
prop="value" <template v-slot:default="scope">
:label="$t('api_definition.document.default_value')" <table-advanced-setting :table-data="scope.row"></table-advanced-setting>
min-width="120px" </template>
show-overflow-tooltip /> </el-table-column>
<el-table-column type="expand" :label="getCollapseOption()" width="80px"> </el-table>
<template slot="header"> </div>
<el-button type="text" size="mini" @click="expandAllRows">
<span :id="tableExpandButtonId">
{{ expandTitle }}
</span>
</el-button>
</template>
<template v-slot:default="scope">
<table-advanced-setting :table-data="scope.row"></table-advanced-setting>
</template>
</el-table-column>
</el-table>
<div <div
v-else-if="apiInfo.requestBodyParamType === 'JSON-SCHEMA' || apiInfo.requestBodyParamType === 'JSON'" v-else-if="apiInfo.requestBodyParamType === 'JSON-SCHEMA' || apiInfo.requestBodyParamType === 'JSON'"
style="margin-left: 10px"> style="margin-left: 10px">
@ -87,10 +77,12 @@ import JsonSchemaShow from '@/business/definition/components/document/components
import tableAdvancedSetting from '@/business/definition/components/document/components/plugin/TableAdvancedSetting'; import tableAdvancedSetting from '@/business/definition/components/document/components/plugin/TableAdvancedSetting';
import { getCurrentUser } from 'metersphere-frontend/src/utils/token'; import { getCurrentUser } from 'metersphere-frontend/src/utils/token';
import { getUUID } from 'metersphere-frontend/src/utils'; import { getUUID } from 'metersphere-frontend/src/utils';
import { getApiParamsConfigFields, getShowFields } from 'metersphere-frontend/src/utils/custom_field';
import ApiParamsConfig from '@/business/definition/components/request/components/ApiParamsConfig';
export default { export default {
name: 'ApiRequestInfo', name: 'ApiRequestInfo',
components: { JsonSchemaShow, tableAdvancedSetting }, components: { JsonSchemaShow, tableAdvancedSetting, ApiParamsConfig },
data() { data() {
return { return {
tableData: [], tableData: [],
@ -98,8 +90,11 @@ export default {
tableExpandButtonId: 'docTableExpandBtn' + getUUID(), tableExpandButtonId: 'docTableExpandBtn' + getUUID(),
active: true, active: true,
expandAllRow: false, expandAllRow: false,
apiParamStorageKey: 'API_PARAMS_SHOW_FIELD',
expandTitle: this.$t('commons.expand_all'), expandTitle: this.$t('commons.expand_all'),
apiParamsConfigFields: getApiParamsConfigFields(this),
formParamTypes: ['form-data', 'x-www-from-urlencoded', 'BINARY'], formParamTypes: ['form-data', 'x-www-from-urlencoded', 'BINARY'],
tableColumnArr: [],
}; };
}, },
props: { props: {
@ -108,38 +103,45 @@ export default {
activated() { activated() {
if (this.apiInfo && this.apiInfo.requestBodyFormData) { if (this.apiInfo && this.apiInfo.requestBodyFormData) {
this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData); this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData);
this.formatTableData();
} }
//language zh_CN/zh_TW/en_US //language zh_CN/zh_TW/en_US
let user = getCurrentUser(); let user = getCurrentUser();
if (user) { if (user) {
this.language = user.language; this.language = user.language;
} }
this.initTableColumn();
}, },
created: function () { created: function () {
if (this.apiInfo && this.apiInfo.requestBodyFormData) { if (this.apiInfo && this.apiInfo.requestBodyFormData) {
this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData); this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData);
this.formatTableData();
} }
//language zh_CN/zh_TW/en_US //language zh_CN/zh_TW/en_US
let user = getCurrentUser(); let user = getCurrentUser();
if (user) { if (user) {
this.language = user.language; this.language = user.language;
} }
this.initTableColumn();
}, },
mounted() { mounted() {
if (this.apiInfo && this.apiInfo.requestBodyFormData) { if (this.apiInfo && this.apiInfo.requestBodyFormData) {
this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData); this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData);
this.formatTableData();
} }
//language zh_CN/zh_TW/en_US //language zh_CN/zh_TW/en_US
let user = getCurrentUser(); let user = getCurrentUser();
if (user) { if (user) {
this.language = user.language; this.language = user.language;
} }
this.initTableColumn();
}, },
computed: {}, computed: {},
watch: { watch: {
'apiInfo.requestBodyFormData': { 'apiInfo.requestBodyFormData': {
handler(v) { handler(v) {
this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData); this.tableData = this.getJsonArr(this.apiInfo.requestBodyFormData);
this.formatTableData();
}, },
deep: true, deep: true,
}, },
@ -163,6 +165,79 @@ export default {
}, },
}, },
methods: { methods: {
formatTableData() {
if (this.tableData) {
this.tableData.forEach((item) => {
if (item.urlEncode !== null && item.urlEncode !== undefined) {
if (item.urlEncode === true) {
item.urlEncode = this.$t('commons.yes');
} else {
item.urlEncode = this.$t('commons.no');
}
}
if (item.enable !== null && item.enable !== undefined) {
if (item.enable === true) {
item.enable = this.$t('commons.yes');
} else {
item.enable = this.$t('commons.no');
}
}
});
}
},
refreshApiParamsField() {
this.initTableColumn();
this.reloadedApiVariable = false;
this.$nextTick(() => {
this.reloadedApiVariable = true;
});
},
initTableColumn() {
this.tableColumnArr = [
{ id: 1, prop: 'name', label: this.$t('api_definition.document.name') },
{ id: 2, prop: 'contentType', label: this.$t('api_definition.document.type') },
{
id: 3,
prop: 'enable',
label: this.$t('api_definition.document.is_required'),
},
{
id: 4,
prop: 'value',
label: this.$t('api_definition.document.value'),
},
];
if (this.formParamTypes.includes(this.apiInfo.requestBodyParamType)) {
let apiParamConfigArr = getShowFields(this.apiParamStorageKey);
if (apiParamConfigArr) {
apiParamConfigArr.forEach((item) => {
let tableColumn = {};
if (item === 'MIX_LENGTH') {
tableColumn.id = 5;
tableColumn.prop = 'min';
tableColumn.label = this.$t('schema.minLength');
} else if (item === 'MAX_LENGTH') {
tableColumn.id = 6;
tableColumn.prop = 'max';
tableColumn.label = this.$t('schema.maxLength');
} else if (item === 'ENCODE') {
tableColumn.id = 7;
tableColumn.prop = 'urlEncode';
tableColumn.label = this.$t('commons.encode');
} else if (item === 'DESCRIPTION') {
tableColumn.id = 8;
tableColumn.prop = 'description';
tableColumn.label = this.$t('commons.description');
} else {
tableColumn = null;
}
if (tableColumn) {
this.tableColumnArr.push(tableColumn);
}
});
}
}
},
getRowClassName({ row, rowIndex }) { getRowClassName({ row, rowIndex }) {
let classname = 'autofix-table-row '; let classname = 'autofix-table-row ';
// //

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="json-schema-editor"> <div class="json-schema-editor" style="padding: 0 10px">
<el-row class="row" :gutter="20"> <el-row class="row" :gutter="10">
<el-col :span="8" class="ms-col-name"> <el-col :style="{ minWidth: `${200 - 10 * deep}px` }" class="ms-col-name">
<div :style="{ marginLeft: `${10 * deep}px` }" class="ms-col-name-c" /> <div :style="{ marginLeft: `${10 * deep}px` }" class="ms-col-name-c" />
<span <span
v-if="pickValue.type === 'object' || pickValue.type === 'array'" v-if="pickValue.type === 'object' || pickValue.type === 'array'"
@ -16,17 +16,18 @@
@blur="onInputName" @blur="onInputName"
size="small" /> size="small" />
</el-col> </el-col>
<el-col :span="4"> <el-col style="width: 120px; padding: 0 5px">
<el-select <el-select
v-model="pickValue.type" v-model="pickValue.type"
:disabled="disabled || disabledType" :disabled="disabled || disabledType"
class="ms-col-type" class="ms-col-type"
@change="onChangeType" @change="onChangeType"
style="width: 110px"
size="small"> size="small">
<el-option :key="t" :value="t" :label="t" v-for="t in types" /> <el-option :key="t" :value="t" :label="t" v-for="t in types" />
</el-select> </el-select>
</el-col> </el-col>
<el-col :span="5"> <el-col style="min-width: 200px; padding: 0 5px">
<ms-mock <ms-mock
:disabled=" :disabled="
disabled || disabled ||
@ -38,9 +39,74 @@
:schema="pickValue" :schema="pickValue"
:scenario-definition="scenarioDefinition" :scenario-definition="scenarioDefinition"
:show-mock-vars="showMockVars" :show-mock-vars="showMockVars"
style="width: 100%"
@editScenarioAdvance="editScenarioAdvance" /> @editScenarioAdvance="editScenarioAdvance" />
</el-col> </el-col>
<el-col :span="5"> <el-col v-if="showColumns('MIX_LENGTH')" class="item kv-select" style="width: 150px; padding: 0 5px">
<el-input-number
:min="0"
v-model="pickValue.minLength"
:placeholder="$t('schema.minLength')"
size="small"
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
style="width: 140px" />
</el-col>
<el-col v-if="showColumns('MAX_LENGTH')" class="item kv-select" style="width: 150px; padding: 0 5px">
<el-input-number
:min="0"
v-model="pickValue.maxLength"
:placeholder="$t('schema.maxLength')"
size="small"
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
style="width: 140px" />
</el-col>
<el-col v-if="showColumns('DEFAULT')" class="item kv-select" style="min-width: 200px; padding: 0 5px">
<el-input
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
v-model="pickValue.default"
class="ms-col-title"
:placeholder="$t('schema.default')"
style="width: 100%"
size="small" />
</el-col>
<el-col v-if="showColumns('PATTERN')" style="min-width: 200px; padding: 0 5px">
<el-input
:disabled="
disabled ||
pickValue.type === 'object' ||
pickKey === 'root' ||
pickValue.type === 'array' ||
pickValue.type === 'null'
"
v-model="pickValue.pattern"
class="ms-col-title"
:placeholder="$t('schema.pattern')"
size="small" />
</el-col>
<el-col v-if="showColumns('FORMAT')" style="min-width: 120px; padding: 0 5px">
<el-input :disabled="true" size="small" :placeholder="$t('schema.format')"></el-input>
</el-col>
<el-col v-if="showColumns('ENUM')" style="min-width: 300px; padding: 0 5px">
<el-input <el-input
:disabled="disabled" :disabled="disabled"
v-model="pickValue.description" v-model="pickValue.description"
@ -48,19 +114,7 @@
:placeholder="$t('schema.description')" :placeholder="$t('schema.description')"
size="small" /> size="small" />
</el-col> </el-col>
<el-col :span="2">
<div v-if="hasAdvancedSetting">
<el-link @click="changeCollapseStatus">{{ getCollapseOption() }}</el-link>
</div>
</el-col>
</el-row> </el-row>
<div>
<el-collapse-transition>
<div v-show="collapseStatus && hasAdvancedSetting" :style="{ marginLeft: `${10 * deep + 10}px` }">
<json-advanced-setting :json-data="pickValue" />
</div>
</el-collapse-transition>
</div>
<template v-if="!hidden && pickValue.properties && !isArray && reloadItemOver"> <template v-if="!hidden && pickValue.properties && !isArray && reloadItemOver">
<json-schema-panel <json-schema-panel
@ -71,6 +125,7 @@
:deep="deep + 1" :deep="deep + 1"
:root="false" :root="false"
class="children" class="children"
:param-columns="paramColumns"
:scenario-definition="scenarioDefinition" :scenario-definition="scenarioDefinition"
:show-mock-vars="showMockVars" :show-mock-vars="showMockVars"
:disabled="disabled" :disabled="disabled"
@ -89,6 +144,7 @@
:deep="deep + 1" :deep="deep + 1"
:root="false" :root="false"
class="children" class="children"
:param-columns="paramColumns"
:scenario-definition="scenarioDefinition" :scenario-definition="scenarioDefinition"
:show-mock-vars="showMockVars" :show-mock-vars="showMockVars"
:expand-all-params="expandAllParams" :expand-all-params="expandAllParams"
@ -124,6 +180,7 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
paramColumns: Array,
disabledType: { disabledType: {
// //
type: Boolean, type: Boolean,
@ -150,12 +207,10 @@ export default {
default: null, default: null,
}, },
custom: { custom: {
//enable custom properties
type: Boolean, type: Boolean,
default: false, default: false,
}, },
lang: { lang: {
// i18n language
type: String, type: String,
default: 'zh_CN', default: 'zh_CN',
}, },
@ -248,6 +303,12 @@ export default {
}, },
}, },
methods: { methods: {
showColumns(columns) {
if (!this.paramColumns) {
return false;
}
return this.paramColumns.indexOf(columns) >= 0;
},
isNotEmptyValue(value) { isNotEmptyValue(value) {
return value && value !== ''; return value && value !== '';
}, },

View File

@ -1,36 +1,49 @@
<template> <template>
<div id="app" v-loading="loading"> <div id="app" v-loading="loading">
<el-row> <el-row>
<el-col> <el-col></el-col>
<el-button style="float: right" type="text" size="mini" @click="expandAll"> <div style="float: right">
<el-button style="margin-right: 5px" type="text" size="mini" @click="expandAll">
{{ expandTitle }} {{ expandTitle }}
</el-button> </el-button>
</el-col>
<api-params-config
v-if="apiJsonSchemaConfigFields"
:storage-key="storageKey"
@refresh="refreshApiParamsField"
:api-params-config-fields="apiJsonSchemaConfigFields" />
</div>
</el-row> </el-row>
<div :style="jsonSchemaDisable ? '' : 'min-height: 200px'"> <div :style="jsonSchemaDisable ? '' : 'min-height: 200px'">
<json-schema-panel <div style="overflow: auto">
class="schema" <json-schema-panel
:disabled="jsonSchemaDisable" class="schema"
:value="schema" v-if="reloadedApiVariable"
:show-mock-vars="showMockVars" :disabled="jsonSchemaDisable"
:scenario-definition="scenarioDefinition" :value="schema"
:expand-all-params="expandAllParams" :show-mock-vars="showMockVars"
@editScenarioAdvance="editScenarioAdvance" :scenario-definition="scenarioDefinition"
lang="zh_CN" :param-columns="apiJsonSchemaShowColumns"
custom /> :expand-all-params="expandAllParams"
@editScenarioAdvance="editScenarioAdvance"
lang="zh_CN"
custom />
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import JsonSchemaPanel from '@/business/definition/components/document/components/JsonSchema/JsonSchemaPanel'; import JsonSchemaPanel from '@/business/definition/components/document/components/JsonSchema/JsonSchemaPanel';
import { getApiJsonSchemaConfigFields, getShowFields } from 'metersphere-frontend/src/utils/custom_field';
import ApiParamsConfig from '@/business/definition/components/request/components/ApiParamsConfig';
const Convert = require('@/business/commons/json-schema/convert/convert.js'); const Convert = require('@/business/commons/json-schema/convert/convert.js');
const MsConvert = new Convert(); const MsConvert = new Convert();
export default { export default {
name: 'JsonSchemaShow', name: 'JsonSchemaShow',
components: { JsonSchemaPanel }, components: { JsonSchemaPanel, ApiParamsConfig },
props: { props: {
body: {}, body: {},
showPreview: { showPreview: {
@ -57,6 +70,7 @@ export default {
this.schema = { root: this.body.jsonSchema }; this.schema = { root: this.body.jsonSchema };
} }
this.body.jsonSchema = this.schema.root; this.body.jsonSchema = this.schema.root;
this.apiJsonSchemaShowColumns = getShowFields(this.storageKey);
}, },
watch: { watch: {
schema: { schema: {
@ -86,6 +100,10 @@ export default {
properties: {}, properties: {},
}, },
}, },
reloadedApiVariable: true,
storageKey: 'API_JSON_SCHEMA_SHOW_FIELD',
apiJsonSchemaConfigFields: getApiJsonSchemaConfigFields(this),
apiJsonSchemaShowColumns: [],
loading: false, loading: false,
expandAllParams: false, expandAllParams: false,
}; };
@ -96,6 +114,9 @@ export default {
}, },
}, },
methods: { methods: {
refreshApiParamsField() {
this.apiJsonSchemaShowColumns = getShowFields(this.storageKey);
},
expandAll() { expandAll() {
this.expandAllParams = !this.expandAllParams; this.expandAllParams = !this.expandAllParams;
}, },

View File

@ -0,0 +1,63 @@
<template>
<el-popover placement="top" width="100" v-model="isActive">
<div v-for="item in apiParamsConfigFields" :key="item.value">
<el-checkbox-group v-model="checkList">
<el-checkbox :label="item.value">{{ item.text }}</el-checkbox>
</el-checkbox-group>
</div>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="cancel">{{ $t('commons.cancel') }}</el-button>
<el-button type="primary" size="mini" @click="confirm">{{ $t('commons.confirm') }}</el-button>
</div>
<i slot="reference" class="el-icon-setting" />
</el-popover>
</template>
<script>
import { getShowFields } from 'metersphere-frontend/src/utils/custom_field';
export default {
name: 'ApiParamsConfig',
data() {
return {
isActive: false,
checkList: [],
};
},
props: {
apiParamsConfigFields: Array,
showColumns: Array,
storageKey: {
type: String,
default() {
return 'API_PARAMS_SHOW_FIELD';
},
},
},
watch: {
isActive() {
if (this.isActive) {
this.checkList = this.getCheckList(this.storageKey);
}
},
},
methods: {
cancel() {
this.isActive = false;
},
confirm() {
let apiParamsShowFields = JSON.stringify(this.checkList);
localStorage.setItem(this.storageKey, apiParamsShowFields);
this.$nextTick(() => {
this.$emit('refresh');
this.isActive = false;
});
},
getCheckList(fieldKey) {
return getShowFields(fieldKey);
},
},
};
</script>
<style scoped></style>

View File

@ -52,10 +52,14 @@
</div> </div>
</span> </span>
</el-tooltip> </el-tooltip>
<el-row> <el-row class="ms-el-link">
<el-link class="ms-el-link" @click="batchAdd" style="color: var(--primary_color)"> <el-link @click="batchAdd" style="margin-right: 5px; color: var(--primary_color)">
{{ $t('commons.batch_add') }} {{ $t('commons.batch_add') }}
</el-link> </el-link>
<api-params-config
v-if="apiParamsConfigFields"
@refresh="refreshApiParamsField"
:api-params-config-fields="apiParamsConfigFields" />
</el-row> </el-row>
<ms-api-variable <ms-api-variable
@editScenarioAdvance="editScenarioAdvance" @editScenarioAdvance="editScenarioAdvance"
@ -84,10 +88,14 @@
</div> </div>
</span> </span>
</el-tooltip> </el-tooltip>
<el-row> <el-row class="ms-el-link">
<el-link class="ms-el-link" @click="batchAdd" style="color: var(--primary_color)"> <el-link @click="batchAdd" style="margin-right: 5px; color: var(--primary_color)">
{{ $t('commons.batch_add') }} {{ $t('commons.batch_add') }}
</el-link> </el-link>
<api-params-config
v-if="apiParamsConfigFields"
@refresh="refreshApiParamsField"
:api-params-config-fields="apiParamsConfigFields" />
</el-row> </el-row>
<ms-api-variable <ms-api-variable
@editScenarioAdvance="editScenarioAdvance" @editScenarioAdvance="editScenarioAdvance"
@ -197,6 +205,7 @@ import MsApiBody from '../../body/ApiBody';
import MsApiAuthConfig from '../../auth/ApiAuthConfig'; import MsApiAuthConfig from '../../auth/ApiAuthConfig';
import ApiRequestMethodSelect from '../../collapse/ApiRequestMethodSelect'; import ApiRequestMethodSelect from '../../collapse/ApiRequestMethodSelect';
import { REQUEST_HEADERS } from 'metersphere-frontend/src/utils/constants'; import { REQUEST_HEADERS } from 'metersphere-frontend/src/utils/constants';
import { getApiParamsConfigFields } from 'metersphere-frontend/src/utils/custom_field';
import MsApiVariable from '../../ApiVariable'; import MsApiVariable from '../../ApiVariable';
import MsApiAssertions from '../../assertion/ApiAssertions'; import MsApiAssertions from '../../assertion/ApiAssertions';
import MsApiExtract from '../../extract/ApiExtract'; import MsApiExtract from '../../extract/ApiExtract';
@ -208,6 +217,7 @@ import MsApiAdvancedConfig from './ApiAdvancedConfig';
import MsJsr233Processor from '@/business/automation/scenario/component/Jsr233Processor'; import MsJsr233Processor from '@/business/automation/scenario/component/Jsr233Processor';
import Convert from '@/business/commons/json-schema/convert/convert'; import Convert from '@/business/commons/json-schema/convert/convert';
import { hisDataProcessing, stepCompute } from '@/business/definition/api-definition'; import { hisDataProcessing, stepCompute } from '@/business/definition/api-definition';
import ApiParamsConfig from '@/business/definition/components/request/components/ApiParamsConfig';
export default { export default {
name: 'MsApiHttpRequestForm', name: 'MsApiHttpRequestForm',
@ -222,6 +232,7 @@ export default {
MsApiBody, MsApiBody,
MsApiKeyValue, MsApiKeyValue,
MsApiAssertions, MsApiAssertions,
ApiParamsConfig,
MsJmxStep: () => import('@/business/definition/components/step/JmxStep'), MsJmxStep: () => import('@/business/definition/components/step/JmxStep'),
}, },
props: { props: {
@ -273,6 +284,8 @@ export default {
}; };
return { return {
activeName: this.request.method === 'POST' ? 'body' : 'parameters', activeName: this.request.method === 'POST' ? 'body' : 'parameters',
queryColumnConfig: false,
apiParamsConfigFields: getApiParamsConfigFields(this),
rules: { rules: {
name: [ name: [
{ {
@ -336,6 +349,13 @@ export default {
}); });
}); });
}, },
refreshApiParamsField() {
let oldActiveName = this.activeName;
this.activeName = 'refreshing';
this.$nextTick(() => {
this.activeName = oldActiveName;
});
},
changeActiveName() { changeActiveName() {
if (this.request.headers && this.request.headers.length > 1) { if (this.request.headers && this.request.headers.length > 1) {
this.activeName = 'headers'; this.activeName = 'headers';

View File

@ -8,11 +8,14 @@
v-loading="tableIsLoading" v-loading="tableIsLoading"
:data="data" :data="data"
:default-sort="defaultSort" :default-sort="defaultSort"
:class="{'ms-select-all-fixed': (showSelectAll && !hidePopover), 'row-click': rowClickStyle}" :class="{
'ms-select-all-fixed': showSelectAll && !hidePopover,
'row-click': rowClickStyle,
}"
:height="screenHeight" :height="screenHeight"
:row-key="rowKey" :row-key="rowKey"
:row-class-name="tableRowClassName" :row-class-name="tableRowClassName"
:row-style='rowStyle' :row-style="rowStyle"
:cell-class-name="addPaddingColClass" :cell-class-name="addPaddingColClass"
:highlight-current-row="highlightCurrentRow" :highlight-current-row="highlightCurrentRow"
@sort-change="sort" @sort-change="sort"
@ -22,35 +25,37 @@
@header-dragend="headerDragend" @header-dragend="headerDragend"
@cell-mouse-enter="showPopover" @cell-mouse-enter="showPopover"
@row-click="handleRowClick" @row-click="handleRowClick"
ref="table"> ref="table"
>
<el-table-column v-if="enableSelection" width="50" type="selection" />
<ms-table-header-select-popover
v-if="enableSelection && showSelectAll && !hidePopover"
:page-size="pageSize > total ? total : pageSize"
:table-data-count-in-page="data.length"
:total="total"
:select-type="condition.selectAll"
@selectPageAll="isSelectDataAll(false)"
@selectAll="isSelectDataAll(true)"
ref="selectPopover"
/>
<el-table-column <el-table-column
v-if="enableSelection" v-if="enableSelection && batchOperators && batchOperators.length > 0"
width="50" width="15"
type="selection"/> fixed="left"
column-key="batchBtnCol"
<ms-table-header-select-popover v-if="enableSelection && showSelectAll && !hidePopover" align="center"
:page-size="pageSize > total ? total : pageSize" :resizable="false"
:table-data-count-in-page="data.length" >
:total="total"
:select-type="condition.selectAll"
@selectPageAll="isSelectDataAll(false)"
@selectAll="isSelectDataAll(true)"
ref="selectPopover"/>
<el-table-column v-if="enableSelection && batchOperators && batchOperators.length > 0"
width="15"
fixed="left"
column-key="batchBtnCol"
align="center"
:resizable="false">
<template v-slot:default="scope"> <template v-slot:default="scope">
<!-- 选中记录后浮现的按钮提供对记录的批量操作 --> <!-- 选中记录后浮现的按钮提供对记录的批量操作 -->
<show-more-btn :has-showed="hasBatchTipShow" <show-more-btn
:is-show="scope.row.showMore" :has-showed="hasBatchTipShow"
:buttons="batchOperators" :is-show="scope.row.showMore"
:size="selectDataCounts"/> :buttons="batchOperators"
:size="selectDataCounts"
/>
</template> </template>
</el-table-column> </el-table-column>
@ -64,11 +69,12 @@
<el-table-column <el-table-column
v-if="enableOrderDrag" v-if="enableOrderDrag"
width="20" width="20"
column-key="tableRowDropCol"> column-key="tableRowDropCol"
>
<template v-slot:default="scope"> <template v-slot:default="scope">
<div class="table-row-drop-bar"> <div class="table-row-drop-bar">
<i class="el-icon-more ms-icon-more"/> <i class="el-icon-more ms-icon-more" />
<i class="el-icon-more ms-icon-more"/> <i class="el-icon-more ms-icon-more" />
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -79,28 +85,24 @@
v-if="operators && operators.length > 0" v-if="operators && operators.length > 0"
:fixed="operatorFixed" :fixed="operatorFixed"
:min-width="operatorWidth" :min-width="operatorWidth"
:label="$t('commons.operating')"> :label="$t('commons.operating')"
>
<template slot="header"> <template slot="header">
<header-label-operate <header-label-operate
v-if="fieldKey" v-if="fieldKey"
:disable-header-config="disableHeaderConfig" :disable-header-config="disableHeaderConfig"
@exec="openCustomHeader"/> @exec="openCustomHeader"
/>
</template> </template>
<template <template v-slot:default="scope">
v-slot:default="scope">
<div> <div>
<slot <slot name="opt-before" :row="scope.row"></slot>
name="opt-before"
:row="scope.row">
</slot>
<ms-table-operators <ms-table-operators
:buttons="operators" :buttons="operators"
:row="scope.row" :row="scope.row"
:index="scope.$index"/> :index="scope.$index"
<slot />
name="opt-behind" <slot name="opt-behind" :row="scope.row"></slot>
:row="scope.row">
</slot>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -111,8 +113,8 @@
:type="fieldKey" :type="fieldKey"
:custom-fields="customFields" :custom-fields="customFields"
@reload="resetHeader" @reload="resetHeader"
ref="customTableHeader"/> ref="customTableHeader"
/>
</div> </div>
</template> </template>
@ -122,15 +124,15 @@ import {
_handleSelect, _handleSelect,
_handleSelectAll, _handleSelectAll,
_sort, _sort,
getSelectDataCounts,
setUnSelectIds,
toggleAllSelection,
checkTableRowIsSelect, checkTableRowIsSelect,
clearShareDragParam,
getCustomTableHeader, getCustomTableHeader,
getSelectDataCounts,
handleRowDrop,
saveCustomTableWidth, saveCustomTableWidth,
saveLastTableSortField, saveLastTableSortField,
handleRowDrop, setUnSelectIds,
clearShareDragParam, toggleAllSelection,
} from "../../utils/tableUtils"; } from "../../utils/tableUtils";
import MsTableHeaderSelectPopover from "./MsTableHeaderSelectPopover"; import MsTableHeaderSelectPopover from "./MsTableHeaderSelectPopover";
import MsTablePagination from "../pagination/TablePagination"; import MsTablePagination from "../pagination/TablePagination";
@ -140,8 +142,7 @@ import MsTableOperators from "../MsTableOperators";
import HeaderLabelOperate from "../head/HeaderLabelOperate"; import HeaderLabelOperate from "../head/HeaderLabelOperate";
import HeaderCustom from "../head/HeaderCustom"; import HeaderCustom from "../head/HeaderCustom";
import MsCustomTableHeader from "./MsCustomTableHeader"; import MsCustomTableHeader from "./MsCustomTableHeader";
import {lineToHump} from "../../utils"; import { getUUID, lineToHump } from "../../utils";
import {getUUID} from "../../utils";
/** /**
* 参考 ApiList * 参考 ApiList
@ -160,7 +161,12 @@ export default {
components: { components: {
MsCustomTableHeader, MsCustomTableHeader,
HeaderLabelOperate, HeaderLabelOperate,
MsTableOperators, MsTableColumn, ShowMoreBtn, MsTablePagination, MsTableHeaderSelectPopover, HeaderCustom MsTableOperators,
MsTableColumn,
ShowMoreBtn,
MsTablePagination,
MsTableHeaderSelectPopover,
HeaderCustom,
}, },
data() { data() {
return { return {
@ -182,91 +188,91 @@ export default {
type: Boolean, type: Boolean,
default() { default() {
return false; return false;
} },
}, },
selectNodeIds: { selectNodeIds: {
type: Array, type: Array,
default() { default() {
return []; return [];
} },
}, },
data: { data: {
type: Array, type: Array,
default() { default() {
return []; return [];
} },
}, },
condition: { condition: {
type: Object, type: Object,
default() { default() {
return {}; return {};
} },
}, },
pageSize: { pageSize: {
type: Number, type: Number,
default() { default() {
return 10; return 10;
} },
}, },
total: { total: {
type: Number, type: Number,
default() { default() {
return 10; return 10;
} },
}, },
// //
operators: { operators: {
type: Array, type: Array,
default() { default() {
return []; return [];
} },
}, },
// //
batchOperators: { batchOperators: {
type: Array, type: Array,
default() { default() {
return []; return [];
} },
}, },
// //
operatorWidth: { operatorWidth: {
type: String, type: String,
default() { default() {
return "150px"; return "150px";
} },
}, },
// //
operatorFixed: { operatorFixed: {
type: [String, Boolean], type: [String, Boolean],
default() { default() {
return "right"; return "right";
} },
}, },
// //
enableSelection: { enableSelection: {
type: Boolean, type: Boolean,
default() { default() {
return true; return true;
} },
}, // }, //
showSelectAll: { showSelectAll: {
type: Boolean, type: Boolean,
default() { default() {
return true; return true;
} },
}, },
// //
rowClickStyle: { rowClickStyle: {
type: Boolean, type: Boolean,
default() { default() {
return false; return false;
} },
}, },
tableIsLoading: { tableIsLoading: {
type: [Boolean, Promise], type: [Boolean, Promise],
default() { default() {
return false; return false;
} },
}, },
disableHeaderConfig: Boolean, disableHeaderConfig: Boolean,
fields: Array, fields: Array,
@ -279,10 +285,9 @@ export default {
rowKey: [String, Function], rowKey: [String, Function],
// idid // idid
rowOrderGroupId: String, rowOrderGroupId: String,
rowOrderFunc: Function rowOrderFunc: Function,
},
created() {
}, },
created() {},
mounted() { mounted() {
this.setDefaultOrders(); this.setDefaultOrders();
}, },
@ -310,15 +315,16 @@ export default {
}, },
selectDataCounts(value) { selectDataCounts(value) {
this.$emit("selectCountChange", value); this.$emit("selectCountChange", value);
} },
}, },
methods: { methods: {
// , , // , ,
// batch-popper , , // batch-popper , ,
removeBatchPopper() { removeBatchPopper() {
let elements = window.document.getElementsByClassName('batch-popper'); let elements = window.document.getElementsByClassName("batch-popper");
let tableHeader = window.document.getElementsByClassName('table-column-mark'); let tableHeader =
let columns = window.document.getElementsByClassName('table-more-icon'); window.document.getElementsByClassName("table-column-mark");
let columns = window.document.getElementsByClassName("table-more-icon");
let tableTop = tableHeader[0].getBoundingClientRect().top; let tableTop = tableHeader[0].getBoundingClientRect().top;
let index = 0; let index = 0;
for (let i = 0; i < columns.length; i++) { for (let i = 0; i < columns.length; i++) {
@ -331,7 +337,7 @@ export default {
if (elements) { if (elements) {
for (let i = 0; i < elements.length; i++) { for (let i = 0; i < elements.length; i++) {
if (i == index) { if (i == index) {
elements[i].classList.remove('batch-popper'); elements[i].classList.remove("batch-popper");
setTimeout(() => { setTimeout(() => {
this.hasBatchTipShow = true; this.hasBatchTipShow = true;
}, 1500); }, 1500);
@ -342,15 +348,20 @@ export default {
// //
listenRowDrop() { listenRowDrop() {
if (this.rowOrderGroupId) { if (this.rowOrderGroupId) {
handleRowDrop(this.data, (param) => { handleRowDrop(
param.groupId = this.rowOrderGroupId; this.data,
if (this.rowOrderFunc) { (param) => {
this.rowOrderFunc(param); param.groupId = this.rowOrderGroupId;
} if (this.rowOrderFunc) {
}, this.msTableKey); this.rowOrderFunc(param);
}
},
this.msTableKey
);
} }
}, },
isScrollShow(column, tableTop) { // isScrollShow(column, tableTop) {
//
let columnTop = column.getBoundingClientRect().top; let columnTop = column.getBoundingClientRect().top;
return columnTop - tableTop > 30; return columnTop - tableTop > 30;
}, },
@ -358,25 +369,35 @@ export default {
setDefaultOrders() { setDefaultOrders() {
let orders = this.condition.orders; let orders = this.condition.orders;
if (orders) { if (orders) {
orders.forEach(item => { orders.forEach((item) => {
this.defaultSort = { this.defaultSort = {
prop: lineToHump(item.name), prop: lineToHump(item.name),
order: 'descending' order: "descending",
}; };
if (item.type === 'asc') { if (item.type === "asc") {
this.defaultSort.order = 'ascending'; this.defaultSort.order = "ascending";
} }
return; return;
}); });
} }
}, },
handleSelectAll(selection) { handleSelectAll(selection) {
_handleSelectAll(this, selection, this.data, this.selectRows, this.condition); _handleSelectAll(
this,
selection,
this.data,
this.selectRows,
this.condition
);
setUnSelectIds(this.data, this.condition, this.selectRows); setUnSelectIds(this.data, this.condition, this.selectRows);
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows); this.selectDataCounts = getSelectDataCounts(
this.selectIds = Array.from(this.selectRows).map(o => o.id); this.condition,
this.total,
this.selectRows
);
this.selectIds = Array.from(this.selectRows).map((o) => o.id);
// //
this.$emit('callBackSelectAll', selection); this.$emit("callBackSelectAll", selection);
this.$nextTick(function () { this.$nextTick(function () {
setTimeout(this.removeBatchPopper, 1); setTimeout(this.removeBatchPopper, 1);
}); });
@ -384,10 +405,14 @@ export default {
handleSelect(selection, row) { handleSelect(selection, row) {
_handleSelect(this, selection, row, this.selectRows); _handleSelect(this, selection, row, this.selectRows);
setUnSelectIds(this.data, this.condition, this.selectRows); setUnSelectIds(this.data, this.condition, this.selectRows);
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows); this.selectDataCounts = getSelectDataCounts(
this.selectIds = Array.from(this.selectRows).map(o => o.id); this.condition,
this.total,
this.selectRows
);
this.selectIds = Array.from(this.selectRows).map((o) => o.id);
// //
this.$emit('callBackSelect', selection); this.$emit("callBackSelect", selection);
this.$nextTick(function () { this.$nextTick(function () {
setTimeout(this.removeBatchPopper, 1); setTimeout(this.removeBatchPopper, 1);
}); });
@ -401,8 +426,12 @@ export default {
//ID() //ID()
this.condition.unSelectIds = []; this.condition.unSelectIds = [];
// //
this.selectDataCounts = getSelectDataCounts(this.condition, this.total, this.selectRows); this.selectDataCounts = getSelectDataCounts(
this.selectIds = Array.from(this.selectRows).map(o => o.id); this.condition,
this.total,
this.selectRows
);
this.selectIds = Array.from(this.selectRows).map((o) => o.id);
}, },
headerDragend(newWidth, oldWidth, column, event) { headerDragend(newWidth, oldWidth, column, event) {
if (column) { if (column) {
@ -417,11 +446,6 @@ export default {
// //
saveCustomTableWidth(this.fieldKey, column.columnKey, newWidth); saveCustomTableWidth(this.fieldKey, column.columnKey, newWidth);
}, },
showPopover(row, column, cell) {
if (column.property === 'name') {
this.currentCaseId = row.id;
}
},
doLayout() { doLayout() {
if (this.$refs.table) { if (this.$refs.table) {
// //
@ -430,9 +454,14 @@ export default {
} }
} }
}, },
showPopover(row, column, cell) {
if (column.property === "name") {
this.currentCaseId = row.id;
}
},
filter(filters) { filter(filters) {
_filter(filters, this.condition); _filter(filters, this.condition);
this.$emit('filter'); this.$emit("filter");
this.handleRefresh(); this.handleRefresh();
}, },
sort(column) { sort(column) {
@ -442,9 +471,12 @@ export default {
} }
_sort(column, this.condition); _sort(column, this.condition);
if (this.rememberOrder) { if (this.rememberOrder) {
saveLastTableSortField(this.fieldKey, JSON.stringify(this.condition.orders)); saveLastTableSortField(
this.fieldKey,
JSON.stringify(this.condition.orders)
);
} }
this.$emit('order', column); this.$emit("order", column);
this.handleRefresh(); this.handleRefresh();
}, },
handleBatchEdit() { handleBatchEdit() {
@ -452,17 +484,21 @@ export default {
this.$refs.batchEdit.open(); this.$refs.batchEdit.open();
}, },
handleBatchMove() { handleBatchMove() {
this.$refs.testBatchMove.open(this.treeNodes, Array.from(this.selectRows).map(row => row.id), this.moduleOptions); this.$refs.testBatchMove.open(
this.treeNodes,
Array.from(this.selectRows).map((row) => row.id),
this.moduleOptions
);
}, },
handleRowClick(row, column) { handleRowClick(row, column) {
this.$emit("handleRowClick", row, column); this.$emit("handleRowClick", row, column);
}, },
handleRefresh() { handleRefresh() {
this.clear(); this.clear();
this.$emit('refresh'); this.$emit("refresh");
}, },
handlePageChange() { handlePageChange() {
this.$emit('pageChange'); this.$emit("pageChange");
}, },
cancelCurrentRow() { cancelCurrentRow() {
this.$refs.table.setCurrentRow(-1); this.$refs.table.setCurrentRow(-1);
@ -474,7 +510,13 @@ export default {
this.clearSelectRows(); this.clearSelectRows();
}, },
checkTableRowIsSelect() { checkTableRowIsSelect() {
checkTableRowIsSelect(this, this.condition, this.data, this.$refs.table, this.selectRows); checkTableRowIsSelect(
this,
this.condition,
this.data,
this.$refs.table,
this.selectRows
);
}, },
clearSelection() { clearSelection() {
this.clearSelectRows(); this.clearSelectRows();
@ -494,7 +536,10 @@ export default {
this.$refs.customTableHeader.open(this.fields); this.$refs.customTableHeader.open(this.fields);
}, },
resetHeader() { resetHeader() {
this.$emit('update:fields', getCustomTableHeader(this.fieldKey, this.customFields)); this.$emit(
"update:fields",
getCustomTableHeader(this.fieldKey, this.customFields)
);
this.tableActive = false; this.tableActive = false;
this.$nextTick(() => { this.$nextTick(() => {
this.doLayout(); this.doLayout();
@ -510,30 +555,32 @@ export default {
this.doLayout(); this.doLayout();
}); });
}, },
addPaddingColClass({column}) { addPaddingColClass({ column }) {
if (column.columnKey === 'tableRowDropCol' if (
|| column.columnKey === 'selectionCol' column.columnKey === "tableRowDropCol" ||
|| column.columnKey === 'batchBtnCol') { column.columnKey === "selectionCol" ||
return 'padding-col'; column.columnKey === "batchBtnCol"
) {
return "padding-col";
} }
}, },
rowStyle({row}) { rowStyle({ row }) {
return row.hidden ? {"display": "none"} : {}; return row.hidden ? { display: "none" } : {};
}, },
tableRowClassName(row) { tableRowClassName(row) {
if (row.row.hidden) { if (row.row.hidden) {
return 'ms-variable-hidden-row'; return "ms-variable-hidden-row";
} }
return ''; return "";
}, },
} },
}; };
</script> </script>
<style scoped> <style scoped>
.batch-popper { .batch-popper {
top: 300px; top: 300px;
color: #1FDD02; color: #1fdd02;
} }
.el-table :deep(.padding-col) .cell { .el-table :deep(.padding-col) .cell {
@ -562,7 +609,10 @@ export default {
} }
.ms-table :deep(.el-table__body) tr.hover-row.current-row > td, .ms-table :deep(.el-table__body) tr.hover-row.current-row > td,
.ms-table :deep(.el-table__body) tr.hover-row.el-table__row--striped.current-row > td, .ms-table
:deep(.el-table__body)
tr.hover-row.el-table__row--striped.current-row
> td,
.ms-table :deep(.el-table__body) tr.hover-row.el-table__row--striped > td, .ms-table :deep(.el-table__body) tr.hover-row.el-table__row--striped > td,
.ms-table :deep(.el-table__body) tr.hover-row > td { .ms-table :deep(.el-table__body) tr.hover-row > td {
background-color: #ffffff; background-color: #ffffff;
@ -570,10 +620,10 @@ export default {
/* 解决拖拽排序后hover阴影错乱问题 */ /* 解决拖拽排序后hover阴影错乱问题 */
.ms-table :deep(.el-table__body) tr:hover > td { .ms-table :deep(.el-table__body) tr:hover > td {
background-color: #F5F7FA; background-color: #f5f7fa;
} }
.disable-hover :deep(tr:hover>td) { .disable-hover :deep(tr:hover > td) {
background-color: #ffffff !important; background-color: #ffffff !important;
} }

View File

@ -1,6 +1,6 @@
import i18n from '../i18n' import i18n from "../i18n";
import {getCurrentUserId} from "../utils/token"; import { getCurrentUserId } from "../utils/token";
import {SYSTEM_FIELD_NAME_MAP} from "../utils/table-constants"; import { SYSTEM_FIELD_NAME_MAP } from "../utils/table-constants";
function setDefaultValue(item, value) { function setDefaultValue(item, value) {
item.defaultValue = value; item.defaultValue = value;
@ -25,8 +25,7 @@ export function parseCustomField(data, template, rules, oldFields) {
let customFieldForm = {}; let customFieldForm = {};
// 设置页面显示的默认值 // 设置页面显示的默认值
template.customFields.forEach(item => { template.customFields.forEach((item) => {
if (item.defaultValue && !item.hasParse) { if (item.defaultValue && !item.hasParse) {
let val = item.defaultValue; let val = item.defaultValue;
try { try {
@ -34,7 +33,12 @@ export function parseCustomField(data, template, rules, oldFields) {
} catch (e) { } catch (e) {
// //
} }
if (item.name === '责任人' && item.system && val && val === 'CURRENT_USER') { if (
item.name === "责任人" &&
item.system &&
val &&
val === "CURRENT_USER"
) {
val = getCurrentUserId(); val = getCurrentUserId();
} }
setDefaultValue(item, val); setDefaultValue(item, val);
@ -42,11 +46,11 @@ export function parseCustomField(data, template, rules, oldFields) {
// 添加自定义字段必填校验 // 添加自定义字段必填校验
if (item.required) { if (item.required) {
let msg = (item.system ? i18n.t(SYSTEM_FIELD_NAME_MAP[item.name]) : item.name) + i18n.t('commons.cannot_be_null'); let msg =
(item.system ? i18n.t(SYSTEM_FIELD_NAME_MAP[item.name]) : item.name) +
i18n.t("commons.cannot_be_null");
if (rules) { if (rules) {
rules[item.name] = [ rules[item.name] = [{ required: true, message: msg, trigger: "blur" }];
{required: true, message: msg, trigger: 'blur'}
];
} }
} }
@ -67,7 +71,7 @@ export function parseCustomField(data, template, rules, oldFields) {
let customField = data.fields[i]; let customField = data.fields[i];
if (customField.id === item.id) { if (customField.id === item.id) {
try { try {
if (item.type === 'textarea' || item.type === 'richText') { if (item.type === "textarea" || item.type === "richText") {
setDefaultValue(item, customField.textValue); setDefaultValue(item, customField.textValue);
} else { } else {
setDefaultValue(item, customField.value); setDefaultValue(item, customField.value);
@ -79,7 +83,8 @@ export function parseCustomField(data, template, rules, oldFields) {
break; break;
} }
} }
} else if (data.fields instanceof Object) { // todo } else if (data.fields instanceof Object) {
// todo
// 兼容旧的存储方式 // 兼容旧的存储方式
for (const key in data.fields) { for (const key in data.fields) {
if (item.name === key) { if (item.name === key) {
@ -107,27 +112,31 @@ export function buildCustomFields(data, param, template) {
let editFields = []; let editFields = [];
let requestFields = []; let requestFields = [];
template.customFields.forEach(item => { template.customFields.forEach((item) => {
let customField = {fieldId: item.id}; let customField = { fieldId: item.id };
if (['richText', 'textarea'].indexOf(item.type) > -1) { if (["richText", "textarea"].indexOf(item.type) > -1) {
customField['textValue'] = item.defaultValue; customField["textValue"] = item.defaultValue;
} else { } else {
customField['value'] = item.defaultValue ? JSON.stringify(item.defaultValue): ""; customField["value"] = item.defaultValue
? JSON.stringify(item.defaultValue)
: "";
} }
if (item.isEdit) { if (item.isEdit) {
editFields.push(customField); editFields.push(customField);
} else { } else {
addFields.push(customField); addFields.push(customField);
} }
let fieldValue = (item.defaultValue instanceof Array && item.type !== 'multipleInput') ? let fieldValue =
JSON.stringify(item.defaultValue) : (item.defaultValue || ""); item.defaultValue instanceof Array && item.type !== "multipleInput"
? JSON.stringify(item.defaultValue)
: item.defaultValue || "";
let requestField = { let requestField = {
id: item.id, id: item.id,
name: item.name, name: item.name,
customData: item.customData, customData: item.customData,
type: item.type, type: item.type,
value: fieldValue value: fieldValue,
} };
requestFields.push(requestField); requestFields.push(requestField);
}); });
param.addFields = addFields; param.addFields = addFields;
@ -142,7 +151,7 @@ export function getTemplate(baseUrl, vueObj) {
vueObj.$get(baseUrl + vueObj.projectId, (response) => { vueObj.$get(baseUrl + vueObj.projectId, (response) => {
template = response.data; template = response.data;
if (template.customFields) { if (template.customFields) {
template.customFields.forEach(item => { template.customFields.forEach((item) => {
if (item.options) { if (item.options) {
item.options = JSON.parse(item.options); item.options = JSON.parse(item.options);
} }
@ -156,28 +165,64 @@ export function getTemplate(baseUrl, vueObj) {
// 兼容旧字段 // 兼容旧字段
export function buildTestCaseOldFields(testCase) { export function buildTestCaseOldFields(testCase) {
let oldFields = new Map(); let oldFields = new Map();
oldFields.set('用例状态', testCase.status); oldFields.set("用例状态", testCase.status);
oldFields.set('责任人', testCase.maintainer); oldFields.set("责任人", testCase.maintainer);
oldFields.set('用例等级', testCase.priority); oldFields.set("用例等级", testCase.priority);
return oldFields; return oldFields;
} }
export function sortCustomFields(customFields) { export function sortCustomFields(customFields) {
let total = 0;//定义total用于控制循环结束 let total = 0; //定义total用于控制循环结束
for (let i = 0; total < customFields.length; total++) { for (let i = 0; total < customFields.length; total++) {
if (typeof (customFields[i].defaultValue) === 'string' || customFields[i].defaultValue instanceof String) { if (
typeof customFields[i].defaultValue === "string" ||
customFields[i].defaultValue instanceof String
) {
try { try {
customFields[i].defaultValue = JSON.parse(customFields[i].defaultValue); customFields[i].defaultValue = JSON.parse(customFields[i].defaultValue);
} catch (e) { } catch (e) {
// nothing // nothing
} }
} }
if (customFields[i].type === 'richText') { if (customFields[i].type === "richText") {
//循环到是0的位置就删除该元素0并且在arr末尾push进这个元素0由于splice删除了该位置元素所以i不用+1下次循环仍然检查i位置的元素 //循环到是0的位置就删除该元素0并且在arr末尾push进这个元素0由于splice删除了该位置元素所以i不用+1下次循环仍然检查i位置的元素
customFields.push(customFields.splice(i, 1)[0]); customFields.push(customFields.splice(i, 1)[0]);
} else { } else {
i++;//循环到不是0的位置就继续往后循环 i++; //循环到不是0的位置就继续往后循环
} }
} }
return customFields; return customFields;
} }
export function getApiParamsConfigFields(_this) {
return [
{ value: "MIX_LENGTH", text: _this.$t("schema.minLength") },
{ value: "MAX_LENGTH", text: _this.$t("schema.maxLength") },
{ value: "ENCODE", text: _this.$t("commons.encode") },
{ value: "DESCRIPTION", text: _this.$t("commons.description") },
];
}
export function getApiJsonSchemaConfigFields(_this) {
return [
{ value: "MIX_LENGTH", text: _this.$t("schema.minLength") },
{ value: "MAX_LENGTH", text: _this.$t("schema.maxLength") },
{ value: "DEFAULT", text: _this.$t("commons.default") },
{ value: "ENUM", text: _this.$t("schema.enum") },
{ value: "PATTERN", text: _this.$t("schema.pattern") },
{ value: "FORMAT", text: _this.$t("schema.format") },
{ value: "DESCRIPTION", text: _this.$t("commons.description") },
];
}
export function getShowFields(key) {
let apiParamsShowFields = localStorage.getItem(key);
if (apiParamsShowFields) {
try {
return JSON.parse(apiParamsShowFields);
} catch (e) {
return [];
}
}
return [];
}