优化历史记录界面样式

main
zcwBit 3 months ago
parent c9aa04fa73
commit d6697b4caa

@ -0,0 +1,645 @@
/* ==================== DCS2025 历史查看器样式 - 极度紧凑版 ==================== */
/* ==================== 主容器和基础样式 ==================== */
QWidget {
background-color: #FFFFFF;
color: #374151;
font-family: "PingFangSC-Regular", "Microsoft YaHei", sans-serif;
font-size: 11px;
margin: 0px;
padding: 0px;
}
/* ==================== 搜索区域样式 ==================== */
QLabel {
font-size: 11px;
color: #374151;
font-weight: 500;
padding: 0px;
margin: 0px 3px 0px 0px;
}
QLineEdit {
background-color: #FFFFFF;
border: 1px solid #D1D5DB;
border-radius: 2px;
padding: 1px 4px;
font-size: 11px;
color: #374151;
selection-background-color: #EBF8FF;
selection-color: #1E40AF;
min-height: 14px;
max-height: 18px;
}
QLineEdit:focus {
border-color: #3B82F6;
outline: none;
background-color: #FEFEFE;
border-width: 1px;
}
QLineEdit:hover {
border-color: #9CA3AF;
background-color: #FEFEFE;
}
QLineEdit::placeholder {
color: #9CA3AF;
font-style: italic;
}
/* ==================== 表格通用样式 ==================== */
QTableView {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 3px;
gridline-color: #F3F4F6;
font-size: 10px;
color: #374151;
selection-background-color: #EBF8FF;
selection-color: #1E40AF;
outline: none;
show-decoration-selected: 1;
alternate-background-color: #F9FAFB;
margin: 0px;
padding: 0px;
}
QTableView::item {
padding: 1px 3px;
border: none;
min-height: 12px;
}
QTableView::item:selected {
background-color: #EBF8FF;
color: #1E40AF;
border: none;
}
QTableView::item:hover {
background-color: #F0F9FF;
color: #1F2937;
}
QTableView::item:selected:hover {
background-color: #DBEAFE;
color: #1565C0;
}
QTableView::item:focus {
background-color: #EBF8FF;
color: #1E40AF;
outline: none;
border: none;
}
/* ==================== 历史记录表格专用样式 ==================== */
QTableView#historyTable {
max-height: 100px; /* 极小的最大高度 */
min-height: 50px; /* 极小的最小高度 */
font-size: 9px; /* 极小的字体 */
}
QTableView#historyTable::item {
padding: 0px 2px; /* 极度紧凑的内边距 */
min-height: 10px; /* 极小的行高 */
}
/* ==================== 步骤详情表格专用样式 ==================== */
QTableView:not(#historyTable) {
min-height: 150px; /* 步骤详情表格最小高度 */
font-size: 10px;
}
QTableView:not(#historyTable)::item {
padding: 2px 4px; /* 适中的内边距 */
min-height: 14px; /* 适中的行高 */
}
/* ==================== 表格头部样式 ==================== */
QTableView QHeaderView {
background-color: transparent;
border: none;
outline: none;
}
QTableView QHeaderView::section {
background-color: #F8F9FA;
color: #374151;
font-weight: 600;
font-size: 9px;
padding: 1px 3px;
border: 1px solid #E5E7EB;
border-left: none;
text-align: center;
min-height: 10px;
}
/* 历史记录表格头部 - 极度紧凑 */
QTableView#historyTable QHeaderView::section {
padding: 0px 2px; /* 极小的头部内边距 */
font-size: 8px; /* 极小的字体 */
font-weight: 600;
min-height: 8px;
}
QTableView QHeaderView::section:first {
border-left: 1px solid #E5E7EB;
border-top-left-radius: 3px;
}
QTableView QHeaderView::section:last {
border-top-right-radius: 3px;
}
QTableView QHeaderView::section:hover {
background-color: #F3F4F6;
color: #1F2937;
}
QTableView QHeaderView::section:pressed {
background-color: #E5E7EB;
color: #111827;
}
/* 垂直表头隐藏 */
QTableView QHeaderView::section:vertical {
border: none;
background-color: transparent;
}
/* ==================== 滚动条样式 ==================== */
QTableView QScrollBar:vertical {
background-color: #F9FAFB;
width: 6px;
border-radius: 3px;
border: none;
margin: 0px;
}
QTableView QScrollBar::handle:vertical {
background-color: #D1D5DB;
border-radius: 3px;
min-height: 10px;
margin: 1px;
}
QTableView QScrollBar::handle:vertical:hover {
background-color: #9CA3AF;
}
QTableView QScrollBar::handle:vertical:pressed {
background-color: #6B7280;
}
QTableView QScrollBar::add-line:vertical,
QTableView QScrollBar::sub-line:vertical {
border: none;
background: none;
height: 0px;
}
QTableView QScrollBar::add-page:vertical,
QTableView QScrollBar::sub-page:vertical {
background: none;
}
QTableView QScrollBar:horizontal {
background-color: #F9FAFB;
height: 6px;
border-radius: 3px;
border: none;
margin: 0px;
}
QTableView QScrollBar::handle:horizontal {
background-color: #D1D5DB;
border-radius: 3px;
min-width: 10px;
margin: 1px;
}
QTableView QScrollBar::handle:horizontal:hover {
background-color: #9CA3AF;
}
QTableView QScrollBar::handle:horizontal:pressed {
background-color: #6B7280;
}
QTableView QScrollBar::add-line:horizontal,
QTableView QScrollBar::sub-line:horizontal {
border: none;
background: none;
width: 0px;
}
QTableView QScrollBar::add-page:horizontal,
QTableView QScrollBar::sub-page:horizontal {
background: none;
}
/* ==================== 按钮样式 ==================== */
QPushButton {
font-size: 10px;
font-weight: 600;
padding: 2px 6px;
border-radius: 2px;
min-width: 50px;
min-height: 16px;
border: 1px solid;
margin: 0px 1px;
}
/* 删除历史记录按钮 - 红色主题 */
QPushButton[text="删除历史记录"] {
color: #DC2626;
background-color: #FEF2F2;
border-color: #FECACA;
}
QPushButton[text="删除历史记录"]:hover {
background-color: #FEE2E2;
border-color: #FCA5A5;
color: #B91C1C;
}
QPushButton[text="删除历史记录"]:pressed {
background-color: #FECACA;
border-color: #F87171;
color: #991B1B;
}
QPushButton[text="删除历史记录"]:disabled {
background-color: #F3F4F6;
color: #9CA3AF;
border-color: #E5E7EB;
}
/* 导出报告按钮 - 绿色主题 */
QPushButton[text="导出报告"] {
color: #059669;
background-color: #ECFDF5;
border-color: #BBF7D0;
}
QPushButton[text="导出报告"]:hover {
background-color: #D1FAE5;
border-color: #86EFAC;
color: #047857;
}
QPushButton[text="导出报告"]:pressed {
background-color: #A7F3D0;
border-color: #6EE7B7;
color: #065F46;
}
QPushButton[text="导出报告"]:disabled {
background-color: #F3F4F6;
color: #9CA3AF;
border-color: #E5E7EB;
}
/* ==================== 分割器样式 ==================== */
QSplitter {
background-color: #FFFFFF;
margin: 0px;
padding: 0px;
}
QSplitter::handle {
background-color: #E5E7EB;
border: 1px solid #D1D5DB;
border-radius: 1px;
}
QSplitter::handle:horizontal {
height: 2px;
margin: 0px;
}
QSplitter::handle:vertical {
width: 2px;
margin: 0px;
}
QSplitter::handle:hover {
background-color: #D1D5DB;
border-color: #9CA3AF;
}
QSplitter::handle:pressed {
background-color: #9CA3AF;
border-color: #6B7280;
}
/* ==================== 右键菜单样式 ==================== */
QMenu {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 3px;
padding: 1px 0;
font-size: 10px;
color: #374151;
}
QMenu::item {
padding: 3px 10px;
margin: 1px 1px;
border-radius: 1px;
}
QMenu::item:selected {
background-color: #F0F9FF;
color: #1F2937;
}
QMenu::item:pressed {
background-color: #EBF8FF;
color: #1E40AF;
}
QMenu::separator {
height: 1px;
background-color: #E5E7EB;
margin: 1px 4px;
}
QMenu::icon {
padding-left: 1px;
}
/* ==================== 对话框样式 ==================== */
QDialog {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 4px;
}
QDialog QLabel {
font-size: 10px;
color: #374151;
font-weight: 500;
padding: 0px;
}
/* 步骤详情信息组 */
QWidget#stepDetailInfoGroup {
background-color: #F8F9FA;
border: 1px solid #E5E7EB;
border-radius: 3px;
padding: 4px;
margin: 1px 0;
}
/* 步骤描述文本 */
QLineEdit#stepDescriptionText {
background-color: #F9FAFB;
border: 1px solid #E5E7EB;
border-radius: 2px;
padding: 2px 4px;
font-size: 10px;
color: #374151;
font-weight: 500;
}
/* 步骤结果文本 */
QLineEdit#stepResultText {
border: 1px solid #E5E7EB;
border-radius: 2px;
padding: 2px 4px;
font-size: 10px;
font-weight: 500;
}
QLineEdit#stepResultText[status="success"] {
background-color: #ECFDF5;
color: #065F46;
border-color: #BBF7D0;
}
QLineEdit#stepResultText[status="error"] {
background-color: #FEF2F2;
color: #991B1B;
border-color: #FECACA;
}
QLineEdit#stepResultText[status="default"] {
background-color: #F9FAFB;
color: #374151;
border-color: #E5E7EB;
}
/* 对话框按钮 */
QDialog QPushButton {
font-size: 10px;
font-weight: 600;
padding: 3px 10px;
border-radius: 2px;
min-width: 50px;
border: 1px solid;
}
QDialogButtonBox QPushButton {
color: #1D4ED8;
background-color: #EBF8FF;
border-color: #BFDBFE;
}
QDialogButtonBox QPushButton:hover {
background-color: #DBEAFE;
border-color: #93C5FD;
color: #1E40AF;
}
QDialogButtonBox QPushButton:pressed {
background-color: #BFDBFE;
border-color: #60A5FA;
color: #1E3A8A;
}
/* ==================== 工具提示样式 ==================== */
QToolTip {
background-color: #1F2937;
color: #FFFFFF;
border: none;
border-radius: 2px;
padding: 2px 4px;
font-size: 9px;
font-weight: 500;
}
/* ==================== 消息框样式 ==================== */
QMessageBox {
background-color: #FFFFFF;
color: #374151;
font-size: 10px;
border-radius: 4px;
}
QMessageBox QPushButton {
font-size: 10px;
font-weight: 600;
padding: 3px 10px;
border-radius: 2px;
min-width: 50px;
border: 1px solid;
}
QMessageBox QPushButton[text="OK"],
QMessageBox QPushButton[text="Yes"] {
color: #1D4ED8;
background-color: #EBF8FF;
border-color: #BFDBFE;
}
QMessageBox QPushButton[text="OK"]:hover,
QMessageBox QPushButton[text="Yes"]:hover {
background-color: #DBEAFE;
border-color: #93C5FD;
color: #1E40AF;
}
QMessageBox QPushButton[text="Cancel"],
QMessageBox QPushButton[text="No"] {
color: #6B7280;
background-color: #F9FAFB;
border-color: #E5E7EB;
}
QMessageBox QPushButton[text="Cancel"]:hover,
QMessageBox QPushButton[text="No"]:hover {
background-color: #F3F4F6;
border-color: #D1D5DB;
color: #4B5563;
}
/* ==================== 状态指示器样式 ==================== */
/* 成功状态 */
QTableView::item[status="success"] {
background-color: #ECFDF5;
color: #065F46;
border-left: 1px solid #10B981;
}
/* 失败状态 */
QTableView::item[status="failed"] {
background-color: #FEF2F2;
color: #991B1B;
border-left: 1px solid #EF4444;
}
/* 部分成功状态 */
QTableView::item[status="partial"] {
background-color: #FEF3C7;
color: #92400E;
border-left: 1px solid #F59E0B;
}
/* 未知状态 */
QTableView::item[status="unknown"] {
background-color: #F3F4F6;
color: #6B7280;
border-left: 1px solid #9CA3AF;
}
/* ==================== 焦点样式 ==================== */
QWidget:focus {
outline: none;
}
QTableView:focus {
border-color: #3B82F6;
border-width: 1px;
}
QPushButton:focus {
border-color: #3B82F6;
border-width: 1px;
}
/* ==================== 极度紧凑布局优化 ==================== */
/* 移除所有不必要的边距和内边距 */
QWidget {
margin: 0px;
padding: 0px;
}
/* 搜索区域极度紧凑化 */
QHBoxLayout {
margin: 1px;
spacing: 2px;
}
/* 按钮区域极度紧凑化 */
QHBoxLayout QPushButton {
margin: 0px 1px;
}
/* 分割器区域极度紧凑化 */
QSplitter {
margin: 0px;
padding: 0px;
spacing: 0px;
}
/* 表格边距优化 */
QTableView {
margin: 0px;
padding: 0px;
}
/* 对话框内容极度紧凑化 */
QDialog {
padding: 4px;
}
QDialog QVBoxLayout {
margin: 1px;
spacing: 2px;
}
/* ==================== 超紧凑模式 ==================== */
QWidget[size="ultra-compact"] {
font-size: 9px;
}
QWidget[size="ultra-compact"] QPushButton {
padding: 1px 4px;
font-size: 9px;
min-height: 12px;
min-width: 40px;
}
QWidget[size="ultra-compact"] QLineEdit {
padding: 0px 2px;
font-size: 9px;
min-height: 8px;
}
QWidget[size="ultra-compact"] QTableView::item {
padding: 0px 1px;
min-height: 8px;
}
QWidget[size="ultra-compact"] QTableView#historyTable::item {
padding: 0px 1px;
min-height: 6px;
}
QWidget[size="ultra-compact"] QTableView#historyTable {
max-height: 60px;
min-height: 30px;
font-size: 8px;
}
QWidget[size="ultra-compact"] QTableView#historyTable QHeaderView::section {
padding: 0px 1px;
font-size: 7px;
min-height: 6px;
}

