家庭动态:老人/家属发言、三种可见范围,家庭内部内容不会播给老人。 共同照护:家庭备忘录、任务创建、认领、完成与交接记录。 用药闭环:计划、未来 7 天提醒实例、确认服用、延后、异常反馈。 风险闭环:红橙黄蓝分级、30 分钟去重、推送、认领、处理与误报记录。 报平安:家属发起、老人语音回应、状态同步。 Web 导航升级为守护、家庭、照护、陪伴、我的。 设备接口已升级为设备令牌认证,UUID 不再单独承担认证。
24 lines
3.5 KiB
TypeScript
24 lines
3.5 KiB
TypeScript
import { AlertTriangle, CheckCircle2, HeartPulse, PhoneCall } from "lucide-react";
|
||
import { AlertActions, CheckInButton } from "@/components/family-guard-actions";
|
||
import { PanelShell } from "@/components/panel-shell";
|
||
import { requireFamilyWorkspace } from "@/lib/family-page";
|
||
import { formatDateTime } from "@/lib/panel-format";
|
||
import { requireCaregiverSession } from "@/lib/page-auth";
|
||
import { getCaregiverDisplayName } from "@/lib/session";
|
||
|
||
export const dynamic = "force-dynamic";
|
||
export default async function GuardPage() {
|
||
const caregiver = await requireCaregiverSession("/guard"); const workspace = await requireFamilyWorkspace(caregiver.id);
|
||
const openAlerts = workspace.alerts.filter((a) => a.status === "OPEN" || a.status === "ACKNOWLEDGED");
|
||
const todayDoses = workspace.medicationPlans.flatMap((p) => p.doses).filter((d) => d.scheduledFor.toDateString() === new Date().toDateString());
|
||
const doneDoses = todayDoses.filter((d) => d.status === "TAKEN").length;
|
||
const openTasks = workspace.tasks.filter((t) => t.status !== "COMPLETED" && t.status !== "CANCELLED");
|
||
const pendingCheckIns = workspace.checkIns.filter((c) => c.status === "PENDING");
|
||
return <PanelShell currentPath="/guard" title="家庭守护" description={`${workspace.elderProfile.preferredName} · 风险线索不是医疗诊断`} caregiverLabel={getCaregiverDisplayName(caregiver)}>
|
||
<section className="stats" style={{ gridTemplateColumns: "repeat(4,1fr)" }}><div className="stat accent"><strong>{openAlerts.length}</strong><span>待处理提醒</span></div><div className="stat"><strong>{doneDoses}/{todayDoses.length}</strong><span>今日用药</span></div><div className="stat"><strong>{openTasks.length}</strong><span>照护事项</span></div><div className="stat"><strong>{pendingCheckIns.length}</strong><span>待报平安</span></div></section>
|
||
<CheckInButton deviceUuid={workspace.elderProfile.elderDevice.deviceUuid} />
|
||
<section><div className="section-title"><h2>风险提醒</h2><span>人工确认后再处置</span></div><div className="card">{workspace.alerts.length ? workspace.alerts.map((alert) => <article id={`alert-${alert.id}`} key={alert.id} className="timeline-item"><div className="timeline-top"><span style={{ color: alert.level === "RED" ? "#b33a2b" : "var(--accent)" }}><AlertTriangle size={15} style={{ verticalAlign: -3, marginRight: 5 }} />{alert.title}</span><span className="timeline-time">{formatDateTime(alert.createdAt)}</span></div><p className="timeline-body">{alert.summary}</p><p className="row-meta">{alert.claimedBy ? `已由 ${alert.claimedBy.nickname || alert.claimedBy.username || "家人"} 接手` : "尚未认领"}</p><AlertActions alertId={alert.id} status={alert.status} /></article>) : <div className="empty"><CheckCircle2 size={26} /><br />当前没有待处理的风险提醒</div>}</div></section>
|
||
<section><div className="section-title"><h2>今日状态</h2></div><div className="card"><div className="timeline-item"><div className="timeline-top"><HeartPulse size={15} />设备最近在线<span className="timeline-time">{formatDateTime(workspace.elderProfile.elderDevice.lastSeenAt)}</span></div><p className="timeline-body">仅根据终端在线和主动交互记录展示,不代表生命体征状态。</p></div><div className="timeline-item"><div className="timeline-top"><PhoneCall size={15} />家庭值守</div><p className="timeline-body">{workspace.memberships.filter((m) => m.emergencyPush).map((m) => m.caregiver.nickname || m.caregiver.username || "家人").join("、") || "尚未设置"}</p></div></div></section>
|
||
</PanelShell>;
|
||
}
|