perf(player): 优化 Tab 切换性能并改进投注历史展示

- 主 Tab 启用 keep-alive,恢复各页滚动位置,避免切页重复加载与重复请求
- 首页数据缓存、余额/头像共用 profile 缓存,冠军盘与串关面板按需加载
- 球赛与串关列表新增「仅显示待开赛」筛选
- 重构历史注单卡片,展示注单类型、赔率与日期

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-10 17:33:06 +08:00
parent a8ee28fcce
commit 785fa4416d
10 changed files with 212 additions and 53 deletions

View File

@@ -10,12 +10,11 @@ import LocaleSwitcher from '../components/LocaleSwitcher.vue';
import { useAppLocale } from '../composables/useAppLocale';
import AnnouncementMarquee from '../components/AnnouncementMarquee.vue';
import BottomNavIcon from '../components/BottomNavIcon.vue';
import { computed, onMounted, watch } from 'vue';
import { computed, onMounted, ref, watch } from 'vue';
import { usePlayerHome } from '../composables/usePlayerHome';
import { useOnLocaleChange } from '../composables/useOnLocaleChange';
import { usePlayerProfile } from '../composables/usePlayerProfile';
const { t } = useI18n();
const { t, locale } = useI18n();
const auth = useAuthStore();
const { initFromUser } = useAppLocale();
const route = useRoute();
@@ -43,8 +42,22 @@ const showBottomNav = computed(() => {
});
const { announcements, load: loadPlayerHome } = usePlayerHome();
const { loadProfile } = usePlayerProfile();
const mainRef = ref<HTMLElement | null>(null);
const tabScrollTops = new Map<string, number>();
useOnLocaleChange(loadPlayerHome);
watch(locale, (next, prev) => {
if (prev && next !== prev) void loadPlayerHome(true);
});
watch(
() => route.fullPath,
(_path, oldPath) => {
const el = mainRef.value;
if (!el) return;
if (oldPath) tabScrollTops.set(oldPath, el.scrollTop);
el.scrollTop = tabScrollTops.get(route.fullPath) ?? 0;
},
);
onMounted(() => {
if (auth.user?.locale) initFromUser(auth.user.locale);
@@ -55,7 +68,7 @@ watch(
(token) => {
if (token) {
void loadPlayerHome();
void loadProfile(true);
void loadProfile();
}
},
{ immediate: true },
@@ -77,8 +90,13 @@ watch(
<AnnouncementMarquee :items="announcements" embedded />
</div>
<main :class="['main', { 'has-nav': showBottomNav }]">
<RouterView />
<main ref="mainRef" :class="['main', { 'has-nav': showBottomNav }]">
<RouterView v-slot="{ Component, route: viewRoute }">
<KeepAlive v-if="viewRoute.meta.keepAlive">
<component :is="Component" :key="viewRoute.path" />
</KeepAlive>
<component v-else :is="Component" :key="viewRoute.fullPath" />
</RouterView>
</main>
<nav v-if="showBottomNav" class="bottom-nav" aria-label="Main">