update 修复文件问题
All checks were successful
Build image / build (push) Successful in 1m24s

This commit is contained in:
timerzz 2025-03-30 21:20:13 +08:00
parent a3f7314ece
commit 00e4f26d71
5 changed files with 49 additions and 74 deletions

View File

@ -15,19 +15,17 @@ import (
"github.com/gofiber/fiber/v3/middleware/cors"
"github.com/gofiber/fiber/v3/middleware/recover"
"github.com/sirupsen/logrus"
"github.com/golang/glog"
)
func main() {
flag.Parse()
glog.Info(">>> BEGIN INIT<<<")
logrus.Info(">>> BEGIN INIT<<<")
ctx, cancel := signal.NotifyContext(context.Background(), os.Kill, os.Interrupt)
defer cancel()
// 初始化数据库
db, err := database.InitDefaultDatabase()
if err != nil {
glog.Fatalf("init database failed: %v", err)
logrus.Fatalf("init database failed: %v", err)
}
client, err := dw_sdk.InitDefaultDWClient()
@ -59,6 +57,6 @@ func main() {
EnablePrintRoutes: true,
GracefulContext: ctx,
}); err != nil {
glog.Warningf("service over: %v", err)
logrus.Warningf("service over: %v", err)
}
}

2
go.mod
View File

@ -8,7 +8,6 @@ require (
gitea.timerzz.com/kedaya_haitao/common v0.0.0-20250329125718-37b1ee0b6a4b
gitea.timerzz.com/kedaya_haitao/dw-sdk v0.0.0-20240904075121-552ef11ea87c
github.com/gofiber/fiber/v3 v3.0.0-beta.4
github.com/golang/glog v1.2.2
github.com/samber/lo v1.49.1
github.com/sirupsen/logrus v1.9.3
github.com/xuri/excelize/v2 v2.9.0
@ -50,6 +49,7 @@ require (
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect
golang.org/x/arch v0.9.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/image v0.25.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect

6
go.sum
View File

@ -25,8 +25,6 @@ github.com/gofiber/schema v1.2.0 h1:j+ZRrNnUa/0ZuWrn/6kAtAufEr4jCJ+JuTURAMxNSZg=
github.com/gofiber/schema v1.2.0/go.mod h1:YYwj01w3hVfaNjhtJzaqetymL56VW642YS3qZPhuE6c=
github.com/gofiber/utils/v2 v2.0.0-beta.7 h1:NnHFrRHvhrufPABdWajcKZejz9HnCWmT/asoxRsiEbQ=
github.com/gofiber/utils/v2 v2.0.0-beta.7/go.mod h1:J/M03s+HMdZdvhAeyh76xT72IfVqBzuz/OJkrMa7cwU=
github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@ -112,8 +110,8 @@ golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k=
golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ=
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -57,16 +57,15 @@ func (s *Tools) CoachOutletExcel(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "导出工具未初始化")
}
// 设置文件名和响应头
fileName := fmt.Sprintf("coach_outlet_%s.xlsx", providerId)
c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
c.Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
// 直接将Excel数据写入响应
if err := s.export.ExportCheapProduct(providerId, c); err != nil {
fileName, err := s.export.ExportCheapProduct(providerId)
if err != nil {
logrus.Errorf("导出Coach Outlet商品数据失败: %v", err)
return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("导出失败: %v", err))
}
// 设置文件名和响应头
c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName))
c.Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
return nil
return c.SendFile(fileName)
}

View File

