162 lines
4.3 KiB
Go
162 lines
4.3 KiB
Go
package bbxt
|
|
|
|
import (
|
|
"ai_scheduler/internal/pkg/utils_oss"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gofiber/fiber/v2/log"
|
|
"github.com/xuri/excelize/v2"
|
|
)
|
|
|
|
type Uploader struct {
|
|
ossClient *utils_oss.Client
|
|
}
|
|
|
|
const RequestUrl = "http://192.168.6.109:8010/api/v1/convert"
|
|
|
|
func NewUploader(oss *utils_oss.Client) *Uploader {
|
|
return &Uploader{
|
|
ossClient: oss,
|
|
}
|
|
}
|
|
|
|
func (u *Uploader) Run(report *ReportRes) (err error) {
|
|
if len(report.Path) == 0 {
|
|
return
|
|
}
|
|
f, err := excelize.OpenFile(report.Path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
excelBytes, err := f.WriteToBuffer()
|
|
if err != nil {
|
|
return fmt.Errorf("write to bytes failed: %v", err)
|
|
}
|
|
|
|
picBytes, err := u.excel2picPy(report.Path, excelBytes.Bytes(), 2)
|
|
if err != nil {
|
|
return fmt.Errorf("excel2picPy failed: %v", err)
|
|
}
|
|
// b.savePic("temp.png", picBytes) // 本地生成图片,仅测试
|
|
// outputPath 提取文件名(不包含扩展名)
|
|
filename := filepath.Base(report.Path)
|
|
filename = strings.TrimSuffix(filename, filepath.Ext(filename))
|
|
report.Url = u.uploadToOSS(filename, picBytes)
|
|
log.Infof("imgUrl: %s", report.Url)
|
|
|
|
return
|
|
}
|
|
|
|
// 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 (u *Uploader) excel2picPy(templatePath string, excelBytes []byte, scale int) ([]byte, error) {
|
|
// 1. 获取 Sheet Name
|
|
// 尝试从 excelBytes 解析,如果失败则使用默认值 "Sheet1"
|
|
sheetName := "Sheet1"
|
|
f, err := excelize.OpenReader(bytes.NewReader(excelBytes))
|
|
if err == nil {
|
|
sheetName = f.GetSheetName(0)
|
|
if sheetName == "" {
|
|
sheetName = "Sheet1"
|
|
}
|
|
f.Close()
|
|
}
|
|
|
|
// 2. 构造 Multipart 请求
|
|
body := &bytes.Buffer{}
|
|
writer := multipart.NewWriter(body)
|
|
|
|
// 添加文件字段
|
|
// 使用 templatePath 的文件名作为上传文件名,如果没有则用 default.xlsx
|
|
filename := "default.xlsx"
|
|
if templatePath != "" {
|
|
filename = filepath.Base(templatePath)
|
|
}
|
|
|
|
part, err := writer.CreateFormFile("file", filename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create form file failed: %v", err)
|
|
}
|
|
if _, err = part.Write(excelBytes); err != nil {
|
|
return nil, fmt.Errorf("write file part failed: %v", err)
|
|
}
|
|
|
|
// 添加 sheet_name 字段
|
|
if err = writer.WriteField("sheet_name", sheetName); err != nil {
|
|
return nil, fmt.Errorf("write field sheet_name failed: %v", err)
|
|
}
|
|
|
|
// 添加 scale 字段
|
|
if scale <= 0 {
|
|
scale = 2
|
|
}
|
|
if err = writer.WriteField("scale", fmt.Sprintf("%d", scale)); err != nil {
|
|
return nil, fmt.Errorf("write field scale failed: %v", err)
|
|
}
|
|
|
|
if err = writer.Close(); err != nil {
|
|
return nil, fmt.Errorf("close writer failed: %v", err)
|
|
}
|
|
|
|
// 3. 发送 HTTP POST 请求
|
|
|
|
req, err := http.NewRequest("POST", RequestUrl, body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create request failed: %v", err)
|
|
}
|
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
|
|
|
client := &http.Client{}
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("send request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
respBody, _ := io.ReadAll(resp.Body)
|
|
return nil, fmt.Errorf("api request failed with status: %d, body: %s", resp.StatusCode, string(respBody))
|
|
}
|
|
|
|
// 4. 读取响应 Body (图片内容)
|
|
picBytes, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read response body failed: %v", err)
|
|
}
|
|
|
|
return picBytes, nil
|
|
}
|
|
|
|
// savePic 保存图片到本地
|
|
func (u *Uploader) savePic(outputPath string, picBytes []byte) error {
|
|
dir := filepath.Dir(outputPath)
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
return fmt.Errorf("create directory failed: %v", err)
|
|
}
|
|
return os.WriteFile(outputPath, picBytes, 0644)
|
|
}
|
|
|
|
// uploadToOSS 上传至 oss 返回图片url
|
|
func (u *Uploader) uploadToOSS(fileName string, fileBytes []byte) string {
|
|
objectKey := fmt.Sprintf("ai-scheduler/data-analytics/images/%s.png", fileName)
|
|
url, err := u.ossClient.UploadBytes(objectKey, fileBytes)
|
|
if err != nil {
|
|
log.Errorf("oss upload failed: %v", err)
|
|
return ""
|
|
}
|
|
return url
|
|
}
|