Files
dtm-py-all/UI/views/system_settings_view.py

790 lines
35 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
系统设置视图
"""
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QGroupBox, QPushButton, QLineEdit, QComboBox,
QCheckBox, QMessageBox, QTabWidget, QTableWidget, QTableWidgetItem, QHeaderView, QGridLayout, QScrollArea)
from PyQt5.QtCore import Qt
from viewmodels.system_settings_viewmodel import SystemSettingsViewModel
from ui_utils.user_session import UserSession
import json
class SystemSettingsView(QWidget):
def __init__(self):
super().__init__()
# 使用 ViewModel 管理数据(响应式)
self.viewModel = SystemSettingsViewModel(self)
# 获取用户角色
self.user_role = UserSession.get_role()
# 检查权限
if not self._check_permission():
self._show_no_permission_ui()
return
self.init_ui()
self._bind_signals() # 绑定响应式信号
self.viewModel.loadAll() # 加载所有数据
def _check_permission(self):
"""检查用户是否有权限访问系统设置"""
return self.user_role in ['admin', 'super']
def _show_no_permission_ui(self):
"""显示无权限提示界面"""
layout = QVBoxLayout(self)
layout.setSpacing(15)
title_label = QLabel("系统设置")
title_label.setObjectName("title")
layout.addWidget(title_label)
# 无权限提示
tip_widget = QWidget()
tip_layout = QVBoxLayout(tip_widget)
tip_layout.setAlignment(Qt.AlignCenter)
icon_label = QLabel("🔒")
icon_label.setStyleSheet("font-size: 72px;")
icon_label.setAlignment(Qt.AlignCenter)
tip_layout.addWidget(icon_label)
message_label = QLabel("您没有权限访问系统设置模块")
message_label.setStyleSheet("font-size: 18px; color: #666; margin-top: 20px;")
message_label.setAlignment(Qt.AlignCenter)
tip_layout.addWidget(message_label)
detail_label = QLabel("请联系管理员获取相应权限")
detail_label.setStyleSheet("font-size: 14px; color: #999; margin-top: 10px;")
detail_label.setAlignment(Qt.AlignCenter)
tip_layout.addWidget(detail_label)
layout.addWidget(tip_widget)
def init_ui(self):
"""初始化界面Tab 结构)"""
layout = QVBoxLayout(self)
layout.setSpacing(15)
title_label = QLabel("系统设置")
title_label.setObjectName("title")
layout.addWidget(title_label)
self.tab = QTabWidget()
# 根据角色显示不同的Tab
if self.user_role == 'super':
# super 拥有所有4个模块
self.tab.addTab(self._init_machine_tab(), "机台设置")
self.tab.addTab(self._init_phase_tab(), "项目阶段设置")
self.tab.addTab(self._init_user_tab(), "用户及权限设置")
self.tab.addTab(self._init_plc_tab(), "PLC设置")
elif self.user_role == 'admin':
# admin 只有机台设置和项目阶段设置
self.tab.addTab(self._init_machine_tab(), "机台设置")
self.tab.addTab(self._init_phase_tab(), "项目阶段设置")
layout.addWidget(self.tab)
def _bind_signals(self):
"""绑定响应式信号 - 数据变化时自动刷新界面"""
# 机台数据变化 -> 刷新机台表格
self.viewModel.machinesChanged.connect(self._refresh_machine_table)
# 样品阶段数据变化 -> 刷新阶段表格
self.viewModel.phasesChanged.connect(self._refresh_phase_table)
# 仅 super 角色才绑定 PLC 相关信号
if self.user_role == 'super':
# 机台数据变化 -> 刷新 PLC 机台下拉框
self.viewModel.machinesChanged.connect(self._refresh_plc_machine_combo)
# PLC 数据变化 -> 刷新 PLC 表单
self.viewModel.plcDataChanged.connect(self._refresh_plc_form)
# 用户数据变化 -> 刷新用户表格
self.viewModel.usersChanged.connect(self._refresh_user_table)
def _init_machine_tab(self):
w = QWidget()
v = QVBoxLayout(w)
self.machine_table = QTableWidget()
self.machine_table.setColumnCount(12)
self.machine_table.setHorizontalHeaderLabels([
"序号","设备名称","设备编号","设备状态","PLC类型",
"通道1","通道2","通道3","通道4","说明","串口","产品类型"
])
self.machine_table.setSelectionBehavior(QTableWidget.SelectRows)
self.machine_table.setSelectionMode(QTableWidget.SingleSelection)
self.machine_table.horizontalHeader().setStretchLastSection(True)
self.machine_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
self.machine_table.verticalHeader().setVisible(False)
self.machine_table.setAlternatingRowColors(True)
self.machine_table.setEditTriggers(QTableWidget.AllEditTriggers)
v.addWidget(self.machine_table)
hl = QHBoxLayout()
add_btn = QPushButton("+ 增加")
add_btn.clicked.connect(self._on_add_machine_row)
save_btn = QPushButton("✓ 保存")
save_btn.clicked.connect(self._on_save_machines)
delete_btn = QPushButton("× 删除选中行")
delete_btn.setStyleSheet("QPushButton { margin-left: 40px; background-color: #f44336; color: white; }")
delete_btn.clicked.connect(self._on_delete_machine_row)
hl.addWidget(add_btn)
hl.addWidget(save_btn)
hl.addWidget(delete_btn)
hl.addStretch()
v.addLayout(hl)
return w
def _init_phase_tab(self):
w = QWidget()
v = QVBoxLayout(w)
self.phase_table = QTableWidget()
self.phase_table.setColumnCount(4)
self.phase_table.setHorizontalHeaderLabels(["序号","阶段名称","阶段标识","说明"])
self.phase_table.setSelectionBehavior(QTableWidget.SelectRows)
self.phase_table.setSelectionMode(QTableWidget.SingleSelection)
self.phase_table.horizontalHeader().setStretchLastSection(True)
self.phase_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
self.phase_table.verticalHeader().setVisible(False)
self.phase_table.setAlternatingRowColors(True)
self.phase_table.setEditTriggers(QTableWidget.AllEditTriggers)
v.addWidget(self.phase_table)
hl = QHBoxLayout()
add_btn = QPushButton("+ 增加")
add_btn.clicked.connect(self._on_add_phase_row)
save_btn = QPushButton("✓ 保存")
save_btn.clicked.connect(self._on_save_phases)
delete_btn = QPushButton("× 删除选中行")
delete_btn.setStyleSheet("QPushButton { margin-left: 40px; background-color: #f44336; color: white; }")
delete_btn.clicked.connect(self._on_delete_phase_row)
hl.addWidget(add_btn)
hl.addWidget(save_btn)
hl.addWidget(delete_btn)
hl.addStretch()
v.addLayout(hl)
return w
def _init_user_tab(self):
w = QWidget()
v = QVBoxLayout(w)
self.user_table = QTableWidget()
self.user_table.setColumnCount(7)
self.user_table.setHorizontalHeaderLabels(["序号","用户名","用户角色","密码","userid","授权","说明"])
self.user_table.setSelectionBehavior(QTableWidget.SelectRows)
self.user_table.setSelectionMode(QTableWidget.SingleSelection)
self.user_table.horizontalHeader().setStretchLastSection(True)
self.user_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
self.user_table.verticalHeader().setVisible(False)
self.user_table.setAlternatingRowColors(True)
self.user_table.setEditTriggers(QTableWidget.AllEditTriggers)
v.addWidget(self.user_table)
hl = QHBoxLayout()
add_btn = QPushButton("+ 增加")
add_btn.clicked.connect(self._on_add_user_row)
save_btn = QPushButton("✓ 保存")
save_btn.clicked.connect(self._on_save_users)
delete_btn = QPushButton("× 删除选中行")
delete_btn.setStyleSheet("QPushButton { margin-left: 40px; background-color: #f44336; color: white; }")
delete_btn.clicked.connect(self._on_delete_user_row)
hl.addWidget(add_btn)
hl.addWidget(save_btn)
hl.addWidget(delete_btn)
hl.addStretch()
v.addLayout(hl)
return w
def _init_plc_tab(self):
w = QWidget()
v = QVBoxLayout(w)
# 选择机台
top = QHBoxLayout()
top.addWidget(QLabel("选择机台:"))
self.plc_machine_combo = QComboBox()
# 响应式绑定:下拉框变化 -> 更新 ViewModel 的当前机台 ID
self.plc_machine_combo.currentIndexChanged.connect(self._on_plc_machine_changed)
top.addWidget(self.plc_machine_combo)
save_btn = QPushButton("✓ 保存到机台")
save_btn.clicked.connect(self._on_save_plc_for_index)
top.addWidget(save_btn)
top.addStretch()
v.addLayout(top)
# 顶层 PLC 通用参数(一行两个字段)
general = QGroupBox("PLC 通用参数")
g = QGridLayout(general)
g.addWidget(QLabel("站点地址(plcAddress):"), 0, 0)
self.plc_address_input = QLineEdit()
g.addWidget(self.plc_address_input, 0, 1)
g.addWidget(QLabel("串口(com):"), 0, 2)
self.plc_com_input = QLineEdit()
g.addWidget(self.plc_com_input, 0, 3)
g.addWidget(QLabel("串行参数(baudrate JSON):"), 1, 0)
self.plc_baud_input = QLineEdit()
g.addWidget(self.plc_baud_input, 1, 1)
g.addWidget(QLabel("测试类型(testType):"), 1, 2)
self.plc_testtype_input = QLineEdit()
g.addWidget(self.plc_testtype_input, 1, 3)
v.addWidget(general)
# 通道编辑器(每通道使用网格布局,一行两个参数)
self.ch_enable = {}
self.ch_edits = {1:{},2:{},3:{},4:{}}
# 将所有4个通道放在滚动区域
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll_content = QWidget()
scroll_layout = QVBoxLayout(scroll_content)
def build_channel(ch_no):
box = QGroupBox(f"通道{ch_no}")
vl = QVBoxLayout(box)
# 启用状态标签(只读显示)
status_label = QLabel()
status_label.setObjectName(f"ch{ch_no}_status")
vl.addWidget(status_label)
self.ch_enable[ch_no] = status_label # 存储标签而非复选框
# 使用网格布局每行2个参数
grid = QGridLayout()
# 每个参数项:标签 + 输入框
# 按照示例 JSON 字段,布局为 6 行 x 4 列每行2对 label-input
fields = [
("高度(height)", "height"),
("循环次数(cycles)", "cycles"),
("已完成(cyclesFinished)", "cyclesFinished"),
("开始(start)", "start"),
("停止(stop)", "stop"),
("暂停(pause)", "pause"),
("运行状态(runStatus)", "runStatus"),
("方向(direction)", "direction"),
("DUT基础(dutBasic)", "dutBasic"),
("DUT参数(dutParam)", "dutParam"),
("结果开关(resultSwitch)", "resultSwitch"),
("站点计数(stationResultCounter)", "stationResultCounter"),
]
row = 0
col = 0
for label_text, key in fields:
lb = QLabel(label_text)
le = QLineEdit()
grid.addWidget(lb, row, col)
grid.addWidget(le, row, col+1)
self.ch_edits[ch_no][key] = le
# 每行2个参数布局为 4 列:(label1, input1, label2, input2)
col += 2
if col >= 4:
col = 0
row += 1
vl.addLayout(grid)
return box
for ch in range(1,5):
b = build_channel(ch)
scroll_layout.addWidget(b)
scroll.setWidget(scroll_content)
v.addWidget(scroll)
return w
# ============ 响应式刷新方法 ============
def _refresh_machine_table(self):
"""响应式刷新机台表格(由 machinesChanged 信号触发)"""
data = self.viewModel.machines
self.machine_table.setRowCount(len(data))
for i, m in enumerate(data):
self.machine_table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
self.machine_table.setItem(i, 1, QTableWidgetItem(m.get("label", "")))
self.machine_table.setItem(i, 2, QTableWidgetItem(m.get("SN", "")))
self.machine_table.setItem(i, 3, QTableWidgetItem(m.get("status", "")))
self.machine_table.setItem(i, 4, QTableWidgetItem(m.get("type", "")))
# 通道状态: 使用绿色复选框表示启用
cb1 = QCheckBox()
cb1.setChecked(str(m.get("station1", "")).lower() in ("1","01","enabled"))
cb1.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 5, cb1)
cb2 = QCheckBox()
cb2.setChecked(str(m.get("station2", "")).lower() in ("2","02","enabled"))
cb2.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 6, cb2)
cb3 = QCheckBox()
cb3.setChecked(str(m.get("station3", "")).lower() in ("3","03","enabled"))
cb3.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 7, cb3)
cb4 = QCheckBox()
cb4.setChecked(str(m.get("station4", "")).lower() in ("4","04","enabled"))
cb4.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 8, cb4)
self.machine_table.setItem(i, 9, QTableWidgetItem(m.get("description", "")))
self.machine_table.setItem(i, 10, QTableWidgetItem(m.get("com", "")))
self.machine_table.setItem(i, 11, QTableWidgetItem(m.get("testType", "")))
# 将 id 缓存到行的0列的 data 中
self.machine_table.item(i,0).setData(Qt.UserRole, m.get("id"))
self.machine_table.resizeColumnsToContents()
def _refresh_plc_machine_combo(self):
"""响应式刷新 PLC 机台下拉框(由 machinesChanged 信号触发)"""
# 仅在 super 角色且控件存在时执行
if not hasattr(self, 'plc_machine_combo'):
return
machines = self.viewModel.machines
# 临时阻断信号,避免填充过程中多次触发
self.plc_machine_combo.blockSignals(True)
current_id = self.viewModel.currentMachineId
self.plc_machine_combo.clear()
selected_index = -1
for idx, m in enumerate(machines):
self.plc_machine_combo.addItem(m.get("label",""), m.get("id"))
if m.get("id") == current_id:
selected_index = idx
self.plc_machine_combo.blockSignals(False)
# 恢复选中项
if selected_index >= 0:
self.plc_machine_combo.setCurrentIndex(selected_index)
elif self.plc_machine_combo.count() > 0:
self.plc_machine_combo.setCurrentIndex(0)
def _refresh_phase_table(self):
"""响应式刷新样品阶段表格(由 phasesChanged 信号触发)"""
data = self.viewModel.phases
self.phase_table.setRowCount(len(data))
for i, p in enumerate(data):
self.phase_table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
self.phase_table.setItem(i, 1, QTableWidgetItem(p.get("name", "")))
self.phase_table.setItem(i, 2, QTableWidgetItem(p.get("PN", "")))
self.phase_table.setItem(i, 3, QTableWidgetItem(p.get("description", "")))
self.phase_table.item(i,0).setData(Qt.UserRole, p.get("id"))
self.phase_table.resizeColumnsToContents()
def _refresh_user_table(self):
"""响应式刷新用户表格(由 usersChanged 信号触发)"""
# 仅在 super 角色且控件存在时执行
if not hasattr(self, 'user_table'):
return
data = self.viewModel.users
self.user_table.setRowCount(len(data))
for i, u in enumerate(data):
self.user_table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
self.user_table.setItem(i, 1, QTableWidgetItem(u.get("username", "")))
self.user_table.setItem(i, 2, QTableWidgetItem(u.get("role", "")))
self.user_table.setItem(i, 3, QTableWidgetItem(u.get("password", "")))
self.user_table.setItem(i, 4, QTableWidgetItem(u.get("userid", "")))
self.user_table.setItem(i, 5, QTableWidgetItem(u.get("auth", "")))
self.user_table.setItem(i, 6, QTableWidgetItem(u.get("description", "")))
self.user_table.item(i,0).setData(Qt.UserRole, u.get("id"))
self.user_table.resizeColumnsToContents()
def _refresh_plc_form(self):
"""响应式刷新 PLC 表单(由 plcDataChanged 信号触发)"""
# 仅在 super 角色且控件存在时执行
if not hasattr(self, 'plc_address_input'):
return
print(f"Refreshing PLC form--更新PLC表单")
plc = self.viewModel.plcData
# 通用参数
self.plc_address_input.setText(str(plc.get("plcAddress", "")))
self.plc_com_input.setText(str(plc.get("com", "")))
self.plc_testtype_input.setText(str(plc.get("testType", "")))
# baudrate
baud = plc.get("baudrate", {})
if isinstance(baud, dict):
self.plc_baud_input.setText(json.dumps(baud, ensure_ascii=False))
else:
self.plc_baud_input.setText(str(baud))
# 通道启用状态(只读显示)
def set_status(ch_no, enabled):
label = self.ch_enable[ch_no]
if enabled:
label.setText("✓ 已启用")
label.setStyleSheet("color: green; font-weight: bold;")
else:
label.setText("✗ 未启用")
label.setStyleSheet("color: gray;")
set_status(1, plc.get("status1", False))
set_status(2, plc.get("status2", False))
set_status(3, plc.get("status3", False))
set_status(4, plc.get("status4", False))
# 通道参数
def fill_channel(ch_no, reg_data):
if isinstance(reg_data, dict):
data = reg_data
else:
data = {}
for key, le in self.ch_edits[ch_no].items():
le.setText(str(data.get(key, "")))
fill_channel(1, plc.get("register01",{}))
fill_channel(2, plc.get("register02",{}))
fill_channel(3, plc.get("register03",{}))
fill_channel(4, plc.get("register04",{}))
def _on_plc_machine_changed(self):
"""下拉框切换机台时,更新 ViewModel 的当前机台 ID响应式触发 PLC 数据刷新)"""
idx = self.plc_machine_combo.currentIndex()
if idx >= 0:
print(f"Switching to machine index: {idx}")
machine_id = self.plc_machine_combo.itemData(idx)
self.viewModel.setCurrentMachineId(machine_id) # 设置后自动触发 plcDataChanged 信号
# ============ 原有事件处理(改为调用 ViewModel ============
def _load_all_tabs(self):
self._load_machine_table()
self._load_phase_table()
self._load_user_table()
# 填充 PLC 机台选择
machines = self.model.load_machines()
# 临时阻断信号,避免填充过程中多次触发
self.plc_machine_combo.blockSignals(True)
self.plc_machine_combo.clear()
for m in machines:
# 用 label 作为显示文本id 作为数据
self.plc_machine_combo.addItem(m.get("label",""), m.get("id"))
self.plc_machine_combo.blockSignals(False)
# 绑定信号(只绑定一次)
try:
self.plc_machine_combo.currentIndexChanged.disconnect()
except:
pass
self.plc_machine_combo.currentIndexChanged.connect(self._on_load_plc_for_index)
# 如果有机台,默认加载第一个
if self.plc_machine_combo.count() > 0:
self.plc_machine_combo.setCurrentIndex(0)
self._on_load_plc_for_index()
# 机台设置
def _load_machine_table(self):
data = self.model.load_machines()
self.machine_table.setRowCount(len(data))
for i, m in enumerate(data):
self.machine_table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
self.machine_table.setItem(i, 1, QTableWidgetItem(m.get("label", "")))
self.machine_table.setItem(i, 2, QTableWidgetItem(m.get("SN", "")))
self.machine_table.setItem(i, 3, QTableWidgetItem(m.get("status", "")))
self.machine_table.setItem(i, 4, QTableWidgetItem(m.get("type", "")))
# 通道状态: 使用绿色复选框表示启用
cb1 = QCheckBox()
cb1.setChecked(str(m.get("status1", "")).lower() in ("1","true","enabled"))
cb1.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 5, cb1)
cb2 = QCheckBox()
cb2.setChecked(str(m.get("status2", "")).lower() in ("1","true","enabled"))
cb2.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 6, cb2)
cb3 = QCheckBox()
cb3.setChecked(str(m.get("status3", "")).lower() in ("1","true","enabled"))
cb3.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 7, cb3)
cb4 = QCheckBox()
cb4.setChecked(str(m.get("status4", "")).lower() in ("1","true","enabled"))
cb4.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(i, 8, cb4)
self.machine_table.setItem(i, 9, QTableWidgetItem(m.get("description", "")))
self.machine_table.setItem(i, 10, QTableWidgetItem(m.get("com", "")))
# 将 id 缓存到行的第0列的 data 中
self.machine_table.item(i,0).setData(Qt.UserRole, m.get("id"))
self.machine_table.resizeColumnsToContents()
def _on_add_machine_row(self):
r = self.machine_table.rowCount()
self.machine_table.insertRow(r)
self.machine_table.setItem(r, 0, QTableWidgetItem(str(r + 1)))
self.machine_table.setItem(r, 1, QTableWidgetItem(""))
self.machine_table.setItem(r, 2, QTableWidgetItem(""))
self.machine_table.setItem(r, 3, QTableWidgetItem(""))
self.machine_table.setItem(r, 4, QTableWidgetItem(""))
# 通道启用复选框 - 绿色样式
cb1 = QCheckBox()
cb1.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(r, 5, cb1)
cb2 = QCheckBox()
cb2.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(r, 6, cb2)
cb3 = QCheckBox()
cb3.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(r, 7, cb3)
cb4 = QCheckBox()
cb4.setStyleSheet("QCheckBox::indicator:checked { background-color: #4CAF50; border: 2px solid #4CAF50; }")
self.machine_table.setCellWidget(r, 8, cb4)
self.machine_table.setItem(r, 9, QTableWidgetItem(""))
self.machine_table.setItem(r, 10, QTableWidgetItem(""))
def _on_save_machines(self):
"""保存机台设置(调用 ViewModel
重要只传入机台基本信息和通道启用状态不传入 PLC 参数
"""
rows = self.machine_table.rowCount()
to_save = []
for i in range(rows):
def get(i,c):
item = self.machine_table.item(i,c)
return item.text().strip() if item else ""
def get_cb(i,c,value):
w = self.machine_table.cellWidget(i,c)
try:
return value if (w and isinstance(w, QCheckBox) and w.isChecked()) else ""
except Exception:
return ""
# 只传入机台设置页的字段,不包含 PLC 相关字段
m = {
"id": self.machine_table.item(i,0).data(Qt.UserRole),
"label": get(i,1),
"SN": get(i,2),
"status": get(i,3),
"type": get(i,4),
"testType": get(i,11), # 产品类型
"station1": get_cb(i,5,"01"), # 通道启用状态
"station2": get_cb(i,6,"02"),
"station3": get_cb(i,7,"03"),
"station4": get_cb(i,8,"04"),
"description": get(i,9),
"com": get(i,10),
# 不传入 PLC 相关字段,保持数据库中的原有值
# "station1", "station2", "station3", "station4",
# "plcAddress", "register01", "register02", "register03", "register04",
# "baudrate", "testType"
}
to_save.append(m)
self.viewModel.saveMachines(to_save) # 调用 ViewModel自动触发响应式刷新
QMessageBox.information(self, "保存成功", "机台设置已保存")
def _on_delete_machine_row(self):
"""删除选中的机台行"""
selected_rows = self.machine_table.selectionModel().selectedRows()
if not selected_rows:
QMessageBox.warning(self, "提示", "请先选中要删除的行")
return
# 确认删除
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除选中的 {len(selected_rows)} 条机台记录吗?\n\n注意:此操作不可恢复!",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply == QMessageBox.No:
return
# 收集要删除的 ID
machine_ids = []
for index in selected_rows:
row = index.row()
id_item = self.machine_table.item(row, 0)
if id_item:
machine_id = id_item.data(Qt.UserRole)
if machine_id:
machine_ids.append(machine_id)
# 调用 ViewModel 删除
if machine_ids:
success = self.viewModel.deleteMachines(machine_ids)
if success:
QMessageBox.information(self, "成功", f"已删除 {len(machine_ids)} 条机台记录")
else:
QMessageBox.warning(self, "错误", "删除失败,请重试")
# 样品阶段设置(旧手动加载方法,已被响应式 _refresh_phase_table 取代)
def _load_phase_table(self):
"""已废弃,使用响应式 _refresh_phase_table 代替"""
pass
def _on_add_phase_row(self):
r = self.phase_table.rowCount()
self.phase_table.insertRow(r)
self.phase_table.setItem(r, 0, QTableWidgetItem(str(r + 1)))
for c in range(1, 4):
self.phase_table.setItem(r, c, QTableWidgetItem(""))
def _on_save_phases(self):
"""保存样品阶段设置(调用 ViewModel"""
rows = self.phase_table.rowCount()
phases = []
for i in range(rows):
def get(i,c):
item = self.phase_table.item(i,c)
return item.text().strip() if item else ""
p = {
"id": self.phase_table.item(i,0).data(Qt.UserRole),
"name": get(i,1),
"PN": get(i,2),
"description": get(i,3),
}
phases.append(p)
self.viewModel.savePhases(phases) # 调用 ViewModel自动触发响应式刷新
QMessageBox.information(self, "保存成功", "样品阶段设置已保存")
def _on_delete_phase_row(self):
"""删除选中的阶段行"""
selected_rows = self.phase_table.selectionModel().selectedRows()
if not selected_rows:
QMessageBox.warning(self, "提示", "请先选中要删除的行")
return
# 确认删除
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除选中的 {len(selected_rows)} 条阶段记录吗?\n\n注意:此操作不可恢复!",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply == QMessageBox.No:
return
# 收集要删除的 ID
phase_ids = []
for index in selected_rows:
row = index.row()
id_item = self.phase_table.item(row, 0)
if id_item:
phase_id = id_item.data(Qt.UserRole)
if phase_id:
phase_ids.append(phase_id)
# 调用 ViewModel 删除
if phase_ids:
success = self.viewModel.deletePhases(phase_ids)
if success:
QMessageBox.information(self, "成功", f"已删除 {len(phase_ids)} 条阶段记录")
else:
QMessageBox.warning(self, "错误", "删除失败,请重试")
# 用户及权限设置(旧手动加载方法,已被响应式 _refresh_user_table 取代)
def _load_user_table(self):
"""已废弃,使用响应式 _refresh_user_table 代替"""
pass
def _on_add_user_row(self):
r = self.user_table.rowCount()
self.user_table.insertRow(r)
self.user_table.setItem(r, 0, QTableWidgetItem(str(r + 1)))
for c in range(1, 7):
self.user_table.setItem(r, c, QTableWidgetItem(""))
def _on_save_users(self):
"""保存用户设置(调用 ViewModel"""
rows = self.user_table.rowCount()
users = []
for i in range(rows):
def get(i,c):
item = self.user_table.item(i,c)
return item.text().strip() if item else ""
u = {
"id": self.user_table.item(i,0).data(Qt.UserRole),
"username": get(i,1),
"role": get(i,2),
"password": get(i,3),
"userid": get(i,4),
"auth": get(i,5),
"description": get(i,6),
}
users.append(u)
self.viewModel.saveUsers(users) # 调用 ViewModel自动触发响应式刷新
QMessageBox.information(self, "保存成功", "用户及权限设置已保存")
def _on_delete_user_row(self):
"""删除选中的用户行"""
selected_rows = self.user_table.selectionModel().selectedRows()
if not selected_rows:
QMessageBox.warning(self, "提示", "请先选中要删除的行")
return
# 确认删除
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除选中的 {len(selected_rows)} 条用户记录吗?\n\n注意:此操作不可恢复!",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No
)
if reply == QMessageBox.No:
return
# 收集要删除的 ID
user_ids = []
for index in selected_rows:
row = index.row()
id_item = self.user_table.item(row, 0)
if id_item:
user_id = id_item.data(Qt.UserRole)
if user_id:
user_ids.append(user_id)
# 调用 ViewModel 删除
if user_ids:
success = self.viewModel.deleteUsers(user_ids)
if success:
QMessageBox.information(self, "成功", f"已删除 {len(user_ids)} 条用户记录")
else:
QMessageBox.warning(self, "错误", "删除失败,请重试")
# PLC: 旧的手动加载方法(已被响应式 _refresh_plc_form 取代,保留用于兼容)
def _on_load_plc_for_index(self):
"""已废弃,使用响应式 _refresh_plc_form 代替"""
pass
def _on_save_plc_for_index(self):
"""保存 PLC 设置(响应式,调用 ViewModel"""
# 收集每通道参数为 dict
def collect(ch_no):
payload = {}
for key, le in self.ch_edits[ch_no].items():
val = le.text().strip()
if val != "":
payload[key] = val
return payload
# baudrate 从输入框解析,容错处理
baud_text = self.plc_baud_input.text().strip()
try:
baud_obj = json.loads(baud_text) if baud_text else {"baudrate": 19200, "stopbits": 1, "bytesize": 8, "parity": "E"}
except Exception:
baud_obj = {"baudrate": 19200, "stopbits": 1, "bytesize": 8, "parity": "E"}
# 构建更新数据register01~04 和 baudrate 都为 dictViewModel 会自动转换为 JSON 字符串)
plc_updates = {
"plcAddress": self.plc_address_input.text().strip(),
"com": self.plc_com_input.text().strip(),
"baudrate": baud_obj, # dict 格式
"testType": self.plc_testtype_input.text().strip(),
# 通道启用状态不在此页修改,保持原值
"register01": collect(1), # dict 格式
"register02": collect(2), # dict 格式
"register03": collect(3), # dict 格式
"register04": collect(4), # dict 格式
}
# 调用 ViewModel 保存(自动触发响应式刷新)
success = self.viewModel.savePlcData(plc_updates)
if success:
QMessageBox.information(self, "保存成功", "PLC 设置已保存到机台")
else:
QMessageBox.warning(self, "保存失败", "请先选择机台")