run_main.py 46 KB

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