fix(settings): use local state in LLMTableRow to avoid props mutation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { Eye, EyeOff, Play, ChevronDown, ChevronRight, Trash2 } from 'lucide-vue-next'
|
||||
import type { LLMModelConfig } from '@/api/settings'
|
||||
|
||||
@@ -17,6 +17,14 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const showApiKey = ref(false)
|
||||
const editingModel = ref<LLMModelConfig>({ ...props.model })
|
||||
|
||||
// Reinitialize editing model when expanding (handles editing different rows)
|
||||
watch(() => props.isExpanded, (expanded, wasExpanded) => {
|
||||
if (expanded && !wasExpanded) {
|
||||
editingModel.value = { ...props.model }
|
||||
}
|
||||
})
|
||||
|
||||
const status = computed(() => {
|
||||
if (!props.model.api_key || !props.model.model) return 'empty'
|
||||
@@ -37,8 +45,8 @@ function onProviderChange() {
|
||||
claude: 'https://api.anthropic.com',
|
||||
deepseek: 'https://api.deepseek.com/v1'
|
||||
}
|
||||
if (!props.model.base_url || Object.values(defaults).includes(props.model.base_url)) {
|
||||
emit('update', { ...props.model, base_url: defaults[props.model.provider] || '' })
|
||||
if (!editingModel.value.base_url || Object.values(defaults).includes(editingModel.value.base_url)) {
|
||||
editingModel.value.base_url = defaults[editingModel.value.provider] || ''
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -69,7 +77,7 @@ function onProviderChange() {
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label>// PROVIDER</label>
|
||||
<select v-model="model.provider" @change="onProviderChange">
|
||||
<select v-model="editingModel.provider" @change="onProviderChange">
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="claude">Claude</option>
|
||||
<option value="ollama">Ollama</option>
|
||||
@@ -79,18 +87,18 @@ function onProviderChange() {
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>// MODEL</label>
|
||||
<input v-model="model.model" type="text" placeholder="gpt-4o" />
|
||||
<input v-model="editingModel.model" type="text" placeholder="gpt-4o" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>// BASE URL</label>
|
||||
<input v-model="model.base_url" type="text" />
|
||||
<input v-model="editingModel.base_url" type="text" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>// API KEY</label>
|
||||
<div class="input-with-toggle">
|
||||
<input
|
||||
v-model="model.api_key"
|
||||
v-model="editingModel.api_key"
|
||||
:type="showApiKey ? 'text' : 'password'"
|
||||
placeholder="sk-..."
|
||||
/>
|
||||
@@ -101,13 +109,13 @@ function onProviderChange() {
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-actions">
|
||||
<button class="test-btn" @click="emit('test', model)">
|
||||
<button class="test-btn" @click="emit('test', editingModel)">
|
||||
<Play :size="12" /> 测试连接
|
||||
</button>
|
||||
<button
|
||||
class="save-btn"
|
||||
:disabled="status !== 'available'"
|
||||
@click="emit('update', model)"
|
||||
@click="emit('update', editingModel)"
|
||||
>
|
||||
保存
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user