feat: 增强点位和区域面板的搜索功能,支持通过关键字过滤点位和动态更新面板展开状态

This commit is contained in:
xudan 2025-08-07 15:10:06 +08:00
parent b35fe5e98b
commit 3c63594d1a

View File

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { MapAreaType, type MapPen, MapPointType, MapRoutePassType } from '@api/map'; import { MapAreaType, type MapPen, MapPointType, MapRoutePassType } from '@api/map';
import type { EditorService } from '@core/editor.service'; import type { EditorService } from '@core/editor.service';
import { computed, inject, type InjectionKey, ref, type ShallowRef } from 'vue'; import { computed, inject, type InjectionKey, ref, type ShallowRef, watch } from 'vue';
type Props = { type Props = {
token: InjectionKey<ShallowRef<EditorService>>; token: InjectionKey<ShallowRef<EditorService>>;
@ -12,10 +12,19 @@ const props = defineProps<Props>();
const editor = inject(props.token)!; const editor = inject(props.token)!;
const keyword = ref<string>(''); const keyword = ref<string>('');
const activeKeys = ref<string[]>([]);
//#region //#region
const points = computed<MapPen[]>(() => const points = computed<MapPen[]>(() =>
editor.value.points.value.filter(({ label }) => label?.includes(keyword.value)), editor.value.points.value.filter(({ label, point }) => {
if (!keyword.value) return true;
const labelMatch = label?.includes(keyword.value);
// associatedStorageLocations
const storageLocationMatch =
point?.type === MapPointType.动作点 &&
point.associatedStorageLocations?.some((location) => location.includes(keyword.value));
return labelMatch || storageLocationMatch;
}),
); );
//#endregion //#endregion
@ -29,10 +38,66 @@ const routes = computed<MapPen[]>(() =>
const areas = computed<MapPen[]>(() => editor.value.areas.value.filter(({ label }) => label?.includes(keyword.value))); const areas = computed<MapPen[]>(() => editor.value.areas.value.filter(({ label }) => label?.includes(keyword.value)));
//#endregion //#endregion
//#region
const updateActiveKeys = () => {
if (!keyword.value) return;
const keys: string[] = [];
//
const pointTypes = [
{ key: '普通点', type: MapPointType.普通点 },
{ key: '等待点', type: MapPointType.等待点 },
{ key: '避让点', type: MapPointType.避让点 },
{ key: '临时避让点', type: MapPointType.临时避让点 },
{ key: '库区点', type: MapPointType.库区点 },
{ key: '电梯点', type: MapPointType.电梯点 },
{ key: '自动门点', type: MapPointType.自动门点 },
{ key: '充电点', type: MapPointType.充电点 },
{ key: '停靠点', type: MapPointType.停靠点 },
{ key: '动作点', type: MapPointType.动作点 },
{ key: '禁行点', type: MapPointType.禁行点 },
];
pointTypes.forEach(({ key, type }) => {
const hasMatch = points.value.some(({ point }) => point?.type === type);
if (hasMatch) keys.push(key);
});
// 线
const routeTypes = [
{ key: '普通路线', pass: MapRoutePassType. },
{ key: '仅载货可通行路线', pass: MapRoutePassType.仅载货可通行 },
{ key: '仅空载可通行路线', pass: MapRoutePassType.仅空载可通行 },
{ key: '禁行路线', pass: MapRoutePassType.禁行 },
];
routeTypes.forEach(({ key, pass }) => {
const hasMatch = routes.value.some(({ route }) => route?.pass === pass);
if (hasMatch) keys.push(key);
});
//
const areaTypes = [
{ key: '互斥区', type: MapAreaType.互斥区 },
{ key: '非互斥区', type: MapAreaType.非互斥区 },
];
areaTypes.forEach(({ key, type }) => {
const hasMatch = areas.value.some(({ area }) => area?.type === type);
if (hasMatch) keys.push(key);
});
activeKeys.value = keys;
};
//#endregion
const select = (id: string) => { const select = (id: string) => {
editor.value.active(id); editor.value.active(id);
editor.value.gotoById(id); editor.value.gotoById(id);
}; };
watch(keyword, updateActiveKeys);
</script> </script>
<template> <template>
@ -43,7 +108,7 @@ const select = (id: string) => {
</template> </template>
</a-input> </a-input>
<a-collapse style="flex: auto; overflow-y: auto" expand-icon-position="end" ghost defaultActiveKey="defaultActive"> <a-collapse style="flex: auto; overflow-y: auto" expand-icon-position="end" ghost v-model:active-key="activeKeys">
<template #expandIcon="v"> <template #expandIcon="v">
<i class="icon dropdown" :class="{ active: v?.isActive }" /> <i class="icon dropdown" :class="{ active: v?.isActive }" />
</template> </template>
@ -64,7 +129,7 @@ const select = (id: string) => {
</a-collapse-panel> </a-collapse-panel>
<template v-else> <template v-else>
<!-- 点位类型面板 --> <!-- 点位类型面板 -->
<a-collapse-panel :header="$t('普通点')"> <a-collapse-panel :header="$t('普通点')" key="普通点">
<a-list <a-list
rowKey="id" rowKey="id"
:data-source=" :data-source="
@ -86,7 +151,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('等待点')"> <a-collapse-panel :header="$t('等待点')" key="等待点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.等待点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.等待点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -101,7 +166,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('避让点')"> <a-collapse-panel :header="$t('避让点')" key="避让点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.避让点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.避让点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -116,7 +181,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('临时避让点')"> <a-collapse-panel :header="$t('临时避让点')" key="临时避让点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.临时避让点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.临时避让点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -131,7 +196,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('库区点')"> <a-collapse-panel :header="$t('库区点')" key="库区点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.库区点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.库区点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -146,7 +211,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('电梯点')"> <a-collapse-panel :header="$t('电梯点')" key="电梯点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.电梯点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.电梯点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -161,7 +226,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('自动门点')"> <a-collapse-panel :header="$t('自动门点')" key="自动门点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.自动门点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.自动门点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -176,7 +241,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('充电点')"> <a-collapse-panel :header="$t('充电点')" key="充电点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.充电点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.充电点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -191,7 +256,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('停靠点')"> <a-collapse-panel :header="$t('停靠点')" key="停靠点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.停靠点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.停靠点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -206,7 +271,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('动作点')"> <a-collapse-panel :header="$t('动作点')" key="动作点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.动作点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.动作点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -215,13 +280,24 @@ const select = (id: string) => {
style="height: 36px" style="height: 36px"
@click="select(item.id)" @click="select(item.id)"
> >
<a-typography-text type="secondary">{{ item.label }}</a-typography-text> <a-typography-text type="secondary">
{{ item.label }}
<a-tag v-if="item.point?.associatedStorageLocations?.length" size="small" type="primary">
{{
keyword
? item.point.associatedStorageLocations
.filter((location: string) => location.includes(keyword))
.join(', ')
: item.point.associatedStorageLocations.join(', ')
}}
</a-tag>
</a-typography-text>
</a-list-item> </a-list-item>
</template> </template>
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('禁行点')"> <a-collapse-panel :header="$t('禁行点')" key="禁行点">
<a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.禁行点)"> <a-list rowKey="id" :data-source="points.filter(({ point }) => point?.type === MapPointType.禁行点)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -237,7 +313,7 @@ const select = (id: string) => {
</a-collapse-panel> </a-collapse-panel>
<!-- 路线类型面板 --> <!-- 路线类型面板 -->
<a-collapse-panel :header="$t('普通路线')"> <a-collapse-panel :header="$t('普通路线')" key="普通路线">
<a-list rowKey="id" :data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.)"> <a-list rowKey="id" :data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -252,7 +328,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('仅载货可通行路线')"> <a-collapse-panel :header="$t('仅载货可通行路线')" key="仅载货可通行路线">
<a-list <a-list
rowKey="id" rowKey="id"
:data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.仅载货可通行)" :data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.仅载货可通行)"
@ -270,7 +346,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('仅空载可通行路线')"> <a-collapse-panel :header="$t('仅空载可通行路线')" key="仅空载可通行路线">
<a-list <a-list
rowKey="id" rowKey="id"
:data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.仅空载可通行)" :data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.仅空载可通行)"
@ -288,7 +364,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('禁行路线')"> <a-collapse-panel :header="$t('禁行路线')" key="禁行路线">
<a-list rowKey="id" :data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.禁行)"> <a-list rowKey="id" :data-source="routes.filter(({ route }) => route?.pass === MapRoutePassType.禁行)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -304,7 +380,7 @@ const select = (id: string) => {
</a-collapse-panel> </a-collapse-panel>
<!-- 区域类型面板 --> <!-- 区域类型面板 -->
<a-collapse-panel :header="$t('互斥区')"> <a-collapse-panel :header="$t('互斥区')" key="互斥区">
<a-list rowKey="id" :data-source="areas.filter(({ area }) => area?.type === MapAreaType.互斥区)"> <a-list rowKey="id" :data-source="areas.filter(({ area }) => area?.type === MapAreaType.互斥区)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item
@ -319,7 +395,7 @@ const select = (id: string) => {
</a-list> </a-list>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel :header="$t('非互斥区')"> <a-collapse-panel :header="$t('非互斥区')" key="非互斥区">
<a-list rowKey="id" :data-source="areas.filter(({ area }) => area?.type === MapAreaType.非互斥区)"> <a-list rowKey="id" :data-source="areas.filter(({ area }) => area?.type === MapAreaType.非互斥区)">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item <a-list-item