diff --git a/ui/src/components/COMPONENT_README.md b/ui/src/components/COMPONENT_README.md index a99af55c9d1..603326e16d4 100644 --- a/ui/src/components/COMPONENT_README.md +++ b/ui/src/components/COMPONENT_README.md @@ -359,6 +359,12 @@ Dialog、Drawer、Popover、嵌套区域等其他大、小表格均禁止开启 多选“全部”只操作可用选项,保留已选禁用项;无草稿选择时仍通过“重置”清空。 过长的扁平选项文案省略,悬停查看完整文案。 +多选模式可通过 `filterable` 开启选项搜索,默认关闭,其他模式不受影响。搜索按 `label` 在前端 +进行不区分大小写的包含匹配,忽略关键词首尾空格,不请求接口、不提交筛选条件。 +搜索框固定在滚动区上方,每次打开清空关键词并回填已生效的勾选;无匹配时展示空状态。 +搜索开启后,“全部”仅操作当前匹配的可用选项,保留隐藏的勾选项和已选禁用项; +确定提交完整草稿,重置清空所有勾选,页面的后台查询参数保持原有约定。 + 级联默认配置为 `{ multiple: true, checkStrictly: true, emitPath: false, showPrefix: false }`,与 v2 文档标签筛选一致: 父子节点独立选择,隐藏节点前的选择框。静态多选时,组件保留面板的原始勾选, 对外将选中的父组递归展开为可用叶子节点并去重;页面直接使用回写值,不再自行转换父组。 diff --git a/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue b/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue index af91af114eb..5006859ba5e 100644 --- a/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue +++ b/ui/src/components/global/mk-table/mk-table-filter/TableFilterMultiple.vue @@ -9,8 +9,9 @@ const props = withDefaults( modelValue: CheckboxValueType[] options: TableFilterOption[] width?: string | number + filterable?: boolean }>(), - { width: 192 }, + { width: 192, filterable: false }, ) const emit = defineEmits<{ select: [value: CheckboxValueType[]]; open: [] }>() defineSlots<{ default(): unknown }>() @@ -18,18 +19,27 @@ defineSlots<{ default(): unknown }>() // 打开时回填草稿,确认或重置后提交。 const visible = ref(false) const pendingValues = ref([]) -const allOptionValues = computed(() => props.options.filter((option) => !option.disabled).map(({ value }) => value)) +const searchKeyword = ref('') +const filteredOptions = computed(() => { + const keyword = searchKeyword.value.trim().toLowerCase() + return props.filterable && keyword ? props.options.filter((option) => option.label.toLowerCase().includes(keyword)) : props.options +}) +const allOptionValues = computed(() => filteredOptions.value.filter((option) => !option.disabled).map(({ value }) => value)) const allSelected = computed(() => allOptionValues.value.length > 0 && allOptionValues.value.every((value) => pendingValues.value.includes(value))) const selectionIndeterminate = computed(() => allOptionValues.value.some((value) => pendingValues.value.includes(value)) && !allSelected.value) function handleOpen() { + searchKeyword.value = '' pendingValues.value = [...props.modelValue] emit('open') } function handleSelectAllChange(checked: CheckboxValueType) { - const disabledValues = pendingValues.value.filter((value) => props.options.some((option) => option.value === value && option.disabled)) - pendingValues.value = checked ? [...disabledValues, ...allOptionValues.value] : disabledValues + // 搜索时保留隐藏的勾选项;未开启搜索时沿用原有全选规则。 + const retainedValues = pendingValues.value.filter((value) => + props.filterable ? !allOptionValues.value.includes(value) : props.options.some((option) => option.value === value && option.disabled), + ) + pendingValues.value = checked ? [...new Set([...retainedValues, ...allOptionValues.value])] : retainedValues } function handleReset() { @@ -47,16 +57,31 @@ function handleConfirm() {