feat(web): DoctorDashboard 集成告警摘要卡片
在医生工作台新增待处理告警摘要区域,展示最近 5 条 pending 状态告警,点击「查看全部」跳转告警仪表盘。
This commit is contained in:
@@ -1,18 +1,38 @@
|
||||
import { Row, Col, Card, Statistic, List, Tag, Spin, Typography, Flex } from 'antd';
|
||||
import { Row, Col, Card, Statistic, List, Tag, Spin, Typography, Flex, Space, Button } from 'antd';
|
||||
import {
|
||||
TeamOutlined,
|
||||
MessageOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
MedicineBoxOutlined,
|
||||
ArrowUpOutlined,
|
||||
AlertOutlined,
|
||||
RightOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { pointsApi, type PersonalStats } from '../../../api/health/points';
|
||||
import { alertApi, type Alert } from '../../../api/health/alerts';
|
||||
import { useStatsData } from './useStatsData';
|
||||
import { useCountUp } from '../../../hooks/useCountUp';
|
||||
|
||||
const SEVERITY_COLOR: Record<string, string> = {
|
||||
info: 'default',
|
||||
warning: 'orange',
|
||||
critical: 'red',
|
||||
urgent: 'magenta',
|
||||
};
|
||||
|
||||
const SEVERITY_LABEL: Record<string, string> = {
|
||||
info: '提示',
|
||||
warning: '警告',
|
||||
critical: '严重',
|
||||
urgent: '紧急',
|
||||
};
|
||||
|
||||
export function DoctorDashboard() {
|
||||
const navigate = useNavigate();
|
||||
const [personal, setPersonal] = useState<PersonalStats | null>(null);
|
||||
const [recentAlerts, setRecentAlerts] = useState<Alert[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { consultationStats } = useStatsData();
|
||||
const myPatientsCount = useCountUp(personal?.my_patients ?? 0);
|
||||
@@ -29,11 +49,21 @@ export function DoctorDashboard() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => { fetchPersonal(); }, [fetchPersonal]);
|
||||
const fetchRecentAlerts = useCallback(async () => {
|
||||
try {
|
||||
const result = await alertApi.list({ status: 'pending', page: 1, page_size: 5 });
|
||||
setRecentAlerts(result.data);
|
||||
} catch {
|
||||
// 静默降级
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => { fetchPersonal(); fetchRecentAlerts(); }, [fetchPersonal, fetchRecentAlerts]);
|
||||
|
||||
if (loading && !personal) return <Spin size="large" style={{ display: 'block', margin: '80px auto' }} />;
|
||||
|
||||
const p = personal;
|
||||
const pendingAlertCount = recentAlerts.length;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -63,6 +93,50 @@ export function DoctorDashboard() {
|
||||
</Col>
|
||||
)}
|
||||
|
||||
{/* 告警摘要卡片 */}
|
||||
{pendingAlertCount > 0 && (
|
||||
<Col span={24}>
|
||||
<Card
|
||||
size="small"
|
||||
style={{ borderLeft: '4px solid #fa8c16' }}
|
||||
title={
|
||||
<Space>
|
||||
<AlertOutlined style={{ color: '#fa8c16' }} />
|
||||
<span>{pendingAlertCount} 条待处理告警</span>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
<Button
|
||||
type="link"
|
||||
size="small"
|
||||
icon={<RightOutlined />}
|
||||
onClick={() => navigate('/health/alert-dashboard')}
|
||||
>
|
||||
查看全部
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<List
|
||||
size="small"
|
||||
dataSource={recentAlerts}
|
||||
renderItem={(alert) => (
|
||||
<List.Item style={{ padding: '4px 0' }}>
|
||||
<Space>
|
||||
<Tag color={SEVERITY_COLOR[alert.severity]} style={{ margin: 0 }}>
|
||||
{SEVERITY_LABEL[alert.severity] ?? alert.severity}
|
||||
</Tag>
|
||||
<Typography.Text style={{ fontSize: 13 }}>{alert.title}</Typography.Text>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12 }}>
|
||||
{new Date(alert.created_at).toLocaleString('zh-CN')}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
|
||||
{/* 统计卡片 */}
|
||||
<Col xs={12} sm={6}>
|
||||
<Card size="small">
|
||||
|
||||
Reference in New Issue
Block a user