import { onBeforeUnmount, onMounted } from 'vue' import { useProjectionStream, type StreamEvent } from './useProjectionStream' /** * 编辑器 / 监控页对 SimpleLite SSE 的事件订阅封装,把以下 5 类事件转给业务回调: * * - `alarm` (来自 AlarmStreamService):报警新增/更新/解除 * - `object-created` (来自 MapEditApiController):对象创建后 * - `object-deleted` (来自 MapEditApiController):对象删除后 * - `object-patched` (来自 MapEditApiController):对象字段被 patch 后 * - `object-batch-changed`(来自 batch / ai 调用):一组对象变化,建议直接整页重拉 * - `pick-result` (来自 /pick):拾取会话完成 * * 业务页只用关心自己感兴趣的事件回调,其它走默认忽略。 */ export interface AlarmEvent { action: 'raise' | 'update' | 'clear' carId: number carName: string info?: string x?: number y?: number timestamp: string } export interface ObjectChangeEvent { kind: string id: number typeName?: string source?: string } export interface PickResultEvent { x: number y: number siteId: number } export interface SelectionDetailEvent { /** 主选中 kind (site|track|car|null);当多选时取首个非空集合的 kind。 */ kind: 'site' | 'track' | 'car' | null /** 主选中 id;多选时取首个。 */ id: number siteIds: number[] trackIds: number[] carIds: number[] /** 完整对象名列表,例如 ["UISite-12", "UITrack-7", "Car-3"]。 */ names: string[] } export interface WorkspaceShortcutEvent { action: 'undo' | 'redo' | 'delete' | 'copy' | 'paste' | 'duplicate' } export interface MapEditStreamHandlers { onAlarm?: (e: AlarmEvent) => void onObjectCreated?: (e: ObjectChangeEvent) => void onObjectDeleted?: (e: ObjectChangeEvent) => void onObjectPatched?: (e: ObjectChangeEvent) => void onObjectBatchChanged?: (e: { count: number; source?: string }) => void onPickResult?: (e: PickResultEvent) => void onSelectionDetail?: (e: SelectionDetailEvent) => void /** iframe 画布聚焦时由 SimpleLite 经 SSE 转发的撤销/重做/删除。 */ onWorkspaceShortcut?: (e: WorkspaceShortcutEvent) => void /** 视口样式(站点/路径 Painter)在 Web 或桌面对话框中变更后广播。 */ onViewportStyleUpdated?: () => void } export function useMapEditStream(handlers: MapEditStreamHandlers) { const stream = useProjectionStream({ autoConnect: false }) function dispatch(ev: StreamEvent) { const payload = ev?.payload as Record | undefined if (!payload) return switch (ev.kind) { case 'alarm': handlers.onAlarm?.(payload as unknown as AlarmEvent) break case 'object-created': handlers.onObjectCreated?.(payload as unknown as ObjectChangeEvent) break case 'object-deleted': handlers.onObjectDeleted?.(payload as unknown as ObjectChangeEvent) break case 'object-patched': handlers.onObjectPatched?.(payload as unknown as ObjectChangeEvent) break case 'object-batch-changed': handlers.onObjectBatchChanged?.(payload as unknown as { count: number; source?: string }) break case 'pick-result': handlers.onPickResult?.(payload as unknown as PickResultEvent) break case 'selection-detail': handlers.onSelectionDetail?.(payload as unknown as SelectionDetailEvent) break case 'workspace-shortcut': handlers.onWorkspaceShortcut?.(payload as unknown as WorkspaceShortcutEvent) break case 'viewport-style-updated': handlers.onViewportStyleUpdated?.() break } } onMounted(() => { stream.on(dispatch) stream.connect() }) onBeforeUnmount(() => { stream.off(dispatch) stream.disconnect() }) return { connected: stream.connected } }