371 lines
9.0 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="robot-menu">
<div class="menu-container">
<!-- 左侧机器人信息区域 -->
<div v-if="robotInfo" class="robot-info-section">
<div class="robot-header">
<div class="robot-name">{{ robotInfo.name }}</div>
<div class="robot-status" :style="{ color: getStatusColor(robotInfo.status) }">
{{ getStatusText(robotInfo.status) }}
</div>
</div>
<div class="robot-details">
<div v-if="robotInfo.batteryLevel !== undefined" class="detail-item">
<span class="detail-label">电量:</span>
<div class="battery-container">
<div class="battery-bar">
<div
class="battery-fill"
:style="{ width: `${robotInfo.batteryLevel}%` }"
:class="getBatteryClass(robotInfo.batteryLevel)"
></div>
</div>
<span class="battery-text">{{ robotInfo.batteryLevel }}%</span>
</div>
</div>
<div v-if="robotInfo.currentTask" class="detail-item">
<span class="detail-label">当前任务:</span>
<span class="detail-value">{{ robotInfo.currentTask }}</span>
</div>
</div>
</div>
<!-- 右侧机器人操作菜单 -->
<div class="robot-actions">
<div class="actions-grid">
<!-- 控制权限 -->
<div class="action-group">
<div class="action-group-title">控制权限</div>
<div class="action-item" @click="handleRobotAction('seize_control', '抢占控制权')">
<span class="action-icon">🎮</span>
<span>抢占控制权</span>
</div>
<div class="action-item" @click="handleRobotAction('enable_orders', '可接单')">
<span class="action-icon"></span>
<span>可接单</span>
</div>
<div class="action-item" @click="handleRobotAction('disable_orders', '不可接单')">
<span class="action-icon"></span>
<span>不可接单</span>
</div>
</div>
<!-- 运行控制 -->
<div class="action-group">
<div class="action-group-title">运行控制</div>
<div class="action-item" @click="handleRobotAction('pause', '暂停')">
<span class="action-icon"></span>
<span>暂停</span>
</div>
<div class="action-item" @click="handleRobotAction('resume', '继续')">
<span class="action-icon"></span>
<span>继续</span>
</div>
<div class="action-item" @click="handleRobotAction('start', '启动')">
<span class="action-icon">🚀</span>
<span>启动</span>
</div>
<div class="action-item" @click="handleRobotAction('stop', '停止')">
<span class="action-icon"></span>
<span>停止</span>
</div>
</div>
<!-- 导航控制 -->
<div class="action-group">
<div class="action-group-title">导航控制</div>
<div class="action-item" @click="handleRobotAction('go_charge', '前往充电')">
<span class="action-icon">🔋</span>
<span>前往充电</span>
</div>
<div class="action-item" @click="handleRobotAction('go_dock', '前往停靠')">
<span class="action-icon">🏠</span>
<span>前往停靠</span>
</div>
<div class="action-item" @click="handleRobotAction('navigate', '路径导航')">
<span class="action-icon">🧭</span>
<span>路径导航</span>
</div>
</div>
<!-- 系统管理 -->
<div class="action-group">
<div class="action-group-title">系统管理</div>
<div class="action-item" @click="handleRobotAction('reset', '重置')">
<span class="action-icon">🔄</span>
<span>重置</span>
</div>
<div class="action-item" @click="handleRobotAction('diagnose', '诊断')">
<span class="action-icon">🔧</span>
<span>诊断</span>
</div>
<div class="action-item" @click="handleRobotAction('update', '更新')">
<span class="action-icon">📱</span>
<span>更新</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import type { RobotAction,RobotInfo } from '../../services/context-menu/robot-menu.service';
import {
executeRobotAction,
getRobotStatusColor,
getRobotStatusText} from '../../services/context-menu/robot-menu.service';
interface Props {
robotInfo?: RobotInfo;
}
interface Emits {
(e: 'actionComplete', data: { action: RobotAction; robot: RobotInfo; success: boolean }): void;
}
const props = defineProps<Props>();
const emit = defineEmits<Emits>();
// 定义组件名称
defineOptions({
name: 'RobotMenu',
});
// 获取状态显示文本
const getStatusText = (status: string): string => {
return getRobotStatusText(status);
};
// 获取状态颜色
const getStatusColor = (status: string): string => {
return getRobotStatusColor(status);
};
// 获取电量条样式类
const getBatteryClass = (batteryLevel: number) => {
if (batteryLevel > 50) return 'battery-high';
if (batteryLevel > 20) return 'battery-medium';
return 'battery-low';
};
// 处理机器人操作
const handleRobotAction = async (action: RobotAction, actionName: string) => {
if (!props.robotInfo) return;
try {
console.log(`执行机器人操作: ${action} (${actionName})`, props.robotInfo);
// 使用服务函数执行操作
const result = await executeRobotAction(action, props.robotInfo);
console.log('机器人操作结果:', result);
// 发送操作完成事件
emit('actionComplete', {
action,
robot: props.robotInfo,
success: result.success
});
} catch (error) {
console.error(`机器人${actionName}操作失败:`, error);
// 发送操作失败事件
emit('actionComplete', {
action,
robot: props.robotInfo,
success: false
});
}
};
</script>
<style scoped>
.robot-menu {
width: 100%;
min-width: 320px;
max-width: 500px;
}
/* 主容器:左右布局 */
.menu-container {
display: flex;
min-height: 200px;
}
/* 左侧:机器人信息区域 */
.robot-info-section {
width: 140px;
padding: 12px;
background-color: #f8f9fa;
border-right: 1px solid #e9ecef;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.robot-header {
display: flex;
flex-direction: column;
gap: 6px;
margin-bottom: 12px;
}
.robot-name {
font-size: 14px;
font-weight: 600;
color: #000;
line-height: 1.2;
}
.robot-status {
font-size: 10px;
font-weight: 500;
padding: 2px 6px;
border-radius: 8px;
background-color: rgba(0, 0, 0, 0.05);
text-align: center;
white-space: nowrap;
}
.robot-details {
display: flex;
flex-direction: column;
gap: 8px;
}
.detail-item {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 11px;
}
.detail-label {
color: #666;
font-size: 10px;
}
.detail-value {
color: #000;
font-size: 11px;
word-break: break-all;
}
/* 电量条样式 */
.battery-container {
display: flex;
flex-direction: column;
gap: 4px;
}
.battery-bar {
width: 100%;
height: 4px;
background-color: #e9ecef;
border-radius: 2px;
overflow: hidden;
}
.battery-fill {
height: 100%;
transition: width 0.3s ease;
border-radius: 2px;
}
.battery-fill.battery-high {
background-color: #52c41a;
}
.battery-fill.battery-medium {
background-color: #faad14;
}
.battery-fill.battery-low {
background-color: #ff4d4f;
}
.battery-text {
font-size: 10px;
color: #666;
text-align: center;
}
/* 右侧:操作区域 */
.robot-actions {
flex: 1;
padding: 8px;
overflow-y: auto;
}
.actions-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
height: 100%;
}
.action-group {
display: flex;
flex-direction: column;
min-height: 0;
}
.action-group-title {
font-size: 10px;
font-weight: 600;
color: #666;
padding: 4px 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
background-color: #f5f5f5;
border-radius: 4px;
margin-bottom: 4px;
text-align: center;
}
.action-item {
display: flex;
align-items: center;
padding: 6px 8px;
cursor: pointer;
transition: background-color 0.2s;
font-size: 11px;
color: #000;
gap: 6px;
border-radius: 4px;
margin-bottom: 2px;
}
.action-item:hover {
background-color: #f0f0f0;
}
.action-icon {
font-size: 12px;
width: 14px;
text-align: center;
flex-shrink: 0;
}
/* 响应式设计 */
@media (max-width: 400px) {
.menu-container {
flex-direction: column;
}
.robot-info-section {
width: 100%;
border-right: none;
border-bottom: 1px solid #e9ecef;
}
.actions-grid {
grid-template-columns: 1fr;
}
}
</style>