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:
@@ -0,0 +1,57 @@
|
||||
// 桌面端原生能力桥 —— 经 Wails 注入的 window.go.main.App 调 Go 方法。
|
||||
// 关键:在浏览器预览(make web,无 Wails 运行时)下 window.go 不存在,
|
||||
// 所有方法自动降级为纯 Web 行为,保证两种模式都能跑。
|
||||
|
||||
interface WailsApp {
|
||||
SaveReportAs(url: string, filename: string): Promise<string>;
|
||||
OpenReport(url: string, filename: string): Promise<void>;
|
||||
Notify(title: string, body: string): Promise<void>;
|
||||
}
|
||||
|
||||
function app(): WailsApp | null {
|
||||
return ((window as unknown as { go?: { main?: { App?: WailsApp } } }).go?.main?.App as WailsApp) ?? null;
|
||||
}
|
||||
|
||||
// isDesktop 是否运行在真实 Wails 桌面窗口(而非浏览器预览)。
|
||||
export function isDesktop(): boolean {
|
||||
return !!app();
|
||||
}
|
||||
|
||||
// isMacDesktop 用于交通灯让位等 macOS 专属适配。
|
||||
export function isMacDesktop(): boolean {
|
||||
return isDesktop() && /Mac/i.test(navigator.userAgent);
|
||||
}
|
||||
|
||||
// saveReportAs:桌面端弹原生"另存为"框落盘;浏览器降级为触发下载。返回保存路径(浏览器/取消为空)。
|
||||
export async function saveReportAs(url: string, filename: string): Promise<string> {
|
||||
const a = app();
|
||||
if (!a) {
|
||||
triggerDownload(url, filename);
|
||||
return "";
|
||||
}
|
||||
return a.SaveReportAs(url, filename);
|
||||
}
|
||||
|
||||
// openReport:桌面端下载到临时目录并用系统默认应用打开;浏览器降级为新标签打开。
|
||||
export async function openReport(url: string, filename: string): Promise<void> {
|
||||
const a = app();
|
||||
if (!a) {
|
||||
window.open(url, "_blank");
|
||||
return;
|
||||
}
|
||||
return a.OpenReport(url, filename);
|
||||
}
|
||||
|
||||
// notify:桌面端弹系统通知;浏览器为空操作(由应用内 Toast 兜底)。
|
||||
export function notify(title: string, body: string): void {
|
||||
app()?.Notify(title, body);
|
||||
}
|
||||
|
||||
function triggerDownload(url: string, filename: string) {
|
||||
const el = document.createElement("a");
|
||||
el.href = url;
|
||||
el.download = filename;
|
||||
document.body.appendChild(el);
|
||||
el.click();
|
||||
el.remove();
|
||||
}
|
||||
Reference in New Issue
Block a user