Jelajahi Sumber

revert: v2.6.1 回退显示地址设计,菜单恢复纯短文本

- 菜单标题恢复 打开 Web 界面(纯文字);移除 (host:port) 后缀——长地址会撑宽菜单

- 移除 复制 Web 地址 菜单项及 copyToClipboard 实现

- 托盘图标 tooltip 恢复为纯状态文本(不含地址)

- 访问地址仅保留两处用途:点击打开、写入日志

- firstLine 改用 ASCII 10 写法,规避模板转义歧义(此前反复踩坑)

- 自检:菜单最长项 9 字符;UI 无 URL 引用;72 函数无死代码
caesar 15 jam lalu
induk
melakukan
ac6d552136
4 mengubah file dengan 18 tambahan dan 76 penghapusan
  1. 8 8
      README.md
  2. 1 1
      build.ps1
  3. 0 28
      proc_windows.go
  4. 9 39
      tray.go

+ 8 - 8
README.md

@@ -60,8 +60,7 @@ nssm start DeepSeekTray
 
 - 状态:运行中 · PID / 启动中 · PID / 已停止 / 外部实例运行中 / 正在更新
   (操作结果会在状态区**临时回显**,如"已是最新版本 x.y.z"、"更新完成"、"失败(详见日志)")
-- 打开 Web 界面(**就绪前置灰**;就绪后点击直达,自动带 token;标题同时显示 host:port)
-- 复制 Web 地址(把含 token 的完整地址复制到剪贴板,便于贴到别处使用)
+- 打开 Web 界面(**就绪前置灰**;就绪后点击直达,自动带 token)
 - 启动 / 停止 / 重启服务
 - 开机自启(勾选)
 - 定期自动更新(勾选)、立即更新 DSH(已是最新则秒回,不重启服务)
@@ -69,11 +68,11 @@ nssm start DeepSeekTray
 - 查看日志 / 打开配置文件
 - 退出(停止服务并退出)
 
-> 菜单标题统一保持短文本(长 URL 会撑宽整个菜单)。
->
-> **关于查看访问地址**:`getlantern/systray` 在 Windows 上**不支持菜单项的悬停提示**(只有图标级 tooltip 有效)。
-> 完整访问地址显示在**托盘图标的悬停提示**中(鼠标移到托盘图标上即可看到;地址置于首行,避免 128 字符上限将其截断),
-> 也可使用菜单中的「复制 Web 地址」。
+> **设计取舍:菜单与提示均不显示访问地址。**
+> 原因:地址(含 token)很长,一旦放进菜单标题就会撑宽整个菜单,视觉不协调;而
+> `getlantern/systray` 在 Windows 上又不支持菜单项悬停提示(只有图标 tooltip 有效)。
+> 因此访问地址只用于两处:点击「打开 Web 界面」直接打开、以及写入日志便于排查。
+> 需要原始地址时,可在日志中查看(token 已脱敏)或从浏览器地址栏获取。
 
 ## 配置
 
@@ -161,7 +160,8 @@ nssm start DeepSeekTray
 
 ## 版本
 
