Toggle navigation
Toggle navigation
This project
Loading...
Sign in
万朱浩
/
Venue-Ops
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
马一丁
2025-11-21 00:25:48 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
de8f253fa0784eeedc98aea4ec25df53517218bf
de8f253f
1 parent
b10dd449
Improves the Front-End Console Experience
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
287 additions
and
40 deletions
templates/index.html
templates/index.html
View file @
de8f253
...
...
@@ -23,6 +23,10 @@
overflow-x
:
hidden
;
}
:root
{
--console-offset
:
52px
;
/* app切换行 + 状态条的预留高度,运行时同步 */
}
.container
{
max-width
:
100vw
;
height
:
100vh
;
/* 固定高度为视口高度 */
...
...
@@ -177,7 +181,7 @@
.upload-button
input
[
type
=
"file"
]
{
position
:
absolute
;
left
:
0
;
top
:
0
;
top
:
52px
;
/* 运行时再用JS同步为app-switcher的真实高度 */
width
:
100%
;
height
:
100%
;
opacity
:
0
;
...
...
@@ -238,6 +242,7 @@
background-color
:
#ffffff
;
min-height
:
0
;
/* 允许子元素缩小 */
overflow
:
hidden
;
/* 防止内容溢出 */
position
:
relative
;
/* 让状态栏悬浮不占用布局空间 */
}
/* 应用切换按钮 */
...
...
@@ -330,7 +335,11 @@
/* 控制台状态栏 - 显示系统消息而不干扰日志查看 */
.console-status-bar
{
height
:
0
;
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
height
:
26px
;
overflow
:
hidden
;
background
:
linear-gradient
(
180deg
,
rgba
(
0
,
120
,
0
,
0.95
)
0%
,
rgba
(
0
,
100
,
0
,
0.9
)
100%
);
color
:
#00ff00
;
...
...
@@ -342,13 +351,17 @@
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
transition
:
height
0.3s
ease
,
padding
0.3s
ease
;
pointer-events
:
none
;
/* 不抢占滚动 */
z-index
:
2
;
opacity
:
0
;
transform
:
translateY
(
-110%
);
transition
:
transform
0.2s
ease
,
opacity
0.2s
ease
;
line-height
:
26px
;
}
.console-status-bar.visible
{
height
:
26px
;
padding
:
0
15px
;
opacity
:
1
;
transform
:
translateY
(
0
);
}
.console-status-bar
.status-message
{
...
...
@@ -372,7 +385,7 @@
left
:
0
;
width
:
100%
;
height
:
100%
;
/* 填满整个黑色框 */
padding
:
15px
;
/* 图层内边距
*/
padding
:
var
(
--console-offset
,
52px
)
15px
15px
;
/* 顶部预留给状态栏与按钮,不影响滚动计算
*/
overflow-y
:
auto
;
/* 允许独立滚动 */
overflow-x
:
hidden
;
box-sizing
:
border-box
;
/* 包含padding在width/height内 */
...
...
@@ -1540,8 +1553,13 @@
this
.
maxVisible
=
150
;
// ↑ from 120(增加可见行数)
this
.
maxLines
=
50000
;
// ↑ from 10000(5倍提升,约5MB/app)
this
.
trimTarget
=
40000
;
// ↑ from 8000(保留更多历史)
this
.
maxPoolSize
=
300
;
// ↑ from 200(更大DOM池)
this
.
preRenderBuffer
=
90
;
// 新增:上下各预渲染90行,提升滚动流畅度
this
.
minPoolSize
=
220
;
// 保底DOM池,避免窗口渲染空白
this
.
poolHardLimit
=
800
;
// 池子硬上限,防止撑爆内存
this
.
maxPoolSize
=
Math
.
max
(
this
.
minPoolSize
,
this
.
maxVisible
+
this
.
preRenderBuffer
*
2
+
50
);
// 默认覆盖可视窗口+缓冲区,再留一些余量
this
.
rafId
=
null
;
this
.
autoScrollEnabled
=
true
;
this
.
resumeDelay
=
3000
;
...
...
@@ -1553,6 +1571,10 @@
this
.
scrollHandler
=
null
;
this
.
beforeSpacer
=
null
;
this
.
afterSpacer
=
null
;
this
.
watchdogTimer
=
null
;
this
.
lastRenderAt
=
0
;
this
.
idleTimer
=
null
;
this
.
idleTimeout
=
3000
;
// 用户3秒不滚动后自动吸附
// 【优化吸附逻辑】记录用户滚动位置,用于智能恢复
this
.
lastUserScrollPosition
=
0
;
// 用户上次滚动的位置
...
...
@@ -1605,6 +1627,90 @@
}
}
clearIdleTimer
()
{
if
(
this
.
idleTimer
)
{
clearTimeout
(
this
.
idleTimer
);
this
.
idleTimer
=
null
;
}
}
startIdleTimer
()
{
this
.
clearIdleTimer
();
this
.
idleTimer
=
setTimeout
(()
=>
{
this
.
autoScrollEnabled
=
true
;
this
.
needsScroll
=
true
;
this
.
clearResumeTimer
();
this
.
scrollToBottom
();
},
this
.
idleTimeout
);
}
// 保障DOM池容量,避免可视窗口比池子大导致空白
ensurePoolCapacity
(
neededCount
)
{
if
(
!
Number
.
isFinite
(
neededCount
))
return
;
// 根据需求量和基线计算DOM池大小,避免窗口比池子大
const
baseline
=
Math
.
min
(
this
.
minPoolSize
,
neededCount
+
80
);
const
targetSize
=
Math
.
min
(
Math
.
max
(
neededCount
,
baseline
,
this
.
pool
.
length
),
this
.
poolHardLimit
);
if
(
targetSize
>
this
.
maxPoolSize
)
{
this
.
maxPoolSize
=
targetSize
;
}
const
missing
=
Math
.
max
(
0
,
targetSize
-
this
.
pool
.
length
);
for
(
let
i
=
0
;
i
<
missing
;
i
++
)
{
const
node
=
document
.
createElement
(
'div'
);
node
.
className
=
'console-line'
;
this
.
pool
.
push
(
node
);
}
}
// DOM意外空白时强制刷新
forceRenderIfBlank
()
{
if
(
!
this
.
container
)
return
false
;
if
(
this
.
lines
.
length
===
0
)
return
false
;
if
(
this
.
container
.
querySelector
(
'.console-line'
))
return
false
;
this
.
lastRenderHash
=
null
;
this
.
needsScroll
=
true
;
this
.
scheduleRender
(
true
);
return
true
;
}
startWatchdog
()
{
if
(
this
.
watchdogTimer
)
return
;
this
.
watchdogTimer
=
setInterval
(()
=>
{
if
(
!
this
.
container
)
return
;
// 黑屏兜底:有数据但没有节点时强制渲染
const
hasLines
=
this
.
lines
.
length
>
0
;
const
hasNodes
=
!!
this
.
container
.
querySelector
(
'.console-line'
);
if
(
hasLines
&&
!
hasNodes
&&
!
this
.
isRendering
)
{
this
.
lastRenderHash
=
null
;
this
.
needsScroll
=
true
;
this
.
updateStatusBar
(
'正在恢复显示...'
,
'检测到渲染延迟'
,
false
,
1200
);
this
.
scheduleRender
(
true
);
return
;
}
// 渲染长时间未推进时,提醒并触发一次刷新
const
now
=
performance
.
now
();
if
(
hasLines
&&
this
.
pending
.
length
>
0
&&
now
-
this
.
lastRenderAt
>
1500
&&
!
this
.
isRendering
)
{
this
.
lastRenderHash
=
null
;
this
.
needsScroll
=
true
;
this
.
updateStatusBar
(
'日志渲染中...'
,
`
$
{
this
.
pending
.
length
}
条待显示`
,
false
,
1200
);
this
.
scheduleRender
(
true
);
}
},
800
);
}
stopWatchdog
()
{
if
(
this
.
watchdogTimer
)
{
clearInterval
(
this
.
watchdogTimer
);
this
.
watchdogTimer
=
null
;
}
}
attachScroll
()
{
if
(
!
this
.
scrollElement
)
return
;
if
(
this
.
scrollHandler
)
return
;
// 防止重复绑定
...
...
@@ -1673,6 +1779,9 @@
// 显示状态栏
this
.
statusBar
.
classList
.
add
(
'visible'
);
if
(
this
.
layoutCache
)
{
this
.
layoutCache
.
invalidate
();
}
// 清除之前的自动隐藏定时器
if
(
this
.
statusBarTimer
)
{
...
...
@@ -1686,6 +1795,9 @@
if
(
this
.
statusBar
)
{
this
.
statusBar
.
classList
.
remove
(
'visible'
);
}
if
(
this
.
layoutCache
)
{
this
.
layoutCache
.
invalidate
();
}
this
.
statusBarTimer
=
null
;
},
duration
);
}
...
...
@@ -1699,6 +1811,9 @@
this
.
statusBarTimer
=
null
;
}
this
.
statusBar
.
classList
.
remove
(
'visible'
);
if
(
this
.
layoutCache
)
{
this
.
layoutCache
.
invalidate
();
}
}
// 添加清理方法
...
...
@@ -1707,6 +1822,7 @@
console
.
log
(
'[性能统计] 最终统计:'
,
this
.
getPerformanceStats
());
// 清理定时器
this
.
stopWatchdog
();
if
(
this
.
rafId
)
{
cancelAnimationFrame
(
this
.
rafId
);
this
.
rafId
=
null
;
...
...
@@ -1716,6 +1832,7 @@
clearTimeout
(
this
.
flushTimer
);
this
.
flushTimer
=
null
;
}
this
.
clearIdleTimer
();
if
(
this
.
statusBarTimer
)
{
clearTimeout
(
this
.
statusBarTimer
);
this
.
statusBarTimer
=
null
;
...
...
@@ -1779,7 +1896,7 @@
// 计算距离底部的距离
const
distanceFromBottom
=
scrollHeight
-
clientHeight
-
currentScrollTop
;
const
atBottom
=
distanceFromBottom
<=
50
;
// 50px阈值
const
atBottom
=
distanceFromBottom
<=
80
;
// 更宽松的阈值,减少误判
if
(
atBottom
)
{
// 用户主动滚动到底部,立即启用自动滚动
...
...
@@ -1808,6 +1925,7 @@
this
.
clearResumeTimer
();
const
delay
=
this
.
calculateResumeDelay
(
distanceFromBottom
);
this
.
startResumeTimer
(
delay
);
this
.
startIdleTimer
();
return
;
}
...
...
@@ -1815,10 +1933,12 @@
console
.
log
(
`
[
自动吸附
]
用户离开底部
$
{
Math
.
round
(
distanceFromBottom
)}
px
,禁用自动滚动`
);
this
.
autoScrollEnabled
=
false
;
this
.
clearResumeTimer
();
this
.
clearIdleTimer
();
// 智能计算恢复时间
const
delay
=
this
.
calculateResumeDelay
(
distanceFromBottom
);
this
.
startResumeTimer
(
delay
);
this
.
startIdleTimer
();
}
/**
...
...
@@ -1847,6 +1967,7 @@
console
.
log
(
`
[
自动吸附
]
$
{
delay
}
ms
后恢复自动滚动,吸附到最新日志`
);
this
.
autoScrollEnabled
=
true
;
this
.
userScrollDistance
=
0
;
this
.
needsScroll
=
true
;
// 【优化】恢复时立即吸附到最新
// 如果有新内容已经渲染完成,直接滚动到最新位置
...
...
@@ -1891,10 +2012,11 @@
}
// 【优化判断】智能阈值:
// - 如果内容少(scrollHeight < 1000px),阈值30px(宽容)
// - 如果内容多,阈值50px(标准)
// 这样能更好地适应不同内容量的情况
const
threshold
=
scrollHeight
<
1000
?
30
:
50
;
// - 超小内容时使用30px
// - 常规50px
// - 当存在状态条/顶部padding时,再增加20px缓冲
const
baseThreshold
=
scrollHeight
<
1000
?
30
:
50
;
const
threshold
=
baseThreshold
+
20
;
const
distanceFromBottom
=
scrollHeight
-
clientHeight
-
scrollTop
;
return
distanceFromBottom
<=
threshold
;
...
...
@@ -1915,9 +2037,42 @@
return
this
.
isNearBottom
();
}
// 将最新一行吸附到可视区域内,而不是盲目对齐到底部
scrollLatestIntoView
(
margin
=
12
)
{
if
(
!
this
.
scrollElement
||
this
.
scrollLocked
)
return
false
;
const
lastLine
=
this
.
scrollElement
.
querySelector
(
'.console-line:last-of-type'
);
if
(
!
lastLine
)
return
false
;
const
container
=
this
.
scrollElement
;
// 最新一行希望落在视口内并留出少量下边距
const
desiredBottom
=
container
.
clientHeight
-
margin
;
const
delta
=
lastLine
.
offsetTop
+
lastLine
.
offsetHeight
-
desiredBottom
;
if
(
delta
>
1
||
delta
<
-
1
)
{
this
.
scrollLocked
=
true
;
requestAnimationFrame
(()
=>
{
container
.
scrollTop
=
Math
.
max
(
0
,
container
.
scrollTop
+
delta
);
if
(
this
.
layoutCache
)
{
this
.
layoutCache
.
invalidate
();
}
setTimeout
(()
=>
{
this
.
scrollLocked
=
false
;
},
80
);
});
}
return
true
;
}
scrollToBottom
()
{
if
(
!
this
.
scrollElement
)
return
;
// 优先将最新一行吸附到视口内,保留边距,避免“对齐页面底部”的跳动
const
snapped
=
this
.
scrollLatestIntoView
(
16
);
if
(
snapped
)
{
this
.
needsScroll
=
false
;
this
.
startIdleTimer
();
return
;
}
// 【修复黑屏】如果正在渲染,延迟滚动避免冲突
if
(
this
.
isRendering
)
{
requestAnimationFrame
(()
=>
this
.
scrollToBottom
());
...
...
@@ -1989,6 +2144,7 @@
}
}
this
.
needsScroll
=
false
;
this
.
startIdleTimer
();
// 解锁滚动(平滑滚动需要更长时间)
setTimeout
(()
=>
{
...
...
@@ -2016,9 +2172,12 @@
this
.
isActive
=
active
;
if
(
active
)
{
this
.
startWatchdog
();
// 【新增逻辑】切换引擎时,重置为自动吸附状态
// 默认用户鼠标未滑动3秒以上
this
.
autoScrollEnabled
=
true
;
this
.
needsScroll
=
true
;
this
.
clearResumeTimer
();
// 【修复】窗口激活时,清除渲染哈希,确保强制渲染
...
...
@@ -2112,6 +2271,17 @@
});
}
}
// 保证切换后立即同步最新内容
this
.
scheduleRender
(
true
);
this
.
startIdleTimer
();
if
(
this
.
lines
.
length
>
0
)
{
requestAnimationFrame
(()
=>
this
.
scrollToBottom
());
}
}
else
{
this
.
stopWatchdog
();
this
.
clearIdleTimer
();
}
}
...
...
@@ -2179,12 +2349,25 @@
}
append
(
text
,
className
=
'console-line'
)
{
const
nearBottom
=
this
.
isNearBottom
();
// 在添加内容前检查是否在底部,如果是则标记需要滚动
if
(
this
.
autoScrollEnabled
&&
this
.
isNearBottom
()
)
{
if
(
this
.
autoScrollEnabled
&&
nearBottom
)
{
this
.
needsScroll
=
true
;
}
else
if
(
!
this
.
autoScrollEnabled
&&
nearBottom
)
{
// 用户并未真正离开底部,自动恢复吸附
this
.
autoScrollEnabled
=
true
;
this
.
needsScroll
=
true
;
this
.
clearResumeTimer
();
}
this
.
pending
.
push
({
text
,
className
});
this
.
pendingHighWaterMark
=
Math
.
max
(
this
.
pendingHighWaterMark
,
this
.
pending
.
length
);
// 队列堆积时给出进度提示(仅当前活动窗口)
if
(
this
.
isActive
&&
this
.
pending
.
length
>
150
)
{
this
.
updateStatusBar
(
'日志渲染中...'
,
`
$
{
this
.
pending
.
length
}
条排队`
,
false
,
1200
);
}
// 【修复黑屏】统一批处理逻辑 - 所有窗口都实时渲染
// 清除之前的定时器
...
...
@@ -2206,6 +2389,9 @@
},
this
.
batchDelay
);
}
// 如果容器当前是空的,强制渲染一次,避免“黑屏等待”
this
.
forceRenderIfBlank
();
this
.
maybeTrim
();
}
...
...
@@ -2332,6 +2518,7 @@
this
.
beforeSpacer
=
null
;
this
.
afterSpacer
=
null
;
}
this
.
lastRenderAt
=
performance
.
now
();
return
;
}
...
...
@@ -2349,6 +2536,7 @@
}
this
.
lastRenderHash
=
contentHash
;
this
.
lastRenderLineCount
=
total
;
this
.
lastRenderAt
=
performance
.
now
();
// 【优化】计算可见区域
const
lh
=
this
.
lineHeight
;
...
...
@@ -2374,14 +2562,33 @@
const
bufferStart
=
Math
.
max
(
0
,
rawStart
-
this
.
preRenderBuffer
);
const
bufferEnd
=
Math
.
min
(
total
,
rawStart
+
visible
+
this
.
preRenderBuffer
);
const
start
=
bufferStart
;
const
end
=
bufferEnd
;
let
start
=
bufferStart
;
let
end
=
bufferEnd
;
let
needed
=
Math
.
max
(
0
,
end
-
start
);
// 【修复白屏】先保证DOM池容量足够覆盖当前窗口
this
.
ensurePoolCapacity
(
needed
);
// 如果窗口仍超过池容量,收缩窗口贴近最新日志,防止中间缺口
if
(
needed
>
this
.
pool
.
length
)
{
const
windowSize
=
this
.
pool
.
length
||
this
.
minPoolSize
;
end
=
Math
.
min
(
total
,
Math
.
max
(
end
,
windowSize
));
start
=
Math
.
max
(
0
,
end
-
windowSize
);
needed
=
Math
.
max
(
0
,
end
-
start
);
}
if
(
needed
===
0
&&
total
>
0
)
{
// 极端情况下兜底展示最新日志,避免空白
end
=
total
;
start
=
Math
.
max
(
0
,
end
-
Math
.
min
(
this
.
maxVisible
,
total
));
needed
=
end
-
start
;
this
.
ensurePoolCapacity
(
needed
);
}
const
beforeHeight
=
start
*
lh
;
const
afterHeight
=
(
total
-
end
)
*
lh
;
const
needed
=
Math
.
max
(
0
,
end
-
start
);
// 【优化】限制DOM节点池大小
// 【优化】限制DOM节点池大小(在更新池容量后执行)
if
(
this
.
pool
.
length
>
this
.
maxPoolSize
)
{
const
excess
=
this
.
pool
.
length
-
this
.
maxPoolSize
;
this
.
pool
.
splice
(
this
.
maxPoolSize
,
excess
).
forEach
(
node
=>
{
...
...
@@ -2391,16 +2598,8 @@
});
}
// 【优化】批量创建DOM节点,减少DOM操作
const
nodesToCreate
=
needed
-
this
.
pool
.
length
;
if
(
nodesToCreate
>
0
&&
this
.
pool
.
length
<
this
.
maxPoolSize
)
{
const
fragment
=
document
.
createDocumentFragment
();
for
(
let
i
=
0
;
i
<
Math
.
min
(
nodesToCreate
,
this
.
maxPoolSize
-
this
.
pool
.
length
);
i
++
)
{
const
node
=
document
.
createElement
(
'div'
);
node
.
className
=
'console-line'
;
this
.
pool
.
push
(
node
);
}
}
// 再次兜底,确保池容量与窗口一致
this
.
ensurePoolCapacity
(
needed
);
// 【优化】复用或创建占位符
if
(
!
this
.
beforeSpacer
)
{
...
...
@@ -2479,6 +2678,8 @@
this
.
scrollToBottom
();
});
}
this
.
lastRenderAt
=
performance
.
now
();
});
}
else
{
// 【优化】增量更新:智能diff算法,只更新必要的节点
...
...
@@ -2579,6 +2780,8 @@
this
.
scrollToBottom
();
});
}
this
.
lastRenderAt
=
performance
.
now
();
}
/**
...
...
@@ -2607,6 +2810,7 @@
const
batchSize
=
200
;
// 每批渲染200行
let
currentBatch
=
0
;
const
totalBatches
=
Math
.
ceil
(
total
/
batchSize
);
this
.
lastRenderAt
=
performance
.
now
();
// 显示渲染进度
const
showProgress
=
()
=>
{
...
...
@@ -2654,6 +2858,7 @@
// 隐藏状态栏
this
.
hideStatusBar
();
this
.
lastRenderAt
=
performance
.
now
();
// 【优化吸附】渲染完成后的智能滚动
// 1. 自动滚动已启用 -> 直接吸附
...
...
@@ -2783,6 +2988,7 @@
// 初始化
document
.
addEventListener
(
'DOMContentLoaded'
,
function
()
{
initializeConsoleLayers
();
syncStatusBarPosition
();
initializeSocket
();
initializeEventListeners
();
ensureSystemReadyOnLoad
();
...
...
@@ -2829,6 +3035,9 @@
// 连接探测定时器(保持运行)
startConnectionProbe
();
// 窗口尺寸变化时同步状态栏位置
window
.
addEventListener
(
'resize'
,
syncStatusBarPosition
);
});
// Socket.IO连接
...
...
@@ -3628,6 +3837,20 @@
return
document
.
getElementById
(
'consoleOutput'
);
}
// 同步状态栏位置,避免覆盖应用切换按钮
function
syncStatusBarPosition
()
{
const
bar
=
document
.
getElementById
(
'consoleStatusBar'
);
const
switcher
=
document
.
querySelector
(
'.app-switcher'
);
if
(
!
bar
||
!
switcher
)
return
;
const
offset
=
switcher
.
offsetHeight
||
0
;
const
barHeight
=
bar
.
offsetHeight
||
26
;
const
totalOffset
=
offset
+
barHeight
+
6
;
// 额外预留6px缓冲
bar
.
style
.
top
=
`
$
{
offset
}
px
`
;
document
.
documentElement
.
style
.
setProperty
(
'--console-offset'
,
`
$
{
totalOffset
}
px
`
);
}
function
initializeConsoleLayers
()
{
const
container
=
getConsoleContainer
();
if
(
!
container
)
return
;
...
...
@@ -3646,11 +3869,7 @@
container
.
appendChild
(
layer
);
consoleLayers
[
app
]
=
layer
;
logRenderers
[
app
]
=
new
LogVirtualList
(
layer
);
// 【图层优化】标记活动窗口
if
(
app
===
currentApp
)
{
logRenderers
[
app
].
isActive
=
true
;
}
logRenderers
[
app
].
setActive
(
app
===
currentApp
);
// 【FIX Bug #3】初始提示立即渲染,避免黑屏
logRenderers
[
app
].
clear
(
`
[
系统
]
$
{
appNames
[
app
]
||
app
}
日志就绪`
);
...
...
@@ -3680,11 +3899,7 @@
container
.
appendChild
(
layer
);
consoleLayers
[
app
]
=
layer
;
logRenderers
[
app
]
=
new
LogVirtualList
(
layer
);
// 【图层优化】标记活动窗口
if
(
app
===
currentApp
)
{
logRenderers
[
app
].
isActive
=
true
;
}
logRenderers
[
app
].
setActive
(
app
===
currentApp
);
return
layer
;
}
...
...
@@ -3718,6 +3933,8 @@
const
renderer
=
logRenderers
[
app
];
if
(
renderer
)
{
renderer
.
setActive
(
true
);
// 会在内部异步渲染待处理内容
renderer
.
needsScroll
=
true
;
renderer
.
scheduleRender
(
true
);
// 确保滚动到底部
if
(
renderer
.
autoScrollEnabled
)
{
...
...
@@ -4485,6 +4702,28 @@
// 创建全局日志管理器实例
const
reportLogManager
=
new
ReportLogManager
();
// 新任务时重置报告日志,避免残留历史输出
function
resetReportLogsForNewTask
(
taskId
,
reason
=
'开始新的报告任务,日志已重置'
)
{
if
(
!
taskId
)
return
;
if
(
reportTaskId
===
taskId
)
return
;
// 已是同一任务,无需重复清空
// 停止当前流与轮询,防止旧日志混入
safeCloseReportStream
();
reportLogManager
.
stop
();
reportLogManager
.
reset
();
// 重置前端计数与缓存
reportLogLineCount
=
0
;
lastLineCount
[
'report'
]
=
0
;
clearConsoleLayer
(
'report'
,
`
[
系统
]
$
{
reason
}
`
);
resetReportStreamOutput
(
'Report Engine 正在启动...'
);
// 重新启动轮询,确保新任务日志即时接入
reportLogManager
.
start
();
reportTaskId
=
taskId
;
}
// 【调试】测试日志管理器
window
.
testReportLogManager
=
function
()
{
console
.
log
(
'[测试] ===== 开始测试Report日志管理器 ====='
);
...
...
@@ -5025,12 +5264,14 @@
if
(
statusData
.
current_task
)
{
updateTaskProgressStatus
(
statusData
.
current_task
);
if
(
statusData
.
current_task
.
status
===
'running'
)
{
reportTaskId
=
statusData
.
current_task
.
task_id
;
const
taskId
=
statusData
.
current_task
.
task_id
;
resetReportLogsForNewTask
(
taskId
,
'检测到正在运行的报告任务,日志已重新开始'
);
reportTaskId
=
taskId
;
reportAutoPreviewLoaded
=
false
;
if
(
window
.
EventSource
)
{
openReportStream
(
reportTaskId
);
}
else
{
startProgressPolling
(
reportT
askId
);
startProgressPolling
(
t
askId
);
}
}
else
if
(
statusData
.
current_task
.
status
===
'completed'
)
{
lastCompletedReportTask
=
statusData
.
current_task
;
...
...
@@ -5527,6 +5768,9 @@
// 更新进度显示(保持向后兼容)
function
updateProgressDisplay
(
task
)
{
if
(
task
&&
task
.
task_id
&&
task
.
status
===
'running'
)
{
resetReportLogsForNewTask
(
task
.
task_id
,
'检测到新的报告任务,日志已同步重置'
);
}
updateTaskProgressStatus
(
task
);
}
...
...
@@ -5735,6 +5979,9 @@
const
task
=
payload
.
task
;
if
(
eventType
===
'status'
&&
task
)
{
if
(
task
.
status
===
'running'
)
{
resetReportLogsForNewTask
(
task
.
task_id
,
'收到流式状态事件,已重置日志'
);
}
updateTaskProgressStatus
(
task
);
reportTaskId
=
task
.
status
===
'running'
?
task
.
task_id
:
null
;
if
(
task
.
status
===
'completed'
)
{
...
...
Please
register
or
login
to post a comment