150 lines
4.4 KiB
Go
150 lines
4.4 KiB
Go
package pdf
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
|
||
"tyapi-server/internal/domains/product/entities"
|
||
|
||
"github.com/jung-kurt/gofpdf/v2"
|
||
"github.com/shopspring/decimal"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// PDFGeneratorRefactored 重构后的PDF生成器
|
||
type PDFGeneratorRefactored struct {
|
||
logger *zap.Logger
|
||
fontManager *FontManager
|
||
textProcessor *TextProcessor
|
||
markdownProc *MarkdownProcessor
|
||
tableParser *TableParser
|
||
tableRenderer *TableRenderer
|
||
jsonProcessor *JSONProcessor
|
||
logoPath string
|
||
watermarkText string
|
||
}
|
||
|
||
// NewPDFGeneratorRefactored 创建重构后的PDF生成器
|
||
func NewPDFGeneratorRefactored(logger *zap.Logger) *PDFGeneratorRefactored {
|
||
// 初始化各个模块
|
||
textProcessor := NewTextProcessor()
|
||
fontManager := NewFontManager(logger)
|
||
markdownProc := NewMarkdownProcessor(textProcessor)
|
||
tableParser := NewTableParser(logger, fontManager)
|
||
tableRenderer := NewTableRenderer(logger, fontManager, textProcessor)
|
||
jsonProcessor := NewJSONProcessor()
|
||
|
||
gen := &PDFGeneratorRefactored{
|
||
logger: logger,
|
||
fontManager: fontManager,
|
||
textProcessor: textProcessor,
|
||
markdownProc: markdownProc,
|
||
tableParser: tableParser,
|
||
tableRenderer: tableRenderer,
|
||
jsonProcessor: jsonProcessor,
|
||
watermarkText: "海南海宇大数据有限公司",
|
||
}
|
||
|
||
// 查找logo文件
|
||
gen.findLogo()
|
||
|
||
return gen
|
||
}
|
||
|
||
// findLogo 查找logo文件(仅从resources/pdf加载)
|
||
func (g *PDFGeneratorRefactored) findLogo() {
|
||
// 获取resources/pdf目录(使用统一的资源路径查找函数)
|
||
resourcesPDFDir := GetResourcesPDFDir()
|
||
logoPath := filepath.Join(resourcesPDFDir, "logo.png")
|
||
|
||
// 检查文件是否存在
|
||
if _, err := os.Stat(logoPath); err == nil {
|
||
g.logoPath = logoPath
|
||
return
|
||
}
|
||
|
||
// 只记录关键错误
|
||
g.logger.Warn("未找到logo文件", zap.String("path", logoPath))
|
||
}
|
||
|
||
// GenerateProductPDF 为产品生成PDF文档(接受响应类型,内部转换)
|
||
func (g *PDFGeneratorRefactored) GenerateProductPDF(ctx context.Context, productID string, productName, productCode, description, content string, price float64, doc *entities.ProductDocumentation) ([]byte, error) {
|
||
// 构建临时的 Product entity(仅用于PDF生成)
|
||
product := &entities.Product{
|
||
ID: productID,
|
||
Name: productName,
|
||
Code: productCode,
|
||
Description: description,
|
||
Content: content,
|
||
}
|
||
|
||
// 如果有价格信息,设置价格
|
||
if price > 0 {
|
||
product.Price = decimal.NewFromFloat(price)
|
||
}
|
||
|
||
return g.generatePDF(product, doc)
|
||
}
|
||
|
||
// GenerateProductPDFFromEntity 从entity类型生成PDF(推荐使用)
|
||
func (g *PDFGeneratorRefactored) GenerateProductPDFFromEntity(ctx context.Context, product *entities.Product, doc *entities.ProductDocumentation) ([]byte, error) {
|
||
return g.generatePDF(product, doc)
|
||
}
|
||
|
||
// generatePDF 内部PDF生成方法
|
||
func (g *PDFGeneratorRefactored) generatePDF(product *entities.Product, doc *entities.ProductDocumentation) (result []byte, err error) {
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
// 将panic转换为error,而不是重新抛出
|
||
if e, ok := r.(error); ok {
|
||
err = fmt.Errorf("PDF生成panic: %w", e)
|
||
} else {
|
||
err = fmt.Errorf("PDF生成panic: %v", r)
|
||
}
|
||
result = nil
|
||
}
|
||
}()
|
||
|
||
// 创建PDF文档 (A4大小,gofpdf v2 默认支持UTF-8)
|
||
pdf := gofpdf.New("P", "mm", "A4", "")
|
||
// 优化边距,减少空白
|
||
pdf.SetMargins(15, 25, 15)
|
||
|
||
// 加载黑体字体(用于所有内容,除了水印)
|
||
chineseFontAvailable := g.fontManager.LoadChineseFont(pdf)
|
||
|
||
// 加载水印字体(使用宋体或其他非黑体字体)
|
||
g.fontManager.LoadWatermarkFont(pdf)
|
||
|
||
// 设置文档信息
|
||
pdf.SetTitle("Product Documentation", true)
|
||
pdf.SetAuthor("TYAPI Server", true)
|
||
pdf.SetCreator("TYAPI Server", true)
|
||
|
||
// 创建页面构建器
|
||
pageBuilder := NewPageBuilder(g.logger, g.fontManager, g.textProcessor, g.markdownProc, g.tableParser, g.tableRenderer, g.jsonProcessor, g.logoPath, g.watermarkText)
|
||
|
||
// 添加第一页(产品信息)
|
||
pageBuilder.AddFirstPage(pdf, product, doc, chineseFontAvailable)
|
||
|
||
// 如果有关联的文档,添加接口文档页面
|
||
if doc != nil {
|
||
pageBuilder.AddDocumentationPages(pdf, doc, chineseFontAvailable)
|
||
}
|
||
|
||
// 生成PDF字节流
|
||
var buf bytes.Buffer
|
||
err = pdf.Output(&buf)
|
||
if err != nil {
|
||
// 错误已返回,不记录日志
|
||
return nil, fmt.Errorf("生成PDF失败: %w", err)
|
||
}
|
||
|
||
pdfBytes := buf.Bytes()
|
||
|
||
return pdfBytes, nil
|
||
}
|