Skip to content

Commit 62052d1

Browse files
committed
✨ 下载祈愿数据
close #202
1 parent 8d54189 commit 62052d1

11 files changed

Lines changed: 258 additions & 37 deletions

File tree

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
"html2canvas": "^1.4.1",
9696
"js-md5": "^0.8.3",
9797
"jsencrypt": "^3.5.4",
98+
"json-bigint": "^1.0.0",
9899
"pinia": "^3.0.4",
99100
"pinia-plugin-persistedstate": "^4.7.1",
100101
"qrcode.vue": "^3.6.0",
@@ -118,6 +119,7 @@
118119
"@tauri-apps/cli": "2.9.6",
119120
"@types/fs-extra": "^11.0.4",
120121
"@types/js-md5": "^0.8.0",
122+
"@types/json-bigint": "^1.0.4",
121123
"@types/node": "^25.0.6",
122124
"@typescript-eslint/parser": "^8.52.0",
123125
"@typescript/native-preview": "7.0.0-dev.20260109.1",

pnpm-lock.yaml

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/userGacha/ugo-hutao-du.vue

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<template>
33
<TOverlay v-model="visible" blur-val="5px">
44
<div class="ugo-hutao-du">
5-
<div class="ugo-hd-title">请选择要{{ props.mode === "upload" ? "上传" : "下载" }}的数据</div>
5+
<div class="ugo-hd-title">请选择要{{ title }}的数据</div>
66
<v-progress-circular v-if="loading" color="var(--tgc-od-blue)" indeterminate />
77
<v-item-group v-else v-model="selectedUid" :multiple="true" class="ugo-hd-list">
88
<v-item
@@ -38,12 +38,13 @@ import hutao from "@Hutao/index.js";
3838
import TSUserGacha from "@Sqlm/userGacha.js";
3939
import useHutaoStore from "@store/hutao.js";
4040
import { storeToRefs } from "pinia";
41-
import { ref, shallowRef, watch } from "vue";
41+
import { computed, ref, shallowRef, watch } from "vue";
4242
43+
export type UgoHutaoMode = "download" | "upload" | "delete";
4344
type UgoHutaoDuUid = { uid: string; cnt: number };
4445
45-
type UgoHutaoDuProps = { mode: "download" | "upload" };
46-
type UgoHutaoDuEmits = (e: "selected", v: Array<string>, m: boolean) => void;
46+
type UgoHutaoDuProps = { mode: UgoHutaoMode };
47+
type UgoHutaoDuEmits = (e: "selected", v: Array<string>, m: UgoHutaoMode) => void;
4748
4849
const visible = defineModel<boolean>();
4950
const emits = defineEmits<UgoHutaoDuEmits>();
@@ -52,6 +53,18 @@ const props = defineProps<UgoHutaoDuProps>();
5253
const loading = ref<boolean>(false);
5354
const uidList = shallowRef<Array<UgoHutaoDuUid>>([]);
5455
const selectedUid = shallowRef<Array<string>>([]);
56+
const title = computed<string>(() => {
57+
switch (props.mode) {
58+
case "upload":
59+
return "上传";
60+
case "download":
61+
return "下载";
62+
case "delete":
63+
return "删除";
64+
default:
65+
return "";
66+
}
67+
});
5568
5669
const hutaoStore = useHutaoStore();
5770
const { accessToken, isLogin } = storeToRefs(hutaoStore);
@@ -63,10 +76,10 @@ watch(
6376
loading.value = true;
6477
selectedUid.value = [];
6578
uidList.value = [];
66-
if (props.mode == "download") {
67-
await loadDownload();
68-
} else {
79+
if (props.mode == "upload") {
6980
await loadUpload();
81+
} else {
82+
await loadDownload();
7083
}
7184
loading.value = false;
7285
}
@@ -105,7 +118,7 @@ function handleSelected(): void {
105118
showSnackbar.warn("请选择至少一个UID");
106119
return;
107120
}
108-
emits("selected", selectedUid.value, props.mode === "upload");
121+
emits("selected", selectedUid.value, props.mode);
109122
visible.value = false;
110123
}
111124
</script>

src/pages/User/Gacha.vue

