287 lines
9.5 KiB
Vue
287 lines
9.5 KiB
Vue
<script setup lang="ts">
|
|
import { type RobotGroup, type RobotInfo, seizeRobotByIds } 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 { useI18n } from 'vue-i18n';
|
|
import { useRouter } from 'vue-router';
|
|
|
|
type Props = {
|
|
token: InjectionKey<ShallowRef<EditorService>>;
|
|
sid: string;
|
|
showGroupEdit?: boolean;
|
|
editable?: boolean;
|
|
current?: string;
|
|
};
|
|
const props = defineProps<Props>();
|
|
const editor = inject(props.token)!;
|
|
|
|
type Events = {
|
|
(e: 'change', id: string): void;
|
|
};
|
|
const emit = defineEmits<Events>();
|
|
|
|
const { t } = useI18n();
|
|
const router = useRouter();
|
|
|
|
//#region 接口
|
|
const seizeRobots = async () => {
|
|
const res = await seizeRobotByIds([...selected.keys()]);
|
|
editor.value.updateRobots(res, { canControl: true });
|
|
};
|
|
//#endregion
|
|
|
|
const keyword = ref<string>('');
|
|
|
|
//#region 机器人列表
|
|
const groups = computed<RobotGroup[]>(() => editor.value.robotGroups.value ?? []);
|
|
const robots = computed<RobotInfo[]>(() => editor.value.robots.filter(({ label }) => label.includes(keyword.value)));
|
|
const getGroupRobots = (ids: RobotGroup['robots']) =>
|
|
ids?.map((id) => editor.value.getRobotById(id)).filter((robot) => robot?.label.includes(keyword.value));
|
|
|
|
const selected = reactive<Set<RobotInfo['id']>>(new Set());
|
|
watch(
|
|
() => props.editable,
|
|
() => selected.clear(),
|
|
);
|
|
|
|
const isAllSelected = computed<boolean>(() => selected.size > 0 && robots.value.every(({ id }) => selected.has(id)));
|
|
const selectAll = (checked: boolean) => {
|
|
if (checked) {
|
|
robots.value.forEach(({ id }) => selected.add(id));
|
|
} else {
|
|
selected.clear();
|
|
}
|
|
};
|
|
|
|
const checkGroupSelected = (ids: RobotGroup['robots']) => !!ids?.length && ids.every((id) => selected.has(id));
|
|
const selectGroup = (ids: RobotGroup['robots'], checked: boolean) => {
|
|
if (checked) {
|
|
ids?.forEach((id) => selected.add(id));
|
|
} else {
|
|
ids?.forEach((id) => selected.delete(id));
|
|
}
|
|
};
|
|
|
|
const selectRobot = (id: RobotInfo['id'], checked: boolean) => {
|
|
if (checked) {
|
|
selected.add(id);
|
|
} else {
|
|
selected.delete(id);
|
|
}
|
|
};
|
|
//#endregion
|
|
|
|
//#region 机器人组操作
|
|
const refAddRobot = shallowRef<RobotAddModalRef>();
|
|
const refRegisterRobot = shallowRef<RobotRegisterModalRef>();
|
|
const refRenameGroup = shallowRef<RobotGroupRenameModalRef>();
|
|
|
|
const toDeleteGroup = (id: RobotGroup['id']) =>
|
|
Modal.confirm({
|
|
class: 'confirm',
|
|
title: t('您确定要删除该机器人组吗?'),
|
|
centered: true,
|
|
cancelText: t('返回'),
|
|
okText: t('删除'),
|
|
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 机器人操作
|
|
const toRemoveRobot = (id: RobotInfo['id']) =>
|
|
Modal.confirm({
|
|
class: 'confirm',
|
|
title: t('您确定要从场景中移除该机器人吗?'),
|
|
centered: true,
|
|
cancelText: t('返回'),
|
|
okText: t('移除'),
|
|
onOk: () => {
|
|
editor.value.removeRobots([id]);
|
|
selected.delete(id);
|
|
},
|
|
});
|
|
|
|
const toRemoveRobots = () =>
|
|
Modal.confirm({
|
|
class: 'confirm',
|
|
title: t('您确定要从场景中移除已选机器人吗?'),
|
|
centered: true,
|
|
cancelText: t('返回'),
|
|
okText: t('移除'),
|
|
onOk: () => {
|
|
editor.value.removeRobots([...selected.keys()]);
|
|
selected.clear();
|
|
},
|
|
});
|
|
//#endregion
|
|
</script>
|
|
|
|
<template>
|
|
<RobotAddModal ref="refAddRobot" :token="token" />
|
|
<RobotRegisterModal ref="refRegisterRobot" :token="token" />
|
|
<RobotGroupRenameModal ref="refRenameGroup" :token="token" />
|
|
|
|
<a-flex class="full" vertical>
|
|
<a-input class="search mb-16" :placeholder="$t('请输入搜索关键字')" v-model:value="keyword">
|
|
<template #suffix>
|
|
<i class="icon search size-16" />
|
|
</template>
|
|
</a-input>
|
|
|
|
<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"
|
|
:title="$t('移除机器人')"
|
|
@click="toRemoveRobots"
|
|
:disabled="!selected.size"
|
|
>
|
|
<i class="mask trash_fill" />
|
|
</a-button>
|
|
</a-space>
|
|
</a-flex>
|
|
|
|
<a-collapse style="flex: auto; overflow-y: auto" expand-icon-position="end" ghost defaultActiveKey="defaultActive">
|
|
<template #expandIcon="v">
|
|
<i class="icon dropdown" :class="{ active: v?.isActive }" />
|
|
</template>
|
|
|
|
<a-collapse-panel v-for="({ id, label, robots }, index) in groups" :key="index === 0 ? 'defaultActive' : id">
|
|
<template v-if="editable" #extra>
|
|
<a-dropdown placement="bottomRight">
|
|
<a-button class="icon-btn" size="small" @click.stop>
|
|
<i class="icon dot" />
|
|
</a-button>
|
|
<template #overlay>
|
|
<a-menu>
|
|
<a-menu-item>
|
|
<a-space align="center" :size="4" @click="refAddRobot?.open(id)">
|
|
<i class="icon plus size-20" />
|
|
<span>{{ $t('添加机器人') }}</span>
|
|
</a-space>
|
|
</a-menu-item>
|
|
<a-menu-item>
|
|
<a-space align="center" :size="4" @click="refRegisterRobot?.open(id)">
|
|
<i class="icon register size-20" />
|
|
<span>{{ $t('注册机器人') }}</span>
|
|
</a-space>
|
|
</a-menu-item>
|
|
<a-menu-item @click="refRenameGroup?.open(id, label)">
|
|
<a-space align="center" :size="4">
|
|
<i class="icon pen size-20" />
|
|
<span>{{ $t('修改组名称') }}</span>
|
|
</a-space>
|
|
</a-menu-item>
|
|
<a-menu-item @click="toDeleteGroup(id)">
|
|
<a-space align="center" :size="4">
|
|
<i class="icon trash size-20" />
|
|
<span>{{ $t('删除组') }}</span>
|
|
</a-space>
|
|
</a-menu-item>
|
|
</a-menu>
|
|
</template>
|
|
</a-dropdown>
|
|
</template>
|
|
|
|
<template #header>
|
|
<a-flex justify="space-between" align="center">
|
|
<a-space align="center" :size="8">
|
|
<a-checkbox
|
|
v-if="editable"
|
|
:checked="checkGroupSelected(robots)"
|
|
@change="selectGroup(robots, $event.target.checked)"
|
|
@click.stop
|
|
/>
|
|
<span>{{ label }}</span>
|
|
</a-space>
|
|
<!-- <a-button
|
|
v-if="showGroupEdit && !editable"
|
|
class="open-group-btn icon-btn"
|
|
size="small"
|
|
:title="$t('编辑组文件')"
|
|
@click.stop="toEditGroup(id)"
|
|
>
|
|
<i class="icon edit_group" />
|
|
</a-button> -->
|
|
</a-flex>
|
|
</template>
|
|
|
|
<a-list rowKey="id" :data-source="getGroupRobots(robots)">
|
|
<template #renderItem="{ item }">
|
|
<a-list-item
|
|
:class="{ 'ph-16': !editable, 'pl-12': editable, 'pr-8': editable, selected: item.id === current }"
|
|
style="height: 36px"
|
|
@click="emit('change', item.id)"
|
|
>
|
|
<template v-if="editable" #actions>
|
|
<a-button
|
|
class="icon-btn panel-btn"
|
|
size="small"
|
|
:title="$t('移除机器人')"
|
|
@click.stop="toRemoveRobot(item.id)"
|
|
>
|
|
<i class="icon trash_fill" />
|
|
</a-button>
|
|
</template>
|
|
<a-space align="center" :size="8">
|
|
<a-checkbox
|
|
v-if="editable"
|
|
:checked="selected.has(item.id)"
|
|
@change="selectRobot(item.id, $event.target.checked)"
|
|
@click.stop
|
|
/>
|
|
<a-typography-text type="secondary">{{ item.label }}</a-typography-text>
|
|
</a-space>
|
|
</a-list-item>
|
|
</template>
|
|
</a-list>
|
|
</a-collapse-panel>
|
|
</a-collapse>
|
|
|
|
<a-button class="mt-8" v-if="editable" type="dashed" size="large" block @click="editor.createRobotGroup()">
|
|
<i class="mask plus size-20 primary" />
|
|
<span>{{ $t('添加机器人组') }}</span>
|
|
</a-button>
|
|
</a-flex>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.open-group-btn {
|
|
margin-right: -8px;
|
|
visibility: hidden;
|
|
|
|
.ant-collapse-header:hover & {
|
|
visibility: visible;
|
|
}
|
|
}
|
|
</style>
|