重构: wails beta.30与chromedp v0.21升级迁移收口

依赖升级后的代码迁移补完: chromedp新API三处调用点改cdp.Call传参/绑定按beta CLI重生成(101 Methods含ReadClipboardImage)/npm与go依赖对齐
This commit is contained in:
lxy
2026-10-24 13:48:18 +08:00
parent 066ac2b339
commit 4675ae381d
5 changed files with 262 additions and 292 deletions
+108 -51
View File
@@ -11,11 +11,15 @@ import (
"strings"
"time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/page"
"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/chromedp"
"github.com/yuin/goldmark"
"gorm.io/gorm"
"u-desk/internal/common"
"u-desk/internal/storage"
"u-desk/internal/storage/models"
)
// PdfExportRequest PDF导出请求结构体
@@ -84,7 +88,7 @@ func (api *PdfAPI) ExportMarkdownToPDF(req PdfExportRequest) (*PdfExportResponse
}
// 获取用户桌面目录作为默认保存位置
saveDir := api.getDesktopDirectory()
saveDir := api.resolveExportDir()
// 确保目录存在
if err := os.MkdirAll(saveDir, 0755); err != nil {
@@ -311,27 +315,28 @@ func (api *PdfAPI) generatePDFFromHTML(htmlContent string, pageWidth, pageHeight
// file URL 需整体转义,与 generatePDFFromLocalFile 同姿势,中文/空格临时路径才能正确导航
fileURL := (&url.URL{Scheme: "file", Path: filepath.ToSlash(htmlFile)}).String()
err = chromedp.Run(chromeCtx,
err = chromedp.Do(chromeCtx,
chromedp.Navigate(fileURL),
// 等待页面加载完成
chromedp.WaitReady("body"),
// 打印到PDF
chromedp.ActionFunc(func(ctx context.Context) error {
// 设置页面打印参数
printToPDF := page.PrintToPDF().
WithPrintBackground(true).
WithLandscape(false).
WithMarginTop(0).
WithMarginBottom(0).
WithMarginLeft(0).
WithMarginRight(0).
WithPaperWidth(float64(pageWidth) / 25.4). // mm to inches
WithPaperHeight(float64(pageHeight) / 25.4) // mm to inches
// 执行打印并获取PDF数据
var err error
buf, _, err = printToPDF.Do(ctx)
return err
chromedp.Func(func(ctx context.Context, t *chromedp.Target) error {
// 新版 cdproto:Command 为变量,参数经结构体字面量由 cdp.Call 传入
yes, zero := true, 0.0
res, err := cdp.Call(ctx, t, page.PrintToPDF, page.PrintToPDFParams{
PrintBackground: &yes,
MarginTop: &zero,
MarginBottom: &zero,
MarginLeft: &zero,
MarginRight: &zero,
PaperWidth: float64(pageWidth) / 25.4, // mm to inches
PaperHeight: float64(pageHeight) / 25.4, // mm to inches
})
if err != nil {
return err
}
buf = res.Data
return nil
}),
)
@@ -436,7 +441,7 @@ func (api *PdfAPI) ExportHtmlFileToPDF(srcPath string, saveName string) (resp *P
return nil, err
}
saveDir := api.getDesktopDirectory()
saveDir := api.resolveExportDir()
if err := os.MkdirAll(saveDir, 0755); err != nil {
return nil, fmt.Errorf("创建目录失败: %v", err)
}
@@ -451,15 +456,7 @@ func (api *PdfAPI) ExportHtmlFileToPDF(srcPath string, saveName string) (resp *P
return nil, fmt.Errorf("获取文件信息失败: %v", err)
}
// 成功弹窗几秒即逝用户难感知产物位置,改用资源管理器选中 PDF 明示落盘位置;失败静默不影响导出结果
// 用户 PATH 无 C:\Windows 根目录,explorer 走 LookPath 解析不到,必须用 WINDIR 拼绝对路径
if common.IsWindows() {
exePath := filepath.Join(os.Getenv("WINDIR"), "explorer.exe")
if selectErr := exec.Command(exePath, "/select,", savePath).Start(); selectErr != nil {
appendExportLog(fmt.Sprintf("ExportHtmlFileToPDF explorer select error=%s", selectErr.Error()))
}
}
// 导出成功只落盘,不自动打开文件/文件夹(弹窗打断工作流),落盘位置经返回值由前端提示
return &PdfExportResponse{
Success: true,
Message: "PDF生成成功",
@@ -516,35 +513,46 @@ func (api *PdfAPI) generatePDFFromLocalFile(srcPath string) (buf []byte, err err
chromeCtx, chromeCancel := chromedp.NewContext(allocCtx)
defer chromeCancel()
err = chromedp.Run(chromeCtx,
err = chromedp.Do(chromeCtx,
chromedp.Navigate(fileURL),
// 先确保新文档的 body 可查询,后续 JS 才会落在正确文档上
chromedp.WaitReady("body"),
// PrintToPDF 不等图片资源,必须等 load 事件完成后才打印
chromedp.ActionFunc(func(ctx context.Context) error {
_, exp, err := runtime.Evaluate(`new Promise(resolve => {
if (document.readyState === 'complete') resolve(true)
else window.addEventListener('load', () => resolve(true))
})`).WithAwaitPromise(true).WithReturnByValue(true).Do(ctx)
if exp != nil {
return exp
chromedp.Func(func(ctx context.Context, t *chromedp.Target) error {
yes := true
res, err := cdp.Call(ctx, t, runtime.Evaluate, runtime.EvaluateParams{
Expression: `new Promise(resolve => {
if (document.readyState === 'complete') resolve(true)
else window.addEventListener('load', () => resolve(true))
})`,
AwaitPromise: &yes,
ReturnByValue: &yes,
})
if err != nil {
return err
}
return err
if res.ExceptionDetails != nil {
return fmt.Errorf("页面加载等待 JS 执行异常: %v", res.ExceptionDetails)
}
return nil
}),
chromedp.ActionFunc(func(ctx context.Context) error {
printToPDF := page.PrintToPDF().
WithPrintBackground(true).
WithLandscape(false).
WithMarginTop(0).
WithMarginBottom(0).
WithMarginLeft(0).
WithMarginRight(0).
WithPaperWidth(210.0/25.4). // CDP 纸张单位是英寸,A4 宽 210mm
WithPaperHeight(297.0/25.4)
var printErr error
buf, _, printErr = printToPDF.Do(ctx)
return printErr
chromedp.Func(func(ctx context.Context, t *chromedp.Target) error {
// 新版 cdproto:Command 为变量,参数经结构体字面量由 cdp.Call 传入
yes, zero := true, 0.0
res, printErr := cdp.Call(ctx, t, page.PrintToPDF, page.PrintToPDFParams{
PrintBackground: &yes,
MarginTop: &zero,
MarginBottom: &zero,
MarginLeft: &zero,
MarginRight: &zero,
PaperWidth: 210.0 / 25.4, // CDP 纸张单位是英寸,A4 宽 210mm
PaperHeight: 297.0 / 25.4,
})
if printErr != nil {
return printErr
}
buf = res.Data
return nil
}),
)
if err != nil {
@@ -558,6 +566,55 @@ func (api *PdfAPI) generatePDFFromLocalFile(srcPath string) (buf []byte, err err
return buf, nil
}
// pdfExportDirConfigKey 导出目录的配置存储键
const pdfExportDirConfigKey = "pdf_export_dir"
// getConfiguredExportDir 读取配置的导出目录,未设置或读取出错返回空串(走默认桌面)
func (api *PdfAPI) getConfiguredExportDir() string {
db, err := storage.InitFast()
if err != nil {
return ""
}
var config models.AppConfig
if err := db.Where("`key` = ?", pdfExportDirConfigKey).First(&config).Error; err != nil {
return ""
}
return config.Value
}
// resolveExportDir 解析本次导出的落盘目录:配置目录不可用时回退桌面,不中断导出
func (api *PdfAPI) resolveExportDir() string {
if dir := api.getConfiguredExportDir(); dir != "" {
if _, err := os.Stat(dir); err == nil || os.MkdirAll(dir, 0755) == nil {
return dir
}
}
return api.getDesktopDirectory()
}
// GetPDFExportDir 获取 PDF 导出目录配置(空串=未设置,走默认桌面)
func (api *PdfAPI) GetPDFExportDir() string {
return api.getConfiguredExportDir()
}
// SavePDFExportDir 保存 PDF 导出目录配置(空串=恢复默认)
func (api *PdfAPI) SavePDFExportDir(dir string) error {
db, err := storage.InitFast()
if err != nil {
return fmt.Errorf("数据库初始化失败: %w", err)
}
var config models.AppConfig
err = db.Where("`key` = ?", pdfExportDirConfigKey).First(&config).Error
if err == gorm.ErrRecordNotFound {
config = models.AppConfig{Key: pdfExportDirConfigKey, Value: dir, Description: "PDF 导出目录"}
return db.Create(&config).Error
} else if err != nil {
return fmt.Errorf("查询配置失败: %w", err)
}
config.Value = dir
return db.Save(&config).Error
}
// getDesktopDirectory 获取用户桌面目录
func (api *PdfAPI) getDesktopDirectory() string {
// Windows系统