This commit is contained in:
aaron 2026-04-25 15:59:11 +08:00
parent 8cb4ad9762
commit 2779330ee5

View File

@ -975,6 +975,91 @@
gap: 10px;
}
.signal-feed-grid {
display: grid;
gap: 12px;
}
.signal-feed-card {
padding: 14px 16px;
border-radius: 16px;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.06);
}
.signal-feed-card.buy {
border-color: rgba(48, 209, 88, 0.18);
background: rgba(48, 209, 88, 0.07);
}
.signal-feed-card.sell {
border-color: rgba(255, 111, 97, 0.18);
background: rgba(255, 111, 97, 0.07);
}
.signal-feed-head {
display: flex;
justify-content: space-between;
gap: 12px;
align-items: flex-start;
margin-bottom: 10px;
}
.signal-feed-symbol {
font-size: 16px;
font-weight: 700;
color: var(--text);
}
.signal-feed-meta {
color: var(--muted);
font-size: 11px;
font-family: "IBM Plex Mono", monospace;
line-height: 1.5;
}
.signal-feed-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 10px;
}
.signal-feed-stats {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
margin-bottom: 10px;
}
.signal-feed-stat {
padding: 10px 12px;
border-radius: 12px;
background: rgba(255,255,255,0.03);
}
.signal-feed-stat .label {
display: block;
color: var(--muted);
font-size: 10px;
margin-bottom: 4px;
text-transform: uppercase;
letter-spacing: 0.05em;
font-family: "IBM Plex Mono", monospace;
}
.signal-feed-stat .value {
font-family: "IBM Plex Mono", monospace;
font-size: 13px;
color: var(--text);
}
.signal-feed-reason {
color: var(--muted);
font-size: 12px;
line-height: 1.65;
}
.workspace-stream {
min-height: 0;
}
@ -1673,6 +1758,101 @@
background: rgba(255,255,255,0.02);
}
.position-card-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.position-card {
padding: 16px;
border-radius: 18px;
background: rgba(255,255,255,0.03);
border: 1px solid rgba(255,255,255,0.06);
}
.position-card.long {
border-color: rgba(48, 209, 88, 0.18);
}
.position-card.short {
border-color: rgba(255, 111, 97, 0.18);
}
.position-card-head {
display: flex;
justify-content: space-between;
gap: 12px;
align-items: flex-start;
margin-bottom: 12px;
}
.position-card-symbol {
font-size: 16px;
font-weight: 700;
color: var(--text);
}
.position-card-meta {
color: var(--muted);
font-size: 11px;
font-family: "IBM Plex Mono", monospace;
line-height: 1.5;
}
.position-card-pnl {
text-align: right;
}
.position-card-pnl .amount {
font-family: "IBM Plex Mono", monospace;
font-size: 18px;
font-weight: 600;
}
.position-card-pnl .ratio {
margin-top: 4px;
font-family: "IBM Plex Mono", monospace;
font-size: 12px;
}
.position-card-gridline {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
margin-bottom: 12px;
}
.position-card-block {
padding: 10px 12px;
border-radius: 12px;
background: rgba(255,255,255,0.03);
}
.position-card-block .label {
display: block;
color: var(--muted);
font-size: 10px;
margin-bottom: 4px;
text-transform: uppercase;
letter-spacing: 0.05em;
font-family: "IBM Plex Mono", monospace;
}
.position-card-block .value {
font-family: "IBM Plex Mono", monospace;
font-size: 13px;
color: var(--text);
line-height: 1.55;
}
.position-card-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 10px;
}
.unified-table table {
min-width: 980px;
}
@ -1771,12 +1951,15 @@
.platform-grid,
.signal-grid,
.ops-grid,
.coord-grid {
.coord-grid,
.position-card-grid {
grid-template-columns: 1fr;
}
.platform-overview,
.platform-stats {
.platform-stats,
.signal-feed-stats,
.position-card-gridline {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@ -1807,6 +1990,8 @@
.hero-metrics,
.platform-stats,
.platform-overview,
.signal-feed-stats,
.position-card-gridline,
.signal-stats,
.heartbeat-grid,
.health-ribbon,
@ -2817,17 +3002,46 @@
return;
}
container.innerHTML = signals.map((signal) => `
<div class="stream-item">
<div class="time">${relativeTime(signal.created_at)}<br>${formatTime(signal.created_at)}</div>
<div class="headline">
<strong>${signal.symbol || '-'}</strong>
${signal.action === 'buy' ? '做多' : signal.action === 'sell' ? '做空' : '观望'}
<span style="color: var(--muted);">| ${signal.signal_type || '-'} | ${signal.timeframe || signal.type || '-'}</span>
container.innerHTML = `
<div class="signal-feed-grid">
${signals.slice(0, 5).map((signal) => `
<article class="signal-feed-card ${signal.action || 'wait'}">
<div class="signal-feed-head">
<div>
<div class="signal-feed-symbol">${signal.symbol || '-'}</div>
<div class="signal-feed-meta">${relativeTime(signal.created_at)} / ${formatTime(signal.created_at)}</div>
</div>
<div class="grade">${signal.grade || '-'} / ${formatPercent(signal.confidence || 0, 1)}</div>
<span class="badge ${statusClassFromAction(signal.action)}">${signal.action === 'buy' ? '做多' : signal.action === 'sell' ? '做空' : '观望'}</span>
</div>
`).join('');
<div class="signal-feed-tags">
<span class="event-inline-badge">${signal.signal_type || '-'}</span>
<span class="event-inline-badge">${signal.timeframe || signal.type || '-'}</span>
${signal.grade ? `<span class="event-inline-badge">${signal.grade}</span>` : ''}
${signal.setup_type ? `<span class="event-inline-badge">${signal.setup_type}</span>` : ''}
</div>
<div class="signal-feed-stats">
<div class="signal-feed-stat">
<span class="label">信心度</span>
<span class="value">${formatPercent(signal.confidence || 0, 1)}</span>
</div>
<div class="signal-feed-stat">
<span class="label">价格</span>
<span class="value">入场 ${formatMoney(signal.entry_price)} / 现价 ${formatMoney(signal.current_price)}</span>
</div>
<div class="signal-feed-stat">
<span class="label">止盈止损</span>
<span class="value">${formatMoney(signal.take_profit)} / ${formatMoney(signal.stop_loss)}</span>
</div>
<div class="signal-feed-stat">
<span class="label">仓位 / 入场方式</span>
<span class="value">${signal.position_size || '-'} / ${signal.entry_type || '-'}</span>
</div>
</div>
<div class="signal-feed-reason">${signal.reasoning || signal.reason || signal.summary || '暂无详细分析理由'}</div>
</article>
`).join('')}
</div>
`;
}
function renderAgentSignals(cryptoAgent, signalStats) {
@ -3280,40 +3494,45 @@
}
container.innerHTML = `
<table>
<thead>
<tr>
<th>平台</th>
<th>账号</th>
<th>交易对</th>
<th>方向</th>
<th>入场 / 现价</th>
<th>仓位 / 杠杆</th>
<th>Setup</th>
<th>止盈 / 止损</th>
<th>未实现盈亏</th>
<th>盈亏比例</th>
<th>时间</th>
</tr>
</thead>
<tbody>
<div class="position-card-grid">
${total.map((item) => `
<tr>
<td><span class="platform-pill">${item.platform}</span></td>
<td class="inline-mono">${item.account_id || '-'}</td>
<td><strong>${item.symbol || '-'}</strong></td>
<td><span class="side-pill ${item.side === 'long' ? 'long' : 'short'}">${item.side === 'long' ? 'long' : 'short'}</span></td>
<td class="inline-mono">${formatMoney(item.entry_price)} / ${formatMoney(item.mark_price)}</td>
<td class="inline-mono">${formatNumber(item.size, 4)} / ${formatNumber(item.leverage, 1)}x</td>
<td>${item.setup_type ? `<div class="inline-mono">${item.setup_type}</div><div class="analysis-log-detail">${item.entry_basis || item.setup_basis || '-'}</div>` : '-'}</td>
<td class="inline-mono">${item.take_profit ? formatMoney(item.take_profit) : '-'} / ${item.stop_loss ? formatMoney(item.stop_loss) : '-'}</td>
<td style="color:${(item.unrealized_pnl || 0) >= 0 ? 'var(--good)' : 'var(--danger)'}">${formatMoney(item.unrealized_pnl)}</td>
<td style="color:${(item.pnl_percent || 0) >= 0 ? 'var(--good)' : 'var(--danger)'}">${formatPercent(item.pnl_percent, 2)}</td>
<td class="inline-mono">${item.opened_at ? relativeTime(item.opened_at) : '-'}</td>
</tr>
<article class="position-card ${item.side === 'long' ? 'long' : 'short'}">
<div class="position-card-head">
<div>
<div class="position-card-symbol">${item.symbol || '-'}</div>
<div class="position-card-meta">${item.platform || '-'} / ${item.account_id || '-'} / ${item.opened_at ? `${relativeTime(item.opened_at)} / ${formatTime(item.opened_at)}` : '-'}</div>
</div>
<div class="position-card-pnl">
<div class="amount" style="color:${(item.unrealized_pnl || 0) >= 0 ? 'var(--good)' : 'var(--danger)'}">${formatMoney(item.unrealized_pnl)}</div>
<div class="ratio" style="color:${(item.pnl_percent || 0) >= 0 ? 'var(--good)' : 'var(--danger)'}">${formatPercent(item.pnl_percent, 2)}</div>
</div>
</div>
<div class="position-card-tags">
<span class="platform-pill">${item.platform}</span>
<span class="side-pill ${item.side === 'long' ? 'long' : 'short'}">${item.side === 'long' ? 'long' : 'short'}</span>
${item.setup_type ? `<span class="event-inline-badge">${item.setup_type}</span>` : ''}
</div>
<div class="position-card-gridline">
<div class="position-card-block">
<span class="label">入场 / 现价</span>
<span class="value">${formatMoney(item.entry_price)} / ${formatMoney(item.mark_price)}</span>
</div>
<div class="position-card-block">
<span class="label">仓位 / 杠杆</span>
<span class="value">${formatNumber(item.size, 4)} / ${formatNumber(item.leverage, 1)}x</span>
</div>
<div class="position-card-block">
<span class="label">止盈 / 止损</span>
<span class="value">${item.take_profit ? formatMoney(item.take_profit) : '-'} / ${item.stop_loss ? formatMoney(item.stop_loss) : '-'}</span>
</div>
<div class="position-card-block">
<span class="label">Setup / Entry</span>
<span class="value">${item.setup_type || '-'}${item.entry_basis || item.setup_basis ? `<br>${item.entry_basis || item.setup_basis}` : ''}</span>
</div>
</div>
</article>
`).join('')}
</tbody>
</table>
</div>
`;
}