Fix hedge-plan option list to 5-row scroll viewport and add auto-deploy rule.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-14 12:43:23 +08:00
parent 27f4f5e2ee
commit 036501b70c
6 changed files with 44 additions and 77 deletions
+18
View File
@@ -0,0 +1,18 @@
---
description: After each completed code change, commit, push origin/main, and deploy to zk.hyf2.cc
alwaysApply: true
---
# Auto push & deploy
When a user-facing code change is **finished** (not mid-debug / not "先不要改代码"):
1. Commit only the relevant files (skip unrelated CRLF-only docs noise).
2. `git push origin main` to `https://git.bz121.com/dekun/crypto_monitor.git`.
3. Deploy to production `zk.hyf2.cc`:`cd /opt/crypto_monitor && git pull && bash deploy/pull_and_restart.sh`.
4. Confirm PM2 processes are online; briefly report commit hash + deploy status.
Do **not** wait for the user to say "推送并部署" again unless they cancel this habit.
SSH: Prefer key auth; if BatchMode fails, use existing Paramiko root login path used in this project.
Do not print or put passwords in user-facing replies.
+3 -55
View File
@@ -276,13 +276,11 @@
}); });
} }
function pickContract(c, list) { function pickContract(c) {
if (!c) return; if (!c) return;
state.selected = c; state.selected = c;
const el = $("hp-sel-inst"); const el = $("hp-sel-inst");
if (el) el.textContent = c.inst_id; if (el) el.textContent = c.inst_id;
const sel = $("hp-strike-select");
if (sel) sel.value = c.inst_id;
const tbody = $("hp-strike-tbody"); const tbody = $("hp-strike-tbody");
if (tbody) { if (tbody) {
tbody.querySelectorAll(".opt-strike-row").forEach(function (r) { tbody.querySelectorAll(".opt-strike-row").forEach(function (r) {
@@ -295,33 +293,6 @@
updatePremiumLine(); updatePremiumLine();
} }
function strikeOptionLabel(c) {
return (
"K" +
c.strike +
" " +
(c.moneyness_label || c.opt_type || "") +
" " +
fmtPxSz(c.ask, c.ask_sz, c.ask_estimated, c.tick_sz)
);
}
function fillStrikeSelect(list, prevInst) {
const sel = $("hp-strike-select");
if (!sel) return;
const rest = (list || []).slice(5);
sel.innerHTML = '<option value="">更多行权价(' + rest.length + ")…</option>";
rest.forEach(function (c) {
const opt = document.createElement("option");
opt.value = c.inst_id;
opt.textContent = strikeOptionLabel(c);
sel.appendChild(opt);
});
if (prevInst && rest.some(function (c) { return c.inst_id === prevInst; })) {
sel.value = prevInst;
}
}
function renderListStrikes() { function renderListStrikes() {
const tbody = $("hp-strike-tbody"); const tbody = $("hp-strike-tbody");
if (!tbody) return; if (!tbody) return;
@@ -332,7 +303,6 @@
tbody.innerHTML = ""; tbody.innerHTML = "";
if (!exp) { if (!exp) {
tbody.innerHTML = '<tr><td colspan="5" class="muted">请选择到期日</td></tr>'; tbody.innerHTML = '<tr><td colspan="5" class="muted">请选择到期日</td></tr>';
fillStrikeSelect([], null);
return; return;
} }
const list = (exp.contracts || []).filter(function (c) { const list = (exp.contracts || []).filter(function (c) {
@@ -340,12 +310,9 @@
}); });
if (!list.length) { if (!list.length) {
tbody.innerHTML = '<tr><td colspan="5" class="muted">无匹配合约</td></tr>'; tbody.innerHTML = '<tr><td colspan="5" class="muted">无匹配合约</td></tr>';
fillStrikeSelect([], null);
return; return;
} }
const visible = list.slice(0, 5); list.forEach(function (c) {
fillStrikeSelect(list, prevInst);
visible.forEach(function (c) {
const tr = document.createElement("tr"); const tr = document.createElement("tr");
tr.className = "opt-strike-row" + (c.moneyness ? " opt-row-" + c.moneyness : ""); tr.className = "opt-strike-row" + (c.moneyness ? " opt-row-" + c.moneyness : "");
if (prevInst && c.inst_id === prevInst) tr.classList.add("opt-row-selected"); if (prevInst && c.inst_id === prevInst) tr.classList.add("opt-row-selected");
@@ -366,21 +333,13 @@
'">选用</button></td>'; '">选用</button></td>';
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
if (list.length > 5) {
const tip = document.createElement("tr");
tip.innerHTML =
'<td colspan="5" class="muted">仅显示前 5 行,其余 ' +
(list.length - 5) +
" 条请用上方下拉框选用</td>";
tbody.appendChild(tip);
}
tbody.querySelectorAll(".hp-pick").forEach(function (btn) { tbody.querySelectorAll(".hp-pick").forEach(function (btn) {
btn.addEventListener("click", function () { btn.addEventListener("click", function () {
const inst = btn.getAttribute("data-inst"); const inst = btn.getAttribute("data-inst");
const c = list.find(function (x) { const c = list.find(function (x) {
return x.inst_id === inst; return x.inst_id === inst;
}); });
pickContract(c, list); pickContract(c);
}); });
}); });
} }
@@ -687,17 +646,6 @@
}); });
if ($("hp-exp-select")) $("hp-exp-select").addEventListener("change", renderListStrikes); if ($("hp-exp-select")) $("hp-exp-select").addEventListener("change", renderListStrikes);
if ($("hp-oo-exp-select")) $("hp-oo-exp-select").addEventListener("change", renderTStrikes); if ($("hp-oo-exp-select")) $("hp-oo-exp-select").addEventListener("change", renderTStrikes);
if ($("hp-strike-select")) {
$("hp-strike-select").addEventListener("change", function () {
const inst = $("hp-strike-select").value;
if (!inst || !state.chain) return;
const exp = currentExp("hp-exp-select");
const c = ((exp && exp.contracts) || []).find(function (x) {
return x.inst_id === inst;
});
if (c) pickContract(c);
});
}
if ($("hp-sheets")) $("hp-sheets").addEventListener("input", updatePremiumLine); if ($("hp-sheets")) $("hp-sheets").addEventListener("input", updatePremiumLine);
if ($("hp-preview-btn")) if ($("hp-preview-btn"))
$("hp-preview-btn").addEventListener("click", function () { $("hp-preview-btn").addEventListener("click", function () {
+13 -7
View File
@@ -3296,8 +3296,7 @@ html[data-theme="light"] .opt-be-dist-down {
margin: 4px 0; margin: 4px 0;
align-items: center; align-items: center;
} }
.hedge-plan-page-wrap .hp-opt-toolbar select, .hedge-plan-page-wrap .hp-opt-toolbar select {
.hedge-plan-page-wrap .hp-strike-pick-label select {
max-width: 168px; max-width: 168px;
font-size: 0.72rem; font-size: 0.72rem;
padding: 3px 6px; padding: 3px 6px;
@@ -3309,9 +3308,14 @@ html[data-theme="light"] .opt-be-dist-down {
min-height: 26px; min-height: 26px;
font-size: 0.72rem; font-size: 0.72rem;
} }
.hedge-plan-page-wrap .hp-strike-table-wrap--5 { /* 视口约 5 行数据 + 表头;超出表内滚动 */
max-height: 168px; /* 表头 + 约 5 行 */ .hedge-plan-page-wrap .hp-strike-table-wrap--5,
.hedge-plan-page-wrap .options-strike-table-wrap--t {
max-height: 220px;
min-height: 220px;
overflow-y: auto;
margin-top: 4px; margin-top: 4px;
flex: 1 1 auto;
} }
.hedge-plan-page-wrap .hp-opt-bal-line { .hedge-plan-page-wrap .hp-opt-bal-line {
margin-top: 4px; margin-top: 4px;
@@ -3319,12 +3323,10 @@ html[data-theme="light"] .opt-be-dist-down {
.hedge-plan-page-wrap .hp-acct-hint { .hedge-plan-page-wrap .hp-acct-hint {
display: none; display: none;
} }
.hedge-plan-page-wrap .options-strike-table-wrap--t {
max-height: 168px;
}
.hedge-plan-page-wrap .options-dual-grid { .hedge-plan-page-wrap .options-dual-grid {
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
align-items: stretch; align-items: stretch;
margin-bottom: 20px;
} }
.hedge-plan-page-wrap .options-dual-grid > .card { .hedge-plan-page-wrap .options-dual-grid > .card {
height: 100%; height: 100%;
@@ -3332,6 +3334,10 @@ html[data-theme="light"] .opt-be-dist-down {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.hedge-plan-page-wrap .hp-preview-card {
margin-top: 8px;
clear: both;
}
.hedge-plan-page-wrap .hp-pick.active, .hedge-plan-page-wrap .hp-pick.active,
.hedge-plan-page-wrap .opt-row-selected td { .hedge-plan-page-wrap .opt-row-selected td {
background: rgba(90, 140, 255, 0.18); background: rgba(90, 140, 255, 0.18);
+8 -13
View File
@@ -57,16 +57,6 @@
<button type="button" class="btn-secondary" id="hp-load-chain">刷新链</button> <button type="button" class="btn-secondary" id="hp-load-chain">刷新链</button>
</div> </div>
<div id="hp-index-line" class="muted hp-quote-line"></div> <div id="hp-index-line" class="muted hp-quote-line"></div>
<div class="form-row hp-pick-row">
<label class="hp-strike-pick-label">合约
<select id="hp-strike-select" title="从列表外合约中快速选用">
<option value="">更多行权价…</option>
</select>
</label>
<label>已选 <code id="hp-sel-inst"></code></label>
<label>张数 <input type="number" step="1" min="1" id="hp-sheets" value="1" /></label>
<span class="muted" id="hp-premium-line"></span>
</div>
<div class="options-strike-table-wrap hp-strike-table-wrap--5"> <div class="options-strike-table-wrap hp-strike-table-wrap--5">
<table class="options-strike-table" id="hp-strike-table"> <table class="options-strike-table" id="hp-strike-table">
<thead> <thead>
@@ -83,10 +73,15 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="form-row hp-pick-row">
<label>已选 <code id="hp-sel-inst"></code></label>
<label>张数 <input type="number" step="1" min="1" id="hp-sheets" value="1" /></label>
<span class="muted" id="hp-premium-line"></span>
</div>
<div id="hp-opt-bal-line" class="muted hp-quote-line hp-opt-bal-line"></div> <div id="hp-opt-bal-line" class="muted hp-quote-line hp-opt-bal-line"></div>
</div> </div>
</div> </div>
<div class="card" style="margin-top:12px" id="hp-preview-card-po"> <div class="card hp-preview-card" id="hp-preview-card-po">
<div style="display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between"> <div style="display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between">
<h2 style="margin:0">情景测算</h2> <h2 style="margin:0">情景测算</h2>
<div class="form-row" style="margin:0"> <div class="form-row" style="margin:0">
@@ -155,7 +150,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="card" style="margin-top:12px"> <div class="card hp-preview-card">
<div style="display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between"> <div style="display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:space-between">
<h2 style="margin:0">情景测算</h2> <h2 style="margin:0">情景测算</h2>
<button type="button" class="primary" id="hp-preview-btn-oo">计算</button> <button type="button" class="primary" id="hp-preview-btn-oo">计算</button>
@@ -197,4 +192,4 @@
</div> </div>
</div> </div>
</div> </div>
<script src="/static/hedge_plan.js?v=5"></script> <script src="/static/hedge_plan.js?v=6"></script>
+1 -1
View File
@@ -7,7 +7,7 @@
<link rel="stylesheet" href="/static/instance_theme_early.css?v=4"> <link rel="stylesheet" href="/static/instance_theme_early.css?v=4">
<link rel="stylesheet" href="/static/account_risk_badge.css?v=4"> <link rel="stylesheet" href="/static/account_risk_badge.css?v=4">
<link rel="stylesheet" href="/static/instance_page.css?v=6"> <link rel="stylesheet" href="/static/instance_page.css?v=6">
<link rel="stylesheet" href="/static/instance_theme.css?v=84"> <link rel="stylesheet" href="/static/instance_theme.css?v=85">
<script src="/static/account_risk_badge.js?v=4"></script> <script src="/static/account_risk_badge.js?v=4"></script>
<meta name="theme-color" content="#0b0d14"> <meta name="theme-color" content="#0b0d14">
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title> <title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
+1 -1
View File
@@ -17,7 +17,7 @@
<link rel="manifest" href="/static/icons/manifest.webmanifest"> <link rel="manifest" href="/static/icons/manifest.webmanifest">
<title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title> <title>{{ exchange_display }} · 加密货币 | 交易监控复盘系统</title>
<link rel="stylesheet" href="/static/instance_page.css?v=3"> <link rel="stylesheet" href="/static/instance_page.css?v=3">
<link rel="stylesheet" href="/static/instance_theme.css?v=84"> <link rel="stylesheet" href="/static/instance_theme.css?v=85">
</head> </head>
<body <body