From 60fa266af6d5085702bb9a48db2ea67c7c41845c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Tue, 31 Mar 2026 22:10:39 +0800 Subject: [PATCH] Add files via upload --- web/static/js/chat.js | 26 ++++++++++++++++++++++++-- web/static/js/monitor.js | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/web/static/js/chat.js b/web/static/js/chat.js index bf296ece..9e6e8505 100644 --- a/web/static/js/chat.js +++ b/web/static/js/chat.js @@ -1695,6 +1695,20 @@ function renderProcessDetails(messageId, processDetails) { detailsContainer.appendChild(contentDiv); } + // processDetails === null 表示“尚未加载(懒加载)” + const isLazyNotLoaded = (processDetails === null); + if (isLazyNotLoaded) { + detailsContainer.dataset.lazyNotLoaded = '1'; + detailsContainer.dataset.loaded = '0'; + timeline.innerHTML = '
' + + (typeof window.t === 'function' ? window.t('chat.expandDetail') : '展开详情') + + '(点击后加载)
'; + // 默认折叠 + timeline.classList.remove('expanded'); + return; + } + detailsContainer.dataset.lazyNotLoaded = '0'; + detailsContainer.dataset.loaded = '1'; // 如果没有processDetails或为空,显示空状态 if (!processDetails || processDetails.length === 0) { // 显示空状态提示 @@ -2327,7 +2341,8 @@ function getConversationGroup(dateObj, todayStart, startOfWeek, yesterdayStart) // 加载对话 async function loadConversation(conversationId) { try { - const response = await apiFetch(`/api/conversations/${conversationId}`); + // 轻量加载:不带 processDetails,避免历史会话切换卡顿;展开详情时再按需拉取 + const response = await apiFetch(`/api/conversations/${conversationId}?include_process_details=0`); const conversation = await response.json(); if (!response.ok) { @@ -2426,11 +2441,18 @@ async function loadConversation(conversationId) { // 传递消息的创建时间 const messageId = addMessage(msg.role, displayContent, msg.mcpExecutionIds || [], null, msg.createdAt); + // 绑定后端 messageId,供按需加载过程详情使用 + const messageEl = document.getElementById(messageId); + if (messageEl && msg && msg.id) { + messageEl.dataset.backendMessageId = String(msg.id); + } // 对于助手消息,总是渲染过程详情(即使没有processDetails也要显示展开详情按钮) if (msg.role === 'assistant') { // 延迟一下,确保消息已经渲染 setTimeout(() => { - renderProcessDetails(messageId, msg.processDetails || []); + // 如果后端未返回 processDetails 字段,传 null 表示“尚未加载,点击展开时再请求” + const hasField = msg && Object.prototype.hasOwnProperty.call(msg, 'processDetails'); + renderProcessDetails(messageId, hasField ? (msg.processDetails || []) : null); // 如果有过程详情,检查是否有错误或取消事件,如果有,确保详情默认折叠 if (msg.processDetails && msg.processDetails.length > 0) { const hasErrorOrCancelled = msg.processDetails.some(d => diff --git a/web/static/js/monitor.js b/web/static/js/monitor.js index ce8020d1..d496114a 100644 --- a/web/static/js/monitor.js +++ b/web/static/js/monitor.js @@ -506,6 +506,46 @@ function toggleProcessDetails(progressId, assistantMessageId) { const detailsId = 'process-details-' + assistantMessageId; const detailsContainer = document.getElementById(detailsId); if (!detailsContainer) return; + + // 懒加载:首次展开时才从后端拉取该条消息的过程详情 + const maybeLazy = detailsContainer.dataset && detailsContainer.dataset.lazyNotLoaded === '1' && detailsContainer.dataset.loaded !== '1'; + if (maybeLazy) { + const messageEl = document.getElementById(assistantMessageId); + const backendMessageId = messageEl && messageEl.dataset ? messageEl.dataset.backendMessageId : ''; + if (backendMessageId && typeof apiFetch === 'function' && typeof renderProcessDetails === 'function') { + if (detailsContainer.dataset.loading === '1') { + // 正在加载中,避免重复请求 + } else { + detailsContainer.dataset.loading = '1'; + // 先展开容器,显示加载态 + const timeline = detailsContainer.querySelector('.progress-timeline'); + if (timeline) { + timeline.innerHTML = '
' + ((typeof window.t === 'function') ? window.t('common.loading') : '加载中…') + '
'; + } + apiFetch(`/api/messages/${encodeURIComponent(String(backendMessageId))}/process-details`) + .then(async (res) => { + const j = await res.json().catch(() => ({})); + if (!res.ok) throw new Error((j && j.error) ? j.error : res.status); + const details = (j && Array.isArray(j.processDetails)) ? j.processDetails : []; + // 重新渲染详情(renderProcessDetails 会清掉 lazy 标记并写入 loaded) + renderProcessDetails(assistantMessageId, details); + }) + .catch((e) => { + console.error('加载过程详情失败:', e); + const tl = detailsContainer.querySelector('.progress-timeline'); + if (tl) { + tl.innerHTML = '
' + ((typeof window.t === 'function') ? window.t('chat.noProcessDetail') : '暂无过程详情(加载失败)') + '
'; + } + // 失败时保留 lazy 状态,允许用户重试 + detailsContainer.dataset.lazyNotLoaded = '1'; + detailsContainer.dataset.loaded = '0'; + }) + .finally(() => { + detailsContainer.dataset.loading = '0'; + }); + } + } + } const content = detailsContainer.querySelector('.process-details-content'); const timeline = detailsContainer.querySelector('.progress-timeline');