run_main.py 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. import settings
  2. from module.view_control.generate_goods_no_detail_pic import detail_func
  3. import json
  4. from base import *
  5. from import_qt_mode import *
  6. from module.view_control.match_and_cutout_mode_control.base_deal_image_v2 import BaseDealImage
  7. from module.view_control.MineQWidget import DialogShow, WorkerOneThread
  8. import threading
  9. from concurrent.futures import ThreadPoolExecutor
  10. import concurrent.futures
  11. from module.view_control.generate_goods_no_detail_pic.data import DataModeGenerateDetail, DataModeUploadPic
  12. from module.view_control.generate_goods_no_detail_pic.detail_func import create_folder
  13. import time
  14. from PIL import Image
  15. from io import BytesIO
  16. import os, re
  17. from functools import partial
  18. # from multiprocessing import Process, Queue
  19. import pickle
  20. from base_deal import BaseDealImage
  21. class RunMain(QThread):
  22. run_end_sign = Signal(dict)
  23. show_dialog_sign = Signal(dict)
  24. show_progress_detail_sign = Signal(str)
  25. # 定义一个信号用于请求显示对话框
  26. show_dialog_signal = Signal()
  27. # 定义一个信号用于返回对话框的结果
  28. dialog_result_signal = Signal(str)
  29. # dialog_result_signal = Signal(str)
  30. def __init__(self, windows):
  31. super().__init__()
  32. self.windows = windows
  33. self.dialog_result = ""
  34. self.data_mode_generate_detail = DataModeGenerateDetail()
  35. self.dialog_result_signal.connect(self.on_dialog_result)
  36. self.event = threading.Event()
  37. def set_state(self, state_value: int):
  38. # 0禁用 1进行中 2已结束
  39. if state_value not in [0, 1, 2, 99]:
  40. return
  41. # self.windows.change_state_sign.emit(state_value)
  42. # self.windows.set_state(state_value)
  43. # 抠图前先做数据规整处理;类似详情图生成逻辑
  44. def check_before_cutout(self, config_data):
  45. return_data = {
  46. "code": 99,
  47. "message": "",
  48. "data": {
  49. "all_goods_art_no_folder_data": [],
  50. "config_data": config_data,
  51. },
  52. }
  53. image_dir = config_data["image_dir"]
  54. image_order = config_data["image_order"]
  55. is_check_number = config_data["is_check_number"]
  56. is_filter = config_data["cutout_is_pass"]
  57. resize_image_view = config_data["resize_image_view"]
  58. logo_path = config_data["logo_path"]
  59. cutout_mode = config_data["cutout_mode"] # 是否精细化抠图,默认为普通抠图
  60. special_goods_art_no_folder_line = config_data["special_goods_art_no_folder_line"]
  61. # 自动处理红蜻蜓货号,进行重命名
  62. if settings.PROJECT == "红蜻蜓":
  63. # 规整红蜻蜓货号图
  64. all_goods_art_no_folder_data = get_all_goods_art_no_folder(path=image_dir)
  65. BaseDealImage().rename_folder_for_hqt(all_goods_art_no_folder_data=all_goods_art_no_folder_data)
  66. # 重新获取文件夹信息
  67. all_goods_art_no_folder_data = get_all_goods_art_no_folder(path=image_dir)
  68. f = True
  69. is_do_other = False
  70. if is_do_other:
  71. for i in all_goods_art_no_folder_data:
  72. i["label"] = "不处理"
  73. is_filter = False
  74. specified_goods_art_no_folder = special_goods_art_no_folder_line
  75. specified_goods_art_no_folder = specified_goods_art_no_folder.strip()
  76. specified_goods_art_no_folder = specified_goods_art_no_folder.replace(",", ",")
  77. specified_goods_art_no_folder_list = specified_goods_art_no_folder.split(",")
  78. specified_goods_art_no_folder_list = [x for x in specified_goods_art_no_folder_list if x]
  79. if not specified_goods_art_no_folder_list:
  80. return_data["message"] += '请手动输入文件夹名称(多选),或关闭指定文件夹模式\n'
  81. else:
  82. for i in all_goods_art_no_folder_data:
  83. if i["folder_path"] in specified_goods_art_no_folder_list:
  84. i["label"] = "待处理"
  85. # 哪些数据不合规
  86. all_folder_name_list = [x["folder_name"] for x in all_goods_art_no_folder_data]
  87. for goods_art_no_folder_name in specified_goods_art_no_folder_list:
  88. if goods_art_no_folder_name not in all_folder_name_list:
  89. return_data["message"] += '文件夹:{},在您选的目录下不存在\n'.format(goods_art_no_folder_name)
  90. f = False
  91. if not f:
  92. self.set_state(state_value=2)
  93. return
  94. # 清空指定文件夹的已抠图文件
  95. if is_do_other:
  96. for folder_data in all_goods_art_no_folder_data:
  97. goods_art_no_folder_path = "{}/原始图_已抠图".format(folder_data["folder_path"])
  98. if os.path.exists(goods_art_no_folder_path):
  99. remove_all_file(goods_art_no_folder_path)
  100. return_data["data"]["succeed_folder_list"] = 1
  101. # ==================检查填写的图片视角是否符合要求
  102. res = BaseDealImage().getImageOrder(image_order=image_order, resize_image_view=resize_image_view)
  103. if res['code'] != 0:
  104. return_data["message"] += "{}\n".format(res['msg'])
  105. return return_data
  106. else:
  107. # 图片命名顺序
  108. image_order_list = res['imageOrderList']
  109. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  110. if goods_art_no_folder_data["label"] != "待处理":
  111. continue
  112. goods_art_no_folder_data["image_order_list"] = image_order_list
  113. # ================是否过滤已有生成的文件夹
  114. if is_filter:
  115. for goods_art_no_folder_data in all_goods_art_no_folder_data:
  116. if goods_art_no_folder_data["label"] != "待处理":
  117. continue
  118. folder_path = goods_art_no_folder_data["folder_path"]
  119. _p = "{}/800x800".format(folder_path)
  120. if os.path.exists(_p):
  121. if len(os.listdir(_p)):
  122. goods_art_no_folder_data["label"] = "不处理"
  123. # ================检查每个货号文件夹图片数量是否符合要求
  124. all_goods_art_no_folder_data, message = BaseDealImage().check_folders_image_amount(all_goods_art_no_folder_data,
  125. image_order_list)
  126. if message:
  127. return_data["message"] += "{}\n".format(message)
  128. return_data["code"] = 0
  129. return_data["data"]["all_goods_art_no_folder_data"] = all_goods_art_no_folder_data
  130. return_data["data"]["image_dir"] = image_dir
  131. return_data["data"]["resize_image_view"] = resize_image_view
  132. return_data["data"]["cutout_mode"] = cutout_mode
  133. return_data["data"]["image_order_list"] = image_order_list
  134. return_data["data"]["logo_path"] = logo_path
  135. return return_data
  136. # 抠图校验后的回调函数处理
  137. def check_for_cutout_image_first_call_back(self, return_data):
  138. # return_data = {
  139. # "code": 99,
  140. # "message": "",
  141. # "data": {
  142. # "all_goods_art_no_folder_data": [],
  143. # },
  144. # }
  145. code = return_data["code"]
  146. config_data = return_data["data"]["config_data"]
  147. config_data["sign_text"] = ""
  148. # if code != 0:
  149. # # self.windows.show_message(return_data["message"])
  150. # # self.show_progress_detail(return_data["message"])
  151. # _dialog_dict = {"text": return_data["message"],
  152. # "windows": self,
  153. # }
  154. # self.show_dialog_sign.emit(_dialog_dict)
  155. # self.event.wait()
  156. # return
  157. do_next = False
  158. text = ""
  159. all_goods_art_no_folder_data = return_data["data"]["all_goods_art_no_folder_data"]
  160. button_1, button_2, button_3 = None, None, None
  161. text += return_data["message"]
  162. # 存在错误文件夹
  163. error_folder = [x for x in all_goods_art_no_folder_data if x["label"] == "错误"]
  164. todo_folder = [x for x in all_goods_art_no_folder_data if x["label"] == "待处理"]
  165. if error_folder:
  166. button_2 = "移除错误文件"
  167. if error_folder and todo_folder:
  168. button_1 = "移除并继续"
  169. button_3 = "继续(忽略其他)"
  170. if not error_folder and todo_folder:
  171. button_1 = "继续"
  172. # do_next = True
  173. text += "\n==================\n错误数据:{}个,校验无误数据:{}个".format(len(error_folder), len(todo_folder))
  174. self.show_progress_detail(text)
  175. if button_1 is None and button_2 is None and button_3 is None:
  176. pass
  177. elif button_1 == "继续" and button_2 is None and button_3 is None:
  178. do_next = True
  179. else:
  180. # print("runmain 179----------------")
  181. # # print(self)
  182. # # print(self.windows)
  183. # _dialog_dict = {"text": text,
  184. # "button_1": button_1,
  185. # "button_2": button_2,
  186. # "button_3": button_3,
  187. # "windows": self,
  188. # }
  189. # self.show_dialog_sign.emit(_dialog_dict)
  190. # # self.exec_()
  191. # # 等待事件被设置
  192. # self.event.wait()
  193. # print("self.dialog_result", self.dialog_result)
  194. # #
  195. # # my_dialog = DialogShow(self.windows, text=text, button_1=button_1, button_2=button_2,
  196. # # button_3=button_3)
  197. # # ret = my_dialog.exec()
  198. # print("460 ===============my_dialog.flag_name===============")
  199. # print(my_dialog.flag_name)
  200. if "移除" in self.dialog_result:
  201. for error_folder_data in [x for x in all_goods_art_no_folder_data if x["label"] == "错误"]:
  202. self.move_error_folders(
  203. one_path=error_folder_data["folder_path"],
  204. target_folder="{}/软件-处理失败".format(config_data["image_dir"]),
  205. )
  206. if "继续" in self.dialog_result:
  207. do_next = True
  208. if do_next:
  209. all_goods_art_no_folder_data = [x for x in all_goods_art_no_folder_data if x["label"] == "待处理"]
  210. print("===============all_goods_art_no_folder_data===============")
  211. print(all_goods_art_no_folder_data)
  212. new_func = partial(self.do_run_cutout_image,
  213. all_goods_art_no_folder_data=all_goods_art_no_folder_data,
  214. callback_func=self.show_progress_detail,
  215. image_order_list=return_data["data"]["image_order_list"],
  216. cutout_mode=return_data["data"]["cutout_mode"],
  217. resize_image_view=return_data["data"]["resize_image_view"],
  218. windows=self.windows,
  219. logo_path=return_data["data"]["logo_path"],
  220. config_data=config_data)
  221. self._w_3 = WorkerOneThread(func=new_func, name="_w_3")
  222. self._w_3.start()
  223. # self.t = threading.Thread(target=self.do_run_cutout_image,
  224. # kwargs={"all_goods_art_no_folder_data": all_goods_art_no_folder_data,
  225. # "callback_func": self.show_progress_detail,
  226. # "image_order_list": return_data["data"]["image_order_list"],
  227. # "cutout_mode": return_data["data"]["cutout_mode"],
  228. # "resize_image_view": return_data["data"]["resize_image_view"],
  229. # "windows": self.windows,
  230. # "logo_path": return_data["data"]["logo_path"],
  231. # "config_data": config_data,
  232. # })
  233. # self.t.start()
  234. else:
  235. config_data["sign_text"] = "已结束抠图处理"
  236. self.run_end_sign.emit(config_data)
  237. def do_run_cutout_image(self,
  238. all_goods_art_no_folder_data,
  239. callback_func,
  240. image_order_list,
  241. cutout_mode,
  242. resize_image_view,
  243. windows,
  244. logo_path,
  245. config_data):
  246. BaseDealImage().run_main(all_goods_art_no_folder_data=all_goods_art_no_folder_data,
  247. callback_func=callback_func,
  248. image_order_list=image_order_list,
  249. cutout_mode=cutout_mode,
  250. resize_image_view=resize_image_view,
  251. windows=windows,
  252. logo_path=logo_path,
  253. )
  254. # ==============完成处理==============
  255. # self.set_state(state_value=2)
  256. callback_func("已结束抠图处理")
  257. config_data["sign_text"] = "已结束抠图处理"
  258. self.run_end_sign.emit(config_data)
  259. def do_run_cutout_image1111(self, all_goods_art_no_folder_data,
  260. callback_func,
  261. image_order_list,
  262. cutout_mode,
  263. resize_image_view,
  264. windows,
  265. logo_path,
  266. config_data):
  267. max_workers = 1
  268. with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
  269. futures = []
  270. futures.append(executor.submit(
  271. BaseDealImage().run_main,
  272. all_goods_art_no_folder_data=all_goods_art_no_folder_data,
  273. callback_func=callback_func,
  274. image_order_list=image_order_list,
  275. cutout_mode=cutout_mode,
  276. resize_image_view=resize_image_view,
  277. windows=windows,
  278. logo_path=logo_path,
  279. ))
  280. # 使用 wait 方法等待所有任务完成
  281. done, not_done = concurrent.futures.wait(futures, timeout=60)
  282. # 处理完成的任务
  283. for future in done:
  284. if settings.IS_TEST:
  285. result = future.result()
  286. else:
  287. try:
  288. result = future.result()
  289. except BaseException as e:
  290. print("2039 图片处理失败.{}".format(e))
  291. callback_func("2039 处理失败.{}".format(e))
  292. # ==============完成处理==============
  293. # self.set_state(state_value=2)
  294. callback_func("已结束抠图处理")
  295. config_data["sign_text"] = "已结束抠图处理"
  296. self.run_end_sign.emit(config_data)
  297. def check_before_detail(self, config_data):
  298. # =============
  299. # 整体数据校验,返回错误内容,以及
  300. # temp_name:模板名称
  301. """
  302. 步骤:
  303. 1、 整体文件夹检查,并输出数据结构
  304. 2、数据进行对应规整(可能有excel,红蜻蜓等)
  305. 3、执行单个款数据处理
  306. """
  307. return_data = {
  308. "code": 99,
  309. "message": "",
  310. "data": {
  311. "error_folder_list": [],
  312. "goods_no_dict": {},
  313. "succeed_folder_list": [],
  314. "temp_name": config_data["temp_name"],
  315. "temp_name_list": config_data["temp_name_list"],
  316. "assigned_page_dict": config_data["assigned_page_dict"],
  317. "excel_temp_goods_no_data": {}, # 表格数据可能存在多模板,数据结构为一个款号下的多个模板的数据列表
  318. "finally_goods_no_need_temps": {}, # 每个款号需要生成的模板数据
  319. "config_data": config_data,
  320. },
  321. }
  322. temp_name = config_data["temp_name"]
  323. temp_name_list = config_data["temp_name_list"]
  324. assigned_page_dict = config_data["assigned_page_dict"]
  325. image_dir = config_data["image_dir"]
  326. is_use_excel = config_data["is_use_excel"]
  327. excel_path = config_data["excel_path"]
  328. temp_class = config_data["temp_class"]
  329. is_check_color_is_all = config_data["is_check_color_is_all"]
  330. detail_is_pass = config_data["detail_is_pass"]
  331. error_folder_list = []
  332. # 遍历货号获取所有货号--可能为编号
  333. folder_name_list = detail_func.get_all_dir_info(image_dir=image_dir)
  334. if not folder_name_list:
  335. return_data["message"] += "不存在任何货号/编号文件夹\n"
  336. print("不存在任何货号/编号文件夹")
  337. return return_data
  338. # =========================组装数据---数据来源多种途径=========================
  339. _result = {"code": 99, "message": "无法解析到数据,请检查登录企业"}
  340. if not is_use_excel:
  341. if settings.PROJECT == "红蜻蜓":
  342. # goods_no_dict输出为文件夹下涉及到的所有款为key的字典,后续通过解析字典,进行提取对应文件夹
  343. _result = self.data_mode_generate_detail.get_basic_goods_art_data_by_hqt_and_hlm(
  344. folder_name_list
  345. )
  346. elif settings.PROJECT == "惠利玛":
  347. if settings.Company:
  348. if "惠利玛" in settings.Company:
  349. _result = self.data_mode_generate_detail.get_basic_goods_art_data_by_hqt_and_hlm(
  350. folder_name_list
  351. )
  352. else:
  353. keys = settings.keys
  354. _result = (
  355. self.data_mode_generate_detail.get_basic_goods_art_data_form_excel(
  356. folder_name_list,
  357. excel_path,
  358. keys,
  359. )
  360. )
  361. if _result["code"] == 0:
  362. remote_data = _result["data"]
  363. else:
  364. return_data["message"] += _result["message"] + "\n"
  365. return return_data
  366. # print(json.dumps(remote_data))
  367. # =========================拼接数据组合为款数据=========================
  368. """
  369. 1、获取所有文件夹基础数据内容
  370. 2、结合上述返回结果进行数据组合拼接
  371. 3、输出结果为按款为主键信息
  372. 4、注意模板ID
  373. """
  374. # 获取所有文件夹基础数据内容 检查不满足要求的文件不满足要求移动到错误文件夹
  375. need_view_list = temp_class[temp_name].need_view
  376. _all_dir_info_data = detail_func.get_all_dir_info_and_pic_info(
  377. image_dir, folder_name_list, need_view_list
  378. )
  379. all_dir_info_data = {}
  380. for one_folder, value in _all_dir_info_data.items():
  381. if "message" in value:
  382. if value["message"]:
  383. error_folder_list.append(
  384. {
  385. "folder_name": one_folder,
  386. "folder_path": "{}/{}".format(image_dir, one_folder),
  387. }
  388. )
  389. return_data["message"] += "文件夹:{} 结构错误:{}\n".format(
  390. one_folder, value["message"]
  391. )
  392. continue
  393. # 符合要求的数据处理
  394. all_dir_info_data[one_folder] = value
  395. # 结合上述返回结果进行数据组合拼接
  396. # 返回可能存在的情况:1、存在文件夹不匹配数据,2、存在货号数据缺失
  397. goods_no_dict, error_folder_name_list = detail_func.merge_local_and_remote_data(
  398. all_dir_info_data=all_dir_info_data, remote_data=remote_data
  399. )
  400. # 文件在系统中没有匹配的结果
  401. if error_folder_name_list:
  402. for one_folder in error_folder_name_list:
  403. error_folder_list.append(
  404. {
  405. "folder_name": one_folder,
  406. "folder_path": "{}/{}".format(image_dir, one_folder),
  407. }
  408. )
  409. return_data["message"] += "文件夹:{} 找不到对应数据\n".format(
  410. one_folder
  411. )
  412. print("===============goods_no_dict==================")
  413. if settings.IS_TEST:
  414. _text = json.dumps(goods_no_dict)
  415. print(goods_no_dict)
  416. create_folder("qt_test")
  417. with open("qt_test/goods_no_dict.txt", 'w', encoding='utf-8') as file:
  418. file.write(_text)
  419. print("===============goods_no_dict==================")
  420. # ===================================是否齐色检查=============================================
  421. # 如为红蜻蜓企业则还需要检查同款下是否齐全;数据返回结果为款号列表
  422. error_data_dict = {}
  423. if is_check_color_is_all:
  424. if not is_use_excel:
  425. if settings.PROJECT == "红蜻蜓":
  426. error_data_dict = (
  427. self.data_mode_generate_detail.check_goods_is_not_deficiency(
  428. goods_no_dict
  429. )
  430. )
  431. else:
  432. error_data_dict = self.data_mode_generate_detail.check_goods_is_not_deficiency_form_excel(
  433. goods_no_dict, excel_path
  434. )
  435. if error_data_dict:
  436. print("----error_data_dict----")
  437. print(json.dumps(error_data_dict))
  438. # 款号反向映射;因为部分key键格式为KUM9999999
  439. _x = {}
  440. for i, v in goods_no_dict.items():
  441. _x[v["款号"]] = i
  442. for goods_no, value in error_data_dict.items():
  443. if goods_no in _x:
  444. goods_no = _x[goods_no]
  445. if goods_no in goods_no_dict:
  446. # =====移动到错误文件夹======
  447. for _folder_name in [
  448. x["文件夹名称"] for x in goods_no_dict[goods_no]["货号资料"]
  449. ]:
  450. error_folder_list.append(
  451. {
  452. "folder_name": _folder_name,
  453. "folder_path": "{}\{}".format(
  454. image_dir, _folder_name
  455. ),
  456. }
  457. )
  458. return_data["message"] += "文件夹:{};{}\n".format(
  459. _folder_name, value["message"]
  460. )
  461. # 从 正确 款下面进行数据剔除
  462. goods_no_dict.pop(goods_no)
  463. print("-----------------1goods_no_dict---------------")
  464. print(json.dumps(goods_no_dict, ensure_ascii=False))
  465. print("-----------------1goods_no_dict---------------")
  466. # 如果没有有效数据则进行退出
  467. if not goods_no_dict:
  468. return_data["message"] += "没有任何有效数据\n"
  469. return return_data
  470. # 校验无误的文件夹数据 goods_no_dict为最终有效数据
  471. for goods_no, value in goods_no_dict.items():
  472. return_data["data"]["succeed_folder_list"].extend(
  473. [x["文件夹名称"] for x in goods_no_dict[goods_no]["货号资料"]]
  474. )
  475. # 如果是表格数据,则获取表格数据中需要生成的货号
  476. # 数据结构
  477. # {“款号1”:
  478. # {“模板名称1”:data_dict1,
  479. # “模板名称2”:data_dict2,
  480. # }}
  481. if is_use_excel:
  482. excel_temp_goods_no_data = self.data_mode_generate_detail.get_basic_template_information(
  483. _goods_no_dict=goods_no_dict, excel_path=excel_path)
  484. else:
  485. excel_temp_goods_no_data = {}
  486. print("731===================excel_temp_goods_no_data,is_use_excel:{}".format(is_use_excel))
  487. print(json.dumps(excel_temp_goods_no_data))
  488. # ===========数据组装,统计每个款需要生成哪些模板==============
  489. # 不适用表格指定模板
  490. goods_no_need_temps = {}
  491. # isUseTemplate 为false 表示使用excel表格数据
  492. if not is_use_excel:
  493. for i in goods_no_dict:
  494. goods_no_need_temps[i] = [temp_name]
  495. else:
  496. for i in goods_no_dict:
  497. # i 为款号
  498. if i in excel_temp_goods_no_data:
  499. # 获取 某个款号的所有允许生成的模板列表
  500. goods_no_need_temps[i] = list(excel_temp_goods_no_data[i].keys())
  501. # ========开始执行详情图生成===================
  502. # _goods_no_dict = goods_no_dict
  503. _goods_no_dict = {}
  504. # assigned_page_dict 如存在对应模板的,则不管是否有过滤都需要生成
  505. # 检查是否已存在模板,已存在的需要进行跳过;可能部分模板已存在,部分不存在。
  506. finally_goods_no_need_temps = {}
  507. for goods_no, value in goods_no_dict.items():
  508. if goods_no not in goods_no_need_temps:
  509. continue
  510. for __temp_name in goods_no_need_temps[goods_no]:
  511. _path = "{}/{}/{}/{}".format(image_dir, "软件-详情图生成", __temp_name, goods_no)
  512. if not os.path.exists(_path):
  513. print("款号详情图不存在", _path)
  514. if goods_no not in finally_goods_no_need_temps:
  515. finally_goods_no_need_temps[goods_no] = []
  516. _goods_no_dict[goods_no] = value # 需要生成的数据
  517. finally_goods_no_need_temps[goods_no].append(__temp_name)
  518. else:
  519. print("款号详情图存在", _path)
  520. # 如果在指定模板中存在,则也需要生成
  521. if __temp_name in assigned_page_dict:
  522. print("指定模板需要更新", _path)
  523. if goods_no not in finally_goods_no_need_temps:
  524. finally_goods_no_need_temps[goods_no] = []
  525. _goods_no_dict[goods_no] = value # 需要生成的数据
  526. finally_goods_no_need_temps[goods_no].append(__temp_name)
  527. else:
  528. if detail_is_pass:
  529. return_data["message"] += "\n款号:{},模板:{} 已存在".format(goods_no, __temp_name)
  530. else:
  531. if goods_no not in finally_goods_no_need_temps:
  532. finally_goods_no_need_temps[goods_no] = []
  533. _goods_no_dict[goods_no] = value # 需要生成的数据
  534. finally_goods_no_need_temps[goods_no].append(__temp_name)
  535. pass
  536. # _path = "{}/{}".format(self.image_dir, "软件-详情图生成")
  537. # if os.path.exists(_path):
  538. # _goods_no_dict = {}
  539. # # 数据返回为 已有的款数据,为款号列表
  540. # is_pass_goods_no = detail_func.get_all_detail_info(_path)
  541. # for goods_no, value in goods_no_dict.items():
  542. # if "软件" in goods_no:
  543. # continue
  544. #
  545. # if value["模板名称"] in assigned_page_dict:
  546. # need_todo = True
  547. # else:
  548. # if goods_no in is_pass_goods_no:
  549. # need_todo = False
  550. # else:
  551. # need_todo = True
  552. # if need_todo:
  553. # _goods_no_dict[goods_no] = value
  554. print("-----------------2goods_no_dict---------------")
  555. print(json.dumps(_goods_no_dict, ensure_ascii=False))
  556. print("-----------------2goods_no_dict---------------")
  557. return_data["data"]["error_folder_list"] = error_folder_list
  558. if len(_goods_no_dict) == 0:
  559. return_data["message"] += "\n没有任何文件夹需要执行"
  560. return_data["data"]["goods_no_dict"] = _goods_no_dict
  561. return_data["data"]["excel_temp_goods_no_data"] = excel_temp_goods_no_data
  562. return_data["data"]["finally_goods_no_need_temps"] = finally_goods_no_need_temps
  563. return_data["code"] = 0
  564. return return_data
  565. def move_error_folders(self, one_path, target_folder, message=""):
  566. if os.path.exists(one_path):
  567. check_path(target_folder)
  568. move_folders(path_list=[one_path], target_folder=target_folder)
  569. def check_for_detail_first_call_back(self, data):
  570. # 首次数据校验的信息返回
  571. # self.show_message(text="22222222222222222222222")
  572. # QMessageBox.critical(self, "警告", "1111111", QMessageBox.Ok)
  573. code = data["code"]
  574. config_data = data["data"]["config_data"]
  575. target_error_folder = config_data["target_error_folder"]
  576. print("635 check_for_detail_first_call_back")
  577. print(data)
  578. if code != 0:
  579. # self.windows.show_message(data["message"])
  580. # my_dialog = DialogShow(self.windows.windows, text=data["message"])
  581. # ret = my_dialog.exec()
  582. self.show_progress_detail(text=data["message"])
  583. _dialog_dict = {"text": data["message"],
  584. "windows": self,
  585. }
  586. self.show_dialog_sign.emit(_dialog_dict)
  587. self.event.wait()
  588. # self.windows.set_state(2)
  589. config_data["sign_text"] = "已结束详情处理"
  590. self.run_end_sign.emit(config_data)
  591. return
  592. do_next = False
  593. if data["message"]:
  594. button_1, button_2, button_3 = None, None, None
  595. text = data["message"]
  596. if code == 0:
  597. if data["data"]:
  598. if data["data"]["error_folder_list"]:
  599. print("22----------error_folder_list------------")
  600. print(json.dumps(data["data"]["error_folder_list"]))
  601. button_2 = "移除错误文件"
  602. if data["data"]["goods_no_dict"]:
  603. if button_2:
  604. button_1 = "移除并继续"
  605. button_3 = "继续(忽略其他)"
  606. else:
  607. button_1 = "继续"
  608. if data["data"]["succeed_folder_list"]:
  609. text += "\n==================\n校验无误数据:{}个文件夹".format(
  610. len(data["data"]["succeed_folder_list"])
  611. )
  612. self.show_progress_detail(text=data["message"])
  613. if button_1 is None and button_2 is None and button_3 is None:
  614. pass
  615. elif button_1 == "继续" and button_2 is None and button_3 is None:
  616. do_next = True
  617. else:
  618. print("runmain 642----------------")
  619. # todo 弹框修改处理等
  620. _dialog_dict = {"text": text,
  621. "button_1": button_1,
  622. "button_2": button_2,
  623. "button_3": button_3,
  624. "windows": self,
  625. }
  626. self.show_dialog_sign.emit(_dialog_dict)
  627. # 等待事件被设置
  628. self.event.wait()
  629. print("self.dialog_result", self.dialog_result)
  630. # my_dialog = DialogShow(
  631. # self.windows, text=text, button_1=button_1, button_2=button_2, button_3=button_3
  632. # )
  633. print("my_dialog.flag_name", self.dialog_result)
  634. if "移除" in self.dialog_result:
  635. for error_folder_data in data["data"]["error_folder_list"]:
  636. self.move_error_folders(
  637. one_path=error_folder_data["folder_path"],
  638. target_folder=target_error_folder,
  639. )
  640. if "继续" in self.dialog_result:
  641. do_next = True
  642. if data["data"]["goods_no_dict"] and not data["data"]["error_folder_list"]:
  643. do_next = True
  644. if do_next:
  645. # self.set_state(state_value=1)
  646. getAllData = data["data"]
  647. base_temp_name = getAllData["temp_name"]
  648. set_temp_name = getAllData.get("template_name", "")
  649. kwargs = {
  650. "config_data": config_data,
  651. "_goods_no_dict": data["data"]["goods_no_dict"],
  652. "temp_name": base_temp_name,
  653. "temp_name_list": data["data"]["temp_name_list"],
  654. "assigned_page_dict": data["data"]["assigned_page_dict"],
  655. "excel_temp_goods_no_data": data["data"]["excel_temp_goods_no_data"],
  656. # 表格数据可能存在多模板,数据结构为一个款号下的多个模板的数据列表
  657. "finally_goods_no_need_temps": data["data"]["finally_goods_no_need_temps"], # 每个款号需要生成的模板数据
  658. }
  659. # todo work
  660. new_func = partial(self.detail_run_by_thread,
  661. config_data=kwargs["config_data"],
  662. _goods_no_dict=kwargs["_goods_no_dict"],
  663. temp_name=kwargs["temp_name"],
  664. temp_name_list=kwargs["temp_name_list"],
  665. assigned_page_dict=kwargs["assigned_page_dict"],
  666. excel_temp_goods_no_data=kwargs["excel_temp_goods_no_data"],
  667. finally_goods_no_need_temps=kwargs["finally_goods_no_need_temps"])
  668. self._w_3 = WorkerOneThread(func=new_func, name="_w_3")
  669. self._w_3.start()
  670. # threading.Thread(target=self.detail_run_by_thread, kwargs=kwargs).start()
  671. else:
  672. config_data["sign_text"] = "已结束详情处理"
  673. self.run_end_sign.emit(config_data)
  674. def detail_run_by_thread(self, config_data, _goods_no_dict, temp_name, temp_name_list, assigned_page_dict,
  675. excel_temp_goods_no_data,
  676. finally_goods_no_need_temps):
  677. """
  678. excel_temp_goods_no_data: {}, # 表格数据可能存在多模板,数据结构为一个款号下的多个模板的数据列表
  679. finally_goods_no_need_temps: {}, # 每个款号需要生成的模板数据
  680. """
  681. # 开始处理
  682. self.n = 0
  683. self.total_num = len(_goods_no_dict)
  684. self.fail_num = 0
  685. is_use_excel = config_data["is_use_excel"]
  686. image_dir = config_data["image_dir"]
  687. # 详情图生成结果文件夹
  688. out_put_dir = "{}\软件-详情图生成".format(image_dir)
  689. if settings.IS_TEST:
  690. print("==============_goods_no_dict 打印=================")
  691. print(json.dumps(_goods_no_dict))
  692. print("==============_goods_no_dict 打印-end=================")
  693. all_detail_path_list = []
  694. for goods_no, temp_name_list in finally_goods_no_need_temps.items():
  695. try:
  696. for _temp_name in temp_name_list:
  697. # if _temp_name != "xiaosushuoxie-4":
  698. # continue
  699. assigned_page_list = []
  700. if _temp_name in assigned_page_dict:
  701. assigned_page_list = assigned_page_dict[_temp_name]
  702. # 如果为使用表格,则获取表格中的数据作为款号的基础数据
  703. temp_info_data = copy.copy(_goods_no_dict[goods_no])
  704. if is_use_excel:
  705. # 将表格中的数据进行替换
  706. if goods_no in excel_temp_goods_no_data:
  707. if _temp_name in excel_temp_goods_no_data[goods_no]:
  708. # 将表格中的特定的模板的行,替换到goods_no的data中,因为不同的模板有数据特殊性
  709. for _key, _key_value in excel_temp_goods_no_data[goods_no][_temp_name].items():
  710. if _key in temp_info_data:
  711. temp_info_data[_key] = _key_value
  712. print("temp_info_data")
  713. print("goods_no:{},_temp_name:{}".format(goods_no, _temp_name))
  714. all_detail_path_list.append("{}/{}/".format(out_put_dir, _temp_name, goods_no))
  715. # continue
  716. self.detail_deal_one_data(goods_no=goods_no,
  717. value=temp_info_data,
  718. out_put_dir=out_put_dir,
  719. temp_name=_temp_name,
  720. assigned_page_list=assigned_page_list)
  721. except BaseException as e:
  722. self.show_progress_detail(
  723. "款:{}生成详情异常:{}".format(goods_no, e))
  724. print(e)
  725. # ==============完成处理==============
  726. self.set_state(state_value=2)
  727. if self.total_num:
  728. if self.fail_num:
  729. self.show_progress_detail("处理完成,-----处理失败数据:{}个款".format(self.fail_num))
  730. else:
  731. self.show_progress_detail("处理完成")
  732. else:
  733. self.show_progress_detail("没有任何数据")
  734. config_data["sign_text"] = "已结束详情处理"
  735. config_data["all_detail_path_list"] = all_detail_path_list
  736. # 打开文件夹
  737. os.startfile(out_put_dir)
  738. self.run_end_sign.emit(config_data)
  739. def detail_run_by_thread11111(self, config_data, _goods_no_dict, temp_name, temp_name_list, assigned_page_dict,
  740. excel_temp_goods_no_data,
  741. finally_goods_no_need_temps):
  742. """
  743. excel_temp_goods_no_data: {}, # 表格数据可能存在多模板,数据结构为一个款号下的多个模板的数据列表
  744. finally_goods_no_need_temps: {}, # 每个款号需要生成的模板数据
  745. """
  746. # 开始处理
  747. self.n = 0
  748. self.total_num = len(_goods_no_dict)
  749. self.fail_num = 0
  750. is_use_excel = config_data["is_use_excel"]
  751. image_dir = config_data["image_dir"]
  752. # 详情图生成结果文件夹
  753. out_put_dir = "{}\软件-详情图生成".format(image_dir)
  754. if settings.IS_TEST:
  755. print("==============_goods_no_dict 打印=================")
  756. print(json.dumps(_goods_no_dict))
  757. print("==============_goods_no_dict 打印-end=================")
  758. if settings.IS_TEST:
  759. max_workers = 1
  760. else:
  761. max_workers = 1
  762. all_detail_path_list = []
  763. with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
  764. futures = []
  765. for goods_no, temp_name_list in finally_goods_no_need_temps.items():
  766. for _temp_name in temp_name_list:
  767. # if _temp_name != "xiaosushuoxie-4":
  768. # continue
  769. assigned_page_list = []
  770. if _temp_name in assigned_page_dict:
  771. assigned_page_list = assigned_page_dict[_temp_name]
  772. # 如果为使用表格,则获取表格中的数据作为款号的基础数据
  773. temp_info_data = copy.copy(_goods_no_dict[goods_no])
  774. if is_use_excel:
  775. # 将表格中的数据进行替换
  776. if goods_no in excel_temp_goods_no_data:
  777. if _temp_name in excel_temp_goods_no_data[goods_no]:
  778. # 将表格中的特定的模板的行,替换到goods_no的data中,因为不同的模板有数据特殊性
  779. for _key, _key_value in excel_temp_goods_no_data[goods_no][_temp_name].items():
  780. if _key in temp_info_data:
  781. temp_info_data[_key] = _key_value
  782. print("temp_info_data")
  783. print("goods_no:{},_temp_name:{}".format(goods_no, _temp_name))
  784. all_detail_path_list.append("{}/{}/".format(out_put_dir, _temp_name, goods_no))
  785. # continue
  786. futures.append(executor.submit(
  787. self.detail_deal_one_data,
  788. goods_no=goods_no,
  789. value=temp_info_data,
  790. out_put_dir=out_put_dir,
  791. temp_name=_temp_name,
  792. assigned_page_list=assigned_page_list,
  793. ))
  794. # for goods_no, value in _goods_no_dict.items():
  795. # _temp_name = temp_name
  796. # # 使用自定义的表格数据
  797. # if self.isUseTemplate is False:
  798. # if "模板名称" in value:
  799. # if value["模板名称"] in temp_name_list:
  800. # _temp_name = value["模板名称"]
  801. # assigned_page_list = []
  802. # if _temp_name in assigned_page_dict:
  803. # assigned_page_list = assigned_page_dict[_temp_name]
  804. #
  805. # futures.append(executor.submit(
  806. # self.deal_one_data,
  807. # goods_no=goods_no,
  808. # value=value,
  809. # out_put_dir=out_put_dir,
  810. # temp_name=_temp_name,
  811. # assigned_page_list=assigned_page_list,
  812. # ))
  813. # 使用 wait 方法等待所有任务完成
  814. done, not_done = concurrent.futures.wait(futures)
  815. # 处理完成的任务
  816. for future in done:
  817. if settings.IS_TEST:
  818. result = future.result()
  819. # ==============完成处理==============
  820. self.set_state(state_value=2)
  821. if self.total_num:
  822. if self.fail_num:
  823. self.show_progress_detail(
  824. "处理完成,-----------处理失败数据:{}个款".format(self.fail_num)
  825. )
  826. else:
  827. self.show_progress_detail("处理完成")
  828. else:
  829. self.show_progress_detail("没有任何数据")
  830. config_data["sign_text"] = "已结束详情处理"
  831. config_data["all_detail_path_list"] = all_detail_path_list
  832. self.run_end_sign.emit(config_data)
  833. def show_progress_detail(self, text):
  834. # self.show_progress_detail_sign.emit(text)
  835. # self.windows.show_progress_detail(text)
  836. def detail_deal_one_data(self, goods_no, value, out_put_dir, temp_name, assigned_page_list):
  837. if self.windows.state == 99:
  838. self.show_progress_detail("用户主动取消:{}".format(goods_no))
  839. return
  840. self.show_progress_detail("正在生成:{},模板:{}".format(goods_no, temp_name))
  841. is_deal_success = False
  842. print("=================deal_one_data=====================")
  843. print("goods_no", goods_no)
  844. print("模板:", temp_name)
  845. print("value:", value)
  846. if settings.IS_TEST:
  847. d = self.windows.temp_class[temp_name](goods_no, value,
  848. out_put_dir=out_put_dir,
  849. windows=self.windows,
  850. assigned_page_list=assigned_page_list)
  851. is_deal_success = True
  852. else:
  853. try:
  854. # # 处理图片详情图生成
  855. d = self.windows.temp_class[temp_name](goods_no, value,
  856. out_put_dir=out_put_dir,
  857. windows=self.windows,
  858. assigned_page_list=assigned_page_list)
  859. is_deal_success = True
  860. except BaseException as e:
  861. self.show_progress_detail("{}处理失败".format(goods_no))
  862. error_text = "{}".format(e)
  863. if "Unable to allocate" in error_text:
  864. error_text = "电脑内存不足,生成失败"
  865. self.show_progress_detail("失败原因:{}".format(error_text))
  866. self.fail_num += 1
  867. self.n += 1
  868. if not is_deal_success:
  869. goods_art_no_list = value["货号资料"]
  870. self.show_progress_detail("处理失败")
  871. self.show_progress_detail(
  872. "相关货号:{}".format([x["货号"] for x in goods_art_no_list])
  873. )
  874. # 将相关的文件夹统一移动至错误文件夹
  875. detail_func.move_folders(
  876. path_list=[
  877. "{}/{}".format(self.windows.image_dir, x)
  878. for x in [x["文件夹名称"] for x in goods_art_no_list]
  879. ],
  880. target_folder=self.windows.target_error_folder,
  881. )
  882. pass
  883. # 更新进度
  884. print(self.n, self.total_num)
  885. self.windows.progress_sign.emit(
  886. {
  887. "type": "详情图生成",
  888. "progress_bar_value": int(self.n / self.total_num * 100),
  889. }
  890. )
  891. def check_serializable(self, obj): # 检查某个对象其中的属性哪些不能被序列化
  892. for attr_name in dir(obj):
  893. if not attr_name.startswith('__'):
  894. try:
  895. attr_value = getattr(obj, attr_name)
  896. serialized = pickle.dumps(attr_value)
  897. print(f"属性 {attr_name} 是可序列化的。")
  898. except (TypeError, pickle.PicklingError):
  899. print(f"属性 {attr_name} 不可序列化。")
  900. def on_dialog_result(self, result):
  901. """处理对话框结果"""
  902. self.dialog_result = result
  903. print("972 处理对话框结果:{}".format(result))
  904. # self.quit() # 结束事件循
  905. self.event.set()