From 9c4c4b1c66829344eff8fd94aceab979d1c05563 Mon Sep 17 00:00:00 2001 From: cjy Date: Mon, 2 Mar 2026 16:25:10 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=96=B0=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF=E4=B8=8B=E7=9A=84=E7=AB=9E=E5=93=81=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/竞品报告导入模板.xlsx | Bin 11324 -> 11785 bytes data/竞品报告导入模板_new.xlsx | Bin 11742 -> 0 bytes pkg/service/cast/report.go | 239 ++++++++++++++++++++++++--------- 3 files changed, 178 insertions(+), 61 deletions(-) delete mode 100644 data/竞品报告导入模板_new.xlsx diff --git a/data/竞品报告导入模板.xlsx b/data/竞品报告导入模板.xlsx index 0f5505ddf41568339e9648c524779d043d940df2..272f60f7e75e1c596697305a54a840d9d394907d 100644 GIT binary patch delta 3245 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 SmSex`1dfgz%h5&t_v>E-Wbh~e diff --git a/data/竞品报告导入模板_new.xlsx b/data/竞品报告导入模板_new.xlsx deleted file mode 100644 index fbfa865d51f98b3aa85d82593f28dc04cab15e00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11742 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 Rs6ePdWPl_8e2Qni{{vH)bw>aI diff --git a/pkg/service/cast/report.go b/pkg/service/cast/report.go index bc47ef58..e9ce8357 100644 --- a/pkg/service/cast/report.go +++ b/pkg/service/cast/report.go @@ -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{}, } - // 解析图片URL(E列,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]) + } + + // 图片URL(O列,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 } }