feat: 更新机器人操作菜单,新增控制权限和运行控制项,优化操作文本和图标,增强机器人状态管理功能
This commit is contained in:
parent
d8622aafbe
commit
db42f4a6d8
@ -35,7 +35,31 @@
|
||||
<!-- 机器人操作菜单 -->
|
||||
<div class="robot-actions">
|
||||
<div class="action-group">
|
||||
<div class="action-group-title">基本操作</div>
|
||||
<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>
|
||||
@ -44,34 +68,26 @@
|
||||
<span class="action-icon">⏹️</span>
|
||||
<span>停止</span>
|
||||
</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>
|
||||
|
||||
<div class="action-group">
|
||||
<div class="action-group-title">导航控制</div>
|
||||
<div class="action-item" @click="handleRobotAction('go_home', '回原点')">
|
||||
<span class="action-icon">🏠</span>
|
||||
<span>回原点</span>
|
||||
</div>
|
||||
<div class="action-item" @click="handleRobotAction('charge', '充电')">
|
||||
<div class="action-item" @click="handleRobotAction('go_charge', '前往充电')">
|
||||
<span class="action-icon">🔋</span>
|
||||
<span>充电</span>
|
||||
<span>前往充电</span>
|
||||
</div>
|
||||
<div class="action-item" @click="handleRobotAction('emergency_stop', '紧急停止')">
|
||||
<span class="action-icon">🛑</span>
|
||||
<span>紧急停止</span>
|
||||
<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-group-title">系统管理</div>
|
||||
<div class="action-item" @click="handleRobotAction('reset', '重置')">
|
||||
<span class="action-icon">🔄</span>
|
||||
<span>重置</span>
|
||||
@ -91,15 +107,21 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import type { RobotInfo } from '../../services/context-menu';
|
||||
import { getRobotStatusText, getRobotStatusColor } from '../../services/context-menu';
|
||||
|
||||
import type { RobotAction,RobotInfo } from '../../services/context-menu/robot-menu.service';
|
||||
import {
|
||||
executeRobotAction,
|
||||
getRobotActionIcon,
|
||||
getRobotActionText,
|
||||
getRobotStatusColor,
|
||||
getRobotStatusText} from '../../services/context-menu/robot-menu.service';
|
||||
|
||||
interface Props {
|
||||
robotInfo?: RobotInfo;
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
(e: 'actionComplete', data: { action: string; robot: RobotInfo; success: boolean }): void;
|
||||
(e: 'actionComplete', data: { action: RobotAction; robot: RobotInfo; success: boolean }): void;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
@ -128,20 +150,22 @@ const getBatteryClass = (batteryLevel: number) => {
|
||||
};
|
||||
|
||||
// 处理机器人操作
|
||||
const handleRobotAction = async (action: string, actionName: string) => {
|
||||
const handleRobotAction = async (action: RobotAction, actionName: string) => {
|
||||
if (!props.robotInfo) return;
|
||||
|
||||
try {
|
||||
console.log(`执行机器人操作: ${action}`, props.robotInfo);
|
||||
console.log(`执行机器人操作: ${action} (${actionName})`, props.robotInfo);
|
||||
|
||||
// 模拟操作延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
// 使用服务函数执行操作
|
||||
const result = await executeRobotAction(action, props.robotInfo);
|
||||
|
||||
console.log('机器人操作结果:', result);
|
||||
|
||||
// 发送操作完成事件
|
||||
emit('actionComplete', {
|
||||
action,
|
||||
robot: props.robotInfo,
|
||||
success: true
|
||||
success: result.success
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`机器人${actionName}操作失败:`, error);
|
||||
|
@ -12,6 +12,9 @@ export interface RobotInfo {
|
||||
batteryLevel?: number;
|
||||
currentTask?: string;
|
||||
position?: { x: number; y: number };
|
||||
canAcceptOrders?: boolean; // 是否可接单
|
||||
isControlled?: boolean; // 是否被控制
|
||||
isPaused?: boolean; // 是否暂停
|
||||
}
|
||||
|
||||
export interface RobotMenuConfig {
|
||||
@ -19,6 +22,22 @@ export interface RobotMenuConfig {
|
||||
robotInfo?: RobotInfo;
|
||||
}
|
||||
|
||||
// 机器人操作类型
|
||||
export type RobotAction =
|
||||
| 'seize_control' // 抢占控制权
|
||||
| 'enable_orders' // 可接单
|
||||
| 'disable_orders' // 不可接单
|
||||
| 'pause' // 暂停
|
||||
| 'resume' // 继续
|
||||
| 'go_charge' // 前往充电
|
||||
| 'go_dock' // 前往停靠
|
||||
| 'navigate' // 路径导航
|
||||
| 'start' // 启动
|
||||
| 'stop' // 停止
|
||||
| 'reset' // 重置
|
||||
| 'diagnose' // 诊断
|
||||
| 'update'; // 更新
|
||||
|
||||
/**
|
||||
* 获取机器人信息
|
||||
* @param data 事件数据
|
||||
@ -55,14 +74,7 @@ export function getRobotInfo(data: ParsedEventData, robotService?: any): RobotIn
|
||||
|
||||
// 回退到模拟数据
|
||||
console.log('使用模拟机器人数据');
|
||||
return {
|
||||
id: robotId,
|
||||
name: data.name || `机器人-${robotId}`,
|
||||
status: 'online',
|
||||
batteryLevel: 85,
|
||||
currentTask: '空闲',
|
||||
position: { x: 0, y: 0 },
|
||||
};
|
||||
return generateMockRobotData(robotId, data.name);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,7 +110,7 @@ export function getRobotMenuConfig(data: ParsedEventData, robotService?: any): R
|
||||
* @returns 操作结果
|
||||
*/
|
||||
export async function executeRobotAction(
|
||||
action: string,
|
||||
action: RobotAction,
|
||||
robotInfo: RobotInfo,
|
||||
robotService?: any
|
||||
): Promise<{ success: boolean; message: string }> {
|
||||
@ -163,3 +175,83 @@ export function getRobotStatusColor(status: string): string {
|
||||
|
||||
return colorMap[status] || '#d9d9d9';
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成模拟机器人数据
|
||||
* @param robotId 机器人ID
|
||||
* @param robotName 机器人名称
|
||||
* @returns 模拟的机器人信息
|
||||
*/
|
||||
export function generateMockRobotData(robotId: string, robotName?: string): RobotInfo {
|
||||
const statuses: Array<'online' | 'offline' | 'busy' | 'idle' | 'error'> = ['online', 'busy', 'idle', 'offline'];
|
||||
const tasks = ['空闲', '运输中', '充电中', '维护中', '等待指令'];
|
||||
|
||||
const randomStatus = statuses[Math.floor(Math.random() * statuses.length)];
|
||||
const randomTask = tasks[Math.floor(Math.random() * tasks.length)];
|
||||
const batteryLevel = Math.floor(Math.random() * 100) + 1;
|
||||
|
||||
return {
|
||||
id: robotId,
|
||||
name: robotName || `机器人-${robotId}`,
|
||||
status: randomStatus,
|
||||
batteryLevel,
|
||||
currentTask: randomTask,
|
||||
position: {
|
||||
x: Math.floor(Math.random() * 1000),
|
||||
y: Math.floor(Math.random() * 1000)
|
||||
},
|
||||
canAcceptOrders: Math.random() > 0.3, // 70%概率可接单
|
||||
isControlled: Math.random() > 0.7, // 30%概率被控制
|
||||
isPaused: Math.random() > 0.8, // 20%概率暂停
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取机器人操作显示文本
|
||||
* @param action 操作类型
|
||||
* @returns 显示文本
|
||||
*/
|
||||
export function getRobotActionText(action: RobotAction): string {
|
||||
const actionMap: Record<RobotAction, string> = {
|
||||
'seize_control': '抢占控制权',
|
||||
'enable_orders': '可接单',
|
||||
'disable_orders': '不可接单',
|
||||
'pause': '暂停',
|
||||
'resume': '继续',
|
||||
'go_charge': '前往充电',
|
||||
'go_dock': '前往停靠',
|
||||
'navigate': '路径导航',
|
||||
'start': '启动',
|
||||
'stop': '停止',
|
||||
'reset': '重置',
|
||||
'diagnose': '诊断',
|
||||
'update': '更新',
|
||||
};
|
||||
|
||||
return actionMap[action] || action;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取机器人操作图标
|
||||
* @param action 操作类型
|
||||
* @returns 图标文本
|
||||
*/
|
||||
export function getRobotActionIcon(action: RobotAction): string {
|
||||
const iconMap: Record<RobotAction, string> = {
|
||||
'seize_control': '🎮',
|
||||
'enable_orders': '✅',
|
||||
'disable_orders': '❌',
|
||||
'pause': '⏸️',
|
||||
'resume': '▶️',
|
||||
'go_charge': '🔋',
|
||||
'go_dock': '🏠',
|
||||
'navigate': '🧭',
|
||||
'start': '🚀',
|
||||
'stop': '⏹️',
|
||||
'reset': '🔄',
|
||||
'diagnose': '🔧',
|
||||
'update': '📱',
|
||||
};
|
||||
|
||||
return iconMap[action] || '⚙️';
|
||||
}
|
||||
|
@ -1125,6 +1125,9 @@ export class EditorService extends Meta2d {
|
||||
await this.addPen(pen, false, true, true);
|
||||
}),
|
||||
);
|
||||
|
||||
// 机器人初始化完成后,确保层级正确(机器人应在最顶层)
|
||||
this.#ensureCorrectLayerOrder();
|
||||
}
|
||||
|
||||
public refreshRobot(id: RobotInfo['id'], info: Partial<RobotRealtimeInfo>): void {
|
||||
@ -1148,6 +1151,9 @@ export class EditorService extends Meta2d {
|
||||
{ render: true, history: false, doEvent: false },
|
||||
);
|
||||
}
|
||||
|
||||
// 机器人位置更新后,确保层级正确(机器人应在最顶层)
|
||||
this.#ensureCorrectLayerOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1175,7 +1181,7 @@ export class EditorService extends Meta2d {
|
||||
#mapRobotImage(
|
||||
type: RobotType,
|
||||
active?: boolean,
|
||||
): Required<Pick<MapPen, 'image' | 'iconWidth' | 'iconHeight' | 'iconTop'>> {
|
||||
): Required<Pick<MapPen, 'image' | 'iconWidth' | 'iconHeight' | 'iconTop' | 'canvasLayer'>> {
|
||||
const theme = this.data().theme;
|
||||
const image =
|
||||
import.meta.env.BASE_URL + (active ? `/robot/${type}-active-${theme}.png` : `/robot/${type}-${theme}.png`);
|
||||
@ -1189,7 +1195,7 @@ export class EditorService extends Meta2d {
|
||||
// 使用优化的像素对齐算法,确保小车和光圈精确重合
|
||||
const iconTop = this.#calculatePixelAlignedOffset(-16);
|
||||
|
||||
return { image, iconWidth, iconHeight, iconTop };
|
||||
return { image, iconWidth, iconHeight, iconTop, canvasLayer: CanvasLayer.CanvasImage };
|
||||
}
|
||||
//#endregion
|
||||
|
||||
|
@ -49,10 +49,14 @@ export class LayerManagerService {
|
||||
this.editor.top(storageLocations);
|
||||
}
|
||||
|
||||
// 将点位和机器人都移到最上层(在路线之上)
|
||||
const topElements = [...points, ...robots];
|
||||
if (topElements.length > 0) {
|
||||
this.editor.top(topElements);
|
||||
// 将点位移到上层
|
||||
if (points.length > 0) {
|
||||
this.editor.top(points);
|
||||
}
|
||||
|
||||
// 将机器人移到最上层(最高优先级)
|
||||
if (robots.length > 0) {
|
||||
this.editor.top(robots);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +68,7 @@ export class LayerManagerService {
|
||||
public movePointsToTop(points: MapPen[]): void {
|
||||
if (points.length > 0) {
|
||||
this.editor.top(points);
|
||||
// 确保机器人仍然与点位在同一层级
|
||||
// 确保机器人仍然在最高层级
|
||||
this.ensureRobotsAtTop();
|
||||
}
|
||||
}
|
||||
@ -95,7 +99,7 @@ export class LayerManagerService {
|
||||
|
||||
/**
|
||||
* 确保机器人在最上层
|
||||
* 与点位保持同一层级,避免被其他元素覆盖
|
||||
* 机器人具有最高交互优先级,始终在最顶层
|
||||
*/
|
||||
public ensureRobotsAtTop(): void {
|
||||
const robots = this.editor.find('robot');
|
||||
|
Loading…
x
Reference in New Issue
Block a user