feat(desktop): 工业化升级 B —— 真桌面集成(Wails Go 桥 + 原生能力)
让它真正像桌面 App 而非套壳网页:启用闲置的 Wails Go 桥,接原生文件框/系统打开/ 通知/无边框标题栏,且全部对浏览器预览(make web)优雅降级。 - app.go:SaveReportAs(原生"另存为"框 + 下载落盘)、OpenReport(下到临时目录 + 系统默认应用打开 docx)、Notify(macOS osascript 通知)、download/openInSystem 跨平台 - main.go:macOS TitleBarHiddenInset —— 隐藏标题栏、内容铺满到顶、保留红绿灯交通灯 - lib/desktop.ts:window.go.main.App 运行时桥 + isDesktop/isMacDesktop 探测; saveReportAs/openReport/notify 在无 Wails(浏览器)时分别降级为 <a download>/新标签/Toast - ReportView:桌面端「另存为 Word」(原生框) +「用系统打开」+ 完成弹系统通知; 浏览器端保持「下载 Word」 - KbView:拖拽文件入库(HTML5 dataTransfer,两种模式通用)+ 拖拽高亮 +「选择文件」按钮 - TopBar:顶栏设为 Wails 可拖拽区(--wails-draggable),控件标 no-drag; macOS 桌面端左留白让位交通灯 验证:GOWORK=off wails build 打出 .app(绑定生成 + mac 标题栏);启动真实原生窗口 截图确认无边框标题栏 + 交通灯内嵌 + 顶栏可拖拽(见会话截图);浏览器(Preview)确认 window.go 不存在时降级正确(下载链路 + 拖拽占位)。tsc + vite build 通过。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+81
-3
@@ -2,10 +2,19 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
goruntime "runtime"
|
||||
|
||||
wr "github.com/wailsapp/wails/v2/pkg/runtime"
|
||||
)
|
||||
|
||||
// App 经 Wails 的 TS/Go 强绑定暴露给前端,承载本地文件 I/O 等只有桌面端能做的能力。
|
||||
// App 经 Wails 的 TS/Go 强绑定暴露给前端,承载只有桌面端能做的原生能力:
|
||||
// 文件读写、系统"另存为"框、用系统默认应用打开、原生通知。
|
||||
type App struct {
|
||||
ctx context.Context
|
||||
}
|
||||
@@ -15,6 +24,9 @@ func NewApp() *App { return &App{} }
|
||||
// startup 在 Wails 启动时注入运行时 ctx。
|
||||
func (a *App) startup(ctx context.Context) { a.ctx = ctx }
|
||||
|
||||
// Ping 供前端探活 Go 桥是否就绪。
|
||||
func (a *App) Ping() string { return "sundynix-desktop ok" }
|
||||
|
||||
// ReadLocalFile 读取本地文件内容(本地文件系统 I/O)。
|
||||
func (a *App) ReadLocalFile(path string) (string, error) {
|
||||
b, err := os.ReadFile(path)
|
||||
@@ -24,5 +36,71 @@ func (a *App) ReadLocalFile(path string) (string, error) {
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// Ping 供前端探活 Go 桥是否就绪。
|
||||
func (a *App) Ping() string { return "sundynix-desktop ok" }
|
||||
// SaveReportAs 弹原生"另存为"对话框,把 url 指向的报告(.docx)下载到用户选定路径。
|
||||
// 返回保存路径;用户取消则返回空串。
|
||||
func (a *App) SaveReportAs(url, filename string) (string, error) {
|
||||
if filename == "" {
|
||||
filename = "report.docx"
|
||||
}
|
||||
path, err := wr.SaveFileDialog(a.ctx, wr.SaveDialogOptions{
|
||||
Title: "保存报告",
|
||||
DefaultFilename: filename,
|
||||
Filters: []wr.FileFilter{{DisplayName: "Word 文档 (*.docx)", Pattern: "*.docx"}},
|
||||
})
|
||||
if err != nil || path == "" {
|
||||
return "", err
|
||||
}
|
||||
if err := download(url, path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// OpenReport 把报告下载到临时目录,并用系统默认应用(Word/Pages/WPS)打开。
|
||||
func (a *App) OpenReport(url, filename string) error {
|
||||
if filename == "" {
|
||||
filename = "report.docx"
|
||||
}
|
||||
dst := filepath.Join(os.TempDir(), "sundynix-open-"+filename)
|
||||
if err := download(url, dst); err != nil {
|
||||
return err
|
||||
}
|
||||
return openInSystem(dst)
|
||||
}
|
||||
|
||||
// Notify 弹一条系统通知(best-effort:macOS 用 osascript,其它平台暂静默)。
|
||||
func (a *App) Notify(title, body string) {
|
||||
if goruntime.GOOS == "darwin" {
|
||||
script := fmt.Sprintf("display notification %q with title %q", body, title)
|
||||
_ = exec.Command("osascript", "-e", script).Start()
|
||||
}
|
||||
}
|
||||
|
||||
func download(url, dst string) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 400 {
|
||||
return fmt.Errorf("下载失败 HTTP %d", resp.StatusCode)
|
||||
}
|
||||
f, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
func openInSystem(path string) error {
|
||||
switch goruntime.GOOS {
|
||||
case "darwin":
|
||||
return exec.Command("open", path).Start()
|
||||
case "windows":
|
||||
return exec.Command("rundll32", "url.dll,FileProtocolHandler", path).Start()
|
||||
default:
|
||||
return exec.Command("xdg-open", path).Start()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user