优化规程界面

main
zcwBit 3 months ago
parent a03c9c0785
commit 13cbe4e3cc

@ -2,9 +2,9 @@
/* ==================== 全局样式 ==================== */
QWidget {
background-color: #F5F7FA;
color: #374151;
font-family: "PingFangSC-Regular", "Microsoft YaHei", "Segoe UI", Arial, sans-serif;
background-color: #F8FAFC;
color: #1F2937;
font-family: "PingFangSC-Medium", "Microsoft YaHei", "Segoe UI", Arial, sans-serif;
font-size: 14px;
selection-background-color: #3B82F6;
selection-color: #FFFFFF;
@ -34,30 +34,38 @@ QToolBar::separator {
margin: 8px 6px;
}
/* 工具栏按钮 */
/* ==================== 工具栏按钮样式 - 与变量表按钮一致 ==================== */
/* 工具栏按钮基础样式 */
QToolBar QToolButton {
background-color: #FFFFFF;
border: 1px solid #E5E7EB;
border-radius: 8px;
padding: 12px 16px;
margin: 4px 2px;
color: #374151;
font-size: 13px;
font-weight: 500;
color: #047857;
font-size: 15px;
font-weight: 600;
padding: 8px 16px;
background-color: #ECFDF5;
border-radius: 6px;
border: 1px solid #BBF7D0;
margin: 2px;
min-width: 80px;
min-height: 36px;
min-height: 32px;
font-family: "PingFangSC-Medium", "Microsoft YaHei", sans-serif;
}
QToolBar QToolButton:hover {
background-color: #F9FAFB;
border-color: #D1D5DB;
color: #1F2937;
background-color: #D1FAE5;
border-color: #86EFAC;
color: #065F46;
}
QToolBar QToolButton:pressed {
background-color: #F3F4F6;
border-color: #9CA3AF;
color: #111827;
background-color: #A7F3D0;
border-color: #6EE7B7;
color: #064E3B;
}
QToolBar QToolButton:disabled {
background-color: #F9FAFB;
color: #9CA3AF;
border-color: #E5E7EB;
}
/* ==================== 标签页样式 ==================== */
@ -390,7 +398,7 @@ QLineEdit {
background-color: #FFFFFF;
border: 2px solid #E5E7EB;
border-radius: 8px;
padding: 12px 16px;
padding: 4px 8px;
color: #374151;
font-size: 14px;
font-weight: 400;
@ -406,11 +414,34 @@ QLineEdit:hover {
border-color: #9CA3AF;
}
/* 规程编辑器中的小型输入框 */
QLineEdit#procedureNameEdit,
QLineEdit#procedureNumberEdit,
QLineEdit#procedureTypeEdit,
QLineEdit#procedureDescriptionEdit {
padding: 4px 8px;
font-size: 12px;
font-family: "Microsoft YaHei", "PingFangSC-Regular", sans-serif;
border: 1px solid #E5E7EB;
border-radius: 4px;
min-height: 22px;
line-height: 1.3;
color: #374151;
}
QLineEdit#procedureNameEdit:focus,
QLineEdit#procedureNumberEdit:focus,
QLineEdit#procedureTypeEdit:focus,
QLineEdit#procedureDescriptionEdit:focus {
border-color: #3B82F6;
background-color: #FEFEFF;
}
QTextEdit {
background-color: #FFFFFF;
border: 2px solid #E5E7EB;
border-radius: 8px;
padding: 16px;
/* padding: 16px; */
color: #374151;
font-size: 14px;
line-height: 1.5;
@ -1218,4 +1249,798 @@ QLabel#statsChange[trend="down"] {
QLabel#statsChange[trend="stable"] {
background-color: #F3F4F6;
color: #6B7280;
}
/* ==================== 规程编辑器专用样式 ==================== */
/* 基本信息标题 */
QLabel#basicInfoTitle {
font-size: 12px;
font-weight: bold;
color: #606266;
}
/* 步骤列表标题 */
QLabel#stepsTitle {
font-size: 12px;
font-weight: bold;
color: #606266;
}
/* 字段标签样式 */
QLabel[fieldLabel="true"] {
font-size: 11px;
font-weight: bold;
color: #909399;
}
/* 添加步骤按钮 */
QPushButton#addStepButton {
font-size: 11px;
padding: 4px 8px;
background-color: #10B981;
color: white;
border: none;
border-radius: 4px;
font-weight: 600;
}
QPushButton#addStepButton:hover {
background-color: #059669;
}
QPushButton#addStepButton:pressed {
background-color: #047857;
}
/* 删除步骤按钮 */
QPushButton#deleteStepButton {
font-size: 11px;
padding: 4px 8px;
background-color: #EF4444;
color: white;
border: none;
border-radius: 4px;
font-weight: 600;
}
QPushButton#deleteStepButton:hover {
background-color: #DC2626;
}
QPushButton#deleteStepButton:pressed {
background-color: #B91C1C;
}
/* 保存规程按钮 */
QPushButton#saveProcedureButton {
font-size: 11px;
padding: 6px 12px;
background-color: #3B82F6;
color: white;
border: none;
border-radius: 4px;
font-weight: 600;
}
QPushButton#saveProcedureButton:hover {
background-color: #2563EB;
}
QPushButton#saveProcedureButton:pressed {
background-color: #1D4ED8;
}
/* 取消编辑按钮 */
QPushButton#cancelEditButton {
font-size: 11px;
padding: 6px 12px;
background-color: #6B7280;
color: white;
border: none;
border-radius: 4px;
font-weight: 600;
}
QPushButton#cancelEditButton:hover {
background-color: #4B5563;
}
QPushButton#cancelEditButton:pressed {
background-color: #374151;
}
/* 规程编辑器步骤表格 */
QTableWidget#stepsTable {
gridline-color: #EBEEF5;
font-size: 11px;
border: 1px solid #DCDFE6;
border-radius: 4px;
background-color: #FFFFFF;
alternate-background-color: #F9FAFC;
}
QTableWidget#stepsTable::item {
padding: 4px;
border-bottom: 1px solid #EBEEF5;
}
QTableWidget#stepsTable::item:selected {
background-color: #ECF5FF;
color: #409EFF;
}
QTableWidget#stepsTable QHeaderView::section {
background-color: #F5F7FA;
color: #606266;
padding: 6px;
border: none;
border-right: 1px solid #EBEEF5;
border-bottom: 1px solid #DCDFE6;
font-weight: bold;
font-size: 11px;
}
/* ==================== 步骤执行器样式 ==================== */
/* 超紧凑信息标签 */
QLabel#ultraCompactInfoLabel {
font-size: 11px;
font-weight: bold;
color: #606266;
}
/* 超紧凑信息值 */
QLabel#ultraCompactInfoValue {
font-size: 11px;
color: #374151;
}
/* 执行状态标签 */
QLabel#executionStatusLabel {
font-weight: bold;
}
/* 执行状态 - 成功 */
QLabel#executionStatusLabel[status="success"] {
color: #059669;
}
/* 执行状态 - 错误 */
QLabel#executionStatusLabel[status="error"] {
color: #DC2626;
}
/* 执行状态 - 警告 */
QLabel#executionStatusLabel[status="warning"] {
color: #D97706;
}
/* 执行状态 - 信息 */
QLabel#executionStatusLabel[status="info"] {
color: #2563EB;
}
/* ==================== 规程管理界面按钮样式 ==================== */
/* 卡片标题 */
QLabel#cardTitle {
font-size: 16px;
font-weight: 600;
color: #1F2937;
padding: 0 0 12px 0;
border-bottom: 2px solid #E5E7EB;
margin-bottom: 16px;
}
/* 规程统计标签 */
QLabel#procedureCountLabel {
color: #6B7280;
font-size: 13px;
font-weight: 500;
padding: 6px 12px;
background-color: #F3F4F6;
border-radius: 16px;
}
/* 搜索框 */
QLineEdit#searchEdit {
padding: 8px 12px;
font-size: 14px;
border-radius: 6px;
border: 2px solid #E5E7EB;
background-color: #FFFFFF;
}
QLineEdit#searchEdit:focus {
border-color: #3B82F6;
background-color: #FEFEFF;
}
/* 类型过滤器 */
QComboBox#typeFilter {
padding: 8px 12px;
font-size: 14px;
border-radius: 6px;
border: 2px solid #E5E7EB;
background-color: #FFFFFF;
min-width: 120px;
}
QComboBox#typeFilter:focus {
border-color: #3B82F6;
}
/* 添加分类按钮 */
QPushButton#addCategoryBtn {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #3B82F6, stop:1 #2563EB);
border: 1px solid #2563EB;
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: 6px;
min-height: 32px;
}
QPushButton#addCategoryBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #2563EB, stop:1 #1D4ED8);
border-color: #1D4ED8;
}
QPushButton#addCategoryBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #1D4ED8, stop:1 #1E40AF);
border-color: #1E40AF;
}
/* 删除分类按钮 */
QPushButton#deleteCategoryBtn {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #EF4444, stop:1 #DC2626);
border: 1px solid #DC2626;
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: 6px;
min-height: 32px;
}
QPushButton#deleteCategoryBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #DC2626, stop:1 #B91C1C);
border-color: #B91C1C;
}
QPushButton#deleteCategoryBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B91C1C, stop:1 #991B1B);
border-color: #991B1B;
}
/* 导入规程按钮 */
QPushButton#importBtn {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #10B981, stop:1 #059669);
border: 1px solid #059669;
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: 6px;
min-height: 32px;
}
QPushButton#importBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #059669, stop:1 #047857);
border-color: #047857;
}
QPushButton#importBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #047857, stop:1 #065F46);
border-color: #065F46;
}
/* 打开规程按钮 */
QPushButton#openBtn {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #3B82F6, stop:1 #2563EB);
border: 1px solid #2563EB;
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: 6px;
min-height: 32px;
}
QPushButton#openBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #2563EB, stop:1 #1D4ED8);
border-color: #1D4ED8;
}
QPushButton#openBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #1D4ED8, stop:1 #1E40AF);
border-color: #1E40AF;
}
/* 导出规程按钮 */
QPushButton#exportBtn {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #F59E0B, stop:1 #D97706);
border: 1px solid #D97706;
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: 6px;
min-height: 32px;
}
QPushButton#exportBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #D97706, stop:1 #B45309);
border-color: #B45309;
}
QPushButton#exportBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B45309, stop:1 #92400E);
border-color: #92400E;
}
/* 删除规程按钮 */
QPushButton#deleteBtn {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #EF4444, stop:1 #DC2626);
border: 1px solid #DC2626;
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
padding: 8px 16px;
border-radius: 6px;
min-height: 32px;
}
QPushButton#deleteBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #DC2626, stop:1 #B91C1C);
border-color: #B91C1C;
}
QPushButton#deleteBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B91C1C, stop:1 #991B1B);
border-color: #991B1B;
}
/* ==================== 历史查看器样式 ==================== */
/* 历史记录表格 */
QTableView#historyTable {
gridline-color: #d0d0d0;
background-color: #FFFFFF;
alternate-background-color: #F8FAFC;
selection-background-color: #EBF8FF;
selection-color: #1E40AF;
border: 1px solid #E5E7EB;
border-radius: 6px;
font-size: 13px;
}
QTableView#historyTable::item {
padding: 8px 12px;
border: none;
}
QTableView#historyTable::item:hover {
background-color: #F3F4F6;
}
QTableView#historyTable::item:selected {
background-color: #EBF8FF;
color: #1E40AF;
}
/* 步骤详情信息组 */
QWidget#stepDetailInfoGroup {
background-color: #f8f9fa;
border: 1px solid #E5E7EB;
border-radius: 8px;
padding: 16px;
}
/* 步骤描述文本 */
QLineEdit#stepDescriptionText {
background-color: #f8f9fa;
border: 1px solid #E5E7EB;
border-radius: 4px;
padding: 8px;
font-size: 13px;
color: #374151;
}
/* 执行结果文本 - 成功 */
QLineEdit#stepResultText[status="success"] {
background-color: #d4edda;
border: 1px solid #c3e6cb;
border-radius: 4px;
padding: 8px;
font-size: 13px;
color: #155724;
}
/* 执行结果文本 - 失败 */
QLineEdit#stepResultText[status="error"] {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 4px;
padding: 8px;
font-size: 13px;
color: #721c24;
}
/* 执行结果文本 - 默认 */
QLineEdit#stepResultText[status="default"] {
background-color: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 4px;
padding: 8px;
font-size: 13px;
color: #856404;
}
/* ==================== 规程管理工具栏按钮样式 - 与变量表按钮一致 ==================== */
/* 工具栏按钮基础样式 - 与变量表保持一致 */
QToolBar QToolButton {
font-size: 14px;
font-weight: 600;
padding: 10px 16px;
border-radius: 8px;
border: 1px solid;
margin: 3px;
min-width: 90px;
min-height: 36px;
font-family: "PingFangSC-Medium", "Microsoft YaHei", sans-serif;
}
/* 导入规程按钮 - 绿色主题 (与变量表"开始通讯"一致) */
#importToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #10B981, stop:1 #059669);
border-color: #059669;
}
#importToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #059669, stop:1 #047857);
border-color: #047857;
}
#importToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #047857, stop:1 #065F46);
border-color: #065F46;
}
/* 添加分类按钮 - 蓝色主题 */
#addCategoryToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #3B82F6, stop:1 #2563EB);
border-color: #2563EB;
}
#addCategoryToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #2563EB, stop:1 #1D4ED8);
border-color: #1D4ED8;
}
#addCategoryToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #1D4ED8, stop:1 #1E40AF);
border-color: #1E40AF;
}
/* 删除分类按钮 - 红色主题 */
#deleteCategoryToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #EF4444, stop:1 #DC2626);
border-color: #DC2626;
}
#deleteCategoryToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #DC2626, stop:1 #B91C1C);
border-color: #B91C1C;
}
#deleteCategoryToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B91C1C, stop:1 #991B1B);
border-color: #991B1B;
}
/* 打开规程按钮 - 蓝色主题 */
#openProcedureToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #3B82F6, stop:1 #2563EB);
border-color: #2563EB;
}
#openProcedureToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #2563EB, stop:1 #1D4ED8);
border-color: #1D4ED8;
}
#openProcedureToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #1D4ED8, stop:1 #1E40AF);
border-color: #1E40AF;
}
/* 删除规程按钮 - 红色主题 */
#deleteProcedureToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #EF4444, stop:1 #DC2626);
border-color: #DC2626;
}
#deleteProcedureToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #DC2626, stop:1 #B91C1C);
border-color: #B91C1C;
}
#deleteProcedureToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B91C1C, stop:1 #991B1B);
border-color: #991B1B;
}
/* 历史记录按钮 - 紫色主题 */
#historyToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8B5CF6, stop:1 #7C3AED);
border-color: #7C3AED;
}
#historyToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #7C3AED, stop:1 #6D28D9);
border-color: #6D28D9;
}
#historyToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #6D28D9, stop:1 #5B21B6);
border-color: #5B21B6;
}
/* 批量执行按钮 - 绿色主题 */
#batchExecuteToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #10B981, stop:1 #059669);
border-color: #059669;
}
#batchExecuteToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #059669, stop:1 #047857);
border-color: #047857;
}
#batchExecuteToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #047857, stop:1 #065F46);
border-color: #065F46;
}
/* 关键词管理按钮 - 紫色主题 */
#keywordManageToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #8B5CF6, stop:1 #7C3AED);
border-color: #7C3AED;
}
#keywordManageToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #7C3AED, stop:1 #6D28D9);
border-color: #6D28D9;
}
#keywordManageToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #6D28D9, stop:1 #5B21B6);
border-color: #5B21B6;
}
/* 导出规程按钮 - 橙色主题 */
#exportProcedureToolBtn {
color: #FFFFFF;
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #F59E0B, stop:1 #D97706);
border-color: #D97706;
}
#exportProcedureToolBtn:hover {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #D97706, stop:1 #B45309);
border-color: #B45309;
}
#exportProcedureToolBtn:pressed {
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
stop:0 #B45309, stop:1 #92400E);
border-color: #92400E;
}/
* ==================== 规程管理工具栏按钮样式 - 遵循PyQt5规范 ==================== */
/* 工具栏按钮基础样式 */
QToolBar QToolButton {
font-size: 14px;
font-weight: 600;
padding: 10px 16px;
border-radius: 8px;
border: 1px solid #E5E7EB;
margin: 3px;
min-width: 90px;
min-height: 36px;
font-family: "Microsoft YaHei", sans-serif;
color: #FFFFFF;
}
/* 导入规程按钮 - 绿色主题 */
#importToolBtn {
background-color: #10B981;
border-color: #059669;
}
#importToolBtn:hover {
background-color: #059669;
border-color: #047857;
}
#importToolBtn:pressed {
background-color: #047857;
border-color: #065F46;
}
/* 添加分类按钮 - 蓝色主题 */
#addCategoryToolBtn {
background-color: #3B82F6;
border-color: #2563EB;
}
#addCategoryToolBtn:hover {
background-color: #2563EB;
border-color: #1D4ED8;
}
#addCategoryToolBtn:pressed {
background-color: #1D4ED8;
border-color: #1E40AF;
}
/* 删除分类按钮 - 红色主题 */
#deleteCategoryToolBtn {
background-color: #EF4444;
border-color: #DC2626;
}
#deleteCategoryToolBtn:hover {
background-color: #DC2626;
border-color: #B91C1C;
}
#deleteCategoryToolBtn:pressed {
background-color: #B91C1C;
border-color: #991B1B;
}
/* 打开规程按钮 - 蓝色主题 */
#openProcedureToolBtn {
background-color: #3B82F6;
border-color: #2563EB;
}
#openProcedureToolBtn:hover {
background-color: #2563EB;
border-color: #1D4ED8;
}
#openProcedureToolBtn:pressed {
background-color: #1D4ED8;
border-color: #1E40AF;
}
/* 删除规程按钮 - 红色主题 */
#deleteProcedureToolBtn {
background-color: #EF4444;
border-color: #DC2626;
}
#deleteProcedureToolBtn:hover {
background-color: #DC2626;
border-color: #B91C1C;
}
#deleteProcedureToolBtn:pressed {
background-color: #B91C1C;
border-color: #991B1B;
}
/* 历史记录按钮 - 紫色主题 */
#historyToolBtn {
background-color: #8B5CF6;
border-color: #7C3AED;
}
#historyToolBtn:hover {
background-color: #7C3AED;
border-color: #6D28D9;
}
#historyToolBtn:pressed {
background-color: #6D28D9;
border-color: #5B21B6;
}
/* 批量执行按钮 - 绿色主题 */
#batchExecuteToolBtn {
background-color: #10B981;
border-color: #059669;
}
#batchExecuteToolBtn:hover {
background-color: #059669;
border-color: #047857;
}
#batchExecuteToolBtn:pressed {
background-color: #047857;
border-color: #065F46;
}
/* 关键词管理按钮 - 紫色主题 */
#keywordManageToolBtn {
background-color: #8B5CF6;
border-color: #7C3AED;
}
#keywordManageToolBtn:hover {
background-color: #7C3AED;
border-color: #6D28D9;
}
#keywordManageToolBtn:pressed {
background-color: #6D28D9;
border-color: #5B21B6;
}
/* 导出规程按钮 - 橙色主题 */
#exportProcedureToolBtn {
background-color: #F59E0B;
border-color: #D97706;
}
#exportProcedureToolBtn:hover {
background-color: #D97706;
border-color: #B45309;
}
#exportProcedureToolBtn:pressed {
background-color: #B45309;
border-color: #92400E;
}

