🌱 完成相关请求,待测试 #47

This commit is contained in:
BTMuli
2023-09-30 16:13:05 +08:00
parent 137180028e
commit bd67ee7a25
6 changed files with 306 additions and 91 deletions

View File

@@ -0,0 +1,136 @@
<template>
<TOverlay v-model="visible" hide blur-val="20px">
<div class="tog-box">
<div class="tog-top">
<div class="tog-title">请完成如下极验测试</div>
</div>
<div id="verify" class="tog-mid">
<div id="geetest"></div>
</div>
</div>
</TOverlay>
</template>
<script setup lang="ts">
// vue
import { computed, watch } from "vue";
import showSnackbar from "../func/snackbar";
import TOverlay from "../main/t-overlay.vue";
// store
import { useUserStore } from "../../store/modules/user";
// utils
import TGRequest from "../../web/request/TGRequest";
interface ToGeetestProps {
modelValue: boolean;
}
type ToGeetestEmits = (e: "update:modelValue", value: boolean) => void;
const props = withDefaults(defineProps<ToGeetestProps>(), {
modelValue: false,
});
const emits = defineEmits<ToGeetestEmits>();
const visible = computed({
get: () => props.modelValue,
set: (value) => {
emits("update:modelValue", value);
},
});
watch(visible, async (value) => {
if (value) {
await getChallenge();
}
});
const userStore = useUserStore();
// 获取极验验证码
async function getChallenge(): Promise<void> {
const cookie = userStore.getCookieGroup3();
const res = await TGRequest.User.verification.get(cookie.ltoken, cookie.ltuid);
if ("retcode" in res) {
showSnackbar({
text: res.message,
color: "error",
});
return;
}
// @ts-expect-error Cannot find name 'initGeetest'.ts(2304)
initGeetest(
{
gt: res.gt,
challenge: res.challenge,
offline: false,
new_captcha: true,
product: "custom", // 产品形式包括floatpopup, bind
area: "#verify", // 选择验证码展示的位置
width: "250px",
},
(captchaObj: TGApp.BBS.Geetest.GeetestCaptcha) => {
captchaObj.appendTo("#geetest");
captchaObj
.onReady(() => {
console.log("ready");
})
.onSuccess(() => {
const validate = captchaObj.getValidate();
(async () => {
await doVerify(validate);
})().catch(() => {}); // 防止报错
})
.onError(() => {
console.log("error");
})
.onClose(() => {
console.log("close");
});
},
);
}
async function doVerify(data: TGApp.BBS.Geetest.GeetestValidate): Promise<void> {
await TGRequest.User.verification.verify(userStore.cookie, data);
emits("update:modelValue", 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-mid {
display: flex;
width: 100%;
align-items: flex-start;
justify-content: center;
padding: 10px;
border-radius: 5px;
background: var(--box-bg-2);
}
#verify {
width: 256px;
height: 320px;
}
</style>

View File

@@ -13,9 +13,27 @@
</div> </div>
</div> </div>
</div> </div>
<h1>极验测试</h1>
<div class="btn-list">
<v-btn class="test-btn" @click="getGC">获取极验</v-btn>
</div>
<to-geetest v-model="visible"></to-geetest>
</div> </div>
</template> </template>
<script lang="ts" setup></script> <script lang="ts" setup>
import { onMounted, ref } from "vue";
import ToGeetest from "../../components/overlay/to-geetest.vue";
const visible = ref<boolean>(false);
onMounted(async () => {
visible.value = false;
});
function getGC(): void {
visible.value = true;
}
</script>
<style lang="css" scoped> <style lang="css" scoped>
.btn-list { .btn-list {
display: flex; display: flex;

View File

@@ -47,4 +47,65 @@ declare namespace TGApp.BBS.Geetest {
challenge: string; challenge: string;
validate: string; validate: string;
} }
/**
* @description 极验验证的请求方法-请求参数
* @since Beta v0.3.3
* @interface InitGeetestParams
* @property {string} gt - 极验验证 gt
* @property {string} challenge - 极验验证 challenge
* @property {boolean} offline - 极验验证 offline
* @property {boolean} new_captcha - 极验验证 new_captcha
* @property {string} product - 极验验证 product
* @property {string} width - 极验验证 width
* @property {boolean} https - 极验验证 https
* @return InitGeetestParams
*/
export interface InitGeetestParams {
gt: string;
challenge: string;
offline: boolean;
new_captcha: boolean;
product: string;
width: string;
https: boolean;
}
/**
* @description Geetest 插件 captchaObj
* @since Beta v0.3.3
* @todo 完善
* @interface GeetestCaptcha
* @property {string} getValidate
* @property {Function} onReady
* @property {Function} onRefresh
* @property {Function} onSuccess
* @property {Function} onError
* @property {Function} onClose
* @return GeetestCaptcha
*/
export interface GeetestCaptcha {
appendTo: (selector: string) => void;
getValidate: () => GeetestValidate;
onReady: (callback: () => void) => GeetestCaptcha;
onRefresh: (callback: () => void) => GeetestCaptcha;
onSuccess: (callback: () => void) => GeetestCaptcha;
onError: (callback: () => void) => GeetestCaptcha;
onClose: (callback: () => void) => GeetestCaptcha;
}
/**
* @description Geetest 插件 validate
* @since Beta v0.3.3
* @interface GeetestValidate
* @property {string} geetest_challenge
* @property {string} geetest_validate
* @property {string} geetest_seccode
* @return GeetestValidate
*/
export interface GeetestValidate {
geetest_challenge: string;
geetest_validate: string;
geetest_seccode: string;
}
} }

