️大幅提升UIGF导入速度 (#225)

* Initial plan

* perf: optimize gacha import with batch transactions and reduced UI delays

- Wrap DB inserts in transactions (batches of 500) for mergeUIGF/mergeUIGF4
- Pre-transform all data before batch insert loop
- Pass timeout: 0 to showLoading.update in progress callbacks
- Remove 1500ms snackbar delay in cleanGachaRecords
- Reduce per-item loading update delay in refreshGachaPool

Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com>

* fix: increment progress counter per item instead of per batch for accurate progress display

Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Mikachu2333 <63829496+Mikachu2333@users.noreply.github.com>
This commit is contained in:
Copilot
2026-02-27 23:49:19 +08:00
committed by BTMuli
parent 43de734884
commit 2d321aad9c
4 changed files with 84 additions and 32 deletions

1
.gitignore vendored
View File

@@ -11,3 +11,4 @@ dist
# Sentry Config File
.env.development.local
package-lock.json

View File

@@ -549,7 +549,7 @@ async function refreshGachaPool(
if (force) await showLoading.update(`[${label}] 第${page}页,${gachaRes.length}`);
for (const item of gachaRes) {
if (!force) {
await showLoading.update(`[${item.item_type}][${item.time}] ${item.name}`);
await showLoading.update(`[${item.item_type}][${item.time}] ${item.name}`, { timeout: 0 });
}
const tempItem: TGApp.Plugins.UIGF.GachaItem = {
gacha_type: item.gacha_type,

View File

@@ -235,7 +235,6 @@ async function cleanGachaRecords(
const res = await db.execute(sql);
if (res.rowsAffected > 0) {
showSnackbar.success(`[${uid}][${pool}][${time}]清理了${res.rowsAffected}条祈愿记录`);
await new Promise<void>((resolve) => setTimeout(resolve, 1500));
}
}
}
@@ -253,27 +252,40 @@ async function mergeUIGF(
data: Array<TGApp.Plugins.UIGF.GachaItem>,
showProgress: boolean = false,
): Promise<void> {
let cnt = 0;
const db = await TGSqlite.getDB();
const len = data.length;
let progress = 0;
let cnt = 0;
let timer: NodeJS.Timeout | null = null;
if (showProgress) {
timer = setInterval(async () => {
progress = Math.round((cnt / len) * 100 * 100) / 100;
const progress = Math.round((cnt / len) * 100 * 100) / 100;
const current = data[cnt]?.time ?? "";
const name = data[cnt]?.name ?? "";
const rank = data[cnt]?.rank_type ?? "0";
await showLoading.update(`[${progress}%][${current}] ${"⭐".repeat(Number(rank))}-${name}`);
await showLoading.update(`[${progress}%][${current}] ${"⭐".repeat(Number(rank))}-${name}`, {
timeout: 0,
});
}, 1000);
}
for (const gacha of data) {
await insertGachaItem(uid, transGacha(gacha));
const transformed = data.map((g) => transGacha(g));
const BATCH_SIZE = 500;
for (let i = 0; i < transformed.length; i += BATCH_SIZE) {
const batch = transformed.slice(i, i + BATCH_SIZE);
await db.execute("BEGIN TRANSACTION;");
try {
for (const item of batch) {
await insertGachaItem(uid, item);
cnt++;
}
await db.execute("COMMIT;");
} catch (e) {
await db.execute("ROLLBACK;");
throw e;
}
}
if (timer) {
clearInterval(timer);
progress = 100;
await showLoading.update(`[${progress}%] 完成`);
await showLoading.update(`[100%] 完成`, { timeout: 0 });
}
}
@@ -288,27 +300,41 @@ async function mergeUIGF4(
data: TGApp.Plugins.UIGF.GachaHk4e,
showProgress: boolean = false,
): Promise<void> {
let cnt: number = 0;
const db = await TGSqlite.getDB();
const len = data.list.length;
let progress: number = 0;
let cnt: number = 0;
let timer: NodeJS.Timeout | null = null;
if (showProgress) {
timer = setInterval(async () => {
progress = Math.round((cnt / len) * 100 * 100) / 100;
const progress = Math.round((cnt / len) * 100 * 100) / 100;
const current = data.list[cnt]?.time ?? "";
const name = data.list[cnt]?.name ?? data.list[cnt]?.item_id;
const rank = data.list[cnt]?.rank_type ?? "0";
await showLoading.update(`[${progress}%][${current}] ${"⭐".repeat(Number(rank))}-${name}`);
await showLoading.update(`[${progress}%][${current}] ${"⭐".repeat(Number(rank))}-${name}`, {
timeout: 0,
});
}, 1000);
}
for (const gacha of data.list) {
await insertGachaItem(data.uid.toString(), transGacha(gacha, data.timezone));
const uid = data.uid.toString();
const transformed = data.list.map((g) => transGacha(g, data.timezone));
const BATCH_SIZE = 500;
for (let i = 0; i < transformed.length; i += BATCH_SIZE) {
const batch = transformed.slice(i, i + BATCH_SIZE);
await db.execute("BEGIN TRANSACTION;");
try {
for (const item of batch) {
await insertGachaItem(uid, item);
cnt++;
}
await db.execute("COMMIT;");
} catch (e) {
await db.execute("ROLLBACK;");
throw e;
}
}
if (timer) {
clearInterval(timer);
progress = 100;
await showLoading.update(`[${progress}%] 完成`);
await showLoading.update(`[100%] 完成`, { timeout: 0 });
}
}

View File

@@ -65,9 +65,21 @@ async function insertGachaList(
uid: string,
list: Array<TGApp.Plugins.UIGF.GachaItemB>,
): Promise<void> {
for (const gacha of list) {
const db = await TGSqlite.getDB();
const BATCH_SIZE = 500;
for (let i = 0; i < list.length; i += BATCH_SIZE) {
const batch = list.slice(i, i + BATCH_SIZE);
await db.execute("BEGIN TRANSACTION;");
try {
for (const gacha of batch) {
await insertGachaItem(uid, gacha);
}
await db.execute("COMMIT;");
} catch (e) {
await db.execute("ROLLBACK;");
throw e;
}
}
}
/**
@@ -106,27 +118,40 @@ async function mergeUIGF4(
data: TGApp.Plugins.UIGF.GachaUgc,
showProgress: boolean = false,
): Promise<void> {
let cnt: number = 0;
const db = await TGSqlite.getDB();
const len = data.list.length;
let progress: number = 0;
let cnt: number = 0;
let timer: NodeJS.Timeout | null = null;
if (showProgress) {
timer = setInterval(async () => {
progress = Math.round((cnt / len) * 100 * 100) / 100;
const progress = Math.round((cnt / len) * 100 * 100) / 100;
const current = data.list[cnt].time ?? "";
const name = data.list[cnt].item_name ?? "";
const rank = data.list[cnt].rank_type ?? "0";
await showLoading.update(`[${progress}%][${current}] ${"⭐".repeat(Number(rank))}-${name}`);
await showLoading.update(`[${progress}%][${current}] ${"⭐".repeat(Number(rank))}-${name}`, {
timeout: 0,
});
}, 1000);
}
for (const gacha of data.list) {
await insertGachaItem(data.uid.toString(), transGacha(gacha, data.timezone));
const uid = data.uid.toString();
const BATCH_SIZE = 500;
for (let i = 0; i < data.list.length; i += BATCH_SIZE) {
const batch = data.list.slice(i, i + BATCH_SIZE);
await db.execute("BEGIN TRANSACTION;");
try {
for (const gacha of batch) {
await insertGachaItem(uid, transGacha(gacha, data.timezone));
cnt++;
}
await db.execute("COMMIT;");
} catch (e) {
await db.execute("ROLLBACK;");
throw e;
}
}
if (timer) {
clearInterval(timer);
progress = 100;
await showLoading.update(`[${progress}%] 完成`);
await showLoading.update(`[100%] 完成`, { timeout: 0 });
}
}