feat(web): IoT + FHIR V1 Plan 5 — Web 前端实施
- API 层: deviceReadings 日聚合查询 + OAuth 合作方 CRUD 接口 - 常量: 设备连接状态/连接类型/实时监控指标常量 - Hook: useVitalSSE — 复用全局 SSE 连接的 vital_update 事件 - 页面: RealtimeMonitor 实时体征监控台 (SSE + 告警排序) - 页面: OAuthClientList FHIR 合作方管理 (CRUD + Secret 重置) - 增强: DeviceManage 设备状态/固件/连接类型列 + 状态筛选 - 路由: 新增 3 个懒加载路由 - 测试: RealtimeMonitor + OAuthClientList 单元测试
This commit is contained in:
67
apps/web/src/hooks/useVitalSSE.ts
Normal file
67
apps/web/src/hooks/useVitalSSE.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { useAlertSSE, type VitalUpdateSSEEvent } from './useAlertSSE';
|
||||
|
||||
export type VitalUpdateEvent = VitalUpdateSSEEvent;
|
||||
|
||||
interface PatientVital {
|
||||
patient_id: string;
|
||||
device_type: string;
|
||||
latest_value?: number;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
interface UseVitalSSEOptions {
|
||||
enabled?: boolean;
|
||||
patientIds?: string[];
|
||||
onUpdate?: (data: VitalUpdateEvent) => void;
|
||||
}
|
||||
|
||||
interface UseVitalSSEReturn {
|
||||
connected: boolean;
|
||||
patientVitals: Map<string, PatientVital>;
|
||||
lastUpdate: VitalUpdateEvent | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实时体征 hook — 复用全局 SSE 连接的 vital_update 事件。
|
||||
*
|
||||
* 内部调用 useAlertSSE(共享 /messages/stream 连接),
|
||||
* 聚合患者最新体征数据到 Map。
|
||||
*/
|
||||
export function useVitalSSE(options: UseVitalSSEOptions = {}): UseVitalSSEReturn {
|
||||
const { enabled = true, patientIds, onUpdate } = options;
|
||||
const [patientVitals, setPatientVitals] = useState<Map<string, PatientVital>>(new Map());
|
||||
const [lastUpdate, setLastUpdate] = useState<VitalUpdateEvent | null>(null);
|
||||
|
||||
const handleVitalUpdate = useCallback(
|
||||
(data: VitalUpdateEvent) => {
|
||||
if (patientIds && patientIds.length > 0 && !patientIds.includes(data.patient_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setPatientVitals((prev) => {
|
||||
const next = new Map(prev);
|
||||
if (data.device_model) {
|
||||
const key = `${data.patient_id}_${data.device_model}`;
|
||||
next.set(key, {
|
||||
patient_id: data.patient_id,
|
||||
device_type: data.device_model,
|
||||
latest_value: data.count > 0 ? undefined : undefined,
|
||||
updated_at: data.occurred_at ?? new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
return next;
|
||||
});
|
||||
setLastUpdate(data);
|
||||
onUpdate?.(data);
|
||||
},
|
||||
[patientIds, onUpdate],
|
||||
);
|
||||
|
||||
const { connected } = useAlertSSE({
|
||||
enabled,
|
||||
onVitalUpdate: handleVitalUpdate,
|
||||
});
|
||||
|
||||
return { connected, patientVitals, lastUpdate };
|
||||
}
|
||||
Reference in New Issue
Block a user