directory.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. package handlers
  2. import (
  3. "context"
  4. "encoding/base64"
  5. "fmt"
  6. "github.com/wailsapp/wails/v2/pkg/runtime"
  7. "io"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. )
  12. // ProcessResult 处理结果结构体
  13. type ProcessResult struct {
  14. Success bool `json:"success"`
  15. Message string `json:"message"`
  16. Progress int `json:"progress"`
  17. }
  18. // ProcessCallback 处理过程回调函数类型
  19. type ProcessCallback func(result ProcessResult)
  20. type DirectoryHandler struct {
  21. ctx context.Context
  22. }
  23. func NewDirectoryHandler(ctx context.Context) *DirectoryHandler {
  24. return &DirectoryHandler{ctx: ctx}
  25. }
  26. // HandlerDirectory 处理目录复制的主要方法
  27. func (dh *DirectoryHandler) HandlerDirectory(sourceDir, targetDir string) error {
  28. // 检查源目录是否存在
  29. if _, err := os.Stat(sourceDir); os.IsNotExist(err) {
  30. return fmt.Errorf("源目录不存在: %s", sourceDir)
  31. }
  32. // 检查目标目录,如果不存在则创建
  33. if _, err := os.Stat(targetDir); os.IsNotExist(err) {
  34. // 源目录不存在时不需要创建目录,但目标目录可以创建
  35. err := os.MkdirAll(targetDir, os.ModePerm)
  36. if err != nil {
  37. return fmt.Errorf("创建目标目录失败: %v", err)
  38. }
  39. }
  40. // 执行具体的处理逻辑
  41. return dh.processDirectories(sourceDir, targetDir)
  42. }
  43. // processDirectories 实际处理目录的逻辑
  44. func (dh *DirectoryHandler) processDirectories(sourceDir, targetDir string) error {
  45. // 发送初始进度
  46. dh.sendProgress(ProcessResult{
  47. Success: true,
  48. Message: "开始处理目录...",
  49. Progress: 0,
  50. })
  51. // 遍历和处理逻辑
  52. err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
  53. if err != nil {
  54. dh.sendProgress(ProcessResult{
  55. Success: false,
  56. Message: fmt.Sprintf("访问路径出错: %v", err),
  57. Progress: 0,
  58. })
  59. return err
  60. }
  61. fmt.Printf("正在处理: %s\n", path)
  62. // 处理 800x800 目录的逻辑
  63. if info.IsDir() && strings.Contains(info.Name(), "800x800") {
  64. fmt.Printf("👍👍👍符合条件: %s\n", path)
  65. // 获取上级目录名称
  66. parentDirName := filepath.Base(filepath.Dir(path))
  67. // 在目标目录中创建以父目录命名的子目录
  68. newTargetDir := filepath.Join(targetDir, parentDirName)
  69. // 检查目标目录,如果不存在则创建
  70. if _, err := os.Stat(newTargetDir); os.IsNotExist(err) {
  71. // 源目录不存在时不需要创建目录,但目标目录可以创建
  72. err := os.MkdirAll(newTargetDir, os.ModePerm)
  73. if err != nil {
  74. return fmt.Errorf("创建目标目录失败: %v", err)
  75. }
  76. }
  77. dh.sendProgress(ProcessResult{
  78. Success: true,
  79. Message: fmt.Sprintf("找到目录: %s,将在目标目录创建子目录: %s", info.Name(), parentDirName),
  80. Progress: 50,
  81. })
  82. // 执行复制操作到新创建的子目录
  83. err := dh.copyFilesFromDir(path, newTargetDir)
  84. if err != nil {
  85. dh.sendProgress(ProcessResult{
  86. Success: false,
  87. Message: fmt.Sprintf("复制文件到:%v 失败: %v", newTargetDir, err),
  88. Progress: 50,
  89. })
  90. return err
  91. }
  92. }
  93. return nil
  94. })
  95. // 发送完成进度
  96. if err != nil {
  97. dh.sendProgress(ProcessResult{
  98. Success: false,
  99. Message: fmt.Sprintf("处理失败: %v", err),
  100. Progress: 100,
  101. })
  102. } else {
  103. dh.sendProgress(ProcessResult{
  104. Success: true,
  105. Message: "处理完成",
  106. Progress: 100,
  107. })
  108. }
  109. return err
  110. }
  111. // copyFilesFromDir 从指定目录复制所有文件到目标目录
  112. func (dh *DirectoryHandler) copyFilesFromDir(sourceDir, targetDir string) error {
  113. entries, err := os.ReadDir(sourceDir)
  114. if err != nil {
  115. return fmt.Errorf("读取目录失败 %s: %v", sourceDir, err)
  116. }
  117. for _, entry := range entries {
  118. // 只处理文件,跳过子目录
  119. if entry.IsDir() {
  120. continue // 忽略目录
  121. }
  122. // 检查是否为有效的图片文件
  123. if !dh.isValidImageFile(entry.Name()) {
  124. continue // 跳过非图片文件
  125. }
  126. sourcePath := filepath.Join(sourceDir, entry.Name())
  127. targetPath := filepath.Join(targetDir, entry.Name())
  128. err := dh.copyFile(sourcePath, targetPath)
  129. if err != nil {
  130. return fmt.Errorf("复制文件失败 %s 到 %s: %v", sourcePath, targetPath, err)
  131. }
  132. }
  133. return nil
  134. }
  135. // copyFile 复制单个文件
  136. func (dh *DirectoryHandler) copyFile(src, dst string) error {
  137. sourceFile, err := os.Open(src)
  138. if err != nil {
  139. return err
  140. }
  141. defer sourceFile.Close()
  142. // 创建目标文件
  143. destFile, err := os.Create(dst)
  144. if err != nil {
  145. return err
  146. }
  147. defer destFile.Close()
  148. // 复制文件内容
  149. _, err = io.Copy(destFile, sourceFile)
  150. if err != nil {
  151. return err
  152. }
  153. // 同步文件内容到磁盘
  154. return destFile.Sync()
  155. }
  156. // isValidImageFile 检查文件是否为有效的图片文件
  157. func (dh *DirectoryHandler) isValidImageFile(filename string) bool {
  158. validExtensions := []string{".avif", ".bmp", ".png", ".jpg", ".jpeg"}
  159. ext := strings.ToLower(filepath.Ext(filename))
  160. for _, validExt := range validExtensions {
  161. if ext == validExt {
  162. return true
  163. }
  164. }
  165. return false
  166. }
  167. type ImageResult struct {
  168. GoodsArtNo string `json:"goods_art_no"`
  169. ImagePath string `json:"image_path"`
  170. Category string `json:"category"`
  171. Description string `json:"description"`
  172. Price string `json:"price"`
  173. ImageBase64 string `json:"image_base64"`
  174. }
  175. // sendProgress 发送进度更新
  176. func (dh *DirectoryHandler) sendProgress(result ProcessResult) {
  177. runtime.EventsEmit(dh.ctx, "copy800-progress", result)
  178. }
  179. // HandlerOutPutDirectory 处理输出目录的主要方法
  180. func (dh *DirectoryHandler) HandlerOutPutDirectory(sourceDir string) ([]ImageResult, error) {
  181. // 检查源目录是否存在
  182. if _, err := os.Stat(sourceDir); os.IsNotExist(err) {
  183. return nil, fmt.Errorf("源目录不存在: %s", sourceDir)
  184. }
  185. var Results []ImageResult
  186. // 执行具体的处理逻辑
  187. // 遍历和处理逻辑
  188. err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
  189. if err != nil {
  190. return err
  191. }
  192. fmt.Printf("正在处理: %s\n", path)
  193. // 处理 800x800 目录的逻辑
  194. if info.IsDir() && strings.Contains(info.Name(), "800x800") {
  195. fmt.Printf("👍👍👍符合条件: %s\n", path)
  196. // 获取父目录名作为 goods_art_no
  197. parentDirName := filepath.Base(filepath.Dir(path))
  198. goodsArtNo := parentDirName
  199. // 查找该目录下的第一张有效图片
  200. imagePath, err := dh.findFirstImageInDir(path)
  201. if err == nil {
  202. toBase64, err := dh.ImageToBase64(imagePath)
  203. if err != nil {
  204. toBase64 = ""
  205. }
  206. // 添加到结果数组
  207. Results = append(Results, ImageResult{
  208. GoodsArtNo: goodsArtNo,
  209. ImagePath: imagePath,
  210. Description: "",
  211. Category: "",
  212. Price: "0",
  213. ImageBase64: toBase64,
  214. })
  215. }
  216. }
  217. return nil
  218. })
  219. if err != nil {
  220. return nil, err
  221. }
  222. return Results, nil
  223. }
  224. // findFirstImageInDir 查找目录下的第一张有效图片
  225. func (dh *DirectoryHandler) findFirstImageInDir(dirPath string) (string, error) {
  226. entries, err := os.ReadDir(dirPath)
  227. if err != nil {
  228. return "", fmt.Errorf("读取目录失败: %v", err)
  229. }
  230. for _, entry := range entries {
  231. if entry.IsDir() {
  232. continue
  233. }
  234. if dh.isValidImageFile(entry.Name()) {
  235. return filepath.Join(dirPath, entry.Name()), nil
  236. }
  237. }
  238. return "", fmt.Errorf("未找到有效图片文件")
  239. }
  240. // ImageToBase64 将图片文件转换为Base64编码
  241. func (dh *DirectoryHandler) ImageToBase64(imagePath string) (string, error) {
  242. // 读取图片文件
  243. fileData, err := os.ReadFile(imagePath)
  244. if err != nil {
  245. return "", fmt.Errorf("读取图片文件失败: %v", err)
  246. }
  247. // 获取文件的MIME类型
  248. mimeType := getMimeType(imagePath)
  249. // 将文件数据编码为Base64
  250. encoded := base64.StdEncoding.EncodeToString(fileData)
  251. // 返回带有数据URI方案的Base64字符串
  252. return fmt.Sprintf("data:%s;base64,%s", mimeType, encoded), nil
  253. }
  254. // getMimeType 根据文件扩展名获取MIME类型
  255. func getMimeType(filePath string) string {
  256. ext := strings.ToLower(filePath[strings.LastIndex(filePath, "."):])
  257. mimeTypes := map[string]string{
  258. ".png": "image/png",
  259. ".jpg": "image/jpeg",
  260. ".jpeg": "image/jpeg",
  261. ".gif": "image/gif",
  262. ".bmp": "image/bmp",
  263. ".webp": "image/webp",
  264. }
  265. if mime, exists := mimeTypes[ext]; exists {
  266. return mime
  267. }
  268. return "application/octet-stream"
  269. }
  270. // GetCurrentWorkingDirectory 获取当前工作目录
  271. func (dh *DirectoryHandler) GetCurrentWorkingDirectory() (string, error) {
  272. return os.Getwd()
  273. }
  274. // GetApplicationDirectory 获取应用程序所在目录
  275. func (dh *DirectoryHandler) GetApplicationDirectory() (string, error) {
  276. execPath, err := os.Executable()
  277. if err != nil {
  278. return "", err
  279. }
  280. return filepath.Dir(execPath), nil
  281. }