diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index ac94e2b..46e7ad2 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -4161,6 +4161,132 @@ body.login-page { overflow: auto; } +.market-vol-rank-list.is-div-scan-list { + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 8px; + max-height: min(52vh, 420px); + padding: 4px 2px 8px; +} + +.market-vol-rank-li { + list-style: none; + min-width: 0; +} + +.market-div-scan-meta-title, +.div-scan-meta-title { + font-size: 0.78rem; + color: var(--text); + font-weight: 600; +} + +.market-div-scan-meta-sub, +.div-scan-meta-sub { + margin-top: 2px; + font-size: 0.68rem; + color: var(--muted); +} + +.market-vol-rank-item.is-div-scan { + display: flex; + flex-direction: column; + align-items: stretch; + gap: 8px; + padding: 10px 12px; + border: 1px solid var(--border-soft); + border-radius: 8px; + background: var(--inset-surface); + min-height: 4.5rem; +} + +.market-vol-rank-item.is-div-scan:hover { + border-color: rgba(0, 255, 157, 0.28); + background: rgba(0, 255, 157, 0.06); +} + +.market-vol-rank-item.is-div-scan.is-active { + border-color: rgba(0, 255, 157, 0.45); + background: rgba(0, 255, 157, 0.1); +} + +.div-scan-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + min-width: 0; +} + +.div-scan-head { + gap: 10px; +} + +.div-scan-head .market-vol-rank-sym { + font-size: 0.92rem; + font-weight: 700; + flex: 1 1 auto; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.div-scan-head .market-vol-rank-no { + font-size: 0.72rem; +} + +.div-scan-head .market-vol-rank-badge { + font-size: 0.7rem; + padding: 2px 8px; +} + +.div-scan-sub { + gap: 10px; + padding-left: 2px; +} + +.div-scan-dir { + font-size: 0.8rem; + font-weight: 600; +} + +.div-scan-dir.is-bull { + color: #4cd97f; +} + +.div-scan-dir.is-bear { + color: #ff7a9a; +} + +.div-scan-dir.is-split { + color: #b8bcc4; +} + +.div-scan-fresh { + font-size: 0.72rem; + color: var(--muted); +} + +.div-scan-split-detail { + font-size: 0.72rem; + color: #b8bcc4; +} + +.div-scan-tf-pills { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-left: auto; +} + +.div-scan-tf-pill { + padding: 1px 6px; + border-radius: 4px; + font-size: 0.65rem; + background: rgba(255, 255, 255, 0.06); + color: var(--muted); +} + .market-vol-rank-item { width: 100%; display: grid; @@ -4202,8 +4328,11 @@ body.login-page { border-left: 3px solid #8a8f98; } -.market-vol-rank-item.is-div-scan { - grid-template-columns: auto 28px 1fr auto; +.market-vol-rank-item.is-div-scan.confluence-c1, +.market-vol-rank-item.is-div-scan.confluence-c2, +.market-vol-rank-item.is-div-scan.confluence-c3, +.market-vol-rank-item.is-div-scan.confluence-split { + border-left-width: 4px; } .market-vol-rank-badge { diff --git a/manual_trading_hub/static/chart.js b/manual_trading_hub/static/chart.js index 5f3998e..7e1a827 100644 --- a/manual_trading_hub/static/chart.js +++ b/manual_trading_hub/static/chart.js @@ -3041,6 +3041,7 @@ function renderDivergenceScan(data) { if (!elVolRankMeta || !elVolRankList) return; elVolRankList.innerHTML = ""; + elVolRankList.classList.add("is-div-scan-list"); const tabLabel = (data && data.tab_label) || "背离"; if (!data || !data.ok || !data.items || !data.items.length) { elVolRankMeta.textContent = @@ -3050,20 +3051,23 @@ } const rankDate = data.rank_date || "—"; const updated = data.scanned_at || data.updated_at || "—"; - let meta = + elVolRankMeta.innerHTML = + "
" + + ""; const curSym = (elSymbol && elSymbol.value.trim().toUpperCase()) || ""; const tabTf = data.tab || activeScanTab; + const tfShort = { "4h": "4h", "1d": "日线", "1w": "周线" }; data.items.forEach(function (row) { const li = document.createElement("li"); + li.className = "market-vol-rank-li"; const btn = document.createElement("button"); btn.type = "button"; const css = row.confluence_css || "none"; @@ -3075,21 +3079,50 @@ const dirLabel = row.is_split ? "分歧" : row.tab_direction_label || row.direction_label || ""; - const confLabel = row.is_split ? row.split_detail || "分歧" : row.confluence_kind || ""; + const confLabel = row.is_split ? "分歧" : row.confluence_kind || "—"; const fresh = row.tab_freshness || ""; + const dirClass = + row.tab_direction === "bull" + ? "is-bull" + : row.tab_direction === "bear" + ? "is-bear" + : row.is_split + ? "is-split" + : ""; + const tfPills = []; + const tfs = row.timeframes || {}; + ["4h", "1d", "1w"].forEach(function (tf) { + if (!tfs[tf]) return; + const pillDir = tfs[tf] === "bull" ? "底" : "顶"; + tfPills.push( + '' + (tfShort[tf] || tf) + pillDir + "" + ); + }); + const subExtra = row.is_split && row.split_detail + ? '' + row.split_detail + "" + : tfPills.length + ? '' + tfPills.join("") + "" + : ""; btn.innerHTML = + '