建立可运行、可构建的 Go 骨架,供后续 R1~R5 在其上叠加。 后端: - main.go / app.go:Wails v2 窗口与 14 个前端可调方法。Wails 专有 API 只出现在这两个文件,internal/ 对 Wails 零依赖,便于将来迁移 v3 - internal/config:config.yaml 的读写、校验、脱敏。保存时按固定模板 渲染以保留注释,不用 yaml.Marshal - internal/store:SQLite(modernc.org/sqlite,无需 CGO)。建表迁移、 商品仓储、KV。重复同步不会覆盖本地下载与上传状态 - internal/logx:9 条脱敏规则,覆盖淘宝 token、Cookie、Authorization、 密码和图片 base64;并发安全的内存日志缓冲 前端(Vue 3 + Naive UI,按已确认原型 v4): - Sidebar:176px 可折叠,仅商品列表与参数设置两项,底部是登录状态的 唯一显示位置 - ProductListView:两行工具栏(四项筛选 + 重置搜索 / 四个操作按钮)、 商品表格、分页 - SettingsView:四张卡片,路径用文件与目录选择框 - LogWindow:运行日志子窗口,按级别过滤、自动滚动、导出 配置改用 YAML:分 huohanhan / taobao / download 三段。taobao 段刻意 没有账号密码字段,并有单元测试挡住后续加入。 构建相关: - .gitignore 只忽略 build/bin/,不忽略 build/。Wails 把 build/ 当源码 目录(图标、manifest),忽略掉会让别人克隆后构建失败 - .gitignore 忽略 config.yaml、payloads/ 和 *.har(含真实手机号与凭据) 未实现的下载数据、下载视频、上传数据三个方法返回明确的「还没实现」, 不静默失败。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LbdtsD3ohhSMy3KPoCgARq
90 lines
2.9 KiB
Go
90 lines
2.9 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()
|
||
|
||
// 窗口尺寸对应已确认的原型:1440x900。
|
||
// MinWidth 设成 1200 是因为工具栏上行有六个筛选控件,
|
||
// 再窄就会挤在一起看不清。
|
||
err := wails.Run(&options.App{
|
||
Title: "cmsp — Shopee 商品视频工具",
|
||
Width: 1440,
|
||
Height: 900,
|
||
MinWidth: 1200,
|
||
MinHeight: 700,
|
||
AssetServer: &assetserver.Options{
|
||
Assets: assets,
|
||
},
|
||
OnStartup: app.startup,
|
||
OnShutdown: app.shutdown,
|
||
// Bind 里的对象会被生成成 JavaScript 给前端调用。
|
||
// 新增可供前端调用的方法,就写成 App 的公开方法,不用改这里。
|
||
Bind: []any{
|
||
app,
|
||
},
|
||
Windows: &windows.Options{
|
||
// 关掉右键菜单里的「检查」等开发者项,避免同事误点。
|
||
// 需要调试时用 wails dev,那时会自动打开。
|
||
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)
|
||
}
|