♻️ 请求重构

This commit is contained in:
目棃
2025-03-07 17:53:35 +08:00
parent fee1872b46
commit ce5a88954a
22 changed files with 582 additions and 876 deletions

View File

@@ -122,7 +122,6 @@ import showGeetest from "@comp/func/geetest.js";
import showLoading from "@comp/func/loading.js";
import showSnackbar from "@comp/func/snackbar.js";
import ToGameLogin from "@comp/pageConfig/tco-gameLogin.vue";
import Mys from "@Mys/index.js";
import TSUserAccount from "@Sqlite/modules/userAccount.js";
import { storeToRefs } from "pinia";
import { computed, ref, shallowRef } from "vue";
@@ -132,6 +131,7 @@ import { useUserStore } from "@/store/modules/user.js";
import TGLogger from "@/utils/TGLogger.js";
import BBSApi from "@/web/request/bbsReq.js";
import PassportApi from "@/web/request/passportReq.js";
import passportReq from "@/web/request/passportReq.js";
import TakumiApi from "@/web/request/takumiReq.js";
const { isLogin } = storeToRefs(useAppStore());
@@ -398,13 +398,13 @@ async function confirmCopyCookie(): Promise<void> {
}
async function tryGetCaptcha(phone: string, aigis?: string): Promise<string | false> {
const captchaResp = await Mys.User.getCaptcha(phone, aigis);
const captchaResp = await passportReq.captcha.create(phone, aigis);
if ("retcode" in captchaResp) {
if (!captchaResp.data || captchaResp.data === "") {
showSnackbar.error(`[${captchaResp.retcode}] ${captchaResp.message}`);
return false;
}
const aigisResp: TGApp.Plugins.Mys.CaptchaLogin.CaptchaAigis = JSON.parse(captchaResp.data);
const aigisResp: TGApp.BBS.CaptchaLogin.CaptchaAigis = JSON.parse(captchaResp.data);
const resp = await showGeetest(JSON.parse(aigisResp.data));
const aigisStr = `${aigisResp.session_id};${btoa(JSON.stringify(resp))}`;
return await tryGetCaptcha(phone, aigisStr);
@@ -417,14 +417,14 @@ async function tryLoginByCaptcha(
captcha: string,
actionType: string,
aigis?: string,
): Promise<TGApp.Plugins.Mys.CaptchaLogin.LoginData | false> {
const loginResp = await Mys.User.login(phone, captcha, actionType, aigis);
): Promise<TGApp.BBS.CaptchaLogin.LoginRes | false> {
const loginResp = await passportReq.captcha.login(phone, captcha, actionType, aigis);
if ("retcode" in loginResp) {
if (!loginResp.data || loginResp.data === "") {
showSnackbar.error(`[${loginResp.retcode}] ${loginResp.message}`);
return false;
}
const aigisResp: TGApp.Plugins.Mys.CaptchaLogin.CaptchaAigis = JSON.parse(loginResp.data);
const aigisResp: TGApp.BBS.CaptchaLogin.CaptchaAigis = JSON.parse(loginResp.data);
const resp = await showGeetest(JSON.parse(aigisResp.data));
const aigisStr = `${aigisResp.session_id};${btoa(JSON.stringify(resp))}`;
return await tryLoginByCaptcha(phone, captcha, actionType, aigisStr);

View File

@@ -6,6 +6,7 @@
<span>{{ showNew ? "查看当前祈愿" : "查看后续祈愿" }}</span>
</template>
<template #default>
<!-- todo 组件化 -->
<div class="pool-grid">
<div v-for="pool in poolSelect" :key="pool.postId" class="pool-card">
<div class="pool-cover" @click="createPost(pool.postId, pool.title)">
@@ -58,20 +59,41 @@
import TItembox, { type TItemBoxData } from "@comp/app/t-itemBox.vue";
import TMiImg from "@comp/app/t-mi-img.vue";
import showSnackbar from "@comp/func/snackbar.js";
import Mys from "@Mys/index.js";
import { storeToRefs } from "pinia";
import { computed, onMounted, onUnmounted, ref } from "vue";
import { useRouter } from "vue-router";
import THomeCard from "./ph-comp-card.vue";
import { AppCharacterData } from "@/data/index.js";
import { useHomeStore } from "@/store/modules/home.js";
import { createPost, createTGWindow } from "@/utils/TGWindow.js";
import { stamp2LastTime } from "@/utils/toolFunc.js";
import postReq from "@/web/request/postReq.js";
import takumiReq from "@/web/request/takumiReq.js";
type TPoolEmits = (e: "success") => void;
type PoolStat = "future" | "now" | "past"; // 未开始 | 进行中 | 已结束
type PoolItem = TGApp.Plugins.Mys.Gacha.RenderCard & { timeRest: number; stat: PoolStat };
type AvatarRender = {
icon: string;
url: string;
info?: TGApp.App.Character.WikiBriefInfo;
};
type PoolCard = {
id: number;
title: string;
cover: string;
postId: number;
characters: Array<AvatarRender>;
time: {
str: string;
startStamp: number;
endStamp: number;
totalStamp: number;
};
timeRest: number;
stat: PoolStat;
};
const emits = defineEmits<TPoolEmits>();
const { poolCover } = storeToRefs(useHomeStore());
@@ -80,43 +102,91 @@ const router = useRouter();
let timer: NodeJS.Timeout | null = null;
const showNew = ref<boolean>(false);
const poolCards = ref<Array<PoolItem>>([]);
const poolCards = ref<Array<PoolCard>>([]);
const hasNew = computed<boolean>(
() => poolCards.value.find((pool) => pool.stat === "future") !== undefined,
);
const poolSelect = computed<Array<PoolItem>>(() => {
const poolSelect = computed<Array<PoolCard>>(() => {
if (!hasNew.value) return poolCards.value;
if (showNew.value) return poolCards.value.filter((pool) => pool.stat === "future");
return poolCards.value.filter((pool) => pool.stat !== "future");
});
onMounted(async () => {
const gachaData = await Mys.Gacha.get();
let cards: Array<TGApp.Plugins.Mys.Gacha.RenderCard>;
if (!checkCover(gachaData)) {
cards = await Mys.Gacha.card(gachaData);
const coverData: Record<string, string> = {};
poolCards.value.map((pool) => {
coverData[pool.id] = pool.cover;
return pool;
});
poolCover.value = coverData;
const gachaData = await takumiReq.obc.gacha();
if (checkCover(gachaData)) {
poolCards.value = await getGachaCard(gachaData, poolCover.value);
} else {
cards = await Mys.Gacha.card(gachaData, poolCover.value);
}
for (const pool of cards) {
const timeRest = pool.time.endStamp - Date.now();
poolCards.value.push({
...pool,
stat: timeRest > pool.time.totalStamp ? "future" : timeRest > 0 ? "now" : "past",
timeRest: timeRest,
});
poolCards.value = await getGachaCard(gachaData);
const coverData: Record<string, string> = {};
for (const pool of poolCards.value) coverData[pool.id] = pool.cover;
poolCover.value = coverData;
}
if (timer !== null) clearInterval(timer);
timer = setInterval(poolTimeout, 1000);
emits("success");
});
async function getGachaItemCard(
data: TGApp.BBS.Obc.GachaItem,
poolCover?: string,
): Promise<PoolCard | null> {
let cover = "/source/UI/empty.webp";
const postId: number | undefined = Number(data.activity_url.split("/").pop()) || undefined;
if (postId === undefined || isNaN(postId)) return null;
if (poolCover !== undefined) {
cover = poolCover;
} else {
const postResp = await postReq.post(postId);
if ("retcode" in postResp) {
showSnackbar.error(`[${postResp.retcode}] ${postResp.message}`);
return null;
}
cover = postResp.cover?.url ?? postResp.post.images[0];
}
const timeStr = `${data.start_time} ~ ${data.end_time}`;
const characters: Array<AvatarRender> = [];
for (const character of data.pool) {
const item: AvatarRender = { icon: character.icon, url: character.url };
const contentId = character.url.match(/(?<=content\/)\d+/)?.[0];
if (contentId) {
const itemF = AppCharacterData.find((item) => item.contentId.toString() === contentId);
if (itemF) item.info = itemF;
}
characters.push(item);
}
const endTs = new Date(data.end_time).getTime();
const totalTs = endTs - new Date(data.start_time).getTime();
const restTs = endTs - Date.now();
return {
id: data.id,
title: data.title,
cover,
postId,
characters,
time: {
str: timeStr,
startStamp: new Date(data.start_time).getTime(),
endStamp: endTs,
totalStamp: totalTs,
},
timeRest: restTs,
stat: restTs > totalTs ? "future" : restTs > 0 ? "now" : "past",
};
}
async function getGachaCard(
gachaData: Array<TGApp.BBS.Obc.GachaItem>,
poolCover?: Record<number, string>,
): Promise<Array<PoolCard>> {
const gachaCard: Array<PoolCard> = [];
for (const data of gachaData) {
const item = await getGachaItemCard(data, poolCover?.[Number(data.id)]);
if (item !== null) gachaCard.push(item);
}
return gachaCard;
}
function poolTimeout(): void {
for (const pool of poolCards.value) {
if (pool.stat === "past") {
@@ -139,7 +209,7 @@ function poolTimeout(): void {
}
}
function checkCover(data: Array<TGApp.Plugins.Mys.Gacha.Data>): boolean {
function checkCover(data: Array<TGApp.BBS.Obc.GachaItem>): boolean {
if (poolCover.value === undefined || Object.keys(poolCover.value).length === 0) return false;
let checkList = data.length;
Object.entries(poolCover.value).forEach(([key, value]: [string, unknown]) => {
@@ -149,10 +219,7 @@ function checkCover(data: Array<TGApp.Plugins.Mys.Gacha.Data>): boolean {
return checkList === 0;
}
async function toOuter(
character: TGApp.Plugins.Mys.Gacha.RenderItem,
title: string,
): Promise<void> {
async function toOuter(character: AvatarRender, title: string): Promise<void> {
if (character.info !== undefined) {
await router.push({ name: "角色图鉴", params: { id: character.info.id } });
return;

View File

@@ -10,47 +10,64 @@
</template>
<script lang="ts" setup>
import PhPositionCard from "@comp/pageHome/ph-position-card.vue";
import Mys from "@Mys/index.js";
import { onMounted, onUnmounted, ref } from "vue";
import THomeCard from "./ph-comp-card.vue";
import takumiReq from "@/web/request/takumiReq.js";
type TPositionEmits = (e: "success") => void;
type PositionStat = "past" | "now" | "future" | "unknown"; // 已结束 | 进行中 | 未开始 | 未知
export type PositionItem = TGApp.Plugins.Mys.Position.RenderCard & {
export type PositionCard = {
title: string;
postId: number;
link: string;
icon: string;
abstract: string;
time: { startStamp: number; endStamp: number; totalStamp: number };
timeRest: number;
stat: PositionStat;
};
const emits = defineEmits<TPositionEmits>();
// eslint-disable-next-line no-undef
let timer: NodeJS.Timeout | null = null;
const positionCards = ref<Array<PositionItem>>([]);
const positionCards = ref<Array<PositionCard>>([]);
onMounted(async () => {
const positionData = await Mys.Position.get();
console.log(positionData);
const cards = Mys.Position.card(positionData);
for (const position of cards) {
if (position.time.endStamp === 0 || position.time.totalStamp < 0) {
positionCards.value.push({
...position,
timeRest: 0,
stat: "unknown",
});
continue;
}
const timeRest = position.time.endStamp - Date.now();
positionCards.value.push({
...position,
timeRest,
stat: timeRest > position.time.totalStamp ? "future" : timeRest > 0 ? "now" : "past",
});
}
const resp = await takumiReq.obc.position();
console.log("positionCards", resp);
positionCards.value = getPositionCard(resp);
if (timer !== null) clearInterval(timer);
timer = setInterval(getPositionTimer, 1000);
emits("success");
});
function getPositionCard(list: Array<TGApp.BBS.Obc.PositionItem>): Array<PositionCard> {
const res: Array<PositionCard> = [];
for (const position of list) {
let link = position.url;
if (position.url === "" && position.content_id !== 0) {
link = `https://bbs.mihoyo.com/ys/obc/content/${position.content_id}/detail?bbs_presentation_style=no_header`;
}
const startTs = new Date(position.create_time).getTime();
const endTs = Number(position.end_time);
const totalTs = endTs - startTs;
const restTs = endTs === 0 || totalTs < 0 ? 0 : endTs - Date.now();
const card: PositionCard = {
title: position.title,
postId: position.url !== "" ? Number(position.url.split("/").pop()) : position.content_id,
link: link,
icon: position.icon,
abstract: position.abstract,
time: { startStamp: startTs, endStamp: endTs, totalStamp: totalTs },
timeRest: restTs,
stat: restTs === 0 ? "unknown" : restTs > totalTs ? "future" : restTs > 0 ? "now" : "past",
};
res.push(card);
}
return res;
}
function getPositionTimer(): void {
for (const position of positionCards.value) {
if (position.stat === "unknown") continue;

View File

@@ -40,16 +40,16 @@
<script lang="ts" setup>
import TMiImg from "@comp/app/t-mi-img.vue";
import showSnackbar from "@comp/func/snackbar.js";
import type { PositionItem } from "@comp/pageHome/ph-comp-position.vue";
import type { PositionCard } from "@comp/pageHome/ph-comp-position.vue";
import { parseLink } from "@/utils/linkParser.js";
import { createPost } from "@/utils/TGWindow.js";
import { stamp2LastTime, timestampToDate } from "@/utils/toolFunc.js";
type PhPositionCardProps = { position: PositionItem };
type PhPositionCardProps = { position: PositionCard };
const props = defineProps<PhPositionCardProps>();
async function openPosition(card: TGApp.Plugins.Mys.Position.RenderCard): Promise<void> {
async function openPosition(card: PositionCard): Promise<void> {
const res = await parseLink(card.link);
if (res === "post") {
await createPost(card.postId, card.title);

View File

@@ -21,11 +21,11 @@
</template>
<script lang="ts" setup>
import showSnackbar from "@comp/func/snackbar.js";
import { getEmojis } from "@Mys/request/getEmojis.js";
import { onMounted, ref, shallowRef, StyleValue, toRaw } from "vue";
import { parseLink, parsePost } from "@/utils/linkParser.js";
import { isColorSimilar, decodeRegExp } from "@/utils/toolFunc.js";
import bbsReq from "@/web/request/bbsReq.js";
export type TpText = {
insert: string;
@@ -114,7 +114,7 @@ async function toLink(): Promise<void> {
function getEmojiUrl(): string {
if (localEmojis.value === null || !JSON.parse(localEmojis.value)[getEmojiName()]) {
console.warn("tpEmoji unknown", getEmojiName());
getEmojis().then((res) => {
bbsReq.emojis().then((res) => {
if ("retcode" in res) {
console.error(res);
showSnackbar.error("获取表情包失败!");