diff --git a/manual_trading_hub/static/app.css b/manual_trading_hub/static/app.css index df048e5..100db95 100644 --- a/manual_trading_hub/static/app.css +++ b/manual_trading_hub/static/app.css @@ -2351,35 +2351,269 @@ body.login-page { padding: 14px 0; } + .brand-sub { + display: none; + } + + .app-header { + padding: 10px 0; + margin-bottom: 4px; + } + .header-right { width: 100%; - flex-direction: column; - align-items: stretch; - gap: 10px; + display: grid; + grid-template-columns: 1fr auto auto; + grid-template-rows: auto auto; + align-items: center; + gap: 8px; + } + + .header-right .theme-toggle { + grid-column: 1; + justify-self: start; } .sys-pill { - align-self: flex-start; - } - - .top-nav { - width: 100%; - justify-content: stretch; - } - - .top-nav a { - flex: 1; - text-align: center; - padding: 10px 12px; - min-height: 44px; - display: flex; - align-items: center; - justify-content: center; + grid-column: 2; + align-self: center; } button.ghost#btn-logout { + grid-column: 3; + width: auto; + min-height: 36px; + padding: 6px 12px; + justify-self: end; + } + + .top-nav { + grid-column: 1 / -1; width: 100%; + display: flex; + flex-wrap: nowrap; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + gap: 6px; + padding-bottom: 2px; + } + + .top-nav::-webkit-scrollbar { + display: none; + } + + .top-nav a { + flex: 0 0 auto; + text-align: center; + padding: 8px 14px; + min-height: 40px; + display: inline-flex; + align-items: center; + justify-content: center; + white-space: nowrap; + } + + .page-desc { + display: none; + } + + .market-toolbar { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + align-items: end; + } + + .market-field { + min-width: 0; + } + + .market-field select, + .market-field input { + width: 100%; + min-width: 0; + } + + .market-field-symbol { + grid-column: 1 / -1; + } + + .market-toolbar .toolbar-spacer { + display: none; + } + + .market-toolbar #market-load { + grid-column: 1; + } + + .market-toolbar #market-refresh { + grid-column: 2; + } + + .market-toolbar .toolbar-meta { + grid-column: 1 / -1; + text-align: left; + font-size: 0.72rem; + } + + .market-chart-wrap { + min-height: 260px; + height: min(52vh, 420px); + } + + .archive-toolbar { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px 10px; + align-items: center; + } + + .archive-toolbar .archive-field { + grid-column: 1 / -1; + } + + .archive-toolbar .chk-label { + margin: 0; + min-height: 36px; + justify-content: flex-start; + } + + .archive-toolbar #archive-btn-refresh { + grid-column: 1; + } + + .archive-toolbar #archive-btn-sync { + grid-column: 2; + } + + .archive-toolbar .toolbar-meta { + grid-column: 1 / -1; + text-align: left; + } + + body.hub-page-ai .page-head { + margin: 4px 0 6px; + } + + body.hub-page-ai .page-head h1 { + margin: 0; + font-size: 15px; + } + + .ai-mobile-tabs { + display: flex; + gap: 8px; + margin-bottom: 8px; + flex-shrink: 0; + } + + .ai-mobile-tab { + flex: 1; + min-height: 40px; + padding: 8px 12px; + border-radius: 8px; + border: 1px solid var(--border-soft); + background: var(--inset-surface); + color: var(--muted); + font-family: var(--font); + font-size: 0.82rem; + font-weight: 600; + cursor: pointer; + } + + .ai-mobile-tab.is-active { + color: var(--text); + border-color: var(--accent); + background: var(--accent-dim); + box-shadow: var(--glow); + } + + body.hub-page-ai .app-shell { + padding-bottom: max(8px, env(safe-area-inset-bottom)); + height: 100dvh; + max-height: 100dvh; + overflow: hidden; + } + + body.hub-page-ai { + overflow: hidden; + } + + body.hub-page-ai #page-ai { + overflow: hidden; + } + + .ai-layout { + grid-template-columns: 1fr; + grid-template-rows: minmax(0, 1fr); + overflow: hidden; + } + + .ai-layout[data-ai-mobile-tab="chat"] .ai-summary-panel { + display: none; + } + + .ai-layout[data-ai-mobile-tab="summary"] .ai-chat-panel { + display: none; + } + + .ai-layout[data-ai-mobile-tab="chat"] .ai-chat-panel, + .ai-layout[data-ai-mobile-tab="summary"] .ai-summary-panel { + display: flex; + min-height: 0; + height: 100%; + } + + .ai-chat-panel { + padding-bottom: 0; + } + + .ai-chat-messages { + padding-bottom: 8px; + } + + .ai-chat-form { + position: sticky; + bottom: 0; + z-index: 3; + margin: 0 -14px; + padding: 10px 14px max(10px, env(safe-area-inset-bottom)); + background: color-mix(in srgb, var(--panel) 92%, transparent); + backdrop-filter: blur(10px); + border-top: 1px solid var(--border-soft); + box-shadow: 0 -10px 28px rgba(0, 0, 0, 0.28); + } + + .ai-chat-form textarea { min-height: 44px; + max-height: 120px; + font-size: 16px; + } + + .ai-chat-compose-actions { + display: grid; + grid-template-columns: auto 1fr auto; + gap: 8px; + align-items: center; + } + + .ai-chat-upload-btn, + #btn-ai-chat-send { + min-height: 44px; + } + + #btn-ai-chat-send { + min-width: 76px; + font-weight: 600; + } + + .ai-msg-row-user { + max-width: 92%; + } + + .ai-msg-row-coach { + max-width: 96%; } .page-head { @@ -3688,23 +3922,8 @@ body.hub-page-ai #page-ai { align-items: stretch; overflow: hidden; } -@media (max-width: 960px) { - body.hub-page-ai .app-shell { - height: auto; - max-height: none; - overflow: visible; - } - body.hub-page-ai { - overflow: auto; - } - body.hub-page-ai #page-ai { - overflow: visible; - } - .ai-layout { - grid-template-columns: 1fr; - grid-template-rows: minmax(280px, 42vh) minmax(280px, 42vh); - overflow: visible; - } +.ai-mobile-tabs { + display: none; } .ai-panel { background: var(--panel); diff --git a/manual_trading_hub/static/app.js b/manual_trading_hub/static/app.js index d45a724..9586382 100644 --- a/manual_trading_hub/static/app.js +++ b/manual_trading_hub/static/app.js @@ -966,7 +966,47 @@ gridEl.style.gridTemplateColumns = `repeat(${cols}, minmax(0, 1fr))`; } + const AI_MOBILE_TAB_KEY = "hub_ai_mobile_tab"; + + function applyAiMobileTab(tab) { + const layout = document.querySelector(".ai-layout"); + const tabs = document.querySelectorAll(".ai-mobile-tab"); + if (!layout) return; + const mobile = isMobileLayout(); + const active = mobile ? tab || localStorage.getItem(AI_MOBILE_TAB_KEY) || "chat" : "both"; + if (mobile) layout.dataset.aiMobileTab = active; + else delete layout.dataset.aiMobileTab; + tabs.forEach((btn) => { + const on = mobile && btn.dataset.aiTab === active; + btn.classList.toggle("is-active", on); + btn.setAttribute("aria-selected", on ? "true" : "false"); + }); + if (mobile && active === "chat") { + const box = document.getElementById("ai-chat-messages"); + if (box) requestAnimationFrame(() => { box.scrollTop = box.scrollHeight; }); + } + } + + function initAiMobileTabs() { + const tabs = document.querySelectorAll(".ai-mobile-tab"); + if (!tabs.length) return; + tabs.forEach((btn) => { + btn.addEventListener("click", () => { + const tab = btn.dataset.aiTab || "chat"; + localStorage.setItem(AI_MOBILE_TAB_KEY, tab); + applyAiMobileTab(tab); + if (tab === "chat") { + const input = document.getElementById("ai-chat-input"); + if (input && isMobileLayout()) input.focus(); + } + }); + }); + window.addEventListener("resize", () => applyAiMobileTab()); + applyAiMobileTab(); + } + function initMobileLayout() { + initAiMobileTabs(); let resizeTimer = null; let wasMobile = isMobileLayout(); window.addEventListener("resize", () => { @@ -3247,7 +3287,14 @@ } async function loadAiPage() { + applyAiMobileTab(); await Promise.all([loadAiSummary(), loadAiChatSession()]); + if (isMobileLayout() && (localStorage.getItem(AI_MOBILE_TAB_KEY) || "chat") === "chat") { + const input = document.getElementById("ai-chat-input"); + if (input && !aiChatLoading) { + setTimeout(() => input.focus(), 80); + } + } } async function generateAiSummary() { diff --git a/manual_trading_hub/static/index.html b/manual_trading_hub/static/index.html index fe368d7..1321419 100644 --- a/manual_trading_hub/static/index.html +++ b/manual_trading_hub/static/index.html @@ -15,7 +15,7 @@ - + @@ -332,8 +332,12 @@

AI 教练

四户今日总结 · 口语化陪聊(单会话,点「新开对话」清空上下文)

-
-
+
+ + +
+
+

今日总结

@@ -345,7 +349,7 @@

点击「生成今日总结」聚合四户平仓与持仓数据(未启用账户显示「未监控」)。

-
+

聊天

@@ -420,6 +424,6 @@ - +