// src/features/imageAnnotation/services/AnnotationManager.ts // 全局注释管理器 - 负责监听Cornerstone事件并管理注释的保存/加载 import { eventTarget, getRenderingEngines } from '@cornerstonejs/core'; import { EVENTS } from '@cornerstonejs/core'; import { annotation as corAnnotation, Enums } from '@cornerstonejs/tools'; import { AnnotationSerializer } from './AnnotationSerializer'; import { AnnotationValidator } from './AnnotationValidator'; import { annotationAPI } from '../../../API/annotation'; import { extractSopInstanceUid } from '../../../utils/dicomUtils'; import type { AnnotationData, AnnotationEventType } from '../types/annotation'; import { IRenderingEngine, IStackViewport } from '@cornerstonejs/core/dist/esm/types'; export class AnnotationManager { private eventListenersRegistered: boolean = false; private activeImageId: string | null = null; private serializer: AnnotationSerializer; private validator: AnnotationValidator; private pendingChanges: Map = new Map(); private saveTimeout: NodeJS.Timeout | null = null; private isLoading: boolean = false; constructor() { this.serializer = new AnnotationSerializer(); this.validator = new AnnotationValidator(); } async initialize(): Promise { console.log('【annotationmanager】🔧 AnnotationManager 初始化中...'); // 注册全局事件监听器 this.registerGlobalEventListeners(); console.log('【annotationmanager】🎧 全局注释事件监听器已设置'); } async cleanup(): Promise { console.log('【annotationmanager】🧹 AnnotationManager 清理中...'); // 取消待处理的保存操作 if (this.saveTimeout) { clearTimeout(this.saveTimeout); this.saveTimeout = null; } // 移除全局事件监听器 this.unregisterGlobalEventListeners(); console.log('【annotationmanager】✅ AnnotationManager 清理完成'); } // ============ 事件监听器注册 ============ private registerGlobalEventListeners(): void { if (this.eventListenersRegistered) { console.warn('【annotationmanager】事件监听器已注册,跳过重复注册'); return; } console.log('【annotationmanager】注册事件监听器...'); // 图像加载完成事件 eventTarget.addEventListener( EVENTS.IMAGE_LOADED, this.handleImageLoadCompleted ); // 图像渲染完成事件 eventTarget.addEventListener( EVENTS.IMAGE_RENDERED, this.handleImageRendered ); // 注释完成事件 eventTarget.addEventListener( Enums.Events.ANNOTATION_COMPLETED, this.handleAnnotationCompleted ); // 注释添加事件 eventTarget.addEventListener( Enums.Events.ANNOTATION_ADDED, this.handleAnnotationAdded ); // 注释修改事件 eventTarget.addEventListener( Enums.Events.ANNOTATION_MODIFIED, this.handleAnnotationModified ); // 注释删除事件 eventTarget.addEventListener( Enums.Events.ANNOTATION_REMOVED, this.handleAnnotationRemoved ); this.eventListenersRegistered = true; console.log('【annotationmanager】✅ 事件监听器注册完成'); } private unregisterGlobalEventListeners(): void { if (!this.eventListenersRegistered) { return; } console.log('【annotationmanager】移除事件监听器...'); eventTarget.removeEventListener( EVENTS.IMAGE_LOADED, this.handleImageLoadCompleted ); eventTarget.removeEventListener( EVENTS.IMAGE_RENDERED, this.handleImageRendered ); eventTarget.removeEventListener( Enums.Events.ANNOTATION_COMPLETED, this.handleAnnotationCompleted ); eventTarget.removeEventListener( Enums.Events.ANNOTATION_ADDED, this.handleAnnotationCompleted ); eventTarget.removeEventListener( Enums.Events.ANNOTATION_MODIFIED, this.handleAnnotationModified ); eventTarget.removeEventListener( Enums.Events.ANNOTATION_REMOVED, this.handleAnnotationRemoved ); this.eventListenersRegistered = false; console.log('【annotationmanager】✅ 事件监听器移除完成'); } // ============ 事件处理方法 ============ private handleImageLoadCompleted = (evt: any) => { const rawImageId = evt.detail.image?.imageId || evt.detail.imageId; console.log(`【annotationmanager】📸 原始图像ID: ${rawImageId}`); // 提取SOP Instance UID const sopInstanceUid = extractSopInstanceUid(rawImageId); if (!sopInstanceUid) { console.warn('【annotationmanager】无法从图像URL中提取SOP Instance UID:', rawImageId); return; } console.log(`【annotationmanager】📸 提取的SOP Instance UID: ${sopInstanceUid}`); // 使用提取的SOP Instance UID加载注释 this.loadAnnotationsForImage(sopInstanceUid); }; private handleImageRendered = (evt: any) => { const { viewportId } = evt.detail; console.log(`【annotationmanager】🎨 图像渲染完成: ${viewportId}`); // TODO: 确保注释正确显示 }; private handleAnnotationCompleted = (evt: any) => { console.log('🎯 监听到注释完成事件:', evt); console.log('📋 事件详情:', evt.detail); const { annotation, toolName } = evt.detail; console.log(`【annotationmanager】✏️ 注释创建完成: ${toolName}`); // 确保有活动的图像ID if (!this.activeImageId) { console.warn('【annotationmanager】没有活动的图像ID,跳过注释保存'); return; } // 实现注释保存逻辑 this.saveAnnotation(annotation, toolName); }; private handleAnnotationAdded = (evt: any) => { console.log('【annotationmanager】🎯 监听到注释添加事件:', evt); console.log('【annotationmanager】📋 事件详情:', evt.detail); const { annotation } = evt.detail; const toolName = annotation.metadata?.toolName; console.log(`【annotationmanager】➕ 注释添加: ${toolName}`); // 确保有活动的图像ID if (!this.activeImageId) { console.warn('【annotationmanager】没有活动的图像ID,跳过注释保存'); return; } // 实现注释保存逻辑 this.saveAnnotation(annotation, toolName); }; private handleAnnotationModified = (evt: any) => { console.log('🎯 监听到注释修改事件:', evt); console.log('📋 事件详情:', evt.detail); const { annotation, toolName } = evt.detail; console.log(`【annotationmanager】🔄 注释修改完成: ${toolName}`); // 确保有活动的图像ID if (!this.activeImageId) { console.warn('【annotationmanager】没有活动的图像ID,跳过注释更新'); return; } // 实现注释更新逻辑 this.updateAnnotation(annotation, toolName); }; private handleAnnotationRemoved = (evt: any) => { console.log('🎯 监听到注释删除事件:', evt); console.log('📋 事件详情:', evt.detail); const { annotation } = evt.detail; const annotationUID = annotation.annotationUID; console.log(`【annotationmanager】🗑️ 注释删除完成: ${annotationUID}`); // 确保有活动的图像ID if (!this.activeImageId) { console.warn('【annotationmanager】没有活动的图像ID,跳过注释删除'); return; } // 实现注释删除逻辑 this.deleteAnnotation(annotation); }; // ============ 注释操作方法 ============ private async loadAnnotationsForImage(imageId: string): Promise { if (this.isLoading) { console.log(`【annotationmanager】注释正在加载中,跳过: ${imageId}`); return; } this.isLoading = true; this.activeImageId = imageId; try { console.log(`【annotationmanager】📥 加载注释数据: ${imageId}`); // 调用API获取注释数据 const response = await annotationAPI.getAnnotations(imageId); if (response.data && Array.isArray(response.data)) { const annotationStrings = response.data; // 验证注释数据 // this.validator.validateAnnotationArray(annotationStrings); // 反序列化并渲染注释 await this.renderAnnotations(annotationStrings); console.log(`【annotationmanager】✅ 注释加载完成: ${imageId} (${annotationStrings.length} 个注释)`); } else { console.log(`【annotationmanager】ℹ️ 图像 ${imageId} 没有注释数据`); } } catch (error) { console.error(`【annotationmanager】❌ 注释加载失败 ${imageId}:`, error); // 不抛出错误,让应用继续运行 } finally { this.isLoading = false; } } private async saveAnnotation(annotation: any, toolName: string): Promise { try { console.log(`【annotationmanager】💾 保存注释: ${toolName}`); // 序列化注释数据 const serializedData = this.serializer.serialize(annotation, toolName); // 验证序列化数据 // this.validator.validateAnnotationData(serializedData); // 添加到待保存队列(延迟保存) this.scheduleSave(serializedData); console.log(`【annotationmanager】✅ 注释保存任务已安排: ${toolName}`); } catch (error) { console.error(`【annotationmanager】❌ 注释保存失败 ${toolName}:`, error); } } private async updateAnnotation(annotation: any, toolName: string): Promise { try { console.log(`【annotationmanager】🔄 更新注释: ${toolName}`); // 复用保存逻辑 await this.saveAnnotation(annotation, toolName); console.log(`【annotationmanager】✅ 注释更新完成: ${toolName}`); } catch (error) { console.error(`【annotationmanager】❌ 注释更新失败 ${toolName}:`, error); } } private async deleteAnnotation(annotation: any): Promise { try { const annotationUID = annotation.annotationUID; console.log(`【annotationmanager】🗑️ 删除注释: ${annotationUID}`); if (!this.activeImageId) { console.warn('【annotationmanager】没有活动的图像ID,跳过删除操作'); return; } // 从 annotation 中获取 FrameOfReferenceUID const forUID = annotation.metadata?.referencedImageId; if (!forUID) { console.warn('【annotationmanager】FrameOfReferenceUID 未找到,跳过删除操作'); return; } // 用 FrameOfReferenceUID 查找相关的 elements const elements = this.findElementsByFOR(forUID); // 收集删除后的所有注释 const allAnnotationStrings: string[] = []; elements.forEach(element => { const anns = corAnnotation.state.getAnnotations('', element); if (anns) { // 序列化所有注释 for (const [toolName, ann] of Object.entries(anns as any)) { try { const serialized = this.serializer.serialize(ann, toolName); allAnnotationStrings.push(serialized); } catch (error) { console.error('序列化注释失败:', error); // 跳过序列化失败的注释 } } } }); // 保存所有注释 await annotationAPI.saveAnnotations(this.activeImageId, allAnnotationStrings); console.log(`【annotationmanager】✅ 注释删除完成: ${annotationUID} (剩余 ${allAnnotationStrings.length} 个注释)`); } catch (error) { console.error(`【annotationmanager】❌ 注释删除失败:`, error); } } // 用 FrameOfReferenceUID 查找 viewport elements private findElementsByFOR(imageId: string): any[] { const elements: any[] = []; if (!!getRenderingEngines) { const renderingEngines = getRenderingEngines(); renderingEngines?.forEach((re: IRenderingEngine) => { re.getViewports().forEach((vp: IStackViewport) => { if (vp && vp.hasImageId(imageId) === true && vp.element) { elements.push(vp.element); } }); }); } else { console.warn('【annotationmanager】getRenderingEngines 方法不可用,无法查找元素'); } return elements; } private async renderAnnotations(annotationStrings: string[]): Promise { console.log(`【annotationmanager】🎨 渲染 ${annotationStrings.length} 个注释`); for (const annotationString of annotationStrings) { try { // 反序列化为Cornerstone格式 const deserializedAnnotation = this.serializer.deserialize(annotationString); // 添加到Cornerstone注释状态 corAnnotation.state.addAnnotation(deserializedAnnotation, deserializedAnnotation.metadata?.toolName || 'UnknownTool'); console.log(`【annotationmanager】✅ 注释渲染成功`); } catch (error) { console.error(`【annotationmanager】❌ 注释渲染失败:`, error); // 继续处理其他注释 } } } // ============ 延迟保存机制 ============ /** * 安排延迟保存 */ private scheduleSave(annotationString: string): void { try { // 从JSON字符串中提取ID作为key const annotation = JSON.parse(annotationString); const key = annotation.annotationUID || annotation.id || `temp_${Date.now()}`; // 添加到待保存队列 this.pendingChanges.set(key, annotationString); // 取消之前的延迟保存 if (this.saveTimeout) { clearTimeout(this.saveTimeout); } // 设置新的延迟保存(1秒后) this.saveTimeout = setTimeout(() => { this.performBulkSave(); }, 1000); } catch (error) { console.error('安排保存时解析注释失败:', error); } } /** * 执行批量保存 */ private async performBulkSave(): Promise { if (this.pendingChanges.size === 0 || !this.activeImageId) { return; } const changes = Array.from(this.pendingChanges.values()); this.pendingChanges.clear(); try { console.log(`【annotationmanager】💾 批量保存 ${changes.length} 个注释`); // 调用API保存注释 await annotationAPI.saveAnnotations(this.activeImageId, changes); console.log(`【annotationmanager】✅ 批量保存成功: ${changes.length} 个注释`); } catch (error) { console.error(`【annotationmanager】❌ 批量保存失败:`, error); // 保存失败时,重新加入待保存队列 changes.forEach(change => { try { const annotation = JSON.parse(change); const key = annotation.annotationUID || annotation.id || `temp_${Date.now()}`; this.pendingChanges.set(key, change); } catch (error) { console.error('重新加入待保存队列时解析失败:', error); } }); // 可以在这里实现重试逻辑 } } }