View File

@@ -1,89 +0,0 @@
/**
* @file src types Plugins Geetest.d.ts
* @description Geetest 插件类型声明文件
* @author BTMuli <bt-muli@outlook.com>
* @since 3.0.0
*/
/**
* @description 因为引入 gt.js其 initGeetest 挂载到 window 上,所以需要声明 window
* @since 3.0.0
* @interface window
* @return window
*/
type window = Window & typeof globalThis;
globalThis.window = globalThis.window || globalThis;
declare global {
interface Window {
initGeetest: InitGeetest;
}
}
/**
* @description Geetest 插件初始化函数
* @since 3.0.0
* @interface InitGeetest
* @return InitGeetest
*/
export type InitGeetest = (
initGeetestOptions: InitGeetestOptions,
initGeetestCallback: InitGeetestCallback,
) => void;
/**
* @description Geetest 插件初始化函数参数
* @since 3.0.0
* @todo 完善
* @interface InitGeetestOptions
* @property {string} gt Geetest ID
* @property {string} challenge Geetest challenge
* @property {boolean} offline Geetest offline
* @property {boolean} new_captcha Geetest new_captcha
* @property {string} product Geetest product
* @property {string} width Geetest width
* @property {boolean} https Geetest https
* @return InitGeetestOptions
*/
export interface InitGeetestOptions {
gt: string;
challenge: string;
offline: boolean;
new_captcha: boolean;
product: string;
width: string;
https: boolean;
}
/**
* @description Geetest 插件初始化函数回调
* @since 3.0.0
* @todo 完善
* @interface InitGeetestCallback
* @return InitGeetestCallback
*/
export type InitGeetestCallback = (captchaObj: GeetestCaptcha) => void;
/**
* @description Geetest 插件 captchaObj
* @since 3.0.0
* @todo 完善
* @interface GeetestCaptcha
* @property {string} getValidate
* @property {Function} onReady
* @property {Function} onRefresh
* @property {Function} onSuccess
* @property {Function} onError
* @property {Function} onClose
* @return GeetestCaptcha
*/
export interface GeetestCaptcha {
appendTo: (selector: string) => void;
getValidate: () => string;
onReady: (callback: () => void) => void;
onRefresh: (callback: () => void) => void;
onSuccess: (callback: () => void) => void;
onError: (callback: () => void) => void;
onClose: (callback: () => void) => void;
}

View File

