From 4e804a4c524099013602c8dd93b0dc30c7015241 Mon Sep 17 00:00:00 2001 From: renzhiyuan <465386466@qq.com> Date: Mon, 9 Feb 2026 15:28:35 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8=E7=94=9F=E6=88=90=E9=80=BB=E8=BE=91=E5=92=8C=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_test.yaml | 13 ++-- internal/biz/group_config.go | 7 +- internal/tools/bbxt/bbxt.go | 96 +++++++++++++++------------- internal/tools/bbxt/excel.go | 33 +++++++--- tmpl/excel_temp/kshj_total_ana.xlsx | Bin 10282 -> 10363 bytes 5 files changed, 82 insertions(+), 67 deletions(-) diff --git a/config/config_test.yaml b/config/config_test.yaml index a6f07b9..563cd0e 100644 --- a/config/config_test.yaml +++ b/config/config_test.yaml @@ -26,12 +26,11 @@ coze: lsxd: # 统一登录 - login_url: "http://api.test.user.1688sup.com/v1/login/phone" - phone: "OFJ8UpqOlI7+w3Qklf36ZA==" - password: "tEbFegH/DRRh6LutFb7o3g==" - code: "123456" - check_token_url: "http://api.test.user.1688sup.com/v1/user/welcome" - + login_url: "https://api.user.1688sup.com/v1/login/phone" + phone: "ORlviZN7N06W2+WKLe76xg==" + password: "V5Uh8C4bamEM6UQZh4TCeQ==" + code: "456789" + check_token_url: "https://api.user.1688sup.com/v1/user/welcome" sys: session_len: 6 @@ -142,7 +141,7 @@ eino_tools: # == 通用工具 == # 表格转图片 excel2pic: - base_url: "http://192.168.6.109:8010/api/v1/convert" + base_url: "http://192.168.6.115:8010/api/v1/convert" dingtalk: api_key: "dingsbbntrkeiyazcfdg" diff --git a/internal/biz/group_config.go b/internal/biz/group_config.go index 0c6dbbc..38cbc01 100644 --- a/internal/biz/group_config.go +++ b/internal/biz/group_config.go @@ -98,13 +98,11 @@ func (g *GroupConfigBiz) GetReportLists(ctx context.Context, groupConfig *model. if err != nil { return } - //追加电商充值系统统计 - 返回统一使用[]*bbxt.ReportRes rechargeReports, err := g.rechargeDailyReport(ctx, time.Now(), nil, g.ossClient) if err != nil || len(rechargeReports) == 0 { return } - reports = append(reports, rechargeReports...) return @@ -175,7 +173,7 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz if _err != nil { return _err } - reports = append(reports, repo...) + reports = append(reports, repo) case "report_sales_analysis": product := strings.Split(groupConfig.ProductName, ",") repo, _err := rep.GetStatisOfficialProductSum(t, product) @@ -200,8 +198,9 @@ func (g *GroupConfigBiz) handleReport(ctx context.Context, rec *entitys.Recogniz if _err != nil { return _err } - reports = append(reports, repo...) reports = append(reports, rechargeReport...) + reports = append(reports, repo...) + case "report_daily_recharge": product := strings.Split(groupConfig.ProductName, ",") repo, _err := g.rechargeDailyReport(ctx, t, product, nil) diff --git a/internal/tools/bbxt/bbxt.go b/internal/tools/bbxt/bbxt.go index 7a03cce..1f9d2b6 100644 --- a/internal/tools/bbxt/bbxt.go +++ b/internal/tools/bbxt/bbxt.go @@ -13,6 +13,8 @@ import ( "sort" "time" + + "github.com/shopspring/decimal" ) const ( @@ -91,9 +93,7 @@ func (b *BbxtTools) DailyReport( if err != nil { return } - reports = append(reports, productLossReport...) - reports = append(reports, profitRankingSum, statisOfficialProductSum, statisOfficialProductSumDecline) - + reports = append(reports, profitRankingSum, statisOfficialProductSum, statisOfficialProductSumDecline, productLossReport) if ossClient != nil { uploader := NewUploader(ossClient, b.config) for _, report := range reports { @@ -135,7 +135,9 @@ func (b *BbxtTools) ResellerLossSort(ctx context.Context, now time.Time) ([]*Res reseller := resellerMap[info.ResellerId] // 累加经销商总亏损 - reseller.Total += info.Loss + num1 := decimal.NewFromFloat(reseller.Total) + num2 := decimal.NewFromFloat(info.Loss) + reseller.Total, _ = num1.Add(num2).Round(2).Float64() // 检查产品是否已存在 if _, ok := reseller.ProductLoss[info.OursProductId]; !ok { @@ -209,14 +211,14 @@ func (b *BbxtTools) ResellerLossToMapResellerLossSumProductRelation(totalDetail } // StatisOursProductLossSum 负利润分析 -func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report []*ReportRes, err error) { +func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, initFunc LossSumInitFunc) (report *ReportRes, err error) { resellers, err := b.ResellerLossSort(ctx, now) var ( - total [][]string - gt []*ResellerLoss + total [][]string + //gt []*ResellerLoss totalDetail []*ResellerLoss - totalSum float64 - totalSum500 float64 + totalSum = decimal.NewFromFloat(0) + //totalSum500 float64 ) // 构建分组 for _, v := range resellers { @@ -225,45 +227,46 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, fmt.Sprintf("%s", v.ResellerName), fmt.Sprintf("%.2f", v.Total), }) - totalSum += v.Total + num := decimal.NewFromFloat(v.Total) + totalSum = totalSum.Add(num).Round(2) totalDetail = append(totalDetail, v) } - if v.Total <= -500 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) { - gt = append(gt, v) - totalSum500 += v.Total - } + //if v.Total <= -500 && !slices.Contains(ResellerBlackListProduct, v.ResellerName) { + // gt = append(gt, v) + // totalSum500 += v.Total + //} } - report = make([]*ReportRes, 3) + //report = make([]*ReportRes, 3) timeCh := now.Format("1月2日15点") //总量生成excel - if len(total) > 0 { - filePath := b.cacheDir + "/kshj_total" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx" - err = b.SimpleFillExcelWithTitle(b.excelTempDir+"/"+"kshj_total.xlsx", filePath, total, "") - if err != nil { - return - } - report[0] = &ReportRes{ - ReportName: "分销商负利润统计", - Title: "截至" + timeCh + "利润累计亏损" + fmt.Sprintf("%.2f", totalSum), - Path: filePath, - Data: total, - } - } - - if len(gt) > 0 { - filePath := b.cacheDir + "/kshj_gt" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx" - title := "截至" + timeCh + "亏损500以上的分销商和产品" - err = b.resellerDetailFillExcelV2(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, gt, title) - if err != nil { - return - } - report[1] = &ReportRes{ - ReportName: "负利润分析(亏损500以上)", - Title: "截至" + timeCh + "亏损500以上利润累计亏损" + fmt.Sprintf("%.2f", totalSum500), - Path: filePath, - Data: total, - } - } + //if len(total) > 0 { + // filePath := b.cacheDir + "/kshj_total" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx" + // err = b.SimpleFillExcelWithTitle(b.excelTempDir+"/"+"kshj_total.xlsx", filePath, total, "") + // if err != nil { + // return + // } + // report[0] = &ReportRes{ + // ReportName: "分销商负利润统计", + // Title: "截至" + timeCh + "利润累计亏损" + fmt.Sprintf("%.2f", totalSum), + // Path: filePath, + // Data: total, + // } + //} + // + //if len(gt) > 0 { + // filePath := b.cacheDir + "/kshj_gt" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx" + // title := "截至" + timeCh + "亏损500以上的分销商和产品" + // err = b.resellerDetailFillExcelV2(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, gt, title) + // if err != nil { + // return + // } + // report[1] = &ReportRes{ + // ReportName: "负利润分析(亏损500以上)", + // Title: "截至" + timeCh + "亏损500以上利润累计亏损" + fmt.Sprintf("%.2f", totalSum500), + // Path: filePath, + // Data: total, + // } + //} if len(totalDetail) > 0 { err = initFunc(ctx, now, totalDetail, b) @@ -271,14 +274,15 @@ func (b *BbxtTools) StatisOursProductLossSum(ctx context.Context, now time.Time, return } filePath := b.cacheDir + "/kshj_total_ana" + fmt.Sprintf("%d%d", time.Now().Unix(), rand.Intn(1000)) + ".xlsx" - title := "截至" + timeCh + "亏损100以上的分销商&产品负利润原因" + totalSumFloat64, _ := totalSum.Float64() + title := "截至" + timeCh + "利润累计亏损" + fmt.Sprintf("%.2f", totalSumFloat64) + ",亏损100以上利润原因如下" err = b.resellerDetailFillExcelAna(b.excelTempDir+"/"+"kshj_total_ana.xlsx", filePath, totalDetail, title) if err != nil { return } - report[2] = &ReportRes{ + report = &ReportRes{ ReportName: "负利润分析(亏损100以上)", - Title: "截至" + timeCh + "亏损100以上利润原因", + Title: title, Path: filePath, Data: total, } diff --git a/internal/tools/bbxt/excel.go b/internal/tools/bbxt/excel.go index 91915dc..c10906d 100644 --- a/internal/tools/bbxt/excel.go +++ b/internal/tools/bbxt/excel.go @@ -343,14 +343,17 @@ func (b *BbxtTools) resellerDetailFillExcelAna(templatePath, outputPath string, styleD3, err := f.GetCellStyle(sheet, fmt.Sprintf("D%d", tplRowData)) if err != nil { - styleC3 = 0 + styleD3 = 0 } styleE3, err := f.GetCellStyle(sheet, fmt.Sprintf("E%d", tplRowData)) if err != nil { - styleC3 = 0 + styleE3 = 0 + } + styleF3, err := f.GetCellStyle(sheet, fmt.Sprintf("F%d", tplRowData)) + if err != nil { + styleF3 = 0 } - rowHeightData, err := f.GetRowHeight(sheet, tplRowData) if err != nil { rowHeightData = 20 @@ -372,11 +375,15 @@ func (b *BbxtTools) resellerDetailFillExcelAna(templatePath, outputPath string, } styleTotalD, err := f.GetCellStyle(sheet, fmt.Sprintf("D%d", tplRowTotal)) if err != nil { - styleTotalC = 0 + styleTotalD = 0 } styleTotalE, err := f.GetCellStyle(sheet, fmt.Sprintf("E%d", tplRowTotal)) if err != nil { - styleTotalC = 0 + styleTotalE = 0 + } + styleTotalF, err := f.GetCellStyle(sheet, fmt.Sprintf("F%d", tplRowTotal)) + if err != nil { + styleTotalF = 0 } rowHeightTotal, err := f.GetRowHeight(sheet, tplRowTotal) if err != nil { @@ -408,8 +415,9 @@ func (b *BbxtTools) resellerDetailFillExcelAna(templatePath, outputPath string, f.SetCellValue(sheet, fmt.Sprintf("A%d", currentRow), reseller.ResellerName) f.SetCellValue(sheet, fmt.Sprintf("B%d", currentRow), p.ProductName) f.SetCellValue(sheet, fmt.Sprintf("C%d", currentRow), p.Loss) - f.SetCellValue(sheet, fmt.Sprintf("D%d", currentRow), reseller.Manager) - f.SetCellValue(sheet, fmt.Sprintf("E%d", currentRow), p.LossReason) + f.SetCellValue(sheet, fmt.Sprintf("D%d", currentRow), reseller.Total) + f.SetCellValue(sheet, fmt.Sprintf("E%d", currentRow), reseller.Manager) + f.SetCellValue(sheet, fmt.Sprintf("F%d", currentRow), p.LossReason) // 设置样式 if styleA3 != 0 { f.SetCellStyle(sheet, fmt.Sprintf("A%d", currentRow), fmt.Sprintf("A%d", currentRow), styleA3) @@ -426,7 +434,9 @@ func (b *BbxtTools) resellerDetailFillExcelAna(templatePath, outputPath string, if styleE3 != 0 { f.SetCellStyle(sheet, fmt.Sprintf("E%d", currentRow), fmt.Sprintf("E%d", currentRow), styleE3) } - + if styleF3 != 0 { + f.SetCellStyle(sheet, fmt.Sprintf("F%d", currentRow), fmt.Sprintf("F%d", currentRow), styleF3) + } totalLoss += p.Loss currentRow++ } @@ -436,6 +446,7 @@ func (b *BbxtTools) resellerDetailFillExcelAna(templatePath, outputPath string, if endRow > startRow { f.MergeCell(sheet, fmt.Sprintf("A%d", startRow), fmt.Sprintf("A%d", endRow)) f.MergeCell(sheet, fmt.Sprintf("D%d", startRow), fmt.Sprintf("D%d", endRow)) + f.MergeCell(sheet, fmt.Sprintf("E%d", startRow), fmt.Sprintf("E%d", endRow)) } } @@ -447,7 +458,7 @@ func (b *BbxtTools) resellerDetailFillExcelAna(templatePath, outputPath string, f.SetCellValue(sheet, fmt.Sprintf("A%d", currentRow), "合计") // B列留空,C列填充总亏损 - f.SetCellValue(sheet, fmt.Sprintf("C%d", currentRow), totalLoss) + f.SetCellValue(sheet, fmt.Sprintf("D%d", currentRow), totalLoss) // 设置合计行样式 if styleTotalA != 0 { @@ -465,7 +476,9 @@ func (b *BbxtTools) resellerDetailFillExcelAna(templatePath, outputPath string, if styleTotalE != 0 { f.SetCellStyle(sheet, fmt.Sprintf("E%d", currentRow), fmt.Sprintf("E%d", currentRow), styleTotalE) } - + if styleTotalF != 0 { + f.SetCellStyle(sheet, fmt.Sprintf("F%d", currentRow), fmt.Sprintf("F%d", currentRow), styleTotalF) + } // 取消合并合计行的A、B列 // f.MergeCell(sheet, fmt.Sprintf("A%d", currentRow), fmt.Sprintf("B%d", currentRow)) diff --git a/tmpl/excel_temp/kshj_total_ana.xlsx b/tmpl/excel_temp/kshj_total_ana.xlsx index fc64998506660abf972ba3af79d5868868071444..73cb4683bde31b53d2a388e343d4419f23077034 100644 GIT binary patch delta 5386 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 delta 5324 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