mirror of
https://github.com/AstrBotDevs/AstrBot.git
synced 2026-09-24 16:39:52 +08:00
fix: wrong index in ObjectEditor updateKey causing false 'key exists' error
* fix: wrong index in ObjectEditor updateKey causing false 'key exists' error * fix: same index mismatch issue in updateJSON * 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. --------- Co-authored-by: RC-CHN <1051989940@qq.com>
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
<v-card-text class="pa-4" style="max-height: 400px; overflow-y: auto;">
|
||||
<!-- Regular key-value pairs (non-template) -->
|
||||
<div v-if="nonTemplatePairs.length > 0">
|
||||
<div v-for="(pair, index) in nonTemplatePairs" :key="index" class="key-value-pair">
|
||||
<div v-for="pair in nonTemplatePairs" :key="pair._id" class="key-value-pair">
|
||||
<v-row no-gutters align="center" class="mb-2">
|
||||
<v-col cols="4">
|
||||
<v-text-field
|
||||
@@ -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)"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="7" class="pl-2 d-flex align-center justify-end">
|
||||
@@ -86,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"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
@@ -221,9 +222,11 @@
|
||||
<script setup>
|
||||
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: {
|
||||
@@ -258,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(() => {
|
||||
@@ -284,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) {
|
||||
@@ -300,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
|
||||
@@ -324,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
|
||||
}
|
||||
|
||||
@@ -337,28 +355,28 @@ 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 = ''
|
||||
}
|
||||
}
|
||||
|
||||
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')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,39 +387,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
|
||||
toastWarning(t('core.common.objectEditor.keyExists'))
|
||||
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) {
|
||||
@@ -420,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
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,10 +463,10 @@ function getDefaultValueForType(type) {
|
||||
case 'boolean':
|
||||
return false
|
||||
case 'json':
|
||||
return "{}"
|
||||
return '{}'
|
||||
case 'string':
|
||||
default:
|
||||
return ""
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,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
|
||||
@@ -502,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
|
||||
}
|
||||
|
||||
@@ -529,3 +538,4 @@ function getTemplateTitle(template, templateKey) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user