From 28875078f18669719d70549e3f5d309eaa30a94a Mon Sep 17 00:00:00 2001 From: dekun Date: Mon, 15 Jun 2026 16:58:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E7=AB=AF=E8=87=AA=E9=80=82=E5=BA=94?= =?UTF-8?q?=E5=B8=83=E5=B1=80=E4=B8=8E=20PWA=20=E5=8F=AF=E5=AE=89=E8=A3=85?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增响应式样式、手机侧滑导航、manifest 与 Service Worker;补充根路径重定向与安装 App 入口。 Co-authored-by: Cursor --- app.py | 22 ++ static/css/responsive.css | 489 ++++++++++++++++++++++++++++++++++++++ static/icons/icon-192.png | Bin 0 -> 1227 bytes static/icons/icon-512.png | Bin 0 -> 3829 bytes static/icons/icon.svg | 12 + static/js/nav.js | 53 +++++ static/js/pwa.js | 76 ++++++ static/manifest.json | 33 +++ static/sw.js | 61 +++++ templates/base.html | 42 ++-- templates/login.html | 14 +- 11 files changed, 785 insertions(+), 17 deletions(-) create mode 100644 static/css/responsive.css create mode 100644 static/icons/icon-192.png create mode 100644 static/icons/icon-512.png create mode 100644 static/icons/icon.svg create mode 100644 static/js/nav.js create mode 100644 static/js/pwa.js create mode 100644 static/manifest.json create mode 100644 static/sw.js diff --git a/app.py b/app.py index 4f240d2..ed55e6f 100644 --- a/app.py +++ b/app.py @@ -551,6 +551,28 @@ def login_required(f): return wrap +@app.route("/") +def index(): + if session.get("logged_in"): + return redirect(url_for("plans")) + return redirect(url_for("login")) + + +@app.route("/manifest.webmanifest") +def web_manifest(): + response = app.send_static_file("manifest.json") + response.mimetype = "application/manifest+json" + return response + + +@app.route("/sw.js") +def service_worker(): + response = app.send_static_file("sw.js") + response.headers["Cache-Control"] = "no-cache" + response.headers["Service-Worker-Allowed"] = "/" + return response + + @app.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": diff --git a/static/css/responsive.css b/static/css/responsive.css new file mode 100644 index 0000000..12c9970 --- /dev/null +++ b/static/css/responsive.css @@ -0,0 +1,489 @@ +/* 响应式布局 — 电脑 / 平板 / 手机 + PWA 独立窗口 */ + +:root { + --safe-top: env(safe-area-inset-top, 0px); + --safe-right: env(safe-area-inset-right, 0px); + --safe-bottom: env(safe-area-inset-bottom, 0px); + --safe-left: env(safe-area-inset-left, 0px); + --touch-min: 44px; +} + +html { + -webkit-text-size-adjust: 100%; + text-size-adjust: 100%; +} + +body { + padding-left: var(--safe-left); + padding-right: var(--safe-right); + padding-bottom: var(--safe-bottom); +} + +.page-wrap { + padding-top: var(--safe-top); +} + +.header-bar { + display: grid; + grid-template-columns: auto 1fr auto; + align-items: center; + gap: .5rem .75rem; + margin-bottom: .85rem; + min-height: var(--touch-min); +} + +.nav-toggle { + display: none; + width: var(--touch-min); + height: var(--touch-min); + border: 1px solid var(--toggle-border); + border-radius: 10px; + background: var(--toggle-bg); + cursor: pointer; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 5px; + padding: 0; + flex-shrink: 0; +} + +.nav-toggle span { + display: block; + width: 18px; + height: 2px; + background: var(--text-primary); + border-radius: 2px; + transition: transform .2s, opacity .2s; +} + +.nav-toggle[aria-expanded="true"] span:nth-child(1) { + transform: translateY(7px) rotate(45deg); +} + +.nav-toggle[aria-expanded="true"] span:nth-child(2) { + opacity: 0; +} + +.nav-toggle[aria-expanded="true"] span:nth-child(3) { + transform: translateY(-7px) rotate(-45deg); +} + +.header-tools { + position: static; + justify-content: flex-start; + flex-wrap: wrap; +} + +.user-bar { + position: static; + text-align: right; + justify-self: end; +} + +.pwa-install-btn { + padding: .38rem .7rem; + border-radius: 999px; + border: 1px solid var(--accent); + background: transparent; + color: var(--accent); + font-size: .72rem; + cursor: pointer; + white-space: nowrap; + width: auto; + flex-shrink: 0; + min-height: 32px; +} + +.pwa-install-btn:hover { + background: var(--dir-bg); +} + +.pwa-ios-hint { + display: none; + font-size: .72rem; + color: var(--text-muted); + padding: .5rem .75rem; + margin: 0 0 .75rem; + border-radius: 10px; + border: 1px dashed var(--card-border); + background: var(--card-inner); + line-height: 1.5; +} + +.pwa-ios-hint.show { + display: block; +} + +.nav-backdrop { + display: none; + position: fixed; + inset: 0; + background: var(--modal-mask); + z-index: 90; + border: none; + padding: 0; + cursor: pointer; +} + +.nav-backdrop.show { + display: block; +} + +@media (min-width: 1025px) { + .site-header { + padding: 1.5rem 1.5rem 1.25rem; + } + + .site-nav { + justify-content: center; + } + + .main { + padding: 1.5rem 1.75rem; + } +} + +@media (min-width: 768px) and (max-width: 1024px) { + .site-header { + padding: 1.25rem 1rem 1rem; + } + + .site-title { + font-size: 1.5rem; + margin-bottom: 1rem; + } + + .site-nav { + gap: .4rem; + justify-content: center; + } + + .site-nav a { + padding: .5rem .85rem; + font-size: .82rem; + } + + .main { + padding: 1.25rem 1rem; + } + + .card { + padding: 1.25rem; + } + + .split-grid { + grid-template-columns: 1fr; + } + + .form-compact .line-4, + .form-compact .line-5 { + grid-template-columns: repeat(2, 1fr); + } + + .form-compact .line-plan-2 { + grid-template-columns: repeat(2, 1fr); + } + + .pos-metrics { + grid-template-columns: repeat(2, 1fr); + } + + .review-detail-grid { + grid-template-columns: repeat(2, 1fr); + } + + .stat-grid-summary { + grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); + } +} + +@media (max-width: 767px) { + .nav-toggle { + display: inline-flex; + } + + .header-bar { + grid-template-columns: auto 1fr; + grid-template-areas: + "toggle tools" + "user user"; + } + + .nav-toggle { grid-area: toggle; } + .header-tools { grid-area: tools; justify-content: flex-end; } + .user-bar { + grid-area: user; + text-align: center; + width: 100%; + } + + .site-header { + padding: .85rem .75rem .75rem; + text-align: left; + } + + .site-title { + font-size: 1.15rem; + margin-bottom: .65rem; + text-align: center; + } + + .site-title-sub { + font-size: .58rem; + letter-spacing: .14em; + } + + .site-nav { + position: fixed; + top: 0; + left: 0; + width: min(86vw, 320px); + height: 100dvh; + flex-direction: column; + align-items: stretch; + justify-content: flex-start; + gap: .35rem; + padding: calc(var(--safe-top) + 3.5rem) 1rem 1.5rem; + background: var(--card-bg); + border-right: 1px solid var(--card-border); + box-shadow: var(--shadow-card-hover); + z-index: 100; + transform: translateX(-105%); + transition: transform .28s ease; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + } + + .site-nav.open { + transform: translateX(0); + } + + .site-nav a { + width: 100%; + text-align: left; + padding: .75rem 1rem; + font-size: .9rem; + min-height: var(--touch-min); + display: flex; + align-items: center; + border-radius: 10px; + } + + .main { + padding: .85rem .75rem 1.25rem; + } + + .card { + padding: 1rem; + border-radius: 12px; + margin-bottom: 1rem; + } + + .card h2 { + font-size: 1rem; + } + + .form-compact .line-2, + .form-compact .line-3, + .form-compact .line-4, + .form-compact .line-5, + .form-compact .line-plan-1, + .form-compact .line-plan-2 { + grid-template-columns: 1fr; + } + + .form-compact-review .tag-grid { + grid-template-columns: repeat(2, 1fr); + } + + .form-compact-review .kline-row { + grid-template-columns: 1fr 1fr; + } + + .form-grid { + grid-template-columns: 1fr; + } + + .split-grid { + grid-template-columns: 1fr; + gap: 1rem; + } + + .split-grid .card { + min-height: auto; + } + + .pos-metrics { + grid-template-columns: repeat(2, 1fr); + } + + .review-detail-grid { + grid-template-columns: 1fr; + } + + .review-detail-item.wide { + grid-column: span 1; + } + + .stat-grid, + .stat-grid-summary { + grid-template-columns: repeat(2, 1fr); + gap: .65rem; + } + + .stat-item { + padding: .75rem .5rem; + } + + .stat-item .value { + font-size: 1.1rem; + } + + .filter-row .field { + width: 100%; + min-width: 0; + } + + .trade-toolbar { + flex-direction: column; + align-items: stretch; + } + + .profile-row { + grid-template-columns: 1fr; + gap: .25rem; + } + + .modal-box { + padding: 1rem; + border-radius: 12px; + max-height: calc(100dvh - 1rem); + } + + .modal-box.review-modal-fullscreen { + width: 100%; + height: 100dvh; + border-radius: 0; + } + + th, td { + padding: .55rem .45rem; + font-size: .8rem; + } + + .card-scroll { + max-height: none; + } + + .stats-card-head { + flex-direction: column; + align-items: stretch; + } + + .stats-view-field { + width: 100%; + } + + input, select, textarea, button { + font-size: 16px; + } + + .form-compact input, + .form-compact select { + font-size: 16px; + } +} + +@media (max-width: 479px) { + .stat-grid, + .stat-grid-summary { + grid-template-columns: 1fr 1fr; + } + + .theme-switch-btn { + padding: .35rem .55rem; + font-size: .7rem; + } + + .pos-metrics { + grid-template-columns: 1fr; + } +} + +@media (display-mode: standalone) { + .site-header { + padding-top: max(.75rem, var(--safe-top)); + } + + .pwa-install-btn, + .pwa-ios-hint { + display: none !important; + } +} + +@media (max-width: 767px) and (orientation: landscape) { + .site-nav { + width: min(50vw, 280px); + padding-top: calc(var(--safe-top) + 2.5rem); + } +} + +@media (hover: none) and (pointer: coarse) { + .site-nav a, + .btn-del, + .trade-actions a, + .trade-actions button, + .preset-tabs a { + min-height: var(--touch-min); + } + + .card:hover { + transform: none; + } + + .list-item:hover { + box-shadow: none; + } + + .stat-item:hover { + transform: none; + } +} + +.table-responsive { + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.table-responsive table { + min-width: 560px; +} + +body.login-page { + display: flex; + align-items: center; + justify-content: center; + min-height: 100vh; + min-height: 100dvh; + padding: 1rem; + padding-top: max(1rem, var(--safe-top)); + padding-bottom: max(1rem, var(--safe-bottom)); +} + +@media (max-width: 767px) { + body.login-page { + align-items: flex-start; + padding: .75rem; + padding-top: max(.75rem, var(--safe-top)); + } + + body.login-page .login-wrap { + max-width: 100%; + } + + body.login-page .login-box { + padding: 1.75rem 1.25rem 1.5rem; + } +} diff --git a/static/icons/icon-192.png b/static/icons/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..d12d4ad54529c8a3f96478278f0e0b66a0e776eb GIT binary patch literal 1227 zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE4M+yv$zf+;V439U;uumf=j~nFyek0=trt0! zWOdk2+On!HaysR9Lr_R`k&mN%=hF=g0<1|AYAMI+&cA;?FZj}fjqk;))jErctA9T_ z&gf*DUCVG`5<`a?!y?Xx3?_wH=uF%ET88|6b@{a%CT0JBrEdQJJMF!En{h=ISJHL{ zp80alE94FYAFkg~9r}5HI>YJX`DdM0NF7LiY+kjlcVQSyD3gVG&En-QJWHK5{u!?L z7<_8y-6?hYkze=d@-a{Tz6;h4Yg((hX> z8y<7@&bO6$pYu94A(&y`Zg2i=Z#LXep0NJko0V7Yg|R=l*e)s8`p1spVi@a#oAc$? z-hBGZy5YEd)U93i{SGd|3>Vk&9awIE=1b-TYle#~4knBOz6>B?8Z)hyfw%J62G8f#P_xJ9|4Yn|jaj#~l_s@ZJ1O@BET zH0e5v9o)xqK~eCHJHy<*aF*W!4vtIRwVQsiT=*H`8Ze!KO=2a-E5QQ_k3}41nIt+m zP6;1KXclpdWRfW8P||Q`Xy)6{o;;(GflV&X|G1GBBahtlEqWn}49ep(vm%#i5vVfzmTA@+$sX2}c7I(!nC6#skU z4F;YAmL0qYe*BL(blx?F;idSWIjTSA9AQ0B>7Bt6$hai#iMMX!b9J?bBi*}?36;%L zV)EF%B3jq+dG;@cNqT9X-X|(&TQyASjyNq;@NXGk!`o>mm1meW+|<7_Z(8U1r=JhE zc*SifpU>y~`_H~RmbE*oOJ|&&!Z>A5!25fBf3M~ryEx6{t+GIj6KN4X`%}1*_pc8} z*NdDxBa1atV9zS3qT%cX!2B|G{|UZq+4mnR=1(tR2j#A9mJI!lTeg(euV&iu&64}u zhP3H&jUC&p80NDXep+sS^gV-8g8$NQ+cX*8v%WYuO*U^IbA?FK5%>97`Ax14z$_7} z(r}r})q!{UZmo|Tac}q(nB1iQ>zi-iu3sm^RrUGnZ~On>3Z9?m*?4ZJ{t{LD8qI%l z5AGb?DShGbkJWb==k1dI^QiAYvfS^a$k)o>S26z4Z@Pcvz^5a^PG{enhw?wTB(UJ9 zc~m*~19Qa-m;EK)$Q{shEV%!{J!=*_gYM5-T*U-ugY%~OY%9E+->kap4lJY?JYD@< J);T3K0RU>;>zDul literal 0 HcmV?d00001 diff --git a/static/icons/icon-512.png b/static/icons/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..473ab5a869dbeffa025b0addf410c3cb73706e9f GIT binary patch literal 3829 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 g?te<>LN+{JCEzM00000 literal 0 HcmV?d00001 diff --git a/static/icons/icon.svg b/static/icons/icon.svg new file mode 100644 index 0000000..22959c3 --- /dev/null +++ b/static/icons/icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/static/js/nav.js b/static/js/nav.js new file mode 100644 index 0000000..b1f7c1d --- /dev/null +++ b/static/js/nav.js @@ -0,0 +1,53 @@ +(function () { + var toggle = document.getElementById('nav-toggle'); + var nav = document.getElementById('site-nav'); + var backdrop = document.getElementById('nav-backdrop'); + if (!toggle || !nav) return; + + function openNav() { + nav.classList.add('open'); + if (backdrop) { + backdrop.hidden = false; + backdrop.classList.add('show'); + } + toggle.setAttribute('aria-expanded', 'true'); + document.body.style.overflow = 'hidden'; + } + + function closeNav() { + nav.classList.remove('open'); + if (backdrop) { + backdrop.classList.remove('show'); + backdrop.hidden = true; + } + toggle.setAttribute('aria-expanded', 'false'); + document.body.style.overflow = ''; + } + + function isMobileNav() { + return window.matchMedia('(max-width: 767px)').matches; + } + + toggle.addEventListener('click', function () { + if (nav.classList.contains('open')) closeNav(); + else openNav(); + }); + + if (backdrop) { + backdrop.addEventListener('click', closeNav); + } + + nav.querySelectorAll('a').forEach(function (link) { + link.addEventListener('click', function () { + if (isMobileNav()) closeNav(); + }); + }); + + window.addEventListener('resize', function () { + if (!isMobileNav()) closeNav(); + }); + + document.addEventListener('keydown', function (e) { + if (e.key === 'Escape') closeNav(); + }); +})(); diff --git a/static/js/pwa.js b/static/js/pwa.js new file mode 100644 index 0000000..8f8f5bc --- /dev/null +++ b/static/js/pwa.js @@ -0,0 +1,76 @@ +(function () { + var deferredPrompt = null; + var installBtn = document.getElementById('pwa-install-btn'); + var iosHint = document.getElementById('pwa-ios-hint'); + + function isStandalone() { + return window.matchMedia('(display-mode: standalone)').matches + || window.navigator.standalone === true; + } + + function isIOS() { + return /iPad|iPhone|iPod/.test(navigator.userAgent) + && !window.MSStream; + } + + function updateThemeColor() { + var meta = document.getElementById('meta-theme-color'); + if (!meta) return; + var theme = document.documentElement.getAttribute('data-theme'); + meta.setAttribute('content', theme === 'light' ? '#e8eef8' : '#050508'); + } + + function showInstallBtn() { + if (installBtn && !isStandalone()) { + installBtn.hidden = false; + } + } + + function showIosHint() { + if (iosHint && isIOS() && !isStandalone()) { + iosHint.classList.add('show'); + } + } + + if ('serviceWorker' in navigator) { + window.addEventListener('load', function () { + navigator.serviceWorker.register('/sw.js', { scope: '/' }).catch(function () { /* ignore */ }); + }); + } + + window.addEventListener('beforeinstallprompt', function (e) { + e.preventDefault(); + deferredPrompt = e; + showInstallBtn(); + }); + + if (installBtn) { + installBtn.addEventListener('click', function () { + if (!deferredPrompt) return; + deferredPrompt.prompt(); + deferredPrompt.userChoice.then(function () { + deferredPrompt = null; + installBtn.hidden = true; + }); + }); + } + + window.addEventListener('appinstalled', function () { + deferredPrompt = null; + if (installBtn) installBtn.hidden = true; + if (iosHint) iosHint.classList.remove('show'); + }); + + document.addEventListener('DOMContentLoaded', function () { + updateThemeColor(); + showIosHint(); + if (!isStandalone() && !deferredPrompt && installBtn) { + installBtn.hidden = true; + } + }); + + document.addEventListener('click', function (e) { + var pick = e.target.closest('[data-theme-pick]'); + if (pick) setTimeout(updateThemeColor, 80); + }); +})(); diff --git a/static/manifest.json b/static/manifest.json new file mode 100644 index 0000000..a2d5c1b --- /dev/null +++ b/static/manifest.json @@ -0,0 +1,33 @@ +{ + "name": "国内期货交易监控复盘系统", + "short_name": "期货监控", + "description": "期货交易监控、持仓管理、复盘与统计分析", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "any", + "background_color": "#050508", + "theme_color": "#050508", + "lang": "zh-CN", + "categories": ["finance", "productivity"], + "icons": [ + { + "src": "/static/icons/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/static/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/static/icons/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/static/sw.js b/static/sw.js new file mode 100644 index 0000000..7fb3f4b --- /dev/null +++ b/static/sw.js @@ -0,0 +1,61 @@ +var CACHE_VERSION = 'qihuo-v2'; +var STATIC_CACHE = CACHE_VERSION + '-static'; +var STATIC_ASSETS = [ + '/static/css/tech.css', + '/static/css/responsive.css', + '/static/js/theme.js', + '/static/js/nav.js', + '/static/js/pwa.js', + '/static/js/symbol.js', + '/static/icons/icon-192.png', + '/static/icons/icon-512.png', + '/static/manifest.json', + '/login' +]; + +self.addEventListener('install', function (event) { + event.waitUntil( + caches.open(STATIC_CACHE).then(function (cache) { + return cache.addAll(STATIC_ASSETS).catch(function () { /* ignore partial */ }); + }).then(function () { return self.skipWaiting(); }) + ); +}); + +self.addEventListener('activate', function (event) { + event.waitUntil( + caches.keys().then(function (keys) { + return Promise.all(keys.filter(function (k) { + return k.startsWith('qihuo-') && k !== STATIC_CACHE; + }).map(function (k) { return caches.delete(k); })); + }).then(function () { return self.clients.claim(); }) + ); +}); + +self.addEventListener('fetch', function (event) { + var req = event.request; + if (req.method !== 'GET') return; + + var url = new URL(req.url); + if (url.origin !== self.location.origin) return; + + if (url.pathname.indexOf('/static/') === 0) { + event.respondWith( + caches.match(req).then(function (cached) { + return cached || fetch(req).then(function (res) { + var copy = res.clone(); + caches.open(STATIC_CACHE).then(function (cache) { cache.put(req, copy); }); + return res; + }); + }) + ); + return; + } + + if (req.mode === 'navigate' || (req.headers.get('accept') || '').indexOf('text/html') !== -1) { + event.respondWith( + fetch(req).catch(function () { + return caches.match('/login'); + }) + ); + } +}); diff --git a/templates/base.html b/templates/base.html index 5e53117..0c6da80 100644 --- a/templates/base.html +++ b/templates/base.html @@ -2,7 +2,16 @@ - + + + + + + + + + + {% block title %}国内期货监控系统{% endblock %} + + {% block extra_js %}{% endblock %} diff --git a/templates/login.html b/templates/login.html index 0d367ac..aeb265f 100644 --- a/templates/login.html +++ b/templates/login.html @@ -2,7 +2,15 @@ - + + + + + + + + + 系统登录