mirror of
https://github.com/BTMuli/TeyvatGuide.git
synced 2025-12-11 09:08:14 +08:00
✨ 完成扫码获取 gameToken
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
"https://bbs-api.miyoushe.com/*",
|
"https://bbs-api.miyoushe.com/*",
|
||||||
"https://bbs.mihoyo.com/*",
|
"https://bbs.mihoyo.com/*",
|
||||||
"https://hk4e-api.mihoyo.com/*",
|
"https://hk4e-api.mihoyo.com/*",
|
||||||
|
"https://hk4e-sdk.mihoyo.com/*",
|
||||||
"https://passport-api.mihoyo.com/*",
|
"https://passport-api.mihoyo.com/*",
|
||||||
"https://passport-api.miyoushe.com/*",
|
"https://passport-api.miyoushe.com/*",
|
||||||
"https://passport-api-v4.mihoyo.com/*",
|
"https://passport-api-v4.mihoyo.com/*",
|
||||||
|
|||||||
166
src/components/overlay/to-gameLogin.vue
Normal file
166
src/components/overlay/to-gameLogin.vue
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
<template>
|
||||||
|
<TOverlay v-model="visible" hide blur-val="20px">
|
||||||
|
<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" />
|
||||||
|
</div>
|
||||||
|
<div class="tog-bottom">
|
||||||
|
<v-btn class="tog-btn" @click="onCancel">取消</v-btn>
|
||||||
|
<v-btn class="tog-btn" @click="freshQr">刷新</v-btn>
|
||||||
|
<v-btn class="tog-btn" @click="getData">已扫码</v-btn>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TOverlay>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
// vue
|
||||||
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
import showSnackbar from "../func/snackbar";
|
||||||
|
import TOverlay from "../main/t-overlay.vue";
|
||||||
|
import QrcodeVue from "qrcode.vue";
|
||||||
|
// store
|
||||||
|
import { useUserStore } from "../../store/modules/user";
|
||||||
|
// utils
|
||||||
|
import { getLoginQr, getLoginStatus } from "../../plugins/Mys/utils/doGameLogin";
|
||||||
|
|
||||||
|
interface ToWebLoginProps {
|
||||||
|
modelValue: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToWebLoginEmits = (e: "update:modelValue", value: boolean) => void;
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<ToWebLoginProps>(), {
|
||||||
|
modelValue: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits<ToWebLoginEmits>();
|
||||||
|
|
||||||
|
const visible = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (value) => {
|
||||||
|
emits("update:modelValue", value);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const qrCode = ref<string>("");
|
||||||
|
const ticket = ref<string>("");
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await freshQr();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function freshQr(): Promise<void> {
|
||||||
|
const res = await getLoginQr();
|
||||||
|
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 getData(): Promise<void> {
|
||||||
|
const res = await getLoginStatus(ticket.value);
|
||||||
|
if ("retcode" in res) {
|
||||||
|
showSnackbar({
|
||||||
|
text: `[${res.retcode}] ${res.message}`,
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
} else if (res.stat === "Init") {
|
||||||
|
showSnackbar({
|
||||||
|
text: "请先扫码",
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
} else if (res.stat === "Scanned") {
|
||||||
|
showSnackbar({
|
||||||
|
text: "请在米游社APP上确认登录",
|
||||||
|
color: "error",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const data: TGApp.Plugins.Mys.GameLogin.StatusPayloadRaw = JSON.parse(res.payload.raw);
|
||||||
|
await userStore.saveCookie("account_id", data.uid);
|
||||||
|
await userStore.saveCookie("game_token", data.token);
|
||||||
|
showSnackbar({
|
||||||
|
text: "登录成功",
|
||||||
|
color: "success",
|
||||||
|
});
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onCancel(): void {
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
</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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tog-bottom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tog-btn {
|
||||||
|
background: var(--tgc-btn-1);
|
||||||
|
color: var(--btn-text);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
90
src/plugins/Mys/types/GameLogin.d.ts
vendored
Normal file
90
src/plugins/Mys/types/GameLogin.d.ts
vendored
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* @file plugins Mys types GameLogin.d.ts
|
||||||
|
* @description Mys 插件 Game 登录类型定义文件
|
||||||
|
* @author BTMuli <bt-muli@outlook.com>
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Mys 插件 Game 登录类型
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @namespace GameLogin
|
||||||
|
* @return GameLogin
|
||||||
|
*/
|
||||||
|
declare namespace TGApp.Plugins.Mys.GameLogin {
|
||||||
|
/**
|
||||||
|
* @description 获取登录二维码返回数据
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @interface GetLoginQrResponse
|
||||||
|
* @extends TGApp.Plugins.Mys.Base.Response
|
||||||
|
* @property {GetLoginQrData} data 数据
|
||||||
|
* @return GetLoginQrResponse
|
||||||
|
*/
|
||||||
|
export interface GetLoginQrResponse extends TGApp.Plugins.Mys.Base.Response {
|
||||||
|
data: GetLoginQrData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取登录二维码返回数据
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @interface GetLoginQrData
|
||||||
|
* @property {string} url 二维码链接
|
||||||
|
* @return GetLoginQrData
|
||||||
|
*/
|
||||||
|
export interface GetLoginQrData {
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取登录状态返回数据
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @interface GetLoginStatusResponse
|
||||||
|
* @extends TGApp.Plugins.Mys.Base.Response
|
||||||
|
* @property {GetLoginStatusData} data 数据
|
||||||
|
* @return GetLoginStatusResponse
|
||||||
|
*/
|
||||||
|
export interface GetLoginStatusResponse extends TGApp.Plugins.Mys.Base.Response {
|
||||||
|
data: GetLoginStatusData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取登录状态返回数据
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @interface GetLoginStatusData
|
||||||
|
* @property {string} stat 状态 // Init: 未扫码,Scanned: 已扫码,Confirmed: 已确认
|
||||||
|
* @property {StatusPayload} payload 状态数据
|
||||||
|
* @return GetLoginStatusData
|
||||||
|
*/
|
||||||
|
export interface GetLoginStatusData {
|
||||||
|
stat: string;
|
||||||
|
payload: StatusPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取登录状态返回数据
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @interface StatusPayload
|
||||||
|
* @property {string} ext 未知
|
||||||
|
* @property {string} proto 未知
|
||||||
|
* @property {string} raw 序列化数据,反序列化后是 {uid: string, token: string}
|
||||||
|
* @return StatusPayload
|
||||||
|
*/
|
||||||
|
export interface StatusPayload {
|
||||||
|
ext: string;
|
||||||
|
proto: string;
|
||||||
|
raw: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 反序列化后的登录状态数据
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @interface StatusPayloadRaw
|
||||||
|
* @property {string} uid 用户 UID
|
||||||
|
* @property {string} token 用户 token
|
||||||
|
* @return StatusPayloadRaw
|
||||||
|
*/
|
||||||
|
export interface StatusPayloadRaw {
|
||||||
|
uid: string;
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/plugins/Mys/utils/doGameLogin.ts
Normal file
58
src/plugins/Mys/utils/doGameLogin.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/**
|
||||||
|
* @file plugins Mys utils doGameLogin
|
||||||
|
* @description 获取 gameToken,曲线获取 stoken
|
||||||
|
* @author BTMuli <bt-muli@outlook.com>
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// tauri
|
||||||
|
import { http } from "@tauri-apps/api";
|
||||||
|
|
||||||
|
const device = crypto.randomUUID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取登录二维码
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @returns {Promise<TGApp.Plugins.Mys.GameLogin.GetLoginQrData|TGApp.Plugins.Mys.Base.Response>}
|
||||||
|
*/
|
||||||
|
export async function getLoginQr(): Promise<
|
||||||
|
TGApp.Plugins.Mys.GameLogin.GetLoginQrData | TGApp.Plugins.Mys.Base.Response
|
||||||
|
> {
|
||||||
|
const url = "https://hk4e-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/fetch";
|
||||||
|
const data = {
|
||||||
|
app_id: "4",
|
||||||
|
device,
|
||||||
|
};
|
||||||
|
return await http
|
||||||
|
.fetch<TGApp.Plugins.Mys.GameLogin.GetLoginQrResponse>(url, {
|
||||||
|
method: "POST",
|
||||||
|
body: http.Body.json(data),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.retcode === 0) return res.data.data;
|
||||||
|
return res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取登录状态
|
||||||
|
* @since Beta v0.3.0
|
||||||
|
* @param {string} ticket 二维码 ticket
|
||||||
|
* @returns {Promise<TGApp.Plugins.Mys.GameLogin.GetLoginStatusData | TGApp.Plugins.Mys.Base.Response>}
|
||||||
|
*/
|
||||||
|
export async function getLoginStatus(
|
||||||
|
ticket: string,
|
||||||
|
): Promise<TGApp.Plugins.Mys.GameLogin.GetLoginStatusData | TGApp.Plugins.Mys.Base.Response> {
|
||||||
|
const url = "https://hk4e-sdk.mihoyo.com/hk4e_cn/combo/panda/qrcode/query";
|
||||||
|
const data = { app_id: "4", device, ticket };
|
||||||
|
console.log(data);
|
||||||
|
return await http
|
||||||
|
.fetch<TGApp.Plugins.Mys.GameLogin.GetLoginStatusResponse>(url, {
|
||||||
|
method: "POST",
|
||||||
|
body: http.Body.json(data),
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (res.data.retcode === 0) return res.data.data;
|
||||||
|
return res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
/**
|
/**
|
||||||
* @file store modules user.ts
|
* @file store modules user.ts
|
||||||
* @description User store module
|
* @description User store module
|
||||||
* @author BTMuli<bt-muli@outlook.com>
|
* @author BTMuli <bt-muli@outlook.com>
|
||||||
* @since Alpha v0.2.0
|
* @since Beta v0.3.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// vue
|
// vue
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
// pinia
|
// pinia
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
// sqlite
|
||||||
|
import TGSqlite from "../../plugins/Sqlite";
|
||||||
|
|
||||||
export const useUserStore = defineStore(
|
export const useUserStore = defineStore(
|
||||||
"user",
|
"user",
|
||||||
@@ -81,10 +83,9 @@ export const useUserStore = defineStore(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function initCookie(ck: Record<string, string>): void {
|
async function saveCookie(type: string, val: string): Promise<void> {
|
||||||
if (cookie.value !== ck) {
|
cookie.value[type] = val;
|
||||||
cookie.value = ck;
|
await TGSqlite.saveAppData("cookie", JSON.stringify(cookie.value));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -100,7 +101,7 @@ export const useUserStore = defineStore(
|
|||||||
getCookieGroup2,
|
getCookieGroup2,
|
||||||
getCookieGroup3,
|
getCookieGroup3,
|
||||||
getCookieGroup4,
|
getCookieGroup4,
|
||||||
initCookie,
|
saveCookie,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user