File size: 4,852 Bytes
605cef2 3cd2062 605cef2 bb35e88 605cef2 fc062b2 605cef2 3cd2062 fc062b2 605cef2 fc062b2 bb35e88 605cef2 fc062b2 bb35e88 605cef2 3cd2062 605cef2 bb35e88 605cef2 bb35e88 605cef2 bb35e88 605cef2 bb35e88 605cef2 3cd2062 fc062b2 605cef2 bb35e88 605cef2 bb35e88 605cef2 bb35e88 605cef2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | /**
* Demo存储控制器 - 协调存储层和UI层
*/
import type { AnalysisData } from '../api/GLTR_API';
import type { IDemoStorage, SaveOptions, SaveResult } from '../storage/demoStorage';
import { showConfirmDialog, showAlertDialog } from '../ui/dialog';
import { tr, trf } from '../lang/i18n-lite';
export interface StorageCallbacks {
onStart?: () => void;
onSuccess?: (name?: string, result?: SaveResult) => void;
onError?: (error: Error) => void;
setLoading?: (loading: boolean) => void;
showToast?: (message: string, type: 'success' | 'error') => void;
/**
* 是否显示成功提示(使用 toast)
* 默认为 true,设置为 false 时成功提示由调用者自行处理
* 注意:错误提示统一使用 alert,不受此参数影响
*/
showSuccessToast?: boolean;
}
/**
* Demo存储控制器
*/
export class DemoStorageController {
constructor(
private storage: IDemoStorage,
private callbacks: StorageCallbacks = {}
) {}
/**
* 保存demo
*/
async save(data: AnalysisData, options: SaveOptions): Promise<SaveResult | null> {
const { onStart, onSuccess, onError, setLoading, showToast, showSuccessToast = true } = this.callbacks;
onStart?.();
setLoading?.(true);
try {
const result = await this._doSave(data, options, false);
setLoading?.(false);
if (result) {
onSuccess?.(options.name, result);
// 成功提示:根据 showSuccessToast 决定是否显示
if (showSuccessToast) {
const hint = this.storage.type === 'local' ? tr('Downloaded to local') : tr('Upload successful');
showToast?.(`Demo "${options.name}" ${hint}!`, 'success');
}
}
return result;
} catch (error) {
setLoading?.(false);
const err = error instanceof Error ? error : new Error(String(error));
onError?.(err);
// 错误提示:统一使用 alert
showAlertDialog(tr('Error'), trf('Save failed: {message}', { message: err.message }));
return null;
}
}
/**
* 内部保存逻辑,处理覆盖
*/
private async _doSave(
data: AnalysisData,
options: SaveOptions,
overwrite: boolean
): Promise<SaveResult | null> {
const result = await this.storage.save(data, { ...options, overwrite });
// 文件已存在 - 仅服务器需要确认覆盖
if (!result.success && result.exists && this.storage.type === 'server') {
return new Promise((resolve) => {
this.callbacks.setLoading?.(false);
showConfirmDialog(
tr('File already exists'),
trf('File "{name}.json" already exists, overwrite?', { name: options.name }),
async () => {
this.callbacks.setLoading?.(true);
const saved = await this._doSave(data, options, true);
resolve(saved);
},
() => {
this.callbacks.onError?.(new Error(tr('User cancelled save')));
resolve(null);
},
tr('Overwrite'),
tr('Cancel')
);
});
}
if (!result.success) {
throw new Error(result.message || 'Save failed');
}
return result;
}
/**
* 加载demo
*/
async load(path?: string): Promise<AnalysisData | null> {
const { onStart, onSuccess, onError, setLoading } = this.callbacks;
onStart?.();
setLoading?.(true);
try {
const result = await this.storage.load(path);
setLoading?.(false);
if (result.success && result.data) {
onSuccess?.();
return result.data;
} else {
// 显示错误(这里不涉及用户取消操作)
if (result.message) {
const err = new Error(result.message || 'Load failed');
onError?.(err);
showAlertDialog(tr('Error'), tr(err.message));
}
return null;
}
} catch (error) {
setLoading?.(false);
const err = error instanceof Error ? error : new Error(String(error));
onError?.(err);
showAlertDialog(tr('Error'), trf('Load failed: {message}', { message: err.message }));
return null;
}
}
}
|