mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-04-23 22:09:51 +08:00
339 lines
9.5 KiB
Vue
339 lines
9.5 KiB
Vue
<!-- 首页 -->
|
|
<template>
|
|
<v-app-bar>
|
|
<div class="home-top-nav">
|
|
<div v-if="isLogin" class="home-tools">
|
|
<v-select
|
|
v-model="curGid"
|
|
:hide-details="true"
|
|
:items="games"
|
|
class="home-tool-select"
|
|
density="compact"
|
|
item-value="gid"
|
|
label="小工具(右侧)分区"
|
|
variant="outlined"
|
|
>
|
|
<template #selection="{ item }">
|
|
<div class="select-item main">
|
|
<img
|
|
v-if="item.icon"
|
|
:alt="item.title"
|
|
:src="item.icon"
|
|
:title="item.title"
|
|
class="icon"
|
|
/>
|
|
<span>{{ item.title }}</span>
|
|
</div>
|
|
</template>
|
|
<template #item="{ props, item }">
|
|
<div
|
|
:class="item.gid === curGid ? 'selected' : ''"
|
|
class="select-item sub"
|
|
v-bind="props"
|
|
>
|
|
<img
|
|
v-if="item.icon"
|
|
:alt="item.title"
|
|
:src="item.icon"
|
|
:title="item.title"
|
|
class="icon"
|
|
/>
|
|
<span>{{ item.title }}</span>
|
|
</div>
|
|
</template>
|
|
</v-select>
|
|
<TGameNav :gid="curGid" :mini="true" />
|
|
</div>
|
|
<div class="home-select">
|
|
<v-select
|
|
v-model="oldItems"
|
|
:chips="true"
|
|
:hide-details="true"
|
|
:items="showItemsAll"
|
|
:multiple="true"
|
|
density="compact"
|
|
label="首页组件显示"
|
|
variant="outlined"
|
|
width="440px"
|
|
/>
|
|
<v-btn :rounded="true" class="select-btn" variant="elevated" @click="submitHome">
|
|
确定
|
|
</v-btn>
|
|
</div>
|
|
</div>
|
|
</v-app-bar>
|
|
<div class="home-container">
|
|
<component :is="item" v-for="item in components" :key="item" @success="loadEnd(item)" />
|
|
</div>
|
|
</template>
|
|
<script lang="ts" setup>
|
|
import TGameNav from "@comp/app/t-gameNav.vue";
|
|
import showDialog from "@comp/func/dialog.js";
|
|
import showLoading from "@comp/func/loading.js";
|
|
import showSnackbar from "@comp/func/snackbar.js";
|
|
import PhCompCalendar from "@comp/pageHome/ph-comp-calendar.vue";
|
|
import PhCompDailyNote from "@comp/pageHome/ph-comp-daily-note.vue";
|
|
import PhCompPool from "@comp/pageHome/ph-comp-pool.vue";
|
|
import PhCompPosition from "@comp/pageHome/ph-comp-position.vue";
|
|
import PhCompSign from "@comp/pageHome/ph-comp-sign.vue";
|
|
import TSUserAccount from "@Sqlm/userAccount.js";
|
|
import useAppStore from "@store/app.js";
|
|
import useBBSStore from "@store/bbs.js";
|
|
import useHomeStore from "@store/home.js";
|
|
import { getVersion } from "@tauri-apps/api/app";
|
|
import { invoke } from "@tauri-apps/api/core";
|
|
import { openUrl } from "@tauri-apps/plugin-opener";
|
|
import getLrv from "@utils/Github.js";
|
|
import TGLogger from "@utils/TGLogger.js";
|
|
import { storeToRefs } from "pinia";
|
|
import { defineComponent, onMounted, ref, shallowRef, watch } from "vue";
|
|
|
|
/**
|
|
* 单文件组件类型
|
|
*/
|
|
type SFComp = ReturnType<typeof defineComponent>;
|
|
/**
|
|
* 选项类型
|
|
*/
|
|
type SelectItem = {
|
|
/** 图标 */
|
|
icon: string;
|
|
/** 标题 */
|
|
title: string;
|
|
/** 分区ID */
|
|
gid: number;
|
|
};
|
|
|
|
const homeStore = useHomeStore();
|
|
const bbsStore = useBBSStore();
|
|
|
|
const { devMode, isLogin, lastUcts } = storeToRefs(useAppStore());
|
|
const { gameList } = storeToRefs(bbsStore);
|
|
|
|
const curGid = ref<number>(2);
|
|
|
|
const games = shallowRef<Array<SelectItem>>();
|
|
const loadItems = shallowRef<Array<string>>([]);
|
|
const components = shallowRef<Array<SFComp>>([]);
|
|
const showItems = shallowRef<Array<string>>([]);
|
|
const showItemsAll = shallowRef<Array<string>>(["素材日历", "限时祈愿", "近期活动"]);
|
|
const oldItems = shallowRef<Array<string>>([]);
|
|
|
|
onMounted(async () => {
|
|
await bbsStore.refreshGameList();
|
|
await bbsStore.refreshGameUidCards();
|
|
// @ts-expect-error-next-line The import.meta meta-property is not allowed in files which will build into CommonJS output.
|
|
const isProdEnv = import.meta.env.MODE === "production";
|
|
if (isProdEnv && devMode.value) devMode.value = false;
|
|
if (isLogin.value) {
|
|
await TSUserAccount.account.updateCk();
|
|
await showLoading.start("正在加载首页小部件");
|
|
games.value = gameList.value.map((i) => ({ icon: i.app_icon, title: i.name, gid: i.id }));
|
|
showItems.value = homeStore.getShowItems();
|
|
showItemsAll.value = ["游戏签到", "实时便笺", "素材日历", "限时祈愿", "近期活动"];
|
|
} else {
|
|
showItems.value = homeStore.getShowItems().filter((i) => i !== "游戏签到");
|
|
showItemsAll.value = ["素材日历", "限时祈愿", "近期活动"];
|
|
}
|
|
oldItems.value = showItems.value;
|
|
await loadComp();
|
|
await checkAppUpdate();
|
|
});
|
|
|
|
watch(
|
|
() => components.value,
|
|
async (cur, old) => {
|
|
const newComp = cur.filter((i) => !old.includes(i));
|
|
if (newComp.length === 0) await showLoading.end();
|
|
},
|
|
);
|
|
|
|
async function loadComp(): Promise<void> {
|
|
const temp: Array<SFComp> = [];
|
|
for (const item of showItems.value) {
|
|
switch (item) {
|
|
case "游戏签到":
|
|
if (isLogin.value) {
|
|
temp.push(PhCompSign);
|
|
} else {
|
|
showSnackbar.warn("未登录不可设置游戏签到组件");
|
|
}
|
|
break;
|
|
case "实时便笺":
|
|
if (isLogin.value) {
|
|
temp.push(PhCompDailyNote);
|
|
} else {
|
|
showSnackbar.warn("未登录不可设置实时便笺组件");
|
|
}
|
|
break;
|
|
case "限时祈愿":
|
|
temp.push(PhCompPool);
|
|
break;
|
|
case "近期活动":
|
|
temp.push(PhCompPosition);
|
|
break;
|
|
case "素材日历":
|
|
temp.push(PhCompCalendar);
|
|
break;
|
|
}
|
|
}
|
|
await showLoading.start(`正在加载:${showItems.value.join("、")}`);
|
|
components.value = temp;
|
|
await TGLogger.Info(`[Home][loadComp] 打开首页,当前显示:${showItems.value.join("、")}`);
|
|
}
|
|
|
|
async function submitHome(): Promise<void> {
|
|
if (oldItems.value.length === 0) {
|
|
showSnackbar.warn("请至少选择一个!");
|
|
oldItems.value = showItems.value;
|
|
return;
|
|
}
|
|
showItems.value = oldItems.value;
|
|
homeStore.setShowItems(showItems.value);
|
|
showSnackbar.success("设置成功!");
|
|
await TGLogger.Info("[Home][submitHome] 首页设置成功,当前显示:" + showItems.value.join("、"));
|
|
loadItems.value = showItems.value.filter((i) => loadItems.value.includes(i));
|
|
await loadComp();
|
|
}
|
|
|
|
function getName(name: string): string | undefined {
|
|
switch (name) {
|
|
case "ph-comp-sign":
|
|
return "游戏签到";
|
|
case "ph-comp-daily-note":
|
|
return "实时便笺";
|
|
case "ph-comp-pool":
|
|
return "限时祈愿";
|
|
case "ph-comp-position":
|
|
return "近期活动";
|
|
case "ph-comp-calendar":
|
|
return "素材日历";
|
|
default:
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
async function loadEnd(item: ReturnType<typeof defineComponent>): Promise<void> {
|
|
const compName = getName(item.__name ?? "");
|
|
if (!compName) return;
|
|
await TGLogger.Info(`[Home][loadEnd] ${compName} 加载完成`);
|
|
await showLoading.update(`${compName} 加载完成`);
|
|
if (!loadItems.value.includes(compName)) loadItems.value.push(compName);
|
|
else showSnackbar.warn(`${compName} 已加载`);
|
|
if (loadItems.value.length === components.value.length) await showLoading.end();
|
|
}
|
|
|
|
async function checkAppUpdate(): Promise<void> {
|
|
const nowTs = Math.floor(Date.now() / 1000);
|
|
const diffTime = nowTs - lastUcts.value;
|
|
if (diffTime < 60 * 60 * 24) return;
|
|
await TGLogger.Info("[Home][CheckAppUpdate]检测版本更新");
|
|
const versionApp = await getVersion();
|
|
const versionCheck = await getLrv();
|
|
if (versionCheck === "0") return;
|
|
if (versionCheck === versionApp) {
|
|
await TGLogger.Info(`[Home][CheckAppUpdate]版本号一致:${versionCheck}`);
|
|
lastUcts.value = nowTs;
|
|
return;
|
|
}
|
|
await TGLogger.Info(`[Home][CheckAppUpdate]检测到新版本:${versionCheck}`);
|
|
const check = await showDialog.checkF({
|
|
title: "检测到新版本",
|
|
text: `${versionApp}→${versionCheck}`,
|
|
otcancel: false,
|
|
confirmLabel: "前往更新",
|
|
cancelLabel: "稍后提醒",
|
|
});
|
|
lastUcts.value = nowTs;
|
|
if (!check) return;
|
|
const isMsix = await invoke<boolean>("is_msix");
|
|
if (isMsix) {
|
|
await openUrl("ms-windows-store://pdp/?ProductId=9nlbnnnbnsjn");
|
|
return;
|
|
}
|
|
await openUrl("https://github.com/BTMuli/TeyvatGuide/releases/latest");
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.home-top-nav {
|
|
position: relative;
|
|
display: flex;
|
|
width: 100%;
|
|
max-width: 100%;
|
|
height: 100%;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.home-container {
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.home-tools {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
.home-tool-select {
|
|
width: 220px;
|
|
max-width: 250px;
|
|
margin-left: 16px;
|
|
}
|
|
|
|
.home-select {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin-right: 16px;
|
|
margin-left: auto;
|
|
gap: 8px;
|
|
}
|
|
|
|
.select-btn {
|
|
width: 100px;
|
|
height: 40px;
|
|
background: var(--tgc-btn-1);
|
|
color: var(--btn-text);
|
|
}
|
|
|
|
.select-item {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
column-gap: 4px;
|
|
|
|
&.main {
|
|
position: relative;
|
|
height: 24px;
|
|
font-family: var(--font-title);
|
|
font-size: 16px;
|
|
}
|
|
|
|
&.sub {
|
|
padding: 8px;
|
|
font-family: var(--font-title);
|
|
font-size: 16px;
|
|
|
|
&:hover {
|
|
background: var(--common-shadow-2);
|
|
}
|
|
|
|
&.selected:not(:hover) {
|
|
background: var(--common-shadow-1);
|
|
}
|
|
}
|
|
|
|
.icon {
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 4px;
|
|
}
|
|
}
|
|
</style>
|