文件分离函数类,增加提示信息

This commit is contained in:
冯佳
2025-09-05 15:40:00 +08:00
parent 79f733126b
commit 0557ba7f1c
6 changed files with 182 additions and 72 deletions

View File

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
import sys, os, io, csv, time, datetime
from typing import Callable, Optional
# PyQt5
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QSize
from PyQt5.QtGui import QImage, QPixmap, QKeySequence
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QComboBox, QTextEdit, QFileDialog, QMessageBox,
QGroupBox, QGridLayout, QDialog, QFormLayout, QSpinBox, QCheckBox,
QLineEdit, QTableWidget, QTableWidgetItem,QDialogButtonBox,QShortcut
)
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import cv2
from PIL import Image
import serial
import serial.tools.list_ports
# ---------- 协议导入----------
from Shared_CODE.FaceRecognitionProtocol import (
build_reset, build_uvc_view, build_face_view, build_verify,
build_enroll_itg_single, build_delete_all, build_get_all_userid,build_delete_user,
MID_REPLY, MID_NOTE, CMD_ENROLL, CMD_ENROLL_ITG,
parse_reply, parse_note
)
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
ui_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../Shared_UI'))
enrill_ui_file_path = os.path.join(ui_path, "enroll.ui")
class EnrollItgSingleDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
uic.loadUi(enrill_ui_file_path, self)
self.cb_admin.setCurrentIndex(0)
self.btn_ok.clicked.connect(self.accept)
def values(self):
admin_val = self.cb_admin.currentIndex()
uname = self.le_name.text().strip()[:32]
face_dir = 0
if self.chk_mid.isChecked(): face_dir |= 0x01
if self.chk_right.isChecked(): face_dir |= 0x02
if self.chk_left.isChecked(): face_dir |= 0x04
if self.chk_down.isChecked(): face_dir |= 0x08
if self.chk_up.isChecked(): face_dir |= 0x10
if face_dir == 0: face_dir = 0x01
timeout_val = self.sb_timeout.value()
try:
itg_val = int(self.le_itg.text().strip(), 0)
except ValueError:
itg_val = 0
return admin_val, uname, face_dir, timeout_val, itg_val
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = EnrollItgSingleDialog()
dialog.exec()
sys.exit(0)

View File

@ -6,13 +6,14 @@ from typing import Callable, Optional
# PyQt5
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QSize
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtGui import QImage, QPixmap, QKeySequence
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QComboBox, QTextEdit, QFileDialog, QMessageBox,
QGroupBox, QGridLayout, QDialog, QFormLayout, QSpinBox, QCheckBox,
QLineEdit, QTableWidget, QTableWidgetItem
QLineEdit, QTableWidget, QTableWidgetItem,QDialogButtonBox,QShortcut
)
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import cv2
from PIL import Image
@ -30,8 +31,6 @@ from Shared_CODE.FaceRecognitionProtocol import (
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
ui_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../Shared_UI'))
users_ui_file_path = os.path.join(ui_path, "users.ui")
verify_ui_file_path = os.path.join(ui_path, "verify.ui")
enrill_ui_file_path = os.path.join(ui_path, "enroll.ui")
CSV_FILE = os.path.join(ui_path, "users.csv")
# -------------------- CSV 工具 --------------------"
@ -71,8 +70,9 @@ def save_user(user_id: int, user_name: str) -> bool:
class UserManageDialog(QDialog):
def __init__(self, parent, send_func):
super().__init__(parent)
uic.loadUi(users_ui_file_path, self)
self.send_func = send_func
uic.loadUi(users_ui_file_path, self)
self.btn_delete.clicked.connect(self.delete_selected)
self.btn_refresh.clicked.connect(self.refresh)
self.btn_get.clicked.connect(self.get_from_device)
@ -114,44 +114,6 @@ class UserManageDialog(QDialog):
self.refresh()
QMessageBox.information(self, "提示", "已请求删除所有用户并清空本地记录")
class VerifyDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
uic.loadUi(verify_ui_file_path, self)
self.cb_rightaway.setCurrentIndex(0)
self.sb_timeout.setValue(10)
self.btn_ok.clicked.connect(self.accept)
def values(self):
pd_val = self.cb_rightaway.currentIndex()
timeout_val = self.sb_timeout.value()
return pd_val, timeout_val
class EnrollItgSingleDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
uic.loadUi(enrill_ui_file_path, self)
self.cb_admin.setCurrentIndex(0)
self.btn_ok.clicked.connect(self.accept)
def values(self):
admin_val = self.cb_admin.currentIndex()
uname = self.le_name.text().strip()[:32]
face_dir = 0
if self.chk_mid.isChecked(): face_dir |= 0x01
if self.chk_right.isChecked(): face_dir |= 0x02
if self.chk_left.isChecked(): face_dir |= 0x04
if self.chk_down.isChecked(): face_dir |= 0x08
if self.chk_up.isChecked(): face_dir |= 0x10
if face_dir == 0: face_dir = 0x01
timeout_val = self.sb_timeout.value()
try:
itg_val = int(self.le_itg.text().strip(), 0)
except ValueError:
itg_val = 0
return admin_val, uname, face_dir, timeout_val, itg_val
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = UserManageDialog()

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
from __future__ import annotations
import sys, os, io, csv, time, datetime
from typing import Callable, Optional
# PyQt5
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QSize
from PyQt5.QtGui import QImage, QPixmap, QKeySequence
from PyQt5.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QPushButton, QComboBox, QTextEdit, QFileDialog, QMessageBox,
QGroupBox, QGridLayout, QDialog, QFormLayout, QSpinBox, QCheckBox,
QLineEdit, QTableWidget, QTableWidgetItem,QDialogButtonBox,QShortcut
)
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import cv2
from PIL import Image
import serial
import serial.tools.list_ports
# ---------- 协议导入----------
from Shared_CODE.FaceRecognitionProtocol import (
build_reset, build_uvc_view, build_face_view, build_verify,
build_enroll_itg_single, build_delete_all, build_get_all_userid,build_delete_user,
MID_REPLY, MID_NOTE, CMD_ENROLL, CMD_ENROLL_ITG,
parse_reply, parse_note
)
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
ui_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../Shared_UI'))
verify_ui_file_path = os.path.join(ui_path, "verify.ui")
class VerifyDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
uic.loadUi(verify_ui_file_path, self)
self.cb_rightaway.setCurrentIndex(0)
self.sb_timeout.setValue(10)
self.btn_ok.clicked.connect(self.accept)
def values(self):
pd_val = self.cb_rightaway.currentIndex()
timeout_val = self.sb_timeout.value()
return pd_val, timeout_val
if __name__ == '__main__':
app = QApplication(sys.argv)
dialog = VerifyDialog()
dialog.exec()
sys.exit(0)

