暂时的方案
This commit is contained in:
parent
264114fce8
commit
9dfb751aaf
177
pkg/utils/pdf.go
177
pkg/utils/pdf.go
@ -11,6 +11,8 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/phpdave11/gofpdf"
|
"github.com/phpdave11/gofpdf"
|
||||||
|
"github.com/signintech/gopdf"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cleanTextForPDF 清理文本,移除PDF不支持的字符(如emoji)
|
// cleanTextForPDF 清理文本,移除PDF不支持的字符(如emoji)
|
||||||
@ -172,3 +174,178 @@ func GeneratePDF(text, imageURL, outputPath, fontPath string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CompetitorReportData 竞品报告数据
|
||||||
|
type CompetitorReportData struct {
|
||||||
|
HighlightAnalysis HighlightAnalysisData `json:"highlight_analysis"`
|
||||||
|
DataPerformance DataPerformanceData `json:"data_performance_analysis"`
|
||||||
|
OverallSummary string `json:"overall_summary_and_optimization"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HighlightAnalysisData struct {
|
||||||
|
Summary string `json:"summary"`
|
||||||
|
Points PointsData `json:"points"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PointsData struct {
|
||||||
|
Theme string `json:"theme"`
|
||||||
|
Narrative string `json:"narrative"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Copywriting string `json:"copywriting"`
|
||||||
|
Data string `json:"data"`
|
||||||
|
Music string `json:"music,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataPerformanceData struct {
|
||||||
|
Views string `json:"views"`
|
||||||
|
Completion string `json:"completion_rate,omitempty"`
|
||||||
|
Engagement string `json:"engagement"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateCompetitorReportPDF 生成竞品报告PDF
|
||||||
|
// 参数:
|
||||||
|
// - templatePath: 模板文件路径
|
||||||
|
// - outputPath: 输出PDF路径
|
||||||
|
// - data: 竞品报告数据
|
||||||
|
//
|
||||||
|
// 返回: 错误信息
|
||||||
|
func GenerateCompetitorReportPDF(templatePath, outputPath string, data CompetitorReportData) error {
|
||||||
|
fmt.Println("================================templatePath:", templatePath)
|
||||||
|
fmt.Println("================================outputPath:", outputPath)
|
||||||
|
|
||||||
|
pdf := gopdf.GoPdf{}
|
||||||
|
pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4})
|
||||||
|
|
||||||
|
// 导入模板文件中的页面
|
||||||
|
err := pdf.ImportPagesFromSource(templatePath, "/MediaBox")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("无法导入页面: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取模板文件的总页数
|
||||||
|
totalPages := pdf.GetNumberOfPages()
|
||||||
|
fmt.Printf("模板文件的总页数: %d\n", totalPages)
|
||||||
|
|
||||||
|
// 根据模板路径推断字体路径(假设字体文件和模板在同一目录或data目录下)
|
||||||
|
dir := filepath.Dir(templatePath)
|
||||||
|
fontPath := filepath.Join(dir, "simfang.ttf")
|
||||||
|
if _, err := os.Stat(fontPath); err != nil {
|
||||||
|
// 尝试使用项目根目录下的data目录
|
||||||
|
fontPath = filepath.Join("data", "simfang.ttf")
|
||||||
|
}
|
||||||
|
fmt.Printf("字体文件路径: %s\n", fontPath)
|
||||||
|
|
||||||
|
// 加载中文字体
|
||||||
|
ttfErr := pdf.AddTTFFont("simfang", fontPath)
|
||||||
|
if ttfErr != nil {
|
||||||
|
zap.L().Error("加载字体失败", zap.String("fontPath", fontPath), zap.Error(ttfErr))
|
||||||
|
return fmt.Errorf("加载中文字体失败: %v", ttfErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置字体和字号
|
||||||
|
err = pdf.SetFont("simfang", "", 10)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("设置字体失败: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 行高15pt
|
||||||
|
lineHeight := 15.0
|
||||||
|
|
||||||
|
pdf.SetPage(1)
|
||||||
|
|
||||||
|
// 概述 - 使用MultiCell自动换行,一行最多35个字
|
||||||
|
pdf.SetXY(200, 104)
|
||||||
|
summaryRect := gopdf.Rect{W: 350.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&summaryRect, data.HighlightAnalysis.Summary)
|
||||||
|
|
||||||
|
// 标题亮点 - 一行最多9个字
|
||||||
|
pdf.SetXY(200, 184)
|
||||||
|
themeRect := gopdf.Rect{W: 120.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&themeRect, data.HighlightAnalysis.Points.Theme)
|
||||||
|
|
||||||
|
// 题材亮点 - 一行最多9个字
|
||||||
|
pdf.SetXY(330, 184)
|
||||||
|
narrativeRect := gopdf.Rect{W: 120.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&narrativeRect, data.HighlightAnalysis.Points.Narrative)
|
||||||
|
|
||||||
|
// 内容亮点 - 一行最多9个字
|
||||||
|
pdf.SetXY(460, 184)
|
||||||
|
contentRect := gopdf.Rect{W: 120.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&contentRect, data.HighlightAnalysis.Points.Content)
|
||||||
|
|
||||||
|
// 文案亮点 - 一行最多9个字
|
||||||
|
pdf.SetXY(200, 323)
|
||||||
|
copywritingRect := gopdf.Rect{W: 120.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(©writingRect, data.HighlightAnalysis.Points.Copywriting)
|
||||||
|
|
||||||
|
// 数据亮点 - 一行最多9个字
|
||||||
|
pdf.SetXY(330, 323)
|
||||||
|
dataRect := gopdf.Rect{W: 120.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&dataRect, data.HighlightAnalysis.Points.Data)
|
||||||
|
|
||||||
|
// 配乐亮点(仅视频) - 一行最多9个字
|
||||||
|
if data.HighlightAnalysis.Points.Music != "" {
|
||||||
|
pdf.SetXY(460, 323)
|
||||||
|
musicRect := gopdf.Rect{W: 120.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&musicRect, data.HighlightAnalysis.Points.Music)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 浏览量 - 一行最多35个字
|
||||||
|
pdf.SetXY(200, 474)
|
||||||
|
viewsRect := gopdf.Rect{W: 350.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&viewsRect, data.DataPerformance.Views)
|
||||||
|
|
||||||
|
// 完播率 - 一行最多35个字
|
||||||
|
// 始终显示在固定位置,有内容时填充内容
|
||||||
|
pdf.SetXY(200, 539)
|
||||||
|
if data.DataPerformance.Completion != "" {
|
||||||
|
completionRect := gopdf.Rect{W: 350.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&completionRect, data.DataPerformance.Completion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点赞/分享/评论 - 一行最多35个字
|
||||||
|
// 始终固定在完播率下面的位置
|
||||||
|
pdf.SetXY(200, 600)
|
||||||
|
engagementRect := gopdf.Rect{W: 350.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&engagementRect, data.DataPerformance.Engagement)
|
||||||
|
|
||||||
|
// 整体总结及可优化建议 - 一行最多35个字
|
||||||
|
pdf.SetXY(200, 676)
|
||||||
|
summaryRect = gopdf.Rect{W: 350.0, H: lineHeight}
|
||||||
|
pdf.MultiCell(&summaryRect, data.OverallSummary)
|
||||||
|
|
||||||
|
// 生成新的 PDF
|
||||||
|
if err = pdf.WritePdf(outputPath); err != nil {
|
||||||
|
return fmt.Errorf("error writing final PDF: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapText 将文本按指定宽度换行(按字符数计算)
|
||||||
|
func wrapText(text string, maxLen int) []string {
|
||||||
|
if text == "" {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines []string
|
||||||
|
runes := []rune(text)
|
||||||
|
currentLine := ""
|
||||||
|
|
||||||
|
for _, r := range runes {
|
||||||
|
// 如果当前行字符数达到最大限度,换行
|
||||||
|
if len(currentLine) >= maxLen {
|
||||||
|
lines = append(lines, currentLine)
|
||||||
|
currentLine = string(r)
|
||||||
|
} else {
|
||||||
|
currentLine += string(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加最后一行
|
||||||
|
if len(currentLine) > 0 {
|
||||||
|
lines = append(lines, currentLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user