Lines changed: 149 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@
4444
>
4545
下载
4646
</v-btn>
47+
<v-btn
48+
:disabled="!isLoginHutao"
49+
class="gacha-top-btn"
50+
prepend-icon="mdi-delete"
51+
variant="elevated"
52+
@click="tryDeleteGacha()"
53+
>
54+
删除
55+
</v-btn>
4756
</div>
4857
</div>
4958
</template>
@@ -156,7 +165,7 @@ import GroHistory from "@comp/userGacha/gro-history.vue";
156165
import GroIframe from "@comp/userGacha/gro-iframe.vue";
157166
import GroOverview from "@comp/userGacha/gro-overview.vue";
158167
import GroTable from "@comp/userGacha/gro-table.vue";
159-
import UgoHutaoDu from "@comp/userGacha/ugo-hutao-du.vue";
168+
import UgoHutaoDu, { type UgoHutaoMode } from "@comp/userGacha/ugo-hutao-du.vue";
160169
import UgoUid from "@comp/userGacha/ugo-uid.vue";
161170
import hutao from "@Hutao/index.js";
162171
import hk4eReq from "@req/hk4eReq.js";
@@ -175,7 +184,7 @@ import { storeToRefs } from "pinia";
175184
import { onMounted, ref, shallowRef, watch } from "vue";
176185
import { useRouter } from "vue-router";
177186
178-
import { AppCharacterData, AppWeaponData } from "@/data/index.js";
187+
import { AppCalendarData, AppCharacterData, AppWeaponData } from "@/data/index.js";
179188
180189
const router = useRouter();
181190
const hutaoStore = useHutaoStore();
@@ -190,7 +199,7 @@ const tab = ref<string>("overview");
190199
const ovShow = ref<boolean>(false);
191200
const hutaoShow = ref<boolean>(false);
192201
const ovMode = ref<"export" | "import">("import");
193-
const htMode = ref<"download" | "upload">("download");
202+
const htMode = ref<UgoHutaoMode>("download");
194203
const selectItem = shallowRef<Array<string>>([]);
195204
const gachaListCur = shallowRef<Array<TGApp.Sqlite.Gacha.Gacha>>([]);
196205
const hakushiData = shallowRef<Array<TGApp.Plugins.Hakushi.ConvertData>>([]);
@@ -243,9 +252,24 @@ async function tryDownloadGacha(): Promise<void> {
243252
hutaoShow.value = true;
244253
}
245254
246-
async function handleHutaoDu(uids: Array<string>, isUpload: boolean): Promise<void> {
247-
if (isUpload) await handleHutaoUpload(uids);
248-
else await handleHutaoDownload(uids);
255+
async function tryDeleteGacha(): Promise<void> {
256+
if (!isLoginHutao.value) return;
257+
htMode.value = "delete";
258+
hutaoShow.value = true;
259+
}
260+
261+
async function handleHutaoDu(uids: Array<string>, mode: UgoHutaoMode): Promise<void> {
262+
switch (mode) {
263+
case "download":
264+
await handleHutaoDownload(uids);
265+
break;
266+
case "upload":
267+
await handleHutaoUpload(uids);
268+
break;
269+
case "delete":
270+
await handleHutaoDelete(uids);
271+
break;
272+
}
249273
}
250274
251275
async function handleHutaoUpload(uids: Array<string>): Promise<void> {
@@ -284,7 +308,7 @@ async function handleHutaoUpload(uids: Array<string>): Promise<void> {
284308
QueryType: Number(i.uigfType),
285309
ItemId: Number(i.itemId),
286310
Time: str2timeStr(i.time),
287-
Id: BigInt(i.id),
311+
Id: i.id.toString(),
288312
})),
289313
};
290314
const resp = await hutao.Gacha.upload(accessToken.value!, data);
@@ -298,8 +322,124 @@ async function handleHutaoUpload(uids: Array<string>): Promise<void> {
298322
}
299323
300324
async function handleHutaoDownload(uids: Array<string>): Promise<void> {
301-
console.log(uids);
302-
// TODO:implement download gacha logs
325+
if (uids.length === 0) {
326+
showSnackbar.warn("没有选中的UID");
327+
return;
328+
}
329+
if (!isLoginHutao.value) {
330+
showSnackbar.warn("未登录胡桃云账号");
331+
return;
332+
}
333+
if (!userInfo.value) {
334+
await hutaoStore.tryRefreshInfo();
335+
if (!userInfo.value) {
336+
showSnackbar.warn("未检测到胡桃云用户信息");
337+
return;
338+
}
339+
}
340+
await showLoading.start("正在下载胡桃云祈愿记录...", "正在刷新Token");
341+
for (const u of uids) {
342+
await showLoading.start(`正在下载UID:${u}的祈愿记录`, "正在获取EndIds");
343+
const endIdResp = await hutao.Gacha.endIds(accessToken.value!, u);
344+
if ("retcode" in endIdResp) {
345+
showSnackbar.warn(`[${endIdResp.retcode}] ${endIdResp.message}`);
346+
continue;
347+
}
348+
for (const [p, i] of Object.entries(endIdResp)) {
349+
if (i === 0) continue;
350+
let endId: string | undefined = undefined;
351+
let flag = true;
352+
const pageSize = 200;
353+
await showLoading.start(`正在下载卡池 ${p}`);
354+
const uigfList: Array<TGApp.Plugins.UIGF.GachaItem> = [];
355+
while (flag) {
356+
await showLoading.update(`EndId:${endId ?? ""}`);
357+
await hutaoStore.tryRefreshToken();
358+
const gachaResp = await hutao.Gacha.logs(accessToken.value!, u, Number(p), pageSize, endId);
359+
if (gachaResp.retcode !== 0) {
360+
showSnackbar.warn(`[${gachaResp.retcode}] ${gachaResp.message}`);
361+
break;
362+
}
363+
const data: TGApp.Plugins.Hutao.Gacha.GachaLogRes = gachaResp.data ?? [];
364+
if (data.length === pageSize) {
365+
endId = data[data.length - 1].Id.toString();
366+
} else flag = false;
367+
for (const item of data) {
368+
const tempItem: TGApp.Plugins.UIGF.GachaItem = {
369+
gacha_type: item.GachaType.toString(),
370+
item_id: item.ItemId.toString(),
371+
count: "1",
372+
time: item.Time,
373+
name: "",
374+
item_type: "",
375+
rank_type: "",
376+
id: BigInt(item.Id).toString(),
377+
uigf_gacha_type: item.QueryType.toString(),
378+
};
379+
const find = AppCalendarData.find((i) => i.id.toString() === item.ItemId.toString());
380+
if (find) {
381+
tempItem.name = find.name;
382+
tempItem.item_type = find.itemType;
383+
tempItem.rank_type = find.star.toString();
384+
} else {
385+
if (hakushiData.value.length === 0) {
386+
await showLoading.update(
387+
`未查找到 ${tempItem.item_id} 的 信息,正在获取 Hakushi 数据`,
388+
);
389+
await loadHakushi();
390+
}
391+
const findH = hakushiData.value.find((i) => i.id.toString() === item.ItemId.toString());
392+
if (findH) {
393+
tempItem.name = findH.name;
394+
tempItem.item_type = findH.type;
395+
tempItem.rank_type = findH.star.toString();
396+
} else {
397+
showSnackbar.warn(`无法搜索到 ${item.ItemId} 的信息,请等待元数据更新`);
398+
continue;
399+
}
400+
}
401+
uigfList.push(tempItem);
402+
}
403+
}
404+
await showLoading.start(`正在写入卡池 ${p}-${uigfList.length}`);
405+
await TSUserGacha.mergeUIGF(u, uigfList, true);
406+
}
407+
}
408+
await showLoading.end();
409+
showSnackbar.success("成功下载,即将刷新页面");
410+
await new Promise<void>((resolve) => setTimeout(resolve, 1000));
411+
window.location.reload();
412+
}
413+
414+
async function handleHutaoDelete(uids: Array<string>): Promise<void> {
415+
if (uids.length === 0) {
416+
showSnackbar.warn("没有选中的UID");
417+
return;
418+
}
419+
if (!isLoginHutao.value) {
420+
showSnackbar.warn("未登录胡桃云账号");
421+
return;
422+
}
423+
if (!userInfo.value) {
424+
await hutaoStore.tryRefreshInfo();
425+
if (!userInfo.value) {
426+
showSnackbar.warn("未检测到胡桃云用户信息");
427+
return;
428+
}
429+
}
430+
const check = await showDialog.check("确定删除?", uids.join(""));
431+
if (!check) return;
432+
await showLoading.start("正在删除胡桃云祈愿记录");
433+
for (const u of uids) {
434+
await showLoading.update(`UID:${u}`);
435+
const deleteResp = await hutao.Gacha.delete(accessToken.value!, u);
436+
if (deleteResp.retcode === 0) {
437+
showSnackbar.success(`删除记录成功:${deleteResp.message}`);
438+
} else {
439+
showSnackbar.warn(`[${deleteResp.retcode}] ${deleteResp.message}`);
440+
}
441+
}
442+
await showLoading.end();
303443
}
304444
305445
async function reloadUid(): Promise<void> {

src/plugins/Hutao/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@ import {
1414
} from "./request/abyssReq.js";
1515
import { getUserInfo, loginPassport, refreshToken } from "./request/accountReq.js";
1616
import { getCombatStatistic, uploadCombatData } from "./request/combatReq.js";
17-
import { getEndIds, getEntries, getGachaLogs, uploadGachaLogs } from "./request/gachaReq.js";
17+
import {
18+
deleteGachaLogs,
19+
getEndIds,
20+
getEntries,
21+
getGachaLogs,
22+
uploadGachaLogs,
23+
} from "./request/gachaReq.js";
1824
import { transAbyssAvatars, transAbyssLocal } from "./utils/abyssUtil.js";
1925
import { transCombatLocal } from "./utils/combatUtil.js";
2026

@@ -62,7 +68,7 @@ const Hutao = {
6268
endIds: getEndIds,
6369
logs: getGachaLogs,
6470
upload: uploadGachaLogs,
65-
delete: _,
71+
delete: deleteGachaLogs,
6672
},
6773
};
6874

0 commit comments

Comments
 (0)