优化路径,添加消息推送

This commit is contained in:
2026-04-17 12:14:57 +08:00
parent b8a842367b
commit 0da5936ce0
34 changed files with 2472 additions and 435 deletions
+113
View File
@@ -0,0 +1,113 @@
import { PanelShell } from "@/components/panel-shell";
import { getCaregiverActivity } from "@/lib/caregiver-panel";
import {
formatDateTime,
getConversationRoleLabel,
getDeviceName,
getUsageLabel,
truncateText,
} from "@/lib/panel-format";
import { requireCaregiverSession } from "@/lib/page-auth";
export const dynamic = "force-dynamic";
export default async function ActivityPage() {
const caregiver = await requireCaregiverSession("/activity");
const { usageEvents, conversationTurns, toolCalls } = await getCaregiverActivity(
caregiver.id,
);
return (
<PanelShell
currentPath="/activity"
title="活动记录独立成页,回看陪伴过程更清楚。"
description="这里专门收下老人端的使用事件、最近对话片段和工具调用,不再和留言流混排。"
caregiverToken={caregiver.sessionToken}
>
{usageEvents.length === 0 && conversationTurns.length === 0 && toolCalls.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>
</section>
) : (
<section className="grid gap-6 xl:grid-cols-3">
<div 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>
<h2 className="mt-2 font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
老人端操作轨迹
</h2>
<div className="mt-5 space-y-3">
{usageEvents.map((event) => (
<div key={event.id} className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
<div className="flex items-center justify-between gap-3 text-xs text-[var(--muted)]">
<span>{getDeviceName(event.elderDevice.displayName)}</span>
<span>{formatDateTime(event.createdAt)}</span>
</div>
<p className="mt-2 text-sm leading-7 text-[var(--ink)]">
{getUsageLabel(event.eventType)}
</p>
</div>
))}
</div>
</div>
<div 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>
<h2 className="mt-2 font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
最近说了什么
</h2>
<div className="mt-5 space-y-3">
{conversationTurns.map((turn) => (
<div key={turn.id} className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
<div className="flex items-center justify-between gap-3 text-xs text-[var(--muted)]">
<span>{getConversationRoleLabel(turn.role)}</span>
<span>{formatDateTime(turn.createdAt)}</span>
</div>
<p className="mt-2 text-xs text-[var(--muted)]">
{getDeviceName(turn.elderDevice.displayName)}
</p>
<p className="mt-2 text-sm leading-7 text-[var(--ink)]">
{truncateText(turn.content, 132)}
</p>
</div>
))}
</div>
</div>
<div 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>
<h2 className="mt-2 font-[family-name:var(--font-display)] text-3xl text-[var(--ink)]">
function calling 执行记录
</h2>
<div className="mt-5 space-y-3">
{toolCalls.map((log) => (
<div key={log.id} className="rounded-[24px] bg-[var(--paper-soft)] px-5 py-4">
<div className="flex items-center justify-between gap-3 text-xs text-[var(--muted)]">
<span>{getDeviceName(log.elderDevice.displayName)}</span>
<span>{formatDateTime(log.createdAt)}</span>
</div>
<p className="mt-2 text-sm font-semibold text-[var(--ink)]">
{log.toolName}
</p>
<p className="mt-2 text-sm leading-7 text-[var(--muted)]">
{truncateText(log.outputText || log.argumentsJson, 136)}
</p>
</div>
))}
</div>
</div>
</section>
)}
</PanelShell>
);
}