/** * 应用状态管理模块 * 负责集中管理应用状态和状态驱动的按钮状态更新 */ 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; saveBtn: d3.Selection; saveLocalBtn: d3.Selection; textField: d3.Selection; textMetrics: d3.Selection; } /** * 应用状态管理器 */ 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 { 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): 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(); } }