@ -106,29 +106,7 @@ class HistoryViewerWidget(QWidget):
table.setSelectionBehavior(QTableView.SelectRows)
table.setStyleSheet("""
QTableView {
gridline-color: #d0d0d0;
background-color: white;
alternate-background-color: #f5f5f5;
selection-background-color: #0078d4;
selection-color: white;
}
QTableView::item {
padding: 5px;
border: none;
}
QTableView::item:selected {
background-color: #0078d4;
color: white;
}
QHeaderView::section {
background-color: #f0f0f0;
padding: 5px;
border: 1px solid #d0d0d0;
font-weight: bold;
}
""")
table.setObjectName("historyTable")
def loadHistory(self):
"""加载历史记录"""
@ -451,15 +429,7 @@ class HistoryViewerWidget(QWidget):
# 基本信息区域
infoLayout = QVBoxLayout()
infoGroup = QWidget()
infoGroup.setStyleSheet("""
QWidget {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 5px;
padding: 10px;
margin: 5px;
}
""")
infoGroup.setObjectName("stepDetailInfoGroup")
infoGroupLayout = QVBoxLayout()
infoGroupLayout.addWidget(QLabel(f"<b>步骤ID:</b> {stepId}"))
@ -476,15 +446,7 @@ class HistoryViewerWidget(QWidget):
descTextEdit = QLineEdit()
descTextEdit.setText(stepDesc)
descTextEdit.setReadOnly(True)
descTextEdit.setStyleSheet("""
QLineEdit {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 3px;
padding: 8px;
font-family: 'Consolas', monospace;
}
""")
descTextEdit.setObjectName("stepDescriptionText")
layout.addWidget(descTextEdit)
# 详细结果区域
@ -495,38 +457,14 @@ class HistoryViewerWidget(QWidget):
# 根据执行状态设置结果显示样式
if "成功" in execStatus:
resultTextEdit.setStyleSheet("""
QLineEdit {
background-color: #d4edda;
border: 1px solid #c3e6cb;
border-radius: 3px;
padding: 8px;
color: #155724;
font-family: 'Consolas', monospace;
}
""")
resultTextEdit.setObjectName("stepResultText")
resultTextEdit.setProperty("status", "success")
elif "失败" in execStatus:
resultTextEdit.setStyleSheet("""
QLineEdit {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
border-radius: 3px;
padding: 8px;
color: #721c24;
font-family: 'Consolas', monospace;
}
""")
resultTextEdit.setObjectName("stepResultText")
resultTextEdit.setProperty("status", "error")
else:
resultTextEdit.setStyleSheet("""
QLineEdit {
background-color: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 3px;
padding: 8px;
color: #856404;
font-family: 'Consolas', monospace;
}
""")
resultTextEdit.setObjectName("stepResultText")
resultTextEdit.setProperty("status", "default")
layout.addWidget(resultTextEdit)

