feat: 添加视角跟随功能,优化机器人菜单组件,支持全局跟随状态管理和相应操作反馈
This commit is contained in:
parent
b237ba834e
commit
53075dbb39
@ -7,24 +7,24 @@
|
||||
:selected-robot-name="selectedRobotName"
|
||||
@save="handleImageSettingsSave"
|
||||
/>
|
||||
|
||||
|
||||
<div class="menu-container">
|
||||
<!-- 左侧:机器人信息区域 -->
|
||||
<div v-if="robotInfo" class="robot-info-section">
|
||||
<div class="robot-header">
|
||||
<div class="robot-name">{{ robotInfo.label }}</div>
|
||||
<div class="robot-status" :style="{ color: getRobotStatusColor(robotInfo.state as any || 'offline') }">
|
||||
{{ getRobotStatusText(robotInfo.state as any || 'offline') }}
|
||||
<div class="robot-status" :style="{ color: getRobotStatusColor((robotInfo.state as any) || 'offline') }">
|
||||
{{ getRobotStatusText((robotInfo.state as any) || 'offline') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="robot-details">
|
||||
<div v-if="robotInfo.battery !== undefined" class="detail-item">
|
||||
<span class="detail-label">电量:</span>
|
||||
<div class="battery-container">
|
||||
<div class="battery-bar">
|
||||
<div
|
||||
class="battery-fill"
|
||||
<div
|
||||
class="battery-fill"
|
||||
:style="{ width: `${robotInfo.battery}%` }"
|
||||
:class="getBatteryClass(robotInfo.battery)"
|
||||
></div>
|
||||
@ -32,7 +32,7 @@
|
||||
<span class="battery-text">{{ robotInfo.battery }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="robotInfo.targetPoint" class="detail-item">
|
||||
<span class="detail-label">目标点位:</span>
|
||||
<span class="detail-value">{{ robotInfo.targetPoint }}</span>
|
||||
@ -98,6 +98,23 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 视角控制 -->
|
||||
<div class="action-group">
|
||||
<div class="action-group-title">视角控制</div>
|
||||
<div v-if="!isFollowing" class="action-item" @click="handleRobotAction('follow_view', '视角跟随')">
|
||||
<span class="action-icon">👁️</span>
|
||||
<span>视角跟随</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="isFollowing"
|
||||
class="action-item follow-active"
|
||||
@click="handleRobotAction('stop_follow_view', '停止跟随')"
|
||||
>
|
||||
<span class="action-icon">👁️🗨️</span>
|
||||
<span>停止跟随</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 系统管理 -->
|
||||
<div class="action-group">
|
||||
<div class="action-group-title">系统管理</div>
|
||||
@ -126,14 +143,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { message } from 'ant-design-vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, onUnmounted, ref } from 'vue';
|
||||
|
||||
import type { RobotInfo } from '../../apis/robot';
|
||||
import type { RobotAction } from '../../services/context-menu/robot-menu.service';
|
||||
import {
|
||||
import {
|
||||
executeRobotAction,
|
||||
getGlobalFollowState,
|
||||
getRobotStatusColor,
|
||||
getRobotStatusText
|
||||
getRobotStatusText,
|
||||
startGlobalFollow,
|
||||
stopGlobalFollow,
|
||||
} from '../../services/context-menu/robot-menu.service';
|
||||
import { editorStore } from '../../stores/editor.store';
|
||||
import RobotImageSettingsModal from '../modal/robot-image-settings-modal.vue';
|
||||
@ -161,6 +181,11 @@ const robotInfo = computed<RobotInfo | null>(() => {
|
||||
const imageSettingsVisible = ref(false);
|
||||
const selectedRobotName = ref('');
|
||||
|
||||
// 视角跟随状态 - 使用全局状态
|
||||
const isFollowing = computed(() => {
|
||||
const globalState = getGlobalFollowState();
|
||||
return globalState.isFollowing;
|
||||
});
|
||||
|
||||
// 定义组件名称
|
||||
defineOptions({
|
||||
@ -176,51 +201,81 @@ const getBatteryClass = (batteryLevel: number) => {
|
||||
return 'battery-low';
|
||||
};
|
||||
|
||||
// 开始视角跟随
|
||||
const startFollowView = () => {
|
||||
if (!robotInfo.value || !editorStore.hasEditor()) return;
|
||||
|
||||
const editor = editorStore.getEditorValue();
|
||||
if (!editor) return;
|
||||
|
||||
// 使用全局跟随功能(内部会处理切换逻辑)
|
||||
startGlobalFollow(robotInfo.value.id, editor);
|
||||
message.success('开始视角跟随');
|
||||
};
|
||||
|
||||
// 停止视角跟随
|
||||
const stopFollowView = () => {
|
||||
// 使用全局停止功能
|
||||
stopGlobalFollow();
|
||||
message.success('停止视角跟随');
|
||||
};
|
||||
|
||||
// 处理机器人操作
|
||||
const handleRobotAction = async (action: RobotAction | 'custom_image', actionName: string) => {
|
||||
if (!robotInfo.value) return;
|
||||
|
||||
|
||||
// 处理自定义图片操作
|
||||
if (action === 'custom_image') {
|
||||
if (!robotInfo.value?.label) {
|
||||
message.error('未找到机器人信息');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
console.log('打开机器人图片设置:', robotInfo.value);
|
||||
|
||||
|
||||
// 打开模态框,不关闭右键菜单
|
||||
selectedRobotName.value = robotInfo.value.label;
|
||||
imageSettingsVisible.value = true;
|
||||
|
||||
|
||||
// 只触发自定义图片事件,不触发操作完成事件
|
||||
emit('customImage', {
|
||||
robotInfo: robotInfo.value
|
||||
robotInfo: robotInfo.value,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 处理视角跟随操作
|
||||
if (action === 'follow_view') {
|
||||
startFollowView();
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'stop_follow_view') {
|
||||
stopFollowView();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`执行机器人操作: ${action} (${actionName})`, robotInfo.value);
|
||||
|
||||
|
||||
// 使用服务函数执行操作
|
||||
const result = await executeRobotAction(action, robotInfo.value);
|
||||
|
||||
|
||||
console.log('机器人操作结果:', result);
|
||||
|
||||
|
||||
// 发送操作完成事件
|
||||
emit('actionComplete', {
|
||||
action,
|
||||
robot: robotInfo.value,
|
||||
success: result.success
|
||||
success: result.success,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`机器人${actionName}操作失败:`, error);
|
||||
|
||||
|
||||
emit('actionComplete', {
|
||||
action,
|
||||
robot: robotInfo.value,
|
||||
success: false
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -229,10 +284,15 @@ const handleRobotAction = async (action: RobotAction | 'custom_image', actionNam
|
||||
const handleImageSettingsSave = (data: any) => {
|
||||
console.log('机器人图片设置保存:', data);
|
||||
message.success('机器人图片设置保存成功');
|
||||
|
||||
|
||||
// 可以在这里添加额外的保存后处理逻辑
|
||||
// 比如通知父组件更新机器人显示等
|
||||
};
|
||||
|
||||
// 组件卸载时不需要清理,因为使用全局状态管理
|
||||
onUnmounted(() => {
|
||||
// 全局跟随状态由服务层管理,组件卸载时不需要清理
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -396,6 +456,16 @@ const handleImageSettingsSave = (data: any) => {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.action-item.follow-active {
|
||||
background-color: #e6f7ff;
|
||||
border: 1px solid #91d5ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.action-item.follow-active:hover {
|
||||
background-color: #bae7ff;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 12px;
|
||||
width: 14px;
|
||||
@ -408,13 +478,13 @@ const handleImageSettingsSave = (data: any) => {
|
||||
.menu-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
.robot-info-section {
|
||||
width: 100%;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
|
||||
.actions-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
@ -3,10 +3,19 @@
|
||||
* 处理机器人相关的菜单逻辑和操作
|
||||
*/
|
||||
|
||||
import { reactive } from 'vue';
|
||||
|
||||
import * as AmrApi from '../../apis/amr';
|
||||
import type { RobotInfo } from '../../apis/robot';
|
||||
import { RobotState } from '../../apis/robot';
|
||||
|
||||
// 全局跟随状态管理 - 使用Vue响应式系统
|
||||
const globalFollowState = reactive({
|
||||
isFollowing: false,
|
||||
robotId: '',
|
||||
timer: null as NodeJS.Timeout | null,
|
||||
});
|
||||
|
||||
export interface RobotMenuConfig {
|
||||
menuType: 'robot' | 'default';
|
||||
robotInfo?: RobotInfo;
|
||||
@ -27,7 +36,9 @@ export type RobotAction =
|
||||
| 'reset' // 重置
|
||||
| 'diagnose' // 诊断
|
||||
| 'update' // 更新
|
||||
| 'custom_image'; // 自定义图片
|
||||
| 'custom_image' // 自定义图片
|
||||
| 'follow_view' // 视角跟随
|
||||
| 'stop_follow_view'; // 停止视角跟随
|
||||
|
||||
|
||||
/**
|
||||
@ -158,6 +169,22 @@ async function executeAmrAction(
|
||||
message: '打开自定义图片设置',
|
||||
};
|
||||
|
||||
case 'follow_view':
|
||||
// 视角跟随 - 前端功能,不需要API调用
|
||||
console.log('视角跟随功能:开始跟随机器人');
|
||||
return {
|
||||
success: true,
|
||||
message: '开始视角跟随',
|
||||
};
|
||||
|
||||
case 'stop_follow_view':
|
||||
// 停止视角跟随 - 前端功能,不需要API调用
|
||||
console.log('停止视角跟随功能');
|
||||
return {
|
||||
success: true,
|
||||
message: '停止视角跟随',
|
||||
};
|
||||
|
||||
default:
|
||||
// 其他操作 - 没有对应API,保持原有打印信息逻辑
|
||||
console.log(`执行机器人操作: ${action} (${robotInfo.id}) - 仅打印信息`);
|
||||
@ -261,6 +288,8 @@ export function getRobotActionText(action: RobotAction): string {
|
||||
'diagnose': '诊断',
|
||||
'update': '更新',
|
||||
'custom_image': '自定义图片',
|
||||
'follow_view': '视角跟随',
|
||||
'stop_follow_view': '停止跟随',
|
||||
};
|
||||
|
||||
return actionMap[action] || action;
|
||||
@ -287,6 +316,8 @@ export function getRobotActionIcon(action: RobotAction): string {
|
||||
'diagnose': '🔧',
|
||||
'update': '📱',
|
||||
'custom_image': '🖼️',
|
||||
'follow_view': '👁️',
|
||||
'stop_follow_view': '👁️🗨️',
|
||||
};
|
||||
|
||||
return iconMap[action] || '⚙️';
|
||||
@ -314,4 +345,53 @@ export function getRobotMenuConfig(robotInfo: RobotInfo): RobotMenuConfig {
|
||||
menuType: 'robot',
|
||||
robotInfo,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始全局视角跟随
|
||||
* @param robotId 机器人ID
|
||||
* @param editor 编辑器实例
|
||||
*/
|
||||
export function startGlobalFollow(robotId: string, editor: any): void {
|
||||
// 如果已经在跟随其他机器人,先停止
|
||||
if (globalFollowState.isFollowing && globalFollowState.robotId !== robotId) {
|
||||
stopGlobalFollow();
|
||||
}
|
||||
|
||||
globalFollowState.isFollowing = true;
|
||||
globalFollowState.robotId = robotId;
|
||||
|
||||
// 立即执行一次聚焦
|
||||
editor.gotoById(robotId);
|
||||
|
||||
// 设置定时器,每36毫秒执行一次(约27.8fps)
|
||||
globalFollowState.timer = setInterval(() => {
|
||||
if (globalFollowState.isFollowing) {
|
||||
editor.gotoById(robotId);
|
||||
}
|
||||
}, 10);
|
||||
|
||||
console.log('开始全局视角跟随:', robotId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止全局视角跟随
|
||||
*/
|
||||
export function stopGlobalFollow(): void {
|
||||
globalFollowState.isFollowing = false;
|
||||
globalFollowState.robotId = '';
|
||||
|
||||
if (globalFollowState.timer) {
|
||||
clearInterval(globalFollowState.timer);
|
||||
globalFollowState.timer = null;
|
||||
}
|
||||
|
||||
console.log('停止全局视角跟随');
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局跟随状态
|
||||
*/
|
||||
export function getGlobalFollowState() {
|
||||
return globalFollowState;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user