diff --git a/frp.go b/frp.go index 1462e58..b525ee4 100644 --- a/frp.go +++ b/frp.go @@ -25,12 +25,12 @@ var FrpcTemplateContent string var ( cachedFrpcPath string - frpsPathMutex sync.Mutex + frpcPathMutex sync.Mutex ) func getFrpcPath() (string, error) { - frpsPathMutex.Lock() - defer frpsPathMutex.Unlock() + frpcPathMutex.Lock() + defer frpcPathMutex.Unlock() if cachedFrpcPath != "" { if _, err := os.Stat(cachedFrpcPath); err == nil { @@ -144,7 +144,6 @@ func GenerateFrpcConfig() error { return fmt.Errorf("渲染模板失败: %w", err) } - // 所有文件写入 ./data/ 目录 if err := os.MkdirAll("./data", 0755); err != nil { return fmt.Errorf("创建 data 目录失败: %w", err) } @@ -219,6 +218,15 @@ func StartFrpc() error { return fmt.Errorf("启动 frpc 失败: %w", err) } + // 回收子进程(防止僵尸进程) + go func() { + if err := cmd.Wait(); err != nil { + log.Printf("frpc 子进程退出: %v", err) + } + // 子进程退出后清理 PID 文件 + os.Remove("./data/frpc.pid") + }() + if err := os.WriteFile("./data/frpc.pid", []byte(fmt.Sprintf("%d", cmd.Process.Pid)), 0644); err != nil { return fmt.Errorf("保存 PID 失败: %w", err) } diff --git a/static/fonts/HarmonyOS_Sans_SC_Regular.ttf b/static/fonts/HarmonyOS_Sans_SC_Regular.ttf new file mode 100644 index 0000000..aff150a Binary files /dev/null and b/static/fonts/HarmonyOS_Sans_SC_Regular.ttf differ diff --git a/static/index.html b/static/index.html index 5ced711..9649269 100644 --- a/static/index.html +++ b/static/index.html @@ -100,7 +100,8 @@ - {{ pingLatency !== null ? pingLatency + 'ms' : '--ms' }} + {{ pingLatency !== null ? pingLatency + 'ms' : '--ms' + }} @@ -343,34 +344,7 @@ - -
-
-

{{ dialogMode === 'add' ? '新增隧道' : '编辑隧道' }}

-
-
-
- - -
-
-
-
-
-
-
-
- - -
-
-
-
+ @@ -378,6 +352,34 @@ + +
+
+

{{ dialogMode === 'add' ? '新增隧道' : '编辑隧道' }}

+
+
+
+ + +
+
+
+
+
+
+
+
+ + +
+
+
+
diff --git a/static/style-1.css b/static/style-1.css index 38eec5f..5165666 100644 --- a/static/style-1.css +++ b/static/style-1.css @@ -1,30 +1,28 @@ /* ===== style-1.css - 全局基础 ===== */ /* ---------- 字体定义 ---------- */ +/* 自托管 HarmonyOS Sans SC Regular */ + +/* 中英文:HarmonyOS Sans SC Regular */ @font-face { font-family: 'HarmonyOS Sans SC'; - src: local('HarmonyOS Sans SC'), - local('PingFang SC'), - local('Microsoft YaHei'), - local('Helvetica Neue'); + src: url('./fonts/HarmonyOS_Sans_SC_Regular.ttf') format('truetype'); font-weight: 400; + font-style: normal; font-display: swap; } + +/* 数字专用:复用 HarmonyOS Sans SC Regular(因 Light 版本缺失) */ @font-face { - font-family: 'HarmonyOS Sans SC'; - src: local('HarmonyOS Sans SC Medium'), - local('PingFang SC Medium'); - font-weight: 500; - font-display: swap; -} -@font-face { - font-family: 'HarmonyOS Sans SC'; - src: local('HarmonyOS Sans SC Bold'), - local('PingFang SC Semibold'); - font-weight: 700; + font-family: 'HarmonyOS Sans'; + src: url('./fonts/HarmonyOS_Sans_SC_Regular.ttf') format('truetype'); + font-weight: 300; + font-style: normal; font-display: swap; } +/* 后备:如果自托管字体加载失败,使用系统字体 */ + /* ---------- 重置 ---------- */ * { margin: 0; @@ -33,14 +31,14 @@ } body { - font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif; + font-family: 'HarmonyOS Sans SC', 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', sans-serif; background: #0a0a0f; height: 100vh; overflow: hidden; color: #e0e0e0; } -/* ---------- 数字专用字体(加粗) ---------- */ +/* ---------- 数字专用字体(使用 HarmonyOS Sans) ---------- */ .digit, .big-number, .remote-port, @@ -51,22 +49,23 @@ body { .login-btn, .save-btn, .btn-confirm { - font-weight: 600 !important; + font-weight: 300 !important; letter-spacing: 0.02em; + font-family: 'HarmonyOS Sans', 'JetBrains Mono', monospace; } /* 数字特别加粗(适用于大数字展示) */ .big-number { - font-weight: 700 !important; + font-weight: 600 !important; letter-spacing: -0.01em; } -/* 代码/端口类数字使用等宽字体,但保持加粗 */ +/* 代码/端口类数字使用等宽字体,但保持 HarmonyOS Sans 风格 */ .digit, .remote-port, .proxy-addr { - font-family: 'HarmonyOS Sans SC', 'JetBrains Mono', monospace; - font-weight: 600 !important; + font-family: 'HarmonyOS Sans', 'JetBrains Mono', monospace; + font-weight: 300 !important; } /* ---------- 全局颜色变量 ---------- */ @@ -175,7 +174,7 @@ body { height: 100%; display: flex; flex-direction: column; - padding: 20px 28px; /* ← 补上内边距 */ + padding: 20px 28px; opacity: 0; transition: opacity 0.3s ease; } diff --git a/static/style-3.css b/static/style-3.css index c0b3a59..e6a3c15 100644 --- a/static/style-3.css +++ b/static/style-3.css @@ -17,8 +17,8 @@ } .top-left .nav-logo { - width: 48px; - height: 48px; + width: 52px; /* 原 48px */ + height: 52px; /* 原 48px */ flex-shrink: 0; display: block; object-fit: contain; @@ -32,7 +32,7 @@ } .brand-info .logo-text { - font-size: 22px; + font-size: 20px; font-weight: 600; color: var(--text-primary); line-height: 1.2; @@ -59,8 +59,9 @@ box-shadow: 0 0 12px rgba(99, 226, 183, 0.4); } +/* 状态文字 12px(原 13px) */ .status-wrapper .status-text { - font-size: 13px; + font-size: 12px; color: var(--text-muted); } @@ -71,7 +72,7 @@ } .user-name { - font-size: 13px; + font-size: 12px; /* 原 13px,与状态文字对齐 */ color: var(--text-secondary); } @@ -375,7 +376,7 @@ .proxy-addr { font-size: 13px; color: var(--text-dim); - font-family: 'JetBrains Mono', monospace; + font-family: 'HarmonyOS Sans','JetBrains Mono', monospace; } .proxy-tag { @@ -395,7 +396,7 @@ } .remote-port { - font-family: 'JetBrains Mono', monospace; + font-family: 'HarmonyOS Sans','JetBrains Mono', monospace; font-size: 14px; color: var(--text-secondary); } @@ -800,4 +801,41 @@ select:disabled { width: 14px; height: 14px; } +} + +/* ---------- Tab 栏 ---------- */ +.tab-bar { + display: flex; + gap: 32px; + padding: 14px 0 12px; + flex-shrink: 0; + border-bottom: 1px solid var(--border-subtle); +} + +/* 将最后一个 Tab(用户配置)推到最右侧 */ +.tab-item:last-child { + margin-left: auto; + /* 防止用户名过长导致溢出 */ + max-width: 220px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tab-item { + font-size: 14px; + color: var(--text-muted); + cursor: pointer; + padding: 4px 0; + transition: color 0.3s, border-color 0.3s; + border-bottom: 2px solid transparent; +} + +.tab-item:hover { + color: var(--text-secondary); +} + +.tab-item.active { + color: var(--primary-blue); + border-bottom-color: var(--primary-blue); } \ No newline at end of file