151 lines
4.4 KiB
TypeScript
151 lines
4.4 KiB
TypeScript
/**
|
||
* 文件:progress-indicator.ts
|
||
* 作用:进度指示和用户反馈管理
|
||
*/
|
||
|
||
import { Notice } from 'obsidian';
|
||
|
||
export interface ProgressOptions {
|
||
showProgress?: boolean;
|
||
duration?: number;
|
||
autoHide?: boolean;
|
||
}
|
||
|
||
class GlobalProgressManager {
|
||
private static instance: GlobalProgressManager | null = null;
|
||
private currentNotice: Notice | null = null;
|
||
private startTime: number = 0;
|
||
|
||
static getInstance(): GlobalProgressManager {
|
||
if (!GlobalProgressManager.instance) {
|
||
GlobalProgressManager.instance = new GlobalProgressManager();
|
||
}
|
||
return GlobalProgressManager.instance;
|
||
}
|
||
|
||
start(message: string, options: ProgressOptions = {}): void {
|
||
// 如果已有通知,先关闭
|
||
if (this.currentNotice) {
|
||
this.currentNotice.hide();
|
||
}
|
||
|
||
this.startTime = Date.now();
|
||
const { duration = 10000 } = options; // 默认10秒自动消失,防止卡住
|
||
|
||
this.currentNotice = new Notice(`🔄 ${message}...`, duration);
|
||
}
|
||
|
||
update(message: string, progress?: number): void {
|
||
if (!this.currentNotice) return;
|
||
|
||
const progressText = progress !== undefined ? ` (${Math.round(progress)}%)` : '';
|
||
this.currentNotice.setMessage(`🔄 ${message}${progressText}...`);
|
||
}
|
||
|
||
finish(message: string, success: boolean = true): void {
|
||
if (this.currentNotice) {
|
||
this.currentNotice.hide();
|
||
this.currentNotice = null;
|
||
}
|
||
|
||
const duration = Date.now() - this.startTime;
|
||
const durationText = duration > 1000 ? ` (${(duration / 1000).toFixed(1)}s)` : '';
|
||
const icon = success ? '✅' : '❌';
|
||
|
||
new Notice(`${icon} ${message}${durationText}`, success ? 3000 : 5000);
|
||
}
|
||
|
||
error(message: string): void {
|
||
if (this.currentNotice) {
|
||
this.currentNotice.hide();
|
||
this.currentNotice = null;
|
||
}
|
||
|
||
const duration = Date.now() - this.startTime;
|
||
const durationText = duration > 1000 ? ` (${(duration / 1000).toFixed(1)}s)` : '';
|
||
|
||
new Notice(`❌ ${message}${durationText}`, 5000);
|
||
}
|
||
|
||
hide(): void {
|
||
if (this.currentNotice) {
|
||
this.currentNotice.hide();
|
||
this.currentNotice = null;
|
||
}
|
||
}
|
||
}
|
||
|
||
export class ProgressIndicator {
|
||
private manager = GlobalProgressManager.getInstance();
|
||
|
||
start(message: string, options: ProgressOptions = {}): void {
|
||
this.manager.start(message, options);
|
||
}
|
||
|
||
update(message: string, progress?: number): void {
|
||
this.manager.update(message, progress);
|
||
}
|
||
|
||
finish(message: string, success: boolean = true): void {
|
||
this.manager.finish(message, success);
|
||
}
|
||
|
||
error(message: string): void {
|
||
this.manager.error(message);
|
||
}
|
||
|
||
hide(): void {
|
||
this.manager.hide();
|
||
}
|
||
}
|
||
|
||
export class BatchProgressIndicator {
|
||
private currentProgress: ProgressIndicator | null = null;
|
||
private totalItems: number = 0;
|
||
private completedItems: number = 0;
|
||
private failedItems: number = 0;
|
||
|
||
start(totalItems: number, operation: string): void {
|
||
this.totalItems = totalItems;
|
||
this.completedItems = 0;
|
||
this.failedItems = 0;
|
||
|
||
this.currentProgress = new ProgressIndicator();
|
||
this.currentProgress.start(`${operation} (0/${totalItems})`);
|
||
}
|
||
|
||
updateItem(itemName: string, success: boolean = true): void {
|
||
if (success) {
|
||
this.completedItems++;
|
||
} else {
|
||
this.failedItems++;
|
||
}
|
||
|
||
const completed = this.completedItems + this.failedItems;
|
||
const progress = (completed / this.totalItems) * 100;
|
||
|
||
if (this.currentProgress) {
|
||
this.currentProgress.update(
|
||
`处理中: ${itemName} (${completed}/${this.totalItems})`,
|
||
progress
|
||
);
|
||
}
|
||
}
|
||
|
||
finish(operation: string): void {
|
||
const successCount = this.completedItems;
|
||
const failCount = this.failedItems;
|
||
const total = this.totalItems;
|
||
|
||
let message = `${operation}完成`;
|
||
if (failCount === 0) {
|
||
message += ` - 全部成功 (${successCount}/${total})`;
|
||
} else {
|
||
message += ` - 成功: ${successCount}, 失败: ${failCount}`;
|
||
}
|
||
|
||
if (this.currentProgress) {
|
||
this.currentProgress.finish(message, failCount === 0);
|
||
}
|
||
}
|
||
} |