324 lines
13 KiB
Python
324 lines
13 KiB
Python
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
|
||
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):
|
||
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)
|
||
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}] 读取最新数据...")
|
||
|
||
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()
|
||
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()
|
||
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
|
||
|
||
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("同步异常", "数据插入成功但无法读取回显。")
|
||
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 表"""
|
||
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()
|
||
with log_timing_context(f"DB提交检验数据 gch={gch}", "base_page"):
|
||
success, message = db.insert_inspection_data(inspection_data)
|
||
|
||
if success:
|
||
logger.info(f"[{self.page_type}] 提交成功: {message}")
|
||
self.show_info("提交成功", message)
|
||
self.clear_data()
|
||
else:
|
||
logger.warning(f"[{self.page_type}] 提交失败: {message}")
|
||
self.show_info("提交失败", message)
|
||
|
||
except Exception as e:
|
||
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) |