feat(接口测试): 断言表格结果列支持筛选/排序
This commit is contained in:
parent
3d69fd433d
commit
eb847d43ab
|
@ -44,6 +44,23 @@
|
||||||
</div>
|
</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</template>
|
</template>
|
||||||
|
<template #columnFilter="{ column }">
|
||||||
|
<DefaultFilter
|
||||||
|
v-if="(column.filterConfig && column.filterConfig.options?.length) || column?.filterConfig?.remoteMethod"
|
||||||
|
v-model:checked-list="column.filterCheckedList"
|
||||||
|
class="ml-[4px]"
|
||||||
|
:options="column.filterConfig.options"
|
||||||
|
:data-index="column.dataIndex"
|
||||||
|
v-bind="column.filterConfig"
|
||||||
|
:filter="filterData"
|
||||||
|
@handle-confirm="(v) => handleFilterConfirm(v, column.dataIndex as string, column.isCustomParam || false)"
|
||||||
|
@click.stop="null"
|
||||||
|
>
|
||||||
|
<template #item="{ filterItem }">
|
||||||
|
<slot :name="column.filterConfig.filterSlotName" :filter-content="filterItem"> </slot>
|
||||||
|
</template>
|
||||||
|
</DefaultFilter>
|
||||||
|
</template>
|
||||||
<template
|
<template
|
||||||
v-for="item of props.columns.filter((e) => e.slotName !== undefined)"
|
v-for="item of props.columns.filter((e) => e.slotName !== undefined)"
|
||||||
:key="item.toString()"
|
:key="item.toString()"
|
||||||
|
@ -232,6 +249,7 @@
|
||||||
|
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||||
|
import DefaultFilter from '@/components/pure/ms-table/comp/defaultFilter.vue';
|
||||||
import type { MsTableColumnData, MsTableProps } from '@/components/pure/ms-table/type';
|
import type { MsTableColumnData, MsTableProps } from '@/components/pure/ms-table/type';
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
|
||||||
|
@ -322,6 +340,13 @@
|
||||||
): void;
|
): void;
|
||||||
(e: 'rowSelect', rowKeys: (string | number)[], _rowKey: string | number, record: TableData): void;
|
(e: 'rowSelect', rowKeys: (string | number)[], _rowKey: string | number, record: TableData): void;
|
||||||
(e: 'selectAll', checked: boolean): void;
|
(e: 'selectAll', checked: boolean): void;
|
||||||
|
(
|
||||||
|
e: 'filterChange',
|
||||||
|
dataIndex: string,
|
||||||
|
value: string[] | (string | number | boolean)[] | undefined,
|
||||||
|
isCustomParam: boolean
|
||||||
|
): void;
|
||||||
|
(e: 'sorterChange', value: { [key: string]: string }): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -330,6 +355,8 @@
|
||||||
const expandedKeys = defineModel<string[]>('expandedKeys', { default: [] });
|
const expandedKeys = defineModel<string[]>('expandedKeys', { default: [] });
|
||||||
const originalSelectedKeys = defineModel<(string | number)[]>('originalSelectedKeys', { default: [] });
|
const originalSelectedKeys = defineModel<(string | number)[]>('originalSelectedKeys', { default: [] });
|
||||||
|
|
||||||
|
const filterData = ref({});
|
||||||
|
|
||||||
async function initColumns() {
|
async function initColumns() {
|
||||||
if (props.showSetting && props.tableKey) {
|
if (props.showSetting && props.tableKey) {
|
||||||
await tableStore.initColumn(props.tableKey, props.columns);
|
await tableStore.initColumn(props.tableKey, props.columns);
|
||||||
|
@ -369,9 +396,20 @@
|
||||||
});
|
});
|
||||||
emit('change', propsRes.value.data);
|
emit('change', propsRes.value.data);
|
||||||
};
|
};
|
||||||
|
propsEvent.value.sorterChange = (value: { [key: string]: string }) => {
|
||||||
|
emit('sorterChange', value);
|
||||||
|
};
|
||||||
|
|
||||||
const dataLength = computed(() => propsRes.value.data.length);
|
const dataLength = computed(() => propsRes.value.data.length);
|
||||||
|
|
||||||
|
const handleFilterConfirm = (
|
||||||
|
value: string[] | (string | number | boolean)[] | undefined,
|
||||||
|
dataIndex: string,
|
||||||
|
isCustomParam: boolean
|
||||||
|
) => {
|
||||||
|
emit('filterChange', dataIndex, value, isCustomParam);
|
||||||
|
};
|
||||||
|
|
||||||
// 校验重复
|
// 校验重复
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
async function validRepeat(
|
async function validRepeat(
|
||||||
|
@ -565,6 +603,9 @@
|
||||||
padding: 5px 8px !important;
|
padding: 5px 8px !important;
|
||||||
line-height: 1.5715;
|
line-height: 1.5715;
|
||||||
}
|
}
|
||||||
|
.arco-table-cell-with-sorter {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.arco-table-td {
|
.arco-table-td {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
|
@ -114,24 +114,29 @@
|
||||||
@init-data="handleInitColumn"
|
@init-data="handleInitColumn"
|
||||||
@page-size-change="pageSizeChange"
|
@page-size-change="pageSizeChange"
|
||||||
/>
|
/>
|
||||||
<DefaultFilter
|
<slot
|
||||||
v-else-if="
|
v-else-if="
|
||||||
!props.notShowTableFilter &&
|
!props.notShowTableFilter &&
|
||||||
((item.filterConfig && item.filterConfig.options?.length) || item?.filterConfig?.remoteMethod)
|
((item.filterConfig && item.filterConfig.options?.length) || item?.filterConfig?.remoteMethod)
|
||||||
"
|
"
|
||||||
v-model:checked-list="item.filterCheckedList"
|
name="columnFilter"
|
||||||
class="ml-[4px]"
|
:column="item"
|
||||||
:options="item.filterConfig.options"
|
|
||||||
:data-index="item.dataIndex"
|
|
||||||
v-bind="item.filterConfig"
|
|
||||||
:filter="filterData"
|
|
||||||
@handle-confirm="(v) => handleFilterConfirm(v, item.dataIndex as string, item.isCustomParam || false)"
|
|
||||||
@click.stop="null"
|
|
||||||
>
|
>
|
||||||
<template #item="{ filterItem }">
|
<DefaultFilter
|
||||||
<slot :name="item.filterConfig.filterSlotName" :filter-content="filterItem"> </slot>
|
v-model:checked-list="item.filterCheckedList"
|
||||||
</template>
|
class="ml-[4px]"
|
||||||
</DefaultFilter>
|
:options="item.filterConfig.options"
|
||||||
|
:data-index="item.dataIndex"
|
||||||
|
v-bind="item.filterConfig"
|
||||||
|
:filter="filterData"
|
||||||
|
@handle-confirm="(v) => handleFilterConfirm(v, item.dataIndex as string, item.isCustomParam || false)"
|
||||||
|
@click.stop="null"
|
||||||
|
>
|
||||||
|
<template #item="{ filterItem }">
|
||||||
|
<slot :name="item.filterConfig.filterSlotName" :filter-content="filterItem"> </slot>
|
||||||
|
</template>
|
||||||
|
</DefaultFilter>
|
||||||
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #cell="{ column, record, rowIndex }">
|
<template #cell="{ column, record, rowIndex }">
|
||||||
|
|
|
@ -7,6 +7,7 @@ export enum FilterSlotNameEnum {
|
||||||
CASE_MANAGEMENT_BUG_STATE = 'CASE_MANAGEMENT_BUG_STATE', // 缺陷状态
|
CASE_MANAGEMENT_BUG_STATE = 'CASE_MANAGEMENT_BUG_STATE', // 缺陷状态
|
||||||
API_TEST_API_REQUEST_METHODS = 'API_TEST_API_REQUEST_METHODS', // 接口测试请求方式
|
API_TEST_API_REQUEST_METHODS = 'API_TEST_API_REQUEST_METHODS', // 接口测试请求方式
|
||||||
API_TEST_API_REQUEST_API_STATUS = 'API_TEST_API_REQUEST_API_STATUS', // 接口测试接口状态
|
API_TEST_API_REQUEST_API_STATUS = 'API_TEST_API_REQUEST_API_STATUS', // 接口测试接口状态
|
||||||
|
API_TEST_API_RESPONSE_ASSERTION_STATUS = 'API_TEST_API_RESPONSE_ASSERTION_STATUS', // 接口测试-响应断言状态
|
||||||
TEST_PLAN_REPORT_EXEC_STATUS = 'TEST_PLAN_REPORT_EXEC_STATUS',
|
TEST_PLAN_REPORT_EXEC_STATUS = 'TEST_PLAN_REPORT_EXEC_STATUS',
|
||||||
PROJECT_MANAGEMENT_COMMON_SCRIPT = 'PROJECT_MANAGEMENT_COMMON_SCRIPT', // 项目管理公共脚本脚本状态
|
PROJECT_MANAGEMENT_COMMON_SCRIPT = 'PROJECT_MANAGEMENT_COMMON_SCRIPT', // 项目管理公共脚本脚本状态
|
||||||
GLOBAL_TASK_CENTER_API_CASE_STATUS = 'GLOBAL_TASK_CENTER_API_CASE_STATUS', // 任务中心执行状态
|
GLOBAL_TASK_CENTER_API_CASE_STATUS = 'GLOBAL_TASK_CENTER_API_CASE_STATUS', // 任务中心执行状态
|
||||||
|
|
|
@ -294,7 +294,7 @@ export function filterTree<T>(
|
||||||
const node = (tree as TreeNode<T>[])[i];
|
const node = (tree as TreeNode<T>[])[i];
|
||||||
// 如果节点满足过滤条件,则保留该节点,并递归过滤子节点
|
// 如果节点满足过滤条件,则保留该节点,并递归过滤子节点
|
||||||
if (filterFn(node, i, parentNode)) {
|
if (filterFn(node, i, parentNode)) {
|
||||||
const newNode = cloneDeep(node);
|
const newNode = cloneDeep({ ...node, [customChildrenKey]: [] });
|
||||||
if (node[customChildrenKey] && node[customChildrenKey].length > 0) {
|
if (node[customChildrenKey] && node[customChildrenKey].length > 0) {
|
||||||
// 递归过滤子节点,并将过滤后的子节点添加到当前节点中
|
// 递归过滤子节点,并将过滤后的子节点添加到当前节点中
|
||||||
newNode[customChildrenKey] = filterTree(node[customChildrenKey], filterFn, customChildrenKey, node);
|
newNode[customChildrenKey] = filterTree(node[customChildrenKey], filterFn, customChildrenKey, node);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<a-scrollbar class="h-full overflow-y-auto">
|
<a-scrollbar class="h-full overflow-y-auto">
|
||||||
<MsFormTable
|
<MsFormTable
|
||||||
:data="props.requestResult?.responseResult.assertions"
|
:data="tableData"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:selectable="false"
|
:selectable="false"
|
||||||
:scroll="props.scroll"
|
:scroll="props.scroll"
|
||||||
|
@filter-change="handleFilterChange"
|
||||||
|
@sorter-change="handleSortChange"
|
||||||
>
|
>
|
||||||
<template #assertionItem="{ record }">
|
<template #assertionItem="{ record }">
|
||||||
<a-tooltip :content="record.name">
|
<a-tooltip :content="record.name">
|
||||||
|
@ -33,6 +35,11 @@
|
||||||
{{ record.pass === true ? t('common.success') : t('common.fail') }}
|
{{ record.pass === true ? t('common.success') : t('common.fail') }}
|
||||||
</MsTag>
|
</MsTag>
|
||||||
</template>
|
</template>
|
||||||
|
<template #[FilterSlotNameEnum.API_TEST_API_RESPONSE_ASSERTION_STATUS]="{ filterContent }">
|
||||||
|
<MsTag :type="filterContent.value === true ? 'success' : 'danger'" theme="light">
|
||||||
|
{{ filterContent.value === true ? t('common.success') : t('common.fail') }}
|
||||||
|
</MsTag>
|
||||||
|
</template>
|
||||||
</MsFormTable>
|
</MsFormTable>
|
||||||
</a-scrollbar>
|
</a-scrollbar>
|
||||||
</template>
|
</template>
|
||||||
|
@ -47,6 +54,7 @@
|
||||||
|
|
||||||
import { RequestResult, ResponseAssertionTableItem } from '@/models/apiTest/common';
|
import { RequestResult, ResponseAssertionTableItem } from '@/models/apiTest/common';
|
||||||
import { FullResponseAssertionType } from '@/enums/apiEnum';
|
import { FullResponseAssertionType } from '@/enums/apiEnum';
|
||||||
|
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
|
||||||
|
|
||||||
import { responseAssertionTypeMap } from '@/views/api-test/components/config';
|
import { responseAssertionTypeMap } from '@/views/api-test/components/config';
|
||||||
|
|
||||||
|
@ -94,6 +102,23 @@
|
||||||
title: 'apiTestDebug.status',
|
title: 'apiTestDebug.status',
|
||||||
dataIndex: 'pass',
|
dataIndex: 'pass',
|
||||||
slotName: 'status',
|
slotName: 'status',
|
||||||
|
sortable: {
|
||||||
|
sortDirections: ['ascend', 'descend'],
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
filterConfig: {
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
label: t('common.success'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
label: t('common.fail'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
filterSlotName: FilterSlotNameEnum.API_TEST_API_RESPONSE_ASSERTION_STATUS,
|
||||||
|
},
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -105,6 +130,25 @@
|
||||||
width: 300,
|
width: 300,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
const tableData = ref(props.requestResult?.responseResult.assertions);
|
||||||
|
|
||||||
|
function handleFilterChange(dataIndex: string, value: string[] | (string | number | boolean)[] | undefined) {
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
tableData.value = props.requestResult?.responseResult.assertions.filter((item) => {
|
||||||
|
return (value as boolean[]).includes(item.pass);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
tableData.value = props.requestResult?.responseResult.assertions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSortChange(sorter: { [key: string]: string }) {
|
||||||
|
const dataIndex = Object.keys(sorter)[0] as keyof ResponseAssertionTableItem;
|
||||||
|
tableData.value = tableData.value?.sort((a, b) => {
|
||||||
|
const sortResult = a[dataIndex] > b[dataIndex] ? -1 : 1;
|
||||||
|
return sorter[dataIndex] === 'asc' ? sortResult : -sortResult;
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
Loading…
Reference in New Issue