mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-15 03:53:16 +08:00
@@ -17,8 +17,8 @@
|
||||
{{ data.subtitle }}
|
||||
</div>
|
||||
<div class="loading-img">
|
||||
<img v-if="data.empty" alt="loading" src="/source/UI/empty.webp" />
|
||||
<img v-else :src="iconUrl" alt="empty" />
|
||||
<img v-if="data.empty" alt="empty" src="/source/UI/empty.webp" />
|
||||
<img v-else :src="iconUrl" alt="loading" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
<slot name="right"></slot>
|
||||
</div>
|
||||
</TOverlay>
|
||||
<VpOverlaySearch v-model="showSearch" :keyword="search" gid="2" />
|
||||
<VpOverlaySearch v-model="showSearch" :keyword="search" :gid="2" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TOverlay from "@comp/app/t-overlay.vue";
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
<!-- 成就系列 -->
|
||||
<template>
|
||||
<div
|
||||
v-if="data"
|
||||
v-if="series"
|
||||
v-show="!(hideFin && progress === 100)"
|
||||
:class="{
|
||||
'tuas-selected': props.cur === props.series,
|
||||
'tuas-selected': props.cur === props.series.id,
|
||||
'tuas-radius': showCard,
|
||||
}"
|
||||
:title="data.name"
|
||||
:title="series.name"
|
||||
class="tuas-card"
|
||||
@click="selectSeries"
|
||||
>
|
||||
<div class="tuas-version">v{{ data.version }}</div>
|
||||
<div class="tuas-version">v{{ series.version }}</div>
|
||||
<div v-if="showCard" class="tuas-reward">
|
||||
<img
|
||||
:class="{ finish: progress === 100 }"
|
||||
:src="`/WIKI/nameCard/bg/${data.card}.webp`"
|
||||
:class="progress === 100 ? 'finish' : ''"
|
||||
:src="`/WIKI/nameCard/bg/${series.card}.webp`"
|
||||
alt="card"
|
||||
/>
|
||||
</div>
|
||||
<div class="tuas-icon">
|
||||
<img :src="`/icon/achievement/${data.icon}.webp`" alt="icon" />
|
||||
<img :src="`/icon/achievement/${series.icon}.webp`" alt="icon" />
|
||||
<v-progress-circular
|
||||
:model-value="progress"
|
||||
bg-color="var(--tgc-od-white)"
|
||||
@@ -28,37 +29,39 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="tuas-content">
|
||||
<span :title="data.name">{{ data.name }}</span>
|
||||
<span :title="series.name">{{ series.name }}</span>
|
||||
<span>{{ overview.fin }}/{{ overview.total }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import TSUserAchi from "@Sqlm/userAchi.js";
|
||||
import { type Event, listen, type UnlistenFn } from "@tauri-apps/api/event";
|
||||
import { computed, onMounted, onUnmounted, shallowRef, watch } from "vue";
|
||||
|
||||
import { AppAchievementSeriesData } from "@/data/index.js";
|
||||
|
||||
type TuaSeriesProps = { uid: number; series: number; cur: number };
|
||||
type TuaSeriesEmits = (e: "selectSeries", v: number) => void;
|
||||
type TuaSeriesProps = {
|
||||
/** 存档 UID */
|
||||
uid: number;
|
||||
/** 成就系列数据 */
|
||||
series: TGApp.App.Achievement.Series;
|
||||
/** 当前选中系列 ID,-1表示未选择 */
|
||||
cur: number;
|
||||
/** 是否隐藏已完成 */
|
||||
hideFin: boolean;
|
||||
};
|
||||
type TuaSeriesEmits = (e: "selected", v: number) => void;
|
||||
|
||||
let achiListener: UnlistenFn | null = null;
|
||||
const props = defineProps<TuaSeriesProps>();
|
||||
const emits = defineEmits<TuaSeriesEmits>();
|
||||
|
||||
const overview = shallowRef<TGApp.App.Achievement.Overview>({ fin: 0, total: 0 });
|
||||
const data = computed<TGApp.App.Achievement.Series | undefined>(() =>
|
||||
AppAchievementSeriesData.find((s) => s.id === props.series),
|
||||
);
|
||||
const progress = computed<number>(() => {
|
||||
if (overview.value.total === 0) return 0;
|
||||
return Math.round((overview.value.fin / overview.value.total) * 100);
|
||||
});
|
||||
const showCard = computed<boolean>(() => {
|
||||
if (data.value === undefined) return false;
|
||||
return data.value.card !== "";
|
||||
return props.series.card !== "";
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -72,12 +75,12 @@ watch(
|
||||
);
|
||||
|
||||
async function refreshOverview(): Promise<void> {
|
||||
overview.value = await TSUserAchi.getOverview(props.uid, props.series);
|
||||
overview.value = await TSUserAchi.getOverview(props.uid, props.series.id);
|
||||
}
|
||||
|
||||
async function listenAchi(): Promise<UnlistenFn> {
|
||||
return await listen<number>("updateAchi", async (e: Event<number>) => {
|
||||
if (e.payload === props.series) await refreshOverview();
|
||||
if (e.payload === props.series.id) await refreshOverview();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -89,11 +92,7 @@ onUnmounted(async () => {
|
||||
});
|
||||
|
||||
function selectSeries(): void {
|
||||
if (props.cur === props.series) {
|
||||
showSnackbar.warn("已选中当前系列!");
|
||||
return;
|
||||
}
|
||||
emits("selectSeries", props.series);
|
||||
emits("selected", props.series.id);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@@ -106,6 +105,7 @@ function selectSeries(): void {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
height: 60px;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
padding: 8px;
|
||||
|
||||
@@ -64,21 +64,22 @@
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<div class="wrap">
|
||||
<v-virtual-scroll :items="seriesList" class="left-wrap" item-height="60">
|
||||
<template #default="{ item }">
|
||||
<TuaSeries
|
||||
v-model:cur="selectedSeries"
|
||||
:series="item"
|
||||
:uid="uidCur"
|
||||
@click="selectedSeries = item"
|
||||
/>
|
||||
</template>
|
||||
</v-virtual-scroll>
|
||||
<div class="left-wrap">
|
||||
<TuaSeries
|
||||
v-for="item in seriesList"
|
||||
:key="item.id"
|
||||
v-model:cur="selectedSeries"
|
||||
:hideFin
|
||||
:series="item"
|
||||
:uid="uidCur"
|
||||
@selected="handleSeriesSelect"
|
||||
/>
|
||||
</div>
|
||||
<TuaAchiList
|
||||
v-model:isSearch="isSearch"
|
||||
v-model:search="search"
|
||||
v-model:series="selectedSeries"
|
||||
:hideFin="hideFin"
|
||||
:hideFin
|
||||
:uid="uidCur"
|
||||
/>
|
||||
</div>
|
||||
@@ -110,7 +111,7 @@ import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
import { AppAchievementSeriesData } from "@/data/index.js";
|
||||
|
||||
const seriesList = AppAchievementSeriesData.sort((a, b) => a.order - b.order).map((s) => s.id);
|
||||
const seriesList = AppAchievementSeriesData.sort((a, b) => a.order - b.order);
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
@@ -171,6 +172,14 @@ function switchHideFin(): void {
|
||||
showSnackbar.success(`已${text}`);
|
||||
}
|
||||
|
||||
function handleSeriesSelect(id: number): void {
|
||||
if (selectedSeries.value === id) {
|
||||
showSnackbar.warn("已经选中当前系列");
|
||||
return;
|
||||
}
|
||||
selectedSeries.value = id;
|
||||
}
|
||||
|
||||
async function refreshOverview(): Promise<void> {
|
||||
overview.value = await TSUserAchi.getOverview(uidCur.value);
|
||||
}
|
||||
@@ -388,12 +397,15 @@ async function toYae(): Promise<void> {
|
||||
|
||||
.left-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 332px;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
padding-right: 8px;
|
||||
overflow-y: auto;
|
||||
row-gap: 8px;
|
||||
}
|
||||
|
||||
:deep(.v-virtual-scroll__item + .v-virtual-scroll__item) {
|
||||
|
||||
Reference in New Issue
Block a user