feat(risk): add account cooldown and daily freeze after manual/external close

Implements shared account_risk_lib with 4h/1h cooloff and daily freeze rules, wires hooks into all four exchange apps and hub monitor UI, with tests and docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-17 17:05:19 +08:00
parent b77741ee21
commit e307eef690
18 changed files with 1015 additions and 5 deletions
+30
View File
@@ -593,6 +593,36 @@ button:disabled {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.risk-status-badge {
font-size: 0.72rem;
font-weight: 600;
padding: 2px 8px;
border-radius: 999px;
border: 1px solid transparent;
white-space: nowrap;
}
.risk-status-normal {
color: #b8f5d0;
background: #14241e;
border-color: #2d6a4f;
}
.risk-status-freeze_1h {
color: #ffd89a;
background: #2a2210;
border-color: #8a6a20;
}
.risk-status-freeze_4h {
color: #ffb4a0;
background: #2a1410;
border-color: #8a4020;
}
.risk-status-freeze_daily {
color: #ffb0c8;
background: #2a1020;
border-color: #8a3050;
}
.status-dot {
+10 -2
View File
@@ -508,6 +508,14 @@
.replace(/"/g, "&quot;");
}
function formatRiskStatusBadge(riskStatus) {
if (!riskStatus || typeof riskStatus !== "object") return "";
const st = riskStatus.status || "normal";
const label = esc(riskStatus.status_label || "正常");
const title = esc(riskStatus.reason || "");
return `<span class="risk-status-badge risk-status-${esc(st)}" title="${title}">${label}</span>`;
}
function fmt(n, d) {
if (n === null || n === undefined || Number.isNaN(Number(n))) return "—";
return Number(n).toLocaleString(undefined, { maximumFractionDigits: d });
@@ -3240,7 +3248,7 @@
<div class="hub-tile-body card-expand-zone" title="点击进入全屏详情">
<div class="hub-tile-top">
<span class="status-dot ${dotCls}" aria-hidden="true"></span>
<span class="hub-tile-name">${esc(row.name)}</span>
<span class="hub-tile-name">${esc(row.name)}${formatRiskStatusBadge(hm.risk_status)}</span>
</div>
${
showAccountPnlPref()
@@ -3293,7 +3301,7 @@
<div>
<div class="card-title-row">
<span class="status-dot ${dotCls}" title="${online ? "在线" : "离线"}"></span>
<div class="card-title">${esc(row.name)}</div>
<div class="card-title">${esc(row.name)}${formatRiskStatusBadge(hm.risk_status)}</div>
</div>
<div class="card-sub">${esc(flaskOpen || "")}</div>
</div>