From 5a329b60d4bc054e2480040a95aab71335dcb768 Mon Sep 17 00:00:00 2001 From: BobLiu Date: Tue, 14 Oct 2025 01:03:37 +0800 Subject: [PATCH] feat(CharList): set unavailable tags as dimmed when filtering by operator class to visually de-emphasize unrelated branches --- src/components/Checkbox.vue | 6 ++++ src/components/FilterRow.vue | 3 ++ src/widgets/CharList/index.vue | 55 ++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/components/Checkbox.vue b/src/components/Checkbox.vue index a5c5d3a2..392d9d36 100644 --- a/src/components/Checkbox.vue +++ b/src/components/Checkbox.vue @@ -6,9 +6,11 @@ const props = withDefaults( modelValue?: boolean; noWidth?: boolean; value?: string; + dimmed?: boolean; }>(), { noWidth: false, + dimmed: false, }, ); const emit = defineEmits<{ @@ -38,6 +40,7 @@ const isSelected = computed({ :class="{ selected: isSelected, 'no-width': noWidth, + dimmed, }" class="checkbox-container" @click=" @@ -75,4 +78,7 @@ const isSelected = computed({ .no-width { width: initial; } +.dimmed { + opacity: 0.45; +} diff --git a/src/components/FilterRow.vue b/src/components/FilterRow.vue index fd1168e9..15c75282 100644 --- a/src/components/FilterRow.vue +++ b/src/components/FilterRow.vue @@ -12,9 +12,11 @@ const props = withDefaults( noWidth?: boolean; someSelected?: boolean; modelValue?: Record; + dimmedLabels?: Record; }>(), { modelValue: () => ({}), + dimmedLabels: () => ({}), }, ); const emit = defineEmits<{ @@ -87,6 +89,7 @@ const removeAll = () => { :key="label" :value="label" :no-width="noWidth" + :dimmed="dimmedLabels?.[label]" > {{ label }} diff --git a/src/widgets/CharList/index.vue b/src/widgets/CharList/index.vue index 5a29e16f..4b639ebf 100644 --- a/src/widgets/CharList/index.vue +++ b/src/widgets/CharList/index.vue @@ -109,6 +109,10 @@ const currDataTypes: Ref> = ref({ const displayModes = ref(["表格", "半身像", "头像"]); const currDisplayMode = ref("表格"); +const dimmedMaps: Record[][] = reactive( + props.filters.map((fg) => fg.filter.map(() => ({}))), +); + const toggleCollapse = (index: number) => { expanded.value[index] = !expanded.value[index]; Cookies.set("opFilterExpandState", JSON.stringify(expanded.value), { @@ -246,6 +250,56 @@ const oridata = computed(() => { } return result; }); + +function computeDimmedMaps() { + for (let fi = 0; fi < props.filters.length; fi++) { + const fg = props.filters[fi]; + for (let fj = 0; fj < fg.filter.length; fj++) { + const f = fg.filter[fj]; + const labels = flat(f.cbt); + const map: Record = {}; + + // 创建 states 副本 + const tempStates = states.map((group) => + group.map((s) => ({ + both: s.both, + selected: { ...s.selected }, + meta: s.meta, + })), + ); + + const originalSelected = tempStates[fi][fj].selected; + + for (const label of labels) { + // 临时替换选中项为仅包含当前 label + tempStates[fi][fj].selected = { [label]: true }; + + const exists = props.source.some((char) => { + for (const g of tempStates) { + for (const sf of g) { + if (!predicate(sf as State, char)) return false; + } + } + return true; + }); + map[label] = !exists; + } + + tempStates[fi][fj].selected = originalSelected; + dimmedMaps[fi][fj] = map; + } + } +} + +computeDimmedMaps(); +watch( + states, + () => { + computeDimmedMaps(); + }, + { deep: true }, +); + watch(oridata, () => { page.value.index = 1; }); @@ -395,6 +449,7 @@ watch(data, () => { :labels="flat(v2.cbt)" :show-both="v2.both" :no-width="i === 2" + :dimmed-labels="dimmedMaps[i][i2]" />