- 新增告警列表页:按状态筛选、分页、严重程度/状态标签 - 新增告警详情页:完整信息展示 + 确认/忽略/恢复操作 - doctor.ts 新增 listAlerts/acknowledgeAlert/dismissAlert/resolveAlert API - DoctorHome 告警 banner 跳转目标改为告警列表页 - 注册 alerts/index + alerts/detail/index 到 doctor subPackage
211 lines
6.9 KiB
TypeScript
211 lines
6.9 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { View, Text, ScrollView, Button } from '@tarojs/components';
|
|
import Taro from '@tarojs/taro';
|
|
import * as doctorApi from '@/services/doctor';
|
|
import Loading from '@/components/Loading';
|
|
import './index.scss';
|
|
|
|
const SEVERITY_MAP: Record<string, { label: string; className: string }> = {
|
|
info: { label: '提示', className: 'detail-severity--info' },
|
|
warning: { label: '警告', className: 'detail-severity--warning' },
|
|
critical: { label: '严重', className: 'detail-severity--critical' },
|
|
urgent: { label: '紧急', className: 'detail-severity--urgent' },
|
|
};
|
|
|
|
const STATUS_MAP: Record<string, { label: string; className: string }> = {
|
|
pending: { label: '待处理', className: 'detail-status--pending' },
|
|
acknowledged: { label: '已确认', className: 'detail-status--acknowledged' },
|
|
resolved: { label: '已恢复', className: 'detail-status--resolved' },
|
|
dismissed: { label: '已忽略', className: 'detail-status--dismissed' },
|
|
};
|
|
|
|
export default function AlertDetail() {
|
|
const [alert, setAlert] = useState<doctorApi.Alert | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [actionLoading, setActionLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const params = Taro.getCurrentInstance().router?.params;
|
|
if (params?.id) {
|
|
loadAlert(params.id);
|
|
}
|
|
}, []);
|
|
|
|
const loadAlert = async (id: string) => {
|
|
try {
|
|
// 告警列表 API 支持按 ID 查询,此处用列表加载后过滤
|
|
const res = await doctorApi.listAlerts({ page: 1, page_size: 100 });
|
|
const found = (res.data || []).find((a) => a.id === id);
|
|
if (found) {
|
|
setAlert(found);
|
|
} else {
|
|
Taro.showToast({ title: '告警不存在', icon: 'none' });
|
|
}
|
|
} catch {
|
|
Taro.showToast({ title: '加载失败', icon: 'none' });
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleAcknowledge = async () => {
|
|
if (!alert) return;
|
|
setActionLoading(true);
|
|
try {
|
|
const updated = await doctorApi.acknowledgeAlert(alert.id, alert.version);
|
|
setAlert(updated);
|
|
Taro.showToast({ title: '已确认', icon: 'success' });
|
|
} catch {
|
|
Taro.showToast({ title: '操作失败', icon: 'none' });
|
|
} finally {
|
|
setActionLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleDismiss = async () => {
|
|
if (!alert) return;
|
|
setActionLoading(true);
|
|
try {
|
|
const updated = await doctorApi.dismissAlert(alert.id, alert.version);
|
|
setAlert(updated);
|
|
Taro.showToast({ title: '已忽略', icon: 'success' });
|
|
} catch {
|
|
Taro.showToast({ title: '操作失败', icon: 'none' });
|
|
} finally {
|
|
setActionLoading(false);
|
|
}
|
|
};
|
|
|
|
const handleResolve = async () => {
|
|
if (!alert) return;
|
|
setActionLoading(true);
|
|
try {
|
|
const updated = await doctorApi.resolveAlert(alert.id, alert.version);
|
|
setAlert(updated);
|
|
Taro.showToast({ title: '已恢复', icon: 'success' });
|
|
} catch {
|
|
Taro.showToast({ title: '操作失败', icon: 'none' });
|
|
} finally {
|
|
setActionLoading(false);
|
|
}
|
|
};
|
|
|
|
if (loading) return <Loading />;
|
|
if (!alert) {
|
|
return (
|
|
<View className='alert-detail-page'>
|
|
<Text>告警不存在</Text>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const severity = SEVERITY_MAP[alert.severity] ?? SEVERITY_MAP.info;
|
|
const status = STATUS_MAP[alert.status] ?? STATUS_MAP.pending;
|
|
const isPending = alert.status === 'pending';
|
|
const isAcknowledged = alert.status === 'acknowledged';
|
|
|
|
return (
|
|
<ScrollView scrollY className='alert-detail-page'>
|
|
{/* 顶部状态 */}
|
|
<View className='alert-detail-header'>
|
|
<View className='alert-detail-header__tags'>
|
|
<Text className={`detail-severity ${severity.className}`}>
|
|
{severity.label}
|
|
</Text>
|
|
<Text className={`detail-status ${status.className}`}>
|
|
{status.label}
|
|
</Text>
|
|
</View>
|
|
<Text className='alert-detail-header__time'>
|
|
{new Date(alert.created_at).toLocaleString('zh-CN')}
|
|
</Text>
|
|
</View>
|
|
|
|
{/* 告警信息 */}
|
|
<View className='alert-detail-card'>
|
|
<Text className='alert-detail-card__label'>告警标题</Text>
|
|
<Text className='alert-detail-card__value'>{alert.title}</Text>
|
|
</View>
|
|
|
|
<View className='alert-detail-card'>
|
|
<Text className='alert-detail-card__label'>患者 ID</Text>
|
|
<Text className='alert-detail-card__value alert-detail-card__value--id'>
|
|
{alert.patient_id.slice(0, 8)}...
|
|
</Text>
|
|
</View>
|
|
|
|
<View className='alert-detail-card'>
|
|
<Text className='alert-detail-card__label'>严重程度</Text>
|
|
<Text className='alert-detail-card__value'>{severity.label}</Text>
|
|
</View>
|
|
|
|
{alert.detail && (
|
|
<View className='alert-detail-card'>
|
|
<Text className='alert-detail-card__label'>告警详情</Text>
|
|
<Text className='alert-detail-card__value alert-detail-card__value--detail'>
|
|
{JSON.stringify(alert.detail, null, 2)}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
|
|
{alert.acknowledged_by && (
|
|
<View className='alert-detail-card'>
|
|
<Text className='alert-detail-card__label'>处理人</Text>
|
|
<Text className='alert-detail-card__value'>{alert.acknowledged_by}</Text>
|
|
</View>
|
|
)}
|
|
|
|
{alert.acknowledged_at && (
|
|
<View className='alert-detail-card'>
|
|
<Text className='alert-detail-card__label'>确认时间</Text>
|
|
<Text className='alert-detail-card__value'>
|
|
{new Date(alert.acknowledged_at).toLocaleString('zh-CN')}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
|
|
{alert.resolved_at && (
|
|
<View className='alert-detail-card'>
|
|
<Text className='alert-detail-card__label'>恢复时间</Text>
|
|
<Text className='alert-detail-card__value'>
|
|
{new Date(alert.resolved_at).toLocaleString('zh-CN')}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
|
|
{/* 操作按钮 */}
|
|
{(isPending || isAcknowledged) && (
|
|
<View className='alert-detail-actions'>
|
|
{isPending && (
|
|
<>
|
|
<Button
|
|
className='alert-action-btn alert-action-btn--primary'
|
|
onClick={handleAcknowledge}
|
|
disabled={actionLoading}
|
|
>
|
|
确认
|
|
</Button>
|
|
<Button
|
|
className='alert-action-btn alert-action-btn--default'
|
|
onClick={handleDismiss}
|
|
disabled={actionLoading}
|
|
>
|
|
忽略
|
|
</Button>
|
|
</>
|
|
)}
|
|
{(isPending || isAcknowledged) && (
|
|
<Button
|
|
className='alert-action-btn alert-action-btn--resolve'
|
|
onClick={handleResolve}
|
|
disabled={actionLoading}
|
|
>
|
|
恢复
|
|
</Button>
|
|
)}
|
|
</View>
|
|
)}
|
|
</ScrollView>
|
|
);
|
|
}
|