fix(admin): 修复零值字段无法保存的问题
- 用户允许分组:前端发送空数组而非 null 表示"允许全部" - 账户代理:前端发送 0 而非 null 表示"无代理" - 后端 UpdateAccount/BulkUpdate 正确处理 ProxyID=0 为清除代理
This commit is contained in:
@@ -773,9 +773,14 @@ func (r *accountRepository) BulkUpdate(ctx context.Context, ids []int64, updates
|
|||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
if updates.ProxyID != nil {
|
if updates.ProxyID != nil {
|
||||||
setClauses = append(setClauses, "proxy_id = $"+itoa(idx))
|
// 0 表示清除代理(前端发送 0 而不是 null 来表达清除意图)
|
||||||
args = append(args, *updates.ProxyID)
|
if *updates.ProxyID == 0 {
|
||||||
idx++
|
setClauses = append(setClauses, "proxy_id = NULL")
|
||||||
|
} else {
|
||||||
|
setClauses = append(setClauses, "proxy_id = $"+itoa(idx))
|
||||||
|
args = append(args, *updates.ProxyID)
|
||||||
|
idx++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if updates.Concurrency != nil {
|
if updates.Concurrency != nil {
|
||||||
setClauses = append(setClauses, "concurrency = $"+itoa(idx))
|
setClauses = append(setClauses, "concurrency = $"+itoa(idx))
|
||||||
|
|||||||
@@ -702,7 +702,12 @@ func (s *adminServiceImpl) UpdateAccount(ctx context.Context, id int64, input *U
|
|||||||
account.Extra = input.Extra
|
account.Extra = input.Extra
|
||||||
}
|
}
|
||||||
if input.ProxyID != nil {
|
if input.ProxyID != nil {
|
||||||
account.ProxyID = input.ProxyID
|
// 0 表示清除代理(前端发送 0 而不是 null 来表达清除意图)
|
||||||
|
if *input.ProxyID == 0 {
|
||||||
|
account.ProxyID = nil
|
||||||
|
} else {
|
||||||
|
account.ProxyID = input.ProxyID
|
||||||
|
}
|
||||||
account.Proxy = nil // 清除关联对象,防止 GORM Save 时根据 Proxy.ID 覆盖 ProxyID
|
account.Proxy = nil // 清除关联对象,防止 GORM Save 时根据 Proxy.ID 覆盖 ProxyID
|
||||||
}
|
}
|
||||||
// 只在指针非 nil 时更新 Concurrency(支持设置为 0)
|
// 只在指针非 nil 时更新 Concurrency(支持设置为 0)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const load = async () => { loading.value = true; try { const res = await adminAP
|
|||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
if (!props.user) return; submitting.value = true
|
if (!props.user) return; submitting.value = true
|
||||||
try {
|
try {
|
||||||
await adminAPI.users.update(props.user.id, { allowed_groups: selectedIds.value.length > 0 ? selectedIds.value : null })
|
await adminAPI.users.update(props.user.id, { allowed_groups: selectedIds.value })
|
||||||
appStore.showSuccess(t('admin.users.allowedGroupsUpdated')); emit('success'); emit('close')
|
appStore.showSuccess(t('admin.users.allowedGroupsUpdated')); emit('success'); emit('close')
|
||||||
} catch {} finally { submitting.value = false }
|
} catch {} finally { submitting.value = false }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,11 +98,11 @@
|
|||||||
<!-- No Proxy option -->
|
<!-- No Proxy option -->
|
||||||
<div
|
<div
|
||||||
@click="selectOption(null)"
|
@click="selectOption(null)"
|
||||||
:class="['select-option', modelValue === null && 'select-option-selected']"
|
:class="['select-option', (modelValue === null || modelValue === 0) && 'select-option-selected']"
|
||||||
>
|
>
|
||||||
<span class="select-option-label">{{ t('admin.accounts.noProxy') }}</span>
|
<span class="select-option-label">{{ t('admin.accounts.noProxy') }}</span>
|
||||||
<svg
|
<svg
|
||||||
v-if="modelValue === null"
|
v-if="modelValue === null || modelValue === 0"
|
||||||
class="h-4 w-4 text-primary-500"
|
class="h-4 w-4 text-primary-500"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -265,7 +265,7 @@ const testingProxyIds = reactive(new Set<number>())
|
|||||||
const batchTesting = ref(false)
|
const batchTesting = ref(false)
|
||||||
|
|
||||||
const selectedProxy = computed(() => {
|
const selectedProxy = computed(() => {
|
||||||
if (props.modelValue === null) return null
|
if (props.modelValue === null || props.modelValue === 0) return null
|
||||||
return props.proxies.find((p) => p.id === props.modelValue) || null
|
return props.proxies.find((p) => p.id === props.modelValue) || null
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -300,7 +300,8 @@ const toggle = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectOption = (value: number | null) => {
|
const selectOption = (value: number | null) => {
|
||||||
emit('update:modelValue', value)
|
// 使用 0 表示"无代理",以便后端能正确识别清除意图
|
||||||
|
emit('update:modelValue', value === null ? 0 : value)
|
||||||
isOpen.value = false
|
isOpen.value = false
|
||||||
searchQuery.value = ''
|
searchQuery.value = ''
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user