readFileSystem/ui/base_page.py

324 lines
13 KiB
Python
Raw Normal View History

from PySide6.QtWidgets import (
QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox, QDialog, QFileDialog
)
from PySide6.QtCore import Qt, QSettings
import os
import glob
from src.db_manager import DatabaseManager
from src.xml_parser import XmlParser
from utils.readMTP import MTPHandler
from src.session_manager import SessionManager
2026-02-28 14:05:55 +08:00
from utils.logger import get_logger, log_timing_context
logger = get_logger("base_page")
class BaseInspectionPage(QDialog):
def __init__(self, title, parent=None):
super().__init__(parent)
self.setWindowTitle(title)
self.setWindowFlags(self.windowFlags() | Qt.Window | Qt.WindowMaximizeButtonHint)
self.settings = QSettings("Tengzhi", "InspectionApp")
self.mtp_handler = MTPHandler()
self.session = SessionManager()
self.page_type = title # 保存页面类型("入检" 或 "手检"
self.main_layout = QVBoxLayout(self)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.setSpacing(0)
self.create_toolbar()
# Content Area (to be filled by subclasses)
self.content_widget = QWidget()
self.content_layout = QVBoxLayout(self.content_widget)
self.content_layout.setContentsMargins(20, 20, 20, 20)
self.content_layout.setSpacing(15)
self.content_layout.setAlignment(Qt.AlignTop)
self.main_layout.addWidget(self.content_widget, 1) # Stretch = 1 to fill space
# Bottom Button Bar
self.create_bottom_bar()
def create_toolbar(self):
toolbar = QWidget()
toolbar.setStyleSheet("background-color: #f8f8f8; border-bottom: 1px solid #ddd;")
layout = QHBoxLayout(toolbar)
layout.setContentsMargins(10, 5, 10, 5)
title_label = QPushButton("⚙ 设置读取路径")
title_label.setStyleSheet("""
QPushButton {
border: none;
background-color: transparent;
font-family: 'Microsoft YaHei';
font-size: 13px;
color: #666;
text-align: left;
}
QPushButton:hover {
color: #0086fa;
}
""")
title_label.clicked.connect(self.on_settings)
layout.addWidget(title_label)
layout.addStretch()
self.main_layout.addWidget(toolbar)
def on_settings(self):
from PySide6.QtWidgets import QFormLayout, QLineEdit, QRadioButton, QButtonGroup
dialog = QDialog(self)
dialog.setWindowTitle("同步设置")
dialog.setFixedWidth(400)
layout = QVBoxLayout(dialog)
form = QFormLayout()
# Mode Selection
mode_group = QButtonGroup(dialog)
current_mode = self.settings.value("sync_mode", "local")
rb_local = QRadioButton("本地路径 (本地硬盘)")
rb_mtp = QRadioButton("MTP设备 (连接的PDA)")
mode_group.addButton(rb_local)
mode_group.addButton(rb_mtp)
if current_mode == "local": rb_local.setChecked(True)
else: rb_mtp.setChecked(True)
form.addRow("同步模式:", rb_local)
form.addRow("", rb_mtp)
self.edit_local_path = QLineEdit(self.settings.value("xml_path", os.getcwd()))
btn_browse = QPushButton("浏览...")
btn_browse.clicked.connect(self.browse_local_path)
local_path_layout = QHBoxLayout()
local_path_layout.addWidget(self.edit_local_path)
local_path_layout.addWidget(btn_browse)
form.addRow("本地文件夹:", local_path_layout)
form.addRow(QWidget()) # Spacer
# MTP Settings
self.edit_mtp_device = QLineEdit(self.settings.value("mtp_device", "Trizeps VII"))
form.addRow("MTP设备名称:", self.edit_mtp_device)
self.edit_mtp_path = QLineEdit(self.settings.value("mtp_path", "Storage Card/Program Files/xSort/Results/Analyses"))
form.addRow("MTP 内部路径:", self.edit_mtp_path)
layout.addLayout(form)
# Save Button
btn_save = QPushButton("保存配置")
btn_save.setStyleSheet("background-color: #0086fa; color: white; padding: 10px; font-weight: bold;")
btn_save.clicked.connect(lambda: self.save_settings(dialog, rb_local.isChecked()))
layout.addWidget(btn_save)
dialog.exec()
def browse_local_path(self):
directory = QFileDialog.getExistingDirectory(self, "选择本地文件夹", self.edit_local_path.text())
if directory:
self.edit_local_path.setText(directory)
def save_settings(self, dialog, is_local):
self.settings.setValue("sync_mode", "local" if is_local else "mtp")
self.settings.setValue("xml_path", self.edit_local_path.text())
self.settings.setValue("mtp_device", self.edit_mtp_device.text())
self.settings.setValue("mtp_path", self.edit_mtp_path.text())
self.show_info("设置成功", "配置已更新。")
dialog.accept()
def create_bottom_bar(self):
button_bar = QWidget()
button_bar.setStyleSheet("background-color: #e0e0e0; border-top: 1px solid #999;")
button_layout = QHBoxLayout(button_bar)
button_layout.setContentsMargins(10, 10, 10, 10)
button_layout.setSpacing(10)
btn_style = """
QPushButton {
background-color: #0086fa;
color: white;
border-radius: 5px;
padding: 15px;
font-family: 'Microsoft YaHei';
font-size: 19px;
font-weight: bold;
}
QPushButton:pressed {
background-color: #006bbd;
}
"""
# Buttons: [Sync, Submit, Print, Close]
self.btn_sync = QPushButton("同步")
self.btn_sync.setStyleSheet(btn_style)
self.btn_sync.clicked.connect(self.on_sync)
self.btn_submit = QPushButton("提交")
self.btn_submit.setStyleSheet(btn_style)
self.btn_submit.clicked.connect(self.on_submit)
self.btn_close = QPushButton("关闭")
self.btn_close.setStyleSheet(btn_style)
self.btn_close.clicked.connect(self.close)
button_layout.addWidget(self.btn_sync)
button_layout.addWidget(self.btn_submit)
button_layout.addWidget(self.btn_close)
self.main_layout.addWidget(button_bar)
def on_sync(self):
2026-02-28 14:05:55 +08:00
logger.info(f"[{self.page_type}] 开始同步操作")
sync_mode = self.settings.value("sync_mode", "local")
xml_path = None
target_xml_name = ""
if sync_mode == "local":
xml_dir = self.settings.value("xml_path", "xml_data")
if not os.path.exists(xml_dir):
self.show_info("同步失败", f"本地路径不存在: {xml_dir}")
return
xml_files = glob.glob(os.path.join(xml_dir, "*.xml"))
if not xml_files:
self.show_info("同步失败", "本地目录下未找到 .xml 文件")
return
latest_xml = max(xml_files, key=os.path.getmtime)
xml_path = latest_xml
target_xml_name = os.path.basename(latest_xml)
2026-02-28 14:05:55 +08:00
logger.info(f"本地模式,选定文件: {target_xml_name}")
else:
device_name = self.settings.value("mtp_device", "Trizeps VII")
remote_path = self.settings.value("mtp_path", "")
self.show_info("正在同步", f"正在从设备 [{device_name}] 读取最新数据...")
2026-02-28 14:05:55 +08:00
with log_timing_context(f"MTP同步 设备={device_name}", "base_page"):
local_cache, filename = self.mtp_handler.get_latest_xml_windows(device_name, remote_path)
if not local_cache:
self.show_info("同步失败", f"MTP同步错误: {filename}")
return
xml_path = local_cache
target_xml_name = filename
# 1.解析xml
parser = XmlParser()
2026-02-28 14:05:55 +08:00
with log_timing_context("XML解析", "base_page"):
parsed_data, msg = parser.parse_file(xml_path)
if not parsed_data:
self.show_info("同步失败", f"XML解析错误: {msg}")
return
# 2. 写入数据
db = DatabaseManager()
2026-02-28 14:05:55 +08:00
with log_timing_context("DB写入分析数据", "base_page"):
success, db_msg = db.insert_analysis_data(parsed_data)
if not success:
self.show_info("数据库错误", f"插入失败: {db_msg}\n(请检查数据库连接)")
return
2026-02-28 14:05:55 +08:00
with log_timing_context("DB读取最新样本数据", "base_page"):
latest_data = db.get_latest_sample_data()
if latest_data:
self.update_ui_with_data(latest_data)
self.show_info("同步成功", f"已同步 {len(parsed_data)} 条元素数据。\n源文件: {target_xml_name}")
else:
self.show_info("同步异常", "数据插入成功但无法读取回显。")
2026-02-28 14:05:55 +08:00
logger.info(f"[{self.page_type}] 同步操作完成")
def update_ui_with_data(self, data):
### 更新UI界面如果不符合对不符合的元素字体标红并且
pass
def clear_data(self):
"""清空界面所有数据(子类实现)"""
pass
def on_submit(self):
"""提交检验数据到 e_pz_hjqy_import 表"""
2026-02-28 14:05:55 +08:00
logger.info(f"[{self.page_type}] 开始提交检验数据")
try:
# 1. 收集表单数据
gch = self.inputs.get("batch_no").text().strip() if self.inputs.get("batch_no") else ""
heat_number = self.inputs.get("material1").text().strip() if self.inputs.get("material1") else ""
heat_number2 = self.inputs.get("info1").text().strip() if self.inputs.get("info1") else ""
cz = self.inputs.get("spec1").text().strip() if self.inputs.get("spec1") else ""
cz2 = self.inputs.get("spec2").text().strip() if self.inputs.get("spec2") else ""
check_information = self.inputs.get("insp_info_1").text().strip() if self.inputs.get("insp_info_1") else ""
check_information2 = self.inputs.get("insp_info_2").text().strip() if self.inputs.get("insp_info_2") else ""
# 产地/材质 拼接显示时,提交只需要产地 (cd)
display_cd = self.inputs.get("material").text().strip() if self.inputs.get("material") else ""
cd = display_cd.split('/')[0] if '/' in display_cd else display_cd
size = self.inputs.get("spec").text().strip() if self.inputs.get("spec") else ""
# 2. 验证必填字段
if not gch:
self.show_info("提交失败", "工程号不能为空")
return
# 3. 收集所有元素数据
element_names = ["C", "Si", "Mn", "P", "S", "Cr", "Ni", "Mo", "Cu", "Ti", "Nb", "V", "Al", "W", "Co", "N", "Fe", "Se"]
elements = {}
for elem in element_names:
if elem in self.inputs:
value_str = self.inputs[elem].text().strip()
if value_str:
try:
elements[elem] = float(value_str)
except ValueError:
pass
# 4. 取当前用户信息
user_id = self.session.get_user_id()
dept_id = self.session.get_dept_id()
data_corp = self.session.get_data_corp()
if not user_id:
self.show_info("提交失败", "未获取到用户信息,请重新登录")
return
# 5. 构建提交数据
inspection_data = {
"gch": gch,
"heat_number": heat_number,
"heat_number2": heat_number2,
"cz": cz,
"cz2": cz2,
"check_information": check_information,
"check_information2": check_information2,
"cd": cd,
"size": size,
"elements": elements,
"user_id": user_id,
"dept_id": dept_id,
"data_corp": data_corp
}
# 6. 插入数据库
db = DatabaseManager()
2026-02-28 14:05:55 +08:00
with log_timing_context(f"DB提交检验数据 gch={gch}", "base_page"):
success, message = db.insert_inspection_data(inspection_data)
if success:
2026-02-28 14:05:55 +08:00
logger.info(f"[{self.page_type}] 提交成功: {message}")
self.show_info("提交成功", message)
self.clear_data()
else:
2026-02-28 14:05:55 +08:00
logger.warning(f"[{self.page_type}] 提交失败: {message}")
self.show_info("提交失败", message)
except Exception as e:
2026-02-28 14:05:55 +08:00
logger.error(f"[{self.page_type}] 提交异常: {e}", exc_info=True)
self.show_info("提交异常", f"发生错误: {str(e)}")
def show_info(self, title, message):
QMessageBox.information(self, title, message)