ai_scheduler/internal/tools/bbxt/excel.go

195 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package bbxt
import (
"fmt"
"reflect"
"sort"
"github.com/go-kratos/kratos/v2/log"
"github.com/xuri/excelize/v2"
)
// 最简单的通用函数
func (b *BbxtTools) SimpleFillExcel(templatePath, outputPath string, dataSlice interface{}) error {
// 1. 打开模板
f, err := excelize.OpenFile(templatePath)
if err != nil {
return err
}
defer f.Close()
sheet := f.GetSheetName(0)
// 1.1 获取第二行模板样式
resellerTplRow := 2
styleIDReseller, err := f.GetCellStyle(sheet, fmt.Sprintf("A%d", resellerTplRow))
if err != nil {
log.Errorf("获取分销商总计样式失败: %v", err)
styleIDReseller = 0
}
// 1.2 获取分销商总计行高
rowHeightReseller, err := f.GetRowHeight(sheet, resellerTplRow)
if err != nil {
log.Errorf("获取分销商总计行高失败: %v", err)
rowHeightReseller = 31 // 默认高度
}
// 2. 反射获取切片数据
v := reflect.ValueOf(dataSlice)
if v.Kind() != reflect.Slice {
return fmt.Errorf("dataSlice must be a slice")
}
// 3. 从第2行开始填充
row := 2
for i := 0; i < v.Len(); i++ {
item := v.Index(i).Interface()
currentRow := row + i
// 4. 将item转换为一行数据
var rowData []interface{}
// 如果是切片
if reflect.TypeOf(item).Kind() == reflect.Slice {
itemV := reflect.ValueOf(item)
for j := 0; j < itemV.Len(); j++ {
rowData = append(rowData, itemV.Index(j).Interface())
}
} else if reflect.TypeOf(item).Kind() == reflect.Struct {
itemV := reflect.ValueOf(item)
for j := 0; j < itemV.NumField(); j++ {
if itemV.Field(j).CanInterface() {
rowData = append(rowData, itemV.Field(j).Interface())
}
}
} else {
rowData = []interface{}{item}
}
// 4.1 设置行高
f.SetRowHeight(sheet, currentRow, rowHeightReseller)
// 5. 填充到Excel
for col, value := range rowData {
cell := fmt.Sprintf("%c%d", 'A'+col, currentRow)
f.SetCellValue(sheet, cell, value)
}
// 5.1 使用第二行模板样式
if styleIDReseller != 0 {
f.SetCellStyle(sheet, fmt.Sprintf("A%d", currentRow), fmt.Sprintf("B%d", currentRow), styleIDReseller)
}
}
// 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 {
log.Errorf("获取分销商总计样式失败: %v", err)
styleIDReseller = 0
}
rowHeightReseller, err := f.GetRowHeight(sheet, resellerTplRow)
if err != nil {
log.Errorf("获取分销商总计行高失败: %v", err)
rowHeightReseller = 31 // 默认高度
}
// 获取模板样式2第三行-产品亏损明细
productTplRow := 3
styleIDProduct, err := f.GetCellStyle(sheet, fmt.Sprintf("A%d", productTplRow))
if err != nil {
log.Errorf("获取商品详情样式失败: %v", err)
styleIDProduct = 0
}
rowHeightProduct, err := f.GetRowHeight(sheet, productTplRow)
if err != nil {
log.Errorf("获取商品详情行高失败: %v", err)
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), fmt.Sprintf("·%s", 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++
}
}
// buffer, err := f.WriteToBuffer()
// if err != nil {
// return err
// }
// return buffer.Bytes(), nil
// 6. 保存
return f.SaveAs(outputPath)
}
// excel2picPy 将excel转换为图片python
// python 接口如下:
// curl --location --request POST 'http://192.168.6.109:8010/api/v1/convert' \
// --header 'Content-Type: multipart/form-data; boundary=--------------------------952147881043913664015069' \
// --form 'file=@"C:\\Users\\Administrator\\Downloads\\销售同比分析2025-12-29 0-12点.xlsx"' \
// --form 'sheet_name="销售同比分析"'
func (b *BbxtTools) excel2picPy(templatePath string, excelBytes []byte) ([]byte, error) {
return nil, nil
// return picBytes, nil
}