336 lines
8.1 KiB
Go
336 lines
8.1 KiB
Go
package imports
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"fonchain-fiee/pkg/config"
|
||
"fonchain-fiee/pkg/service"
|
||
"fonchain-fiee/pkg/utils"
|
||
"io"
|
||
"log"
|
||
"net/http"
|
||
"os"
|
||
"path/filepath"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/fonchain_enterprise/utils/objstorage"
|
||
"github.com/xuri/excelize/v2"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
const (
|
||
fail string = "操作失败"
|
||
)
|
||
|
||
type excelData struct {
|
||
ArtistName string //艺人 必须字段
|
||
SubNum string //用户编号 必须字段
|
||
TikTok string
|
||
Instagram string
|
||
Youtube string
|
||
Desc string //艺人简介
|
||
TitleRequire string //标题要求 必须字段
|
||
ContentRequire string //内容要求 必须字段
|
||
PhotoRequire string //图片要求 必须字段
|
||
PhotoUrl string //画作地址
|
||
PhotoNum int //图片数量 必须字段
|
||
LineNum int
|
||
Title string //标题
|
||
Content string //内容
|
||
MediaAccountUuids []string
|
||
MediaAccountNames []string
|
||
}
|
||
type publishImageReq struct {
|
||
ArtistName string //艺人
|
||
SubNum string //用户编号
|
||
Title string //标题
|
||
Content string //内容
|
||
TikTok string
|
||
Instagram string
|
||
GeneratePhotoUrl []string //生成图片地址
|
||
MediaAccountUuids []string
|
||
MediaAccountNames []string
|
||
}
|
||
|
||
func getErrorMessage(err error) string {
|
||
if err == nil {
|
||
return ""
|
||
}
|
||
return err.Error()
|
||
}
|
||
|
||
func ImageContentImport(c *gin.Context) {
|
||
processor := GetOrCreateBatchProcessor()
|
||
currentStatus := processor.getStatus()
|
||
switch currentStatus {
|
||
case StatusProcessing: //进行中
|
||
service.Error(c, errors.New("当前有任务正在执行中,请先查看执行进度"))
|
||
return
|
||
case StatusIdle, StatusCompleted: //空闲状态,完成可以执行下一次导入
|
||
}
|
||
|
||
defer func() {
|
||
if r := recover(); r != nil {
|
||
service.Error(c, errors.New("操作失败"))
|
||
}
|
||
}()
|
||
|
||
// 导入excel
|
||
excelFile, err := c.FormFile("excel")
|
||
if err != nil {
|
||
service.Error(c, errors.New("缺少excel文件"))
|
||
return
|
||
}
|
||
|
||
// 创建临时文件
|
||
tempDir := "tmp"
|
||
if err = os.MkdirAll(tempDir, 0755); err != nil {
|
||
service.Error(c, errors.New("创建临时目录失败"))
|
||
return
|
||
}
|
||
defer os.RemoveAll(tempDir)
|
||
|
||
// 保存excel
|
||
excelPath := filepath.Join(tempDir, "excel.xlsx")
|
||
if err = c.SaveUploadedFile(excelFile, excelPath); err != nil {
|
||
service.Error(c, errors.New("保存excel文件失败"))
|
||
return
|
||
}
|
||
|
||
// 读取excel
|
||
readExcelResult, err := readExcel(excelPath)
|
||
if err != nil {
|
||
service.Error(c, fmt.Errorf("读取excel失败: %v", err))
|
||
return
|
||
}
|
||
if len(readExcelResult) == 0 {
|
||
service.Error(c, errors.New("请检查excel文件"))
|
||
return
|
||
}
|
||
//设置全局状态为进行中
|
||
processor.setStatus(StatusProcessing)
|
||
//设置请求间隔
|
||
qps := 10
|
||
interval := time.Second / time.Duration(qps)
|
||
for i, v := range readExcelResult {
|
||
if i > 0 {
|
||
time.Sleep(interval)
|
||
}
|
||
|
||
if err := processor.submitTask(&v); err != nil {
|
||
task := &ImageTask{
|
||
Data: &v,
|
||
TaskID: i,
|
||
Error: err,
|
||
StartTime: time.Now(),
|
||
}
|
||
processor.tasks[v.LineNum] = task
|
||
processor.inProgress[v.LineNum] = true
|
||
}
|
||
}
|
||
//开始轮询
|
||
processor.startPolling()
|
||
service.Success(c, gin.H{
|
||
"message": "导入成功",
|
||
"total": len(readExcelResult),
|
||
})
|
||
}
|
||
|
||
func readExcel(excelPath string) ([]excelData, error) {
|
||
//打开excel
|
||
f, err := excelize.OpenFile(excelPath)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer f.Close()
|
||
|
||
//读取第一页
|
||
sheetName := f.GetSheetName(0)
|
||
if sheetName == "" {
|
||
return nil, errors.New("excel文件中没有工作表")
|
||
}
|
||
|
||
//读取数据
|
||
rows, err := f.GetRows(sheetName)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("读取工作表失败: %v", err)
|
||
}
|
||
|
||
if len(rows) <= 1 {
|
||
return nil, errors.New("excel文件没有数据行(只有表头或为空)")
|
||
}
|
||
var result []excelData
|
||
for i := 1; i < len(rows); i++ { // 从第2行开始(跳过表头)
|
||
row := rows[i]
|
||
if len(row) == 0 {
|
||
continue
|
||
}
|
||
|
||
artistName := getCellValue(f, sheetName, i, 0)
|
||
if artistName == "" {
|
||
return nil, fmt.Errorf("第%d行应该有艺人名称", i+1)
|
||
}
|
||
subNum := getCellValue(f, sheetName, i, 1)
|
||
if subNum == "" {
|
||
return nil, fmt.Errorf("第%d行应该有编号", i+1)
|
||
}
|
||
tikTok := getCellValue(f, sheetName, i, 2)
|
||
if tikTok == "" {
|
||
return nil, fmt.Errorf("第%d行应该有tiktok账号昵称", i+1)
|
||
}
|
||
instagram := getCellValue(f, sheetName, i, 3)
|
||
if instagram == "" {
|
||
return nil, fmt.Errorf("第%d行应该有ins账号昵称", i+1)
|
||
}
|
||
desc := getCellValue(f, sheetName, i, 4)
|
||
titleRequire := getCellValue(f, sheetName, i, 5)
|
||
if titleRequire == "" {
|
||
return nil, fmt.Errorf("第%d行应该有标题要求", i+1)
|
||
}
|
||
contentRequire := getCellValue(f, sheetName, i, 6)
|
||
if contentRequire == "" {
|
||
return nil, fmt.Errorf("第%d行应该有内容要求", i+1)
|
||
}
|
||
photoRequire := getCellValue(f, sheetName, i, 7)
|
||
photoUrl := getCellValue(f, sheetName, i, 8)
|
||
photoNumStr := getCellValue(f, sheetName, i, 9)
|
||
var num int
|
||
if photoUrl == "" { //如果没有关联画作,数量必须有,需求必须有
|
||
//需求必须有
|
||
if photoRequire == "" {
|
||
return nil, fmt.Errorf("第%d行应该有图片需求", i+1)
|
||
}
|
||
//转换成功
|
||
photoNum, err := strconv.Atoi(strings.TrimSpace(photoNumStr))
|
||
if err != nil {
|
||
return nil, fmt.Errorf("第%d行图片数量格式错误: '%s',必须是整数", i+1, photoNumStr)
|
||
}
|
||
// 数量大于
|
||
if photoNum <= 0 {
|
||
return nil, fmt.Errorf("第%d行图片数量必须大于0,当前值: %d", i+1, photoNum)
|
||
}
|
||
num = photoNum
|
||
}
|
||
|
||
data := excelData{
|
||
ArtistName: artistName,
|
||
SubNum: subNum,
|
||
TikTok: tikTok,
|
||
Instagram: instagram,
|
||
Desc: desc,
|
||
TitleRequire: titleRequire,
|
||
ContentRequire: contentRequire,
|
||
PhotoRequire: photoRequire,
|
||
PhotoUrl: photoUrl,
|
||
PhotoNum: num,
|
||
LineNum: i, //行数
|
||
}
|
||
|
||
result = append(result, data)
|
||
}
|
||
|
||
return result, nil
|
||
}
|
||
|
||
func getCellValue(f *excelize.File, sheetName string, rowIndex, colIndex int) string {
|
||
colName, _ := excelize.ColumnNumberToName(colIndex + 1)
|
||
cell := fmt.Sprintf("%s%d", colName, rowIndex+1)
|
||
|
||
value, err := f.GetCellValue(sheetName, cell)
|
||
if err != nil {
|
||
log.Printf("读取单元格 %s 失败: %v", cell, err)
|
||
return ""
|
||
}
|
||
|
||
return strings.TrimSpace(value)
|
||
}
|
||
|
||
func Test1(c *gin.Context) {
|
||
// 创建临时目录
|
||
tempDir := "tmp"
|
||
if err := os.MkdirAll(tempDir, 0755); err != nil {
|
||
}
|
||
defer os.RemoveAll(tempDir) // 程序结束时清理整个目录
|
||
// 生成唯一文件名
|
||
fileName := fmt.Sprintf("%d.jpg", time.Now().Unix())
|
||
|
||
// 构建文件路径
|
||
imgPath := filepath.Join(tempDir, fileName)
|
||
|
||
// 创建文件
|
||
file, err := os.Create(imgPath)
|
||
if err != nil {
|
||
}
|
||
defer file.Close()
|
||
|
||
log.Printf("文件创建在: %s", imgPath)
|
||
|
||
// 下载图片到文件
|
||
resp, err := http.Get("https://e-cdn.fontree.cn/fontree-fiee/tmp/unzipped/9.23-04/邬小明/90_1758873144.jpg")
|
||
if err != nil {
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
}
|
||
|
||
// 复制到文件
|
||
_, err = io.Copy(file, resp.Body)
|
||
if err != nil {
|
||
}
|
||
|
||
file.Sync()
|
||
fileBytes, err := os.ReadFile(imgPath)
|
||
if err != nil {
|
||
|
||
}
|
||
// 上传到桶
|
||
BOSClient, err := objstorage.NewOSS(
|
||
config.ConfigData.Oss.AccessKeyId,
|
||
config.ConfigData.Oss.AccessKeySecret,
|
||
config.ConfigData.Oss.Endpoint,
|
||
)
|
||
_, err = BOSClient.PutObjectFromBytes(config.ConfigData.Oss.BucketName, fileName, fileBytes)
|
||
if err != nil {
|
||
return
|
||
}
|
||
url := fmt.Sprintf("%s/%s", config.ConfigData.Oss.CdnHost, fileName)
|
||
|
||
log.Printf("图片上传成功: %s -> %s", fileName, url)
|
||
service.Success(c)
|
||
}
|
||
|
||
func Test(c *gin.Context) {
|
||
err := publishImage(publishImageReq{
|
||
ArtistName: "荣小松",
|
||
SubNum: "FE00062",
|
||
Title: "test",
|
||
Content: "test",
|
||
GeneratePhotoUrl: []string{"0221", "2"},
|
||
})
|
||
if err != nil {
|
||
return
|
||
}
|
||
service.Success(c)
|
||
}
|
||
|
||
func Test2(c *gin.Context) {
|
||
titleList := []string{
|
||
"1",
|
||
}
|
||
var dataList []interface{}
|
||
data := []string{
|
||
"123123",
|
||
}
|
||
dataList = append(dataList, &data)
|
||
content, err := utils.ToExcelByType(titleList, dataList, "slice", "")
|
||
if err != nil {
|
||
service.Error(c, err)
|
||
return
|
||
}
|
||
utils.ResponseXls(c, content, "1")
|
||
}
|