Files
TeyvatGuide/src/App.vue

266 lines
8.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<v-app :theme="vuetifyTheme">
<TSidebar v-if="isMain" />
<v-main>
<v-container :fluid="true" class="app-container">
<router-view />
</v-container>
</v-main>
<TBackTop />
</v-app>
</template>
<script lang="ts" setup>
import { app, event, fs, tauri, window as TauriWindow } from "@tauri-apps/api";
import { UnlistenFn } from "@tauri-apps/api/helpers/event";
import { storeToRefs } from "pinia";
import { computed, onBeforeMount, onMounted, onUnmounted, ref } from "vue";
import { useRouter } from "vue-router";
import TBackTop from "./components/app/t-backTop.vue";
import TSidebar from "./components/app/t-sidebar.vue";
import showConfirm from "./components/func/confirm";
import showSnackbar from "./components/func/snackbar";
import TGSqlite from "./plugins/Sqlite";
import { useAppStore } from "./store/modules/app";
import { useUserStore } from "./store/modules/user";
import { getBuildTime } from "./utils/TGBuild";
import TGLogger from "./utils/TGLogger";
import TGRequest from "./web/request/TGRequest";
const appStore = useAppStore();
const userStore = storeToRefs(useUserStore());
const isMain = ref<boolean>(false);
const theme = ref<string>(appStore.theme);
const router = useRouter();
const vuetifyTheme = computed(() => {
return appStore.theme === "dark" ? "dark" : "light";
});
let themeListener: UnlistenFn;
let urlListener: UnlistenFn;
onBeforeMount(async () => {
const win = TauriWindow.getCurrent();
isMain.value = win.label === "TeyvatGuide";
if (isMain.value) {
const title = "Teyvat Guide v" + (await app.getVersion()) + " Beta";
await win.setTitle(title);
await listenOnInit();
await tauri.invoke("init_app");
urlListener = await getDeepLink();
}
});
onMounted(async () => {
document.documentElement.className = theme.value;
themeListener = await event.listen("readTheme", async (e) => {
const themeGet = <string>e.payload;
if (theme.value !== themeGet) {
theme.value = themeGet;
document.documentElement.className = theme.value;
}
});
});
// 启动后只执行一次的监听
async function listenOnInit(): Promise<void> {
await event.listen("initApp", async () => {
await tauri.invoke("register_deep_link");
await checkAppLoad();
await checkDeviceFp();
try {
await checkUserLoad();
} catch (e) {
if (e instanceof Error) {
await TGLogger.Error(`[App][listenOnInit] ${e.name}: ${e.message}`);
} else console.error(e);
}
await checkUpdate();
});
return;
}
async function checkAppLoad(): Promise<void> {
let checkDB = false;
try {
checkDB = await TGSqlite.check();
} catch (error) {
if (error instanceof Error) {
await TGLogger.Error(`[App][checkAppLoad] ${error.name}: ${error.message}`);
} else console.error(error);
}
if (!checkDB) await resetDB();
else await TGLogger.Info("[App][checkAppLoad] 数据库已成功加载!");
}
async function resetDB(): Promise<void> {
await TGSqlite.reset();
showSnackbar({
text: "检测到数据库不完整!已重置数据库!",
color: "error",
timeout: 3000,
});
appStore.loading = true;
await TGLogger.Info("[App][resetDB] 数据库已重置!");
}
// 检测 deviceFp
async function checkDeviceFp(): Promise<void> {
const appData = await TGSqlite.getAppData();
const deviceInfo = appData.find((item) => item.key === "deviceInfo")?.value;
const deviceLocal = appStore.deviceInfo;
if (deviceInfo === undefined) {
if (deviceLocal.device_fp === "0000000000000")
appStore.deviceInfo = await TGRequest.Device.getFp(appStore.deviceInfo);
await TGSqlite.saveAppData("deviceInfo", JSON.stringify(deviceLocal));
return;
}
if (JSON.parse(deviceInfo) !== deviceLocal) appStore.deviceInfo = JSON.parse(deviceInfo);
}
// 检测 ck,info 数据
async function checkUserLoad(): Promise<void> {
const ckDB = await TGSqlite.getCookie();
if (JSON.stringify(ckDB) === "{}" && appStore.isLogin) {
showSnackbar({
text: "获取 Cookie 失败!请重新登录!",
color: "error",
timeout: 3000,
});
appStore.isLogin = false;
await TGLogger.Error("[App][checkUserLoad] 获取 Cookie 失败!");
return;
}
if (JSON.stringify(ckDB) !== "{}" && !appStore.isLogin) appStore.isLogin = true;
const ckLocal = userStore.cookie;
if (JSON.stringify(ckLocal) !== JSON.stringify(ckDB)) userStore.cookie.value = ckDB;
const infoLocal = userStore.briefInfo.value;
const appData = await TGSqlite.getAppData();
const infoDB = appData.find((item) => item.key === "userInfo")?.value;
if (infoDB === undefined && JSON.stringify(infoLocal) !== "{}") {
await TGSqlite.saveAppData("userInfo", JSON.stringify(infoLocal));
} else if (infoDB !== undefined && infoLocal !== JSON.parse(infoDB)) {
userStore.briefInfo.value = JSON.parse(infoDB);
console.info("briefInfo 数据已更新!");
}
const accountLocal = userStore.account.value;
const accountDB = await TGSqlite.getCurAccount();
if (accountDB === false) {
if (!appStore.isLogin) return;
showSnackbar({
text: "获取 GameAccount 失败!请尝试更新数据库!",
color: "error",
timeout: 3000,
});
await TGLogger.Error("[App][checkUserLoad] 获取 GameAccount 失败!");
return;
}
if (accountDB !== accountLocal) userStore.account.value = accountDB;
const userDir = appData.find((item) => item.key === "userDir")?.value;
if (userDir === undefined) {
await TGSqlite.saveAppData("userDir", appStore.userDir);
return;
}
if (userDir !== appStore.userDir) appStore.userDir = userDir;
await fs.createDir(appStore.userDir, { recursive: true });
}
async function getDeepLink(): Promise<UnlistenFn> {
return await event.listen("active_deep_link", async (e) => {
const windowGet = new TauriWindow.WebviewWindow("TeyvatGuide");
if (await windowGet.isMinimized()) {
await windowGet.unminimize();
}
await windowGet.setFocus();
if (typeof e.payload !== "string") {
showSnackbar({
text: "无效的 deep link",
color: "error",
timeout: 3000,
});
await TGLogger.Error(`[App][getDeepLink] 无效的 deep link ${JSON.stringify(e)}`);
return;
}
await TGLogger.Info(`[App][getDeepLink] ${e.payload}`);
if (e.payload === "") return;
if (
e.payload.startsWith("teyvatguide://import_uigf") ||
e.payload.startsWith("teyvatguide://import_uiaf")
) {
await toUIAF(e.payload);
return;
}
if (e.payload.startsWith("router?path=")) {
const routerPath = e.payload.replace("router?path=", "");
if (router.currentRoute.value.path === routerPath) {
showSnackbar({
text: "已在当前页面!",
color: "warn",
timeout: 3000,
});
return;
}
await router.push(routerPath);
return;
}
showSnackbar({
text: "无效的 deep link",
color: "error",
timeout: 3000,
});
});
}
async function toUIAF(link: string) {
const url = new URL(link);
const app = url.searchParams.get("app");
if (app === null || app === "") {
await router.push("/achievements");
} else {
await router.push("/achievements/?app=" + app);
}
}
// 检测更新
async function checkUpdate(): Promise<void> {
const isProdEnv = import.meta.env.MODE === "production";
const needUpdate = await TGSqlite.checkUpdate();
if (needUpdate && isProdEnv) {
await TGLogger.Info("[App][checkUpdate] 检测到版本更新!");
const confirm = await showConfirm({
title: "检测到版本更新",
text: "是否更新数据库数据?",
});
if (!confirm) {
showSnackbar({
text: "请到设置页手动更新数据库!",
color: "error",
timeout: 3000,
});
return;
}
appStore.buildTime = getBuildTime();
await TGSqlite.update();
showSnackbar({
text: "数据库已更新!",
color: "success",
timeout: 3000,
});
window.open("https://app.btmuli.ink/docs/Changelogs.html");
}
}
onUnmounted(() => {
if (themeListener) themeListener();
if (urlListener) urlListener();
});
</script>
<style lang="css">
.app-container {
height: 100%;
background: var(--app-page-bg);
color: var(--app-page-content);
}
</style>