全新UI语言
This commit is contained in:
@@ -3,119 +3,35 @@ import { notFound } from "next/navigation";
|
||||
|
||||
import { PanelShell } from "@/components/panel-shell";
|
||||
import { getCaregiverMessageDetail } from "@/lib/caregiver-panel";
|
||||
import {
|
||||
formatDateTime,
|
||||
getDeviceName,
|
||||
getImportanceLabel,
|
||||
getMessageDirectionLabel,
|
||||
getMessageStatusLabel,
|
||||
} from "@/lib/panel-format";
|
||||
import { formatDateTime, getDeviceName, getMessageDirectionLabel, getMessageStatusLabel } from "@/lib/panel-format";
|
||||
import { requireCaregiverSession } from "@/lib/page-auth";
|
||||
import { getCaregiverDisplayName } from "@/lib/session";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
type MessageDetailPageProps = {
|
||||
params: Promise<{ messageId: string }>;
|
||||
};
|
||||
|
||||
export default async function MessageDetailPage({ params }: MessageDetailPageProps) {
|
||||
const { messageId } = await params;
|
||||
const publicId = Number.parseInt(messageId, 10);
|
||||
|
||||
if (!Number.isFinite(publicId) || publicId <= 0) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
export default async function MessageDetailPage({ params }: PageProps<"/messages/[messageId]">) {
|
||||
const publicId = Number.parseInt((await params).messageId, 10);
|
||||
if (!Number.isFinite(publicId) || publicId <= 0) notFound();
|
||||
const caregiver = await requireCaregiverSession(`/messages/${publicId}`);
|
||||
const message = await getCaregiverMessageDetail(caregiver.id, publicId);
|
||||
|
||||
if (!message) {
|
||||
notFound();
|
||||
}
|
||||
if (!message) notFound();
|
||||
|
||||
return (
|
||||
<PanelShell
|
||||
currentPath="/messages"
|
||||
title={`留言 #${message.publicId}`}
|
||||
description="查看这条留言的完整内容和设备信息。"
|
||||
caregiverLabel={getCaregiverDisplayName(caregiver)}
|
||||
>
|
||||
<section className="grid gap-6 xl:grid-cols-[1.2fr_0.8fr]">
|
||||
<article className="rounded-[32px] border border-white/75 bg-white/82 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]">
|
||||
<div className="flex flex-wrap items-center gap-2 text-sm text-[var(--muted)]">
|
||||
<span className="rounded-full bg-[var(--paper-soft)] px-3 py-1 font-semibold text-[var(--ink)]">
|
||||
#{message.publicId}
|
||||
</span>
|
||||
<span className="rounded-full bg-[var(--paper-soft)] px-3 py-1">
|
||||
{getMessageDirectionLabel(message.direction)}
|
||||
</span>
|
||||
<span className="rounded-full bg-[var(--paper-soft)] px-3 py-1">
|
||||
{getImportanceLabel(message.importance)}
|
||||
</span>
|
||||
<span className="rounded-full bg-[var(--paper-soft)] px-3 py-1">
|
||||
{getMessageStatusLabel(message)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h2 className="mt-5 font-[family-name:var(--font-display)] text-4xl leading-[1.2] text-[var(--ink)]">
|
||||
{message.content}
|
||||
</h2>
|
||||
|
||||
{message.recipientRelation ? (
|
||||
<p className="mt-4 text-sm leading-7 text-[var(--muted)]">
|
||||
目标对象:{message.recipientRelation}
|
||||
</p>
|
||||
) : null}
|
||||
</article>
|
||||
|
||||
<aside className="rounded-[32px] border border-white/75 bg-white/82 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]">
|
||||
<p className="text-sm font-medium tracking-[0.18em] text-[var(--copper)] uppercase">
|
||||
设备信息
|
||||
</p>
|
||||
<div className="mt-5 space-y-4 text-sm leading-7 text-[var(--muted)]">
|
||||
<div className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
|
||||
<p>所属设备</p>
|
||||
<p className="mt-2 font-semibold text-[var(--ink)]">
|
||||
{getDeviceName(message.elderDevice.displayName)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
|
||||
<p>设备标识</p>
|
||||
<p className="mt-2 break-all font-semibold text-[var(--ink)]">
|
||||
{message.elderDevice.deviceUuid}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
|
||||
<p>创建时间</p>
|
||||
<p className="mt-2 font-semibold text-[var(--ink)]">
|
||||
{formatDateTime(message.createdAt)}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
|
||||
<p>最近在线</p>
|
||||
<p className="mt-2 font-semibold text-[var(--ink)]">
|
||||
{formatDateTime(message.elderDevice.lastSeenAt)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex flex-wrap gap-3">
|
||||
<Link
|
||||
href="/messages"
|
||||
className="inline-flex h-12 items-center justify-center rounded-full bg-[var(--copper)] px-5 text-sm font-semibold text-white transition hover:bg-[var(--copper-deep)]"
|
||||
>
|
||||
返回留言板
|
||||
</Link>
|
||||
<Link
|
||||
href={`/devices/${message.elderDevice.deviceUuid}`}
|
||||
className="inline-flex h-12 items-center justify-center rounded-full border border-[var(--line)] bg-white px-5 text-sm font-semibold text-[var(--ink)] transition hover:bg-[var(--paper-soft)]"
|
||||
>
|
||||
查看设备
|
||||
</Link>
|
||||
</div>
|
||||
</aside>
|
||||
<PanelShell currentPath="/messages" title={`留言 #${message.publicId}`} caregiverLabel={getCaregiverDisplayName(caregiver)} backHref="/messages">
|
||||
<article className="card card-pad" style={{ paddingTop: 16, paddingBottom: 16 }}>
|
||||
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
|
||||
<span className="tag" style={{ color: "var(--muted)", background: "rgba(32,29,26,.06)" }}>{getMessageDirectionLabel(message.direction)}</span>
|
||||
{message.importance !== "NORMAL" ? <span className="tag">重要</span> : null}
|
||||
<span className="tag" style={{ color: "var(--muted)", background: "rgba(32,29,26,.06)" }}>{getMessageStatusLabel(message)}</span>
|
||||
</div>
|
||||
<p style={{ margin: "12px 0 0", fontSize: 17, lineHeight: 1.65 }}>{message.content}</p>
|
||||
</article>
|
||||
<section className="card">
|
||||
<div className="list-row"><span style={{ color: "var(--muted)" }}>所属设备</span><strong style={{ marginLeft: "auto", fontSize: 13 }}>{getDeviceName(message.elderDevice.displayName)}</strong></div>
|
||||
<div className="list-row"><span style={{ color: "var(--muted)" }}>时间</span><strong style={{ marginLeft: "auto", fontSize: 13 }}>{formatDateTime(message.createdAt)}</strong></div>
|
||||
<div className="list-row"><span style={{ color: "var(--muted)" }}>送达方式</span><strong style={{ marginLeft: "auto", fontSize: 13 }}>数字人口播</strong></div>
|
||||
</section>
|
||||
<Link href={`/devices/${message.elderDevice.deviceUuid}`} className="btn primary block">回一句问候</Link>
|
||||
</PanelShell>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+28
-130
@@ -1,145 +1,43 @@
|
||||
import Link from "next/link";
|
||||
import { PenLine } from "lucide-react";
|
||||
|
||||
import { PanelShell } from "@/components/panel-shell";
|
||||
import { getCaregiverMessages } from "@/lib/caregiver-panel";
|
||||
import {
|
||||
formatDateTime,
|
||||
getDeviceName,
|
||||
getImportanceLabel,
|
||||
getMessageDirectionLabel,
|
||||
getMessageHref,
|
||||
getMessageStatusLabel,
|
||||
truncateText,
|
||||
} from "@/lib/panel-format";
|
||||
import { formatDateTime, getDeviceName, getMessageHref, getMessageStatusLabel, truncateText } from "@/lib/panel-format";
|
||||
import { requireCaregiverSession } from "@/lib/page-auth";
|
||||
import { getCaregiverDisplayName } from "@/lib/session";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function MessagesPage() {
|
||||
export default async function MessagesPage({ searchParams }: PageProps<"/messages">) {
|
||||
const caregiver = await requireCaregiverSession("/messages");
|
||||
const { messages, unreadIncomingCount, unreadOutgoingCount } =
|
||||
await getCaregiverMessages(caregiver.id);
|
||||
|
||||
const incomingMessages = messages.filter(
|
||||
(message) => message.direction === "ELDER_TO_FAMILY",
|
||||
);
|
||||
const outgoingMessages = messages.filter(
|
||||
(message) => message.direction === "FAMILY_TO_ELDER",
|
||||
);
|
||||
const { messages, unreadIncomingCount } = await getCaregiverMessages(caregiver.id);
|
||||
const filter = (await searchParams).filter === "out" ? "out" : "in";
|
||||
const items = messages.filter((m) => filter === "in" ? m.direction === "ELDER_TO_FAMILY" : m.direction === "FAMILY_TO_ELDER");
|
||||
|
||||
return (
|
||||
<PanelShell
|
||||
currentPath="/messages"
|
||||
title="留言板"
|
||||
description="长辈捆来的话和您发出的问候,都在这里。"
|
||||
caregiverLabel={getCaregiverDisplayName(caregiver)}
|
||||
>
|
||||
<section className="grid gap-4 md:grid-cols-3">
|
||||
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5">
|
||||
<p className="text-sm text-[var(--muted)]">全部留言</p>
|
||||
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
||||
{messages.length}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5">
|
||||
<p className="text-sm text-[var(--muted)]">长辈的未读留言</p>
|
||||
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
||||
{unreadIncomingCount}
|
||||
</p>
|
||||
</div>
|
||||
<div className="rounded-[28px] border border-white/80 bg-white/88 p-5">
|
||||
<p className="text-sm text-[var(--muted)]">待长辈查看</p>
|
||||
<p className="mt-3 font-[family-name:var(--font-display)] text-4xl text-[var(--ink)]">
|
||||
{unreadOutgoingCount}
|
||||
</p>
|
||||
</div>
|
||||
<PanelShell currentPath="/messages" title="留言板" caregiverLabel={getCaregiverDisplayName(caregiver)} unreadCount={unreadIncomingCount}
|
||||
actions={<Link href="/devices" className="btn primary small"><PenLine size={14}/>写留言</Link>}>
|
||||
<div className="segment">
|
||||
<Link href="/messages?filter=in" className={filter === "in" ? "active" : ""}>收到 · {unreadIncomingCount} 未读</Link>
|
||||
<Link href="/messages?filter=out" className={filter === "out" ? "active" : ""}>发出</Link>
|
||||
</div>
|
||||
<section className="card">
|
||||
{items.length ? items.map((message) => (
|
||||
<Link key={message.id} href={getMessageHref(message.publicId)} className="list-row">
|
||||
<span className="dot" style={{ background: message.readAt ? "transparent" : "var(--accent)" }} />
|
||||
<span className="row-main">
|
||||
<span className="row-meta" style={{ marginTop: 0 }}>
|
||||
<strong style={{ color: "var(--ink-soft)" }}>{getDeviceName(message.elderDevice.displayName)}</strong>
|
||||
{message.importance !== "NORMAL" ? <span className="tag">重要</span> : null}
|
||||
<span style={{ marginLeft: "auto", color: "var(--muted-light)" }}>{formatDateTime(message.createdAt)}</span>
|
||||
</span>
|
||||
<span className="row-title" style={{ marginTop: 4, fontWeight: message.readAt ? 400 : 600 }}>{truncateText(message.content, 82)}</span>
|
||||
<span className="row-meta">#{message.publicId} · {getMessageStatusLabel(message)}</span>
|
||||
</span>
|
||||
</Link>
|
||||
)) : <div className="empty">这一侧暂时还没有留言。</div>}
|
||||
</section>
|
||||
|
||||
{messages.length === 0 ? (
|
||||
<section className="rounded-[32px] border border-dashed border-[var(--line)] bg-white/72 px-6 py-10 text-center shadow-[0_20px_50px_rgba(115,76,42,0.10)]">
|
||||
<h2 className="font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
|
||||
还没有留言
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-base leading-8 text-[var(--muted)]">
|
||||
连接长辈的设备后,就可以在这里查看长辈的留言,也可以给长辈写问候。
|
||||
</p>
|
||||
<div className="mt-6 flex justify-center gap-3">
|
||||
<Link
|
||||
href="/devices"
|
||||
className="inline-flex h-12 items-center justify-center rounded-full bg-[var(--copper)] px-5 text-sm font-semibold text-white transition hover:bg-[var(--copper-deep)]"
|
||||
>
|
||||
连接设备
|
||||
</Link>
|
||||
<Link
|
||||
href="/scan"
|
||||
className="inline-flex h-12 items-center justify-center rounded-full border border-[var(--line)] bg-white px-5 text-sm font-semibold text-[var(--ink)] transition hover:bg-[var(--paper-soft)]"
|
||||
>
|
||||
扫码连接
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
) : (
|
||||
<section className="grid gap-6 xl:grid-cols-2">
|
||||
{[
|
||||
{
|
||||
title: "长辈的留言",
|
||||
subtitle: "长辈通过智能助理捆来的话。",
|
||||
items: incomingMessages,
|
||||
},
|
||||
{
|
||||
title: "我发出的问候",
|
||||
subtitle: "您写给长辈的每一条问候。",
|
||||
items: outgoingMessages,
|
||||
},
|
||||
].map((section) => (
|
||||
<div
|
||||
key={section.title}
|
||||
className="rounded-[32px] border border-white/75 bg-white/80 p-6 shadow-[0_26px_60px_rgba(115,76,42,0.12)]"
|
||||
>
|
||||
<p className="text-sm font-medium tracking-[0.18em] text-[var(--copper)] uppercase">
|
||||
{section.title === "长辈的留言" ? "收到的" : "发出的"}
|
||||
</p>
|
||||
<h2 className="mt-2 font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
|
||||
{section.title}
|
||||
</h2>
|
||||
<p className="mt-3 text-sm leading-7 text-[var(--muted)]">{section.subtitle}</p>
|
||||
|
||||
<div className="mt-5 space-y-3">
|
||||
{section.items.length === 0 ? (
|
||||
<p className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 text-sm leading-7 text-[var(--muted)]">
|
||||
这一侧暂时还没有留言。
|
||||
</p>
|
||||
) : (
|
||||
section.items.map((message) => (
|
||||
<Link
|
||||
key={message.id}
|
||||
href={getMessageHref(message.publicId)}
|
||||
className="block rounded-[24px] bg-[var(--paper-soft)] px-5 py-4 transition hover:bg-white"
|
||||
>
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs text-[var(--muted)]">
|
||||
<span className="rounded-full bg-white px-3 py-1 font-semibold text-[var(--ink)]">
|
||||
#{message.publicId}
|
||||
</span>
|
||||
<span>{getMessageDirectionLabel(message.direction)}</span>
|
||||
<span>{getDeviceName(message.elderDevice.displayName)}</span>
|
||||
<span>{getImportanceLabel(message.importance)}</span>
|
||||
<span>{getMessageStatusLabel(message)}</span>
|
||||
</div>
|
||||
<p className="mt-3 text-sm leading-7 text-[var(--ink)]">
|
||||
{truncateText(message.content, 112)}
|
||||
</p>
|
||||
<p className="mt-3 text-xs text-[var(--muted)]">
|
||||
创建于 {formatDateTime(message.createdAt)}
|
||||
</p>
|
||||
</Link>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
)}
|
||||
</PanelShell>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user