@ -133,81 +133,815 @@ class ProcedureEditor(QWidget):
self.createButtonSection(layout)
def createBasicInfoSection(self, layout):
"""创建基本信息区域"""
"""创建基本信息区域 - 优化为紧凑布局"""
info_group = QWidget()
info_group.setObjectName("basicInfoGroup") # 设置对象名称以便QSS选择器使用
info_group.setObjectName("basicInfoGroup")
info_group.setMaximumHeight(80) # 限制基本信息区域的最大高度
info_group.setMinimumHeight(80)
layout.addWidget(info_group)
# 标题
info_title = QLabel("基本信息")
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") # 设置对象名称以便QSS选择器使用
form_layout.addRow("规程名称:", self.nameEdit)
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") # 设置对象名称以便QSS选择器使用
form_layout.addRow("规程编号:", self.numberEdit)
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") # 设置对象名称以便QSS选择器使用
form_layout.addRow("规程类型:", self.typeEdit)
self.typeEdit.setObjectName("procedureTypeEdit")
self.typeEdit.setMaximumHeight(32)
col2_layout.addWidget(type_label)
col2_layout.addWidget(self.typeEdit)
self.descriptionEdit = QTextEdit()
self.descriptionEdit.setMaximumHeight(80)
# 规程描述(简化为单行输入)
desc_label = QLabel("规程描述:")
desc_label.setFixedWidth(60)
desc_label.setProperty("fieldLabel", True)
self.descriptionEdit = QLineEdit() # 改为单行输入
self.descriptionEdit.setPlaceholderText("输入规程描述")
self.descriptionEdit.setObjectName("procedureDescriptionEdit") # 设置对象名称以便QSS选择器使用
form_layout.addRow("规程描述:", self.descriptionEdit)
self.descriptionEdit.setObjectName("procedureDescriptionEdit")
self.descriptionEdit.setMaximumHeight(32)
col2_layout.addWidget(desc_label)
col2_layout.addWidget(self.descriptionEdit)
info_layout.addLayout(form_layout)
grid_layout.addLayout(col2_layout)
grid_layout.addStretch() # 添加弹性空间
info_layout.addLayout(grid_layout)
def createStepsSection(self, layout):
"""创建步骤表格区域"""
"""创建步骤表格区域 - 优化为最大化表格显示"""
steps_group = QWidget()
steps_group.setObjectName("stepsGroup") # 设置对象名称以便QSS选择器使用
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 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") # 设置对象名称以便QSS选择器使用
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(False)
self.stepsTable.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.stepsTable.setAlternatingRowColors(True) # 启用交替行颜色
self.stepsTable.setShowGrid(True) # 显示网格线
# 优化表格样式
# 设置列宽
header = self.stepsTable.horizontalHeader()
@ -219,15 +953,12 @@ class ProcedureEditor(QWidget):
header.setSectionResizeMode(4, QHeaderView.ResizeToContents) # 预期值
header.setSectionResizeMode(5, QHeaderView.ResizeToContents) # 备注
# 设置最小列宽,确保表头显示完整
self.stepsTable.setColumnWidth(0, 60) # 序号
self.stepsTable.setColumnWidth(1, 120) # 步骤ID
self.stepsTable.setColumnWidth(3, 80) # 类型
self.stepsTable.setColumnWidth(4, 100) # 预期值
self.stepsTable.setColumnWidth(5, 120) # 备注
# 移除双击弹窗
# self.stepsTable.cellDoubleClicked.connect(self.editStep)
# 设置最小列宽
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)
@ -236,25 +967,34 @@ class ProcedureEditor(QWidget):
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") # 设置对象名称以便QSS选择器使用
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") # 设置对象名称以便QSS选择器使用
cancel_btn.setObjectName("cancelEditButton")
cancel_btn.setMaximumHeight(32) # 减小按钮高度
cancel_btn.clicked.connect(self.cancelEdit)
button_layout.addWidget(cancel_btn)
button_layout.addStretch()
layout.addLayout(button_layout)
button_layout.addStretch() # 将按钮推到左侧
layout.addWidget(button_widget)
def loadProcedureData(self):
"""加载规程数据"""
@ -276,7 +1016,7 @@ class ProcedureEditor(QWidget):
# 尝试从测试用例信息中获取描述
test_case_info = self.procedureData.get('测试用例信息', {})
description = test_case_info.get('工况描述', '')
self.descriptionEdit.setPlainText(description)
self.descriptionEdit.setText(description)
# 加载步骤数据
self.loadStepsData()
@ -593,7 +1333,7 @@ class ProcedureEditor(QWidget):
'测试用例信息': {
'测试用例': procedureInfo['procedureName'],
'用例编号': procedureInfo['procedureNumber'],
'工况描述': self.descriptionEdit.toPlainText()
'工况描述': self.descriptionEdit.text() # 修改为text()因为现在是QLineEdit
},
'测试步骤': testSteps,
'updatedAt': datetime.now().isoformat()

