From eb8a01541afc64ff12f740ad150dea78addf190d Mon Sep 17 00:00:00 2001 From: Zyy Date: Thu, 17 Sep 2026 18:25:31 +0800 Subject: [PATCH] refactor(ui): refine settings and account interactions Split settings into focused cards while retaining the original tabs and page layout. Simplify save feedback and help controls, preserve settings drafts, and align account dialog and model restriction widths. Keep select option scrolling tied to keyboard navigation and focus so hovering does not shift the dropdown. Co-authored-by: Codex --- .../src/components/base/BaseModal/index.vue | 11 +- frontend/src/components/base/BaseSelect.vue | 15 +- .../AccountCreateModal/presenter.ts | 2 +- .../accounts/components/AccountEditModal.vue | 2 +- .../components/AccountModelAccessField.vue | 2 +- .../components/AccountAutoFreezeCard.vue | 32 ++- .../settings/components/ModelAliasesCard.vue | 21 +- .../settings/components/RequestQueueCard.vue | 26 +++ .../components/ResponseBodyLimitCard.vue | 22 ++ .../components/RotationStrategyCard.vue | 9 +- .../components/RuntimeSettingsCard.vue | 73 +------ .../settings/components/TokenRefreshCard.vue | 31 +++ .../backup/SettingsBackupSection.vue | 21 +- .../components/ClientVersionPolicyCard.vue | 21 +- .../settings/composables/useSettingsForm.ts | 21 ++ frontend/src/views/settings/index.vue | 188 +++++++++--------- 16 files changed, 277 insertions(+), 220 deletions(-) create mode 100644 frontend/src/views/settings/components/RequestQueueCard.vue create mode 100644 frontend/src/views/settings/components/ResponseBodyLimitCard.vue create mode 100644 frontend/src/views/settings/components/TokenRefreshCard.vue diff --git a/frontend/src/components/base/BaseModal/index.vue b/frontend/src/components/base/BaseModal/index.vue index f90dd44ab..e9981496c 100644 --- a/frontend/src/components/base/BaseModal/index.vue +++ b/frontend/src/components/base/BaseModal/index.vue @@ -8,7 +8,7 @@ import BaseScrollbar from '../BaseScrollbar.vue' import { lockBodyScroll, unlockBodyScroll } from './bodyScrollLock' import { useModalDrag } from './useModalDrag' -type ModalSize = 'sm' | 'md' | 'lg' | 'xl' +type ModalSize = 'sm' | 'md' | 'md-wide' | 'lg' | 'xl' type ModalTone = 'neutral' | 'info' | 'warning' | 'danger' | 'success' const props = withDefaults( @@ -58,10 +58,11 @@ const focusableSelector = [ ].join(',') const sizeClasses: Record = { - sm: 'max-w-md', - md: 'max-w-xl', - lg: 'max-w-3xl', - xl: 'max-w-5xl', + 'sm': 'max-w-md', + 'md': 'max-w-xl', + 'md-wide': 'max-w-2xl', + 'lg': 'max-w-3xl', + 'xl': 'max-w-5xl', } const iconMap = { diff --git a/frontend/src/components/base/BaseSelect.vue b/frontend/src/components/base/BaseSelect.vue index fe0e6e691..e374c95bb 100644 --- a/frontend/src/components/base/BaseSelect.vue +++ b/frontend/src/components/base/BaseSelect.vue @@ -210,6 +210,17 @@ function moveActive(delta: number) { const current = indexes.indexOf(activeIndex.value) const next = current === -1 ? (delta > 0 ? 0 : indexes.length - 1) : current + delta activeIndex.value = indexes[(next + indexes.length) % indexes.length] + // 只有键盘导航主动定位;鼠标悬停不能把半露出的选项滚入视口。 + scrollActiveIntoView() +} + +function handleOptionFocus(index: number) { + const option = props.options[index] + if (!option || option.disabled) + return + + activeIndex.value = index + scrollActiveIntoView() } function chooseOption(option: SelectOption, index: number) { @@ -282,8 +293,6 @@ function optionClasses(option: SelectOption, index: number) { ] } -watch(activeIndex, scrollActiveIntoView, { flush: 'post' }) - watch( () => [props.options, props.size, model.value], async () => { @@ -382,7 +391,7 @@ useEventListener(window, 'scroll', updatePopoverPositionThrottled, { capture: tr :disabled="option.disabled" :class="optionClasses(option, index)" @mouseenter="activeIndex = option.disabled ? activeIndex : index" - @focus="activeIndex = option.disabled ? activeIndex : index" + @focus="handleOptionFocus(index)" @mousedown.prevent @click="chooseOption(option, index)" > diff --git a/frontend/src/views/accounts/components/AccountCreateModal/presenter.ts b/frontend/src/views/accounts/components/AccountCreateModal/presenter.ts index 41bff4206..1e67a7c13 100644 --- a/frontend/src/views/accounts/components/AccountCreateModal/presenter.ts +++ b/frontend/src/views/accounts/components/AccountCreateModal/presenter.ts @@ -59,7 +59,7 @@ function resolveModal( title: '账号设置', description: '设置将应用于本次导入的账号', tone: 'neutral' as const, - size: 'md' as const, + size: 'md-wide' as const, } } diff --git a/frontend/src/views/accounts/components/AccountEditModal.vue b/frontend/src/views/accounts/components/AccountEditModal.vue index 84e58721e..201c99887 100644 --- a/frontend/src/views/accounts/components/AccountEditModal.vue +++ b/frontend/src/views/accounts/components/AccountEditModal.vue @@ -42,7 +42,7 @@ const selectedGroupIds = defineModel('selectedGroupIds', { required: t
diff --git a/frontend/src/views/accounts/components/AccountModelAccessField.vue b/frontend/src/views/accounts/components/AccountModelAccessField.vue index 50b6d90ab..c6f296c87 100644 --- a/frontend/src/views/accounts/components/AccountModelAccessField.vue +++ b/frontend/src/views/accounts/components/AccountModelAccessField.vue @@ -125,7 +125,7 @@ watch(search, () => { - +