upload_pic.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. from import_qt_mode import *
  2. from module.view_control.generate_goods_no_detail_pic.data import DataModeUploadPic
  3. from module.view_control.MineQWidget import DialogShow, WorkerOneThread
  4. import os
  5. import threading
  6. import time
  7. import concurrent.futures
  8. import re
  9. from PIL import Image
  10. from io import BytesIO
  11. # 详情图上传
  12. class UploadPic(QObject):
  13. signal_data = Signal(dict)
  14. run_end_sign = Signal(dict)
  15. show_progress_detail_sign = Signal(str)
  16. def __init__(self, windows, to_deal_dir, config_data):
  17. super().__init__()
  18. self.windows = windows
  19. self.data_mode_upload_pic = DataModeUploadPic()
  20. self.goods_no_data = {}
  21. # ------------------
  22. # 0未选择文件,1已选文件未开始,2进行中
  23. self.state = 0
  24. self.state_change(self.state)
  25. self.to_deal_dir = to_deal_dir
  26. self.config_data = config_data
  27. def check_path(self, _path):
  28. if not os.path.exists(_path):
  29. os.mkdir(_path)
  30. return True
  31. def run_by_thread(self):
  32. self.run_by_thread_real()
  33. self.config_data["sign_text"] = "结束"
  34. self.run_end_sign.emit(self.config_data)
  35. def run(self):
  36. self._w_5 = WorkerOneThread(func=self.run_by_thread, name="_w_5")
  37. self._w_5.start()
  38. def run_by_thread_real(self, *args):
  39. self.show_info("====开始处理====")
  40. # 统计哪些需要处理
  41. total_num = 0
  42. flag = True
  43. # group_folders 分组文件夹
  44. for group_folders in os.listdir(self.to_deal_dir):
  45. path = "{}\{}".format(self.to_deal_dir, group_folders)
  46. if not os.path.isdir(path):
  47. continue
  48. for goods_no in os.listdir(path):
  49. # 检测是不是货号或款号文件夹
  50. goods_no_path = "{}\{}\{}".format(self.to_deal_dir, group_folders, goods_no)
  51. if not os.path.isdir(goods_no_path):
  52. continue
  53. total_num += 1
  54. # 检查每个款号文件夹是不是合规
  55. # 款的一级目录文件
  56. files = os.listdir(goods_no_path)
  57. if "details" not in files:
  58. continue
  59. for f in files:
  60. f_path = "{}\{}\{}\{}".format(self.to_deal_dir, group_folders, goods_no, f)
  61. if os.path.isdir(f_path):
  62. # 处理货号文件夹
  63. if "details" != f and "货号素材" not in f and "main" not in f and "拼接图" not in f:
  64. # 是否货号文件夹判断
  65. if not self.is_goods_art_dir(f, goods_no):
  66. self.show_info("{}文件夹下 {} {} 疑似不是货号".format(group_folders, goods_no, f))
  67. flag = False
  68. if not flag:
  69. self.show_info("请解决以上问题后重试")
  70. return
  71. if total_num == 0:
  72. self.show_info("没有任何款号文件夹 需要上传")
  73. return
  74. self.lock = threading.Lock()
  75. error_data = []
  76. n = 0
  77. for group_folders in os.listdir(self.to_deal_dir):
  78. path = "{}\{}".format(self.to_deal_dir, group_folders)
  79. if not os.path.isdir(path):
  80. continue
  81. for goods_no in os.listdir(path):
  82. goods_no_path = "{}\{}\{}".format(self.to_deal_dir, group_folders, goods_no)
  83. if not os.path.isdir(goods_no_path):
  84. self.show_info("{} 不是文件夹".format(goods_no))
  85. continue
  86. if goods_no in self.data_mode_upload_pic.is_deal_goods_no:
  87. continue
  88. else:
  89. self.data_mode_upload_pic.is_deal_goods_no.append(goods_no)
  90. # ================处理单个款号信息,图片上传处理============
  91. self.show_info("开始处理 {}".format(goods_no))
  92. try:
  93. if self.deal_goods_pic(goods_no, goods_no_path):
  94. # 移动文件到已完成
  95. # dest = "{}\{}\{}".format(self.is_deal_dir, group_folders, goods_no)
  96. # if os.path.exists(dest):
  97. # self.show_info("{} 文件夹在目标目录已存在".format(goods_no))
  98. # else:
  99. # shutil.move(goods_no_path, dest)
  100. self.show_info("{} 上传成功".format(goods_no))
  101. else:
  102. self.show_info("{} 处理失败".format(goods_no))
  103. error_data.append(goods_no)
  104. pass
  105. except BaseException as e:
  106. self.show_info("上传异常:{},{}".format(goods_no, e))
  107. # n += 1
  108. # self.show_info({"type": "show_p",
  109. # "data": int(n * 100 / total_num)})
  110. self.show_info("========已结束========== ")
  111. if error_data:
  112. self.show_info("以下编号/款号处理失败")
  113. for data in error_data:
  114. self.show_info("{}".format(data))
  115. # self.show_info({"type": "change_state",
  116. # "data": 2})
  117. def deal_goods_pic(self, goods_no, goods_no_path):
  118. """
  119. 两种模式:货号模式、编号模式
  120. :param goods_no:
  121. :param goods_no_path:
  122. :return:
  123. """
  124. print("==========开始上传系统=============")
  125. s = time.time()
  126. self.show_info("{} 开始上传 ".format(goods_no))
  127. if "NUM" in goods_no.upper():
  128. mode = "编号"
  129. else:
  130. mode = "货号"
  131. # 校验所有编号是否存在,是否是同个款
  132. _numbers = []
  133. if mode == "编号":
  134. _numbers.append(goods_no)
  135. self.goods_no_data[goods_no] = {}
  136. # 收集该款号下可能存在的货号或编号
  137. files = os.listdir(goods_no_path)
  138. if "details" not in files:
  139. self.show_info("{} 缺少details 文件夹".format(goods_no, ))
  140. return False
  141. for f in files:
  142. f_path = "{}\{}".format(goods_no_path, f)
  143. if os.path.isdir(f_path):
  144. if "details" != f and "货号素材" not in f and "main" not in f and "拼接图" not in f:
  145. if not self.is_goods_art_dir(f, goods_no):
  146. self.show_info("{} {} 疑似不是货号".format(goods_no, f))
  147. # return False
  148. continue
  149. else:
  150. _numbers.append(f)
  151. if "货号素材" in f:
  152. if "_" not in f:
  153. self.show_info("{} 货号素材文件夹 格式错误".format(goods_no))
  154. return False
  155. # 校验所有编号是否存在,是否是同个款
  156. if mode == "编号":
  157. _numbers = [x.replace("KNUM", "").replace("NUM", "") for x in _numbers]
  158. _numbers = list(set(_numbers))
  159. goods_number_data = self.data_mode_upload_pic.get_goods_art_no_info(numbers_list=_numbers)
  160. else:
  161. goods_number_data = self.data_mode_upload_pic.get_goods_art_no_info(goods_art_list=_numbers)
  162. t = True
  163. for num in _numbers:
  164. if num not in goods_number_data:
  165. t = False
  166. if mode == "编号":
  167. self.show_info("{} 编号在系统中不存在".format(num))
  168. else:
  169. self.show_info("{} 货号在系统中不存在".format(num))
  170. else:
  171. if self.config_data["upload_is_pass"]:
  172. if self.data_mode_upload_pic.check_is_uploaded(num):
  173. t = False
  174. self.show_info("{} 货号在系统已有详情页,已跳过".format(num))
  175. return True
  176. if not t:
  177. return False
  178. _ = set([goods_number_data[x]["款号"] for x in goods_number_data])
  179. if len(_) != 1:
  180. self.show_info("{} 存在多个不同的款号".format(_))
  181. return False
  182. # 重新定义款号
  183. goods_no = _.pop()
  184. # 上传所有图片
  185. self.pic_data = {}
  186. ignore_text = ["main", "拼接图", "货号素材"]
  187. _Type = ['.png', '.PNG', '.jpg', '.JPG', '.gif', '.GIF']
  188. for dirpath, dirnames, filenames in os.walk(goods_no_path):
  189. for file in filenames:
  190. if os.path.splitext(file)[1] in _Type:
  191. # 获取当前路径的文件夹名称
  192. f_path = dirpath + '/' + file
  193. f = True
  194. for i in ignore_text:
  195. if i in f_path:
  196. f = False
  197. break
  198. if f:
  199. print(f_path)
  200. f_path = f_path.replace("\\", "/")
  201. self.pic_data[f_path] = {"url": ""}
  202. with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
  203. for key in self.pic_data:
  204. if "货号素材" in key:
  205. # 货号素材图不上传
  206. is_resize = False
  207. continue
  208. else:
  209. is_resize = True
  210. executor.submit(self.to_upload_pic, file_path=key, is_resize=is_resize)
  211. for key in self.pic_data:
  212. if "货号素材" in key:
  213. is_resize = False
  214. continue
  215. if not self.pic_data[key]["url"]:
  216. self.show_info("{} {} 图片未上传完成".format(key, goods_no))
  217. return
  218. up_data = {"goods_art_no": [],
  219. "details": [],
  220. "goods_no": [],
  221. "goods_art_no_material": []
  222. }
  223. details_index = 0
  224. goods_no_index = 0
  225. # 款号转换
  226. # files 为当前款下的所有文件或文件夹
  227. for f in files:
  228. f_path = "{}\{}".format(goods_no_path, f)
  229. f_path = f_path.replace("\\", "/")
  230. # 如果为文件夹则
  231. if os.path.isdir(f_path):
  232. if "details" == f:
  233. # 处理详情图
  234. for pic in os.listdir(f_path):
  235. pic_path = "{}\{}".format(f_path, pic)
  236. pic_path = pic_path.replace("\\", "/")
  237. details_index += 1
  238. data = {
  239. "index": details_index,
  240. "name": goods_no,
  241. "number": goods_no,
  242. "status": "success",
  243. "type": "2", # 2 为详情图
  244. "uid": "",
  245. "url": self.pic_data[pic_path]["url"],
  246. }
  247. up_data["details"].append(data)
  248. pass
  249. elif "货号素材" in f:
  250. continue
  251. x = f.split("_")[0]
  252. if mode == "编号":
  253. x = f.replace("NUM", "")
  254. x = x.replace("_货号素材", "")
  255. goods_art_no = goods_number_data[x]["商品货号"]
  256. else:
  257. goods_art_no = x
  258. n = 0
  259. for pic in os.listdir(f_path):
  260. pic_path = "{}\{}".format(f_path, pic)
  261. pic_path = pic_path.replace("\\", "/")
  262. n += 1
  263. data = {
  264. "index": n,
  265. "name": goods_art_no,
  266. "number": goods_art_no,
  267. "status": "success",
  268. "type": "3",
  269. "uid": "",
  270. "url": self.pic_data[pic_path]["url"],
  271. }
  272. up_data["goods_art_no_material"].append(data)
  273. else:
  274. if "拼接图" in f:
  275. continue
  276. if "main" in f:
  277. continue
  278. # 处理货号图
  279. if mode == "编号":
  280. x = f.replace("NUM", "")
  281. goods_art_no = goods_number_data[x]["商品货号"]
  282. else:
  283. goods_art_no = f
  284. for pic in os.listdir(f_path):
  285. pic_path = "{}\{}".format(f_path, pic)
  286. pic_path = pic_path.replace("\\", "/")
  287. data = {
  288. "index": 1,
  289. "name": goods_art_no,
  290. "number": goods_art_no,
  291. "status": "success",
  292. "type": "0", # 0为货号图
  293. "uid": "",
  294. "url": self.pic_data[pic_path]["url"],
  295. }
  296. up_data["goods_art_no"].append(data)
  297. break
  298. else:
  299. # 处理款号图
  300. goods_no_index += 1
  301. data = {
  302. "index": goods_no_index,
  303. "name": goods_no,
  304. "number": goods_no,
  305. "status": "success",
  306. "type": "1",
  307. "uid": "",
  308. "url": self.pic_data[f_path]["url"],
  309. }
  310. up_data["goods_no"].append(data)
  311. pass
  312. # -----------上传数据-----------------
  313. # print(up_data["goods_no"])
  314. # print(up_data["goods_art_no_material"])
  315. # print(up_data["details"])
  316. # 上传图片
  317. for key, value in up_data.items():
  318. if value:
  319. if not self.data_mode_upload_pic.upload_pic_list_data(data={"images": value}):
  320. self.show_info("{} {}上传错误".format(goods_no, key))
  321. return False
  322. print("---{} {} 完成".format(goods_no, time.time() - s))
  323. return True
  324. def to_upload_pic(self, file_path, is_resize=True):
  325. file_name = os.path.split(file_path)[1]
  326. e = os.path.splitext(file_name)[1][1:]
  327. im = Picture(file_path)
  328. if im.x > 1200:
  329. im.resize(width=1200)
  330. # print(file_name, e)
  331. # if e == "png":
  332. # im.im.show()
  333. # return
  334. _ = {"jpg": "JPEG",
  335. "JPG": "JPEG",
  336. "JPEG": "JPEG",
  337. "jpeg": "JPEG",
  338. "png": "PNG",
  339. "PNG": "PNG", }
  340. e = _[e]
  341. image_io = im.save_to_io(e)
  342. # if is_resize:
  343. # im = Picture(file_path)
  344. # if im.x > 1200:
  345. # im.resize(width=1200)
  346. # image_io = im.save_to_io()
  347. # e = "JPEG"
  348. # else:
  349. # file_name = os.path.split(file_path)[1]
  350. # e = os.path.splitext(file_name)[0][1:]
  351. # image_io = open(file_path, 'rb')
  352. # image_io = open(file_path, 'rb')
  353. # self.lock.acquire()
  354. # self.pic_data[file_path]["url"] = "1111"
  355. # self.lock.release()
  356. # return
  357. goods_data = {"file_path": os.path.split(file_path)[1],
  358. "image_io": image_io,
  359. "e": e
  360. }
  361. url = self.data_mode_upload_pic.upload_pic(goods_data=goods_data)
  362. self.lock.acquire()
  363. self.pic_data[file_path]["url"] = url
  364. self.lock.release()
  365. def is_goods_art_dir(self, file, goods_no):
  366. if goods_no in file:
  367. return True
  368. # 判断是不是货号文件夹
  369. _r_text = re.findall("[a-zA-Z0-9]+", file)
  370. if _r_text:
  371. # print(_r_text)
  372. if _r_text[0] != file:
  373. # 文件夹中包含有非字母或数字判断不是货号
  374. return False
  375. else:
  376. return True
  377. else:
  378. # 非字母和数字 判断为非货号
  379. return False
  380. def show_info(self, text: str):
  381. self.show_progress_detail_sign.emit(text)
  382. # self.windows.show_progress_detail(text)
  383. def show_text_browser(self, text):
  384. pass
  385. def state_change(self, to_state: int):
  386. self.state = to_state
  387. class Picture:
  388. def __init__(self, in_path):
  389. self.im = Image.open(in_path)
  390. self.x, self.y = self.im.size
  391. # print(self.x, self.y)
  392. def resize(self, width):
  393. re_x = int(width)
  394. re_y = int(self.y * re_x / self.x)
  395. self.im = self.im.resize((re_x, re_y), Image.Resampling.LANCZOS)
  396. self.x, self.y = self.im.size
  397. def save_to_io(self, format):
  398. img = BytesIO()
  399. self.im.save(img, format=format) # format: PNG or JPEG
  400. img.seek(0) # rewind to the start
  401. return img