@ -2,12 +2,12 @@ import sys
import os
from PyQt5.QtCore import Qt, QTimer, QAbstractTableModel, QModelIndex, QPoint, QSize, pyqtSignal, QFile,QTextStream
from PyQt5.QtGui import QBrush, QColor, QFont, QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableView,
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableView, QToolButton,
QPushButton, QVBoxLayout, QWidget, QHBoxLayout,
QLabel, QCheckBox, QSpinBox, QMenu, QFileDialog,
QTabWidget, QTabBar, QListWidget, QListWidgetItem, QDialog,
QLineEdit, QFormLayout, QDialogButtonBox, QMessageBox,
QHeaderView, QToolBar, QAction, QStatusBar, QComboBox, QSplitter, QAbstractItemView)
QHeaderView, QToolBar, QAction, QStatusBar, QSplitter, QAbstractItemView)
from docx import Document
from docx.shared import Pt, RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
@ -80,13 +80,14 @@ class ProcedureManager(QMainWindow):
self.setWindowTitle("规程管理系统")
self.setGeometry(100, 100, 1200, 800)
# 创建工具栏
# 创建工具栏 - 优化图标大小和布局
self.toolbar = QToolBar("主工具栏")
self.toolbar.setIconSize(QSize(32, 32))
# 新增:在工具栏级别统一设置文字显示位置
self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.toolbar.setIconSize(QSize(12, 12)) # 减小图标尺寸避免遮盖
self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) # 文字在图标旁边
self.toolbar.setMaximumHeight(50) # 适当的工具栏高度
self.toolbar.setContentsMargins(0, 0, 0, 0) # 移除边距
self.addToolBar(self.toolbar)
self.createActions()
self.createActions()
# 添加状态栏
self.statusBar = QStatusBar()
@ -223,149 +224,307 @@ class ProcedureManager(QMainWindow):
self.loadProcedures(categoryId)
def initProcedureManagementTab(self):
"""创建规程管理主标签页"""
"""创建规程管理主标签页 - 现代化卡片式设计"""
mainWidget = QWidget()
mainWidget.setStyleSheet("background-color: #F5F7FA;")
# 主布局 - 优化边距去除空白
mainLayout = QHBoxLayout()
mainLayout.setSpacing(8)
mainLayout.setContentsMargins(8, 8, 8, 8)
# 左侧分类卡片
categoryCard = QWidget()
categoryCard.setObjectName("categoryCard")
categoryCard.setFixedWidth(280)
categoryCard.setMaximumHeight(600)
categoryLayout = QVBoxLayout()
categoryLayout.setSpacing(16)
categoryLayout.setContentsMargins(0, 0, 0, 0)
# 分类标题
categoryTitle = QLabel("规程分类")
categoryTitle.setObjectName("cardTitle")
categoryLayout.addWidget(categoryTitle)
# 分类列表
self.categoryList = QListWidget()
self.categoryList.setFixedWidth(200)
self.categoryList.setObjectName("categoryList")
self.categoryList.currentItemChanged.connect(self.categorySelected)
# 设置分类列表接受拖放
self.categoryList.setAcceptDrops(True)
self.categoryList.setDragDropMode(QAbstractItemView.DropOnly)
# 新增:设置分类列表右键菜单
# 设置分类列表右键菜单
self.categoryList.setContextMenuPolicy(Qt.CustomContextMenu)
self.categoryList.customContextMenuRequested.connect(self.showCategoryContextMenu) # 新增
self.categoryList.customContextMenuRequested.connect(self.showCategoryContextMenu)
categoryLayout.addWidget(self.categoryList)
# 分类操作按钮
categoryButtonLayout = QHBoxLayout()
categoryButtonLayout.setSpacing(8)
addCategoryBtn = QPushButton("添加分类")
addCategoryBtn.setObjectName("addCategoryBtn")
addCategoryBtn.clicked.connect(self.addCategory)
addCategoryBtn.setIcon(qta.icon('fa5s.plus', color='white'))
deleteCategoryBtn = QPushButton("删除分类")
deleteCategoryBtn.setObjectName("deleteCategoryBtn")
deleteCategoryBtn.clicked.connect(self.deleteCurrentCategory)
deleteCategoryBtn.setIcon(qta.icon('fa5s.trash', color='white'))
categoryButtonLayout.addWidget(addCategoryBtn)
categoryButtonLayout.addWidget(deleteCategoryBtn)
categoryLayout.addLayout(categoryButtonLayout)
categoryCard.setLayout(categoryLayout)
# 右侧规程卡片
procedureCard = QWidget()
procedureCard.setObjectName("procedureCard")
procedureLayout = QVBoxLayout()
procedureLayout.setSpacing(16)
procedureLayout.setContentsMargins(0, 0, 0, 0)
# 规程标题和统计信息
procedureHeaderLayout = QHBoxLayout()
procedureTitle = QLabel("规程列表")
procedureTitle.setObjectName("cardTitle")
# 规程统计标签
self.procedureCountLabel = QLabel("共 0 个规程")
self.procedureCountLabel.setObjectName("procedureCountLabel")
procedureHeaderLayout.addWidget(procedureTitle)
procedureHeaderLayout.addStretch()
procedureHeaderLayout.addWidget(self.procedureCountLabel)
procedureLayout.addLayout(procedureHeaderLayout)
# 搜索和过滤器
searchLayout = QHBoxLayout()
searchLayout.setSpacing(12)
# 搜索框
self.searchEdit = QLineEdit()
self.searchEdit.setObjectName("searchEdit")
self.searchEdit.setPlaceholderText("搜索规程名称或编号...")
self.searchEdit.textChanged.connect(self.filterProcedures)
searchLayout.addWidget(self.searchEdit, 1)
procedureLayout.addLayout(searchLayout)
# 规程列表
self.procedureList = QListWidget()
self.procedureList.setObjectName("procedureList")
# 设置规程列表支持拖拽
self.procedureList.setDragEnabled(True)
self.procedureList.setDragDropMode(QAbstractItemView.DragOnly)
self.procedureList.itemDoubleClicked.connect(
lambda item: self.openProcedureInExecutor(item)
)
# 新增:设置规程列表右键菜单
# 设置规程列表右键菜单
self.procedureList.setContextMenuPolicy(Qt.CustomContextMenu)
self.procedureList.customContextMenuRequested.connect(self.showProcedureContextMenu) # 新增
self.procedureList.customContextMenuRequested.connect(self.showProcedureContextMenu)
# 新增:拖拽事件处理
# 拖拽事件处理
self.procedureList.dragEnterEvent = self.procedureDragEnterEvent
self.categoryList.dropEvent = self.categoryDropEvent
leftPanel = QWidget()
leftLayout = QVBoxLayout()
leftLayout.addWidget(QLabel("规程分类"))
leftLayout.addWidget(self.categoryList)
leftPanel.setLayout(leftLayout)
leftPanel.setFixedWidth(220)
procedureLayout.addWidget(self.procedureList)
# 规程操作按钮
procedureButtonLayout = QHBoxLayout()
procedureButtonLayout.setSpacing(8)
importBtn = QPushButton("导入规程")
importBtn.setObjectName("importBtn")
importBtn.clicked.connect(self.importProcedure)
importBtn.setIcon(qta.icon('fa5s.file-import', color='white'))
openBtn = QPushButton("打开规程")
openBtn.setObjectName("openBtn")
openBtn.clicked.connect(self.openProcedureInExecutor)
openBtn.setIcon(qta.icon('fa5s.folder-open', color='white'))
exportBtn = QPushButton("导出规程")
exportBtn.setObjectName("exportBtn")
exportBtn.clicked.connect(self.exportSelectedProcedure)
exportBtn.setIcon(qta.icon('fa5s.file-export', color='white'))
deleteBtn = QPushButton("删除规程")
deleteBtn.setObjectName("deleteBtn")
deleteBtn.clicked.connect(self.deleteSelectedProcedure)
deleteBtn.setIcon(qta.icon('fa5s.trash', color='white'))
procedureButtonLayout.addWidget(importBtn)
procedureButtonLayout.addWidget(openBtn)
procedureButtonLayout.addWidget(exportBtn)
procedureButtonLayout.addWidget(deleteBtn)
procedureButtonLayout.addStretch()
procedureLayout.addLayout(procedureButtonLayout)
rightPanel = QWidget()
rightLayout = QVBoxLayout()
rightLayout.addWidget(QLabel("规程列表"))
rightLayout.addWidget(self.procedureList)
rightPanel.setLayout(rightLayout)
procedureCard.setLayout(procedureLayout)
mainLayout.addWidget(leftPanel)
mainLayout.addWidget(rightPanel)
# 添加到主布局
mainLayout.addWidget(categoryCard)
mainLayout.addWidget(procedureCard, 1) # 规程卡片占据剩余空间
mainWidget.setLayout(mainLayout)
self.tabs.addTab(mainWidget, "规程管理")
def getButtonStyle(self, bg_color, border_color, hover_bg, hover_border, pressed_bg, pressed_border):
"""生成统一的按钮样式"""
return f"""
QToolButton {{
background-color: {bg_color};
border: 1px solid {border_color};
border-radius: 6px;
padding: 6px 12px;
color: #FFFFFF;
font-size: 13px;
font-weight: 600;
min-width: 80px;
min-height: 32px;
font-family: "Microsoft YaHei", sans-serif;
}}
QToolButton:hover {{
background-color: {hover_bg};
border-color: {hover_border};
}}
QToolButton:pressed {{
background-color: {pressed_bg};
border-color: {pressed_border};
}}
"""
def createActions(self):
self.importAction = QAction(
qta.icon('fa5s.file-import', color='green'),
"导入规程",
self
)
self.importAction.setIconText("导入规程")
self.importAction.setShortcut("Ctrl+I")
self.importAction.setStatusTip("导入Excel规程文件")
self.importAction.triggered.connect(self.importProcedure)
self.toolbar.addAction(self.importAction) # 修改变量名
self.addCategoryAction = QAction(
qta.icon('fa5s.folder-plus', color='blue'),
"添加分类",
self
)
self.addCategoryAction.setIconText("添加分类")
self.addCategoryAction.setStatusTip("添加新的分类")
self.addCategoryAction.triggered.connect(self.addCategory)
self.toolbar.addAction(self.addCategoryAction) # 修改变量名
self.deleteCategoryAction = QAction(
qta.icon('fa5s.folder-minus', color='red'),
"删除分类",
self
)
self.deleteCategoryAction.setIconText("删除分类")
self.deleteCategoryAction.setStatusTip("删除当前分类")
self.deleteCategoryAction.triggered.connect(self.deleteCurrentCategory)
self.toolbar.addAction(self.deleteCategoryAction) # 修改变量名
self.deleteProcedureAction = QAction(
qta.icon('fa5s.trash', color='red'),
"删除规程",
self
)
self.deleteProcedureAction.setIconText("删除规程")
self.deleteProcedureAction.setStatusTip("删除选中的规程")
self.deleteProcedureAction.triggered.connect(self.deleteSelectedProcedure)
self.toolbar.addAction(self.deleteProcedureAction) # 修改变量名
self.openProcedureAction = QAction(
qta.icon('fa5s.folder-open', color='orange'),
"打开规程",
self
)
self.openProcedureAction.setIconText("打开规程")
self.openProcedureAction.setStatusTip("在步骤执行工具中打开选中的规程")
self.openProcedureAction.triggered.connect(self.openProcedureInExecutor)
self.toolbar.addAction(self.openProcedureAction) # 修改变量名
# 添加历史记录查看器动作
self.historyAction = QAction(
qta.icon('fa5s.history', color='purple'),
"历史记录",
self
)
self.historyAction.setIconText("历史记录")
self.historyAction.setStatusTip("查看历史执行记录")
self.historyAction.triggered.connect(self.openHistoryViewer)
self.toolbar.addAction(self.historyAction)
# 添加批量执行规程动作
self.batchExecuteAction = QAction(
qta.icon('fa5s.play-circle', color='green'),
"批量执行",
self
)
self.batchExecuteAction.setIconText("批量执行")
self.batchExecuteAction.setStatusTip("按顺序批量执行当前分类中的所有规程")
self.batchExecuteAction.triggered.connect(self.batchExecuteProcedures)
self.toolbar.addAction(self.batchExecuteAction)
# 添加关键词管理动作
self.keywordManageAction = QAction(
qta.icon('fa5s.key', color='purple'),
"关键词管理",
self
)
self.keywordManageAction.setIconText("关键词管理")
self.keywordManageAction.setStatusTip("管理执行步骤关键词字段库")
self.keywordManageAction.triggered.connect(self.openKeywordManager)
self.toolbar.addAction(self.keywordManageAction)
# 添加导出规程动作
self.exportProcedureAction = QAction(
qta.icon('fa5s.file-export', color='green'),
"导出规程",
self
)
self.exportProcedureAction.setIconText("导出规程")
self.exportProcedureAction.setStatusTip("导出规程为Excel文件")
self.exportProcedureAction.triggered.connect(self.exportSelectedProcedure)
self.toolbar.addAction(self.exportProcedureAction)
# 导入规程按钮 - 绿色主题
self.importBtn = QToolButton()
self.importBtn.setObjectName("importToolBtn")
self.importBtn.setIcon(qta.icon('fa5s.file-import', color='#FFFFFF'))
self.importBtn.setText("导入规程")
self.importBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.importBtn.setStatusTip("导入Excel规程文件")
self.importBtn.setStyleSheet(self.getButtonStyle(
"#10B981", "#059669", "#059669", "#047857", "#047857", "#065F46"
))
self.importBtn.clicked.connect(self.importProcedure)
self.toolbar.addWidget(self.importBtn)
# 添加分类按钮 - 蓝色主题
self.addCategoryBtn = QToolButton()
self.addCategoryBtn.setObjectName("addCategoryToolBtn")
self.addCategoryBtn.setIcon(qta.icon('fa5s.folder-plus', color='#FFFFFF'))
self.addCategoryBtn.setText("添加分类")
self.addCategoryBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.addCategoryBtn.setStatusTip("添加新的分类")
self.addCategoryBtn.setStyleSheet(self.getButtonStyle(
"#3B82F6", "#2563EB", "#2563EB", "#1D4ED8", "#1D4ED8", "#1E40AF"
))
self.addCategoryBtn.clicked.connect(self.addCategory)
self.toolbar.addWidget(self.addCategoryBtn)
# 删除分类按钮 - 红色主题
self.deleteCategoryBtn = QToolButton()
self.deleteCategoryBtn.setObjectName("deleteCategoryToolBtn")
self.deleteCategoryBtn.setIcon(qta.icon('fa5s.folder-minus', color='#FFFFFF'))
self.deleteCategoryBtn.setText("删除分类")
self.deleteCategoryBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.deleteCategoryBtn.setStatusTip("删除当前分类")
self.deleteCategoryBtn.setStyleSheet(self.getButtonStyle(
"#EF4444", "#DC2626", "#DC2626", "#B91C1C", "#B91C1C", "#991B1B"
))
self.deleteCategoryBtn.clicked.connect(self.deleteCurrentCategory)
self.toolbar.addWidget(self.deleteCategoryBtn)
self.toolbar.addSeparator()
# 打开规程按钮 - 蓝色主题
self.openProcedureBtn = QToolButton()
self.openProcedureBtn.setObjectName("openProcedureToolBtn")
self.openProcedureBtn.setIcon(qta.icon('fa5s.folder-open', color='#FFFFFF'))
self.openProcedureBtn.setText("打开规程")
self.openProcedureBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.openProcedureBtn.setStatusTip("在步骤执行工具中打开选中的规程")
self.openProcedureBtn.setStyleSheet(self.getButtonStyle(
"#3B82F6", "#2563EB", "#2563EB", "#1D4ED8", "#1D4ED8", "#1E40AF"
))
self.openProcedureBtn.clicked.connect(self.openProcedureInExecutor)
self.toolbar.addWidget(self.openProcedureBtn)
# 删除规程按钮 - 红色主题
self.deleteProcedureBtn = QToolButton()
self.deleteProcedureBtn.setObjectName("deleteProcedureToolBtn")
self.deleteProcedureBtn.setIcon(qta.icon('fa5s.trash', color='#FFFFFF'))
self.deleteProcedureBtn.setText("删除规程")
self.deleteProcedureBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.deleteProcedureBtn.setStatusTip("删除选中的规程")
self.deleteProcedureBtn.setStyleSheet(self.getButtonStyle(
"#EF4444", "#DC2626", "#DC2626", "#B91C1C", "#B91C1C", "#991B1B"
))
self.deleteProcedureBtn.clicked.connect(self.deleteSelectedProcedure)
self.toolbar.addWidget(self.deleteProcedureBtn)
self.toolbar.addSeparator()
# 历史记录按钮 - 紫色主题
self.historyBtn = QToolButton()
self.historyBtn.setObjectName("historyToolBtn")
self.historyBtn.setIcon(qta.icon('fa5s.history', color='#FFFFFF'))
self.historyBtn.setText("历史记录")
self.historyBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.historyBtn.setStatusTip("查看历史执行记录")
self.historyBtn.setStyleSheet(self.getButtonStyle(
"#8B5CF6", "#7C3AED", "#7C3AED", "#6D28D9", "#6D28D9", "#5B21B6"
))
self.historyBtn.clicked.connect(self.openHistoryViewer)
self.toolbar.addWidget(self.historyBtn)
# 批量执行按钮 - 绿色主题
self.batchExecuteBtn = QToolButton()
self.batchExecuteBtn.setObjectName("batchExecuteToolBtn")
self.batchExecuteBtn.setIcon(qta.icon('fa5s.play-circle', color='#FFFFFF'))
self.batchExecuteBtn.setText("批量执行")
self.batchExecuteBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.batchExecuteBtn.setStatusTip("按顺序批量执行当前分类中的所有规程")
self.batchExecuteBtn.setStyleSheet(self.getButtonStyle(
"#10B981", "#059669", "#059669", "#047857", "#047857", "#065F46"
))
self.batchExecuteBtn.clicked.connect(self.batchExecuteProcedures)
self.toolbar.addWidget(self.batchExecuteBtn)
# 关键词管理按钮 - 紫色主题
self.keywordManageBtn = QToolButton()
self.keywordManageBtn.setObjectName("keywordManageToolBtn")
self.keywordManageBtn.setIcon(qta.icon('fa5s.key', color='#FFFFFF'))
self.keywordManageBtn.setText("关键词管理")
self.keywordManageBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.keywordManageBtn.setStatusTip("管理执行步骤关键词字段库")
self.keywordManageBtn.setStyleSheet(self.getButtonStyle(
"#8B5CF6", "#7C3AED", "#7C3AED", "#6D28D9", "#6D28D9", "#5B21B6"
))
self.keywordManageBtn.clicked.connect(self.openKeywordManager)
self.toolbar.addWidget(self.keywordManageBtn)
# 导出规程按钮 - 橙色主题
self.exportProcedureBtn = QToolButton()
self.exportProcedureBtn.setObjectName("exportProcedureToolBtn")
self.exportProcedureBtn.setIcon(qta.icon('fa5s.file-export', color='#FFFFFF'))
self.exportProcedureBtn.setText("导出规程")
self.exportProcedureBtn.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.exportProcedureBtn.setStatusTip("导出规程为Excel文件")
self.exportProcedureBtn.setStyleSheet(self.getButtonStyle(
"#F59E0B", "#D97706", "#D97706", "#B45309", "#B45309", "#92400E"
))
self.exportProcedureBtn.clicked.connect(self.exportSelectedProcedure)
self.toolbar.addWidget(self.exportProcedureBtn)
def loadCategories(self):
self.categoryList.clear()
@ -384,11 +543,49 @@ class ProcedureManager(QMainWindow):
self.procedureList.clear()
procedures = self.db.getProcedures(categoryId)
# 存储原始数据用于过滤
self.allProcedures = procedures
for procId, name, number, type, createdAt in procedures:
item = QListWidgetItem(f"{name} ({number})")
item.setData(Qt.UserRole, procId)
item.setToolTip(f"类型: {type}\n创建时间: {createdAt}")
self.procedureList.addItem(item)
# 更新规程统计信息
count = len(procedures)
if hasattr(self, 'procedureCountLabel'):
self.procedureCountLabel.setText(f"{count} 个规程")
def filterProcedures(self):
"""过滤规程列表"""
if not hasattr(self, 'allProcedures') or not hasattr(self, 'searchEdit'):
return
searchText = self.searchEdit.text().lower()
self.procedureList.clear()
filteredCount = 0
for procId, name, number, type, createdAt in self.allProcedures:
# 文本搜索过滤
if searchText and searchText not in name.lower() and searchText not in number.lower():
continue
# 添加到列表
item = QListWidgetItem(f"{name} ({number})")
item.setData(Qt.UserRole, procId)
item.setToolTip(f"类型: {type}\n创建时间: {createdAt}")
self.procedureList.addItem(item)
filteredCount += 1
# 更新统计信息
if hasattr(self, 'procedureCountLabel'):
totalCount = len(self.allProcedures)
if filteredCount == totalCount:
self.procedureCountLabel.setText(f"{totalCount} 个规程")
else:
self.procedureCountLabel.setText(f"显示 {filteredCount} / {totalCount} 个规程")
def categorySelected(self, currentItem, previousItem):
if currentItem:
@ -562,16 +759,28 @@ class ProcedureManager(QMainWindow):
def loadStylesheet(self):
qssPath = "Static/Procedure.qss"
try:
qssFile = QFile(qssPath) # 修改变量名
# 尝试加载优化版QSS如果不存在则使用原版QSS
optimizedQssPath = "Static/Procedure_optimized.qss"
qssFile = QFile(optimizedQssPath)
if qssFile.exists():
qssFile.open(QFile.ReadOnly | QFile.Text)
stream = QTextStream(qssFile)
stream.setCodec("UTF-8")
self.setStyleSheet(stream.readAll())
qssFile.close()
print(f"成功加载样式表: {qssPath}")
print("已加载优化版样式表")
else:
print(f"警告:样式表文件不存在: {qssPath}")
# 回退到原始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"成功加载样式表: {qssPath}")
# else:
# print(f"警告:样式表文件不存在: {qssPath}")
except Exception as e:
print(f"加载样式表失败: {str(e)}")

