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