forked from Rowland/EG
1.虚拟维修考核简单流程
This commit is contained in:
parent
e9039ab832
commit
a76277b2fc
@ -22,6 +22,9 @@ class AssemblyInteractionManager(DirectObject):
|
||||
self.current_step = 0
|
||||
self.total_steps = 0
|
||||
self.is_active = False
|
||||
|
||||
# --- 模式控制 ---
|
||||
self.mode = "training" # 默认训练模式,可选 "training" 或 "exam"
|
||||
|
||||
# --- 拖拽相关(优化) ---
|
||||
self.dragging_model = None
|
||||
@ -37,6 +40,11 @@ class AssemblyInteractionManager(DirectObject):
|
||||
|
||||
# --- 操作权限控制 ---
|
||||
self.operation_enabled = True # 是否允许进行操作
|
||||
|
||||
# --- 考核相关 ---
|
||||
self.exam_score = 0 # 考核总分
|
||||
self.exam_max_score = 0 # 考核满分
|
||||
self.step_scores = {} # 每步得分记录
|
||||
|
||||
# --- 碰撞检测(优化) ---
|
||||
self.picker_traverser = CollisionTraverser('picker_traverser')
|
||||
@ -44,10 +52,38 @@ class AssemblyInteractionManager(DirectObject):
|
||||
self.picker_ray_node = None
|
||||
|
||||
print("拆装交互管理器初始化完成")
|
||||
|
||||
def init_exam_mode(self):
|
||||
"""初始化考核模式"""
|
||||
print("📝 初始化考核模式...")
|
||||
|
||||
# 重置考核数据
|
||||
self.exam_score = 0
|
||||
self.exam_max_score = 0
|
||||
self.step_scores = {}
|
||||
|
||||
# 计算总分
|
||||
steps = self.config_data.get('steps', [])
|
||||
for i, step_data in enumerate(steps):
|
||||
step_score = step_data.get('score', 10) # 默认每步10分
|
||||
self.exam_max_score += step_score
|
||||
self.step_scores[i] = {
|
||||
'max_score': step_score,
|
||||
'current_score': step_score, # 初始满分,操作错误时扣分
|
||||
'tool_error': False, # 是否有工具错误
|
||||
'operation_attempts': 0 # 操作尝试次数
|
||||
}
|
||||
|
||||
print(f"📝 考核模式初始化完成,总分: {self.exam_max_score} 分")
|
||||
|
||||
def play_step_audio(self, step_data):
|
||||
"""播放步骤音频"""
|
||||
try:
|
||||
# 考核模式下不播放音频
|
||||
if self.mode == "exam":
|
||||
print("🔇 考核模式,音频播放已禁用")
|
||||
return
|
||||
|
||||
# 检查是否启用了自动播放音频
|
||||
settings = self.config_data.get('settings', {})
|
||||
auto_play_audio = settings.get('auto_play_audio', True)
|
||||
@ -294,10 +330,89 @@ class AssemblyInteractionManager(DirectObject):
|
||||
"""设置操作是否启用"""
|
||||
self.operation_enabled = enabled
|
||||
print(f"🔧 操作权限: {'启用' if enabled else '禁用'}")
|
||||
|
||||
def check_operation_permission(self):
|
||||
"""检查操作权限"""
|
||||
if not self.is_active:
|
||||
print("⚠️ 交互模式未激活")
|
||||
return False
|
||||
|
||||
# 获取当前步骤数据
|
||||
if self.current_step >= self.total_steps:
|
||||
print("⚠️ 所有步骤已完成")
|
||||
return False
|
||||
|
||||
step_data = self.config_data['steps'][self.current_step]
|
||||
required_tool = step_data.get('required_tool', '无')
|
||||
|
||||
# 获取当前选择的工具
|
||||
current_tool = "无"
|
||||
if hasattr(self, 'step_dialog') and self.step_dialog and self.step_dialog.current_tool_combo:
|
||||
current_tool = self.step_dialog.current_tool_combo.currentText()
|
||||
|
||||
# 检查工具是否匹配
|
||||
tool_matches = self.check_tool_match(current_tool, required_tool)
|
||||
|
||||
if self.mode == "training":
|
||||
# 训练模式:显示提示并阻止错误操作
|
||||
if not tool_matches:
|
||||
print("⚠️ 训练模式 - 工具不匹配,无法进行操作")
|
||||
if hasattr(self, 'step_dialog') and self.step_dialog:
|
||||
QMessageBox.warning(self.step_dialog, "工具不匹配",
|
||||
f"当前步骤需要使用 '{required_tool}' 工具,请先选择正确的工具!")
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
# 考核模式:不显示提示,但记录工具错误并阻止操作
|
||||
if not tool_matches:
|
||||
print(f"❌ 考核模式 - 工具错误:需要'{required_tool}',实际选择'{current_tool}',操作被阻止")
|
||||
|
||||
# 记录工具错误(扣分)
|
||||
self.record_tool_error()
|
||||
return False
|
||||
return True
|
||||
|
||||
def check_tool_match(self, current_tool, required_tool):
|
||||
"""检查工具是否匹配"""
|
||||
# 如果步骤不要求特定工具,任何工具都可以
|
||||
if required_tool == "无" or required_tool == "" or not required_tool:
|
||||
return True
|
||||
|
||||
# 精确匹配
|
||||
if current_tool == required_tool:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def record_tool_error(self):
|
||||
"""记录工具错误(考核模式下扣分)"""
|
||||
if self.mode != "exam":
|
||||
return
|
||||
|
||||
# 获取当前步骤的考核记录
|
||||
if self.current_step in self.step_scores:
|
||||
step_record = self.step_scores[self.current_step]
|
||||
|
||||
# 如果是第一次工具错误,扣除一定分数
|
||||
if not step_record['tool_error']:
|
||||
step_record['tool_error'] = True
|
||||
# 扣除该步骤50%的分数作为工具错误惩罚
|
||||
# penalty = step_record['max_score'] * 0.5
|
||||
penalty = step_record['max_score']
|
||||
step_record['current_score'] = max(0, step_record['current_score'] - penalty)
|
||||
|
||||
print(f"📝 考核记录:工具错误,扣除{penalty:.0f}分,当前步骤剩余{step_record['current_score']:.0f}分")
|
||||
|
||||
# 增加操作尝试次数
|
||||
step_record['operation_attempts'] += 1
|
||||
|
||||
def start_interaction_mode(self):
|
||||
def start_interaction_mode(self, mode="training"):
|
||||
"""启动交互模式"""
|
||||
try:
|
||||
# 设置模式
|
||||
self.mode = mode
|
||||
print(f"🎯 启动拆装交互模式: {self.mode}")
|
||||
|
||||
if not self.load_configuration():
|
||||
return False
|
||||
|
||||
@ -308,6 +423,10 @@ class AssemblyInteractionManager(DirectObject):
|
||||
self.total_steps = len(self.config_data['steps'])
|
||||
self.current_step = 0
|
||||
self.is_active = True
|
||||
|
||||
# 如果是考核模式,初始化考核相关数据
|
||||
if self.mode == "exam":
|
||||
self.init_exam_mode()
|
||||
|
||||
# 设置碰撞检测
|
||||
self.setup_picking()
|
||||
@ -793,11 +912,7 @@ class AssemblyInteractionManager(DirectObject):
|
||||
return
|
||||
|
||||
# 检查操作权限
|
||||
if not self.operation_enabled:
|
||||
print("⚠️ 工具不匹配,无法进行操作")
|
||||
if hasattr(self, 'step_dialog') and self.step_dialog:
|
||||
QMessageBox.warning(self.step_dialog, "工具不匹配",
|
||||
f"当前步骤需要使用 '{self.step_dialog.current_required_tool}' 工具,请先选择正确的工具!")
|
||||
if not self.check_operation_permission():
|
||||
return
|
||||
|
||||
# 获取当前步骤的目标模型
|
||||
@ -1002,8 +1117,8 @@ class AssemblyInteractionManager(DirectObject):
|
||||
def start_dragging(self, model_node, hit_point):
|
||||
"""开始拖拽模型(优化版:计算偏移量)"""
|
||||
# 再次检查操作权限(双重保险)
|
||||
if not self.operation_enabled:
|
||||
print("⚠️ 工具不匹配,无法开始拖拽")
|
||||
if not self.check_operation_permission():
|
||||
print("⚠️ 权限检查失败,无法开始拖拽")
|
||||
return
|
||||
|
||||
self.dragging_model = model_node
|
||||
@ -1231,7 +1346,59 @@ class AssemblyInteractionManager(DirectObject):
|
||||
self.step_dialog.close()
|
||||
self.step_dialog = None
|
||||
|
||||
QMessageBox.information(None, "完成", "所有拆装步骤已完成!")
|
||||
# 如果是考核模式,显示考核结果
|
||||
if self.mode == "exam":
|
||||
self.show_exam_results()
|
||||
else:
|
||||
QMessageBox.information(None, "完成", "所有拆装步骤已完成!")
|
||||
|
||||
def show_exam_results(self):
|
||||
"""显示考核结果"""
|
||||
# 计算最终得分
|
||||
final_score = 0
|
||||
for step_record in self.step_scores.values():
|
||||
final_score += step_record['current_score']
|
||||
|
||||
# 计算得分率
|
||||
score_rate = (final_score / self.exam_max_score * 100) if self.exam_max_score > 0 else 0
|
||||
|
||||
# 生成详细报告
|
||||
report = f"📝 拆装考核结果报告\n"
|
||||
report += f"{'='*40}\n\n"
|
||||
report += f"总得分: {final_score:.0f} / {self.exam_max_score:.0f} 分\n"
|
||||
report += f"得分率: {score_rate:.1f}%\n\n"
|
||||
|
||||
# 评级
|
||||
if score_rate >= 90:
|
||||
grade = "优秀 ⭐⭐⭐"
|
||||
elif score_rate >= 80:
|
||||
grade = "良好 ⭐⭐"
|
||||
elif score_rate >= 60:
|
||||
grade = "及格 ⭐"
|
||||
else:
|
||||
grade = "不及格 ❌"
|
||||
|
||||
report += f"评级: {grade}\n\n"
|
||||
report += f"各步骤详情:\n"
|
||||
report += f"{'-'*30}\n"
|
||||
|
||||
# 显示每步详情
|
||||
for step_idx, step_record in self.step_scores.items():
|
||||
step_name = self.config_data['steps'][step_idx]['name']
|
||||
max_score = step_record['max_score']
|
||||
current_score = step_record['current_score']
|
||||
tool_error = "❌" if step_record['tool_error'] else "✅"
|
||||
attempts = step_record['operation_attempts']
|
||||
|
||||
report += f"{step_name}:\n"
|
||||
report += f" 得分: {current_score:.0f}/{max_score:.0f} 分\n"
|
||||
report += f" 工具使用: {tool_error}\n"
|
||||
report += f" 操作次数: {attempts}\n\n"
|
||||
|
||||
print(report)
|
||||
|
||||
# 显示结果对话框
|
||||
QMessageBox.information(None, "考核完成", report)
|
||||
|
||||
def stop_interaction_mode(self):
|
||||
"""停止交互模式"""
|
||||
@ -1280,8 +1447,8 @@ class AssemblyInteractionManager(DirectObject):
|
||||
"""触发点击位移动画"""
|
||||
try:
|
||||
# 检查操作权限(双重保险)
|
||||
if not self.operation_enabled:
|
||||
print("⚠️ 工具不匹配,无法进行点击触发位移")
|
||||
if not self.check_operation_permission():
|
||||
print("⚠️ 权限检查失败,无法进行点击触发位移")
|
||||
return
|
||||
|
||||
step_type = self.normalize_step_type(step_data)
|
||||
@ -1410,10 +1577,15 @@ class StepGuideDialog(QDialog):
|
||||
super().__init__()
|
||||
self.interaction_manager = interaction_manager
|
||||
self.current_required_tool = "无" # 当前步骤要求的工具
|
||||
self.mode = interaction_manager.mode # 获取模式
|
||||
self.setupUI()
|
||||
|
||||
def setupUI(self):
|
||||
self.setWindowTitle("拆装步骤指引")
|
||||
if self.mode == "exam":
|
||||
self.setWindowTitle("拆装考核")
|
||||
else:
|
||||
self.setWindowTitle("拆装步骤指引")
|
||||
|
||||
self.setFixedSize(450, 400)
|
||||
self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint)
|
||||
layout = QVBoxLayout(self)
|
||||
@ -1423,19 +1595,26 @@ class StepGuideDialog(QDialog):
|
||||
self.step_info_label.setStyleSheet("font-size: 14px; font-weight: bold; color: #2E86C1;")
|
||||
layout.addWidget(self.step_info_label)
|
||||
|
||||
# 步骤描述
|
||||
self.step_desc_text = QTextEdit()
|
||||
self.step_desc_text.setMaximumHeight(100)
|
||||
self.step_desc_text.setReadOnly(True)
|
||||
layout.addWidget(self.step_desc_text)
|
||||
# 步骤描述(考核模式下隐藏)
|
||||
if self.mode != "exam":
|
||||
self.step_desc_text = QTextEdit()
|
||||
self.step_desc_text.setMaximumHeight(100)
|
||||
self.step_desc_text.setReadOnly(True)
|
||||
layout.addWidget(self.step_desc_text)
|
||||
else:
|
||||
self.step_desc_text = None
|
||||
|
||||
# 工具选择组
|
||||
tool_group = QGroupBox("工具选择")
|
||||
tool_layout = QVBoxLayout(tool_group)
|
||||
|
||||
self.required_tool_label = QLabel("当前步骤要求工具: 无")
|
||||
self.required_tool_label.setStyleSheet("font-weight: bold; color: #E74C3C;")
|
||||
tool_layout.addWidget(self.required_tool_label)
|
||||
# 在训练模式下显示要求的工具,考核模式下不显示
|
||||
if self.mode != "exam":
|
||||
self.required_tool_label = QLabel("当前步骤要求工具: 无")
|
||||
self.required_tool_label.setStyleSheet("font-weight: bold; color: #E74C3C;")
|
||||
tool_layout.addWidget(self.required_tool_label)
|
||||
else:
|
||||
self.required_tool_label = None
|
||||
|
||||
current_tool_layout = QHBoxLayout()
|
||||
current_tool_layout.addWidget(QLabel("当前选择工具:"))
|
||||
@ -1445,20 +1624,28 @@ class StepGuideDialog(QDialog):
|
||||
current_tool_layout.addWidget(self.current_tool_combo)
|
||||
tool_layout.addLayout(current_tool_layout)
|
||||
|
||||
self.tool_status_label = QLabel("✅ 工具匹配,可以进行操作")
|
||||
self.tool_status_label.setStyleSheet("color: #27AE60; font-weight: bold;")
|
||||
tool_layout.addWidget(self.tool_status_label)
|
||||
# 在训练模式下显示工具状态,考核模式下不显示
|
||||
if self.mode != "exam":
|
||||
self.tool_status_label = QLabel("✅ 工具匹配,可以进行操作")
|
||||
self.tool_status_label.setStyleSheet("color: #27AE60; font-weight: bold;")
|
||||
tool_layout.addWidget(self.tool_status_label)
|
||||
else:
|
||||
self.tool_status_label = None
|
||||
|
||||
layout.addWidget(tool_group)
|
||||
|
||||
# 操作提示
|
||||
self.operation_label = QLabel("操作提示:")
|
||||
self.operation_label.setStyleSheet("font-weight: bold;")
|
||||
layout.addWidget(self.operation_label)
|
||||
self.operation_text = QTextEdit()
|
||||
self.operation_text.setMaximumHeight(80)
|
||||
self.operation_text.setReadOnly(True)
|
||||
layout.addWidget(self.operation_text)
|
||||
# 操作提示(考核模式下隐藏)
|
||||
if self.mode != "exam":
|
||||
self.operation_label = QLabel("操作提示:")
|
||||
self.operation_label.setStyleSheet("font-weight: bold;")
|
||||
layout.addWidget(self.operation_label)
|
||||
self.operation_text = QTextEdit()
|
||||
self.operation_text.setMaximumHeight(80)
|
||||
self.operation_text.setReadOnly(True)
|
||||
layout.addWidget(self.operation_text)
|
||||
else:
|
||||
self.operation_label = None
|
||||
self.operation_text = None
|
||||
|
||||
# 按钮
|
||||
button_layout = QHBoxLayout()
|
||||
@ -1522,16 +1709,22 @@ class StepGuideDialog(QDialog):
|
||||
# 检查工具是否匹配
|
||||
tool_matches = self.check_tool_permission(current_tool, required_tool)
|
||||
|
||||
if tool_matches:
|
||||
self.tool_status_label.setText("✅ 工具匹配,可以进行操作")
|
||||
self.tool_status_label.setStyleSheet("color: #27AE60; font-weight: bold;")
|
||||
# 启用交互操作
|
||||
self.interaction_manager.set_operation_enabled(True)
|
||||
if self.mode == "training":
|
||||
# 训练模式:显示工具匹配状态
|
||||
if tool_matches:
|
||||
self.tool_status_label.setText("✅ 工具匹配,可以进行操作")
|
||||
self.tool_status_label.setStyleSheet("color: #27AE60; font-weight: bold;")
|
||||
# 启用交互操作
|
||||
self.interaction_manager.set_operation_enabled(True)
|
||||
else:
|
||||
self.tool_status_label.setText(f"❌ 工具不匹配,需要选择 '{required_tool}' 工具")
|
||||
self.tool_status_label.setStyleSheet("color: #E74C3C; font-weight: bold;")
|
||||
# 禁用交互操作
|
||||
self.interaction_manager.set_operation_enabled(False)
|
||||
else:
|
||||
self.tool_status_label.setText(f"❌ 工具不匹配,需要选择 '{required_tool}' 工具")
|
||||
self.tool_status_label.setStyleSheet("color: #E74C3C; font-weight: bold;")
|
||||
# 禁用交互操作
|
||||
self.interaction_manager.set_operation_enabled(False)
|
||||
# 考核模式:不显示工具状态,但仍然需要正确的工具才能操作
|
||||
# 这里不再总是启用操作,而是让权限检查在实际操作时进行
|
||||
self.interaction_manager.set_operation_enabled(True)
|
||||
|
||||
def check_tool_permission(self, current_tool, required_tool):
|
||||
"""检查工具权限"""
|
||||
@ -1547,14 +1740,24 @@ class StepGuideDialog(QDialog):
|
||||
|
||||
def update_step_info(self, step_data, current_step, total_steps):
|
||||
step_name = step_data.get('name', f'步骤 {current_step}')
|
||||
self.step_info_label.setText(f"第 {current_step}/{total_steps} 步: {step_name}")
|
||||
|
||||
if self.mode == "exam":
|
||||
# 考核模式:显示考核信息
|
||||
step_score = step_data.get('score', 10)
|
||||
self.step_info_label.setText(f"第 {current_step}/{total_steps} 步: {step_name} (分值: {step_score})")
|
||||
else:
|
||||
# 训练模式:正常显示
|
||||
self.step_info_label.setText(f"第 {current_step}/{total_steps} 步: {step_name}")
|
||||
|
||||
step_desc = step_data.get('description', '无描述')
|
||||
self.step_desc_text.setPlainText(step_desc)
|
||||
# 步骤描述(考核模式下不显示)
|
||||
if self.step_desc_text is not None:
|
||||
step_desc = step_data.get('description', '无描述')
|
||||
self.step_desc_text.setPlainText(step_desc)
|
||||
|
||||
# 更新工具要求
|
||||
self.current_required_tool = step_data.get('required_tool', '无')
|
||||
self.required_tool_label.setText(f"当前步骤要求工具: {self.current_required_tool}")
|
||||
if self.required_tool_label is not None:
|
||||
self.required_tool_label.setText(f"当前步骤要求工具: {self.current_required_tool}")
|
||||
|
||||
# 更新工具状态
|
||||
self.update_tool_status()
|
||||
@ -1590,7 +1793,9 @@ class StepGuideDialog(QDialog):
|
||||
else:
|
||||
operation_hint = f"🔧 拆卸操作\n请操作模型 '{target_model}' 将其拆卸。"
|
||||
|
||||
self.operation_text.setPlainText(operation_hint)
|
||||
# 操作提示(考核模式下不显示)
|
||||
if self.operation_text is not None:
|
||||
self.operation_text.setPlainText(operation_hint)
|
||||
|
||||
def skip_current_step(self):
|
||||
if self.interaction_manager.is_active:
|
||||
|
||||
@ -192,6 +192,22 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
self.step_type_combo.addItems(["拆卸", "安装"])
|
||||
basic_layout.addWidget(self.step_type_combo, 2, 1)
|
||||
|
||||
# 步骤分值(考核模式用)
|
||||
basic_layout.addWidget(QLabel("步骤分值:"), 3, 0)
|
||||
self.step_score_spin = QDoubleSpinBox()
|
||||
self.step_score_spin.setRange(0, 100)
|
||||
self.step_score_spin.setValue(10) # 默认10分
|
||||
self.step_score_spin.setSingleStep(1)
|
||||
self.step_score_spin.setDecimals(0)
|
||||
self.step_score_spin.setSuffix(" 分")
|
||||
basic_layout.addWidget(self.step_score_spin, 3, 1)
|
||||
|
||||
# 添加分值说明
|
||||
score_note = QLabel("注:在考核模式下,此分值将用于计算该步骤的得分。")
|
||||
score_note.setWordWrap(True)
|
||||
score_note.setStyleSheet("color: #666; font-style: italic; font-size: 10px;")
|
||||
basic_layout.addWidget(score_note, 4, 0, 1, 2)
|
||||
|
||||
scroll_layout.addWidget(basic_group)
|
||||
|
||||
# 目标模型
|
||||
@ -519,12 +535,15 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
'target_position': [0, 0, 0],
|
||||
'audio_file': '',
|
||||
'hint_text': '',
|
||||
'required_tool': '无'
|
||||
'required_tool': '无',
|
||||
'score': 10 # 默认分值
|
||||
}
|
||||
|
||||
self.config_data['steps'].append(step_data)
|
||||
|
||||
list_item = QListWidgetItem(step_name)
|
||||
# 显示步骤名称和分值
|
||||
display_text = f"{step_name} ({step_data['score']}分)"
|
||||
list_item = QListWidgetItem(display_text)
|
||||
list_item.setData(Qt.UserRole, step_data)
|
||||
self.steps_list.addItem(list_item)
|
||||
|
||||
@ -587,7 +606,9 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
step_data = item.data(Qt.UserRole)
|
||||
new_name = f"步骤 {i + 1}"
|
||||
step_data['name'] = new_name
|
||||
item.setText(new_name)
|
||||
step_score = step_data.get('score', 10)
|
||||
display_text = f"{new_name} ({step_score}分)"
|
||||
item.setText(display_text)
|
||||
|
||||
def onStepSelectionChanged(self):
|
||||
"""步骤选择改变"""
|
||||
@ -657,6 +678,9 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
self.required_tool_combo.setCurrentIndex(index)
|
||||
else:
|
||||
self.required_tool_combo.setCurrentIndex(0)
|
||||
|
||||
# 加载分值配置
|
||||
self.step_score_spin.setValue(step_data.get('score', 10))
|
||||
|
||||
finally:
|
||||
# 确保信号重新连接
|
||||
@ -678,6 +702,7 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
self.audio_edit.textChanged.disconnect(self.saveCurrentStepConfig)
|
||||
self.hint_text_edit.textChanged.disconnect(self.saveCurrentStepConfig)
|
||||
self.required_tool_combo.currentTextChanged.disconnect(self.saveCurrentStepConfig)
|
||||
self.step_score_spin.valueChanged.disconnect(self.saveCurrentStepConfig)
|
||||
except:
|
||||
# 忽略断开连接时的错误
|
||||
pass
|
||||
@ -697,6 +722,7 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
self.audio_edit.textChanged.connect(self.saveCurrentStepConfig)
|
||||
self.hint_text_edit.textChanged.connect(self.saveCurrentStepConfig)
|
||||
self.required_tool_combo.currentTextChanged.connect(self.saveCurrentStepConfig)
|
||||
self.step_score_spin.valueChanged.connect(self.saveCurrentStepConfig)
|
||||
|
||||
def saveCurrentStepConfig(self):
|
||||
"""保存当前步骤的配置到list_item的UserRole数据中"""
|
||||
@ -724,12 +750,16 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
step_data['audio_file'] = self.audio_edit.text()
|
||||
step_data['hint_text'] = self.hint_text_edit.toPlainText()
|
||||
step_data['required_tool'] = self.required_tool_combo.currentText()
|
||||
step_data['score'] = int(self.step_score_spin.value()) # 保存分值
|
||||
|
||||
# 确保数据更新到list_item的UserRole中
|
||||
self._current_step_item.setData(Qt.UserRole, step_data)
|
||||
|
||||
# 更新列表项的显示文本
|
||||
self._current_step_item.setText(step_data['name'])
|
||||
# 更新列表项的显示文本,包含分值信息
|
||||
step_name = step_data['name']
|
||||
step_score = step_data.get('score', 10)
|
||||
display_text = f"{step_name} ({step_score}分)"
|
||||
self._current_step_item.setText(display_text)
|
||||
|
||||
# 同时更新config_data中的对应数据(保持数据一致性)
|
||||
current_row = self.steps_list.row(self._current_step_item)
|
||||
@ -869,7 +899,10 @@ class AssemblyDisassemblyConfigDialog(QDialog):
|
||||
# 加载步骤配置
|
||||
self.config_data['steps'] = data.get('steps', [])
|
||||
for step_data in self.config_data['steps']:
|
||||
list_item = QListWidgetItem(step_data['name'])
|
||||
step_name = step_data['name']
|
||||
step_score = step_data.get('score', 10)
|
||||
display_text = f"{step_name} ({step_score}分)"
|
||||
list_item = QListWidgetItem(display_text)
|
||||
list_item.setData(Qt.UserRole, step_data)
|
||||
self.steps_list.addItem(list_item)
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QMenu, QAction
|
||||
QLabel, QLineEdit, QFormLayout, QDoubleSpinBox, QScrollArea,
|
||||
QFileSystemModel, QButtonGroup, QToolButton, QPushButton, QHBoxLayout,
|
||||
QComboBox, QGroupBox, QInputDialog, QFileDialog, QMessageBox, QDesktopWidget, QDialog,
|
||||
QSpinBox, QFrame)
|
||||
QSpinBox, QFrame, QRadioButton, QTextEdit)
|
||||
from PyQt5.QtCore import Qt, QDir, QTimer, QSize, QPoint, QUrl, QRect
|
||||
from direct.showbase.ShowBaseGlobal import aspect2d
|
||||
|
||||
@ -2886,20 +2886,139 @@ class MainWindow(QMainWindow):
|
||||
def onStartAssemblyInteraction(self):
|
||||
"""开始拆装交互"""
|
||||
try:
|
||||
# 显示模式选择对话框
|
||||
mode_dialog = AssemblyModeSelectionDialog(self)
|
||||
if mode_dialog.exec_() != QDialog.Accepted:
|
||||
return
|
||||
|
||||
selected_mode = mode_dialog.get_selected_mode()
|
||||
print(f"🎯 用户选择的拆装模式: {selected_mode}")
|
||||
|
||||
from core.assembly_interaction import AssemblyInteractionManager
|
||||
|
||||
# 检查是否已有交互管理器实例
|
||||
if not hasattr(self.world, 'assembly_interaction'):
|
||||
self.world.assembly_interaction = AssemblyInteractionManager(self.world)
|
||||
|
||||
# 启动交互模式
|
||||
self.world.assembly_interaction.start_interaction_mode()
|
||||
# 启动交互模式,传递模式参数
|
||||
self.world.assembly_interaction.start_interaction_mode(mode=selected_mode)
|
||||
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"启动拆装交互失败: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
class AssemblyModeSelectionDialog(QDialog):
|
||||
"""拆装模式选择对话框"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.selected_mode = "training" # 默认选择训练模式
|
||||
self.setupUI()
|
||||
|
||||
def setupUI(self):
|
||||
self.setWindowTitle("选择拆装模式")
|
||||
self.setFixedSize(400, 300)
|
||||
self.setModal(True)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
# 标题
|
||||
title_label = QLabel("请选择拆装交互模式")
|
||||
title_label.setStyleSheet("font-size: 16px; font-weight: bold; color: #2E86C1; margin: 10px;")
|
||||
title_label.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(title_label)
|
||||
|
||||
# 模式选择组
|
||||
mode_group = QGroupBox("模式选择")
|
||||
mode_layout = QVBoxLayout(mode_group)
|
||||
|
||||
# 训练模式
|
||||
self.training_radio = QRadioButton("训练模式")
|
||||
self.training_radio.setChecked(True) # 默认选中
|
||||
self.training_radio.setStyleSheet("font-size: 14px; margin: 5px;")
|
||||
mode_layout.addWidget(self.training_radio)
|
||||
|
||||
training_desc = QTextEdit()
|
||||
training_desc.setMaximumHeight(60)
|
||||
training_desc.setReadOnly(True)
|
||||
training_desc.setPlainText("• 显示详细的步骤描述和操作提示\n• 提供工具选择的正确性提示\n• 播放语音指导")
|
||||
training_desc.setStyleSheet("background-color: #f0f8ff; border: 1px solid #ccc; margin-left: 20px;")
|
||||
mode_layout.addWidget(training_desc)
|
||||
|
||||
# 考核模式
|
||||
self.exam_radio = QRadioButton("考核模式")
|
||||
self.exam_radio.setStyleSheet("font-size: 14px; margin: 5px;")
|
||||
mode_layout.addWidget(self.exam_radio)
|
||||
|
||||
exam_desc = QTextEdit()
|
||||
exam_desc.setMaximumHeight(60)
|
||||
exam_desc.setReadOnly(True)
|
||||
exam_desc.setPlainText("• 不显示步骤描述\n• 工具选择错误时不提示,直接扣分\n• 不播放语音指导")
|
||||
exam_desc.setStyleSheet("background-color: #fff5f5; border: 1px solid #ccc; margin-left: 20px;")
|
||||
mode_layout.addWidget(exam_desc)
|
||||
|
||||
layout.addWidget(mode_group)
|
||||
|
||||
# 按钮
|
||||
button_layout = QHBoxLayout()
|
||||
|
||||
self.ok_button = QPushButton("开始")
|
||||
self.ok_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #27AE60;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
padding: 8px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #2ECC71;
|
||||
}
|
||||
""")
|
||||
self.ok_button.clicked.connect(self.accept)
|
||||
|
||||
self.cancel_button = QPushButton("取消")
|
||||
self.cancel_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #95A5A6;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
padding: 8px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #BDC3C7;
|
||||
}
|
||||
""")
|
||||
self.cancel_button.clicked.connect(self.reject)
|
||||
|
||||
button_layout.addStretch()
|
||||
button_layout.addWidget(self.ok_button)
|
||||
button_layout.addWidget(self.cancel_button)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
|
||||
# 连接单选按钮信号
|
||||
self.training_radio.toggled.connect(self.on_mode_changed)
|
||||
self.exam_radio.toggled.connect(self.on_mode_changed)
|
||||
|
||||
def on_mode_changed(self):
|
||||
"""模式改变时的处理"""
|
||||
if self.training_radio.isChecked():
|
||||
self.selected_mode = "training"
|
||||
elif self.exam_radio.isChecked():
|
||||
self.selected_mode = "exam"
|
||||
print(f"🔄 模式选择改变: {self.selected_mode}")
|
||||
|
||||
def get_selected_mode(self):
|
||||
"""获取选中的模式"""
|
||||
return self.selected_mode
|
||||
|
||||
|
||||
def setup_main_window(world,path = None):
|
||||
"""设置主窗口的便利函数"""
|
||||
app = QApplication.instance()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user