InfoRadar / client /src /ts /utils /appStateManager.ts
dqy08's picture
Enhance model selection and demo management
9702df4
/**
* 应用状态管理模块
* 负责集中管理应用状态和状态驱动的按钮状态更新
*/
import * as d3 from 'd3';
/**
* 应用状态对象
*/
export interface AppState {
isAnalyzing: boolean;
isGlobalLoading: boolean;
isSaving: boolean; // 是否正在保存
hasValidData: boolean; // 是否有有效数据
// 以下字段仅用于按钮状态控制
dataSource: 'local' | 'server' | null; // 数据来源:null表示新分析的内容
isSavedToLocal: boolean; // 是否已保存到本地
isSavedToServer: boolean; // 是否已保存到服务器
currentFileName: string | null; // 当前文件名(本地或服务器)
}
/**
* 按钮状态管理依赖
*/
export interface ButtonStateDependencies {
submitBtn: d3.Selection<HTMLElement, unknown, HTMLElement, unknown>;
saveBtn: d3.Selection<HTMLElement, unknown, HTMLElement, unknown>;
saveLocalBtn: d3.Selection<HTMLElement, unknown, HTMLElement, unknown>;
textField: d3.Selection<HTMLElement, unknown, HTMLElement, unknown>;
textMetrics: d3.Selection<HTMLElement, unknown, HTMLElement, unknown>;
}
/**
* 应用状态管理器
*/
export class AppStateManager {
private state: AppState;
private deps: ButtonStateDependencies;
constructor(deps: ButtonStateDependencies) {
this.state = {
isAnalyzing: false,
isGlobalLoading: false,
isSaving: false,
hasValidData: false,
dataSource: null,
isSavedToLocal: false,
isSavedToServer: false,
currentFileName: null
};
this.deps = deps;
}
/**
* 获取当前状态
*/
getState(): Readonly<AppState> {
return { ...this.state };
}
/**
* 获取 isAnalyzing 状态
*/
getIsAnalyzing(): boolean {
return this.state.isAnalyzing;
}
/**
* 设置 isAnalyzing 状态
*/
setIsAnalyzing(analyzing: boolean): void {
this.updateState({ isAnalyzing: analyzing });
}
/**
* 设置全局 loading 状态
*/
setGlobalLoading(loading: boolean): void {
this.updateState({ isGlobalLoading: loading });
}
/**
* 根据应用状态计算并更新所有按钮状态和UI元素状态
*/
private updateButtonStatesFromAppState(): void {
const hasText = (this.deps.textField.property('value') || '').trim().length > 0;
const isBusy = this.state.isAnalyzing || this.state.isGlobalLoading || this.state.isSaving;
// Analyze按钮:有文本 && 不忙
this.deps.submitBtn.classed('inactive', !hasText || isBusy);
// Upload按钮:有有效数据 && 不忙 && 不是从服务器加载的 && 未保存到服务器
this.deps.saveBtn.classed('inactive',
!this.state.hasValidData ||
isBusy ||
this.state.dataSource === 'server' ||
this.state.isSavedToServer
);
// Save to local按钮:有有效数据 && 不忙 && 不是从本地加载的 && 未保存到本地
this.deps.saveLocalBtn.classed('inactive',
!this.state.hasValidData ||
isBusy ||
this.state.dataSource === 'local' ||
this.state.isSavedToLocal
);
// TextMetrics显示:有有效数据(hasValidData = true 时,stats 一定不为 null)
if (!this.deps.textMetrics.empty()) {
this.deps.textMetrics.classed('is-hidden', !this.state.hasValidData);
}
}
/**
* 更新应用状态并触发按钮状态更新
*/
updateState(updates: Partial<AppState>): void {
Object.assign(this.state, updates);
this.updateButtonStatesFromAppState();
// 同时更新全局loading的UI(如果需要)
if (updates.isGlobalLoading !== undefined) {
d3.selectAll(".loadersmall").style('display', updates.isGlobalLoading ? null : 'none');
// 隐藏进度显示
if (!updates.isGlobalLoading) {
d3.select('#analyze_progress').text('').style('display', 'none');
}
}
}
/**
* 手动触发按钮状态更新(用于外部调用)
*/
updateButtonStates(): void {
this.updateButtonStatesFromAppState();
}
}