From bec7d017226a76174a4d30399baa5db28621ef78 Mon Sep 17 00:00:00 2001 From: Stardust Date: Sat, 21 Mar 2026 13:29:42 +0800 Subject: [PATCH 1/3] fix: wrong index in ObjectEditor updateKey causing false 'key exists' error --- .../src/components/shared/ObjectEditor.vue | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/dashboard/src/components/shared/ObjectEditor.vue b/dashboard/src/components/shared/ObjectEditor.vue index 3247d1d22b..e20bc9f31a 100644 --- a/dashboard/src/components/shared/ObjectEditor.vue +++ b/dashboard/src/components/shared/ObjectEditor.vue @@ -37,7 +37,8 @@ variant="outlined" hide-details :placeholder="t('core.common.objectEditor.placeholders.keyName')" - @blur="updateKey(index, pair.key)" + @focus="pair._originalKey = pair.key" + @blur="onKeyBlur(pair)" > @@ -369,39 +370,30 @@ function removeKeyValuePairByKey(key) { } } -function updateKey(index, newKey) { - const originalKey = localKeyValuePairs.value[index].key - // 如果键名没有改变,则不执行任何操作 - if (originalKey === newKey) return +function onKeyBlur(pair) { + const originalKey = pair._originalKey + const newKey = pair.key + if (originalKey === undefined || originalKey === newKey) return - // 检查新键名是否已存在 - const isKeyExists = localKeyValuePairs.value.some((pair, i) => i !== index && pair.key === newKey) + const isKeyExists = localKeyValuePairs.value.some(p => p !== pair && p.key === newKey) if (isKeyExists) { - // 如果键名已存在,提示用户并恢复原值 alert(t('core.common.objectEditor.keyExists')) - // 将键名恢复为修改前的原始值 - localKeyValuePairs.value[index].key = originalKey + pair.key = originalKey return } - // 检查新键名是否有模板 const template = templateSchema.value[newKey] if (template) { - // 更新类型和默认值 - localKeyValuePairs.value[index].type = template.type || localKeyValuePairs.value[index].type - if (localKeyValuePairs.value[index].value === undefined || localKeyValuePairs.value[index].value === null || localKeyValuePairs.value[index].value === '') { - localKeyValuePairs.value[index].value = template.default !== undefined ? template.default : localKeyValuePairs.value[index].value + pair.type = template.type || pair.type + if (pair.value === undefined || pair.value === null || pair.value === '') { + pair.value = template.default !== undefined ? template.default : pair.value } - localKeyValuePairs.value[index].slider = template.slider - localKeyValuePairs.value[index].template = template + pair.slider = template.slider + pair.template = template } else { - // 清除模板信息 - localKeyValuePairs.value[index].slider = undefined - localKeyValuePairs.value[index].template = undefined + pair.slider = undefined + pair.template = undefined } - - // 更新本地副本 - localKeyValuePairs.value[index].key = newKey } function isTemplateKeyAdded(templateKey) { From 20eca0401f554b21d8b0272faa750e9f30281bc6 Mon Sep 17 00:00:00 2001 From: Stardust Date: Sat, 21 Mar 2026 14:15:00 +0800 Subject: [PATCH 2/3] fix: same index mismatch issue in updateJSON --- dashboard/src/components/shared/ObjectEditor.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dashboard/src/components/shared/ObjectEditor.vue b/dashboard/src/components/shared/ObjectEditor.vue index e20bc9f31a..98d62d6b9e 100644 --- a/dashboard/src/components/shared/ObjectEditor.vue +++ b/dashboard/src/components/shared/ObjectEditor.vue @@ -87,7 +87,7 @@ variant="outlined" hide-details="auto" :placeholder="t('core.common.objectEditor.placeholders.jsonValue')" - @blur="updateJSON(index, pair.value)" + @blur="validateJSON(pair)" :error-messages="pair.jsonError" > @@ -354,12 +354,12 @@ function addKeyValuePair() { } } -function updateJSON(index, newValue) { +function validateJSON(pair) { try { - JSON.parse(newValue) - localKeyValuePairs.value[index].jsonError = '' + JSON.parse(pair.value) + pair.jsonError = '' } catch (e) { - localKeyValuePairs.value[index].jsonError = t('core.common.objectEditor.invalidJson') + pair.jsonError = t('core.common.objectEditor.invalidJson') } } From 657078152a90f36536693b36131988a6091d23c8 Mon Sep 17 00:00:00 2001 From: RC-CHN <1051989940@qq.com> Date: Tue, 24 Mar 2026 09:28:08 +0800 Subject: [PATCH 3/3] fix(ui): stabilize ObjectEditor pair keys Use generated ids for key-value pairs instead of array indexes to prevent mismatch issues during editing and rendering. Also replace duplicate-key alerts with toast warnings for a more consistent UI experience. --- .../src/components/shared/ObjectEditor.vue | 68 ++++++++++++------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/dashboard/src/components/shared/ObjectEditor.vue b/dashboard/src/components/shared/ObjectEditor.vue index 98d62d6b9e..58b010ce93 100644 --- a/dashboard/src/components/shared/ObjectEditor.vue +++ b/dashboard/src/components/shared/ObjectEditor.vue @@ -28,7 +28,7 @@
-
+
import { ref, computed, watch } from 'vue' import { useI18n, useModuleI18n } from '@/i18n/composables' +import { useToast } from '@/utils/toast' const { t } = useI18n() const { tm, getRaw } = useModuleI18n('features/config-metadata') +const { warning: toastWarning } = useToast() const props = defineProps({ modelValue: { @@ -259,6 +261,7 @@ const localKeyValuePairs = ref([]) const originalKeyValuePairs = ref([]) const newKey = ref('') const newValueType = ref('string') +const nextPairId = ref(0) // Template schema support const templateSchema = computed(() => { @@ -285,12 +288,26 @@ watch(() => props.modelValue, (newValue) => { // The dialog-based editing handles internal updates }, { immediate: true }) +function createPair({ key, value, type, slider, template, jsonError = '', _originalKey }) { + return { + _id: nextPairId.value++, + key, + value, + type, + slider, + template, + jsonError, + _originalKey + } +} + function initializeLocalKeyValuePairs() { localKeyValuePairs.value = [] + nextPairId.value = 0 for (const [key, value] of Object.entries(props.modelValue)) { let _type = (typeof value) === 'object' ? 'json':(typeof value) - let _value = _type === 'json'?JSON.stringify(value):value - + let _value = _type === 'json' ? JSON.stringify(value) : value + // Check if this key has a template schema const template = templateSchema.value[key] if (template) { @@ -301,20 +318,20 @@ function initializeLocalKeyValuePairs() { _value = template.default !== undefined ? template.default : _value } } - - localKeyValuePairs.value.push({ - key: key, + + localKeyValuePairs.value.push(createPair({ + key, value: _value, type: _type, slider: template?.slider, - template: template - }) + template + })) } } function openDialog() { initializeLocalKeyValuePairs() - originalKeyValuePairs.value = JSON.parse(JSON.stringify(localKeyValuePairs.value)) // Deep copy + originalKeyValuePairs.value = localKeyValuePairs.value.map(pair => ({ ...pair })) newKey.value = '' newValueType.value = 'string' dialog.value = true @@ -325,7 +342,7 @@ function addKeyValuePair() { if (key !== '') { const isKeyExists = localKeyValuePairs.value.some(pair => pair.key === key) if (isKeyExists) { - alert(t('core.common.objectEditor.keyExists')) + toastWarning(t('core.common.objectEditor.keyExists')) return } @@ -338,18 +355,18 @@ function addKeyValuePair() { defaultValue = false break case 'json': - defaultValue = "{}" + defaultValue = '{}' break default: // string - defaultValue = "" + defaultValue = '' break } - localKeyValuePairs.value.push({ - key: key, + localKeyValuePairs.value.push(createPair({ + key, value: defaultValue, type: newValueType.value - }) + })) newKey.value = '' } } @@ -377,7 +394,7 @@ function onKeyBlur(pair) { const isKeyExists = localKeyValuePairs.value.some(p => p !== pair && p.key === newKey) if (isKeyExists) { - alert(t('core.common.objectEditor.keyExists')) + toastWarning(t('core.common.objectEditor.keyExists')) pair.key = originalKey return } @@ -412,20 +429,20 @@ function getTemplateValue(templateKey) { function updateTemplateValue(templateKey, newValue) { const existingIndex = localKeyValuePairs.value.findIndex(pair => pair.key === templateKey) const template = templateSchema.value[templateKey] - + if (existingIndex >= 0) { // 更新现有值 localKeyValuePairs.value[existingIndex].value = newValue } else { // 添加新字段 - let valueType = template?.type || 'string' - localKeyValuePairs.value.push({ + const valueType = template?.type || 'string' + localKeyValuePairs.value.push(createPair({ key: templateKey, value: newValue, type: valueType, slider: template?.slider, - template: template - }) + template + })) } } @@ -446,10 +463,10 @@ function getDefaultValueForType(type) { case 'boolean': return false case 'json': - return "{}" + return '{}' case 'string': default: - return "" + return '' } } @@ -473,7 +490,7 @@ function confirmDialog() { case 'bool': case 'boolean': // 布尔值通常由 v-switch 正确处理,但为保险起见可以显式转换 - // 注意:在 JavaScript 中,只有严格的 false, 0, "", null, undefined, NaN 会被转换为 false + // 注意:在 JavaScript 中,只有严格的 false, 0, '', null, undefined, NaN 会被转换为 false // 这里直接赋值 pair.value 应该是安全的,因为 v-model 绑定的就是布尔值 // convertedValue = Boolean(pair.value) break @@ -494,7 +511,7 @@ function confirmDialog() { function cancelDialog() { // Reset to original state - localKeyValuePairs.value = JSON.parse(JSON.stringify(originalKeyValuePairs.value)) + localKeyValuePairs.value = originalKeyValuePairs.value.map(pair => ({ ...pair })) dialog.value = false } @@ -521,3 +538,4 @@ function getTemplateTitle(template, templateKey) { opacity: 0.8; } +