重构: wails beta.30与chromedp v0.21升级迁移收口
依赖升级后的代码迁移补完: chromedp新API三处调用点改cdp.Call传参/绑定按beta CLI重生成(101 Methods含ReadClipboardImage)/npm与go依赖对齐
This commit is contained in:
+108
-51
@@ -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系统
|
||||
|
||||
Reference in New Issue
Block a user