From 8deb91dea93030eafe563d385531c0cf72d10ea8 Mon Sep 17 00:00:00 2001 From: fuzhongyun <15339891972@163.com> Date: Tue, 30 Dec 2025 09:15:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=88=86=E9=94=80?= =?UTF-8?q?=E5=95=86=E8=B4=9F=E5=88=A9=E6=B6=A6=E8=AF=A6=E6=83=85excel?= =?UTF-8?q?=E5=A1=AB=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/tools/bbxt/bbxt.go | 96 ++++++++++++++++++++++++++++++- internal/tools/bbxt/bbxt_test.go | 2 +- tmpl/excel_temp/kshj_gt.xlsx | Bin 0 -> 9469 bytes 3 files changed, 94 insertions(+), 4 deletions(-) create mode 100755 tmpl/excel_temp/kshj_gt.xlsx diff --git a/internal/tools/bbxt/bbxt.go b/internal/tools/bbxt/bbxt.go index 8fe2885..cd1024f 100644 --- a/internal/tools/bbxt/bbxt.go +++ b/internal/tools/bbxt/bbxt.go @@ -4,6 +4,7 @@ import ( "ai_scheduler/internal/pkg" "fmt" "reflect" + "sort" "time" "github.com/xuri/excelize/v2" @@ -92,7 +93,7 @@ func (b *BbxtTools) StatisOursProductLossSumTotal(ct []string) (err error) { for _, v := range resellerMap { if v.Total <= -100 { total = append(total, []string{ - fmt.Sprintf("%d", v.ResellerName), + fmt.Sprintf("%s", v.ResellerName), fmt.Sprintf("%.2f", v.Total), }) } @@ -103,12 +104,13 @@ func (b *BbxtTools) StatisOursProductLossSumTotal(ct []string) (err error) { //总量生成excel if len(total) > 0 { filePath := b.cacheDir + "/kshj_total" + fmt.Sprintf("%d", time.Now().Unix()) + ".xlsx" - err = b.SimpleFillExcel(b.excelTempDir+"/"+"kshj_total.xlsx", filePath, total) + err = b.SimpleFillExcel(b.excelTempDir+"/"+"kshj_total_v2.xlsx", filePath, total) } if len(gt) > 0 { filePath := b.cacheDir + "/kshj_gt" + fmt.Sprintf("%d", time.Now().Unix()) + ".xlsx" - err = b.SimpleFillExcel(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, total) + // err = b.SimpleFillExcel(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, total) + err = b.resellerDetailFillExcel(b.excelTempDir+"/"+"kshj_gt.xlsx", filePath, gt) } return err } @@ -166,3 +168,91 @@ func (b *BbxtTools) SimpleFillExcel(templatePath, outputPath string, dataSlice i // 6. 保存 return f.SaveAs(outputPath) } + +// 分销商负利润详情填充excel +// 1.使用模板文件作为输出文件 +// 2.分销商总计使用第二行样式(宽高、背景、颜色等) +// 3.商品详情使用第三行样式(宽高、背景、颜色等) +// 4.保存为新文件 +func (b *BbxtTools) resellerDetailFillExcel(templatePath, outputPath string, dataSlice []*ResellerLoss) error { + // 1. 读取模板 + f, err := excelize.OpenFile(templatePath) + if err != nil { + return err + } + defer f.Close() + + sheet := f.GetSheetName(0) + + // 获取模板样式1:第二行-分销商总计 + resellerTplRow := 2 + styleIDReseller, err := f.GetCellStyle(sheet, fmt.Sprintf("A%d", resellerTplRow)) + if err != nil { + // 如果获取失败,就不应用样式,或者记录日志,这里选择忽略错误继续 + styleIDReseller = 0 + } + rowHeightReseller, err := f.GetRowHeight(sheet, resellerTplRow) + if err != nil { + rowHeightReseller = 31 // 默认高度 + } + // 获取模板样式2:第三行-产品亏损明细 + productTplRow := 3 + styleIDProduct, err := f.GetCellStyle(sheet, fmt.Sprintf("A%d", productTplRow)) + if err != nil { + // 如果获取失败,就不应用样式,或者记录日志,这里选择忽略错误继续 + styleIDProduct = 0 + } + rowHeightProduct, err := f.GetRowHeight(sheet, productTplRow) + if err != nil { + rowHeightProduct = 25 // 默认高度 + } + + currentRow := 2 + + for _, reseller := range dataSlice { + // 3. 填充经销商数据 (ResellerName, Total) + // 设置行高 + f.SetRowHeight(sheet, currentRow, rowHeightReseller) + + // 设置单元格值 + f.SetCellValue(sheet, fmt.Sprintf("A%d", currentRow), reseller.ResellerName) + f.SetCellValue(sheet, fmt.Sprintf("B%d", currentRow), reseller.Total) + + // 应用样式 + if styleIDReseller != 0 { + f.SetCellStyle(sheet, fmt.Sprintf("A%d", currentRow), fmt.Sprintf("B%d", currentRow), styleIDReseller) + } + + currentRow++ + + // 4. 填充产品亏损明细 + // 先对 ProductLoss 进行排序 + var products []ProductLoss + for _, p := range reseller.ProductLoss { + products = append(products, p) + } + // 按 Loss 升序排序 (亏损越多越靠前,负数越小) + sort.Slice(products, func(i, j int) bool { + return products[i].Loss < products[j].Loss + }) + + for _, p := range products { + // 设置行高 + f.SetRowHeight(sheet, currentRow, rowHeightProduct) + + // 设置单元格值 + f.SetCellValue(sheet, fmt.Sprintf("A%d", currentRow), p.ProductName) + f.SetCellValue(sheet, fmt.Sprintf("B%d", currentRow), p.Loss) + + // 应用样式 + if styleIDProduct != 0 { + f.SetCellStyle(sheet, fmt.Sprintf("A%d", currentRow), fmt.Sprintf("B%d", currentRow), styleIDProduct) + } + + currentRow++ + } + } + + // 6. 保存 + return f.SaveAs(outputPath) +} diff --git a/internal/tools/bbxt/bbxt_test.go b/internal/tools/bbxt/bbxt_test.go index 80e6b29..628c675 100644 --- a/internal/tools/bbxt/bbxt_test.go +++ b/internal/tools/bbxt/bbxt_test.go @@ -7,7 +7,7 @@ func Test_StatisOursProductLossSumApiTotal(t *testing.T) { if err != nil { panic(err) } - err = o.StatisOursProductLossSumTotal() + err = o.StatisOursProductLossSumTotal([]string{"2025-12-28+00:00:00", "2025-12-28+23:59:59.999"}) t.Log(err) diff --git a/tmpl/excel_temp/kshj_gt.xlsx b/tmpl/excel_temp/kshj_gt.xlsx new file mode 100755 index 0000000000000000000000000000000000000000..9ab76f5e450a7e10ea61eded595909e5f46182a2 GIT binary patch literal 9469 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