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, 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) from docx import Document from docx.shared import Pt, RGBColor from docx.enum.text import WD_PARAGRAPH_ALIGNMENT import qtawesome as qta from datetime import datetime # 导入其他模块 from model.ProcedureModel.ProcedureProcessor import ExcelParser, StepTableModel from utils.DBModels.ProcedureModel import DatabaseManager from UI.ProcedureManager.StepExecutor import StepExecutor # 修改导入路径 class HistoryViewerWidget(QDialog): def __init__(self, dbManager, parent=None): super().__init__(parent) self.dbManager = dbManager self.setWindowTitle("历史记录查看器") self.setGeometry(200, 200, 1000, 800) self.initUi() self.loadHistory() def initUi(self): layout = QVBoxLayout() # 搜索栏 searchLayout = QHBoxLayout() self.searchEdit = QLineEdit() self.searchEdit.setPlaceholderText("搜索规程...") self.searchEdit.textChanged.connect(self.loadHistory) searchLayout.addWidget(QLabel("搜索:")) searchLayout.addWidget(self.searchEdit) # 将搜索栏布局添加到主布局 layout.addLayout(searchLayout) # 修复:在此处添加搜索栏 # 历史记录表格 self.table = QTableView() self.table.setEditTriggers(QTableView.NoEditTriggers) self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(["ID", "规程全名", "类型", "执行时间", "报告路径"]) self.table.setModel(self.model) self.table.doubleClicked.connect(self.openReportOrDetails) self.table.setSelectionBehavior(QTableView.SelectRows) # 新增:设置表格的右键菜单策略 self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.showHistoryContextMenu) # 新增:设置表格列宽自适应内容 self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) # 步骤详情表格 self.stepTable = QTableView() self.stepTable.setEditTriggers(QTableView.NoEditTriggers) # 新增:禁用编辑 self.stepModel = QStandardItemModel() self.stepModel.setHorizontalHeaderLabels(["步骤ID", "步骤描述", "执行时间", "执行结果"]) self.stepTable.setModel(self.stepModel) # 新增:设置表格列宽自适应内容 self.stepTable.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) # 分割窗口 splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.table) splitter.addWidget(self.stepTable) splitter.setSizes([400, 400]) # 初始分配高度 layout.addWidget(splitter) # 新增:操作按钮布局 button_layout = QHBoxLayout() self.deleteButton = QPushButton("删除历史记录") self.deleteButton.setIcon(qta.icon('fa5s.trash', color='red')) self.deleteButton.clicked.connect(self.deleteSelectedHistory) button_layout.addWidget(self.deleteButton) # 新增:导出报告按钮 self.exportButton = QPushButton("导出报告") self.exportButton.setIcon(qta.icon('fa5s.file-export', color='green')) self.exportButton.clicked.connect(self.exportReport) button_layout.addWidget(self.exportButton) button_layout.addStretch() layout.addLayout(button_layout) # 按钮 buttonBox = QDialogButtonBox(QDialogButtonBox.Ok) buttonBox.accepted.connect(self.accept) layout.addWidget(buttonBox) self.setLayout(layout) def loadHistory(self): self.model.removeRows(0, self.model.rowCount()) filterText = self.searchEdit.text().strip() history = self.dbManager.getExecutionHistory(filterText) for record in history: # 修改:使用正确的列索引(0-4) row = [ QStandardItem(str(record[0])), # ID QStandardItem(record[1]), # 规程全名(名称+编号) QStandardItem(record[2]), # 类型 QStandardItem(record[3]), # 执行时间 QStandardItem(record[4]) # 报告路径 ] self.model.appendRow(row) self.table.resizeColumnsToContents() def openReportOrDetails(self, index): # 修改:将 get_step_results 改为 getStepResults execution_id = self.model.item(index.row(), 0).text() step_results = self.dbManager.getStepResults(execution_id) # 修正方法名 self.showStepDetails(step_results) # 保存操作历史 self.saveOperationHistory(execution_id, "查看步骤详情", "") def saveOperationHistory(self, executionId, operationType, operationDetail): """保存操作历史记录""" self.dbManager.saveOperationHistory( executionId, operationType, operationDetail, datetime.now().strftime("%Y-%m-%d %H:%M:%S") ) def showStepDetails(self, stepResults): """显示步骤详情""" self.stepModel.removeRows(0, self.stepModel.rowCount()) if not stepResults: return for step in stepResults: row = [ QStandardItem(step['step_id']), QStandardItem(step['step_description']), QStandardItem(step['execution_time']), QStandardItem('成功' if step['result'] else '失败') ] self.stepModel.appendRow(row) # 新增删除历史记录的方法 def deleteSelectedHistory(self): """删除选中的历史记录""" selected_indexes = self.table.selectionModel().selectedRows() if not selected_indexes: QMessageBox.warning(self, "未选择", "请先选择要删除的历史记录") return # 获取选中的执行ID execution_ids = [] for index in selected_indexes: execution_id = self.model.item(index.row(), 0).text() execution_ids.append(execution_id) # 确认删除 reply = QMessageBox.question( self, "确认删除", f"确定要删除选中的 {len(execution_ids)} 条历史记录吗?\n此操作不可恢复!", QMessageBox.Yes | QMessageBox.No ) if reply == QMessageBox.Yes: # 修改:将 delete_execution_history 改为 deleteExecutionHistory success = self.dbManager.deleteExecutionHistory(execution_ids) # 修正方法名 if success: QMessageBox.information(self, "删除成功", "已成功删除选中的历史记录") self.loadHistory() # 重新加载历史记录 else: QMessageBox.warning(self, "删除失败", "删除历史记录时发生错误") def exportReport(self): """导出选中历史记录的报告""" selected_indexes = self.table.selectionModel().selectedRows() if not selected_indexes: QMessageBox.warning(self, "未选择", "请先选择要导出的历史记录") return if len(selected_indexes) > 1: QMessageBox.warning(self, "选择过多", "一次只能导出一个历史记录的报告") return index = selected_indexes[0] execution_id = self.model.item(index.row(), 0).text() # 修改:报告路径现在是第5列(索引4) reportPath = self.model.item(index.row(), 4).text() # 获取执行详情数据 # 修改:将 get_execution_details 改为 getExecutionDetails execution_data = self.dbManager.getExecutionDetails(execution_id) # 修正方法名 if not execution_data: QMessageBox.warning(self, "数据错误", "无法获取执行详情数据") return # 生成报告 try: # 创建临时StepExecutor实例用于生成报告 executor = StepExecutor(execution_data['procedure_content'], execution_data['procedure_id'], self.dbManager) executor.stepResults = execution_data['step_results'] # 设置步骤数据 for step in executor.tableModel.stepData: step_result = next((s for s in execution_data['step_results'] if s['step_id'] == step['stepId']), None) if step_result: step['executed'] = True step['result'] = step_result['result'] step['time'] = datetime.strptime(step_result['execution_time'], "%Y-%m-%d %H:%M:%S") # 生成报告文件 default_name = f"{execution_data['procedure_name']}_历史报告_{execution_id}.docx" # file_path, _ = QFileDialog.getSaveFileName( # self, "保存报告", default_name, "Word文档 (*.docx)" # ) # if file_path: res = executor.generateReport() # QMessageBox.information(self, "导出成功", f"报告已保存到:\n{res}") except Exception as e: QMessageBox.critical(self, "导出错误", f"生成报告时出错:\n{str(e)}") # 新增:历史记录表格的右键菜单 def showHistoryContextMenu(self, pos): """显示历史记录的右键菜单""" index = self.table.indexAt(pos) if index.isValid(): menu = QMenu() deleteAction = menu.addAction("删除历史记录") deleteAction.triggered.connect(self.deleteSelectedHistory) menu.exec_(self.table.viewport().mapToGlobal(pos))