优化界面显示样式

main
zcwBit 3 months ago
parent d6697b4caa
commit afa66d5c92

@ -55,7 +55,8 @@ QTableView {
border: 1px solid #E5E7EB; border: 1px solid #E5E7EB;
border-radius: 3px; border-radius: 3px;
gridline-color: #F3F4F6; gridline-color: #F3F4F6;
font-size: 10px; font-size: 12px;
/* 调大表格内容字体 */
color: #374151; color: #374151;
selection-background-color: #EBF8FF; selection-background-color: #EBF8FF;
selection-color: #1E40AF; selection-color: #1E40AF;
@ -67,9 +68,11 @@ QTableView {
} }
QTableView::item { QTableView::item {
padding: 1px 3px; padding: 2px 4px;
/* 稍微增加内边距以适应更大字体 */
border: none; border: none;
min-height: 12px; min-height: 14px;
/* 增加行高以适应更大字体 */
} }
QTableView::item:selected { QTableView::item:selected {
@ -97,25 +100,30 @@ QTableView::item:focus {
/* ==================== 历史记录表格专用样式 ==================== */ /* ==================== 历史记录表格专用样式 ==================== */
QTableView#historyTable { QTableView#historyTable {
max-height: 100px; /* 极小的最大高度 */ /* 完全移除高度限制,让分割器控制大小 */
min-height: 50px; /* 极小的最小高度 */ font-size: 11px;
font-size: 9px; /* 极小的字体 */ /* 调大历史记录表格字体 */
} }
QTableView#historyTable::item { QTableView#historyTable::item {
padding: 0px 2px; /* 极度紧凑的内边距 */ padding: 1px 3px;
min-height: 10px; /* 极小的行高 */ /* 稍微增加内边距 */
min-height: 12px;
/* 稍微增加行高 */
} }
/* ==================== 步骤详情表格专用样式 ==================== */ /* ==================== 步骤详情表格专用样式 ==================== */
QTableView:not(#historyTable) { QTableView:not(#historyTable) {
min-height: 150px; /* 步骤详情表格最小高度 */ /* 移除最小高度限制,让分割器控制大小 */
font-size: 10px; font-size: 12px;
/* 调大步骤详情表格字体 */
} }
QTableView:not(#historyTable)::item { QTableView:not(#historyTable)::item {
padding: 2px 4px; /* 适中的内边距 */ padding: 2px 4px;
min-height: 14px; /* 适中的行高 */ /* 适中的内边距 */
min-height: 14px;
/* 适中的行高 */
} }
/* ==================== 表格头部样式 ==================== */ /* ==================== 表格头部样式 ==================== */
@ -129,7 +137,8 @@ QTableView QHeaderView::section {
background-color: #F8F9FA; background-color: #F8F9FA;
color: #374151; color: #374151;
font-weight: 600; font-weight: 600;
font-size: 9px; font-size: 8px;
/* 调小表头字体 */
padding: 1px 3px; padding: 1px 3px;
border: 1px solid #E5E7EB; border: 1px solid #E5E7EB;
border-left: none; border-left: none;
@ -139,8 +148,10 @@ QTableView QHeaderView::section {
/* 历史记录表格头部 - 极度紧凑 */ /* 历史记录表格头部 - 极度紧凑 */
QTableView#historyTable QHeaderView::section { QTableView#historyTable QHeaderView::section {
padding: 0px 2px; /* 极小的头部内边距 */ padding: 0px 2px;
font-size: 8px; /* 极小的字体 */ /* 极小的头部内边距 */
font-size: 7px;
/* 更小的表头字体 */
font-weight: 600; font-weight: 600;
min-height: 8px; min-height: 8px;
} }
@ -243,64 +254,81 @@ QTableView QScrollBar::sub-page:horizontal {
/* ==================== 按钮样式 ==================== */ /* ==================== 按钮样式 ==================== */
QPushButton { QPushButton {
font-size: 10px; font-size: 13px;
font-weight: 600; font-weight: bold;
padding: 2px 6px; padding: 8px 20px;
border-radius: 2px; border-radius: 8px;
min-width: 50px; min-width: 120px;
min-height: 16px; min-height: 36px;
border: 1px solid; border: 1px solid #D1D5DB;
margin: 0px 1px; margin: 4px 8px;
font-family: "Microsoft YaHei", sans-serif;
background-color: #F9FAFB;
color: #374151;
} }
/* 删除历史记录按钮 - 红色主题 */ /* 删除历史记录按钮 - 现代红色主题 */
QPushButton[text="删除历史记录"] { QPushButton#deleteHistoryButton {
color: #DC2626; color: white;
background-color: #FEF2F2; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
border-color: #FECACA; stop: 0 #F87171, stop: 1 #DC2626);
border: 2px solid #DC2626;
font-weight: bold;
border-radius: 8px;
font-size: 14px;
padding: 10px 20px;
min-height: 40px;
min-width: 120px;
} }
QPushButton[text="删除历史记录"]:hover { QPushButton#deleteHistoryButton:hover {
background-color: #FEE2E2; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
border-color: #FCA5A5; stop: 0 #FCA5A5, stop: 1 #EF4444);
color: #B91C1C; border: 2px solid #F87171;
} }
QPushButton[text="删除历史记录"]:pressed { QPushButton#deleteHistoryButton:pressed {
background-color: #FECACA; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
border-color: #F87171; stop: 0 #DC2626, stop: 1 #B91C1C);
color: #991B1B; border: 2px solid #B91C1C;
} }
QPushButton[text="删除历史记录"]:disabled { QPushButton#deleteHistoryButton:disabled {
background-color: #F3F4F6; background: #F3F4F6;
color: #9CA3AF; color: #9CA3AF;
border-color: #E5E7EB; border: 1px solid #E5E7EB;
} }
/* 导出报告按钮 - 绿色主题 */ /* 导出报告按钮 - 现代绿色主题 */
QPushButton[text="导出报告"] { QPushButton#exportReportButton {
color: #059669; color: white;
background-color: #ECFDF5; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
border-color: #BBF7D0; stop: 0 #34D399, stop: 1 #059669);
border: 2px solid #10B981;
font-weight: bold;
border-radius: 8px;
font-size: 14px;
padding: 10px 20px;
min-height: 40px;
min-width: 120px;
} }
QPushButton[text="导出报告"]:hover { QPushButton#exportReportButton:hover {
background-color: #D1FAE5; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
border-color: #86EFAC; stop: 0 #6EE7B7, stop: 1 #10B981);
color: #047857; border: 2px solid #34D399;
} }
QPushButton[text="导出报告"]:pressed { QPushButton#exportReportButton:pressed {
background-color: #A7F3D0; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
border-color: #6EE7B7; stop: 0 #059669, stop: 1 #047857);
color: #065F46; border: 2px solid #047857;
} }
QPushButton[text="导出报告"]:disabled { QPushButton#exportReportButton:disabled {
background-color: #F3F4F6; background: #F3F4F6;
color: #9CA3AF; color: #9CA3AF;
border-color: #E5E7EB; border: 1px solid #E5E7EB;
} }
/* ==================== 分割器样式 ==================== */ /* ==================== 分割器样式 ==================== */
@ -433,33 +461,7 @@ QLineEdit#stepResultText[status="default"] {
border-color: #E5E7EB; 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 { QToolTip {
@ -548,9 +550,7 @@ QTableView::item[status="unknown"] {
} }
/* ==================== 焦点样式 ==================== */ /* ==================== 焦点样式 ==================== */
QWidget:focus {
outline: none;
}
QTableView:focus { QTableView:focus {
border-color: #3B82F6; border-color: #3B82F6;
@ -562,84 +562,6 @@ QPushButton:focus {
border-width: 1px; 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;
}

@ -0,0 +1,579 @@
/* ==================== DCS2025 规程编辑器样式 ==================== */
/* ==================== 主容器样式 ==================== */
QWidget {
background-color: #FFFFFF;
color: #374151;
font-family: "PingFangSC-Regular", "Microsoft YaHei", sans-serif;
}
/* ==================== 标题样式 ==================== */
QLabel#procedureEditorTitle {
font-size: 20px;
font-weight: 700;
color: #1F2937;
padding: 12px 16px;
background-color: #F8F9FA;
border: 1px solid #E5E7EB;
border-radius: 8px;
margin-bottom: 16px;
}
/* ==================== 基本信息区域样式 ==================== */
QWidget#basicInfoGroup {
background-color: #F8F9FA;
border: 1px solid #E5E7EB;
border-radius: 8px;
margin-bottom: 8px;
}
QLabel#basicInfoTitle {
font-size: 14px;
font-weight: 600;
color: #374151;
margin-bottom: 4px;
}
/* 字段标签样式 */
QLabel[fieldLabel="true"] {
font-size: 13px;
font-weight: 500;
color: #4B5563;
text-align: right;
}
/* 输入框样式 */
QLineEdit#procedureNameEdit,
QLineEdit#procedureNumberEdit,
QLineEdit#procedureTypeEdit,
QLineEdit#procedureDescriptionEdit {
background-color: #FFFFFF;
border: 1px solid #D1D5DB;
border-radius: 4px;
padding: 6px 12px;
font-size: 13px;
color: #374151;
selection-background-color: #EBF8FF;
selection-color: #1E40AF;
}
QLineEdit#procedureNameEdit:focus,
QLineEdit#procedureNumberEdit:focus,
QLineEdit#procedureTypeEdit:focus,
QLineEdit#procedureDescriptionEdit:focus {
border-color: #3B82F6;
outline: none;
background-color: #FEFEFE;
}
QLineEdit#procedureNameEdit:hover,
QLineEdit#procedureNumberEdit:hover,
QLineEdit#procedureTypeEdit:hover,
QLineEdit#procedureDescriptionEdit:hover {
border-color: #9CA3AF;
background-color: #FEFEFE;
}
/* ==================== 步骤区域样式 ==================== */
QWidget#stepsGroup {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 8px;
}
QLabel#stepsTitle {
font-size: 14px;
font-weight: 600;
color: #374151;
}
/* ==================== 按钮样式 ==================== */
/* 添加步骤按钮 - 绿色主题 */
QPushButton#addStepButton {
color: #047857;
font-size: 13px;
font-weight: 600;
padding: 6px 12px;
background-color: #ECFDF5;
border-radius: 4px;
border: 1px solid #BBF7D0;
min-width: 80px;
}
QPushButton#addStepButton:hover {
background-color: #D1FAE5;
border-color: #86EFAC;
color: #065F46;
}
QPushButton#addStepButton:pressed {
background-color: #A7F3D0;
border-color: #6EE7B7;
color: #064E3B;
}
/* 删除步骤按钮 - 红色主题 */
QPushButton#deleteStepButton {
color: #B91C1C;
font-size: 13px;
font-weight: 600;
padding: 6px 12px;
background-color: #FEF2F2;
border-radius: 4px;
border: 1px solid #FECACA;
min-width: 80px;
}
QPushButton#deleteStepButton:hover {
background-color: #FEE2E2;
border-color: #FCA5A5;
color: #991B1B;
}
QPushButton#deleteStepButton:pressed {
background-color: #FECACA;
border-color: #F87171;
color: #7F1D1D;
}
/* 保存规程按钮 - 蓝色主题 */
QPushButton#saveProcedureButton {
color: #1D4ED8;
font-size: 14px;
font-weight: 600;
padding: 8px 16px;
background-color: #EBF8FF;
border-radius: 6px;
border: 1px solid #BFDBFE;
min-width: 100px;
}
QPushButton#saveProcedureButton:hover {
background-color: #DBEAFE;
border-color: #93C5FD;
color: #1E40AF;
}
QPushButton#saveProcedureButton:pressed {
background-color: #BFDBFE;
border-color: #60A5FA;
color: #1E3A8A;
}
/* 取消编辑按钮 - 灰色主题 */
QPushButton#cancelEditButton {
color: #6B7280;
font-size: 14px;
font-weight: 600;
padding: 8px 16px;
background-color: #F9FAFB;
border-radius: 6px;
border: 1px solid #E5E7EB;
min-width: 100px;
}
QPushButton#cancelEditButton:hover {
background-color: #F3F4F6;
border-color: #D1D5DB;
color: #4B5563;
}
QPushButton#cancelEditButton:pressed {
background-color: #E5E7EB;
border-color: #9CA3AF;
color: #374151;
}
/* ==================== 步骤表格样式 ==================== */
QTableWidget#stepsTable {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 6px;
gridline-color: #F3F4F6;
font-size: 13px;
color: #374151;
selection-background-color: #EBF8FF;
selection-color: #1E40AF;
outline: none;
show-decoration-selected: 1;
}
/* 表格项基础样式 */
QTableWidget#stepsTable::item {
padding: 8px;
border: none;
min-height: 36px;
}
/* 表格项选中状态 - 整行选中效果 */
QTableWidget#stepsTable::item:selected {
background-color: #EBF8FF;
color: #1E40AF;
border: none;
}
/* 表格项hover状态 - 整行hover效果 */
QTableWidget#stepsTable::item:hover {
background-color: #F0F9FF;
color: #1F2937;
}
/* 表格项选中且hover状态 */
QTableWidget#stepsTable::item:selected:hover {
background-color: #DBEAFE;
color: #1565C0;
}
/* 表格项焦点状态 */
QTableWidget#stepsTable::item:focus {
background-color: #EBF8FF;
color: #1E40AF;
outline: none;
border: none;
}
/* 表格项编辑状态 */
QTableWidget#stepsTable::item:edit-focus {
background-color: #FEFEFE;
border: 2px solid #3B82F6;
border-radius: 2px;
}
/* 交替行颜色 */
QTableWidget#stepsTable::item:alternate {
background-color: #F9FAFB;
}
QTableWidget#stepsTable::item:alternate:hover {
background-color: #F0F9FF;
}
QTableWidget#stepsTable::item:alternate:selected {
background-color: #EBF8FF;
}
/* ==================== 表格头部样式 ==================== */
QTableWidget#stepsTable QHeaderView {
background-color: transparent;
border: none;
outline: none;
}
QTableWidget#stepsTable QHeaderView::section {
background-color: #F8F9FA;
color: #374151;
font-weight: 600;
font-size: 13px;
padding: 10px 8px;
border: 1px solid #E5E7EB;
border-left: none;
text-align: center;
}
QTableWidget#stepsTable QHeaderView::section:first {
border-left: 1px solid #E5E7EB;
border-top-left-radius: 6px;
}
QTableWidget#stepsTable QHeaderView::section:last {
border-top-right-radius: 6px;
}
QTableWidget#stepsTable QHeaderView::section:hover {
background-color: #F3F4F6;
color: #1F2937;
}
QTableWidget#stepsTable QHeaderView::section:pressed {
background-color: #E5E7EB;
color: #111827;
}
/* 垂直表头隐藏 */
QTableWidget#stepsTable QHeaderView::section:vertical {
border: none;
background-color: transparent;
}
/* ==================== 滚动条样式 ==================== */
QTableWidget#stepsTable QScrollBar:vertical {
background-color: #F9FAFB;
width: 12px;
border-radius: 6px;
border: none;
}
QTableWidget#stepsTable QScrollBar::handle:vertical {
background-color: #D1D5DB;
border-radius: 6px;
min-height: 20px;
margin: 2px;
}
QTableWidget#stepsTable QScrollBar::handle:vertical:hover {
background-color: #9CA3AF;
}
QTableWidget#stepsTable QScrollBar::handle:vertical:pressed {
background-color: #6B7280;
}
QTableWidget#stepsTable QScrollBar::add-line:vertical,
QTableWidget#stepsTable QScrollBar::sub-line:vertical {
border: none;
background: none;
height: 0px;
}
QTableWidget#stepsTable QScrollBar::add-page:vertical,
QTableWidget#stepsTable QScrollBar::sub-page:vertical {
background: none;
}
QTableWidget#stepsTable QScrollBar:horizontal {
background-color: #F9FAFB;
height: 12px;
border-radius: 6px;
border: none;
}
QTableWidget#stepsTable QScrollBar::handle:horizontal {
background-color: #D1D5DB;
border-radius: 6px;
min-width: 20px;
margin: 2px;
}
QTableWidget#stepsTable QScrollBar::handle:horizontal:hover {
background-color: #9CA3AF;
}
QTableWidget#stepsTable QScrollBar::handle:horizontal:pressed {
background-color: #6B7280;
}
QTableWidget#stepsTable QScrollBar::add-line:horizontal,
QTableWidget#stepsTable QScrollBar::sub-line:horizontal {
border: none;
background: none;
width: 0px;
}
QTableWidget#stepsTable QScrollBar::add-page:horizontal,
QTableWidget#stepsTable QScrollBar::sub-page:horizontal {
background: none;
}
/* ==================== 对话框样式 ==================== */
/* 步骤编辑对话框 */
QDialog {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 8px;
}
QDialog QLabel {
font-size: 13px;
color: #374151;
font-weight: 500;
}
QDialog QLineEdit {
background-color: #FFFFFF;
border: 1px solid #D1D5DB;
border-radius: 4px;
padding: 6px 12px;
font-size: 13px;
color: #374151;
selection-background-color: #EBF8FF;
selection-color: #1E40AF;
}
QDialog QLineEdit:focus {
border-color: #3B82F6;
outline: none;
background-color: #FEFEFE;
}
QDialog QTextEdit {
background-color: #FFFFFF;
border: 1px solid #D1D5DB;
border-radius: 4px;
padding: 6px 12px;
font-size: 13px;
color: #374151;
selection-background-color: #EBF8FF;
selection-color: #1E40AF;
}
QDialog QTextEdit:focus {
border-color: #3B82F6;
outline: none;
background-color: #FEFEFE;
}
QDialog QSpinBox {
background-color: #FFFFFF;
border: 1px solid #D1D5DB;
border-radius: 4px;
padding: 6px 12px;
font-size: 13px;
color: #374151;
min-width: 80px;
}
QDialog QSpinBox:focus {
border-color: #3B82F6;
outline: none;
}
/* 对话框按钮 */
QDialog QPushButton {
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: 4px;
min-width: 80px;
}
QDialog QPushButton[text="OK"] {
color: #1D4ED8;
background-color: #EBF8FF;
border: 1px solid #BFDBFE;
}
QDialog QPushButton[text="OK"]:hover {
background-color: #DBEAFE;
border-color: #93C5FD;
color: #1E40AF;
}
QDialog QPushButton[text="Cancel"] {
color: #6B7280;
background-color: #F9FAFB;
border: 1px solid #E5E7EB;
}
QDialog QPushButton[text="Cancel"]:hover {
background-color: #F3F4F6;
border-color: #D1D5DB;
color: #4B5563;
}
/* ==================== 右键菜单样式 ==================== */
QMenu {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 6px;
padding: 4px 0;
font-size: 13px;
color: #374151;
}
QMenu::item {
padding: 8px 16px;
margin: 0 4px;
border-radius: 4px;
}
QMenu::item:selected {
background-color: #F0F9FF;
color: #1F2937;
}
QMenu::item:pressed {
background-color: #EBF8FF;
color: #1E40AF;
}
QMenu::separator {
height: 1px;
background-color: #E5E7EB;
margin: 4px 8px;
}
/* ==================== 工具提示样式 ==================== */
QToolTip {
background-color: #1F2937;
color: #FFFFFF;
border: none;
border-radius: 4px;
padding: 6px 8px;
font-size: 12px;
opacity: 230;
}
/* ==================== 消息框样式 ==================== */
QMessageBox {
background-color: #FFFFFF;
color: #374151;
font-size: 13px;
}
QMessageBox QPushButton {
font-size: 13px;
font-weight: 600;
padding: 6px 16px;
border-radius: 4px;
min-width: 70px;
}
QMessageBox QPushButton[text="OK"],
QMessageBox QPushButton[text="Yes"] {
color: #1D4ED8;
background-color: #EBF8FF;
border: 1px solid #BFDBFE;
}
QMessageBox QPushButton[text="OK"]:hover,
QMessageBox QPushButton[text="Yes"]:hover {
background-color: #DBEAFE;
border-color: #93C5FD;
}
QMessageBox QPushButton[text="Cancel"],
QMessageBox QPushButton[text="No"] {
color: #6B7280;
background-color: #F9FAFB;
border: 1px solid #E5E7EB;
}
QMessageBox QPushButton[text="Cancel"]:hover,
QMessageBox QPushButton[text="No"]:hover {
background-color: #F3F4F6;
border-color: #D1D5DB;
}
/* ==================== 响应式设计 ==================== */
/* 紧凑模式 */
QWidget[size="compact"] {
font-size: 12px;
}
QWidget[size="compact"] QPushButton {
padding: 4px 8px;
font-size: 12px;
}
QWidget[size="compact"] QLineEdit {
padding: 4px 8px;
font-size: 12px;
}
/* 大尺寸模式 */
QWidget[size="large"] {
font-size: 14px;
}
QWidget[size="large"] QPushButton {
padding: 10px 20px;
font-size: 14px;
}
QWidget[size="large"] QLineEdit {
padding: 8px 16px;
font-size: 14px;
}