-- v2.6.0 — 修复"悬停看不到 URL":查源码确认 **getlantern/systray 在 Windows 上不支持菜单项 tooltip**(`MenuItem.SetTooltip` 是空操作),改为把完整地址放进**托盘图标 tooltip**(地址置于首行,规避 128 字符上限截断),并新增**「复制 Web 地址」**(临时文件 + clip.exe,文本不经 shell 解析)
+- v2.6.1 — 回退"显示访问地址"的设计(长地址会撑宽菜单、视觉不协调):菜单恢复纯短文本、移除「复制 Web 地址」与图标 tooltip 中的地址;访问地址只用于打开与日志。`firstLine` 改用 ASCII 码 10,避免转义写法歧义
+- v2.6.0 — (已被 v2.6.1 推翻)尝试把地址放进 tooltip/剪贴板:查源码确认 **getlantern/systray 在 Windows 上不支持菜单项 tooltip**(`MenuItem.SetTooltip` 是空操作),改为把完整地址放进**托盘图标 tooltip**(地址置于首行,规避 128 字符上限截断),并新增**「复制 Web 地址」**(临时文件 + clip.exe,文本不经 shell 解析)
 - v2.5.0 — 依据实际使用反馈优化:**菜单宽度**(长 URL 移入悬停提示)、**操作结果回显**(解决"点更新没反应"的观感问题)、**版本号改由构建脚本注入**(避免源码与版本号不一致)、更新流程合并为唯一入口(去掉重复查询)、耗时操作防重入
 - v2.4.0 — 修复实测发现的三个问题:**打开日志/配置无反应**(误用 SW_HIDE 把 explorer 窗口隐藏了 → 改用 ShellExecuteW)、**Web 界面启动期不可用**(新增就绪状态,启动中禁用点击而非打开无效地址)、**更新白等 5 分钟**(版本相同时跳过整包重装与重启);菜单耗时操作后台执行不再阻塞;日志记录 Web 启动耗时
 - v2.3.0 — 三次迭代:修复**停止/启动竞态**(不再残留进程)、配置写入线程安全、更新前先停服务、配置读写单元测试与守护生命周期测试、`build.ps1` 一键构建

+ 1 - 1
build.ps1

@@ -1,6 +1,6 @@
 # deepseek-tray 构建脚本:格式检查 -> 静态检查 -> 单元测试 -> 构建
 # 版本号唯一维护点(README 的版本历史与此保持一致)
-$Version = '2.6.0'
+$Version = '2.6.1'
 
 $ErrorActionPreference = 'Stop'
 Push-Location $PSScriptRoot

+ 0 - 28
proc_windows.go

@@ -128,34 +128,6 @@ func (s *singleInstance) release() {
 	}
 }
 
