重构聊天会话管理,支持会话历史和存储
This commit is contained in:
+120
-107
@@ -7,37 +7,32 @@ import {
|
||||
Avatar,
|
||||
Box,
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Stack,
|
||||
Tooltip,
|
||||
Typography,
|
||||
alpha,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import AddCommentRounded from "@mui/icons-material/AddCommentRounded";
|
||||
import EditNoteRounded from "@mui/icons-material/EditNoteRounded";
|
||||
import CloseRounded from "@mui/icons-material/CloseRounded";
|
||||
import HistoryRounded from "@mui/icons-material/HistoryRounded";
|
||||
|
||||
type AgentHeaderProps = {
|
||||
isStreaming: boolean;
|
||||
menuAnchorEl: HTMLElement | null;
|
||||
onMenuOpen: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
onMenuClose: () => void;
|
||||
isHistoryOpen: boolean;
|
||||
onHistoryToggle: () => void;
|
||||
onNewConversation: () => void;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export const AgentHeader = ({
|
||||
isStreaming,
|
||||
menuAnchorEl,
|
||||
onMenuOpen,
|
||||
onMenuClose,
|
||||
isHistoryOpen,
|
||||
onHistoryToggle,
|
||||
onNewConversation,
|
||||
onClose,
|
||||
}: AgentHeaderProps) => {
|
||||
const theme = useTheme();
|
||||
const isMenuOpen = Boolean(menuAnchorEl);
|
||||
|
||||
return (
|
||||
<Box
|
||||
@@ -55,55 +50,46 @@ export const AgentHeader = ({
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" alignItems="center" spacing={2}>
|
||||
<motion.div whileHover={{ rotate: 10, scale: 1.05 }} 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: alpha("#ffffff", 0.9),
|
||||
boxShadow: `0 8px 24px ${alpha("#00acc1", 0.4)}`,
|
||||
width: 44,
|
||||
height: 44,
|
||||
border: `2px solid ${alpha("#fff", 0.8)}`,
|
||||
p: 0.75,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src="/ai-agent.svg"
|
||||
alt="TJWater Agent"
|
||||
width={30}
|
||||
height={30}
|
||||
style={{ width: "100%", height: "100%", objectFit: "contain" }}
|
||||
/>
|
||||
</Avatar>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: -2,
|
||||
right: -2,
|
||||
width: 14,
|
||||
height: 14,
|
||||
bgcolor: isStreaming ? "#ff9800" : "#00e676",
|
||||
borderRadius: "50%",
|
||||
border: "2.5px solid #fff",
|
||||
boxShadow: `0 0 10px ${isStreaming ? "#ff9800" : "#00e676"}`,
|
||||
animation: isStreaming ? "pulse 1.5s infinite" : "none",
|
||||
"@keyframes pulse": {
|
||||
"0%": { boxShadow: `0 0 0 0 ${alpha("#ff9800", 0.7)}` },
|
||||
"70%": { boxShadow: `0 0 0 6px ${alpha("#ff9800", 0)}` },
|
||||
"100%": { boxShadow: `0 0 0 0 ${alpha("#ff9800", 0)}` },
|
||||
}
|
||||
}}
|
||||
<motion.div whileHover={{ rotate: 10, scale: 1.05 }} whileTap={{ scale: 0.95 }} style={{ display: "flex" }}>
|
||||
<Box sx={{ position: "relative" }}>
|
||||
<Avatar
|
||||
sx={{
|
||||
background: alpha("#ffffff", 0.9),
|
||||
boxShadow: `0 8px 24px ${alpha("#00acc1", 0.4)}`,
|
||||
width: 44,
|
||||
height: 44,
|
||||
border: `2px solid ${alpha("#fff", 0.8)}`,
|
||||
p: 0.75,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
src="/ai-agent.svg"
|
||||
alt="TJWater Agent"
|
||||
width={30}
|
||||
height={30}
|
||||
style={{ width: "100%", height: "100%", objectFit: "contain" }}
|
||||
/>
|
||||
</Box>
|
||||
</IconButton>
|
||||
</Avatar>
|
||||
<Box
|
||||
sx={{
|
||||
position: "absolute",
|
||||
bottom: -2,
|
||||
right: -2,
|
||||
width: 14,
|
||||
height: 14,
|
||||
bgcolor: isStreaming ? "#ff9800" : "#00e676",
|
||||
borderRadius: "50%",
|
||||
border: "2.5px solid #fff",
|
||||
boxShadow: `0 0 10px ${isStreaming ? "#ff9800" : "#00e676"}`,
|
||||
animation: isStreaming ? "pulse 1.5s infinite" : "none",
|
||||
"@keyframes pulse": {
|
||||
"0%": { boxShadow: `0 0 0 0 ${alpha("#ff9800", 0.7)}` },
|
||||
"70%": { boxShadow: `0 0 0 6px ${alpha("#ff9800", 0)}` },
|
||||
"100%": { boxShadow: `0 0 0 0 ${alpha("#ff9800", 0)}` },
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</motion.div>
|
||||
<Box>
|
||||
<Typography
|
||||
@@ -124,54 +110,81 @@ export const AgentHeader = ({
|
||||
</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>
|
||||
<Stack direction="row" spacing={1.25} alignItems="center">
|
||||
<Tooltip title="新建对话">
|
||||
<motion.div whileHover={{ scale: 1.08 }} whileTap={{ scale: 0.92 }} style={{ display: "flex" }}>
|
||||
<IconButton
|
||||
onClick={onNewConversation}
|
||||
aria-label="新建对话"
|
||||
sx={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
color: "text.primary",
|
||||
bgcolor: alpha("#fff", 0.54),
|
||||
border: `1px solid ${alpha("#fff", 0.4)}`,
|
||||
boxShadow: `0 2px 8px ${alpha("#000", 0.02)}`,
|
||||
"&:hover": {
|
||||
bgcolor: "#fff",
|
||||
color: "#00acc1",
|
||||
borderColor: alpha("#fff", 0.8),
|
||||
boxShadow: `0 4px 12px ${alpha("#000", 0.05)}`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<EditNoteRounded sx={{ fontSize: 22 }} />
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
|
||||
<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>
|
||||
<Tooltip title={isHistoryOpen ? "收起历史会话" : "打开历史会话"}>
|
||||
<motion.div whileHover={{ scale: 1.08 }} whileTap={{ scale: 0.92 }} style={{ display: "flex" }}>
|
||||
<IconButton
|
||||
onClick={onHistoryToggle}
|
||||
aria-label={isHistoryOpen ? "收起历史会话" : "打开历史会话"}
|
||||
sx={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
color: isHistoryOpen ? "#00acc1" : "text.primary",
|
||||
bgcolor: isHistoryOpen ? alpha("#00acc1", 0.12) : alpha("#fff", 0.54),
|
||||
border: `1px solid ${isHistoryOpen ? alpha("#00acc1", 0.2) : alpha("#fff", 0.4)}`,
|
||||
boxShadow: `0 2px 8px ${isHistoryOpen ? alpha("#00acc1", 0.05) : alpha("#000", 0.02)}`,
|
||||
"&:hover": {
|
||||
bgcolor: isHistoryOpen ? alpha("#00acc1", 0.16) : "#fff",
|
||||
borderColor: isHistoryOpen ? alpha("#00acc1", 0.3) : alpha("#fff", 0.8),
|
||||
boxShadow: `0 4px 12px ${isHistoryOpen ? alpha("#00acc1", 0.1) : alpha("#000", 0.05)}`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<HistoryRounded sx={{ fontSize: 20 }} />
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="关闭 Agent">
|
||||
<motion.div whileHover={{ scale: 1.08, rotate: 90 }} whileTap={{ scale: 0.92 }} style={{ display: "flex" }}>
|
||||
<IconButton
|
||||
onClick={onClose}
|
||||
aria-label="关闭 Agent"
|
||||
sx={{
|
||||
width: 36,
|
||||
height: 36,
|
||||
color: "text.primary",
|
||||
bgcolor: alpha("#fff", 0.54),
|
||||
border: `1px solid ${alpha("#fff", 0.4)}`,
|
||||
boxShadow: `0 2px 8px ${alpha("#000", 0.02)}`,
|
||||
"&:hover": {
|
||||
bgcolor: "#fff",
|
||||
color: "#e53935",
|
||||
borderColor: alpha("#fff", 0.8),
|
||||
boxShadow: `0 4px 12px ${alpha("#000", 0.05)}`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<CloseRounded sx={{ fontSize: 20 }} />
|
||||
</IconButton>
|
||||
</motion.div>
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user