api.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. from natsort.natsort import order_by_index
  2. from sqlalchemy import func
  3. from models import *
  4. import requests
  5. import json
  6. from logger import logger
  7. from serial.tools import list_ports
  8. from model import PhotoRecord
  9. import settings, datetime
  10. import pandas as pd
  11. from utils.hlm_http_request import forward_request
  12. from utils.utils_func import check_path
  13. from sockets.socket_client import socket_manager
  14. from mcu.DeviceControl import DeviceControl
  15. import time, shutil, os
  16. from sqlalchemy import and_, asc, desc
  17. from functools import partial
  18. from service.deal_image import DealImage
  19. from databases import DeviceConfig, SysConfigs, SqlQuery, CRUD, select,DeviceConfigTabs
  20. from service.run_main import RunMain
  21. import importlib
  22. from service.auto_deal_pics.upload_pic import UploadPic
  23. from service.OnePicTest import OnePicTest
  24. import hashlib
  25. import win32api, win32gui, win32con
  26. from win32gui import EnumWindows, GetWindowText
  27. # from service.AutoDealPics import AutoDealPics
  28. # for plugin in settings.plugins:
  29. # module_path, class_name = plugin.rsplit(".", 1)
  30. # print("module_path", module_path, class_name)
  31. # module = importlib.import_module(module_path)
  32. # getattr(module, class_name)
  33. def calculate_md5(filepath):
  34. # 打开文件,以二进制只读模式打开
  35. with open(filepath, "rb") as f:
  36. # 创建MD5哈希对象
  37. md5hash = hashlib.md5()
  38. # 循环读取文件的内容并更新哈希对象
  39. for chunk in iter(lambda: f.read(4096), b""):
  40. md5hash.update(chunk)
  41. # 返回MD5哈希的十六进制表示
  42. return md5hash.hexdigest()
  43. @app.get("/")
  44. async def index():
  45. # await socket_manager.send_message(msg="测试")
  46. return {"message": "Hello World"}
  47. @app.get("/scan_serials", description="扫描可用的设备端口")
  48. async def scanSerials():
  49. """扫描串口"""
  50. ports = list_ports.comports()
  51. print("Scanning", ports)
  52. return {"message": "Hello World"}
  53. @app.api_route("/forward_request", methods=["GET", "POST"], description="代理转发hlm项目得请求")
  54. async def forwardRequest(request: HlmForwardRequest):
  55. """
  56. 转发HTTP请求到目标URL
  57. :param request: FastAPI Request对象
  58. :return: 目标接口的响应
  59. """
  60. try:
  61. if request.method == "GET":
  62. params = request.query_params
  63. elif request.method == "POST":
  64. params = json.dump(request.query_params)
  65. else:
  66. raise UnicornException("仅支持GET和POST方法")
  67. target_url = request.target_url
  68. method = request.method.upper()
  69. headers = request.headers
  70. if not target_url:
  71. raise UnicornException("目标url地址不能为空")
  72. # 调用 hlm_http_request 中的 forward_request 函数
  73. response = forward_request(target_url, params=params, method=method, headers=headers)
  74. return response
  75. except requests.RequestException as e:
  76. raise UnicornException(e)
  77. except Exception as e:
  78. raise UnicornException(e)
  79. def fromExcelHandler(params: HandlerDetail):
  80. excel_path = params.excel_path
  81. token = "Bearer " + params.token
  82. excel_df = pd.read_excel(excel_path, sheet_name=0, header=0)
  83. handler_result = []
  84. handler_result_folder = ""
  85. if "文件夹名称" not in excel_df.columns:
  86. raise UnicornException("缺失 [文件夹名称] 列")
  87. if "商品货号" not in excel_df.columns:
  88. raise UnicornException("缺失 [商品货号] 列")
  89. if "款号" not in excel_df.columns:
  90. raise UnicornException("缺失 [款号] 列")
  91. goods_art_dirs = excel_df.groupby(excel_df["款号"])
  92. obj = None
  93. run_main = RunMain(obj, token)
  94. for index, row in excel_df.iterrows():
  95. goods_art_no_image_dir = str(row["文件夹名称"])
  96. goods_art_no = str(row["商品货号"])
  97. print("货号数据", goods_art_no)
  98. goods_no = str(row["款号"])
  99. a001_df = goods_art_dirs.get_group(goods_no)
  100. goods_art_nos = a001_df["商品货号"].tolist()
  101. print("goods_art_nos", goods_art_nos)
  102. try:
  103. if not goods_art_no:
  104. raise UnicornException("货号不能为空")
  105. session = SqlQuery()
  106. pr = CRUD(PhotoRecord)
  107. images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
  108. if not images:
  109. raise UnicornException("没有可用货号数据")
  110. image_dir = "{}/data/{}".format(os.getcwd(), goods_no).replace("\\", "/")
  111. check_path(image_dir)
  112. for itemImg in images:
  113. if itemImg.image_path == "" or itemImg.image_path == None:
  114. raise UnicornException(
  115. f"货号【{goods_art_no}】存在没有拍摄完成的图片,请重拍或删除后重试"
  116. )
  117. new_file_name = (
  118. str(itemImg.goods_art_no) + "_" + str(itemImg.id) + ".jpg"
  119. )
  120. if not os.path.exists(
  121. image_dir + "/" + os.path.basename(new_file_name)
  122. ):
  123. shutil.copy(itemImg.image_path, image_dir + "/" + new_file_name)
  124. dealImage = DealImage(image_dir)
  125. resFlag, path = dealImage.dealMoveImage(
  126. image_dir=image_dir,
  127. callback_func=None,
  128. goods_art_no=goods_art_no_image_dir,
  129. )
  130. if not resFlag:
  131. raise UnicornException(path)
  132. temp_class = {}
  133. temp_name_list = []
  134. for tempItem in params.temp_list:
  135. temp_class[tempItem.template_id] = tempItem.template_local_classes
  136. temp_name_list.append(tempItem.template_id)
  137. # if goods_art_no_image_dir not in path:
  138. # path = path + "/" + goods_art_no_image_dir
  139. config_data = {
  140. "image_dir": path,
  141. "image_order": params.template_image_order,
  142. "goods_art_no": goods_art_no,
  143. "goods_art_nos": goods_art_nos,
  144. "is_check_number": False,
  145. "resize_image_view": "后跟",
  146. "cutout_mode": settings.CUTOUT_MODE,
  147. "logo_path": params.logo_path,
  148. "special_goods_art_no_folder_line": "",
  149. "is_use_excel": (
  150. False if params.excel_path == "" else True
  151. ), # 是否使用excel
  152. "excel_path": params.excel_path, # excel路径
  153. "is_check_color_is_all": False,
  154. "cutout_is_pass": False,
  155. "assigned_page_dict": {},
  156. "detail_is_pass": False,
  157. "upload_is_pass": False,
  158. "upload_is_enable": False,
  159. "is_filter": False,
  160. "temp_class": temp_class,
  161. "temp_name": params.temp_name,
  162. "temp_name_list": temp_name_list,
  163. "target_error_folder": f"{path}/软件-生成详情错误",
  164. }
  165. # 动态导入类
  166. temp_class_dict = {}
  167. for key, class_path in config_data["temp_class"].items():
  168. module_path, class_name = class_path.rsplit(".", 1)
  169. module = importlib.import_module(module_path)
  170. cls = getattr(module, class_name)
  171. temp_class_dict[key] = cls
  172. config_data["temp_class"] = temp_class_dict
  173. return_data = run_main.check_before_cutout(config_data)
  174. cutout_res = run_main.check_for_cutout_image_first_call_back(return_data)
  175. check_for_detail_first_res = None
  176. if cutout_res == True:
  177. return_data_check_before_detail = run_main.check_before_detail(config_data)
  178. print(
  179. "return_data_check_before_detail======> 测试 ==>",
  180. return_data_check_before_detail,
  181. )
  182. check_for_detail_first_res = run_main.check_for_detail_first_call_back(
  183. return_data_check_before_detail
  184. )
  185. if isinstance(check_for_detail_first_res, partial):
  186. result = check_for_detail_first_res()
  187. try:
  188. config_data = result["config_data"]
  189. except:
  190. config_data = result
  191. if config_data["sign_text"] == "已结束详情处理":
  192. # at_pic = AutoDealPics()
  193. print("config_data", config_data)
  194. if config_data["upload_is_enable"]:
  195. to_deal_dir = "{}/软件-详情图生成".format(config_data["image_dir"])
  196. check_path(to_deal_dir)
  197. print("to_deal_dir", to_deal_dir)
  198. if os.path.exists(to_deal_dir):
  199. upload_pic = UploadPic(
  200. windows=None,
  201. to_deal_dir=to_deal_dir,
  202. config_data=config_data,
  203. token=token,
  204. )
  205. upload_pic.run()
  206. out_put_dir = config_data["out_put_dir"]
  207. out_put_dir_path = "{}/{}".format(os.getcwd(), out_put_dir).replace("\\", "/")
  208. handler_result_folder = os.path.dirname(out_put_dir_path)
  209. handler_result.append({"goods_art_no": goods_art_no, "success": True, "info": "处理成功"})
  210. else:
  211. handler_result.append({"goods_art_no": goods_art_no, "success": False, "info": "处理失败"})
  212. except Exception as e:
  213. handler_result.append({"goods_art_no": goods_art_no, "success": False, "info": str(e)})
  214. handler_result_folder = "/".join(handler_result_folder.split("/")[:-1])
  215. return {
  216. "code": 0,
  217. "msg": "",
  218. "data": {"output_folder": handler_result_folder, "list": handler_result},
  219. }
  220. @app.post("/handle_detail")
  221. async def handle_detail(request: Request, params: HandlerDetail):
  222. goods_art_no_array = params.goods_art_no
  223. is_only_cutout = params.is_only_cutout
  224. handler_result = []
  225. handler_result_folder = ""
  226. if params.excel_path != "" and params.excel_path != None:
  227. return fromExcelHandler(params)
  228. for goods_art_no in goods_art_no_array:
  229. try:
  230. if not goods_art_no:
  231. raise UnicornException("货号不能为空")
  232. token = "Bearer " + params.token
  233. session = SqlQuery()
  234. pr = CRUD(PhotoRecord)
  235. images = pr.read_all(session, conditions={"goods_art_no": goods_art_no})
  236. if not images:
  237. raise UnicornException("没有可用货号数据")
  238. if is_only_cutout != 1:
  239. detail_counts = len(params.template_image_order.split(","))
  240. image_counts = len(images)
  241. if image_counts < detail_counts:
  242. raise UnicornException(
  243. f"货号:[{goods_art_no}],实际照片数量:{image_counts}张,小于详情图要求数量:{detail_counts}张"
  244. )
  245. image_dir = "{}/data/".format(os.getcwd()).replace("\\", "/")
  246. check_path(image_dir)
  247. for itemImg in images:
  248. if itemImg.image_path == "" or itemImg.image_path == None:
  249. raise UnicornException(
  250. f"货号【{goods_art_no}】存在没有拍摄完成的图片,请重拍或删除后重试"
  251. )
  252. new_file_name = (
  253. str(itemImg.goods_art_no) + "_" + str(itemImg.id) + ".jpg"
  254. )
  255. if not os.path.exists(
  256. image_dir + "/" + os.path.basename(new_file_name)
  257. ):
  258. shutil.copy(itemImg.image_path, image_dir + "/" + new_file_name)
  259. dealImage = DealImage(image_dir)
  260. resFlag, path = dealImage.dealMoveImage(
  261. image_dir=image_dir, callback_func=None, goods_art_no=goods_art_no
  262. )
  263. if not resFlag:
  264. raise UnicornException(path)
  265. temp_class = {}
  266. temp_name_list = []
  267. for tempItem in params.temp_list:
  268. temp_class[tempItem.template_id] = tempItem.template_local_classes
  269. temp_name_list.append(tempItem.template_id)
  270. config_data = {
  271. "image_dir": path,
  272. "image_order": (
  273. "俯视,侧视,后跟,鞋底,内里"
  274. if params.template_image_order == None
  275. or params.template_image_order == ""
  276. else params.template_image_order
  277. ),
  278. "goods_art_no": goods_art_no,
  279. "goods_art_nos": [goods_art_no],
  280. "is_check_number": False,
  281. "resize_image_view": "后跟",
  282. "cutout_mode": settings.CUTOUT_MODE,
  283. "logo_path": params.logo_path,
  284. "special_goods_art_no_folder_line": "",
  285. "is_use_excel": (
  286. False if params.excel_path == "" else True
  287. ), # 是否使用excel
  288. "excel_path": params.excel_path, # excel路径
  289. "is_check_color_is_all": False,
  290. "cutout_is_pass": True,
  291. "assigned_page_dict": {},
  292. "detail_is_pass": False,
  293. "upload_is_pass": False,
  294. "upload_is_enable": False,
  295. "is_filter": False,
  296. "temp_class": temp_class,
  297. "temp_name": params.temp_name,
  298. "temp_name_list": temp_name_list,
  299. "target_error_folder": f"{path}/软件-生成详情错误",
  300. }
  301. # 动态导入类
  302. temp_class_dict = {}
  303. for key, class_path in config_data["temp_class"].items():
  304. module_path, class_name = class_path.rsplit(".", 1)
  305. module = importlib.import_module(module_path)
  306. cls = getattr(module, class_name)
  307. temp_class_dict[key] = cls
  308. config_data["temp_class"] = temp_class_dict
  309. obj = None
  310. run_main = RunMain(obj, token)
  311. return_data = run_main.check_before_cutout(config_data)
  312. cutout_res = run_main.check_for_cutout_image_first_call_back(return_data)
  313. check_for_detail_first_res = None
  314. if is_only_cutout == 1 and cutout_res == True:
  315. out_put_dir = return_data["data"]["image_dir"] + "/" + goods_art_no
  316. out_put_dir_path = "{}/{}".format(os.getcwd(), out_put_dir).replace(
  317. "\\", "/"
  318. )
  319. # print("out_put_dir_path", out_put_dir_path)
  320. handler_result_folder = os.path.dirname(out_put_dir_path)
  321. handler_result.append(
  322. {"goods_art_no": goods_art_no, "success": True, "info": "处理成功"}
  323. )
  324. # print("检测到需要裁剪图片,开始裁剪图片", return_data)
  325. continue
  326. if cutout_res == True:
  327. return_data_check_before_detail = run_main.check_before_detail(config_data)
  328. print(
  329. "return_data_check_before_detail======> 测试 ==>",
  330. return_data_check_before_detail,
  331. )
  332. check_for_detail_first_res = run_main.check_for_detail_first_call_back(
  333. return_data_check_before_detail
  334. )
  335. if isinstance(check_for_detail_first_res, partial):
  336. result = check_for_detail_first_res()
  337. try:
  338. config_data = result["config_data"]
  339. except:
  340. config_data = result
  341. if config_data["sign_text"] == "已结束详情处理":
  342. # at_pic = AutoDealPics()
  343. print("config_data", config_data)
  344. if config_data["upload_is_enable"]:
  345. to_deal_dir = "{}/软件-详情图生成".format(config_data["image_dir"])
  346. check_path(to_deal_dir)
  347. print("to_deal_dir", to_deal_dir)
  348. if os.path.exists(to_deal_dir):
  349. upload_pic = UploadPic(
  350. windows=None,
  351. to_deal_dir=to_deal_dir,
  352. config_data=config_data,
  353. token=token,
  354. )
  355. upload_pic.run()
  356. out_put_dir = config_data["out_put_dir"]
  357. out_put_dir_path = "{}/{}".format(os.getcwd(), out_put_dir).replace("\\", "/")
  358. handler_result_folder = os.path.dirname(out_put_dir_path)
  359. handler_result.append({"goods_art_no": goods_art_no, "success": True, "info": "处理成功"})
  360. else:
  361. handler_result.append({"goods_art_no": goods_art_no, "success": False, "info": "处理失败"})
  362. except Exception as e:
  363. handler_result.append({"goods_art_no": goods_art_no, "success": False, "info": str(e)})
  364. return {
  365. "code": 0,
  366. "msg": "",
  367. "data": {"output_folder": handler_result_folder, "list": handler_result},
  368. }
  369. @app.get("/get_device_tabs", description="获取可执行程序命令列表")
  370. def get_device_tabs(type:int):
  371. session = SqlQuery()
  372. statement = (
  373. select(DeviceConfigTabs)
  374. .where(DeviceConfigTabs.mode_type == type).order_by(asc("id"))
  375. )
  376. result = session.exec(statement).all()
  377. session.close()
  378. sys = CRUD(SysConfigs)
  379. action_configs = sys.read(session, conditions={"key": "action_configs"})
  380. session.close()
  381. return {
  382. "code": 0,
  383. "msg": "",
  384. "data": {"tabs": result, "select_configs": json.loads(action_configs.value)},
  385. }
  386. @app.post("/update_tab_name", description="更改tab名称")
  387. def update_tab_name(params: DeviceConfigTabsReq):
  388. if params.mode_name == "":
  389. return {"code": 1, "msg": "名称不能为空", "data": {}}
  390. session = SqlQuery()
  391. tabModel = CRUD(DeviceConfigTabs)
  392. kwargs = {"mode_name": params.mode_name}
  393. tabModel.updateConditions(session, conditions={"id": params.id}, **kwargs)
  394. session.close()
  395. return {
  396. "code": 0,
  397. "msg": "",
  398. "data": None,
  399. }
  400. @app.post("/get_device_configs", description="获取可执行程序命令列表")
  401. def get_device_configs(params: ModelGetDeviceConfig):
  402. tab_id = params.tab_id
  403. session = SqlQuery()
  404. configModel = CRUD(DeviceConfig)
  405. configList = configModel.read_all(
  406. session,
  407. conditions={"tab_id": tab_id},
  408. order_by="action_index",
  409. ascending=True,
  410. )
  411. return {
  412. "code": 0,
  413. "msg": "",
  414. "data": {"list": configList},
  415. }
  416. @app.post("/device_config_detail", description="获取可执行程序详情")
  417. def get_device_configs(params: ModelGetDeviceConfigDetail):
  418. action_id = params.id
  419. session = SqlQuery()
  420. configModel = CRUD(DeviceConfig)
  421. model = configModel.read(session, conditions={"id": action_id})
  422. if model == None:
  423. return {"code": 1, "msg": "数据不存在", "data": None}
  424. return {"code": 0, "msg": "", "data": model}
  425. @app.post("/device_config_detail_query", description="通过条件获取可执行程序详情")
  426. def device_config_detail_query():
  427. # tab_id = params.tab_id
  428. # action_name = params.action_name
  429. session = SqlQuery()
  430. sys = CRUD(SysConfigs)
  431. action_configs = sys.read(session, conditions={"key": "action_configs"})
  432. action_configs_value = json.loads(action_configs.value)
  433. left_config = action_configs_value.get("left")
  434. configModel = CRUD(DeviceConfig)
  435. model = configModel.read(
  436. session, conditions={"tab_id": left_config, "action_name": "侧视"}
  437. )
  438. if model == None:
  439. model = configModel.read(
  440. session, conditions={"tab_id": left_config}
  441. )
  442. return {"code": 0, "msg": "", "data": model}
  443. @app.post("/remove_config", description="删除一条可执行命令")
  444. def get_device_configs(params: ModelGetDeviceConfigDetail):
  445. action_id = params.id
  446. session = SqlQuery()
  447. configModel = CRUD(DeviceConfig)
  448. model = configModel.read(session, conditions={"id": action_id})
  449. if model == None:
  450. return {"code": 1, "msg": "数据不存在", "data": None}
  451. if model.is_system == True:
  452. return {"code": 1, "msg": "系统配置不允许删除", "data": None}
  453. configArray = configModel.read_all(session, conditions={"tab_id": model.tab_id})
  454. if len(configArray) == 1:
  455. return {"code": 1, "msg": "请至少保留一个配置", "data": None}
  456. configModel.delete(session, obj_id=action_id)
  457. return {"code": 0, "msg": "删除成功", "data": None}
  458. @app.post("/save_device_config", description="创建或修改一条可执行命令")
  459. def save_device_config(params: SaveDeviceConfig):
  460. action_id = params.id
  461. session = SqlQuery()
  462. deviceConfig = CRUD(DeviceConfig)
  463. if action_id == None or action_id == 0:
  464. # 走新增逻辑
  465. params.id = None
  466. save_device_config = deviceConfig.create(session, obj_in=params)
  467. else:
  468. model = deviceConfig.read(session, conditions={"id": action_id})
  469. if model == None:
  470. return {"code": 1, "msg": "数据不存在", "data": None}
  471. # 走编辑逻辑
  472. kwargs = params.__dict__
  473. save_device_config = deviceConfig.update(session, obj_id=action_id, **kwargs)
  474. return {"code": 0, "msg": "操作成功", "data": save_device_config}
  475. @app.post("/reset_config", description="创建或修改一条可执行命令")
  476. def reset_config(params: ModelGetDeviceConfig):
  477. tab_id = params.tab_id
  478. if tab_id == None or tab_id == "":
  479. return {"code": 1, "msg": "参数错误", "data": None}
  480. session = SqlQuery()
  481. deviceConfig = CRUD(DeviceConfig)
  482. first_config = deviceConfig.read(session, conditions={"tab_id": tab_id})
  483. res = deviceConfig.deleteConditions(session, conditions={"tab_id": tab_id})
  484. if res is False:
  485. return {"code": 1, "msg": "操作失败", "data": None}
  486. actions = json.load(open("action.json", encoding="utf-8"))
  487. for data in actions:
  488. data["tab_id"] = tab_id
  489. data["is_system"] = first_config.is_system
  490. device_config = DeviceConfig(**data)
  491. session.add(device_config)
  492. session.commit()
  493. session.close()
  494. return {"code": 0, "msg": "操作成功", "data": None}
  495. @app.get("/get_photo_records", description="获取拍照记录")
  496. def get_photo_records(page: int = 1, size: int = 5):
  497. session = SqlQuery()
  498. photos = CRUD(PhotoRecord)
  499. print("准备查询拍摄记录", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  500. statement = (
  501. select(PhotoRecord)
  502. .offset((page - 1) * size)
  503. .limit(size)
  504. .order_by(desc("id"))
  505. .group_by("goods_art_no")
  506. )
  507. list = []
  508. result = session.exec(statement).all()
  509. print("group 完成 ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  510. join_conditions = [
  511. {
  512. "model": DeviceConfig,
  513. "on": PhotoRecord.action_id == DeviceConfig.id,
  514. "is_outer": False, # 可选,默认False,设为True则为LEFT JOIN
  515. }
  516. ]
  517. for item in result:
  518. print(item)
  519. # list_item = photos.read_all(
  520. # session,
  521. # conditions={"goods_art_no": item.goods_art_no},
  522. # join_conditions=join_conditions,
  523. # )
  524. query = (
  525. select(PhotoRecord, DeviceConfig.action_name)
  526. .where(PhotoRecord.goods_art_no == item.goods_art_no)
  527. .join(DeviceConfig, PhotoRecord.action_id == DeviceConfig.id)
  528. )
  529. list_item = session.exec(query).mappings().all()
  530. session.close()
  531. list.append(
  532. {
  533. "goods_art_no": item.goods_art_no,
  534. "action_time": item.create_time,
  535. "items": list_item,
  536. }
  537. )
  538. session.close()
  539. print("循环查询 完成 ", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  540. return {
  541. "code": 0,
  542. "msg": "",
  543. "data": {"list": list, "page": page, "size": size},
  544. }
  545. @app.get("/get_last_photo_record", description="获取最后一条拍照记录")
  546. def get_last_photo_record():
  547. session = SqlQuery()
  548. statement = select(PhotoRecord).where(PhotoRecord.image_path != None).order_by(desc("photo_create_time"))
  549. result = session.exec(statement).first()
  550. session.close()
  551. return {
  552. "code": 0,
  553. "msg": "",
  554. "data": result,
  555. }
  556. @app.get("/get_photo_record_detail", description="通过货号获取拍照记录详情")
  557. def get_photo_records(goods_art_no: str = None):
  558. if goods_art_no == None:
  559. return {"code": 1, "msg": "参数错误", "data": None}
  560. session = SqlQuery()
  561. photos = CRUD(PhotoRecord)
  562. items = photos.read_all(session, conditions={"goods_art_no": goods_art_no})
  563. session.close()
  564. return {
  565. "code": 0,
  566. "msg": "",
  567. "data": {"list": items},
  568. }
  569. @app.post("/delect_goods_arts", description="通过货号删除记录")
  570. def delect_goods_arts(params: PhotoRecordDelete):
  571. session = SqlQuery()
  572. photos = CRUD(PhotoRecord)
  573. for item in params.goods_art_nos:
  574. photos.deleteConditions(session, conditions={"goods_art_no": item})
  575. session.close()
  576. return {
  577. "code": 0,
  578. "msg": "操作成功",
  579. "data": None,
  580. }
  581. @app.get("/get_sys_config", description="查询系统配置")
  582. def get_sys_config(key: str = None):
  583. if key == None:
  584. return {"code": 1, "msg": "参数错误", "data": None}
  585. session = SqlQuery()
  586. photos = CRUD(SysConfigs)
  587. item = photos.read(session, conditions={"key": key})
  588. session.close()
  589. return {
  590. "code": 0,
  591. "msg": "",
  592. "data": json.loads(item.value),
  593. }
  594. @app.post("/update_left_right_config", description="更新左右脚配置")
  595. def update_left_right_config(params: LeftRightParams):
  596. session = SqlQuery()
  597. sysConfig = CRUD(SysConfigs)
  598. model = sysConfig.read(session, conditions={"key": "action_configs"})
  599. if model == None:
  600. return {"code": 1, "msg": "配置不存在", "data": None}
  601. config_value = json.loads(model.value)
  602. config_value[params.type] = params.id
  603. update_value = json.dumps(config_value)
  604. # 走编辑逻辑
  605. kwargs = {"key": "action_configs", "value": update_value}
  606. save_device_config = sysConfig.updateConditions(
  607. session, conditions={"key": "action_configs"}, **kwargs
  608. )
  609. # return {"code": 0, "msg": "操作成功", "data": save_device_config}
  610. return {"code": 0, "msg": "操作成功", "data": None}
  611. @app.post("/update_sys_configs", description="创建或修改系统配置")
  612. def save_sys_configs(params: SysConfigParams):
  613. session = SqlQuery()
  614. sysConfig = CRUD(SysConfigs)
  615. model = sysConfig.read(session, conditions={"key": params.key})
  616. if model == None:
  617. return {"code": 1, "msg": "配置不存在", "data": None}
  618. # 走编辑逻辑
  619. kwargs = params.__dict__
  620. save_device_config = sysConfig.updateConditions(session, conditions={"key": params.key}, **kwargs)
  621. return {"code": 0, "msg": "操作成功", "data": save_device_config}
  622. @app.post("/create_main_image", description="创建主图测试")
  623. def create_main_image(params: MaineImageTest):
  624. file_path = params.file_path
  625. onePic = OnePicTest(pic_path=file_path)
  626. # session = SqlQuery()
  627. # sysConfig = CRUD(SysConfigs)
  628. # model = sysConfig.read(session, conditions={"key": params.key})
  629. # if model == None:
  630. # return {"code": 1, "msg": "配置不存在", "data": None}
  631. # # 走编辑逻辑
  632. # kwargs = params.__dict__
  633. # save_device_config = sysConfig.updateConditions(
  634. # session, conditions={"key": params.key}, **kwargs
  635. # )
  636. main_out_path = onePic.HandlerMainImage()
  637. return {"code": 0, "msg": "操作成功", "data": {"main_out_path": main_out_path}}
  638. def insertEmptyLogoList(session):
  639. """插入空logo列表"""
  640. data = {"key": "logo_configs", "value": "[]"}
  641. config = SysConfigs(**data)
  642. session.add(config)
  643. session.commit()
  644. session.close()
  645. item = SysConfigs()
  646. item.key = "logo_configs"
  647. item.value = "[]"
  648. return item
  649. @app.get("/logo_list", description="logo列表")
  650. def logo_list():
  651. logo_dir = "{}/data/logo/".format(os.getcwd()).replace("\\", "/")
  652. check_path(logo_dir)
  653. logo_files = os.listdir(logo_dir)
  654. logo_list = []
  655. for logoItem in logo_files:
  656. logo_list.append(f"{logo_dir}{logoItem}")
  657. return {"code": 0, "msg": "操作成功", "data": logo_list}
  658. @app.post("/add_logo", description="添加logo")
  659. def add_logo(params: LogoParams):
  660. logo_path = params.logo_path.replace("\\", "/")
  661. session = SqlQuery()
  662. sysConfig = CRUD(SysConfigs)
  663. item = sysConfig.read(session, conditions={"key": "logo_configs"})
  664. if item == None:
  665. item = insertEmptyLogoList(session)
  666. if os.path.isfile(logo_path) == False:
  667. return {"code": 1, "msg": "logo文件不存在", "data": None}
  668. logo_dir = "{}/data/logo/".format(os.getcwd()).replace("\\", "/")
  669. check_path(logo_dir)
  670. fpath, fname = os.path.split(logo_path)
  671. logo_path_info = logo_dir + fname
  672. shutil.copy(logo_path, logo_path_info) # 复制文件
  673. logo_files = os.listdir(logo_dir)
  674. logo_list = []
  675. for logoItem in logo_files:
  676. logo_list.append(f"{logo_dir}{logoItem}")
  677. return {
  678. "code": 0,
  679. "msg": "",
  680. "data": {"logo": logo_path_info},
  681. }
  682. @app.post("/delete_logo", description="删除logo")
  683. def delete_logo(params: LogoParamsupdate):
  684. logo_path = params.path
  685. if os.path.isfile(logo_path) == False:
  686. return {"code": 1, "msg": "logo文件不存在", "data": None}
  687. os.remove(logo_path)
  688. logo_dir = "{}/data/logo/".format(os.getcwd()).replace("\\", "/")
  689. check_path(logo_dir)
  690. logo_files = os.listdir(logo_dir)
  691. logo_list = []
  692. for logoItem in logo_files:
  693. logo_list.append(f"{logo_dir}{logoItem}")
  694. return {"code": 0, "msg": "操作成功", "data": logo_list}
  695. @app.post("/close_other_window", description="关闭窗口")
  696. def close_other_window():
  697. hwnd_list = []
  698. def callback(hwnd, _):
  699. title = GetWindowText(hwnd)
  700. if title == "digiCamControl by Duka Istvan":
  701. hwnd_list.append(hwnd)
  702. EnumWindows(callback, None)
  703. if hwnd_list:
  704. hwnd = hwnd_list[0]
  705. win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
  706. return {"code": 0, "msg": "关闭成功", "data": {"status":True}}
  707. return {"code": 0, "msg": "关闭失败", "data": {"status": False}}