Agent 初版设计

This commit is contained in:
2026-04-29 17:15:49 +08:00
parent 2c1afdc97c
commit e5ca9e24aa
13 changed files with 1819 additions and 1255 deletions
+158
View File
@@ -0,0 +1,158 @@
"use client";
import React from "react";
import { motion } from "framer-motion";
import {
Avatar,
Box,
IconButton,
ListItemIcon,
ListItemText,
Menu,
MenuItem,
Stack,
Typography,
alpha,
useTheme,
} from "@mui/material";
import AutoAwesome from "@mui/icons-material/AutoAwesome";
import AddCommentRounded from "@mui/icons-material/AddCommentRounded";
import CloseRounded from "@mui/icons-material/CloseRounded";
type AgentHeaderProps = {
isStreaming: boolean;
menuAnchorEl: HTMLElement | null;
onMenuOpen: (event: React.MouseEvent<HTMLElement>) => void;
onMenuClose: () => void;
onNewConversation: () => void;
onClose: () => void;
};
export const AgentHeader = ({
isStreaming,
menuAnchorEl,
onMenuOpen,
onMenuClose,
onNewConversation,
onClose,
}: AgentHeaderProps) => {
const theme = useTheme();
const isMenuOpen = Boolean(menuAnchorEl);
return (
<Box
sx={{
px: 3,
py: 2.5,
zIndex: 10,
display: "flex",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Stack direction="row" alignItems="center" spacing={2}>
<motion.div whileHover={{ rotate: 10, scale: 1.08 }} whileTap={{ scale: 0.95 }}>
<IconButton
onClick={onMenuOpen}
aria-label="打开 Agent 菜单"
aria-controls={isMenuOpen ? "global-chatbox-header-menu" : undefined}
aria-expanded={isMenuOpen ? "true" : undefined}
aria-haspopup="menu"
sx={{ p: 0, borderRadius: "50%" }}
>
<Box sx={{ position: "relative" }}>
<Avatar
sx={{
background: `linear-gradient(135deg, ${theme.palette.primary.light}, ${theme.palette.primary.main})`,
boxShadow: `0 8px 20px ${alpha(theme.palette.primary.main, 0.4)}`,
width: 48,
height: 48,
}}
>
<AutoAwesome fontSize="medium" sx={{ color: "#fff" }} />
</Avatar>
<Box
sx={{
position: "absolute",
bottom: 2,
right: 2,
width: 12,
height: 12,
bgcolor: isStreaming ? "warning.main" : "success.main",
borderRadius: "50%",
border: "2px solid #fff",
}}
/>
</Box>
</IconButton>
</motion.div>
<Box>
<Typography
variant="h6"
fontWeight={900}
sx={{
background: `linear-gradient(90deg, ${theme.palette.primary.dark}, ${theme.palette.secondary.dark})`,
backgroundClip: "text",
color: "transparent",
letterSpacing: -0.5,
}}
>
TJWater Agent
</Typography>
<Typography variant="caption" color="text.secondary" fontWeight={600}>
{isStreaming ? "正在分析管网任务" : "管网分析工作台"}
</Typography>
</Box>
</Stack>
<Menu
id="global-chatbox-header-menu"
anchorEl={menuAnchorEl}
open={isMenuOpen}
onClose={onMenuClose}
anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
transformOrigin={{ vertical: "top", horizontal: "left" }}
slotProps={{
paper: {
elevation: 8,
sx: {
mt: 1,
minWidth: 180,
borderRadius: 3,
border: `1px solid ${alpha(theme.palette.divider, 0.12)}`,
backdropFilter: "blur(12px)",
bgcolor: alpha("#fff", 0.92),
},
},
}}
>
<MenuItem onClick={onNewConversation}>
<ListItemIcon>
<AddCommentRounded fontSize="small" />
</ListItemIcon>
<ListItemText
primary="新建对话"
secondary="清空当前会话"
primaryTypographyProps={{ sx: { fontSize: "0.95rem", fontWeight: 700 } }}
secondaryTypographyProps={{ sx: { fontSize: "0.8rem" } }}
/>
</MenuItem>
</Menu>
<motion.div whileHover={{ scale: 1.08, rotate: 90 }} whileTap={{ scale: 0.92 }}>
<IconButton
onClick={onClose}
size="small"
aria-label="关闭 Agent"
sx={{
color: "text.primary",
bgcolor: alpha("#fff", 0.54),
"&:hover": { bgcolor: "#fff" },
}}
>
<CloseRounded />
</IconButton>
</motion.div>
</Box>
);
};