"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; })} ); };