main_window.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. import ctypes
  2. import inspect
  3. import os
  4. import signal
  5. import sys
  6. sys.path.append('..')
  7. import datetime
  8. import json
  9. import threading
  10. import time
  11. import traceback
  12. from functools import partial
  13. import requests
  14. from PyQt5.QtCore import QSize, QDateTime
  15. from PyQt5.QtCore import pyqtSignal, QTimer, Qt
  16. from PyQt5.QtGui import QFont, QIcon, QPixmap, QCursor, QColor
  17. from PyQt5.QtWidgets import QMessageBox, QListWidgetItem, QMainWindow, QMenu, QPushButton, QGridLayout, QListWidget, \
  18. QLabel, QHeaderView, QTableWidgetItem, QAbstractItemView, QSizePolicy, QApplication
  19. import google.protobuf.text_format as tf
  20. import ui.spaceUi as sui
  21. from window_controller.pickup_passwd_window import PickupWindow, ResultReturn
  22. import message.message_pb2 as message
  23. from window_controller.reparking_window import ReparkingWindow
  24. from window_controller.full_car_window import FullcarWindow
  25. from window_controller.led import Led
  26. import copy
  27. import async_communication as cmt
  28. import mytool.db_helper.db_operation as spmng
  29. class MainWindow(QMainWindow, sui.Ui_MainWindow):
  30. # # 取车界面信号
  31. # signal_dict = pyqtSignal(dict)
  32. def __init__(self, parking_config, mq_config, db_config, parent=None):
  33. super(MainWindow, self).__init__(parent)
  34. self.command_dict = {}
  35. self.unit_space_dict = None
  36. self.setupUi(self)
  37. # 数据存储
  38. self.btn_positions = [(i, j) for i in range(parking_config['row'], -1, -1) for j in
  39. range(parking_config['column'])]
  40. self._dispatch_statu = {}
  41. self.unit_space_is_init = False
  42. self.process_is_init = False
  43. self.unit_list = {'A1': 11, 'A2': 12, 'A3': 13, 'A4': 14, 'B1': 21, 'B2': 22, 'B3': 23, 'B4': 24, 'B5': 25,
  44. 'C1': 31, 'C2': 32,
  45. 'A': [11, 12, 13, 14], 'B': [21, 22, 23, 24, 25], 'C': [31, 32], '所有': None}
  46. self.label_dict = {}
  47. self.list_widget_dict = {}
  48. self.setWindowTitle(parking_config['window_title'])
  49. # 锁
  50. self.data_lock = threading.Lock()
  51. # 配置导入初始化数据库和rabbitmq
  52. self.parking_config = parking_config
  53. self.db = spmng.DBOperation(db_config['db_ip'], db_config['db_port'], db_config['db_name'],
  54. db_config['db_user'], db_config['db_password'])
  55. self.rabbitmq = cmt.RabbitAsyncCommunicator(mq_config['mq_ip'], mq_config['mq_port'], mq_config['mq_user'],
  56. mq_config['mq_password'])
  57. try:
  58. self.rabbitmq.Init(None, mq_config['mq_statu_exchange_keys'])
  59. for ex, key in mq_config['mq_statu_exchange_keys']:
  60. self.rabbitmq.bind_statu_callback(ex, key, self.receive_dispatch_statu)
  61. self.rabbitmq.start()
  62. except Exception as e:
  63. print('rabbitmq启动失败!' + str(e.args))
  64. self.out_date = None
  65. self.in_date = None
  66. # 记录表单元号,流程表单元号,车位表单元号
  67. self.record_unit = self.db_comboBox.currentText()
  68. self.process_unit = self.process_comboBox.currentText()
  69. self.parking_unit = self.unit_comboBox.currentText()
  70. # 调度状态指示灯
  71. self.plc_statu_led = Led()
  72. self.plc_statu_led.setEnabled(False) # 设置为不使能状态,如果需要切换可以设置为True。则可以实现点击切换指示灯颜色的效果
  73. self.plc_statu_led.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
  74. self.plc_statu_led.setChecked(False) # 设置状态
  75. self.dispatch_heart_timer = cmt.TimeStatu(1, 0.1)
  76. self.horizontalLayout_11.addWidget(self.plc_statu_led)
  77. self.db_statu_led = Led()
  78. self.db_statu_led.setEnabled(False) # 设置为不使能状态,如果需要切换可以设置为True。则可以实现点击切换指示灯颜色的效果
  79. self.db_statu_led.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
  80. self.db_statu_led.setChecked(False) # 设置状态
  81. self.horizontalLayout_11.addWidget(self.db_statu_led)
  82. # 是否输入过密码 密码保护默认五分钟
  83. self.t_time = time.time()
  84. self.is_pwd = False
  85. # 数据历史记录默认设置
  86. self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
  87. self.tableWidget.itemClicked.connect(self.show_car_image)
  88. self.tableWidget.setHorizontalHeaderLabels(parking_config['record_title'])
  89. now = datetime.datetime.now()
  90. zero_today = now - datetime.timedelta(hours=now.hour, minutes=now.minute, seconds=now.second,
  91. microseconds=now.microsecond)
  92. last_today = zero_today + datetime.timedelta(hours=23, minutes=59, seconds=59)
  93. self.in_dateTimeEdit.setDateTime(zero_today)
  94. self.out_dateTimeEdit.setDateTime(last_today)
  95. self.in_dateTimeEdit_2.setDateTime(zero_today)
  96. self.out_dateTimeEdit_2.setDateTime(last_today)
  97. self.db_find_Button.clicked.connect(self.db_record_find)
  98. # 车位显示模式
  99. self.show_model = self.car_number_rbtn_2.isChecked()
  100. # 切换库位按钮关联函数
  101. self.find_btn.clicked.connect(self.find_btn_click)
  102. self.update_unit_btn.clicked.connect(self.update_btn_click)
  103. self.update_unit_btn_2.clicked.connect(self.update_process_unit_btn_click)
  104. # 车位管理显示的相关配置
  105. self.unit = parking_config["unit"]
  106. if self.unit == 11 or self.unit == 25 or self.unit == 32:
  107. self.in_occupy_space = 2
  108. self.out_occupy_space = 2
  109. else:
  110. self.in_occupy_space = 3
  111. self.out_occupy_space = 3
  112. self.controlroom_occupy_space = 0
  113. key = list(self.unit_list.keys())[list(self.unit_list.values()).index(self.unit)]
  114. self.unit_comboBox.setCurrentText(key)
  115. # 初始化显示库位高度
  116. font = QFont()
  117. font.setFamily('宋体')
  118. font.setBold(False)
  119. font.setPointSize(15)
  120. self.parking_listWidget.setFont(font)
  121. self.pushButton_grade1.setIcon(QIcon(QPixmap("./images/grade1.png")))
  122. self.pushButton_grade2.setIcon(QIcon(QPixmap("./images/grade2.png")))
  123. self.pushButton_grade3.setIcon(QIcon(QPixmap("./images/grade3.png")))
  124. self.pushButton_grade1.setText("限高:" + str(parking_config['grade1']))
  125. self.pushButton_grade2.setText("限高:" + str(parking_config['grade2']))
  126. self.pushButton_grade3.setText("限高:" + str(parking_config['grade3']))
  127. # 数据缓存
  128. self.space_dict = {}
  129. self.record_all_unit_park_dict = {}
  130. self.record_all_unit_pick_dict = {}
  131. self.record_unit_park_dict = {}
  132. self.record_unit_pick_dict = {}
  133. self.record_total_unit_park_dict = {11:{},12:{},13:{},14:{},21:{},22:{},23:{},24:{},25:{},31:{},32:{}}
  134. self.record_total_unit_pick_dict = {11:{},12:{},13:{},14:{},21:{},22:{},23:{},24:{},25:{},31:{},32:{}}
  135. self.last_command_dict = {}
  136. # 数据库更新时间
  137. self.db_update_time = time.time() - 3
  138. self.db_connect_statu = False
  139. # 数据库查询线程
  140. self.db_query = threading.Thread(target=self.db_query)
  141. self.db_query_isClose = False
  142. self.db_query.start()
  143. # 启动界面刷新定时器
  144. self.timer = QTimer()
  145. self.timer.timeout.connect(self.Switch)
  146. self.timer.start(200)
  147. def receive_dispatch_statu(self, statu, ex, key):
  148. # 调度状态接收
  149. self._dispatch_statu[key] = statu
  150. def db_query(self):
  151. while self.db_query_isClose is False:
  152. # 查询车位
  153. self.data_lock.acquire()
  154. self.space_dict = self.db.query_space_in_unit(self.unit)
  155. # 查询指令表
  156. for unit in self.unit_list[self.process_unit]:
  157. self.last_command_dict[unit] = self.db.query_command_all_in_unit_and_sort(unit)
  158. # 当前选中时间段内所有单元记录表数据
  159. self.record_all_unit_park_dict = self.db.query_park_count_in_time(self.in_date, self.out_date)
  160. self.record_all_unit_pick_dict = self.db.query_pick_count_out_time(self.in_date, self.out_date)
  161. # 当前选中时间内指定单元记录数据
  162. if len(self.record_unit) != 1 and self.unit_list[self.record_unit] is not None:
  163. self.record_unit_park_dict = self.db.query_park_count_in_time_and_unit(self.in_date, self.out_date,
  164. self.unit_list[self.record_unit])
  165. self.record_unit_pick_dict = self.db.query_pick_count_out_time_and_unit(self.in_date, self.out_date,
  166. self.unit_list[
  167. self.record_unit])
  168. # 当前选中时间内指定总单元记录数据
  169. if len(self.record_unit) == 1:
  170. for unit in self.unit_list[self.record_unit]:
  171. self.record_total_unit_park_dict[unit] = self.db.query_park_count_in_time_and_unit(self.in_date,
  172. self.out_date,
  173. unit)
  174. self.record_total_unit_pick_dict[unit] = self.db.query_pick_count_out_time_and_unit(self.in_date,
  175. self.out_date,
  176. unit)
  177. self.data_lock.release()
  178. # 数据库更新时间
  179. self.db_update_time = time.time()
  180. time.sleep(0.1)
  181. # 界面刷新定时器
  182. def Switch(self):
  183. # 200毫秒刷新一次,同时检查密码定时器是否超过五分钟
  184. time_now = time.time()
  185. if self.is_pwd is True and time_now - self.t_time > 300:
  186. self.is_pwd = False
  187. self.t_time = time_now
  188. self.in_date = self.in_dateTimeEdit_2.dateTime().toPyDateTime().strftime("%Y-%m-%d %H:%M:%S")
  189. self.out_date = self.out_dateTimeEdit_2.dateTime().toPyDateTime().strftime("%Y-%m-%d %H:%M:%S")
  190. # 更新记录表单元号,流程表单元号,车位表单元号
  191. self.record_unit = self.db_comboBox.currentText()
  192. # 检查连接
  193. self.db_connect_statu = self.check_connect_statu()
  194. if self.db_connect_statu:
  195. # self.data_lock.acquire()
  196. # 车位管理
  197. self.parkspace_show(self.unit, self.in_occupy_space, self.out_occupy_space)
  198. # # 流程监控
  199. self.process_monitoring(self.process_unit)
  200. # # 停车数量记录
  201. self.show_parkingData()
  202. # self.data_lock.release()
  203. # 检查数据库连接
  204. def check_connect_statu(self):
  205. # 检查调度连接
  206. key = "dispatch_%d_statu_port" % self.unit
  207. if (key in self._dispatch_statu) is False or self._dispatch_statu[key].timeout():
  208. self.plc_statu_led.setChecked(False)
  209. else:
  210. statu = self._dispatch_statu[key].statu
  211. dispatch_node_statu = message.dispatch_node_statu()
  212. try:
  213. tf.Parse(statu, dispatch_node_statu)
  214. except Exception:
  215. pass
  216. if self.dispatch_heart_timer.statu != dispatch_node_statu.plc_heartbeat:
  217. self.dispatch_heart_timer = cmt.TimeStatu(dispatch_node_statu.plc_heartbeat)
  218. self.plc_statu_led.setChecked(True)
  219. if self.dispatch_heart_timer.timeout():
  220. self.plc_statu_led.setChecked(False)
  221. # 检查数据库连接
  222. if time.time() - self.db_update_time > 3:
  223. self.db_statu_led.setChecked(False)
  224. else:
  225. self.db_statu_led.setChecked(True)
  226. return self.db_statu_led.isChecked()
  227. # 车位显示
  228. def parkspace_show(self, unit, in_occupy_space, out_occupy_space):
  229. if unit == 1:
  230. self.unit_label.setText("A")
  231. elif unit == 2:
  232. self.unit_label.setText("B")
  233. elif unit == 11:
  234. self.unit_label.setText("A-1")
  235. elif unit == 12:
  236. self.unit_label.setText("A-2")
  237. elif unit == 13:
  238. self.unit_label.setText("A-3")
  239. elif unit == 14:
  240. self.unit_label.setText("A-4")
  241. elif unit == 21:
  242. self.unit_label.setText("B-1")
  243. elif unit == 22:
  244. self.unit_label.setText("B-2")
  245. elif unit == 23:
  246. self.unit_label.setText("B-3")
  247. elif unit == 24:
  248. self.unit_label.setText("B-4")
  249. elif unit == 25:
  250. self.unit_label.setText("B-5")
  251. elif unit == 31:
  252. self.unit_label.setText("C-1")
  253. elif unit == 32:
  254. self.unit_label.setText("C-2")
  255. if unit == 31 or unit == 32:
  256. self.pushButton_grade1.setIcon(QIcon(QPixmap("./images/grade1.png")))
  257. self.pushButton_grade2.setIcon(QIcon(QPixmap("./images/grade1.png")))
  258. self.pushButton_grade3.setIcon(QIcon(QPixmap("./images/grade3.png")))
  259. self.pushButton_grade1.setText("限高:" + str(self.parking_config['grade4']))
  260. self.pushButton_grade2.setText("限高:" + str(self.parking_config['grade4']))
  261. self.pushButton_grade3.setText("限高:" + str(self.parking_config['grade3']))
  262. else:
  263. self.pushButton_grade1.setIcon(QIcon(QPixmap("./images/grade1.png")))
  264. self.pushButton_grade2.setIcon(QIcon(QPixmap("./images/grade2.png")))
  265. self.pushButton_grade3.setIcon(QIcon(QPixmap("./images/grade3.png")))
  266. self.pushButton_grade1.setText("限高:" + str(self.parking_config['grade1']))
  267. self.pushButton_grade2.setText("限高:" + str(self.parking_config['grade2']))
  268. self.pushButton_grade3.setText("限高:" + str(self.parking_config['grade3']))
  269. # 绘制车位按钮
  270. if self.space_dict is None:
  271. return
  272. space_dict = copy.deepcopy(self.space_dict)
  273. is_show_car_number = self.car_number_rbtn_2.isChecked()
  274. if self.unit_space_dict != space_dict:
  275. print('有修改')
  276. if self.unit_space_is_init == False:
  277. self.unit_space_dict = copy.deepcopy(space_dict)
  278. self.unit_space_is_init = True
  279. is_drawIn = False
  280. is_drawOut = False
  281. is_drawControlRoom = False
  282. for park, position in zip(space_dict, self.btn_positions):
  283. btn = QPushButton()
  284. font, text_str, stylesheet, tool_tip = self.get_btn_show(park)
  285. btn.setFont(font)
  286. btn.setLayout(QGridLayout())
  287. btn.setText(text_str)
  288. btn.setStyleSheet(stylesheet)
  289. btn.setToolTip(tool_tip)
  290. btn.setObjectName(str(park["table_id"]))
  291. if text_str == "入 口" and is_drawIn is False:
  292. self.unit_gridLayout.addWidget(btn, *position, 1, in_occupy_space)
  293. is_drawIn = True
  294. elif text_str == "出 口" and is_drawOut is False:
  295. self.unit_gridLayout.addWidget(btn, *position, 1, out_occupy_space)
  296. is_drawOut = True
  297. elif text_str == " 控制室 " and is_drawControlRoom is False:
  298. self.unit_gridLayout.addWidget(btn, *position, 1,
  299. self.parking_config['controlroom_occupy_space'])
  300. is_drawControlRoom = True
  301. elif text_str != "出 口" and text_str != "入 口" and text_str != " 控制室 ":
  302. btn.setContextMenuPolicy(Qt.CustomContextMenu)
  303. btn.customContextMenuRequested.connect(self.park_btn_right_click)
  304. btn.clicked.connect(self.park_btn_left_click)
  305. self.unit_gridLayout.addWidget(btn, *position)
  306. else:
  307. for park1, park2 in zip(self.unit_space_dict, space_dict):
  308. if park1 != park2:
  309. font, text_str, stylesheet, tool_tip = self.get_btn_show(park2)
  310. results = self.findChild(QPushButton, str(park2["table_id"]))
  311. if results is None :
  312. return
  313. results.setFont(font)
  314. results.setText(text_str)
  315. results.setStyleSheet(stylesheet)
  316. results.setToolTip(tool_tip)
  317. self.unit_space_dict = copy.deepcopy(space_dict)
  318. if self.show_model != is_show_car_number:
  319. self.show_model = is_show_car_number
  320. for park in self.unit_space_dict:
  321. if park["statu"] == 2:
  322. font, text_str, stylesheet, tool_tip = self.get_btn_show(park)
  323. results = self.findChild(QPushButton, str(park["table_id"]))
  324. results.setFont(font)
  325. results.setText(text_str)
  326. results.setStyleSheet(stylesheet)
  327. results.setToolTip(tool_tip)
  328. # 流程监控
  329. def process_monitoring(self, unit_char):
  330. if self.process_is_init is False:
  331. for i in self.unit_list[unit_char]:
  332. self.list_widget_dict[i] = QListWidget(self)
  333. self.list_widget_dict[i].setContextMenuPolicy(Qt.CustomContextMenu)
  334. self.list_widget_dict[i].customContextMenuRequested.connect(self.custom_right_menu)
  335. self.list_widget_dict[i].setStyleSheet("border:5px solid #014F84;")
  336. self.list_widget_dict[i].setObjectName(('list_widget_%d' % (i + 1)))
  337. self.process_horizontalLayout.addWidget(self.list_widget_dict[i])
  338. self.label_dict[i] = QLabel(self)
  339. self.label_dict[i].setText(unit_char + "-" + str((i % 10)))
  340. self.label_dict[i].setAlignment(Qt.AlignCenter)
  341. self.label_dict[i].setFont(QFont("华文楷体", 60, QFont.Bold))
  342. self.command_dict[i] = []
  343. self.unit_horizontalLayout.addWidget(self.label_dict[i])
  344. self.process_is_init = True
  345. for i in self.unit_list[unit_char]:
  346. if (i in self.last_command_dict.keys()) is False or self.last_command_dict[i] is None:
  347. return
  348. else:
  349. last_command_dict = copy.deepcopy(self.last_command_dict[i])
  350. if self.command_dict[i] != last_command_dict:
  351. self.command_dict[i] = copy.deepcopy(last_command_dict)
  352. self.list_widget_dict[i].clear()
  353. for dict in self.command_dict[i]:
  354. if dict['statu'] != 3:
  355. self.list_widget_dict[i].addItem(self.get_listWidget_item(dict))
  356. for dict in self.command_dict[i]:
  357. if dict['statu'] == 3:
  358. self.list_widget_dict[i].addItem(self.get_listWidget_item(dict))
  359. # 刷新停车数据
  360. def show_parkingData(self):
  361. # 有一个数据是空就直接返回
  362. if self.record_all_unit_park_dict is None or self.record_all_unit_pick_dict is None or self.record_unit_park_dict is None or \
  363. self.record_unit_pick_dict is None or self.record_total_unit_park_dict is None or self.record_total_unit_pick_dict is None:
  364. return
  365. record_all_unit_park_dict,record_all_unit_pick_dict,record_unit_park_dict,record_unit_pick_dict,record_total_unit_park_dict,record_total_unit_pick_dict = \
  366. copy.deepcopy(self.record_all_unit_park_dict),copy.deepcopy(self.record_all_unit_pick_dict),copy.deepcopy(self.record_unit_park_dict),copy.deepcopy(self.record_unit_pick_dict),copy.deepcopy(self.record_total_unit_park_dict),copy.deepcopy(self.record_total_unit_pick_dict)
  367. unit_park_count = unit_pick_count = 0
  368. all_park_count, all_pick_count = len(record_all_unit_park_dict), len(record_all_unit_pick_dict)
  369. # 当前选中时间内指定总单元记录数据
  370. if len(self.record_unit) == 1:
  371. for unit in self.unit_list[self.record_unit]:
  372. unit_park_count = unit_park_count + len(record_total_unit_park_dict[unit])
  373. unit_pick_count = unit_pick_count + len(record_total_unit_pick_dict[unit])
  374. # 当前选中时间内指定单元记录数据
  375. elif len(self.record_unit) != 1 and self.unit_list[self.record_unit] is not None:
  376. unit_park_count, unit_pick_count = len(record_unit_park_dict), len(record_unit_pick_dict)
  377. else:
  378. unit_park_count, unit_pick_count = all_park_count, all_pick_count
  379. self.unit_park_count_label.setText("该单元停车{value}次".format(value=unit_park_count))
  380. self.unit_pick_count_label.setText("该单元取车{value}次".format(value=unit_pick_count))
  381. self.all_park_count_label.setText("所有库停车{value}次".format(value=all_park_count))
  382. self.all_pick_count_label.setText("所有库取车{value}次".format(value=all_pick_count))
  383. def show_parking_details(self, park_dict):
  384. self.parking_listWidget.clear()
  385. for poit in park_dict.items():
  386. item = QListWidgetItem()
  387. item.setSizeHint(QSize(50, 39))
  388. name = self.get_name(poit[0])
  389. if name == '未知':
  390. continue
  391. value = poit[1]
  392. if name == '楼层':
  393. value = value - self.parking_config['floor_minus']
  394. item.setText(name + ":" + str(value))
  395. self.parking_listWidget.addItem(item)
  396. res = self.db.query_space_in_car_number(park_dict['car_number'])
  397. self.plate_full_image_label.setPixmap(QPixmap(""))
  398. self.plate_clip_image_label.setPixmap(QPixmap(""))
  399. if len(res) > 0:
  400. try:
  401. rep = requests.get(res[0]['plate_full_image'])
  402. pix = QPixmap()
  403. pix.loadFromData(rep.content)
  404. pix = pix.scaled(self.plate_full_image_label.size(), Qt.KeepAspectRatio)
  405. self.plate_full_image_label.setPixmap(pix)
  406. except Exception as e:
  407. print('全景图:' + str(e.args))
  408. try:
  409. rep = requests.get(res[0]['plate_clip_image'])
  410. pix = QPixmap()
  411. pix.loadFromData(rep.content)
  412. pix = pix.scaled(self.plate_clip_image_label.size(), Qt.KeepAspectRatio)
  413. self.plate_clip_image_label.setPixmap(pix)
  414. except Exception as e:
  415. print('特写图:' + str(e.args))
  416. def find_btn_click(self):
  417. text = self.find_lineEdit.text()
  418. if text == '':
  419. QMessageBox.question(None, "提示", "请输入要查询的内容",
  420. QMessageBox.Ok)
  421. return
  422. if self.car_number_rbtn.isChecked():
  423. park_dict = self.db.query_space_in_car_number(text)
  424. if len(park_dict) > 0:
  425. self.show_parking_details(park_dict[0])
  426. else:
  427. QMessageBox.question(None, "查询结果", "车牌号:" + text + " 未查询到数据!",
  428. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  429. elif self.key_rbtn.isChecked():
  430. park_dict = self.db.query_space_in_primary_key(text)
  431. if len(park_dict) > 0:
  432. self.show_parking_details(park_dict[0])
  433. else:
  434. QMessageBox.question(None, "查询结果", "唯一码:" + text + " 未查询到数据!",
  435. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  436. # elif self.parking_rbtn.isChecked():
  437. # park_dict = self.db.query_space_in_unit_and_table_id(self.unit, text)
  438. # if len(park_dict) > 0:
  439. # self.show_parking_details(park_dict[0])
  440. #
  441. # else:
  442. # QMessageBox.question(None, "查询结果", "车位id:" + text + " 未查询到数据!",
  443. # QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  444. return
  445. def update_process_unit_btn_click(self):
  446. self.process_unit = self.process_comboBox.currentText()
  447. for i in range(self.process_horizontalLayout.count()):
  448. self.process_horizontalLayout.itemAt(i).widget().deleteLater()
  449. for i in range(self.unit_horizontalLayout.count()):
  450. self.unit_horizontalLayout.itemAt(i).widget().deleteLater()
  451. self.process_is_init = False
  452. def update_btn_click(self):
  453. self.parking_unit = self.unit_comboBox.currentText()
  454. if self.unit == self.unit_list[self.parking_unit]:
  455. return
  456. self.unit = self.unit_list[self.parking_unit]
  457. if self.unit == 11 or self.unit == 25 or self.unit == 32:
  458. self.in_occupy_space = 2
  459. self.out_occupy_space = 2
  460. else:
  461. self.in_occupy_space = 3
  462. self.out_occupy_space = 3
  463. for i in range(self.unit_gridLayout.count()):
  464. self.unit_gridLayout.itemAt(i).widget().deleteLater()
  465. self.unit_space_is_init = False
  466. def park_btn_left_click(self):
  467. if self.db_connect_statu:
  468. sender = self.sender()
  469. tool_tip = sender.toolTip()
  470. dict = json.loads(tool_tip)
  471. self.show_parking_details(dict)
  472. else:
  473. QMessageBox.critical(None, "提示", "数据库连接断开!", QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  474. def park_btn_right_click(self):
  475. if self.db_connect_statu:
  476. menu = QMenu(self)
  477. sender = self.sender()
  478. tool_tip = sender.toolTip()
  479. dict = json.loads(tool_tip)
  480. action = menu.addAction('启用车位')
  481. action.triggered.connect(partial(self.btn_opeSpace, dict, 0))
  482. action = menu.addAction('停用车位')
  483. action.triggered.connect(partial(self.btn_disableSpace, dict, 10))
  484. action = menu.addAction('清除车位')
  485. action.triggered.connect(partial(self.btn_clearSpace, dict))
  486. action = menu.addAction('正常取车')
  487. action.triggered.connect(partial(self.btn_pickUp, dict, message.PROCESS_NORMAL))
  488. action = menu.addAction('强制取车')
  489. action.triggered.connect(partial(self.btn_pickUp, dict, message.PROCESS_ONLY_TO_DISPATCH))
  490. action = menu.addAction('虚拟取车')
  491. action.triggered.connect(partial(self.btn_pickUp, dict, message.PROCESS_ONLY_TO_PAY))
  492. # action = menu.addAction('更换车位')
  493. # action.triggered.connect(partial(self.btn_replace_parking, dict))
  494. action = menu.addAction('填充车位')
  495. action.triggered.connect(partial(self.btn_fill_parking, dict))
  496. action = menu.addAction('增加备注')
  497. action.triggered.connect(partial(self.btn_add_remarks, dict))
  498. menu.exec_(QCursor.pos())
  499. else:
  500. QMessageBox.critical(None, "提示", "数据库连接断开!", QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  501. def btn_disableSpace(self, dict, statu):
  502. if self.is_input_pwd() is True:
  503. res = self.db.update_space_status_in_space_id(dict["id"], statu)
  504. if res == 0:
  505. QMessageBox.question(None, '提示', '更新车位失败!请检查是否点击错误!',
  506. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  507. def btn_opeSpace(self, dict, statu):
  508. if self.is_input_pwd() is True:
  509. res = self.db.update_space_status_in_space_id(dict["id"], statu)
  510. if res == 0:
  511. QMessageBox.question(None, '提示', '更新车位失败!请检查是否点击错误!',
  512. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  513. def btn_clearSpace(self, dict):
  514. if self.is_input_pwd() is True:
  515. res = self.db.clear_space_data(dict["id"])
  516. if res == 0:
  517. QMessageBox.question(None, '提示', '更新车位失败!请检查是否点击错误!',
  518. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  519. def btn_pickUp(self, dict, table_process_mod):
  520. if self.is_input_pwd() is True:
  521. table = message.pick_table()
  522. # table.statu = message.table_statu()
  523. table.statu.table_process_mod = table_process_mod
  524. a = dict['primary_key']
  525. table.primary_key = dict["primary_key"]
  526. self.rabbitmq.publish("command_ex", "user_pick_command_request_port",
  527. tf.MessageToString(table, as_utf8=True))
  528. QMessageBox.question(None, '提示', '取车消息发送成功!',
  529. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  530. # def btn_replace_parking(self, dict):
  531. # if self.is_input_pwd() is True:
  532. # if dict['car_number'] == 'None' or dict['primary_key'] == 'None':
  533. # QMessageBox.question(None, '提示', '没有车牌号或唯一码,不符合更换车位条件!',
  534. # QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  535. # return
  536. # repwind = ReparkingWindow()
  537. # repwind.exec()
  538. # res = repwind.get_results()
  539. # if res is True:
  540. # target_parking = self.db.query_parking_in_unit_tableid(dict['unit'], repwind.get_park_tableid())[0]
  541. # if target_parking['car_number'] is not None:
  542. # QMessageBox.question(None, '提示', '目标车位不为空!',
  543. # QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  544. # return
  545. # parking = self.db.query_space_in_car_number(dict['car_number'])[0]
  546. #
  547. # space_info_sql = "NULL"
  548. # measure_info_sql = "NULL"
  549. # plate_color_sql = "NULL"
  550. # plate_type_sql = "NULL"
  551. # plate_confidence_sql = "NULL"
  552. # recognition_time_sql = "NULL"
  553. # plate_full_image_sql = "NULL"
  554. # plate_clip_image_sql = "NULL"
  555. #
  556. # if parking['space_info'] is not None:
  557. # space_info_sql = "'%s'" % parking['space_info']
  558. #
  559. # if parking['measure_info'] is not None:
  560. # measure_info_sql = "'%s'" % parking['measure_info']
  561. #
  562. # if parking['plate_color'] is not None:
  563. # plate_color_sql = "'%s'" % parking['plate_color']
  564. #
  565. # if parking['plate_type'] is not None:
  566. # plate_type_sql = "'%s'" % parking['plate_type']
  567. #
  568. # if parking['plate_confidence'] is not None:
  569. # plate_confidence_sql = "%d" % parking['plate_confidence']
  570. #
  571. # if parking['recognition_time'] is not None:
  572. # recognition_time_sql = "'%s'" % parking['recognition_time']
  573. #
  574. # if parking['plate_full_image'] is not None:
  575. # plate_full_image_sql = "'%s'" % parking['plate_full_image']
  576. #
  577. # if parking['plate_clip_image'] is not None:
  578. # plate_clip_image_sql = "'%s'" % parking['plate_clip_image']
  579. #
  580. # sql2 = "update space set car_number='%s', primary_key='%s', statu=%d , space_info=%s , measure_info=%s ,\
  581. # plate_color=%s , plate_type=%s , plate_confidence=%s , recognition_time=%s , plate_full_image=%s , plate_clip_image=%s where id=%d" \
  582. # % (parking['car_number'], parking['primary_key'], parking['statu'], space_info_sql,
  583. # measure_info_sql,
  584. # plate_color_sql, \
  585. # plate_type_sql, plate_confidence_sql, recognition_time_sql, plate_full_image_sql,
  586. # plate_clip_image_sql, target_parking['id'])
  587. # # print(sql2)
  588. #
  589. # res = self.db.update(sql2)
  590. # if res == 0:
  591. # QMessageBox.question(None, '提示', '执行失败!',
  592. # QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  593. # return
  594. # res = self.db.clear_space_data(parking['id'])
  595. # if res > 0:
  596. # QMessageBox.question(None, '提示', '车位交换成功!',
  597. # QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  598. def btn_fill_parking(self, dict):
  599. if self.is_input_pwd() is True:
  600. fullcar = FullcarWindow()
  601. fullcar.exec()
  602. if fullcar.get_results() is True:
  603. car_number = fullcar.get_text()
  604. res = self.db.update_space_status_car_number_in_space_id(dict['id'], car_number, 2)
  605. if res > 0:
  606. QMessageBox.question(None, '提示', '车位填充成功!',
  607. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  608. def btn_add_remarks(self, dict):
  609. if self.is_input_pwd() is True:
  610. fullcar = FullcarWindow()
  611. fullcar.exec()
  612. if fullcar.get_results() is True:
  613. remark = fullcar.get_text()
  614. res = self.db.update_space_remark_in_space_id(dict['id'],remark)
  615. if res > 0:
  616. QMessageBox.question(None, '提示', '车位添加备注成功!',
  617. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  618. def get_btn_show(self, park):
  619. font = QFont()
  620. font.setFamily('宋体')
  621. font.setPointSize(21)
  622. if park["statu"] == 6:
  623. text_str = "入 口"
  624. font.setBold(True)
  625. elif park["statu"] == 7:
  626. text_str = "出 口"
  627. font.setBold(True)
  628. elif park["statu"] == 8:
  629. text_str = " 控制室 "
  630. font.setBold(True)
  631. # elif park["statu"] == 10 and park["remark"] is not None:
  632. # text_str = park["remark"][0:4]
  633. # font.setPointSize(20)
  634. elif (park["statu"] == 2 or park["statu"] == 1) and park[
  635. "car_number"] is not None and self.car_number_rbtn_2.isChecked():
  636. text_str = park["car_number"]
  637. font.setPointSize(20)
  638. else:
  639. text_str = "车位:%d\n楼层:%d" % (park["table_id"], (park["floor"] - self.parking_config['floor_minus']))
  640. font.setPointSize(10)
  641. background_color = ""
  642. background_image = ""
  643. if park["statu"] == 10:
  644. background_color = "background-color:rgb(255,130,130);"
  645. elif park["statu"] == 2:
  646. background_color = "background-color:rgb(248,239,71);"
  647. elif park["statu"] == 1:
  648. background_color = "background-color:rgb(240,120,30);"
  649. elif park["statu"] == 6 or park["statu"] == 7 or park["statu"] == 8:
  650. background_color = "background-color:rgb(0,162,232);"
  651. # elif park["statu"] == 0 and park["remark"] is not None:
  652. # background_color = "background-color:rgb(255,130,130);"
  653. elif park["statu"] == 0:
  654. background_color = "background-color:rgb(195,195,195);"
  655. # 设置背景图
  656. if park["height"] == self.parking_config['grade1']:
  657. background_image = "background-image: url(./images/grade1.png);"
  658. elif park["height"] == self.parking_config['grade2']:
  659. background_image = "background-image: url(./images/grade2.png);"
  660. elif park["height"] == self.parking_config['grade3']:
  661. background_image = "background-image: url(./images/grade3.png);"
  662. elif park["height"] == self.parking_config['grade4']:
  663. background_image = "background-image: url(./images/grade1.png);"
  664. stylesheet = background_color + "pressed{padding-top:2px;padding-left:2px;};" + background_image + "background-repeat:no-repeat;"
  665. for key in park.keys():
  666. if park[key] is None:
  667. park[key] = ''
  668. tool_tip = json.dumps(park)
  669. return font, text_str, stylesheet, tool_tip
  670. # 显示车辆图片
  671. def show_car_image(self, Item):
  672. try:
  673. row = Item.row() # 获取行数
  674. col = self.tableWidget.columnCount() # 获取列数 注意是column而不是col哦
  675. plate_full_image = self.tableWidget.item(row, col - 2)
  676. plate_clip_image = self.tableWidget.item(row, col - 1)
  677. self.plate_full_image_label_2.setPixmap(QPixmap(""))
  678. self.plate_clip_image_label_2.setPixmap(QPixmap(""))
  679. if plate_full_image is not None:
  680. rep = requests.get(plate_full_image.text())
  681. pix = QPixmap()
  682. pix.loadFromData(rep.content)
  683. pix = pix.scaled(self.plate_full_image_label_2.size(), Qt.KeepAspectRatio)
  684. self.plate_full_image_label_2.setPixmap(pix)
  685. if plate_clip_image is not None:
  686. rep = requests.get(plate_clip_image.text())
  687. pix = QPixmap()
  688. pix.loadFromData(rep.content)
  689. pix = pix.scaled(self.plate_clip_image_label_2.size(), Qt.KeepAspectRatio)
  690. self.plate_clip_image_label_2.setPixmap(pix)
  691. except Exception as e:
  692. traceback.print_exc()
  693. # 查询历史记录
  694. def db_record_find(self):
  695. if self.db_connect_statu is False:
  696. QMessageBox.critical(None, "提示", "数据库连接断开!", QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  697. return
  698. if self.unit_list[self.record_unit] == None:
  699. unit_sql = ""
  700. elif type(self.unit_list[self.record_unit]) != int:
  701. unit_sql = "and ("
  702. for i in self.unit_list[self.record_unit]:
  703. unit_sql = unit_sql + "unit_id=%d or " % i
  704. unit_sql = unit_sql[:-3] + ")"
  705. else:
  706. unit_sql = "and (unit_id = %s)" % self.unit_list[self.record_unit]
  707. in_datatime = self.in_dateTimeEdit.dateTime().toPyDateTime()
  708. out_datatime = self.out_dateTimeEdit.dateTime().toPyDateTime()
  709. car_number = self.car_number_lineEdit.text()
  710. in_time_sql = "(in_time_start >= '%s' and in_time_start <= '%s') " % (in_datatime, out_datatime)
  711. out_time_sql = "(out_time_start >= '%s' and out_time_start <= '%s') " % (in_datatime, out_datatime)
  712. in_and_out_time_sql = "(" + in_time_sql + " or " + out_time_sql + ")"
  713. if self.park_radioButton.isChecked():
  714. time_sql = in_time_sql
  715. elif self.pick_radioButton.isChecked():
  716. time_sql = out_time_sql
  717. else:
  718. time_sql = in_and_out_time_sql
  719. car_number_sql = ""
  720. if car_number != "":
  721. car_number_sql = "and car_number like '%{}%'".format(car_number)
  722. sql = "select * from record where %s %s %s " % (time_sql, unit_sql, car_number_sql)
  723. print(sql)
  724. results = self.db.query(sql)
  725. self.tableWidget.clearContents()
  726. self.tableWidget.setRowCount(0)
  727. for i in range(len(results)):
  728. row_count = self.tableWidget.rowCount() # 返回当前行数(尾部)
  729. self.tableWidget.insertRow(row_count) # 尾部插入一行
  730. for j, value in zip(range(0, len(results[i])), results[i].values()):
  731. self.tableWidget.setItem(i, j, QTableWidgetItem(str(value)))
  732. # print(results)
  733. def custom_right_menu(self, pos):
  734. sender = self.sender()
  735. menu = QMenu()
  736. opt1 = menu.addAction("恢复排队")
  737. opt2 = menu.addAction("设为故障")
  738. opt3 = menu.addAction("删除任务")
  739. try:
  740. hitIndex = sender.indexAt(pos).row()
  741. # print(hitIndex)
  742. if hitIndex > -1:
  743. # 获取item内容
  744. car_number = sender.item(hitIndex).toolTip()
  745. action = menu.exec_(sender.mapToGlobal(pos))
  746. if self.is_input_pwd() is True:
  747. if action == opt1:
  748. res = self.db.update_command_status_in_car_number(car_number, 0)
  749. if action == opt2:
  750. res = self.db.update_command_status_in_car_number(car_number, 3)
  751. if action == opt3:
  752. self.is_pwd = False
  753. if self.is_input_pwd('该操作存在风险,请再次输入密码!') is True:
  754. res = self.db.delete_command(car_number)
  755. if res > 0:
  756. QMessageBox.question(None, '提示', '指令修改成功!',
  757. QMessageBox.Ok) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  758. except Exception as e:
  759. pass
  760. def is_input_pwd(self, tipstr=None):
  761. if self.is_pwd is False:
  762. # 组装显示信息
  763. # 实例取车窗口,并以模态窗口形式显示
  764. pickup_window = PickupWindow(tipstr)
  765. pickup_window.exec_()
  766. res = pickup_window.getResult()
  767. if res is ResultReturn.OK:
  768. self.is_pwd = True
  769. self.t_time = time.time()
  770. return True
  771. else:
  772. return False
  773. return True
  774. def get_listWidget_item(self, dict):
  775. item = QListWidgetItem()
  776. item.setFont(QFont('微软雅黑', 15, QFont.Bold))
  777. item.setToolTip(dict['car_number'])
  778. show_str = ""
  779. if dict['type'] == 1: # 存车指令
  780. item.setBackground(QColor(185, 240, 240))
  781. if (dict['statu'] == 0): # 排队
  782. item.setForeground(QColor(80, 80, 80))
  783. show_str = dict['car_number'] + " 排队中,请稍等片刻"
  784. elif (dict['statu'] == 1): # 工作
  785. item.setForeground(QColor('blue'))
  786. show_str = dict['car_number'] + " 存车中,等待存车结束"
  787. elif (dict['statu'] == 2): # 已完成
  788. item.setForeground(QColor('green'))
  789. show_str = dict['car_number'] + " 存车已完成"
  790. elif (dict['statu'] == 3): # 已完成
  791. item.setForeground(QColor('red'))
  792. show_str = dict['car_number'] + " 故障,请联系管理员!"
  793. show_str = "存 " + show_str
  794. elif dict['type'] == 2: # 取车指令
  795. item.setBackground(QColor(250, 240, 200))
  796. if (dict['statu'] == 0): # 排队
  797. item.setForeground(QColor(80, 80, 80))
  798. show_str = dict['car_number'] + " 排队中,请稍等片刻"
  799. elif (dict['statu'] == 1): # 工作
  800. item.setForeground(QColor('blue'))
  801. show_str = dict['car_number'] + " 取车中,等待取车结束"
  802. elif (dict['statu'] == 2): # 已完成
  803. item.setForeground(QColor('green'))
  804. show_str = dict['car_number'] + " 已完成,请到 %d 号出口取车" % (dict["export_id"])
  805. elif (dict['statu'] == 3): # 已完成
  806. item.setForeground(QColor('red'))
  807. show_str = dict['car_number'] + " 故障,请联系管理员!"
  808. show_str = "取 " + show_str
  809. item.setText(show_str)
  810. return item
  811. def closeEvent(self, event):
  812. results = QMessageBox.question(self, '退出', '你确定要退出吗?', QMessageBox.Yes | QMessageBox.No,
  813. QMessageBox.No) # "退出"代表的是弹出框的标题,"你确认退出.."表示弹出框的内容
  814. if results == QMessageBox.Yes:
  815. self.db_query_isClose = True
  816. self.db_query.join()
  817. self.rabbitmq.close()
  818. event.accept() # 接受关闭事件
  819. # 强制结束进程
  820. pid = os.getpid()
  821. os.kill(pid, signal.SIGTERM)
  822. else:
  823. event.ignore() # 忽略关闭事件
  824. def get_name(self, key):
  825. if key == 'id':
  826. return '总车位号'
  827. elif key == 'table_id':
  828. return '表编号'
  829. elif key == 'floor':
  830. return '楼层'
  831. elif key == 'height_level':
  832. return '限高等级'
  833. elif key == 'height':
  834. return '限高'
  835. elif key == 'wheel_base_level':
  836. return '限制轴距等级'
  837. elif key == 'wheel_base':
  838. return '限制轴距'
  839. elif key == 'car_number':
  840. return '车牌号'
  841. elif key == 'statu':
  842. return '车位状态'
  843. elif key == 'plate_color':
  844. return '号牌颜色'
  845. elif key == 'plate_type':
  846. return '号牌类型'
  847. elif key == 'plate_confidence':
  848. return '号牌可信度'
  849. elif key == 'recognition_time':
  850. return '识别时间'
  851. elif key == 'primary_key':
  852. return '唯一码'
  853. elif key == 'plate_full_image':
  854. return '号牌全景图'
  855. elif key == 'plate_clip_image':
  856. return '号牌特写图'
  857. elif key == 'remark':
  858. return '备注'
  859. else:
  860. return '未知'