From 341b7440f255a7e7213c106361943040ffb27ff8 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期一, 23 三月 2026 12:58:19 +0800
Subject: [PATCH] #ai 页面优化
---
rsf-admin/src/i18n/zh.js | 3 +
rsf-admin/src/i18n/en.js | 3 +
rsf-admin/src/layout/AiChatDrawer.jsx | 135 +++++++++++++++++++++++++++-----------------
3 files changed, 88 insertions(+), 53 deletions(-)
diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js
index e83334f..5069c5b 100644
--- a/rsf-admin/src/i18n/en.js
+++ b/rsf-admin/src/i18n/en.js
@@ -544,6 +544,9 @@
noFacts: "No Facts",
retainLatestRound: "Keep Latest Round",
clearMemory: "Clear Memory",
+ runtimeOverview: "Runtime Overview",
+ runtimeExpand: "Show Overview",
+ runtimeCollapse: "Hide Overview",
loadingRuntime: "Loading AI runtime info...",
emptyHint: "AI responses stream back through SSE here. You can also maintain parameters, prompts, and MCP mounts from the quick links above.",
userRole: "You",
diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index 08fe8bf..fd62ee9 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -560,6 +560,9 @@
noFacts: "鏃犱簨瀹�",
retainLatestRound: "浠呬繚鐣欏綋鍓嶈疆",
clearMemory: "娓呯┖璁板繂",
+ runtimeOverview: "杩愯姒傝",
+ runtimeExpand: "灞曞紑姒傝",
+ runtimeCollapse: "鏀惰捣姒傝",
loadingRuntime: "姝e湪鍔犺浇 AI 杩愯鏃朵俊鎭�...",
emptyHint: "杩欓噷浼氶�氳繃 SSE 娴佸紡杩斿洖 AI 鍥炲銆備綘涔熷彲浠ュ厛鍘讳笂闈㈢殑蹇嵎鍏ュ彛缁存姢鍙傛暟銆丳rompt 鍜� MCP 鎸傝浇銆�",
userRole: "浣�",
diff --git a/rsf-admin/src/layout/AiChatDrawer.jsx b/rsf-admin/src/layout/AiChatDrawer.jsx
index 92f29df..fc1eb06 100644
--- a/rsf-admin/src/layout/AiChatDrawer.jsx
+++ b/rsf-admin/src/layout/AiChatDrawer.jsx
@@ -47,6 +47,8 @@
import { clearAiSessionMemory, getAiRuntime, getAiSessions, pinAiSession, removeAiSession, renameAiSession, retainAiSessionLatestRound, streamAiChat } from "@/api/ai/chat";
const DEFAULT_PROMPT_CODE = "home.default";
+const AI_CHAT_DRAWER_Z_INDEX = 1400;
+const AI_CHAT_DIALOG_Z_INDEX = AI_CHAT_DRAWER_Z_INDEX + 20;
const THINKING_PHASE_ORDER = {
ANALYZE: 0,
TOOL_CALL: 1,
@@ -248,6 +250,7 @@
const [drawerError, setDrawerError] = useState("");
const [sessionKeyword, setSessionKeyword] = useState("");
const [renameDialog, setRenameDialog] = useState({ open: false, sessionId: null, title: "" });
+ const [runtimePanelExpanded, setRuntimePanelExpanded] = useState(false);
const quickLinks = useMemo(() => ([
{ label: translate("menu.aiParam"), path: "/aiParam", icon: <SettingsSuggestOutlinedIcon fontSize="small" /> },
@@ -297,6 +300,7 @@
useEffect(() => {
if (open) {
+ setRuntimePanelExpanded(false);
initializeDrawer();
} else {
stopStream(false);
@@ -726,7 +730,7 @@
onClose={onClose}
ModalProps={{ keepMounted: true }}
sx={{
- zIndex: 1400,
+ zIndex: AI_CHAT_DRAWER_Z_INDEX,
"& .MuiDrawer-paper": {
top: 0,
height: "100vh",
@@ -935,63 +939,80 @@
<Box flex={1} display="flex" flexDirection="column" minHeight={0}>
<Box px={2} py={1.5}>
- <Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
- <Chip size="small" label={translate("ai.drawer.requestMetric", { value: runtimeSummary.requestId })} />
- <Chip size="small" label={translate("ai.drawer.sessionMetric", { id: sessionId || "--" })} />
- <Chip size="small" label={translate("ai.drawer.promptMetric", { value: runtimeSummary.promptName })} />
- <Chip size="small" label={translate("ai.drawer.modelMetric", { value: runtimeSummary.model })} />
- <Chip size="small" label={translate("ai.drawer.mcpMetric", { value: runtimeSummary.mountedMcpCount })} />
- <Chip size="small" label={translate("ai.drawer.historyMetric", { value: persistedMessages.length })} />
- <Chip size="small" label={translate("ai.drawer.recentMetric", { value: runtimeSummary.recentMessageCount })} />
- <Chip size="small" color={runtimeSummary.hasSummary ? "success" : "default"} label={translate(runtimeSummary.hasSummary ? "ai.drawer.hasSummary" : "ai.drawer.noSummary")} />
- <Chip size="small" color={runtimeSummary.hasFacts ? "info" : "default"} label={translate(runtimeSummary.hasFacts ? "ai.drawer.hasFacts" : "ai.drawer.noFacts")} />
+ <Stack direction="row" alignItems="center" justifyContent="space-between" spacing={1}>
+ <Typography variant="subtitle2">
+ {translate("ai.drawer.runtimeOverview")}
+ </Typography>
+ <Button
+ size="small"
+ onClick={() => setRuntimePanelExpanded((prev) => !prev)}
+ endIcon={runtimePanelExpanded
+ ? <ExpandLessOutlinedIcon fontSize="small" />
+ : <ExpandMoreOutlinedIcon fontSize="small" />}
+ sx={{ minWidth: "auto", px: 1 }}
+ >
+ {translate(runtimePanelExpanded ? "ai.drawer.runtimeCollapse" : "ai.drawer.runtimeExpand")}
+ </Button>
</Stack>
- <Stack direction="row" spacing={1} mt={1.5} flexWrap="wrap" useFlexGap>
- {quickLinks.map((item) => (
+ <Collapse in={runtimePanelExpanded} timeout="auto" unmountOnExit>
+ <Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap sx={{ mt: 1.5 }}>
+ <Chip size="small" label={translate("ai.drawer.requestMetric", { value: runtimeSummary.requestId })} />
+ <Chip size="small" label={translate("ai.drawer.sessionMetric", { id: sessionId || "--" })} />
+ <Chip size="small" label={translate("ai.drawer.promptMetric", { value: runtimeSummary.promptName })} />
+ <Chip size="small" label={translate("ai.drawer.modelMetric", { value: runtimeSummary.model })} />
+ <Chip size="small" label={translate("ai.drawer.mcpMetric", { value: runtimeSummary.mountedMcpCount })} />
+ <Chip size="small" label={translate("ai.drawer.historyMetric", { value: persistedMessages.length })} />
+ <Chip size="small" label={translate("ai.drawer.recentMetric", { value: runtimeSummary.recentMessageCount })} />
+ <Chip size="small" color={runtimeSummary.hasSummary ? "success" : "default"} label={translate(runtimeSummary.hasSummary ? "ai.drawer.hasSummary" : "ai.drawer.noSummary")} />
+ <Chip size="small" color={runtimeSummary.hasFacts ? "info" : "default"} label={translate(runtimeSummary.hasFacts ? "ai.drawer.hasFacts" : "ai.drawer.noFacts")} />
+ </Stack>
+ <Stack direction="row" spacing={1} mt={1.5} flexWrap="wrap" useFlexGap>
+ {quickLinks.map((item) => (
+ <Button
+ key={item.path}
+ size="small"
+ variant="outlined"
+ startIcon={item.icon}
+ onClick={() => navigate(item.path)}
+ >
+ {item.label}
+ </Button>
+ ))}
<Button
- key={item.path}
size="small"
variant="outlined"
- startIcon={item.icon}
- onClick={() => navigate(item.path)}
+ startIcon={<HistoryOutlinedIcon />}
+ onClick={handleRetainLatestRound}
+ disabled={!sessionId || streaming}
>
- {item.label}
+ {translate("ai.drawer.retainLatestRound")}
</Button>
- ))}
- <Button
- size="small"
- variant="outlined"
- startIcon={<HistoryOutlinedIcon />}
- onClick={handleRetainLatestRound}
- disabled={!sessionId || streaming}
- >
- {translate("ai.drawer.retainLatestRound")}
- </Button>
- <Button
- size="small"
- variant="outlined"
- color="warning"
- startIcon={<AutoDeleteOutlinedIcon />}
- onClick={handleClearMemory}
- disabled={!sessionId || streaming}
- >
- {translate("ai.drawer.clearMemory")}
- </Button>
- </Stack>
- {!!runtime?.memorySummary && (
- <Alert severity="info" sx={{ mt: 1.5 }}>
- <Typography variant="body2" sx={{ whiteSpace: "pre-wrap" }}>
- {runtime.memorySummary}
- </Typography>
- </Alert>
- )}
- {!!runtime?.memoryFacts && (
- <Alert severity="success" sx={{ mt: 1.5 }}>
- <Typography variant="body2" sx={{ whiteSpace: "pre-wrap" }}>
- {runtime.memoryFacts}
- </Typography>
- </Alert>
- )}
+ <Button
+ size="small"
+ variant="outlined"
+ color="warning"
+ startIcon={<AutoDeleteOutlinedIcon />}
+ onClick={handleClearMemory}
+ disabled={!sessionId || streaming}
+ >
+ {translate("ai.drawer.clearMemory")}
+ </Button>
+ </Stack>
+ {!!runtime?.memorySummary && (
+ <Alert severity="info" sx={{ mt: 1.5 }}>
+ <Typography variant="body2" sx={{ whiteSpace: "pre-wrap" }}>
+ {runtime.memorySummary}
+ </Typography>
+ </Alert>
+ )}
+ {!!runtime?.memoryFacts && (
+ <Alert severity="success" sx={{ mt: 1.5 }}>
+ <Typography variant="body2" sx={{ whiteSpace: "pre-wrap" }}>
+ {runtime.memoryFacts}
+ </Typography>
+ </Alert>
+ )}
+ </Collapse>
{loadingRuntime && (
<Typography variant="body2" color="text.secondary" mt={1}>
{translate("ai.drawer.loadingRuntime")}
@@ -1205,7 +1226,15 @@
</Box>
</Box>
</Box>
- <Dialog open={renameDialog.open} onClose={closeRenameDialog} fullWidth maxWidth="xs">
+ <Dialog
+ open={renameDialog.open}
+ onClose={closeRenameDialog}
+ fullWidth
+ maxWidth="xs"
+ sx={{
+ zIndex: AI_CHAT_DIALOG_Z_INDEX,
+ }}
+ >
<DialogTitle>{translate("ai.drawer.renameDialogTitle")}</DialogTitle>
<DialogContent>
<TextField
--
Gitblit v1.9.1