@ -18,22 +18,48 @@ class HistoryViewerWidget(QWidget):
self.dbManager = dbManager
self.initUi()
self.loadStylesheet() # 加载样式表
self.loadHistory()
def loadStylesheet(self):
"""加载历史查看器样式表"""
try:
qssPath = "Static/HistoryViewer.qss"
qssFile = QFile(qssPath)
if qssFile.exists():
qssFile.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(qssFile)
stream.setCodec("UTF-8")
self.setStyleSheet(stream.readAll())
qssFile.close()
print(f"✅ HistoryViewer成功加载样式表: {qssPath}")
else:
print(f"⚠️ HistoryViewer样式表文件不存在: {qssPath}")
except Exception as e:
print(f"❌ HistoryViewer加载样式表失败: {str(e)}")
def initUi(self):
layout = QVBoxLayout()
layout.setContentsMargins(1, 1, 1, 1) # 极小边距
layout.setSpacing(1) # 极小间距
# 搜索栏
# 搜索栏 - 极度紧凑布局,固定高度
searchLayout = QHBoxLayout()
searchLayout.setContentsMargins(0, 0, 0, 0)
searchLayout.setSpacing(2)
self.searchEdit = QLineEdit()
self.searchEdit.setPlaceholderText("搜索规程...")
self.searchEdit.setMaximumHeight(20) # 限制搜索框高度
self.searchEdit.textChanged.connect(self.loadHistory)
searchLayout.addWidget(QLabel("搜索:"))
searchLabel = QLabel("搜索:")
searchLabel.setMaximumHeight(20) # 限制标签高度
searchLayout.addWidget(searchLabel)
searchLayout.addWidget(self.searchEdit)
layout.addLayout(searchLayout)
layout.addLayout(searchLayout, 0) # 拉伸因子为0不占用额外空间
# 历史记录表格
# 历史记录表格 - 设置对象名称用于样式识别
self.table = QTableView()
self.table.setObjectName("historyTable") # 重要:设置对象名称
self.table.setEditTriggers(QTableView.NoEditTriggers)
self.model = QStandardItemModel()
self.model.setHorizontalHeaderLabels(["ID", "规程全名", "类型", "执行时间", "报告路径"])
@ -42,6 +68,7 @@ class HistoryViewerWidget(QWidget):
self.table.setSelectionBehavior(QTableView.SelectRows)
self.table.setContextMenuPolicy(Qt.CustomContextMenu)
self.table.customContextMenuRequested.connect(self.showHistoryContextMenu)
self.table.verticalHeader().hide()
self.setupTableDisplay(self.table)
# 步骤详情表格
@ -51,53 +78,67 @@ class HistoryViewerWidget(QWidget):
self.stepModel.setHorizontalHeaderLabels(["步骤ID", "步骤描述", "执行时间", "执行状态", "详细结果", "实际/预期对比"])
self.stepTable.setModel(self.stepModel)
self.stepTable.doubleClicked.connect(self.showStepDetailDialog)
self.stepTable.verticalHeader().hide()
self.setupTableDisplay(self.stepTable)
# 分割窗口
# 使用分割器 - 表格占据绝大部分空间
splitter = QSplitter(Qt.Vertical)
splitter.setContentsMargins(0, 0, 0, 0)
splitter.addWidget(self.table)
splitter.addWidget(self.stepTable)
splitter.setSizes([400, 400])
layout.addWidget(splitter)
# 操作按钮
# 设置比例上方历史记录表格占15%下方步骤详情表格占85%
splitter.setSizes([120, 680])
splitter.setStretchFactor(0, 0) # 历史记录表格不拉伸
splitter.setStretchFactor(1, 1) # 步骤详情表格可拉伸
splitter.setChildrenCollapsible(False) # 防止子窗口被完全折叠
layout.addWidget(splitter, 1) # 拉伸因子为1占据主要空间
# 操作按钮 - 极度紧凑布局,固定高度
buttonLayout = QHBoxLayout()
separator = QWidget()
separator.setFixedWidth(20)
buttonLayout.addWidget(separator)
buttonLayout.setContentsMargins(0, 0, 0, 0)
buttonLayout.setSpacing(2)
self.deleteButton = QPushButton("删除历史记录")
self.deleteButton.setIcon(qta.icon('fa5s.trash', color='red'))
self.deleteButton.setIcon(qta.icon('fa5s.trash', color='#B91C1C'))
self.deleteButton.setMaximumHeight(24) # 限制按钮高度
self.deleteButton.clicked.connect(self.deleteSelectedHistory)
buttonLayout.addWidget(self.deleteButton)
self.exportButton = QPushButton("导出报告")
self.exportButton.setIcon(qta.icon('fa5s.file-export', color='green'))
self.exportButton.setIcon(qta.icon('fa5s.file-export', color='#047857'))
self.exportButton.setMaximumHeight(24) # 限制按钮高度
self.exportButton.clicked.connect(self.exportReport)
buttonLayout.addWidget(self.exportButton)
buttonLayout.addStretch()
layout.addLayout(buttonLayout)
layout.addLayout(buttonLayout, 0) # 拉伸因子为0不占用额外空间
self.setLayout(layout)
def setupTableDisplay(self, table):
"""设置表格显示属性"""
table.setWordWrap(True)
table.setAlternatingRowColors(False)
"""设置表格显示属性 - 极度紧凑版"""
table.setWordWrap(False) # 禁用自动换行以节省空间
table.setAlternatingRowColors(True) # 启用交替行颜色
table.setSortingEnabled(True)
# 水平表头设置
header = table.horizontalHeader()
if header:
header.setStretchLastSection(True)
header.setSectionResizeMode(QHeaderView.Interactive)
header.setDefaultAlignment(Qt.AlignLeft)
header.setMinimumSectionSize(50) # 设置最小列宽
header.setDefaultSectionSize(80) # 设置默认列宽
# 垂直表头设置 - 极度紧凑
verticalHeader = table.verticalHeader()
if verticalHeader:
verticalHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
verticalHeader.setDefaultAlignment(Qt.AlignCenter)
verticalHeader.setVisible(False) # 隐藏行号以节省空间
verticalHeader.setSectionResizeMode(QHeaderView.Fixed)
if table.objectName() == "historyTable":
verticalHeader.setDefaultSectionSize(12) # 历史表格极小行高
else:
verticalHeader.setDefaultSectionSize(16) # 步骤表格稍大行高
if table == self.table:
table.setSelectionMode(QTableView.ExtendedSelection)
@ -106,8 +147,6 @@ class HistoryViewerWidget(QWidget):
table.setSelectionBehavior(QTableView.SelectRows)
table.setObjectName("historyTable")
def loadHistory(self):
"""加载历史记录"""
self.model.removeRows(0, self.model.rowCount())

