fix: 修改全局部分bug

This commit is contained in:
xinxin.wu 2024-04-07 23:20:25 +08:00 committed by Craftsman
parent f98260a2eb
commit a0c6ed78a7
36 changed files with 383 additions and 145 deletions

View File

@ -35,7 +35,11 @@
}, },
}" }"
allow-search allow-search
/> >
<template #tree-slot-title="node">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</template>
</a-tree-select>
<div class="flex items-center justify-end gap-[12px]"> <div class="flex items-center justify-end gap-[12px]">
<a-button type="secondary" @click="handleSaveFileCancel">{{ t('common.cancel') }}</a-button> <a-button type="secondary" @click="handleSaveFileCancel">{{ t('common.cancel') }}</a-button>
<a-button type="primary" :loading="saveLoading" @click="handleSaveFileConfirm"> <a-button type="primary" :loading="saveLoading" @click="handleSaveFileConfirm">

View File

@ -14,6 +14,7 @@
v-model:params="condition.jsonPathAssertion.assertions" v-model:params="condition.jsonPathAssertion.assertions"
:disabled-except-param="props.disabled" :disabled-except-param="props.disabled"
:selectable="true" :selectable="true"
:response="props.response"
:columns="jsonPathColumns" :columns="jsonPathColumns"
:scroll="{ minWidth: '700px' }" :scroll="{ minWidth: '700px' }"
:default-param-item="jsonPathDefaultParamItem" :default-param-item="jsonPathDefaultParamItem"
@ -90,6 +91,17 @@
<span class="invisible relative"></span> <span class="invisible relative"></span>
</a-popover> </a-popover>
</template> </template>
<!-- <template #expectedTitle="{ columnConfig }">
<div class="flex items-center text-[var(--color-text-3)]">
{{ t('apiTestDebug.paramType') }}
<a-tooltip :content="columnConfig.typeTitleTooltip" position="right">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</template> -->
</paramsTable> </paramsTable>
</div> </div>
<!-- jsonPath结束 --> <!-- jsonPath结束 -->
@ -259,9 +271,9 @@
v-model:params="condition.regexAssertion.assertions" v-model:params="condition.regexAssertion.assertions"
:selectable="true" :selectable="true"
:disabled-except-param="props.disabled" :disabled-except-param="props.disabled"
:columns="xPathColumns" :columns="regexColumns"
:scroll="{ minWidth: '700px' }" :scroll="{ minWidth: '700px' }"
:default-param-item="xPathDefaultParamItem" :default-param-item="regexDefaultParamItem"
@change="(data) => handleChange(data, ResponseBodyAssertionType.REGEX)" @change="(data) => handleChange(data, ResponseBodyAssertionType.REGEX)"
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)" @more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
> >
@ -472,6 +484,8 @@
title: 'ms.assertion.matchValue', title: 'ms.assertion.matchValue',
dataIndex: 'expectedValue', dataIndex: 'expectedValue',
slotName: 'expectedValue', slotName: 'expectedValue',
titleSlotName: 'expectedTitle',
typeTitleTooltip: t('ms.assertion.expectedValueTitle'),
}, },
{ {
title: '', title: '',
@ -493,16 +507,45 @@
// json // json
const jsonPathDefaultParamItem = { const jsonPathDefaultParamItem = {
expression: '',
condition: EQUAL.value,
expectedValue: '',
enable: true, enable: true,
variableName: '',
variableType: RequestExtractEnvType.TEMPORARY,
extractScope: RequestExtractScope.BODY,
expression: '',
extractType: RequestExtractExpressionEnum.JSON_PATH,
expressionMatchingRule: RequestExtractExpressionRuleType.EXPRESSION,
resultMatchingRule: RequestExtractResultMatchingRule.RANDOM,
resultMatchingRuleNum: 1,
responseFormat: ResponseBodyXPathAssertionFormat.XML,
moreSettingPopoverVisible: false,
}; };
// xpath // xpath
const xPathDefaultParamItem = { const xPathDefaultParamItem = {
expression: '', expression: '',
enable: true, enable: true,
valid: true, valid: true,
variableType: RequestExtractEnvType.TEMPORARY,
extractScope: RequestExtractScope.BODY,
extractType: RequestExtractExpressionEnum.X_PATH,
expressionMatchingRule: RequestExtractExpressionRuleType.EXPRESSION,
resultMatchingRule: RequestExtractResultMatchingRule.RANDOM,
resultMatchingRuleNum: 1,
responseFormat: ResponseBodyXPathAssertionFormat.XML,
moreSettingPopoverVisible: false,
};
// xpath
const regexDefaultParamItem = {
expression: '',
enable: true,
valid: true,
variableType: RequestExtractEnvType.TEMPORARY,
extractScope: RequestExtractScope.BODY,
extractType: RequestExtractExpressionEnum.REGEX,
expressionMatchingRule: RequestExtractExpressionRuleType.EXPRESSION,
resultMatchingRule: RequestExtractResultMatchingRule.RANDOM,
resultMatchingRuleNum: 1,
responseFormat: ResponseBodyXPathAssertionFormat.XML,
moreSettingPopoverVisible: false,
}; };
const handleChange = (data: any[], type: string, isInit?: boolean) => { const handleChange = (data: any[], type: string, isInit?: boolean) => {
@ -562,6 +605,30 @@
], ],
}, },
]; ];
const regexColumns: ParamTableColumn[] = [
{
title: 'ms.assertion.expression',
dataIndex: 'expression',
slotName: 'expression',
},
{
title: '',
slotName: 'operation',
fixed: 'right',
width: 130,
moreAction: [
{
eventTag: 'copy',
label: 'common.copy',
},
// TODO
// {
// eventTag: 'setting',
// label: 'common.setting',
// },
],
},
];
const documentColumns: ParamTableColumn[] = [ const documentColumns: ParamTableColumn[] = [
{ {
@ -644,28 +711,62 @@
* 提取参数表格-应用更多设置 * 提取参数表格-应用更多设置
*/ */
function applyMoreSetting(record: ExpressionConfig) { function applyMoreSetting(record: ExpressionConfig) {
condition.value.jsonPathAssertion.assertions = condition.value.jsonPathAssertion.assertions?.map((e) => { switch (condition.value.assertionBodyType) {
if (e.id === activeRecord.value.id) { case ResponseBodyAssertionType.JSON_PATH:
record.moreSettingPopoverVisible = false; condition.value.jsonPathAssertion.assertions = condition.value.jsonPathAssertion.assertions?.map((e) => {
return { if (e.id === activeRecord.value.id) {
...activeRecord.value, record.moreSettingPopoverVisible = false;
moreSettingPopoverVisible: false, return {
} as any; ...activeRecord.value,
} moreSettingPopoverVisible: false,
return e; } as any;
}); }
handleChange(condition.value.assertion, condition.value.assertion); return e;
});
break;
case ResponseBodyAssertionType.XPATH:
condition.value.xpathAssertion.assertions = condition.value.xpathAssertion.assertions?.map((e) => {
if (e.id === activeRecord.value.id) {
record.moreSettingPopoverVisible = false;
return {
...activeRecord.value,
moreSettingPopoverVisible: false,
} as any;
}
return e;
});
break;
case ResponseBodyAssertionType.REGEX:
condition.value.regexAssertion.assertions = condition.value.regexAssertion.assertions?.map((e) => {
if (e.id === activeRecord.value.id) {
record.moreSettingPopoverVisible = false;
return {
...activeRecord.value,
moreSettingPopoverVisible: false,
} as any;
}
return { ...e };
});
break;
default:
break;
}
emit('change', { ...condition.value });
} }
/** /**
* 提取参数表格-保存快速提取的配置 * 提取参数表格-保存快速提取的配置
*/ */
function handleFastExtractionApply(config: RegexExtract | JSONPathExtract | XPathExtract) { function handleFastExtractionApply(
config: RegexExtract | JSONPathExtract | XPathExtract,
matchResult: Record<string, any>
) {
condition.value.jsonPathAssertion.assertions = condition.value.jsonPathAssertion.assertions?.map((e) => { condition.value.jsonPathAssertion.assertions = condition.value.jsonPathAssertion.assertions?.map((e) => {
if (e.id === activeRecord.value.id) { if (e.id === activeRecord.value.id) {
return { return {
...e, ...e,
...config, ...config,
expectedValue: matchResult.join(''),
}; };
} }
return e; return e;

View File

@ -1,11 +1,29 @@
export default { export default {
'ms.assertion.button': 'Assertion', 'ms.assertion.button': 'Assertion',
'ms.assertion.statusCode': 'code',
'ms.assertion.responseHeader': 'Response header',
'ms.assertion.responseBody': 'Response body',
'ms.assertion.responseTime': 'Response time',
'ms.assertion.param': 'variable',
'ms.assertion.noValidation': 'uncheck',
'ms.assertion.matchCondition': 'Matching condition',
'ms.assertion.variableName': 'Variable name',
'ms.assertion.jsonPath': 'JSONPath', 'ms.assertion.jsonPath': 'JSONPath',
'ms.assertion.xpath': 'XPath', 'ms.assertion.xpath': 'XPath',
'ms.assertion.document': 'Document', 'ms.assertion.document': 'Document',
'ms.assertion.regular': 'Regular', 'ms.assertion.regular': 'Regular',
'ms.assertion.script': 'Script', 'ms.assertion.script': 'Script',
'ms.assertion.expression': 'expression',
'ms.assertion.responseContentType': 'Response Content Format',
'ms.assertion.followApi': 'Follow API definitions',
'ms.assertion.paramsName': 'params name',
'ms.assertion.mustInclude': 'required',
'ms.assertion.typeChecking': 'Type checking',
'ms.assertion.addChild': 'Add subfield',
'ms.assertion.validateChild': 'Additive check',
'ms.assertion.openGlobal': 'Implement the Global Declaration', 'ms.assertion.openGlobal': 'Implement the Global Declaration',
'ms.assertion.openGlobalTip': 'ms.assertion.openGlobalTip':
'It is enabled by default. If it is disabled, the global assertion will not be executed when running this interface.', 'It is enabled by default. If it is disabled, the global assertion will not be executed when running this interface.',
'ms.assertion.expectedValueTitle':
'The special characters $() * +. "[]{}^ |" to escape as the "special characters", such as "$" escaped"$',
}; };

View File

@ -24,4 +24,5 @@ export default {
'ms.assertion.validateChild': '添加子校验', 'ms.assertion.validateChild': '添加子校验',
'ms.assertion.openGlobal': '启用全局断言', 'ms.assertion.openGlobal': '启用全局断言',
'ms.assertion.openGlobalTip': '默认开启,关闭则运行该接口时不执行全局断言', 'ms.assertion.openGlobalTip': '默认开启,关闭则运行该接口时不执行全局断言',
'ms.assertion.expectedValueTitle': `特殊字符"$ ( ) * + . [ ]{ } \\^ |"需转义为"\\特殊字符",如"$"转义后为"\\$`,
}; };

View File

@ -188,7 +188,7 @@
const columns: MsTableColumn = [ const columns: MsTableColumn = [
{ {
title: 'ID', title: 'ID',
dataIndex: 'id', dataIndex: 'num',
sortIndex: 1, sortIndex: 1,
showTooltip: true, showTooltip: true,
sortable: { sortable: {
@ -241,6 +241,7 @@
dataIndex: 'createUserName', dataIndex: 'createUserName',
showInTable: true, showInTable: true,
width: 300, width: 300,
showTooltip: true,
}, },
{ {
title: 'caseManagement.featureCase.tableColumnCreateTime', title: 'caseManagement.featureCase.tableColumnCreateTime',
@ -253,7 +254,7 @@
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable( const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(
getFormApiImportPageList, getFormApiImportPageList,
{ {
scroll: { x: 'auto' }, scroll: { x: '100%' },
columns, columns,
showSetting: false, showSetting: false,
selectable: true, selectable: true,

View File

@ -168,9 +168,9 @@
{ {
title: 'project.commonScript.description', title: 'project.commonScript.description',
dataIndex: 'description', dataIndex: 'description',
width: 200,
showDrag: true, showDrag: true,
showTooltip: true, showTooltip: true,
width: 150,
}, },
{ {
title: 'project.commonScript.enable', title: 'project.commonScript.enable',
@ -179,13 +179,14 @@
showInTable: true, showInTable: true,
width: 150, width: 150,
showDrag: true, showDrag: true,
showTooltip: true,
}, },
{ {
title: 'project.commonScript.tags', title: 'project.commonScript.tags',
dataIndex: 'tags', dataIndex: 'tags',
showInTable: true, showInTable: true,
isTag: true, isTag: true,
width: 456, width: 440,
showDrag: true, showDrag: true,
}, },
{ {
@ -193,8 +194,9 @@
dataIndex: 'createUserName', dataIndex: 'createUserName',
titleSlotName: 'createUserFilter', titleSlotName: 'createUserFilter',
showInTable: true, showInTable: true,
width: 200,
showDrag: true, showDrag: true,
showTooltip: true,
width: 150,
}, },
{ {
title: 'project.commonScript.createTime', title: 'project.commonScript.createTime',
@ -204,18 +206,20 @@
sorter: true, sorter: true,
}, },
showInTable: true, showInTable: true,
width: 300,
showDrag: true, showDrag: true,
showTooltip: true,
width: 200,
}, },
{ {
title: 'system.resourcePool.tableColumnUpdateTime', title: 'system.resourcePool.tableColumnUpdateTime',
dataIndex: 'updateTime', dataIndex: 'updateTime',
width: 180,
showDrag: true, showDrag: true,
sortable: { sortable: {
sortDirections: ['ascend', 'descend'], sortDirections: ['ascend', 'descend'],
sorter: true, sorter: true,
}, },
showTooltip: true,
width: 200,
}, },
]; ];
@ -226,7 +230,7 @@
{ {
columns, columns,
scroll: { scroll: {
x: '100%', x: 1300,
}, },
showSetting: false, showSetting: false,
selectable: true, selectable: true,

View File

@ -37,18 +37,17 @@
<a-form-item field="tags" :label="t('project.commonScript.tags')"> <a-form-item field="tags" :label="t('project.commonScript.tags')">
<MsTagsInput v-model:modelValue="form.tags"></MsTagsInput> <MsTagsInput v-model:modelValue="form.tags"></MsTagsInput>
</a-form-item> </a-form-item>
<a-form-item field="inputParameters" :label="t('project.commonScript.inputParams')"> <div class="mb-4">{{ t('project.commonScript.inputParams') }}</div>
<paramTable <paramTable
v-model:params="innerParams" v-model:params="innerParams"
:scroll="{ x: '100%' }" :columns="columns"
:columns="columns" :scroll="{ x: 'auto' }"
:height-used="heightUsed" :height-used="heightUsed"
:selectable="false" :selectable="false"
@change="handleParamTableChange" @change="handleParamTableChange"
/> />
</a-form-item> <div class="mb-2 mt-4 flex items-center justify-between">
<div class="mb-2 flex items-center justify-between"> <a-radio-group v-model:model-value="scriptType" type="button">
<a-radio-group v-model:model-value="scriptType" type="button" size="small">
<a-radio value="commonScript">{{ t('project.commonScript.commonScript') }}</a-radio> <a-radio value="commonScript">{{ t('project.commonScript.commonScript') }}</a-radio>
<a-radio value="executionResult">{{ t('project.commonScript.executionResult') }}</a-radio> <a-radio value="executionResult">{{ t('project.commonScript.executionResult') }}</a-radio>
</a-radio-group> </a-radio-group>
@ -147,6 +146,7 @@
title: 'project.commonScript.ParameterValue', title: 'project.commonScript.ParameterValue',
dataIndex: 'value', dataIndex: 'value',
slotName: 'value', slotName: 'value',
width: 300,
}, },
{ {
title: 'project.commonScript.description', title: 'project.commonScript.description',
@ -157,6 +157,7 @@
title: 'project.commonScript.isRequired', title: 'project.commonScript.isRequired',
slotName: 'mustContain', slotName: 'mustContain',
dataIndex: 'required', dataIndex: 'required',
width: 60,
}, },
{ {
title: '', title: '',

View File

@ -1,5 +1,5 @@
<template> <template>
<div v-if="!innerExpand" class="w-[32%] min-w-[25%] bg-white p-3 pl-0"> <div v-if="!innerExpand" class="w-[32%] min-w-[30%] max-w-[42%] bg-white p-3 pl-0">
<div class="mb-2 flex items-center justify-between"> <div class="mb-2 flex items-center justify-between">
<div class="flex items-center"> <div class="flex items-center">
<span v-if="innerExpand" class="collapsebtn mr-1 flex items-center justify-center" @click="expandedHandler"> <span v-if="innerExpand" class="collapsebtn mr-1 flex items-center justify-center" @click="expandedHandler">

View File

@ -20,7 +20,7 @@
<template v-if="$slots['title']" #title="_props"> <template v-if="$slots['title']" #title="_props">
<a-tooltip <a-tooltip
:content="_props[props.fieldNames.title]" :content="_props[props.fieldNames.title]"
:mouse-enter-delay="800" :mouse-enter-delay="300"
:position="props.titleTooltipPosition" :position="props.titleTooltipPosition"
:disabled="props.disabledTitleTooltip" :disabled="props.disabledTitleTooltip"
> >

View File

@ -31,7 +31,7 @@
<slot name="right"></slot> <slot name="right"></slot>
<MsTag no-margin size="large" class="cursor-pointer" theme="outline" @click="handleRefresh"> <MsTag no-margin size="large" class="cursor-pointer" theme="outline" @click="handleRefresh">
<MsIcon class="text-[var(color-text-4)]" :size="16" type="icon-icon_reset_outlined" /> <MsIcon class="text-[16px] text-[var(color-text-4)]" :size="32" type="icon-icon_reset_outlined" />
</MsTag> </MsTag>
</div> </div>
</div> </div>

View File

@ -143,6 +143,16 @@
</template> </template>
</slot> </slot>
</template> </template>
<template
v-for="item of props.columns.filter((e) => e.titleSlotName !== undefined)"
#[item.titleSlotName!]="{ record, rowIndex, column }"
>
<slot
:name="item.titleSlotName"
v-bind="{ record, rowIndex, column, dataIndex: item.dataIndex, columnConfig: item }"
>
</slot>
</template>
</MsBaseTable> </MsBaseTable>
</template> </template>

View File

@ -68,7 +68,7 @@
if (ev.target && ev.target.classList.contains('pick-path')) { if (ev.target && ev.target.classList.contains('pick-path')) {
setTimeout(() => { setTimeout(() => {
if (ip.value) { if (ip.value) {
jsonPath.value = `$${ip.value.value}`; jsonPath.value = `$.${ip.value.value}`;
emit( emit(
'pick', 'pick',
jsonPath.value, jsonPath.value,

View File

@ -1,7 +1,11 @@
<template> <template>
<a-button :disabled="props.disabled" type="outline" size="mini" @click="showBatchAddParamDrawer = true"> <div class="flex w-full" :class="[props.typeTitle ? 'justify-between' : 'justify-start']">
{{ t('apiTestDebug.batchAdd') }} <span v-if="props.typeTitle">{{ props.typeTitle }}</span>
</a-button> <a-button :disabled="props.disabled" type="outline" size="mini" @click="showBatchAddParamDrawer = true">
{{ t('apiTestDebug.batchAdd') }}
</a-button>
</div>
<MsDrawer <MsDrawer
v-model:visible="showBatchAddParamDrawer" v-model:visible="showBatchAddParamDrawer"
:width="680" :width="680"
@ -60,6 +64,7 @@
noParamType?: boolean; // noParamType?: boolean; //
addTypeText?: string; // addTypeText?: string; //
disabled?: boolean; disabled?: boolean;
typeTitle?: string;
}>(), }>(),
{ {
noParamType: false, noParamType: false,

View File

@ -206,31 +206,19 @@
{{ t('apiTestDebug.quote') }} {{ t('apiTestDebug.quote') }}
</MsButton> </MsButton>
</div> </div>
<div v-if="showParameters() || showScript()"> <div v-show="showParameters() || showScript()" class="h-[calc(100%-47px)] min-h-[300px]">
<a-radio-group v-model:model-value="commonScriptShowType" size="small" type="button" class="mb-[8px] w-fit"> <a-radio-group v-model:model-value="commonScriptShowType" size="small" type="button" class="mb-[8px] w-fit">
<a-radio v-if="showParameters()" value="parameters">{{ t('apiTestDebug.parameters') }}</a-radio> <a-radio v-if="showParameters()" value="parameters">{{ t('apiTestDebug.parameters') }}</a-radio>
<a-radio value="scriptContent">{{ t('apiTestDebug.scriptContent') }}</a-radio> <a-radio value="scriptContent">{{ t('apiTestDebug.scriptContent') }}</a-radio>
</a-radio-group> </a-radio-group>
<MsBaseTable <paramTable
v-if="showParameters()" v-if="commonScriptShowType === 'parameters'"
v-show="commonScriptShowType === 'parameters'" v-model:params="scriptParams"
v-bind="propsRes" :scroll="{ x: '100%' }"
v-on="propsEvent" :columns="scriptColumns"
> :height-used="heightUsed"
<template #value="{ record }"> :selectable="false"
<a-tooltip :content="t(record.required ? 'apiTestDebug.paramRequired' : 'apiTestDebug.paramNotRequired')"> />
<div
:class="[
record.required ? '!text-[rgb(var(--danger-5))]' : '!text-[var(--color-text-brand)]',
'!mr-[4px] !p-[4px]',
]"
>
<div>*</div>
</div>
</a-tooltip>
{{ record.value }}
</template>
</MsBaseTable>
<div v-show="commonScriptShowType === 'scriptContent'" class="h-[calc(100%-76px)]"> <div v-show="commonScriptShowType === 'scriptContent'" class="h-[calc(100%-76px)]">
<MsCodeEditor <MsCodeEditor
v-if="condition.commonScriptInfo" v-if="condition.commonScriptInfo"
@ -619,30 +607,38 @@ if (!result){
} }
const commonScriptShowType = ref<'parameters' | 'scriptContent'>('parameters'); const commonScriptShowType = ref<'parameters' | 'scriptContent'>('parameters');
const columns: MsTableColumn = [
const scriptParams = ref<any[]>([]);
const scriptColumns: MsTableColumn = [
{ {
title: 'apiTestDebug.paramName', title: 'project.commonScript.ParameterNames',
slotName: 'key', slotName: 'key',
dataIndex: 'key', dataIndex: 'key',
showTooltip: true, addLineDisabled: true,
disabledColumn: true,
}, },
{ {
title: 'apiTestDebug.paramValue', title: 'project.commonScript.ParameterValue',
dataIndex: 'value', dataIndex: 'value',
slotName: 'value', slotName: 'value',
addLineDisabled: true,
}, },
{ {
title: 'apiTestDebug.desc', title: 'project.commonScript.description',
dataIndex: 'description',
slotName: 'description', slotName: 'description',
showTooltip: true, dataIndex: 'description',
addLineDisabled: true,
disabledColumn: true,
},
{
title: 'project.commonScript.isRequired',
slotName: 'mustContain',
dataIndex: 'required',
addLineDisabled: true,
disabledColumn: true,
}, },
]; ];
const { propsRes, propsEvent } = useTable(() => Promise.resolve([]), {
scroll: { x: '100%' },
columns,
noDisable: true,
});
const showQuoteDrawer = ref(false); const showQuoteDrawer = ref(false);
function saveQuoteScriptHandler(item: any) { function saveQuoteScriptHandler(item: any) {
@ -659,7 +655,7 @@ if (!result){
}; };
}), }),
}; };
propsRes.value.data = (condition.value.commonScriptInfo?.params as any[]) || []; scriptParams.value = (condition.value.commonScriptInfo?.params as any[]) || [];
showQuoteDrawer.value = false; showQuoteDrawer.value = false;
} }
@ -951,7 +947,7 @@ if (!result){
watch( watch(
() => condition.value.commonScriptInfo, () => condition.value.commonScriptInfo,
(info) => { (info) => {
propsRes.value.data = info?.params as any[]; // scriptParams.value = info?.params as any[]; //
if (!showParameters()) { if (!showParameters()) {
commonScriptShowType.value = 'scriptContent'; commonScriptShowType.value = 'scriptContent';
} }

View File

@ -5,7 +5,8 @@
:show-full-screen="true" :show-full-screen="true"
:title="t('apiTestDebug.fastExtraction')" :title="t('apiTestDebug.fastExtraction')"
disabled-width-drag disabled-width-drag
@confirm="emit('apply', expressionForm)" @confirm="confirmHandler"
@close="closeHandler"
> >
<div v-if="expressionForm.extractType === RequestExtractExpressionEnum.REGEX" class="h-[400px]"> <div v-if="expressionForm.extractType === RequestExtractExpressionEnum.REGEX" class="h-[400px]">
<MsCodeEditor <MsCodeEditor
@ -137,7 +138,7 @@
</MsButton> </MsButton>
</template> </template>
<div class="mt-[16px]"> <div class="mt-[16px]">
<moreSetting v-model:config="expressionForm" /> <moreSetting v-model:config="expressionForm" :is-show-result-match-rules="false" />
</div> </div>
</a-collapse-item> </a-collapse-item>
</a-collapse> </a-collapse>
@ -146,7 +147,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { useVModel } from '@vueuse/core'; import { useVModel } from '@vueuse/core';
import FormInstance, { Message } from '@arco-design/web-vue'; import { FormInstance, Message, ValidatedError } from '@arco-design/web-vue';
import { JSONPath } from 'jsonpath-plus'; import { JSONPath } from 'jsonpath-plus';
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
@ -176,14 +177,18 @@
); );
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:visible', value: boolean): void; (e: 'update:visible', value: boolean): void;
(e: 'apply', config: (RegexExtract | JSONPathExtract | XPathExtract) & Record<string, any>): void; (
e: 'apply',
config: (RegexExtract | JSONPathExtract | XPathExtract) & Record<string, any>,
matchResult: any[]
): void;
}>(); }>();
const { t } = useI18n(); const { t } = useI18n();
const innerVisible = useVModel(props, 'visible', emit); const innerVisible = useVModel(props, 'visible', emit);
const expressionForm = ref({ ...props.config }); const expressionForm = ref({ ...props.config });
const expressionFormRef = ref<typeof FormInstance>(); const expressionFormRef = ref<FormInstance | null>(null);
const parseJson = ref<string | Record<string, any>>({}); const parseJson = ref<string | Record<string, any>>({});
const matchResult = ref<any[]>([]); // const matchResult = ref<any[]>([]); //
const isMatched = ref(false); // const isMatched = ref(false); //
@ -272,6 +277,17 @@
} }
const moreSettingActive = ref<number[]>([]); const moreSettingActive = ref<number[]>([]);
function confirmHandler() {
expressionFormRef.value?.validate(async (errors: undefined | Record<string, ValidatedError>) => {
if (!errors) {
emit('apply', expressionForm.value, matchResult.value);
}
});
}
function closeHandler() {
expressionFormRef.value?.resetFields();
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -29,7 +29,7 @@
</a-radio> </a-radio>
</a-radio-group> </a-radio-group>
</div> </div>
<div class="mb-[16px]"> <div v-if="props.isShowResultMatchRules" class="mb-[16px]">
<div class="mb-[8px] text-[14px] text-[var(--color-text-1)]"> <div class="mb-[8px] text-[14px] text-[var(--color-text-1)]">
{{ t('apiTestDebug.resultMatchRule') }} {{ t('apiTestDebug.resultMatchRule') }}
</div> </div>
@ -116,6 +116,7 @@
const props = defineProps<{ const props = defineProps<{
config: ExpressionConfig; config: ExpressionConfig;
isPopover?: boolean; // isPopover?: boolean; //
isShowResultMatchRules?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:config', config: ExpressionConfig): void; (e: 'update:config', config: ExpressionConfig): void;

View File

@ -86,8 +86,8 @@
<a-auto-complete <a-auto-complete
v-if="columnConfig.inputType === 'autoComplete'" v-if="columnConfig.inputType === 'autoComplete'"
v-model:model-value="record[columnConfig.dataIndex as string]" v-model:model-value="record[columnConfig.dataIndex as string]"
:disabled="props.disabledExceptParam" :disabled="props.disabledExceptParam || columnConfig.disabledColumn"
:data="columnConfig.autoCompleteParams?.filter((e) => e.isShow !== false)" :data="columnConfig.autoCompleteParams?.filter((e) => e.isShow === true)"
class="ms-form-table-input" class="ms-form-table-input"
:trigger-props="{ contentClass: 'ms-form-table-input-trigger' }" :trigger-props="{ contentClass: 'ms-form-table-input-trigger' }"
:filter-option="false" :filter-option="false"
@ -110,7 +110,7 @@
<a-input <a-input
v-else v-else
v-model:model-value="record[columnConfig.dataIndex as string]" v-model:model-value="record[columnConfig.dataIndex as string]"
:disabled="props.disabledExceptParam" :disabled="props.disabledExceptParam || columnConfig.disabledColumn"
:placeholder="t('apiTestDebug.commonPlaceholder')" :placeholder="t('apiTestDebug.commonPlaceholder')"
class="ms-form-table-input" class="ms-form-table-input"
size="mini" size="mini"
@ -232,9 +232,9 @@
v-model:value="record.value" v-model:value="record.value"
:disabled="props.disabledParamValue" :disabled="props.disabledParamValue"
size="mini" size="mini"
@change="() => addTableLine(rowIndex)" @change="() => addTableLine(rowIndex, columnConfig.addLineDisabled)"
@dblclick="quickInputParams(record)" @dblclick="quickInputParams(record)"
@apply="() => addTableLine(rowIndex)" @apply="() => addTableLine(rowIndex, columnConfig.addLineDisabled)"
/> />
</template> </template>
<!-- 长度范围 --> <!-- 长度范围 -->
@ -293,7 +293,7 @@
<template #description="{ record, columnConfig, rowIndex }"> <template #description="{ record, columnConfig, rowIndex }">
<paramDescInput <paramDescInput
v-model:desc="record[columnConfig.dataIndex as string]" v-model:desc="record[columnConfig.dataIndex as string]"
:disabled="props.disabledExceptParam" :disabled="props.disabledExceptParam || columnConfig.disabledColumn"
size="mini" size="mini"
@input="() => addTableLine(rowIndex)" @input="() => addTableLine(rowIndex)"
@dblclick="quickInputDesc(record)" @dblclick="quickInputDesc(record)"
@ -315,7 +315,7 @@
<template #mustContain="{ record, columnConfig }"> <template #mustContain="{ record, columnConfig }">
<a-checkbox <a-checkbox
v-model:model-value="record[columnConfig.dataIndex as string]" v-model:model-value="record[columnConfig.dataIndex as string]"
:disabled="props.disabledExceptParam" :disabled="props.disabledExceptParam || columnConfig.disabledColumn"
@change="handleMustContainColChange(false)" @change="handleMustContainColChange(false)"
/> />
</template> </template>
@ -348,6 +348,17 @@
</a-select> </a-select>
</template> </template>
<!-- 匹配值 --> <!-- 匹配值 -->
<template #expectedTitle="{ columnConfig }">
<div class="flex items-center text-[var(--color-text-3)]">
{{ t('apiTestDebug.paramType') }}
<a-tooltip :content="columnConfig.typeTitleTooltip" position="right">
<icon-question-circle
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
size="16"
/>
</a-tooltip>
</div>
</template>
<template #expectedValue="{ record, rowIndex, columnConfig }"> <template #expectedValue="{ record, rowIndex, columnConfig }">
<a-tooltip <a-tooltip
v-if="columnConfig.hasRequired" v-if="columnConfig.hasRequired"
@ -583,6 +594,7 @@
moreAction?: ActionsItem[]; // operation moreAction?: ActionsItem[]; // operation
format?: RequestBodyFormat; // operation format?: RequestBodyFormat; // operation
addLineDisabled?: boolean; // addLineDisabled?: boolean; //
disabledColumn?: boolean; //
} }
const props = withDefaults( const props = withDefaults(

View File

@ -5,6 +5,7 @@
:params="innerParams" :params="innerParams"
:default-param-item="defaultHeaderParamsItem" :default-param-item="defaultHeaderParamsItem"
no-param-type no-param-type
:type-title="props.typeTitle"
@apply="handleBatchParamApply" @apply="handleBatchParamApply"
/> />
</div> </div>
@ -28,18 +29,21 @@
import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue'; import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
import { responseHeaderOption } from '@/config/apiTest'; import { responseHeaderOption } from '@/config/apiTest';
import { useI18n } from '@/hooks/useI18n';
import { EnableKeyValueParam } from '@/models/apiTest/common'; import { EnableKeyValueParam } from '@/models/apiTest/common';
import { filterKeyValParams } from '../utils'; import { filterKeyValParams } from '../utils';
import { defaultHeaderParamsItem } from '@/views/api-test/components/config'; import { defaultHeaderParamsItem } from '@/views/api-test/components/config';
const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
params: EnableKeyValueParam[]; params: EnableKeyValueParam[];
layout: 'horizontal' | 'vertical'; layout: 'horizontal' | 'vertical';
secondBoxHeight: number; secondBoxHeight: number;
disabledParamValue?: boolean; // disabledParamValue?: boolean; //
disabledExceptParam?: boolean; // disabledExceptParam?: boolean; //
typeTitle?: string;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:selectedKeys', value: string[]): void; (e: 'update:selectedKeys', value: string[]): void;

View File

@ -357,7 +357,13 @@
}, },
}" }"
allow-search allow-search
/> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-modal> </a-modal>

View File

@ -9,12 +9,14 @@
/> />
</a-tooltip> </a-tooltip>
</div> </div>
<batchAddKeyVal <span>
:params="innerParams" <batchAddKeyVal
:disabled="props.disabledExceptParam" :params="innerParams"
:default-param-item="defaultRequestParamsItem" :disabled="props.disabledExceptParam"
@apply="handleBatchParamApply" :default-param-item="defaultRequestParamsItem"
/> @apply="handleBatchParamApply"
/>
</span>
</div> </div>
<paramTable <paramTable
:params="innerParams" :params="innerParams"

View File

@ -343,21 +343,15 @@
const originStepId = ref<string | undefined>(''); const originStepId = ref<string | undefined>('');
watch( watchEffect(() => {
() => props.stepItem?.stepId, if (props.stepItem?.stepId && !props.stepItem.fold) {
(val) => { if (isShowLoopControl.value && props.stepItem?.stepChildren) {
if (val) { getStepDetail(props.stepItem?.stepChildren[controlCurrent.value - 1].stepId as string);
if (isShowLoopControl.value && props.stepItem?.stepChildren) { } else {
getStepDetail(props.stepItem?.stepChildren[controlCurrent.value - 1].stepId as string); getStepDetail(props.stepItem.stepId);
} else {
getStepDetail(val);
}
} }
},
{
immediate: true,
} }
); });
onMounted(() => { onMounted(() => {
originStepId.value = props.stepItem?.stepId; originStepId.value = props.stepItem?.stepId;

View File

@ -9,12 +9,14 @@
/> />
</a-tooltip> </a-tooltip>
</div> </div>
<batchAddKeyVal <div>
:params="innerParams" <batchAddKeyVal
:disabled="props.disabledExceptParam" :params="innerParams"
:default-param-item="defaultRequestParamsItem" :disabled="props.disabledExceptParam"
@apply="handleBatchParamApply" :default-param-item="defaultRequestParamsItem"
/> @apply="handleBatchParamApply"
/>
</div>
</div> </div>
<paramTable <paramTable
:params="innerParams" :params="innerParams"

View File

@ -201,4 +201,5 @@ export default {
'The content of some tabs has not been saved. The unsaved content will be lost after leaving. Are you sure you want to leave?', 'The content of some tabs has not been saved. The unsaved content will be lost after leaving. Are you sure you want to leave?',
'apiTestDebug.testSuccess': 'Test success', 'apiTestDebug.testSuccess': 'Test success',
'apiTestDebug.searchByDataBaseName': 'Search by data source name', 'apiTestDebug.searchByDataBaseName': 'Search by data source name',
'apiTestDebug.regexMatchRules': 'Expression matching rules',
}; };

View File

@ -188,4 +188,5 @@ export default {
'apiTestDebug.unsavedLeave': '有标签页的内容未保存,离开后后未保存的内容将丢失,确定要离开吗?', 'apiTestDebug.unsavedLeave': '有标签页的内容未保存,离开后后未保存的内容将丢失,确定要离开吗?',
'apiTestDebug.testSuccess': '测试成功', 'apiTestDebug.testSuccess': '测试成功',
'apiTestDebug.searchByDataBaseName': '按数据源名称搜索', 'apiTestDebug.searchByDataBaseName': '按数据源名称搜索',
'apiTestDebug.regexMatchRules': '表达式匹配规则',
}; };

View File

@ -47,7 +47,13 @@
:field-names="{ title: 'name', key: 'id', children: 'children' }" :field-names="{ title: 'name', key: 'id', children: 'children' }"
allow-search allow-search
allow-clear allow-clear
/> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<template #label> <template #label>
@ -243,7 +249,13 @@
class="w-[436px]" class="w-[436px]"
:field-names="{ title: 'name', key: 'id', children: 'children' }" :field-names="{ title: 'name', key: 'id', children: 'children' }"
allow-search allow-search
/> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<template #label> <template #label>

View File

@ -27,7 +27,13 @@
}" }"
allow-search allow-search
@change="() => emit('change')" @change="() => emit('change')"
/> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
</a-form-item> </a-form-item>
<a-form-item :label="t('apiScenario.scenarioLevel')"> <a-form-item :label="t('apiScenario.scenarioLevel')">
<a-select <a-select

View File

@ -192,7 +192,13 @@
}, },
}" }"
@change="handleChangeModule" @change="handleChangeModule"
></a-tree-select> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
</span> </span>
</div> </div>
<!-- 自定义字段开始 --> <!-- 自定义字段开始 -->

View File

@ -199,7 +199,13 @@
}, },
}" }"
@change="(value) => handleChangeModule(record, value)" @change="(value) => handleChangeModule(record, value)"
></a-tree-select> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
<a-tooltip v-else :content="getModules(record.moduleId)" position="top"> <a-tooltip v-else :content="getModules(record.moduleId)" position="top">
<span class="one-line-text inline-block" @click="record.showModuleTree = true">{{ <span class="one-line-text inline-block" @click="record.showModuleTree = true">{{
getModules(record.moduleId) getModules(record.moduleId)

View File

@ -199,9 +199,9 @@
}" }"
> >
<template #tree-slot-title="node"> <template #tree-slot-title="node">
<div class="inline-flex w-full"> <a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div> <div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</div> </a-tooltip>
</template> </template>
</a-tree-select> </a-tree-select>
</a-form-item> </a-form-item>

View File

@ -25,7 +25,13 @@
height: 200, height: 200,
}, },
}" }"
></a-tree-select> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
<template #footer> <template #footer>
<div class="flex flex-row justify-end gap-[14px]"> <div class="flex flex-row justify-end gap-[14px]">
<a-button type="secondary" :disabled="loading" @click="handleCancel"> <a-button type="secondary" :disabled="loading" @click="handleCancel">

View File

@ -33,7 +33,13 @@
:field-names="{ title: 'name', key: 'id', children: 'children' }" :field-names="{ title: 'name', key: 'id', children: 'children' }"
:loading="moduleLoading" :loading="moduleLoading"
allow-search allow-search
/> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
</a-form-item> </a-form-item>
<a-form-item field="type" :label="t('caseManagement.caseReview.type')"> <a-form-item field="type" :label="t('caseManagement.caseReview.type')">
<a-radio-group v-model:modelValue="reviewForm.type" :disabled="isEdit"> <a-radio-group v-model:modelValue="reviewForm.type" :disabled="isEdit">

View File

@ -80,7 +80,7 @@
<template #id="{ record }"> <template #id="{ record }">
<div class="flex items-center"> <div class="flex items-center">
<div class="one-line-text mr-2 max-w-[200px]"> {{ record.id }} </div> <div class="one-line-text mr-2 max-w-[200px]"> {{ record.id }} </div>
<MsTag>{{ t('project.processor.current') }}</MsTag> <!-- <MsTag>{{ t('project.processor.current') }}</MsTag> -->
</div> </div>
</template> </template>
<template #operation="{ record }"> <template #operation="{ record }">

View File

@ -14,12 +14,14 @@
</span> </span>
</template> </template>
</a-input-search> </a-input-search>
<batchAddKeyVal <div>
:add-type-text="t('project.environmental.env.constantBatchAddTip')" <batchAddKeyVal
:params="innerParams" :add-type-text="t('project.environmental.env.constantBatchAddTip')"
no-param-type :params="innerParams"
@apply="handleBatchParamApply" no-param-type
/> @apply="handleBatchParamApply"
/>
</div>
</div> </div>
<paramsTable <paramsTable
v-model:params="innerParams" v-model:params="innerParams"

View File

@ -141,7 +141,13 @@
height: 200, height: 200,
}, },
}" }"
></a-tree-select> >
<template #tree-slot-title="node">
<a-tooltip :content="`${node.name}`" position="tl">
<div class="one-line-text w-[300px] text-[var(--color-text-1)]">{{ node.name }}</div>
</a-tooltip>
</template>
</a-tree-select>
</a-form-item> </a-form-item>
<!-- 路径 --> <!-- 路径 -->
<a-form-item <a-form-item
@ -171,6 +177,7 @@
:disabled-param-value="false" :disabled-param-value="false"
:disabled-except-param="false" :disabled-except-param="false"
:second-box-height="secondBoxHeight" :second-box-height="secondBoxHeight"
:type-title="t('project.environmental.requestHeader')"
/> />
</MsDrawer> </MsDrawer>
</template> </template>

View File

@ -3,14 +3,21 @@
<MsSplitBox> <MsSplitBox>
<template #first> <template #first>
<div class="p-[24px]"> <div class="p-[24px]">
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type" @change="changeShowType"> <div
<a-radio v-permission="['PROJECT_ENVIRONMENT:READ']" value="PROJECT">{{ ><a-radio-group
t('project.environmental.env') v-model:model-value="showType"
}}</a-radio> type="button"
<a-radio v-permission="['PROJECT_ENVIRONMENT:READ']" value="PROJECT_GROUP">{{ class="file-show-type w-[50%]"
@change="changeShowType"
>
<a-radio v-permission="['PROJECT_ENVIRONMENT:READ']" value="PROJECT">{{
t('project.environmental.env')
}}</a-radio>
<!-- <a-radio v-permission="['PROJECT_ENVIRONMENT:READ']" value="PROJECT_GROUP">{{
t('project.environmental.envGroup') t('project.environmental.envGroup')
}}</a-radio> }}</a-radio> -->
</a-radio-group> </a-radio-group></div
>
<template v-if="showType === 'PROJECT'"> <template v-if="showType === 'PROJECT'">
<a-input-search <a-input-search
v-model="keyword" v-model="keyword"
@ -764,7 +771,7 @@
background-color: rgba(var(--primary-1)); background-color: rgba(var(--primary-1));
} }
.file-show-type { .file-show-type {
@apply grid grid-cols-2; @apply grid grid-cols-1;
margin-bottom: 8px; margin-bottom: 8px;
:deep(.arco-radio-button-content) { :deep(.arco-radio-button-content) {

View File

@ -249,7 +249,7 @@
const params: UpdateWorkFlowSetting = { const params: UpdateWorkFlowSetting = {
fromId: props.stateItem?.id, fromId: props.stateItem?.id,
toId: props.columnItem?.dataIndex as string, toId: props.columnItem?.dataIndex as string,
enable: type === 'create' ? true : props.stateItem?.statusDefinitions.join().includes('END'), enable: type === 'create',
}; };
await updateOrdWorkStateFlow(params); await updateOrdWorkStateFlow(params);
Message.success( Message.success(