♻️ 重构WIKI筛选组件筛选逻辑

This commit is contained in:
BTMuli
2025-12-28 22:55:12 +08:00
parent bfab4a6ac6
commit e779467034
4 changed files with 115 additions and 51 deletions

View File

@@ -1,12 +1,13 @@
<!-- 角色筛选 -->
<template>
<TOverlay v-model="visible">
<div class="two-sc-container">
<div class="two-sc-item">
<div class="two-sc-title">星级</div>
<v-item-group multiple mandatory v-model="selectedStar" class="two-sc-select">
<v-item-group v-model="selectedStar" class="two-sc-select" multiple>
<div v-for="(item, index) in selectStarList" :key="index">
<v-item v-slot="{ isSelected, toggle }" :value="item">
<v-btn @click="toggle" :color="isSelected ? 'primary' : ''">
<v-btn :color="isSelected ? 'primary' : ''" @click="toggle">
<v-icon>{{ isSelected ? "mdi-star" : "mdi-star-outline" }}</v-icon>
<span>{{ item }}</span>
</v-btn>
@@ -16,10 +17,10 @@
</div>
<div class="two-sc-item">
<div class="two-sc-title">武器</div>
<v-item-group multiple mandatory v-model="selectedWeapon" class="two-sc-select">
<v-item-group v-model="selectedWeapon" class="two-sc-select" multiple>
<div v-for="(item, index) in selectWeaponList" :key="index">
<v-item v-slot="{ isSelected, toggle }" :value="item">
<v-btn @click="toggle" :color="isSelected ? 'primary' : ''">
<v-btn :color="isSelected ? 'primary' : ''" @click="toggle">
<img :alt="`${item}`" :src="`/icon/weapon/${item}.webp`" class="two-sci-icon" />
<span>{{ item }}</span>
</v-btn>
@@ -29,10 +30,10 @@
</div>
<div class="two-sc-item">
<div class="two-sc-title">元素</div>
<v-item-group multiple mandatory v-model="selectedElements" class="two-sc-select">
<v-item-group v-model="selectedElements" class="two-sc-select" multiple>
<div v-for="(item, index) in selectElementList" :key="index">
<v-item v-slot="{ isSelected, toggle }" :value="item">
<v-btn @click="toggle" class="element-btn" :color="isSelected ? 'primary' : ''">
<v-btn :color="isSelected ? 'primary' : ''" class="element-btn" @click="toggle">
<img
:alt="`${item}元素`"
:src="`/icon/element/${item}元素.webp`"
@@ -46,10 +47,10 @@
</div>
<div class="two-sc-item">
<div class="two-sc-title">阵营</div>
<v-item-group multiple mandatory v-model="selectedArea" class="two-sc-select">
<v-item-group v-model="selectedArea" class="two-sc-select" multiple>
<div v-for="(item, index) in selectAreaList" :key="index">
<v-item v-slot="{ isSelected, toggle }" :value="item">
<v-btn @click="toggle" :color="isSelected ? 'primary' : ''">
<v-btn :color="isSelected ? 'primary' : ''" @click="toggle">
<v-icon>{{ isSelected ? "mdi-check" : "mdi-checkbox-blank-outline" }}</v-icon>
<span>{{ item }}</span>
</v-btn>
@@ -64,10 +65,10 @@
</div>
</TOverlay>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import TOverlay from "@comp/app/t-overlay.vue";
import showSnackbar from "@comp/func/snackbar.js";
import { ref, toRaw, watch } from "vue";
import { ref, shallowRef, watch } from "vue";
export type SelectedCValue = {
star: Array<number>;
@@ -97,11 +98,16 @@ const selectAreaList = [
"挪德卡莱",
];
// 选中的元素
const selectedStar = ref<Array<number>>(selectStarList);
const selectedWeapon = ref<Array<string>>(selectWeaponList);
const selectedElements = ref<Array<string>>(selectElementList);
const selectedArea = ref<Array<string>>(selectAreaList);
const selectedStar = ref<Array<number>>([]);
const selectedWeapon = ref<Array<string>>([]);
const selectedElements = ref<Array<string>>([]);
const selectedArea = ref<Array<string>>([]);
const oldVal = shallowRef<SelectedCValue>({
star: selectedStar.value,
weapon: selectedWeapon.value,
elements: selectedElements.value,
area: selectedArea.value,
});
const visible = defineModel<boolean>();
const resetModel = defineModel<boolean>("reset");
@@ -110,25 +116,47 @@ watch(
() => {
if (resetModel.value) {
if (
toRaw(selectedStar.value) === selectStarList &&
toRaw(selectedWeapon.value) === selectWeaponList &&
toRaw(selectedElements.value) === selectElementList &&
toRaw(selectedArea.value) === selectAreaList
isNotFilter(selectedStar.value, selectStarList) &&
isNotFilter(selectedWeapon.value, selectWeaponList) &&
isNotFilter(selectedElements.value, selectElementList) &&
isNotFilter(selectedArea.value, selectAreaList)
) {
showSnackbar.warn("无需重置");
resetModel.value = false;
return;
}
selectedStar.value = selectStarList;
selectedWeapon.value = selectWeaponList;
selectedElements.value = selectElementList;
selectedArea.value = selectAreaList;
selectedStar.value = [];
selectedWeapon.value = [];
selectedElements.value = [];
selectedArea.value = [];
oldVal.value = {
star: selectedStar.value,
weapon: selectedWeapon.value,
elements: selectedElements.value,
area: selectedArea.value,
};
resetModel.value = false;
showSnackbar.success("已重置");
}
},
);
watch(
() => visible.value,
() => {
if (visible.value) {
selectedStar.value = oldVal.value.star;
selectedWeapon.value = oldVal.value.weapon;
selectedArea.value = oldVal.value.area;
selectedElements.value = oldVal.value.elements;
}
},
);
function isNotFilter<T>(list: Array<T>, data: Array<T>): boolean {
return list.length === 0 || list.length === data.length;
}
function confirmSelect() {
const value: SelectedCValue = {
star: selectedStar.value,
@@ -137,6 +165,7 @@ function confirmSelect() {
area: selectedArea.value,
};
emits("select-c", value);
oldVal.value = value;
visible.value = false;
}
</script>

View File

@@ -1,12 +1,13 @@
<!-- 武器筛选 -->
<template>
<TOverlay v-model="visible">
<div class="two-sw-container">
<div class="two-sw-item">
<div class="two-sw-title">星级</div>
<v-item-group multiple mandatory v-model="selectedStar" class="two-sw-select">
<v-item-group v-model="selectedStar" class="two-sw-select" mandatory multiple>
<div v-for="(item, index) in selectStarList" :key="index">
<v-item v-slot="{ isSelected, toggle }" :value="item">
<v-btn @click="toggle" :color="isSelected ? 'primary' : ''">
<v-btn :color="isSelected ? 'primary' : ''" @click="toggle">
<v-icon>{{ isSelected ? "mdi-star" : "mdi-star-outline" }}</v-icon>
<span>{{ item }}</span>
</v-btn>
@@ -16,10 +17,10 @@
</div>
<div class="two-sw-item">
<div class="two-sw-title">武器</div>
<v-item-group multiple mandatory v-model="selectedWeapon" class="two-sw-select">
<v-item-group v-model="selectedWeapon" class="two-sw-select" mandatory multiple>
<div v-for="(item, index) in selectWeaponList" :key="index">
<v-item v-slot="{ isSelected, toggle }" :value="item">
<v-btn @click="toggle" :color="isSelected ? 'primary' : ''">
<v-btn :color="isSelected ? 'primary' : ''" @click="toggle">
<img :alt="`${item}元素`" :src="`/icon/weapon/${item}.webp`" class="two-swi-icon" />
<span>{{ item }}</span>
</v-btn>
@@ -34,12 +35,12 @@
</div>
</TOverlay>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import TOverlay from "@comp/app/t-overlay.vue";
import showSnackbar from "@comp/func/snackbar.js";
import { ref, toRaw, watch } from "vue";
import { ref, shallowRef, watch } from "vue";
export type SelectedWValue = { star: Array<number>; weapon: Array<string>; isReset: boolean };
export type SelectedWValue = { star: Array<number>; weapon: Array<string> };
type TwoSelectWEmits = (e: "select-w", value: SelectedWValue) => void;
const emits = defineEmits<TwoSelectWEmits>();
@@ -47,8 +48,12 @@ const emits = defineEmits<TwoSelectWEmits>();
const selectStarList = [4, 5];
const selectWeaponList = ["单手剑", "双手剑", "弓", "法器", "长柄武器"];
const selectedStar = ref<Array<number>>(selectStarList);
const selectedWeapon = ref<Array<string>>(selectWeaponList);
const selectedStar = ref<Array<number>>([]);
const selectedWeapon = ref<Array<string>>([]);
const oldVal = shallowRef<SelectedWValue>({
star: selectedStar.value,
weapon: selectedWeapon.value,
});
const visible = defineModel<boolean>();
const resetModel = defineModel<boolean>("reset");
@@ -57,23 +62,43 @@ watch(
() => {
if (resetModel.value) {
if (
toRaw(selectedStar.value) === selectStarList &&
toRaw(selectedWeapon.value) === selectWeaponList
isNotFilter(selectedStar.value, selectStarList) &&
isNotFilter(selectedWeapon.value, selectWeaponList)
) {
showSnackbar.warn("无需重置");
resetModel.value = false;
return;
}
selectedStar.value = selectStarList;
selectedWeapon.value = selectWeaponList;
selectedStar.value = [];
selectedWeapon.value = [];
oldVal.value = {
star: selectedStar.value,
weapon: selectedWeapon.value,
};
resetModel.value = false;
emits("select-w", { star: selectedStar.value, weapon: selectedWeapon.value, isReset: true });
showSnackbar.success("已重置");
}
},
);
watch(
() => visible.value,
() => {
if (visible.value) {
selectedStar.value = oldVal.value.star;
selectedWeapon.value = oldVal.value.weapon;
}
},
);
function isNotFilter<T>(list: Array<T>, data: Array<T>): boolean {
return list.length === 0 || list.length === data.length;
}
function confirmSelect(): void {
emits("select-w", { star: selectedStar.value, weapon: selectedWeapon.value, isReset: false });
const value: SelectedWValue = { star: selectedStar.value, weapon: selectedWeapon.value };
emits("select-w", value);
oldVal.value = value;
visible.value = false;
}
</script>

View File

@@ -77,17 +77,17 @@ onBeforeMount(() => {
watch(
() => resetSelect.value,
(val) => {
if (val) cardsInfo.value = AppCharacterData;
if (val) cardsInfo.value = appCData;
},
);
function handleSelect(val: SelectedCValue): void {
showSelect.value = false;
const filterC = AppCharacterData.filter((item) => {
if (!val.star.includes(item.star)) return false;
if (!val.weapon.includes(item.weapon)) return false;
if (!val.elements.includes(item.element)) return false;
return val.area.includes(item.area);
if (val.star.length > 0 && !val.star.includes(item.star)) return false;
if (val.weapon.length > 0 && !val.weapon.includes(item.weapon)) return false;
if (val.elements.length > 0 && !val.elements.includes(item.element)) return false;
return !(val.area.length > 0 && val.area.includes(item.area));
});
if (filterC.length === 0) {
showSnackbar.warn("未找到符合条件的角色");
@@ -134,6 +134,7 @@ async function toOuter(item?: TGApp.App.Character.WikiBriefInfo): Promise<void>
}
.wc-left {
position: relative;
display: flex;
width: fit-content;
flex-direction: column;
@@ -161,11 +162,11 @@ async function toOuter(item?: TGApp.App.Character.WikiBriefInfo): Promise<void>
.wc-list {
position: relative;
display: grid;
overflow: hidden auto;
width: 100%;
padding-right: 8px;
gap: 8px;
grid-template-columns: repeat(3, 160px);
overflow-y: auto;
}
.wc-detail {

View File

@@ -30,12 +30,12 @@ import TwcListItem from "@comp/pageWiki/twc-list-item.vue";
import TwcWeapon from "@comp/pageWiki/twc-weapon.vue";
import TwoSelectW, { type SelectedWValue } from "@comp/pageWiki/two-select-w.vue";
import { toObcPage } from "@utils/TGWindow.js";
import { onBeforeMount, ref, shallowRef } from "vue";
import { onBeforeMount, ref, shallowRef, watch } from "vue";
import { useRoute } from "vue-router";
import { AppWeaponData } from "@/data/index.js";
const sortedData = AppWeaponData.sort((a, b) => {
const appWData = AppWeaponData.sort((a, b) => {
if (a.star !== b.star) return b.star - a.star;
if (a.weapon !== b.weapon) return a.weapon.localeCompare(b.weapon);
return b.id - a.id;
@@ -44,7 +44,7 @@ const sortedData = AppWeaponData.sort((a, b) => {
const id = useRoute().params.id.toString() ?? "0";
const showSelect = ref<boolean>(false);
const resetSelect = ref<boolean>(false);
const cardsInfo = shallowRef<Array<TGApp.App.Weapon.WikiBriefInfo>>(sortedData);
const cardsInfo = shallowRef<Array<TGApp.App.Weapon.WikiBriefInfo>>(appWData);
const curItem = shallowRef<TGApp.App.Weapon.WikiBriefInfo>({
id: 0,
contentId: 0,
@@ -67,15 +67,24 @@ onBeforeMount(() => {
curItem.value = cardsInfo.value[0];
});
watch(
() => resetSelect.value,
() => {
if (resetSelect.value) {
cardsInfo.value = appWData;
}
},
);
function switchW(item: TGApp.App.Weapon.WikiBriefInfo): void {
curItem.value = item;
}
function handleSelectW(val: SelectedWValue) {
if (!val.isReset) showSelect.value = true;
showSelect.value = false;
const filterW = AppWeaponData.filter((item) => {
if (!val.star.includes(item.star)) return false;
return val.weapon.includes(item.weapon);
if (val.star.length > 0 && !val.star.includes(item.star)) return false;
return !(val.weapon.length > 0 && !val.weapon.includes(item.weapon));
});
if (filterW.length === 0) {
showSnackbar.warn("未找到符合条件的武器");
@@ -139,7 +148,7 @@ async function toOuter(item?: TGApp.App.Weapon.WikiBriefInfo): Promise<void> {
padding-right: 8px;
gap: 8px;
grid-template-columns: repeat(3, 160px);
overflow-y: auto;
overflow: hidden auto;
}
.ww-detail {