@ -30,13 +30,70 @@ class HistoryViewerWidget(QWidget):
qssFile.open(QFile.ReadOnly | QFile.Text) qssFile.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(qssFile) stream = QTextStream(qssFile)
stream.setCodec("UTF-8") stream.setCodec("UTF-8")
self.setStyleSheet(stream.readAll()) qss_content = stream.readAll()
qssFile.close() qssFile.close()
# 应用样式表到当前widget
self.setStyleSheet(qss_content)
# 确保按钮样式生效 - 直接设置按钮样式
self.applyButtonStyles()
print(f"✅ HistoryViewer成功加载样式表: {qssPath}") print(f"✅ HistoryViewer成功加载样式表: {qssPath}")
else: else:
print(f"⚠️ HistoryViewer样式表文件不存在: {qssPath}") print(f"⚠️ HistoryViewer样式表文件不存在: {qssPath}")
except Exception as e: except Exception as e:
print(f"❌ HistoryViewer加载样式表失败: {str(e)}") print(f"❌ HistoryViewer加载样式表失败: {str(e)}")
def applyButtonStyles(self):
"""直接应用按钮样式"""
# 删除按钮样式
delete_style = """
QPushButton#deleteHistoryButton {
color: white;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #F87171, stop: 1 #DC2626);
border: 2px solid #DC2626;
font-weight: bold;
border-radius: 8px;
font-size: 14px;
padding: 10px 20px;
min-height: 40px;
min-width: 120px;
}
QPushButton#deleteHistoryButton:hover {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #FCA5A5, stop: 1 #EF4444);
border: 2px solid #F87171;
}
"""
# 导出按钮样式
export_style = """
QPushButton#exportReportButton {
color: white;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #34D399, stop: 1 #059669);
border: 2px solid #10B981;
font-weight: bold;
border-radius: 8px;
font-size: 14px;
padding: 10px 20px;
min-height: 40px;
min-width: 120px;
}
QPushButton#exportReportButton:hover {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #6EE7B7, stop: 1 #10B981);
border: 2px solid #34D399;
}
"""
# 应用样式到按钮
if hasattr(self, 'deleteButton'):
self.deleteButton.setStyleSheet(delete_style)
if hasattr(self, 'exportButton'):
self.exportButton.setStyleSheet(export_style)
def initUi(self): def initUi(self):
layout = QVBoxLayout() layout = QVBoxLayout()
@ -86,10 +143,10 @@ class HistoryViewerWidget(QWidget):
splitter.setContentsMargins(0, 0, 0, 0) splitter.setContentsMargins(0, 0, 0, 0)
splitter.addWidget(self.table) splitter.addWidget(self.table)
splitter.addWidget(self.stepTable) splitter.addWidget(self.stepTable)
# 设置比例:上方历史记录表格占15%下方步骤详情表格占85% # 设置比例:上方历史记录表格占40%下方步骤详情表格占60% (2:3比例)
splitter.setSizes([120, 680]) splitter.setSizes([2, 3]) # 直接使用比例值
splitter.setStretchFactor(0, 0) # 历史记录表格不拉伸 splitter.setStretchFactor(0, 2) # 历史记录表格拉伸因子为2
splitter.setStretchFactor(1, 1) # 步骤详情表格可拉伸 splitter.setStretchFactor(1, 3) # 步骤详情表格拉伸因子为3
splitter.setChildrenCollapsible(False) # 防止子窗口被完全折叠 splitter.setChildrenCollapsible(False) # 防止子窗口被完全折叠
layout.addWidget(splitter, 1) # 拉伸因子为1占据主要空间 layout.addWidget(splitter, 1) # 拉伸因子为1占据主要空间
@ -99,14 +156,14 @@ class HistoryViewerWidget(QWidget):
buttonLayout.setSpacing(2) buttonLayout.setSpacing(2)
self.deleteButton = QPushButton("删除历史记录") self.deleteButton = QPushButton("删除历史记录")
self.deleteButton.setIcon(qta.icon('fa5s.trash', color='#B91C1C')) self.deleteButton.setObjectName("deleteHistoryButton") # 设置对象名称
self.deleteButton.setMaximumHeight(24) # 限制按钮高度 self.deleteButton.setIcon(qta.icon('fa5s.trash', color='#FFFFFF')) # 白色图标
self.deleteButton.clicked.connect(self.deleteSelectedHistory) self.deleteButton.clicked.connect(self.deleteSelectedHistory)
buttonLayout.addWidget(self.deleteButton) buttonLayout.addWidget(self.deleteButton)
self.exportButton = QPushButton("导出报告") self.exportButton = QPushButton("导出报告")
self.exportButton.setIcon(qta.icon('fa5s.file-export', color='#047857')) self.exportButton.setObjectName("exportReportButton") # 设置对象名称
self.exportButton.setMaximumHeight(24) # 限制按钮高度 self.exportButton.setIcon(qta.icon('fa5s.file-export', color='#FFFFFF')) # 白色图标
self.exportButton.clicked.connect(self.exportReport) self.exportButton.clicked.connect(self.exportReport)
buttonLayout.addWidget(self.exportButton) buttonLayout.addWidget(self.exportButton)
@ -115,6 +172,9 @@ class HistoryViewerWidget(QWidget):
self.setLayout(layout) self.setLayout(layout)
# 在UI创建完成后应用按钮样式
QTimer.singleShot(0, self.applyButtonStyles)
def setupTableDisplay(self, table): def setupTableDisplay(self, table):
"""设置表格显示属性 - 极度紧凑版""" """设置表格显示属性 - 极度紧凑版"""
table.setWordWrap(False) # 禁用自动换行以节省空间 table.setWordWrap(False) # 禁用自动换行以节省空间
@ -136,9 +196,9 @@ class HistoryViewerWidget(QWidget):
verticalHeader.setVisible(False) # 隐藏行号以节省空间 verticalHeader.setVisible(False) # 隐藏行号以节省空间
verticalHeader.setSectionResizeMode(QHeaderView.Fixed) verticalHeader.setSectionResizeMode(QHeaderView.Fixed)
if table.objectName() == "historyTable": if table.objectName() == "historyTable":
verticalHeader.setDefaultSectionSize(12) # 历史表格极小行高 verticalHeader.setDefaultSectionSize(20) # 历史表格适中行高适应2:3比例
else: else:
verticalHeader.setDefaultSectionSize(16) # 步骤表格稍大行高 verticalHeader.setDefaultSectionSize(18) # 步骤表格稍大行高
if table == self.table: if table == self.table:
table.setSelectionMode(QTableView.ExtendedSelection) table.setSelectionMode(QTableView.ExtendedSelection)
@ -617,12 +677,33 @@ class HistoryViewerWidget(QWidget):
"""窗口显示事件""" """窗口显示事件"""
super().showEvent(event) super().showEvent(event)
QTimer.singleShot(100, self.adjustTablesAfterShow) QTimer.singleShot(100, self.adjustTablesAfterShow)
QTimer.singleShot(500, self.forceSplitterRatio) # 延迟强制设置比例
def adjustTablesAfterShow(self): def adjustTablesAfterShow(self):
"""窗口显示后调整表格""" """窗口显示后调整表格"""
self.adjustTableColumns(self.table, self.model) self.adjustTableColumns(self.table, self.model)
self.adjustTableColumns(self.stepTable, self.stepModel) self.adjustTableColumns(self.stepTable, self.stepModel)
def forceSplitterRatio(self):
"""强制设置分割器比例为2:3"""
splitter = self.findChild(QSplitter)
if splitter:
total_height = splitter.height()
if total_height > 0:
# 计算2:3比例的实际像素值
history_height = int(total_height * 0.4) # 40%
step_height = int(total_height * 0.6) # 60%
# 设置表格的固定高度以确保比例
self.table.setFixedHeight(history_height)
self.stepTable.setMinimumHeight(step_height)
# 设置分割器尺寸
splitter.setSizes([history_height, step_height])
def selectAllHistory(self): def selectAllHistory(self):
"""全选历史记录""" """全选历史记录"""
self.table.selectAll() self.table.selectAll()

