fix(scene-editor): 优化场景加载逻辑,增加导入状态管理,改善用户体验

This commit is contained in:
xudan 2025-10-27 16:59:06 +08:00
parent f7cd51c679
commit 85f7b94313

View File

@ -60,6 +60,8 @@ const normalizeSceneJson = (raw: unknown): unknown => {
//#region //#region
const readScene = async () => { const readScene = async () => {
isImporting.value = true;
try {
const res = await getSceneById(props.id); const res = await getSceneById(props.id);
title.value = res?.label ?? ''; title.value = res?.label ?? '';
const sceneJson = normalizeSceneJson(res?.json); const sceneJson = normalizeSceneJson(res?.json);
@ -98,6 +100,9 @@ const readScene = async () => {
previousFloorIndex.value = 0; previousFloorIndex.value = 0;
editor.value?.load('{}', editable.value, undefined, false); editor.value?.load('{}', editable.value, undefined, false);
} }
} finally {
isImporting.value = false;
}
}; };
type SaveScenePayload = { type SaveScenePayload = {
@ -208,6 +213,8 @@ const isMultiFloor = computed(() => floorScenes.value.length > 1);
const requireImportTransform = ref(false); const requireImportTransform = ref(false);
// floorScenes // floorScenes
const floorImportFlags = ref<boolean[]>([]); const floorImportFlags = ref<boolean[]>([]);
//
const isImporting = ref(false);
onMounted(() => { onMounted(() => {
document.title = '场景编辑器'; document.title = '场景编辑器';
@ -345,6 +352,7 @@ const openImportModal = () => {
}; };
const handleImportConfirm = async () => { const handleImportConfirm = async () => {
isImporting.value = true;
try { try {
/* NORMAL_IMPORT_DISABLED /* NORMAL_IMPORT_DISABLED
if (importMode.value === 'normal') { if (importMode.value === 'normal') {
@ -417,7 +425,7 @@ const handleImportConfirm = async () => {
console.log('[MapConverter] OriginalProperties by floor:', OriginalProperties.value); console.log('[MapConverter] OriginalProperties by floor:', OriginalProperties.value);
console.log('[MapConverter] Request payload (object):', payload); console.log('[MapConverter] Request payload (object):', payload);
console.log('[MapConverter] Request payload (JSON):', JSON.stringify(payload, null, 2)); console.log('[MapConverter] Request payload (JSON):', JSON.stringify(payload, null, 2));
message.info('已在控制台打印请求参数'); // message.info('');
} catch { } catch {
// //
} }
@ -496,10 +504,13 @@ const handleImportConfirm = async () => {
} catch (error) { } catch (error) {
console.error('导入失败:', error); console.error('导入失败:', error);
message.error(`导入失败: ${(error as Error).message || '请检查文件格式或内容。'}`); message.error(`导入失败: ${(error as Error).message || '请检查文件格式或内容。'}`);
} finally {
isImporting.value = false;
} }
}; };
const processAndLoadSceneData = async (sceneData: any) => { const processAndLoadSceneData = async (sceneData: any) => {
isImporting.value = true;
try { try {
// //
if (Array.isArray(sceneData)) { if (Array.isArray(sceneData)) {
@ -552,12 +563,16 @@ const processAndLoadSceneData = async (sceneData: any) => {
message.error('导入失败文件不是有效的JSON格式或数据无法加载。'); message.error('导入失败文件不是有效的JSON格式或数据无法加载。');
// //
throw error; throw error;
} finally {
isImporting.value = false;
} }
}; };
const importSmapModalVisible = ref(false); const importSmapModalVisible = ref(false);
const handleImportSmapConfirm = async ({ smapFile, keepProperties }: { smapFile: File; keepProperties: boolean }) => { const handleImportSmapConfirm = async ({ smapFile, keepProperties }: { smapFile: File; keepProperties: boolean }) => {
isImporting.value = true;
try {
let sceneJson: string | null = null; let sceneJson: string | null = null;
if (keepProperties) { if (keepProperties) {
// Update mode // Update mode
@ -580,6 +595,12 @@ const handleImportSmapConfirm = async ({ smapFile, keepProperties }: { smapFile:
requireImportTransform.value = true; requireImportTransform.value = true;
editor.value?.load(sceneJson, editable.value, undefined, requireImportTransform.value); editor.value?.load(sceneJson, editable.value, undefined, requireImportTransform.value);
} }
} catch (error) {
console.error('导入 SMAP 文件失败:', error);
message.error('导入 SMAP 文件失败');
} finally {
isImporting.value = false;
}
}; };
const importBinTask = async () => { const importBinTask = async () => {
@ -748,7 +769,7 @@ const handleFloorChange = async (value: any) => {
</a-button> </a-button>
<a-button @click="toPush">{{ $t('推送') }}</a-button> <a-button @click="toPush">{{ $t('推送') }}</a-button>
<a-dropdown-button @click="openImportModal" :loading="isConverting"> <a-dropdown-button @click="openImportModal" :loading="isConverting || isImporting">
{{ $t('导入') }} {{ $t('导入') }}
<template #overlay> <template #overlay>
<a-menu> <a-menu>
@ -929,7 +950,7 @@ const handleFloorChange = async (value: any) => {
<span class="hint-text">* 多文件仅支持 smap请确保 floors 连续且类型与后缀一致</span> <span class="hint-text">* 多文件仅支持 smap请确保 floors 连续且类型与后缀一致</span>
<a-space> <a-space>
<a-button @click="importModalVisible = false">取消</a-button> <a-button @click="importModalVisible = false">取消</a-button>
<a-button type="primary" @click="handleImportConfirm">导入</a-button> <a-button type="primary" @click="handleImportConfirm" :loading="isImporting">导入</a-button>
</a-space> </a-space>
</div> </div>
</div> </div>
@ -1079,6 +1100,7 @@ const handleFloorChange = async (value: any) => {
padding: 16px; padding: 16px;
border-radius: 4px; border-radius: 4px;
margin-bottom: 16px; margin-bottom: 16px;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
@ -1087,5 +1109,8 @@ html[theme='dark'] {
.sider-toggle { .sider-toggle {
background-color: #5a5d5e; background-color: #5a5d5e;
} }
.floor-uploader-item {
border: 1px solid #141414;
}
} }
</style> </style>