fix(项目管理): 环境管理断言参数调整&部项目管理bug修复
This commit is contained in:
parent
de60f207be
commit
ad7bcaa7cf
|
@ -7,14 +7,16 @@
|
||||||
</a-radio>
|
</a-radio>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'jsonPath'" class="mt-[16px]">
|
<!-- jsonPath开始 -->
|
||||||
|
<div v-if="activeTab === ResponseBodyAssertionType.JSON_PATH" class="mt-[16px]">
|
||||||
<paramsTable
|
<paramsTable
|
||||||
v-model:params="innerParams.jsonPath"
|
ref="extractParamsTableRef"
|
||||||
|
v-model:params="condition.jsonPathAssertion.assertions"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
:columns="jsonPathColumns"
|
:columns="jsonPathColumns"
|
||||||
:scroll="{ minWidth: '700px' }"
|
:scroll="{ minWidth: '700px' }"
|
||||||
:default-param-item="jsonPathDefaultParamItem"
|
:default-param-item="jsonPathDefaultParamItem"
|
||||||
@change="(data) => handleChange(data, 'jsonPath')"
|
@change="(data) => handleChange(data, ResponseBodyAssertionType.JSON_PATH)"
|
||||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||||
>
|
>
|
||||||
<template #expression="{ record, rowIndex }">
|
<template #expression="{ record, rowIndex }">
|
||||||
|
@ -82,24 +84,22 @@
|
||||||
</template>
|
</template>
|
||||||
</paramsTable>
|
</paramsTable>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'xPath'" class="mt-[16px]">
|
<!-- jsonPath结束 -->
|
||||||
|
<!-- xPath开始 -->
|
||||||
|
<div v-if="activeTab === ResponseBodyAssertionType.XPATH" class="mt-[16px]">
|
||||||
<div class="text-[var(--color-text-1)]">{{ t('ms.assertion.responseContentType') }}</div>
|
<div class="text-[var(--color-text-1)]">{{ t('ms.assertion.responseContentType') }}</div>
|
||||||
<a-radio-group
|
<a-radio-group v-model="activeResponseFormat" class="mb-[16px] mt-[16px]" type="button" size="small">
|
||||||
v-model:model-value="innerParams.xPath.responseFormat"
|
<a-radio key="XML" value="XML">XML</a-radio>
|
||||||
class="mb-[16px] mt-[16px]"
|
<a-radio key="HTML" value="HTML">HTML</a-radio>
|
||||||
type="button"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
<a-radio value="XML">XML</a-radio>
|
|
||||||
<a-radio value="HTML">HTML</a-radio>
|
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
<paramsTable
|
<paramsTable
|
||||||
v-model:params="innerParams.xPath.data"
|
ref="extractParamsTableRef"
|
||||||
|
v-model:params="condition.xpathAssertion.assertions"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
:columns="xPathColumns"
|
:columns="xPathColumns"
|
||||||
:scroll="{ minWidth: '700px' }"
|
:scroll="{ minWidth: '700px' }"
|
||||||
:default-param-item="xPathDefaultParamItem"
|
:default-param-item="xPathDefaultParamItem"
|
||||||
@change="(data) => handleChange(data, 'xPath')"
|
@change="(data) => handleChange(data, ResponseBodyAssertionType.XPATH)"
|
||||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||||
>
|
>
|
||||||
<template #expression="{ record, rowIndex }">
|
<template #expression="{ record, rowIndex }">
|
||||||
|
@ -167,22 +167,24 @@
|
||||||
</template>
|
</template>
|
||||||
</paramsTable>
|
</paramsTable>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'document'" class="relative mt-[16px]">
|
<!-- xPath结束 -->
|
||||||
|
<!-- document开始 -->
|
||||||
|
<div v-if="activeTab === ResponseBodyAssertionType.DOCUMENT" class="relative mt-[16px]">
|
||||||
<div class="text-[var(--color-text-1)]">
|
<div class="text-[var(--color-text-1)]">
|
||||||
{{ t('ms.assertion.responseContentType') }}
|
{{ t('ms.assertion.responseContentType') }}
|
||||||
</div>
|
</div>
|
||||||
<a-radio-group v-model:model-value="innerParams.document.responseFormat" class="mt-[16px]" size="small">
|
<a-radio-group v-model:model-value="condition.document.responseFormat" class="mt-[16px]" size="small">
|
||||||
<a-radio value="JSON">JSON</a-radio>
|
<a-radio value="JSON">JSON</a-radio>
|
||||||
<a-radio value="XML">XML</a-radio>
|
<a-radio value="XML">XML</a-radio>
|
||||||
</a-radio-group>
|
</a-radio-group>
|
||||||
<div class="mt-[16px]">
|
<div class="mt-[16px]">
|
||||||
<a-checkbox v-model:model-value="innerParams.document.followApi">
|
<a-checkbox v-model:model-value="condition.document.followApi">
|
||||||
<span class="text-[var(--color-text-1)]">{{ t('ms.assertion.followApi') }}</span>
|
<span class="text-[var(--color-text-1)]">{{ t('ms.assertion.followApi') }}</span>
|
||||||
</a-checkbox>
|
</a-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-[16px]">
|
<div class="mt-[16px]">
|
||||||
<paramsTable
|
<paramsTable
|
||||||
v-model:params="innerParams.document.data"
|
v-model:params="condition.document.jsonAssertion"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
:columns="documentColumns"
|
:columns="documentColumns"
|
||||||
:scroll="{
|
:scroll="{
|
||||||
|
@ -193,7 +195,7 @@
|
||||||
:span-method="documentSpanMethod"
|
:span-method="documentSpanMethod"
|
||||||
is-tree-table
|
is-tree-table
|
||||||
@tree-delete="deleteAllParam"
|
@tree-delete="deleteAllParam"
|
||||||
@change="(data) => handleChange(data, 'document')"
|
@change="(data) => handleChange(data, ResponseBodyAssertionType.DOCUMENT)"
|
||||||
>
|
>
|
||||||
<template #matchValueDelete="{ record }">
|
<template #matchValueDelete="{ record }">
|
||||||
<icon-minus-circle
|
<icon-minus-circle
|
||||||
|
@ -227,14 +229,17 @@
|
||||||
</paramsTable>
|
</paramsTable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'regular'" class="mt-[16px]">
|
<!-- document结束 -->
|
||||||
|
<!-- 正则开始 -->
|
||||||
|
<div v-if="activeTab === ResponseBodyAssertionType.REGEX" class="mt-[16px]">
|
||||||
<paramsTable
|
<paramsTable
|
||||||
v-model:params="innerParams.regular"
|
ref="extractParamsTableRef"
|
||||||
|
v-model:params="condition.regexAssertion.assertions"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
:columns="xPathColumns"
|
:columns="xPathColumns"
|
||||||
:scroll="{ minWidth: '700px' }"
|
:scroll="{ minWidth: '700px' }"
|
||||||
:default-param-item="xPathDefaultParamItem"
|
:default-param-item="xPathDefaultParamItem"
|
||||||
@change="(data) => handleChange(data, 'regular')"
|
@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)"
|
||||||
>
|
>
|
||||||
<template #expression="{ record, rowIndex }">
|
<template #expression="{ record, rowIndex }">
|
||||||
|
@ -302,14 +307,17 @@
|
||||||
</template>
|
</template>
|
||||||
</paramsTable>
|
</paramsTable>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'script'" class="mt-[16px]">
|
<!-- 正则结束 -->
|
||||||
<conditionContent v-model:data="innerParams.script" :height-used="600" is-build-in class="mt-[16px]" />
|
<!-- 这一版断言里边的脚本不需要 -->
|
||||||
</div>
|
<!-- <div v-if="activeTab === ResponseBodyAssertionType.SCRIPT" class="mt-[16px]">
|
||||||
|
<conditionContent v-model:data="condition.script" :height-used="600" is-build-in class="mt-[16px]" />
|
||||||
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<fastExtraction v-model:visible="fastExtractionVisible" :config="activeRecord" @apply="handleFastExtractionApply" />
|
<fastExtraction v-model:visible="fastExtractionVisible" :config="activeRecord" @apply="handleFastExtractionApply" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useVModel } from '@vueuse/core';
|
||||||
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
||||||
|
@ -345,6 +353,7 @@
|
||||||
RequestExtractExpressionRuleType,
|
RequestExtractExpressionRuleType,
|
||||||
RequestExtractResultMatchingRule,
|
RequestExtractResultMatchingRule,
|
||||||
RequestExtractScope,
|
RequestExtractScope,
|
||||||
|
ResponseBodyAssertionType,
|
||||||
ResponseBodyXPathAssertionFormat,
|
ResponseBodyXPathAssertionFormat,
|
||||||
} from '@/enums/apiEnum';
|
} from '@/enums/apiEnum';
|
||||||
|
|
||||||
|
@ -353,7 +362,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:data', data: ExecuteConditionProcessor): void;
|
// (e: 'update:data', data: ExecuteConditionProcessor): void;
|
||||||
(e: 'copy'): void;
|
(e: 'copy'): void;
|
||||||
(e: 'delete', id: number): void;
|
(e: 'delete', id: number): void;
|
||||||
(e: 'change', param: Param): void;
|
(e: 'change', param: Param): void;
|
||||||
|
@ -362,44 +371,43 @@
|
||||||
const rootId = 0; // 1970-01-01 00:00:00 UTC
|
const rootId = 0; // 1970-01-01 00:00:00 UTC
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
value: Param;
|
data: Param;
|
||||||
}>();
|
}>();
|
||||||
|
const activeTab = ref(ResponseBodyAssertionType.JSON_PATH);
|
||||||
|
const activeResponseFormat = ref('XML');
|
||||||
const defaultParamItem = {
|
const defaultParamItem = {
|
||||||
jsonPath: [],
|
jsonPathAssertion: {
|
||||||
xPath: { responseFormat: 'XML', data: [] },
|
assertions: [],
|
||||||
document: {
|
|
||||||
data: [
|
|
||||||
{
|
|
||||||
id: rootId,
|
|
||||||
paramsName: 'root',
|
|
||||||
mustInclude: false,
|
|
||||||
typeChecking: false,
|
|
||||||
paramType: 'object',
|
|
||||||
matchCondition: '',
|
|
||||||
matchValue: '',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
responseFormat: 'JSON',
|
|
||||||
followApi: false,
|
|
||||||
},
|
},
|
||||||
script: {
|
xpathAssertion: { responseFormat: 'XML', assertions: [] },
|
||||||
id: new Date().getTime(),
|
assertionBodyType: activeTab.value,
|
||||||
processorType: RequestConditionProcessor.SCRIPT,
|
regexAssertion: {
|
||||||
scriptName: '断言脚本名称',
|
assertions: [],
|
||||||
enableCommonScript: false,
|
|
||||||
params: [],
|
|
||||||
scriptId: '',
|
|
||||||
scriptLanguage: RequestConditionScriptLanguage.JAVASCRIPT,
|
|
||||||
script: new Date().getTime().toString(),
|
|
||||||
},
|
},
|
||||||
|
// TODO文档暂时不做
|
||||||
|
// documentAssertion: {
|
||||||
|
// jsonAssertion: [
|
||||||
|
// {
|
||||||
|
// id: rootId,
|
||||||
|
// paramsName: 'root',
|
||||||
|
// mustInclude: false,
|
||||||
|
// typeChecking: false,
|
||||||
|
// paramType: 'object',
|
||||||
|
// matchCondition: '',
|
||||||
|
// matchValue: '',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// responseFormat: 'JSON',
|
||||||
|
// followApi: false,
|
||||||
|
// },
|
||||||
};
|
};
|
||||||
|
|
||||||
const innerParams = ref<Param>(props.value || defaultParamItem);
|
const condition = useVModel(props, 'data', emit);
|
||||||
watchEffect(() => {
|
// const condition = ref<Param>(props.data || defaultParamItem);
|
||||||
emit('change', innerParams.value);
|
// watchEffect(() => {
|
||||||
});
|
// emit('change', { ...condition.value });
|
||||||
const activeTab = ref('jsonPath');
|
// });
|
||||||
|
|
||||||
const extractParamsTableRef = ref<InstanceType<typeof paramsTable>>();
|
const extractParamsTableRef = ref<InstanceType<typeof paramsTable>>();
|
||||||
const fastExtractionVisible = ref(false);
|
const fastExtractionVisible = ref(false);
|
||||||
const disabledExpressionSuffix = ref(false);
|
const disabledExpressionSuffix = ref(false);
|
||||||
|
@ -422,11 +430,10 @@
|
||||||
const activeRecord = ref({ ...defaultExtractParamItem }); // 用于暂存当前操作的提取参数表格项
|
const activeRecord = ref({ ...defaultExtractParamItem }); // 用于暂存当前操作的提取参数表格项
|
||||||
|
|
||||||
const responseRadios = [
|
const responseRadios = [
|
||||||
{ label: 'ms.assertion.jsonPath', value: 'jsonPath' },
|
{ label: 'ms.assertion.jsonPath', value: ResponseBodyAssertionType.JSON_PATH },
|
||||||
{ label: 'ms.assertion.xpath', value: 'xPath' },
|
{ label: 'ms.assertion.xpath', value: ResponseBodyAssertionType.XPATH },
|
||||||
// { label: 'ms.assertion.document', value: 'document' },
|
// { label: 'ms.assertion.document', value: 'document' },
|
||||||
{ label: 'ms.assertion.regular', value: 'regular' },
|
{ label: 'ms.assertion.regular', value: ResponseBodyAssertionType.REGEX },
|
||||||
{ label: 'ms.assertion.script', value: 'script' },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const jsonPathColumns: ParamTableColumn[] = [
|
const jsonPathColumns: ParamTableColumn[] = [
|
||||||
|
@ -438,15 +445,15 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.assertion.matchCondition',
|
title: 'ms.assertion.matchCondition',
|
||||||
dataIndex: 'matchCondition',
|
dataIndex: 'condition',
|
||||||
slotName: 'matchCondition',
|
slotName: 'condition',
|
||||||
options: statusCodeOptions,
|
options: statusCodeOptions,
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.assertion.matchValue',
|
title: 'ms.assertion.matchValue',
|
||||||
dataIndex: 'matchValue',
|
dataIndex: 'expectedValue',
|
||||||
slotName: 'matchValue',
|
slotName: 'expectedValue',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '',
|
title: '',
|
||||||
|
@ -469,19 +476,38 @@
|
||||||
|
|
||||||
const jsonPathDefaultParamItem = {
|
const jsonPathDefaultParamItem = {
|
||||||
expression: '',
|
expression: '',
|
||||||
matchCondition: '',
|
condition: '',
|
||||||
matchValue: '',
|
expectedValue: '',
|
||||||
enable: true,
|
valid: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (data: any[], type: string) => {
|
const handleChange = (data: any[], type: string) => {
|
||||||
if (type === 'jsonPath') {
|
switch (type) {
|
||||||
innerParams.value.jsonPath = data;
|
case ResponseBodyAssertionType.JSON_PATH:
|
||||||
} else if (type === 'xPath') {
|
if (data.length > 1) {
|
||||||
innerParams.value.xPath.data = data;
|
data.splice(data.length - 1, 1);
|
||||||
} else if (type === 'document') {
|
}
|
||||||
innerParams.value.document.data = data;
|
condition.value.jsonPathAssertion.assertions = data;
|
||||||
} else if (type === 'regular') {
|
emit('change', { ...defaultParamItem, ...condition.value, assertionBodyType: activeTab.value });
|
||||||
innerParams.value.regular = data;
|
break;
|
||||||
|
case ResponseBodyAssertionType.XPATH:
|
||||||
|
condition.value.xpathAssertion.assertions = data;
|
||||||
|
emit('change', {
|
||||||
|
...defaultParamItem,
|
||||||
|
...condition.value,
|
||||||
|
assertionBodyType: activeTab.value,
|
||||||
|
responseFormat: activeResponseFormat.value,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case ResponseBodyAssertionType.DOCUMENT:
|
||||||
|
condition.value.documentAssertion.jsonAssertion = data;
|
||||||
|
break;
|
||||||
|
case ResponseBodyAssertionType.REGEX:
|
||||||
|
condition.value.regexAssertion.assertions = data;
|
||||||
|
emit('change', { ...defaultParamItem, ...condition.value, assertionBodyType: activeTab.value });
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function handleExpressionChange(rowIndex: number) {
|
function handleExpressionChange(rowIndex: number) {
|
||||||
|
@ -615,20 +641,22 @@
|
||||||
* 提取参数表格-保存快速提取的配置
|
* 提取参数表格-保存快速提取的配置
|
||||||
*/
|
*/
|
||||||
function handleFastExtractionApply(config: RegexExtract | JSONPathExtract | XPathExtract) {
|
function handleFastExtractionApply(config: RegexExtract | JSONPathExtract | XPathExtract) {
|
||||||
// condition.value.extractParams = condition.value.extractParams?.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,
|
||||||
// };
|
};
|
||||||
// }
|
}
|
||||||
// return e;
|
return e;
|
||||||
// });
|
});
|
||||||
// fastExtractionVisible.value = false;
|
fastExtractionVisible.value = false;
|
||||||
// nextTick(() => {
|
nextTick(() => {
|
||||||
// extractParamsTableRef.value?.addTableLine();
|
extractParamsTableRef.value?.addTableLine(
|
||||||
// });
|
condition.value.jsonPathAssertion.assertions?.findIndex((e) => e.id === activeRecord.value.id) || 0
|
||||||
// emit('change');
|
);
|
||||||
|
});
|
||||||
|
emit('change', { ...condition.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -672,9 +700,9 @@
|
||||||
const addValidateChild = (record: Record<string, any>) => {
|
const addValidateChild = (record: Record<string, any>) => {
|
||||||
if (record.groupId) {
|
if (record.groupId) {
|
||||||
// 子项点击,找到父级
|
// 子项点击,找到父级
|
||||||
const parent = innerParams.value.document.data.find((item: any) => item.id === record.groupId);
|
const parent = condition.value.documentAssertion.jsonAssertion.find((item: any) => item.id === record.groupId);
|
||||||
insertNode(
|
insertNode(
|
||||||
innerParams.value.document.data,
|
condition.value.documentAssertion.jsonAssertion,
|
||||||
{ id: record.id, groupId: record.groupId },
|
{ id: record.id, groupId: record.groupId },
|
||||||
{
|
{
|
||||||
...record,
|
...record,
|
||||||
|
@ -688,18 +716,18 @@
|
||||||
parent.rowSpan = parent.rowSpan ? parent.rowSpan + 1 : 2;
|
parent.rowSpan = parent.rowSpan ? parent.rowSpan + 1 : 2;
|
||||||
} else {
|
} else {
|
||||||
// 找到第一个子节点
|
// 找到第一个子节点
|
||||||
const fisrtChildNode = findFirstByGroupId(innerParams.value.document.data, record.groupId);
|
const fisrtChildNode = findFirstByGroupId(condition.value.documentAssertion.jsonAssertion, record.groupId);
|
||||||
if (fisrtChildNode) {
|
if (fisrtChildNode) {
|
||||||
fisrtChildNode.rowSpan = fisrtChildNode.rowSpan
|
fisrtChildNode.rowSpan = fisrtChildNode.rowSpan
|
||||||
? fisrtChildNode.rowSpan + 1
|
? fisrtChildNode.rowSpan + 1
|
||||||
: countNodesByGroupId(innerParams.value.document.data, record.groupId) + 1;
|
: countNodesByGroupId(condition.value.documentAssertion.jsonAssertion, record.groupId) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
record.rowSpan = record.rowSpan ? record.rowSpan + 1 : 2;
|
record.rowSpan = record.rowSpan ? record.rowSpan + 1 : 2;
|
||||||
// 父级点击
|
// 父级点击
|
||||||
insertNode(
|
insertNode(
|
||||||
innerParams.value.document.data,
|
condition.value.documentAssertion.jsonAssertion,
|
||||||
{ id: record.id, groupId: record.groupId },
|
{ id: record.id, groupId: record.groupId },
|
||||||
{
|
{
|
||||||
...record,
|
...record,
|
||||||
|
@ -712,23 +740,23 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const showDeleteSingle = computed(() => {
|
const showDeleteSingle = computed(() => {
|
||||||
return countNodes(innerParams.value.document.data) > 1;
|
return countNodes(condition.value.documentAssertion.jsonAssertion) > 1;
|
||||||
});
|
});
|
||||||
const deleteSingleParam = (record: Record<string, any>) => {
|
const deleteSingleParam = (record: Record<string, any>) => {
|
||||||
deleteNodeById(innerParams.value.document.data, record.id);
|
deleteNodeById(condition.value.documentAssertion.jsonAssertion, record.id);
|
||||||
};
|
};
|
||||||
const deleteAllParam = (record: Record<string, any>) => {
|
const deleteAllParam = (record: Record<string, any>) => {
|
||||||
if (record.groupId) {
|
if (record.groupId) {
|
||||||
// 验证子项,根据groupId删除
|
// 验证子项,根据groupId删除
|
||||||
deleteNodesByGroupId(innerParams.value.document.data, record.groupId);
|
deleteNodesByGroupId(condition.value.documentAssertion.jsonAssertion, record.groupId);
|
||||||
} else if (record.rowspan > 2) {
|
} else if (record.rowspan > 2) {
|
||||||
// 验证主体, 根据主体的id 作为groupId删除
|
// 验证主体, 根据主体的id 作为groupId删除
|
||||||
deleteNodesByGroupId(innerParams.value.document.data, record.id);
|
deleteNodesByGroupId(condition.value.documentAssertion.jsonAssertion, record.id);
|
||||||
// 删除本体
|
// 删除本体
|
||||||
deleteNodeById(innerParams.value.document.data, record.id);
|
deleteNodeById(condition.value.documentAssertion.jsonAssertion, record.id);
|
||||||
} else {
|
} else {
|
||||||
// 删除本体
|
// 删除本体
|
||||||
deleteNodeById(innerParams.value.document.data, record.id);
|
deleteNodeById(condition.value.documentAssertion.jsonAssertion, record.id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -752,6 +780,6 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleScriptChange = (data: ExecuteConditionProcessor) => {
|
const handleScriptChange = (data: ExecuteConditionProcessor) => {
|
||||||
innerParams.value.script = data;
|
condition.value.script = data;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -11,86 +11,101 @@
|
||||||
<a-doption v-for="item in assertOptionSource" :key="item.value" :value="item.value">{{ item.label }}</a-doption>
|
<a-doption v-for="item in assertOptionSource" :key="item.value" :value="item.value">{{ item.label }}</a-doption>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<div v-if="showBody" class="ms-assertion-body">
|
|
||||||
<VueDraggable v-model="assertions" class="ms-assertion-body-left" ghost-class="ghost" handle=".sort-handle">
|
|
||||||
<div
|
|
||||||
v-for="(item, index) in assertions"
|
|
||||||
:key="item.id"
|
|
||||||
class="ms-assertion-body-left-item"
|
|
||||||
:class="{
|
|
||||||
'ms-assertion-body-left-item-active': activeKey === item.id,
|
|
||||||
'ms-assertion-body-left-item-active-focus': focusKey === item.id,
|
|
||||||
}"
|
|
||||||
@click="handleItemClick(item)"
|
|
||||||
>
|
|
||||||
<div class="ms-assertion-body-left-item-row">
|
|
||||||
<span class="ms-assertion-body-left-item-row-num">{{ index + 1 }}</span>
|
|
||||||
<span class="ms-assertion-body-left-item-row-title">{{ item.name }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="ms-assertion-body-left-item-switch">
|
|
||||||
<div class="ms-assertion-body-left-item-switch-action">
|
|
||||||
<MsIcon
|
|
||||||
type="icon-icon_drag"
|
|
||||||
class="action-btn-move sort-handle cursor-move text-[12px] text-[var(--color-text-4)]"
|
|
||||||
/>
|
|
||||||
<MsTableMoreAction
|
|
||||||
:list="itemMoreActions"
|
|
||||||
trigger="click"
|
|
||||||
@select="handleMoreActionSelect($event, item)"
|
|
||||||
@close="focusKey = ''"
|
|
||||||
>
|
|
||||||
<MsButton type="icon" size="mini" class="action-btn-more">
|
|
||||||
<MsIcon
|
|
||||||
type="icon-icon_more_outlined"
|
|
||||||
size="14"
|
|
||||||
class="text-[var(--color-text-4)]"
|
|
||||||
@click="focusKey = item.id"
|
|
||||||
/>
|
|
||||||
</MsButton>
|
|
||||||
</MsTableMoreAction>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a-switch v-model:model-value="item.enable" type="line" size="small" />
|
<div v-if="showBody" class="ms-assertion-body">
|
||||||
|
<a-scrollbar
|
||||||
|
:style="{
|
||||||
|
overflow: 'auto',
|
||||||
|
height: 'calc(100vh - 458px)',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<VueDraggable v-model="assertions" class="ms-assertion-body-left" ghost-class="ghost" handle=".sort-handle">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in assertions"
|
||||||
|
:key="item.id"
|
||||||
|
class="ms-assertion-body-left-item"
|
||||||
|
:class="{
|
||||||
|
'ms-assertion-body-left-item-active': activeKey === item.id,
|
||||||
|
'ms-assertion-body-left-item-active-focus': focusKey === item.id,
|
||||||
|
}"
|
||||||
|
@click="handleItemClick(item)"
|
||||||
|
>
|
||||||
|
<div class="ms-assertion-body-left-item-row">
|
||||||
|
<span class="ms-assertion-body-left-item-row-num">{{ index + 1 }}</span>
|
||||||
|
<span class="ms-assertion-body-left-item-row-title">{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="ms-assertion-body-left-item-switch">
|
||||||
|
<div class="ms-assertion-body-left-item-switch-action">
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_drag"
|
||||||
|
class="action-btn-move sort-handle cursor-move text-[12px] text-[var(--color-text-4)]"
|
||||||
|
/>
|
||||||
|
<MsTableMoreAction
|
||||||
|
:list="itemMoreActions"
|
||||||
|
trigger="click"
|
||||||
|
@select="handleMoreActionSelect($event, item)"
|
||||||
|
@close="focusKey = ''"
|
||||||
|
>
|
||||||
|
<MsButton type="icon" size="mini" class="action-btn-more">
|
||||||
|
<MsIcon
|
||||||
|
type="icon-icon_more_outlined"
|
||||||
|
size="14"
|
||||||
|
class="text-[var(--color-text-4)]"
|
||||||
|
@click="focusKey = item.id"
|
||||||
|
/>
|
||||||
|
</MsButton>
|
||||||
|
</MsTableMoreAction>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-switch v-model:model-value="item.enable" type="line" size="small" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</VueDraggable>
|
||||||
</VueDraggable>
|
</a-scrollbar>
|
||||||
<section class="ms-assertion-body-right">
|
<section class="ms-assertion-body-right">
|
||||||
<!-- 响应头 -->
|
<a-scrollbar
|
||||||
<ResponseHeaderTab
|
:style="{
|
||||||
v-if="valueKey === ResponseAssertionType.RESPONSE_HEADER"
|
overflow: 'auto',
|
||||||
v-model:data="getCurrentItemState"
|
height: '200px',
|
||||||
@change="handleChange"
|
}"
|
||||||
/>
|
>
|
||||||
<!-- 状态码 -->
|
<!-- 响应头 -->
|
||||||
<StatusCodeTab
|
<ResponseHeaderTab
|
||||||
v-if="valueKey === ResponseAssertionType.RESPONSE_CODE"
|
v-if="valueKey === ResponseAssertionType.RESPONSE_HEADER"
|
||||||
v-model:data="getCurrentItemState"
|
v-model:data="getCurrentItemState"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
/>
|
/>
|
||||||
<!-- 响应体 -->
|
<!-- 状态码 -->
|
||||||
<ResponseBodyTab
|
<StatusCodeTab
|
||||||
v-if="valueKey === ResponseAssertionType.RESPONSE_BODY"
|
v-if="valueKey === ResponseAssertionType.RESPONSE_CODE"
|
||||||
:value="getCurrentItemState"
|
v-model:data="getCurrentItemState"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
/>
|
/>
|
||||||
<!-- 响应时间 -->
|
<!-- 响应体 -->
|
||||||
<ResponseTimeTab
|
<ResponseBodyTab
|
||||||
v-if="valueKey === ResponseAssertionType.RESPONSE_TIME"
|
v-if="valueKey === ResponseAssertionType.RESPONSE_BODY"
|
||||||
v-model:data="getCurrentItemState"
|
v-model:data="getCurrentItemState"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
/>
|
/>
|
||||||
<!-- 变量 -->
|
<!-- 响应时间 -->
|
||||||
<VariableTab
|
<ResponseTimeTab
|
||||||
v-if="valueKey === ResponseAssertionType.VARIABLE"
|
v-if="valueKey === ResponseAssertionType.RESPONSE_TIME"
|
||||||
v-model:data="getCurrentItemState"
|
v-model:data="getCurrentItemState"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
/>
|
/>
|
||||||
<!-- 脚本 -->
|
<!-- 变量 -->
|
||||||
<ScriptTab
|
<VariableTab
|
||||||
v-if="valueKey === ResponseAssertionType.SCRIPT"
|
v-if="valueKey === ResponseAssertionType.VARIABLE"
|
||||||
:value="getCurrentItemState"
|
v-model:data="getCurrentItemState"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
/>
|
/>
|
||||||
|
<!-- 脚本 -->
|
||||||
|
<ScriptTab
|
||||||
|
v-if="valueKey === ResponseAssertionType.SCRIPT"
|
||||||
|
:value="getCurrentItemState"
|
||||||
|
@change="handleChange"
|
||||||
|
/>
|
||||||
|
</a-scrollbar>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -133,11 +148,50 @@
|
||||||
const valueKey = computed(() => {
|
const valueKey = computed(() => {
|
||||||
return activeKey.value && assertions.value.find((item) => item.id === activeKey.value)?.assertionType;
|
return activeKey.value && assertions.value.find((item) => item.id === activeKey.value)?.assertionType;
|
||||||
});
|
});
|
||||||
|
const defaultResBodyItem = {
|
||||||
|
jsonPathAssertion: {
|
||||||
|
assertions: [],
|
||||||
|
},
|
||||||
|
xpathAssertion: { responseFormat: 'XML', assertions: [] },
|
||||||
|
assertionBodyType: '',
|
||||||
|
regexAssertion: {
|
||||||
|
assertions: [],
|
||||||
|
},
|
||||||
|
// TODO文档暂时不做
|
||||||
|
// documentAssertion: {
|
||||||
|
// jsonAssertion: [
|
||||||
|
// {
|
||||||
|
// id: rootId,
|
||||||
|
// paramsName: 'root',
|
||||||
|
// mustInclude: false,
|
||||||
|
// typeChecking: false,
|
||||||
|
// paramType: 'object',
|
||||||
|
// matchCondition: '',
|
||||||
|
// matchValue: '',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// responseFormat: 'JSON',
|
||||||
|
// followApi: false,
|
||||||
|
// },
|
||||||
|
};
|
||||||
|
|
||||||
// 计算当前页面的存储的状态
|
// 计算当前页面的存储的状态
|
||||||
const getCurrentItemState = computed({
|
const getCurrentItemState = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
return assertions.value.find((item) => item.id === activeKey.value);
|
const currentResItem =
|
||||||
|
assertions.value.find((item: any) => item.id === activeKey.value) || assertions.value[0] || {};
|
||||||
|
if (currentResItem && currentResItem?.assertionType === ResponseAssertionType.RESPONSE_BODY) {
|
||||||
|
const { jsonPathAssertion, xpathAssertion, regexAssertion } = currentResItem;
|
||||||
|
return {
|
||||||
|
...currentResItem,
|
||||||
|
jsonPathAssertion: jsonPathAssertion || defaultResBodyItem.jsonPathAssertion,
|
||||||
|
xpathAssertion: xpathAssertion || defaultResBodyItem.xpathAssertion,
|
||||||
|
assertionBodyType: '',
|
||||||
|
regexAssertion: regexAssertion || defaultResBodyItem.regexAssertion,
|
||||||
|
bodyAssertionDataByType: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return currentResItem;
|
||||||
},
|
},
|
||||||
set: (val: ExecuteAssertion) => {
|
set: (val: ExecuteAssertion) => {
|
||||||
const currentIndex = assertions.value.findIndex((item) => item.id === activeKey.value);
|
const currentIndex = assertions.value.findIndex((item) => item.id === activeKey.value);
|
||||||
|
@ -223,11 +277,12 @@
|
||||||
assertions: [],
|
assertions: [],
|
||||||
},
|
},
|
||||||
xpathAssertion: {
|
xpathAssertion: {
|
||||||
|
responseFormat: 'XML',
|
||||||
assertions: [],
|
assertions: [],
|
||||||
},
|
},
|
||||||
regexAssertion: {
|
// regexAssertion: {
|
||||||
assertions: [],
|
// assertions: [],
|
||||||
},
|
// },
|
||||||
bodyAssertionDataByType: {},
|
bodyAssertionDataByType: {},
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
@ -284,6 +339,7 @@
|
||||||
getCurrentItemState.value = { ...val };
|
getCurrentItemState.value = { ...val };
|
||||||
break;
|
break;
|
||||||
case ResponseAssertionType.RESPONSE_BODY:
|
case ResponseAssertionType.RESPONSE_BODY:
|
||||||
|
getCurrentItemState.value = { ...val };
|
||||||
break;
|
break;
|
||||||
case ResponseAssertionType.RESPONSE_TIME:
|
case ResponseAssertionType.RESPONSE_TIME:
|
||||||
getCurrentItemState.value = { ...val };
|
getCurrentItemState.value = { ...val };
|
||||||
|
@ -300,7 +356,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
console.log(getCurrentItemState.value);
|
getCurrentItemState.value =
|
||||||
|
assertions.value.find((item: any) => item.id === activeKey.value) || assertions.value[0] || {};
|
||||||
|
activeKey.value = getCurrentItemState.value.id;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -317,7 +375,6 @@
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
width: 216px;
|
width: 216px;
|
||||||
min-width: 216px;
|
min-width: 216px;
|
||||||
height: calc(100vh - 394px);
|
|
||||||
background-color: var(--color-text-n9);
|
background-color: var(--color-text-n9);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|
|
@ -119,4 +119,8 @@ export const editorProps = {
|
||||||
type: Boolean as PropType<boolean>,
|
type: Boolean as PropType<boolean>,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
widthClass: {
|
||||||
|
type: String as PropType<string>,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,10 +68,9 @@ export const MEMBER = {
|
||||||
value: '',
|
value: '',
|
||||||
options: [],
|
options: [],
|
||||||
props: {
|
props: {
|
||||||
'multiple': false,
|
multiple: false,
|
||||||
// 'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'modelValue': '',
|
modelValue: '',
|
||||||
'allow-clear': true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,11 +81,10 @@ export const MULTIPLE_MEMBER = {
|
||||||
value: [],
|
value: [],
|
||||||
options: [],
|
options: [],
|
||||||
props: {
|
props: {
|
||||||
'multiple': true,
|
multiple: true,
|
||||||
// 'placeholder': t('formCreate.PleaseSelect'),
|
// 'placeholder': t('formCreate.PleaseSelect'),
|
||||||
'options': [],
|
options: [],
|
||||||
'modelValue': [],
|
modelValue: [],
|
||||||
'allow-clear': true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -657,7 +657,7 @@ export const pathMap: PathMapItem[] = [
|
||||||
level: MENU_LEVEL[2],
|
level: MENU_LEVEL[2],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'PROJECT_MANAGEMENT_COMMON_SCRIPT', // 项目管理-公共脚本
|
key: ' PROJECT_CUSTOM_FUNCTION', // 项目管理-公共脚本
|
||||||
locale: 'menu.projectManagement.commonScript',
|
locale: 'menu.projectManagement.commonScript',
|
||||||
route: RouteEnum.PROJECT_MANAGEMENT_COMMON_SCRIPT,
|
route: RouteEnum.PROJECT_MANAGEMENT_COMMON_SCRIPT,
|
||||||
permission: [],
|
permission: [],
|
||||||
|
|
|
@ -113,6 +113,7 @@ export enum ResponseBodyAssertionType {
|
||||||
JSON_PATH = 'JSON_PATH',
|
JSON_PATH = 'JSON_PATH',
|
||||||
REGEX = 'REGEX', // 正则表达式
|
REGEX = 'REGEX', // 正则表达式
|
||||||
XPATH = 'XPATH',
|
XPATH = 'XPATH',
|
||||||
|
SCRIPT = 'SCRIPT',
|
||||||
}
|
}
|
||||||
// 接口断言-响应体断言-文档类型
|
// 接口断言-响应体断言-文档类型
|
||||||
export enum ResponseBodyAssertionDocumentType {
|
export enum ResponseBodyAssertionDocumentType {
|
||||||
|
|
|
@ -270,6 +270,7 @@
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
|
import useUserStore from '@/store/modules/user';
|
||||||
import { downloadByteFile, getGenerateId } from '@/utils';
|
import { downloadByteFile, getGenerateId } from '@/utils';
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
|
@ -279,12 +280,15 @@
|
||||||
CreateOrUpdateCase,
|
CreateOrUpdateCase,
|
||||||
CustomAttributes,
|
CustomAttributes,
|
||||||
DetailCase,
|
DetailCase,
|
||||||
|
OptionsFieldId,
|
||||||
StepList,
|
StepList,
|
||||||
} from '@/models/caseManagement/featureCase';
|
} from '@/models/caseManagement/featureCase';
|
||||||
import type { ModuleTreeNode, TableQueryParams } from '@/models/common';
|
import type { ModuleTreeNode, TableQueryParams } from '@/models/common';
|
||||||
|
|
||||||
import { convertToFile, initFormCreate } from './utils';
|
import { convertToFile, initFormCreate } from './utils';
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
@ -382,16 +386,33 @@
|
||||||
const { customFields, id } = res;
|
const { customFields, id } = res;
|
||||||
form.value.templateId = id;
|
form.value.templateId = id;
|
||||||
const result = customFields.map((item: any) => {
|
const result = customFields.map((item: any) => {
|
||||||
|
const memberType = ['MEMBER', 'MULTIPLE_MEMBER'];
|
||||||
|
let initValue = item.defaultValue;
|
||||||
|
let optionsValue: OptionsFieldId[] = item.options;
|
||||||
|
if (memberType.includes(item.type)) {
|
||||||
|
optionsValue = [
|
||||||
|
{
|
||||||
|
fieldId: item.fieldId,
|
||||||
|
internal: item.internal,
|
||||||
|
text: userStore.name || '',
|
||||||
|
value: userStore.id || '',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
if (item.defaultValue === 'CREATE_USER') {
|
||||||
|
initValue = item.type === 'MEMBER' ? userStore.id : [userStore.id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: item.type,
|
type: item.type,
|
||||||
name: item.fieldId,
|
name: item.fieldId,
|
||||||
label: item.fieldName,
|
label: item.fieldName,
|
||||||
value: item.defaultValue,
|
value: initValue,
|
||||||
required: item.required,
|
required: item.required,
|
||||||
options: item.options || [],
|
options: item.options || [],
|
||||||
props: {
|
props: {
|
||||||
modelValue: item.defaultValue,
|
modelValue: initValue,
|
||||||
options: item.options || [],
|
options: optionsValue || [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
tableSelectData: DefinedFieldItem[]; // 表格选择字段
|
tableSelectData: DefinedFieldItem[]; // 表格选择字段
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['confirm', 'update:visible', 'update-data']);
|
const emit = defineEmits(['confirm', 'update:visible', 'update-data', 'brash']);
|
||||||
|
|
||||||
const totalList = ref<DefinedFieldItem[]>([]);
|
const totalList = ref<DefinedFieldItem[]>([]);
|
||||||
|
|
||||||
|
@ -229,9 +229,9 @@
|
||||||
showAddDrawer.value = false;
|
showAddDrawer.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const okHandler = () => {
|
const okHandler = (editFlag: boolean, fieldId: string) => {
|
||||||
// eslint-disable-next-line vue/custom-event-name-casing
|
// eslint-disable-next-line vue/custom-event-name-casing
|
||||||
emit('update-data');
|
emit('update-data', editFlag, fieldId);
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
|
@ -182,6 +182,7 @@
|
||||||
:table-select-data="(selectData as DefinedFieldItem[])"
|
:table-select-data="(selectData as DefinedFieldItem[])"
|
||||||
:mode="props.mode"
|
:mode="props.mode"
|
||||||
@confirm="confirmHandler"
|
@confirm="confirmHandler"
|
||||||
|
@update-data="updateFieldHandler"
|
||||||
/>
|
/>
|
||||||
<EditFieldDrawer
|
<EditFieldDrawer
|
||||||
ref="fieldDrawerRef"
|
ref="fieldDrawerRef"
|
||||||
|
|
Loading…
Reference in New Issue