-// copyToClipboard 把文本放入系统剪贴板。
-// 实现:写临时文件后交给 clip.exe 重定向读入——文本内容不经过 shell 解析;
-// 临时文件用后即删(内容含访问 token)。
-func copyToClipboard(text string) error {
-	if text == "" {
-		return fmt.Errorf("无可复制内容")
-	}
-	tmp := os.TempDir() + "\\deepseek-tray-url.txt"
-	if err := os.WriteFile(tmp, []byte(text), 0o600); err != nil {
-		return err
-	}
-	defer os.Remove(tmp)
-
-	f, err := os.Open(tmp)
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-
-	cmd := exec.Command("cmd", "/c", "clip")
-	cmd.Stdin = f
-	hideWindow(cmd)
-	if err := cmd.Run(); err != nil {
-		return fmt.Errorf("写入剪贴板失败: %w", err)
-	}
-	return nil
-}
-
 // attachConsole 让 windowsgui 子系统程序能输出到调用它的终端(仅 CLI 子命令使用)。
 func attachConsole() {
 	const attachParentProcess = 0xFFFFFFFF

+ 9 - 39
tray.go

@@ -26,12 +26,10 @@ func runTray(cfg *Config, log *Logger) {
 }
 
 func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
-	// 菜单标题保持短文本(长 URL 会撑宽整个菜单)。
-	// 注意:getlantern/systray 在 Windows 上不支持"菜单项 tooltip"(只有图标 tooltip 有效),
-	// 因此完整地址通过"托盘图标悬停提示"与"复制 Web 地址"提供。
+	// 菜单标题一律使用短文本:长文本会撑宽整个菜单、视觉不协调。
+	// 因此菜单内不显示访问地址——需要时点"打开 Web 界面"直接打开。
 	mStatus := systray.AddMenuItem("初始化…", "当前服务状态")
 	mURL := systray.AddMenuItem("打开 Web 界面", "服务就绪后可用(自动带 token)")
-	mCopyURL := systray.AddMenuItem("复制 Web 地址", "把含 token 的完整地址复制到剪贴板")
 	systray.AddSeparator()
 	mStart := systray.AddMenuItem("启动服务", "启动 dsh web")
 	mStop := systray.AddMenuItem("停止服务", "停止 dsh web")
@@ -49,7 +47,6 @@ func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
 
 	mStop.Disable()
 	mURL.Disable() // 服务就绪前不可点(避免打开无 token 的无效地址)
-	mCopyURL.Disable()
 
 	// 临时通知:覆盖状态标题若干秒,让"点完看不到变化"的操作有回显。
 	var noticeMu sync.Mutex
@@ -89,7 +86,7 @@ func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
 	go func() {
 		ticker := time.NewTicker(3 * time.Second)
 		defer ticker.Stop()
-		var lastTitle, lastTip, lastURL, lastIconTip string
+		var lastTitle, lastTip, lastIconTip string
 		lastRunning, lastWebEnabled := false, false
 		for range ticker.C {
 			st := sup.Status()
@@ -107,33 +104,19 @@ func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
 				lastTip = tip
 			}
 
-			// Web 相关菜单:标题短文本;完整地址走托盘图标 tooltip(Windows 上唯一有效的悬停提示)
-			addr := fmt.Sprintf("%s:%d", cfg.WebHost, cfg.WebPort)
-			webEnable, webText := false, "打开 Web 界面(服务未运行)"
-			iconTip := "DeepSeek Tray · " + statusTitle(st)
-			switch {
-			case st.Ready || st.External:
-				webEnable, webText = true, "打开 Web 界面 ("+addr+")"
-				// 地址放在最前:Windows 图标 tooltip 上限 128 字符,避免地址被截断
-				iconTip = st.URL + "\n" + statusTitle(st)
-			case st.Running:
-				webText = "打开 Web 界面(启动中…)"
-				iconTip = "DeepSeek Tray · 启动中…(就绪后此处显示地址)"
-			}
-			if webText != lastURL {
-				mURL.SetTitle(webText)
-				lastURL = webText
-			}
+			// Web 菜单只切换可用状态,标题恒为短文本
+			webEnable := st.Ready || st.External
 			if webEnable != lastWebEnabled {
 				if webEnable {
 					mURL.Enable()
-					mCopyURL.Enable()
 				} else {
 					mURL.Disable()
-					mCopyURL.Disable()
 				}
 				lastWebEnabled = webEnable
 			}
+
+			// 托盘图标 tooltip 同样保持简洁(不含地址)
+			iconTip := "DeepSeek Tray · " + statusTitle(st)
 			if iconTip != lastIconTip {
 				systray.SetTooltip(iconTip)
 				lastIconTip = iconTip
@@ -189,19 +172,6 @@ func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
 					log.Printf("打开 Web 界面失败: %v", err)
 					setNotice("打开失败(详见日志)", 6*time.Second)
 				}
-			case <-mCopyURL.ClickedCh:
-				st := sup.Status()
-				if !st.Ready && !st.External {
-					log.Printf("菜单:复制 Web 地址被忽略(服务未就绪)")
-					continue
-				}
-				log.Printf("菜单:复制 Web 地址")
-				if err := copyToClipboard(st.URL); err != nil {
-					log.Printf("复制 Web 地址失败: %v", err)
-					setNotice("复制失败(详见日志)", 6*time.Second)
-				} else {
-					setNotice("Web 地址已复制到剪贴板", 4*time.Second)
-				}
 			case <-mAutoStart.ClickedCh:
 				next := !mAutoStart.Checked()
 				if err := setAutoStart(next); err != nil {
@@ -315,7 +285,7 @@ func statusTooltip(st Status) string {
 
 // firstLine 取多行输出的首行,便于日志摘要。
 func firstLine(s string) string {
-	if i := strings.IndexByte(s, '\n'); i >= 0 {
+	if i := strings.IndexByte(s, 10); i >= 0 { // 10 = LF
 		return s[:i]
 	}
 	return s