256 lines
5.2 KiB
Vue
Raw Normal View History

<template>
<div class="point-menu">
<!-- 菜单头部显示站点信息 -->
<div class="menu-header">
<div class="point-info">
<div class="point-icon">📍</div>
<div class="point-details">
<div class="point-name">{{ pointInfo?.name || '未知站点' }}</div>
<div class="point-id">ID: {{ pointInfo?.id }}</div>
</div>
</div>
</div>
<!-- 菜单分割线 -->
<a-divider style="margin: 12px 0;" />
<!-- 菜单选项 -->
<div class="menu-options">
<!-- 导航至此站点 -->
<div
class="menu-item"
:class="{ disabled: !canNavigate }"
@click="handleNavigateToPoint"
>
<div class="menu-item-content">
<span class="menu-icon">🧭</span>
<span class="menu-text">导航至此站点</span>
</div>
<div class="menu-description">
选择机器人并下发移动任务到当前站点
</div>
</div>
</div>
<!-- 机器人选择弹窗 -->
<RobotSelectorModal
v-model:open="showRobotSelector"
:target-point-name="pointInfo?.name"
@confirm="handleRobotSelected"
@cancel="handleRobotSelectorCancel"
/>
</div>
</template>
<script setup lang="ts">
import { message } from 'ant-design-vue';
import { computed, ref } from 'vue';
import type { RobotInfo } from '../../apis/robot';
import { executeNavigateToPoint } from '../../services/context-menu/point-menu.service';
import RobotSelectorModal from '../modal/robot-selector-modal.vue';
interface Props {
menuType?: 'point' | 'default';
pointInfo?: {
id: string;
name: string;
type: string;
};
}
interface Emits {
(e: 'actionComplete', data: {
action: string;
point: any;
success: boolean;
message?: string;
}): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
// 响应式数据
const showRobotSelector = ref(false);
const loading = ref(false);
// 计算属性
const pointInfo = computed(() => props.pointInfo);
// 判断是否可以进行导航
const canNavigate = computed(() => {
return pointInfo.value?.name && pointInfo.value?.id;
});
// 处理导航到站点
const handleNavigateToPoint = async () => {
if (!canNavigate.value) {
message.warning('站点信息不完整,无法导航');
return;
}
// 打开机器人选择弹窗
showRobotSelector.value = true;
};
// 处理机器人选择
const handleRobotSelected = async (data: { robot: RobotInfo; targetPointName: string }) => {
if (!pointInfo.value) {
message.error('站点信息丢失,无法执行导航');
return;
}
loading.value = true;
try {
console.log('选择机器人进行导航:', {
robot: data.robot.label,
targetPoint: data.targetPointName,
});
// 调用导航API
const result = await executeNavigateToPoint(
pointInfo.value.id,
pointInfo.value.name,
data.robot.id,
data.robot.label
);
// 发送操作完成事件
emit('actionComplete', {
action: 'navigateToPoint',
point: pointInfo.value,
success: result.success,
message: result.message,
});
// 显示结果提示
if (result.success) {
message.success(`已为机器人 ${data.robot.label} 下发导航任务到 ${data.targetPointName}`);
} else {
// 如果API返回了错误信息让全局错误处理显示
if (!result.message) {
message.error('导航任务下发失败');
}
}
} catch (error) {
console.error('导航操作失败:', error);
// 发送失败事件
emit('actionComplete', {
action: 'navigateToPoint',
point: pointInfo.value,
success: false,
message: undefined, // 让全局错误处理显示
});
message.error('导航操作失败');
} finally {
loading.value = false;
}
};
// 处理机器人选择弹窗取消
const handleRobotSelectorCancel = () => {
showRobotSelector.value = false;
console.log('用户取消了机器人选择');
};
</script>
<style scoped>
.point-menu {
width: 100%;
min-width: 320px;
max-width: 400px;
padding: 8px;
}
/* 菜单头部 */
.menu-header {
padding: 8px 12px;
}
.point-info {
display: flex;
align-items: center;
gap: 12px;
}
.point-icon {
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.point-details {
flex: 1;
}
.point-name {
font-size: 14px;
font-weight: 500;
color: #262626;
margin-bottom: 4px;
}
.point-id {
font-size: 12px;
color: #8c8c8c;
}
/* 菜单选项 */
.menu-options {
padding: 0 4px;
}
.menu-item {
padding: 12px;
margin: 4px 0;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s;
}
.menu-item:hover:not(.disabled) {
background-color: #f5f5f5;
}
.menu-item.disabled {
opacity: 0.6;
cursor: not-allowed;
}
.menu-item-content {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 4px;
}
.menu-icon {
font-size: 16px;
width: 20px;
text-align: center;
}
.menu-text {
font-size: 14px;
font-weight: 500;
color: #262626;
}
.menu-description {
font-size: 12px;
color: #8c8c8c;
margin-left: 32px;
}
/* 分割线样式 */
:deep(.ant-divider) {
border-color: #f0f0f0;
}
</style>