@ -5,14 +5,12 @@ import (
"io"
"net/http"
"strconv"
"strings"
"time"
"gitea.timerzz.com/kedaya_haitao/common/structs/storage"
"gitea.timerzz.com/kedaya_haitao/common/structs/utils"
v2 "gitea.timerzz.com/kedaya_haitao/common/structs/v2"
dw_sdk "gitea.timerzz.com/kedaya_haitao/dw-sdk"
"github.com/gofiber/fiber/v3"
"github.com/samber/lo"
"github.com/sirupsen/logrus"
"github.com/xuri/excelize/v2"
@ -37,19 +35,23 @@ func NewExporter(storage *storage.Storage, dw *dw_sdk.Client) (e *Exporter, err
}
// ExportCheapProduct 导出价格较低的商品数据到Excel直接写入到HTTP响应
func (e *Exporter) ExportCheapProduct(providerId string, c fiber.Ctx) error {
func (e *Exporter) ExportCheapProduct(providerId string) (string, error) {
// 创建Excel文件
f := excelize.NewFile()
defer f.Close()
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 创建工作表
sheetName := providerId
_, err := f.NewSheet(sheetName)
if err != nil {
return fmt.Errorf("创建工作表失败: %w", err)
return "", fmt.Errorf("创建工作表失败: %w", err)
}
_ = f.DeleteSheet("Sheet1") // 删除默认的Sheet1
// 确定查询的供应商ID
var cheapId, otherId string
cheapId = providerId
@ -70,47 +72,47 @@ func (e *Exporter) ExportCheapProduct(providerId string, c fiber.Ctx) error {
Where("pa1.cost->>'finalPrice' <= pa2.cost->>'finalPrice'").
FindInBatches(&articles, 20, func(tx *gorm.DB, batch int) error {
for _, article := range articles {
// 更新DW价格如果需要
dwSeller, idx, exist := lo.FindIndexOf(article.Sellers, func(seller v2.SellerArticle) bool {
return seller.SellerId == "dw-normal"
pArticle, _ := lo.Find(article.Providers, func(p v2.ProviderArticle) bool {
return p.ProviderId == v2.ProviderId(cheapId)
})
if exist && dwSeller.Sell.CreatedAt.Before(time.Now().AddDate(0, 0, -1)) {
// 如果已经是一天前的数据,那么就要更新下
dwSeller = e.pullDwPrice(dwSeller)
article.Sellers[idx] = dwSeller
}
if pArticle.Cost.OriginalPrice != 0 {
// 更新DW价格如果需要
dwSeller, idx, exist := lo.FindIndexOf(article.Sellers, func(seller v2.SellerArticle) bool {
return seller.SellerId == "dw-normal"
})
if exist && dwSeller.Sell.CreatedAt.Before(time.Now().AddDate(0, 0, -1)) {
// 如果已经是一天前的数据,那么就要更新下
dwSeller = e.pullDwPrice(dwSeller)
article.Sellers[idx] = dwSeller
}
// 计算利润率
utils.ProfitRate(article)
// 计算利润率
utils.ProfitRate(article)
// 添加到Excel
rowIndex++
if err = addRow(f, sheetName, rowIndex, article); err != nil {
logrus.Errorf("添加行失败: %v", err)
continue
// 添加到Excel
rowIndex++
if err = addRow(f, sheetName, rowIndex, article); err != nil {
logrus.Errorf("添加行失败: %v", err)
continue
}
}
}
return nil
}).Error
if err != nil {
return fmt.Errorf("查询数据失败: %w", err)
return "", fmt.Errorf("查询数据失败: %w", err)
}
// 保存Excel文件
filename := fmt.Sprintf("coach_outlet_%s.xlsx", providerId)
if err = f.SaveAs(filename); err != nil {
return fmt.Errorf("保存Excel文件失败: %w", err)
}
// 直接将Excel文件写入到HTTP响应
if err = f.Write(c.Response().BodyWriter()); err != nil {
return fmt.Errorf("写入Excel数据失败: %w", err)
return "", fmt.Errorf("保存Excel文件失败: %w", err)
}
logrus.Infof("成功导出 %d 条数据", rowIndex-1)
return nil
return filename, nil
}
// 设置标题行
@ -172,11 +174,13 @@ func addRow(f *excelize.File, sheetName string, rowIndex int, article *v2.Articl
cell, _ := excelize.CoordinatesToCellName(i+1, rowIndex)
_ = f.SetCellValue(sheetName, cell, value)
}
// 设置行高以适应图片
_ = f.SetRowHeight(sheetName, rowIndex, 80)
// 处理图片
linkCell, _ := excelize.CoordinatesToCellName(1, rowIndex)
_ = f.SetCellHyperLink(sheetName, linkCell, caProvider.Link, "External")
if len(article.Image) > 0 {
imgCell, _ := excelize.CoordinatesToCellName(2, rowIndex)
@ -188,8 +192,8 @@ func addRow(f *excelize.File, sheetName string, rowIndex int, article *v2.Articl
_ = f.SetCellValue(sheetName, imgCell, article.Image)
} else {
// 添加图片到Excel
if err := f.AddPictureFromBytes(sheetName, imgCell, &excelize.Picture{
Extension: getImageExtension(article.Image),
if err = f.AddPictureFromBytes(sheetName, imgCell, &excelize.Picture{
Extension: ".jpg",
File: imgData,
Format: &excelize.GraphicOptions{
AutoFit: true,
@ -202,6 +206,7 @@ func addRow(f *excelize.File, sheetName string, rowIndex int, article *v2.Articl
// 如果添加失败显示URL
_ = f.SetCellValue(sheetName, imgCell, article.Image)
}
}
}
@ -236,31 +241,6 @@ func downloadImage(url string) ([]byte, error) {
return imgData, nil
}
// getImageExtension 从URL获取图片扩展名
func getImageExtension(url string) string {
// 默认扩展名
ext := ".jpg"
// 从URL中提取扩展名
if strings.Contains(url, ".") {
parts := strings.Split(url, ".")
lastPart := parts[len(parts)-1]
// 处理可能的查询参数
if strings.Contains(lastPart, "?") {
lastPart = strings.Split(lastPart, "?")[0]
}
// 常见图片扩展名
switch strings.ToLower(lastPart) {
case "jpg", "jpeg", "png", "gif", "bmp", "webp":
ext = "." + strings.ToLower(lastPart)
}
}
return ext
}
func (e *Exporter) pullDwPrice(sArticle v2.SellerArticle) v2.SellerArticle {
skuId, _ := strconv.Atoi(sArticle.SkuID)
resp, err := e.dw.NormalBidClient().LowestPrice(skuId)