View File

@ -3,6 +3,7 @@ from __future__ import annotations
import struct
from dataclasses import dataclass
from typing import Optional, Tuple, List
from QT5_Project.Shared_CODE.DialogInform import DialogInform
SYNC = b"\xEF\xAA"
@ -296,71 +297,86 @@ def build_enroll_with_photo_chunk(seq: int, chunk: bytes) -> bytes:
# ---- Parsers (Reply / Note / Image) ----
def parse_reply(data: bytes) -> dict:
if len(data) < 2:
return {"type":"REPLY","error":"short"}
return {"type": "REPLY", "error": "short"}
mid = data[0]
result = data[1]
rest = data[2:]
# 初始化 info 字典
# 通用字段
info = {
"type":"REPLY",
"type": "REPLY",
"mid": mid,
"mid_name": CMD_NAMES.get(mid, f"0x{mid:02X}"),
"result": result,
"result_name": RESULT_NAMES.get(result, f"0x{result:02X}")
"result_name": RESULT_NAMES.get(result, f"0x{result:02X}"),
"ok": (result == 0), # 成功标志
}
# ========== 分支解析 ==========
if mid == CMD_VERIFY and len(rest) >= 36:
uid = (rest[0]<<8)|rest[1]
uid = (rest[0] << 8) | rest[1]
name = rest[2:34].rstrip(b"\x00").decode("utf-8", errors="ignore")
admin = rest[34]
unlock = rest[35]
info.update({"user_id": uid, "user_name": name, "admin": admin, "unlock_status": unlock})
info.update({
"user_id": uid,
"user_name": name,
"admin": admin,
"unlock_status": unlock,
})
elif mid in (CMD_ENROLL, 0x1D, CMD_ENROLL_ITG) and len(rest) >= 3:
uid = (rest[0]<<8)|rest[1]
uid = (rest[0] << 8) | rest[1]
face_dir = rest[2]
info.update({"user_id": uid, "face_direction": face_dir})
elif mid == CMD_GET_STATUS and len(rest) >= 1:
status = rest[0]
info.update({"status": status, "status_name": {
0: "空闲",
1: "录入中",
2: "验证中"
}.get(status, f"0x{status:02X}")})
status_map = {0: "空闲", 1: "录入中", 2: "验证中"}
info.update({"status": status, "status_name": status_map.get(status, f"0x{status:02X}")})
elif mid == CMD_GET_USER_INFO and len(rest) >= 35:
uid = (rest[0]<<8)|rest[1]
uid = (rest[0] << 8) | rest[1]
name = rest[2:34].decode("ascii", errors="ignore")
admin = rest[34]
info.update({"user_id": uid, "user_name": name, "admin": admin})
elif mid == CMD_GET_ALL_USERID and len(rest) >= 1:
n = rest[0]
ids = [(rest[i]<<8)|rest[i+1] for i in range(1, 1+2*n, 2) if i+1 < len(rest)]
ids = [(rest[i] << 8) | rest[i + 1] for i in range(1, 1 + 2 * n, 2) if i + 1 < len(rest)]
info.update({"count": n, "user_ids": ids})
elif mid == CMD_GET_VERSION:
info["version_str"] = rest.decode("ascii", errors="ignore")
elif mid == CMD_LED_CONTROL and len(rest) >= 1:
led_state = rest[0]
info.update({"led_state": led_state, "led_state_name": {
0: "",
1: ""
}.get(led_state, f"0x{led_state:02X}")})
led_map = {0: "", 1: ""}
info.update({"led_state": led_state, "led_state_name": led_map.get(led_state, f"0x{led_state:02X}")})
elif mid == CMD_ENROLL_WITH_PHOTO:
if len(rest) >= 2:
seq = (rest[0]<<8)|rest[1]
seq = (rest[0] << 8) | rest[1]
info["seq"] = seq
if len(rest) >= 6:
uid = (rest[2]<<8)|rest[3]
uid = (rest[2] << 8) | rest[3]
info["user_id"] = uid
# 自动生成提示消息
if info.get("ok"):
info["message"] = f"{info['mid_name']} 成功"
inform_box : DialogInform = DialogInform()
inform_box.information("提示", f"{info['mid_name']} 成功")
else:
info["message"] = f"{info['mid_name']} 失败: {info['result_name']}"
inform_box : DialogInform = DialogInform()
inform_box.information("提示", f"{info['mid_name']} 失败: {info['result_name']}")
return info
def parse_note(data: bytes) -> dict:
if len(data) < 1:
return {"type":"NOTE","error":"short"}