mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-14 09:38:13 +08:00
♻️ 完善日志,重构设置页面
This commit is contained in:
@@ -50,16 +50,13 @@ function toStore() {
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tab-box {
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
right: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 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);
|
||||
}
|
||||
|
||||
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>
|
||||
Reference in New Issue
Block a user