Repair the Logic of the Log Viewing System

This commit is contained in:
马一丁
2025-11-15 16:21:49 +08:00
parent 6e8741f0ae
commit cab812e261
+181 -83
View File
@@ -326,6 +326,16 @@
min-height: 0; /* 允许内容缩小 */ min-height: 0; /* 允许内容缩小 */
} }
.console-layer {
display: none;
width: 100%;
min-height: 100%;
}
.console-layer.active {
display: block;
}
.console-line { .console-line {
margin-bottom: 2px; margin-bottom: 2px;
} }
@@ -1153,9 +1163,7 @@
</div> </div>
<!-- 控制台输出 --> <!-- 控制台输出 -->
<div class="console-output" id="consoleOutput"> <div class="console-output" id="consoleOutput"></div>
<div class="console-line">[系统] 等待连接...</div>
</div>
</div> </div>
</div> </div>
@@ -1214,6 +1222,10 @@
let socketConnected = false; let socketConnected = false;
let reportStreamConnected = false; let reportStreamConnected = false;
let backendReachable = false; let backendReachable = false;
const consoleLayerApps = ['insight', 'media', 'query', 'forum', 'report'];
const consoleLayers = {};
const consoleLayerScrollPositions = {};
let activeConsoleLayer = currentApp;
const CONFIG_ENDPOINT = '/api/config'; const CONFIG_ENDPOINT = '/api/config';
const SYSTEM_STATUS_ENDPOINT = '/api/system/status'; const SYSTEM_STATUS_ENDPOINT = '/api/system/status';
@@ -1318,9 +1330,11 @@
// 初始化 // 初始化
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
initializeConsoleLayers();
initializeSocket(); initializeSocket();
initializeEventListeners(); initializeEventListeners();
ensureSystemReadyOnLoad(); ensureSystemReadyOnLoad();
loadConsoleOutput(currentApp);
updateTime(); updateTime();
setInterval(updateTime, 1000); setInterval(updateTime, 1000);
checkStatus(); checkStatus();
@@ -1370,9 +1384,7 @@
socket.on('console_output', function(data) { socket.on('console_output', function(data) {
// 处理控制台输出 // 处理控制台输出
if (data.app === currentApp) { addConsoleOutput(data.line, data.app);
addConsoleOutput(data.line);
}
// 如果是forum的输出,同时也处理为论坛消息 // 如果是forum的输出,同时也处理为论坛消息
if (data.app === 'forum') { if (data.app === 'forum') {
@@ -2014,6 +2026,7 @@
document.querySelector(`[data-app="${app}"]`).classList.add('active'); document.querySelector(`[data-app="${app}"]`).classList.add('active');
currentApp = app; currentApp = app;
setActiveConsoleLayer(app);
// 根据应用类型处理不同的显示逻辑 // 根据应用类型处理不同的显示逻辑
if (app === 'forum') { if (app === 'forum') {
@@ -2024,8 +2037,8 @@
document.getElementById('forumContainer').classList.add('active'); document.getElementById('forumContainer').classList.add('active');
document.getElementById('reportContainer').classList.remove('active'); document.getElementById('reportContainer').classList.remove('active');
// 清空控制台并加载forum日志 // 追加提示并加载forum日志
document.getElementById('consoleOutput').innerHTML = '<div class="console-line">[系统] 切换到论坛模式</div>'; appendConsoleTextLine('forum', '[系统] 切换到论坛模式');
loadForumLog(); loadForumLog();
} else if (app === 'report') { } else if (app === 'report') {
@@ -2036,8 +2049,8 @@
document.getElementById('reportContainer').classList.add('active'); document.getElementById('reportContainer').classList.add('active');
document.getElementById('forumContainer').classList.remove('active'); document.getElementById('forumContainer').classList.remove('active');
// 清空控制台并加载report日志 // 追加提示并加载report日志
document.getElementById('consoleOutput').innerHTML = '<div class="console-line">[系统] 切换到报告生成模式</div>'; appendConsoleTextLine('report', '[系统] 切换到报告生成模式');
loadReportLog(); loadReportLog();
// 只在报告界面未初始化时才重新加载 // 只在报告界面未初始化时才重新加载
@@ -2059,11 +2072,8 @@
document.getElementById('forumContainer').classList.remove('active'); document.getElementById('forumContainer').classList.remove('active');
document.getElementById('reportContainer').classList.remove('active'); document.getElementById('reportContainer').classList.remove('active');
// 清空并加载新的控制台输出 // 追加提示并加载新的控制台输出
document.getElementById('consoleOutput').innerHTML = '<div class="console-line">[系统] 切换到 ' + appNames[app] + '</div>'; appendConsoleTextLine(app, '[系统] 切换到 ' + appNames[app]);
// 重置行计数
lastLineCount[app] = 0;
loadConsoleOutput(app); loadConsoleOutput(app);
} }
@@ -2073,6 +2083,127 @@
// 存储最后显示的行数,避免重复加载 // 存储最后显示的行数,避免重复加载
let lastLineCount = {}; let lastLineCount = {};
function getConsoleContainer() {
return document.getElementById('consoleOutput');
}
function initializeConsoleLayers() {
const container = getConsoleContainer();
if (!container) return;
container.innerHTML = '';
consoleLayerApps.forEach(app => {
const layer = document.createElement('div');
layer.className = 'console-layer';
layer.dataset.app = app;
if (app === currentApp) {
layer.classList.add('active');
layer.style.display = 'block';
activeConsoleLayer = app;
} else {
layer.style.display = 'none';
}
const placeholder = document.createElement('div');
placeholder.className = 'console-line';
placeholder.textContent = `[系统] ${appNames[app] || app} 日志就绪`;
layer.appendChild(placeholder);
container.appendChild(layer);
consoleLayers[app] = layer;
});
container.scrollTop = container.scrollHeight;
}
function getConsoleLayer(app) {
if (consoleLayers[app]) {
return consoleLayers[app];
}
const container = getConsoleContainer();
if (!container) return null;
const layer = document.createElement('div');
layer.className = 'console-layer';
layer.dataset.app = app;
layer.style.display = app === currentApp ? 'block' : 'none';
if (app === currentApp) {
layer.classList.add('active');
activeConsoleLayer = app;
}
container.appendChild(layer);
consoleLayers[app] = layer;
return layer;
}
function setActiveConsoleLayer(app) {
const container = getConsoleContainer();
if (!container) return;
if (activeConsoleLayer && consoleLayers[activeConsoleLayer]) {
consoleLayerScrollPositions[activeConsoleLayer] = container.scrollTop;
consoleLayers[activeConsoleLayer].classList.remove('active');
consoleLayers[activeConsoleLayer].style.display = 'none';
}
const targetLayer = getConsoleLayer(app);
if (!targetLayer) return;
targetLayer.style.display = 'block';
targetLayer.classList.add('active');
activeConsoleLayer = app;
const storedScroll = consoleLayerScrollPositions[app];
if (typeof storedScroll === 'number') {
container.scrollTop = storedScroll;
} else {
container.scrollTop = container.scrollHeight;
}
}
function syncConsoleScroll(app) {
if (app !== currentApp) {
return;
}
const container = getConsoleContainer();
if (container) {
container.scrollTop = container.scrollHeight;
consoleLayerScrollPositions[app] = container.scrollTop;
}
}
function appendConsoleTextLine(app, text, className = 'console-line') {
const layer = getConsoleLayer(app);
if (!layer) return;
const line = document.createElement('div');
line.className = className;
line.textContent = text;
layer.appendChild(line);
syncConsoleScroll(app);
}
function appendConsoleElement(app, element) {
const layer = getConsoleLayer(app);
if (!layer || !element) return;
layer.appendChild(element);
syncConsoleScroll(app);
}
function clearConsoleLayer(app, message = null) {
const layer = getConsoleLayer(app);
if (!layer) return;
layer.innerHTML = '';
if (message) {
appendConsoleTextLine(app, message);
}
}
// 加载控制台输出 // 加载控制台输出
function loadConsoleOutput(app) { function loadConsoleOutput(app) {
@@ -2090,21 +2221,15 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success && data.output.length > 0) { if (data.success && data.output.length > 0) {
const consoleOutput = document.getElementById('consoleOutput');
// 只添加新的行
const lastCount = lastLineCount[app] || 0; const lastCount = lastLineCount[app] || 0;
const newLines = data.output.slice(lastCount); const newLines = data.output.slice(lastCount);
newLines.forEach(line => { if (newLines.length > 0) {
const div = document.createElement('div'); newLines.forEach(line => {
div.className = 'console-line'; appendConsoleTextLine(app, line);
div.textContent = line; });
consoleOutput.appendChild(div); lastLineCount[app] = data.output.length;
}); }
lastLineCount[app] = data.output.length;
consoleOutput.scrollTop = consoleOutput.scrollHeight;
} }
}) })
.catch(error => { .catch(error => {
@@ -2129,22 +2254,15 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success && data.output.length > 0) { if (data.success && data.output.length > 0) {
const consoleOutput = document.getElementById('consoleOutput');
// 只添加新的行 // 只添加新的行
const lastCount = lastLineCount[currentApp] || 0; const lastCount = lastLineCount[currentApp] || 0;
const newLines = data.output.slice(lastCount); const newLines = data.output.slice(lastCount);
if (newLines.length > 0) { if (newLines.length > 0) {
newLines.forEach(line => { newLines.forEach(line => {
const div = document.createElement('div'); appendConsoleTextLine(currentApp, line);
div.className = 'console-line';
div.textContent = line;
consoleOutput.appendChild(div);
}); });
lastLineCount[currentApp] = data.output.length; lastLineCount[currentApp] = data.output.length;
consoleOutput.scrollTop = consoleOutput.scrollHeight;
} }
} }
}) })
@@ -2155,15 +2273,13 @@
} }
// 添加控制台输出 // 添加控制台输出
function addConsoleOutput(line) { function addConsoleOutput(line, app = currentApp) {
const consoleOutput = document.getElementById('consoleOutput'); const targetApp = app || currentApp;
const div = document.createElement('div'); appendConsoleTextLine(targetApp, line);
div.className = 'console-line';
div.textContent = line;
consoleOutput.appendChild(div);
// 自动滚动到底部显示最新内容 if (targetApp !== 'report') {
consoleOutput.scrollTop = consoleOutput.scrollHeight; lastLineCount[targetApp] = (lastLineCount[targetApp] || 0) + 1;
}
} }
// 预加载的iframe存储 // 预加载的iframe存储
@@ -2522,15 +2638,16 @@
`; `;
// 加载控制台日志 // 加载控制台日志
const consoleOutput = document.getElementById('consoleOutput');
consoleOutput.innerHTML = '<div class="console-line">[系统] Forum Engine 日志输出</div>';
if (data.log_lines && data.log_lines.length > 0) { if (data.log_lines && data.log_lines.length > 0) {
data.log_lines.forEach(line => { if (forumLogLineCount === 0) {
const div = document.createElement('div'); clearConsoleLayer('forum', '[系统] Forum Engine 日志输出');
div.className = 'console-line'; }
div.textContent = line;
consoleOutput.appendChild(div); const newLines = data.log_lines.slice(forumLogLineCount);
const linesToProcess = forumLogLineCount === 0 ? data.log_lines : newLines;
linesToProcess.forEach(line => {
appendConsoleTextLine('forum', line);
// 解析并添加到对话区 // 解析并添加到对话区
const parsed = parseForumMessage(line); const parsed = parseForumMessage(line);
@@ -2553,7 +2670,6 @@
}); });
} }
consoleOutput.scrollTop = consoleOutput.scrollHeight;
} }
}) })
.catch(error => { .catch(error => {
@@ -2567,15 +2683,10 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success && data.log_lines.length > forumLogLineCount) { if (data.success && data.log_lines.length > forumLogLineCount) {
const consoleOutput = document.getElementById('consoleOutput');
// 只添加新的行 // 只添加新的行
const newLines = data.log_lines.slice(forumLogLineCount); const newLines = data.log_lines.slice(forumLogLineCount);
newLines.forEach(line => { newLines.forEach(line => {
const div = document.createElement('div'); appendConsoleTextLine('forum', line);
div.className = 'console-line';
div.textContent = line;
consoleOutput.appendChild(div);
// 如果是论坛对话内容,也显示到左侧对话区 // 如果是论坛对话内容,也显示到左侧对话区
const parsed = parseForumMessage(line); const parsed = parseForumMessage(line);
@@ -2585,7 +2696,6 @@
}); });
forumLogLineCount = data.log_lines.length; forumLogLineCount = data.log_lines.length;
consoleOutput.scrollTop = consoleOutput.scrollHeight;
} }
}) })
.catch(error => { .catch(error => {
@@ -2650,19 +2760,13 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success && data.log_lines.length > reportLogLineCount) { if (data.success && data.log_lines.length > reportLogLineCount) {
const consoleOutput = document.getElementById('consoleOutput');
// 只添加新的行 // 只添加新的行
const newLines = data.log_lines.slice(reportLogLineCount); const newLines = data.log_lines.slice(reportLogLineCount);
newLines.forEach(line => { newLines.forEach(line => {
const div = document.createElement('div'); appendConsoleTextLine('report', line);
div.className = 'console-line';
div.textContent = line;
consoleOutput.appendChild(div);
}); });
reportLogLineCount = data.log_lines.length; reportLogLineCount = data.log_lines.length;
consoleOutput.scrollTop = consoleOutput.scrollHeight;
} }
}) })
.catch(error => { .catch(error => {
@@ -2676,15 +2780,16 @@
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
if (data.success) { if (data.success) {
const consoleOutput = document.getElementById('consoleOutput'); if (reportLogLineCount === 0) {
consoleOutput.innerHTML = '<div class="console-line">[系统] Report Engine 日志监控已启动</div>'; clearConsoleLayer('report', '[系统] Report Engine 日志监控已启动');
}
if (data.log_lines && data.log_lines.length > 0) { if (data.log_lines && data.log_lines.length > 0) {
data.log_lines.forEach(line => { const newLines = data.log_lines.slice(reportLogLineCount);
const div = document.createElement('div'); const linesToProcess = reportLogLineCount === 0 ? data.log_lines : newLines;
div.className = 'console-line';
div.textContent = line; linesToProcess.forEach(line => {
consoleOutput.appendChild(div); appendConsoleTextLine('report', line);
}); });
// 重置计数器以确保后续消息能正确显示 // 重置计数器以确保后续消息能正确显示
@@ -2693,8 +2798,6 @@
// 如果没有日志,重置计数器 // 如果没有日志,重置计数器
reportLogLineCount = 0; reportLogLineCount = 0;
} }
consoleOutput.scrollTop = consoleOutput.scrollHeight;
} }
}) })
.catch(error => { .catch(error => {
@@ -3168,8 +3271,7 @@
safeCloseReportStream(true); safeCloseReportStream(true);
// 清空控制台显示 // 清空控制台显示
const consoleOutput = document.getElementById('consoleOutput'); clearConsoleLayer('report', '[系统] 开始生成报告,日志已重置');
consoleOutput.innerHTML = '<div class="console-line">[系统] 开始生成报告,日志已重置</div>';
resetReportStreamOutput('Report Engine 正在调度任务...'); resetReportStreamOutput('Report Engine 正在调度任务...');
setGenerateButtonState(true); setGenerateButtonState(true);
@@ -3381,9 +3483,6 @@
// 往黑色控制台输出区域追加一条流式日志 // 往黑色控制台输出区域追加一条流式日志
function appendReportStreamLine(message, level = 'info', options = {}) { function appendReportStreamLine(message, level = 'info', options = {}) {
const consoleOutput = document.getElementById('consoleOutput');
if (!consoleOutput) return;
if (level === 'chunk' && !options.force) { if (level === 'chunk' && !options.force) {
return; // 章节内容流式写入不再逐条输出 return; // 章节内容流式写入不再逐条输出
} }
@@ -3408,8 +3507,7 @@
textSpan.textContent = message; textSpan.textContent = message;
line.appendChild(textSpan); line.appendChild(textSpan);
consoleOutput.appendChild(line); appendConsoleElement('report', line);
consoleOutput.scrollTop = consoleOutput.scrollHeight;
} }
function startStreamHeartbeat() { function startStreamHeartbeat() {