mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-14 09:38:13 +08:00
@@ -6,6 +6,36 @@
|
||||
<template #title>{{ userInfo.nickname }}</template>
|
||||
<template #subtitle>UID:{{ userInfo.uid }}</template>
|
||||
<template #text>{{ userInfo.desc }}</template>
|
||||
<template #append>
|
||||
<v-menu location="start">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn
|
||||
variant="outlined"
|
||||
@click="showAccounts()"
|
||||
title="切换默认游戏账户"
|
||||
v-bind="props"
|
||||
icon="mdi-gamepad-variant"
|
||||
/>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="account in gameAccounts"
|
||||
:key="account.gameUid"
|
||||
@click="switchGameAccount(account)"
|
||||
>
|
||||
<v-list-item-title>{{ account.nickname }}</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
{{ account.gameUid }}({{ account.regionName }})
|
||||
</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<div v-if="account.gameUid === userStore.account.value.gameUid" title="当前登录账号">
|
||||
<v-icon color="green">mdi-check</v-icon>
|
||||
</div>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
<template #actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
@@ -16,26 +46,50 @@
|
||||
/>
|
||||
<v-btn
|
||||
variant="outlined"
|
||||
@click="confirmRefreshUser"
|
||||
@click="confirmRefreshUser(userStore.uid.value!)"
|
||||
:disabled="userStore.uid.value === undefined"
|
||||
icon="mdi-refresh"
|
||||
:loading="loading"
|
||||
title="刷新用户信息"
|
||||
/>
|
||||
<v-btn variant="outlined" @click="confirmCopyCookie" icon="mdi-cookie" title="复制Cookie" />
|
||||
<v-menu location="start">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn
|
||||
variant="outlined"
|
||||
icon="mdi-account-switch"
|
||||
title="切换账户"
|
||||
@click="showMenu"
|
||||
v-bind="props"
|
||||
/>
|
||||
</template>
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="account in accounts"
|
||||
:key="account.uid"
|
||||
@click="loadAccount(account.uid)"
|
||||
>
|
||||
<v-list-item-title>{{ account.brief.nickname }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ account.brief.uid }}</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<div v-if="account.uid === userStore.uid.value" title="当前登录账号">
|
||||
<v-icon color="green">mdi-check</v-icon>
|
||||
</div>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { UnlistenFn } from "@tauri-apps/api/event";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
|
||||
import Mys from "../../plugins/Mys/index.js";
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import { useAppStore } from "../../store/modules/app.js";
|
||||
import TSUserAccount from "../../plugins/Sqlite/modules/userAccount.js";
|
||||
import { useUserStore } from "../../store/modules/user.js";
|
||||
import TGLogger from "../../utils/TGLogger.js";
|
||||
import { getDeviceFp } from "../../web/request/getDeviceFp.js";
|
||||
import TGRequest from "../../web/request/TGRequest.js";
|
||||
import showConfirm from "../func/confirm.js";
|
||||
import showGeetest from "../func/geetest.js";
|
||||
@@ -46,58 +100,36 @@ interface TcUserBadgeEmits {
|
||||
}
|
||||
|
||||
const emits = defineEmits<TcUserBadgeEmits>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
|
||||
const loading = ref<boolean>(false);
|
||||
const userInfo = ref<TGApp.App.Account.BriefInfo>({
|
||||
nickname: "未登录",
|
||||
uid: "-1",
|
||||
desc: "请扫码登录",
|
||||
avatar: "/source/UI/lumine.webp",
|
||||
});
|
||||
|
||||
let signListener: UnlistenFn;
|
||||
|
||||
onMounted(() => {
|
||||
if (userStore.briefInfo.value && userStore.briefInfo.value.nickname) {
|
||||
userInfo.value = userStore.briefInfo.value;
|
||||
}
|
||||
});
|
||||
|
||||
watch(userStore.briefInfo, (v) => {
|
||||
if (v && v.nickname) {
|
||||
userInfo.value = v;
|
||||
}
|
||||
const accounts = ref<TGApp.App.Account.User[]>([]);
|
||||
const gameAccounts = ref<TGApp.Sqlite.Account.Game[]>([]);
|
||||
const userInfo = computed<TGApp.App.Account.BriefInfo>(() => {
|
||||
if (userStore.uid.value === undefined)
|
||||
return {
|
||||
nickname: "未登录",
|
||||
uid: "-1",
|
||||
desc: "请使用短信验证码登录",
|
||||
avatar: "/source/UI/lumine.webp",
|
||||
};
|
||||
return userStore.briefInfo.value;
|
||||
});
|
||||
|
||||
async function tryCaptchaLogin(): Promise<void> {
|
||||
const phone = await showConfirm({
|
||||
mode: "input",
|
||||
title: "请输入手机号",
|
||||
text: "+86",
|
||||
});
|
||||
const phone = await showConfirm({ mode: "input", title: "请输入手机号", text: "+86" });
|
||||
if (!phone) {
|
||||
showSnackbar({
|
||||
color: "cancel",
|
||||
text: "已取消验证码登录",
|
||||
});
|
||||
showSnackbar({ color: "cancel", text: "已取消验证码登录" });
|
||||
return;
|
||||
}
|
||||
const phoneReg = /^1[3-9]\d{9}$/;
|
||||
if (!phoneReg.test(phone)) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "请输入正确的手机号",
|
||||
});
|
||||
showSnackbar({ color: "error", text: "请输入正确的手机号" });
|
||||
return;
|
||||
}
|
||||
const actionType = await tryGetCaptcha(phone);
|
||||
if (!actionType) return;
|
||||
showSnackbar({
|
||||
text: `已发送验证码到 ${phone}`,
|
||||
});
|
||||
showSnackbar({ text: `已发送验证码到 ${phone}` });
|
||||
const captcha = await showConfirm({
|
||||
mode: "input",
|
||||
title: "请输入验证码",
|
||||
@@ -105,15 +137,13 @@ async function tryCaptchaLogin(): Promise<void> {
|
||||
otcancel: false,
|
||||
});
|
||||
if (!captcha) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "输入验证码为空",
|
||||
});
|
||||
showSnackbar({ color: "error", text: "输入验证码为空" });
|
||||
return;
|
||||
}
|
||||
const loginResp = await tryLoginByCaptcha(phone, captcha, actionType);
|
||||
if (!loginResp) return;
|
||||
userStore.cookie.value = {
|
||||
loading.value = true;
|
||||
const ck: TGApp.App.Account.Cookie = {
|
||||
account_id: loginResp.user_info.aid,
|
||||
ltuid: loginResp.user_info.aid,
|
||||
stuid: loginResp.user_info.aid,
|
||||
@@ -122,34 +152,84 @@ async function tryCaptchaLogin(): Promise<void> {
|
||||
stoken: loginResp.token.token,
|
||||
ltoken: "",
|
||||
};
|
||||
showSnackbar({
|
||||
text: "登录成功,即将刷新用户信息",
|
||||
color: "success",
|
||||
});
|
||||
setTimeout(() => {
|
||||
refreshUser();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async function refreshUser() {
|
||||
const ck = userStore.cookie.value;
|
||||
if (ck === undefined || JSON.stringify(ck) === "{}") {
|
||||
await TGLogger.Error("[tc-userBadge][refreshUser] cookie 不存在");
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "登录后才能刷新用户信息!",
|
||||
});
|
||||
appStore.isLogin = false;
|
||||
emits("loadOuter", { show: true, title: "正在获取 LToken" });
|
||||
const ltokenRes = await TGRequest.User.bySToken.getLToken(ck.mid, ck.stoken);
|
||||
if (typeof ltokenRes !== "string") {
|
||||
showSnackbar({ text: `[${ltokenRes.retcode}]${ltokenRes.message}`, color: "error" });
|
||||
await TGLogger.Error(`获取LToken失败:${ltokenRes.retcode}-${ltokenRes.message}`);
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
return;
|
||||
}
|
||||
ck.ltoken = ltokenRes;
|
||||
emits("loadOuter", { show: true, title: "正在获取 cookieToken " });
|
||||
const cookieTokenRes = await TGRequest.User.bySToken.getCookieToken(ck.mid, ck.stoken);
|
||||
if (typeof cookieTokenRes !== "string") {
|
||||
showSnackbar({ text: `[${cookieTokenRes.retcode}]${cookieTokenRes.message}`, color: "error" });
|
||||
await TGLogger.Error(
|
||||
`获取CookieToken失败:${cookieTokenRes.retcode}-${cookieTokenRes.message}`,
|
||||
);
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
return;
|
||||
}
|
||||
ck.cookie_token = cookieTokenRes;
|
||||
emits("loadOuter", { show: true, title: "正在获取用户信息" });
|
||||
const briefRes = await TGRequest.User.byCookie.getUserInfo(ck.cookie_token, ck.account_id);
|
||||
if ("retcode" in briefRes) {
|
||||
showSnackbar({ text: `[${briefRes.retcode}]${briefRes.message}` });
|
||||
await TGLogger.Error(`获取用户数据失败:${briefRes.retcode}-${briefRes.message}`);
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
return;
|
||||
}
|
||||
const briefInfo: TGApp.App.Account.BriefInfo = {
|
||||
nickname: briefRes.nickname,
|
||||
uid: briefRes.uid,
|
||||
avatar: briefRes.avatar_url,
|
||||
desc: briefRes.introduce,
|
||||
};
|
||||
emits("loadOuter", { show: true, title: "正在保存并切换用户" });
|
||||
await TSUserAccount.account.saveAccount({
|
||||
uid: briefInfo.uid,
|
||||
cookie: ck,
|
||||
brief: briefInfo,
|
||||
updated: "",
|
||||
});
|
||||
userStore.uid.value = briefInfo.uid;
|
||||
userStore.briefInfo.value = briefInfo;
|
||||
userStore.cookie.value = ck;
|
||||
emits("loadOuter", { show: true, title: "正在获取游戏账号" });
|
||||
const gameRes = await TGRequest.User.bySToken.getAccounts(ck.stoken, ck.stuid);
|
||||
if (!Array.isArray(gameRes)) {
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
showSnackbar({ text: `[${gameRes.retcode}]${gameRes.message}` });
|
||||
return;
|
||||
}
|
||||
await TSUserAccount.game.saveAccounts(briefInfo.uid, gameRes);
|
||||
const curAccount = await TSUserAccount.game.getCurAccount(briefInfo.uid);
|
||||
if (!curAccount) {
|
||||
showSnackbar({ text: "未检测到游戏账号,请重新刷新", color: "warn" });
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
return;
|
||||
}
|
||||
userStore.account.value = curAccount;
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
showSnackbar({ text: "成功加载用户数据!" });
|
||||
}
|
||||
|
||||
async function refreshUser(uid: string) {
|
||||
let account = await TSUserAccount.account.getAccount(uid);
|
||||
if (!account) {
|
||||
showSnackbar({ text: `未获取到${userStore.uid.value}账号数据,请重新登录!`, color: "error" });
|
||||
return;
|
||||
}
|
||||
let ck = account.cookie;
|
||||
loading.value = true;
|
||||
emits("loadOuter", { show: true, title: "正在刷新用户信息" });
|
||||
const deviceInfo = appStore.deviceInfo;
|
||||
if (deviceInfo.device_fp === "00000000000") {
|
||||
appStore.deviceInfo = await getDeviceFp(appStore.deviceInfo);
|
||||
await TGLogger.Warn("[tc-userBadge][refreshUser] 刷新设备信息");
|
||||
}
|
||||
let failCount = 0;
|
||||
emits("loadOuter", { show: true, title: "正在验证 LToken" });
|
||||
const verifyLTokenRes = await TGRequest.User.byLToken.verify(ck.ltoken, ck.ltuid);
|
||||
if (typeof verifyLTokenRes === "string") {
|
||||
@@ -176,7 +256,6 @@ async function refreshUser() {
|
||||
await TGLogger.Error(
|
||||
`[tc-userBadge][refreshUser] ${ltokenRes.retcode}: ${ltokenRes.message}`,
|
||||
);
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
emits("loadOuter", { show: true, title: "正在获取 CookieToken" });
|
||||
@@ -199,93 +278,74 @@ async function refreshUser() {
|
||||
await TGLogger.Error(
|
||||
`[tc-userBadge][refreshUser] ${cookieTokenRes.retcode}: ${cookieTokenRes.message}`,
|
||||
);
|
||||
failCount++;
|
||||
}
|
||||
userStore.cookie.value = ck;
|
||||
await TGSqlite.saveAppData("cookie", JSON.stringify(ck));
|
||||
failCount = await refreshUserInfo();
|
||||
if (failCount > 0) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "刷新失败!重试或者重新扫码登录!",
|
||||
});
|
||||
} else {
|
||||
showSnackbar({ text: "刷新成功!" });
|
||||
appStore.isLogin = true;
|
||||
}
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
}
|
||||
|
||||
async function refreshUserInfo(): Promise<number> {
|
||||
let failCount = 0;
|
||||
const ck = userStore.cookie.value;
|
||||
if (ck === undefined) {
|
||||
showSnackbar({
|
||||
text: "未获取到用户 ck!",
|
||||
color: "error",
|
||||
});
|
||||
await TGLogger.Error("[tc-userBadge][refreshUserInfo] 未获取到用户 ck");
|
||||
return 0;
|
||||
}
|
||||
account.cookie = ck;
|
||||
emits("loadOuter", { show: true, title: "正在获取用户信息" });
|
||||
const infoRes = await TGRequest.User.byCookie.getUserInfo(ck.cookie_token, ck.account_id);
|
||||
if ("retcode" in infoRes) {
|
||||
emits("loadOuter", { show: true, title: "正在获取用户信息", text: "获取用户信息失败!" });
|
||||
await TGLogger.Error("[tc-userBadge][refreshUserInfo] 获取用户信息失败");
|
||||
await TGLogger.Error(`[tc-userBadge][refreshUserInfo] ${infoRes.retcode}: ${infoRes.message}`);
|
||||
failCount++;
|
||||
} else {
|
||||
emits("loadOuter", { show: true, title: "正在获取用户信息", text: "获取用户信息成功!" });
|
||||
const briefInfo: TGApp.App.Account.BriefInfo = {
|
||||
account.brief = {
|
||||
nickname: infoRes.nickname,
|
||||
uid: infoRes.uid,
|
||||
avatar: infoRes.avatar_url,
|
||||
desc: infoRes.introduce,
|
||||
};
|
||||
userStore.briefInfo.value = briefInfo;
|
||||
await TGSqlite.saveAppData("userInfo", JSON.stringify(briefInfo));
|
||||
await TGLogger.Info("[tc-userBadge][refreshUserInfo] 获取用户信息成功");
|
||||
}
|
||||
await TSUserAccount.account.saveAccount(account);
|
||||
emits("loadOuter", { show: true, title: "正在获取账号信息" });
|
||||
const accountRes = await TGRequest.User.byCookie.getAccounts(ck.cookie_token, ck.account_id);
|
||||
if (Array.isArray(accountRes)) {
|
||||
emits("loadOuter", { show: true, title: "正在获取账号信息", text: "获取账号信息成功!" });
|
||||
await TGLogger.Info("[tc-userBadge][refreshUserInfo] 获取账号信息成功");
|
||||
await TGSqlite.saveAccount(accountRes);
|
||||
const curAccount = await TGSqlite.getCurAccount();
|
||||
if (curAccount) userStore.account.value = curAccount;
|
||||
await TSUserAccount.game.saveAccounts(account.uid, accountRes);
|
||||
} else {
|
||||
emits("loadOuter", { show: true, title: "正在获取账号信息", text: "获取账号信息失败!" });
|
||||
await TGLogger.Error("[tc-userBadge][refreshUserInfo] 获取账号信息失败");
|
||||
await TGLogger.Error(
|
||||
`[tc-userBadge][refreshUserInfo] ${accountRes.retcode}: ${accountRes.message}`,
|
||||
);
|
||||
failCount++;
|
||||
}
|
||||
return failCount;
|
||||
loading.value = false;
|
||||
emits("loadOuter", { show: false });
|
||||
}
|
||||
|
||||
async function confirmRefreshUser(): Promise<void> {
|
||||
const res = await showConfirm({
|
||||
title: "确认刷新用户信息吗?",
|
||||
text: "将会重新获取用户信息",
|
||||
});
|
||||
async function loadAccount(uid: string): Promise<void> {
|
||||
if (userStore.uid.value && uid === userStore.uid.value) {
|
||||
showSnackbar({ text: "该账户已经登录,无需切换", color: "warn" });
|
||||
return;
|
||||
}
|
||||
const account = await TSUserAccount.account.getAccount(uid);
|
||||
if (!account) {
|
||||
showSnackbar({ text: `无法获取${uid}的账号信息`, color: "warn" });
|
||||
return;
|
||||
}
|
||||
userStore.uid.value = uid;
|
||||
userStore.briefInfo.value = account.brief;
|
||||
userStore.cookie.value = account.cookie;
|
||||
const gameAccount = await TSUserAccount.game.getCurAccount(uid);
|
||||
if (!gameAccount) {
|
||||
showSnackbar({ text: `无法获取${uid}的游戏信息`, color: "warn" });
|
||||
return;
|
||||
}
|
||||
userStore.account.value = gameAccount;
|
||||
showSnackbar({ text: `成功切换到用户${uid}` });
|
||||
}
|
||||
|
||||
async function confirmRefreshUser(uid: string): Promise<void> {
|
||||
const res = await showConfirm({ title: "确认刷新用户信息吗?", text: "将会重新获取用户信息" });
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "cancel",
|
||||
text: "已取消刷新",
|
||||
});
|
||||
showSnackbar({ color: "cancel", text: "已取消刷新" });
|
||||
return;
|
||||
}
|
||||
if (!userStore.cookie) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "请先登录",
|
||||
});
|
||||
return;
|
||||
}
|
||||
await refreshUser();
|
||||
await refreshUser(uid);
|
||||
const confirm = await showConfirm({ title: "是否切换用户?", text: `将切换到用户${uid}` });
|
||||
if (!confirm) return;
|
||||
await loadAccount(uid);
|
||||
}
|
||||
|
||||
async function confirmCopyCookie(): Promise<void> {
|
||||
@@ -294,35 +354,23 @@ async function confirmCopyCookie(): Promise<void> {
|
||||
text: "将会复制当前登录的 Cookie",
|
||||
});
|
||||
if (!res) {
|
||||
showSnackbar({
|
||||
color: "cancel",
|
||||
text: "已取消复制",
|
||||
});
|
||||
showSnackbar({ color: "cancel", text: "已取消复制" });
|
||||
return;
|
||||
}
|
||||
if (!userStore.cookie) {
|
||||
showSnackbar({
|
||||
color: "error",
|
||||
text: "请先登录",
|
||||
});
|
||||
if (!userStore.cookie.value) {
|
||||
showSnackbar({ color: "error", text: "请先登录" });
|
||||
return;
|
||||
}
|
||||
const ckText = useUserStore().getAllCookie();
|
||||
const ckText = TSUserAccount.account.copy(userStore.cookie.value);
|
||||
await navigator.clipboard.writeText(ckText);
|
||||
showSnackbar({
|
||||
text: "已复制 Cookie!",
|
||||
color: "success",
|
||||
});
|
||||
showSnackbar({ text: "已复制 Cookie!", color: "success" });
|
||||
}
|
||||
|
||||
async function tryGetCaptcha(phone: string, aigis?: string): Promise<string | false> {
|
||||
const captchaResp = await Mys.User.getCaptcha(phone, aigis);
|
||||
if ("retcode" in captchaResp) {
|
||||
if (!captchaResp.data || captchaResp.data === "") {
|
||||
showSnackbar({
|
||||
text: `[${captchaResp.retcode}] ${captchaResp.message}`,
|
||||
color: "error",
|
||||
});
|
||||
showSnackbar({ text: `[${captchaResp.retcode}] ${captchaResp.message}`, color: "error" });
|
||||
return false;
|
||||
}
|
||||
const aigisResp: TGApp.Plugins.Mys.CaptchaLogin.CaptchaAigis = JSON.parse(captchaResp.data);
|
||||
@@ -342,10 +390,7 @@ async function tryLoginByCaptcha(
|
||||
const loginResp = await Mys.User.login(phone, captcha, actionType, aigis);
|
||||
if ("retcode" in loginResp) {
|
||||
if (!loginResp.data || loginResp.data === "") {
|
||||
showSnackbar({
|
||||
text: `[${loginResp.retcode}] ${loginResp.message}`,
|
||||
color: "error",
|
||||
});
|
||||
showSnackbar({ text: `[${loginResp.retcode}] ${loginResp.message}`, color: "error" });
|
||||
return false;
|
||||
}
|
||||
const aigisResp: TGApp.Plugins.Mys.CaptchaLogin.CaptchaAigis = JSON.parse(loginResp.data);
|
||||
@@ -356,9 +401,29 @@ async function tryLoginByCaptcha(
|
||||
return loginResp;
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (signListener) signListener();
|
||||
});
|
||||
async function showMenu(): Promise<void> {
|
||||
accounts.value = await TSUserAccount.account.getAllAccount();
|
||||
}
|
||||
|
||||
async function showAccounts(): Promise<void> {
|
||||
if (!userStore.uid.value) return;
|
||||
gameAccounts.value = await TSUserAccount.game.getAccount(userStore.uid.value);
|
||||
}
|
||||
|
||||
async function switchGameAccount(account: TGApp.Sqlite.Account.Game): Promise<void> {
|
||||
if (account.gameUid === userStore.account.value.gameUid) {
|
||||
showSnackbar({ text: "已经登录,无需切换!", color: "warn" });
|
||||
return;
|
||||
}
|
||||
await TSUserAccount.game.switchAccount(account.uid, account.gameUid);
|
||||
const gameAccount = await TSUserAccount.game.getCurAccount(account.uid);
|
||||
if (!gameAccount) {
|
||||
showSnackbar({ text: `无法获取${account.uid}的游戏信息`, color: "warn" });
|
||||
return;
|
||||
}
|
||||
userStore.account.value = gameAccount;
|
||||
showSnackbar({ text: "成功切换游戏账户!", color: "success" });
|
||||
}
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tcu-box {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<TItemBox :model-value="box" />
|
||||
<TItemBox :model-value="box" v-if="box" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import { AppCharacterData } from "../../data/index.js";
|
||||
import TItemBox from "../main/t-itembox.vue";
|
||||
import type { TItemBoxData } from "../main/t-itembox.vue";
|
||||
|
||||
@@ -13,10 +13,11 @@ interface TibAbyssDetailProps {
|
||||
}
|
||||
|
||||
const props = defineProps<TibAbyssDetailProps>();
|
||||
const box = ref<TItemBoxData>(<TItemBoxData>{});
|
||||
const box = ref<TItemBoxData>();
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await TGSqlite.getAppCharacter(props.modelValue.id);
|
||||
const res = AppCharacterData.find((a) => a.id === props.modelValue.id);
|
||||
if (res === undefined) return;
|
||||
if (props.modelValue.id === 10000005 || props.modelValue.id === 10000007) {
|
||||
box.value = {
|
||||
clickable: false,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<TItemBox v-model="box" />
|
||||
<TItemBox v-model="box" v-if="box" />
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import { AppCharacterData } from "../../data/index.js";
|
||||
import TItemBox from "../main/t-itembox.vue";
|
||||
import type { TItemBoxData } from "../main/t-itembox.vue";
|
||||
|
||||
@@ -13,10 +13,11 @@ interface TibAbyssOverviewProps {
|
||||
}
|
||||
|
||||
const props = defineProps<TibAbyssOverviewProps>();
|
||||
const box = ref<TItemBoxData>(<TItemBoxData>{});
|
||||
const box = ref<TItemBoxData>();
|
||||
|
||||
onMounted(async () => {
|
||||
const res = await TGSqlite.getAppCharacter(props.modelValue.id);
|
||||
onMounted(() => {
|
||||
const res = AppCharacterData.find((a) => a.id === props.modelValue.id);
|
||||
if (res === undefined) return;
|
||||
box.value = {
|
||||
height: "80px",
|
||||
ltSize: "20px",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import { AppCharacterData } from "../../data/index.js";
|
||||
import TItemBox, { type TItemBoxData } from "../main/t-itembox.vue";
|
||||
|
||||
interface TibWikiAbyssProps {
|
||||
@@ -12,33 +12,24 @@ interface TibWikiAbyssProps {
|
||||
}
|
||||
|
||||
const props = defineProps<TibWikiAbyssProps>();
|
||||
const defaultAvatar = <TGApp.Sqlite.Character.AppData>{
|
||||
birthday: "",
|
||||
element: "",
|
||||
id: Number(props.modelValue),
|
||||
name: "旅行者",
|
||||
nameCard: "",
|
||||
star: 5,
|
||||
title: "",
|
||||
updated: "",
|
||||
weapon: "单手剑",
|
||||
};
|
||||
|
||||
const avatar = ref<TGApp.Sqlite.Character.AppData>(defaultAvatar);
|
||||
const avatar = ref<TGApp.App.Character.WikiBriefInfo>();
|
||||
|
||||
const box = computed<TItemBoxData>(() => {
|
||||
return {
|
||||
bg: `/icon/bg/${avatar.value?.star}-Star.webp`,
|
||||
bg: `/icon/bg/${avatar.value?.star ?? 5}-Star.webp`,
|
||||
clickable: false,
|
||||
display: "outer",
|
||||
height: "80px",
|
||||
icon: `/WIKI/character/${avatar.value?.id}.webp`,
|
||||
icon: `/WIKI/character/${props.modelValue}.webp`,
|
||||
innerHeight: 20,
|
||||
innerText: avatar.value.name,
|
||||
innerText: avatar.value?.name ?? "旅行者",
|
||||
lt:
|
||||
avatar.value.element !== ""
|
||||
? `/icon/element/${avatar.value.element}元素.webp`
|
||||
: `/icon/weapon/${avatar.value.weapon}.webp`,
|
||||
avatar.value === undefined
|
||||
? ""
|
||||
: avatar.value.element !== ""
|
||||
? `/icon/element/${avatar.value.element}元素.webp`
|
||||
: `/icon/weapon/${avatar.value.weapon}.webp`,
|
||||
ltSize: "20px",
|
||||
size: "80px",
|
||||
};
|
||||
@@ -49,6 +40,6 @@ onMounted(async () => {
|
||||
if (props.modelValue === "10000005" || props.modelValue === "10000007") {
|
||||
return;
|
||||
}
|
||||
avatar.value = await TGSqlite.getAppCharacter(Number(props.modelValue));
|
||||
avatar.value = AppCharacterData.find((a) => a.id === props.modelValue)!;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
|
||||
import TGSqlite from "../../plugins/Sqlite/index.js";
|
||||
import { AppCharacterData } from "../../data/index.js";
|
||||
import TItemBox, { type TItemBoxData } from "../main/t-itembox.vue";
|
||||
|
||||
interface TibWikiAbyssProps {
|
||||
@@ -15,18 +15,8 @@ interface TibWikiAbyssProps {
|
||||
}
|
||||
|
||||
const props = defineProps<TibWikiAbyssProps>();
|
||||
const defaultAvatar = <TGApp.Sqlite.Character.AppData>{
|
||||
birthday: "",
|
||||
element: "",
|
||||
id: props.modelValue.Item,
|
||||
name: "旅行者",
|
||||
nameCard: "",
|
||||
star: 5,
|
||||
title: "",
|
||||
updated: "",
|
||||
weapon: "单手剑",
|
||||
};
|
||||
const avatar = ref<TGApp.Sqlite.Character.AppData>(defaultAvatar);
|
||||
|
||||
const avatar = ref<TGApp.App.Character.WikiBriefInfo>();
|
||||
|
||||
const box = computed<TItemBoxData>(() => {
|
||||
return {
|
||||
@@ -38,12 +28,14 @@ const box = computed<TItemBoxData>(() => {
|
||||
innerHeight: 20,
|
||||
innerText: (props.modelValue.Rate * 100).toFixed(3) + "%",
|
||||
lt:
|
||||
avatar.value.element !== ""
|
||||
? `/icon/element/${avatar.value.element}元素.webp`
|
||||
: `/icon/weapon/${avatar.value.weapon}.webp`,
|
||||
avatar.value === undefined
|
||||
? ""
|
||||
: avatar.value.element !== ""
|
||||
? `/icon/element/${avatar.value.element}元素.webp`
|
||||
: `/icon/weapon/${avatar.value.weapon}.webp`,
|
||||
ltSize: "20px",
|
||||
outerHeight: 20,
|
||||
outerText: avatar.value.name,
|
||||
outerText: avatar.value?.name ?? "旅行者",
|
||||
size: "80px",
|
||||
};
|
||||
});
|
||||
@@ -53,6 +45,6 @@ onMounted(async () => {
|
||||
if (props.modelValue.Item === 10000005 || props.modelValue.Item === 10000007) {
|
||||
return;
|
||||
}
|
||||
avatar.value = await TGSqlite.getAppCharacter(props.modelValue.Item);
|
||||
avatar.value = AppCharacterData.find((a) => a.id === props.modelValue.Item);
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
<template>
|
||||
<TOverlay v-model="visible" hide blur-val="20px" :to-click="onCancel">
|
||||
<div class="tog-box">
|
||||
<div class="tog-top">
|
||||
<div class="tog-title">请使用米游社APP进行操作</div>
|
||||
<div class="tog-subtitle">所需米游社版本 >= 2.57.1</div>
|
||||
</div>
|
||||
<div class="tog-mid">
|
||||
<qrcode-vue
|
||||
class="tog-qr"
|
||||
:value="qrCode"
|
||||
render-as="svg"
|
||||
:background="'var(--box-bg-1)'"
|
||||
foreground="var(--box-text-1)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</TOverlay>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { storeToRefs } from "pinia";
|
||||
import QrcodeVue from "qrcode.vue";
|
||||
import { computed, onUnmounted, reactive, ref, watch } from "vue";
|
||||
|
||||
import Mys from "../../plugins/Mys/index.js";
|
||||
import { useUserStore } from "../../store/modules/user.js";
|
||||
import TGLogger from "../../utils/TGLogger.js";
|
||||
import TGRequest from "../../web/request/TGRequest.js";
|
||||
import showSnackbar from "../func/snackbar.js";
|
||||
import TOverlay from "../main/t-overlay.vue";
|
||||
|
||||
interface ToWebLoginProps {
|
||||
modelValue: boolean;
|
||||
}
|
||||
|
||||
type ToWebLoginEmits = {
|
||||
(e: "update:modelValue", value: boolean): void;
|
||||
(e: "success"): void;
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<ToWebLoginProps>(), {
|
||||
modelValue: false,
|
||||
});
|
||||
|
||||
const emits = defineEmits<ToWebLoginEmits>();
|
||||
|
||||
const visible = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emits("update:modelValue", value);
|
||||
},
|
||||
});
|
||||
// eslint-disable-next-line no-undef
|
||||
let cycleTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
const qrCode = ref<string>("");
|
||||
const ticket = ref<string>("");
|
||||
const cookie = reactive<TGApp.User.Account.Cookie>({
|
||||
account_id: "",
|
||||
ltuid: "",
|
||||
stuid: "",
|
||||
mid: "",
|
||||
cookie_token: "",
|
||||
stoken: "",
|
||||
ltoken: "",
|
||||
});
|
||||
|
||||
const userStore = storeToRefs(useUserStore());
|
||||
|
||||
watch(visible, async (value) => {
|
||||
if (value) {
|
||||
await freshQr();
|
||||
cycleTimer = setInterval(cycleGetData, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
function onCancel(): void {
|
||||
visible.value = false;
|
||||
showSnackbar({
|
||||
text: "已取消登录",
|
||||
color: "cancel",
|
||||
});
|
||||
if (cycleTimer !== null) {
|
||||
clearInterval(cycleTimer);
|
||||
cycleTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function freshQr(): Promise<void> {
|
||||
const res = await Mys.User.getQr();
|
||||
if ("retcode" in res) {
|
||||
showSnackbar({
|
||||
text: `[${res.retcode}] ${res.message}`,
|
||||
color: "error",
|
||||
});
|
||||
return;
|
||||
}
|
||||
qrCode.value = res.url;
|
||||
const ticketReg = /ticket=(\w+)/;
|
||||
const ticketRes = ticketReg.exec(res.url);
|
||||
if (ticketRes) {
|
||||
ticket.value = ticketRes[1];
|
||||
} else {
|
||||
showSnackbar({
|
||||
text: "获取ticket失败",
|
||||
color: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function cycleGetData() {
|
||||
if (cycleTimer === null) return;
|
||||
const res = await Mys.User.getData(ticket.value);
|
||||
console.log(res);
|
||||
if ("retcode" in res) {
|
||||
showSnackbar({
|
||||
text: `[${res.retcode}] ${res.message}`,
|
||||
color: "error",
|
||||
});
|
||||
if (res.retcode === -106) {
|
||||
await freshQr();
|
||||
} else {
|
||||
clearInterval(cycleTimer);
|
||||
cycleTimer = null;
|
||||
visible.value = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (res.stat === "Init" || res.stat === "Scanned") {
|
||||
return;
|
||||
}
|
||||
if (res.stat === "Confirmed") {
|
||||
clearInterval(cycleTimer);
|
||||
cycleTimer = null;
|
||||
if (res.payload.proto !== "OpenToken" && res.payload.proto !== "Account") {
|
||||
await TGLogger.Warn(`[to-gameLogin] 检测到意外协议:${res.payload.proto}`);
|
||||
showSnackbar({
|
||||
text: "请使用米游社APP进行扫码操作",
|
||||
color: "error",
|
||||
});
|
||||
visible.value = false;
|
||||
return;
|
||||
}
|
||||
if (res.payload.proto === "OpenToken") {
|
||||
const data: TGApp.Plugins.Mys.GameLogin.StatusPayloadRawOpen = JSON.parse(res.payload.raw);
|
||||
cookie.account_id = data.open_id;
|
||||
cookie.ltuid = data.open_id;
|
||||
cookie.stuid = data.open_id;
|
||||
await getTokens(data.open_token);
|
||||
} else {
|
||||
const data: TGApp.Plugins.Mys.GameLogin.StatusPayloadRawAccount = JSON.parse(res.payload.raw);
|
||||
cookie.account_id = data.uid;
|
||||
cookie.ltuid = data.uid;
|
||||
cookie.stuid = data.uid;
|
||||
await getTokens(data.token, true);
|
||||
}
|
||||
showSnackbar({
|
||||
text: "登录成功",
|
||||
color: "success",
|
||||
});
|
||||
visible.value = false;
|
||||
setTimeout(() => {
|
||||
emits("success");
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
async function getTokens(game_token: string, isGT: boolean = false): Promise<void> {
|
||||
const stokenRes = await TGRequest.User.bgGameToken.getStoken(cookie.account_id, game_token, isGT);
|
||||
if (!("retcode" in stokenRes)) {
|
||||
cookie.stoken = stokenRes.token.token;
|
||||
cookie.mid = stokenRes.user_info.mid;
|
||||
} else {
|
||||
await TGLogger.Error("[to-gameLogin] 获取stoken失败");
|
||||
}
|
||||
const cookieTokenRes = await TGRequest.User.bgGameToken.getCookieToken(
|
||||
cookie.account_id,
|
||||
game_token,
|
||||
);
|
||||
if (typeof cookieTokenRes === "string") cookie.cookie_token = cookieTokenRes;
|
||||
else await TGLogger.Error("[to-gameLogin] 获取cookieToken失败");
|
||||
const ltokenRes = await TGRequest.User.bySToken.getLToken(cookie.mid, cookie.stoken);
|
||||
if (typeof ltokenRes === "string") cookie.ltoken = ltokenRes;
|
||||
else await TGLogger.Error("[to-gameLogin] 获取ltoken失败");
|
||||
userStore.cookie.value = cookie;
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (cycleTimer !== null) clearInterval(cycleTimer);
|
||||
cycleTimer = null;
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped>
|
||||
.tog-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: var(--box-bg-1);
|
||||
color: var(--app-page-content);
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tog-top {
|
||||
border-bottom: 1px solid var(--common-shadow-4);
|
||||
font-family: var(--font-title);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tog-title {
|
||||
color: var(--common-text-title);
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.tog-subtitle {
|
||||
font-size: 14px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.tog-mid {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
border: 1px solid var(--common-shadow-2);
|
||||
border-radius: 5px;
|
||||
aspect-ratio: 1;
|
||||
background: var(--box-bg-2);
|
||||
}
|
||||
|
||||
.tog-qr {
|
||||
width: 256px;
|
||||
height: 256px;
|
||||
}
|
||||
</style>
|
||||
@@ -109,16 +109,8 @@ watch(
|
||||
);
|
||||
|
||||
async function loadData(): Promise<void> {
|
||||
if (props.modelValue.cid === 10000005 || props.modelValue.cid === 10000007) {
|
||||
bg.value = "url('/source/nameCard/profile/原神·印象.webp')";
|
||||
} else {
|
||||
const card = await TSUserAvatar.getAvatarCard(props.modelValue.cid);
|
||||
if (card !== false) {
|
||||
bg.value = `url("/source/nameCard/profile/${card}.webp")`;
|
||||
} else {
|
||||
bg.value = "url('/source/nameCard/profile/原神·印象.webp')";
|
||||
}
|
||||
}
|
||||
const card = TSUserAvatar.getAvatarCard(props.modelValue.cid);
|
||||
bg.value = `url("/source/nameCard/profile/${card}.webp")`;
|
||||
if (!avatar.value.startsWith("blob:")) {
|
||||
avatar.value = await saveImgLocal(props.modelValue.avatar.image);
|
||||
}
|
||||
|
||||
@@ -87,16 +87,8 @@ watch(
|
||||
);
|
||||
|
||||
async function loadData(): Promise<void> {
|
||||
if (props.modelValue.cid === 10000005 || props.modelValue.cid === 10000007) {
|
||||
nameCard.value = "/source/nameCard/profile/原神·印象.webp";
|
||||
} else {
|
||||
const card = await TSUserAvatar.getAvatarCard(props.modelValue.cid);
|
||||
if (card !== false) {
|
||||
nameCard.value = `/source/nameCard/profile/${card}.webp`;
|
||||
} else {
|
||||
nameCard.value = false;
|
||||
}
|
||||
}
|
||||
const card = TSUserAvatar.getAvatarCard(props.modelValue.cid);
|
||||
nameCard.value = `/source/nameCard/profile/${card}.webp`;
|
||||
}
|
||||
|
||||
async function share(): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user