feat:批量导入竞品报告
This commit is contained in:
parent
e6ca737fb1
commit
8fa9f89db9
@ -4,18 +4,23 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"fonchain-fiee/api/accountFiee"
|
||||
"fonchain-fiee/api/bundle"
|
||||
"fonchain-fiee/api/cast"
|
||||
"fonchain-fiee/cmd/config"
|
||||
"fonchain-fiee/pkg/cache"
|
||||
"fonchain-fiee/pkg/e"
|
||||
modelCast "fonchain-fiee/pkg/model/cast"
|
||||
"fonchain-fiee/pkg/model/login"
|
||||
"fonchain-fiee/pkg/service"
|
||||
"fonchain-fiee/pkg/utils"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"dubbo.apache.org/dubbo-go/v3/common/constant"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@ -48,19 +53,211 @@ func CreateCompetitiveReport(ctx *gin.Context) {
|
||||
|
||||
// ImportCompetitiveReportBatch 批量导入竞品报告
|
||||
func ImportCompetitiveReportBatch(ctx *gin.Context) {
|
||||
var req *cast.ImportCompetitiveReportBatchReq
|
||||
var err error
|
||||
if err = ctx.ShouldBind(&req); err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
newCtx := NewCtxWithUserInfo(ctx)
|
||||
resp, err := service.CastProvider.ImportCompetitiveReportBatch(newCtx, req)
|
||||
// 获取上传的Excel文件
|
||||
excelFile, err := ctx.FormFile("file")
|
||||
if err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
service.Success(ctx, resp)
|
||||
|
||||
loginInfo := login.GetUserInfoFromC(ctx)
|
||||
lockKey := fmt.Sprintf("import_competitive_report_batch:%d", loginInfo.ID)
|
||||
replay := cache.RedisClient.SetNX(lockKey, time.Now().Format("20060102150405"), 5*time.Minute)
|
||||
if !replay.Val() {
|
||||
service.Error(ctx, errors.New("有导入任务正在进行,请稍后再试"))
|
||||
return
|
||||
}
|
||||
defer cache.RedisClient.Del(lockKey)
|
||||
|
||||
tempDir := "./runtime/report"
|
||||
_, err = utils.CheckDirPath(tempDir, true)
|
||||
if err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 生成文件名并保存文件
|
||||
fileName := fmt.Sprintf("%d_competitive_report.xlsx", time.Now().UnixMicro())
|
||||
excelPath := filepath.Join(tempDir, fileName)
|
||||
if err = ctx.SaveUploadedFile(excelFile, excelPath); err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 打开Excel文件
|
||||
excelData, err := excelize.OpenFile(excelPath)
|
||||
if err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
defer excelData.Close()
|
||||
|
||||
// 解析Excel中的数据
|
||||
rows, err := excelData.GetRows("Sheet1")
|
||||
if err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 初始化请求结构
|
||||
req := cast.ImportCompetitiveReportBatchReq{
|
||||
Reports: make([]*cast.CreateCompetitiveReportReq, 0),
|
||||
}
|
||||
|
||||
// 生成结果文件URL
|
||||
urlHost := config.AppConfig.System.FieeHost
|
||||
urlResult := fmt.Sprintf("%s/api/fiee/static/report/%s", urlHost, fileName)
|
||||
|
||||
// 记录每行数据对应的Excel行号(用于后续匹配失败记录)
|
||||
reportRowMap := make(map[*cast.CreateCompetitiveReportReq]int)
|
||||
|
||||
for line, row := range rows {
|
||||
// 跳过表头
|
||||
if line == 0 {
|
||||
continue
|
||||
}
|
||||
// 跳过空行
|
||||
if len(row) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// 创建报告请求对象
|
||||
temp := &cast.CreateCompetitiveReportReq{
|
||||
Source: 2, // 来源:2 导入
|
||||
}
|
||||
// 记录Excel行号(line+1是因为Excel行号从1开始,且跳过表头)
|
||||
excelRowNum := line + 1
|
||||
reportRowMap[temp] = excelRowNum
|
||||
|
||||
// 解析艺人编号(B列,row[1])
|
||||
var artistNum string
|
||||
if len(row) > 1 && utils.CleanString(row[1]) != "" {
|
||||
artistNum = utils.CleanString(row[1])
|
||||
artistSubNum := utils.CleanString(row[1])
|
||||
if artistSubNum == "" {
|
||||
temp.Remark = "艺人编号不能为空"
|
||||
req.Reports = append(req.Reports, temp)
|
||||
continue
|
||||
}
|
||||
var subInfoResp *accountFiee.UserInfoResponse
|
||||
subInfoResp, err := service.AccountFieeProvider.SubNumGetInfo(context.Background(), &accountFiee.SubNumGetInfoRequest{
|
||||
SubNum: artistSubNum,
|
||||
Domain: "app",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
temp.Remark = fmt.Sprintf("自媒体用户查询失败:%s", err.Error())
|
||||
zap.L().Error("AccountFieeProvider.SubNumGetInfo", zap.Error(err))
|
||||
req.Reports = append(req.Reports, temp)
|
||||
continue
|
||||
}
|
||||
|
||||
if subInfoResp == nil || subInfoResp.Id == 0 {
|
||||
temp.Remark = "自媒体用户不存在"
|
||||
zap.L().Error("AccountFieeProvider.SubNumGetInfo user not found", zap.String("subNum", artistSubNum))
|
||||
req.Reports = append(req.Reports, temp)
|
||||
continue
|
||||
}
|
||||
|
||||
// 设置艺人信息
|
||||
temp.SubNum = artistSubNum
|
||||
temp.ArtistID = fmt.Sprint(subInfoResp.Id)
|
||||
temp.ArtistName = subInfoResp.Name
|
||||
temp.ArtistPhone = subInfoResp.TelNum
|
||||
}
|
||||
|
||||
// 解析标题(C列,row[2])
|
||||
if len(row) > 2 {
|
||||
temp.Title = utils.CleanString(row[2])
|
||||
}
|
||||
|
||||
// 解析报告内容(D列,row[3])
|
||||
if len(row) > 3 {
|
||||
temp.ReportContent = row[3]
|
||||
}
|
||||
|
||||
// 解析图片URL(E列,row[4])
|
||||
if len(row) > 4 && utils.CleanString(row[4]) != "" {
|
||||
temp.ImageUrl = utils.CleanString(row[4])
|
||||
}
|
||||
|
||||
// 解析PDF URL(F列,row[5]),可选
|
||||
if len(row) > 5 && utils.CleanString(row[5]) != "" {
|
||||
temp.PdfUrl = utils.CleanString(row[5])
|
||||
}
|
||||
|
||||
// 验证必填字段
|
||||
if artistNum == "" {
|
||||
temp.Remark = "艺人编号不能为空"
|
||||
req.Reports = append(req.Reports, temp)
|
||||
continue
|
||||
}
|
||||
|
||||
if temp.PdfUrl == "" {
|
||||
temp.Remark = "PDF URL不能为空"
|
||||
req.Reports = append(req.Reports, temp)
|
||||
continue
|
||||
}
|
||||
|
||||
req.Reports = append(req.Reports, temp)
|
||||
}
|
||||
|
||||
// 检查是否有数据
|
||||
if len(req.Reports) == 0 {
|
||||
service.Error(ctx, errors.New(e.ErrNoData))
|
||||
return
|
||||
}
|
||||
|
||||
// 调用批量导入接口
|
||||
newCtx := NewCtxWithUserInfo(ctx)
|
||||
resp, err := service.CastProvider.ImportCompetitiveReportBatch(newCtx, &req)
|
||||
if err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
// 如果有失败的数据,生成结果文件
|
||||
if resp.FailCount > 0 {
|
||||
hasValueRows := make(map[int]bool, resp.FailCount)
|
||||
// 遍历响应结果,标记失败的行
|
||||
// resp.Reports的顺序应该与req.Reports的顺序一致
|
||||
for i, v := range resp.Reports {
|
||||
if !v.Success {
|
||||
// 根据索引找到对应的请求对象
|
||||
if i < len(req.Reports) {
|
||||
reqReport := req.Reports[i]
|
||||
// 通过请求对象找到对应的Excel行号
|
||||
if excelRowNum, ok := reportRowMap[reqReport]; ok {
|
||||
// 将错误信息写入最后一列(G列,可根据实际模板调整)
|
||||
excelData.SetCellValue("Sheet1", fmt.Sprintf("G%d", excelRowNum), v.Remark)
|
||||
hasValueRows[excelRowNum] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除成功的行(从后往前删除,避免行号变化)
|
||||
for i := len(rows) - 1; i >= 1; i-- {
|
||||
if !hasValueRows[i+1] {
|
||||
if err = excelData.RemoveRow("Sheet1", i+1); err != nil {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
// 保存结果文件
|
||||
resultPath := fmt.Sprintf("./runtime/report/%s", fileName)
|
||||
if err = excelData.SaveAs(resultPath); err != nil {
|
||||
service.Error(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 返回结果
|
||||
service.Success(ctx, map[string]interface{}{
|
||||
"successCount": resp.SuccessCount,
|
||||
"failCount": resp.FailCount,
|
||||
"resultUrl": urlResult,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user