118 lines
3.8 KiB
TypeScript
118 lines
3.8 KiB
TypeScript
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<string, unknown> | 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 }
|
|
}
|