@ -81,18 +81,23 @@ class StepExecutor(QWidget):
self.createTableSection(layout, testSteps)
self.createControlSection(layout)
self.createSettingsSection(layout)
layout.setSpacing(0)
self.setLayout(layout)
self.createToolbar()
def createInfoSection(self, layout):
"""创建信息显示区域"""
"""创建信息显示区域 - 超紧凑的两行布局"""
# 创建主信息容器
infoContainer = QWidget()
infoContainer.setObjectName("procedureInfoContainer")
infoContainer.setMaximumHeight(60) # 两行布局每行约25像素
infoContainer.setMinimumHeight(60) # 固定高度
infoLayout = QVBoxLayout()
infoContainer.setLayout(infoLayout)
# 使用垂直布局包含两行
mainInfoLayout = QVBoxLayout()
mainInfoLayout.setContentsMargins(4, 2, 4, 2)
mainInfoLayout.setSpacing(2)
infoContainer.setLayout(mainInfoLayout)
# 兼容新旧数据结构
procedure_info = self.procedureData.get("规程信息", {})
@ -108,51 +113,63 @@ class StepExecutor(QWidget):
case_number = test_case_info.get("用例编号", "") or test_case_info.get("caseNumber", "")
condition_description = test_case_info.get("工况描述", "") or test_case_info.get("conditionDescription", "")
# 第一行:规程基本信息(三个并排)
procedureRow = QHBoxLayout()
procedureRow.setSpacing(15)
# 第一行:规程名称和规程编号
row1Layout = QHBoxLayout()
row1Layout.setContentsMargins(0, 0, 0, 0)
row1Layout.setSpacing(8)
# 规程名称
nameGroup = self.createInfoGroup("规程名称", procedure_name, "procedureNameGroup", "procedureNameLabel")
procedureRow.addWidget(nameGroup)
nameGroup = self.createUltraCompactInfoGroup("规程名称", procedure_name)
numberGroup = self.createUltraCompactInfoGroup("规程编号", procedure_number)
# 规程编号
numberGroup = self.createInfoGroup("规程编号", procedure_number, "procedureNumberGroup", "procedureNumberLabel")
procedureRow.addWidget(numberGroup)
row1Layout.addWidget(nameGroup)
row1Layout.addWidget(numberGroup)
row1Layout.addStretch()
# 规程类型
typeGroup = self.createInfoGroup("规程类型", procedure_type, "procedureTypeGroup", "procedureTypeLabel")
procedureRow.addWidget(typeGroup)
# 第二行:规程类型和规程版本
row2Layout = QHBoxLayout()
row2Layout.setContentsMargins(0, 0, 0, 0)
row2Layout.setSpacing(8)
procedureRow.addStretch()
infoLayout.addLayout(procedureRow)
typeGroup = self.createUltraCompactInfoGroup("规程类型", procedure_type)
versionGroup = self.createUltraCompactInfoGroup("规程版本", "IC") # 从截图看到的版本信息
# 第二行:测试用例信息(两个并排)
testCaseRow = QHBoxLayout()
testCaseRow.setSpacing(15)
row2Layout.addWidget(typeGroup)
row2Layout.addWidget(versionGroup)
row2Layout.addStretch()
# 测试用例
testCaseGroup = self.createInfoGroup("测试用例", test_case, "testCaseGroup", "testCaseLabel")
testCaseRow.addWidget(testCaseGroup)
# 添加两行到主布局
mainInfoLayout.addLayout(row1Layout)
mainInfoLayout.addLayout(row2Layout)
# 用例编号
caseNumberGroup = self.createInfoGroup("用例编号", case_number, "caseNumberGroup", "caseNumberLabel")
testCaseRow.addWidget(caseNumberGroup)
layout.addWidget(infoContainer)
layout.addSpacing(4) # 减小与表格的间距
def createCompactInfoGroup(self, label, value):
"""创建紧凑型信息组件 - 水平布局,适合单行显示"""
group = QWidget()
group.setObjectName("compactInfoGroup")
group.setMaximumHeight(24) # 限制高度
testCaseRow.addStretch()
infoLayout.addLayout(testCaseRow)
layout = QHBoxLayout()
layout.setContentsMargins(1, 0, 1, 0) # 极小的边距
layout.setSpacing(2) # 减小间距
# 第三行:工况描述(独占一行,因为可能较长)
if condition_description:
descriptionRow = QHBoxLayout()
descriptionGroup = self.createInfoGroup("工况描述", condition_description, "conditionDescriptionGroup", "conditionDescriptionLabel", isDescription=True)
descriptionRow.addWidget(descriptionGroup)
descriptionRow.addStretch()
infoLayout.addLayout(descriptionRow)
# 标签
labelWidget = QLabel(f"{label}:")
labelWidget.setObjectName("compactInfoLabel")
labelWidget.setFixedWidth(50) # 减小固定宽度
layout.addWidget(labelWidget)
# 值
valueWidget = QLabel(value if value else "未设置")
valueWidget.setObjectName("compactInfoValue")
valueWidget.setElideMode(Qt.ElideRight) # 文本过长时显示省略号
valueWidget.setMaximumWidth(100) # 限制最大宽度
layout.addWidget(valueWidget)
group.setLayout(layout)
return group
layout.addWidget(infoContainer)
layout.addSpacing(20)
def createInfoGroup(self, label, value, groupObjectName, labelObjectName, isDescription=False):
"""创建信息分组组件"""
groupWidget = QWidget()
@ -180,6 +197,64 @@ class StepExecutor(QWidget):
return groupWidget
def createCompactInfoGroup(self, label, value):
"""创建紧凑的信息组件 - 用于单行布局"""
groupWidget = QWidget()
groupWidget.setObjectName("compactInfoGroup")
# 使用水平布局
groupLayout = QHBoxLayout()
groupLayout.setContentsMargins(8, 2, 8, 2)
groupLayout.setSpacing(4)
groupWidget.setLayout(groupLayout)
# 标签
labelWidget = QLabel(f"{label}:")
labelWidget.setObjectName("compactInfoLabel")
labelWidget.setMinimumWidth(60)
groupLayout.addWidget(labelWidget)
# 值
valueWidget = QLabel(value if value else "未设置")
valueWidget.setObjectName("compactInfoValue")
valueWidget.setWordWrap(False) # 不换行以保持紧凑
groupLayout.addWidget(valueWidget)
return groupWidget
def createUltraCompactInfoGroup(self, label, value):
"""创建超紧凑的信息组件 - 用于两行布局"""
groupWidget = QWidget()
groupWidget.setObjectName("ultraCompactInfoGroup")
groupWidget.setMaximumHeight(25) # 限制每个组件的高度
# 使用水平布局
groupLayout = QHBoxLayout()
groupLayout.setContentsMargins(2, 0, 2, 0) # 极小边距
groupLayout.setSpacing(4)
groupWidget.setLayout(groupLayout)
# 标签
labelWidget = QLabel(f"{label}:")
labelWidget.setObjectName("ultraCompactInfoLabel")
labelWidget.setFixedWidth(60) # 固定标签宽度
groupLayout.addWidget(labelWidget)
# 值
valueWidget = QLabel(value if value else "未设置")
valueWidget.setObjectName("ultraCompactInfoValue")
valueWidget.setObjectName("ultraCompactInfoValue")
valueWidget.setWordWrap(False)
valueWidget.setMaximumWidth(200) # 限制值的最大宽度
# 手动处理文本截断
if value and len(value) > 25: # 如果文本过长,手动截断并添加省略号
valueWidget.setText(value[:22] + "...")
groupLayout.addWidget(valueWidget)
return groupWidget
def createTableSection(self, layout, testSteps):
"""创建表格区域"""
try:
@ -429,7 +504,21 @@ class StepExecutor(QWidget):
def updateStatusDisplay(self, message, color="blue"):
"""更新状态显示"""
self.statusLabel.setText(message)
self.statusLabel.setStyleSheet(f"color: {color}; font-weight: bold;")
self.statusLabel.setObjectName("executionStatusLabel")
# 根据颜色设置状态属性
if color == "#059669" or "green" in color.lower():
self.statusLabel.setProperty("status", "success")
elif color == "#DC2626" or "red" in color.lower():
self.statusLabel.setProperty("status", "error")
elif color == "#D97706" or "orange" in color.lower():
self.statusLabel.setProperty("status", "warning")
else:
self.statusLabel.setProperty("status", "info")
# 刷新样式
self.statusLabel.style().unpolish(self.statusLabel)
self.statusLabel.style().polish(self.statusLabel)
def startAutoExecute(self):
"""开始自动执行"""
@ -568,10 +657,18 @@ class StepExecutor(QWidget):
if not stepInfo:
return
# 计算需要的行高
description = stepInfo.get('description', '')
result = stepInfo.get('result', '')
note = stepInfo.get('note', '')
# 计算需要的行高确保所有值都不为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))
@ -597,7 +694,14 @@ class StepExecutor(QWidget):
def adjustAllRowHeights(self):
"""调整所有行的高度"""
try:
for row in range(self.tableModel.rowCount()):
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}")

@ -15,6 +15,7 @@ logging.getLogger('modbus_tk').setLevel(logging.ERROR)
if __name__ == '__main__':
app = QApplication(sys.argv)
print(1111111)
app.setStyle(QStyleFactory.create('Fusion'))
app.setStyleSheet(CommonHelper.readQss('Static/Main.qss')
+ CommonHelper.readQss('Static/profibus.qss')
@ -27,6 +28,7 @@ if __name__ == '__main__':
regWidget = RegisterWidget()
regWidget.show()
else:
Globals._init()
Client.initDB()
ex = MainWindow()

Loading…
Cancel
Save