mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2026-03-15 03:53:16 +08:00
✨ 胡桃深渊数据库
This commit is contained in:
@@ -116,6 +116,11 @@
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-list :nav="true" class="side-list-menu sub" density="compact">
|
||||
<v-list-item class="side-item-menu" title="深渊数据库" :link="true" href="/wiki/abyss">
|
||||
<template #prepend>
|
||||
<img src="/source/UI/wikiAbyss.webp" alt="abyssIcon" class="side-icon-menu" />
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item :link="true" class="side-item-menu" href="/wiki/character" title="角色图鉴">
|
||||
<template #prepend>
|
||||
<img alt="characterIcon" class="side-icon-menu" src="/source/UI/wikiAvatar.webp" />
|
||||
|
||||
@@ -50,6 +50,20 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
<template #extension>
|
||||
<div class="uat-extension">
|
||||
<v-btn :rounded="true" variant="elevated" class="ua-btn" @click="toWiki()">
|
||||
<img alt="wiki" src="/source/UI/wikiAbyss.webp" />
|
||||
<span>统计数据</span>
|
||||
</v-btn>
|
||||
<div class="uat-extension-right">
|
||||
<span @click="editHutaoEmail()">{{ hutaoEmail ?? "胡桃云邮箱" }}</span>
|
||||
<v-btn class="ua-btn" prepend-icon="mdi-upload" variant="elevated" @click="uploadAbyss()">
|
||||
上传
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<div class="ua-box">
|
||||
<v-tabs v-model="userTab" center-active class="ua-tabs-box" direction="vertical">
|
||||
@@ -110,8 +124,10 @@ import showLoading from "@comp/func/loading.js";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import TuaDetail from "@comp/userAbyss/tua-detail.vue";
|
||||
import TuaOverview from "@comp/userAbyss/tua-overview.vue";
|
||||
import hutao from "@Hutao/index.js";
|
||||
import recordReq from "@req/recordReq.js";
|
||||
import TSUserAbyss from "@Sqlm/userAbyss.js";
|
||||
import TSUserAvatar from "@Sqlm/userAvatar.js";
|
||||
import useAppStore from "@store/app.js";
|
||||
import useUserStore from "@store/user.js";
|
||||
import { getVersion } from "@tauri-apps/api/app";
|
||||
@@ -125,7 +141,7 @@ import { useRouter } from "vue-router";
|
||||
|
||||
const router = useRouter();
|
||||
const { isLogin } = storeToRefs(useAppStore());
|
||||
const { account, cookie } = storeToRefs(useUserStore());
|
||||
const { account, cookie, hutaoEmail } = storeToRefs(useUserStore());
|
||||
const userTab = ref<number>(0);
|
||||
const version = ref<string>();
|
||||
const uidCur = ref<string>();
|
||||
@@ -163,6 +179,33 @@ async function toChallenge(): Promise<void> {
|
||||
await router.push({ name: "幽境危战" });
|
||||
}
|
||||
|
||||
async function toWiki(): Promise<void> {
|
||||
await router.push({ name: "深渊数据库" });
|
||||
}
|
||||
|
||||
async function editHutaoEmail(): Promise<void> {
|
||||
if (hutaoEmail.value) {
|
||||
const chgCheck = await showDialog.check("是否更改胡桃云账号", `当前账号:${hutaoEmail.value}`);
|
||||
if (!chgCheck) {
|
||||
showSnackbar.cancel("已取消更改胡桃云账号");
|
||||
return;
|
||||
}
|
||||
}
|
||||
const newEmail = await showDialog.input("请输入胡桃云账号", "胡桃云账号", hutaoEmail.value);
|
||||
if (!newEmail) {
|
||||
showSnackbar.cancel("已取消设置胡桃云账号");
|
||||
return;
|
||||
}
|
||||
// 简单验证邮箱格式
|
||||
const mailReg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
|
||||
if (!mailReg.test(newEmail)) {
|
||||
showSnackbar.error("邮箱格式错误");
|
||||
return;
|
||||
}
|
||||
hutaoEmail.value = newEmail;
|
||||
showSnackbar.success("已设置胡桃云账号");
|
||||
}
|
||||
|
||||
async function loadAbyss(): Promise<void> {
|
||||
localAbyss.value = [];
|
||||
if (uidCur.value === undefined || uidCur.value === "") return;
|
||||
@@ -306,6 +349,67 @@ async function tryReadAbyss(): Promise<void> {
|
||||
showSnackbar.error("导入深渊数据失败,请检查文件格式是否正确");
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadAbyss(): Promise<void> {
|
||||
if (!hutaoEmail.value || hutaoEmail.value === "") {
|
||||
const check = await showDialog.check("确定上传?", "未设置胡桃云账号");
|
||||
if (!check) return;
|
||||
}
|
||||
await TGLogger.Info("[UserAbyss][uploadAbyss] 上传深渊数据");
|
||||
const maxId = Math.max(...localAbyss.value.map((i) => i.id));
|
||||
const abyssData = localAbyss.value.find((item) => item.id === maxId);
|
||||
if (!abyssData) {
|
||||
showSnackbar.warn("未找到深渊数据");
|
||||
await TGLogger.Warn("[UserAbyss][uploadAbyss] 未找到深渊数据");
|
||||
return;
|
||||
}
|
||||
const maxFloor = Number(abyssData.maxFloor.split("-")[0]);
|
||||
if (isNaN(maxFloor) || maxFloor <= 9) {
|
||||
showSnackbar.warn("尚未完成深渊,请完成深渊后重试!");
|
||||
await TGLogger.Warn(`[UserAbyss][uploadAbyss] 尚未完成深渊 ${abyssData.maxFloor}`);
|
||||
return;
|
||||
}
|
||||
const startTime = new Date(abyssData.startTime).getTime();
|
||||
const endTime = new Date(abyssData.endTime).getTime();
|
||||
const nowTime = new Date().getTime();
|
||||
if (nowTime < startTime || nowTime > endTime) {
|
||||
showSnackbar.warn("非最新深渊数据,请刷新深渊数据后重试!");
|
||||
await TGLogger.Warn("[UserAbyss][uploadAbyss] 非最新深渊数据");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await showLoading.start(`正在上传${account.value.gameUid}的深渊数据`, `期数:${abyssData.id}`);
|
||||
const transAbyss = hutao.Abyss.utils.transData(abyssData);
|
||||
if (hutaoEmail.value) transAbyss.ReservedUserName = hutaoEmail.value;
|
||||
await showLoading.update("正在获取角色数据");
|
||||
const roles = await TSUserAvatar.getAvatars(Number(account.value.gameUid));
|
||||
if (!roles) {
|
||||
await showLoading.end();
|
||||
showSnackbar.warn("未找到角色数据");
|
||||
return;
|
||||
}
|
||||
await showLoading.update("正在转换角色数据");
|
||||
transAbyss.Avatars = hutao.Abyss.utils.transAvatars(roles);
|
||||
await showLoading.update("正在上传深渊数据");
|
||||
const res = await hutao.Abyss.upload(transAbyss);
|
||||
if (res.retcode !== 0) {
|
||||
showSnackbar.error(`[${res.retcode}]${res.message}`);
|
||||
await TGLogger.Error("[UserAbyss][uploadAbyss] 上传深渊数据失败");
|
||||
await TGLogger.Error(`[UserAbyss][uploadAbyss] ${res.retcode} ${res.message}`);
|
||||
return;
|
||||
}
|
||||
showSnackbar.success(res.message ?? "上传深渊数据成功");
|
||||
await TGLogger.Info("[UserAbyss][uploadAbyss] 上传深渊数据成功");
|
||||
await TGLogger.Info(`[${res.retcode}] ${res.message}`);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
showSnackbar.error(e.message);
|
||||
await TGLogger.Error("[UserAbyss][uploadAbyss] 上传深渊数据失败");
|
||||
await TGLogger.Error(`[UserAbyss][uploadAbyss] ${e.message}`);
|
||||
}
|
||||
}
|
||||
await showLoading.end();
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.uat-left {
|
||||
@@ -352,6 +456,31 @@ async function tryReadAbyss(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
.uat-extension {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-right: 16px;
|
||||
padding-left: 16px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.uat-extension-right {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 8px;
|
||||
|
||||
span {
|
||||
color: var(--tgc-od-red);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.ua-box {
|
||||
display: flex;
|
||||
height: calc(100vh - 96px);
|
||||
|
||||
@@ -55,6 +55,25 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
<template #extension>
|
||||
<div class="uct-extension">
|
||||
<v-btn class="uc-btn" variant="elevated" @click="loadWiki()">
|
||||
<img alt="abyss" src="/source/UI/wikiAbyss.webp" />
|
||||
<span>统计数据</span>
|
||||
</v-btn>
|
||||
<div class="uct-extension-right">
|
||||
<span @click="editHutaoEmail()">{{ hutaoEmail ?? "设置胡桃云邮箱" }}</span>
|
||||
<v-btn
|
||||
class="uc-btn"
|
||||
prepend-icon="mdi-cloud-upload"
|
||||
variant="elevated"
|
||||
@click="uploadCombat()"
|
||||
>
|
||||
上传
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<div class="uc-box">
|
||||
<v-tabs v-model="userTab" center-active class="uc-tabs-box" direction="vertical">
|
||||
@@ -97,6 +116,7 @@
|
||||
<span>暂无数据,请尝试刷新</span>
|
||||
</div>
|
||||
</div>
|
||||
<TucOverlay v-model="showData" :data="cloudCombat" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TSubLine from "@comp/app/t-subline.vue";
|
||||
@@ -104,8 +124,10 @@ import showDialog from "@comp/func/dialog.js";
|
||||
import showLoading from "@comp/func/loading.js";
|
||||
import showSnackbar from "@comp/func/snackbar.js";
|
||||
import TucAvatars from "@comp/userCombat/tuc-avatars.vue";
|
||||
import TucOverlay from "@comp/userCombat/tuc-overlay.vue";
|
||||
import TucOverview from "@comp/userCombat/tuc-overview.vue";
|
||||
import TucRound from "@comp/userCombat/tuc-round.vue";
|
||||
import hutao from "@Hutao/index.js";
|
||||
import recordReq from "@req/recordReq.js";
|
||||
import TSUserCombat from "@Sqlm/userCombat.js";
|
||||
import useAppStore from "@store/app.js";
|
||||
@@ -121,11 +143,13 @@ import { useRouter } from "vue-router";
|
||||
|
||||
const router = useRouter();
|
||||
const { isLogin } = storeToRefs(useAppStore());
|
||||
const { account, cookie } = storeToRefs(useUserStore());
|
||||
const { account, cookie, hutaoEmail } = storeToRefs(useUserStore());
|
||||
const userTab = ref<number>(0);
|
||||
const version = ref<string>();
|
||||
const uidCur = ref<string>();
|
||||
const showData = ref<boolean>(false);
|
||||
const uidList = shallowRef<Array<string>>();
|
||||
const cloudCombat = shallowRef<TGApp.Plugins.Hutao.Combat.Data>();
|
||||
const localCombat = shallowRef<Array<TGApp.Sqlite.Combat.TableTrans>>([]);
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -151,6 +175,16 @@ async function toChallenge(): Promise<void> {
|
||||
await router.push({ name: "幽境危战" });
|
||||
}
|
||||
|
||||
async function loadWiki(): Promise<void> {
|
||||
await showLoading.start("正在加载统计数据");
|
||||
const res = await hutao.Combat.data();
|
||||
if (res === undefined) showSnackbar.error("未获取到剧诗数据");
|
||||
else cloudCombat.value = <TGApp.Plugins.Hutao.Combat.Data>res;
|
||||
await showLoading.end();
|
||||
showSnackbar.success("成功获取统计数据");
|
||||
showData.value = true;
|
||||
}
|
||||
|
||||
async function reloadUid(): Promise<void> {
|
||||
uidList.value = await TSUserCombat.getAllUid();
|
||||
if (uidList.value.includes(account.value.gameUid)) uidCur.value = account.value.gameUid;
|
||||
@@ -168,6 +202,29 @@ async function loadCombat(): Promise<void> {
|
||||
if (localCombat.value.length > 0) userTab.value = localCombat.value[0].id;
|
||||
}
|
||||
|
||||
async function editHutaoEmail(): Promise<void> {
|
||||
if (hutaoEmail.value) {
|
||||
const chgCheck = await showDialog.check("是否更改胡桃云账号", `当前账号:${hutaoEmail.value}`);
|
||||
if (!chgCheck) {
|
||||
showSnackbar.cancel("已取消更改胡桃云账号");
|
||||
return;
|
||||
}
|
||||
}
|
||||
const newEmail = await showDialog.input("请输入胡桃云账号", "胡桃云账号", hutaoEmail.value);
|
||||
if (!newEmail) {
|
||||
showSnackbar.cancel("已取消设置胡桃云账号");
|
||||
return;
|
||||
}
|
||||
// 简单验证邮箱格式
|
||||
const mailReg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
|
||||
if (!mailReg.test(newEmail)) {
|
||||
showSnackbar.error("邮箱格式错误");
|
||||
return;
|
||||
}
|
||||
hutaoEmail.value = newEmail;
|
||||
showSnackbar.success("已设置胡桃云账号");
|
||||
}
|
||||
|
||||
async function refreshCombat(): Promise<void> {
|
||||
if (!cookie.value) {
|
||||
showSnackbar.error("未登录");
|
||||
@@ -254,6 +311,54 @@ async function deleteCombat(): Promise<void> {
|
||||
await showLoading.end();
|
||||
}
|
||||
|
||||
async function uploadCombat(): Promise<void> {
|
||||
if (!hutaoEmail.value || hutaoEmail.value === "") {
|
||||
const check = await showDialog.check("确定上传?", "未设置胡桃云账号");
|
||||
if (!check) return;
|
||||
}
|
||||
await TGLogger.Info("[UserCombat][uploadCombat] 上传剧诗数据");
|
||||
const maxId = Math.max(...localCombat.value.map((i) => i.id));
|
||||
const combatData = localCombat.value.find((item) => item.id === maxId);
|
||||
if (!combatData) {
|
||||
showSnackbar.error("未找到剧诗数据");
|
||||
await TGLogger.Warn("[UserCombat][uploadCombat] 未找到深渊数据");
|
||||
return;
|
||||
}
|
||||
if (!combatData.hasDetailData) {
|
||||
showSnackbar.error("未获取到详情数据");
|
||||
await TGLogger.Warn(`[UserCombat][uploadCombat] 未获取到详细数据`);
|
||||
return;
|
||||
}
|
||||
const startTime = new Date(combatData.startTime).getTime();
|
||||
const endTime = new Date(combatData.endTime).getTime();
|
||||
const nowTime = new Date().getTime();
|
||||
if (nowTime < startTime || nowTime > endTime) {
|
||||
showSnackbar.warn("非最新剧诗数据,请刷新剧诗数据后重试!");
|
||||
await TGLogger.Warn("[UserCombat][uploadCombat] 非最新剧诗数据");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await showLoading.start("正在上传剧诗数据");
|
||||
const transCombat = hutao.Combat.trans(combatData);
|
||||
const res = await hutao.Combat.upload(transCombat);
|
||||
if (res.retcode === 0) {
|
||||
showSnackbar.success(res.message ?? "上传剧诗数据成功");
|
||||
await TGLogger.Info("[UserCombat][uploadCombat] 上传剧诗数据成功");
|
||||
} else {
|
||||
showSnackbar.error(`[${res.retcode}]${res.message}`);
|
||||
await TGLogger.Error("[UserCombat][uploadCombat] 上传剧诗数据失败");
|
||||
await TGLogger.Error(`[UserCombat][uploadCombat] ${res.retcode} ${res.message}`);
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
showSnackbar.error(e.message);
|
||||
await TGLogger.Error("[UserCombat][uploadCombat] 上传剧诗数据失败");
|
||||
await TGLogger.Error(`[UserCombat][uploadCombat] ${e.message}`);
|
||||
}
|
||||
}
|
||||
await showLoading.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试读取胡桃工具箱导出的剧诗数据
|
||||
* @since Beta v0.8.6
|
||||
@@ -318,6 +423,31 @@ async function tryReadCombat(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
.uct-extension {
|
||||
position: relative;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-right: 16px;
|
||||
padding-left: 16px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.uct-extension-right {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
column-gap: 8px;
|
||||
|
||||
span {
|
||||
color: var(--tgc-od-red);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.uct-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -52,7 +52,6 @@ import HtaTabHold from "@comp/hutaoAbyss/hta-tab-hold.vue";
|
||||
import HtaTabTeam from "@comp/hutaoAbyss/hta-tab-team.vue";
|
||||
import HtaTabUp from "@comp/hutaoAbyss/hta-tab-up.vue";
|
||||
import HtaTabUse from "@comp/hutaoAbyss/hta-tab-use.vue";
|
||||
import Hutao from "@Hutao/index.js";
|
||||
import hutao from "@Hutao/index.js";
|
||||
import { timestampToDate } from "@utils/toolFunc.js";
|
||||
import { onMounted, reactive, ref, type ShallowRef, shallowRef, watch } from "vue";
|
||||
@@ -147,7 +146,7 @@ async function getUseData(): Promise<void> {
|
||||
} else {
|
||||
cur = curResp;
|
||||
}
|
||||
const lastResp = await Hutao.Abyss.avatar.use(true);
|
||||
const lastResp = await hutao.Abyss.avatar.use(true);
|
||||
if (!Array.isArray(lastResp)) {
|
||||
await showLoading.update(`[${lastResp.retcode}] ${lastResp.message}`);
|
||||
} else {
|
||||
@@ -166,7 +165,7 @@ async function getUpData(): Promise<void> {
|
||||
} else {
|
||||
cur = curResp;
|
||||
}
|
||||
const lastResp = await Hutao.Abyss.avatar.use(true);
|
||||
const lastResp = await hutao.Abyss.avatar.use(true);
|
||||
if (!Array.isArray(lastResp)) {
|
||||
await showLoading.update(`[${lastResp.retcode}] ${lastResp.message}`);
|
||||
} else {
|
||||
@@ -195,7 +194,7 @@ async function getHoldData(): Promise<void> {
|
||||
} else {
|
||||
cur = curResp;
|
||||
}
|
||||
const lastResp = await Hutao.Abyss.avatar.hold(true);
|
||||
const lastResp = await hutao.Abyss.avatar.hold(true);
|
||||
if (!Array.isArray(lastResp)) {
|
||||
await showLoading.update(`[${lastResp.retcode}] ${lastResp.message}`);
|
||||
} else {
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
/**
|
||||
* wiki 路由模块
|
||||
* @since Beta v0.8.6
|
||||
* @since Beta v0.9.1
|
||||
*/
|
||||
import type { RouteRecordRaw } from "vue-router";
|
||||
|
||||
const wikiRoutes = (<const>[
|
||||
{
|
||||
path: "/wiki/abyss",
|
||||
name: "深渊数据库",
|
||||
component: async () => await import("@/pages/WIKI/Abyss.vue"),
|
||||
},
|
||||
{
|
||||
path: "/wiki/character/:id?",
|
||||
name: "角色图鉴",
|
||||
|
||||
@@ -33,7 +33,7 @@ const useUserStore = defineStore(
|
||||
const cookie = ref<TGApp.App.Account.Cookie>();
|
||||
const propMap = ref<TGApp.Game.Avatar.PropMap>();
|
||||
|
||||
// 胡桃账号(邮箱),用于上传深渊记录
|
||||
/** 胡桃云邮箱 */
|
||||
const hutaoEmail = ref<string>();
|
||||
|
||||
function getProp(prop: number): TGApp.Game.Avatar.PropMapItem | false {
|
||||
|
||||
Reference in New Issue
Block a user