From 6129173fe68de336d5f2e64200c36efa3dae09a7 Mon Sep 17 00:00:00 2001 From: Wang Defa <1+wangdefa@noreply.gitea.bcde.io> Date: Tue, 21 Jul 2026 19:26:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E9=A1=B5=E9=9D=A2=E9=87=8D=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E4=B8=8E=E7=A7=BB=E5=8A=A8=E7=AB=AF=E9=80=82=E9=85=8D?= =?UTF-8?q?;=E6=8E=A5=E5=85=A5=20PWA=20=E4=B8=8E=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E5=88=86=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 + index.html | 2 + package-lock.json | 4613 ++++++++++++++++- package.json | 1 + public/apple-touch-icon.png | Bin 0 -> 10593 bytes public/pwa-192.png | Bin 0 -> 11510 bytes public/pwa-512.png | Bin 0 -> 11728 bytes src/assets/main.css | 83 + src/components/FilterBar.vue | 33 + src/components/FormModal.vue | 39 +- src/components/MobileCardList.vue | 28 + src/components/PanelHeader.vue | 20 +- src/components/TenantHoverCard.vue | 57 + src/components/TenantPicker.vue | 2 +- src/components/ai/AiChannelModelsModal.vue | 5 +- src/components/ai/AiChannelPanel.vue | 24 +- src/components/ai/AiKeyPanel.vue | 4 +- .../instance/InstanceTrafficPanel.vue | 24 +- src/components/instance/VnicPanel.vue | 5 +- src/components/logs/AiCallLogPanel.vue | 13 +- src/components/logs/LogEventPanel.vue | 98 +- src/components/logs/SystemLogPanel.vue | 35 +- src/components/network/ReservedIpPanel.vue | 9 +- .../objectstorage/ObjectBrowser.vue | 440 +- .../objectstorage/ObjectViewerModal.vue | 18 +- src/components/objectstorage/ParPanel.vue | 1 + src/components/proxy/ProxyPanel.vue | 33 +- src/components/proxy/ProxyTenantsModal.vue | 5 +- .../settings/AccountSecurityCard.vue | 13 +- src/components/settings/AiSettingsTab.vue | 9 +- src/components/settings/BlacklistAddModal.vue | 5 +- .../settings/NotifyTemplateModal.vue | 5 +- src/components/tenant/AuditLogTab.vue | 18 +- src/components/tenant/IdpTab.vue | 7 +- src/components/tenant/InvoiceDetailModal.vue | 5 +- src/components/tenant/InvoicePdfModal.vue | 8 +- src/components/tenant/InvoiceTab.vue | 2 - src/components/tenant/MiscTab.vue | 2 +- src/components/tenant/PaymentMethodsModal.vue | 6 +- src/components/tenant/QuotaTab.vue | 93 +- src/components/tenant/SubsTab.vue | 4 +- src/components/tenant/UsersTab.vue | 2 +- src/composables/useActionLabel.ts | 22 + src/composables/useIsMobile.ts | 22 + src/composables/useMobileModal.ts | 17 + src/layouts/AppLayout.vue | 30 +- src/layouts/MobileTabBar.vue | 65 + src/layouts/MoreSheet.vue | 53 + src/layouts/SidebarNav.vue | 150 +- src/layouts/navItems.ts | 149 + src/theme/naive.ts | 9 + src/views/AiGatewayView.vue | 41 +- src/views/BootVolumeListView.vue | 10 +- src/views/InstanceDetailView.vue | 74 +- src/views/InstanceListView.vue | 77 +- src/views/NetworkListView.vue | 2 +- src/views/ObjectStorageView.vue | 5 +- src/views/OverviewView.vue | 4 +- src/views/ProxyListView.vue | 6 +- src/views/SettingsView.vue | 17 +- src/views/TenantDetailView.vue | 66 +- src/views/TenantListView.vue | 65 + src/views/VcnDetailView.vue | 54 +- vite.config.ts | 79 +- 64 files changed, 6243 insertions(+), 549 deletions(-) create mode 100644 public/apple-touch-icon.png create mode 100644 public/pwa-192.png create mode 100644 public/pwa-512.png create mode 100644 src/components/FilterBar.vue create mode 100644 src/components/MobileCardList.vue create mode 100644 src/components/TenantHoverCard.vue create mode 100644 src/composables/useIsMobile.ts create mode 100644 src/composables/useMobileModal.ts create mode 100644 src/layouts/MobileTabBar.vue create mode 100644 src/layouts/MoreSheet.vue create mode 100644 src/layouts/navItems.ts diff --git a/README.md b/README.md index ce54abb..8294843 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,10 @@ npm run build # 类型检查 + 产物构建到 dist/ 1. **静态直出**:`dist/` 交给 Caddy/nginx 伺服,`/api/*`、`/ai/*` 反代到后端 2. **单文件嵌入**:产物经后端 `go:embed` 打进单个二进制。本仓库 Release 流程(tag `v*`)自动构建并发布 `dist.zip`,后端 Release 流程从这里下载嵌入;本地则 `npm run build` 后把 `dist/` 内容拷入后端 `internal/webui/dist/` +### PWA + +构建产物自带 PWA(vite-plugin-pwa,`manifest.webmanifest` + Service Worker),HTTPS 部署下手机浏览器可「添加到主屏幕」以独立窗口运行;前端发版后用户刷新即自动更新(`registerType: autoUpdate`)。Service Worker 只预缓存应用壳(约 4.6MB,office 预览大块按需缓存),`/api/*`、`/ai/*` 一律直连不缓存。图标源自 `public/favicon.svg`,改版时需同步重生成 `public/pwa-*.png` 与 `apple-touch-icon.png`。 + ## 规范 编码规范与项目约定见 [AGENTS.md](AGENTS.md) 与 [.trellis/spec/](.trellis/spec/)。 diff --git a/index.html b/index.html index 765d5b6..25dd407 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,8 @@ + +
e`rMM!Pjc7cJ`hxtTgxgisH@h_tPK9#+ZJs;3$PSf72 z(V^*$T`Ol?nMc(hQGZR;aizyO oZ<^IWxa!;WaSkHTdFb)Qe8xK@9& z>94_kplfEvQUwqI=wl}oFyF z0y?_Gwy+LSICS4mc !bj=~Pk1WaV6Wik-JtP+vyl|Sr zdx(4$NQL!soV$1CT8#q8))2piC2QgOrZ~8W;qzcP=F$FO&RK@+KN~1}NT}kAkeuTQ z!S?g;SWVC+jE@9k<*3EVILWKboFoj e@A$sDY`AB&6-CVPsKyY9XO-b zPQ(#N*%OUHgRq)EcQUg^#_YRU!i6tl-rl{u$a Jc=K+ zfVH%QApcIv&|VDrOuAp?=w$jv4t{^7>qP`}?7nsAE3lvw>zZLAOg*(X|HuQap;<8- zm~xLtDd~mzP}{NX&7+ONiNS!3z-4j>LpG@V6T)hK^+cu%&0g1N`wGp@IafX+59_Yu znFWCk^?H3g8$P>}LEQ%hBzB3kkRV!IP!w&rvn&enLAQwhSEIm?%O@TAX~b%}{n?6{ ztN~t3TiaIL-BP#t&^cI;89in`tN@CGNeE`#?8xK0%cfc&Qj5jNSf0 uL8pVQ?k764p)g_GhoFXDanG8 L#VMZZ ztDW?xME*9t6TA1Dz@Q-2D&HeD^x`b^FhpGn2X8wKAz)c-I5xKwJSRb&07_lqBoMTw z93$W#A&ICVxGNhv&e0vr8cQ0t+7rp&b#-V>?sp0MoiI%C_={+**Hr`E``d`5V0$}? z3F)KRPM>%Pet!qHTm_Q- =KJ gXCItq2ZSNb`1p;VfiZ?NJ(R4uG5Ur#^xe9!0ONe&*4-Uo$jlXRWpM~%D2Pm8YI z{ffNao=N`B8l<9ro?*@%foU4d#lLEnzMfeU9$3+ome$krc}fHlWujJ)oZjK@aZvRn z)Nt-P@sny<|KPSgj*Vf=#d7s4X^`8Wk6ukJ$Rm)_aFnKp4=(Sv&?Pz?VoDWiK|o}) z!Xq)toRhMY@WRy+;m?-t$Z%&`bb`N#kDLS`jJ9 Dym) zf@B%;*u&{TRl>B{*(0)kX~zDJ8!_{?#n>2WeK`TL@7B1B%9+`HG#Q2};c9TNH>!?5 zM83>e$=>qWK>~ RkS%e(MYExr zzQPzqMpiW+GOM4?;+fz?7j+yNlyO4tKy4;zkXVjv#O7&<{GgH~?DCbMN`%z?B|0^9 z7YnT8w!P0iie<>TLdM9x%)lI_Y_osv;xzfpQ{6K2j3ze3C*c3^gS5t4M4hCPbr_{h zi59HpU%JtcXo@}2y-T=HXk6R6?Crb&W{&C8s4e${MsgPwpEVNJiWz@qhi4*5TZD53 z5>5Ge1)ftJ5n3a5@!7vINhKf?!Q}@S`SBHrN2cql sU|-}3ZFlhq=}4Wvol5)(sDt7SYZ;8nuvd!r+*&GUPpSwZ^@L$Pa0 zMdWw1@+8RbjN8gPjD&>~mtHH_Gg8e?&!N16y@2fmck8fBlSlFPi9JHizx{a>Gdzxp zHm+#3wG+q16t3<&ew{DCyzM&TYhR6uZue<|UtpO0!)T7c*AWwn@BTXO%P`eiYmDFA zZ-F>uS(&Y7B0C~^=zK1^W27=v*>h~1n2E!G*0USE>H1{bru#ndTO8h>58e~H{SArh zBgiyO``APY%=tLN*L6wT5BVk8{78g=>wmL?mJtTD(i*ZjS$Wgl%s;C?0jVYWuMeYp zhS9MmPqZDv{j%KGjy=wS*0M3OtL%)aMk4^evF-TI+&o5^m3q=$ZKieknobq%UwXC) z>&>JOZ!sYL_;6OeC8m3$LiK9UE6Zua&MFge8I;N$Mhv4aMO3ykccH^lY09_b{%G&B zpIuXpT82yBo r4sw<+oe=AvJ}xi53+l znIooSIkoA5f9<4#!uz?srM?6{dJbm@yoA1blY#k^nR0$!?W|ea_X1}&hy-kX9Nm`| z69+ZqQ@GS&LbiA#PC=e7SgsXq NJ{ zz&FF=v+SGqJM~d^SAV!V-Np5CrCd|DxXogVU>Ys>@02ghA5;3! I8R!`Wz_D65 zh q6wOfXpxOrsk-c>r$?k6FlNCtrh>3l_2Fj1_c*6RX z??E%unYb|v;J?<<#`@3_gZx_|z6scR4$L)fGs}i+9+!lz9eN9fI?VEttyD-lAAf=k zOlR KvW>AVttpWq{I!;P=p&A6O_= znu!%|@ G2uovB=>i);%lBU00p{ zfTnmXy)LP6Gdjo@_aHwO!v;wdQ|L8|4Nl#t;tOg30F^uAZggTQM}Wb4wnC?X*SCf= z3HCtzr}F9jD%k$3&=wYRzaOckN54h$hLdyRhhEM5#gcYBbF Y+QB!Q|8yg$T-?7#@Q&J5)$whW_$u{ab7$h5wr-0#DtUj*vuQ2A5etdV9haQ z_|qy%H7*Ke8?EVhVRCvZOI 8`PcJ^yK`_TVnpAQZ^Di@T z8&k#ipU)WFhF?z$L~shQ+-PQly|Y)lUK?d8{7oi*HoFtDDRBOk<8m?ijJ{F_>IbaD z=O-L+k<<_H>r<0cORYFmyp>Zdm$A*c>fqayv^Se7wdHjI?oZ#gss%QEc0VPKKW%sD z^BdhxrrT@(9dQ4EtM-@%2Z*He-xp=HDP|A~=$ety96U*=R_DxK6b;C)c1w`(ZwHqn z(}TMHKAb+^c6qf1-OFp5hi+c*kSGING%kG$f}XQAwONO??7`4Md4}^3rMYLq z+*g(2!Y3AQeCrvPw?iXI?Ch;4^TuPWeG?2q>U)y)w$$ciJf_Noj7a0PwT6w(q{_l{ z)E_}yW4FD7!Rx()9mavr^7FI41p;9x4!ej-5PgXJ-roMCai_~!1p2s&p{|-%7N EO?#kHI05+r8={Mv(r)rVop|@lpYq9*ES);<*<;d0HsQ11 zDGl7fXUY>wF86HeW(6vjUbQ~s5{tbsB~uUYpTgmS(U*m(Tgp_Fs;GF}Gh@^KnY60$ zXo$gb#4VjyC-d)5`uZ|u`LN#JqT4im$y>O+gE{EXi~?UfTOVQrVFX;(uW8>4e!~LR zj6?dV>@ BuewOJ!s}X#E^Q(k+PRDB4RBixwOXXMU}$)qgxNb1opirA9mwvumXgg z%8?5W@R{TzwqWUF5%mzOFpqFo1XtV%S#`Rc&VKMLW@LnOiqpy!{YI1D?kB8($7t(O zBg*DikO*=3 cNr0EETF9ImdL!=nLklQ=$Ih%Ga8Km4}&l2vt0k1v!W zfE!39g*GCJ7JwW1%c|?}@F9IVXVj;2i|)-rNhKLy$)73xYKK7{4ERh0g~h