chore: page turn

This commit is contained in:
xiaojunnuo
2026-01-24 23:36:44 +08:00
parent 9f21b1a097
commit f7b13c69e9
4 changed files with 62 additions and 23 deletions

View File

@@ -0,0 +1,136 @@
import { logger } from "@certd/basic"
export class BackTaskExecutor {
tasks: Record<string, Record<string, BackTask>> = {}
start(type: string, task: BackTask) {
if (!this.tasks[type]) {
this.tasks[type] = {}
}
const oldTask = this.tasks[type][task.key]
if (oldTask && oldTask.status === "running") {
throw new Error(`任务 ${type}${task.key} 正在运行中`)
}
this.tasks[type][task.key] = task
this.run(type, task);
}
get(type: string, key: string) {
if (!this.tasks[type]) {
this.tasks[type] = {}
}
return this.tasks[type][key]
}
removeIsEnd(type: string, key: string) {
const task = this.tasks[type]?.[key]
if (task && task.status !== "running") {
this.clear(type, key);
}
}
clear(type: string, key: string) {
const task = this.tasks[type]?.[key]
if (task) {
task.clearTimeout();
delete this.tasks[type][key]
}
}
private async run(type: string, task: any) {
if (task.status === "running") {
throw new Error(`任务 ${type}${task.key} 正在运行中`)
}
task.startTime = Date.now();
task.clearTimeout();
try {
task.status = "running";
return await task.run(task);
} catch (e) {
logger.error(`任务 ${task.title}[${type}-${task.key}] 执行失败`, e.message);
task.status = "failed";
task.error = e.message;
} finally {
task.endTime = Date.now();
task.status = "done";
task.timeoutId = setTimeout(() => {
this.clear(type, task.key);
}, 24 * 60 * 60 * 1000);
delete task.run;
}
}
}
export class BackTask {
key: string;
title: string;
total: number = 0;
current: number = 0;
skip: number = 0;
startTime: number;
endTime: number;
status: string = "pending";
errors?: string[] = [];
timeoutId?: NodeJS.Timeout;
run: (task: BackTask) => Promise<void>;
constructor(opts:{
key: string, title: string, run: (task: BackTask) => Promise<void>
}) {
const {key, title, run} = opts
this.key = key;
this.title = title;
Object.defineProperty(this, 'run', {
value: run,
writable: true,
enumerable: false, // 设置为false使其不可遍历
configurable: true
});
}
clearTimeout() {
if (this.timeoutId) {
clearTimeout(this.timeoutId);
this.timeoutId = null;
}
}
setTotal(total: number) {
this.total = total;
}
incrementCurrent() {
this.current++
}
addError(error: string) {
logger.error(error)
this.errors.push(error)
}
getSuccessCount() {
return this.current - this.errors.length
}
getErrorCount() {
return this.errors.length
}
getProgress() {
return (this.current / this.total * 1.0).toFixed(2)
}
getSkipCount() {
return this.skip
}
incrementSkip() {
this.skip++
}
}
export const taskExecutor = new BackTaskExecutor();