fix
This commit is contained in:
@@ -156,7 +156,24 @@ func (fm *FontManager) tryAddFont(pdf *gofpdf.Fpdf, fontPath, fontName string) b
|
|||||||
)
|
)
|
||||||
|
|
||||||
// gofpdf v2使用AddUTF8Font添加支持UTF-8的字体
|
// 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, "", normalizedPath) // 常规样式
|
||||||
pdf.AddUTF8Font(fontName, "B", normalizedPath) // 粗体样式
|
pdf.AddUTF8Font(fontName, "B", normalizedPath) // 粗体样式
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"tyapi-server/internal/domains/product/entities"
|
"tyapi-server/internal/domains/product/entities"
|
||||||
|
|
||||||
@@ -139,14 +140,66 @@ func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *ent
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 生成PDF字节流
|
// 生成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
|
var buf bytes.Buffer
|
||||||
|
|
||||||
// 在Output前记录环境信息,便于调试
|
// 在Output前验证字体文件路径
|
||||||
if workDir, err := os.Getwd(); err == nil {
|
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",
|
g.logger.Debug("准备生成PDF",
|
||||||
zap.String("work_dir", workDir),
|
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 {
|
if wd, e := os.Getwd(); e == nil {
|
||||||
currentWorkDir = wd
|
currentWorkDir = wd
|
||||||
}
|
}
|
||||||
g.logger.Error("PDF Output失败",
|
|
||||||
zap.Error(err),
|
// 尝试分析错误:如果是路径问题,记录更多信息
|
||||||
zap.String("current_work_dir", currentWorkDir),
|
errStr := err.Error()
|
||||||
zap.String("resources_pdf_dir", GetResourcesPDFDir()),
|
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)
|
return nil, fmt.Errorf("生成PDF失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user