feat: 实现新模板下的竞品报告批量导入

This commit is contained in:
cjy 2026-03-02 16:25:10 +08:00
parent 6242962b43
commit 9c4c4b1c66
3 changed files with 178 additions and 61 deletions

Binary file not shown.

View File

@ -372,16 +372,86 @@ func ImportCompetitiveReportBatch(ctx *gin.Context) {
temp.Title = nowDate + temp.ArtistName + "老师竞品报告"
}
}
// 解析报告内容D列row[3]
if len(row) > 3 {
temp.ReportContent = row[3]
// 构建竞品报告数据(新模板格式)
// D列row[3]):亮点表现分析 - 对应Summary字段
// E列row[4]):标题亮点
// F列row[5]):题材亮点
// G列row[6]):内容亮点
// H列row[7]):文案亮点
// I列row[8]):数据亮点
// J列row[9]):配乐亮点
// K列row[10]):浏览量
// L列row[11]):完播率
// M列row[12]):点赞/分享/评论
// N列row[13]):整体总结及可优化建议
// O列row[14]):图片
var competitorReportData utils.CompetitorReportData
// 解析亮点表现分析
highlightAnalysis := utils.HighlightAnalysisData{
Points: utils.PointsData{},
}
// 解析图片URLE列row[4]
if len(row) > 4 && utils.CleanString(row[4]) != "" {
temp.ImageUrl = utils.CleanString(row[4])
// 亮点表现分析摘要D列row[3]
if len(row) > 3 {
highlightAnalysis.Summary = utils.CleanString(row[3])
}
// 标题亮点E列row[4]
if len(row) > 4 {
highlightAnalysis.Points.Theme = utils.CleanString(row[4])
}
// 题材亮点F列row[5]
if len(row) > 5 {
highlightAnalysis.Points.Narrative = utils.CleanString(row[5])
}
// 内容亮点G列row[6]
if len(row) > 6 {
highlightAnalysis.Points.Content = utils.CleanString(row[6])
}
// 文案亮点H列row[7]
if len(row) > 7 {
highlightAnalysis.Points.Copywriting = utils.CleanString(row[7])
}
// 数据亮点I列row[8]
if len(row) > 8 {
highlightAnalysis.Points.Data = utils.CleanString(row[8])
}
// 配乐亮点J列row[9]
if len(row) > 9 {
highlightAnalysis.Points.Music = utils.CleanString(row[9])
}
// 解析数据表现
dataPerformance := utils.DataPerformanceData{}
// 浏览量K列row[10]
if len(row) > 10 {
dataPerformance.Views = utils.CleanString(row[10])
}
// 完播率L列row[11]
if len(row) > 11 {
dataPerformance.Completion = utils.CleanString(row[11])
}
// 点赞/分享/评论M列row[12]
if len(row) > 12 {
dataPerformance.Engagement = utils.CleanString(row[12])
}
// 整体总结及可优化建议N列row[13]
if len(row) > 13 {
competitorReportData.OverallSummary = utils.CleanString(row[13])
}
// 图片URLO列row[14]
if len(row) > 14 && utils.CleanString(row[14]) != "" {
competitorReportData.ImageURL = utils.CleanString(row[14])
}
competitorReportData.HighlightAnalysis = highlightAnalysis
competitorReportData.DataPerformance = dataPerformance
// 验证必填字段
if artistNum == "" {
temp.Remark = "艺人编号不能为空"
@ -389,82 +459,129 @@ func ImportCompetitiveReportBatch(ctx *gin.Context) {
continue
}
// 验证报告内容和图片不能同时为空
if temp.ReportContent == "" && temp.ImageUrl == "" {
temp.Remark = "报告内容和图片不能同时为空"
// 验证亮点表现分析D列Summary
if highlightAnalysis.Summary == "" {
temp.Remark = "亮点表现分析摘要不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 如果已经有错误信息跳过PDF生成
if temp.Remark != "" {
// 验证标题亮点E列
if highlightAnalysis.Points.Theme == "" {
temp.Remark = "标题亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 检查图片URL是否包含阿里云如果包含则下载并重新上传到OSS
if temp.ImageUrl != "" {
newImageUrl, err := checkAndReuploadImageForReport(temp.ImageUrl)
// 验证题材亮点F列
if highlightAnalysis.Points.Narrative == "" {
temp.Remark = "题材亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证内容亮点G列
if highlightAnalysis.Points.Content == "" {
temp.Remark = "内容亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证文案亮点H列
if highlightAnalysis.Points.Copywriting == "" {
temp.Remark = "文案亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证数据亮点I列
if highlightAnalysis.Points.Data == "" {
temp.Remark = "数据亮点不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证浏览量K列
if dataPerformance.Views == "" {
temp.Remark = "浏览量不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证点赞/分享/评论M列
if dataPerformance.Engagement == "" {
temp.Remark = "点赞/分享/评论不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 验证整体总结及可优化建议N列
if competitorReportData.OverallSummary == "" {
temp.Remark = "整体总结及可优化建议不能为空"
req.Reports = append(req.Reports, temp)
continue
}
// 处理图片URL
if competitorReportData.ImageURL != "" {
newImageUrl, err := checkAndReuploadImageForReport(competitorReportData.ImageURL)
if err != nil {
temp.Remark = fmt.Sprintf("图片处理失败: %v", err)
zap.L().Error("图片重新上传失败", zap.String("imageUrl", temp.ImageUrl), zap.Error(err))
zap.L().Error("图片重新上传失败", zap.String("imageUrl", competitorReportData.ImageURL), zap.Error(err))
req.Reports = append(req.Reports, temp)
continue
}
temp.ImageUrl = newImageUrl
competitorReportData.ImageURL = newImageUrl
}
// 如果提供了报告内容则生成PDF并上传
if temp.ReportContent != "" {
// 生成临时PDF文件路径
today := time.Now().Format("20060102")
timestamp := time.Now().UnixMicro()
pdfFileName := fmt.Sprintf("%s%s老师的竞品报告%d.pdf", today, temp.ArtistName, timestamp)
pdfFilePath := "./runtime/report_pdf/" + pdfFileName
// 生成PDF并上传
// 生成临时PDF文件路径
today := time.Now().Format("20060102")
timestamp := time.Now().UnixMicro()
pdfFileName := fmt.Sprintf("%s%s老师的竞品报告%d.pdf", today, temp.ArtistName, timestamp)
pdfFilePath := "./runtime/report_pdf/" + pdfFileName
// 确保目录存在
_, err = utils.CheckDirPath("./runtime/report_pdf/", true)
if err != nil {
temp.Remark = fmt.Sprintf("创建PDF目录失败: %v", err)
req.Reports = append(req.Reports, temp)
continue
}
// 确保目录存在
_, err = utils.CheckDirPath("./runtime/report_pdf/", true)
if err != nil {
temp.Remark = fmt.Sprintf("创建PDF目录失败: %v", err)
req.Reports = append(req.Reports, temp)
continue
}
// 生成PDF文件
fontPath := "./data/simfang.ttf"
err = utils.GeneratePDF(temp.ReportContent, temp.ImageUrl, pdfFilePath, fontPath)
if err != nil {
zap.L().Error("生成PDF失败", zap.Error(err))
temp.Remark = "生成PDF失败"
req.Reports = append(req.Reports, temp)
continue
}
// 模板路径
templatePath := "./data/竞品报告pdf模板.pdf"
// 上传PDF到OSS
pdfUrl, uploadErr := upload.PutBos(pdfFilePath, upload.PdfType, true)
if uploadErr != nil {
zap.L().Error("上传PDF失败", zap.Error(uploadErr))
temp.Remark = "上传PDF失败"
req.Reports = append(req.Reports, temp)
// 清理临时PDF文件
if _, err := os.Stat(pdfFilePath); err == nil {
os.Remove(pdfFilePath)
}
continue
}
// 将上传后的PDF链接设置到请求中
temp.PdfUrl = pdfUrl
// 使用新的 GenerateCompetitorReportPDF 生成PDF
err = utils.GenerateCompetitorReportPDF(templatePath, pdfFilePath, competitorReportData)
if err != nil {
zap.L().Error("生成PDF失败", zap.Error(err))
temp.Remark = "生成PDF失败"
req.Reports = append(req.Reports, temp)
continue
}
// 上传PDF到OSS
pdfUrl, uploadErr := upload.PutBos(pdfFilePath, upload.PdfType, true)
if uploadErr != nil {
zap.L().Error("上传PDF失败", zap.Error(uploadErr))
temp.Remark = "上传PDF失败"
req.Reports = append(req.Reports, temp)
// 清理临时PDF文件
if _, err := os.Stat(pdfFilePath); err == nil {
if err := os.Remove(pdfFilePath); err != nil {
zap.L().Warn("删除临时PDF文件失败", zap.String("path", pdfFilePath), zap.Error(err))
}
os.Remove(pdfFilePath)
}
continue
}
// 将上传后的PDF链接设置到请求中
temp.PdfUrl = pdfUrl
// 清理临时PDF文件
if _, err := os.Stat(pdfFilePath); err == nil {
if err := os.Remove(pdfFilePath); err != nil {
zap.L().Warn("删除临时PDF文件失败", zap.String("path", pdfFilePath), zap.Error(err))
}
} else {
// 如果没有报告内容则将图片URL设置为PDF URL
temp.PdfUrl = temp.ImageUrl
}
req.Reports = append(req.Reports, temp)
@ -497,7 +614,7 @@ func ImportCompetitiveReportBatch(ctx *gin.Context) {
// 通过请求对象找到对应的Excel行号
if excelRowNum, ok := reportRowMap[reqReport]; ok {
// 将错误信息写入最后一列F列
excelData.SetCellValue("Sheet1", fmt.Sprintf("F%d", excelRowNum), v.Remark)
excelData.SetCellValue("Sheet1", fmt.Sprintf("P%d", excelRowNum), v.Remark)
hasValueRows[excelRowNum] = true
}
}