This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user