这是使用PyQT5作为UI的首次提交,将后端和UI合并到1个工程中,统一使用了Python,没有使用JS和HTML

This commit is contained in:
2025-12-14 12:13:19 +08:00
commit 872b181703
122 changed files with 70944 additions and 0 deletions

253
UI/views/dut_form_dialog.py Normal file
View File

@@ -0,0 +1,253 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
DUT表单对话框全局复用
- 新建/编辑公用一个对话框,根据模式禁用部分字段
- 数据以 dict(dut_form) 形式在模块间传递
- 设备分配为二级选择:机台 -> 通道
"""
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QFormLayout, QLineEdit, QComboBox,
QTextEdit, QPushButton, QLabel, QWidget
)
from PyQt5.QtCore import Qt
class DUTFormDialog(QDialog):
def __init__(self, mode="create", dut_form=None, lock_fields=None, system_model=None, parent=None):
super().__init__(parent)
self.mode = mode # "create" | "edit"
self.dut_form = dut_form or {}
self.lock_fields = set(lock_fields or [])
self.system_model = system_model # 用于加载机台数据
self.setWindowTitle("编辑试验样品详情" if self.mode == "edit" else "新建试验样品")
self.setModal(True)
self.resize(800, 480)
# 机台数据缓存
self.machines = []
self.current_machine = None
self._build_ui()
self._load_machines() # 加载机台数据
self._fill_form(self.dut_form)
self._apply_lock()
def _build_ui(self):
layout = QVBoxLayout(self)
layout.setContentsMargins(20, 20, 20, 20)
layout.setSpacing(12)
#title = QLabel("编辑试验样品详情" if self.mode == "edit" else "新建试验样品详情")
#title.setObjectName("title")
#title.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
#layout.addWidget(title)
form = QFormLayout()
form.setLabelAlignment(Qt.AlignRight)
form.setFormAlignment(Qt.AlignTop)
form.setHorizontalSpacing(16)
form.setVerticalSpacing(12)
# 左右两列容器
row = QHBoxLayout()
left = QVBoxLayout()
right = QVBoxLayout()
# 左列控件
self.input_SN = QLineEdit()
self.input_project = QLineEdit()
self.input_testReq = QLineEdit()
self.input_phase = QComboBox()
self.input_phase.setEditable(True)
self.input_phase.addItems(["A Sample", "B Sample", "C Sample", "Work Sample", "阶段1", "阶段2"]) # 示例项
# 右列控件 - 设备分配(二级选择)
self.input_dtMachine = QComboBox() # 机台选择
self.input_dtMachine.setEditable(False)
self.input_dtMachine.addItem("", None) # 空选项
self.input_dtMachine.currentIndexChanged.connect(self._on_machine_changed)
self.input_station = QComboBox() # 通道选择
self.input_station.setEditable(False)
self.input_station.addItem("", None) # 空选项
self.input_weeks = QLineEdit()
self.input_workOrder = QLineEdit()
self.input_inspector = QLineEdit()
# 说明
self.input_description = QTextEdit()
self.input_description.setPlaceholderText("请输入内容")
# 左列布局
left_form = QFormLayout()
left_form.setLabelAlignment(Qt.AlignRight)
left_form.addRow("* 产品序列号", self.input_SN)
left_form.addRow("项目代码", self.input_project)
left_form.addRow("项目方案", self.input_testReq)
left_form.addRow("项目阶段", self.input_phase)
left.addLayout(left_form)
# 右列布局
right_form = QFormLayout()
right_form.setLabelAlignment(Qt.AlignRight)
right_form.addRow("机台选择", self.input_dtMachine)
right_form.addRow("通道选择", self.input_station)
right_form.addRow("测试周次", self.input_weeks)
right_form.addRow("工单名称", self.input_workOrder)
right_form.addRow("测试人员", self.input_inspector)
right.addLayout(right_form)
row.addLayout(left, 1)
row.addLayout(right, 1)
layout.addLayout(row)
# 说明一行单独处理
desc_form = QFormLayout()
desc_form.setLabelAlignment(Qt.AlignRight)
desc_form.addRow("说明", self.input_description)
layout.addLayout(desc_form)
# 底部按钮
btn_row = QHBoxLayout()
btn_row.addStretch()
self.btn_submit = QPushButton("修改" if self.mode == "edit" else "保存")
self.btn_close = QPushButton("关闭")
btn_row.addWidget(self.btn_submit)
btn_row.addWidget(self.btn_close)
layout.addLayout(btn_row)
self.btn_submit.clicked.connect(self.accept)
self.btn_close.clicked.connect(self.reject)
def _load_machines(self):
"""加载机台数据"""
if not self.system_model:
return
try:
self.machines = self.system_model.load_machines()
# 填充机台下拉框
self.input_dtMachine.clear()
self.input_dtMachine.addItem("", None) # 空选项
for machine in self.machines:
sn = machine.get("SN", "")
label = machine.get("label", "")
display = f"{sn} - {label}" if label else sn
self.input_dtMachine.addItem(display, machine)
except Exception as e:
print(f"加载机台数据失败: {e}")
def _on_machine_changed(self, index):
"""机台选择变化时更新通道列表"""
self.input_station.clear()
self.input_station.addItem("", None) # 空选项
machine = self.input_dtMachine.currentData()
if not machine:
return
self.current_machine = machine
# 添加有效的通道station1-4
for i in range(1, 5):
station_key = f"station{i}"
status_key = f"status{i}"
try:
# 安全获取通道名称处理None和空值
station_name = machine.get(station_key)
if station_name is None:
continue
station_name = str(station_name).strip()
station_status = machine.get(status_key, "")
# 过滤掉空值和 NA/N/A 的通道
if station_name and station_name.upper() not in ['NA', 'N/A']:
display = f"{i:02d} - {station_name}"
if station_status:
display += f" ({station_status})"
self.input_station.addItem(display, f"{i:02d}")
except Exception as e:
print(f"加载通道数据失败: {e}")
def _fill_form(self, f):
# 将已有数据填充到控件
self.input_SN.setText(str(f.get("SN", "")))
self.input_project.setText(str(f.get("project", "")))
self.input_testReq.setText(str(f.get("testReq", "")))
phase_val = str(f.get("phase", ""))
if phase_val:
idx = self.input_phase.findText(phase_val)
if idx >= 0:
self.input_phase.setCurrentIndex(idx)
else:
self.input_phase.setEditText(phase_val)
# 设备分配:使用 Model 解析后的 dtMachine 和 station 字段
dtm = f.get("dtMachine", "").strip()
station = f.get("station", "").strip()
# 选中机台
if dtm:
for i in range(self.input_dtMachine.count()):
machine = self.input_dtMachine.itemData(i)
if machine and machine.get("SN") == dtm:
self.input_dtMachine.setCurrentIndex(i)
break
# 选中通道(需要在机台选中后)
if station:
for i in range(self.input_station.count()):
station_num = self.input_station.itemData(i)
if station_num == station:
self.input_station.setCurrentIndex(i)
break
self.input_weeks.setText(str(f.get("weeks", "")))
self.input_workOrder.setText(str(f.get("workOrder", "")))
self.input_inspector.setText(str(f.get("inspector", "")))
self.input_description.setPlainText(str(f.get("description", "")))
def _apply_lock(self):
# 根据锁定字段禁用编辑(默认在编辑模式锁定 SN
defaults = {"SN"} if self.mode == "edit" else set()
locked = defaults | self.lock_fields
if "SN" in locked:
self.input_SN.setDisabled(True)
# 注意:设备分配在编辑模式下是可以更改的
def get_form_dict(self):
# 以 dut_form 的结构返回数据
dut_form = {
"SN": self.input_SN.text().strip(),
"project": self.input_project.text().strip(),
"testReq": self.input_testReq.text().strip(),
"phase": self.input_phase.currentText().strip(),
"weeks": int(self.input_weeks.text() or 0),
"workOrder": self.input_workOrder.text().strip(),
"inspector": self.input_inspector.text().strip(),
"description": self.input_description.toPlainText().strip(),
}
# 设备分配:从二级选择中获取 dtMachine 和 station
# Model 会自动将这两个字段合成为 JSON 字符串存入 stationAssigned
machine = self.input_dtMachine.currentData()
station_num = self.input_station.currentData()
if machine and station_num:
dut_form["dtMachine"] = machine.get("SN", "")
dut_form["station"] = station_num
else:
dut_form["dtMachine"] = ""
dut_form["station"] = ""
# 保留可能存在的 id 等字段
if "id" in self.dut_form:
dut_form["id"] = self.dut_form["id"]
return dut_form