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