Refine runtime data flow and UI layering
This commit is contained in:
@@ -57,7 +57,7 @@ export default function AgentCard({ agent, onClose, isClosing }) {
|
||||
background: '#ffffff',
|
||||
borderBottom: '2px solid #000000',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
||||
zIndex: 1000,
|
||||
zIndex: 800,
|
||||
animation: isClosing ? 'slideUp 0.2s ease-out forwards' : 'slideDown 0.25s ease-out'
|
||||
}}>
|
||||
{/* Horizontal scrollable content */}
|
||||
|
||||
@@ -455,6 +455,9 @@ export default function AppShell({
|
||||
newsSnapshot={newsByTicker[selectedExplainSymbol] || null}
|
||||
insiderTradesSnapshot={insiderTradesByTicker[selectedExplainSymbol] || null}
|
||||
technicalIndicatorsSnapshot={technicalIndicatorsByTicker[selectedExplainSymbol] || null}
|
||||
onRequestHistory={stockRequests?.requestStockHistory}
|
||||
onRequestExplainEvents={stockRequests?.requestStockExplainEvents}
|
||||
onRequestNews={stockRequests?.requestStockNews}
|
||||
onRequestRangeExplain={stockRequests?.requestStockRangeExplain}
|
||||
onRequestNewsForDate={stockRequests?.requestStockNewsForDate}
|
||||
onRequestStory={stockRequests?.requestStockStory}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
export default function RuntimeLogsModal({
|
||||
@@ -9,6 +9,32 @@ export default function RuntimeLogsModal({
|
||||
onClose,
|
||||
onRefresh
|
||||
}) {
|
||||
const logRef = useRef(null);
|
||||
const [autoRefresh, setAutoRefresh] = useState(true);
|
||||
const [followTail, setFollowTail] = useState(true);
|
||||
|
||||
const refreshIntervalMs = useMemo(() => 2000, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen || !autoRefresh) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const timerId = window.setInterval(() => {
|
||||
onRefresh();
|
||||
}, refreshIntervalMs);
|
||||
|
||||
return () => window.clearInterval(timerId);
|
||||
}, [autoRefresh, isOpen, onRefresh, refreshIntervalMs]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen || !followTail || !logRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
logRef.current.scrollTop = logRef.current.scrollHeight;
|
||||
}, [followTail, isOpen, logPayload?.content]);
|
||||
|
||||
if (!isOpen) {
|
||||
return null;
|
||||
}
|
||||
@@ -108,8 +134,35 @@ export default function RuntimeLogsModal({
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
padding: '0 20px 12px',
|
||||
display: 'flex',
|
||||
gap: 16,
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap'
|
||||
}}>
|
||||
<label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11, color: '#374151', cursor: 'pointer' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={autoRefresh}
|
||||
onChange={(event) => setAutoRefresh(event.target.checked)}
|
||||
/>
|
||||
实时刷新
|
||||
</label>
|
||||
<label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11, color: '#374151', cursor: 'pointer' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={followTail}
|
||||
onChange={(event) => setFollowTail(event.target.checked)}
|
||||
/>
|
||||
自动滚底
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: '0 20px 20px', minHeight: 0 }}>
|
||||
<pre style={{
|
||||
<pre
|
||||
ref={logRef}
|
||||
style={{
|
||||
margin: 0,
|
||||
height: '100%',
|
||||
minHeight: 320,
|
||||
@@ -125,7 +178,8 @@ export default function RuntimeLogsModal({
|
||||
fontFamily: '"SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace',
|
||||
whiteSpace: 'pre-wrap',
|
||||
wordBreak: 'break-word'
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{logPayload?.content || '暂无日志输出'}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
@@ -33,6 +33,9 @@ export default function StockExplainView({
|
||||
insiderTradesSnapshot,
|
||||
technicalIndicatorsSnapshot,
|
||||
onRequestRangeExplain,
|
||||
onRequestHistory,
|
||||
onRequestExplainEvents,
|
||||
onRequestNews,
|
||||
onRequestNewsForDate,
|
||||
onRequestStory,
|
||||
onRequestInsiderTrades,
|
||||
@@ -142,6 +145,32 @@ export default function StockExplainView({
|
||||
setActiveNewsSentiment('all');
|
||||
}, [selectedSymbol, selectedEventDate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedSymbol) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (onRequestHistory && (!Array.isArray(ohlcHistoryByTicker?.[selectedSymbol]) || ohlcHistoryByTicker[selectedSymbol].length === 0)) {
|
||||
onRequestHistory(selectedSymbol);
|
||||
}
|
||||
|
||||
if (onRequestExplainEvents && !explainEventsSnapshot) {
|
||||
onRequestExplainEvents(selectedSymbol);
|
||||
}
|
||||
|
||||
if (onRequestNews && (!Array.isArray(newsSnapshot?.items) || newsSnapshot.items.length === 0)) {
|
||||
onRequestNews(selectedSymbol);
|
||||
}
|
||||
}, [
|
||||
explainEventsSnapshot,
|
||||
newsSnapshot,
|
||||
ohlcHistoryByTicker,
|
||||
onRequestExplainEvents,
|
||||
onRequestHistory,
|
||||
onRequestNews,
|
||||
selectedSymbol,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedSymbol || !selectedEventDate || !onRequestNewsForDate) {
|
||||
return;
|
||||
|
||||
@@ -578,7 +578,7 @@ export default function GlobalStyles() {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
z-index: 700;
|
||||
}
|
||||
|
||||
.room-scene-wrapper {
|
||||
@@ -680,7 +680,7 @@ export default function GlobalStyles() {
|
||||
line-height: 1.5;
|
||||
animation: bubbleAppear 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
overflow: hidden;
|
||||
z-index: 30;
|
||||
z-index: 1500;
|
||||
}
|
||||
|
||||
@keyframes bubbleAppear {
|
||||
@@ -713,7 +713,7 @@ export default function GlobalStyles() {
|
||||
right: 8px;
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
z-index: 10;
|
||||
z-index: 1510;
|
||||
}
|
||||
|
||||
.bubble-jump-btn,
|
||||
|
||||
Reference in New Issue
Block a user