diff --git a/UI/ProcedureManager/HistoryViewer.py b/UI/ProcedureManager/HistoryViewer.py
index e98c456..0c15abb 100644
--- a/UI/ProcedureManager/HistoryViewer.py
+++ b/UI/ProcedureManager/HistoryViewer.py
@@ -48,8 +48,9 @@ class HistoryViewerWidget(QWidget):
self.stepTable = QTableView()
self.stepTable.setEditTriggers(QTableView.NoEditTriggers)
self.stepModel = QStandardItemModel()
- self.stepModel.setHorizontalHeaderLabels(["步骤ID", "步骤描述", "执行时间", "执行结果"])
+ self.stepModel.setHorizontalHeaderLabels(["步骤ID", "步骤描述", "执行时间", "执行状态", "详细结果", "实际/预期对比"])
self.stepTable.setModel(self.stepModel)
+ self.stepTable.doubleClicked.connect(self.showStepDetailDialog)
self.setupTableDisplay(self.stepTable)
# 分割窗口
@@ -188,42 +189,354 @@ class HistoryViewerWidget(QWidget):
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)))
+ # 解析执行结果
+ resultInfo = self.parseStepResult(step.get('result', ''))
+
+ # 执行状态
+ statusItem = QStandardItem(resultInfo['statusText'])
+ statusItem.setTextAlignment(Qt.AlignCenter)
+ statusItem.setBackground(QBrush(resultInfo['statusColor']))
+ if resultInfo['status'] == 'success':
+ statusItem.setText("✓ 成功")
+ elif resultInfo['status'] == 'failed':
+ statusItem.setText("✗ 失败")
+ elif resultInfo['status'] == 'partial':
+ statusItem.setText("⚠ 部分成功")
else:
- resultItem.setBackground(QBrush(QColor(255, 200, 200)))
- rowItems.append(resultItem)
+ statusItem.setText("? 未知")
+ rowItems.append(statusItem)
+
+ # 详细结果
+ detailItem = QStandardItem(resultInfo['details'])
+ detailItem.setTextAlignment(Qt.AlignTop | Qt.AlignLeft)
+ detailItem.setToolTip(resultInfo['details'])
+ rowItems.append(detailItem)
+
+ # 实际/预期对比
+ comparisonItem = QStandardItem(resultInfo['comparison'])
+ comparisonItem.setTextAlignment(Qt.AlignCenter)
+ comparisonItem.setBackground(QBrush(resultInfo['typeColor']))
+ comparisonItem.setToolTip(resultInfo['comparisonDetail'])
+ rowItems.append(comparisonItem)
self.stepModel.appendRow(rowItems)
self.adjustTableColumns(self.stepTable, self.stepModel)
+ def parseStepResult(self, result):
+ """解析步骤执行结果"""
+ if not result or result == 'None':
+ return {
+ 'status': 'failed',
+ 'statusText': '失败',
+ 'statusColor': QColor(255, 200, 200),
+ 'details': '无执行结果',
+ 'comparison': '无对比',
+ 'comparisonDetail': '步骤未执行或执行失败',
+ 'typeColor': QColor(220, 220, 220)
+ }
+
+ result_str = str(result)
+
+ # 设置操作结果解析
+ if "=" in result_str:
+ # 提取设置的变量和值
+ import re
+ matches = re.findall(r'([^\s=]+)\s*=\s*([0-9]+(?:\.[0-9]+)?)', result_str)
+ failedMatches = re.findall(r'([^\s=]+)强制失败', result_str)
+
+ if matches or failedMatches:
+ successCount = len(matches)
+ failCount = len(failedMatches)
+ totalCount = successCount + failCount
+
+ if failCount > 0:
+ status = 'partial' if successCount > 0 else 'failed'
+ statusColor = QColor(255, 255, 200) if status == 'partial' else QColor(255, 200, 200)
+ statusText = '部分成功' if status == 'partial' else '失败'
+ comparison = f"设置 {successCount}/{totalCount} 成功"
+ comparisonDetail = f"成功设置: {', '.join([f'{var}={val}' for var, val in matches])}"
+ if failedMatches:
+ comparisonDetail += f"; 失败变量: {', '.join(failedMatches)}"
+ else:
+ status = 'success'
+ statusColor = QColor(200, 255, 200)
+ statusText = '成功'
+ comparison = f"设置 {successCount} 个变量"
+ comparisonDetail = f"成功设置: {', '.join([f'{var}={val}' for var, val in matches])}"
+
+ return {
+ 'status': status,
+ 'statusText': statusText,
+ 'statusColor': statusColor,
+ 'details': result_str,
+ 'comparison': comparison,
+ 'comparisonDetail': comparisonDetail,
+ 'typeColor': QColor(173, 216, 230)
+ }
+ elif "成功" in result_str or "✓" in result_str:
+ # 包含等号但没有匹配到具体变量,但有成功标识
+ return {
+ 'status': 'success',
+ 'statusText': '成功',
+ 'statusColor': QColor(200, 255, 200),
+ 'details': result_str,
+ 'comparison': "设置成功",
+ 'comparisonDetail': "变量设置操作执行成功",
+ 'typeColor': QColor(173, 216, 230)
+ }
+
+ # 检查操作结果解析
+ if any(op in result_str for op in ['>', '<', '>=', '<=', '==', '!=']):
+ # 分析检查结果
+ successCount = result_str.count('✓')
+ failCount = result_str.count('✗')
+ totalChecks = successCount + failCount
+
+ if failCount > 0:
+ status = 'partial' if successCount > 0 else 'failed'
+ statusColor = QColor(255, 255, 200) if status == 'partial' else QColor(255, 200, 200)
+ statusText = '部分成功' if status == 'partial' else '失败'
+ comparison = f"{successCount}/{totalChecks} 通过"
+ comparisonDetail = f"检查结果: {successCount}个成功, {failCount}个失败"
+ else:
+ status = 'success'
+ statusColor = QColor(200, 255, 200)
+ statusText = '成功'
+ comparison = f"{totalChecks}/{totalChecks} 通过"
+ comparisonDetail = f"所有 {totalChecks} 个检查项均通过"
+
+ return {
+ 'status': status,
+ 'statusText': statusText,
+ 'statusColor': statusColor,
+ 'details': result_str,
+ 'comparison': comparison,
+ 'comparisonDetail': comparisonDetail,
+ 'typeColor': QColor(255, 218, 185)
+ }
+
+ # 等待操作结果解析
+ if "等待" in result_str or "wait" in result_str.lower():
+ # 提取等待时间
+ import re
+ timeMatch = re.search(r'([0-9]+(?:\.[0-9]+)?)', result_str)
+ if timeMatch:
+ waitTime = timeMatch.group(1)
+ comparison = f"等待 {waitTime}s"
+ comparisonDetail = f"按预期等待了 {waitTime} 秒"
+ else:
+ comparison = "等待完成"
+ comparisonDetail = "等待操作按预期完成"
+
+ return {
+ 'status': 'success',
+ 'statusText': '成功',
+ 'statusColor': QColor(200, 255, 200),
+ 'details': result_str,
+ 'comparison': comparison,
+ 'comparisonDetail': comparisonDetail,
+ 'typeColor': QColor(221, 160, 221)
+ }
+
+ # 接收操作结果解析
+ if "t1=" in result_str or "deltaT" in result_str:
+ # 计算接收到的数据点数量
+ import re
+ dataPoints = re.findall(r't\d+=[\d.-]+', result_str)
+ comparison = f"接收 {len(dataPoints)} 个数据"
+ comparisonDetail = f"成功接收数据: {result_str}"
+
+ return {
+ 'status': 'success',
+ 'statusText': '成功',
+ 'statusColor': QColor(200, 255, 200),
+ 'details': result_str,
+ 'comparison': comparison,
+ 'comparisonDetail': comparisonDetail,
+ 'typeColor': QColor(144, 238, 144)
+ }
+
+ # 错误情况
+ if "失败" in result_str or "error" in result_str.lower() or "错误" in result_str:
+ return {
+ 'status': 'failed',
+ 'statusText': '失败',
+ 'statusColor': QColor(255, 200, 200),
+ 'details': result_str,
+ 'comparison': '执行失败',
+ 'comparisonDetail': f"执行过程中出现错误: {result_str}",
+ 'typeColor': QColor(255, 182, 193)
+ }
+
+ # 成功情况
+ if "成功" in result_str or "执行成功" in result_str:
+ return {
+ 'status': 'success',
+ 'statusText': '成功',
+ 'statusColor': QColor(200, 255, 200),
+ 'details': result_str,
+ 'comparison': '执行成功',
+ 'comparisonDetail': '操作按预期成功执行',
+ 'typeColor': QColor(220, 220, 220)
+ }
+
+ # 默认情况
+ return {
+ 'status': 'unknown',
+ 'statusText': '未知',
+ 'statusColor': QColor(240, 240, 240),
+ 'details': result_str,
+ 'comparison': '结果未知',
+ 'comparisonDetail': f'无法解析的执行结果: {result_str}',
+ 'typeColor': QColor(220, 220, 220)
+ }
+
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:
+ if model == self.model: # 历史记录表格
+ for col in range(model.columnCount()):
+ if col == 0: # ID列
+ header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
+ elif col == 1: # 规程全名列
header.setSectionResizeMode(col, QHeaderView.Stretch)
- else:
+ elif col == 2: # 类型列
+ header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
+ elif col == 3: # 执行时间列
+ header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
+ elif col == 4: # 报告路径列
+ header.setSectionResizeMode(col, QHeaderView.Stretch)
+ else: # 步骤详情表格
+ 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: # 详细结果列
+ header.setSectionResizeMode(col, QHeaderView.Stretch)
+ elif col == 5: # 操作类型列
header.setSectionResizeMode(col, QHeaderView.ResizeToContents)
table.resizeRowsToContents()
+
+ def showStepDetailDialog(self, index):
+ """显示步骤详情对话框"""
+ if not index.isValid():
+ return
+
+ row = index.row()
+ stepId = self.stepModel.item(row, 0).text()
+ stepDesc = self.stepModel.item(row, 1).text()
+ execTime = self.stepModel.item(row, 2).text()
+ execStatus = self.stepModel.item(row, 3).text()
+ detailResult = self.stepModel.item(row, 4).text()
+ operationType = self.stepModel.item(row, 5).text()
+
+ # 创建详情对话框
+ dialog = QDialog(self)
+ dialog.setWindowTitle(f"步骤详情 - {stepId}")
+ dialog.setMinimumSize(600, 400)
+ dialog.setModal(True)
+
+ layout = QVBoxLayout()
+
+ # 基本信息区域
+ infoLayout = QVBoxLayout()
+ infoGroup = QWidget()
+ infoGroup.setStyleSheet("""
+ QWidget {
+ background-color: #f8f9fa;
+ border: 1px solid #dee2e6;
+ border-radius: 5px;
+ padding: 10px;
+ margin: 5px;
+ }
+ """)
+
+ infoGroupLayout = QVBoxLayout()
+ infoGroupLayout.addWidget(QLabel(f"步骤ID: {stepId}"))
+ infoGroupLayout.addWidget(QLabel(f"实际/预期对比: {operationType}"))
+ infoGroupLayout.addWidget(QLabel(f"执行时间: {execTime}"))
+ infoGroupLayout.addWidget(QLabel(f"执行状态: {execStatus}"))
+ infoGroup.setLayout(infoGroupLayout)
+
+ layout.addWidget(QLabel("基本信息"))
+ layout.addWidget(infoGroup)
+
+ # 步骤描述区域
+ layout.addWidget(QLabel("步骤描述"))
+ 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;
+ }
+ """)
+ layout.addWidget(descTextEdit)
+
+ # 详细结果区域
+ layout.addWidget(QLabel("执行结果详情"))
+ resultTextEdit = QLineEdit()
+ resultTextEdit.setText(detailResult)
+ resultTextEdit.setReadOnly(True)
+
+ # 根据执行状态设置结果显示样式
+ if "成功" in execStatus:
+ resultTextEdit.setStyleSheet("""
+ QLineEdit {
+ background-color: #d4edda;
+ border: 1px solid #c3e6cb;
+ border-radius: 3px;
+ padding: 8px;
+ color: #155724;
+ font-family: 'Consolas', monospace;
+ }
+ """)
+ elif "失败" in execStatus:
+ resultTextEdit.setStyleSheet("""
+ QLineEdit {
+ background-color: #f8d7da;
+ border: 1px solid #f5c6cb;
+ border-radius: 3px;
+ padding: 8px;
+ color: #721c24;
+ font-family: 'Consolas', monospace;
+ }
+ """)
+ else:
+ resultTextEdit.setStyleSheet("""
+ QLineEdit {
+ background-color: #fff3cd;
+ border: 1px solid #ffeaa7;
+ border-radius: 3px;
+ padding: 8px;
+ color: #856404;
+ font-family: 'Consolas', monospace;
+ }
+ """)
+
+ layout.addWidget(resultTextEdit)
+
+ # 按钮区域
+ buttonBox = QDialogButtonBox(QDialogButtonBox.Ok)
+ buttonBox.accepted.connect(dialog.accept)
+ layout.addWidget(buttonBox)
+
+ dialog.setLayout(layout)
+ dialog.exec_()
def deleteSelectedHistory(self):
"""删除选中的历史记录"""
diff --git a/UI/ProcedureManager/KeywordManager.py b/UI/ProcedureManager/KeywordManager.py
index 2c931a2..ae9a3cb 100644
--- a/UI/ProcedureManager/KeywordManager.py
+++ b/UI/ProcedureManager/KeywordManager.py
@@ -24,6 +24,9 @@ class KeywordTableModel(QAbstractTableModel):
"""加载数据"""
self.beginResetModel()
self.keywordData = self.dbManager.getStepKeywords()
+ # 按ID排序确保顺序正确
+ if self.keywordData:
+ self.keywordData.sort(key=lambda x: x[0]) # 按第一列(ID)排序
self.endResetModel()
def rowCount(self, parent=QModelIndex()):
@@ -46,7 +49,7 @@ class KeywordTableModel(QAbstractTableModel):
if role == QtCore.Qt.DisplayRole:
if col == 0:
- return str(keywordInfo[0]) # ID
+ return str(row + 1) # 显示行号作为ID
elif col == 1:
return keywordInfo[1] # 关键词
elif col == 2:
@@ -96,7 +99,7 @@ class KeywordEditDialog(QDialog):
self.isEdit = keywordInfo is not None
self.setWindowTitle("编辑关键词" if self.isEdit else "添加关键词")
- self.setFixedSize(400, 200)
+ self.setFixedSize(500, 300)
self.setupUi()
if self.isEdit:
@@ -335,4 +338,6 @@ class KeywordManagerWidget(QWidget):
def getOperationTypes(self):
"""获取所有操作类型"""
- return self.dbManager.getOperationTypes()
\ No newline at end of file
+ return self.dbManager.getOperationTypes()
+
+
\ No newline at end of file
diff --git a/UI/ProcedureManager/StepExecutor.py b/UI/ProcedureManager/StepExecutor.py
index d7cb20f..a59c102 100644
--- a/UI/ProcedureManager/StepExecutor.py
+++ b/UI/ProcedureManager/StepExecutor.py
@@ -529,7 +529,7 @@ class StepExecutor(QWidget):
# 计算最终执行统计
totalSteps = len([step for step in self.tableModel.stepData])
executedSteps = len([step for step in self.tableModel.stepData if step.get('executed', False)])
- successSteps = len([step for step in self.tableModel.stepData if step.get('executed', False) and step.get('result', False)])
+ successSteps = len([step for step in self.tableModel.stepData if step.get('executed', False)])
failedSteps = executedSteps - successSteps
successRate = (successSteps/executedSteps*100) if executedSteps > 0 else 0
@@ -1099,7 +1099,7 @@ class StepExecutor(QWidget):
for i in range(self.currentIndex, len(self.tableModel.stepData)):
step = self.tableModel.stepData[i]
if not step['isMain']:
- stepType = step.get('stepType', '')
+ stepType = str(step.get('stepType', ''))
if 'Time' in stepType:
timeMatch = re.search(r'Time\s*=\s*(\d+)\s*ms', stepType, re.IGNORECASE)
if timeMatch:
@@ -1218,7 +1218,7 @@ class StepExecutor(QWidget):
for step in self.tableModel.stepData:
if not step['isMain']:
# 根据步骤类型预估额外时间
- stepType = step.get('stepType', '')
+ stepType = str(step.get('stepType', ''))
if 'Time' in stepType:
# 设置操作带超时时间
timeMatch = re.search(r'Time\s*=\s*(\d+)\s*ms', stepType, re.IGNORECASE)