main
zcwBit 4 months ago
parent c1915ae41d
commit 82148397e0

@ -1,32 +1,21 @@
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
from PyQt5.QtCore import Qt, QTimer, QModelIndex, QSize, pyqtSignal, QFile, QTextStream
from PyQt5.QtGui import QBrush, QColor, QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import (QTableView, QPushButton, QVBoxLayout, QWidget, QHBoxLayout,
QLabel, QMenu, QFileDialog, QDialog, QLineEdit,
QDialogButtonBox, QMessageBox, QHeaderView, QSplitter)
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 # 修改导入路径
from UI.ProcedureManager.StepExecutor import StepExecutor
class HistoryViewerWidget(QDialog):
class HistoryViewerWidget(QWidget):
def __init__(self, dbManager, parent=None):
super().__init__(parent)
self.dbManager = dbManager
self.setWindowTitle("历史记录查看器")
self.setGeometry(200, 200, 1000, 800)
self.initUi()
self.loadHistory()
@ -41,8 +30,7 @@ class HistoryViewerWidget(QDialog):
self.searchEdit.textChanged.connect(self.loadHistory)
searchLayout.addWidget(QLabel("搜索:"))
searchLayout.addWidget(self.searchEdit)
# 将搜索栏布局添加到主布局
layout.addLayout(searchLayout) # 修复:在此处添加搜索栏
layout.addLayout(searchLayout)
# 历史记录表格
self.table = QTableView()
@ -52,81 +40,122 @@ class HistoryViewerWidget(QDialog):
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.setupTableDisplay(self.table)
# 步骤详情表格
self.stepTable = QTableView()
self.stepTable.setEditTriggers(QTableView.NoEditTriggers) # 新增:禁用编辑
self.stepTable.setEditTriggers(QTableView.NoEditTriggers)
self.stepModel = QStandardItemModel()
self.stepModel.setHorizontalHeaderLabels(["步骤ID", "步骤描述", "执行时间", "执行结果"])
self.stepTable.setModel(self.stepModel)
# 新增:设置表格列宽自适应内容
self.stepTable.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.setupTableDisplay(self.stepTable)
# 分割窗口
splitter = QSplitter(Qt.Vertical)
splitter.addWidget(self.table)
splitter.addWidget(self.stepTable)
splitter.setSizes([400, 400]) # 初始分配高度
splitter.setSizes([400, 400])
layout.addWidget(splitter)
# 新增:操作按钮布局
button_layout = QHBoxLayout()
# 操作按钮
buttonLayout = QHBoxLayout()
separator = QWidget()
separator.setFixedWidth(20)
buttonLayout.addWidget(separator)
self.deleteButton = QPushButton("删除历史记录")
self.deleteButton.setIcon(qta.icon('fa5s.trash', color='red'))
self.deleteButton.clicked.connect(self.deleteSelectedHistory)
button_layout.addWidget(self.deleteButton)
buttonLayout.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)
buttonLayout.addWidget(self.exportButton)
button_layout.addStretch()
layout.addLayout(button_layout)
# 按钮
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
layout.addWidget(buttonBox)
buttonLayout.addStretch()
layout.addLayout(buttonLayout)
self.setLayout(layout)
def setupTableDisplay(self, table):
"""设置表格显示属性"""
table.setWordWrap(True)
table.setAlternatingRowColors(True)
table.setSortingEnabled(True)
header = table.horizontalHeader()
if header:
header.setStretchLastSection(True)
header.setSectionResizeMode(QHeaderView.Interactive)
header.setDefaultAlignment(Qt.AlignLeft)
verticalHeader = table.verticalHeader()
if verticalHeader:
verticalHeader.setSectionResizeMode(QHeaderView.ResizeToContents)
verticalHeader.setDefaultAlignment(Qt.AlignCenter)
if table == self.table:
table.setSelectionMode(QTableView.ExtendedSelection)
else:
table.setSelectionMode(QTableView.SingleSelection)
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;
}
""")
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()
rowItems = []
for i, value in enumerate(record):
item = QStandardItem(str(value) if value is not None else "")
item.setTextAlignment(Qt.AlignTop | Qt.AlignLeft)
if i in [1, 4]: # 规程全名和报告路径列
item.setToolTip(str(value) if value is not None else "")
rowItems.append(item)
self.model.appendRow(rowItems)
self.adjustTableColumns(self.table, self.model)
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, "查看步骤详情", "")
"""打开报告或详情"""
executionId = self.model.item(index.row(), 0).text()
stepResults = self.dbManager.getStepResults(executionId)
self.showStepDetails(stepResults)
self.saveOperationHistory(executionId, "查看步骤详情", "")
def saveOperationHistory(self, executionId, operationType, operationDetail):
"""保存操作历史记录"""
"""保存操作历史"""
self.dbManager.saveOperationHistory(
executionId,
operationType,
@ -141,104 +170,178 @@ class HistoryViewerWidget(QDialog):
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)
rowItems = []
# 步骤ID
stepIdItem = QStandardItem(step.get('step_id', ''))
stepIdItem.setTextAlignment(Qt.AlignCenter)
rowItems.append(stepIdItem)
# 步骤描述
descItem = QStandardItem(step.get('step_description', ''))
descItem.setTextAlignment(Qt.AlignTop | Qt.AlignLeft)
descItem.setToolTip(step.get('step_description', ''))
rowItems.append(descItem)
# 执行时间
timeItem = QStandardItem(step.get('execution_time', ''))
timeItem.setTextAlignment(Qt.AlignCenter)
rowItems.append(timeItem)
# 执行结果
resultText = '成功' if step.get('result', False) else '失败'
resultItem = QStandardItem(resultText)
resultItem.setTextAlignment(Qt.AlignCenter)
if step.get('result', False):
resultItem.setBackground(QBrush(QColor(200, 255, 200)))
else:
resultItem.setBackground(QBrush(QColor(255, 200, 200)))
rowItems.append(resultItem)
self.stepModel.appendRow(rowItems)
self.adjustTableColumns(self.stepTable, self.stepModel)
def adjustTableColumns(self, table, model):
"""调整表格列宽"""
header = table.horizontalHeader()
if not header:
return
for col in range(model.columnCount()):
if col == 0: # ID列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 1: # 描述列
header.setSectionResizeMode(col, QHeaderView.Stretch)
elif col == 2: # 类型列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 3: # 时间列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
elif col == 4: # 报告路径或结果列
if model == self.model:
header.setSectionResizeMode(col, QHeaderView.Stretch)
else:
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
table.resizeRowsToContents()
# 新增删除历史记录的方法
def deleteSelectedHistory(self):
"""删除选中的历史记录"""
selected_indexes = self.table.selectionModel().selectedRows()
if not selected_indexes:
selectedIndexes = self.table.selectionModel().selectedRows()
if not selectedIndexes:
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)
executionIds = []
for index in selectedIndexes:
executionId = self.model.item(index.row(), 0).text()
executionIds.append(executionId)
# 确认删除
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除选中的 {len(execution_ids)} 条历史记录吗?\n此操作不可恢复!",
f"确定要删除选中的 {len(executionIds)} 条历史记录吗?\n此操作不可恢复!",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
# 修改:将 delete_execution_history 改为 deleteExecutionHistory
success = self.dbManager.deleteExecutionHistory(execution_ids) # 修正方法名
success = self.dbManager.deleteExecutionHistory(executionIds)
if success:
QMessageBox.information(self, "删除成功", "已成功删除选中的历史记录")
self.loadHistory() # 重新加载历史记录
self.loadHistory()
else:
QMessageBox.warning(self, "删除失败", "删除历史记录时发生错误")
def exportReport(self):
"""导出选中历史记录的报告"""
selected_indexes = self.table.selectionModel().selectedRows()
if not selected_indexes:
"""导出报告"""
selectedIndexes = self.table.selectionModel().selectedRows()
if not selectedIndexes:
QMessageBox.warning(self, "未选择", "请先选择要导出的历史记录")
return
if len(selected_indexes) > 1:
if len(selectedIndexes) > 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()
index = selectedIndexes[0]
executionId = self.model.item(index.row(), 0).text()
# 获取执行详情数据
# 修改:将 get_execution_details 改为 getExecutionDetails
execution_data = self.dbManager.getExecutionDetails(execution_id) # 修正方法名
if not execution_data:
executionData = self.dbManager.getExecutionDetails(executionId)
if not executionData:
QMessageBox.warning(self, "数据错误", "无法获取执行详情数据")
return
# 生成报告
try:
# 创建临时StepExecutor实例用于生成报告
executor = StepExecutor(execution_data['procedure_content'],
execution_data['procedure_id'],
executor = StepExecutor(executionData['procedure_content'],
executionData['procedure_id'],
self.dbManager)
executor.stepResults = execution_data['step_results']
# 设置步骤数据
executor.stepResults = executionData['step_results']
for step in executor.tableModel.stepData:
step_result = next((s for s in execution_data['step_results']
stepResult = next((s for s in executionData['step_results']
if s['step_id'] == step['stepId']), None)
if step_result:
if stepResult:
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}")
step['result'] = stepResult['result']
step['time'] = datetime.strptime(stepResult['execution_time'], "%Y-%m-%d %H:%M:%S")
resultPath = executor.generateReport()
if resultPath:
return
else:
QMessageBox.information(self, "导出取消", "用户取消了报告导出")
except Exception as e:
QMessageBox.critical(self, "导出错误", f"生成报告时出错:\n{str(e)}")
import traceback
print(f"导出报告详细错误: {traceback.format_exc()}")
# 新增:历史记录表格的右键菜单
def showHistoryContextMenu(self, pos):
"""显示历史记录的右键菜单"""
"""显示右键菜单"""
index = self.table.indexAt(pos)
menu = QMenu()
if index.isValid():
menu = QMenu()
deleteAction = menu.addAction("删除历史记录")
deleteAction = menu.addAction(qta.icon('fa5s.trash', color='red'), "删除历史记录")
deleteAction.triggered.connect(self.deleteSelectedHistory)
menu.exec_(self.table.viewport().mapToGlobal(pos))
menu.addSeparator()
exportAction = menu.addAction(qta.icon('fa5s.file-export', color='green'), "导出报告")
exportAction.triggered.connect(lambda: self.exportReportFromContextMenu(index))
menu.addSeparator()
selectAllAction = menu.addAction("全选")
selectAllAction.triggered.connect(self.selectAllHistory)
deselectAllAction = menu.addAction("取消全选")
deselectAllAction.triggered.connect(self.deselectAllHistory)
if index.isValid():
menu.exec_(self.table.viewport().mapToGlobal(pos))
else:
menu.exec_(self.table.mapToGlobal(pos))
def showEvent(self, event):
"""窗口显示事件"""
super().showEvent(event)
QTimer.singleShot(100, self.adjustTablesAfterShow)
def adjustTablesAfterShow(self):
"""窗口显示后调整表格"""
self.adjustTableColumns(self.table, self.model)
self.adjustTableColumns(self.stepTable, self.stepModel)
def selectAllHistory(self):
"""全选历史记录"""
self.table.selectAll()
def deselectAllHistory(self):
"""取消全选历史记录"""
self.table.clearSelection()
def exportReportFromContextMenu(self, index):
"""从右键菜单导出报告"""
self.table.selectRow(index.row())
self.exportReport()

@ -0,0 +1,338 @@
import sys
from PyQt5 import QtCore
from PyQt5.QtCore import QAbstractTableModel, QModelIndex, pyqtSignal, QSize
from PyQt5.QtGui import QFont, QBrush, QColor
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QTableView,
QPushButton, QLabel, QLineEdit, QComboBox,
QDialog, QFormLayout, QDialogButtonBox, QMessageBox,
QHeaderView, QMenu, QAction, QToolBar, QSpinBox)
import qtawesome as qta
from datetime import datetime
class KeywordTableModel(QAbstractTableModel):
"""关键词表格模型"""
columns = ['ID', '关键词', '操作类型', '描述', '创建时间']
def __init__(self, dbManager):
super().__init__()
self.dbManager = dbManager
self.keywordData = []
self.loadData()
def loadData(self):
"""加载数据"""
self.beginResetModel()
self.keywordData = self.dbManager.getStepKeywords()
self.endResetModel()
def rowCount(self, parent=QModelIndex()):
return len(self.keywordData)
def columnCount(self, parent=QModelIndex()):
return len(self.columns)
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return None
row = index.row()
col = index.column()
if row >= len(self.keywordData):
return None
keywordInfo = self.keywordData[row]
if role == QtCore.Qt.DisplayRole:
if col == 0:
return str(keywordInfo[0]) # ID
elif col == 1:
return keywordInfo[1] # 关键词
elif col == 2:
return keywordInfo[2] # 操作类型
elif col == 3:
return keywordInfo[3] or "" # 描述
elif col == 4:
return keywordInfo[4] # 创建时间
elif role == QtCore.Qt.BackgroundRole:
if row % 2 == 0:
return QBrush(QColor(245, 245, 245))
else:
return QBrush(QColor(255, 255, 255))
elif role == QtCore.Qt.FontRole:
font = QFont()
if col == 1: # 关键词列加粗
font.setBold(True)
return font
return None
def headerData(self, section, orientation, role):
if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal:
return self.columns[section]
return None
def getKeywordInfo(self, row):
"""获取指定行的关键词信息"""
if 0 <= row < len(self.keywordData):
return {
'id': self.keywordData[row][0],
'keyword': self.keywordData[row][1],
'operationType': self.keywordData[row][2],
'description': self.keywordData[row][3],
'createdAt': self.keywordData[row][4]
}
return None
class KeywordEditDialog(QDialog):
"""关键词编辑对话框"""
def __init__(self, parent=None, keywordInfo=None):
super().__init__(parent)
self.keywordInfo = keywordInfo
self.isEdit = keywordInfo is not None
self.setWindowTitle("编辑关键词" if self.isEdit else "添加关键词")
self.setFixedSize(400, 200)
self.setupUi()
if self.isEdit:
self.loadKeywordInfo()
def setupUi(self):
"""设置界面"""
layout = QVBoxLayout()
formLayout = QFormLayout()
self.keywordEdit = QLineEdit()
self.keywordEdit.setPlaceholderText("请输入关键词")
formLayout.addRow("关键词:", self.keywordEdit)
self.operationTypeCombo = QComboBox()
self.operationTypeCombo.addItems(['set', 'check', 'wait', 'deltaT'])
formLayout.addRow("操作类型:", self.operationTypeCombo)
self.descriptionEdit = QLineEdit()
self.descriptionEdit.setPlaceholderText("请输入描述(可选)")
formLayout.addRow("描述:", self.descriptionEdit)
layout.addLayout(formLayout)
buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
layout.addWidget(buttonBox)
self.setLayout(layout)
def loadKeywordInfo(self):
"""加载关键词信息"""
if self.keywordInfo:
self.keywordEdit.setText(self.keywordInfo['keyword'])
self.operationTypeCombo.setCurrentText(self.keywordInfo['operationType'])
self.descriptionEdit.setText(self.keywordInfo['description'] or "")
def getKeywordData(self):
"""获取关键词数据"""
return {
'keyword': self.keywordEdit.text().strip(),
'operationType': self.operationTypeCombo.currentText(),
'description': self.descriptionEdit.text().strip()
}
class KeywordManagerWidget(QWidget):
"""关键词字段库管理界面"""
def __init__(self, dbManager, parent=None):
super().__init__(parent)
self.dbManager = dbManager
self.setupUi()
self.setupToolbar()
self.setupContextMenu()
def setupUi(self):
"""设置界面"""
layout = QVBoxLayout()
# 创建工具栏
self.toolbar = QToolBar("关键词管理工具栏")
self.toolbar.setIconSize(QSize(24, 24))
layout.addWidget(self.toolbar)
# 创建表格
self.tableModel = KeywordTableModel(self.dbManager)
self.tableView = QTableView()
self.tableView.setModel(self.tableModel)
self.tableView.setSelectionBehavior(QTableView.SelectRows)
self.tableView.setSelectionMode(QTableView.SingleSelection)
self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tableView.customContextMenuRequested.connect(self.showContextMenu)
# 设置表格样式
self.setupTableStyle()
layout.addWidget(self.tableView)
# 创建状态栏
self.statusLabel = QLabel("就绪")
layout.addWidget(self.statusLabel)
self.setLayout(layout)
def setupToolbar(self):
"""设置工具栏"""
# 添加关键词
addAction = QAction(qta.icon('fa5s.plus', color='green'), "添加关键词", self)
addAction.triggered.connect(self.addKeyword)
self.toolbar.addAction(addAction)
# 编辑关键词
editAction = QAction(qta.icon('fa5s.edit', color='blue'), "编辑关键词", self)
editAction.triggered.connect(self.editKeyword)
self.toolbar.addAction(editAction)
# 删除关键词
deleteAction = QAction(qta.icon('fa5s.trash', color='red'), "删除关键词", self)
deleteAction.triggered.connect(self.deleteKeyword)
self.toolbar.addAction(deleteAction)
self.toolbar.addSeparator()
# 刷新
refreshAction = QAction(qta.icon('fa5s.sync', color='orange'), "刷新", self)
refreshAction.triggered.connect(self.refreshData)
self.toolbar.addAction(refreshAction)
def setupTableStyle(self):
"""设置表格样式"""
header = self.tableView.horizontalHeader()
if header:
header.setSectionResizeMode(0, QHeaderView.ResizeToContents) # ID
header.setSectionResizeMode(1, QHeaderView.Stretch) # 关键词
header.setSectionResizeMode(2, QHeaderView.ResizeToContents) # 操作类型
header.setSectionResizeMode(3, QHeaderView.Stretch) # 描述
header.setSectionResizeMode(4, QHeaderView.ResizeToContents) # 创建时间
# 设置交替行颜色
self.tableView.setAlternatingRowColors(True)
# 设置表格不可编辑
self.tableView.setEditTriggers(QTableView.NoEditTriggers)
def setupContextMenu(self):
"""设置右键菜单"""
self.tableView.customContextMenuRequested.connect(self.showContextMenu)
def showContextMenu(self, pos):
"""显示右键菜单"""
index = self.tableView.indexAt(pos)
if not index.isValid():
return
menu = QMenu()
editAction = menu.addAction("编辑关键词")
editAction.triggered.connect(self.editKeyword)
deleteAction = menu.addAction("删除关键词")
deleteAction.triggered.connect(self.deleteKeyword)
if hasattr(self.tableView, 'viewport') and hasattr(self.tableView.viewport(), 'mapToGlobal'):
menu.exec_(self.tableView.viewport().mapToGlobal(pos))
def addKeyword(self):
"""添加关键词"""
dialog = KeywordEditDialog(self)
if dialog.exec_() == QDialog.Accepted:
keywordData = dialog.getKeywordData()
if not keywordData['keyword']:
QMessageBox.warning(self, "输入错误", "关键词不能为空")
return
keywordId = self.dbManager.addStepKeyword(
keywordData['keyword'],
keywordData['operationType'],
keywordData['description']
)
if keywordId:
self.tableModel.loadData()
self.statusLabel.setText(f"成功添加关键词: {keywordData['keyword']}")
else:
QMessageBox.warning(self, "添加失败", "关键词已存在或添加失败")
def editKeyword(self):
"""编辑关键词"""
currentRow = self.tableView.currentIndex().row()
if currentRow < 0:
QMessageBox.information(self, "提示", "请先选择要编辑的关键词")
return
keywordInfo = self.tableModel.getKeywordInfo(currentRow)
if not keywordInfo:
return
dialog = KeywordEditDialog(self, keywordInfo)
if dialog.exec_() == QDialog.Accepted:
keywordData = dialog.getKeywordData()
if not keywordData['keyword']:
QMessageBox.warning(self, "输入错误", "关键词不能为空")
return
success = self.dbManager.updateStepKeyword(
keywordInfo['id'],
keywordData['keyword'],
keywordData['operationType'],
keywordData['description']
)
if success:
self.tableModel.loadData()
self.statusLabel.setText(f"成功更新关键词: {keywordData['keyword']}")
else:
QMessageBox.warning(self, "更新失败", "关键词已存在或更新失败")
def deleteKeyword(self):
"""删除关键词"""
currentRow = self.tableView.currentIndex().row()
if currentRow < 0:
QMessageBox.information(self, "提示", "请先选择要删除的关键词")
return
keywordInfo = self.tableModel.getKeywordInfo(currentRow)
if not keywordInfo:
return
reply = QMessageBox.question(
self,
"确认删除",
f"确定要删除关键词 '{keywordInfo['keyword']}' 吗?",
QMessageBox.Yes | QMessageBox.No
)
if reply == QMessageBox.Yes:
success = self.dbManager.deleteStepKeyword(keywordInfo['id'])
if success:
self.tableModel.loadData()
self.statusLabel.setText(f"成功删除关键词: {keywordInfo['keyword']}")
else:
QMessageBox.warning(self, "删除失败", "删除关键词失败")
def refreshData(self):
"""刷新数据"""
self.tableModel.loadData()
self.statusLabel.setText("数据已刷新")
def getKeywordByText(self, text):
"""根据文本获取关键词"""
return self.dbManager.getKeywordByText(text)
def getOperationTypes(self):
"""获取所有操作类型"""
return self.dbManager.getOperationTypes()

@ -20,6 +20,7 @@ from model.ProcedureModel.ProcedureProcessor import ExcelParser, StepTableModel
from utils.DBModels.ProcedureModel import DatabaseManager
from UI.ProcedureManager.HistoryViewer import HistoryViewerWidget
from UI.ProcedureManager.StepExecutor import StepExecutor # 修改导入路径
from UI.ProcedureManager.KeywordManager import KeywordManagerWidget # 新增导入
class ExecutionDetailDialog(QDialog):
@ -209,7 +210,8 @@ class ProcedureManager(QMainWindow):
# 切换到新添加的标签页
self.tabs.setCurrentWidget(executor)
executor.executionFinished.connect(lambda _: QTimer.singleShot(0, lambda: executor.resetExecution(fromAuto=True)))
# 修改:只在多轮次执行完成时自动重置,单轮次执行完成时不重置
executor.executionFinished.connect(lambda executor_instance: self.handleExecutionFinished(executor_instance))
def initProcedureManagementTab(self):
"""创建规程管理主标签页"""
@ -334,6 +336,17 @@ class ProcedureManager(QMainWindow):
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)
def loadCategories(self):
self.categoryList.clear()
categories = self.db.getCategories()
@ -471,8 +484,14 @@ class ProcedureManager(QMainWindow):
# 新增:打开历史记录查看器
def openHistoryViewer(self):
"""打开历史记录查看器"""
historyViewer = HistoryViewerWidget(self.db, self)
historyViewer.exec_()
# 创建新标签页
tabIndex = self.tabs.addTab(historyViewer, "历史记录")
self.tabs.setCurrentIndex(tabIndex)
self.statusBar.showMessage("已打开历史记录查看器", 3000)
def loadStylesheet(self):
qssPath = "Static/Procedure.qss"
@ -713,3 +732,24 @@ class ProcedureManager(QMainWindow):
"批量执行完成",
"所有规程已按顺序执行完毕!"
)
def handleExecutionFinished(self, executor_instance):
"""处理执行完成事件"""
# 检查是否为多轮次执行
if executor_instance.infiniteCycles or executor_instance.remainingCycles > 1:
# 多轮次执行完成,自动重置
QTimer.singleShot(0, lambda: executor_instance.resetExecution(fromAuto=True))
else:
# 单轮次执行完成,不自动重置,让用户手动控制
# 可以在这里添加其他处理逻辑,比如显示完成提示等
pass
def openKeywordManager(self):
"""打开关键词管理界面"""
keywordManager = KeywordManagerWidget(self.db, self)
# 创建新标签页
tabIndex = self.tabs.addTab(keywordManager, "关键词管理")
self.tabs.setCurrentIndex(tabIndex)
self.statusBar.showMessage("已打开关键词管理界面", 3000)

File diff suppressed because it is too large Load Diff

@ -133,9 +133,17 @@ class StepTableModel(QAbstractTableModel):
elif col == 2:
return step['time'].strftime("%Y-%m-%d %H:%M:%S") if step['time'] else ''
elif col == 3:
return {True: '', False: '', None: ''}[step['result']]
# print(step['result'])
if not step['result']:
return ' '
if '失败' in step['result']:
return ''
if step['result'] == '未检测到关键字':
return ''
return ''
elif col == 4:
return {True: '成功', False: '失败', None: ''}[step['result']]
# print(step['result'])
return step['result']
elif col == 5:
return step['note'] if step['note'] else ''
@ -181,6 +189,7 @@ class StepTableModel(QAbstractTableModel):
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

@ -57,6 +57,18 @@ class DatabaseManager:
)
""")
# 创建关键词字段库表
self.cursor.execute("""
CREATE TABLE IF NOT EXISTS step_keywords (
id INTEGER PRIMARY KEY AUTOINCREMENT,
keyword TEXT NOT NULL,
operation_type TEXT NOT NULL,
description TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
UNIQUE(keyword, operation_type)
)
""")
# 插入默认分类
self.cursor.execute("""
INSERT OR IGNORE INTO categories (name) VALUES
@ -66,6 +78,19 @@ class DatabaseManager:
('维护规程')
""")
# 插入默认关键词
self.cursor.execute("""
INSERT OR IGNORE INTO step_keywords (keyword, operation_type, description) VALUES
('设置', 'set', '设置操作类型'),
('检查', 'check', '检查操作类型'),
('等待', 'wait', '等待操作类型'),
('接收', 'deltaT', '接收操作类型'),
('配置', 'set', '配置操作类型'),
('验证', 'check', '验证操作类型'),
('暂停', 'wait', '暂停操作类型'),
('获取', 'deltaT', '获取操作类型')
""")
# 确保procedures表有report_path列
try:
self.cursor.execute("ALTER TABLE procedures ADD COLUMN report_path TEXT DEFAULT ''")
@ -299,4 +324,72 @@ class DatabaseManager:
return self.cursor.lastrowid
def close(self):
self.conn.close()
self.conn.close()
# 关键词字段库相关方法
def getStepKeywords(self, operationType=None):
"""获取关键词列表"""
if operationType:
self.cursor.execute("""
SELECT id, keyword, operation_type, description, created_at
FROM step_keywords
WHERE operation_type = ?
ORDER BY keyword
""", (operationType,))
else:
self.cursor.execute("""
SELECT id, keyword, operation_type, description, created_at
FROM step_keywords
ORDER BY keyword
""")
return self.cursor.fetchall()
def addStepKeyword(self, keyword, operationType, description=""):
"""添加关键词"""
try:
self.cursor.execute("""
INSERT INTO step_keywords (keyword, operation_type, description)
VALUES (?, ?, ?)
""", (keyword, operationType, description))
self.conn.commit()
return self.cursor.lastrowid
except sqlite3.IntegrityError:
return None
def updateStepKeyword(self, keywordId, newKeyword, operationType, description=""):
"""更新关键词"""
try:
self.cursor.execute("""
UPDATE step_keywords
SET keyword = ?, operation_type = ?, description = ?
WHERE id = ?
""", (newKeyword, operationType, description, keywordId))
self.conn.commit()
return self.cursor.rowcount > 0
except sqlite3.IntegrityError:
return False
def deleteStepKeyword(self, keywordId):
"""删除关键词"""
self.cursor.execute("DELETE FROM step_keywords WHERE id = ?", (keywordId,))
self.conn.commit()
return self.cursor.rowcount > 0
def getKeywordByText(self, text):
"""根据文本查找匹配的关键词"""
self.cursor.execute("""
SELECT keyword, operation_type
FROM step_keywords
WHERE ? LIKE '%' || keyword || '%'
ORDER BY LENGTH(keyword) DESC
""", (text,))
return self.cursor.fetchall()
def getOperationTypes(self):
"""获取所有操作类型"""
self.cursor.execute("""
SELECT DISTINCT operation_type
FROM step_keywords
ORDER BY operation_type
""")
return [row[0] for row in self.cursor.fetchall()]
Loading…
Cancel
Save