feat(环境管理): 断言-请求体-文档
This commit is contained in:
parent
1ca47f0481
commit
18ac2c019d
|
@ -167,7 +167,7 @@
|
||||||
</template>
|
</template>
|
||||||
</paramsTable>
|
</paramsTable>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="activeTab === 'document'">
|
<div v-if="activeTab === 'document'" class="relative mt-[16px]">
|
||||||
<paramsTable
|
<paramsTable
|
||||||
v-model:params="innerParams.document.data"
|
v-model:params="innerParams.document.data"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
|
@ -175,7 +175,9 @@
|
||||||
:scroll="{
|
:scroll="{
|
||||||
minWidth: '700px',
|
minWidth: '700px',
|
||||||
}"
|
}"
|
||||||
|
:height-used="580"
|
||||||
:default-param-item="documentDefaultParamItem"
|
:default-param-item="documentDefaultParamItem"
|
||||||
|
:span-method="documentSpanMethod"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
|
||||||
>
|
>
|
||||||
|
@ -183,17 +185,17 @@
|
||||||
<a-tooltip v-if="['object', 'array'].includes(record.paramType)" :content="t('ms.assertion.addChild')">
|
<a-tooltip v-if="['object', 'array'].includes(record.paramType)" :content="t('ms.assertion.addChild')">
|
||||||
<div
|
<div
|
||||||
class="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-[rgb(var(--primary-5))] hover:bg-[rgb(var(--primary-1))]"
|
class="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-[rgb(var(--primary-5))] hover:bg-[rgb(var(--primary-1))]"
|
||||||
@click="addChild"
|
@click="addChild(record)"
|
||||||
>
|
>
|
||||||
<icon-plus size="14" />
|
<icon-plus size="16" />
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-tooltip v-else :content="t('ms.assertion.validateChild')">
|
<a-tooltip v-else :content="t('ms.assertion.validateChild')">
|
||||||
<div
|
<div
|
||||||
class="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-[rgb(var(--primary-5))] hover:bg-[rgb(var(--primary-1))]"
|
class="flex h-[24px] w-[24px] cursor-pointer items-center justify-center rounded text-[rgb(var(--primary-5))] hover:bg-[rgb(var(--primary-1))]"
|
||||||
@click="addValidateChild"
|
@click="addValidateChild(record)"
|
||||||
>
|
>
|
||||||
<icon-bookmark size="14" />
|
<icon-bookmark size="16" />
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
@ -288,14 +290,18 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
import { statusCodeOptions } from '@/components/pure/ms-advance-filter';
|
||||||
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||||
|
import { TableOperationColumn } from '../../ms-user-group-comp/authTable.vue';
|
||||||
import conditionContent from '@/views/api-test/components/condition/content.vue';
|
import conditionContent from '@/views/api-test/components/condition/content.vue';
|
||||||
import fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
|
import fastExtraction from '@/views/api-test/components/fastExtraction/index.vue';
|
||||||
import moreSetting from '@/views/api-test/components/fastExtraction/moreSetting.vue';
|
import moreSetting from '@/views/api-test/components/fastExtraction/moreSetting.vue';
|
||||||
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||||
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import { findFirstByGroupId, insertTreeByCurrentId, insertTreeByGroupId } from '@/utils/tree';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ExecuteConditionProcessor,
|
ExecuteConditionProcessor,
|
||||||
|
@ -359,7 +365,7 @@
|
||||||
script: new Date().getTime().toString(),
|
script: new Date().getTime().toString(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const activeTab = ref('jsonPath');
|
const activeTab = ref('document');
|
||||||
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);
|
||||||
|
@ -394,12 +400,14 @@
|
||||||
title: 'ms.assertion.expression',
|
title: 'ms.assertion.expression',
|
||||||
dataIndex: 'expression',
|
dataIndex: 'expression',
|
||||||
slotName: 'expression',
|
slotName: 'expression',
|
||||||
|
width: 300,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.assertion.matchCondition',
|
title: 'ms.assertion.matchCondition',
|
||||||
dataIndex: 'matchCondition',
|
dataIndex: 'matchCondition',
|
||||||
slotName: 'matchCondition',
|
slotName: 'matchCondition',
|
||||||
options: statusCodeOptions,
|
options: statusCodeOptions,
|
||||||
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.assertion.matchValue',
|
title: 'ms.assertion.matchValue',
|
||||||
|
@ -473,6 +481,7 @@
|
||||||
title: 'ms.assertion.paramsName',
|
title: 'ms.assertion.paramsName',
|
||||||
dataIndex: 'paramsName',
|
dataIndex: 'paramsName',
|
||||||
slotName: 'key',
|
slotName: 'key',
|
||||||
|
width: 300,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.assertion.mustInclude',
|
title: 'ms.assertion.mustInclude',
|
||||||
|
@ -480,6 +489,7 @@
|
||||||
slotName: 'mustContain',
|
slotName: 'mustContain',
|
||||||
titleSlotName: 'documentMustIncludeTitle',
|
titleSlotName: 'documentMustIncludeTitle',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
width: 80,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'ms.assertion.typeChecking',
|
title: 'ms.assertion.typeChecking',
|
||||||
|
@ -487,6 +497,7 @@
|
||||||
slotName: 'typeChecking',
|
slotName: 'typeChecking',
|
||||||
titleSlotName: 'documentTypeCheckingTitle',
|
titleSlotName: 'documentTypeCheckingTitle',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'project.environmental.paramType',
|
title: 'project.environmental.paramType',
|
||||||
|
@ -522,7 +533,8 @@
|
||||||
title: '',
|
title: '',
|
||||||
slotName: 'operation',
|
slotName: 'operation',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 130,
|
width: 60,
|
||||||
|
align: 'right',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const documentDefaultParamItem = {
|
const documentDefaultParamItem = {
|
||||||
|
@ -602,21 +614,71 @@
|
||||||
const addChild = (record: Record<string, any>) => {
|
const addChild = (record: Record<string, any>) => {
|
||||||
const children = record.children || [];
|
const children = record.children || [];
|
||||||
const newRecord = {
|
const newRecord = {
|
||||||
|
...documentDefaultParamItem,
|
||||||
id: new Date().getTime(),
|
id: new Date().getTime(),
|
||||||
parentId: record.id,
|
parentId: record.id,
|
||||||
rowIndex: children.length,
|
|
||||||
};
|
};
|
||||||
record.children = [...children, newRecord];
|
record.children = [...children, newRecord];
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加验证子项
|
// 添加验证子项
|
||||||
const addValidateChild = (record: Record<string, any>) => {
|
const addValidateChild = (record: Record<string, any>) => {
|
||||||
const children = record.children || [];
|
if (record.groupId) {
|
||||||
const newRecord = {
|
// 子项点击,找到父级
|
||||||
id: new Date().getTime(),
|
const parent = innerParams.value.document.data.find((item: any) => item.id === record.groupId);
|
||||||
parentId: record.id,
|
insertTreeByCurrentId(innerParams.value.document.data, record.id, {
|
||||||
rowIndex: children.length,
|
...documentDefaultParamItem,
|
||||||
};
|
id: new Date().getTime(),
|
||||||
record.children = [...children, newRecord];
|
groupId: parent ? parent.id : record.groupId,
|
||||||
|
});
|
||||||
|
if (parent) {
|
||||||
|
parent.rowSpan = parent.rowSpan ? parent.rowSpan + 1 : 2;
|
||||||
|
} else {
|
||||||
|
// 找到第一个子节点
|
||||||
|
const fisrtChildNode = findFirstByGroupId(innerParams.value.document.data, record.groupId);
|
||||||
|
if (fisrtChildNode) {
|
||||||
|
fisrtChildNode.rowSpan = fisrtChildNode.rowSpan ? fisrtChildNode.rowSpan + 1 : 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 父级点击,直接添加到末尾
|
||||||
|
insertTreeByCurrentId(innerParams.value.document.data, record.id, {
|
||||||
|
...documentDefaultParamItem,
|
||||||
|
id: new Date().getTime(),
|
||||||
|
groupId: record.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const documentSpanMethod = (data: {
|
||||||
|
record: TableData;
|
||||||
|
column: TableColumnData | TableOperationColumn;
|
||||||
|
rowIndex: number;
|
||||||
|
columnIndex: number;
|
||||||
|
}): { rowspan?: number; colspan?: number } | void => {
|
||||||
|
// groupId 是后端传过来的id,然后根据这个id去找到对应的子项
|
||||||
|
// 前端根据groupId 去过滤出rowspan的数量,然后返回
|
||||||
|
const { record, column } = data;
|
||||||
|
const currentColumn = column as TableColumnData;
|
||||||
|
if (record.rowSpan > 1) {
|
||||||
|
if (currentColumn.slotName === 'key') {
|
||||||
|
return {
|
||||||
|
rowspan: record.rowSpan,
|
||||||
|
colspan: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (currentColumn.slotName === 'operation') {
|
||||||
|
return {
|
||||||
|
rowspan: record.rowSpan,
|
||||||
|
colspan: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (currentColumn.slotName === 'mustContain') {
|
||||||
|
return {
|
||||||
|
rowspan: record.rowSpan,
|
||||||
|
colspan: 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { rowspan: record.rowSpan, colspan: 1 };
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -194,9 +194,11 @@
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #expand-icon="{ expanded }">
|
<template #expand-icon="{ expanded, record }">
|
||||||
<MsIcon v-if="!expanded" :size="8" type="icon-icon_right_outlined" class="text-[var(--color-text-4)]" />
|
<slot name="expand-icon" v-bind="{ expanded, record }">
|
||||||
<MsIcon v-else :size="8" class="text-[rgb(var(--primary-6))]" type="icon-icon_down_outlined" />
|
<MsIcon v-if="!expanded" :size="8" type="icon-icon_right_outlined" class="text-[var(--color-text-4)]" />
|
||||||
|
<MsIcon v-else :size="8" class="text-[rgb(var(--primary-6))]" type="icon-icon_down_outlined" />
|
||||||
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
<div
|
<div
|
||||||
|
@ -700,7 +702,7 @@
|
||||||
height: 16px;
|
height: 16px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: var(--color-text-n8) !important;
|
background: var(--color-text-n8);
|
||||||
}
|
}
|
||||||
:deep(.arco-table .arco-table-expand-btn:hover) {
|
:deep(.arco-table .arco-table-expand-btn:hover) {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
|
|
|
@ -166,6 +166,14 @@
|
||||||
loadColumn(props.tableKey);
|
loadColumn(props.tableKey);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
(value) => {
|
||||||
|
if (value) {
|
||||||
|
hasChange.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
||||||
drawer: 'Drawer',
|
drawer: 'Drawer',
|
||||||
newWindow: 'New Window',
|
newWindow: 'New Window',
|
||||||
header: 'Header Settings',
|
header: 'Header Settings',
|
||||||
resetDefault: 'Reset default',
|
resetDefault: 'Undo Changes',
|
||||||
nonSort: 'The above properties cannot be sorted',
|
nonSort: 'The above properties cannot be sorted',
|
||||||
tooltipContentDrawer: 'Drawer: open a new page as a drawer',
|
tooltipContentDrawer: 'Drawer: open a new page as a drawer',
|
||||||
tooltipContentWindow: 'New Window: open a new page with a new page',
|
tooltipContentWindow: 'New Window: open a new page with a new page',
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
||||||
drawer: '抽屉',
|
drawer: '抽屉',
|
||||||
newWindow: '新窗口',
|
newWindow: '新窗口',
|
||||||
header: '表头设置',
|
header: '表头设置',
|
||||||
resetDefault: '恢复默认',
|
resetDefault: '撤销修改',
|
||||||
nonSort: '以上属性不可排序',
|
nonSort: '以上属性不可排序',
|
||||||
tooltipContentDrawer: '抽屉:以抽屉形式打开新页面',
|
tooltipContentDrawer: '抽屉:以抽屉形式打开新页面',
|
||||||
tooltipContentWindow: '新窗口:以新开网页打开新页面',
|
tooltipContentWindow: '新窗口:以新开网页打开新页面',
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
interface TreeData {
|
||||||
|
id: number;
|
||||||
|
groupId?: number;
|
||||||
|
children?: TreeData[];
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function insertTreeByCurrentId(tree: TreeData[], currentId: number, newData: TreeData) {
|
||||||
|
const stack: Array<{ node: TreeData; parent: TreeData | null }> = tree.map((node) => ({ node, parent: null }));
|
||||||
|
|
||||||
|
while (stack.length > 0) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const { node, parent } = stack.pop()!;
|
||||||
|
|
||||||
|
if (parent && parent.children) {
|
||||||
|
const index = parent.children.findIndex((child) => child.id === currentId);
|
||||||
|
if (index !== -1) {
|
||||||
|
// 在目标节点后面插入新数据
|
||||||
|
parent.children.splice(index + 1, 0, newData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.children) {
|
||||||
|
node.children.forEach((child) => {
|
||||||
|
stack.push({ node: child, parent: node });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function insertTreeByGroupId(tree: TreeData[], currentId: number, newData: TreeData) {
|
||||||
|
const stack: Array<{ node: TreeData; parent: TreeData | null }> = tree.map((node) => ({ node, parent: null }));
|
||||||
|
|
||||||
|
while (stack.length > 0) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const { node, parent } = stack.pop()!;
|
||||||
|
|
||||||
|
if (parent && parent.children) {
|
||||||
|
const index = parent.children.findIndex((child) => child.groupId === currentId);
|
||||||
|
if (index !== -1) {
|
||||||
|
// 在目标节点后面插入新数据
|
||||||
|
parent.children.splice(index + 1, 0, newData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.children) {
|
||||||
|
node.children.forEach((child) => {
|
||||||
|
stack.push({ node: child, parent: node });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function findFirstByGroupId(tree: TreeData[], groupId: number): TreeData | null {
|
||||||
|
const queue: TreeData[] = [...tree];
|
||||||
|
while (queue.length > 0) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const node = queue.shift()!; // 取出队列的第一个元素
|
||||||
|
if (node.groupId === groupId) {
|
||||||
|
return node; // 如果匹配,返回当前节点
|
||||||
|
}
|
||||||
|
if (node.children) {
|
||||||
|
queue.push(...node.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
|
@ -1,5 +1,19 @@
|
||||||
<template>
|
<template>
|
||||||
<MsBaseTable v-bind="propsRes" :hoverable="false" no-disable is-simple-setting v-on="propsEvent">
|
<MsBaseTable
|
||||||
|
v-bind="propsRes"
|
||||||
|
:hoverable="false"
|
||||||
|
no-disable
|
||||||
|
is-simple-setting
|
||||||
|
:span-method="props.spanMethod"
|
||||||
|
v-on="propsEvent"
|
||||||
|
>
|
||||||
|
<!-- 展开行-->
|
||||||
|
<template #expand-icon="{ record }">
|
||||||
|
<div class="flex flex-row items-center gap-[2px] text-[var(--color-text-4)]">
|
||||||
|
<icon-branch class="scale-y-[-1]" />
|
||||||
|
<span v-if="record.children">{{ record.children.length }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<!-- 表格头 slot -->
|
<!-- 表格头 slot -->
|
||||||
<template #encodeTitle>
|
<template #encodeTitle>
|
||||||
<div class="flex items-center text-[var(--color-text-3)]">
|
<div class="flex items-center text-[var(--color-text-3)]">
|
||||||
|
@ -224,42 +238,49 @@
|
||||||
@change="() => addTableLine(rowIndex)"
|
@change="() => addTableLine(rowIndex)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #mustContain="{ record, columnConfig, rowIndex }">
|
<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]"
|
||||||
@change="() => addTableLine(rowIndex)"
|
@change="handleMustContainColChange(false)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #typeChecking="{ record, columnConfig }">
|
||||||
|
<a-checkbox
|
||||||
|
v-model:model-value="record[columnConfig.dataIndex as string]"
|
||||||
|
@change="handleTypeCheckingColChange(false)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #operation="{ record, rowIndex, columnConfig }">
|
<template #operation="{ record, rowIndex, columnConfig }">
|
||||||
<a-switch
|
<div class="flex flex-row items-center">
|
||||||
v-if="columnConfig.hasDisable"
|
<a-switch
|
||||||
v-model:model-value="record.disable"
|
v-if="columnConfig.hasDisable"
|
||||||
size="small"
|
v-model:model-value="record.disable"
|
||||||
type="line"
|
size="small"
|
||||||
class="mr-[8px]"
|
type="line"
|
||||||
@change="() => addTableLine(rowIndex)"
|
class="mr-[8px]"
|
||||||
/>
|
@change="(val) => addTableLine(val as number)"
|
||||||
<slot name="operationPre" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot>
|
/>
|
||||||
<MsTableMoreAction
|
<slot name="operationPre" :record="record" :row-index="rowIndex" :column-config="columnConfig"></slot>
|
||||||
v-if="columnConfig.moreAction"
|
<MsTableMoreAction
|
||||||
:list="getMoreActionList(columnConfig.moreAction, record)"
|
v-if="columnConfig.moreAction"
|
||||||
@select="(e) => handleMoreActionSelect(e, record)"
|
:list="getMoreActionList(columnConfig.moreAction, record)"
|
||||||
/>
|
@select="(e) => handleMoreActionSelect(e, record)"
|
||||||
<a-trigger v-if="columnConfig.format === RequestBodyFormat.FORM_DATA" trigger="click" position="br">
|
/>
|
||||||
<MsButton type="icon" class="mr-[8px]"><icon-more /></MsButton>
|
<a-trigger v-if="columnConfig.format === RequestBodyFormat.FORM_DATA" trigger="click" position="br">
|
||||||
<template #content>
|
<MsButton type="icon" class="mr-[8px]"><icon-more /></MsButton>
|
||||||
<div class="content-type-trigger-content">
|
<template #content>
|
||||||
<div class="mb-[8px] text-[var(--color-text-1)]">Content-Type</div>
|
<div class="content-type-trigger-content">
|
||||||
<a-select
|
<div class="mb-[8px] text-[var(--color-text-1)]">Content-Type</div>
|
||||||
v-model:model-value="record.contentType"
|
<a-select
|
||||||
:options="Object.values(RequestContentTypeEnum).map((e) => ({ label: e, value: e }))"
|
v-model:model-value="record.contentType"
|
||||||
allow-create
|
:options="Object.values(RequestContentTypeEnum).map((e) => ({ label: e, value: e }))"
|
||||||
@change="() => addTableLine(rowIndex)"
|
allow-create
|
||||||
/>
|
@change="(val) => addTableLine(val as number)"
|
||||||
</div>
|
/>
|
||||||
</template>
|
</div>
|
||||||
</a-trigger>
|
</template>
|
||||||
<div>
|
</a-trigger>
|
||||||
|
|
||||||
<icon-minus-circle
|
<icon-minus-circle
|
||||||
v-if="paramsLength > 1 && rowIndex !== paramsLength - 1"
|
v-if="paramsLength > 1 && rowIndex !== paramsLength - 1"
|
||||||
class="ml-[8px] cursor-pointer text-[var(--color-text-4)]"
|
class="ml-[8px] cursor-pointer text-[var(--color-text-4)]"
|
||||||
|
@ -273,13 +294,28 @@
|
||||||
<a-option v-for="item in columnConfig.options" :key="item.value">{{ t(item.label) }}</a-option>
|
<a-option v-for="item in columnConfig.options" :key="item.value">{{ t(item.label) }}</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</template>
|
</template>
|
||||||
<template #matchCondition="{ record, columnConfig, rowIndex }">
|
<template #matchCondition="{ record, columnConfig }">
|
||||||
<a-select v-model="record.condition" class="param-input" @change="() => addTableLine(rowIndex)">
|
<a-select v-model="record.condition" class="param-input">
|
||||||
<a-option v-for="item in columnConfig.options" :key="item.value">{{ t(item.label) }}</a-option>
|
<a-option v-for="item in columnConfig.options" :key="item.value">{{ t(item.label) }}</a-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</template>
|
</template>
|
||||||
<template #matchValue="{ record, rowIndex }">
|
<template #matchValue="{ record, rowIndex, columnConfig }">
|
||||||
<a-input v-model="record.matchValue" class="param-input" @change="() => addTableLine(rowIndex)" />
|
<a-tooltip
|
||||||
|
v-if="columnConfig.hasRequired"
|
||||||
|
:content="t(record.required ? 'apiTestDebug.paramRequired' : 'apiTestDebug.paramNotRequired')"
|
||||||
|
>
|
||||||
|
<MsButton
|
||||||
|
type="icon"
|
||||||
|
:class="[
|
||||||
|
record.required ? '!text-[rgb(var(--danger-5))]' : '!text-[var(--color-text-brand)]',
|
||||||
|
'!mr-[4px] !p-[4px]',
|
||||||
|
]"
|
||||||
|
@click="toggleRequired(record, rowIndex)"
|
||||||
|
>
|
||||||
|
<div>*</div>
|
||||||
|
</MsButton>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-input v-model="record.matchValue" class="param-input" />
|
||||||
</template>
|
</template>
|
||||||
<template #project="{ record, columnConfig, rowIndex }">
|
<template #project="{ record, columnConfig, rowIndex }">
|
||||||
<a-select
|
<a-select
|
||||||
|
@ -346,7 +382,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script async setup lang="ts">
|
<script async setup lang="ts">
|
||||||
import { cloneDeep } from 'lodash-es';
|
import { TableColumnData, TableData } from '@arco-design/web-vue';
|
||||||
|
import { cloneDeep, isEqual } from 'lodash-es';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||||
|
@ -366,6 +403,8 @@
|
||||||
|
|
||||||
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
import { RequestBodyFormat, RequestContentTypeEnum, RequestParamsType } from '@/enums/apiEnum';
|
||||||
import { SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum';
|
import { SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
|
||||||
|
import { TableOperationColumn } from '@arco-design/web-vue/es/table/interface';
|
||||||
// 异步加载组件
|
// 异步加载组件
|
||||||
const MsAddAttachment = defineAsyncComponent(() => import('@/components/business/ms-add-attachment/index.vue'));
|
const MsAddAttachment = defineAsyncComponent(() => import('@/components/business/ms-add-attachment/index.vue'));
|
||||||
const MsParamsInput = defineAsyncComponent(() => import('@/components/business/ms-params-input/index.vue'));
|
const MsParamsInput = defineAsyncComponent(() => import('@/components/business/ms-params-input/index.vue'));
|
||||||
|
@ -400,6 +439,12 @@
|
||||||
showSelectorAll?: boolean; // 是否显示全选
|
showSelectorAll?: boolean; // 是否显示全选
|
||||||
isSimpleSetting?: boolean; // 是否简单Column设置
|
isSimpleSetting?: boolean; // 是否简单Column设置
|
||||||
response?: string; // 响应内容
|
response?: string; // 响应内容
|
||||||
|
spanMethod?: (data: {
|
||||||
|
record: TableData;
|
||||||
|
column: TableColumnData | TableOperationColumn;
|
||||||
|
rowIndex: number;
|
||||||
|
columnIndex: number;
|
||||||
|
}) => { rowspan?: number; colspan?: number } | void;
|
||||||
uploadTempFileApi?: (...args) => Promise<any>; // 上传临时文件接口
|
uploadTempFileApi?: (...args) => Promise<any>; // 上传临时文件接口
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
|
@ -496,6 +541,69 @@
|
||||||
emit('change', propsRes.value.data);
|
emit('change', propsRes.value.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 断言-文档-Begin */
|
||||||
|
// 断言-文档-必须包含-全选
|
||||||
|
const mustIncludeAllChecked = ref(false);
|
||||||
|
const mustIncludeIndeterminate = ref(false);
|
||||||
|
const handleMustIncludeChange = (val: boolean) => {
|
||||||
|
mustIncludeAllChecked.value = val;
|
||||||
|
mustIncludeIndeterminate.value = false;
|
||||||
|
const { data } = propsRes.value;
|
||||||
|
data.forEach((e: any) => {
|
||||||
|
e.mustInclude = val;
|
||||||
|
});
|
||||||
|
propsRes.value.data = data;
|
||||||
|
emit('change', propsRes.value.data);
|
||||||
|
};
|
||||||
|
const handleMustContainColChange = (notEmit?: boolean) => {
|
||||||
|
const { data } = propsRes.value;
|
||||||
|
const checkedList = data.filter((e: any) => e.mustInclude).map((e: any) => e.id);
|
||||||
|
if (checkedList.length === data.length) {
|
||||||
|
mustIncludeAllChecked.value = true;
|
||||||
|
mustIncludeIndeterminate.value = false;
|
||||||
|
} else if (checkedList.length === 0) {
|
||||||
|
mustIncludeAllChecked.value = false;
|
||||||
|
mustIncludeIndeterminate.value = false;
|
||||||
|
} else {
|
||||||
|
mustIncludeAllChecked.value = false;
|
||||||
|
mustIncludeIndeterminate.value = true;
|
||||||
|
}
|
||||||
|
if (!notEmit) {
|
||||||
|
emit('change', propsRes.value.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const typeCheckingAllChecked = ref(false);
|
||||||
|
const typeCheckingIndeterminate = ref(false);
|
||||||
|
const handleTypeCheckingChange = (val: boolean) => {
|
||||||
|
typeCheckingAllChecked.value = val;
|
||||||
|
typeCheckingIndeterminate.value = false;
|
||||||
|
const { data } = propsRes.value;
|
||||||
|
data.forEach((e: any) => {
|
||||||
|
e.typeChecking = val;
|
||||||
|
});
|
||||||
|
propsRes.value.data = data;
|
||||||
|
emit('change', propsRes.value.data);
|
||||||
|
};
|
||||||
|
const handleTypeCheckingColChange = (notEmit?: boolean) => {
|
||||||
|
const { data } = propsRes.value;
|
||||||
|
const checkedList = data.filter((e: any) => e.typeChecking).map((e: any) => e.id);
|
||||||
|
if (checkedList.length === data.length) {
|
||||||
|
typeCheckingAllChecked.value = true;
|
||||||
|
typeCheckingIndeterminate.value = false;
|
||||||
|
} else if (checkedList.length === 0) {
|
||||||
|
typeCheckingAllChecked.value = false;
|
||||||
|
typeCheckingIndeterminate.value = false;
|
||||||
|
} else {
|
||||||
|
typeCheckingAllChecked.value = false;
|
||||||
|
typeCheckingIndeterminate.value = true;
|
||||||
|
}
|
||||||
|
if (!notEmit) {
|
||||||
|
emit('change', propsRes.value.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/** 断言-文档-end */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当表格输入框变化时,给参数表格添加一行数据行
|
* 当表格输入框变化时,给参数表格添加一行数据行
|
||||||
* @param val 输入值
|
* @param val 输入值
|
||||||
|
@ -513,6 +621,8 @@
|
||||||
} as any);
|
} as any);
|
||||||
emit('change', propsRes.value.data);
|
emit('change', propsRes.value.data);
|
||||||
}
|
}
|
||||||
|
handleMustContainColChange(true);
|
||||||
|
handleTypeCheckingColChange(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -667,30 +777,6 @@
|
||||||
addTableLine(rowIndex);
|
addTableLine(rowIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 断言-文档-Begin */
|
|
||||||
// 断言-文档-必须包含-全选
|
|
||||||
const mustIncludeList = ref([]);
|
|
||||||
const mustIncludeAllChecked = ref(false);
|
|
||||||
const mustIncludeIndeterminate = ref(false);
|
|
||||||
const handleMustIncludeChange = (val: boolean) => {
|
|
||||||
mustIncludeAllChecked.value = val;
|
|
||||||
mustIncludeIndeterminate.value = false;
|
|
||||||
const data = propsRes.value;
|
|
||||||
mustIncludeList.value = val ? data.map((e: any) => e.id) : [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// 断言-文档-类型校验-存储用户勾选的id
|
|
||||||
const typeCheckingList = ref([]);
|
|
||||||
const typeCheckingAllChecked = ref(false);
|
|
||||||
const typeCheckingIndeterminate = ref(false);
|
|
||||||
const handleTypeCheckingChange = (val: boolean) => {
|
|
||||||
typeCheckingAllChecked.value = val;
|
|
||||||
typeCheckingIndeterminate.value = false;
|
|
||||||
const data = propsRes.value;
|
|
||||||
typeCheckingList.value = val ? data.map((e: any) => e.id) : [];
|
|
||||||
};
|
|
||||||
/** 断言-文档-end */
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
addTableLine,
|
addTableLine,
|
||||||
});
|
});
|
||||||
|
@ -774,4 +860,7 @@
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
color: var(--color-text-1);
|
color: var(--color-text-1);
|
||||||
}
|
}
|
||||||
|
:deep(.arco-table-expand-btn) {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -188,57 +188,57 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {useRoute} from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import {Message} from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsCard from '@/components/pure/ms-card/index.vue';
|
import MsCard from '@/components/pure/ms-card/index.vue';
|
||||||
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
import MsFormCreate from '@/components/pure/ms-form-create/ms-form-create.vue';
|
||||||
import {FormItem, FormRuleItem} from '@/components/pure/ms-form-create/types';
|
import { FormItem, FormRuleItem } from '@/components/pure/ms-form-create/types';
|
||||||
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
import MsRichText from '@/components/pure/ms-rich-text/MsRichText.vue';
|
||||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||||
import MsFileList from "@/components/pure/ms-upload/fileList.vue";
|
import MsFileList from '@/components/pure/ms-upload/fileList.vue';
|
||||||
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
import MsUpload from '@/components/pure/ms-upload/index.vue';
|
||||||
import {MsFileItem} from '@/components/pure/ms-upload/types';
|
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||||
import RelateFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
import RelateFileDrawer from '@/components/business/ms-link-file/associatedFileDrawer.vue';
|
||||||
import TransferModal from '@/views/case-management/caseManagementFeature/components/tabContent/transferModal.vue';
|
import TransferModal from '@/views/case-management/caseManagementFeature/components/tabContent/transferModal.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
checkFileIsUpdateRequest,
|
checkFileIsUpdateRequest,
|
||||||
createOrUpdateBug,
|
createOrUpdateBug,
|
||||||
downloadFileRequest,
|
downloadFileRequest,
|
||||||
editorUploadFile,
|
editorUploadFile,
|
||||||
getAssociatedFileList,
|
getAssociatedFileList,
|
||||||
getBugDetail,
|
getBugDetail,
|
||||||
getTemplateById,
|
getTemplateById,
|
||||||
getTemplateOption,
|
getTemplateOption,
|
||||||
previewFile,
|
previewFile,
|
||||||
transferFileRequest,
|
transferFileRequest,
|
||||||
updateFile,
|
updateFile,
|
||||||
} from '@/api/modules/bug-management';
|
} from '@/api/modules/bug-management';
|
||||||
import {getModules, getModulesCount} from '@/api/modules/project-management/fileManagement';
|
import { getModules, getModulesCount } from '@/api/modules/project-management/fileManagement';
|
||||||
import {useI18n} from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useVisit from '@/hooks/useVisit';
|
import useVisit from '@/hooks/useVisit';
|
||||||
import router from '@/router';
|
import router from '@/router';
|
||||||
import {useAppStore} from '@/store';
|
import { useAppStore } from '@/store';
|
||||||
import {downloadByteFile} from '@/utils';
|
import { downloadByteFile } from '@/utils';
|
||||||
import {scrollIntoView} from '@/utils/dom';
|
import { scrollIntoView } from '@/utils/dom';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BugEditCustomField,
|
BugEditCustomField,
|
||||||
BugEditCustomFieldItem,
|
BugEditCustomFieldItem,
|
||||||
BugEditFormObject,
|
BugEditFormObject,
|
||||||
BugTemplateRequest
|
BugTemplateRequest,
|
||||||
} from '@/models/bug-management';
|
} from '@/models/bug-management';
|
||||||
import {AssociatedList, AttachFileInfo} from '@/models/caseManagement/featureCase';
|
import { AssociatedList, AttachFileInfo } from '@/models/caseManagement/featureCase';
|
||||||
import {TableQueryParams} from '@/models/common';
|
import { TableQueryParams } from '@/models/common';
|
||||||
import {SelectValue} from '@/models/projectManagement/menuManagement';
|
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||||
import {BugManagementRouteEnum} from '@/enums/routeEnum';
|
import { BugManagementRouteEnum } from '@/enums/routeEnum';
|
||||||
|
|
||||||
import {convertToFile} from '../case-management/caseManagementFeature/components/utils';
|
import { convertToFile } from '../case-management/caseManagementFeature/components/utils';
|
||||||
import {convertToFileByBug} from './utils';
|
import { convertToFileByBug } from './utils';
|
||||||
|
|
||||||
defineOptions({ name: 'BugEditPage' });
|
defineOptions({ name: 'BugEditPage' });
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
@ -356,9 +356,9 @@ defineOptions({ name: 'BugEditPage' });
|
||||||
const templateChange = async (v: SelectValue, request?: BugTemplateRequest) => {
|
const templateChange = async (v: SelectValue, request?: BugTemplateRequest) => {
|
||||||
if (v) {
|
if (v) {
|
||||||
try {
|
try {
|
||||||
let param = {projectId: appStore.currentProjectId, id: v}
|
let param = { projectId: appStore.currentProjectId, id: v };
|
||||||
if (request) {
|
if (request) {
|
||||||
param = {...param, ...request}
|
param = { ...param, ...request };
|
||||||
}
|
}
|
||||||
const res = await getTemplateById(param);
|
const res = await getTemplateById(param);
|
||||||
getFormRules(res.customFields);
|
getFormRules(res.customFields);
|
||||||
|
@ -555,7 +555,7 @@ defineOptions({ name: 'BugEditPage' });
|
||||||
// 复制, 只需返回初始状态
|
// 复制, 只需返回初始状态
|
||||||
await templateChange(templateId);
|
await templateChange(templateId);
|
||||||
} else {
|
} else {
|
||||||
await templateChange(templateId, {fromStatusId: res.status, platformBugKey: res.platformBugId})
|
await templateChange(templateId, { fromStatusId: res.status, platformBugKey: res.platformBugId });
|
||||||
}
|
}
|
||||||
if (attachments && attachments.length) {
|
if (attachments && attachments.length) {
|
||||||
attachmentsList.value = attachments;
|
attachmentsList.value = attachments;
|
||||||
|
|
|
@ -192,6 +192,7 @@
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.page {
|
.page {
|
||||||
transform: scale3d(1, 1, 1);
|
transform: scale3d(1, 1, 1);
|
||||||
|
padding-bottom: 180px;
|
||||||
.header {
|
.header {
|
||||||
padding: 24px 24px 0;
|
padding: 24px 24px 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue