♻️ 重构祈愿页面数据刷新逻辑

This commit is contained in:
BTMuli
2026-02-17 12:34:43 +08:00
parent c071538ecc
commit be48c32d0d
7 changed files with 1064 additions and 757 deletions

View File

@@ -3,7 +3,7 @@
"version": "0.9.5",
"description": "Game Tool for GenshinImpact player",
"private": true,
"packageManager": "pnpm@10.28.2",
"packageManager": "pnpm@10.29.3",
"type": "module",
"scripts": {
"build": "tsx scripts/auto-build.ts",
@@ -72,9 +72,9 @@
"dependencies": {
"@date-fns/tz": "^1.4.1",
"@mdi/font": "7.4.47",
"@sentry/vite-plugin": "^4.9.0",
"@sentry/vue": "^10.38.0",
"@sentry/core": "^10.38.0",
"@sentry/vite-plugin": "^4.9.1",
"@sentry/vue": "^10.39.0",
"@sentry/core": "^10.39.0",
"@skipperndt/plugin-machine-uid": "^0.1.3",
"@tauri-apps/api": "^2.10.1",
"@tauri-apps/plugin-cli": "^2.4.1",
@@ -88,7 +88,7 @@
"@tauri-apps/plugin-os": "^2.3.2",
"@tauri-apps/plugin-process": "^2.3.1",
"@tauri-apps/plugin-sql": "^2.3.2",
"ajv": "^8.17.1",
"ajv": "^8.18.0",
"artplayer": "^5.3.0",
"colord": "^2.9.3",
"date-fns": "^4.1.0",
@@ -102,9 +102,9 @@
"qrcode.vue": "^3.8.0",
"rsa-oaep-encryption": "^1.1.0",
"sass-embedded": "^1.97.3",
"swiper": "^12.1.0",
"swiper": "^12.1.1",
"uuid": "^13.0.0",
"vue": "^3.5.27",
"vue": "^3.5.28",
"vue-echarts": "^8.0.1",
"vue-json-pretty": "^2.6.0",
"vue-router": "^5.0.2",
@@ -120,29 +120,29 @@
"@types/fs-extra": "^11.0.4",
"@types/js-md5": "^0.8.0",
"@types/json-bigint": "^1.0.4",
"@types/node": "^25.2.1",
"@typescript-eslint/parser": "^8.54.0",
"@typescript/native-preview": "7.0.0-dev.20260207.1",
"@types/node": "^25.2.3",
"@typescript-eslint/parser": "^8.56.0",
"@typescript/native-preview": "7.0.0-dev.20260216.1",
"@vitejs/plugin-vue": "^6.0.4",
"app-root-path": "^3.1.0",
"concurrently": "^9.2.1",
"envfile": "^7.1.0",
"eslint": "^9.39.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsonc": "^2.21.0",
"eslint-plugin-jsonc": "^2.21.1",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-tsdoc": "^0.5.0",
"eslint-plugin-vue": "^10.7.0",
"eslint-plugin-yml": "^3.1.0",
"eslint-plugin-vue": "^10.8.0",
"eslint-plugin-yml": "^3.1.2",
"fs-extra": "^11.3.3",
"globals": "^17.3.0",
"husky": "^9.1.7",
"jsonc-eslint-parser": "^2.4.2",
"lint-staged": "^16.2.7",
"oxlint": "^1.43.0",
"oxlint": "^1.48.0",
"postcss-preset-env": "^11.1.3",
"prettier": "3.8.1",
"stylelint": "^17.1.1",
"stylelint": "^17.3.0",
"stylelint-config-idiomatic-order": "^10.0.0",
"stylelint-config-standard-scss": "^17.0.0",
"stylelint-config-standard-vue": "^1.0.0",
@@ -153,11 +153,11 @@
"stylelint-scss": "^7.0.0",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.54.0",
"typescript-eslint": "^8.56.0",
"vite": "npm:rolldown-vite@^7.3.1",
"vite-plugin-vue-devtools": "^8.0.6",
"vite-plugin-vuetify": "^2.1.3",
"vue-eslint-parser": "^10.2.0",
"vue-eslint-parser": "^10.4.0",
"vue-tsc": "^3.2.4",
"yaml-eslint-parser": "^2.0.0"
}

1083
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

531
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@ image = "0.25.9"
log = "0.4.29"
prost = "=0.14.1"
prost-types = "=0.14.1"
sentry = { version = "0.46.1", features = ["backtrace", "panic"] }
sentry = { version = "0.46.2", features = ["backtrace", "panic"] }
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
tauri = { version = "2.10.2", features = ["tray-icon"] }

View File

@@ -1,6 +1,6 @@
//! @file src/client/mod.rs
//! @desc 客户端模块,负责操作米游社客户端
//! @since Beta v0.9.1
//! @since Beta v0.9.6
mod menu;
mod utils;
@@ -8,7 +8,7 @@ mod utils;
use tauri::{AppHandle, Manager, WebviewWindowBuilder};
use tauri_utils::config::WebviewUrl;
static BBS_VERSION: &'static str = "2.100.0";
static BBS_VERSION: &'static str = "2.102.1";
#[tauri::command]
pub async fn create_mhy_client(handle: AppHandle, func: String, url: String) {

View File

@@ -8,7 +8,7 @@
<v-select
v-model="uidCur"
:hide-details="true"
:items="selectItem"
:items="uidList"
density="compact"
label="游戏UID"
variant="outlined"
@@ -156,8 +156,8 @@ import UgoUid from "@comp/userGacha/ugo-uid.vue";
import hutao from "@Hutao/index.js";
import hk4eReq from "@req/hk4eReq.js";
import takumiReq from "@req/takumiReq.js";
import TSUserAccount from "@Sqlm/userAccount.js";
import TSUserGacha from "@Sqlm/userGacha.js";
import useAppStore from "@store/app.js";
import useHutaoStore from "@store/hutao.js";
import useUserStore from "@store/user.js";
import { path } from "@tauri-apps/api";
@@ -175,7 +175,6 @@ import { AppCalendarData } from "@/data/index.js";
const router = useRouter();
const hutaoStore = useHutaoStore();
const { isLogin } = storeToRefs(useAppStore());
const { account, cookie } = storeToRefs(useUserStore());
const { isLogin: isLoginHutao, accessToken, userName, userInfo } = storeToRefs(hutaoStore);
@@ -188,7 +187,7 @@ const uidCur = ref<string>();
const tab = ref<string>("overview");
const hutaoShow = ref<boolean>(false);
const htMode = ref<UgoHutaoMode>("download");
const selectItem = shallowRef<Array<string>>([]);
const uidList = shallowRef<Array<string>>([]);
const gachaListCur = shallowRef<Array<TGApp.Sqlite.Gacha.Gacha>>([]);
const yattaData = shallowRef<Array<TGApp.Plugins.Yatta.ConvertData>>([]);
@@ -196,28 +195,16 @@ onMounted(async () => {
await showLoading.start("正在加载祈愿数据", "正在获取祈愿 UID 列表");
await TGLogger.Info("[UserGacha][onMounted] 进入角色祈愿页面");
await reloadUid();
if (uidCur.value) {
await showLoading.update(`UID${uidCur.value}`);
gachaListCur.value = await TSUserGacha.record.all(uidCur.value);
await TGLogger.Info(
`[UserGacha][onMounted] 获取到 ${uidCur.value}${gachaListCur.value.length} 条祈愿数据`,
);
}
await showLoading.end();
showSnackbar.success(`成功获取 ${gachaListCur.value.length} 条祈愿数据`);
});
// 监听 UID 变化
watch(
() => uidCur.value,
async (newUid) => {
if (!newUid) return;
gachaListCur.value = await TSUserGacha.record.all(newUid);
showSnackbar.success(`成功获取 ${gachaListCur.value.length} 条祈愿数据`);
await TGLogger.Info(
`[UserGacha][${newUid}][watch] 成功获取 ${gachaListCur.value.length} 条祈愿数据`,
);
},
async () => await loadGachaList(),
);
watch(
() => account.value,
async () => await reloadUid(),
);
async function toBeyond(): Promise<void> {
@@ -444,72 +431,89 @@ async function handleHutaoDelete(uids: Array<string>): Promise<void> {
await showLoading.end();
}
async function reloadUid(): Promise<void> {
selectItem.value = await TSUserGacha.getUidList();
if (selectItem.value.includes(account.value.gameUid)) uidCur.value = account.value.gameUid;
if (selectItem.value.length > 0) uidCur.value = selectItem.value[0];
else if (isLogin.value) {
selectItem.value = [account.value.gameUid];
uidCur.value = account.value.gameUid;
} else uidCur.value = undefined;
async function loadGachaList(): Promise<void> {
if (uidCur.value === undefined || uidCur.value === "") return;
gachaListCur.value = await TSUserGacha.record.all(uidCur.value);
showSnackbar.success(`成功获取 ${uidCur.value}${gachaListCur.value.length} 条祈愿数据`);
await TGLogger.Info(
`[UserGacha][loadGachaList] 成功获取 ${gachaListCur.value.length} 条祈愿数据`,
);
}
async function reloadUid(uid?: string): Promise<void> {
uidList.value = await TSUserGacha.getUidList();
if (uidList.value.length === 0) uidList.value = [account.value.gameUid];
if (uidList.value.includes(account.value.gameUid)) {
if (uid === undefined) uidCur.value = account.value.gameUid;
} else {
uidList.value = [account.value.gameUid, ...uidList.value];
if (uid === undefined) uidCur.value = uidList.value[0];
}
}
// 刷新按钮点击事件
async function confirmRefresh(force: boolean): Promise<void> {
await TGLogger.Info(`[UserGacha][${account.value.gameUid}][confirmRefresh] 刷新祈愿数据`);
if (!cookie.value) {
showSnackbar.error("请先登录");
await TGLogger.Warn("[UserGacha][${account.gameUid}][confirmRefresh] 未检测到 cookie");
return;
}
if (uidCur.value && uidCur.value !== account.value.gameUid) {
const switchCheck = await showDialog.check(
"是否切换游戏账户",
`确认则尝试切换至 ${uidCur.value}`,
);
if (switchCheck) {
await useUserStore().switchGameAccount(uidCur.value);
await confirmRefresh(force);
let rfAccount = account.value;
let rfCk = cookie.value;
if (!uidCur.value) {
if (!rfCk) {
showSnackbar.warn("请先登录");
await TGLogger.Warn(`[Gacha][confirmRefresh][${rfAccount.gameUid}] 未登录`);
return;
}
const freshCheck = await showDialog.check(
"确定刷新?",
`用户${account.value.gameUid}与当前UID${uidCur.value}不一致`,
);
if (!freshCheck) {
showSnackbar.cancel("已取消祈愿数据刷新");
return;
} else {
const gcFind = await TSUserAccount.game.getAccountByGid(uidCur.value.toString());
console.log(uidCur.value, gcFind);
if (!gcFind) {
const check = await showDialog.check(
`确定刷新?`,
`未找到 ${uidCur.value} 对应 UID将刷新 ${rfAccount.gameUid} 数据`,
);
if (!check) return;
} else {
const acFind = await TSUserAccount.account.getAccount(gcFind.uid);
if (!acFind) {
const check = await showDialog.check(
`确定刷新?`,
`未找到 ${uidCur.value} 对应 CK将刷新 ${rfAccount.gameUid} 数据`,
);
if (!check) return;
} else {
rfAccount = gcFind;
rfCk = acFind.cookie;
}
}
}
await showLoading.start(`正在刷新祈愿数据`, `UID:${account.value.gameUid},正在获取 authkey`);
const authkeyRes = await takumiReq.bind.authKey(cookie.value, account.value);
await TGLogger.Info(`[Gacha][${rfAccount.gameUid}][confirmRefresh] 刷新祈愿数据`);
await showLoading.start(`正在刷新祈愿数据`, `UID:${rfAccount.gameUid},正在获取 authkey`);
const authkeyRes = await takumiReq.bind.authKey(rfCk!, rfAccount);
if (typeof authkeyRes === "string") {
authkey.value = authkeyRes;
await TGLogger.Info(`[UserGacha][${account.value.gameUid}][confirmRefresh] 成功获取 authkey`);
await TGLogger.Info(`[Gacha][${rfAccount.gameUid}][confirmRefresh] 成功获取 authkey`);
} else {
showSnackbar.error("获取 authkey 失败");
await TGLogger.Error(`[UserGacha][${account.value.gameUid}][confirmRefresh] 获取 authkey 失败`);
await TGLogger.Error(`[Gacha][${rfAccount.gameUid}][confirmRefresh] 获取 authkey 失败`);
await TGLogger.Error(
`[UserGacha][${account.value.gameUid}][confirmRefresh] ${authkeyRes.retcode} ${authkeyRes.message}`,
`[Gacha][${rfAccount.gameUid}][confirmRefresh] ${authkeyRes.retcode} ${authkeyRes.message}`,
);
await showLoading.end();
return;
}
await refreshGachaPool("100", "新手祈愿", force);
await refreshGachaPool("200", "常驻祈愿", force);
await refreshGachaPool("301", "角色祈愿", force);
await refreshGachaPool("400", "角色祈愿2", force);
await refreshGachaPool("302", "武器祈愿", force);
await refreshGachaPool("500", "集录祈愿", force);
await refreshGachaPool(rfAccount, "100", "新手祈愿", force);
await refreshGachaPool(rfAccount, "200", "常驻祈愿", force);
await refreshGachaPool(rfAccount, "301", "角色祈愿", force);
await refreshGachaPool(rfAccount, "400", "角色祈愿2", force);
await refreshGachaPool(rfAccount, "302", "武器祈愿", force);
await refreshGachaPool(rfAccount, "500", "集录祈愿", force);
await TGLogger.Info(`[Gacha][${rfAccount.gameUid}][confirmRefresh] 刷新祈愿数据完成`);
await reloadUid(uidCur.value);
await loadGachaList();
await showLoading.end();
await TGLogger.Info(`[UserGacha][${account.value.gameUid}][confirmRefresh] 刷新祈愿数据完成`);
showSnackbar.success("祈愿数据刷新完成,即将刷新页面");
await new Promise<void>((resolve) => setTimeout(resolve, 1500));
window.location.reload();
}
// 刷新单个池子
async function refreshGachaPool(
ac: TGApp.Sqlite.Account.Game,
type: string,
label: string,
force: boolean = false,
@@ -519,17 +523,15 @@ async function refreshGachaPool(
let gachaDataMap: Record<string, Array<string>> | undefined = undefined;
let page = 0;
await showLoading.start(`正在刷新${label}数据`);
if (!force) endId = (await TSUserGacha.getGachaCheck(account.value.gameUid, type)) ?? "0";
if (!force) endId = (await TSUserGacha.getGachaCheck(ac.gameUid, type)) ?? "0";
while (true) {
page++;
const gachaRes = await hk4eReq.gacha(authkey.value, type, reqId);
if (!Array.isArray(gachaRes)) {
showSnackbar.error(`[${type}][${gachaRes.retcode}] ${gachaRes.message}`);
await TGLogger.Error(`[Gacha][${ac.gameUid}][refreshGachaPool] 获取祈愿数据失败`);
await TGLogger.Error(
`[UserGacha][${account.value.gameUid}][refreshGachaPool] 获取祈愿数据失败`,
);
await TGLogger.Error(
`[UserGacha][${account.value.gameUid}][refreshGachaPool] ${gachaRes.retcode} ${gachaRes.message}`,
`[Gacha][${ac.gameUid}][refreshGachaPool] ${gachaRes.retcode} ${gachaRes.message}`,
);
await new Promise<void>((resolve) => setTimeout(resolve, 1000));
break;
@@ -538,7 +540,7 @@ async function refreshGachaPool(
if (force) {
await showLoading.update(`正在清理${label}数据`);
if (gachaDataMap) {
await TSUserGacha.cleanGachaRecords(account.value.gameUid, type, gachaDataMap);
await TSUserGacha.cleanGachaRecords(ac.gameUid, type, gachaDataMap);
}
}
break;
@@ -582,7 +584,7 @@ async function refreshGachaPool(
gachaDataMap[item.time].push(item.id.toString());
}
}
await TSUserGacha.mergeUIGF(account.value.gameUid, uigfList);
await TSUserGacha.mergeUIGF(ac.gameUid, uigfList);
if (!force && gachaRes.some((i) => i.id.toString() === endId.toString())) break;
reqId = gachaRes[gachaRes.length - 1].id.toString();
if (force) await new Promise<void>((resolve) => setTimeout(resolve, 1000));
@@ -683,13 +685,10 @@ async function deleteGacha(): Promise<void> {
}
await showLoading.start("正在删除祈愿数据", `UID:${uidCur.value}`);
await TSUserGacha.deleteGachaRecords(uidCur.value);
await reloadUid();
await loadGachaList();
await showLoading.end();
showSnackbar.success(`已成功删除 ${uidCur.value} 的祈愿数据,即将刷新页面`);
await TGLogger.Info(
`[UserGacha][${uidCur.value}][deleteGacha] 成功删除 ${gachaListCur.value.length} 条祈愿数据`,
);
await new Promise<void>((resolve) => setTimeout(resolve, 1500));
window.location.reload();
}
async function checkData(): Promise<void> {

View File

@@ -1,26 +1,26 @@
/**
* 关于 BBS 的工具函数
* @since Beta v0.9.1
* @since Beta v0.9.6
*/
/**
* salt 类型
* @since Beta v0.9.1
* @since Beta v0.9.6
*/
export type SaltKey = "K2" | "LK2" | "X4" | "X6" | "PROD";
const BBS_VERSION: Readonly<string> = "2.100.0";
const BBS_VERSION: Readonly<string> = "2.102.1";
const BBS_UA_MOBILE: Readonly<string> = `Mozilla/5.0 (Linux; Android 12) Mobile miHoYoBBS/${BBS_VERSION}`;
const BBS_UA_PC: Readonly<string> = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) miHoYoBBS/${BBS_VERSION}`;
/**
* salt 值
* @since Beta v0.9.1
* @remarks 2.100.0
* @since Beta v0.9.6
* @remarks 2.102.1
*/
const BBS_SALT: Readonly<Record<SaltKey, string>> = {
K2: "SVHcDPuPJYhcm57aSLDe7IwI5gvjgAib",
LK2: "AUtLYA9P6PLDXW6VC7pEBDLRarap3RsA",
K2: "lX8m5VO5at5JG7hR8hzqFwzyL5aB1tYo",
LK2: "yBh10ikxtLPoIhgwgPZSv5dmfaOTSJ6a",
X4: "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs",
X6: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",
PROD: "t0qEgfub6cvueAPgR5m9aQWWVciEer7v",