|
|
@@ -26,9 +26,12 @@ func runTray(cfg *Config, log *Logger) {
|
|
|
}
|
|
|
|
|
|
func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
|
|
|
- // 菜单标题保持短文本(长 URL 会撑宽整个菜单、显得不协调),详情放 tooltip。
|
|
|
+ // 菜单标题保持短文本(长 URL 会撑宽整个菜单)。
|
|
|
+ // 注意:getlantern/systray 在 Windows 上不支持"菜单项 tooltip"(只有图标 tooltip 有效),
|
|
|
+ // 因此完整地址通过"托盘图标悬停提示"与"复制 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")
|
|
|
@@ -46,6 +49,7 @@ func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
|
|
|
|
|
|
mStop.Disable()
|
|
|
mURL.Disable() // 服务就绪前不可点(避免打开无 token 的无效地址)
|
|
|
+ mCopyURL.Disable()
|
|
|
|
|
|
// 临时通知:覆盖状态标题若干秒,让"点完看不到变化"的操作有回显。
|
|
|
var noticeMu sync.Mutex
|
|
|
@@ -85,7 +89,7 @@ func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
|
|
|
go func() {
|
|
|
ticker := time.NewTicker(3 * time.Second)
|
|
|
defer ticker.Stop()
|
|
|
- var lastTitle, lastTip, lastWebTip string
|
|
|
+ var lastTitle, lastTip, lastURL, lastIconTip string
|
|
|
lastRunning, lastWebEnabled := false, false
|
|
|
for range ticker.C {
|
|
|
st := sup.Status()
|
|
|
@@ -103,29 +107,36 @@ func trayReady(sup *Supervisor, cfg *Config, log *Logger) {
|
|
|
lastTip = tip
|
|
|
}
|
|
|
|
|
|
- // Web 菜单:标题固定,仅切换可用状态与 tooltip
|
|
|
- webEnable, webTip := false, ""
|
|
|
+ // 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:
|
|
|
- webEnable, webTip = true, "打开:"+st.URL
|
|
|
- case st.External:
|
|
|
- webEnable, webTip = true, "外部实例:"+st.URL
|
|
|
+ case st.Ready || st.External:
|
|
|
+ webEnable, webText = true, "打开 Web 界面 ("+addr+")"
|
|
|
+ // 地址放在最前:Windows 图标 tooltip 上限 128 字符,避免地址被截断
|
|
|
+ iconTip = st.URL + "\n" + statusTitle(st)
|
|
|
case st.Running:
|
|
|
- webTip = "服务启动中,就绪后自动可用(首次约 10~40 秒)"
|
|
|
- default:
|
|
|
- webTip = "服务未运行"
|
|
|
+ webText = "打开 Web 界面(启动中…)"
|
|
|
+ iconTip = "DeepSeek Tray · 启动中…(就绪后此处显示地址)"
|
|
|
+ }
|
|
|
+ if webText != lastURL {
|
|
|
+ mURL.SetTitle(webText)
|
|
|
+ lastURL = webText
|
|
|
}
|
|
|
if webEnable != lastWebEnabled {
|
|
|
if webEnable {
|
|
|
mURL.Enable()
|
|
|
+ mCopyURL.Enable()
|
|
|
} else {
|
|
|
mURL.Disable()
|
|
|
+ mCopyURL.Disable()
|
|
|
}
|
|
|
lastWebEnabled = webEnable
|
|
|
}
|
|
|
- if webTip != lastWebTip {
|
|
|
- mURL.SetTooltip(webTip)
|
|
|
- lastWebTip = webTip
|
|
|
+ if iconTip != lastIconTip {
|
|
|
+ systray.SetTooltip(iconTip)
|
|
|
+ lastIconTip = iconTip
|
|
|
}
|
|
|
|
|
|
if st.Running != lastRunning {
|
|
|
@@ -178,6 +189,19 @@ 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 {
|