修复编辑器不同步bug

This commit is contained in:
nnwang
2025-12-04 23:57:23 +08:00
parent febe90a2d1
commit 8904afa511
2 changed files with 401 additions and 113 deletions

View File

@@ -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
};
}
}

View File

@@ -1,2 +1,7 @@
@import "tailwindcss";
@plugin "daisyui";
/* 修复JSON编辑状态的颜色问题 */
.text-error {
color: #18181B !important;
}