- 表格主图列的缩略图可点击,弹出原图弹窗,鼠标指针改为 zoom-in - main.go 打开 EnableDefaultContextMenu,这样在弹窗图片上右键才有 「图片另存为」。代价是整个界面右键都会出现浏览器菜单,其中包含 「检查」,同事可能误点开发者工具;权衡后仍然打开,因为另存图片是 实际需要,误点开发者工具关掉即可,没有破坏性。同时移除 main.go 中 已不再成立的「关掉右键检查」注释。 - 弹窗另配一个「另存为」按钮:WebView2 的原生右键菜单在个别机器上 不给图片选项,这条路径不依赖浏览器菜单 - app.go 新增 SaveImageAs:只接受 http/https,避免变成可读取本地 任意文件的入口;30 秒超时、20 MB 上限、空响应判失败 - 原图限制在 70vh 内并可滚动,避免大图撑出屏幕 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LbdtsD3ohhSMy3KPoCgARq
109 lines
4.0 KiB
Go
109 lines
4.0 KiB
Go
// cmsp 是一个 Windows 桌面工具:把货憨憨 ERP 里指定 Shopee 店铺的商品,
|
||
// 按商品主图到淘宝搜同款,抓取同款商品详情页的介绍视频,下载到本地,
|
||
// 再批量上传回货憨憨对应商品,使 Shopee 商品页刷新后能看到视频。
|
||
//
|
||
// 从哪里开始读:
|
||
//
|
||
// main.go 这里,负责启动窗口
|
||
// app.go 暴露给前端的方法清单
|
||
// internal/config/ 参数设置的读写与校验
|
||
// internal/store/ SQLite,所有状态的唯一事实来源
|
||
// internal/logx/ 带脱敏的日志
|
||
// frontend/src/ 界面
|
||
//
|
||
// 完整说明见 Wiki:https://git.ilapage.cn/chengma/cmsp/wiki
|
||
package main
|
||
|
||
import (
|
||
"embed"
|
||
"log"
|
||
"os"
|
||
"path/filepath"
|
||
|
||
"github.com/wailsapp/wails/v2"
|
||
"github.com/wailsapp/wails/v2/pkg/options"
|
||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||
)
|
||
|
||
// 把编译好的前端打包进可执行文件,这样发给同事就是单个 exe,
|
||
// 不用再带一堆网页文件。
|
||
//
|
||
//go:embed all:frontend/dist
|
||
var assets embed.FS
|
||
|
||
func main() {
|
||
app := NewApp()
|
||
|
||
// 窗口尺寸。这里有个容易踩的坑,改之前先读完:
|
||
//
|
||
// Width/Height 是逻辑像素,Windows 会按系统缩放放大。
|
||
// 在 125% 缩放的 1920x1080 笔记本上,1440x900 会变成
|
||
// 1800x1125 物理像素,比工作区(1920x1030)还高,
|
||
// 窗口被居中后标题栏和最大化/关闭按钮会跑到屏幕外面,
|
||
// 使用者会以为"程序没有标题栏"。
|
||
//
|
||
// 所以这里不写死原型尺寸,改成启动即最大化:
|
||
// 不管同事的屏幕多大、缩放多少,都能用满可用空间。
|
||
// 下面的 Width/Height 只是还原窗口后的大小,取一个
|
||
// 在 1366x768 笔记本上也放得下的值。
|
||
//
|
||
// MinWidth 设 1024 是底线:再窄工具栏上行的六个筛选控件
|
||
// 会挤在一起。界面本身会换行,不会错乱。
|
||
err := wails.Run(&options.App{
|
||
Title: "cmsp — Shopee 商品视频工具",
|
||
WindowStartState: options.Maximised,
|
||
Width: 1280,
|
||
Height: 760,
|
||
MinWidth: 1024,
|
||
MinHeight: 600,
|
||
AssetServer: &assetserver.Options{
|
||
Assets: assets,
|
||
},
|
||
OnStartup: app.startup,
|
||
OnShutdown: app.shutdown,
|
||
// 打开浏览器默认右键菜单,这样在商品主图弹窗上右键才有「图片另存为」。
|
||
//
|
||
// 代价:整个界面右键都会出现浏览器菜单,其中包含「检查」,
|
||
// 同事可能误点开发者工具。权衡后仍然打开,因为另存图片是实际需要,
|
||
// 误点开发者工具关掉即可,没有破坏性。
|
||
// 弹窗里另外放了一个「另存为」按钮,WebView2 的原生菜单在个别机器上
|
||
// 不给图片选项时仍然可用。
|
||
EnableDefaultContextMenu: true,
|
||
// Bind 里的对象会被生成成 JavaScript 给前端调用。
|
||
// 新增可供前端调用的方法,就写成 App 的公开方法,不用改这里。
|
||
Bind: []any{
|
||
app,
|
||
},
|
||
Windows: &windows.Options{
|
||
DisableWindowIcon: false,
|
||
},
|
||
})
|
||
if err != nil {
|
||
// 走到这里说明窗口没能创建,界面上什么都看不到,
|
||
// 所以要同时写到控制台和文件,否则同事只会看到程序一闪而过。
|
||
log.Println("启动失败:", err)
|
||
writeStartupError(err)
|
||
}
|
||
}
|
||
|
||
// writeStartupError 把启动失败的原因写到程序目录下的文件里。
|
||
//
|
||
// 双击 exe 启动时没有控制台,报错会一闪而过。留个文件,
|
||
// 同事能直接把它发给维护者。
|
||
func writeStartupError(runErr error) {
|
||
exe, err := os.Executable()
|
||
if err != nil {
|
||
return
|
||
}
|
||
path := filepath.Join(filepath.Dir(exe), "启动失败.txt")
|
||
_ = writeTextFile(path, "cmsp 启动失败:\n"+runErr.Error()+"\n")
|
||
}
|
||
|
||
// writeTextFile 用 UTF-8 写一个文本文件。
|
||
//
|
||
// 单独抽出来是因为 app.go 导出日志时也要用。
|
||
func writeTextFile(path, content string) error {
|
||
return os.WriteFile(path, []byte(content), 0o600)
|
||
}
|