This commit is contained in:
2025-12-03 16:53:31 +08:00
parent 3f5a126bfa
commit 1f06f21faf
4 changed files with 114 additions and 37 deletions

View File

@@ -104,7 +104,7 @@ func (pb *PageBuilder) AddFirstPage(pdf *gofpdf.Fpdf, product *entities.Product,
_, lineHt = pdf.GetFontSize()
// 居中对齐的MultiCell通过计算宽度实现
descWidth := pageWidth * 0.7
descLines := pdf.SplitText(desc, descWidth)
descLines := pb.safeSplitText(pdf, desc, descWidth, chineseFontAvailable)
currentX := (pageWidth - descWidth) / 2
for _, line := range descLines {
pdf.SetX(currentX)
@@ -120,7 +120,7 @@ func (pb *PageBuilder) AddFirstPage(pdf *gofpdf.Fpdf, product *entities.Product,
pb.fontManager.SetFont(pdf, "", 12)
_, lineHt = pdf.GetFontSize()
contentWidth := pageWidth * 0.7
contentLines := pdf.SplitText(content, contentWidth)
contentLines := pb.safeSplitText(pdf, content, contentWidth, chineseFontAvailable)
currentX := (pageWidth - contentWidth) / 2
for _, line := range contentLines {
pdf.SetX(currentX)
@@ -731,3 +731,100 @@ func (pb *PageBuilder) getContentPreview(content string, maxLen int) string {
}
return content[:maxLen] + "..."
}
// safeSplitText 安全地分割文本避免在没有中文字体时调用SplitText导致panic
func (pb *PageBuilder) safeSplitText(pdf *gofpdf.Fpdf, text string, width float64, chineseFontAvailable bool) []string {
// 检查文本是否包含中文字符
hasChinese := false
for _, r := range text {
if (r >= 0x4E00 && r <= 0x9FFF) || // 中文字符范围
(r >= 0x3400 && r <= 0x4DBF) || // 扩展A
(r >= 0x20000 && r <= 0x2A6DF) || // 扩展B
(r >= 0x3000 && r <= 0x303F) || // CJK符号和标点
(r >= 0xFF00 && r <= 0xFFEF) { // 全角字符
hasChinese = true
break
}
}
// 如果文本包含中文但中文字体不可用,直接使用手动分割方法
// 如果中文字体可用且文本不包含中文可以尝试使用SplitText
// 即使中文字体可用,如果文本包含中文,也要小心处理(字体可能未正确加载)
if chineseFontAvailable && !hasChinese {
// 对于纯英文/ASCII文本可以安全使用SplitText
var lines []string
func() {
defer func() {
if r := recover(); r != nil {
pb.logger.Warn("SplitText发生panic使用备用方法", zap.Any("error", r))
}
}()
lines = pdf.SplitText(text, width)
}()
if len(lines) > 0 {
return lines
}
}
// 使用手动分割方法适用于中文文本或SplitText失败的情况
// 估算字符宽度中文字符约6mm英文字符约3mm基于14号字体
fontSize, _ := pdf.GetFontSize()
chineseCharWidth := fontSize * 0.43 // 中文字符宽度mm
englishCharWidth := fontSize * 0.22 // 英文字符宽度mm
var lines []string
var currentLine strings.Builder
currentWidth := 0.0
runes := []rune(text)
for _, r := range runes {
// 计算字符宽度
var charWidth float64
if (r >= 0x4E00 && r <= 0x9FFF) || // 中文字符范围
(r >= 0x3400 && r <= 0x4DBF) || // 扩展A
(r >= 0x20000 && r <= 0x2A6DF) || // 扩展B
(r >= 0x3000 && r <= 0x303F) || // CJK符号和标点
(r >= 0xFF00 && r <= 0xFFEF) { // 全角字符
charWidth = chineseCharWidth
} else {
charWidth = englishCharWidth
}
// 检查是否需要换行
if currentWidth+charWidth > width && currentLine.Len() > 0 {
// 保存当前行
lines = append(lines, currentLine.String())
currentLine.Reset()
currentWidth = 0.0
}
// 处理换行符
if r == '\n' {
if currentLine.Len() > 0 {
lines = append(lines, currentLine.String())
currentLine.Reset()
currentWidth = 0.0
} else {
// 空行
lines = append(lines, "")
}
continue
}
// 添加字符到当前行
currentLine.WriteRune(r)
currentWidth += charWidth
}
// 添加最后一行
if currentLine.Len() > 0 {
lines = append(lines, currentLine.String())
}
// 如果没有分割出任何行,至少返回一行
if len(lines) == 0 {
lines = []string{text}
}
return lines
}

View File

@@ -28,11 +28,8 @@ func GetDocumentationDir() (string, error) {
checkedDirs = append(checkedDirs, docDir)
if info, err := os.Stat(docDir); err == nil && info.IsDir() {
absPath, err := filepath.Abs(docDir)
if err != nil {
return "", fmt.Errorf("获取绝对路径失败: %w", err)
}
return absPath, nil
// 直接返回相对路径,不转换为绝对路径
return docDir, nil
}
// 尝试父目录
@@ -177,22 +174,13 @@ func (f *PDFFinder) FindPDFByProductCode(productCode string) (string, error) {
return "", fmt.Errorf("未找到产品代码为 %s 的PDF文档", productCode)
}
// 转换为绝对路径
absPath, err := filepath.Abs(foundPath)
if err != nil {
f.logger.Error("获取文件绝对路径失败",
zap.String("file_path", foundPath),
zap.Error(err),
)
return "", fmt.Errorf("获取文件绝对路径失败: %w", err)
}
// 直接返回相对路径,不转换为绝对路径
f.logger.Info("成功找到PDF文件",
zap.String("product_code", productCode),
zap.String("file_path", absPath),
zap.String("file_path", foundPath),
)
return absPath, nil
return foundPath, nil
}
// FindPDFByProductCodeWithFallback 根据产品代码查找PDF文件支持多个可能的命名格式
@@ -233,10 +221,6 @@ func (f *PDFFinder) FindPDFByProductCodeWithFallback(productCode string) (string
return "", fmt.Errorf("未找到产品代码为 %s 的PDF文档", productCode)
}
absPath, err := filepath.Abs(foundPath)
if err != nil {
return "", fmt.Errorf("获取文件绝对路径失败: %w", err)
}
return absPath, nil
// 直接返回相对路径,不转换为绝对路径
return foundPath, nil
}

View File

@@ -108,12 +108,10 @@ func (g *PDFGenerator) findLogo() {
for _, logoPath := range logoPaths {
if _, err := os.Stat(logoPath); err == nil {
absPath, err := filepath.Abs(logoPath)
if err == nil {
g.logoPath = absPath
g.logger.Info("找到logo文件", zap.String("logo_path", absPath))
return
}
// 直接使用相对路径,不转换为绝对路径
g.logoPath = logoPath
g.logger.Info("找到logo文件", zap.String("logo_path", logoPath))
return
}
}

View File

@@ -70,12 +70,10 @@ func (g *PDFGeneratorRefactored) findLogo() {
for _, logoPath := range logoPaths {
if _, err := os.Stat(logoPath); err == nil {
absPath, err := filepath.Abs(logoPath)
if err == nil {
g.logoPath = absPath
g.logger.Info("找到logo文件", zap.String("logo_path", absPath))
return
}
// 直接使用相对路径,不转换为绝对路径
g.logoPath = logoPath
g.logger.Info("找到logo文件", zap.String("logo_path", logoPath))
return
}
}