run_main.py 48 KB

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