"use client";
import React, { useMemo, useState } from "react";
import {
Box,
Collapse,
LinearProgress,
Stack,
Typography,
alpha,
useTheme,
} from "@mui/material";
import AutoAwesome from "@mui/icons-material/AutoAwesome";
import CheckCircleRounded from "@mui/icons-material/CheckCircleRounded";
import ErrorOutlineRounded from "@mui/icons-material/ErrorOutlineRounded";
import ManageSearchRounded from "@mui/icons-material/ManageSearchRounded";
import BuildCircleRounded from "@mui/icons-material/BuildCircleRounded";
import TaskAltRounded from "@mui/icons-material/TaskAltRounded";
import PsychologyRounded from "@mui/icons-material/PsychologyRounded";
import SyncRounded from "@mui/icons-material/SyncRounded";
import KeyboardArrowDownRounded from "@mui/icons-material/KeyboardArrowDownRounded";
import type { ChatProgress } from "./GlobalChatbox.types";
const phaseIcon = (phase: string, status: ChatProgress["status"]) => {
const sx = { fontSize: 16 };
if (status === "completed") return ;
if (status === "error") return ;
if (phase === "planning") return ;
if (phase === "tool") return ;
if (phase === "complete") return ;
if (phase === "session") return ;
if (phase === "start") return ;
return ;
};
const formatToolTitle = (item: ChatProgress) => {
const text = `${item.title} ${item.detail ?? ""}`;
if (text.includes("dynamic_http_call")) return "查询后端数据";
if (text.includes("show_chart")) return "生成图表";
if (text.includes("locate_features")) return "地图定位";
if (text.includes("view_history")) return "打开历史曲线";
if (text.includes("view_scada")) return "打开 SCADA 面板";
return item.title;
};
export const AgentProgressTimeline = ({ progress, isAborted }: { progress: ChatProgress[], isAborted?: boolean }) => {
const theme = useTheme();
// 判断是否最终完成(哪怕中间有报错,只要有完整的标记就算成功)
const isOverallComplete = progress.some(
(item) => item.phase === "complete" && item.status === "completed",
);
// 修正状态判断:如果外部标记为中断,或者没有完成标记
const hasRunning = !isAborted && !isOverallComplete && progress.some((item) => item.status === "running");
const hasError = isAborted || progress.some((item) => item.status === "error");
// 展开状态逻辑:默认折叠,保持界面整洁
const [expanded, setExpanded] = useState(false);
const summary = useMemo(() => {
if (isAborted) return `已中断 (进行到第 ${progress.length} 步)`;
if (isOverallComplete) {
return hasError ? `已完成 (含 ${progress.length} 步探索)` : `已完成 (${progress.length} 步)`;
}
const runningItem = [...progress].reverse().find((item) => item.status === "running");
if (runningItem) return `${runningItem.title}...`;
if (hasError) return "过程异常,尝试恢复中...";
return `已执行 ${progress.length} 步`;
}, [isOverallComplete, hasError, progress, isAborted]);
// 根据整体状态决定顶部卡片的颜色主题
const statusColor = isOverallComplete
? "#4caf50" // Success Green
: isAborted || (hasError && !hasRunning)
? theme.palette.error.main // Error Red
: "#00acc1"; // Primary Cyan
// 默认折叠:只显示最新的三条
const visibleCount = 3;
const isCollapsible = progress.length > visibleCount;
return (
setExpanded(!expanded)}
sx={{
px: 2,
py: 1.25,
cursor: "pointer",
userSelect: "none"
}}
>
{isOverallComplete ? (
) : hasRunning ? (
) : hasError ? (
) : (
)}
Agent 过程: {summary}
{hasRunning && !expanded ? (
) : null}
{hasRunning ? (
) : (
)}
{progress.map((item, index) => {
const isLast = index === progress.length - 1;
const isHiddenWhenCollapsed = isCollapsible && index < progress.length - visibleCount;
const itemColor = isAborted && isLast
? theme.palette.error.main
: item.status === "error"
? theme.palette.error.main
: item.status === "completed"
? "#4caf50"
: "#00acc1";
const content = (
{!isLast ? (
) : null}
{phaseIcon(
item.phase,
isAborted && isLast ? "error" :
isOverallComplete && item.status === "running"
? "completed"
: item.status,
)}
{item.phase === "tool" ? formatToolTitle(item) : item.title}
{item.detail && (
{item.detail}
)}
);
if (isHiddenWhenCollapsed) {
return (
{content}
);
}
return content;
})}
);
};