Files
TeyvatGuide/src/pages/User/Characters.vue
2024-08-17 12:49:05 +08:00

246 lines
7.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<ToLoading v-model="loading" :title="loadingTitle" :subtitle="loadingSub" />
<div class="uc-box">
<div class="uc-top">
<div class="uc-top-title" @click="switchOld">
<span v-if="user">
{{ user.nickname }} UID{{ user.gameUid }} 更新于 {{ getUpdateTime() }}
</span>
<span v-else> 暂无数据 </span>
</div>
<div class="uc-top-btns" data-html2canvas-ignore>
<v-btn class="uc-top-btn" @click="refresh()">
<template #prepend>
<v-icon>mdi-refresh</v-icon>
</template>
刷新
</v-btn>
<v-btn class="uc-top-btn" @click="share()">
<template #prepend>
<v-icon>mdi-share</v-icon>
</template>
分享
</v-btn>
</div>
</div>
<div class="uc-content">
<div class="uc-left">
<div class="ucl-top"></div>
<div class="uc-grid">
<TuaAvatarBox
v-for="(role, index) in roleList"
:key="index"
:model-value="role"
@click="selectRole(role)"
/>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { storeToRefs } from "pinia";
import { onBeforeMount, onMounted, ref } from "vue";
import showSnackbar from "../../components/func/snackbar.js";
import ToLoading from "../../components/overlay/to-loading.vue";
import TuaAvatarBox from "../../components/userAvatar/tua-avatar-box.vue";
import TSUserAvatar from "../../plugins/Sqlite/modules/userAvatar.js";
import { useUserStore } from "../../store/modules/user.js";
import TGLogger from "../../utils/TGLogger.js";
import { generateShareImg } from "../../utils/TGShare.js";
import TGRequest from "../../web/request/TGRequest.js";
// store
const userStore = storeToRefs(useUserStore());
const user = ref<TGApp.Sqlite.Account.Game>();
// loading
const loading = ref<boolean>(false);
const loadingTitle = ref<string>();
const loadingSub = ref<string>();
// data
const isEmpty = ref(true);
const roleList = ref<TGApp.Sqlite.Character.UserRole[]>([]);
// overlay
const visible = ref(false);
const dataVal = ref<TGApp.Sqlite.Character.UserRole>(<TGApp.Sqlite.Character.UserRole>{});
const selectIndex = ref(0);
const detailDev = ref(true);
onBeforeMount(() => {
if (userStore.account.value) {
user.value = userStore.account.value;
}
});
onMounted(async () => {
await TGLogger.Info("[Character][onMounted] 进入角色页面");
loadingTitle.value = "正在获取角色数据";
loading.value = true;
await load();
loading.value = false;
});
function switchOld(): void {
detailDev.value = !detailDev.value;
showSnackbar({
text: `已切换到${detailDev.value ? "新" : "旧"}版角色详情页面`,
});
}
async function load(): Promise<void> {
if (!user.value) return;
const roleData = await TSUserAvatar.getAvatars(user.value.gameUid);
roleData.sort((a, b) => {
if (a.avatar.rarity !== b.avatar.rarity) return b.avatar.rarity - a.avatar.rarity;
if (a.avatar.element !== b.avatar.element)
return a.avatar.element.localeCompare(b.avatar.element);
return a.cid - b.cid;
});
roleList.value = roleData;
dataVal.value = roleData[selectIndex.value];
isEmpty.value = false;
await TGLogger.Info(`[Character][loadRole][${user.value.gameUid}] 成功加载角色数据`);
await TGLogger.Info(
`[Character][loadRole][${user.value.gameUid}] 共获取到${roleData.length}个角色`,
);
}
async function refresh(): Promise<void> {
if (!user.value) return;
await TGLogger.Info(`[Character][refreshRoles][${user.value.gameUid}] 正在更新角色数据`);
loadingTitle.value = "正在获取角色列表";
loading.value = true;
if (!userStore.cookie.value) {
showSnackbar({
text: "请先登录",
color: "error",
});
loading.value = false;
return;
}
const cookie = {
account_id: userStore.cookie.value.account_id,
cookie_token: userStore.cookie.value.cookie_token,
};
const listRes = await TGRequest.User.byCookie.getAvatarList(cookie, user.value.gameUid);
if (!Array.isArray(listRes)) {
showSnackbar({
text: `[${listRes.retcode}] ${listRes.message}`,
color: "error",
});
await TGLogger.Error(`[Character][refreshRoles][${user.value.gameUid}] 获取角色列表失败`);
await TGLogger.Error(
`[Character][refreshRoles][${user.value.gameUid}] ${listRes.retcode} ${listRes.message}`,
);
loading.value = false;
return;
}
const idList = listRes.map((i) => i.id.toString());
loadingTitle.value = "正在获取角色数据";
loadingSub.value = `${idList.length}个角色`;
const res = await TGRequest.User.byCookie.getAvatarDetail(cookie, user.value.gameUid, idList);
if ("retcode" in res) {
showSnackbar({
text: `[${res.retcode}] ${res.message}`,
color: "error",
});
await TGLogger.Error(`[Character][refreshRoles][${user.value.gameUid}] 获取角色数据失败`);
await TGLogger.Error(
`[Character][refreshRoles][${user.value.gameUid}] ${res.retcode} ${res.message}`,
);
loading.value = false;
return;
}
userStore.propMap.value = res.property_map;
loadingTitle.value = "正在保存角色数据";
await TSUserAvatar.saveAvatars(user.value.gameUid, res.list);
await TGLogger.Info(`[Character][refreshRoles][${user.value.gameUid}] 成功更新角色数据`);
await TGLogger.Info(
`[Character][refreshRoles][${user.value.gameUid}] 共更新${res.list.length}个角色`,
);
await load();
loading.value = false;
}
async function share(): Promise<void> {
if (!user.value) return;
await TGLogger.Info(`[Character][shareRoles][${user.value.gameUid}] 正在生成分享图片`);
const rolesBox = <HTMLElement>document.querySelector(".uc-box");
const fileName = `【角色列表】-${user.value.gameUid}`;
loadingTitle.value = "正在生成图片";
loadingSub.value = `${fileName}.png`;
loading.value = true;
await generateShareImg(fileName, rolesBox);
loadingSub.value = "";
loading.value = false;
await TGLogger.Info(`[Character][shareRoles][${user.value.gameUid}] 生成分享图片成功`);
}
function getUpdateTime(): string {
let lastUpdateTime = 0;
roleList.value.forEach((role) => {
const updateTime = new Date(role.updated).getTime();
if (updateTime > lastUpdateTime) {
lastUpdateTime = updateTime;
}
});
return new Date(lastUpdateTime).toLocaleString().replace(/\//g, "-");
}
function selectRole(role: TGApp.Sqlite.Character.UserRole): void {
dataVal.value = role;
selectIndex.value = roleList.value.indexOf(role);
visible.value = true;
}
</script>
<style lang="css" scoped>
.uc-box {
display: flex;
flex-direction: column;
padding: 10px;
border: 1px solid var(--common-shadow-2);
border-radius: 5px;
background: var(--box-bg-1);
gap: 10px;
}
.uc-top {
display: flex;
width: 100%;
height: 50px;
align-items: center;
justify-content: space-between;
padding: 10px;
border-bottom: 1px solid var(--common-shadow-2);
}
.uc-top-title {
color: var(--common-text-title);
font-family: var(--font-title);
font-size: 20px;
}
.uc-top-btns {
display: flex;
align-items: center;
gap: 15px;
}
.uc-top-btn {
border-radius: 5px;
background: var(--tgc-btn-1);
color: var(--btn-text);
font-family: var(--font-text);
}
.uc-grid {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
</style>