feat: 修改table过滤筛选样式和新增过滤筛选自定义内容(还未统一替换完)_测试计划

This commit is contained in:
xinxin.wu 2024-05-11 10:47:19 +08:00 committed by Craftsman
parent 725f46d0f0
commit a3394c7a24
8 changed files with 129 additions and 93 deletions

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 3C2 2.44772 2.44772 2 3 2H13C13.5523 2 14 2.44772 14 3V4.78597L9.75 7.28597V14H6.25V7.28597L2 4.78597V3ZM13 3H3V4.21403L7.25 6.71403V13H8.75V6.71403L13 4.21403V3Z" fill="#783887"/>
</svg>

After

Width:  |  Height:  |  Size: 296 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 3C2 2.44772 2.44772 2 3 2H13C13.5523 2 14 2.44772 14 3V4.78597L9.75 7.28597V14H6.25V7.28597L2 4.78597V3ZM13 3H3V4.21403L7.25 6.71403V13H8.75V6.71403L13 4.21403V3Z" fill="#7D7D7F"/>
</svg>

After

Width:  |  Height:  |  Size: 296 B

View File

@ -66,7 +66,9 @@
:sortable="item.sortable" :sortable="item.sortable"
:filterable="item.filterable" :filterable="item.filterable"
:cell-class="item.cellClass" :cell-class="item.cellClass"
:header-cell-class="item.headerCellClass" :header-cell-class="`${
item.headerCellClass || (item.filterConfig && isHeighten) ? 'header-cell-filter' : ''
}`"
:body-cell-class="item.bodyCellClass" :body-cell-class="item.bodyCellClass"
:summary-cell-class="item.summaryCellClass" :summary-cell-class="item.summaryCellClass"
:cell-style="item.cellStyle" :cell-style="item.cellStyle"
@ -80,7 +82,13 @@
<template #title> <template #title>
<div :class="{ 'flex w-full flex-row flex-nowrap items-center gap-[4px]': !item.align }"> <div :class="{ 'flex w-full flex-row flex-nowrap items-center gap-[4px]': !item.align }">
<slot :name="item.titleSlotName" :column-config="item"> <slot :name="item.titleSlotName" :column-config="item">
<div v-if="item.title" class="text-[var(--color-text-3)]">{{ t(item.title as string) }}</div> <div
v-if="item.title"
:class="`${
item.filterConfig && isHeighten ? 'text-[rgb(var(--primary-5))]' : 'text-[var(--color-text-3)]'
} pl-1`"
>{{ t(item.title as string) }}</div
>
</slot> </slot>
<columnSelectorIcon <columnSelectorIcon
v-if=" v-if="
@ -92,22 +100,18 @@
@show-setting="handleShowSetting" @show-setting="handleShowSetting"
@init-data="handleInitColumn" @init-data="handleInitColumn"
/> />
<slot v-else-if="item.filterConfig" :name="item.filterConfig.filterSlotName"> <DefaultFilter
<!-- <DefaultFilter v-else-if="item.filterConfig"
class="ml-[4px]" class="ml-[4px]"
:options="item.filterConfig.options" :options="item.filterConfig.options"
@handle-confirm="(v) => handleFilterConfirm(v, item.dataIndex as string, item.isCustomParam || false)" @handle-confirm="(v) => handleFilterConfirm(v, item.dataIndex as string, item.isCustomParam || false)"
/> --> @show="showFilter(true)"
<!-- TODO 待办 过滤选项不生效 --> @hide="showFilter(false)"
<!-- <TableFilter
v-bind="item.filterConfig"
@handle-confirm="(v) => handleFilterConfirm(v, item.dataIndex as string,item.isCustomParam || false)"
> >
<template #item="{ item: itemValue, index }"> <template #item="{ filterItem }">
<slot name="filter-content" :item="itemValue" :index="index"> </slot> <slot :name="item.filterConfig.filterSlotName" :filter-content="filterItem"> </slot>
</template> </template>
</TableFilter> --> </DefaultFilter>
</slot>
</div> </div>
</template> </template>
<template #cell="{ column, record, rowIndex }"> <template #cell="{ column, record, rowIndex }">
@ -280,9 +284,7 @@
import BatchAction from './batchAction.vue'; import BatchAction from './batchAction.vue';
import ColumnSelector from './columnSelector.vue'; import ColumnSelector from './columnSelector.vue';
import columnSelectorIcon from './columnSelectorIcon.vue'; import columnSelectorIcon from './columnSelectorIcon.vue';
// TODO import DefaultFilter from './comp/defaultFilter.vue';
// import DefaultFilter from './comp/defaultFilter.vue';
// import TableFilter from './comp/tableFilter.vue';
import SelectALL from './select-all.vue'; import SelectALL from './select-all.vue';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
@ -628,15 +630,20 @@
columnSelectorVisible.value = true; columnSelectorVisible.value = true;
}; };
// const handleFilterConfirm = (value: (string | number)[], dataIndex: string, isCustomParam: boolean) => { const handleFilterConfirm = (value: (string | number)[], dataIndex: string, isCustomParam: boolean) => {
// emit('filterChange', dataIndex, value, isCustomParam); emit('filterChange', dataIndex, value, isCustomParam);
// }; };
onMounted(async () => { onMounted(async () => {
await initColumn(); await initColumn();
batchLeft.value = getBatchLeft(); batchLeft.value = getBatchLeft();
}); });
const isHeighten = ref<boolean>(false);
function showFilter(visible: boolean) {
isHeighten.value = visible;
}
watch( watch(
() => props.columns, () => props.columns,
() => { () => {
@ -809,6 +816,20 @@
} }
} }
} }
:deep(.header-cell-filter) {
.arco-table-cell-with-filter {
float: left;
border-radius: 4px;
.arco-table-th-title {
border-radius: 4px;
color: rgb(var(--primary-5));
background: rgb(var(--primary-1)) content-box;
.filter-icon {
color: rgb(var(--primary-5)) !important;
}
}
}
}
</style> </style>
<style lang="less"> <style lang="less">

View File

@ -1,24 +1,36 @@
<template> <template>
<a-trigger v-model:popup-visible="visible" trigger="click"> <a-trigger v-model:popup-visible="visible" trigger="click">
<a-button type="text" @click="visible = true"> <span class="cursor-pointer pr-[2px]" @click="visible = true">
<template #icon> <svg-icon
<icon-filter class="text-[var(--color-text-4)]" /> width="16px"
</template> height="16px"
</a-button> :name="visible ? 'filter-icon-color' : 'filter-icon'"
class="text-[12px] font-medium text-[rgb(var(--danger-6))]"
/>
</span>
<template #content> <template #content>
<div class="arco-table-filters-content"> <div class="arco-table-filters-content">
<div class="arco-table-filters-content-list"> <div class="arco-table-filters-content-list">
<div class="max-h-[300px] overflow-y-auto px-[12px] py-[4px]"> <div class="max-h-[300px] overflow-y-auto px-[12px] py-[4px]">
<a-checkbox-group v-if="props.multiple" v-model="checkedList" size="mini" direction="vertical"> <a-checkbox-group v-model="checkedList" size="mini" direction="vertical">
<a-checkbox v-for="item in props.options" :key="item.value" :value="item.value"> <a-checkbox
{{ item.label }} v-for="(item, index) of props.options"
:key="item[props.valueKey || 'value']"
:value="item[props.valueKey || 'value']"
>
<a-tooltip
:content="item[props.labelKey || 'label']"
:mouse-enter-delay="300"
:disabled="!item[props.labelKey || 'label']"
>
<div class="one-line-text max-w-[120px]">
<slot name="item" :filter-item="item" :index="index">
<div class="one-line-text max-w-[120px]">{{ item[props.labelKey || 'label'] }}</div>
</slot>
</div>
</a-tooltip>
</a-checkbox> </a-checkbox>
</a-checkbox-group> </a-checkbox-group>
<a-radio-group v-else v-model="checkedValue" size="mini" direction="vertical">
<a-radio v-for="item in props.options" :key="item.value" :value="item.value">
{{ item.label }}
</a-radio>
</a-radio-group>
</div> </div>
<div class="arco-table-filters-bottom"> <div class="arco-table-filters-bottom">
<a-button size="mini" type="secondary" @click="handleFilterReset"> <a-button size="mini" type="secondary" @click="handleFilterReset">
@ -38,9 +50,14 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
const { t } = useI18n(); const { t } = useI18n();
export interface FilterListItem {
[key: string]: any;
}
const props = defineProps<{ const props = defineProps<{
multiple: boolean; options?: FilterListItem[];
options?: { label: string; value: string | number }[]; valueKey?: string;
labelKey?: string;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'handleConfirm', value: (string | number)[]): void; (e: 'handleConfirm', value: (string | number)[]): void;
@ -49,24 +66,15 @@
const visible = ref(false); const visible = ref(false);
const checkedList = ref<(string | number)[]>([]); const checkedList = ref<(string | number)[]>([]);
const checkedValue = ref<string | number>('');
const handleFilterReset = () => { const handleFilterReset = () => {
if (props.multiple) {
checkedList.value = []; checkedList.value = [];
} else {
checkedValue.value = '';
}
emit('handleConfirm', []); emit('handleConfirm', []);
visible.value = false; visible.value = false;
}; };
const handleFilterSubmit = () => { const handleFilterSubmit = () => {
if (props.multiple) {
emit('handleConfirm', checkedList.value); emit('handleConfirm', checkedList.value);
} else {
emit('handleConfirm', checkedValue.value ? [checkedValue.value] : []);
}
visible.value = false; visible.value = false;
}; };
</script> </script>

View File

@ -1,5 +1,6 @@
import type { TableQueryParams } from '@/models/common'; import type { TableQueryParams } from '@/models/common';
import { ColumnEditTypeEnum, SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum'; import { ColumnEditTypeEnum, SelectAllEnum, TableKeyEnum } from '@/enums/tableEnum';
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import type { TableChangeExtra, TableColumnData, TableData, TableDraggable } from '@arco-design/web-vue'; import type { TableChangeExtra, TableColumnData, TableData, TableDraggable } from '@arco-design/web-vue';
@ -15,13 +16,10 @@ export interface MsPaginationI {
} }
export interface MsTableColumnFilterConfig { export interface MsTableColumnFilterConfig {
filterSlotName?: string; // 筛选组件的slotName filterSlotName?: FilterSlotNameEnum; // 筛选组件的slotName @desc 定义枚举是为了table组件内的插槽的filterSlotName 可以精确的让外部组件使用的时候可以拿到插槽作用域的值
multiple?: boolean; // 是否多选 options?: Record<string, any>[]; // 筛选数据
// 筛选数据 valueKey?: string;
options?: { labelKey?: string;
label: string;
value: string;
}[];
} }
export interface MsTableColumnData extends TableColumnData { export interface MsTableColumnData extends TableColumnData {
@ -51,6 +49,8 @@ export interface MsTableColumnData extends TableColumnData {
columnTitle?: string; columnTitle?: string;
// 是否是自定义字段 // 是否是自定义字段
isCustomParam?: boolean; isCustomParam?: boolean;
// 插槽表格过滤筛选数据item
filterItem?: any;
// 自定义属性 // 自定义属性
[key: string]: any; [key: string]: any;
} }

View File

@ -0,0 +1,5 @@
export enum FilterSlotNameEnum {
TEST_PLAN_STATUS_FILTER = 'TEST_PLAN_STATUS_FILTER',
}
export default {};

View File

@ -96,40 +96,9 @@
</a-tooltip></div </a-tooltip></div
> >
</template> </template>
<template #statusFilter="{ columnConfig }"> <template #[FilterSlotNameEnum.TEST_PLAN_STATUS_FILTER]="{ filterContent }">
<a-trigger v-model:popup-visible="statusFilterVisible" trigger="click" @popup-visible-change="handleFilterHidden"> <statusTag :status="filterContent.value" />
<a-button type="text" class="arco-btn-text--secondary" @click="statusFilterVisible = true">
{{ t(columnConfig.title as string) }}
<icon-down :class="statusFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
</a-button>
<template #content>
<div class="arco-table-filters-content">
<div class="flex items-center justify-center px-[6px] py-[2px]">
<a-checkbox-group v-model:model-value="statusFilters" direction="vertical" size="small">
<a-checkbox v-for="key of Object.keys(planStatusMap)" :key="key" :value="key">
<a-tag
:color="planStatusMap[key as planStatusType].color"
:class="[planStatusMap[key as planStatusType].class, 'px-[4px]']"
size="small"
>
{{ t(planStatusMap[key as planStatusType].label) }}
</a-tag>
</a-checkbox>
</a-checkbox-group>
</div>
<div class="filter-button">
<a-button size="mini" class="mr-[8px]" @click="resetStatusFilter">
{{ t('common.reset') }}
</a-button>
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
{{ t('system.orgTemplate.confirm') }}
</a-button>
</div>
</div>
</template> </template>
</a-trigger>
</template>
<template #status="{ record }"> <template #status="{ record }">
<statusTag :status="record.status" /> <statusTag :status="record.status" />
</template> </template>
@ -298,9 +267,10 @@
import type { planStatusType, TestPlanItem } from '@/models/testPlan/testPlan'; import type { planStatusType, TestPlanItem } from '@/models/testPlan/testPlan';
import { TestPlanRouteEnum } from '@/enums/routeEnum'; import { TestPlanRouteEnum } from '@/enums/routeEnum';
import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum'; import { ColumnEditTypeEnum, TableKeyEnum } from '@/enums/tableEnum';
import { FilterSlotNameEnum } from '@/enums/tableFilterEnum';
import { testPlanTypeEnum } from '@/enums/testPlanEnum'; import { testPlanTypeEnum } from '@/enums/testPlanEnum';
import { planStatusMap } from '../config'; import { planStatusOptions } from '../config';
const tableStore = useTableStore(); const tableStore = useTableStore();
const appStore = useAppStore(); const appStore = useAppStore();
@ -358,7 +328,10 @@
title: 'testPlan.testPlanIndex.executionResult', title: 'testPlan.testPlanIndex.executionResult',
dataIndex: 'status', dataIndex: 'status',
slotName: 'status', slotName: 'status',
titleSlotName: 'statusFilter', filterConfig: {
options: planStatusOptions,
filterSlotName: FilterSlotNameEnum.TEST_PLAN_STATUS_FILTER,
},
showInTable: true, showInTable: true,
showDrag: true, showDrag: true,
width: 150, width: 150,
@ -610,7 +583,6 @@
selectAll: !!batchParams.value?.selectAll, selectAll: !!batchParams.value?.selectAll,
selectIds: batchParams.value.selectedIds || [], selectIds: batchParams.value.selectedIds || [],
keyword: keyword.value, keyword: keyword.value,
filter: {},
condition: { condition: {
keyword: keyword.value, keyword: keyword.value,
}, },

View File

@ -1,5 +1,9 @@
import { useI18n } from '@/hooks/useI18n';
import type { planStatusType } from '@/models/testPlan/testPlan'; import type { planStatusType } from '@/models/testPlan/testPlan';
const { t } = useI18n();
export type PlanStatusMap = Record< export type PlanStatusMap = Record<
planStatusType, planStatusType,
{ {
@ -8,6 +12,7 @@ export type PlanStatusMap = Record<
class: string; class: string;
} }
>; >;
export const planStatusMap: PlanStatusMap = { export const planStatusMap: PlanStatusMap = {
PREPARED: { PREPARED: {
label: 'caseManagement.caseReview.unStart', label: 'caseManagement.caseReview.unStart',
@ -30,3 +35,22 @@ export const planStatusMap: PlanStatusMap = {
class: '!text-[var(--color-text-4)]', class: '!text-[var(--color-text-4)]',
}, },
}; };
export const planStatusOptions: { value: planStatusType; label: string }[] = [
{
value: 'PREPARED',
label: t('caseManagement.caseReview.unStart'),
},
{
value: 'UNDERWAY',
label: t('caseManagement.caseReview.going'),
},
{
value: 'COMPLETED',
label: t('caseManagement.caseReview.unStart'),
},
{
value: 'ARCHIVED',
label: t('caseManagement.caseReview.going'),
},
];