feat: 新增自动生成库位功能,包含对话框组件和编辑器服务集成,优化库位创建逻辑
This commit is contained in:
parent
616992e855
commit
87ef9b7212
159
src/components/modal/auto-create-storage-modal.vue
Normal file
159
src/components/modal/auto-create-storage-modal.vue
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
v-model:open="modalVisible"
|
||||||
|
title="自动生成库位"
|
||||||
|
width="500px"
|
||||||
|
@ok="handleConfirm"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<div class="auto-create-storage-content">
|
||||||
|
<a-alert
|
||||||
|
message="检测到库区中包含动作点"
|
||||||
|
:description="`库区 ${areaName} 包含 ${actionPoints.length} 个动作点,是否自动为这些动作点生成库位?`"
|
||||||
|
type="info"
|
||||||
|
show-icon
|
||||||
|
style="margin-bottom: 16px"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="storage-preview">
|
||||||
|
<h4>预览生成的库位:</h4>
|
||||||
|
<div class="preview-list">
|
||||||
|
<div
|
||||||
|
v-for="point in actionPoints"
|
||||||
|
:key="point.id"
|
||||||
|
class="preview-item"
|
||||||
|
>
|
||||||
|
<div class="point-info">
|
||||||
|
<span class="point-name">{{ point.label || point.id }}</span>
|
||||||
|
<span class="point-type">动作点</span>
|
||||||
|
</div>
|
||||||
|
<div class="storage-locations">
|
||||||
|
<a-tag
|
||||||
|
v-for="locationName in getGeneratedLocationNames(point)"
|
||||||
|
:key="locationName"
|
||||||
|
color="blue"
|
||||||
|
class="location-tag"
|
||||||
|
>
|
||||||
|
{{ locationName }}
|
||||||
|
</a-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-alert
|
||||||
|
message="库位命名规则"
|
||||||
|
description="库位名称格式:库区名_动作点名称_序号(如:A001_P001_1)"
|
||||||
|
type="warning"
|
||||||
|
show-icon
|
||||||
|
style="margin-top: 16px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
interface Props {
|
||||||
|
visible: boolean;
|
||||||
|
areaName: string;
|
||||||
|
actionPoints: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'update:visible', value: boolean): void;
|
||||||
|
(e: 'confirm', actionPoints: any[]): void;
|
||||||
|
(e: 'cancel'): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const modalVisible = computed({
|
||||||
|
get: () => props.visible,
|
||||||
|
set: (value) => emit('update:visible', value)
|
||||||
|
});
|
||||||
|
|
||||||
|
// 生成库位名称
|
||||||
|
const getGeneratedLocationNames = (point: any): string[] => {
|
||||||
|
const pointName = point.label || point.id || '';
|
||||||
|
const areaName = props.areaName;
|
||||||
|
|
||||||
|
// 为每个动作点生成一个库位,名称格式:库区名_动作点名称_1
|
||||||
|
return [`${areaName}_${pointName}_1`];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认生成库位
|
||||||
|
const handleConfirm = () => {
|
||||||
|
emit('confirm', props.actionPoints);
|
||||||
|
modalVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取消生成
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('cancel');
|
||||||
|
modalVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'AutoCreateStorageModal'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.auto-create-storage-content {
|
||||||
|
.storage-preview {
|
||||||
|
h4 {
|
||||||
|
margin: 0 0 12px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-list {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
.preview-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.point-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.point-type {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.storage-locations {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 4px;
|
||||||
|
|
||||||
|
.location-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,14 +1,17 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getSceneById, pushSceneById, saveSceneById } from '@api/scene';
|
|
||||||
import { EditorService } from '@core/editor.service';
|
|
||||||
import { useViewState } from '@core/useViewState';
|
|
||||||
import { decodeTextFile, downloadFile, selectFile, textToBlob } from '@core/utils';
|
|
||||||
import { message, Modal } from 'ant-design-vue';
|
import { message, Modal } from 'ant-design-vue';
|
||||||
import { computed, watch } from 'vue';
|
import { computed, watch } from 'vue';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { onMounted, provide, shallowRef } from 'vue';
|
import { onMounted, provide, shallowRef } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import BatchEditToolbar from '@common/batch-edit-toolbar.vue';
|
|
||||||
|
import type { MapPen } from '../apis/map';
|
||||||
|
import { getSceneById, pushSceneById, saveSceneById } from '../apis/scene';
|
||||||
|
import BatchEditToolbar from '../components/batch-edit-toolbar.vue';
|
||||||
|
import AutoCreateStorageModal from '../components/modal/auto-create-storage-modal.vue';
|
||||||
|
import { EditorService } from '../services/editor.service';
|
||||||
|
import { useViewState } from '../services/useViewState';
|
||||||
|
import { decodeTextFile, downloadFile, selectFile, textToBlob } from '../services/utils';
|
||||||
|
|
||||||
const EDITOR_KEY = Symbol('editor-key');
|
const EDITOR_KEY = Symbol('editor-key');
|
||||||
|
|
||||||
@ -71,8 +74,25 @@ watch(
|
|||||||
const container = shallowRef<HTMLDivElement>();
|
const container = shallowRef<HTMLDivElement>();
|
||||||
const editor = shallowRef<EditorService>();
|
const editor = shallowRef<EditorService>();
|
||||||
provide(EDITOR_KEY, editor);
|
provide(EDITOR_KEY, editor);
|
||||||
|
|
||||||
|
// 自动生成库位对话框相关状态
|
||||||
|
const autoCreateStorageVisible = ref(false);
|
||||||
|
const autoCreateStorageData = ref<{
|
||||||
|
areaName: string;
|
||||||
|
actionPoints: any[];
|
||||||
|
}>({
|
||||||
|
areaName: '',
|
||||||
|
actionPoints: []
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
editor.value = new EditorService(container.value!);
|
editor.value = new EditorService(container.value!);
|
||||||
|
|
||||||
|
// 监听自动生成库位对话框事件
|
||||||
|
editor.value?.on('autoCreateStorageDialog', (data: any) => {
|
||||||
|
autoCreateStorageData.value = data;
|
||||||
|
autoCreateStorageVisible.value = true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const editable = ref<boolean>(false);
|
const editable = ref<boolean>(false);
|
||||||
@ -162,6 +182,19 @@ const handleAutoSaveAndRestoreViewState = async () => {
|
|||||||
const backToCards = () => {
|
const backToCards = () => {
|
||||||
window.parent?.postMessage({ type: 'scene_return_to_cards' }, '*');
|
window.parent?.postMessage({ type: 'scene_return_to_cards' }, '*');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 处理自动生成库位确认
|
||||||
|
const handleAutoCreateStorageConfirm = (actionPoints: any[]) => {
|
||||||
|
if (!editor.value) return;
|
||||||
|
|
||||||
|
editor.value.autoCreateStorageLocations(autoCreateStorageData.value.areaName, actionPoints);
|
||||||
|
message.success(`已为 ${actionPoints.length} 个动作点自动生成库位`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理自动生成库位取消
|
||||||
|
const handleAutoCreateStorageCancel = () => {
|
||||||
|
autoCreateStorageVisible.value = false;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -222,6 +255,15 @@ const backToCards = () => {
|
|||||||
<!-- 批量编辑工具栏 - 只在编辑模式下显示 -->
|
<!-- 批量编辑工具栏 - 只在编辑模式下显示 -->
|
||||||
<BatchEditToolbar v-if="editable && editor" :token="EDITOR_KEY" />
|
<BatchEditToolbar v-if="editable && editor" :token="EDITOR_KEY" />
|
||||||
|
|
||||||
|
<!-- 自动生成库位对话框 -->
|
||||||
|
<AutoCreateStorageModal
|
||||||
|
v-model:visible="autoCreateStorageVisible"
|
||||||
|
:area-name="autoCreateStorageData.areaName"
|
||||||
|
:action-points="autoCreateStorageData.actionPoints"
|
||||||
|
@confirm="handleAutoCreateStorageConfirm"
|
||||||
|
@cancel="handleAutoCreateStorageCancel"
|
||||||
|
/>
|
||||||
|
|
||||||
<template v-if="current?.id">
|
<template v-if="current?.id">
|
||||||
<a-float-button style="top: 80px; right: 16px" shape="square" @click="show = !show">
|
<a-float-button style="top: 80px; right: 16px" shape="square" @click="show = !show">
|
||||||
<template #icon><i class="icon detail" /></template>
|
<template #icon><i class="icon detail" /></template>
|
||||||
|
|||||||
@ -38,6 +38,7 @@ import {
|
|||||||
} from './draw/storage-location-drawer';
|
} from './draw/storage-location-drawer';
|
||||||
import { LayerManagerService } from './layer-manager.service';
|
import { LayerManagerService } from './layer-manager.service';
|
||||||
import { createStorageLocationUpdater,StorageLocationService } from './storage-location.service';
|
import { createStorageLocationUpdater,StorageLocationService } from './storage-location.service';
|
||||||
|
import { AutoStorageGenerator } from './utils/auto-storage-generator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 场景编辑器服务类
|
* 场景编辑器服务类
|
||||||
@ -59,6 +60,9 @@ export class EditorService extends Meta2d {
|
|||||||
/** 区域操作服务实例 */
|
/** 区域操作服务实例 */
|
||||||
private readonly areaOperationService!: AreaOperationService;
|
private readonly areaOperationService!: AreaOperationService;
|
||||||
|
|
||||||
|
/** 自动生成库位工具实例 */
|
||||||
|
private readonly autoStorageGenerator!: AutoStorageGenerator;
|
||||||
|
|
||||||
//#region 场景文件管理
|
//#region 场景文件管理
|
||||||
/**
|
/**
|
||||||
* 加载场景文件到编辑器
|
* 加载场景文件到编辑器
|
||||||
@ -947,9 +951,56 @@ export class EditorService extends Meta2d {
|
|||||||
/**
|
/**
|
||||||
* 为所有动作点创建库位pen对象
|
* 为所有动作点创建库位pen对象
|
||||||
* 用于初始化或刷新所有动作点的库位显示
|
* 用于初始化或刷新所有动作点的库位显示
|
||||||
|
* 优化性能:使用批量操作减少DOM操作次数
|
||||||
*/
|
*/
|
||||||
public createAllStorageLocationPens(): void {
|
public createAllStorageLocationPens(): void {
|
||||||
this.storageLocationService?.createAll();
|
if (!this.storageLocationService) return;
|
||||||
|
|
||||||
|
// 使用 requestIdleCallback 在浏览器空闲时执行,避免阻塞UI
|
||||||
|
if (typeof requestIdleCallback !== 'undefined') {
|
||||||
|
requestIdleCallback(() => {
|
||||||
|
this.storageLocationService?.createAll();
|
||||||
|
}, { timeout: 200 });
|
||||||
|
} else {
|
||||||
|
// 降级到 requestAnimationFrame
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.storageLocationService?.createAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动为动作点生成库位
|
||||||
|
* @param areaName 库区名称
|
||||||
|
* @param actionPoints 动作点列表
|
||||||
|
*/
|
||||||
|
public autoCreateStorageLocations(areaName: string, actionPoints: MapPen[]): void {
|
||||||
|
this.autoStorageGenerator.autoCreateStorageLocations(areaName, actionPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为指定动作点生成库位
|
||||||
|
* @param pointId 动作点ID
|
||||||
|
* @param areaName 库区名称
|
||||||
|
* @returns 生成的库位名称,如果失败返回null
|
||||||
|
*/
|
||||||
|
public generateStorageForPoint(pointId: string, areaName: string): string | null {
|
||||||
|
return this.autoStorageGenerator.generateStorageForPoint(pointId, areaName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量生成库位
|
||||||
|
* @param pointIds 动作点ID列表
|
||||||
|
* @param areaName 库区名称
|
||||||
|
* @returns 生成结果统计
|
||||||
|
*/
|
||||||
|
public batchGenerateStorageForPoints(pointIds: string[], areaName: string): {
|
||||||
|
success: number;
|
||||||
|
skipped: number;
|
||||||
|
failed: number;
|
||||||
|
generatedNames: string[];
|
||||||
|
} {
|
||||||
|
return this.autoStorageGenerator.batchGenerateStorageForPoints(pointIds, areaName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1197,14 +1248,14 @@ export class EditorService extends Meta2d {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public updatePoint(id: string, info: Partial<MapPointInfo>): void {
|
public updatePoint(id: string, info: Partial<MapPointInfo>, autoCreateStorage = true): void {
|
||||||
const { point } = this.getPenById(id) ?? {};
|
const { point } = this.getPenById(id) ?? {};
|
||||||
if (!point?.type) return;
|
if (!point?.type) return;
|
||||||
const o = { ...point, ...info };
|
const o = { ...point, ...info };
|
||||||
this.setValue({ id, point: o }, { render: true, history: true, doEvent: true });
|
this.setValue({ id, point: o }, { render: true, history: true, doEvent: true });
|
||||||
|
|
||||||
// 如果是动作点且库位信息发生变化,重新创建库位pen对象
|
// 如果是动作点且库位信息发生变化,重新创建库位pen对象
|
||||||
if (point.type === MapPointType.动作点 && info.associatedStorageLocations) {
|
if (point.type === MapPointType.动作点 && info.associatedStorageLocations && autoCreateStorage) {
|
||||||
this.createStorageLocationPens(id, info.associatedStorageLocations);
|
this.createStorageLocationPens(id, info.associatedStorageLocations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1399,6 +1450,11 @@ export class EditorService extends Meta2d {
|
|||||||
};
|
};
|
||||||
const area = await this.addPen(pen, true, true, true);
|
const area = await this.addPen(pen, true, true, true);
|
||||||
this.bottom(area);
|
this.bottom(area);
|
||||||
|
|
||||||
|
// 如果是库区且包含动作点,触发自动生成库位的确认对话框
|
||||||
|
if (type === MapAreaType.库区 && points.length > 0) {
|
||||||
|
this.autoStorageGenerator.triggerAutoCreateStorageDialog(pen, points);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateArea(id: string, info: Partial<MapAreaInfo>): void {
|
public updateArea(id: string, info: Partial<MapAreaInfo>): void {
|
||||||
@ -1425,6 +1481,9 @@ export class EditorService extends Meta2d {
|
|||||||
// 初始化库位服务
|
// 初始化库位服务
|
||||||
this.storageLocationService = new StorageLocationService(this, '');
|
this.storageLocationService = new StorageLocationService(this, '');
|
||||||
|
|
||||||
|
// 初始化自动生成库位工具
|
||||||
|
this.autoStorageGenerator = new AutoStorageGenerator(this);
|
||||||
|
|
||||||
// 设置颜色配置服务的编辑器实例
|
// 设置颜色配置服务的编辑器实例
|
||||||
colorConfig.setEditorService(this);
|
colorConfig.setEditorService(this);
|
||||||
|
|
||||||
|
|||||||
@ -518,16 +518,10 @@ export class StorageLocationService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否已存在库位pen对象
|
// 先删除已存在的库位pen对象,避免重复
|
||||||
const existingPens = this.getStorageLocationPens(pointId);
|
this.delete(pointId);
|
||||||
|
|
||||||
// 如果已存在pen对象,只更新状态,不重新创建
|
// 创建新的库位pen对象
|
||||||
if (existingPens.length > 0) {
|
|
||||||
this.update(pointId, storageLocations);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 只有在不存在pen对象时才创建新的
|
|
||||||
const pointRect = this.editor.getPointRect(pointPen) ?? { x: 0, y: 0, width: 0, height: 0 };
|
const pointRect = this.editor.getPointRect(pointPen) ?? { x: 0, y: 0, width: 0, height: 0 };
|
||||||
const pens = createStorageLocationPens(pointId, storageLocations, pointRect, storageStateMap);
|
const pens = createStorageLocationPens(pointId, storageLocations, pointRect, storageStateMap);
|
||||||
|
|
||||||
@ -605,14 +599,24 @@ export class StorageLocationService {
|
|||||||
if (!this.editor) return;
|
if (!this.editor) return;
|
||||||
|
|
||||||
const { penTypes, tags } = this.config;
|
const { penTypes, tags } = this.config;
|
||||||
const storagePens = this.editor.find(
|
|
||||||
`${penTypes.storageLocation},${penTypes.storageMore},${penTypes.storageBackground}`
|
// 分别查找每种类型的库位pen对象
|
||||||
).filter(
|
const storageLocationPens = this.editor.find(penTypes.storageLocation).filter(
|
||||||
(pen) => pen.tags?.includes(`${tags.pointPrefix}${pointId}`)
|
(pen) => pen.tags?.includes(`${tags.pointPrefix}${pointId}`)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (storagePens.length > 0) {
|
const storageMorePens = this.editor.find(penTypes.storageMore).filter(
|
||||||
this.editor.delete(storagePens, true, true);
|
(pen) => pen.tags?.includes(`${tags.pointPrefix}${pointId}`)
|
||||||
|
);
|
||||||
|
|
||||||
|
const storageBackgroundPens = this.editor.find(penTypes.storageBackground).filter(
|
||||||
|
(pen) => pen.tags?.includes(`${tags.pointPrefix}${pointId}`)
|
||||||
|
);
|
||||||
|
|
||||||
|
const allStoragePens = [...storageLocationPens, ...storageMorePens, ...storageBackgroundPens];
|
||||||
|
|
||||||
|
if (allStoragePens.length > 0) {
|
||||||
|
this.editor.delete(allStoragePens, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
184
src/services/utils/auto-storage-generator.ts
Normal file
184
src/services/utils/auto-storage-generator.ts
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
import type { MapPen } from '../../apis/map';
|
||||||
|
import { MapPointType } from '../../apis/map';
|
||||||
|
import type { EditorService } from '../editor.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动生成库位工具类
|
||||||
|
* 负责处理库区创建时的库位自动生成逻辑
|
||||||
|
*/
|
||||||
|
export class AutoStorageGenerator {
|
||||||
|
private editor: EditorService;
|
||||||
|
|
||||||
|
constructor(editor: EditorService) {
|
||||||
|
this.editor = editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发自动生成库位的确认对话框
|
||||||
|
* @param area 库区对象
|
||||||
|
* @param pointIds 动作点ID列表
|
||||||
|
*/
|
||||||
|
public triggerAutoCreateStorageDialog(area: MapPen, pointIds: string[]): void {
|
||||||
|
const actionPoints = pointIds
|
||||||
|
.map(id => this.editor.getPenById(id))
|
||||||
|
.filter((pen): pen is MapPen => !!pen && pen.point?.type === MapPointType.动作点);
|
||||||
|
|
||||||
|
if (actionPoints.length === 0) return;
|
||||||
|
|
||||||
|
// 触发自定义事件,让外部组件处理对话框显示
|
||||||
|
this.editor.emit('autoCreateStorageDialog', {
|
||||||
|
areaName: area.label || area.id || '',
|
||||||
|
actionPoints
|
||||||
|
} as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动为动作点生成库位
|
||||||
|
* @param areaName 库区名称
|
||||||
|
* @param actionPoints 动作点列表
|
||||||
|
*/
|
||||||
|
public autoCreateStorageLocations(areaName: string, actionPoints: MapPen[]): void {
|
||||||
|
actionPoints.forEach(point => {
|
||||||
|
if (point.point?.type !== MapPointType.动作点) return;
|
||||||
|
|
||||||
|
const pointName = point.label || point.id || '';
|
||||||
|
const locationName = this.generateStorageLocationName(areaName, pointName);
|
||||||
|
|
||||||
|
// 获取现有的库位列表,避免覆盖
|
||||||
|
const existingLocations = point.point.associatedStorageLocations || [];
|
||||||
|
|
||||||
|
// 检查是否已存在相同的库位名称
|
||||||
|
if (existingLocations.includes(locationName)) {
|
||||||
|
return; // 如果已存在,跳过
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新库位到现有列表
|
||||||
|
const newLocations = [...existingLocations, locationName];
|
||||||
|
|
||||||
|
// 更新动作点的库位信息(禁用自动创建库位pen对象,避免重复)
|
||||||
|
this.editor.updatePoint(point.id!, {
|
||||||
|
associatedStorageLocations: newLocations
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// 重新创建库位pen对象(create方法内部会先删除再创建)
|
||||||
|
this.editor.createStorageLocationPens(point.id!, newLocations);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成库位名称
|
||||||
|
* @param areaName 库区名称
|
||||||
|
* @param pointName 动作点名称
|
||||||
|
* @returns 生成的库位名称
|
||||||
|
*/
|
||||||
|
private generateStorageLocationName(areaName: string, pointName: string): string {
|
||||||
|
const baseName = `${areaName}_${pointName}_1`;
|
||||||
|
|
||||||
|
// 检查是否已存在同名库位
|
||||||
|
if (!this.checkStorageLocationExists(baseName)) {
|
||||||
|
return baseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果存在,则递增序号
|
||||||
|
let counter = 2;
|
||||||
|
let newName = `${areaName}_${pointName}_${counter}`;
|
||||||
|
|
||||||
|
while (this.checkStorageLocationExists(newName)) {
|
||||||
|
counter++;
|
||||||
|
newName = `${areaName}_${pointName}_${counter}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查库位名称是否已存在
|
||||||
|
* @param locationName 库位名称
|
||||||
|
* @returns 如果存在则返回true
|
||||||
|
*/
|
||||||
|
private checkStorageLocationExists(locationName: string): boolean {
|
||||||
|
// 检查所有动作点的库位信息
|
||||||
|
const allPoints = this.editor.find('point').filter(
|
||||||
|
pen => pen.point?.type === MapPointType.动作点
|
||||||
|
);
|
||||||
|
|
||||||
|
return allPoints.some(point =>
|
||||||
|
point.point?.associatedStorageLocations?.includes(locationName)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为指定动作点生成库位(单个)
|
||||||
|
* @param pointId 动作点ID
|
||||||
|
* @param areaName 库区名称
|
||||||
|
* @returns 生成的库位名称,如果失败返回null
|
||||||
|
*/
|
||||||
|
public generateStorageForPoint(pointId: string, areaName: string): string | null {
|
||||||
|
const point = this.editor.getPenById(pointId);
|
||||||
|
if (!point || point.point?.type !== MapPointType.动作点) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pointName = point.label || point.id || '';
|
||||||
|
const locationName = this.generateStorageLocationName(areaName, pointName);
|
||||||
|
|
||||||
|
// 获取现有的库位列表
|
||||||
|
const existingLocations = point.point.associatedStorageLocations || [];
|
||||||
|
|
||||||
|
// 检查是否已存在相同的库位名称
|
||||||
|
if (existingLocations.includes(locationName)) {
|
||||||
|
return null; // 如果已存在,返回null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加新库位到现有列表
|
||||||
|
const newLocations = [...existingLocations, locationName];
|
||||||
|
|
||||||
|
// 先删除原有的库位pen对象,避免重复
|
||||||
|
this.editor.deleteStorageLocation(pointId);
|
||||||
|
|
||||||
|
// 更新动作点的库位信息
|
||||||
|
this.editor.updatePoint(pointId, {
|
||||||
|
associatedStorageLocations: newLocations
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重新创建库位pen对象
|
||||||
|
this.editor.createStorageLocationPens(pointId, newLocations);
|
||||||
|
|
||||||
|
return locationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量生成库位(为多个动作点)
|
||||||
|
* @param pointIds 动作点ID列表
|
||||||
|
* @param areaName 库区名称
|
||||||
|
* @returns 生成结果统计
|
||||||
|
*/
|
||||||
|
public batchGenerateStorageForPoints(pointIds: string[], areaName: string): {
|
||||||
|
success: number;
|
||||||
|
skipped: number;
|
||||||
|
failed: number;
|
||||||
|
generatedNames: string[];
|
||||||
|
} {
|
||||||
|
let success = 0;
|
||||||
|
let skipped = 0;
|
||||||
|
let failed = 0;
|
||||||
|
const generatedNames: string[] = [];
|
||||||
|
|
||||||
|
pointIds.forEach(pointId => {
|
||||||
|
const result = this.generateStorageForPoint(pointId, areaName);
|
||||||
|
if (result) {
|
||||||
|
success++;
|
||||||
|
generatedNames.push(result);
|
||||||
|
} else {
|
||||||
|
const point = this.editor.getPenById(pointId);
|
||||||
|
if (point && point.point?.type === MapPointType.动作点) {
|
||||||
|
skipped++; // 已存在相同名称
|
||||||
|
} else {
|
||||||
|
failed++; // 不是动作点或不存在
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { success, skipped, failed, generatedNames };
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/services/utils/index.ts
Normal file
1
src/services/utils/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { AutoStorageGenerator } from './auto-storage-generator';
|
||||||
Loading…
x
Reference in New Issue
Block a user