From a17ff2140e6b804c836b165cb1b5aadc381efb21 Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Thu, 4 Dec 2025 14:26:56 +0800 Subject: [PATCH] fix --- .../shared/pdf/pdf_generator_refactored.go | 100 ++++++++++-------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/internal/shared/pdf/pdf_generator_refactored.go b/internal/shared/pdf/pdf_generator_refactored.go index 7333c44..da8d891 100644 --- a/internal/shared/pdf/pdf_generator_refactored.go +++ b/internal/shared/pdf/pdf_generator_refactored.go @@ -112,12 +112,45 @@ func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *ent } }() + // 保存当前工作目录(用于后续恢复) + originalWorkDir, _ := os.Getwd() + + // 关键修复:gofpdf在AddUTF8Font和Output时都会处理字体路径 + // 如果路径是绝对路径 /app/resources/pdf/fonts/simhei.ttf,gofpdf会去掉开头的/ + // 变成相对路径 app/resources/pdf/fonts/simhei.ttf + // 解决方案:在AddUTF8Font之前就切换工作目录到根目录(/) + resourcesDir := GetResourcesPDFDir() + workDirChanged := false + if resourcesDir != "" && len(resourcesDir) > 0 && resourcesDir[0] == '/' { + // 切换到根目录,这样 gofpdf 转换后的相对路径 app/resources 就能解析为 /app/resources + if err := os.Chdir("/"); err == nil { + workDirChanged = true + g.logger.Info("切换工作目录到根目录(在AddUTF8Font之前)以修复gofpdf路径问题", + zap.String("reason", "gofpdf在AddUTF8Font时就会处理路径,需要在加载字体前切换工作目录"), + zap.String("original_work_dir", originalWorkDir), + zap.String("new_work_dir", "/"), + zap.String("resources_dir", resourcesDir), + ) + defer func() { + // 恢复原始工作目录 + if originalWorkDir != "" { + if err := os.Chdir(originalWorkDir); err == nil { + g.logger.Debug("已恢复原始工作目录", zap.String("work_dir", originalWorkDir)) + } + } + }() + } else { + g.logger.Warn("无法切换到根目录", zap.Error(err)) + } + } + // 创建PDF文档 (A4大小,gofpdf v2 默认支持UTF-8) pdf := gofpdf.New("P", "mm", "A4", "") // 优化边距,减少空白 pdf.SetMargins(15, 25, 15) // 加载黑体字体(用于所有内容,除了水印) + // 注意:此时工作目录应该是根目录(/),这样gofpdf处理路径时就能正确解析 chineseFontAvailable := g.fontManager.LoadChineseFont(pdf) // 加载水印字体(使用宋体或其他非黑体字体) @@ -140,58 +173,36 @@ func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *ent } // 生成PDF字节流 - // 注意:gofpdf在Output时会重新访问字体文件 - // 保存当前工作目录 - originalWorkDir, _ := os.Getwd() - - // 关键修复:gofpdf在Output时会将绝对路径 /app/resources/pdf/fonts/simhei.ttf - // 转换为相对路径 app/resources/pdf/fonts/simhei.ttf(去掉开头的/) - // - // 为什么开发环境可以,生产环境不行? - // 1. Windows开发环境:路径格式为 C:\...,不以/开头,gofpdf处理方式不同 - // 2. Linux生产环境:路径格式为 /app/...,以/开头,gofpdf在Output时会去掉开头的/ - // 如果工作目录是 /app,相对路径 app/resources 无法正确解析 - // 3. 解决方案:将工作目录切换到根目录(/),这样相对路径 app/resources 就能解析为 /app/resources - resourcesDir := GetResourcesPDFDir() - if resourcesDir != "" && len(resourcesDir) > 0 && resourcesDir[0] == '/' { - // 切换到根目录,这样 gofpdf 转换后的相对路径 app/resources/pdf/fonts 就能解析为 /app/resources/pdf/fonts - if err := os.Chdir("/"); err == nil { - g.logger.Info("临时切换工作目录到根目录以修复gofpdf路径问题", - zap.String("reason", "gofpdf在Linux环境下会将绝对路径去掉开头的/转换为相对路径"), - zap.String("original_work_dir", originalWorkDir), - zap.String("new_work_dir", "/"), - zap.String("resources_dir", resourcesDir), - zap.String("example", "gofpdf将 /app/resources/pdf/fonts 转换为 app/resources/pdf/fonts,需要工作目录为/才能正确解析"), - ) - defer func() { - // 恢复原始工作目录 - if originalWorkDir != "" { - if err := os.Chdir(originalWorkDir); err == nil { - g.logger.Debug("已恢复原始工作目录", zap.String("work_dir", originalWorkDir)) - } - } - }() - } else { - g.logger.Warn("无法切换到根目录", zap.Error(err)) - } - } + // 注意:工作目录已经在AddUTF8Font之前切换到了根目录(/) + // 这样gofpdf在Output时使用相对路径 app/resources/pdf/fonts 就能正确解析 var buf bytes.Buffer - // 在Output前验证字体文件路径 + // 在Output前验证字体文件路径(此时工作目录应该是根目录/) if workDir, err := os.Getwd(); err == nil { - fontPath := filepath.Join(resourcesDir, "fonts", "simhei.ttf") + // 验证绝对路径 + fontAbsPath := filepath.Join(resourcesDir, "fonts", "simhei.ttf") + if _, err := os.Stat(fontAbsPath); err == nil { + g.logger.Debug("Output前验证字体文件存在(绝对路径)", + zap.String("font_abs_path", fontAbsPath), + zap.String("work_dir", workDir), + ) + } - // 验证字体文件是否存在(使用绝对路径) - if absFontPath, err := filepath.Abs(fontPath); err == nil { - if _, err := os.Stat(absFontPath); err == nil { - g.logger.Debug("Output前验证字体文件存在", - zap.String("font_path", absFontPath), + // 验证相对路径(gofpdf可能使用的路径) + fontRelPath := "app/resources/pdf/fonts/simhei.ttf" + if relAbsPath, err := filepath.Abs(fontRelPath); err == nil { + if _, err := os.Stat(relAbsPath); err == nil { + g.logger.Debug("Output前验证字体文件存在(相对路径解析)", + zap.String("font_rel_path", fontRelPath), + zap.String("resolved_abs_path", relAbsPath), zap.String("work_dir", workDir), ) } else { - g.logger.Warn("Output前字体文件不存在", - zap.String("font_path", absFontPath), + g.logger.Warn("Output前相对路径解析的字体文件不存在", + zap.String("font_rel_path", fontRelPath), + zap.String("resolved_abs_path", relAbsPath), + zap.String("work_dir", workDir), zap.Error(err), ) } @@ -200,6 +211,7 @@ func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *ent g.logger.Debug("准备生成PDF", zap.String("work_dir", workDir), zap.String("resources_pdf_dir", resourcesDir), + zap.Bool("work_dir_changed", workDirChanged), ) }