diff --git a/packages/frontend/src/components/LayoutRenderer.vue b/packages/frontend/src/components/LayoutRenderer.vue
index 030df39..c9515af 100644
--- a/packages/frontend/src/components/LayoutRenderer.vue
+++ b/packages/frontend/src/components/LayoutRenderer.vue
@@ -159,12 +159,9 @@ const componentProps = computed(() => {
// FileManager 可能也需要转发事件,例如文件操作相关的,暂时省略
};
case 'statusMonitor':
- // 仅当有活动会话时才返回实际 props,否则返回空对象
- if (!currentActiveSession) return {};
+ // 始终渲染,传递 activeSessionId
return {
- sessionId: props.activeSessionId ?? '', // 确保 sessionId 不为 null
- serverStatus: currentActiveSession.statusMonitorManager.serverStatus.value, // 此时 currentActiveSession 必不为 null
- statusError: currentActiveSession.statusMonitorManager.statusError.value, // 此时 currentActiveSession 必不为 null
+ activeSessionId: props.activeSessionId, // 传递 activeSessionId
class: 'pane-content',
};
case 'editor':
@@ -253,17 +250,11 @@ const sidebarProps = computed(() => (paneName: PaneName | null, side: 'left' | '
return baseProps; // Return only base props if no active session
}
case 'statusMonitor':
- // Only provide props if there's an active session
- if (activeSession.value) {
- return {
- ...baseProps,
- sessionId: activeSession.value.sessionId, // Pass session ID
- serverStatus: activeSession.value.statusMonitorManager.serverStatus.value,
- statusError: activeSession.value.statusMonitorManager.statusError.value,
- };
- } else {
- return baseProps; // Return only base props if no active session
- }
+ // 始终渲染,传递 activeSessionId
+ return {
+ ...baseProps,
+ activeSessionId: props.activeSessionId, // 传递 activeSessionId
+ };
// Add cases for other components if they need specific props or event forwarding in the sidebar
// case 'commandHistory': return { ...baseProps, onExecuteCommand: (cmd: string) => emit('sendCommand', cmd) };
// case 'quickCommands': return { ...baseProps, onExecuteCommand: (cmd: string) => emit('sendCommand', cmd) };
@@ -493,20 +484,13 @@ onMounted(() => {
-
-
+
+
+
@@ -547,26 +531,22 @@ onMounted(() => {
-
-
-
-
-
{{ t('layout.noActiveSession.title') }}
-
{{ t('layout.noActiveSession.fileManagerSidebar') }}
-
-
-
-
-
-
{{ t('layout.noActiveSession.title') }}
-
{{ t('layout.noActiveSession.statusMonitorSidebar') }}
-
-
+
+ v-if="currentLeftSidebarComponent && activeLeftSidebarPane && (activeLeftSidebarPane === 'statusMonitor' || activeLeftSidebarPane !== 'fileManager' || activeSession)"
+ :is="currentLeftSidebarComponent"
+ :key="`left-comp-${activeLeftSidebarPane}`"
+ v-bind="sidebarProps(activeLeftSidebarPane, 'left')"
+ class="flex flex-col flex-grow">
+
+
+
+
+
+
{{ t('layout.noActiveSession.title') }}
+
{{ t('layout.noActiveSession.fileManagerSidebar') }}
+
+
+
@@ -583,26 +563,21 @@ onMounted(() => {
-
-
-
-
-
{{ t('layout.noActiveSession.title') }}
-
{{ t('layout.noActiveSession.fileManagerSidebar') }}
-
-
-
-
-
-
{{ t('layout.noActiveSession.title') }}
-
{{ t('layout.noActiveSession.statusMonitorSidebar') }}
-
-
+ v-if="currentRightSidebarComponent && activeRightSidebarPane && (activeRightSidebarPane === 'statusMonitor' || activeRightSidebarPane !== 'fileManager' || activeSession)"
+ :is="currentRightSidebarComponent"
+ :key="`right-comp-${activeRightSidebarPane}`"
+ v-bind="sidebarProps(activeRightSidebarPane, 'right')"
+ class="flex flex-col flex-grow">
+
+
+
+
+
+
{{ t('layout.noActiveSession.title') }}
+
{{ t('layout.noActiveSession.fileManagerSidebar') }}
+
+
+
diff --git a/packages/frontend/src/components/StatusCharts.vue b/packages/frontend/src/components/StatusCharts.vue
index ce123d8..2d38cb6 100644
--- a/packages/frontend/src/components/StatusCharts.vue
+++ b/packages/frontend/src/components/StatusCharts.vue
@@ -40,9 +40,11 @@
\ No newline at end of file
diff --git a/packages/frontend/src/components/StatusMonitor.vue b/packages/frontend/src/components/StatusMonitor.vue
index 1f07713..6c6769b 100644
--- a/packages/frontend/src/components/StatusMonitor.vue
+++ b/packages/frontend/src/components/StatusMonitor.vue
@@ -6,14 +6,20 @@
{{ t('statusMonitor.title') }}
+
+
+
+ {{ t('layout.noActiveSession.title') }}
+
+
-
+
- {{ t('statusMonitor.errorPrefix') }} {{ statusError }}
+ {{ t('statusMonitor.errorPrefix') }} {{ currentStatusError }}
-
+
{{ t('statusMonitor.loading') }}
@@ -40,10 +46,10 @@
- {{ serverStatus.cpuPercent?.toFixed(1) ?? t('statusMonitor.notAvailable') }}%
+ {{ currentServerStatus.cpuPercent?.toFixed(1) ?? t('statusMonitor.notAvailable') }}%
@@ -53,7 +59,7 @@
{{ memDisplay }}
@@ -66,9 +72,9 @@
{{ swapDisplay }}
@@ -80,7 +86,7 @@
{{ diskDisplay }}
@@ -91,32 +97,36 @@
-
+
- {{ formatBytesPerSecond(serverStatus?.netRxRate) }}
+ {{ formatBytesPerSecond(currentServerStatus?.netRxRate) }}
- {{ formatBytesPerSecond(serverStatus?.netTxRate) }}
+ {{ formatBytesPerSecond(currentServerStatus?.netTxRate) }}
-
+
+
-
diff --git a/packages/frontend/src/composables/useStatusMonitor.ts b/packages/frontend/src/composables/useStatusMonitor.ts
index bce0087..5cf7dc4 100644
--- a/packages/frontend/src/composables/useStatusMonitor.ts
+++ b/packages/frontend/src/composables/useStatusMonitor.ts
@@ -18,10 +18,28 @@ export interface StatusMonitorDependencies {
*/
export function createStatusMonitorManager(sessionId: string, wsDeps: StatusMonitorDependencies) {
const { onMessage, isConnected } = wsDeps;
+ const MAX_HISTORY_POINTS = 60; // 图表显示的点数
const serverStatus = ref(null);
const statusError = ref(null); // 存储状态获取错误
+ // --- 历史数据存储 ---
+ // 初始化为包含60个 null 或 0 的数组,这样图表初始时有占位
+ const cpuHistory = ref<(number | null)[]>(Array(MAX_HISTORY_POINTS).fill(null));
+ const memUsedHistory = ref<(number | null)[]>(Array(MAX_HISTORY_POINTS).fill(null)); // Store memUsed in MB
+ const netRxHistory = ref<(number | null)[]>(Array(MAX_HISTORY_POINTS).fill(null)); // Store rate in Bytes/sec
+ const netTxHistory = ref<(number | null)[]>(Array(MAX_HISTORY_POINTS).fill(null)); // Store rate in Bytes/sec
+
+ // --- 辅助函数:更新历史数据数组 ---
+ const updateHistory = (historyRef: Ref<(number | null)[]>, newValue: number | undefined) => {
+ const currentHistory = historyRef.value;
+ currentHistory.shift(); // 移除最旧的数据点
+ // 如果新值无效(undefined 或 null),推入 null,否则推入数字
+ currentHistory.push((newValue === undefined || newValue === null || isNaN(newValue)) ? null : newValue);
+ historyRef.value = [...currentHistory]; // 触发响应式更新
+ };
+
+
// --- WebSocket 消息处理 ---
const handleStatusUpdate = (payload: MessagePayload, message?: WebSocketMessage) => {
// 检查消息是否属于此会话
@@ -29,12 +47,20 @@ export function createStatusMonitorManager(sessionId: string, wsDeps: StatusMoni
return; // 忽略不属于此会话的消息
}
- // console.debug(`[会话 ${sessionId}][状态监控模块] 收到 status_update:`, JSON.stringify(payload)); // 添加日志
- if (payload && payload.status) {
- serverStatus.value = payload.status;
+ // console.debug(`[会话 ${sessionId}][状态监控模块] 收到 status_update:`, JSON.stringify(payload));
+ if (payload?.status) {
+ const newStatus: ServerStatus = payload.status;
+ serverStatus.value = newStatus;
statusError.value = null; // 收到有效状态时清除错误
+
+ // 更新历史数据
+ updateHistory(cpuHistory, newStatus.cpuPercent);
+ updateHistory(memUsedHistory, newStatus.memUsed);
+ updateHistory(netRxHistory, newStatus.netRxRate);
+ updateHistory(netTxHistory, newStatus.netTxRate);
+
} else {
- console.warn(`[会话 ${sessionId}][状态监控模块] 收到缺少 payload.status 的 status_update 消息`);
+ console.warn(`[会话 ${sessionId}][状态监控模块] 收到无效的 status_update 消息`);
// 可以选择设置一个错误状态,表明数据格式不正确
// statusError.value = '收到的状态数据格式无效';
}
@@ -113,11 +139,17 @@ export function createStatusMonitorManager(sessionId: string, wsDeps: StatusMoni
// --- 暴露接口 ---
return {
- serverStatus: readonly(serverStatus), // 只读状态
- statusError: readonly(statusError), // 只读错误状态
- registerStatusHandlers, // 暴露注册函数,以便在需要时可以重新注册
- unregisterAllStatusHandlers, // 暴露注销函数,以便在需要时可以手动注销
- cleanup, // 暴露清理函数,在会话关闭时调用
+ serverStatus: readonly(serverStatus), // 当前状态
+ statusError: readonly(statusError), // 错误状态
+ // --- 暴露历史数据 ---
+ cpuHistory: readonly(cpuHistory),
+ memUsedHistory: readonly(memUsedHistory),
+ netRxHistory: readonly(netRxHistory),
+ netTxHistory: readonly(netTxHistory),
+ // --- 控制函数 ---
+ registerStatusHandlers,
+ unregisterAllStatusHandlers,
+ cleanup,
};
}
diff --git a/packages/frontend/src/types/server.types.ts b/packages/frontend/src/types/server.types.ts
index bded8c0..19dbb2d 100644
--- a/packages/frontend/src/types/server.types.ts
+++ b/packages/frontend/src/types/server.types.ts
@@ -8,8 +8,13 @@ export interface ServerStatus {
diskUsed?: number; // KB
diskTotal?: number; // KB
cpuModel?: string;
- // 可以根据后端实际发送的数据添加更多字段
- // 例如:swapPercent?, swapUsed?, swapTotal?, netRxRate?, netTxRate?, netInterface?, osName?, loadAvg?, timestamp?
+ swapPercent?: number;
+ swapUsed?: number; // MB
+ swapTotal?: number; // MB
+ netRxRate?: number; // Bytes/sec
+ netTxRate?: number; // Bytes/sec
+ netInterface?: string;
+ osName?: string;
}
// 可以根据需要添加其他与服务器或连接状态相关的类型