@ -12,7 +12,7 @@ from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QTableWidgetItem, QHeaderView, QMessageBox,
QDialog, QFormLayout, QSpinBox, QComboBox,
QDialogButtonBox, QAbstractItemView, QMenu)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtCore import Qt, pyqtSignal, QFile, QTextStream
from PyQt5.QtGui import QFont, QBrush, QColor
import qtawesome as qta
@ -111,684 +111,25 @@ class ProcedureEditor(QWidget):
self.parent = parent
self.initUI()
self.loadStylesheet() # 加载样式表
self.loadProcedureData()
def initUI(self):
"""初始化界面"""
layout = QVBoxLayout()
self.setLayout(layout)
# 标题
title_label = QLabel("规程编辑器")
title_label.setObjectName("procedureEditorTitle") # 设置对象名称以便QSS选择器使用
layout.addWidget(title_label)
# 基本信息区域
self.createBasicInfoSection(layout)
# 步骤表格区域
self.createStepsSection(layout)
# 按钮区域
self.createButtonSection(layout)
def createBasicInfoSection(self, layout):
"""创建基本信息区域 - 优化为紧凑布局"""
info_group = QWidget()
info_group.setObjectName("basicInfoGroup")
info_group.setMaximumHeight(80) # 限制基本信息区域的最大高度
info_group.setMinimumHeight(80)
layout.addWidget(info_group)
info_layout = QVBoxLayout()
info_layout.setContentsMargins(8, 4, 8, 4) # 减小边距
info_layout.setSpacing(4) # 减小间距
info_group.setLayout(info_layout)
# 标题
info_title = QLabel("基本信息")
info_title.setObjectName("basicInfoTitle")
info_layout.addWidget(info_title)
# 使用网格布局实现紧凑的两行布局
grid_layout = QHBoxLayout()
grid_layout.setSpacing(16)
# 第一列
col1_layout = QHBoxLayout()
col1_layout.setSpacing(8)
# 规程名称
name_label = QLabel("规程名称:")
name_label.setFixedWidth(60)
name_label.setProperty("fieldLabel", True)
self.nameEdit = QLineEdit()
self.nameEdit.setPlaceholderText("输入规程名称")
self.nameEdit.setObjectName("procedureNameEdit")
self.nameEdit.setMaximumHeight(32)
col1_layout.addWidget(name_label)
col1_layout.addWidget(self.nameEdit)
# 规程编号
number_label = QLabel("规程编号:")
number_label.setFixedWidth(60)
number_label.setProperty("fieldLabel", True)
self.numberEdit = QLineEdit()
self.numberEdit.setPlaceholderText("输入规程编号")
self.numberEdit.setObjectName("procedureNumberEdit")
self.numberEdit.setMaximumHeight(32)
col1_layout.addWidget(number_label)
col1_layout.addWidget(self.numberEdit)
grid_layout.addLayout(col1_layout)
# 第二列
col2_layout = QHBoxLayout()
col2_layout.setSpacing(8)
# 规程类型
type_label = QLabel("规程类型:")
type_label.setFixedWidth(60)
type_label.setProperty("fieldLabel", True)
self.typeEdit = QLineEdit()
self.typeEdit.setPlaceholderText("输入规程类型")
self.typeEdit.setObjectName("procedureTypeEdit")
self.typeEdit.setMaximumHeight(32)
col2_layout.addWidget(type_label)
col2_layout.addWidget(self.typeEdit)
# 规程描述(简化为单行输入)
desc_label = QLabel("规程描述:")
desc_label.setFixedWidth(60)
desc_label.setProperty("fieldLabel", True)
self.descriptionEdit = QLineEdit() # 改为单行输入
self.descriptionEdit.setPlaceholderText("输入规程描述")
self.descriptionEdit.setObjectName("procedureDescriptionEdit")
self.descriptionEdit.setMaximumHeight(32)
col2_layout.addWidget(desc_label)
col2_layout.addWidget(self.descriptionEdit)
grid_layout.addLayout(col2_layout)
grid_layout.addStretch() # 添加弹性空间
info_layout.addLayout(grid_layout)
def createStepsSection(self, layout):
"""创建步骤表格区域 - 优化为最大化表格显示"""
steps_group = QWidget()
steps_group.setObjectName("stepsGroup")
layout.addWidget(steps_group)
steps_layout = QVBoxLayout()
steps_layout.setContentsMargins(8, 4, 8, 4) # 减小边距
steps_layout.setSpacing(4) # 减小间距
steps_group.setLayout(steps_layout)
# 紧凑的标题和按钮行
header_layout = QHBoxLayout()
header_layout.setSpacing(8)
# 标题
steps_title = QLabel("步骤列表")
steps_title.setObjectName("stepsTitle")
header_layout.addWidget(steps_title)
# 添加步骤按钮(紧凑样式)
add_step_btn = QPushButton("添加步骤")
add_step_btn.setIcon(qta.icon('fa5s.plus', color='white'))
add_step_btn.setObjectName("addStepButton")
add_step_btn.setMaximumHeight(28) # 减小按钮高度
add_step_btn.clicked.connect(self.addStep)
header_layout.addWidget(add_step_btn)
# 删除步骤按钮(紧凑样式)
delete_step_btn = QPushButton("删除步骤")
delete_step_btn.setIcon(qta.icon('fa5s.trash', color='white'))
delete_step_btn.setObjectName("deleteStepButton")
delete_step_btn.setMaximumHeight(28) # 减小按钮高度
delete_step_btn.clicked.connect(self.deleteStep)
header_layout.addWidget(delete_step_btn)
header_layout.addStretch()
steps_layout.addLayout(header_layout)
# 步骤表格(最大化显示)
self.stepsTable = QTableWidget()
self.stepsTable.setObjectName("stepsTable")
self.stepsTable.setColumnCount(6)
self.stepsTable.setHorizontalHeaderLabels(['序号', '步骤ID', '操作', '类型', '预期值', '备注'])
# 设置表格属性
self.stepsTable.setSelectionBehavior(QAbstractItemView.SelectRows)
self.stepsTable.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.stepsTable.setAlternatingRowColors(True) # 启用交替行颜色
self.stepsTable.setShowGrid(True) # 显示网格线
# 优化表格样式
# 设置列宽
header = self.stepsTable.horizontalHeader()
if header:
header.setSectionResizeMode(0, QHeaderView.ResizeToContents) # 序号
header.setSectionResizeMode(1, QHeaderView.ResizeToContents) # 步骤ID
header.setSectionResizeMode(2, QHeaderView.Stretch) # 操作
header.setSectionResizeMode(3, QHeaderView.ResizeToContents) # 类型
header.setSectionResizeMode(4, QHeaderView.ResizeToContents) # 预期值
header.setSectionResizeMode(5, QHeaderView.ResizeToContents) # 备注
# 设置最小列宽
self.stepsTable.setColumnWidth(0, 50) # 序号
self.stepsTable.setColumnWidth(1, 100) # 步骤ID
self.stepsTable.setColumnWidth(3, 70) # 类型
self.stepsTable.setColumnWidth(4, 80) # 预期值
self.stepsTable.setColumnWidth(5, 100) # 备注
# 添加右键菜单
self.stepsTable.setContextMenuPolicy(Qt.CustomContextMenu)
self.stepsTable.customContextMenuRequested.connect(self.showContextMenu)
steps_layout.addWidget(self.stepsTable)
def createButtonSection(self, layout):
"""创建紧凑的按钮区域"""
button_widget = QWidget()
button_widget.setMaximumHeight(40) # 限制按钮区域高度
button_widget.setMinimumHeight(40)
button_layout = QHBoxLayout()
button_layout.setContentsMargins(8, 4, 8, 4) # 减小边距
button_layout.setSpacing(8) # 减小按钮间距
button_widget.setLayout(button_layout)
# 保存按钮(紧凑样式)
save_btn = QPushButton("保存规程")
save_btn.setIcon(qta.icon('fa5s.save', color='white'))
save_btn.setObjectName("saveProcedureButton")
save_btn.setMaximumHeight(32) # 减小按钮高度
save_btn.clicked.connect(self.saveProcedure)
button_layout.addWidget(save_btn)
# 取消按钮(紧凑样式)
cancel_btn = QPushButton("取消")
cancel_btn.setIcon(qta.icon('fa5s.times', color='red'))
cancel_btn.setObjectName("cancelEditButton")
cancel_btn.setMaximumHeight(32) # 减小按钮高度
cancel_btn.clicked.connect(self.cancelEdit)
button_layout.addWidget(cancel_btn)
button_layout.addStretch() # 将按钮推到左侧
layout.addWidget(button_widget)
def loadProcedureData(self):
"""加载规程数据"""
if not self.procedureData:
print("警告:规程数据为空")
return
print(f"加载规程数据: {self.procedureData.keys()}")
# 加载基本信息
procedure_info = self.procedureData.get('规程信息', {})
self.nameEdit.setText(procedure_info.get('规程名称', ''))
self.numberEdit.setText(procedure_info.get('规程编号', ''))
self.typeEdit.setText(procedure_info.get('规程类型', ''))
# 加载描述(可能在不同位置)
description = self.procedureData.get('description', '')
if not description:
# 尝试从测试用例信息中获取描述
test_case_info = self.procedureData.get('测试用例信息', {})
description = test_case_info.get('工况描述', '')
self.descriptionEdit.setText(description) # 修改为setText因为现在是QLineEdit
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
规程编辑器
支持编辑规程内容并保存到数据库
"""
import json
from datetime import datetime
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QLineEdit, QTextEdit, QPushButton, QTableWidget,
QTableWidgetItem, QHeaderView, QMessageBox,
QDialog, QFormLayout, QSpinBox, QComboBox,
QDialogButtonBox, QAbstractItemView, QMenu)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QFont, QBrush, QColor
import qtawesome as qta
class NoClearDelegate(QAbstractItemView):
"""自定义委托,防止双击时清除内容"""
def createEditor(self, parent, option, index):
editor = super().createEditor(parent, option, index)
if hasattr(editor, 'setText'):
# 保持原有内容
current_text = index.data()
if current_text:
editor.setText(current_text)
return editor
class StepEditDialog(QDialog):
"""步骤编辑对话框"""
def __init__(self, step_data=None, parent=None):
super().__init__(parent)
self.setWindowTitle("编辑步骤")
self.setModal(True)
self.setMinimumWidth(500)
self.step_data = step_data or {}
self.initUI()
def initUI(self):
layout = QVBoxLayout()
self.setLayout(layout)
# 表单布局
form_layout = QFormLayout()
# 步骤ID
self.stepIdEdit = QLineEdit()
self.stepIdEdit.setText(self.step_data.get('stepId', ''))
form_layout.addRow("步骤ID:", self.stepIdEdit)
# 操作(合并关键词和步骤描述)
self.operationEdit = QTextEdit()
self.operationEdit.setMaximumHeight(80)
self.operationEdit.setPlainText(self.step_data.get('operation', ''))
form_layout.addRow("操作:", self.operationEdit)
# 操作类型(直接输入)
self.typeEdit = QLineEdit()
self.typeEdit.setText(self.step_data.get('type', 'SET'))
form_layout.addRow("操作类型:", self.typeEdit)
# 预期值
self.expectedValueEdit = QLineEdit()
self.expectedValueEdit.setText(str(self.step_data.get('expectedValue', '')))
form_layout.addRow("预期值:", self.expectedValueEdit)
# 备注
self.remarkEdit = QTextEdit()
self.remarkEdit.setMaximumHeight(60)
self.remarkEdit.setPlainText(self.step_data.get('remark', ''))
form_layout.addRow("备注:", self.remarkEdit)
# 序号
self.orderSpin = QSpinBox()
self.orderSpin.setRange(1, 999)
self.orderSpin.setValue(self.step_data.get('order', 1))
form_layout.addRow("序号:", self.orderSpin)
layout.addLayout(form_layout)
# 按钮
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
layout.addWidget(button_box)
def getStepData(self):
"""获取步骤数据"""
return {
'stepId': self.stepIdEdit.text(),
'operation': self.operationEdit.toPlainText(),
'type': self.typeEdit.text(),
'expectedValue': self.expectedValueEdit.text(),
'remark': self.remarkEdit.toPlainText(),
'order': self.orderSpin.value()
}
class ProcedureEditor(QWidget):
"""规程编辑器"""
procedureSaved = pyqtSignal(int) # 规程保存信号
def __init__(self, procedureData, procedureId, dbManager, parent=None):
super().__init__(parent)
self.procedureData = procedureData
self.procedureId = procedureId
self.dbManager = dbManager
self.parent = parent
self.initUI()
self.loadProcedureData()
def initUI(self):
"""初始化界面"""
layout = QVBoxLayout()
self.setLayout(layout)
# 标题
title_label = QLabel("规程编辑器")
title_label.setObjectName("procedureEditorTitle") # 设置对象名称以便QSS选择器使用
layout.addWidget(title_label)
# 基本信息区域
self.createBasicInfoSection(layout)
# 步骤表格区域
self.createStepsSection(layout)
# 按钮区域
self.createButtonSection(layout)
def createBasicInfoSection(self, layout):
"""创建基本信息区域 - 优化为紧凑布局"""
info_group = QWidget()
info_group.setObjectName("basicInfoGroup")
info_group.setMaximumHeight(80) # 限制基本信息区域的最大高度
info_group.setMinimumHeight(80)
layout.addWidget(info_group)
info_layout = QVBoxLayout()
info_layout.setContentsMargins(8, 4, 8, 4) # 减小边距
info_layout.setSpacing(4) # 减小间距
info_group.setLayout(info_layout)
# 标题
info_title = QLabel("基本信息")
info_title.setObjectName("basicInfoTitle")
info_layout.addWidget(info_title)
# 使用网格布局实现紧凑的两行布局
grid_layout = QHBoxLayout()
grid_layout.setSpacing(16)
# 第一列
col1_layout = QHBoxLayout()
col1_layout.setSpacing(8)
# 规程名称
name_label = QLabel("规程名称:")
name_label.setFixedWidth(60)
name_label.setProperty("fieldLabel", True)
self.nameEdit = QLineEdit()
self.nameEdit.setPlaceholderText("输入规程名称")
self.nameEdit.setObjectName("procedureNameEdit")
self.nameEdit.setMaximumHeight(32)
col1_layout.addWidget(name_label)
col1_layout.addWidget(self.nameEdit)
# 规程编号
number_label = QLabel("规程编号:")
number_label.setFixedWidth(60)
number_label.setProperty("fieldLabel", True)
self.numberEdit = QLineEdit()
self.numberEdit.setPlaceholderText("输入规程编号")
self.numberEdit.setObjectName("procedureNumberEdit")
self.numberEdit.setMaximumHeight(32)
col1_layout.addWidget(number_label)
col1_layout.addWidget(self.numberEdit)
grid_layout.addLayout(col1_layout)
# 第二列
col2_layout = QHBoxLayout()
col2_layout.setSpacing(8)
# 规程类型
type_label = QLabel("规程类型:")
type_label.setFixedWidth(60)
type_label.setProperty("fieldLabel", True)
self.typeEdit = QLineEdit()
self.typeEdit.setPlaceholderText("输入规程类型")
self.typeEdit.setObjectName("procedureTypeEdit")
self.typeEdit.setMaximumHeight(32)
col2_layout.addWidget(type_label)
col2_layout.addWidget(self.typeEdit)
# 规程描述(简化为单行输入)
desc_label = QLabel("规程描述:")
desc_label.setFixedWidth(60)
desc_label.setProperty("fieldLabel", True)
self.descriptionEdit = QLineEdit() # 改为单行输入
self.descriptionEdit.setPlaceholderText("输入规程描述")
self.descriptionEdit.setObjectName("procedureDescriptionEdit")
self.descriptionEdit.setMaximumHeight(32)
col2_layout.addWidget(desc_label)
col2_layout.addWidget(self.descriptionEdit)
grid_layout.addLayout(col2_layout)
grid_layout.addStretch() # 添加弹性空间
info_layout.addLayout(grid_layout)
def createStepsSection(self, layout):
"""创建步骤表格区域 - 优化为最大化表格显示"""
steps_group = QWidget()
steps_group.setObjectName("stepsGroup")
layout.addWidget(steps_group)
steps_layout = QVBoxLayout()
steps_layout.setContentsMargins(8, 4, 8, 4) # 减小边距
steps_layout.setSpacing(4) # 减小间距
steps_group.setLayout(steps_layout)
# 紧凑的标题和按钮行
header_layout = QHBoxLayout()
header_layout.setSpacing(8)
# 标题
steps_title = QLabel("步骤列表")
steps_title.setObjectName("stepsTitle")
header_layout.addWidget(steps_title)
# 添加步骤按钮(紧凑样式)
add_step_btn = QPushButton("添加步骤")
add_step_btn.setIcon(qta.icon('fa5s.plus', color='white'))
add_step_btn.setObjectName("addStepButton")
add_step_btn.setMaximumHeight(28) # 减小按钮高度
add_step_btn.clicked.connect(self.addStep)
header_layout.addWidget(add_step_btn)
# 删除步骤按钮(紧凑样式)
delete_step_btn = QPushButton("删除步骤")
delete_step_btn.setIcon(qta.icon('fa5s.trash', color='white'))
delete_step_btn.setObjectName("deleteStepButton")
delete_step_btn.setMaximumHeight(28) # 减小按钮高度
delete_step_btn.clicked.connect(self.deleteStep)
header_layout.addWidget(delete_step_btn)
header_layout.addStretch()
steps_layout.addLayout(header_layout)
# 步骤表格(最大化显示)
self.stepsTable = QTableWidget()
self.stepsTable.setObjectName("stepsTable")
self.stepsTable.setColumnCount(6)
self.stepsTable.setHorizontalHeaderLabels(['序号', '步骤ID', '操作', '类型', '预期值', '备注'])
# 设置表格属性
self.stepsTable.setSelectionBehavior(QAbstractItemView.SelectRows)
self.stepsTable.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.stepsTable.setAlternatingRowColors(True) # 启用交替行颜色
self.stepsTable.setShowGrid(True) # 显示网格线
# 优化表格样式
# 设置列宽
header = self.stepsTable.horizontalHeader()
if header:
header.setSectionResizeMode(0, QHeaderView.ResizeToContents) # 序号
header.setSectionResizeMode(1, QHeaderView.ResizeToContents) # 步骤ID
header.setSectionResizeMode(2, QHeaderView.Stretch) # 操作
header.setSectionResizeMode(3, QHeaderView.ResizeToContents) # 类型
header.setSectionResizeMode(4, QHeaderView.ResizeToContents) # 预期值
header.setSectionResizeMode(5, QHeaderView.ResizeToContents) # 备注
# 设置最小列宽
self.stepsTable.setColumnWidth(0, 50) # 序号
self.stepsTable.setColumnWidth(1, 100) # 步骤ID
self.stepsTable.setColumnWidth(3, 70) # 类型
self.stepsTable.setColumnWidth(4, 80) # 预期值
self.stepsTable.setColumnWidth(5, 100) # 备注
# 添加右键菜单
self.stepsTable.setContextMenuPolicy(Qt.CustomContextMenu)
self.stepsTable.customContextMenuRequested.connect(self.showContextMenu)
steps_layout.addWidget(self.stepsTable)
def createButtonSection(self, layout):
"""创建紧凑的按钮区域"""
button_widget = QWidget()
button_widget.setMaximumHeight(40) # 限制按钮区域高度
button_widget.setMinimumHeight(40)
button_layout = QHBoxLayout()
button_layout.setContentsMargins(8, 4, 8, 4) # 减小边距
button_layout.setSpacing(8) # 减小按钮间距
button_widget.setLayout(button_layout)
# 保存按钮(紧凑样式)
save_btn = QPushButton("保存规程")
save_btn.setIcon(qta.icon('fa5s.save', color='white'))
save_btn.setObjectName("saveProcedureButton")
save_btn.setMaximumHeight(32) # 减小按钮高度
save_btn.clicked.connect(self.saveProcedure)
button_layout.addWidget(save_btn)
# 取消按钮(紧凑样式)
cancel_btn = QPushButton("取消")
cancel_btn.setIcon(qta.icon('fa5s.times', color='red'))
cancel_btn.setObjectName("cancelEditButton")
cancel_btn.setMaximumHeight(32) # 减小按钮高度
cancel_btn.clicked.connect(self.cancelEdit)
button_layout.addWidget(cancel_btn)
button_layout.addStretch() # 将按钮推到左侧
layout.addWidget(button_widget)
def loadProcedureData(self):
"""加载规程数据"""
if not self.procedureData:
print("警告:规程数据为空")
return
print(f"加载规程数据: {self.procedureData.keys()}")
# 加载基本信息
procedure_info = self.procedureData.get('规程信息', {})
self.nameEdit.setText(procedure_info.get('规程名称', ''))
self.numberEdit.setText(procedure_info.get('规程编号', ''))
self.typeEdit.setText(procedure_info.get('规程类型', ''))
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
规程编辑器
支持编辑规程内容并保存到数据库
"""
import json
from datetime import datetime
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
QLineEdit, QTextEdit, QPushButton, QTableWidget,
QTableWidgetItem, QHeaderView, QMessageBox,
QDialog, QFormLayout, QSpinBox, QComboBox,
QDialogButtonBox, QAbstractItemView, QMenu)
from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QFont, QBrush, QColor
import qtawesome as qta
class NoClearDelegate(QAbstractItemView):
"""自定义委托,防止双击时清除内容"""
def createEditor(self, parent, option, index):
editor = super().createEditor(parent, option, index)
if hasattr(editor, 'setText'):
# 保持原有内容
current_text = index.data()
if current_text:
editor.setText(current_text)
return editor
class StepEditDialog(QDialog):
"""步骤编辑对话框"""
def __init__(self, step_data=None, parent=None):
super().__init__(parent)
self.setWindowTitle("编辑步骤")
self.setModal(True)
self.setMinimumWidth(500)
self.step_data = step_data or {}
self.initUI()
def initUI(self):
layout = QVBoxLayout()
self.setLayout(layout)
# 表单布局
form_layout = QFormLayout()
# 步骤ID
self.stepIdEdit = QLineEdit()
self.stepIdEdit.setText(self.step_data.get('stepId', ''))
form_layout.addRow("步骤ID:", self.stepIdEdit)
# 操作(合并关键词和步骤描述)
self.operationEdit = QTextEdit()
self.operationEdit.setMaximumHeight(80)
self.operationEdit.setPlainText(self.step_data.get('operation', ''))
form_layout.addRow("操作:", self.operationEdit)
# 操作类型(直接输入)
self.typeEdit = QLineEdit()
self.typeEdit.setText(self.step_data.get('type', 'SET'))
form_layout.addRow("操作类型:", self.typeEdit)
# 预期值
self.expectedValueEdit = QLineEdit()
self.expectedValueEdit.setText(str(self.step_data.get('expectedValue', '')))
form_layout.addRow("预期值:", self.expectedValueEdit)
# 备注
self.remarkEdit = QTextEdit()
self.remarkEdit.setMaximumHeight(60)
self.remarkEdit.setPlainText(self.step_data.get('remark', ''))
form_layout.addRow("备注:", self.remarkEdit)
# 序号
self.orderSpin = QSpinBox()
self.orderSpin.setRange(1, 999)
self.orderSpin.setValue(self.step_data.get('order', 1))
form_layout.addRow("序号:", self.orderSpin)
layout.addLayout(form_layout)
# 按钮
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
button_box.accepted.connect(self.accept)
button_box.rejected.connect(self.reject)
layout.addWidget(button_box)
def getStepData(self):
"""获取步骤数据"""
return {
'stepId': self.stepIdEdit.text(),
'operation': self.operationEdit.toPlainText(),
'type': self.typeEdit.text(),
'expectedValue': self.expectedValueEdit.text(),
'remark': self.remarkEdit.toPlainText(),
'order': self.orderSpin.value()
}
class ProcedureEditor(QWidget):
"""规程编辑器"""
procedureSaved = pyqtSignal(int) # 规程保存信号
def __init__(self, procedureData, procedureId, dbManager, parent=None):
super().__init__(parent)
self.procedureData = procedureData
self.procedureId = procedureId
self.dbManager = dbManager
self.parent = parent
self.initUI()
self.loadProcedureData()
def loadStylesheet(self):
"""加载规程编辑器样式表"""
try:
qssPath = "Static/ProcedureEditor.qss"
qssFile = QFile(qssPath)
if qssFile.exists():
qssFile.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(qssFile)
stream.setCodec("UTF-8")
self.setStyleSheet(stream.readAll())
qssFile.close()
print(f"✅ ProcedureEditor成功加载样式表: {qssPath}")
else:
print(f"⚠️ ProcedureEditor样式表文件不存在: {qssPath}")
except Exception as e:
print(f"❌ ProcedureEditor加载样式表失败: {str(e)}")
def initUI(self):
"""初始化界面"""
@ -912,7 +253,7 @@ class ProcedureEditor(QWidget):
# 添加步骤按钮(紧凑样式)
add_step_btn = QPushButton("添加步骤")
add_step_btn.setIcon(qta.icon('fa5s.plus', color='white'))
add_step_btn.setIcon(qta.icon('fa5s.plus', color='#047857'))
add_step_btn.setObjectName("addStepButton")
add_step_btn.setMaximumHeight(28) # 减小按钮高度
add_step_btn.clicked.connect(self.addStep)
@ -920,7 +261,7 @@ class ProcedureEditor(QWidget):
# 删除步骤按钮(紧凑样式)
delete_step_btn = QPushButton("删除步骤")
delete_step_btn.setIcon(qta.icon('fa5s.trash', color='white'))
delete_step_btn.setIcon(qta.icon('fa5s.trash', color='#B91C1C'))
delete_step_btn.setObjectName("deleteStepButton")
delete_step_btn.setMaximumHeight(28) # 减小按钮高度
delete_step_btn.clicked.connect(self.deleteStep)
@ -941,8 +282,6 @@ class ProcedureEditor(QWidget):
self.stepsTable.setAlternatingRowColors(True) # 启用交替行颜色
self.stepsTable.setShowGrid(True) # 显示网格线
# 优化表格样式
# 设置列宽
header = self.stepsTable.horizontalHeader()
if header:
@ -963,6 +302,7 @@ class ProcedureEditor(QWidget):
# 添加右键菜单
self.stepsTable.setContextMenuPolicy(Qt.CustomContextMenu)
self.stepsTable.customContextMenuRequested.connect(self.showContextMenu)
self.stepsTable.verticalHeader().hide()
steps_layout.addWidget(self.stepsTable)
@ -979,7 +319,7 @@ class ProcedureEditor(QWidget):
# 保存按钮(紧凑样式)
save_btn = QPushButton("保存规程")
save_btn.setIcon(qta.icon('fa5s.save', color='white'))
save_btn.setIcon(qta.icon('fa5s.save', color='#1D4ED8'))
save_btn.setObjectName("saveProcedureButton")
save_btn.setMaximumHeight(32) # 减小按钮高度
save_btn.clicked.connect(self.saveProcedure)
@ -987,7 +327,7 @@ class ProcedureEditor(QWidget):
# 取消按钮(紧凑样式)
cancel_btn = QPushButton("取消")
cancel_btn.setIcon(qta.icon('fa5s.times', color='red'))
cancel_btn.setIcon(qta.icon('fa5s.times', color='#6B7280'))
cancel_btn.setObjectName("cancelEditButton")
cancel_btn.setMaximumHeight(32) # 减小按钮高度
cancel_btn.clicked.connect(self.cancelEdit)

Loading…
Cancel
Save