run_main.py 49 KB

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