|
@@ -1,11 +1,16 @@
|
|
|
package handlers
|
|
package handlers
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
|
|
+ "Vali-Tools/utils"
|
|
|
|
|
+ "bytes"
|
|
|
"context"
|
|
"context"
|
|
|
"encoding/base64"
|
|
"encoding/base64"
|
|
|
|
|
+ "encoding/json"
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
|
|
"io"
|
|
"io"
|
|
|
|
|
+ "mime/multipart"
|
|
|
|
|
+ "net/http"
|
|
|
"os"
|
|
"os"
|
|
|
"path/filepath"
|
|
"path/filepath"
|
|
|
"strings"
|
|
"strings"
|
|
@@ -201,6 +206,34 @@ type ImageResult struct {
|
|
|
ImageBase64 string `json:"image_base64"`
|
|
ImageBase64 string `json:"image_base64"`
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// UploadSkuResult SKU图片上传结果
|
|
|
|
|
+type UploadSkuResult struct {
|
|
|
|
|
+ FileName string `json:"FileName"`
|
|
|
|
|
+ ImageType string `json:"ImageType"`
|
|
|
|
|
+ Size int64 `json:"Size"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// UploadSkuResponse SKU图片上传响应
|
|
|
|
|
+type UploadSkuResponse struct {
|
|
|
|
|
+ Data []UploadSkuResult `json:"data"`
|
|
|
|
|
+ Success bool `json:"success"`
|
|
|
|
|
+ Code int `json:"code"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// BatchFileItem 批量上传文件项
|
|
|
|
|
+type BatchFileItem struct {
|
|
|
|
|
+ FilePath string
|
|
|
|
|
+ ImageType string
|
|
|
|
|
+ FileName string
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// ActionNamesResponse 动作名称响应
|
|
|
|
|
+type ActionNamesResponse struct {
|
|
|
|
|
+ Code int `json:"code"`
|
|
|
|
|
+ Msg string `json:"msg"`
|
|
|
|
|
+ Data []string `json:"data"`
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// sendProgress 发送进度更新
|
|
// sendProgress 发送进度更新
|
|
|
func (dh *DirectoryHandler) sendProgress(result ProcessResult) {
|
|
func (dh *DirectoryHandler) sendProgress(result ProcessResult) {
|
|
|
runtime.EventsEmit(dh.ctx, "copy800-progress", result)
|
|
runtime.EventsEmit(dh.ctx, "copy800-progress", result)
|
|
@@ -325,3 +358,273 @@ func (dh *DirectoryHandler) GetApplicationDirectory() (string, error) {
|
|
|
}
|
|
}
|
|
|
return filepath.Dir(execPath), nil
|
|
return filepath.Dir(execPath), nil
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+// HandlerUploadSkuImages 处理SKU图片上传
|
|
|
|
|
+func (dh *DirectoryHandler) HandlerUploadSkuImages(sourceDir string) error {
|
|
|
|
|
+ // 检查源目录是否存在
|
|
|
|
|
+ if _, err := os.Stat(sourceDir); os.IsNotExist(err) {
|
|
|
|
|
+ return fmt.Errorf("源目录不存在: %s", sourceDir)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 发送初始进度
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: true,
|
|
|
|
|
+ Message: "开始扫描目录...",
|
|
|
|
|
+ Progress: 0,
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 遍历和处理逻辑
|
|
|
|
|
+ err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: false,
|
|
|
|
|
+ Message: fmt.Sprintf("访问路径出错: %v", err),
|
|
|
|
|
+ Progress: 0,
|
|
|
|
|
+ })
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 处理 800x800 目录的逻辑
|
|
|
|
|
+ if info.IsDir() && strings.Contains(info.Name(), "800x800") {
|
|
|
|
|
+ fmt.Printf("👍👍👍找到800x800目录: %s\n", path)
|
|
|
|
|
+
|
|
|
|
|
+ // 获取上级目录名称作为Key参数
|
|
|
|
|
+ parentDirName := filepath.Base(filepath.Dir(path))
|
|
|
|
|
+
|
|
|
|
|
+ // 读取800x800目录下的所有文件
|
|
|
|
|
+ files, err := os.ReadDir(path)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: false,
|
|
|
|
|
+ Message: fmt.Sprintf("读取目录失败 %s: %v", path, err),
|
|
|
|
|
+ Progress: 0,
|
|
|
|
|
+ })
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 尝试从接口获取动作名称列表
|
|
|
|
|
+ var actionNames []string
|
|
|
|
|
+ actionNamesResponse, err := dh.getActionNamesByGoods(parentDirName)
|
|
|
|
|
+ if err == nil && actionNamesResponse.Code == 0 && len(actionNamesResponse.Data) > 0 {
|
|
|
|
|
+ actionNames = actionNamesResponse.Data
|
|
|
|
|
+ fmt.Printf("📋 获取到动作名称列表 [%s]: %v\n", parentDirName, actionNames)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ fmt.Printf("️ 获取动作名称失败或为空,将使用默认逻辑 [%s]\n", parentDirName)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 收集所有有效的图片文件
|
|
|
|
|
+ var validFiles []BatchFileItem
|
|
|
|
|
+ fileIndex := 0
|
|
|
|
|
+
|
|
|
|
|
+ for _, file := range files {
|
|
|
|
|
+ if file.IsDir() {
|
|
|
|
|
+ continue // 跳过子目录
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否为有效的图片文件
|
|
|
|
|
+ if !dh.isValidImageFile(file.Name()) {
|
|
|
|
|
+ continue // 跳过非图片文件
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ filePath := filepath.Join(path, file.Name())
|
|
|
|
|
+
|
|
|
|
|
+ // 确定ImageType:如果接口返回了数据且索引有效,则使用接口返回的值
|
|
|
|
|
+ var imageType string
|
|
|
|
|
+ if len(actionNames) > 0 && fileIndex < len(actionNames) {
|
|
|
|
|
+ imageType = actionNames[fileIndex]
|
|
|
|
|
+ fmt.Printf("️ 使用接口返回的ImageType [%s]: %s\n", file.Name(), imageType)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 使用文件名(不含扩展名)作为ImageType参数
|
|
|
|
|
+ imageType = strings.TrimSuffix(file.Name(), filepath.Ext(file.Name()))
|
|
|
|
|
+ fmt.Printf("🏷️ 使用默认ImageType [%s]: %s\n", file.Name(), imageType)
|
|
|
|
|
+ }
|
|
|
|
|
+ fileIndex++
|
|
|
|
|
+
|
|
|
|
|
+ validFiles = append(validFiles, BatchFileItem{
|
|
|
|
|
+ FilePath: filePath,
|
|
|
|
|
+ ImageType: imageType,
|
|
|
|
|
+ FileName: file.Name(),
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 如果没有有效文件,跳过
|
|
|
|
|
+ if len(validFiles) == 0 {
|
|
|
|
|
+ fmt.Printf("⚠️ 目录 %s 中没有有效的图片文件\n", path)
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("📦 开始批量上传 [%s]: 共 %d 个文件\n", parentDirName, len(validFiles))
|
|
|
|
|
+
|
|
|
|
|
+ // 批量上传该目录下的所有文件(一次性请求)
|
|
|
|
|
+ var response UploadSkuResponse
|
|
|
|
|
+ err = dh.uploadSkuImagesBatch(validFiles, parentDirName, &response)
|
|
|
|
|
+
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: false,
|
|
|
|
|
+ Message: fmt.Sprintf("[%s] 批量上传失败: %v", parentDirName, err),
|
|
|
|
|
+ Progress: 0,
|
|
|
|
|
+ })
|
|
|
|
|
+ fmt.Printf("❌ 批量上传失败: %v\n", err)
|
|
|
|
|
+ } else if !response.Success {
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: false,
|
|
|
|
|
+ Message: fmt.Sprintf("[%s] 批量上传失败: API返回错误 code=%d", parentDirName, response.Code),
|
|
|
|
|
+ Progress: 0,
|
|
|
|
|
+ })
|
|
|
|
|
+ fmt.Printf("❌ 批量上传失败: API返回错误 code=%d\n", response.Code)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: true,
|
|
|
|
|
+ Message: fmt.Sprintf("[%s] 批量上传成功: 共 %d 个文件", parentDirName, len(response.Data)),
|
|
|
|
|
+ Progress: 0,
|
|
|
|
|
+ })
|
|
|
|
|
+ fmt.Printf("✅ 批量上传成功: %+v\n", response)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 发送完成进度
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: false,
|
|
|
|
|
+ Message: fmt.Sprintf("处理失败: %v", err),
|
|
|
|
|
+ Progress: 100,
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ dh.sendProgress(ProcessResult{
|
|
|
|
|
+ Success: true,
|
|
|
|
|
+ Message: "所有文件处理完成",
|
|
|
|
|
+ Progress: 100,
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return err
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// uploadSkuImagesBatch 批量上传SKU图片(同一个Key下的多个文件一次性上传)
|
|
|
|
|
+func (dh *DirectoryHandler) uploadSkuImagesBatch(files []BatchFileItem, key string, result interface{}) error {
|
|
|
|
|
+ // 创建multipart表单
|
|
|
|
|
+ var buf bytes.Buffer
|
|
|
|
|
+ writer := multipart.NewWriter(&buf)
|
|
|
|
|
+
|
|
|
|
|
+ // 添加Key字段
|
|
|
|
|
+ err := writer.WriteField("Key", key)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("写入Key字段失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 添加多个ImageType和File字段对
|
|
|
|
|
+ for i, file := range files {
|
|
|
|
|
+ // 添加ImageType字段
|
|
|
|
|
+ err = writer.WriteField("ImageType", file.ImageType)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("写入ImageType字段失败 [%d]: %w", i, err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 打开文件
|
|
|
|
|
+ fileHandle, err := os.Open(file.FilePath)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("打开文件失败 [%s]: %w", file.FilePath, err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 添加文件字段
|
|
|
|
|
+ fileWriter, err := writer.CreateFormFile("File", file.FileName)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ fileHandle.Close()
|
|
|
|
|
+ return fmt.Errorf("创建表单文件字段失败 [%s]: %w", file.FileName, err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 复制文件内容到表单
|
|
|
|
|
+ _, err = io.Copy(fileWriter, fileHandle)
|
|
|
|
|
+ fileHandle.Close()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("复制文件内容失败 [%s]: %w", file.FileName, err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fmt.Printf("📤 已添加文件 [%d/%d]: %s (ImageType: %s)\n", i+1, len(files), file.FileName, file.ImageType)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 关闭表单写入器
|
|
|
|
|
+ err = writer.Close()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("关闭表单写入器失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 创建请求
|
|
|
|
|
+ req, err := http.NewRequestWithContext(dh.ctx, "POST", utils.UploadSkuImage, &buf)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("创建请求失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 设置内容类型为multipart表单
|
|
|
|
|
+ req.Header.Set("Content-Type", writer.FormDataContentType())
|
|
|
|
|
+
|
|
|
|
|
+ // 创建HTTP客户端并执行请求
|
|
|
|
|
+ client := &http.Client{}
|
|
|
|
|
+ resp, err := client.Do(req)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("请求失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ defer resp.Body.Close()
|
|
|
|
|
+
|
|
|
|
|
+ // 读取响应体
|
|
|
|
|
+ body, err := io.ReadAll(resp.Body)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return fmt.Errorf("读取响应体失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查HTTP状态码
|
|
|
|
|
+ if resp.StatusCode >= 400 {
|
|
|
|
|
+ return fmt.Errorf("HTTP请求失败 status=%d body=%s", resp.StatusCode, string(body))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 解析JSON响应
|
|
|
|
|
+ if err := json.Unmarshal(body, result); err != nil {
|
|
|
|
|
+ return fmt.Errorf("解析JSON失败: %w, body=%s", err, string(body))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return nil
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// getActionNamesByGoods 获取动作名称列表
|
|
|
|
|
+func (dh *DirectoryHandler) getActionNamesByGoods(goodsArtNo string) (*ActionNamesResponse, error) {
|
|
|
|
|
+ // 创建请求
|
|
|
|
|
+ url := fmt.Sprintf("%s?goods_art_no=%s", utils.GetActionNames, goodsArtNo)
|
|
|
|
|
+ req, err := http.NewRequestWithContext(dh.ctx, "GET", url, nil)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("创建请求失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 设置请求头
|
|
|
|
|
+ req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
+
|
|
|
|
|
+ // 创建HTTP客户端并执行请求
|
|
|
|
|
+ client := &http.Client{}
|
|
|
|
|
+ resp, err := client.Do(req)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("请求失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ defer resp.Body.Close()
|
|
|
|
|
+
|
|
|
|
|
+ // 读取响应体
|
|
|
|
|
+ body, err := io.ReadAll(resp.Body)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("读取响应体失败: %w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查HTTP状态码
|
|
|
|
|
+ if resp.StatusCode >= 400 {
|
|
|
|
|
+ return nil, fmt.Errorf("HTTP请求失败 status=%d body=%s", resp.StatusCode, string(body))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 解析JSON响应
|
|
|
|
|
+ var response ActionNamesResponse
|
|
|
|
|
+ if err := json.Unmarshal(body, &response); err != nil {
|
|
|
|
|
+ return nil, fmt.Errorf("解析JSON失败: %w, body=%s", err, string(body))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return &response, nil
|
|
|
|
|
+}
|