fix(ui): refine account settings and key displays

Show all batch account settings by default while updating only edited fields. Add ellipsis and full-text titles to API key names and labels, and adjust the token usage summary icon size and alignment.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Zyy
2026-09-16 02:54:23 +08:00
co-authored by Codex
parent cca89f2f96
commit 5a5cdbdcde
6 changed files with 72 additions and 70 deletions
@@ -2,7 +2,6 @@
import type { AccountGroup, AccountModelAccess } from '@/api'
import BaseButton from '@/components/base/BaseButton.vue'
import BaseCheckbox from '@/components/base/BaseCheckbox.vue'
import BaseModal from '@/components/base/BaseModal/index.vue'
import AccountSettingsFields from './AccountSettingsFields.vue'
@@ -12,6 +11,7 @@ defineProps<{
groups: AccountGroup[]
groupsLoading: boolean
saving: boolean
hasChanges: boolean
}>()
const emit = defineEmits<{
@@ -22,7 +22,6 @@ const open = defineModel<boolean>({ required: true })
const enabled = defineModel<boolean>('enabled', { required: true })
const concurrencyLimit = defineModel<string>('concurrencyLimit', { required: true })
const modelAccess = defineModel<AccountModelAccess | undefined>('modelAccess', { required: true })
const updateScheduling = defineModel<boolean>('updateScheduling', { required: true })
const weight = defineModel<string>('weight', { required: true })
const proxyMode = defineModel<string>('proxyMode', { required: true })
const proxyId = defineModel<string>('proxyId', { required: true })
@@ -38,7 +37,6 @@ const selectedGroupIds = defineModel<string[]>('selectedGroupIds', { required: t
:dismissible="!saving"
>
<div class="grid gap-5">
<BaseCheckbox v-model="updateScheduling" label="同时更新调度、分组和代理设置" show-label :disabled="saving" />
<AccountSettingsFields
v-model:enabled="enabled"
v-model:concurrency-limit="concurrencyLimit"
@@ -48,7 +46,6 @@ const selectedGroupIds = defineModel<string[]>('selectedGroupIds', { required: t
v-model:proxy-mode="proxyMode"
v-model:proxy-id="proxyId"
preserve-model-access
:model-only="!updateScheduling"
:account-id="catalogAccountId"
:groups="groups"
:groups-loading="groupsLoading"
@@ -63,7 +60,7 @@ const selectedGroupIds = defineModel<string[]>('selectedGroupIds', { required: t
<BaseButton
variant="primary"
:loading="saving"
:disabled="selectedCount === 0 || (updateScheduling && groupsLoading) || (!updateScheduling && !modelAccess)"
:disabled="selectedCount === 0 || groupsLoading || !hasChanges"
@click="emit('save')"
>
保存更改
@@ -15,7 +15,6 @@ withDefaults(defineProps<{
accountId?: string
preserveProxy?: boolean
preserveModelAccess?: boolean
modelOnly?: boolean
proxyError?: string
}>(), { preserveProxy: true })
@@ -31,50 +30,48 @@ const selectedGroupIds = defineModel<string[]>('selectedGroupIds', { required: t
<template>
<div class="grid gap-5">
<AccountModelAccessField v-model="modelAccess" :account-id="accountId" :disabled="disabled" :allow-preserve="preserveModelAccess" />
<template v-if="!modelOnly">
<div class="flex min-h-6 items-center justify-between gap-3">
<span class="text-cp leading-none font-medium text-cp-text-secondary">调度</span>
<BaseSwitch
v-model="enabled"
label="切换账号调度"
:disabled="disabled"
/>
</div>
<div class="flex min-h-6 items-center justify-between gap-3">
<span class="text-cp leading-none font-medium text-cp-text-secondary">调度</span>
<BaseSwitch
v-model="enabled"
label="切换账号调度"
:disabled="disabled"
/>
</div>
<div class="grid gap-4 sm:grid-cols-2">
<BaseFormItem label="并发限制">
<BaseInput
v-model="concurrencyLimit"
aria-label="账号并发限制"
type="number"
min="1"
max="4294967295"
placeholder="留空使用默认值"
:disabled="disabled"
/>
</BaseFormItem>
<BaseFormItem label="权重">
<BaseInput
v-model="weight"
aria-label="账号调度权重"
type="number"
min="1"
max="100"
placeholder="越高越优先,最大 100"
:disabled="disabled"
/>
</BaseFormItem>
</div>
<BaseFormItem label="所属分组">
<AccountGroupCheckboxGrid
v-model="selectedGroupIds"
:groups="groups"
:loading="groupsLoading"
<div class="grid gap-4 sm:grid-cols-2">
<BaseFormItem label="并发限制">
<BaseInput
v-model="concurrencyLimit"
aria-label="账号并发限制"
type="number"
min="1"
max="4294967295"
placeholder="留空使用默认值"
:disabled="disabled"
/>
</BaseFormItem>
<AccountProxyField v-model:mode="proxyMode" v-model:proxy-id="proxyId" :preserve="preserveProxy" :error="proxyError" :endpoint="endpoint" :account-id="accountId" :disabled="disabled" />
</template>
<BaseFormItem label="权重">
<BaseInput
v-model="weight"
aria-label="账号调度权重"
type="number"
min="1"
max="100"
placeholder="越高越优先,最大 100"
:disabled="disabled"
/>
</BaseFormItem>
</div>
<BaseFormItem label="所属分组">
<AccountGroupCheckboxGrid
v-model="selectedGroupIds"
:groups="groups"
:loading="groupsLoading"
:disabled="disabled"
/>
</BaseFormItem>
<AccountProxyField v-model:mode="proxyMode" v-model:proxy-id="proxyId" :preserve="preserveProxy" :error="proxyError" :endpoint="endpoint" :account-id="accountId" :disabled="disabled" />
</div>
</template>
@@ -1,7 +1,7 @@
import type { Ref } from 'vue'
import type { AccountModelAccess, getAccounts } from '@/api'
import { ref, shallowRef, watch } from 'vue'
import { computed, ref, shallowRef, watch } from 'vue'
import { batchUpdateAccounts } from '@/api'
import { toast } from '@/components/base/BaseToast'
import { useAsyncAction } from '@/composables/useAsyncAction'
@@ -22,13 +22,25 @@ export function useAccountBatchEditor(options: {
const concurrencyLimit = shallowRef('')
const weight = shallowRef('1')
const modelAccess = ref<AccountModelAccess | undefined>()
const updateScheduling = shallowRef(false)
const editedFields = ref(new Set<'enabled' | 'concurrencyLimit' | 'weight' | 'groupIds'>())
const catalogAccountId = shallowRef<string>()
const proxyMode = shallowRef('preserve')
const proxyId = shallowRef('')
const selectedGroupIds = ref<string[]>([])
const saveAction = useAsyncAction()
const saving = saveAction.loading
const hasChanges = computed(() => Boolean(modelAccess.value) || editedFields.value.size > 0 || proxyMode.value !== 'preserve')
// 未操作的字段保持每个账号原值,避免展开表单就覆盖混合设置。
watch([schedulingEnabled, concurrencyLimit, weight, selectedGroupIds], (values, previous) => {
if (!showBatchEditModal.value || saving.value)
return
const fields = ['enabled', 'concurrencyLimit', 'weight', 'groupIds'] as const
fields.forEach((field, index) => {
if (values[index] !== previous[index])
editedFields.value.add(field)
})
}, { flush: 'sync' })
function open() {
const accounts = selectedAccounts()
@@ -36,7 +48,7 @@ export function useAccountBatchEditor(options: {
return
modelAccess.value = undefined
updateScheduling.value = false
editedFields.value.clear()
catalogAccountId.value = accounts[0]?.id
schedulingEnabled.value = accounts.every(account => account.enabled)
proxyMode.value = 'preserve'
@@ -55,12 +67,12 @@ export function useAccountBatchEditor(options: {
toast.warning(modelError)
return
}
if (!updateScheduling.value && !modelAccess.value) {
if (!hasChanges.value) {
toast.warning('请选择需要更新的设置')
return
}
const scheduling = parseAccountSchedulingForm(updateScheduling.value ? concurrencyLimit.value : '', updateScheduling.value ? weight.value : '1')
if (updateScheduling.value && proxyMode.value === 'proxy' && !proxyId.value.trim()) {
const scheduling = parseAccountSchedulingForm(editedFields.value.has('concurrencyLimit') ? concurrencyLimit.value : '', editedFields.value.has('weight') ? weight.value : '1')
if (proxyMode.value === 'proxy' && !proxyId.value.trim()) {
toast.warning('请选择已通过测试的代理')
return
}
@@ -74,15 +86,11 @@ export function useAccountBatchEditor(options: {
await batchUpdateAccounts({
accountIds,
modelAccess: modelAccess.value,
...(updateScheduling.value
? {
outboundProxyId: proxyMode.value === 'preserve' ? undefined : proxyMode.value === 'direct' ? '' : proxyId.value.trim(),
enabled: schedulingEnabled.value,
concurrencyLimit: scheduling.values.concurrencyLimit,
weight: scheduling.values.weight,
groupIds: [...new Set(selectedGroupIds.value)],
}
: {}),
outboundProxyId: proxyMode.value === 'preserve' ? undefined : proxyMode.value === 'direct' ? '' : proxyId.value.trim(),
enabled: editedFields.value.has('enabled') ? schedulingEnabled.value : undefined,
concurrencyLimit: editedFields.value.has('concurrencyLimit') ? scheduling.values.concurrencyLimit : undefined,
weight: editedFields.value.has('weight') ? scheduling.values.weight : undefined,
groupIds: editedFields.value.has('groupIds') ? [...new Set(selectedGroupIds.value)] : undefined,
})
showBatchEditModal.value = false
options.selectedIds.value = new Set()
@@ -132,7 +140,7 @@ export function useAccountBatchEditor(options: {
concurrencyLimit,
weight,
modelAccess,
updateScheduling,
hasChanges,
catalogAccountId,
proxyMode,
proxyId,
+2 -2
View File
@@ -129,7 +129,7 @@ const {
concurrencyLimit: batchConcurrencyLimit,
weight: batchWeight,
modelAccess: batchModelAccess,
updateScheduling: batchUpdateScheduling,
hasChanges: batchHasChanges,
catalogAccountId: batchCatalogAccountId,
proxyMode: batchProxyMode,
proxyId: batchProxyId,
@@ -375,7 +375,6 @@ const {
v-model:concurrency-limit="batchConcurrencyLimit"
v-model:weight="batchWeight"
v-model:model-access="batchModelAccess"
v-model:update-scheduling="batchUpdateScheduling"
v-model:proxy-mode="batchProxyMode"
v-model:proxy-id="batchProxyId"
v-model:selected-group-ids="batchGroupIds"
@@ -384,6 +383,7 @@ const {
:groups="groups"
:groups-loading="groupsLoading"
:saving="savingBatchEdit"
:has-changes="batchHasChanges"
@save="saveBatchEdit"
/>
@@ -25,8 +25,8 @@ const metrics = computed(() => [
<section class="grid min-w-0 gap-4 xl:grid-cols-[minmax(340px,0.95fr)_minmax(0,3fr)]" aria-label="用量汇总">
<BaseCard as="article" padding="compact" class="flex min-h-28 min-w-0 flex-col justify-between gap-4">
<div class="flex min-w-0 flex-1 items-center gap-3">
<BaseMotionIcon class="inline-flex size-8.5 shrink-0 items-center justify-center rounded-cp-lg bg-cp-info-container text-cp-info-on-container" aria-hidden="true">
<Zap :size="18" />
<BaseMotionIcon class="inline-flex size-9 shrink-0 items-center relative -top-0.5 justify-center rounded-cp-lg bg-cp-info-container text-cp-info-on-container" aria-hidden="true">
<Zap :size="19" />
</BaseMotionIcon>
<span class="sr-only">消耗 Tokens</span>
<div class="flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-1">
@@ -9,11 +9,11 @@ defineProps<{
</script>
<template>
<div class="flex flex-col gap-0.5">
<span class="text-cp font-bold text-cp-text">
<div class="flex min-w-0 flex-col gap-0.5">
<span class="truncate text-cp font-bold text-cp-text" :title="apiKey.name">
{{ apiKey.name }}
</span>
<span v-if="apiKey.label" class="text-cp-sm font-emphasis text-cp-text-tertiary">
<span v-if="apiKey.label" class="truncate text-cp-sm font-emphasis text-cp-text-tertiary" :title="apiKey.label">
{{ apiKey.label }}
</span>
</div>