mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-15 09:48:14 +08:00
♻️ 完善日志,重构设置页面
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use tauri::{Manager, WindowBuilder};
|
use tauri::{Manager, WindowBuilder};
|
||||||
use tauri_plugin_log::LogTarget;
|
use tauri_plugin_log::{LogTarget, TimezoneStrategy};
|
||||||
use tauri_utils::config::WindowConfig;
|
use tauri_utils::config::WindowConfig;
|
||||||
mod client;
|
mod client;
|
||||||
mod utils;
|
mod utils;
|
||||||
@@ -117,6 +117,7 @@ fn main() {
|
|||||||
.plugin(
|
.plugin(
|
||||||
tauri_plugin_log::Builder::default()
|
tauri_plugin_log::Builder::default()
|
||||||
.targets([LogTarget::LogDir, LogTarget::Stdout])
|
.targets([LogTarget::LogDir, LogTarget::Stdout])
|
||||||
|
.timezone_strategy(TimezoneStrategy::UseLocal)
|
||||||
.level(LevelFilter::Info)
|
.level(LevelFilter::Info)
|
||||||
.log_name(utils::get_current_date())
|
.log_name(utils::get_current_date())
|
||||||
.build(),
|
.build(),
|
||||||
|
|||||||
85
src/App.vue
85
src/App.vue
@@ -24,6 +24,7 @@ import TGSqlite from "./plugins/Sqlite";
|
|||||||
import { useAppStore } from "./store/modules/app";
|
import { useAppStore } from "./store/modules/app";
|
||||||
import { useUserStore } from "./store/modules/user";
|
import { useUserStore } from "./store/modules/user";
|
||||||
import { getBuildTime } from "./utils/TGBuild";
|
import { getBuildTime } from "./utils/TGBuild";
|
||||||
|
import TGLogger from "./utils/TGLogger";
|
||||||
import TGRequest from "./web/request/TGRequest";
|
import TGRequest from "./web/request/TGRequest";
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
@@ -36,7 +37,6 @@ const vuetifyTheme = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
// 获取当前窗口
|
|
||||||
const win = TauriWindow.getCurrent();
|
const win = TauriWindow.getCurrent();
|
||||||
isMain.value = win.label === "TeyvatGuide";
|
isMain.value = win.label === "TeyvatGuide";
|
||||||
if (isMain.value) {
|
if (isMain.value) {
|
||||||
@@ -54,7 +54,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
// 监听主题变化
|
// 监听主题变化
|
||||||
async function listenOnTheme(): Promise<void> {
|
async function listenOnTheme(): Promise<void> {
|
||||||
await event.listen("readTheme", (e) => {
|
await event.listen("readTheme", async (e) => {
|
||||||
const themeGet = <string>e.payload;
|
const themeGet = <string>e.payload;
|
||||||
if (theme.value !== themeGet) {
|
if (theme.value !== themeGet) {
|
||||||
theme.value = themeGet;
|
theme.value = themeGet;
|
||||||
@@ -72,8 +72,10 @@ async function listenOnInit(): Promise<void> {
|
|||||||
await checkDeviceFp();
|
await checkDeviceFp();
|
||||||
try {
|
try {
|
||||||
await checkUserLoad();
|
await checkUserLoad();
|
||||||
} catch (error) {
|
} catch (e) {
|
||||||
console.error(error);
|
if (e instanceof Error) {
|
||||||
|
await TGLogger.Error(`[App][listenOnInit] ${e.name}: ${e.message}`);
|
||||||
|
} else console.error(e);
|
||||||
}
|
}
|
||||||
await checkUpdate();
|
await checkUpdate();
|
||||||
});
|
});
|
||||||
@@ -85,13 +87,12 @@ async function checkAppLoad(): Promise<void> {
|
|||||||
try {
|
try {
|
||||||
checkDB = await TGSqlite.check();
|
checkDB = await TGSqlite.check();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
if (error instanceof Error) {
|
||||||
}
|
await TGLogger.Error(`[App][checkAppLoad] ${error.name}: ${error.message}`);
|
||||||
if (!checkDB) {
|
} else console.error(error);
|
||||||
await resetDB();
|
|
||||||
} else {
|
|
||||||
console.info("数据库已加载!");
|
|
||||||
}
|
}
|
||||||
|
if (!checkDB) await resetDB();
|
||||||
|
else await TGLogger.Info("[App][checkAppLoad] 数据库已成功加载!");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resetDB(): Promise<void> {
|
async function resetDB(): Promise<void> {
|
||||||
@@ -101,8 +102,8 @@ async function resetDB(): Promise<void> {
|
|||||||
color: "error",
|
color: "error",
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
});
|
});
|
||||||
await createDataDir();
|
|
||||||
appStore.loading = true;
|
appStore.loading = true;
|
||||||
|
await TGLogger.Info("[App][resetDB] 数据库已重置!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测 deviceFp
|
// 检测 deviceFp
|
||||||
@@ -111,48 +112,30 @@ async function checkDeviceFp(): Promise<void> {
|
|||||||
const deviceInfo = appData.find((item) => item.key === "deviceInfo")?.value;
|
const deviceInfo = appData.find((item) => item.key === "deviceInfo")?.value;
|
||||||
const deviceLocal = appStore.deviceInfo;
|
const deviceLocal = appStore.deviceInfo;
|
||||||
if (deviceInfo === undefined) {
|
if (deviceInfo === undefined) {
|
||||||
if (deviceLocal.device_fp === "0000000000000") {
|
if (deviceLocal.device_fp === "0000000000000")
|
||||||
appStore.deviceInfo = await TGRequest.Device.getFp(appStore.deviceInfo);
|
appStore.deviceInfo = await TGRequest.Device.getFp(appStore.deviceInfo);
|
||||||
console.info("deviceInfo 已重新获取!");
|
|
||||||
}
|
|
||||||
await TGSqlite.saveAppData("deviceInfo", JSON.stringify(deviceLocal));
|
await TGSqlite.saveAppData("deviceInfo", JSON.stringify(deviceLocal));
|
||||||
console.info("deviceInfo 数据已插入!");
|
return;
|
||||||
} else if (JSON.parse(deviceInfo) !== deviceLocal) {
|
|
||||||
appStore.deviceInfo = JSON.parse(deviceInfo);
|
|
||||||
console.info("deviceInfo 数据已加载!");
|
|
||||||
} else {
|
|
||||||
console.info("deviceInfo 数据已同步!");
|
|
||||||
}
|
}
|
||||||
|
if (JSON.parse(deviceInfo) !== deviceLocal) appStore.deviceInfo = JSON.parse(deviceInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测 ck,info 数据
|
// 检测 ck,info 数据
|
||||||
async function checkUserLoad(): Promise<void> {
|
async function checkUserLoad(): Promise<void> {
|
||||||
const ckDB = await TGSqlite.getCookie();
|
const ckDB = await TGSqlite.getCookie();
|
||||||
if (JSON.stringify(ckDB) === "{}" && appStore.isLogin) {
|
if (JSON.stringify(ckDB) === "{}" && appStore.isLogin) {
|
||||||
await new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
text: "获取 Cookie 失败!请重新登录!",
|
text: "获取 Cookie 失败!请重新登录!",
|
||||||
color: "error",
|
color: "error",
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
});
|
});
|
||||||
resolve(true);
|
|
||||||
}, 3000);
|
|
||||||
});
|
|
||||||
appStore.isLogin = false;
|
appStore.isLogin = false;
|
||||||
|
await TGLogger.Error("[App][checkUserLoad] 获取 Cookie 失败!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (JSON.stringify(ckDB) !== "{}" && !appStore.isLogin) {
|
if (JSON.stringify(ckDB) !== "{}" && !appStore.isLogin) appStore.isLogin = true;
|
||||||
appStore.isLogin = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ckLocal = userStore.cookie;
|
const ckLocal = userStore.cookie;
|
||||||
if (JSON.stringify(ckLocal) !== JSON.stringify(ckDB)) {
|
if (JSON.stringify(ckLocal) !== JSON.stringify(ckDB)) userStore.cookie.value = ckDB;
|
||||||
userStore.cookie.value = ckDB;
|
|
||||||
console.info("cookie 数据已更新!");
|
|
||||||
} else {
|
|
||||||
console.info("cookie 数据已加载!");
|
|
||||||
}
|
|
||||||
const infoLocal = userStore.briefInfo.value;
|
const infoLocal = userStore.briefInfo.value;
|
||||||
const appData = await TGSqlite.getAppData();
|
const appData = await TGSqlite.getAppData();
|
||||||
const infoDB = appData.find((item) => item.key === "userInfo")?.value;
|
const infoDB = appData.find((item) => item.key === "userInfo")?.value;
|
||||||
@@ -161,45 +144,27 @@ async function checkUserLoad(): Promise<void> {
|
|||||||
} else if (infoDB !== undefined && infoLocal !== JSON.parse(infoDB)) {
|
} else if (infoDB !== undefined && infoLocal !== JSON.parse(infoDB)) {
|
||||||
userStore.briefInfo.value = JSON.parse(infoDB);
|
userStore.briefInfo.value = JSON.parse(infoDB);
|
||||||
console.info("briefInfo 数据已更新!");
|
console.info("briefInfo 数据已更新!");
|
||||||
} else {
|
|
||||||
console.info("briefInfo 数据已加载!");
|
|
||||||
}
|
}
|
||||||
const accountLocal = userStore.account.value;
|
const accountLocal = userStore.account.value;
|
||||||
const accountDB = await TGSqlite.getCurAccount();
|
const accountDB = await TGSqlite.getCurAccount();
|
||||||
if (accountDB === false) {
|
if (accountDB === false) {
|
||||||
if (appStore.isLogin) {
|
if (!appStore.isLogin) return;
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
text: "获取 GameAccount 失败!请尝试更新数据库!",
|
text: "获取 GameAccount 失败!请尝试更新数据库!",
|
||||||
color: "error",
|
color: "error",
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
});
|
});
|
||||||
}
|
await TGLogger.Error("[App][checkUserLoad] 获取 GameAccount 失败!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (accountDB !== accountLocal) {
|
if (accountDB !== accountLocal) userStore.account.value = accountDB;
|
||||||
userStore.account.value = accountDB;
|
|
||||||
console.info("curAccount 数据已更新!");
|
|
||||||
} else {
|
|
||||||
console.info("curAccount 数据已加载!");
|
|
||||||
}
|
|
||||||
|
|
||||||
const userDir = appData.find((item) => item.key === "userDir")?.value;
|
const userDir = appData.find((item) => item.key === "userDir")?.value;
|
||||||
if (userDir === undefined) {
|
if (userDir === undefined) {
|
||||||
await TGSqlite.saveAppData("userDir", appStore.userDir);
|
await TGSqlite.saveAppData("userDir", appStore.userDir);
|
||||||
} else if (userDir !== appStore.userDir) {
|
return;
|
||||||
appStore.userDir = userDir;
|
|
||||||
console.info("userDir 数据已更新!");
|
|
||||||
} else {
|
|
||||||
console.info("userDir 数据已加载!");
|
|
||||||
}
|
}
|
||||||
}
|
if (userDir !== appStore.userDir) appStore.userDir = userDir;
|
||||||
|
await fs.createDir(appStore.userDir, { recursive: true });
|
||||||
// 创建数据文件夹
|
|
||||||
async function createDataDir(): Promise<void> {
|
|
||||||
if (!(await fs.exists("userData", { dir: fs.BaseDirectory.AppLocalData }))) {
|
|
||||||
await fs.createDir("userData", { dir: fs.BaseDirectory.AppLocalData, recursive: true });
|
|
||||||
}
|
|
||||||
console.info("数据文件夹创建完成!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getDeepLink(): Promise<void> {
|
async function getDeepLink(): Promise<void> {
|
||||||
@@ -215,8 +180,10 @@ async function getDeepLink(): Promise<void> {
|
|||||||
color: "error",
|
color: "error",
|
||||||
timeout: 3000,
|
timeout: 3000,
|
||||||
});
|
});
|
||||||
|
await TGLogger.Error(`[App][getDeepLink] 无效的 deep link! ${JSON.stringify(e)}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
await TGLogger.Info(`[App][getDeepLink] ${e.payload}`);
|
||||||
if (e.payload === "") return;
|
if (e.payload === "") return;
|
||||||
// 导入格式: teyvatguide://import_uigf?app=appName
|
// 导入格式: teyvatguide://import_uigf?app=appName
|
||||||
// 跳转格式: localhost:4000/achievements/?app=appName
|
// 跳转格式: localhost:4000/achievements/?app=appName
|
||||||
|
|||||||
@@ -50,16 +50,13 @@ function toStore() {
|
|||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.tab-box {
|
.tab-box {
|
||||||
position: fixed;
|
|
||||||
top: 16px;
|
|
||||||
right: 10px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
background-image: linear-gradient(to bottom, rgb(19 84 122 / 80%), rgb(128 208 199 / 80%));
|
background-image: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);
|
||||||
box-shadow: 0 0 10px var(--common-shadow-2);
|
box-shadow: 0 0 10px var(--common-shadow-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
178
src/components/config/tc-dataDir.vue
Normal file
178
src/components/config/tc-dataDir.vue
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
<template>
|
||||||
|
<v-list class="config-list">
|
||||||
|
<v-list-subheader :inset="true" class="config-header" title="路径" />
|
||||||
|
<v-divider :inset="true" class="border-opacity-75" />
|
||||||
|
<v-list-item prepend-icon="mdi-folder-key">
|
||||||
|
<v-list-item-title style="cursor: pointer" @click="confirmCUD"
|
||||||
|
>用户数据目录</v-list-item-title
|
||||||
|
>
|
||||||
|
<v-list-item-subtitle @click="openPath('user')">{{ appStore.userDir }}</v-list-item-subtitle>
|
||||||
|
<template #append>
|
||||||
|
<v-icon @click="copyPath('user')">mdi-content-copy</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item prepend-icon="mdi-folder-account" title="应用数据库路径">
|
||||||
|
<v-list-item-subtitle @click="openPath('db')">{{ appStore.dbPath }}</v-list-item-subtitle>
|
||||||
|
<template #append>
|
||||||
|
<v-icon @click="copyPath('db')">mdi-content-copy</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item prepend-icon="mdi-folder-multiple">
|
||||||
|
<v-list-item-title style="cursor: pointer" @click="confirmCLD">日志目录</v-list-item-title>
|
||||||
|
<v-list-item-subtitle @click="openPath('log')">{{ appStore.logDir }} </v-list-item-subtitle>
|
||||||
|
<template #append>
|
||||||
|
<v-icon @click="copyPath('log')">mdi-content-copy</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { dialog, fs, path } from "@tauri-apps/api";
|
||||||
|
|
||||||
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
|
import { useAppStore } from "../../store/modules/app";
|
||||||
|
import { backUpUserData } from "../../utils/dataBS";
|
||||||
|
import showConfirm from "../func/confirm";
|
||||||
|
import showSnackbar from "../func/snackbar";
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
async function confirmCUD(): Promise<void> {
|
||||||
|
const oriDir = appStore.userDir;
|
||||||
|
const check = await showConfirm({
|
||||||
|
title: "确认修改用户数据路径吗?",
|
||||||
|
text: "祈愿数据需修改后重新手动备份!",
|
||||||
|
});
|
||||||
|
if (!check) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "cancel",
|
||||||
|
text: "已取消修改",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dir = await dialog.open({
|
||||||
|
directory: true,
|
||||||
|
defaultPath: oriDir,
|
||||||
|
multiple: false,
|
||||||
|
});
|
||||||
|
if (dir === null) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "路径不能为空!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof dir !== "string") {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "路径错误!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dir === oriDir) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "warn",
|
||||||
|
text: "路径未修改!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
appStore.userDir = dir;
|
||||||
|
await TGSqlite.saveAppData("userDir", dir);
|
||||||
|
await backUpUserData(dir);
|
||||||
|
await fs.removeDir(oriDir, { recursive: true });
|
||||||
|
showSnackbar({
|
||||||
|
text: "已重新备份数据!即将刷新页面!",
|
||||||
|
timeout: 3000,
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmCLD(): Promise<void> {
|
||||||
|
const check = await showConfirm({
|
||||||
|
title: "确认清理日志文件吗?",
|
||||||
|
text: "将保留一周内的日志文件",
|
||||||
|
});
|
||||||
|
if (!check) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "cancel",
|
||||||
|
text: "已取消清理",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const now = new Date();
|
||||||
|
const nowDate = `${now.getFullYear()}${now.getMonth() + 1}${now.getDate()}`;
|
||||||
|
const logDir = appStore.logDir;
|
||||||
|
const files = await fs.readDir(logDir);
|
||||||
|
const delFiles = files.filter((file) => {
|
||||||
|
const fileName = file.path.split(path.sep).pop()?.replace(".log", "");
|
||||||
|
if (fileName === undefined) return false;
|
||||||
|
const fileDate = parseInt(fileName.replace(/-/g, ""));
|
||||||
|
return fileDate < parseInt(nowDate) - 7;
|
||||||
|
});
|
||||||
|
if (delFiles.length < 1) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "warn",
|
||||||
|
text: "无需清理!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const file of delFiles) {
|
||||||
|
await fs.removeFile(file.path);
|
||||||
|
}
|
||||||
|
showSnackbar({
|
||||||
|
text: `已清理 ${delFiles.length} 个日志文件!`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyPath(type: "db" | "user" | "log"): void {
|
||||||
|
let targetPath: string, targetName: string;
|
||||||
|
switch (type) {
|
||||||
|
case "db":
|
||||||
|
targetPath = appStore.dbPath;
|
||||||
|
targetName = "数据库";
|
||||||
|
break;
|
||||||
|
case "user":
|
||||||
|
targetPath = appStore.userDir;
|
||||||
|
targetName = "用户数据";
|
||||||
|
break;
|
||||||
|
case "log":
|
||||||
|
targetPath = appStore.logDir;
|
||||||
|
targetName = "日志";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
navigator.clipboard.writeText(targetPath);
|
||||||
|
showSnackbar({
|
||||||
|
text: `${targetName}路径已复制!`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openPath(type: "db" | "user" | "log"): Promise<void> {
|
||||||
|
let targetPath: string;
|
||||||
|
switch (type) {
|
||||||
|
case "db":
|
||||||
|
targetPath = appStore.dbPath;
|
||||||
|
break;
|
||||||
|
case "user":
|
||||||
|
targetPath = appStore.userDir;
|
||||||
|
break;
|
||||||
|
case "log":
|
||||||
|
targetPath = appStore.logDir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await dialog.open({
|
||||||
|
directory: type !== "db",
|
||||||
|
defaultPath: targetPath,
|
||||||
|
multiple: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.config-header {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: var(--common-text-title);
|
||||||
|
font-family: var(--font-title);
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
109
src/components/config/tc-info.vue
Normal file
109
src/components/config/tc-info.vue
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<v-list class="config-list">
|
||||||
|
<v-list-subheader :inset="true" class="config-header" title="相关信息" />
|
||||||
|
<v-divider :inset="true" class="border-opacity-75" />
|
||||||
|
<v-list-item title="Tauri 版本" @click="toOuter('https://next--tauri.netlify.app/')">
|
||||||
|
<template #prepend>
|
||||||
|
<v-img class="config-icon" src="/platforms/tauri.webp" alt="Tauri" />
|
||||||
|
</template>
|
||||||
|
<template #append>
|
||||||
|
<v-list-item-subtitle>{{ versionTauri }}</v-list-item-subtitle>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item title="成就版本">
|
||||||
|
<template #prepend>
|
||||||
|
<img class="config-icon" src="../../assets/icons/achievements.svg" alt="Achievements" />
|
||||||
|
</template>
|
||||||
|
<template #append>
|
||||||
|
<v-list-item-subtitle>{{ achievementsStore.lastVersion }}</v-list-item-subtitle>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item title="系统平台" prepend-icon="mdi-microsoft-windows">
|
||||||
|
<template #append>
|
||||||
|
<v-list-item-subtitle>{{ osPlatform }}</v-list-item-subtitle>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item title="系统版本" prepend-icon="mdi-monitor-dashboard">
|
||||||
|
<template #append>
|
||||||
|
<v-list-item-subtitle>{{ osVersion }}</v-list-item-subtitle>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item title="数据库更新时间" prepend-icon="mdi-database-sync">
|
||||||
|
<template #append>
|
||||||
|
<v-list-item-subtitle
|
||||||
|
>{{ dbInfo.find((item) => item.key === "dataUpdated")?.value }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
</template>
|
||||||
|
<v-list-item-subtitle
|
||||||
|
>更新于
|
||||||
|
{{ dbInfo.find((item) => item.key === "dataUpdated")?.updated }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item title="数据库版本" prepend-icon="mdi-database-search">
|
||||||
|
<template #append>
|
||||||
|
<v-list-item-subtitle
|
||||||
|
>{{ dbInfo.find((item) => item.key === "appVersion")?.value }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
</template>
|
||||||
|
<v-list-item-subtitle
|
||||||
|
>更新于
|
||||||
|
{{ dbInfo.find((item) => item.key === "appVersion")?.updated }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { app, os } from "@tauri-apps/api";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
|
||||||
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
|
import { useAchievementsStore } from "../../store/modules/achievements";
|
||||||
|
import showSnackbar from "../func/snackbar";
|
||||||
|
|
||||||
|
const achievementsStore = useAchievementsStore();
|
||||||
|
|
||||||
|
const versionApp = ref<string>("");
|
||||||
|
const versionTauri = ref<string>("");
|
||||||
|
const osPlatform = ref<string>("");
|
||||||
|
const osVersion = ref<string>("");
|
||||||
|
const dbInfo = ref<Array<TGApp.Sqlite.AppData.Item>>([]);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
versionApp.value = await app.getVersion();
|
||||||
|
versionTauri.value = await app.getTauriVersion();
|
||||||
|
osPlatform.value = `${await os.platform()}`;
|
||||||
|
osVersion.value = await os.version();
|
||||||
|
try {
|
||||||
|
dbInfo.value = await TGSqlite.getAppData();
|
||||||
|
} catch (e) {
|
||||||
|
showSnackbar({
|
||||||
|
text: "加载数据库错误,请重置数据库!",
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function toOuter(url: string) {
|
||||||
|
window.open(url);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.config-header {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: var(--common-text-title);
|
||||||
|
font-family: var(--font-title);
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config-icon {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid var(--common-shadow-1);
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-right: 15px;
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
background: var(--app-side-bg);
|
||||||
|
box-shadow: 0 0 5px var(--common-shadow-1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
184
src/components/config/tc-userBadge.vue
Normal file
184
src/components/config/tc-userBadge.vue
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
<template>
|
||||||
|
<ToGameLogin v-model="scan" @success="refreshUser" />
|
||||||
|
<v-card class="tcu-box">
|
||||||
|
<template #prepend>
|
||||||
|
<v-avatar :image="userInfo.avatar" />
|
||||||
|
</template>
|
||||||
|
<template #title>{{ userInfo.nickname }}</template>
|
||||||
|
<template #subtitle>UID:{{ userInfo.uid }}</template>
|
||||||
|
<template #text>{{ userInfo.desc }}</template>
|
||||||
|
<template #actions>
|
||||||
|
<v-spacer />
|
||||||
|
<v-btn variant="outlined" @click="scan = true" icon="mdi-qrcode-scan" />
|
||||||
|
<v-btn variant="outlined" @click="confirmRefreshUser" icon="mdi-refresh" :loading="loading" />
|
||||||
|
</template>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { storeToRefs } from "pinia";
|
||||||
|
import { onMounted, ref } from "vue";
|
||||||
|
|
||||||
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
|
import { useAppStore } from "../../store/modules/app";
|
||||||
|
import { useUserStore } from "../../store/modules/user";
|
||||||
|
import { getDeviceFp } from "../../web/request/getDeviceFp";
|
||||||
|
import TGRequest from "../../web/request/TGRequest";
|
||||||
|
import showConfirm from "../func/confirm";
|
||||||
|
import showSnackbar from "../func/snackbar";
|
||||||
|
import ToGameLogin from "../overlay/to-gameLogin.vue";
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const userStore = storeToRefs(useUserStore());
|
||||||
|
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const scan = ref<boolean>(false);
|
||||||
|
const userInfo = ref<TGApp.App.Account.BriefInfo>({
|
||||||
|
nickname: "未登录",
|
||||||
|
uid: "-1",
|
||||||
|
desc: "请扫码登录",
|
||||||
|
avatar: "/source/UI/lumine.webp",
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (userStore.briefInfo.value && userStore.briefInfo.value.nickname) {
|
||||||
|
userInfo.value = userStore.briefInfo.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// todo 完善 log
|
||||||
|
async function refreshUser() {
|
||||||
|
const ck = userStore.cookie.value;
|
||||||
|
if (ck === undefined || JSON.stringify(ck) === "{}") {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "扫码登录后才能刷新用户信息!",
|
||||||
|
});
|
||||||
|
appStore.isLogin = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
const deviceInfo = appStore.deviceInfo;
|
||||||
|
if (deviceInfo.device_fp === "00000000000") {
|
||||||
|
appStore.deviceInfo = await getDeviceFp(appStore.deviceInfo);
|
||||||
|
}
|
||||||
|
let failCount = 0;
|
||||||
|
const verifyLTokenRes = await TGRequest.User.byLToken.verify(ck.ltoken, ck.ltuid);
|
||||||
|
if (typeof verifyLTokenRes === "string") {
|
||||||
|
showSnackbar({
|
||||||
|
color: "success",
|
||||||
|
text: "验证 LToken 成功!",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showSnackbar({
|
||||||
|
color: "warn",
|
||||||
|
text: "验证 LToken 失败!即将重新获取 LToken",
|
||||||
|
});
|
||||||
|
const ltokenRes = await TGRequest.User.bySToken.getLToken(ck.mid, ck.stoken);
|
||||||
|
if (typeof ltokenRes === "string") {
|
||||||
|
ck.ltoken = ltokenRes;
|
||||||
|
showSnackbar({
|
||||||
|
color: "success",
|
||||||
|
text: "获取 LToken 成功!",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "获取 LToken 失败!",
|
||||||
|
});
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cookieTokenRes = await TGRequest.User.bySToken.getCookieToken(ck.mid, ck.stoken);
|
||||||
|
if (typeof cookieTokenRes === "string") {
|
||||||
|
ck.cookie_token = cookieTokenRes;
|
||||||
|
showSnackbar({
|
||||||
|
color: "success",
|
||||||
|
text: "获取 CookieToken 成功!",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "获取 CookieToken 失败!",
|
||||||
|
});
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
userStore.cookie.value = ck;
|
||||||
|
await TGSqlite.saveAppData("cookie", JSON.stringify(ck));
|
||||||
|
const infoRes = await TGRequest.User.byCookie.getUserInfo(ck.cookie_token, ck.account_id);
|
||||||
|
if ("retcode" in infoRes) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "获取用户信息失败!",
|
||||||
|
});
|
||||||
|
failCount++;
|
||||||
|
} else {
|
||||||
|
const briefInfo: TGApp.App.Account.BriefInfo = {
|
||||||
|
nickname: infoRes.nickname,
|
||||||
|
uid: infoRes.uid,
|
||||||
|
avatar: infoRes.avatar_url,
|
||||||
|
desc: infoRes.introduce,
|
||||||
|
};
|
||||||
|
userStore.briefInfo.value = briefInfo;
|
||||||
|
await TGSqlite.saveAppData("userInfo", JSON.stringify(briefInfo));
|
||||||
|
showSnackbar({
|
||||||
|
color: "success",
|
||||||
|
text: "获取用户信息成功!",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const accountRes = await TGRequest.User.byCookie.getAccounts(ck.cookie_token, ck.account_id);
|
||||||
|
if (Array.isArray(accountRes)) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "success",
|
||||||
|
text: "获取账号信息成功!",
|
||||||
|
});
|
||||||
|
await TGSqlite.saveAccount(accountRes);
|
||||||
|
const curAccount = await TGSqlite.getCurAccount();
|
||||||
|
if (curAccount) userStore.account.value = curAccount;
|
||||||
|
} else {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "获取账号信息失败!",
|
||||||
|
});
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
if (failCount > 0) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "刷新失败!重试或者重新扫码登录!",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
showSnackbar({ text: "刷新成功!" });
|
||||||
|
appStore.isLogin = true;
|
||||||
|
}
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function confirmRefreshUser(): Promise<void> {
|
||||||
|
const res = await showConfirm({
|
||||||
|
title: "确认刷新用户信息吗?",
|
||||||
|
text: "将会重新获取用户信息",
|
||||||
|
});
|
||||||
|
if (!res) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "cancel",
|
||||||
|
text: "已取消刷新",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!userStore.cookie) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "请先登录",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await refreshUser();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.tcu-box {
|
||||||
|
border-radius: 10px;
|
||||||
|
background-image: linear-gradient(to right, #f78ca0 0%, #f9748f 19%, #fd868c 60%, #fe9a8b 100%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,89 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- todo ui 优化 -->
|
||||||
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
||||||
<ToGameLogin v-model="scan" @success="refreshUser" />
|
|
||||||
<div class="config-box">
|
<div class="config-box">
|
||||||
|
<TcInfo />
|
||||||
<v-list class="config-list">
|
<v-list class="config-list">
|
||||||
<v-list-subheader :inset="true" class="config-header" title="应用信息" />
|
|
||||||
<v-divider :inset="true" class="border-opacity-75" />
|
|
||||||
<v-list-item title="Tauri 版本" @click="toOuter('https://next--tauri.netlify.app/')">
|
|
||||||
<template #prepend>
|
|
||||||
<img class="config-icon" src="/platforms/tauri.webp" alt="Tauri" />
|
|
||||||
</template>
|
|
||||||
<template #append>
|
|
||||||
<v-list-item-subtitle>{{ versionTauri }}</v-list-item-subtitle>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item title="成就版本">
|
|
||||||
<template #prepend>
|
|
||||||
<img class="config-icon" src="../../assets/icons/achievements.svg" alt="Achievements" />
|
|
||||||
</template>
|
|
||||||
<template #append>
|
|
||||||
<v-list-item-subtitle>{{ achievementsStore.lastVersion }}</v-list-item-subtitle>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item title="登录信息">
|
|
||||||
<v-list-item-subtitle v-show="userInfo?.nickname !== '未登录'">
|
|
||||||
{{ userInfo?.nickname }} uid:{{ userInfo?.uid }}
|
|
||||||
</v-list-item-subtitle>
|
|
||||||
<v-list-item-subtitle v-show="userInfo?.nickname === '未登录'">
|
|
||||||
未登录,请扫码登录!
|
|
||||||
</v-list-item-subtitle>
|
|
||||||
<template #prepend>
|
|
||||||
<img class="config-icon user" :src="userInfo?.avatar" alt="Login" />
|
|
||||||
</template>
|
|
||||||
<template #append>
|
|
||||||
<v-btn class="config-btn" @click="confirmScanLogin">扫码登录</v-btn>
|
|
||||||
<v-btn class="config-btn" @click="confirmRefreshUser"> 刷新数据</v-btn>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-subheader :inset="true" class="config-header" title="系统信息" />
|
|
||||||
<v-divider :inset="true" class="border-opacity-75" />
|
|
||||||
<v-list-item title="系统平台" prepend-icon="mdi-microsoft-windows">
|
|
||||||
<template #append>
|
|
||||||
<v-list-item-subtitle>{{ osPlatform }}</v-list-item-subtitle>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item title="系统版本" prepend-icon="mdi-monitor-dashboard">
|
|
||||||
<template #append>
|
|
||||||
<v-list-item-subtitle>{{ osVersion }}</v-list-item-subtitle>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item title="数据库更新时间" prepend-icon="mdi-database-sync">
|
|
||||||
<template #append>
|
|
||||||
<v-list-item-subtitle
|
|
||||||
>{{ dbInfo.find((item) => item.key === "dataUpdated")?.value }}
|
|
||||||
</v-list-item-subtitle>
|
|
||||||
</template>
|
|
||||||
<v-list-item-subtitle
|
|
||||||
>更新于
|
|
||||||
{{ dbInfo.find((item) => item.key === "dataUpdated")?.updated }}
|
|
||||||
</v-list-item-subtitle>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item title="数据库版本" prepend-icon="mdi-database-search">
|
|
||||||
<template #append>
|
|
||||||
<v-list-item-subtitle
|
|
||||||
>{{ dbInfo.find((item) => item.key === "appVersion")?.value }}
|
|
||||||
</v-list-item-subtitle>
|
|
||||||
</template>
|
|
||||||
<v-list-item-subtitle
|
|
||||||
>更新于
|
|
||||||
{{ dbInfo.find((item) => item.key === "appVersion")?.updated }}
|
|
||||||
</v-list-item-subtitle>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-subheader :inset="true" class="config-header" title="设置" />
|
<v-list-subheader :inset="true" class="config-header" title="设置" />
|
||||||
<v-divider :inset="true" class="border-opacity-75" />
|
<v-divider :inset="true" class="border-opacity-75" />
|
||||||
<v-list-item prepend-icon="mdi-camera-iris">
|
|
||||||
<v-select
|
|
||||||
v-model="showHome"
|
|
||||||
:items="homeStore.getShowItems()"
|
|
||||||
label="首页显示组件"
|
|
||||||
:multiple="true"
|
|
||||||
:chips="true"
|
|
||||||
/>
|
|
||||||
<template #append>
|
|
||||||
<v-btn class="config-btn" @click="submitHome"> 确定</v-btn>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item prepend-icon="mdi-database-export" title="数据备份" @click="confirmBackup" />
|
<v-list-item prepend-icon="mdi-database-export" title="数据备份" @click="confirmBackup" />
|
||||||
<v-list-item prepend-icon="mdi-database-import" title="数据恢复" @click="confirmRestore" />
|
<v-list-item prepend-icon="mdi-database-import" title="数据恢复" @click="confirmRestore" />
|
||||||
<v-list-item prepend-icon="mdi-database-arrow-up" title="数据更新" @click="confirmUpdate()" />
|
<v-list-item prepend-icon="mdi-database-arrow-up" title="数据更新" @click="confirmUpdate()" />
|
||||||
@@ -119,253 +41,88 @@
|
|||||||
@click="confirmResetDB()"
|
@click="confirmResetDB()"
|
||||||
/>
|
/>
|
||||||
<v-list-item prepend-icon="mdi-cog-sync" title="恢复默认设置" @click="confirmResetApp" />
|
<v-list-item prepend-icon="mdi-cog-sync" title="恢复默认设置" @click="confirmResetApp" />
|
||||||
<v-list-subheader :inset="true" class="config-header" title="路径" />
|
|
||||||
<v-divider :inset="true" class="border-opacity-75" />
|
|
||||||
<v-list-item prepend-icon="mdi-folder-key">
|
|
||||||
<v-list-item-title style="cursor: pointer" @click="confirmCUD"
|
|
||||||
>用户数据目录</v-list-item-title
|
|
||||||
>
|
|
||||||
<v-list-item-subtitle>{{ appStore.userDir }}</v-list-item-subtitle>
|
|
||||||
<template #append>
|
|
||||||
<v-icon @click="copyPath('user')">mdi-content-copy</v-icon>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
<v-list-item
|
|
||||||
prepend-icon="mdi-folder-account"
|
|
||||||
title="应用数据库路径"
|
|
||||||
:subtitle="appStore.dbPath"
|
|
||||||
>
|
|
||||||
<template #append>
|
|
||||||
<v-icon @click="copyPath('db')">mdi-content-copy</v-icon>
|
|
||||||
</template>
|
|
||||||
</v-list-item>
|
|
||||||
</v-list>
|
</v-list>
|
||||||
<TAppBadge />
|
<TcDataDir />
|
||||||
|
</div>
|
||||||
|
<div class="config-right">
|
||||||
|
<TcAppBadge />
|
||||||
|
<TcUserBadge />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { app, dialog, fs, invoke, os, process as TauriProcess } from "@tauri-apps/api";
|
import { dialog, fs, invoke, process as TauriProcess } from "@tauri-apps/api";
|
||||||
import { storeToRefs } from "pinia";
|
import { onMounted, ref } from "vue";
|
||||||
import { computed, onMounted, ref } from "vue";
|
|
||||||
|
|
||||||
import TAppBadge from "../../components/app/t-appBadge.vue";
|
import TcAppBadge from "../../components/config/tc-appBadge.vue";
|
||||||
|
import TcDataDir from "../../components/config/tc-dataDir.vue";
|
||||||
|
import TcInfo from "../../components/config/tc-info.vue";
|
||||||
|
import TcUserBadge from "../../components/config/tc-userBadge.vue";
|
||||||
import showConfirm from "../../components/func/confirm";
|
import showConfirm from "../../components/func/confirm";
|
||||||
import showSnackbar from "../../components/func/snackbar";
|
import showSnackbar from "../../components/func/snackbar";
|
||||||
import ToGameLogin from "../../components/overlay/to-gameLogin.vue";
|
|
||||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||||
import TGSqlite from "../../plugins/Sqlite";
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
import { useAchievementsStore } from "../../store/modules/achievements";
|
import { useAchievementsStore } from "../../store/modules/achievements";
|
||||||
import { useAppStore } from "../../store/modules/app";
|
import { useAppStore } from "../../store/modules/app";
|
||||||
import { useHomeStore } from "../../store/modules/home";
|
import { useHomeStore } from "../../store/modules/home";
|
||||||
import { useUserStore } from "../../store/modules/user";
|
|
||||||
import { backUpUserData, restoreUserData } from "../../utils/dataBS";
|
import { backUpUserData, restoreUserData } from "../../utils/dataBS";
|
||||||
import { getBuildTime } from "../../utils/TGBuild";
|
import { getBuildTime } from "../../utils/TGBuild";
|
||||||
import { bytesToSize, getCacheDir, getDeviceInfo, getRandomString } from "../../utils/toolFunc";
|
import { bytesToSize, getCacheDir, getDeviceInfo, getRandomString } from "../../utils/toolFunc";
|
||||||
import { getDeviceFp } from "../../web/request/getDeviceFp";
|
|
||||||
import TGRequest from "../../web/request/TGRequest";
|
import TGRequest from "../../web/request/TGRequest";
|
||||||
|
|
||||||
// Store
|
// Store
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const userStore = storeToRefs(useUserStore());
|
|
||||||
const homeStore = useHomeStore();
|
const homeStore = useHomeStore();
|
||||||
const achievementsStore = useAchievementsStore();
|
const achievementsStore = useAchievementsStore();
|
||||||
|
|
||||||
const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
|
const isDevEnv = ref<boolean>(import.meta.env.MODE === "development");
|
||||||
|
|
||||||
// About App
|
|
||||||
const versionApp = ref<string>("");
|
|
||||||
const versionTauri = ref<string>("");
|
|
||||||
|
|
||||||
// About OS
|
|
||||||
const osPlatform = ref<string>("");
|
|
||||||
const osVersion = ref<string>("");
|
|
||||||
const dbInfo = ref<Array<TGApp.Sqlite.AppData.Item>>([]);
|
|
||||||
|
|
||||||
// loading
|
// loading
|
||||||
const loading = ref<boolean>(true);
|
const loading = ref<boolean>(true);
|
||||||
const loadingTitle = ref<string>("正在加载...");
|
const loadingTitle = ref<string>("正在加载...");
|
||||||
const loadingSub = ref<string>("");
|
const loadingSub = ref<string>("");
|
||||||
const scan = ref<boolean>(false);
|
|
||||||
const showReset = ref<boolean>(false);
|
const showReset = ref<boolean>(false);
|
||||||
|
|
||||||
// data
|
onMounted(() => (loading.value = false));
|
||||||
const showHome = ref<string[]>(homeStore.getShowValue());
|
|
||||||
const userInfo = computed(() => {
|
|
||||||
const info = userStore.briefInfo;
|
|
||||||
if (info.value && info.value.nickname) {
|
|
||||||
return {
|
|
||||||
nickname: info.value.nickname,
|
|
||||||
uid: info.value.uid,
|
|
||||||
desc: info.value.desc,
|
|
||||||
avatar: info.value.avatar,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
nickname: "未登录",
|
|
||||||
uid: "-1",
|
|
||||||
desc: "请扫码登录",
|
|
||||||
avatar: "/source/UI/lumine.webp",
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// load version
|
|
||||||
onMounted(async () => {
|
|
||||||
loadingSub.value = "正在获取应用版本";
|
|
||||||
versionApp.value = await app.getVersion();
|
|
||||||
loadingSub.value = "正在获取 Tauri 版本";
|
|
||||||
versionTauri.value = await app.getTauriVersion();
|
|
||||||
loadingSub.value = "正在获取系统信息";
|
|
||||||
osPlatform.value = `${await os.platform()}`;
|
|
||||||
loadingSub.value = "正在获取系统版本";
|
|
||||||
osVersion.value = await os.version();
|
|
||||||
loadingSub.value = "正在获取数据库信息";
|
|
||||||
try {
|
|
||||||
dbInfo.value = await TGSqlite.getAppData();
|
|
||||||
} catch (e) {
|
|
||||||
showSnackbar({
|
|
||||||
text: "加载数据库错误,请重置数据库!",
|
|
||||||
color: "error",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
loadingSub.value = "";
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 打开外部链接
|
|
||||||
function toOuter(url: string): void {
|
|
||||||
window.open(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 扫码登录
|
|
||||||
async function confirmScanLogin(): Promise<void> {
|
|
||||||
scan.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 刷新用户信息
|
|
||||||
async function confirmRefreshUser(): Promise<void> {
|
|
||||||
const res = await showConfirm({
|
|
||||||
title: "确认刷新用户信息吗?",
|
|
||||||
text: "将会重新获取用户信息",
|
|
||||||
});
|
|
||||||
if (!res) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "cancel",
|
|
||||||
text: "已取消刷新",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!userStore.cookie) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "error",
|
|
||||||
text: "请先登录",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await refreshUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 刷新用户信息
|
|
||||||
async function refreshUser(): Promise<void> {
|
|
||||||
const ck = userStore.cookie.value;
|
|
||||||
if (ck === undefined || JSON.stringify(ck) === "{}") {
|
|
||||||
showSnackbar({
|
|
||||||
color: "error",
|
|
||||||
text: "扫码登录后才能刷新用户信息!",
|
|
||||||
});
|
|
||||||
appStore.isLogin = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const deviceInfo = appStore.deviceInfo;
|
|
||||||
if (deviceInfo.device_fp === "00000000000") {
|
|
||||||
appStore.deviceInfo = await getDeviceFp(appStore.deviceInfo);
|
|
||||||
}
|
|
||||||
let failCount = 0;
|
|
||||||
loadingTitle.value = "正在验证 ltoken...";
|
|
||||||
loading.value = true;
|
|
||||||
const verifyLTokenRes = await TGRequest.User.byLToken.verify(ck.ltoken, ck.ltuid);
|
|
||||||
if (typeof verifyLTokenRes === "string") {
|
|
||||||
loadingTitle.value = "验证成功!正在刷新 cookie_token";
|
|
||||||
} else {
|
|
||||||
console.error(verifyLTokenRes);
|
|
||||||
loadingTitle.value = "验证失败!正在重新获取 ltoken";
|
|
||||||
const ltokenRes = await TGRequest.User.bySToken.getLToken(ck.mid, ck.stoken);
|
|
||||||
if (typeof ltokenRes === "string") {
|
|
||||||
ck.ltoken = ltokenRes;
|
|
||||||
loadingTitle.value = "刷新成功!正在获取用户头像、昵称信息";
|
|
||||||
} else {
|
|
||||||
console.error(ltokenRes);
|
|
||||||
loadingTitle.value = "刷新失败!正在获取用户头像、昵称信息";
|
|
||||||
failCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const cookieTokenRes = await TGRequest.User.bySToken.getCookieToken(ck.mid, ck.stoken);
|
|
||||||
if (typeof cookieTokenRes === "string") {
|
|
||||||
ck.cookie_token = cookieTokenRes;
|
|
||||||
console.log(JSON.stringify(ck));
|
|
||||||
loadingTitle.value = "刷新成功!正在获取用户头像、昵称信息";
|
|
||||||
} else {
|
|
||||||
console.error(cookieTokenRes);
|
|
||||||
loadingTitle.value = "刷新失败!正在获取用户头像、昵称信息";
|
|
||||||
failCount++;
|
|
||||||
}
|
|
||||||
userStore.cookie.value = ck;
|
|
||||||
await TGSqlite.saveAppData("cookie", JSON.stringify(ck));
|
|
||||||
const infoRes = await TGRequest.User.byCookie.getUserInfo(ck.cookie_token, ck.account_id);
|
|
||||||
if ("retcode" in infoRes) {
|
|
||||||
console.error(infoRes);
|
|
||||||
loadingTitle.value = "获取失败!正在获取用户游戏账号信息";
|
|
||||||
failCount++;
|
|
||||||
} else {
|
|
||||||
const briefInfo: TGApp.App.Account.BriefInfo = {
|
|
||||||
nickname: infoRes.nickname,
|
|
||||||
uid: infoRes.uid,
|
|
||||||
avatar: infoRes.avatar_url,
|
|
||||||
desc: infoRes.introduce,
|
|
||||||
};
|
|
||||||
userStore.briefInfo.value = briefInfo;
|
|
||||||
await TGSqlite.saveAppData("userInfo", JSON.stringify(briefInfo));
|
|
||||||
loadingTitle.value = "获取成功!正在获取用户游戏账号信息";
|
|
||||||
}
|
|
||||||
const accountRes = await TGRequest.User.byCookie.getAccounts(ck.cookie_token, ck.account_id);
|
|
||||||
if (Array.isArray(accountRes)) {
|
|
||||||
loadingTitle.value = "获取成功!正在保存到数据库!";
|
|
||||||
await TGSqlite.saveAccount(accountRes);
|
|
||||||
const curAccount = await TGSqlite.getCurAccount();
|
|
||||||
if (curAccount) userStore.account.value = curAccount;
|
|
||||||
} else {
|
|
||||||
console.error(accountRes);
|
|
||||||
loadingTitle.value = "获取失败!";
|
|
||||||
failCount++;
|
|
||||||
}
|
|
||||||
loading.value = false;
|
|
||||||
if (failCount > 0) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "error",
|
|
||||||
text: "刷新失败!重试或者重新扫码登录!",
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
showSnackbar({ text: "刷新成功!" });
|
|
||||||
appStore.isLogin = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 备份数据
|
// 备份数据
|
||||||
async function confirmBackup(): Promise<void> {
|
async function confirmBackup(): Promise<void> {
|
||||||
const res = await showConfirm({
|
const res = await showConfirm({
|
||||||
title: "确认备份数据吗?",
|
title: "是否备份到默认路径",
|
||||||
text: "若已备份将会被覆盖,祈愿数据备份请到对应页面执行",
|
text: "取消则自选路径,点击外部不做处理",
|
||||||
});
|
});
|
||||||
if (!res) {
|
if (res === undefined) {
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
color: "cancel",
|
color: "cancel",
|
||||||
text: "已取消备份",
|
text: "已取消备份",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let saveDir = appStore.userDir;
|
||||||
|
if (res === false) {
|
||||||
|
const dir = await dialog.open({
|
||||||
|
directory: true,
|
||||||
|
defaultPath: saveDir,
|
||||||
|
multiple: false,
|
||||||
|
});
|
||||||
|
if (dir === null) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "路径不能为空!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof dir !== "string") {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "路径错误!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
saveDir = dir;
|
||||||
|
}
|
||||||
loadingTitle.value = "正在备份数据...";
|
loadingTitle.value = "正在备份数据...";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const saveDir = appStore.userDir;
|
|
||||||
loadingSub.value = "祈愿数据需单独备份";
|
loadingSub.value = "祈愿数据需单独备份";
|
||||||
await backUpUserData(saveDir);
|
await backUpUserData(saveDir);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@@ -375,28 +132,46 @@ async function confirmBackup(): Promise<void> {
|
|||||||
// 恢复数据
|
// 恢复数据
|
||||||
async function confirmRestore(): Promise<void> {
|
async function confirmRestore(): Promise<void> {
|
||||||
const resConfirm = await showConfirm({
|
const resConfirm = await showConfirm({
|
||||||
title: "确认恢复数据吗?",
|
title: "是否从默认路径恢复",
|
||||||
text: "请确保存在备份数据,祈愿数据恢复请到对应页面执行",
|
text: "取消则自选路径,点击外部不做处理",
|
||||||
});
|
});
|
||||||
if (!resConfirm) {
|
if (resConfirm === undefined) {
|
||||||
showSnackbar({
|
showSnackbar({
|
||||||
color: "cancel",
|
color: "cancel",
|
||||||
text: "已取消恢复",
|
text: "已取消恢复",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// todo 自定义路径
|
let saveDir = appStore.userDir;
|
||||||
|
if (resConfirm === false) {
|
||||||
|
const dir = await dialog.open({
|
||||||
|
directory: true,
|
||||||
|
defaultPath: saveDir,
|
||||||
|
multiple: false,
|
||||||
|
});
|
||||||
|
if (dir === null) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "路径不能为空!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof dir !== "string") {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "路径错误!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
saveDir = dir;
|
||||||
|
}
|
||||||
loadingTitle.value = "正在恢复数据...";
|
loadingTitle.value = "正在恢复数据...";
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
loadingSub.value = "祈愿数据需单独恢复";
|
loadingSub.value = "祈愿数据需单独恢复";
|
||||||
const saveDir = appStore.userDir;
|
|
||||||
await restoreUserData(saveDir);
|
await restoreUserData(saveDir);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo 设置自定义数据保存路径并进行数据迁移
|
|
||||||
// todo macOS 需要测试
|
|
||||||
|
|
||||||
// 更新数据
|
// 更新数据
|
||||||
async function confirmUpdate(title?: string): Promise<void> {
|
async function confirmUpdate(title?: string): Promise<void> {
|
||||||
const res = await showConfirm({
|
const res = await showConfirm({
|
||||||
@@ -608,94 +383,18 @@ function submitDevMode(): void {
|
|||||||
? showSnackbar({ text: "已关闭 dev 模式!" })
|
? showSnackbar({ text: "已关闭 dev 模式!" })
|
||||||
: showSnackbar({ text: "已开启 dev 模式!" });
|
: showSnackbar({ text: "已开启 dev 模式!" });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改首页显示
|
|
||||||
function submitHome(): void {
|
|
||||||
// 获取已选
|
|
||||||
const show = showHome.value;
|
|
||||||
if (show.length < 1) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "error",
|
|
||||||
text: "请至少选择一个!",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 设置
|
|
||||||
homeStore.setShowValue(show);
|
|
||||||
showSnackbar({ text: "已修改!" });
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyPath(type: "db" | "user"): void {
|
|
||||||
const path = type === "db" ? appStore.dbPath : appStore.userDir;
|
|
||||||
navigator.clipboard.writeText(path);
|
|
||||||
const content = type === "db" ? "数据库" : "用户数据";
|
|
||||||
showSnackbar({
|
|
||||||
text: `${content}路径已复制!`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function confirmCUD(): Promise<void> {
|
|
||||||
const oriDir = appStore.userDir;
|
|
||||||
const check = await showConfirm({
|
|
||||||
title: "确认修改用户数据路径吗?",
|
|
||||||
text: "祈愿数据需修改后重新手动备份!",
|
|
||||||
});
|
|
||||||
if (!check) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "cancel",
|
|
||||||
text: "已取消修改",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const dir = await dialog.open({
|
|
||||||
directory: true,
|
|
||||||
defaultPath: oriDir,
|
|
||||||
multiple: false,
|
|
||||||
});
|
|
||||||
if (dir === null) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "error",
|
|
||||||
text: "路径不能为空!",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (typeof dir !== "string") {
|
|
||||||
showSnackbar({
|
|
||||||
color: "error",
|
|
||||||
text: "路径错误!",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dir === oriDir) {
|
|
||||||
showSnackbar({
|
|
||||||
color: "warn",
|
|
||||||
text: "路径未修改!",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
appStore.userDir = dir;
|
|
||||||
await TGSqlite.saveAppData("userDir", dir);
|
|
||||||
await backUpUserData(dir);
|
|
||||||
await fs.removeDir(oriDir, { recursive: true });
|
|
||||||
showSnackbar({
|
|
||||||
text: "已重新备份数据!即将刷新页面!",
|
|
||||||
timeout: 3000,
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.reload();
|
|
||||||
}, 4000);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
.config-box {
|
.config-box {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: compact;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
row-gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-list {
|
.config-list {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
margin-right: 220px;
|
margin-right: 260px;
|
||||||
background: var(--box-bg-1);
|
background: var(--box-bg-1);
|
||||||
color: var(--box-text-4);
|
color: var(--box-text-4);
|
||||||
font-family: var(--font-text);
|
font-family: var(--font-text);
|
||||||
@@ -708,27 +407,13 @@ async function confirmCUD(): Promise<void> {
|
|||||||
font-size: large;
|
font-size: large;
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-icon {
|
.config-right {
|
||||||
width: 40px;
|
position: fixed;
|
||||||
height: 40px;
|
top: 16px;
|
||||||
padding: 5px;
|
right: 10px;
|
||||||
border: 1px solid var(--common-shadow-1);
|
display: flex;
|
||||||
border-radius: 5px;
|
width: 256px;
|
||||||
margin-right: 15px;
|
flex-direction: column;
|
||||||
backdrop-filter: blur(20px);
|
row-gap: 15px;
|
||||||
background: var(--app-side-bg);
|
|
||||||
box-shadow: 0 0 5px var(--common-shadow-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.config-icon.user {
|
|
||||||
padding: 2px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.config-btn {
|
|
||||||
width: 100px;
|
|
||||||
margin-left: 20px;
|
|
||||||
background: var(--tgc-btn-1);
|
|
||||||
color: var(--btn-text);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,16 +1,29 @@
|
|||||||
<template>
|
<template>
|
||||||
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSubtitle" />
|
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSubtitle" />
|
||||||
<div class="home-container">
|
<div class="home-container">
|
||||||
|
<div class="home-select">
|
||||||
|
<v-select
|
||||||
|
variant="outlined"
|
||||||
|
v-model="showHome"
|
||||||
|
:items="homeStore.getShowItems()"
|
||||||
|
hide-details
|
||||||
|
:multiple="true"
|
||||||
|
:chips="true"
|
||||||
|
/>
|
||||||
|
<v-btn class="select-btn" @click="submitHome">确定</v-btn>
|
||||||
|
</div>
|
||||||
<component :is="item" v-for="item in components" :key="item" :ref="setItemRef" />
|
<component :is="item" v-for="item in components" :key="item" :ref="setItemRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { markRaw, onMounted, onUnmounted, onUpdated, ref } from "vue";
|
import { computed, markRaw, onMounted, onUnmounted, onUpdated, ref, watch } from "vue";
|
||||||
|
|
||||||
|
import showSnackbar from "../../components/func/snackbar";
|
||||||
import TCalendar from "../../components/home/t-calendar.vue";
|
import TCalendar from "../../components/home/t-calendar.vue";
|
||||||
import TPool from "../../components/home/t-pool.vue";
|
import TPool from "../../components/home/t-pool.vue";
|
||||||
import TPosition from "../../components/home/t-position.vue";
|
import TPosition from "../../components/home/t-position.vue";
|
||||||
|
import TUserBadge from "../../components/home/t-userBadge.vue";
|
||||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||||
import { useAppStore } from "../../store/modules/app";
|
import { useAppStore } from "../../store/modules/app";
|
||||||
import { useHomeStore } from "../../store/modules/home";
|
import { useHomeStore } from "../../store/modules/home";
|
||||||
@@ -27,10 +40,16 @@ const loadingSubtitle = ref<string>("");
|
|||||||
// data
|
// data
|
||||||
const components = ref<any[]>([]);
|
const components = ref<any[]>([]);
|
||||||
const itemRefs = ref<any[]>([]);
|
const itemRefs = ref<any[]>([]);
|
||||||
|
const showHome = ref<string[]>(homeStore.getShowValue());
|
||||||
|
|
||||||
// 定时器
|
// 定时器
|
||||||
const timer = ref<any>(null);
|
const timer = ref<any>(null);
|
||||||
|
|
||||||
|
function setItemRef(item: any): void {
|
||||||
|
if (itemRefs.value.includes(item)) return;
|
||||||
|
itemRefs.value.push(item);
|
||||||
|
}
|
||||||
|
|
||||||
function readLoading(): void {
|
function readLoading(): void {
|
||||||
if (!loading.value) return;
|
if (!loading.value) return;
|
||||||
let loadingMap = itemRefs.value.map((item) => {
|
let loadingMap = itemRefs.value.map((item) => {
|
||||||
@@ -49,9 +68,8 @@ onMounted(async () => {
|
|||||||
if (isProdEnv && appStore.devMode) {
|
if (isProdEnv && appStore.devMode) {
|
||||||
appStore.devMode = false;
|
appStore.devMode = false;
|
||||||
}
|
}
|
||||||
const showItems = homeStore.getShowValue();
|
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(
|
||||||
showItems.map((item) => {
|
showHome.value.map((item) => {
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case "限时祈愿":
|
case "限时祈愿":
|
||||||
return components.value.push(markRaw(TPool));
|
return components.value.push(markRaw(TPool));
|
||||||
@@ -67,9 +85,24 @@ onMounted(async () => {
|
|||||||
timer.value = setInterval(readLoading, 100);
|
timer.value = setInterval(readLoading, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
function setItemRef(item: any): void {
|
function submitHome(): void {
|
||||||
if (itemRefs.value.includes(item)) return;
|
// 获取已选
|
||||||
itemRefs.value.push(item);
|
const show = showHome.value;
|
||||||
|
if (show.length < 1) {
|
||||||
|
showSnackbar({
|
||||||
|
color: "error",
|
||||||
|
text: "请至少选择一个!",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
homeStore.setShowValue(show);
|
||||||
|
showSnackbar({
|
||||||
|
color: "success",
|
||||||
|
text: "设置成功!",
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload();
|
||||||
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听定时器
|
// 监听定时器
|
||||||
@@ -82,6 +115,22 @@ onUnmounted(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
|
.home-select {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-btn {
|
||||||
|
width: 100px;
|
||||||
|
height: 40px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-top: 8px;
|
||||||
|
background: var(--tgc-btn-1);
|
||||||
|
color: var(--btn-text);
|
||||||
|
}
|
||||||
|
|
||||||
.home-container {
|
.home-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* @file store/modules/app.ts
|
* @file store/modules/app.ts
|
||||||
* @description App store module
|
* @description App store module
|
||||||
* @since Beta v0.4.1
|
* @since Beta v0.4.2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { path } from "@tauri-apps/api";
|
import { path } from "@tauri-apps/api";
|
||||||
@@ -14,6 +14,8 @@ import { getInitDeviceInfo } from "../../utils/toolFunc";
|
|||||||
const userDataDir = `${await path.appLocalDataDir()}userData`;
|
const userDataDir = `${await path.appLocalDataDir()}userData`;
|
||||||
// 用于存放数据库的路径
|
// 用于存放数据库的路径
|
||||||
const dbDataPath = `${await path.appConfigDir()}TeyvatGuide.db`;
|
const dbDataPath = `${await path.appConfigDir()}TeyvatGuide.db`;
|
||||||
|
// 用于存放日志的路径
|
||||||
|
const logDataDir = `${await path.appConfigDir()}logs`;
|
||||||
|
|
||||||
export const useAppStore = defineStore(
|
export const useAppStore = defineStore(
|
||||||
"app",
|
"app",
|
||||||
@@ -37,6 +39,8 @@ export const useAppStore = defineStore(
|
|||||||
const userDir = ref(userDataDir);
|
const userDir = ref(userDataDir);
|
||||||
// 数据库路径
|
// 数据库路径
|
||||||
const dbPath = ref(dbDataPath);
|
const dbPath = ref(dbDataPath);
|
||||||
|
// 日志目录
|
||||||
|
const logDir = ref(logDataDir);
|
||||||
// 设备信息
|
// 设备信息
|
||||||
const deviceInfo = ref<TGApp.App.Device.DeviceInfo>(getInitDeviceInfo());
|
const deviceInfo = ref<TGApp.App.Device.DeviceInfo>(getInitDeviceInfo());
|
||||||
|
|
||||||
@@ -68,6 +72,7 @@ export const useAppStore = defineStore(
|
|||||||
isLogin,
|
isLogin,
|
||||||
userDir,
|
userDir,
|
||||||
dbPath,
|
dbPath,
|
||||||
|
logDir,
|
||||||
init,
|
init,
|
||||||
changeTheme,
|
changeTheme,
|
||||||
};
|
};
|
||||||
@@ -77,7 +82,7 @@ export const useAppStore = defineStore(
|
|||||||
{
|
{
|
||||||
key: "appPath",
|
key: "appPath",
|
||||||
storage: window.localStorage,
|
storage: window.localStorage,
|
||||||
paths: ["userDir", "dbPath"],
|
paths: ["userDir", "dbPath", "logDir"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: "app",
|
key: "app",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
|||||||
import TShareBtn from "../components/main/t-shareBtn.vue";
|
import TShareBtn from "../components/main/t-shareBtn.vue";
|
||||||
import ToLoading from "../components/overlay/to-loading.vue";
|
import ToLoading from "../components/overlay/to-loading.vue";
|
||||||
import { useAppStore } from "../store/modules/app";
|
import { useAppStore } from "../store/modules/app";
|
||||||
|
import TGLogger from "../utils/TGLogger";
|
||||||
import { saveImgLocal } from "../utils/TGShare";
|
import { saveImgLocal } from "../utils/TGShare";
|
||||||
import { createTGWindow } from "../utils/TGWindow";
|
import { createTGWindow } from "../utils/TGWindow";
|
||||||
import TGRequest from "../web/request/TGRequest";
|
import TGRequest from "../web/request/TGRequest";
|
||||||
@@ -57,6 +58,7 @@ onMounted(async () => {
|
|||||||
if (!annoId) {
|
if (!annoId) {
|
||||||
loadingEmpty.value = true;
|
loadingEmpty.value = true;
|
||||||
loadingTitle.value = "未找到数据";
|
loadingTitle.value = "未找到数据";
|
||||||
|
await TGLogger.Error("[t-anno.vue] 未找到数据");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 获取数据
|
// 获取数据
|
||||||
@@ -70,7 +72,9 @@ onMounted(async () => {
|
|||||||
await appWindow.setTitle(`Anno_${annoId} ${annoData.value.title}`);
|
await appWindow.setTitle(`Anno_${annoId} ${annoData.value.title}`);
|
||||||
annoRef.value = <HTMLElement>document.querySelector(".anno-body");
|
annoRef.value = <HTMLElement>document.querySelector(".anno-body");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
if (error instanceof Error)
|
||||||
|
await TGLogger.Error(`[t-anno.vue][${annoId}] ${error.name}:${error.message}`);
|
||||||
|
else console.error(error);
|
||||||
loadingEmpty.value = true;
|
loadingEmpty.value = true;
|
||||||
loadingTitle.value = "公告不存在或解析失败";
|
loadingTitle.value = "公告不存在或解析失败";
|
||||||
await appWindow.setTitle(`Anno_${annoId} Parsing Error`);
|
await appWindow.setTitle(`Anno_${annoId} Parsing Error`);
|
||||||
@@ -78,9 +82,7 @@ onMounted(async () => {
|
|||||||
}
|
}
|
||||||
// 打开 json
|
// 打开 json
|
||||||
const isDev = useAppStore().devMode ?? false;
|
const isDev = useAppStore().devMode ?? false;
|
||||||
if (isDev) {
|
if (isDev) createAnnoJson(annoId);
|
||||||
createAnnoJson(annoId);
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ import TSwitchTheme from "../components/app/t-switchTheme.vue";
|
|||||||
import ToLoading from "../components/overlay/to-loading.vue";
|
import ToLoading from "../components/overlay/to-loading.vue";
|
||||||
import Mys from "../plugins/Mys";
|
import Mys from "../plugins/Mys";
|
||||||
import { useAppStore } from "../store/modules/app";
|
import { useAppStore } from "../store/modules/app";
|
||||||
|
import TGLogger from "../utils/TGLogger";
|
||||||
|
|
||||||
// loading
|
// loading
|
||||||
const loading = ref<boolean>(true);
|
const loading = ref<boolean>(true);
|
||||||
@@ -80,7 +81,7 @@ function flushTimeStatus(): void {
|
|||||||
const timeDiff = Number(jsonData.draw_time) * 1000 - timeNow;
|
const timeDiff = Number(jsonData.draw_time) * 1000 - timeNow;
|
||||||
if (timeDiff <= 0) {
|
if (timeDiff <= 0) {
|
||||||
timeStatus.value = "已开奖";
|
timeStatus.value = "已开奖";
|
||||||
clearInterval(lotteryTimer);
|
clearInterval(lotteryTimer.value);
|
||||||
} else {
|
} else {
|
||||||
const day = Math.floor(timeDiff / (24 * 3600 * 1000));
|
const day = Math.floor(timeDiff / (24 * 3600 * 1000));
|
||||||
const hour = Math.floor((timeDiff % (24 * 3600 * 1000)) / (3600 * 1000));
|
const hour = Math.floor((timeDiff % (24 * 3600 * 1000)) / (3600 * 1000));
|
||||||
@@ -108,6 +109,7 @@ onMounted(async () => {
|
|||||||
if (!lotteryId) {
|
if (!lotteryId) {
|
||||||
loadingEmpty.value = true;
|
loadingEmpty.value = true;
|
||||||
loadingTitle.value = "未找到数据";
|
loadingTitle.value = "未找到数据";
|
||||||
|
await TGLogger.Error("[t-lottery.vue] 未找到 lottery_id");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 获取数据
|
// 获取数据
|
||||||
@@ -116,6 +118,7 @@ onMounted(async () => {
|
|||||||
if (!jsonData) {
|
if (!jsonData) {
|
||||||
loadingEmpty.value = true;
|
loadingEmpty.value = true;
|
||||||
loadingTitle.value = "未找到数据";
|
loadingTitle.value = "未找到数据";
|
||||||
|
await TGLogger.Error("[t-lottery.vue] 未找到数据");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await appWindow.setTitle("抽奖详情 " + jsonData.lottery_entity_summary);
|
await appWindow.setTitle("抽奖详情 " + jsonData.lottery_entity_summary);
|
||||||
@@ -147,7 +150,7 @@ function getUpWay(upWay: string): string {
|
|||||||
// 监听 timeStatus
|
// 监听 timeStatus
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
if (timeStatus.value === "已开奖") {
|
if (timeStatus.value === "已开奖") {
|
||||||
clearInterval(lotteryTimer);
|
clearInterval(lotteryTimer.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ import TpoCollection from "../components/post/tpo-collection.vue";
|
|||||||
import Mys from "../plugins/Mys";
|
import Mys from "../plugins/Mys";
|
||||||
import { useAppStore } from "../store/modules/app";
|
import { useAppStore } from "../store/modules/app";
|
||||||
import TGClient from "../utils/TGClient";
|
import TGClient from "../utils/TGClient";
|
||||||
|
import TGLogger from "../utils/TGLogger";
|
||||||
import { createTGWindow } from "../utils/TGWindow";
|
import { createTGWindow } from "../utils/TGWindow";
|
||||||
|
|
||||||
// loading
|
// loading
|
||||||
@@ -123,6 +124,7 @@ onMounted(async () => {
|
|||||||
loadingEmpty.value = true;
|
loadingEmpty.value = true;
|
||||||
loadingTitle.value = "未找到数据";
|
loadingTitle.value = "未找到数据";
|
||||||
await appWindow.setTitle("未找到数据");
|
await appWindow.setTitle("未找到数据");
|
||||||
|
await TGLogger.Error("[t-post.vue] PostID 不存在");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 获取数据
|
// 获取数据
|
||||||
@@ -134,18 +136,22 @@ onMounted(async () => {
|
|||||||
shareTitle.value = `Post_${postId}`;
|
shareTitle.value = `Post_${postId}`;
|
||||||
await appWindow.setTitle(`Post_${postId} ${postData.value.post.subject}`);
|
await appWindow.setTitle(`Post_${postId} ${postData.value.post.subject}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
await TGLogger.Error(`[t-post.vue] ${error.name}: ${error.message}`);
|
||||||
|
loadingTitle.value = error.name;
|
||||||
|
loadingSub.value = error.message;
|
||||||
|
} else {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
loadingEmpty.value = true;
|
|
||||||
loadingTitle.value = "帖子不存在或解析失败";
|
loadingTitle.value = "帖子不存在或解析失败";
|
||||||
loadingSub.value = error instanceof Error ? error.message : <string>error;
|
loadingSub.value = "请检查帖子是否存在或者是否为合法的帖子";
|
||||||
|
}
|
||||||
|
loadingEmpty.value = true;
|
||||||
await appWindow.setTitle(`Post_${postId} Parsing Error`);
|
await appWindow.setTitle(`Post_${postId} Parsing Error`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 打开 json
|
// 打开 json
|
||||||
const isDev = useAppStore().devMode ?? false;
|
const isDev = useAppStore().devMode ?? false;
|
||||||
if (isDev) {
|
if (isDev) createPostJson(postId);
|
||||||
createPostJson(postId);
|
|
||||||
}
|
|
||||||
await nextTick(() => {
|
await nextTick(() => {
|
||||||
shareTimeTimer.value = setInterval(() => {
|
shareTimeTimer.value = setInterval(() => {
|
||||||
shareTime.value = Math.floor(Date.now() / 1000);
|
shareTime.value = Math.floor(Date.now() / 1000);
|
||||||
@@ -184,6 +190,10 @@ function getRenderPost(data: TGApp.Plugins.Mys.Post.FullData): TGApp.Plugins.Mys
|
|||||||
try {
|
try {
|
||||||
jsonParse = parseContent(data.post.content);
|
jsonParse = parseContent(data.post.content);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e instanceof SyntaxError) {
|
||||||
|
console.error(e);
|
||||||
|
TGLogger.Warn(`[t-post.vue] ${e.name}: ${e.message}`);
|
||||||
|
}
|
||||||
jsonParse = data.post.structured_content;
|
jsonParse = data.post.structured_content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user