'use client'; import Link from 'next/link'; import { useParams } from 'next/navigation'; import React from 'react'; import { ArrowLeft, ArrowRight, Boxes, FolderOutput, ListTree, MessageSquare, PanelRightOpen, Siren, Users, } from 'lucide-react'; import { OfficeStatusBadge, formatOfficeDuration, formatOfficeTime, progressPercent, } from '@/components/office/OfficeShared'; import { OfficePhaserCanvas } from '@/components/office/OfficePhaserCanvas'; import { TaskManagementTabs } from '@/components/task-management/TaskManagementTabs'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle, } from '@/components/ui/sheet'; import { ScrollArea } from '@/components/ui/scroll-area'; import { buildOfficeView, isOfficeTaskTerminal } from '@/lib/office'; import { useChatStore } from '@/lib/store'; function PixelPanel({ title, subtitle, children, icon: Icon, }: { title: string; subtitle?: string; children: React.ReactNode; icon?: React.ComponentType<{ className?: string }>; }) { return (
{Icon ? : null} {title}
{subtitle ? (
{subtitle}
) : null}
{children}
); } function BoardPanel({ icon: Icon, title, description, children, }: { icon: React.ComponentType<{ className?: string }>; title: string; description?: string; children: React.ReactNode; }) { return ( {title} {description ? {description} : null} {children} ); } export default function OfficeDetailPage() { const params = useParams<{ taskId: string }>(); const taskId = decodeURIComponent(Array.isArray(params?.taskId) ? params.taskId[0] : params?.taskId ?? ''); const sessions = useChatStore((state) => state.sessions); const processRuns = useChatStore((state) => state.processRuns); const processEvents = useChatStore((state) => state.processEvents); const processArtifacts = useChatStore((state) => state.processArtifacts); const office = React.useMemo( () => buildOfficeView(taskId, { sessions, processRuns, processEvents, processArtifacts }), [processArtifacts, processEvents, processRuns, sessions, taskId] ); const [selectedRunId, setSelectedRunId] = React.useState(null); const [detailOpen, setDetailOpen] = React.useState(false); React.useEffect(() => { setSelectedRunId(office?.rootRunId ?? null); setDetailOpen(false); }, [office?.rootRunId]); const selectedTask = React.useMemo( () => office?.tasks.find((task) => task.runId === selectedRunId) ?? office?.tasks[0] ?? null, [office?.tasks, selectedRunId] ); const selectedEvents = React.useMemo( () => processEvents .filter((event) => event.run_id === selectedTask?.runId) .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) .slice(0, 8), [processEvents, selectedTask?.runId] ); const selectedArtifacts = React.useMemo( () => processArtifacts .filter((artifact) => artifact.run_id === selectedTask?.runId) .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()), [processArtifacts, selectedTask?.runId] ); const openRunDetail = React.useCallback((runId: string) => { setSelectedRunId(runId); setDetailOpen(true); }, []); if (!office) { return (

任务不存在

当前 store 中没有这个 task 的运行数据。先从对话页发起任务,或者回到 Office 列表查看当前可用任务。

); } const progressValue = progressPercent(office.progress.value, office.progress.max); return (

{office.title}

Lead: {office.rootActorName} Session: {office.sourceSessionLabel} Started: {formatOfficeTime(office.createdAt)} Duration: {formatOfficeDuration(office.durationMs)}
{selectedTask?.summary || '当前选中任务没有摘要,先从右侧任务看板切一个具体 run 看现场。'}
{office.alerts.slice(0, 2).map((alert) => ( ))}
{office.progress.label} {progressValue}%
{selectedTask ? (
当前聚焦
{selectedTask.title}
{selectedTask.actorName} · {selectedTask.stageLabel ?? '无阶段标签'}
) : null}
{isOfficeTaskTerminal(office.status) ? (
任务已结束,办公室已解散,但现场记录仍可回看。
) : null}
{office.members.map((member) => ( ))}
{office.tasks.map((task) => ( ))}
{office.assignments.length === 0 ? (
当前没有可见的子任务分工。
) : ( office.assignments.map((assignment) => ( )) )}
{office.alerts.length === 0 ? (
当前没有高优先级告警。
) : ( office.alerts.map((alert) => ( )) )}
{selectedTask?.title ?? '任务详情'} {selectedTask ? `${selectedTask.actorName} · ${selectedTask.stageLabel ?? '无阶段标签'}` : '当前没有选中的任务实例。'} {!selectedTask ? (
当前没有可展示的任务详情。
) : (
{selectedTask.title}
{selectedTask.actorName}
开始时间 {formatOfficeTime(selectedTask.startedAt)}
最近更新 {formatOfficeTime(selectedTask.updatedAt)}
阶段 {selectedTask.stageLabel ?? '-'}
{selectedTask.summary ? (
{selectedTask.summary}
) : null}
产物
{selectedArtifacts.length === 0 ? (
当前没有产物。
) : ( selectedArtifacts.map((artifact) => (
{artifact.title}
{artifact.artifact_type} · {formatOfficeTime(artifact.created_at)}
)) )}
最近事件
{selectedEvents.length === 0 ? (
当前没有事件。
) : ( selectedEvents.map((event) => (
{event.kind}
{formatOfficeTime(event.created_at)}
{event.text || '结构化更新'}
)) )}
)}
); } function MetricTile({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); } function MiniMetric({ label, value }: { label: string; value: string }) { return (
{label}
{value}
); }