This commit is contained in:
2025-12-04 14:26:56 +08:00
parent 6a2241bc66
commit a17ff2140e

View File

@@ -112,12 +112,45 @@ func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *ent
}
}()
// 保存当前工作目录(用于后续恢复)
originalWorkDir, _ := os.Getwd()
// 关键修复gofpdf在AddUTF8Font和Output时都会处理字体路径
// 如果路径是绝对路径 /app/resources/pdf/fonts/simhei.ttfgofpdf会去掉开头的/
// 变成相对路径 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),
)
}