diff --git a/config/architecture-inventory.json b/config/architecture-inventory.json index ccd1323..1ae0149 100644 --- a/config/architecture-inventory.json +++ b/config/architecture-inventory.json @@ -468,8 +468,8 @@ }, { "path": "frontend/shared/shell.css", - "bytes": 63733, - "lines": 3767 + "bytes": 64839, + "lines": 3794 }, { "path": "backend/features/heaven/engine.py", @@ -766,16 +766,16 @@ "bytes": 3316, "lines": 55 }, + { + "path": "frontend/pages/rotation/page.html", + "bytes": 3299, + "lines": 57 + }, { "path": "backend/features/market/insights_context.py", "bytes": 3175, "lines": 84 }, - { - "path": "frontend/pages/rotation/page.html", - "bytes": 3031, - "lines": 54 - }, { "path": "frontend/pages/market/bindings.js", "bytes": 2663, diff --git a/frontend/pages/rotation/foundation.css b/frontend/pages/rotation/foundation.css index 3dac085..a81d0a0 100644 --- a/frontend/pages/rotation/foundation.css +++ b/frontend/pages/rotation/foundation.css @@ -28,14 +28,6 @@ background: var(--selected); } -.rotation-sector-chip.selected { - border-color: var(--action); - - background: var(--action-soft); - - color: var(--action-hover); -} - .rotation-sector-chip > span { color: var(--text-secondary); @@ -158,8 +150,6 @@ cursor: pointer; border-bottom: 1px dashed var(--border); - - background: color-mix(in srgb, var(--accent) calc(4% + var(--rotation-heat) * 46%), transparent); } .redesigned-rotation-view { @@ -397,8 +387,12 @@ display: flex; + flex-wrap: wrap; + align-items: center; + row-gap: 4px; + gap: 14px; padding: 8px 14px; @@ -434,18 +428,32 @@ border-radius: 2px; } -#rotationView .rotation-swatch.strong { - background: var(--accent); +#rotationView .rotation-swatch.tier-1 { + background: var(--rotation-tier1-bar); } -#rotationView .rotation-swatch.warm { - background: var(--accent-soft); +#rotationView .rotation-swatch.tier-2 { + background: var(--rotation-tier2-bar); } -#rotationView .rotation-swatch.mild { - background: var(--surface-muted); +#rotationView .rotation-swatch.tier-3 { + background: var(--rotation-tier3-bar); +} - border: 1px solid var(--border); +#rotationView .rotation-swatch.tier-4 { + background: var(--rotation-tier4-bar); +} + +#rotationView .rotation-swatch.tier-5 { + background: var(--rotation-tier5-bar); +} + +#rotationView .rotation-legend-note { + margin-left: auto; + + color: var(--r2-faint); + + white-space: nowrap; } #rotationView .rotation-tracker { @@ -818,10 +826,59 @@ #rotationView .rotation-history.tracking .rotation-sector-chip.selected { opacity: 1; +} - border-color: var(--r2-blue); +/* 追踪态:命中被追踪板块名、但不是当次点击的那一格 —— 保持档位底色,2px 同档位描边(含 80% 不透明度), + 连点标记不做动画,仅描边淡入 200ms */ +#rotationView .rotation-sector-chip.selected:not(.current-cell) { + border-width: 2px; - box-shadow: inset 3px 0 0 var(--r2-blue), 0 0 0 1px var(--accent-soft); + border-color: color-mix(in srgb, var(--tier-bar) 80%, transparent); + + transition: border-color 200ms var(--ease-out); +} + +/* 选中态:仅当次点击的日期+板块这一格 —— 同档位实色渐变 + 2px 亮描边 + 克制光晕,全页最多一张 */ +#rotationView .rotation-sector-chip.selected.current-cell { + border-width: 2px; + + border-color: var(--tier-text); + + background: linear-gradient(135deg, var(--tier-fill-start), var(--tier-fill-end)); + + box-shadow: 0 0 16px color-mix(in srgb, var(--tier-bar) var(--rotation-tier-glow-alpha), transparent); + + color: var(--text-inverse); + + transition: background 160ms var(--ease-out), border-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out); +} + +#rotationView .rotation-sector-chip.selected.current-cell strong, +#rotationView .rotation-sector-chip.selected.current-cell small, +#rotationView .rotation-sector-chip.selected.current-cell small b { + color: var(--text-inverse); +} + +#rotationView .rotation-track-dot { + width: 6px; + + height: 6px; + + position: absolute; + + top: 6px; + + right: 6px; + + border-radius: 50%; + + background: var(--tier-bar); +} + +@media (prefers-reduced-motion: reduce) { + #rotationView .rotation-sector-chip.selected.current-cell { + box-shadow: none; + } } .rotation-cell-tooltip { @@ -1050,40 +1107,79 @@ } } -#rotationView .rotation-sector-chip.heat-mild { - border-color: var(--border); - - background: var(--surface-muted); - - box-shadow: none; +/* HEL-524: 五档强度色 —— 同一强度值在 9 个日期列中颜色完全一致,仅代表强度档位,与涨跌无关。 + 普通卡只用低透明着色,页面/主容器/日期分栏的层级由 HEL-522 的明度骨架承担,这里不重复叠加。 */ +#rotationView .rotation-sector-chip.heat-tier-1 { + --tier-bar: var(--rotation-tier1-bar); + --tier-bg: var(--rotation-tier1-bg); + --tier-border: var(--rotation-tier1-border); + --tier-text: var(--rotation-tier1-text); + --tier-fill-start: var(--rotation-tier1-fill-start); + --tier-fill-end: var(--rotation-tier1-fill-end); } -#rotationView .rotation-sector-chip.heat-strong { - border-color: var(--action-line); - - background: var(--accent-soft); - - box-shadow: none; +#rotationView .rotation-sector-chip.heat-tier-2 { + --tier-bar: var(--rotation-tier2-bar); + --tier-bg: var(--rotation-tier2-bg); + --tier-border: var(--rotation-tier2-border); + --tier-text: var(--rotation-tier2-text); + --tier-fill-start: var(--rotation-tier2-fill-start); + --tier-fill-end: var(--rotation-tier2-fill-end); } -#rotationView .rotation-sector-chip.heat-warm { - border-color: var(--action-line); - - background: color-mix(in srgb, var(--accent) 12%, var(--surface)); - - box-shadow: none; +#rotationView .rotation-sector-chip.heat-tier-3 { + --tier-bar: var(--rotation-tier3-bar); + --tier-bg: var(--rotation-tier3-bg); + --tier-border: var(--rotation-tier3-border); + --tier-text: var(--rotation-tier3-text); + --tier-fill-start: var(--rotation-tier3-fill-start); + --tier-fill-end: var(--rotation-tier3-fill-end); } -#rotationView .rotation-sector-chip:hover { +#rotationView .rotation-sector-chip.heat-tier-4 { + --tier-bar: var(--rotation-tier4-bar); + --tier-bg: var(--rotation-tier4-bg); + --tier-border: var(--rotation-tier4-border); + --tier-text: var(--rotation-tier4-text); + --tier-fill-start: var(--rotation-tier4-fill-start); + --tier-fill-end: var(--rotation-tier4-fill-end); +} + +#rotationView .rotation-sector-chip.heat-tier-5 { + --tier-bar: var(--rotation-tier5-bar); + --tier-bg: var(--rotation-tier5-bg); + --tier-border: var(--rotation-tier5-border); + --tier-text: var(--rotation-tier5-text); + --tier-fill-start: var(--rotation-tier5-fill-start); + --tier-fill-end: var(--rotation-tier5-fill-end); +} + +#rotationView .rotation-sector-chip[class*="heat-tier-"] { + border-color: var(--tier-border); + + background: var(--tier-bg); + + box-shadow: inset 4px 0 0 0 var(--tier-bar); + + transition: transform 280ms cubic-bezier(0.22, 1, 0.36, 1), background-color 120ms var(--ease-out), border-color 120ms var(--ease-out), box-shadow 120ms var(--ease-out), filter 240ms, opacity 220ms; +} + +#rotationView .rotation-sector-chip[class*="heat-tier-"] .rotation-strength { + color: var(--tier-text); +} + +/* 悬停态:卡底与描边 alpha 适度提升,120ms ease-out,可打断,不打乱档位色含义; + 已经处于选中/追踪态的卡片保持其自身样式,不叠加普通悬停处理 */ +#rotationView .rotation-sector-chip[class*="heat-tier-"]:hover:not(.selected) { z-index: 6; - border-color: var(--accent); + background: color-mix(in srgb, var(--tier-bar) 8%, var(--tier-bg) 92%); + + border-color: color-mix(in srgb, var(--tier-bar) 26%, var(--tier-border) 74%); filter: saturate(1.06); transform: translate3d(2px, -2px, 0px) scale(1.015); - - box-shadow: none; } #rotationView .rotation-table { @@ -1207,30 +1303,6 @@ box-shadow: var(--control-shadow); } -:root[data-theme="dark"] #rotationView .rotation-sector-chip.heat-strong { - border-color: var(--blue-line); - - background: var(--heat-strong-bg); - - color: var(--heat-strong-ink); -} - -:root[data-theme="dark"] #rotationView .rotation-sector-chip.heat-warm { - border-color: var(--border-strong); - - background: var(--heat-warm-bg); - - color: var(--heat-warm-ink); -} - -:root[data-theme="dark"] #rotationView .rotation-sector-chip.heat-mild { - border-color: var(--border); - - background: var(--heat-mild-bg); - - color: var(--heat-mild-ink); -} - :root[data-theme="dark"] #rotationView :is(.rotation-rank, .rotation-table thead th, .trend-flat) { border-color: var(--border); @@ -1243,20 +1315,6 @@ background: var(--action-soft); } -:root[data-theme="dark"] #rotationView :is(.rotation-swatch.warm) { - border-color: var(--blue-line); - - background: var(--action-soft); - - color: var(--action); -} - -:root[data-theme="dark"] #rotationView :is(.rotation-swatch.mild) { - border-color: var(--border); - - background: var(--surface-muted); -} - @media (max-width: 767px) { #rotationView :is(.rotation-table-frame, .rotation-detail-card) { max-height: none; diff --git a/frontend/pages/rotation/page.html b/frontend/pages/rotation/page.html index 90b14fa..95cf0ec 100644 --- a/frontend/pages/rotation/page.html +++ b/frontend/pages/rotation/page.html @@ -22,9 +22,12 @@ 每日 Top 12 热点
- 强度高(90+) - 强度中(70–89) - 强度低(<70) + 低·青(<65) + 中低·蓝(65–74) + 中高·紫(75–84) + 高·橙(85–94) + 最高·红(95+) + 颜色=强度档位,与涨跌无关
正在读取轮动历史
diff --git a/frontend/pages/rotation/page.js b/frontend/pages/rotation/page.js index 5bd762f..580c874 100644 --- a/frontend/pages/rotation/page.js +++ b/frontend/pages/rotation/page.js @@ -3,6 +3,16 @@ window.XiaobaiPageModules.register("rotation", ["rotationView"], { enter: ["loadRotation"], }); +// HEL-524: 五档强度色固定映射,所有日期列共用同一套阈值 —— <65 青,65-74 蓝,75-84 紫,85-94 橙,95+ 红。 +function rotationHeatTier(strengthValue) { + const value = clamp(number(strengthValue), 0, 100); + if (value >= 95) return 5; + if (value >= 85) return 4; + if (value >= 75) return 3; + if (value >= 65) return 2; + return 1; +} + async function loadRotationHistory(force = false) { if (!state.dashboard || state.rotationLoading) return; const key = `${elements.tradeDate.value}:9`; @@ -87,10 +97,14 @@ function renderRotationHistory() {
${(day.sectors || []).length} 个热点
${(day.sectors || []).map((sector) => { const strength = clamp(number(sector.strength), 0, 100); - const heatClass = strength >= 90 ? "heat-strong" : strength >= 70 ? "heat-warm" : "heat-mild"; + const heatClass = `heat-tier-${rotationHeatTier(strength)}`; + const isTrackedName = Boolean(selected) && selected === sector.name; + const isCurrentCell = isTrackedName && day.trade_date === state.rotationSelectedDate; + const stateClass = isCurrentCell ? "selected current-cell" : isTrackedName ? "selected" : ""; return ` - `; }).join("")}
diff --git a/frontend/shared/shell.css b/frontend/shared/shell.css index 8daa720..2738e62 100644 --- a/frontend/shared/shell.css +++ b/frontend/shared/shell.css @@ -3765,3 +3765,30 @@ body.mobile-shell[data-active-view="heavenView"] .app-header .overview-strip[dat overflow: hidden; } +/* HEL-524: 侧栏去掉作为整块独立色板的背景,融入页面底层;品牌区与顶栏保持同层; + 收起侧栏整行不再单独着色。展开/收起态均生效。「问天」冻结路由维持原有外观。 */ +body:not(.mobile-shell):not([data-active-view="heavenView"]) .module-nav, +body.sidebar-collapsed:not(.mobile-shell):not([data-active-view="heavenView"]) .module-nav { + background: var(--canvas); +} + +body:not(.mobile-shell):not([data-active-view="heavenView"]) .sidebar-brand { + background: var(--header-bg); +} + +body:not(.mobile-shell):not([data-active-view="heavenView"]) .sidebar-collapse-button { + background: transparent; +} + +:root[data-theme="dark"] body:not(.mobile-shell):not([data-active-view="heavenView"]) .module-nav { + background: var(--canvas); +} + +:root[data-theme="dark"] body:not(.mobile-shell):not([data-active-view="heavenView"]) .sidebar-brand { + background-color: var(--header-bg); +} + +:root[data-theme="dark"] body:not(.mobile-shell):not([data-active-view="heavenView"]) :is(.nav-group, .sidebar-collapse-button) { + background-color: transparent; +} + diff --git a/frontend/shared/tokens.css b/frontend/shared/tokens.css index 749c5b0..7587ba4 100644 --- a/frontend/shared/tokens.css +++ b/frontend/shared/tokens.css @@ -381,6 +381,40 @@ --r2-radius: var(--size-radius-lg); --r2-shadow: var(--elevation-card); + /* HEL-524: 板块轮动五档强度色(日间)。五档单调递进:青→蓝→紫→橙→红,冷到暖; + 同一强度值在所有日期列使用完全相同的颜色,颜色仅代表强度档位,与涨跌无关。 */ + --rotation-tier1-bar: #0D9488; + --rotation-tier1-bg: rgba(13, 148, 136, .08); + --rotation-tier1-border: rgba(13, 148, 136, .25); + --rotation-tier1-text: #0F766E; + --rotation-tier1-fill-start: #11766D; + --rotation-tier1-fill-end: #0C443F; + --rotation-tier2-bar: #2563EB; + --rotation-tier2-bg: rgba(37, 99, 235, .07); + --rotation-tier2-border: rgba(37, 99, 235, .22); + --rotation-tier2-text: #1D4ED8; + --rotation-tier2-fill-start: #2059D7; + --rotation-tier2-fill-end: #1D46A2; + --rotation-tier3-bar: #7C3AED; + --rotation-tier3-bg: rgba(124, 58, 237, .07); + --rotation-tier3-border: rgba(124, 58, 237, .22); + --rotation-tier3-text: #6D28D9; + --rotation-tier3-fill-start: #6F2DE0; + --rotation-tier3-fill-end: #5720B5; + --rotation-tier4-bar: #EA580C; + --rotation-tier4-bg: rgba(234, 88, 12, .08); + --rotation-tier4-border: rgba(234, 88, 12, .25); + --rotation-tier4-text: #C2410C; + --rotation-tier4-fill-start: #C85215; + --rotation-tier4-fill-end: #913E13; + --rotation-tier5-bar: #DC2626; + --rotation-tier5-bg: rgba(220, 38, 38, .08); + --rotation-tier5-border: rgba(220, 38, 38, .25); + --rotation-tier5-text: #B91C1C; + --rotation-tier5-fill-start: #BE2B2B; + --rotation-tier5-fill-end: #8C2424; + --rotation-tier-glow-alpha: 22%; + font-family: "PingFang SC", "Microsoft YaHei", system-ui, sans-serif; font-size: 14px; } @@ -557,6 +591,40 @@ --heat-warm-ink: #dfeaf7; --heat-mild-bg: #293440; --heat-mild-ink: #c7d2dc; + + /* HEL-524: 板块轮动五档强度色(夜间)。五档单调递进:青→蓝→紫→橙→红,冷到暖; + 同一强度值在所有日期列使用完全相同的颜色,颜色仅代表强度档位,与涨跌无关。 */ + --rotation-tier1-bar: #2DD4BF; + --rotation-tier1-bg: rgba(45, 212, 191, .09); + --rotation-tier1-border: rgba(45, 212, 191, .20); + --rotation-tier1-text: #5EEAD4; + --rotation-tier1-fill-start: #32B6A5; + --rotation-tier1-fill-end: #2A867A; + --rotation-tier2-bar: #60A5FA; + --rotation-tier2-bg: rgba(96, 165, 250, .10); + --rotation-tier2-border: rgba(96, 165, 250, .22); + --rotation-tier2-text: #93C5FD; + --rotation-tier2-fill-start: #5098F1; + --rotation-tier2-fill-end: #217AE7; + --rotation-tier3-bar: #A78BFA; + --rotation-tier3-bg: rgba(167, 139, 250, .11); + --rotation-tier3-border: rgba(167, 139, 250, .24); + --rotation-tier3-text: #C4B5FD; + --rotation-tier3-fill-start: #9879F2; + --rotation-tier3-fill-end: #724AE9; + --rotation-tier4-bar: #FB923C; + --rotation-tier4-bg: rgba(251, 146, 60, .12); + --rotation-tier4-border: rgba(251, 146, 60, .26); + --rotation-tier4-text: #FDBA74; + --rotation-tier4-fill-start: #F07C2D; + --rotation-tier4-fill-end: #D05A14; + --rotation-tier5-bar: #F87171; + --rotation-tier5-bg: rgba(248, 113, 113, .13); + --rotation-tier5-border: rgba(248, 113, 113, .28); + --rotation-tier5-text: #FCA5A5; + --rotation-tier5-fill-start: #EF6161; + --rotation-tier5-fill-end: #E53333; + --rotation-tier-glow-alpha: 35%; --heaven-field-bg: #23241f; --shadow-soft: 0 1px 2px rgba(0, 0, 0, .28), 0 8px 24px rgba(0, 0, 0, .16); --shadow: 0 18px 50px rgba(0, 0, 0, .46); diff --git a/tests/e2e/app-shell.spec.js b/tests/e2e/app-shell.spec.js index b3422a5..1cb5750 100644 --- a/tests/e2e/app-shell.spec.js +++ b/tests/e2e/app-shell.spec.js @@ -1260,9 +1260,9 @@ test("sector rotation transfers the nine-day matrix, tracking and sortable detai await expect(page.locator("#rotationHistory .rotation-day").last()).toHaveClass(/latest-day/); await expect(page.locator("#rotationView .rotation-legend")).not.toContainText("单元格 ="); const firstDayCells = page.locator("#rotationHistory .rotation-day").first().locator(".rotation-sector-chip"); - await expect(firstDayCells.nth(0)).toHaveClass(/heat-strong/); - await expect(firstDayCells.nth(1)).toHaveClass(/heat-warm/); - await expect(firstDayCells.nth(2)).toHaveClass(/heat-mild/); + await expect(firstDayCells.nth(0)).toHaveClass(/heat-tier-4/); // strength 92 → 85-94 档(高·橙) + await expect(firstDayCells.nth(1)).toHaveClass(/heat-tier-3/); // strength 76 → 75-84 档(中高·紫) + await expect(firstDayCells.nth(2)).toHaveClass(/heat-tier-1/); // strength 58 → <65 档(低·青) const cellVisuals = await firstDayCells.evaluateAll((cells) => cells.map((cell) => { const style = getComputedStyle(cell); return { background: style.backgroundColor, radius: parseFloat(style.borderRadius), duration: style.transitionDuration };