From a9821ab8325702847fb43862b358ee42ffbc4113 Mon Sep 17 00:00:00 2001 From: iven Date: Thu, 7 May 2026 07:38:04 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20=E5=91=8A=E8=AD=A6=E8=AF=A6?= =?UTF-8?q?=E6=83=85=E9=9D=A2=E6=9D=BF=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C?= =?UTF-8?q?=E6=94=B9=E8=BF=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 用 Alert 横幅醒目展示严重程度、标题和行动指引 - 患者信息卡片显示姓名而非原始 UUID - 将 JSON 详情解析为中文标签(告警描述/监测值/阈值等) - 技术信息(原始 ID)移入折叠面板 --- .../health/components/AlertDetailPanel.tsx | 306 ++++++++++++------ 1 file changed, 199 insertions(+), 107 deletions(-) diff --git a/apps/web/src/pages/health/components/AlertDetailPanel.tsx b/apps/web/src/pages/health/components/AlertDetailPanel.tsx index a995eb8..1f693fd 100644 --- a/apps/web/src/pages/health/components/AlertDetailPanel.tsx +++ b/apps/web/src/pages/health/components/AlertDetailPanel.tsx @@ -1,18 +1,21 @@ -import { Descriptions, Tag, Typography, Space, Button, Popconfirm, Tooltip } from 'antd'; +import { Descriptions, Tag, Typography, Space, Button, Popconfirm, Tooltip, Collapse, Alert as AntAlert } from 'antd'; import { CheckOutlined, StopOutlined, SafetyCertificateOutlined, ClockCircleOutlined, ExclamationCircleOutlined, + UserOutlined, + CodeOutlined, + MedicineBoxOutlined, } from '@ant-design/icons'; import type { Alert } from '../../../api/health/alerts'; -const SEVERITY_CONFIG: Record = { - info: { color: 'default', label: '提示', icon: }, - warning: { color: 'orange', label: '警告', icon: }, - critical: { color: 'red', label: '严重', icon: }, - urgent: { color: 'magenta', label: '紧急', icon: }, +const SEVERITY_CONFIG: Record = { + info: { color: 'default', label: '提示', icon: , bannerType: 'info' }, + warning: { color: 'orange', label: '警告', icon: , bannerType: 'warning' }, + critical: { color: 'red', label: '严重', icon: , bannerType: 'error' }, + urgent: { color: 'magenta', label: '紧急', icon: , bannerType: 'error' }, }; const STATUS_CONFIG: Record = { @@ -23,17 +26,56 @@ const STATUS_CONFIG: Record = { dismissed: { color: 'default', label: '已忽略' }, }; +const SEVERITY_GUIDANCE: Record = { + info: '请关注患者状态变化,必要时进行随访。', + warning: '建议尽快确认并安排相关检查或随访。', + critical: '需要立即关注!请确认告警并安排紧急处理。', + urgent: '紧急状况!请立即确认并采取干预措施。', +}; + +const DETAIL_LABEL_MAP: Record = { + message: '告警描述', + value: '监测值', + threshold: '阈值', + unit: '单位', + metric: '指标', + metric_name: '指标名称', + indicator_type: '体征类型', + recorded_at: '记录时间', + patient_name: '患者', + blood_pressure_systolic: '收缩压', + blood_pressure_diastolic: '舒张压', + heart_rate: '心率', + blood_glucose: '血糖', + temperature: '体温', + spo2: '血氧饱和度', +}; + +function formatDetailValue(key: string, value: unknown): string { + if (value === null || value === undefined) return '-'; + if (typeof value === 'string') { + if (key.endsWith('_at') || key === 'recorded_at') { + try { return new Date(value).toLocaleString('zh-CN'); } catch { return value; } + } + return value; + } + if (typeof value === 'number') return String(value); + if (typeof value === 'boolean') return value ? '是' : '否'; + return JSON.stringify(value); +} + +function getDetailLabel(key: string): string { + return DETAIL_LABEL_MAP[key] ?? key; +} + interface AlertDetailPanelProps { alert: Alert; onAcknowledge?: (id: string, version: number) => Promise; - onDismiss?: (id: string, version: number) => Promise; + onDismiss?: (id: string, version: number, reason?: string) => Promise; onResolve?: (id: string, version: number) => Promise; loading?: boolean; } -/** - * 告警详情面板 — 展示告警完整信息及操作按钮。 - */ export function AlertDetailPanel({ alert, onAcknowledge, @@ -46,124 +88,174 @@ export function AlertDetailPanel({ const isPending = alert.status === 'pending' || alert.status === 'active'; const isAcknowledged = alert.status === 'acknowledged'; + const detailEntries = alert.detail + ? Object.entries(alert.detail).filter(([, v]) => v !== null && v !== undefined) + : []; + + const detailMessage = alert.detail?.message as string | undefined; + return (
- {/* 顶部摘要 */} -
- - - {severity.label} - - {status.label} + {/* 严重程度提示 */} + + {alert.title || severity.label} + {status.label} + + } + description={SEVERITY_GUIDANCE[alert.severity] ?? '请关注此告警并及时处理。'} + /> + + {/* 患者信息 */} +
+ + + + + {alert.patient_name || '未知患者'} + + + + (ID: {alert.patient_id.slice(0, 8)}...) + + + - {new Date(alert.created_at).toLocaleString('zh-CN')} + 告警时间:{new Date(alert.created_at).toLocaleString('zh-CN')}
- {/* 详情 */} - - - {alert.id} - - - {alert.patient_id} - - - {alert.rule_id} - - - {severity.label} - - - {status.label} - - {alert.acknowledged_by && ( - - {alert.acknowledged_by} - - )} - {alert.acknowledged_at && ( - - {new Date(alert.acknowledged_at).toLocaleString('zh-CN')} - - )} - {alert.resolved_at && ( - - {new Date(alert.resolved_at).toLocaleString('zh-CN')} - - )} - - - {/* 告警详情 JSON */} - {alert.detail && ( -
- 告警详情: -
 0 && (
+        
+ + + 告警详情 + +
- {JSON.stringify(alert.detail, null, 2)} -
+ {detailMessage && ( + 1 ? 8 : 0 }}> + {detailMessage} + + )} + k !== 'message') + .map(([key, value]) => ({ + key, + label: getDetailLabel(key), + children: {formatDetailValue(key, value)}, + })) + } + /> +
)} + {/* 处理记录 */} + {(alert.acknowledged_by || alert.resolved_at) && ( + + {alert.acknowledged_by && ( + + {alert.acknowledged_by} + + )} + {alert.acknowledged_at && ( + + + {new Date(alert.acknowledged_at).toLocaleString('zh-CN')} + + + )} + {alert.resolved_at && ( + + + {new Date(alert.resolved_at).toLocaleString('zh-CN')} + + + )} + + )} + + {/* 技术信息(折叠) */} + 技术信息, + children: ( + + + {alert.id} + + + {alert.rule_id} + + + {alert.patient_id} + + {alert.version} + + ), + }]} + /> + {/* 操作按钮 */} -
+
{isPending && onAcknowledge && ( - - onAcknowledge(alert.id, alert.version)} - > - - - + onAcknowledge(alert.id, alert.version)} + > + + )} {isPending && onDismiss && ( - - onDismiss(alert.id, alert.version)} - > - - - + onDismiss(alert.id, alert.version)} + > + + )} {(isPending || isAcknowledged) && onResolve && ( - - onResolve(alert.id, alert.version)} - > - - - + onResolve(alert.id, alert.version)} + > + + )}