feat(接口测试): csv部分页面

This commit is contained in:
baiqi 2024-05-11 17:55:23 +08:00 committed by Craftsman
parent 1c1d52f45f
commit 472e7ae5eb
12 changed files with 354 additions and 52 deletions

View File

@ -403,7 +403,7 @@
function handleOpenSaveAs(item: TagData) { function handleOpenSaveAs(item: TagData) {
inputFilesPopoverVisible.value = false; inputFilesPopoverVisible.value = false;
// uid // uid
savingFile.value = fileList.value.find((file) => (file.uid || file[props.fields.id]) === item.value); savingFile.value = fileList.value.find((file) => file.uid === item.value || file[props.fields.id] === item.value);
saveFilePopoverVisible.value = true; saveFilePopoverVisible.value = true;
} }

View File

@ -122,7 +122,7 @@
(visible) => { (visible) => {
if (visible) { if (visible) {
initModuleOptions(); initModuleOptions();
saveFileForm.value.name = props.savingFile?.name?.split('.').shift() || ''; saveFileForm.value.name = (props.savingFile?.name || props.savingFile?.fileName)?.split('.').shift() || '';
} }
}, },
{ {

View File

@ -1,5 +1,5 @@
<template> <template>
<a-form ref="formRef" :model="propsRes"> <a-form ref="formRef" :model="propsRes" layout="vertical">
<MsBaseTable <MsBaseTable
v-bind="propsRes" v-bind="propsRes"
:hoverable="false" :hoverable="false"

View File

@ -13,6 +13,7 @@ import {
ResponseDefinition, ResponseDefinition,
} from '@/models/apiTest/common'; } from '@/models/apiTest/common';
import type { MockParams } from '@/models/apiTest/mock'; import type { MockParams } from '@/models/apiTest/mock';
import type { CsvVariable } from '@/models/apiTest/scenario';
import { import {
FullResponseAssertionType, FullResponseAssertionType,
RequestAssertionCondition, RequestAssertionCondition,
@ -242,16 +243,13 @@ export const regexDefaultParamItem = {
moreSettingPopoverVisible: false, moreSettingPopoverVisible: false,
}; };
// 响应断言类型映射 // 响应断言类型映射
export const responseAssertionTypeMap: Record<FullResponseAssertionType, string> = { export const responseAssertionTypeMap: Record<string, string> = {
[FullResponseAssertionType.DOCUMENT]: 'apiTestManagement.document', [FullResponseAssertionType.DOCUMENT]: 'apiTestManagement.document',
[FullResponseAssertionType.RESPONSE_CODE]: 'apiTestManagement.responseCode', [FullResponseAssertionType.RESPONSE_CODE]: 'apiTestManagement.responseCode',
[FullResponseAssertionType.RESPONSE_HEADER]: 'apiTestManagement.responseHeader', [FullResponseAssertionType.RESPONSE_HEADER]: 'apiTestManagement.responseHeader',
[FullResponseAssertionType.RESPONSE_TIME]: 'apiTestManagement.responseTime', [FullResponseAssertionType.RESPONSE_TIME]: 'apiTestManagement.responseTime',
[FullResponseAssertionType.SCRIPT]: 'apiTestManagement.script', [FullResponseAssertionType.SCRIPT]: 'apiTestManagement.script',
[FullResponseAssertionType.VARIABLE]: 'apiTestManagement.variable', [FullResponseAssertionType.VARIABLE]: 'apiTestManagement.variable',
[FullResponseAssertionType.JSON_PATH]: 'jsonPath',
[FullResponseAssertionType.XPATH]: 'xPath',
[FullResponseAssertionType.REGEX]: 'apiTestManagement.regex',
}; };
// 提取类型选项 // 提取类型选项
export const extractTypeOptions = [ export const extractTypeOptions = [
@ -415,3 +413,32 @@ export const matchRuleOptions = [
]; ];
// mock 参数为文件类型的匹配规则选项 // mock 参数为文件类型的匹配规则选项
export const mockFileMatchRules = ['EQUALS', 'NOT_EQUALS', 'IS_EMPTY', 'IS_NOT_EMPTY']; export const mockFileMatchRules = ['EQUALS', 'NOT_EQUALS', 'IS_EMPTY', 'IS_NOT_EMPTY'];
// 场景-常规参数默认值
export const defaultNormalParamItem = {
key: '',
paramType: 'CONSTANT',
value: '',
description: '',
tags: [],
enable: true,
};
// 场景-csv参数默认值
export const defaultCsvParamItem: CsvVariable = {
id: '',
fileId: '',
scenarioId: '',
name: '',
fileName: '',
scope: 'SCENARIO',
enable: true,
association: false,
encoding: 'UTF-8',
random: false,
variableNames: '',
ignoreFirstLine: false,
delimiter: ',',
allowQuotedData: false,
recycleOnEof: false,
stopThreadOnEof: false,
};

View File

@ -26,7 +26,13 @@
<template #typeTitle="{ columnConfig }"> <template #typeTitle="{ columnConfig }">
<div class="flex items-center text-[var(--color-text-3)]"> <div class="flex items-center text-[var(--color-text-3)]">
{{ t('apiTestDebug.paramType') }} {{ t('apiTestDebug.paramType') }}
<a-tooltip :content="columnConfig.typeTitleTooltip" :disabled="!columnConfig.typeTitleTooltip" position="right"> <a-tooltip :disabled="!columnConfig.typeTitleTooltip" position="right">
<template #content>
<template v-if="Array.isArray(columnConfig.typeTitleTooltip)">
<div v-for="tip of columnConfig.typeTitleTooltip" :key="tip">{{ tip }}</div>
</template>
<div v-else>{{ columnConfig.typeTitleTooltip }}</div>
</template>
<icon-question-circle <icon-question-circle
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]" class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
size="16" size="16"
@ -184,6 +190,17 @@
<template #expression="{ record, rowIndex, columnConfig }"> <template #expression="{ record, rowIndex, columnConfig }">
<slot name="expression" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot> <slot name="expression" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot>
</template> </template>
<!-- 作用域 -->
<template #scope="{ record, columnConfig, rowIndex }">
<a-select
v-model:model-value="record.scope"
:disabled="props.disabledExceptParam"
:options="columnConfig.typeOptions || []"
class="ms-form-table-input w-[180px]"
size="mini"
@change="() => addTableLine(rowIndex)"
/>
</template>
<!-- 参数值 --> <!-- 参数值 -->
<template #value="{ record, columnConfig, rowIndex }"> <template #value="{ record, columnConfig, rowIndex }">
<a-popover <a-popover
@ -238,6 +255,27 @@
@apply="() => addTableLine(rowIndex, columnConfig.addLineDisabled)" @apply="() => addTableLine(rowIndex, columnConfig.addLineDisabled)"
/> />
</template> </template>
<!-- 文件 -->
<template #file="{ record, rowIndex }">
<MsAddAttachment
v-model:file-list="record.files"
:disabled="props.disabledParamValue"
:multiple="false"
mode="input"
:fields="{
id: 'fileId',
name: 'fileAlias',
}"
:file-save-as-source-id="props.fileSaveAsSourceId"
:file-save-as-api="props.fileSaveAsApi"
:file-module-options-api="props.fileModuleOptionsApi"
input-class="ms-form-table-input h-[24px]"
input-size="small"
tag-size="small"
@change="(files, file) => handleFileChange(files, record, rowIndex, file)"
@delete-file="() => emitChange('deleteFile')"
/>
</template>
<!-- 长度范围 --> <!-- 长度范围 -->
<template #lengthRange="{ record, rowIndex }"> <template #lengthRange="{ record, rowIndex }">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
@ -430,9 +468,20 @@
/> />
<div v-else class="text-[var(--color-text-1)]">{{ '-' }}</div> <div v-else class="text-[var(--color-text-1)]">{{ '-' }}</div>
</template> </template>
<!-- 单独启用/禁用列 -->
<template #enable="{ record, rowIndex }">
<a-switch
v-model="record.enable"
:disabled="props.disabledExceptParam"
size="small"
type="line"
class="ml-[8px]"
@change="() => addTableLine(rowIndex)"
/>
</template>
<!-- 操作 --> <!-- 操作 -->
<template v-if="!props.disabledExceptParam" #operation="{ record, rowIndex, columnConfig }"> <template v-if="!props.disabledExceptParam" #operation="{ record, rowIndex, columnConfig }">
<div class="flex flex-row items-center" :class="{ 'justify-end': columnConfig.align === 'right' }"> <div class="flex w-full flex-row items-center" :class="{ 'justify-end': columnConfig.align === 'right' }">
<a-switch <a-switch
v-if="columnConfig.hasDisable" v-if="columnConfig.hasDisable"
v-model="record.enable" v-model="record.enable"
@ -573,7 +622,7 @@
isNormal?: boolean; // value MsParamsInput isNormal?: boolean; // value MsParamsInput
hasRequired?: boolean; // type required hasRequired?: boolean; // type required
typeOptions?: { label: string; value: string }[]; // type typeOptions?: { label: string; value: string }[]; // type
typeTitleTooltip?: string; // type tooltip typeTitleTooltip?: string | string[]; // type tooltip
hasDisable?: boolean; // operation enable hasDisable?: boolean; // operation enable
moreAction?: ActionsItem[]; // operation moreAction?: ActionsItem[]; // operation
format?: RequestBodyFormat; // operation format?: RequestBodyFormat; // operation

View File

@ -8,7 +8,12 @@
> >
<template #assertionItem="{ record }"> <template #assertionItem="{ record }">
<div class="flex items-center gap-[4px]"> <div class="flex items-center gap-[4px]">
{{ t(responseAssertionTypeMap[(record as ResponseAssertionTableItem).assertionType]) }} {{
t(
responseAssertionTypeMap[(record as ResponseAssertionTableItem).assertionType] ||
'apiTestDebug.responseBody'
)
}}
{{ record.name }} {{ record.name }}
</div> </div>
</template> </template>
@ -16,7 +21,7 @@
{{ {{
record.assertionType === FullResponseAssertionType.RESPONSE_TIME record.assertionType === FullResponseAssertionType.RESPONSE_TIME
? t('advanceFilter.operator.le') ? t('advanceFilter.operator.le')
: t(statusCodeOptions.find((item) => item.value === record.condition)?.label || '') : t(statusCodeOptions.find((item) => item.value === record.condition)?.label || '-')
}} }}
</template> </template>
<template #status="{ record }"> <template #status="{ record }">

View File

@ -1,16 +1,16 @@
<template> <template>
<div class="history-container"> <div class="history-container">
<a-alert v-if="isShowTip" :show-icon="true" class="mb-[8px]" type="info"> <a-alert :show-icon="true" class="mb-[8px]" type="info">
{{ t('apiScenario.params.priority') }} {{ t('apiScenario.params.priority') }}
</a-alert> </a-alert>
</div> </div>
<!-- <div class="mb-[16px]"> <div class="mb-[8px] flex items-center justify-between">
<a-radio-group v-model="activeRadio" type="button" size="medium"> <a-radio-group v-model="activeRadio" type="button" size="medium">
<a-radio value="convention">{{ t('apiScenario.params.convention') }}</a-radio> <a-radio value="convention">{{ t('apiScenario.params.convention') }}</a-radio>
<a-radio value="csv">{{ t('apiScenario.params.csv') }}</a-radio>
</a-radio-group> </a-radio-group>
</div>-->
<div class="mb-[8px] flex items-center justify-between">
<a-input-search <a-input-search
v-if="activeRadio === 'convention'"
v-model="searchValue" v-model="searchValue"
:placeholder="t('apiScenario.params.searchPlaceholder')" :placeholder="t('apiScenario.params.searchPlaceholder')"
allow-clear allow-clear
@ -21,58 +21,146 @@
/> />
</div> </div>
<paramTable <paramTable
v-model:params="innerParams" v-if="activeRadio === 'convention'"
v-model:params="commonVariables"
:columns="columns" :columns="columns"
:default-param-item="defaultParamItem" :default-param-item="defaultNormalParamItem"
draggable :draggable="false"
:selectable="false"
@change="handleParamTableChange" @change="handleParamTableChange"
@batch-add="batchAddKeyValVisible = true" @batch-add="batchAddKeyValVisible = true"
/> />
<paramTable
v-else
v-model:params="csvVariables"
:columns="csvColumns"
:default-param-item="defaultCsvParamItem"
:draggable="false"
:selectable="false"
@change="handleParamTableChange"
@batch-add="batchAddKeyValVisible = true"
>
<template #operationPre="{ record }">
<a-trigger trigger="click" position="br" class="scenario-csv-trigger">
<MsButton type="text" class="!mr-0">{{ t('apiScenario.params.config') }}</MsButton>
<template #content>
<div class="scenario-csv-trigger-content">
<div class="mb-[16px] flex items-center">
<div class="font-semibold text-[var(--color-text-1)]">{{ t('apiScenario.params.csvConfig') }}</div>
<!-- <div class="text-[var(--color-text-4)]">({{ record.key }})</div> -->
</div>
<div class="scenario-csv-trigger-content-scroll">
<a-form ref="paramFormRef" :model="record" layout="vertical">
<a-form-item
field="key"
:label="t('apiScenario.params.csvName')"
:rules="[{ required: true, message: t('apiScenario.params.csvNameNotNull') }]"
asterisk-position="end"
class="mb-[16px]"
>
<a-input v-model:model-value="record.key" :max-length="255"></a-input>
</a-form-item>
<a-form-item field="variableNames" :label="t('apiScenario.params.csvParamName')" class="mb-[16px]">
<a-input
v-model:model-value="record.variableNames"
:placeholder="t('apiScenario.params.csvParamNamePlaceholder')"
></a-input>
</a-form-item>
<a-form-item field="encoding" :label="t('apiScenario.params.csvFileCode')" class="mb-[16px]">
<a-select
v-model:model-value="record.encoding"
:options="encodingOptions"
class="w-[120px]"
></a-select>
</a-form-item>
<a-form-item field="delimiter" :label="t('apiScenario.params.csvSplitChar')" class="mb-[16px]">
<a-input
v-model:model-value="record.delimiter"
:placeholder="t('common.pleaseInput')"
:max-length="64"
class="w-[120px]"
></a-input>
</a-form-item>
<a-form-item
field="ignoreFirstLine"
:label="t('apiScenario.params.csvIgnoreFirstLine')"
class="mb-[16px]"
>
<a-radio-group v-model:model-value="record.ignoreFirstLine">
<a-radio :value="false">False</a-radio>
<a-radio :value="true">True</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item field="random" :label="t('apiScenario.params.csvIsRandom')" class="mb-[16px]">
<a-radio-group v-model:model-value="record.random">
<a-radio :value="false">False</a-radio>
<a-radio :value="true">True</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item field="allowQuotedData" :label="t('apiScenario.params.csvQuoteAllow')" class="mb-[16px]">
<a-radio-group v-model:model-value="record.allowQuotedData">
<a-radio :value="false">False</a-radio>
<a-radio :value="true">True</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item field="recycleOnEof" :label="t('apiScenario.params.csvRecycle')" class="mb-[16px]">
<a-radio-group v-model:model-value="record.recycleOnEof">
<a-radio :value="false">False</a-radio>
<a-radio :value="true">True</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item field="stopThreadOnEof" :label="t('apiScenario.params.csvStop')" class="mb-[16px]">
<a-radio-group v-model:model-value="record.stopThreadOnEof">
<a-radio :value="false">False</a-radio>
<a-radio :value="true">True</a-radio>
</a-radio-group>
</a-form-item>
</a-form>
</div>
</div>
</template>
</a-trigger>
</template>
</paramTable>
<batchAddKeyVal <batchAddKeyVal
v-model:visible="batchAddKeyValVisible" v-model:visible="batchAddKeyValVisible"
:params="innerParams" :params="commonVariables"
:default-param-item="defaultParamItem" :default-param-item="defaultNormalParamItem"
no-param-type no-param-type
@apply="handleBatchParamApply" @apply="handleBatchParamApply"
/> />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useVModel } from '@vueuse/core'; import { FormInstance } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue'; import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue'; import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
import { CommonVariable } from '@/models/apiTest/scenario'; import { CommonVariable, CsvVariable } from '@/models/apiTest/scenario';
import { defaultCsvParamItem, defaultNormalParamItem } from '@/views/api-test/components/config';
import { filterKeyValParams } from '@/views/api-test/components/utils'; import { filterKeyValParams } from '@/views/api-test/components/utils';
const props = defineProps<{
activeKey?: string;
params: CommonVariable[];
}>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:params', value: CommonVariable[]): void;
(e: 'change'): void; // (e: 'change'): void; //
}>(); }>();
const innerParams = useVModel(props, 'params', emit);
const isShowTip = ref<boolean>(true);
const { t } = useI18n(); const { t } = useI18n();
const commonVariables = defineModel<CommonVariable[]>('commonVariables', {
required: true,
});
const csvVariables = defineModel<CsvVariable[]>('csvVariables', {
required: true,
});
const searchValue = ref(''); const searchValue = ref('');
const firstSearch = ref(true); const firstSearch = ref(true);
const backupParams = ref(props.params); const backupParams = ref(commonVariables.value);
const batchAddKeyValVisible = ref(false); const batchAddKeyValVisible = ref(false);
const activeRadio = ref('convention');
const defaultParamItem = {
key: '',
paramType: 'CONSTANT',
value: '',
description: '',
tags: [],
enable: true,
};
const columns: ParamTableColumn[] = [ const columns: ParamTableColumn[] = [
{ {
@ -104,6 +192,11 @@
dataIndex: 'value', dataIndex: 'value',
slotName: 'value', slotName: 'value',
}, },
{
title: 'apiScenario.table.columns.status',
dataIndex: 'enable',
slotName: 'enable',
},
{ {
title: 'apiScenario.params.tag', title: 'apiScenario.params.tag',
dataIndex: 'tags', dataIndex: 'tags',
@ -120,12 +213,12 @@
slotName: 'operation', slotName: 'operation',
titleSlotName: 'batchAddTitle', titleSlotName: 'batchAddTitle',
dataIndex: 'operation', dataIndex: 'operation',
width: 70, width: 90,
}, },
]; ];
function handleParamTableChange(resultArr: any[], isInit?: boolean) { function handleParamTableChange(resultArr: any[], isInit?: boolean) {
innerParams.value = [...resultArr]; commonVariables.value = [...resultArr];
if (!isInit) { if (!isInit) {
emit('change'); emit('change');
firstSearch.value = true; firstSearch.value = true;
@ -135,16 +228,16 @@
// //
function handleSearch() { function handleSearch() {
if (firstSearch.value) { if (firstSearch.value) {
backupParams.value = [...innerParams.value]; backupParams.value = [...commonVariables.value];
firstSearch.value = false; firstSearch.value = false;
} }
if (!searchValue.value) { if (!searchValue.value) {
innerParams.value = [...backupParams.value]; commonVariables.value = [...backupParams.value];
} else { } else {
const result = backupParams.value.filter( const result = backupParams.value.filter(
(item) => item.key.includes(searchValue.value) || item.tags.includes(searchValue.value) (item) => item.key.includes(searchValue.value) || item.tags.includes(searchValue.value)
); );
innerParams.value = [...result]; commonVariables.value = [...result];
} }
} }
@ -152,14 +245,113 @@
* 批量参数代码转换为参数表格数据 * 批量参数代码转换为参数表格数据
*/ */
function handleBatchParamApply(resultArr: any[]) { function handleBatchParamApply(resultArr: any[]) {
const filterResult = filterKeyValParams(innerParams.value, defaultParamItem); const filterResult = filterKeyValParams(commonVariables.value, defaultNormalParamItem);
if (filterResult.lastDataIsDefault) { if (filterResult.lastDataIsDefault) {
innerParams.value = [...resultArr, innerParams.value[innerParams.value.length - 1]].filter(Boolean); commonVariables.value = [...resultArr, commonVariables.value[commonVariables.value.length - 1]].filter(Boolean);
} else { } else {
innerParams.value = resultArr.filter(Boolean); commonVariables.value = resultArr.filter(Boolean);
} }
emit('change'); emit('change');
} }
const csvColumns: ParamTableColumn[] = [
{
title: 'apiScenario.params.csvName',
dataIndex: 'key',
slotName: 'key',
needValidRepeat: true,
},
{
title: 'apiScenario.params.csvScoped',
dataIndex: 'scope',
slotName: 'scope',
typeOptions: [
{
label: t('apiScenario.scenario'),
value: 'SCENARIO',
},
{
label: t('apiScenario.step'),
value: 'STEP',
},
],
width: 80,
titleSlotName: 'typeTitle',
typeTitleTooltip: [t('apiScenario.params.csvScopedTip1'), t('apiScenario.params.csvScopedTip2')],
},
// {
// title: 'apiScenario.params.file',
// dataIndex: 'file',
// slotName: 'file',
// },
{
title: 'apiScenario.table.columns.status',
dataIndex: 'enable',
slotName: 'enable',
},
{
title: '',
slotName: 'operation',
dataIndex: 'operation',
width: 90,
},
];
const configFormRef = ref<FormInstance>();
const encodingOptions = [
{
label: 'UTF-8',
value: 'UTF-8',
},
{
label: 'UTF-16',
value: 'UTF-16',
},
{
label: 'ISO-8859-15',
value: 'ISO-8859-15',
},
{
label: 'US-ASCII',
value: 'US-ASCII',
},
];
</script> </script>
<style lang="less" scoped></style> <style lang="less">
.scenario-csv-trigger {
@apply bg-white;
.scenario-csv-trigger-content {
padding: 16px;
width: 400px;
border-radius: var(--border-radius-medium);
box-shadow: 0 5px 5px -3px rgb(0 0 0 / 10%), 0 8px 10px 1px rgb(0 0 0 / 6%), 0 3px 14px 2px rgb(0 0 0 / 5%);
&::before {
@apply absolute left-0 top-0;
content: '';
z-index: -1;
width: 200%;
height: 200%;
border: 1px solid var(--color-text-input-border);
border-radius: 12px;
transform-origin: 0 0;
transform: scale(0.5, 0.5);
}
.scenario-csv-trigger-content-scroll {
.ms-scroll-bar();
overflow-y: auto;
margin-right: -6px;
max-height: 400px;
.scenario-csv-trigger-content-scroll-preview {
@apply w-full overflow-y-auto overflow-x-hidden break-all;
.ms-scroll-bar();
max-height: 100px;
color: var(--color-text-1);
}
}
}
}
</style>

View File

@ -20,7 +20,8 @@
> >
<params <params
v-if="activeKey === ScenarioCreateComposition.PARAMS" v-if="activeKey === ScenarioCreateComposition.PARAMS"
v-model:params="scenario.scenarioConfig.variable.commonVariables" v-model:commonVariables="scenario.scenarioConfig.variable.commonVariables"
v-model:csvVariables="scenario.scenarioConfig.variable.csvVariables"
/> />
</a-tab-pane> </a-tab-pane>
<a-tab-pane <a-tab-pane

View File

@ -62,7 +62,8 @@
> >
<params <params
v-if="activeKey === ScenarioDetailComposition.PARAMS" v-if="activeKey === ScenarioDetailComposition.PARAMS"
v-model:params="scenario.scenarioConfig.variable.commonVariables" v-model:commonVariables="scenario.scenarioConfig.variable.commonVariables"
v-model:csvVariables="scenario.scenarioConfig.variable.csvVariables"
@change="scenario.unSaved = true" @change="scenario.unSaved = true"
/> />
</a-tab-pane> </a-tab-pane>

View File

@ -515,6 +515,7 @@
environmentId: appStore.getCurrentEnvId || '', environmentId: appStore.getCurrentEnvId || '',
}); });
const scenarioDetail = await getScenarioDetail(res.id); const scenarioDetail = await getScenarioDetail(res.id);
//
scenarioDetail.stepDetails = {}; scenarioDetail.stepDetails = {};
scenarioDetail.isNew = false; scenarioDetail.isNew = false;
scenarioDetail.id = res.id; scenarioDetail.id = res.id;