@@ -15,12 +15,13 @@ import { getGameAccountsByCookie, getGameAccountsBySToken } from "./getGameAccou
import { getGameRecord } from "./getGameRecord"; import { getGameRecord } from "./getGameRecord";
import { getLTokenBySToken } from "./getLToken"; import { getLTokenBySToken } from "./getLToken";
import { getGameRoleListByLToken } from "./getRoleList"; import { getGameRoleListByLToken } from "./getRoleList";
import { getStokenByGameToken } from "./getStoken";
import getSyncAvatarDetail from "./getSyncAvatarDetail"; import getSyncAvatarDetail from "./getSyncAvatarDetail";
import getSyncAvatarListAll from "./getSyncAvatarListAll"; import getSyncAvatarListAll from "./getSyncAvatarListAll";
import { getTokensByLoginTicket } from "./getTokens"; import { getTokensByLoginTicket } from "./getTokens";
import { getUserInfoByCookie } from "./getUserInfo"; import { getUserInfoByCookie } from "./getUserInfo";
import { getVerification, submitVerification } from "./operVerification";
import { verifyLToken } from "./verifyLToken"; import { verifyLToken } from "./verifyLToken";
import { getStokenByGameToken } from "./getStoken";
const TGRequest = { const TGRequest = {
Anno: { Anno: {
@@ -56,6 +57,10 @@ const TGRequest = {
getSyncAvatarListAll, getSyncAvatarListAll,
getSyncAvatarDetail, getSyncAvatarDetail,
}, },
verification: {
get: getVerification,
verify: submitVerification,
},
}, },
}; };

View File

@@ -0,0 +1,84 @@
/**
* @file src web request operVerification.ts
* @description 验证码操作请求函数
* @since Beta v0.3.3
*/
import TGUtils from "../utils/TGUtils";
import { http } from "@tauri-apps/api";
import showSnackbar from "../../components/func/snackbar";
/**
* @description 发起验证请求
* @param {string} Ltoken ltoken
* @param {string} Ltuid ltuid
* @return {Promise<TGApp.Plugins.Geetest.getData|TGApp.BBS.Response.Base>} 验证码参数
*/
export async function getVerification(
Ltoken: string,
Ltuid: string,
): Promise<TGApp.BBS.Geetest.getData | TGApp.BBS.Response.Base> {
const url = "https://api-takumi-record.mihoyo.com/game_record/app/card/wapi/createVerification";
const cookie = {
ltoken: Ltoken,
ltuid: Ltuid,
};
const params = { is_high: "true" };
const header = TGUtils.User.getHeader(cookie, "GET", params, "common");
return await http
.fetch<TGApp.BBS.Geetest.getResponse>(url, {
method: "GET",
headers: header,
query: params,
})
.then((res) => {
if (res.data.retcode !== 0) return res.data;
return res.data.data;
});
}
/**
* @description 将验证完的参数提交给米游社
* @since Beta v0.3.3
* @todo 待测试
* @param {Record<string, string>} cookie cookie
* @param {TGApp.BBS.Geetest.GeetestValidate} validate 验证码参数
* @return {Promise<TGApp.BBS.Response.Base|unknown>} 提交结果
*/
export async function submitVerification(
cookie: Record<string, string>,
validate: TGApp.BBS.Geetest.GeetestValidate,
): Promise<TGApp.BBS.Response.Base | unknown> {
const url = "https://api-takumi-record.mihoyo.com/game_record/app/card/wapi/verifyVerification";
const data = {
geetest_challenge: validate.geetest_challenge,
geetest_validate: validate.geetest_validate,
geetest_seccode: validate.geetest_seccode,
};
console.log(data);
const header = TGUtils.User.getHeader(cookie, "POST", data, "lk2", true);
const reqHeader = {
...header,
"x-rpc-challenge_game": "2",
"x-rpc-challenge_trace": validate.geetest_challenge,
"x-rpc-validate": validate.geetest_validate,
"x-rpc-seccode": validate.geetest_seccode,
};
console.log(reqHeader);
return await http
.fetch<TGApp.BBS.Response.Base>(url, {
method: "POST",
headers: reqHeader,
body: http.Body.json(data),
})
.then((res) => {
if (res.data.retcode !== 0) {
showSnackbar({
text: `[${res.data.retcode}] ${res.data.message}`,
color: "error",
});
console.error(res.data);
}
return res.data;
});
}