feat: add elder bed operational context
This commit is contained in:
@@ -12,8 +12,10 @@ import { Table } from "@/components/ui/table";
|
||||
import type { ApiResult } from "@/modules/core/server/api";
|
||||
import type { Admission, BedStatus, FacilityBed, Permission, Room } from "@/modules/core/types";
|
||||
import type { Elder } from "@/modules/elders/types";
|
||||
import type { BedOperationalContext, OperationalContextLine } from "@/modules/operations/types";
|
||||
|
||||
type BedsWorkspaceProps = {
|
||||
bedContexts?: Record<string, BedOperationalContext>;
|
||||
initialRooms: Room[];
|
||||
initialBeds: FacilityBed[];
|
||||
initialAdmissions: Admission[];
|
||||
@@ -23,6 +25,12 @@ type BedsWorkspaceProps = {
|
||||
|
||||
type WorkspaceTab = "overview" | "operations" | "history";
|
||||
|
||||
const workspaceTabs: Array<{ value: WorkspaceTab; label: string }> = [
|
||||
{ value: "overview", label: "概览" },
|
||||
{ value: "operations", label: "办理" },
|
||||
{ value: "history", label: "记录" },
|
||||
];
|
||||
|
||||
const bedStatusLabels: Record<BedStatus, string> = {
|
||||
available: "空闲",
|
||||
occupied: "占用",
|
||||
@@ -65,6 +73,7 @@ function makeSelectOptions(items: Array<{ id: string; label: string }>, emptyLab
|
||||
}
|
||||
|
||||
export function BedsWorkspace({
|
||||
bedContexts = {},
|
||||
initialRooms,
|
||||
initialBeds,
|
||||
initialAdmissions,
|
||||
@@ -246,22 +255,14 @@ export function BedsWorkspace({
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex w-full max-w-7xl flex-col gap-5">
|
||||
<section className="flex flex-col gap-4 border-b pb-5 lg:flex-row lg:items-end lg:justify-between">
|
||||
<div>
|
||||
<Badge variant="success">床位工作区</Badge>
|
||||
<h1 className="mt-3 text-3xl font-semibold tracking-normal">床位房间</h1>
|
||||
<p className="mt-2 text-sm text-muted-foreground">查看占用、办理入住、换床和退住。</p>
|
||||
</div>
|
||||
<section className="flex border-b pb-4">
|
||||
<div className="flex flex-wrap gap-2" role="tablist" aria-label="床位工作区">
|
||||
{[
|
||||
{ value: "overview", label: "概览" },
|
||||
{ value: "operations", label: "办理" },
|
||||
{ value: "history", label: "记录" },
|
||||
].map((tab) => (
|
||||
{workspaceTabs.map((tab) => (
|
||||
<Button
|
||||
aria-selected={activeTab === tab.value}
|
||||
key={tab.value}
|
||||
onClick={() => setActiveTab(tab.value as WorkspaceTab)}
|
||||
onClick={() => setActiveTab(tab.value)}
|
||||
role="tab"
|
||||
type="button"
|
||||
variant={activeTab === tab.value ? "default" : "outline"}
|
||||
>
|
||||
@@ -380,24 +381,33 @@ export function BedsWorkspace({
|
||||
<Table.Head className="px-4 py-3 font-medium">床位</Table.Head>
|
||||
<Table.Head className="px-4 py-3 font-medium">状态</Table.Head>
|
||||
<Table.Head className="px-4 py-3 font-medium">当前老人</Table.Head>
|
||||
<Table.Head className="px-4 py-3 font-medium">入住上下文</Table.Head>
|
||||
<Table.Head className="px-4 py-3 font-medium">备注</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body className="divide-y bg-card">
|
||||
{beds.map((bed) => (
|
||||
<Table.Row key={bed.id}>
|
||||
<Table.Cell className="px-4 py-3">{bed.roomName}</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3 font-medium">{bed.code}</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3">
|
||||
<Badge variant={bedBadgeVariant(bed.status)}>{bedStatusLabels[bed.status]}</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3">{bed.currentElderName ?? "-"}</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3 text-muted-foreground">{bed.notes || "-"}</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
{beds.map((bed) => {
|
||||
const context = bedContexts[bed.id];
|
||||
return (
|
||||
<Table.Row key={bed.id}>
|
||||
<Table.Cell className="px-4 py-3">{bed.roomName}</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3 font-medium">{bed.code}</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3">
|
||||
<Badge variant={bedBadgeVariant(bed.status)}>{bedStatusLabels[bed.status]}</Badge>
|
||||
</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3">
|
||||
<OccupantSummary context={context} fallbackName={bed.currentElderName} />
|
||||
</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3">
|
||||
<ContextLines lines={context?.lines ?? []} />
|
||||
</Table.Cell>
|
||||
<Table.Cell className="px-4 py-3 text-muted-foreground">{bed.notes || "-"}</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
})}
|
||||
{beds.length === 0 ? (
|
||||
<Table.Row>
|
||||
<Table.Cell className="px-4 py-8 text-center text-muted-foreground" colSpan={5}>
|
||||
<Table.Cell className="px-4 py-8 text-center text-muted-foreground" colSpan={6}>
|
||||
暂无床位主数据
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
@@ -576,3 +586,50 @@ export function BedsWorkspace({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function contextToneClass(tone: OperationalContextLine["tone"]): string {
|
||||
if (tone === "danger") {
|
||||
return "text-destructive";
|
||||
}
|
||||
if (tone === "warning") {
|
||||
return "text-amber-700";
|
||||
}
|
||||
return "text-muted-foreground";
|
||||
}
|
||||
|
||||
function ContextLines({ lines }: { lines: OperationalContextLine[] }): React.ReactElement {
|
||||
if (lines.length === 0) {
|
||||
return <span className="text-muted-foreground">-</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid gap-1">
|
||||
{lines.map((line) => (
|
||||
<p className={`max-w-[260px] truncate text-xs ${contextToneClass(line.tone)}`} key={`${line.kind}-${line.label}-${line.value}`}>
|
||||
<span className="font-medium">{line.label}</span> {line.value}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function OccupantSummary({
|
||||
context,
|
||||
fallbackName,
|
||||
}: {
|
||||
context: BedOperationalContext | undefined;
|
||||
fallbackName: string | undefined;
|
||||
}): React.ReactElement {
|
||||
if (!context?.occupant) {
|
||||
return <span className="text-muted-foreground">{fallbackName ?? "-"}</span>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p className="font-medium">{context.occupant.elderName}</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{context.occupant.careLevel} / {context.occupant.status}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user