View File

@ -24,6 +24,14 @@ export default {
'apiScenario.dependency': 'Dependency', 'apiScenario.dependency': 'Dependency',
'apiScenario.quote': 'Quote', 'apiScenario.quote': 'Quote',
'apiScenario.params.convention': 'Conventional Parameters', 'apiScenario.params.convention': 'Conventional Parameters',
'apiScenario.params.csv': 'CSV Parameters',
'apiScenario.params.csvName': 'CSV name',
'apiScenario.params.csvScoped': 'Scope',
'apiScenario.params.file': 'File',
'apiScenario.params.csvScopedTip1':
'Scenario level: Load CSV before executing the scenario. Data can be read from CSV in any step of the current scenario.',
'apiScenario.params.csvScopedTip2':
'Step level: The CSV needs to be added to the scenario step. The CSV is loaded when executing this step, and the scope is the request within the step.',
'apiScenario.params.searchPlaceholder': 'Search by name or tag', 'apiScenario.params.searchPlaceholder': 'Search by name or tag',
'apiScenario.params.priority': 'apiScenario.params.priority':
'Variable Priority: Temporary Parameters > Scenario Parameters > Environment Parameters > Global Parameters; Note: Avoid using variables with the same name. In case of same name variables, scenario-level CSV has the highest priority.', 'Variable Priority: Temporary Parameters > Scenario Parameters > Environment Parameters > Global Parameters; Note: Avoid using variables with the same name. In case of same name variables, scenario-level CSV has the highest priority.',

View File

@ -23,6 +23,24 @@ export default {
'apiScenario.dependency': '依赖关系', 'apiScenario.dependency': '依赖关系',
'apiScenario.quote': '引用关系', 'apiScenario.quote': '引用关系',
'apiScenario.params.convention': '常规参数', 'apiScenario.params.convention': '常规参数',
'apiScenario.params.csv': 'CSV 参数',
'apiScenario.params.csvName': 'CSV 名称',
'apiScenario.params.csvNameNotNull': 'CSV 名称不能为空',
'apiScenario.params.csvScoped': '作用域',
'apiScenario.params.file': '文件',
'apiScenario.params.csvScopedTip1': '场景级执行场景前加载CSV当前场景任意步骤均可从CSV中读取到数据',
'apiScenario.params.csvScopedTip2': '步骤级需在场景步骤中添加该CSV执行该步骤时加载CSV作用域为步骤内的请求',
'apiScenario.params.config': '配置',
'apiScenario.params.csvConfig': 'CSV 配置',
'apiScenario.params.csvParamName': '参数名称',
'apiScenario.params.csvParamNamePlaceholder': '多个参数名以 , 隔开',
'apiScenario.params.csvFileCode': '文件编码',
'apiScenario.params.csvSplitChar': '分隔符',
'apiScenario.params.csvIgnoreFirstLine': '忽略首行',
'apiScenario.params.csvIsRandom': '是否随机',
'apiScenario.params.csvQuoteAllow': '允许带引号',
'apiScenario.params.csvRecycle': '遇到文件结束符再次循环',
'apiScenario.params.csvStop': '遇到文件结束符停止线程',
'apiScenario.params.searchPlaceholder': '通过名称或标签搜索', 'apiScenario.params.searchPlaceholder': '通过名称或标签搜索',
'apiScenario.params.priority': 'apiScenario.params.priority':
'变量优先级:临时参数>场景参数 >环境参数>全局参数;注: 避免使用同名变量,同名变量时场景级 CSV 优先级最高', '变量优先级:临时参数>场景参数 >环境参数>全局参数;注: 避免使用同名变量,同名变量时场景级 CSV 优先级最高',