upload_pic.py 18 KB

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