Add status column with blinking dots, widen shell, risk/open format.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -106,7 +106,7 @@ type RiskLines = {
|
||||
lossPct: string | null;
|
||||
exit: string;
|
||||
openRatio: string | null;
|
||||
/** 表格「风险/开仓」列:以损显示风险%;手动显示名义比例 */
|
||||
/** 表格「风险/开仓」列:如 5%/1:2;手动为 —/名义比 */
|
||||
riskOrOpen: string;
|
||||
leverage: string;
|
||||
};
|
||||
@@ -144,7 +144,7 @@ function riskLines(strat: Record<string, unknown>): RiskLines {
|
||||
const openRatio = riskBased
|
||||
? `${unitLabel(strat.risk_perp_unit)}:${unitLabel(strat.risk_option_unit)}`
|
||||
: `${unitLabel(strat.perp_qty_eth)}:${unitLabel(strat.option_qty_eth)}`;
|
||||
const riskOrOpen = riskBased ? lossPct || "—" : openRatio;
|
||||
const riskOrOpen = `${lossPct || "—"}/${openRatio}`;
|
||||
return {
|
||||
riskBased,
|
||||
sizing: riskBased ? "以损定仓" : "手动仓位",
|
||||
@@ -516,6 +516,7 @@ export default function MonitorPage() {
|
||||
<th className="col-check">
|
||||
<span className="sr-only">选择</span>
|
||||
</th>
|
||||
<th className="col-status">状态</th>
|
||||
<th>机器名字</th>
|
||||
<th>模式</th>
|
||||
<th>交易所</th>
|
||||
@@ -550,30 +551,38 @@ export default function MonitorPage() {
|
||||
aria-label={`选择 ${n.name}`}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div className="machine-cell">
|
||||
<td className="col-status">
|
||||
<div
|
||||
className="status-dots"
|
||||
title={`在线:${n.online ? "是" : "否"} · ${tokenDotTitle(n)} · ${running ? "运行中" : "已停"}`}
|
||||
>
|
||||
<span
|
||||
className={`dot ${n.online ? "ok" : "bad"}`}
|
||||
className={`dot pulse d1 ${n.online ? "ok" : "bad"}`}
|
||||
title={n.online ? "在线" : "离线"}
|
||||
/>
|
||||
<span
|
||||
className={tokenDotClass(n)}
|
||||
className={`dot pulse d2 ${tokenDotClass(n).replace("dot ", "")}`}
|
||||
title={tokenDotTitle(n)}
|
||||
/>
|
||||
<span
|
||||
className={`run-dot ${running ? "ok" : "bad"}`}
|
||||
className={`dot pulse d3 ${running ? "ok" : "bad"}`}
|
||||
title={running ? "运行中" : "已停"}
|
||||
/>
|
||||
<strong className="machine-name">{n.name}</strong>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<strong className="machine-name">{n.name}</strong>
|
||||
</td>
|
||||
<td className="mono">{modeLabel(s.mode, s.strat)}</td>
|
||||
<td className="mono">{s.exchange}</td>
|
||||
<td className={inPos ? "pnl-pos" : "pnl-neg"}>
|
||||
{inPos ? "持仓中" : "无持仓"}
|
||||
</td>
|
||||
<td className="mono">{s.rounds ?? "—"}</td>
|
||||
<td className="mono" title={risk.riskBased ? "风险比例" : "开仓比例"}>
|
||||
<td
|
||||
className="mono"
|
||||
title="风险比例 / 开仓比例"
|
||||
>
|
||||
{risk.riskOrOpen}
|
||||
</td>
|
||||
<td className="mono">{risk.exit}</td>
|
||||
|
||||
@@ -25,9 +25,11 @@ body {
|
||||
}
|
||||
|
||||
.shell {
|
||||
max-width: 1200px;
|
||||
width: 100%;
|
||||
max-width: min(1920px, 100%);
|
||||
margin: 0 auto;
|
||||
padding: 16px 20px 40px;
|
||||
padding: 16px 24px 40px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -211,17 +213,20 @@ input {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
background: var(--panel);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.monitor-table {
|
||||
width: 100%;
|
||||
min-width: 1100px;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.88rem;
|
||||
font-size: 0.9rem;
|
||||
table-layout: auto;
|
||||
}
|
||||
|
||||
.monitor-table th,
|
||||
.monitor-table td {
|
||||
padding: 10px 12px;
|
||||
padding: 12px 14px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
@@ -254,53 +259,91 @@ input {
|
||||
}
|
||||
|
||||
.monitor-table .col-check {
|
||||
width: 36px;
|
||||
width: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.monitor-table .col-status {
|
||||
width: 88px;
|
||||
}
|
||||
|
||||
.monitor-table .col-actions {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.machine-cell {
|
||||
.status-dots {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
min-width: 0;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.machine-name {
|
||||
font-weight: 650;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.dot,
|
||||
.run-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
.dot {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
background: var(--muted);
|
||||
}
|
||||
|
||||
.dot.ok,
|
||||
.run-dot.ok {
|
||||
.dot.ok {
|
||||
background: var(--ok, #3cb371);
|
||||
box-shadow: 0 0 0 2px rgba(60, 179, 113, 0.2);
|
||||
box-shadow: 0 0 0 2px rgba(60, 179, 113, 0.25);
|
||||
}
|
||||
|
||||
.dot.bad,
|
||||
.run-dot.bad {
|
||||
.dot.bad {
|
||||
background: var(--bad, #e35d5d);
|
||||
box-shadow: 0 0 0 2px rgba(227, 93, 93, 0.2);
|
||||
box-shadow: 0 0 0 2px rgba(227, 93, 93, 0.25);
|
||||
}
|
||||
|
||||
.dot.warn {
|
||||
background: #e6a23c;
|
||||
box-shadow: 0 0 0 2px rgba(230, 162, 60, 0.25);
|
||||
box-shadow: 0 0 0 2px rgba(230, 162, 60, 0.3);
|
||||
}
|
||||
|
||||
.dot.muted {
|
||||
background: #5a6570;
|
||||
box-shadow: 0 0 0 2px rgba(90, 101, 112, 0.25);
|
||||
}
|
||||
|
||||
.dot.pulse {
|
||||
animation: status-blink 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.dot.pulse.d1 {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.dot.pulse.d2 {
|
||||
animation-delay: 0.25s;
|
||||
}
|
||||
|
||||
.dot.pulse.d3 {
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
|
||||
@keyframes status-blink {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
filter: brightness(1.15);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.35;
|
||||
transform: scale(0.85);
|
||||
filter: brightness(0.85);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.dot.pulse {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.row-actions {
|
||||
|
||||
Reference in New Issue
Block a user