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

790 lines
35 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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, "保存失败", "请先选择机台")