import Link from "next/link"; import { Activity, AlertTriangle, BedDouble, CheckCircle2, HeartPulse, ListChecks, Users } from "lucide-react"; import type { LucideIcon } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Table } from "@/components/ui/table"; import type { AdmissionStatus, BedStatus, IncidentSeverity } from "@/modules/core/types"; import type { CareTaskPriority, CareTaskStatus } from "@/modules/care/types"; import { CARE_TASK_PRIORITY_LABELS, CARE_TASK_STATUS_LABELS } from "@/modules/care/types"; import { BedOccupancyChart, type BedOccupancyDatum } from "@/modules/dashboard/components/BedOccupancyChart"; import { INCIDENT_SEVERITY_LABELS, INCIDENT_STATUS_LABELS } from "@/modules/emergency/types"; import type { HealthReviewSeverity, HealthReviewStatus } from "@/modules/health/types"; import { HEALTH_REVIEW_SEVERITY_LABELS, HEALTH_REVIEW_STATUS_LABELS } from "@/modules/health/types"; export type DashboardMetric = { label: string; value: string; trend: string; icon: "admissions" | "beds" | "care" | "health" | "incidents" | "users"; }; export type DashboardAdmission = { id: string; elderName: string; bedLabel: string; status: AdmissionStatus; admittedAt: string; dischargedAt?: string; }; export type DashboardIncident = { id: string; severity: IncidentSeverity; status: string; title: string; source: string; createdAt: string; }; export type DashboardCareTask = { id: string; assigneeLabel: string; elderName: string; priority: CareTaskPriority; scheduledAt: string; status: CareTaskStatus; title: string; }; export type DashboardHealthReview = { id: string; elderName: string; severity: HealthReviewSeverity; status: HealthReviewStatus; title: string; }; type DashboardHomeProps = { bedsHref: string; careHref: string; careTasks: DashboardCareTask[]; emergencyHref: string; emergencyIncidents: DashboardIncident[]; healthHref: string; healthReviews: DashboardHealthReview[]; metrics: DashboardMetric[]; occupancyData: BedOccupancyDatum[]; recentAdmissions: DashboardAdmission[]; incidents: DashboardIncident[]; }; const metricIcons: Record = { admissions: CheckCircle2, beds: BedDouble, care: ListChecks, health: HeartPulse, incidents: HeartPulse, users: Users, }; const admissionStatusLabels: Record = { active: "在住", transferred: "已换床", discharged: "已退住", }; const bedStatusLabels: Record = { available: "空闲", occupied: "占用", maintenance: "维修", disabled: "停用", }; function formatDateTime(value: string): string { return new Date(value).toLocaleString("zh-CN"); } function incidentVariant(severity: IncidentSeverity): "secondary" | "warning" | "danger" { switch (severity) { case "critical": return "danger"; case "warning": return "warning"; case "info": return "secondary"; } } export function DashboardHome({ bedsHref, careHref, careTasks, emergencyHref, emergencyIncidents, healthHref, healthReviews, metrics, occupancyData, recentAdmissions, incidents, }: DashboardHomeProps): React.ReactElement { return (

运营看板

老人、床位、护理、健康和应急事件概况。

{metrics.map((metric) => { const Icon = metricIcons[metric.icon]; return ( {metric.label} {metric.value}

{metric.trend}

); })}
({ id: task.id, title: task.title, detail: `${task.elderName || "公共区域"} / ${task.assigneeLabel || "未分配"} / ${formatDateTime(task.scheduledAt)}`, badge: CARE_TASK_STATUS_LABELS[task.status], variant: task.priority === "urgent" ? "danger" : task.priority === "high" ? "warning" : "secondary", meta: CARE_TASK_PRIORITY_LABELS[task.priority], }))} title="护理待办" /> ({ id: review.id, title: review.title, detail: review.elderName, badge: HEALTH_REVIEW_STATUS_LABELS[review.status], variant: review.severity === "critical" ? "danger" : "warning", meta: HEALTH_REVIEW_SEVERITY_LABELS[review.severity], }))} title="健康复核" /> ({ id: incident.id, title: incident.title, detail: `${incident.source} / ${formatDateTime(incident.createdAt)}`, badge: INCIDENT_STATUS_LABELS[incident.status as keyof typeof INCIDENT_STATUS_LABELS], variant: incidentVariant(incident.severity), meta: INCIDENT_SEVERITY_LABELS[incident.severity], }))} title="安全应急" />
{occupancyData.map((item) => `${bedStatusLabels[item.label as BedStatus] ?? item.label} ${item.count}`).join(" / ")} 最近入住记录
老人 床位 状态 时间 {recentAdmissions.map((admission) => ( {admission.elderName} {admission.bedLabel} {admissionStatusLabels[admission.status]} {formatDateTime(admission.dischargedAt ?? admission.admittedAt)} ))} {recentAdmissions.length === 0 ? ( 暂无入住记录 ) : null}
未关闭故障 {incidents.map((incident) => (

{incident.source} / {formatDateTime(incident.createdAt)}

{incident.status}
))} {incidents.length === 0 ?

暂无未关闭故障

: null}
); } type QueueItem = { id: string; badge: string; detail: string; meta: string; title: string; variant: "danger" | "secondary" | "warning"; }; function QueueCard({ emptyText, href, items, title, }: { emptyText: string; href: string; items: QueueItem[]; title: string; }): React.ReactElement { return ( {title} 进入 {items.map((item) => (

{item.title}

{item.detail}

{item.meta} {item.badge}
))} {items.length === 0 ?

{emptyText}

: null}
); }