From 0327f49f4ef7354d95a2d0c8ffe7e8f955711cbf Mon Sep 17 00:00:00 2001 From: dekun Date: Mon, 5 Oct 2026 18:54:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=AD=E6=8E=A7=E6=94=AF=E6=8C=81=E4=B8=80?= =?UTF-8?q?=E9=94=AE=E5=AE=89=E8=A3=85=E5=88=B0=E6=A1=8C=E9=9D=A2=EF=BC=8C?= =?UTF-8?q?HTTPS=20=E4=B8=8B=E5=8F=AF=E8=A3=85=E6=88=90=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E5=BA=94=E7=94=A8=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- app.py | 24 ++++++++ static/hub.css | 40 ++++++++++++- static/hub_pwa.js | 89 +++++++++++++++++++++++++++++ static/icons/apple-touch-icon.png | Bin 0 -> 1596 bytes static/icons/favicon.ico | Bin 0 -> 1949 bytes static/icons/icon-16.png | Bin 0 -> 281 bytes static/icons/icon-192-maskable.png | Bin 0 -> 1679 bytes static/icons/icon-192.png | Bin 0 -> 1757 bytes static/icons/icon-32.png | Bin 0 -> 378 bytes static/icons/icon-512-maskable.png | Bin 0 -> 4577 bytes static/icons/icon-512.png | Bin 0 -> 4847 bytes static/icons/icon.svg | 7 +++ static/icons/manifest.webmanifest | 37 ++++++++++++ static/sw.js | 7 +++ templates/base.html | 21 +++++-- 15 files changed, 220 insertions(+), 5 deletions(-) create mode 100644 static/hub_pwa.js create mode 100644 static/icons/apple-touch-icon.png create mode 100644 static/icons/favicon.ico create mode 100644 static/icons/icon-16.png create mode 100644 static/icons/icon-192-maskable.png create mode 100644 static/icons/icon-192.png create mode 100644 static/icons/icon-32.png create mode 100644 static/icons/icon-512-maskable.png create mode 100644 static/icons/icon-512.png create mode 100644 static/icons/icon.svg create mode 100644 static/icons/manifest.webmanifest create mode 100644 static/sw.js diff --git a/app.py b/app.py index 55ff4dd..444ebd7 100644 --- a/app.py +++ b/app.py @@ -362,6 +362,8 @@ def api_hub_backup_create(): env_path=str(ENV_PATH), db_path=_resolved_hub_db_path(), label="manual", + username=hub_username(), + password=hub_password(), ) return jsonify(result) except Exception as exc: @@ -395,6 +397,12 @@ def api_hub_backup_restore(): env_path=str(ENV_PATH), db_path=_resolved_hub_db_path(), ) + if result.get("ok"): + u = str(result.get("hub_username") or "").strip() + p = result.get("hub_password") + if u or p is not None: + set_hub_credentials(u or hub_username(), "" if p is None else str(p)) + result.pop("hub_password", None) return jsonify(result), (200 if result.get("ok") else 400) @@ -517,6 +525,7 @@ try: env_path=str(ENV_PATH), db_path_fn=_resolved_hub_db_path, hour=3, + get_credentials=lambda: (hub_username(), hub_password()), ) except Exception as _hub_bak_err: print(f"[backup] scheduler: {_hub_bak_err}") @@ -781,6 +790,21 @@ def api_cond_orders_exit(hub_order_id: str): return jsonify(post_cond_exit(inst, hub_order_id, payload)) +@app.route("/manifest.webmanifest") +def pwa_manifest(): + path = ROOT / "static" / "icons" / "manifest.webmanifest" + return send_file(path, mimetype="application/manifest+json; charset=utf-8") + + +@app.route("/sw.js") +def pwa_service_worker(): + path = ROOT / "static" / "sw.js" + resp = send_file(path, mimetype="application/javascript; charset=utf-8") + resp.headers["Cache-Control"] = "no-cache" + resp.headers["Service-Worker-Allowed"] = "/" + return resp + + if __name__ == "__main__": # PM2 下禁止 debug reloader,否则会 Bad file descriptor 崩循环 _debug = (os.getenv("APP_DEBUG") or "").strip().lower() in ("1", "true", "yes", "on") diff --git a/static/hub.css b/static/hub.css index 98b424c..43902eb 100644 --- a/static/hub.css +++ b/static/hub.css @@ -169,11 +169,16 @@ a:hover { color: #7dd3fc; } .nav-spot--flat .nav-spot-last, .nav-spot--flat .nav-spot-chg, .nav-spot--flat .nav-spot-pct { color: #9aa3bf; } -.topbar-logout { +.topbar-actions { position: fixed; top: 16px; right: 22px; z-index: 20; + display: flex; + align-items: center; + gap: 10px; +} +.topbar-logout { color: var(--muted); font-size: 0.82rem; letter-spacing: 0.04em; @@ -181,6 +186,39 @@ a:hover { color: #7dd3fc; } .topbar-logout:hover { color: #e8f1ff; } +.topbar-install { + appearance: none; + border: 1px solid #304164; + background: #151a2a; + color: #dbe4ff; + font-size: 0.78rem; + border-radius: 8px; + padding: 4px 10px; + cursor: pointer; + font-family: inherit; +} +.topbar-install:hover { + color: #ffffff; + border-color: #3d5278; +} +.topbar-install-hint { + position: fixed; + top: 46px; + right: 22px; + z-index: 20; + margin: 0; + max-width: min(360px, calc(100vw - 40px)); + color: var(--muted); + font-size: 0.75rem; + line-height: 1.4; + text-align: right; +} +@media (display-mode: standalone) { + .topbar-install, + .topbar-install-hint { + display: none !important; + } +} @media (max-width: 1100px) { .topbar-row { grid-template-columns: 1fr; diff --git a/static/hub_pwa.js b/static/hub_pwa.js new file mode 100644 index 0000000..de3a6e7 --- /dev/null +++ b/static/hub_pwa.js @@ -0,0 +1,89 @@ +(function (global) { + var deferredPrompt = null; + + function isStandalone() { + return ( + (global.matchMedia && global.matchMedia("(display-mode: standalone)").matches) || + global.navigator.standalone === true + ); + } + + function btn() { + return document.getElementById("hub-install-btn"); + } + + function setHint(msg) { + var el = document.getElementById("hub-install-hint"); + if (el) el.textContent = msg || ""; + } + + function showInstall() { + var el = btn(); + if (!el || isStandalone()) return; + el.hidden = false; + } + + function hideInstall() { + var el = btn(); + if (el) el.hidden = true; + setHint(""); + } + + function downloadShortcut() { + var origin = global.location.origin; + var body = "[InternetShortcut]\r\nURL=" + origin + "/\r\n"; + var blob = new Blob([body], { type: "application/internet-shortcut" }); + var a = document.createElement("a"); + a.href = URL.createObjectURL(blob); + a.download = "期权中控.url"; + document.body.appendChild(a); + a.click(); + a.remove(); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 1000); + } + + async function onInstallClick() { + setHint(""); + if (deferredPrompt) { + deferredPrompt.prompt(); + try { + var choice = await deferredPrompt.userChoice; + deferredPrompt = null; + if (choice && choice.outcome === "accepted") { + hideInstall(); + return; + } + } catch (e) { + deferredPrompt = null; + } + } + downloadShortcut(); + setHint("已下载快捷方式,拖到桌面即可。Chrome / Edge 也可在地址栏右侧点「安装」。"); + } + + function boot() { + if (isStandalone()) { + hideInstall(); + return; + } + showInstall(); + global.addEventListener("beforeinstallprompt", function (ev) { + ev.preventDefault(); + deferredPrompt = ev; + showInstall(); + }); + global.addEventListener("appinstalled", function () { + deferredPrompt = null; + hideInstall(); + }); + var el = btn(); + if (el) el.addEventListener("click", onInstallClick); + if ("serviceWorker" in navigator) { + navigator.serviceWorker.register("/sw.js", { scope: "/" }).catch(function () {}); + } + } + + global.HubPwa = { boot: boot }; +})(window); diff --git a/static/icons/apple-touch-icon.png b/static/icons/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..47284017384c2ea3688025c434f5d22edb3f363b GIT binary patch literal 1596 zcmV-C2E+M@P)FUq5fYtKQX9 zufAzbOIsQsufKWsImz^SdVJV=uVDjNA_3nZmPoiah$Ry44P=P~JHsrIHUl=0B~n{w zm?ctMZy-ygw$3n1q_)m5OC;18W{HG)8wvBLj~_gX6Xwm^_ruK8TTjdY16~^S)&uh; z$lreVJq;7)pTGZV0(%eYttIA{AVVAeaUEsSt6m%wHGYX(nv1d&M?bS)FoRwmwdwn zX6b>tC}{U%NE+zgo?L3*SvyNFJ73z(Mh%HHdSw4fiIjYH+|bT4QcFJ@*3c5Kq3vu) z3bNyo?QBS-9gpl3x1>O)#LdvM_6%)zLq^{1(9mL+Lj-6MphbWdphbWd0a^rT5ugQV z5uioJ$t(YYvib3s-w*%HAHV+O9|!cjfN%W{z=56)@!sDLH_%feh8yV6kgu%;>|~c? zcFZ%ZOG5{Re566oK9;tAIor`w-_g$$_TF~0?U(-dT`WhxhXv@9kXj%baZNx6!rT+g z3~L+#bT%)~0cG#wuYSR}bVKiX@<(jES=X(hp*X#+RhxRrhQ9S=&(v;_{uT`lz|Hlp z*3=p1`P&R?GjzC%DDN092Krh{-NNuZ&y6rso<+S%OJ|t(VeX0g$Qo8hZR9x6iak(| zum+$5wDTo6EkT`K!^$n4VLlF~1?qd(uqtXJ$4RU;QID_&po6sYk#|6AfI9L!Z>@F3 zmd^H@$3a~Z^Q!yPMvg&H*T8J#a3-(|>Ry;5jvd*!(HC_K%qxu@MvjiCjTu09dl@Z_ zdKApj#*S>HC>SKpp)a4R8$W<<_OjdR*i>!QzBI_#(fkZxkEV`zB+JM#(1*YnKY%X&^4t4# zc4^eUcyocV(-P7>YgnX?ljfl#lu-wgDQmYNmC zt#$j-AgE!UG~4TM-hDpu1D`&A2yw-|2kyuiW?z5W`L_O>x9>G{sXNU^ZR_ZmHFSfE zsS$w8v{ns0_`TD;+j=F;8oI-_R|_~Ju4(j!2D(5KmxR>&@qvc=E?_Mm3+P2b&#)&Q zeO7i+xDcAvFZ{0Mm4CrLJR`I<$Us-Y)DkzuKu?bwVxWf^18lni?LtzL+ebx!7NA9d z76DoWXc3?VXc3@AfEEE-1ZYWaPKunLf0*~1rGER%!dp9T!?_@YoE2;6p*HrW7 zq!QbCBDJjLRu3f7!dPzofFd<*6+vmPmfnzy-ae|WWfVijA!=*sS%!J^1q#ev8(LdS u&(dqwrf@^t;&Hl+2XI3i3N+vV*UG=RI^!hPkjj?+| literal 0 HcmV?d00001 diff --git a/static/icons/favicon.ico b/static/icons/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..842383994c10610aeba335fdb587ede753b21fcf GIT binary patch literal 1949 zcmah{c{tnY7XD?SA~Iqp(u&w=NNq(s5`s%DlZjqi?R!HFTCTcuBued*qSF!vEmf)& zZMBF&Xf&!(sPa>*Y5LP(>e#a9t7&JGlD6;A|^ zQj+4Vv9cE;E&>+^yOSvuVc{9zxWLPMGTIrcw3B~%cUo#;@8YZimnx;z5qYlg z12Bzo3WqQ(;I7o``f1xD8!wV-h-8oXjTnam_{`vJyc|WQSF$}S-e_(?X;T(rFOP~Z z_@=_IJD5jXHJv@HYdUd?Tlh-HO-2!{8%rNL6O=0tf&9I8q8Ic&Dtxc67nt0`Jfjbu zR?%hRt;{OyX5S@&jusmQ8#g4|5Ay(D*%PXmdX^i`*{vtEwqMN?VTBB7m!3q%svTfP zG6GrfVFZW&NhAWs3~c=Xf)cA#M3jq8d5Jf!kn6oy zw`TjNiVXY9#&*PHpqjr!$&*R$TJ=i80ntGjkcS!#EjqV>qkrpGRiaCzU!_|(b>}p80X%v&fP9$QtUg3DNJ{p8{4|@IQGb zffmjvYfUKcuG!}9J}*;zG;45QQrqfPVtUv4B0hAc=+?t>+Tv^Nnwy?EfspES^9EuR zvTE*H)0FBo&)zl4UAh;$%Pb zS{l_ke~RoYGt6Ocp}@F-2Ns-<|9(rYBD6LfCNXEs{YQtgRyD2eAJWxvG}zE+F#Y*O zhzkgj-M8~=@M=Cxlz+Qy@Y)Bzk-;UTQ|S1L(OO3{iv9jL`5y!kdmF%i6~r67c}Xk? ze_xR4@?(_8c$w@7_YMhEwLr@C3SB)OC2iaTY6G~xWUG_g=vw3+OCnX(?46p{`^U+p ztx8JUIT|ZF#TqBj5Uq#Sw%gf~u^VYeTTDkyQ}U26!5U#^2ErhXAIN=09z%LsA^n0F zTD{aCST||W5?7fzvAY&Qfg1Jnje~!J)nG43Jotv7GdE*c%O_{9lXN>+O-5i8!meFY z|5047$M#fxbXj^E)tg8Fdn`M{IHca^4c*aD`)g0w2>%(`rc2XtAD{LnCr4_NQMRH5 z3dnElc>(l9-`TS8jZ=P5dPc&bb%ElAMm`66F%bSFsc|Ijwn+iq8T!WInG28}V8klT z`}EiVTWb~oozE_=vD(IGI98L>FfW_)nU9V;Yr1n)BZO<^Vo}LPRa3TCJj~EJtp71P`i=0LJL@6Fi`gW z>9=e{=@#fe8wimBT)Riv-iWq!9sDAn@!Ap}dxLeyA?#TLLEyY;Is0*(@eeK_iu=T` zE@(WR@D>2Tar-WqXC9&S;gOEsKfcHsMoJeU8x{QxB~%0`#R{xHV<#Vn| z4ykdjZbW$r^MT?FN|GfWuR1UCD8s(xS@p6-*@2KlgsY{ zDkWnf!~X5)$Y2klU&8%?3>*YW^(EZgn=({KA5}P>gf*9}0w+*A&wURyW$X#3GYN#l zC5Im7|3SlbKzTj~9X{{I7Y+@W#C(giXWRd%xL!ljjgPpb8yy8QH(Jps$~?&ah2k{| zWnAv?f+K24EV9>Xl24KZqa{?=S%8zclV@+%W`GGhq8tX&FQK^c+SM{+|07SIf13-o zFn-_Z`_$o<4de?f*xH>~#B>8ajQ~F|oa?$CI`?6Fk1{*tyH7kY-%ICr+Otn|LmMI=Q2C)$SvQ61K?jF0ctNMKERB0uM ztstSxzvY7s)bhEyr&!WtLc=YY6h051C{{xl(KVxMLVU^T$G?JH4Y@G!s@4oCgiM%3?`fw fMbQM~qi1ITCqux+Ri#G$00000NkvXXu0mjf7!h&Z literal 0 HcmV?d00001 diff --git a/static/icons/icon-192-maskable.png b/static/icons/icon-192-maskable.png new file mode 100644 index 0000000000000000000000000000000000000000..573979fc8c12ce535a02bfa15045351f58c34b64 GIT binary patch literal 1679 zcmYjRdsLE#8~(r#1=QbwG!>nEDTJD2sm0owkdb&f%Ns_NCat`r#ysg<<%LhgbY(=T zXu1+N^O%+^T?6d`(=D5_)U>>0UTd{7qb#E2^27bL_nh~ApXZb(rhlR3YEL*+YXlu)inaHpK0P7uLtSy|w<1Zh5A#{k^Medz4kk6(H@D_UT-G zzwd1R#L5FYv)PrbPv235ujF$apGBt>%p@v^tY+}v%iIq>Ve8W$Ice_3p9);E71A&s zoWh_X*3`nR%&x2nng7R|($6nP?Lzz#L@ph`WRp-nL+$VKGyQNOFrL0@oOEzNW0zJa zMj zBN5@KIy8vO^T0u|+V|o^uhI$i=dyfz&z}r+QDG!);*RGr&yD+Hb#7-5_2IoiXJ=(V z_sSy~;7%r-j@%d!&$}H4vykz`=Fr04&yta#!}J+wn}F&s5jFxFyJ-%lh#sdS-U=S- zxQnSQ;yAB0427%kzR#pU>b4mw0?}Ji2ZCOt0s@YIc&B@=bNuf%!yne$BU)=-uC*7E zF|95`u_N58*zB1p#v)tF@2?J(qlgc_)>J^V)#xkJ^X7PYGPv+y{Y9jYTB_}r@`tM@ z9GnRJSC?}B$~hT8R{p&~FqRf`0h`@!?g=Eg;Z4uuTm80?A!2xtZ(6f%HNp>_oT zF?SnS-^=E;H01O!R1O14-H}LS#U~65Ix5IOUbaWLXxggGDnSoCFb(#duIo1R0dcCZdW(ERiwMT74ftk&|iAQQtA4*I%6Luv#-0JWIL=G zauv7?O_m&6A>TAfzBfq0_psn?EovjY4Lg2qpZ`*Bum*?mcfUn3fL^&-&l;-$r~aIl z;wK$1URQGnzH2P@$S+w8gWCvb^J0d=@cIPz8)5tsed<uaGyO zMUk-dWzT7U^p}X3NpWkZI1E5%wSP*4044wf00K^S^xC8{RG7zhtISW7EJt~&p4%y* zfJ)Uvzc=OfT-&dPUvzv+ZNdULpc+!s7_8Ds>&rQF&aaP#^6IkeOFBjV@4nfiwZFOvqnv$ui`DBaP99&SJ6YBHxbS718S0OU>A#! znxDMCmF-(Z-pMdTk59Q@b0QaN70>!@QmrK68If-1MmHPtI%FvRaTVkHDF{(RMA?f~mw$2PY+yEq`OVKqSl9c}06bU+G~jan8~)2!z13jz X$!gr(v5{3jF7vQ$+gYu_e9`{_m*DCn literal 0 HcmV?d00001 diff --git a/static/icons/icon-192.png b/static/icons/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..423310ed0fd793ed837a85e945d99d4c3cdb5b8a GIT binary patch literal 1757 zcmZ9NX;f1O8isFfFL*B)2>T)!Ai+x5H%W155(Sa~6{G2 z005xrGQ#6eZ^dwH{C5IGM`~cm8zSckj5J6leih?#phjraL8eMF^A?A+EEK95ngo~3?{DlD zhxsDGft-0CbK?0Gm;hwpKL>%N zk0;VkRVW@jB1tx|Joyw{fLl!5HulGeo>wqeQXZ4pPQBf09ob|yqxVw~1@T}=-$EL5 zq-~w0dFJ!sn6ZNZ66)FoNb42WI>OyLCfPX9JxWfv3KO)U-%wGfVJ?$ z<&^>7W{@ssd1AMpfyBM62JwIabLJnf&*~kFlu~ay3#DZYfO0Mn%>cpMsU>(6%D)xH zn~>+lMQmVDaIsCC^Nap!x&bOs_)Ve!OXr%0wXc122;>mt3sGCJX03r1(nKB%zFw~B zZlr}eMwCseGV*)Q8y6Aypc9g&js$=A2=8r@G}8gg#jwz35}^t#dDO+gCuV zr%D@7aH7|-m6}G*lBgQ+#Uhr;?Go_XR2YqEi(XH|-Ut~=)h|hP5H*7oqf?JIWN;@O zNvI~$I6g~v%dwRbAk*^ZmQM*smCtcNI)BNO9E_y%fOF=URM4m;;Z=w56oJwtX3Au@ zlT2&DOC>!6zJMl7LeWg*kO@bu#fJKPcifqsaq%kdwV5;n)X)wHTyRLf!(nrm!<@i( zht45+Jn8CQ)-ne5dmA?SrNnP!?A!B&_;*QJ1;CTYEls(ys}7J!5_p4P6`F*=ex4oH zXCGt+CDTP{`?xeXF^OK~mGI`3SreHPA3Ln3VG^?M(yC)8l`e9=KgO>w4P2{*qPng6 zZ%yxMt4r`jIxSA?=ug-EQE5rZsL>p@)mJKC<+9S8z+uQNeH{gUJLV`g( zjdIfUKx4PdL#M*fhyAU)(DX8OyPz9xuYR<)+W0(wr0RQ7(=MtZuN_u2OOALlD*5B) z_{Lq*>e52#m+ub?kxjVbv;MaSRfUJUk|n2=MrECTtI-7(asv77QXh?Ccws<;0H6#9 zR^5&||4u{-M7fo?Pjs)uLSpp14JX$@4a95lA5F8qz@*5JftXO~GUTwd600Nf=&erh z(C%H2G$ng#Ks><019KHjk0q@aQ{EwVGiJ|q51?qAX`<7AqxHX8V^7+7I z@U}0!YG*MzP$L0~?Zn2(kzIshu=9h?_ z>&{f93kUN{?!v@&#hh8sSh?!ggC$nc9KKR=^3@xQ%BI8bh4}+DfFCM&jadzN-cay# zLeK9Dr^1y>@{q``_0!iradSNJpsYft&)_7F=XkoZ)G}0P^&%xB*1{W4UJ$q5RBEi?qW&q z_u?D!sp7XjGnq)j7oY>IC}-Bj>GGSQ4R@2H6AJmC9e+z4lfL}>)_x&+QVaFypBcu2 zZW_A_Z^9LAsBE7_trxQ~VA>_=2_&Hy>Y13bjhH>26)02#+yvcoRv5%CS?Yq#z@a?V z(u#)p_?~-H%r3Zv_}jbQ$=NHw3jlYm`-+ku+RjVN(qqH=6*a`#2vg9kWjJ$V(VbkC q6h7i%Y49{ff`46ywn$gdw)R|5xbpTJ=Zx*VEr9NE%)RbNDED95DiU-6 literal 0 HcmV?d00001 diff --git a/static/icons/icon-32.png b/static/icons/icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..613ec4933df419c3a43fe30a82e36d82e20b22ac GIT binary patch literal 378 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 literal 0 HcmV?d00001 diff --git a/static/icons/icon-512.png b/static/icons/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..6a4b8e02aeaa8deba794bfd0ad997f38e8b47819 GIT binary patch literal 4847 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 + + + + + + diff --git a/static/icons/manifest.webmanifest b/static/icons/manifest.webmanifest new file mode 100644 index 0000000..719cbf1 --- /dev/null +++ b/static/icons/manifest.webmanifest @@ -0,0 +1,37 @@ +{ + "name": "加密货币|OKX 期权中控", + "short_name": "期权中控", + "description": "多机期权持仓总览与工作台", + "id": "/", + "start_url": "/", + "scope": "/", + "display": "standalone", + "background_color": "#070b14", + "theme_color": "#070b14", + "icons": [ + { + "src": "/static/icons/icon-192.png?v=1", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/static/icons/icon-512.png?v=1", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/static/icons/icon-192-maskable.png?v=1", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/static/icons/icon-512-maskable.png?v=1", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/static/sw.js b/static/sw.js new file mode 100644 index 0000000..7800c8c --- /dev/null +++ b/static/sw.js @@ -0,0 +1,7 @@ +/* 期权中控 PWA:仅占位使可安装,请求一律走网络 */ +self.addEventListener("install", function (event) { + event.waitUntil(self.skipWaiting()); +}); +self.addEventListener("activate", function (event) { + event.waitUntil(self.clients.claim()); +}); diff --git a/templates/base.html b/templates/base.html index 390648a..5c66ec8 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,12 +4,23 @@ {% block title %}加密货币|OKX 期权中控{% endblock %} - + + + + + + + + - {% if session.get('logged_in') %} - 退出 - {% endif %} +
+ + {% if session.get('logged_in') %} + 退出 + {% endif %} +
+

{% if session.get('logged_in') %} 加密货币|OKX 期权中控 @@ -54,5 +65,7 @@ {% if session.get('logged_in') and not request.path.startswith('/desk') %} {% endif %} + +