@ -0,0 +1,453 @@
from PyQt5 import QtCore
from PyQt5.QtWidgets import QHeaderView, QStyle, QStyleOptionButton, QTableView, QAbstractItemView, QDesktopWidget
from PyQt5.QtCore import (pyqtSignal, Qt, QRect)
from PyQt5.QtCore import Qt, QTimer, QAbstractTableModel, QModelIndex, QPoint, QSize
from PyQt5.QtGui import QFont, QBrush, QColor
from PyQt5.QtWidgets import QTableView, QStyledItemDelegate
from utils import Globals
class BackgroundDelegate(QStyledItemDelegate):
def __init__(self, *args):
super(BackgroundDelegate, self).__init__(*args)
self.setObjectName('item')
def sizeHint(self, option, index):
"""设置项目的尺寸提示,确保足够的高度"""
size = super().sizeHint(option, index)
size.setHeight(max(46, size.height())) # 最小高度60px
return size
def paint(self, painter, option, index):
# 确保绘制区域有足够的高度
if index.data(QtCore.Qt.BackgroundRole):
height = option.rect.height()
top = option.rect.top()
# 减少高度调整,保持更多的绘制区域
option.rect.setHeight(max(46, height - 4)) # 最小保持56px高度
option.rect.moveTop(top + 2)
painter.fillRect(option.rect, index.data(QtCore.Qt.BackgroundRole))
super().paint(painter, option, index)
class ProcedureTabel(QTableView):
def __init__(self, testSteps, parent=None):
super(ProcedureTabel, self).__init__(parent)
self.parent = parent
self.createTableSection(testSteps)
self.setupTableHeaders()
self.delegate = BackgroundDelegate(self)
self.setItemDelegate(self.delegate)
self.loadStylesheet()
def loadStylesheet(self):
"""加载表格样式表"""
try:
from PyQt5.QtCore import QFile, QTextStream
qssPath = "Static/ProcedureTable.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"✅ ProcedureTable成功加载样式表: {qssPath}")
else:
print(f"⚠️ ProcedureTable样式表文件不存在: {qssPath}")
except Exception as e:
print(f"❌ ProcedureTable加载样式表失败: {str(e)}")
def createTableSection(self, testSteps):
"""创建表格区域"""
self.tableModel = StepTableModel(testSteps)
self.setModel(self.tableModel)
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.parent.showContextMenu)
# 设置表格编辑行为
self.setEditTriggers(QTableView.DoubleClicked)
# 设置选择行为为整行选中
self.setSelectionBehavior(QTableView.SelectRows)
self.setSelectionMode(QAbstractItemView.SingleSelection) # 单行选择
# 设置表格显示优化
self.setAlternatingRowColors(False) # 交替行颜色
self.setShowGrid(True) # 显示网格线
self.setGridStyle(Qt.SolidLine) # 实线网格
self.setSortingEnabled(False) # 禁用排序避免干扰执行顺序
# 启用鼠标跟踪以支持hover效果
self.setMouseTracking(True)
# 设置最小行高
self.verticalHeader().setMinimumSectionSize(30)
self.setupTableHeaders()
# 初始调整所有行高
self.adjustAllRowHeights()
def setupTableHeaders(self):
"""设置表格头部"""
try:
header = self.horizontalHeader()
if header:
# 设置表格自动调整行高
self.verticalHeader().setDefaultSectionSize(35)
self.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.verticalHeader().hide()
# 设置列宽模式 - 让表格填充满整个宽度
header.setStretchLastSection(True) # 让最后一列自动拉伸填充剩余空间
# 设置各列的调整模式
header.setSectionResizeMode(0, QHeaderView.Fixed) # 步骤ID - 固定宽度
header.setSectionResizeMode(1, QHeaderView.Stretch) # 步骤描述 - 拉伸
header.setSectionResizeMode(2, QHeaderView.Fixed) # 操作类型 - 固定宽度
header.setSectionResizeMode(3, QHeaderView.Fixed) # 执行时间 - 固定宽度
header.setSectionResizeMode(4, QHeaderView.Fixed) # 执行结果 - 固定宽度
header.setSectionResizeMode(5, QHeaderView.Stretch) # 详细结果 - 拉伸
header.setSectionResizeMode(6, QHeaderView.Stretch) # 备注 - 拉伸
# 设置固定列的宽度
self.setColumnWidth(0, 80) # 步骤ID
self.setColumnWidth(2, 120) # 操作类型
self.setColumnWidth(3, 160) # 执行时间
self.setColumnWidth(4, 80) # 执行结果
# 设置拉伸列的最小宽度
header.setMinimumSectionSize(100) # 设置所有列的最小宽度
# 启用文本换行
self.setWordWrap(True)
except Exception as e:
print(f"设置表格头部时出错: {e}")
def adjustRowHeight(self, row):
"""调整指定行的高度以适应内容"""
try:
# 获取该行的内容
stepInfo = self.tableModel.getStepInfo(row)
if not stepInfo:
return
# 计算需要的行高确保所有值都不为None
description = stepInfo.get('description') or ''
result = stepInfo.get('result') or ''
note = stepInfo.get('note') or ''
# 确保所有值都是字符串类型
if not isinstance(description, str):
description = str(description) if description is not None else ''
if not isinstance(result, str):
result = str(result) if result is not None else ''
if not isinstance(note, str):
note = str(note) if note is not None else ''
# 基于最长文本计算行高
max_text_length = max(len(description), len(result), len(note))
# 基础行高
base_height = 35
# 根据文本长度动态调整
if max_text_length > 100:
height = base_height + (max_text_length // 50) * 15
elif max_text_length > 50:
height = base_height + 15
else:
height = base_height
# 设置行高最大不超过150像素
height = min(height, 150)
self.setRowHeight(row, height)
except Exception as e:
print(f"调整行高时出错: {e}")
def adjustAllRowHeights(self):
"""调整所有行的高度"""
try:
if not hasattr(self, 'tableModel') or self.tableModel is None:
return
row_count = self.tableModel.rowCount()
if row_count <= 0:
return
for row in range(row_count):
self.adjustRowHeight(row)
except Exception as e:
print(f"调整所有行高时出错: {e}")
def mouseMoveEvent(self, event):
"""鼠标移动事件实现hover效果"""
super().mouseMoveEvent(event)
# 获取鼠标位置对应的行
index = self.indexAt(event.pos())
if index.isValid():
row = index.row()
if row != self.tableModel.hoverRow:
# 清除之前的hover行
oldHoverRow = self.tableModel.hoverRow
self.tableModel.hoverRow = row
# 更新显示
if oldHoverRow >= 0:
self.update(self.tableModel.index(oldHoverRow, 0))
for col in range(self.tableModel.columnCount()):
self.update(self.tableModel.index(oldHoverRow, col))
# 更新新的hover行
self.update(self.tableModel.index(row, 0))
for col in range(self.tableModel.columnCount()):
self.update(self.tableModel.index(row, col))
else:
# 鼠标不在任何行上清除hover效果
if self.tableModel.hoverRow >= 0:
oldHoverRow = self.tableModel.hoverRow
self.tableModel.hoverRow = -1
self.update(self.tableModel.index(oldHoverRow, 0))
for col in range(self.tableModel.columnCount()):
self.update(self.tableModel.index(oldHoverRow, col))
def leaveEvent(self, event):
"""鼠标离开事件清除hover效果"""
super().leaveEvent(event)
if self.tableModel.hoverRow >= 0:
oldHoverRow = self.tableModel.hoverRow
self.tableModel.hoverRow = -1
self.update(self.tableModel.index(oldHoverRow, 0))
for col in range(self.tableModel.columnCount()):
self.update(self.tableModel.index(oldHoverRow, col))
class StepTableModel(QAbstractTableModel):
columns = ['序号', '实验步骤','操作类型', '执行时间', '是否与预期一致', '实际结果', '备注']
def __init__(self, testSteps):
super().__init__()
self.stepData = []
self.stepIndex = 0
self.hoverRow = -1 # 添加hover行跟踪
for mainStep in testSteps:
self.stepData.append({
'id': self.stepIndex,
'isMain': True,
'stepId': mainStep['步骤ID'],
'description': mainStep['步骤描述'],
'executed': False,
'stepType': mainStep['操作类型'],
'time': None,
'result': None,
'note': mainStep.get('备注', '') # 修复:从主步骤的备注字段读取
})
self.stepIndex += 1
for subStep in mainStep['子步骤']:
self.stepData.append({
'id': self.stepIndex,
'isMain': False,
'stepId': f"{mainStep['步骤ID']}{subStep['序号']}",
'description': subStep['操作'],
'stepType': subStep['操作类型'],
'executed': False,
'time': None,
'result': None,
'note': subStep['备注'] # 新增从Excel解析的备注字段
})
self.stepIndex += 1
def rowCount(self, parent=QModelIndex()):
return len(self.stepData)
def columnCount(self, parent=QModelIndex()):
return len(self.columns)
def data(self, index, role=Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
col = index.column()
step = self.stepData[row]
if role == Qt.DisplayRole:
if col == 0:
return step['stepId'] or ''
elif col == 1:
return step['description'] or ''
elif col == 2:
return step['stepType'] or ''
elif col == 3:
return step['time'].strftime("%Y-%m-%d %H:%M:%S") if step['time'] else ''
elif col == 4:
# print(step['result'])
if step['executed']:
if '失败' in step['result']:
return ''
else:
return ''
elif col == 5:
# print(step['result'])
return step['result'] or ''
elif col == 6:
return step['note'] if step['note'] else ''
elif role == Qt.BackgroundRole:
# 优先级:执行结果 > hover效果 > 主步骤背景
if step['executed']:
if '失败' in step['result']:
# 失败状态:红色背景
if row == self.hoverRow:
return QBrush(QColor(255, 160, 170)) # hover时稍微深一点的红色
else:
return QBrush(QColor(255, 182, 193)) # 浅红色
else:
# 成功状态:绿色背景
if row == self.hoverRow:
return QBrush(QColor(120, 220, 120)) # hover时稍微深一点的绿色
else:
return QBrush(QColor(144, 238, 144)) # 浅绿色
elif row == self.hoverRow:
# hover效果浅蓝色背景
if step['isMain']:
return QBrush(QColor(200, 200, 230)) # 主步骤hover时的颜色
else:
return QBrush(QColor(230, 240, 255)) # 子步骤hover时的颜色
elif step['isMain']:
# 主步骤默认背景:浅灰色
return QBrush(QColor(220, 220, 220))
elif role == Qt.TextAlignmentRole:
if col in [0, 2, 3, 4]: # 步骤ID、操作类型、执行时间、执行结果居中对齐
return Qt.AlignCenter
else: # 其他列左对齐并顶部对齐
return Qt.AlignLeft | Qt.AlignTop
elif role == Qt.FontRole and step['isMain']:
font = QFont()
font.setBold(True)
return font
# 新增:支持自动换行
elif role == Qt.TextAlignmentRole:
if col in [1, 5]: # 描述和备注列
return Qt.AlignLeft | Qt.AlignVCenter
elif role == Qt.TextWordWrap:
if col in [1, 5]:
return True
return None
def flags(self, index):
"""返回单元格标志"""
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
return flags
def headerData(self, section, orientation, role):
if role == Qt.DisplayRole and orientation == Qt.Horizontal:
return self.columns[section]
return None
def getStepInfo(self, row):
if 0 <= row < len(self.stepData):
return self.stepData[row]
return None
def getFullStepInfo(self, row):
"""获取完整的步骤信息"""
if 0 <= row < len(self.stepData):
return self.stepData[row]
return None
def updateStepResult(self, row, result, time):
if 0 <= row < len(self.stepData):
# print(result)
self.stepData[row]['executed'] = True
self.stepData[row]['time'] = time
self.stepData[row]['result'] = result
self.dataChanged.emit(self.index(row, 0),
self.index(row, self.columnCount()-1),
[Qt.DisplayRole, Qt.BackgroundRole])
return True
return False
def resetExecutionState(self):
"""只重置执行状态(颜色),不清除时间和结果"""
for step in self.stepData:
step['executed'] = False
step['result'] = None
self.dataChanged.emit(self.index(0, 0),
self.index(self.rowCount()-1, self.columnCount()-1),
[Qt.BackgroundRole])
def resetAll(self):
"""完全重置所有状态(包括时间和结果)"""
for step in self.stepData:
step.update({
'executed': False,
'time': None,
'result': None
})
self.dataChanged.emit(self.index(0, 0),
self.index(self.rowCount()-1, self.columnCount()-1),
[Qt.DisplayRole, Qt.BackgroundRole])
def getTestSteps(self):
"""获取测试步骤数据,用于保存"""
testSteps = []
currentMainStep = None
for step in self.stepData:
if step['isMain']:
# 如果有前一个主步骤,先添加到结果中
if currentMainStep:
testSteps.append(currentMainStep)
# 创建新的主步骤
currentMainStep = {
'步骤ID': step['stepId'],
'步骤描述': step['description'],
'操作类型': step['stepType'],
'预期结果': '',
'子步骤': []
}
else:
# 子步骤
if currentMainStep:
# 从步骤ID中提取序号
stepId = step['stepId']
if currentMainStep['步骤ID'] in stepId:
subStepId = stepId.replace(currentMainStep['步骤ID'], '')
else:
subStepId = stepId
subStep = {
'序号': subStepId,
'操作': step['description'],
'操作类型': step['stepType'],
'预期结果': '',
'实际结果': step.get('result', ''),
'一致性': '' if step.get('result') and '失败' not in step.get('result', '') else '',
'测试时间': step.get('time', ''),
'备注': step.get('note', '')
}
currentMainStep['子步骤'].append(subStep)
# 添加最后一个主步骤
if currentMainStep:
testSteps.append(currentMainStep)
return testSteps
Loading…
Cancel
Save