From 6a2241bc66ff2e065cfe5ef3167bf08d43ad9afa Mon Sep 17 00:00:00 2001 From: liangzai <2440983361@qq.com> Date: Thu, 4 Dec 2025 14:21:58 +0800 Subject: [PATCH] fix --- internal/shared/pdf/font_manager.go | 19 ++++- .../shared/pdf/pdf_generator_refactored.go | 81 +++++++++++++++++-- 2 files changed, 91 insertions(+), 9 deletions(-) diff --git a/internal/shared/pdf/font_manager.go b/internal/shared/pdf/font_manager.go index 0d78898..2273463 100644 --- a/internal/shared/pdf/font_manager.go +++ b/internal/shared/pdf/font_manager.go @@ -156,7 +156,24 @@ func (fm *FontManager) tryAddFont(pdf *gofpdf.Fpdf, fontPath, fontName string) b ) // gofpdf v2使用AddUTF8Font添加支持UTF-8的字体 - // 注意:必须传入绝对路径,且使用正确的路径分隔符 + // 注意:gofpdf在Output时可能会重新解析路径,必须确保路径格式正确 + // 关键:确保路径是绝对路径且以/开头,并使用filepath.ToSlash统一分隔符 + // 如果normalizedPath不是以/开头,说明路径有问题,需要重新处理 + if len(normalizedPath) == 0 || normalizedPath[0] != '/' { + fm.logger.Error("字体路径格式错误,无法添加到PDF", + zap.String("normalized_path", normalizedPath), + zap.String("font_name", fontName), + ) + return false + } + + // 记录传递给gofpdf的实际路径 + fm.logger.Info("添加字体到gofpdf", + zap.String("font_path", normalizedPath), + zap.String("font_name", fontName), + zap.Bool("is_absolute", len(normalizedPath) > 0 && normalizedPath[0] == '/'), + ) + pdf.AddUTF8Font(fontName, "", normalizedPath) // 常规样式 pdf.AddUTF8Font(fontName, "B", normalizedPath) // 粗体样式 diff --git a/internal/shared/pdf/pdf_generator_refactored.go b/internal/shared/pdf/pdf_generator_refactored.go index 5f3844e..7333c44 100644 --- a/internal/shared/pdf/pdf_generator_refactored.go +++ b/internal/shared/pdf/pdf_generator_refactored.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path/filepath" + "strings" "tyapi-server/internal/domains/product/entities" @@ -139,14 +140,66 @@ func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *ent } // 生成PDF字节流 - // 注意:gofpdf在Output时会重新访问字体文件,确保路径正确 + // 注意: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)) + } + } + var buf bytes.Buffer - // 在Output前记录环境信息,便于调试 + // 在Output前验证字体文件路径 if workDir, err := os.Getwd(); err == nil { + fontPath := filepath.Join(resourcesDir, "fonts", "simhei.ttf") + + // 验证字体文件是否存在(使用绝对路径) + if absFontPath, err := filepath.Abs(fontPath); err == nil { + if _, err := os.Stat(absFontPath); err == nil { + g.logger.Debug("Output前验证字体文件存在", + zap.String("font_path", absFontPath), + zap.String("work_dir", workDir), + ) + } else { + g.logger.Warn("Output前字体文件不存在", + zap.String("font_path", absFontPath), + zap.Error(err), + ) + } + } + g.logger.Debug("准备生成PDF", zap.String("work_dir", workDir), - zap.String("resources_pdf_dir", GetResourcesPDFDir()), + zap.String("resources_pdf_dir", resourcesDir), ) } @@ -157,11 +210,23 @@ func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *ent if wd, e := os.Getwd(); e == nil { currentWorkDir = wd } - g.logger.Error("PDF Output失败", - zap.Error(err), - zap.String("current_work_dir", currentWorkDir), - zap.String("resources_pdf_dir", GetResourcesPDFDir()), - ) + + // 尝试分析错误:如果是路径问题,记录更多信息 + errStr := err.Error() + if strings.Contains(errStr, "stat ") && strings.Contains(errStr, ": no such file") { + g.logger.Error("PDF Output失败(字体文件路径问题)", + zap.Error(err), + zap.String("current_work_dir", currentWorkDir), + zap.String("resources_pdf_dir", resourcesDir), + zap.String("error_message", errStr), + ) + } else { + g.logger.Error("PDF Output失败", + zap.Error(err), + zap.String("current_work_dir", currentWorkDir), + zap.String("resources_pdf_dir", resourcesDir), + ) + } return nil, fmt.Errorf("生成PDF失败: %w", err) }