This commit is contained in:
@@ -104,7 +104,7 @@ func (pb *PageBuilder) AddFirstPage(pdf *gofpdf.Fpdf, product *entities.Product,
|
|||||||
_, lineHt = pdf.GetFontSize()
|
_, lineHt = pdf.GetFontSize()
|
||||||
// 居中对齐的MultiCell(通过计算宽度实现)
|
// 居中对齐的MultiCell(通过计算宽度实现)
|
||||||
descWidth := pageWidth * 0.7
|
descWidth := pageWidth * 0.7
|
||||||
descLines := pdf.SplitText(desc, descWidth)
|
descLines := pb.safeSplitText(pdf, desc, descWidth, chineseFontAvailable)
|
||||||
currentX := (pageWidth - descWidth) / 2
|
currentX := (pageWidth - descWidth) / 2
|
||||||
for _, line := range descLines {
|
for _, line := range descLines {
|
||||||
pdf.SetX(currentX)
|
pdf.SetX(currentX)
|
||||||
@@ -120,7 +120,7 @@ func (pb *PageBuilder) AddFirstPage(pdf *gofpdf.Fpdf, product *entities.Product,
|
|||||||
pb.fontManager.SetFont(pdf, "", 12)
|
pb.fontManager.SetFont(pdf, "", 12)
|
||||||
_, lineHt = pdf.GetFontSize()
|
_, lineHt = pdf.GetFontSize()
|
||||||
contentWidth := pageWidth * 0.7
|
contentWidth := pageWidth * 0.7
|
||||||
contentLines := pdf.SplitText(content, contentWidth)
|
contentLines := pb.safeSplitText(pdf, content, contentWidth, chineseFontAvailable)
|
||||||
currentX := (pageWidth - contentWidth) / 2
|
currentX := (pageWidth - contentWidth) / 2
|
||||||
for _, line := range contentLines {
|
for _, line := range contentLines {
|
||||||
pdf.SetX(currentX)
|
pdf.SetX(currentX)
|
||||||
@@ -731,3 +731,100 @@ func (pb *PageBuilder) getContentPreview(content string, maxLen int) string {
|
|||||||
}
|
}
|
||||||
return content[:maxLen] + "..."
|
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)
|
checkedDirs = append(checkedDirs, docDir)
|
||||||
|
|
||||||
if info, err := os.Stat(docDir); err == nil && info.IsDir() {
|
if info, err := os.Stat(docDir); err == nil && info.IsDir() {
|
||||||
absPath, err := filepath.Abs(docDir)
|
// 直接返回相对路径,不转换为绝对路径
|
||||||
if err != nil {
|
return docDir, nil
|
||||||
return "", fmt.Errorf("获取绝对路径失败: %w", err)
|
|
||||||
}
|
|
||||||
return absPath, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 尝试父目录
|
// 尝试父目录
|
||||||
@@ -177,22 +174,13 @@ func (f *PDFFinder) FindPDFByProductCode(productCode string) (string, error) {
|
|||||||
return "", fmt.Errorf("未找到产品代码为 %s 的PDF文档", productCode)
|
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文件",
|
f.logger.Info("成功找到PDF文件",
|
||||||
zap.String("product_code", productCode),
|
zap.String("product_code", productCode),
|
||||||
zap.String("file_path", absPath),
|
zap.String("file_path", foundPath),
|
||||||
)
|
)
|
||||||
|
|
||||||
return absPath, nil
|
return foundPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FindPDFByProductCodeWithFallback 根据产品代码查找PDF文件,支持多个可能的命名格式
|
// FindPDFByProductCodeWithFallback 根据产品代码查找PDF文件,支持多个可能的命名格式
|
||||||
@@ -233,10 +221,6 @@ func (f *PDFFinder) FindPDFByProductCodeWithFallback(productCode string) (string
|
|||||||
return "", fmt.Errorf("未找到产品代码为 %s 的PDF文档", productCode)
|
return "", fmt.Errorf("未找到产品代码为 %s 的PDF文档", productCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
absPath, err := filepath.Abs(foundPath)
|
// 直接返回相对路径,不转换为绝对路径
|
||||||
if err != nil {
|
return foundPath, nil
|
||||||
return "", fmt.Errorf("获取文件绝对路径失败: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return absPath, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,12 +108,10 @@ func (g *PDFGenerator) findLogo() {
|
|||||||
|
|
||||||
for _, logoPath := range logoPaths {
|
for _, logoPath := range logoPaths {
|
||||||
if _, err := os.Stat(logoPath); err == nil {
|
if _, err := os.Stat(logoPath); err == nil {
|
||||||
absPath, err := filepath.Abs(logoPath)
|
// 直接使用相对路径,不转换为绝对路径
|
||||||
if err == nil {
|
g.logoPath = logoPath
|
||||||
g.logoPath = absPath
|
g.logger.Info("找到logo文件", zap.String("logo_path", logoPath))
|
||||||
g.logger.Info("找到logo文件", zap.String("logo_path", absPath))
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,12 +70,10 @@ func (g *PDFGeneratorRefactored) findLogo() {
|
|||||||
|
|
||||||
for _, logoPath := range logoPaths {
|
for _, logoPath := range logoPaths {
|
||||||
if _, err := os.Stat(logoPath); err == nil {
|
if _, err := os.Stat(logoPath); err == nil {
|
||||||
absPath, err := filepath.Abs(logoPath)
|
// 直接使用相对路径,不转换为绝对路径
|
||||||
if err == nil {
|
g.logoPath = logoPath
|
||||||
g.logoPath = absPath
|
g.logger.Info("找到logo文件", zap.String("logo_path", logoPath))
|
||||||
g.logger.Info("找到logo文件", zap.String("logo_path", absPath))
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user