upload_pic.py 17 KB

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