feat: 添加右键菜单功能,优化机器人列表交互,增强用户体验

This commit is contained in:
xudan 2025-09-11 15:07:44 +08:00
parent fe1ef44e9d
commit c32dd105ef
2 changed files with 61 additions and 31 deletions

View File

@ -1,15 +1,15 @@
<script setup lang="ts">
import { type RobotGroup, type RobotInfo, seizeRobotByIds } from '@api/robot';
import { type RobotGroup, type RobotInfo } from '@api/robot';
import type { RobotAddModalRef } from '@common/modal/robot-add-modal.vue';
import type { RobotGroupRenameModalRef } from '@common/modal/robot-group-rename-modal.vue';
import type { RobotRegisterModalRef } from '@common/modal/robot-register-modal.vue';
import type { EditorService } from '@core/editor.service';
import { Modal } from 'ant-design-vue';
import { watch } from 'vue';
import { reactive } from 'vue';
import { computed, inject, type InjectionKey, ref, type ShallowRef, shallowRef } from 'vue';
import { computed, inject, type InjectionKey, reactive, ref, type ShallowRef, shallowRef, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { createContextMenuManager, handleContextMenu } from '../services/context-menu';
import ContextMenu from './context-menu/context-menu.vue';
type Props = {
token: InjectionKey<ShallowRef<EditorService>>;
@ -27,15 +27,25 @@ type Events = {
const emit = defineEmits<Events>();
const { t } = useI18n();
const router = useRouter();
// const router = useRouter(); // 使
//#region
const seizeRobots = async () => {
const res = await seizeRobotByIds([...selected.keys()]);
editor.value.updateRobots(res, { canControl: true });
//#region
const contextMenuManager = createContextMenuManager();
const contextMenuState = ref(contextMenuManager.getState());
//
contextMenuManager.subscribe((state) => {
contextMenuState.value = state;
});
//
const handleContextMenuClose = () => {
contextMenuManager.close();
};
//#endregion
const keyword = ref<string>('');
//#region
@ -75,6 +85,22 @@ const selectRobot = (id: RobotInfo['id'], checked: boolean) => {
selected.delete(id);
}
};
//
const handleRobotRightClick = (event: MouseEvent, robot: RobotInfo) => {
//
if (event.target && event.target instanceof HTMLElement) {
event.target.setAttribute('data-robot-id', robot.id);
event.target.setAttribute('data-robot-type', 'robot');
}
// - handleContextMenu preventDefault stopPropagation
handleContextMenu(event, contextMenuManager, {
robotService: {
getRobotById: (id: string) => editor.value.getRobotById(id)
}
});
};
//#endregion
//#region
@ -92,16 +118,6 @@ const toDeleteGroup = (id: RobotGroup['id']) =>
onOk: () => editor.value.deleteRobotGroup(id),
});
const toEditGroup = (id: RobotGroup['id']) =>
Modal.confirm({
class: 'confirm',
title: t('您确定要编辑该机器人组吗?'),
content: t('请确保当前场景已经保存,否则将导致当前场景数据丢失。'),
centered: true,
cancelText: t('取消'),
okText: t('编辑'),
onOk: () => router.push({ name: '组编辑', params: { sid: props.sid, id } }),
});
//#endregion
//#region
@ -137,6 +153,16 @@ const toRemoveRobots = () =>
<RobotAddModal ref="refAddRobot" :token="token" />
<RobotRegisterModal ref="refRegisterRobot" :token="token" />
<RobotGroupRenameModal ref="refRenameGroup" :token="token" />
<!-- 右键菜单 -->
<ContextMenu
:visible="contextMenuState.visible"
:x="contextMenuState.x"
:y="contextMenuState.y"
:menu-type="contextMenuState.menuType"
:robot-info="contextMenuState.robotInfo"
@close="handleContextMenuClose"
/>
<a-flex class="full" vertical>
<a-input class="search mb-16" :placeholder="$t('请输入搜索关键字')" v-model:value="keyword">
@ -148,16 +174,6 @@ const toRemoveRobots = () =>
<a-flex v-if="editable" class="mb-8" style="height: 32px" justify="space-between" align="center">
<a-checkbox :checked="isAllSelected" @change="selectAll($event.target.checked)">{{ $t('全选') }}</a-checkbox>
<a-space align="center">
<a-button
v-if="false"
class="icon-btn panel-btn"
size="small"
:title="$t('抢占控制权')"
@click="seizeRobots"
:disabled="!selected.size"
>
<i class="mask control" />
</a-button>
<a-button
class="icon-btn panel-btn"
size="small"
@ -241,6 +257,7 @@ const toRemoveRobots = () =>
:class="{ 'ph-16': !editable, 'pl-12': editable, 'pr-8': editable, selected: item.id === current }"
style="height: 36px"
@click="emit('change', item.id)"
@contextmenu="handleRobotRightClick($event, item)"
>
<template v-if="editable" #actions>
<a-button
@ -283,4 +300,14 @@ const toRemoveRobots = () =>
visibility: visible;
}
}
//
.ant-list-item {
cursor: pointer;
transition: background-color 0.2s ease;
&:hover {
background-color: #f5f5f5;
}
}
</style>

View File

@ -165,7 +165,10 @@ export function parseEventData(event: MouseEvent | PointerEvent): ParsedEventDat
}
// 回退到DOM元素检查
if (target?.closest('.robot-item')) {
// 检查机器人类型 - 支持多种选择器
if (target?.closest('.robot-item') ||
target?.closest('.ant-list-item') && target.dataset.robotType === 'robot' ||
target?.classList.contains('ant-list-item') && target.dataset.robotType === 'robot') {
return {
type: 'robot',
id: target.dataset.robotId || target.id,