Files
deerflow-code/frontend-web/src/report-collaboration/components/ReportSpeakerShell.tsx
T
2026-09-05 11:28:25 +08:00

61 lines
1.8 KiB
TypeScript

"use client";
import type { ReactNode } from "react";
import { desensitize } from "@/lib/desensitize";
import { cn } from "@/lib/utils";
import { getAvatar } from "@/roundtable-planning/components/Avatars";
import { MessageBubble } from "@/roundtable-planning/components/MessageBubble";
import type { ReportSpeaker } from "@/report-collaboration/state/speaker";
interface ReportSpeakerShellProps {
speaker: ReportSpeaker;
onAvatarClick?: (agentRunId: string) => void;
avatarSelected?: boolean;
children: ReactNode;
}
/**
* 会商第二步气泡壳:头像 + 席位名 + 正文(步骤条 / 思考 / 输出仍走 MessageList)。
*/
export function ReportSpeakerShell({
speaker,
onAvatarClick,
avatarSelected = false,
children,
}: ReportSpeakerShellProps) {
const avatarInner = getAvatar(speaker.avatarType, "h-9 w-9 shrink-0");
const canFilter = Boolean(speaker.agentRunId && onAvatarClick);
const avatar = canFilter ? (
<button
type="button"
onClick={() => onAvatarClick?.(speaker.agentRunId!)}
aria-pressed={avatarSelected}
title={
avatarSelected
? "取消筛选,显示全部发言"
: `只看 ${desensitize(speaker.name)} 的发言`
}
className={cn(
"shrink-0 cursor-pointer rounded-full transition hover:opacity-80 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/60",
avatarSelected && "ring-2 ring-primary ring-offset-1 ring-offset-white",
)}
>
{avatarInner}
</button>
) : (
avatarInner
);
return (
<MessageBubble
avatar={avatar}
senderName={speaker.name}
badge={speaker.role && speaker.role !== speaker.name ? speaker.role : undefined}
time={speaker.time}
>
{children}
</MessageBubble>
);
}