mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-13 09:28:14 +08:00
@@ -1,27 +1,49 @@
|
||||
<template>
|
||||
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
|
||||
<div class="ua-box">
|
||||
<div class="ua-left-box">
|
||||
<v-tabs v-model="userTab" direction="vertical" class="ua-tabs-box">
|
||||
<v-tab v-for="item in localAbyss" :key="item.id" :value="item.id" @click="toAbyss(item.id)">
|
||||
第{{ item.id }}期
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
<div class="ua-tab-bottom">
|
||||
<v-btn class="ua-btn" @click="shareAbyss" rounded>
|
||||
<v-app-bar>
|
||||
<template #prepend>
|
||||
<div class="uat-left">
|
||||
<img alt="icon" src="/source/UI/userAbyss.webp" />
|
||||
<span>深境螺旋</span>
|
||||
<v-select
|
||||
variant="outlined"
|
||||
v-model="uidCur"
|
||||
:items="uidList"
|
||||
:hide-details="true"
|
||||
title="游戏UID"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #append>
|
||||
<div class="uat-right">
|
||||
<v-btn
|
||||
class="ua-btn"
|
||||
@click="shareAbyss()"
|
||||
:rounded="true"
|
||||
:disabled="localAbyss.length === 0"
|
||||
>
|
||||
<v-icon>mdi-share</v-icon>
|
||||
<span>分享</span>
|
||||
</v-btn>
|
||||
<v-btn class="ua-btn" @click="getAbyssData" rounded>
|
||||
<v-btn class="ua-btn" @click="refreshAbyss()" :rounded="true">
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
<span>刷新</span>
|
||||
</v-btn>
|
||||
<v-btn class="ua-btn" @click="uploadAbyss" rounded>
|
||||
<v-btn class="ua-btn" @click="uploadAbyss()" :rounded="true">
|
||||
<v-icon>mdi-cloud-upload</v-icon>
|
||||
<span>上传</span>
|
||||
</v-btn>
|
||||
<v-btn class="ua-btn" @click="deleteAbyss()" :rounded="true">
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
<span>删除</span>
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<div class="ua-box">
|
||||
<v-tabs v-model="userTab" direction="vertical" class="ua-tabs-box" center-active>
|
||||
<v-tab v-for="item in localAbyss" :key="item.id" :value="item.id"> 第{{ item.id }}期</v-tab>
|
||||
</v-tabs>
|
||||
<v-window v-model="userTab" class="ua-window">
|
||||
<v-window-item
|
||||
v-for="item in localAbyss"
|
||||
@@ -61,7 +83,7 @@
|
||||
</div>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
<div v-show="localAbyssID.length === 0" class="user-empty">
|
||||
<div v-show="localAbyss.length === 0" class="user-empty">
|
||||
<img src="/source/UI/empty.webp" alt="empty" />
|
||||
<span>暂无数据,请尝试刷新</span>
|
||||
</div>
|
||||
@@ -69,15 +91,16 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { onMounted, ref, watch, computed } from "vue";
|
||||
|
||||
import showConfirm from "../../components/func/confirm.js";
|
||||
import showSnackbar from "../../components/func/snackbar.js";
|
||||
import TSubLine from "../../components/main/t-subline.vue";
|
||||
import ToLoading from "../../components/overlay/to-loading.vue";
|
||||
import TuaDetail from "../../components/userAbyss/tua-detail.vue";
|
||||
import TuaOverview from "../../components/userAbyss/tua-overview.vue";
|
||||
import Hutao from "../../plugins/Hutao/index.js";
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import TSUserAbyss from "../../plugins/Sqlite/modules/userAbyss.js";
|
||||
import TSUserAvatar from "../../plugins/Sqlite/modules/userAvatar.js";
|
||||
import { useUserStore } from "../../store/modules/user.js";
|
||||
import TGLogger from "../../utils/TGLogger.js";
|
||||
@@ -96,123 +119,114 @@ const userTab = ref<number>(0);
|
||||
const user = ref<TGApp.Sqlite.Account.Game>(userStore.account.value);
|
||||
|
||||
const localAbyss = ref<TGApp.Sqlite.Abyss.SingleTable[]>([]);
|
||||
const localAbyssID = ref<number[]>([]);
|
||||
const curAbyss = ref<TGApp.Sqlite.Abyss.SingleTable>(<TGApp.Sqlite.Abyss.SingleTable>{});
|
||||
const abyssRef = ref<HTMLElement>(<HTMLElement>{});
|
||||
|
||||
const uidList = ref<string[]>();
|
||||
const uidCur = ref<string>();
|
||||
const abyssIdList = computed<number[]>(() => {
|
||||
return localAbyss.value.map((abyss) => abyss.id);
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await TGLogger.Info("[UserAbyss][onMounted] 打开角色深渊页面");
|
||||
loadingTitle.value = "正在加载深渊数据";
|
||||
await initAbyssData();
|
||||
uidList.value = await TSUserAbyss.getAllUid();
|
||||
if (uidList.value.includes(user.value.gameUid)) uidCur.value = user.value.gameUid;
|
||||
else if (uidList.value.length > 0) uidCur.value = uidList.value[0];
|
||||
else uidCur.value = "";
|
||||
await loadAbyss();
|
||||
loading.value = false;
|
||||
});
|
||||
|
||||
async function initAbyssData(): Promise<void> {
|
||||
const abyssGet = await TGSqlite.getAbyss(user.value.gameUid);
|
||||
if (abyssGet.length === 0) {
|
||||
await TGLogger.Warn("[UserAbyss][initAbyssData] 未找到深渊数据");
|
||||
return;
|
||||
}
|
||||
localAbyss.value = abyssGet;
|
||||
localAbyss.value.forEach((item) => {
|
||||
localAbyssID.value.push(item.id);
|
||||
});
|
||||
curAbyss.value = localAbyss.value[0];
|
||||
userTab.value = localAbyssID.value[0];
|
||||
await TGLogger.Info(`[UserAbyss][initAbyssData] 成功获取 ${abyssGet.length} 条深渊数据`);
|
||||
watch(
|
||||
() => uidCur.value,
|
||||
async () => await loadAbyss(),
|
||||
);
|
||||
|
||||
async function loadAbyss(): Promise<void> {
|
||||
localAbyss.value = [];
|
||||
if (uidCur.value === undefined || uidCur.value === "") return;
|
||||
localAbyss.value = await TSUserAbyss.getAbyss(uidCur.value);
|
||||
if (localAbyss.value.length > 0) userTab.value = localAbyss.value[0].id;
|
||||
}
|
||||
|
||||
async function getAbyssData(): Promise<void> {
|
||||
await TGLogger.Info("[UserAbyss][getAbyssData] 更新深渊数据");
|
||||
loadingTitle.value = "正在获取深渊数据";
|
||||
loading.value = true;
|
||||
async function refreshAbyss(): Promise<void> {
|
||||
if (!userStore.cookie.value) {
|
||||
showSnackbar({
|
||||
text: "未登录",
|
||||
color: "error",
|
||||
});
|
||||
loading.value = false;
|
||||
await TGLogger.Warn("[UserAbyss][getAbyssData] 未登录");
|
||||
return;
|
||||
}
|
||||
if (uidCur.value && uidCur.value !== user.value.gameUid) {
|
||||
const confirm = showConfirm({
|
||||
title: "确定刷新?",
|
||||
text: `用户UID-${user.value.gameUid}与当前深渊UID-${uidCur.value}不一致`,
|
||||
});
|
||||
if (!confirm) {
|
||||
showSnackbar({ text: "已取消深渊数据刷新", color: "cancel" });
|
||||
return;
|
||||
}
|
||||
}
|
||||
await TGLogger.Info("[UserAbyss][getAbyssData] 更新深渊数据");
|
||||
loadingTitle.value = `正在获取${user.value.gameUid}的深渊数据`;
|
||||
loading.value = true;
|
||||
const cookie = {
|
||||
account_id: userStore.cookie.value.account_id,
|
||||
cookie_token: userStore.cookie.value.cookie_token,
|
||||
ltoken: userStore.cookie.value.ltoken,
|
||||
ltuid: userStore.cookie.value.ltuid,
|
||||
};
|
||||
loadingTitle.value = "正在获取上期深渊数据";
|
||||
loadingTitle.value = `正在获取${user.value.gameUid}的上期深渊数据`;
|
||||
const resP = await TGRequest.User.byCookie.getAbyss(cookie, "2", user.value);
|
||||
if (!("retcode" in resP)) {
|
||||
await TGLogger.Info("[UserAbyss][getAbyssData] 成功获取上期深渊数据");
|
||||
loadingTitle.value = "正在保存上期深渊数据";
|
||||
await TGSqlite.saveAbyss(user.value.gameUid, resP);
|
||||
loadingTitle.value = `正在保存${user.value.gameUid}的上期深渊数据`;
|
||||
await TSUserAbyss.saveAbyss(user.value.gameUid, resP);
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: `[${resP.retcode}]${resP.message}`,
|
||||
color: "error",
|
||||
});
|
||||
showSnackbar({ text: `[${resP.retcode}]${resP.message}`, color: "error" });
|
||||
loading.value = false;
|
||||
await TGLogger.Error("[UserAbyss][getAbyssData] 获取上期深渊数据失败");
|
||||
await TGLogger.Error(`[UserAbyss][getAbyssData] 获取${user.value.gameUid}的上期深渊数据失败`);
|
||||
await TGLogger.Error(`[UserAbyss][getAbyssData] ${resP.retcode} ${resP.message}`);
|
||||
return;
|
||||
}
|
||||
loadingTitle.value = "正在获取本期深渊数据";
|
||||
loadingTitle.value = `正在获取${user.value.gameUid}的上期深渊数据`;
|
||||
const res = await TGRequest.User.byCookie.getAbyss(cookie, "1", user.value);
|
||||
if (!("retcode" in res)) {
|
||||
loadingTitle.value = "正在保存本期深渊数据";
|
||||
await TGSqlite.saveAbyss(user.value.gameUid, res);
|
||||
await TGLogger.Info("[UserAbyss][getAbyssData] 成功获取本期深渊数据");
|
||||
loadingTitle.value = `正在保存${user.value.gameUid}的本期深渊数据`;
|
||||
await TSUserAbyss.saveAbyss(user.value.gameUid, res);
|
||||
await TGLogger.Info(`[UserAbyss][getAbyssData] 成功获取${user.value.gameUid}的本期深渊数据`);
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: `[${res.retcode}]${res.message}`,
|
||||
color: "error",
|
||||
});
|
||||
showSnackbar({ text: `[${res.retcode}]${res.message}`, color: "error" });
|
||||
loading.value = false;
|
||||
await TGLogger.Error("[UserAbyss][getAbyssData] 获取本期深渊数据失败");
|
||||
await TGLogger.Error(`[UserAbyss][getAbyssData] 获取${user.value.gameUid}的本期深渊数据失败`);
|
||||
await TGLogger.Error(`[UserAbyss][getAbyssData] ${res.retcode} ${res.message}`);
|
||||
return;
|
||||
}
|
||||
loadingTitle.value = "正在加载深渊数据";
|
||||
await initAbyssData();
|
||||
uidList.value = await TSUserAbyss.getAllUid();
|
||||
uidCur.value = user.value.gameUid;
|
||||
await loadAbyss();
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
function toAbyss(id: number): void {
|
||||
const abyssFind = localAbyss.value.find((item) => item.id === id);
|
||||
if (abyssFind) {
|
||||
curAbyss.value = abyssFind;
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "未找到该深渊数据",
|
||||
color: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function shareAbyss(): Promise<void> {
|
||||
if (localAbyssID.value.length === 0) {
|
||||
showSnackbar({
|
||||
text: "暂无数据",
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
await TGLogger.Info(`[UserAbyss][shareAbyss][${curAbyss.value.id}] 生成深渊数据分享图片`);
|
||||
const fileName = `【深渊数据】${curAbyss.value.id}-${user.value.gameUid}`;
|
||||
await TGLogger.Info(`[UserAbyss][shareAbyss][${userTab.value}] 生成深渊数据分享图片`);
|
||||
const fileName = `【深渊数据】${userTab.value}-${user.value.gameUid}`;
|
||||
loadingTitle.value = "正在生成图片";
|
||||
loadingSub.value = `${fileName}.png`;
|
||||
loading.value = true;
|
||||
abyssRef.value = <HTMLElement>document.getElementById(`user-abyss-${curAbyss.value.id}`);
|
||||
abyssRef.value = <HTMLElement>document.getElementById(`user-abyss-${userTab.value}`);
|
||||
await generateShareImg(fileName, abyssRef.value);
|
||||
loadingSub.value = "";
|
||||
loading.value = false;
|
||||
await TGLogger.Info(`[UserAbyss][shareAbyss][${curAbyss.value.id}] 生成深渊数据分享图片成功`);
|
||||
await TGLogger.Info(`[UserAbyss][shareAbyss][${userTab.value}] 生成深渊数据分享图片成功`);
|
||||
}
|
||||
|
||||
async function uploadAbyss(): Promise<void> {
|
||||
await TGLogger.Info("[UserAbyss][uploadAbyss] 上传深渊数据");
|
||||
const abyssData = localAbyss.value.find((item) => item.id === Math.max(...localAbyssID.value));
|
||||
const abyssData = localAbyss.value.find((item) => item.id === Math.max(...abyssIdList.value));
|
||||
if (!abyssData) {
|
||||
showSnackbar({
|
||||
text: "未找到深渊数据",
|
||||
@@ -279,43 +293,58 @@ async function uploadAbyss(): Promise<void> {
|
||||
}
|
||||
if (loading.value) loading.value = false;
|
||||
}
|
||||
|
||||
async function deleteAbyss(): Promise<void> {
|
||||
if (uidCur.value === undefined || uidCur.value === "") {
|
||||
showSnackbar({ text: "未找到符合条件的数据!", color: "error" });
|
||||
return;
|
||||
}
|
||||
const confirm = await showConfirm({
|
||||
title: "确定删除数据?",
|
||||
text: `将清除 ${uidCur.value} 的所有深渊数据`,
|
||||
});
|
||||
if (!confirm) {
|
||||
showSnackbar({ text: "已取消删除", color: "cancel" });
|
||||
return;
|
||||
}
|
||||
loadingTitle.value = `正在删除 ${uidCur.value} 的深渊数据`;
|
||||
loading.value = true;
|
||||
await TSUserAbyss.delAbyss(uidCur.value);
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
loading.value = false;
|
||||
showSnackbar({ text: `已清除 ${uidCur.value} 的深渊数据,即将刷新`, color: "success" });
|
||||
uidList.value = await TSUserAbyss.getAllUid();
|
||||
if (uidList.value.length > 0) uidCur.value = uidList.value[0];
|
||||
else uidCur.value = undefined;
|
||||
await loadAbyss();
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.ua-box {
|
||||
display: flex;
|
||||
height: calc(100vh - 35px);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--common-shadow-4);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.ua-left-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100px;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-right: 1px solid var(--common-shadow-2);
|
||||
color: var(--box-text-4);
|
||||
}
|
||||
|
||||
/* stylelint-disable-next-line selector-class-pattern */
|
||||
.ua-left-box :deep(.v-tabs.v-slide-group--vertical) {
|
||||
max-height: calc(100% - 150px);
|
||||
}
|
||||
|
||||
.ua-tabs-box {
|
||||
max-height: calc(100% - 150px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ua-tab-bottom {
|
||||
.uat-left {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
gap: 10px;
|
||||
|
||||
img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: var(--common-text-title);
|
||||
font-family: var(--font-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.uat-right {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
gap: 10px;
|
||||
}
|
||||
@@ -326,6 +355,20 @@ async function uploadAbyss(): Promise<void> {
|
||||
font-family: var(--font-text);
|
||||
}
|
||||
|
||||
.ua-box {
|
||||
display: flex;
|
||||
height: calc(100vh - 100px);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--common-shadow-4);
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.ua-tabs-box {
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ua-window {
|
||||
overflow: hidden;
|
||||
width: calc(100% - 100px);
|
||||
|
||||
@@ -66,10 +66,7 @@ onMounted(async () => {
|
||||
loadingTitle.value = "正在加载战绩数据";
|
||||
loading.value = true;
|
||||
await initUserRecordData();
|
||||
// 保证图片加载完毕
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
async function initUserRecordData(): Promise<void> {
|
||||
|
||||
@@ -8,13 +8,7 @@ import { app } from "@tauri-apps/api";
|
||||
import Database from "@tauri-apps/plugin-sql";
|
||||
|
||||
import initDataSql from "./sql/initData.js";
|
||||
import {
|
||||
importAbyssData,
|
||||
insertAbyssData,
|
||||
insertAppData,
|
||||
insertGameAccountData,
|
||||
insertRecordData,
|
||||
} from "./sql/insertData.js";
|
||||
import { insertAppData, insertGameAccountData, insertRecordData } from "./sql/insertData.js";
|
||||
|
||||
class Sqlite {
|
||||
/**
|
||||
@@ -30,11 +24,9 @@ class Sqlite {
|
||||
*/
|
||||
private readonly tables: string[] = [
|
||||
"Achievements",
|
||||
"AchievementSeries",
|
||||
"AppCharacters",
|
||||
"AppData",
|
||||
"GameAccount",
|
||||
"NameCard",
|
||||
"SpiralAbyss",
|
||||
"UserCharacters",
|
||||
"UserRecord",
|
||||
@@ -181,53 +173,6 @@ class Sqlite {
|
||||
await this.initDB();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 保存深渊数据
|
||||
* @since Beta v0.3.3
|
||||
* @param {string} uid 游戏 UID
|
||||
* @param {TGApp.Game.Abyss.FullData} data 深渊数据
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async saveAbyss(uid: string, data: TGApp.Game.Abyss.FullData): Promise<void> {
|
||||
const db = await this.getDB();
|
||||
const sql = insertAbyssData(uid, data);
|
||||
await db.execute(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取深渊数据
|
||||
* @since Beta v0.3.3
|
||||
* @param {string} uid 游戏 UID
|
||||
* @returns {Promise<TGApp.Game.Abyss.FullData>}
|
||||
*/
|
||||
public async getAbyss(uid?: string): Promise<TGApp.Sqlite.Abyss.SingleTable[]> {
|
||||
const db = await this.getDB();
|
||||
let sql;
|
||||
if (uid) {
|
||||
sql = `SELECT *
|
||||
FROM SpiralAbyss
|
||||
WHERE uid = '${uid}'
|
||||
order by id desc`;
|
||||
} else {
|
||||
sql = "SELECT * FROM SpiralAbyss order by uid, id desc";
|
||||
}
|
||||
return await db.select(sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 恢复深渊数据
|
||||
* @since Beta v0.3.3
|
||||
* @param {TGApp.Sqlite.Abyss.SingleTable[]} data 深渊数据
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async restoreAbyss(data: TGApp.Sqlite.Abyss.SingleTable[]): Promise<void> {
|
||||
const db = await this.getDB();
|
||||
for (const item of data) {
|
||||
const sql = importAbyssData(item);
|
||||
await db.execute(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 保存战绩数据
|
||||
* @since Beta v0.3.3
|
||||
|
||||
198
src/plugins/Sqlite/modules/userAbyss.ts
Normal file
198
src/plugins/Sqlite/modules/userAbyss.ts
Normal file
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/modules/userAbyss.ts
|
||||
* @description Sqlite-用户深渊模块
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { path } from "@tauri-apps/api";
|
||||
import { exists, mkdir, readTextFile, writeTextFile } from "@tauri-apps/plugin-fs";
|
||||
|
||||
import TGLogger from "../../../utils/TGLogger.js";
|
||||
import { timestampToDate } from "../../../utils/toolFunc.js";
|
||||
import TGSqlite from "../index.js";
|
||||
import { transCharacterData, transFloorData } from "../utils/transAbyssData.js";
|
||||
|
||||
/**
|
||||
* @description 直接插入数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {TGApp.Sqlite.Abyss.SingleTable} data - 数据
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRestoreSql(data: TGApp.Sqlite.Abyss.SingleTable): string {
|
||||
const timeNow = timestampToDate(new Date().getTime());
|
||||
return `
|
||||
INSERT INTO SpiralAbyss (uid, id, startTime, endTime, totalBattleTimes, totalWinTimes,
|
||||
maxFloor, totalStar, isUnlock, revealRank, defeatRank, damageRank,
|
||||
takeDamageRank, normalSkillRank, energySkillRank, floors, updated)
|
||||
VALUES ('${data.uid}', ${data.id}, '${data.startTime}', '${data.endTime}', ${data.totalBattleTimes},
|
||||
${data.totalWinTimes}, '${data.maxFloor}', ${data.totalStar},
|
||||
${data.isUnlock}, '${data.revealRank}', '${data.defeatRank}', '${data.damageRank}',
|
||||
'${data.takeDamageRank}', '${data.normalSkillRank}', '${data.energySkillRank}', '${data.floors}',
|
||||
'${timeNow}')
|
||||
ON CONFLICT(uid, id) DO UPDATE
|
||||
SET startTime = '${data.startTime}',
|
||||
endTime = '${data.endTime}',
|
||||
totalBattleTimes = ${data.totalBattleTimes},
|
||||
totalWinTimes = ${data.totalWinTimes},
|
||||
maxFloor = '${data.maxFloor}',
|
||||
totalStar = ${data.totalStar},
|
||||
isUnlock = ${data.isUnlock},
|
||||
revealRank = '${data.revealRank}',
|
||||
defeatRank = '${data.defeatRank}',
|
||||
damageRank = '${data.damageRank}',
|
||||
takeDamageRank = '${data.takeDamageRank}',
|
||||
normalSkillRank = '${data.normalSkillRank}',
|
||||
energySkillRank = '${data.energySkillRank}',
|
||||
floors = '${data.floors}',
|
||||
updated = '${timeNow}';
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取深渊数据的插入更新Sql
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} uid - 用户UID
|
||||
* @param {TGApp.Game.Abyss.FullData} data -深渊数据
|
||||
* @returns {string}
|
||||
*/
|
||||
function getInsertSql(uid: string, data: TGApp.Game.Abyss.FullData): string {
|
||||
const startTime = timestampToDate(Number(data.start_time) * 1000);
|
||||
const endTime = timestampToDate(Number(data.end_time) * 1000);
|
||||
const isUnlock = data.is_unlock ? 1 : 0;
|
||||
const revealRank = transCharacterData(data.reveal_rank);
|
||||
const defeatRank = transCharacterData(data.defeat_rank);
|
||||
const damageRank = transCharacterData(data.damage_rank);
|
||||
const takeDamageRank = transCharacterData(data.take_damage_rank);
|
||||
const normalSkillRank = transCharacterData(data.normal_skill_rank);
|
||||
const energySkillRank = transCharacterData(data.energy_skill_rank);
|
||||
const floors = transFloorData(data.floors);
|
||||
const timeNow = timestampToDate(new Date().getTime());
|
||||
return `
|
||||
INSERT INTO SpiralAbyss (uid, id, startTime, endTime, totalBattleTimes, totalWinTimes,
|
||||
maxFloor, totalStar, isUnlock, revealRank, defeatRank, damageRank,
|
||||
takeDamageRank, normalSkillRank, energySkillRank, floors, updated)
|
||||
VALUES ('${uid}', ${data.schedule_id}, '${startTime}', '${endTime}', ${data.total_battle_times},
|
||||
${data.total_win_times}, '${data.max_floor}', ${data.total_star},
|
||||
${isUnlock}, '${revealRank}', '${defeatRank}', '${damageRank}', '${takeDamageRank}',
|
||||
'${normalSkillRank}', '${energySkillRank}', '${floors}', '${timeNow}')
|
||||
ON CONFLICT(uid, id) DO UPDATE
|
||||
SET startTime = '${startTime}',
|
||||
endTime = '${endTime}',
|
||||
totalBattleTimes = ${data.total_battle_times},
|
||||
totalWinTimes = ${data.total_win_times},
|
||||
maxFloor = '${data.max_floor}',
|
||||
totalStar = ${data.total_star},
|
||||
isUnlock = ${isUnlock},
|
||||
revealRank = '${revealRank}',
|
||||
defeatRank = '${defeatRank}',
|
||||
damageRank = '${damageRank}',
|
||||
takeDamageRank = '${takeDamageRank}',
|
||||
normalSkillRank = '${normalSkillRank}',
|
||||
energySkillRank = '${energySkillRank}',
|
||||
floors = '${floors}',
|
||||
updated = '${timeNow}';
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取所有有数据的UID
|
||||
* @since Beta v0.6.0
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function getAllUid(): Promise<Array<string>> {
|
||||
const db = await TGSqlite.getDB();
|
||||
type resType = Array<{ uid: string }>;
|
||||
const res = await db.select<resType>("SELECT DISTINCT uid FROM SpiralAbyss;");
|
||||
return res.map((i) => i.uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取深渊数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} uid - 游戏UID
|
||||
* @returns {Promise<TGApp.Sqlite.Abyss.SingleTable[]>}
|
||||
*/
|
||||
async function getAbyss(uid?: string): Promise<TGApp.Sqlite.Abyss.SingleTable[]> {
|
||||
const db = await TGSqlite.getDB();
|
||||
if (uid === undefined) {
|
||||
return await db.select<TGApp.Sqlite.Abyss.SingleTable[]>(
|
||||
"SELECT * FROM SpiralAbyss order by id DESC;",
|
||||
);
|
||||
}
|
||||
return await db.select<TGApp.Sqlite.Abyss.SingleTable[]>(
|
||||
"SELECT * FROM SpiralAbyss WHERE uid = ? order by id DESC;",
|
||||
[uid],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 保存深渊数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} uid - 游戏UID
|
||||
* @param {TGApp.Game.Abyss.FullData} data - 深渊数据
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function saveAbyss(uid: string, data: TGApp.Game.Abyss.FullData): Promise<void> {
|
||||
const db = await TGSqlite.getDB();
|
||||
await db.execute(getInsertSql(uid, data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除指定UID存档的数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} uid - 游戏UID
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function delAbyss(uid: string): Promise<void> {
|
||||
const db = await TGSqlite.getDB();
|
||||
await db.execute("DELETE FROM SpiralAbyss WHERE uid = ?;", [uid]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 备份深渊数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} dir - 备份目录
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function backupAbyss(dir: string): Promise<void> {
|
||||
if (!(await exists(dir))) {
|
||||
await mkdir(dir, { recursive: true });
|
||||
await TGLogger.Warn(`未检测到备份目录,已创建`);
|
||||
}
|
||||
const data = await getAbyss();
|
||||
await writeTextFile(`${dir}${path.sep()}abyss.json`, JSON.stringify(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 恢复深渊数据
|
||||
* @since Beta v0.6.0
|
||||
* @param {string} dir - 备份文件目录
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function restoreAbyss(dir: string): Promise<boolean> {
|
||||
const filePath = `${dir}${path.sep()}abyss.json`;
|
||||
if (!(await exists(filePath))) return false;
|
||||
try {
|
||||
const data: TGApp.Sqlite.Abyss.SingleTable[] = JSON.parse(await readTextFile(filePath));
|
||||
const db = await TGSqlite.getDB();
|
||||
for (const abyss of data) {
|
||||
await db.execute(getRestoreSql(abyss));
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
await TGLogger.Error(`恢复深渊数据失败${filePath}`);
|
||||
await TGLogger.Error(`${e}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const TSUserAbyss = {
|
||||
getAllUid,
|
||||
getAbyss,
|
||||
saveAbyss,
|
||||
delAbyss,
|
||||
backupAbyss,
|
||||
restoreAbyss,
|
||||
};
|
||||
|
||||
export default TSUserAbyss;
|
||||
@@ -307,14 +307,14 @@ async function restoreUiaf(dir: string): Promise<boolean> {
|
||||
if (!(await exists(dir))) return false;
|
||||
const filesRead = await readDir(dir);
|
||||
const files = filesRead.filter((item) => item.name.includes("UIAF_") && item.isFile);
|
||||
// 正则匹配 UIAF_xx.json
|
||||
for (const file of files) {
|
||||
try {
|
||||
// todo 完善正则判断
|
||||
const reg = new RegExp(/(.*)UIAF_d{9}.json/);
|
||||
const reg = /UIAF_(\d+).json/;
|
||||
if (!file.name.match(reg)) return false;
|
||||
const uid: number = Number(file.name.match(reg)![0]);
|
||||
const data: TGApp.Plugins.UIAF.Achievement[] = JSON.parse(await readTextFile(file.name));
|
||||
const filePath = `${dir}${path.sep()}${file.name}`;
|
||||
const data: TGApp.Plugins.UIAF.Achievement[] = JSON.parse(await readTextFile(filePath));
|
||||
await TSUserAchi.mergeUiaf(data, uid);
|
||||
} catch (e) {
|
||||
await TGLogger.Error(`[UIAF][RESTORE] 恢复成就数据${file.name} `);
|
||||
|
||||
@@ -56,16 +56,8 @@ create table if not exists GameAccount
|
||||
primary key (gameBiz, gameUid)
|
||||
);
|
||||
|
||||
-- @brief 名片数据表
|
||||
create table if not exists NameCard
|
||||
(
|
||||
name text,
|
||||
desc text,
|
||||
type text,
|
||||
source text,
|
||||
updated text,
|
||||
primary key (name, type)
|
||||
);
|
||||
-- @brief 移除名片表
|
||||
drop table if exists NameCard;
|
||||
|
||||
-- @brief 创建深渊数据表
|
||||
create table if not exists SpiralAbyss
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { transCharacterData, transFloorData } from "../utils/transAbyssData.js";
|
||||
import { timeToSecond } from "../utils/transTime.js";
|
||||
import { transUserRecord } from "../utils/transUserRecord.js";
|
||||
import { transUserRoles } from "../utils/transUserRoles.js";
|
||||
|
||||
@@ -89,86 +87,6 @@ export function insertCharacterData(data: TGApp.App.Character.WikiBriefInfo): st
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 插入深渊数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} uid 用户 uid
|
||||
* @param {TGApp.User.Abyss} data 深渊数据
|
||||
* @returns {string} sql
|
||||
*/
|
||||
export function insertAbyssData(uid: string, data: TGApp.Game.Abyss.FullData): string {
|
||||
const startTime = timeToSecond(data.start_time);
|
||||
const endTime = timeToSecond(data.end_time);
|
||||
const isUnlock = data.is_unlock ? 1 : 0;
|
||||
const revealRank = transCharacterData(data.reveal_rank);
|
||||
const defeatRank = transCharacterData(data.defeat_rank);
|
||||
const damageRank = transCharacterData(data.damage_rank);
|
||||
const takeDamageRank = transCharacterData(data.take_damage_rank);
|
||||
const normalSkillRank = transCharacterData(data.normal_skill_rank);
|
||||
const energySkillRank = transCharacterData(data.energy_skill_rank);
|
||||
const floors = transFloorData(data.floors);
|
||||
return `
|
||||
INSERT INTO SpiralAbyss (uid, id, startTime, endTime, totalBattleTimes, totalWinTimes,
|
||||
maxFloor, totalStar, isUnlock, revealRank, defeatRank, damageRank,
|
||||
takeDamageRank, normalSkillRank, energySkillRank, floors, updated)
|
||||
VALUES ('${uid}', ${data.schedule_id}, '${startTime}', '${endTime}', ${data.total_battle_times},
|
||||
${data.total_win_times}, '${data.max_floor}', ${data.total_star},
|
||||
${isUnlock}, '${revealRank}', '${defeatRank}', '${damageRank}', '${takeDamageRank}',
|
||||
'${normalSkillRank}', '${energySkillRank}', '${floors}', datetime('now', 'localtime'))
|
||||
ON CONFLICT(uid, id) DO UPDATE
|
||||
SET startTime = '${startTime}',
|
||||
endTime = '${endTime}',
|
||||
totalBattleTimes = ${data.total_battle_times},
|
||||
totalWinTimes = ${data.total_win_times},
|
||||
maxFloor = '${data.max_floor}',
|
||||
totalStar = ${data.total_star},
|
||||
isUnlock = ${isUnlock},
|
||||
revealRank = '${revealRank}',
|
||||
defeatRank = '${defeatRank}',
|
||||
damageRank = '${damageRank}',
|
||||
takeDamageRank = '${takeDamageRank}',
|
||||
normalSkillRank = '${normalSkillRank}',
|
||||
energySkillRank = '${energySkillRank}',
|
||||
floors = '${floors}',
|
||||
updated = datetime('now', 'localtime');
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 恢复深渊数据
|
||||
* @since Alpha v0.2.0
|
||||
* @param {TGApp.Sqlite.Abyss.SingleTable} data 深渊数据
|
||||
* @returns {string} sql
|
||||
*/
|
||||
export function importAbyssData(data: TGApp.Sqlite.Abyss.SingleTable): string {
|
||||
return `
|
||||
INSERT INTO SpiralAbyss (uid, id, startTime, endTime, totalBattleTimes, totalWinTimes,
|
||||
maxFloor, totalStar, isUnlock, revealRank, defeatRank, damageRank,
|
||||
takeDamageRank, normalSkillRank, energySkillRank, floors, updated)
|
||||
VALUES ('${data.uid}', ${data.id}, '${data.startTime}', '${data.endTime}', ${data.totalBattleTimes},
|
||||
${data.totalWinTimes}, '${data.maxFloor}', ${data.totalStar},
|
||||
${data.isUnlock}, '${data.revealRank}', '${data.defeatRank}', '${data.damageRank}',
|
||||
'${data.takeDamageRank}', '${data.normalSkillRank}', '${data.energySkillRank}', '${data.floors}',
|
||||
datetime('now', 'localtime'))
|
||||
ON CONFLICT(uid, id) DO UPDATE
|
||||
SET startTime = '${data.startTime}',
|
||||
endTime = '${data.endTime}',
|
||||
totalBattleTimes = ${data.totalBattleTimes},
|
||||
totalWinTimes = ${data.totalWinTimes},
|
||||
maxFloor = '${data.maxFloor}',
|
||||
totalStar = ${data.totalStar},
|
||||
isUnlock = ${data.isUnlock},
|
||||
revealRank = '${data.revealRank}',
|
||||
defeatRank = '${data.defeatRank}',
|
||||
damageRank = '${data.damageRank}',
|
||||
takeDamageRank = '${data.takeDamageRank}',
|
||||
normalSkillRank = '${data.normalSkillRank}',
|
||||
energySkillRank = '${data.energySkillRank}',
|
||||
floors = '${data.floors}',
|
||||
updated = datetime('now', 'localtime');
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 插入原神战绩数据
|
||||
* @since Alpha v0.2.0
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* @file plugins/Sqlite/utils/transCharacter.ts
|
||||
* @description Sqlite 数据转换
|
||||
* @since Beta v0.3.9
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { timeToSecond } from "./transTime.js";
|
||||
import { timestampToDate } from "../../../utils/toolFunc.js";
|
||||
|
||||
/**
|
||||
* @description 将通过 api 获取到的深渊数据转换为数据库中的数据
|
||||
@@ -66,13 +66,13 @@ function transLevelData(data: TGApp.Game.Abyss.Level): TGApp.Sqlite.Abyss.Level
|
||||
|
||||
/**
|
||||
* @description 将通过 api 获取到的深渊数据转换为数据库中的数据
|
||||
* @since Alpha v0.2.0
|
||||
* @since Beta v0.6.0
|
||||
* @param {TGApp.Game.Abyss.Battle} data 深渊数据
|
||||
* @returns {TGApp.Sqlite.Abyss.Battle} 转换后的深渊数据
|
||||
*/
|
||||
function transBattleData(data: TGApp.Game.Abyss.Battle): TGApp.Sqlite.Abyss.Battle {
|
||||
return {
|
||||
time: timeToSecond(data.timestamp),
|
||||
time: timestampToDate(Number(data.timestamp) * 1000),
|
||||
characters: data.avatars.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* @file plugins Sqlite utils transTime.ts
|
||||
* @description Sqlite 时间转换工具类
|
||||
* @author BTMuli <bt-muli@outlook.com>
|
||||
* @since Alpha v0.2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description 将时间戳转换为时间字符串
|
||||
* @since Alpha v0.2.0
|
||||
* @param {string} timestamp 时间戳 (秒)
|
||||
* @returns {string} 时间字符串,格式为 YYYY-MM-DD HH:mm:ss
|
||||
*/
|
||||
export function timeToSecond(timestamp: string): string {
|
||||
const date = new Date(Number(timestamp) * 1000);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
const hour = String(date.getHours()).padStart(2, "0");
|
||||
const minute = String(date.getMinutes()).padStart(2, "0");
|
||||
const second = String(date.getSeconds()).padStart(2, "0");
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { exists, mkdir, writeTextFile, readDir, readTextFile } from "@tauri-apps
|
||||
|
||||
import showSnackbar from "../components/func/snackbar.js";
|
||||
import TGSqlite from "../plugins/Sqlite/index.js";
|
||||
import TSUserAbyss from "../plugins/Sqlite/modules/userAbyss.js";
|
||||
import TSUserAchi from "../plugins/Sqlite/modules/userAchi.js";
|
||||
import TSUserGacha from "../plugins/Sqlite/modules/userGacha.js";
|
||||
|
||||
@@ -32,8 +33,7 @@ export async function backUpUserData(dir: string): Promise<void> {
|
||||
const dataCK = await TGSqlite.getCookie();
|
||||
await writeTextFile(`${dir}${path.sep()}cookie.json`, JSON.stringify(dataCK));
|
||||
// 备份深渊数据
|
||||
const dataAbyss = await TGSqlite.getAbyss();
|
||||
await writeTextFile(`${dir}${path.sep()}abyss.json`, JSON.stringify(dataAbyss));
|
||||
await TSUserAbyss.backupAbyss(dir);
|
||||
// 备份祈愿数据
|
||||
const uidList = await TSUserGacha.getUidList();
|
||||
for (const uid of uidList) {
|
||||
@@ -81,23 +81,11 @@ export async function restoreUserData(dir: string): Promise<void> {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
}
|
||||
// 恢复深渊数据
|
||||
const abyssFind = files.find((item) => item.name === "abyss.json");
|
||||
if (abyssFind) {
|
||||
try {
|
||||
const dataAbyss: TGApp.Sqlite.Abyss.SingleTable[] = JSON.parse(
|
||||
await readTextFile(abyssFind.name),
|
||||
);
|
||||
await TGSqlite.restoreAbyss(dataAbyss);
|
||||
} catch (e) {
|
||||
await TGLogger.Error(`[DataBS][restoreUserData] 深渊数据恢复失败 ${e}`);
|
||||
const restoreAbyss = await TSUserAbyss.restoreAbyss(dir);
|
||||
if (!restoreAbyss) {
|
||||
showSnackbar({ text: "深渊数据恢复失败", color: "error" });
|
||||
errNum++;
|
||||
}
|
||||
} else {
|
||||
showSnackbar({ text: "深渊数据恢复失败,备份文件不存在", color: "warn" });
|
||||
await TGLogger.Warn(`[DataBS][restoreUserData] 未检测到深渊数据备份文件`);
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
||||
}
|
||||
// 恢复祈愿数据
|
||||
const reg = /UIGF_(\d+).json/;
|
||||
const dataGachaList = files.filter((item) => reg.test(item.name));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file utils/toolFunc.ts
|
||||
* @description 一些工具函数
|
||||
* @since Beta v0.5.0
|
||||
* @since Beta v0.6.0
|
||||
*/
|
||||
|
||||
import { path } from "@tauri-apps/api";
|
||||
@@ -28,35 +28,19 @@ export function stamp2LastTime(time: number): string {
|
||||
|
||||
/**
|
||||
* @description 时间戳转换为日期
|
||||
* @since Alpha v0.2.3
|
||||
* @since Beta v0.6.0
|
||||
* @param {number} timestamp - 时间戳(毫秒)
|
||||
* @returns {string} 日期 2021-01-01 00:00:00
|
||||
*/
|
||||
export function timestampToDate(timestamp: number): string {
|
||||
return new Date(timestamp).toLocaleString("zh", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取当前时间, YY-MM-DD HH:MM:SS
|
||||
* @since Beta v0.3.6
|
||||
* @returns {string} 当前时间
|
||||
*/
|
||||
export function getNowStr(): string {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = (now.getMonth() + 1).toString().padStart(2, "0");
|
||||
const date = now.getDate().toString().padStart(2, "0");
|
||||
const hour = now.getHours().toString().padStart(2, "0");
|
||||
const minute = now.getMinutes().toString().padStart(2, "0");
|
||||
const second = now.getSeconds().toString().padStart(2, "0");
|
||||
return `${year}-${month}-${date} ${hour}:${minute}:${second}`;
|
||||
const date = new Date(timestamp);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(date.getDate()).padStart(2, "0");
|
||||
const hour = String(date.getHours()).padStart(2, "0");
|
||||
const minute = String(date.getMinutes()).padStart(2, "0");
|
||||
const second = String(date.getSeconds()).padStart(2, "0");
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user