修复编辑器不同步bug
This commit is contained in:
481
src/App.vue
481
src/App.vue
@@ -144,6 +144,7 @@
|
||||
theme="vs"
|
||||
:options="editorOptions"
|
||||
:disabled="!isParsed"
|
||||
@change="onJsonEditorChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -175,10 +176,11 @@
|
||||
<button
|
||||
class="btn btn-success flex-1"
|
||||
@click="updateDataFromJson"
|
||||
:disabled="!isParsed"
|
||||
:disabled="!isParsed || !hasJsonChanges"
|
||||
>
|
||||
<i class="fas fa-save mr-2"></i>
|
||||
更新数据
|
||||
<span v-if="isDataSyncing" class="loading loading-spinner"></span>
|
||||
{{ isDataSyncing ? '更新中...' : '更新数据' }}
|
||||
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -188,6 +190,15 @@
|
||||
<i class="fas fa-info-circle text-info mr-2"></i> {{ exportStatus }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JSON编辑状态(整合错误信息) -->
|
||||
<div v-if="jsonEditStatus" class="mt-4 rounded-xl p-4" :class="jsonValidationError ? 'bg-error bg-opacity-10' : 'bg-base-100'">
|
||||
<h3 class="font-bold text-lg mb-2" :class="jsonValidationError ? 'text-error' : ''">JSON编辑状态:</h3>
|
||||
<div class="text-sm" :class="jsonValidationError ? 'text-error' : ''">
|
||||
<i class="fas mr-2" :class="jsonValidationError ? 'fa-exclamation-triangle' : 'fa-info-circle text-info'"></i>
|
||||
{{ jsonValidationError || jsonEditStatus }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -236,6 +247,7 @@
|
||||
class="input input-bordered"
|
||||
v-model="blueprintData.name"
|
||||
placeholder="输入蓝图名称"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -249,18 +261,21 @@
|
||||
class="input input-bordered dimension-input"
|
||||
v-model.number="blueprintData.header.designerDimension.x"
|
||||
placeholder="X"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
class="input input-bordered dimension-input"
|
||||
v-model.number="blueprintData.header.designerDimension.y"
|
||||
placeholder="Y"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
class="input input-bordered dimension-input"
|
||||
v-model.number="blueprintData.header.designerDimension.z"
|
||||
placeholder="Z"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -294,6 +309,7 @@
|
||||
type="number"
|
||||
class="input input-bordered"
|
||||
v-model.number="blueprintData.config.iconID"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -306,6 +322,7 @@
|
||||
class="input input-bordered"
|
||||
v-model="blueprintData.config.referencedIconLibrary"
|
||||
placeholder="输入图标库路径"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -318,6 +335,7 @@
|
||||
class="input input-bordered"
|
||||
v-model="blueprintData.config.iconLibraryType"
|
||||
placeholder="输入图标库类型"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -329,6 +347,7 @@
|
||||
class="textarea textarea-bordered"
|
||||
v-model="blueprintData.config.description"
|
||||
placeholder="输入蓝图描述"
|
||||
@change="onBasicDataChange"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
@@ -346,6 +365,7 @@
|
||||
max="1"
|
||||
step="0.01"
|
||||
placeholder="R"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
@@ -355,6 +375,7 @@
|
||||
max="1"
|
||||
step="0.01"
|
||||
placeholder="G"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
@@ -364,6 +385,7 @@
|
||||
max="1"
|
||||
step="0.01"
|
||||
placeholder="B"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
@@ -373,6 +395,7 @@
|
||||
max="1"
|
||||
step="0.01"
|
||||
placeholder="A"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
@@ -403,6 +426,7 @@
|
||||
class="input input-bordered"
|
||||
v-model="blueprintData.config.lastEditedBy[0].accountId"
|
||||
placeholder="输入账户ID"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -415,6 +439,7 @@
|
||||
class="input input-bordered"
|
||||
v-model="blueprintData.config.lastEditedBy[0].displayName"
|
||||
placeholder="输入显示名称"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
|
||||
@@ -427,6 +452,7 @@
|
||||
class="input input-bordered"
|
||||
v-model="blueprintData.config.lastEditedBy[0].platformName"
|
||||
placeholder="输入平台名称"
|
||||
@change="onBasicDataChange"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
@@ -490,9 +516,9 @@
|
||||
class="fieldset bg-base-200 border-base-300 rounded-box border p-4"
|
||||
>
|
||||
<div class="join">
|
||||
<input type="text" class="input join-item flex-grow" v-model="item[0].pathName" />
|
||||
<input type="text" class="input join-item flex-grow" v-model="item[0].pathName" @change="onBasicDataChange" />
|
||||
|
||||
<input type="number" class="input join-item w-20" v-model.number="item[1]" />
|
||||
<input type="number" class="input join-item w-20" v-model.number="item[1]" @change="onBasicDataChange" />
|
||||
<button class="btn join-item btn-error "@click="removeItemCost(index)">删除</button>
|
||||
</div>
|
||||
|
||||
@@ -520,7 +546,7 @@
|
||||
>
|
||||
|
||||
<div class="join ">
|
||||
<input class="input join-item flex-grow" type="text" v-model="recipe.pathName" placeholder="输入路径名称"/>
|
||||
<input class="input join-item flex-grow" type="text" v-model="recipe.pathName" placeholder="输入路径名称" @change="onBasicDataChange" />
|
||||
<button class="btn join-item btn-error" @click="removeRecipe(index)">删除</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -536,7 +562,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 进阶编辑区域 - 使用第一个文件的编辑器 -->
|
||||
<!-- 进阶编辑区域 -->
|
||||
<div v-show="activeVisualTab === 'advanced'">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-4 gap-1">
|
||||
<!-- 左侧实体列表 -->
|
||||
@@ -590,6 +616,7 @@
|
||||
language="json"
|
||||
theme="vs"
|
||||
:options="editorOptions"
|
||||
@change="onEntityJsonChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-3 flex justify-end">
|
||||
@@ -608,25 +635,25 @@
|
||||
<label class="label">
|
||||
<span class="label-text">X</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.x" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.x" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Y</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.y" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.y" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Z</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.z" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.z" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">W</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.w" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.rotation.w" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -638,19 +665,19 @@
|
||||
<label class="label">
|
||||
<span class="label-text">X</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.translation.x" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.translation.x" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Y</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.translation.y" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.translation.y" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Z</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.translation.z" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.translation.z" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -662,19 +689,19 @@
|
||||
<label class="label">
|
||||
<span class="label-text">X</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.scale3d.x" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.scale3d.x" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Y</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.scale3d.y" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.scale3d.y" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Z</span>
|
||||
</label>
|
||||
<input type="number" v-model.number="selectedEntity.transform.scale3d.z" class="input input-bordered">
|
||||
<input type="number" v-model.number="selectedEntity.transform.scale3d.z" class="input input-bordered" @change="onEntityDataChange">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -701,6 +728,7 @@
|
||||
type="text"
|
||||
v-model="value.name"
|
||||
class="input input-bordered input-sm"
|
||||
@change="onEntityDataChange"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
@@ -709,6 +737,7 @@
|
||||
v-model="value.ueType"
|
||||
class="input input-bordered input-sm"
|
||||
placeholder="输入类型"
|
||||
@change="onEntityDataChange"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
@@ -719,6 +748,7 @@
|
||||
language="json"
|
||||
theme="vs"
|
||||
:options="smallEditorOptions"
|
||||
@change="(val) => onObjectPropertyChange(key, val)"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
@@ -727,6 +757,7 @@
|
||||
:value="getPropertyDisplayValue(value)"
|
||||
@input="setPropertyValue(value, $event.target.value)"
|
||||
class="input input-bordered input-sm"
|
||||
@change="onEntityDataChange"
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
@@ -770,6 +801,7 @@
|
||||
language="json"
|
||||
theme="vs"
|
||||
:options="editorOptions"
|
||||
@change="onComponentsJsonChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-3 flex justify-end">
|
||||
@@ -799,6 +831,7 @@
|
||||
language="json"
|
||||
theme="vs"
|
||||
:options="editorOptions"
|
||||
@change="(val) => onAttachedComponentChange(index, val)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
@@ -834,7 +867,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { ref, computed, watch, nextTick } from 'vue';
|
||||
import { Parser } from '@etothepii/satisfactory-file-parser';
|
||||
import { CodeEditor } from 'monaco-editor-vue3';
|
||||
|
||||
@@ -853,16 +886,24 @@ export default {
|
||||
const progress = ref(0);
|
||||
const error = ref('');
|
||||
const exportStatus = ref('');
|
||||
const jsonEditStatus = ref('');
|
||||
const jsonValidationError = ref('');
|
||||
const isParsing = ref(false);
|
||||
const isExporting = ref(false);
|
||||
const showObjects = ref(false);
|
||||
const activeVisualTab = ref('basic');
|
||||
const isParsed = ref(false);
|
||||
const isDataSyncing = ref(false);
|
||||
const hasJsonChanges = ref(false);
|
||||
|
||||
// JSON编辑器内容缓存
|
||||
const jsonEditorContent = ref('');
|
||||
const lastValidJson = ref('');
|
||||
|
||||
// 默认的 sbpcfg 十六进制数据
|
||||
const defaultSbpcfgHex = '04000000e5ffffff5300610074006900730066006100630074006f00720079002000dd84fe56167f918f6856d89ea48b73006200700063006600670000000e0300000000803f0000803f0000803f0000803f300000002f47616d652f466163746f727947616d652f2d5368617265642f426c75657072696e742f49636f6e4c696272617279000c00000049636f6e4c69627261727900010000000000000000000000000000000000000000';
|
||||
|
||||
// 编辑器选项 - 调整行号宽度
|
||||
// 编辑器选项
|
||||
const editorOptions = ref({
|
||||
automaticLayout: true,
|
||||
minimap: { enabled: false },
|
||||
@@ -877,7 +918,6 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const smallEditorOptions = ref({
|
||||
...editorOptions.value,
|
||||
fontSize: 12,
|
||||
@@ -886,7 +926,7 @@ export default {
|
||||
tabSize: 2,
|
||||
});
|
||||
|
||||
// 蓝图数据对象
|
||||
// 蓝图数据对象 - 统一管理所有数据
|
||||
const blueprintData = ref({
|
||||
name: '',
|
||||
compressionInfo: {
|
||||
@@ -924,13 +964,10 @@ export default {
|
||||
displayName: "",
|
||||
platformName: ""
|
||||
}]
|
||||
}
|
||||
},
|
||||
objects: [] // 统一管理所有对象数据
|
||||
});
|
||||
|
||||
// Objects 数据
|
||||
const rawObjects = ref([]);
|
||||
const newObjects = ref([]);
|
||||
|
||||
// 使用轻量级对象存储文件信息
|
||||
const fileInfo = ref({
|
||||
blueprintName: '',
|
||||
@@ -938,7 +975,7 @@ export default {
|
||||
configFileName: ''
|
||||
});
|
||||
|
||||
// 第一个文件编辑器的状态
|
||||
// 实体编辑器状态
|
||||
const selectedEntityIndex = ref(null);
|
||||
const activeTab = ref('raw');
|
||||
const newProperty = ref({
|
||||
@@ -965,9 +1002,39 @@ export default {
|
||||
const configFileName = computed(() => fileInfo.value.configFileName);
|
||||
const blueprintName = computed(() => fileInfo.value.blueprintName);
|
||||
|
||||
// 第一个文件编辑器的计算属性
|
||||
// 计算属性:根据开关状态决定显示的JSON内容
|
||||
const displayedJson = computed({
|
||||
get: () => {
|
||||
if (!isParsed.value) return '';
|
||||
|
||||
// 如果有JSON验证错误,显示当前编辑器内容
|
||||
if (jsonValidationError.value && jsonEditorContent.value) {
|
||||
return jsonEditorContent.value;
|
||||
}
|
||||
|
||||
// 如果有未保存的JSON编辑器内容,优先使用
|
||||
if (jsonEditorContent.value && hasJsonChanges.value) {
|
||||
return jsonEditorContent.value;
|
||||
}
|
||||
|
||||
// 否则使用当前数据生成JSON
|
||||
const jsonObj = {
|
||||
...blueprintData.value,
|
||||
objects: showObjects.value ? blueprintData.value.objects : undefined
|
||||
};
|
||||
|
||||
const currentJson = JSON.stringify(jsonObj, null, 2);
|
||||
lastValidJson.value = currentJson;
|
||||
return currentJson;
|
||||
},
|
||||
set: (value) => {
|
||||
jsonEditorContent.value = value;
|
||||
}
|
||||
});
|
||||
|
||||
// 实体编辑器计算属性
|
||||
const filteredEntities = computed(() => {
|
||||
return newObjects.value.filter(entity =>
|
||||
return blueprintData.value.objects.filter(entity =>
|
||||
entity && entity.type === 'SaveEntity'
|
||||
);
|
||||
});
|
||||
@@ -1002,42 +1069,18 @@ export default {
|
||||
const attachedComponents = computed(() => {
|
||||
if (!selectedEntity.value) return [];
|
||||
|
||||
return newObjects.value.filter(e =>
|
||||
return blueprintData.value.objects.filter(e =>
|
||||
e && e.type === 'SaveComponent' &&
|
||||
e.parentEntityName === selectedEntity.value.instanceName
|
||||
);
|
||||
});
|
||||
|
||||
// 计算属性:根据开关状态决定显示的JSON内容
|
||||
const displayedJson = computed({
|
||||
get: () => {
|
||||
if (!isParsed.value) return '';
|
||||
|
||||
const jsonObj = {
|
||||
...blueprintData.value,
|
||||
objects: showObjects.value ? newObjects.value : undefined
|
||||
};
|
||||
|
||||
return JSON.stringify(jsonObj, null, 2);
|
||||
},
|
||||
set: (value) => {
|
||||
// 仅存储JSON字符串,不自动更新数据模型
|
||||
}
|
||||
});
|
||||
|
||||
// 辅助函数:检查是否为复杂对象需要JSON编辑器
|
||||
// 辅助函数
|
||||
const isComplexValue = (value) => {
|
||||
if (value === null || value === undefined) return false;
|
||||
return typeof value === 'object' && !(value instanceof Array);
|
||||
};
|
||||
|
||||
// 辅助函数:获取属性显示类型
|
||||
const getPropertyDisplayType = (property) => {
|
||||
if (!property) return '';
|
||||
return property.ueType || property.type || '';
|
||||
};
|
||||
|
||||
// 辅助函数:获取属性值用于显示
|
||||
const getPropertyDisplayValue = (property) => {
|
||||
if (!property) return '';
|
||||
|
||||
@@ -1053,7 +1096,6 @@ export default {
|
||||
return property.value;
|
||||
};
|
||||
|
||||
// 辅助函数:设置属性值
|
||||
const setPropertyValue = (property, newValue) => {
|
||||
if (!property) return;
|
||||
|
||||
@@ -1068,24 +1110,98 @@ export default {
|
||||
property.value = newValue;
|
||||
}
|
||||
} catch (e) {
|
||||
// 如果JSON解析失败,保持原值
|
||||
console.warn('JSON解析失败,保持原值:', e);
|
||||
}
|
||||
};
|
||||
|
||||
// 方法:处理显示名称
|
||||
const getDisplayName = (instanceName) => {
|
||||
if (!instanceName) return '';
|
||||
return instanceName.replace(/^Persistent_Level:PersistentLevel\./, '');
|
||||
};
|
||||
|
||||
// 方法:处理类型名称
|
||||
const getTypeName = (typePath) => {
|
||||
if (!typePath) return '';
|
||||
return typePath.split('/').pop() || typePath;
|
||||
};
|
||||
|
||||
// 方法
|
||||
// JSON验证函数
|
||||
const validateJson = (jsonString) => {
|
||||
if (!jsonString || jsonString.trim() === '') {
|
||||
return { isValid: true };
|
||||
}
|
||||
|
||||
try {
|
||||
// 尝试解析JSON
|
||||
const parsed = JSON.parse(jsonString);
|
||||
return { isValid: true, data: parsed };
|
||||
} catch (error) {
|
||||
return { isValid: false, error: error.message };
|
||||
}
|
||||
};
|
||||
|
||||
// JSON编辑器变化处理
|
||||
const onJsonEditorChange = (value) => {
|
||||
jsonEditorContent.value = value;
|
||||
|
||||
// 验证JSON格式
|
||||
const validationResult = validateJson(value);
|
||||
if (validationResult.isValid) {
|
||||
jsonValidationError.value = '';
|
||||
hasJsonChanges.value = true;
|
||||
jsonEditStatus.value = 'JSON已修改,点击"更新数据"保存更改';
|
||||
} else {
|
||||
jsonValidationError.value = validationResult.error;
|
||||
jsonEditStatus.value = 'JSON格式错误,请修复后再更新';
|
||||
}
|
||||
};
|
||||
|
||||
// 数据同步方法
|
||||
const syncJsonDisplay = () => {
|
||||
// 在下一次DOM更新后刷新JSON显示
|
||||
nextTick(() => {
|
||||
jsonEditorContent.value = ''; // 清空缓存,强制使用最新数据
|
||||
});
|
||||
};
|
||||
|
||||
const onBasicDataChange = () => {
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '数据已修改,JSON将自动更新';
|
||||
};
|
||||
|
||||
const onEntityDataChange = () => {
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '实体数据已修改,JSON将自动更新';
|
||||
};
|
||||
|
||||
const onEntityJsonChange = () => {
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '实体JSON已修改,JSON将自动更新';
|
||||
};
|
||||
|
||||
const onObjectPropertyChange = (key, value) => {
|
||||
if (selectedEntity.value && selectedEntity.value.properties && selectedEntity.value.properties[key]) {
|
||||
try {
|
||||
selectedEntity.value.properties[key].value = JSON.parse(value);
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '属性已修改,JSON将自动更新';
|
||||
} catch (e) {
|
||||
console.error('JSON解析错误:', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onComponentsJsonChange = () => {
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '组件已修改,JSON将自动更新';
|
||||
};
|
||||
|
||||
const onAttachedComponentChange = (index, value) => {
|
||||
attachedComponentJson.value[index] = value;
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '附属组件已修改,JSON将自动更新';
|
||||
};
|
||||
|
||||
// 文件操作方法
|
||||
const triggerFileInput = () => {
|
||||
fileInput.value.click();
|
||||
};
|
||||
@@ -1135,15 +1251,61 @@ export default {
|
||||
progress.value = 0;
|
||||
error.value = '';
|
||||
exportStatus.value = '';
|
||||
jsonEditStatus.value = '';
|
||||
jsonValidationError.value = '';
|
||||
isParsing.value = false;
|
||||
isExporting.value = false;
|
||||
isDataSyncing.value = false;
|
||||
hasJsonChanges.value = false;
|
||||
showObjects.value = false;
|
||||
activeVisualTab.value = 'basic';
|
||||
isParsed.value = false;
|
||||
rawObjects.value = [];
|
||||
newObjects.value = [];
|
||||
selectedEntityIndex.value = null;
|
||||
activeTab.value = 'raw';
|
||||
jsonEditorContent.value = '';
|
||||
lastValidJson.value = '';
|
||||
|
||||
// 重置蓝图数据
|
||||
blueprintData.value = {
|
||||
name: '',
|
||||
compressionInfo: {
|
||||
chunkHeaderVersion: 0,
|
||||
packageFileTag: 0,
|
||||
maxUncompressedChunkContentSize: 0,
|
||||
compressionAlgorithm: 0
|
||||
},
|
||||
header: {
|
||||
headerVersion: 0,
|
||||
saveVersion: 0,
|
||||
buildVersion: 0,
|
||||
designerDimension: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
recipeReferences: [],
|
||||
itemCosts: []
|
||||
},
|
||||
config: {
|
||||
configVersion: 0,
|
||||
description: '',
|
||||
color: {
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0,
|
||||
a: 1
|
||||
},
|
||||
iconID: 0,
|
||||
referencedIconLibrary: '',
|
||||
iconLibraryType: '',
|
||||
lastEditedBy: [{
|
||||
accountId: "",
|
||||
displayName: "",
|
||||
platformName: ""
|
||||
}]
|
||||
},
|
||||
objects: []
|
||||
};
|
||||
};
|
||||
|
||||
const parseBlueprint = async () => {
|
||||
@@ -1154,10 +1316,12 @@ export default {
|
||||
statusMessages.value = [];
|
||||
progress.value = 0;
|
||||
error.value = '';
|
||||
jsonEditStatus.value = '';
|
||||
jsonValidationError.value = '';
|
||||
selectedEntityIndex.value = null;
|
||||
activeTab.value = 'raw';
|
||||
rawObjects.value = [];
|
||||
newObjects.value = [];
|
||||
jsonEditorContent.value = '';
|
||||
hasJsonChanges.value = false;
|
||||
|
||||
const sbpFile = uploadedFiles.value.find(f => f.name.endsWith('.sbp'));
|
||||
const sbpcfgFile = uploadedFiles.value.find(f => f.name.endsWith('.sbpcfg'));
|
||||
@@ -1202,9 +1366,7 @@ export default {
|
||||
}
|
||||
);
|
||||
|
||||
rawObjects.value = blueprint.objects || [];
|
||||
newObjects.value = JSON.parse(JSON.stringify(rawObjects.value));
|
||||
|
||||
// 统一设置所有数据到主蓝图数据对象
|
||||
blueprintData.value = {
|
||||
name: blueprint.name || '',
|
||||
compressionInfo: {
|
||||
@@ -1242,17 +1404,27 @@ export default {
|
||||
displayName: "",
|
||||
platformName: ""
|
||||
}]
|
||||
}
|
||||
},
|
||||
objects: blueprint.objects || [] // 统一管理对象数据
|
||||
};
|
||||
|
||||
statusMessages.value.push('蓝图文件解析完成!');
|
||||
isParsed.value = true;
|
||||
progress.value = 100;
|
||||
jsonEditStatus.value = '数据解析完成,可以开始编辑';
|
||||
|
||||
// 初始化lastValidJson
|
||||
const jsonObj = {
|
||||
...blueprintData.value,
|
||||
objects: showObjects.value ? blueprintData.value.objects : undefined
|
||||
};
|
||||
lastValidJson.value = JSON.stringify(jsonObj, null, 2);
|
||||
|
||||
} catch (err) {
|
||||
console.error('解析错误:', err);
|
||||
error.value = `解析错误: ${err.message}`;
|
||||
statusMessages.value.push('解析失败!');
|
||||
jsonEditStatus.value = '解析失败,请检查文件格式';
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
isParsing.value = false;
|
||||
@@ -1270,18 +1442,15 @@ export default {
|
||||
// 创建当前时间戳
|
||||
const timestamp = Date.now().toString();
|
||||
|
||||
// 准备导出的数据 - 深拷贝避免修改原始数据
|
||||
const exportData = JSON.parse(JSON.stringify({
|
||||
...blueprintData.value,
|
||||
objects: newObjects.value
|
||||
}));
|
||||
// 准备导出的数据
|
||||
const exportData = JSON.parse(JSON.stringify(blueprintData.value));
|
||||
|
||||
// 确保 lastEditedBy 数组存在
|
||||
if (!exportData.config.lastEditedBy) {
|
||||
exportData.config.lastEditedBy = [];
|
||||
}
|
||||
|
||||
// 在数组尾部添加新的编辑者信息(第二位)
|
||||
// 在数组尾部添加新的编辑者信息
|
||||
exportData.config.lastEditedBy.push({
|
||||
accountId: timestamp,
|
||||
displayName: "LinXingLuo",
|
||||
@@ -1333,44 +1502,111 @@ export default {
|
||||
|
||||
const formatJson = () => {
|
||||
try {
|
||||
const obj = JSON.parse(displayedJson.value);
|
||||
displayedJson.value = JSON.stringify(obj, null, 2);
|
||||
if (!jsonEditorContent.value) {
|
||||
jsonEditStatus.value = '没有内容可格式化';
|
||||
return;
|
||||
}
|
||||
|
||||
const validationResult = validateJson(jsonEditorContent.value);
|
||||
if (!validationResult.isValid) {
|
||||
jsonValidationError.value = validationResult.error;
|
||||
jsonEditStatus.value = 'JSON格式错误,无法格式化';
|
||||
return;
|
||||
}
|
||||
|
||||
const obj = validationResult.data;
|
||||
const formattedJson = JSON.stringify(obj, null, 2);
|
||||
jsonEditorContent.value = formattedJson;
|
||||
jsonEditStatus.value = 'JSON已格式化';
|
||||
|
||||
} catch (e) {
|
||||
error.value = 'JSON格式错误,无法格式化';
|
||||
jsonEditStatus.value = '格式化失败:JSON格式错误';
|
||||
}
|
||||
};
|
||||
|
||||
const refreshJson = () => {
|
||||
const jsonObj = {
|
||||
...blueprintData.value,
|
||||
objects: showObjects.value ? newObjects.value : undefined
|
||||
// 只有有更改时才提示刷新
|
||||
if (hasJsonChanges.value) {
|
||||
if (confirm('刷新将丢失当前的更改,是否继续?')) {
|
||||
forceRefreshJson();
|
||||
}
|
||||
} else {
|
||||
forceRefreshJson();
|
||||
}
|
||||
};
|
||||
|
||||
displayedJson.value = JSON.stringify(jsonObj, null, 2);
|
||||
const forceRefreshJson = () => {
|
||||
// 清空缓存,强制使用最新数据
|
||||
jsonEditorContent.value = '';
|
||||
jsonValidationError.value = '';
|
||||
hasJsonChanges.value = false;
|
||||
jsonEditStatus.value = 'JSON已刷新到最新数据';
|
||||
};
|
||||
|
||||
const updateDataFromJson = () => {
|
||||
try {
|
||||
const editedObj = JSON.parse(displayedJson.value);
|
||||
if (!jsonEditorContent.value || !hasJsonChanges.value) {
|
||||
jsonEditStatus.value = '没有要更新的内容或内容无变化';
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key in editedObj) {
|
||||
if (key !== 'objects') {
|
||||
// 首先验证JSON
|
||||
const validationResult = validateJson(jsonEditorContent.value);
|
||||
if (!validationResult.isValid) {
|
||||
jsonValidationError.value = validationResult.error;
|
||||
jsonEditStatus.value = 'JSON格式错误,无法更新数据';
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
isDataSyncing.value = true;
|
||||
jsonEditStatus.value = '正在更新数据...';
|
||||
|
||||
const editedObj = validationResult.data;
|
||||
|
||||
// 更新所有数据到主蓝图数据对象
|
||||
Object.keys(editedObj).forEach(key => {
|
||||
if (key === 'objects') {
|
||||
// 特殊处理objects字段
|
||||
if (editedObj.objects !== undefined) {
|
||||
blueprintData.value.objects = editedObj.objects;
|
||||
}
|
||||
} else {
|
||||
// 简单赋值
|
||||
blueprintData.value[key] = editedObj[key];
|
||||
}
|
||||
});
|
||||
|
||||
// 确保objects字段始终存在
|
||||
if (!blueprintData.value.objects) {
|
||||
blueprintData.value.objects = [];
|
||||
}
|
||||
|
||||
if (editedObj.objects) {
|
||||
newObjects.value = editedObj.objects;
|
||||
// 保存当前状态为有效状态
|
||||
lastValidJson.value = jsonEditorContent.value;
|
||||
hasJsonChanges.value = false;
|
||||
|
||||
statusMessages.value.push('数据更新成功!');
|
||||
jsonEditStatus.value = '数据更新成功!';
|
||||
|
||||
// 如果当前有选中的实体,重新初始化相关数据
|
||||
if (selectedEntityIndex.value !== null) {
|
||||
initObjectProperties();
|
||||
initAttachedComponentJson();
|
||||
}
|
||||
|
||||
statusMessages.value.push('数据已从JSON更新!');
|
||||
} catch (e) {
|
||||
console.error('JSON更新错误:', e);
|
||||
error.value = '更新数据失败:JSON解析错误';
|
||||
error.value = '更新数据失败:' + e.message;
|
||||
jsonEditStatus.value = '更新失败:' + e.message;
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
isDataSyncing.value = false;
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
// 第一个文件编辑器的方法
|
||||
// 实体编辑器方法
|
||||
const selectEntity = (index) => {
|
||||
selectedEntityIndex.value = index;
|
||||
activeTab.value = 'raw';
|
||||
@@ -1381,16 +1617,19 @@ export default {
|
||||
const updateEntityFromJson = () => {
|
||||
try {
|
||||
const updatedEntity = JSON.parse(entityJson.value);
|
||||
const originalIndex = newObjects.value.findIndex(
|
||||
const originalIndex = blueprintData.value.objects.findIndex(
|
||||
e => e.instanceName === selectedEntity.value.instanceName
|
||||
);
|
||||
|
||||
if (originalIndex !== -1) {
|
||||
newObjects.value[originalIndex] = updatedEntity;
|
||||
blueprintData.value.objects[originalIndex] = updatedEntity;
|
||||
initObjectProperties();
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '实体更新成功,JSON已同步';
|
||||
}
|
||||
} catch (error) {
|
||||
alert('更新实体错误: ' + error.message);
|
||||
jsonEditStatus.value = '实体更新失败:' + error.message;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1399,25 +1638,31 @@ export default {
|
||||
const updatedComponents = JSON.parse(componentsJson.value);
|
||||
if (selectedEntity.value) {
|
||||
selectedEntity.value.components = updatedComponents;
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '组件更新成功,JSON已同步';
|
||||
}
|
||||
} catch (error) {
|
||||
alert('更新组件错误: ' + error.message);
|
||||
jsonEditStatus.value = '组件更新失败:' + error.message;
|
||||
}
|
||||
};
|
||||
|
||||
const updateAttachedComponent = (index) => {
|
||||
try {
|
||||
const updatedComponent = JSON.parse(attachedComponentJson.value[index]);
|
||||
const compIndex = newObjects.value.findIndex(e =>
|
||||
const compIndex = blueprintData.value.objects.findIndex(e =>
|
||||
e && e.instanceName === attachedComponents.value[index].instanceName
|
||||
);
|
||||
|
||||
if (compIndex !== -1) {
|
||||
newObjects.value[compIndex] = updatedComponent;
|
||||
blueprintData.value.objects[compIndex] = updatedComponent;
|
||||
attachedComponentJson.value[index] = JSON.stringify(updatedComponent, null, 2);
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '附属组件更新成功,JSON已同步';
|
||||
}
|
||||
} catch (error) {
|
||||
alert('更新附属组件错误: ' + error.message);
|
||||
jsonEditStatus.value = '附属组件更新失败:' + error.message;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1425,6 +1670,8 @@ export default {
|
||||
if (selectedEntity.value && selectedEntity.value.properties && selectedEntity.value.properties[key]) {
|
||||
delete selectedEntity.value.properties[key];
|
||||
delete objectProperties.value[key];
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '属性已删除,JSON已同步';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1451,6 +1698,9 @@ export default {
|
||||
type: 'FloatProperty',
|
||||
value: 0
|
||||
};
|
||||
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '属性已添加,JSON已同步';
|
||||
};
|
||||
|
||||
const initObjectProperties = () => {
|
||||
@@ -1477,10 +1727,14 @@ export default {
|
||||
blueprintData.value.header.recipeReferences.push({
|
||||
pathName: ""
|
||||
});
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '配方已添加,JSON已同步';
|
||||
};
|
||||
|
||||
const removeRecipe = (index) => {
|
||||
blueprintData.value.header.recipeReferences.splice(index, 1);
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '配方已删除,JSON已同步';
|
||||
};
|
||||
|
||||
const addItemCost = () => {
|
||||
@@ -1488,19 +1742,36 @@ export default {
|
||||
{ pathName: "" },
|
||||
0
|
||||
]);
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '物品成本已添加,JSON已同步';
|
||||
};
|
||||
|
||||
const removeItemCost = (index) => {
|
||||
blueprintData.value.header.itemCosts.splice(index, 1);
|
||||
syncJsonDisplay();
|
||||
jsonEditStatus.value = '物品成本已删除,JSON已同步';
|
||||
};
|
||||
|
||||
// 监听newObjects变化
|
||||
watch(newObjects, () => {
|
||||
// 监听对象变化
|
||||
watch(() => blueprintData.value.objects, () => {
|
||||
if (selectedEntity.value) {
|
||||
initAttachedComponentJson();
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
// 监听showObjects变化,确保JSON显示同步
|
||||
watch(showObjects, (newVal) => {
|
||||
// 当切换Objects段显示时,如果有未保存的更改,提示用户
|
||||
if (hasJsonChanges.value) {
|
||||
jsonEditStatus.value = `Objects段显示${newVal ? '开启' : '关闭'} - 注意:有未保存的更改`;
|
||||
} else {
|
||||
jsonEditStatus.value = `Objects段显示${newVal ? '开启' : '关闭'}`;
|
||||
}
|
||||
|
||||
// 刷新JSON显示,但不标记为有更改
|
||||
jsonEditorContent.value = '';
|
||||
});
|
||||
|
||||
return {
|
||||
// 文件操作相关
|
||||
fileInput,
|
||||
@@ -1511,8 +1782,12 @@ export default {
|
||||
progress,
|
||||
error,
|
||||
exportStatus,
|
||||
jsonEditStatus,
|
||||
jsonValidationError,
|
||||
isParsing,
|
||||
isExporting,
|
||||
isDataSyncing,
|
||||
hasJsonChanges,
|
||||
showObjects,
|
||||
activeVisualTab,
|
||||
blueprintData,
|
||||
@@ -1523,7 +1798,7 @@ export default {
|
||||
editorOptions,
|
||||
smallEditorOptions,
|
||||
|
||||
// 第一个文件编辑器相关
|
||||
// 实体编辑器相关
|
||||
filteredEntities,
|
||||
selectedEntityIndex,
|
||||
activeTab,
|
||||
@@ -1538,7 +1813,6 @@ export default {
|
||||
|
||||
// 辅助函数
|
||||
isComplexValue,
|
||||
getPropertyDisplayType,
|
||||
getPropertyDisplayValue,
|
||||
setPropertyValue,
|
||||
|
||||
@@ -1559,13 +1833,22 @@ export default {
|
||||
getDisplayName,
|
||||
getTypeName,
|
||||
|
||||
// 第一个文件编辑器方法
|
||||
// 实体编辑器方法
|
||||
selectEntity,
|
||||
updateEntityFromJson,
|
||||
updateComponents,
|
||||
updateAttachedComponent,
|
||||
deleteProperty,
|
||||
addProperty
|
||||
addProperty,
|
||||
|
||||
// 数据同步方法
|
||||
onJsonEditorChange,
|
||||
onBasicDataChange,
|
||||
onEntityDataChange,
|
||||
onEntityJsonChange,
|
||||
onObjectPropertyChange,
|
||||
onComponentsJsonChange,
|
||||
onAttachedComponentChange
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
@import "tailwindcss";
|
||||
@plugin "daisyui";
|
||||
|
||||
/* 修复JSON编辑状态的颜色问题 */
|
||||
.text-error {
|
||||
color: #18181B !important;
|
||||
}
|
||||
Reference in New Issue
Block a user