From 9c5fbdba70eed5575cb102922e29bf221e3c9c7d Mon Sep 17 00:00:00 2001 From: Zyy Date: Mon, 5 Oct 2026 10:34:10 +0800 Subject: [PATCH] refactor(frontend): clarify module boundaries and simplify state Move shared components and helpers to their actual owners, standardize component directory names, and use concise names for common utilities. Remove redundant wrappers, copied API models, and duplicate state. Separate API key editing from key usage, isolate settings drafts, reuse paged queries, and tie debounced queries and requests to their scopes. Validated with frontend lint, type checking and production build, local import checks, and 15 temporary behavioral regression groups. Co-authored-by: Codex --- .../components/AnimatedMetricValue.vue | 0 .../account}/AccountPlanBadge.vue | 2 +- .../AccountRequestTimeline.vue | 2 +- .../account/account-usage-window}/index.vue | 8 +- .../account-usage-window}/presenter.ts | 4 +- frontend/src/components/charts/BaseChart.vue | 14 +- .../{SchemaForm => schema-form}/index.vue | 7 +- .../{SchemaForm => schema-form}/schema.ts | 0 .../usage}/HealthTimelinePointPopover.vue | 6 +- .../usage}/RequestHealthTimelineCard.vue | 20 +- .../usage}/UsageBillingCell.vue | 10 +- .../usage}/UsageClientIpCell.vue | 2 +- .../usage}/UsageDetailPopover.vue | 0 .../usage}/UsageLatencyCell.vue | 8 +- .../usage}/UsageModelCell.vue | 7 +- .../usage}/UsageReasoningEffortCell.vue | 10 +- .../usage}/UsageRecordsTable.vue | 31 +- .../usage}/UsageTokenCell.vue | 10 +- .../usage}/UsageTransportBadge.vue | 2 +- .../src/components/usage/shared/columns.ts | 35 ++ .../src/components/usage/shared/health.ts | 68 +++ .../src/components/usage/shared/presenter.ts | 154 +++++++ .../src/composables/useAccountGroupCatalog.ts | 17 +- frontend/src/composables/useAsyncAction.ts | 5 +- frontend/src/composables/useProxyCatalog.ts | 18 +- .../src/composables/useStablePagedQuery.ts | 2 + frontend/src/layout/components/AppSidebar.vue | 2 +- .../index.vue | 0 .../presenter.ts | 0 frontend/src/layout/index.vue | 2 +- frontend/src/utils/client.ts | 12 +- .../utils/visualTone.ts => utils/color.ts} | 9 +- frontend/src/utils/data.ts | 41 +- frontend/src/utils/format.ts | 48 ++- frontend/src/utils/location.ts | 16 + .../utils/navigation.ts => utils/plugin.ts} | 4 +- frontend/src/utils/providers.ts | 11 +- .../components/AccountConnectionTestModal.vue | 2 +- .../accounts/components/AccountEditModal.vue | 8 +- .../components/AccountIdentityCell.vue | 12 +- .../components/AccountTableActions.vue | 17 +- .../accounts/components/AccountUsagePanel.vue | 6 +- .../AccountImportFields.vue | 0 .../AccountOAuthFields.vue | 0 .../AccountProviderChooser.vue | 2 +- .../AccountSetupFields.vue | 2 +- .../index.vue | 12 +- .../presenter.ts | 19 +- .../TaskDetail.vue | 0 .../index.vue | 0 .../presenter.ts | 0 .../ActivityInsights.vue | 0 .../Metrics.vue | 0 .../ProfileHero.vue | 10 +- .../Skeleton.vue | 0 .../Subscription.vue | 0 .../TokenActivity.vue | 4 +- .../account-profile-modal/activity.ts} | 0 .../index.vue | 5 +- .../ForecastCapacity.vue | 0 .../Skeleton.vue | 0 .../index.vue | 4 +- .../Credits.vue | 0 .../Entry.vue | 6 +- .../ResetCredits.vue | 0 .../UsageLimits.vue | 4 +- .../index.vue | 13 +- .../Entry.vue | 8 +- .../WindowGroup.vue | 4 +- .../index.vue | 8 +- .../presenter.ts | 5 +- .../index.vue | 4 +- .../presenter.ts | 14 +- .../account-status-badge/useStatusClock.ts} | 2 +- .../composables/useAccountBatchEditor.ts | 14 +- .../accounts/composables/useAccountEditor.ts | 8 +- .../composables/useAccountMutations.ts | 24 +- .../composables/useAccountOnboarding.ts | 11 +- .../accounts/composables/useAccountsQuery.ts | 17 +- .../accounts/composables/useAccountsTable.ts | 6 +- frontend/src/views/accounts/constants.ts | 21 +- frontend/src/views/accounts/index.vue | 16 +- .../model.ts => utils/accountCreate.ts} | 25 +- .../src/views/accounts/utils/accountImport.ts | 2 +- .../views/accounts/utils/schedulingForm.ts | 2 +- .../components/AccountOverviewCard.vue | 4 +- .../components/DashboardAccountIdentity.vue | 6 +- .../dashboard/components/DashboardContent.vue | 4 +- .../views/dashboard/components/MetricCard.vue | 4 +- .../dashboard/components/RequestTrendCard.vue | 2 +- .../dashboard/components/UsageRecordCard.vue | 6 +- .../dashboard/composables/useDashboard.ts | 378 +--------------- .../composables/useRequestTrendChart.ts | 2 +- frontend/src/views/dashboard/constants.ts | 95 +--- frontend/src/views/dashboard/presenter.ts | 370 ++++++++++++++++ .../components/AccountGroupMetricsCell.vue | 2 +- .../groups/composables/useAccountGroups.ts | 30 +- .../key-usage/components/KeyUsageRecords.vue | 10 +- .../key-usage/components/KeyUsageSummary.vue | 2 +- .../key-usage/composables/useKeyUsage.ts | 2 - frontend/src/views/key-usage/index.vue | 2 +- frontend/src/views/key-usage/utils/format.ts | 5 - frontend/src/views/key-usage/utils/metrics.ts | 6 +- .../views/keys/components/ApiKeyActions.vue | 19 +- .../keys/components/ApiKeyCreatedModal.vue | 62 +++ ...KeyCreateModal.vue => ApiKeyFormModal.vue} | 99 ++--- .../keys/components/ApiKeyIdentityCell.vue | 6 +- .../views/keys/composables/useApiKeyEditor.ts | 182 ++++++++ .../keys/composables/useApiKeyMutations.ts | 268 +----------- .../views/keys/composables/useApiKeyUse.ts | 95 ++-- .../views/keys/composables/useApiKeysQuery.ts | 25 +- frontend/src/views/keys/constants.ts | 9 +- frontend/src/views/keys/index.vue | 77 ++-- .../components/PluginCapabilityTags.vue | 4 +- .../plugins/components/PluginCatalogPanel.vue | 3 +- .../components/PluginConfigurationFields.vue | 18 +- .../components/PluginConfigurationModal.vue | 17 +- .../components/PluginConfigurationSummary.vue | 3 +- .../plugins/components/PluginDetailModal.vue | 5 +- .../components/PluginExtensionsPanel.vue | 2 +- .../plugins/components/PluginInstallModal.vue | 4 +- .../components/PluginLegacyConfigurations.vue | 3 +- .../plugins/components/PluginManagement.vue | 2 +- .../views/plugins/components/PluginPage.vue | 2 +- .../plugins/components/PluginVersionCard.vue | 3 +- .../plugins/composables/usePluginActions.ts | 36 -- .../composables/usePluginArtifactActions.ts | 7 +- .../composables/usePluginCredentials.ts | 28 +- .../composables/usePluginInstallation.ts | 32 +- .../plugins/composables/usePluginInstances.ts | 32 +- .../composables/usePluginManagement.ts | 25 +- .../plugins/composables/usePluginUninstall.ts | 5 +- .../composables/usePluginUpdateCheck.ts | 5 +- .../plugins/composables/usePluginVersions.ts | 15 +- frontend/src/views/plugins/constants.ts | 53 +++ .../src/views/plugins/management/frame.ts | 2 +- frontend/src/views/plugins/utils/actions.ts | 14 + frontend/src/views/plugins/utils/catalog.ts | 10 - frontend/src/views/plugins/utils/model.ts | 58 +-- .../proxies/components/ProxyAccountsModal.vue | 4 +- .../views/proxies/composables/useProxies.ts | 258 +++++++++++ .../proxies/composables/useProxyAccounts.ts | 8 +- frontend/src/views/proxies/constants.ts | 12 + frontend/src/views/proxies/index.vue | 266 ++---------- .../components/backup/BackupScheduleCard.vue | 18 +- .../components/backup/BackupStorageCard.vue | 27 +- .../backup/SettingsBackupSection.vue | 15 +- .../settings/composables/useBackupSettings.ts | 95 ++-- .../settings/composables/useSettingsForm.ts | 49 +-- .../components/ThemeDashboardPreview.vue | 2 +- .../views/theme/composables/useThemeEditor.ts | 14 +- .../views/usage/components/OpsErrorPanel.vue | 6 +- .../views/usage/components/UsageCostCard.vue | 12 +- .../usage/components/UsageDiagnosticCard.vue | 6 +- .../usage/components/UsageHealthCard.vue | 6 +- .../usage/components/UsagePerformanceCard.vue | 7 +- .../components/UsageRecordDetailModal.vue | 24 +- .../usage/composables/useOpsErrorsTable.ts | 21 +- .../usage/composables/useUsageRecordDetail.ts | 9 +- .../usage/composables/useUsageRecordsTable.ts | 85 ++-- .../usage/composables/useUsageTimeRange.ts | 2 +- frontend/src/views/usage/constants.ts | 38 +- frontend/src/views/usage/index.vue | 8 +- frontend/src/views/usage/utils/chart.ts | 30 +- frontend/src/views/usage/utils/detail.ts | 77 ++++ frontend/src/views/usage/utils/format.ts | 78 ---- frontend/src/views/usage/utils/records.ts | 404 ------------------ 167 files changed, 2196 insertions(+), 2449 deletions(-) rename frontend/src/{views/dashboard => }/components/AnimatedMetricValue.vue (100%) rename frontend/src/{views/accounts/components => components/account}/AccountPlanBadge.vue (97%) rename frontend/src/{views/accounts/components/AccountUsageWindow => components/account/account-usage-window}/AccountRequestTimeline.vue (88%) rename frontend/src/{views/accounts/components/AccountUsageWindow => components/account/account-usage-window}/index.vue (91%) rename frontend/src/{views/accounts/components/AccountUsageWindow => components/account/account-usage-window}/presenter.ts (98%) rename frontend/src/components/{SchemaForm => schema-form}/index.vue (96%) rename frontend/src/components/{SchemaForm => schema-form}/schema.ts (100%) rename frontend/src/{views/dashboard/components => components/usage}/HealthTimelinePointPopover.vue (96%) rename frontend/src/{views/dashboard/components => components/usage}/RequestHealthTimelineCard.vue (92%) rename frontend/src/{views/usage/components => components/usage}/UsageBillingCell.vue (93%) rename frontend/src/{views/usage/components => components/usage}/UsageClientIpCell.vue (90%) rename frontend/src/{views/usage/components => components/usage}/UsageDetailPopover.vue (100%) rename frontend/src/{views/usage/components => components/usage}/UsageLatencyCell.vue (90%) rename frontend/src/{views/usage/components => components/usage}/UsageModelCell.vue (88%) rename frontend/src/{views/usage/components => components/usage}/UsageReasoningEffortCell.vue (74%) rename frontend/src/{views/usage/components => components/usage}/UsageRecordsTable.vue (81%) rename frontend/src/{views/usage/components => components/usage}/UsageTokenCell.vue (88%) rename frontend/src/{views/usage/components => components/usage}/UsageTransportBadge.vue (80%) create mode 100644 frontend/src/components/usage/shared/columns.ts create mode 100644 frontend/src/components/usage/shared/health.ts create mode 100644 frontend/src/components/usage/shared/presenter.ts rename frontend/src/layout/components/{SystemUpdateModal => system-update-modal}/index.vue (100%) rename frontend/src/layout/components/{SystemUpdateModal => system-update-modal}/presenter.ts (100%) rename frontend/src/{views/accounts/utils/visualTone.ts => utils/color.ts} (75%) create mode 100644 frontend/src/utils/location.ts rename frontend/src/{views/plugins/utils/navigation.ts => utils/plugin.ts} (83%) rename frontend/src/views/accounts/components/{AccountCreateModal => account-create-modal}/AccountImportFields.vue (100%) rename frontend/src/views/accounts/components/{AccountCreateModal => account-create-modal}/AccountOAuthFields.vue (100%) rename frontend/src/views/accounts/components/{AccountCreateModal => account-create-modal}/AccountProviderChooser.vue (94%) rename frontend/src/views/accounts/components/{AccountCreateModal => account-create-modal}/AccountSetupFields.vue (95%) rename frontend/src/views/accounts/components/{AccountCreateModal => account-create-modal}/index.vue (95%) rename frontend/src/views/accounts/components/{AccountCreateModal => account-create-modal}/presenter.ts (83%) rename frontend/src/views/accounts/components/{AccountImportTasks => account-import-tasks}/TaskDetail.vue (100%) rename frontend/src/views/accounts/components/{AccountImportTasks => account-import-tasks}/index.vue (100%) rename frontend/src/views/accounts/components/{AccountImportTasks => account-import-tasks}/presenter.ts (100%) rename frontend/src/views/accounts/components/{AccountProfileModal => account-profile-modal}/ActivityInsights.vue (100%) rename frontend/src/views/accounts/components/{AccountProfileModal => account-profile-modal}/Metrics.vue (100%) rename frontend/src/views/accounts/components/{AccountProfileModal => account-profile-modal}/ProfileHero.vue (91%) rename frontend/src/views/accounts/components/{AccountProfileModal => account-profile-modal}/Skeleton.vue (100%) rename frontend/src/views/accounts/components/{AccountProfileModal => account-profile-modal}/Subscription.vue (100%) rename frontend/src/views/accounts/components/{AccountProfileModal => account-profile-modal}/TokenActivity.vue (97%) rename frontend/src/views/accounts/{utils/accountProfileStatistics.ts => components/account-profile-modal/activity.ts} (100%) rename frontend/src/views/accounts/components/{AccountProfileModal => account-profile-modal}/index.vue (97%) rename frontend/src/views/accounts/components/{AccountQuotaForecastModal => account-quota-forecast-modal}/ForecastCapacity.vue (100%) rename frontend/src/views/accounts/components/{AccountQuotaForecastModal => account-quota-forecast-modal}/Skeleton.vue (100%) rename frontend/src/views/accounts/components/{AccountQuotaForecastModal => account-quota-forecast-modal}/index.vue (98%) rename frontend/src/views/accounts/components/{AccountQuotaPanel => account-quota-panel}/Credits.vue (100%) rename frontend/src/views/accounts/components/{AccountQuotaPanel => account-quota-panel}/Entry.vue (95%) rename frontend/src/views/accounts/components/{AccountQuotaPanel => account-quota-panel}/ResetCredits.vue (100%) rename frontend/src/views/accounts/components/{AccountQuotaPanel => account-quota-panel}/UsageLimits.vue (94%) rename frontend/src/views/accounts/components/{AccountQuotaPanel => account-quota-panel}/index.vue (93%) rename frontend/src/views/accounts/components/{AccountQuotaSummaryCell => account-quota-summary-cell}/Entry.vue (95%) rename frontend/src/views/accounts/components/{AccountQuotaSummaryCell => account-quota-summary-cell}/WindowGroup.vue (94%) rename frontend/src/views/accounts/components/{AccountQuotaSummaryCell => account-quota-summary-cell}/index.vue (95%) rename frontend/src/views/accounts/components/{AccountQuotaSummaryCell => account-quota-summary-cell}/presenter.ts (92%) rename frontend/src/views/accounts/components/{AccountStatusBadge => account-status-badge}/index.vue (98%) rename frontend/src/views/accounts/components/{AccountStatusBadge => account-status-badge}/presenter.ts (93%) rename frontend/src/{composables/useUiClock.ts => views/accounts/components/account-status-badge/useStatusClock.ts} (72%) rename frontend/src/views/accounts/{components/AccountCreateModal/model.ts => utils/accountCreate.ts} (71%) create mode 100644 frontend/src/views/dashboard/presenter.ts create mode 100644 frontend/src/views/keys/components/ApiKeyCreatedModal.vue rename frontend/src/views/keys/components/{ApiKeyCreateModal.vue => ApiKeyFormModal.vue} (60%) create mode 100644 frontend/src/views/keys/composables/useApiKeyEditor.ts delete mode 100644 frontend/src/views/plugins/composables/usePluginActions.ts create mode 100644 frontend/src/views/plugins/constants.ts create mode 100644 frontend/src/views/plugins/utils/actions.ts create mode 100644 frontend/src/views/proxies/composables/useProxies.ts create mode 100644 frontend/src/views/proxies/constants.ts delete mode 100644 frontend/src/views/usage/utils/format.ts delete mode 100644 frontend/src/views/usage/utils/records.ts diff --git a/frontend/src/views/dashboard/components/AnimatedMetricValue.vue b/frontend/src/components/AnimatedMetricValue.vue similarity index 100% rename from frontend/src/views/dashboard/components/AnimatedMetricValue.vue rename to frontend/src/components/AnimatedMetricValue.vue diff --git a/frontend/src/views/accounts/components/AccountPlanBadge.vue b/frontend/src/components/account/AccountPlanBadge.vue similarity index 97% rename from frontend/src/views/accounts/components/AccountPlanBadge.vue rename to frontend/src/components/account/AccountPlanBadge.vue index 906717c18..0f053d6f5 100644 --- a/frontend/src/views/accounts/components/AccountPlanBadge.vue +++ b/frontend/src/components/account/AccountPlanBadge.vue @@ -1,7 +1,7 @@ @@ -15,7 +15,7 @@ defineProps<{ > {{ usageReasoningEffort(record) }} import type { BaseTableColumn } from '@codex-proxy/ui' -import type { UsageDisplayRecord } from '../utils/records' +import type { UsageListRecord } from '@/api' + import { BaseTable } from '@codex-proxy/ui' import { Minimize2 } from '@lucide/vue' +import AccountPlanBadge from '@/components/account/AccountPlanBadge.vue' import ProviderIconGroup from '@/components/ProviderIconGroup.vue' -import AccountPlanBadge from '@/views/accounts/components/AccountPlanBadge.vue' +import UsageBillingCell from '@/components/usage/UsageBillingCell.vue' +import UsageClientIpCell from '@/components/usage/UsageClientIpCell.vue' +import UsageLatencyCell from '@/components/usage/UsageLatencyCell.vue' +import UsageModelCell from '@/components/usage/UsageModelCell.vue' +import UsageReasoningEffortCell from '@/components/usage/UsageReasoningEffortCell.vue' +import UsageTokenCell from '@/components/usage/UsageTokenCell.vue' +import UsageTransportBadge from '@/components/usage/UsageTransportBadge.vue' import { usageAccountText, - usageAuthenticationKind, - usageIsCompact, usageUserAgent, -} from '../utils/records' -import UsageBillingCell from './UsageBillingCell.vue' -import UsageClientIpCell from './UsageClientIpCell.vue' -import UsageLatencyCell from './UsageLatencyCell.vue' -import UsageModelCell from './UsageModelCell.vue' -import UsageReasoningEffortCell from './UsageReasoningEffortCell.vue' -import UsageTokenCell from './UsageTokenCell.vue' -import UsageTransportBadge from './UsageTransportBadge.vue' +} from './shared/presenter' // 使用记录表只负责该领域的单元格呈现;筛选与分页由页面组合。 withDefaults( defineProps<{ - columns: BaseTableColumn[] - rows: UsageDisplayRecord[] + columns: BaseTableColumn[] + rows: UsageListRecord[] loading?: boolean emptyText?: string }>(), @@ -53,7 +52,7 @@ withDefaults( @@ -105,7 +104,7 @@ withDefaults(
{{ row.route || '—' }} -import type { UsageDisplayRecord } from '../utils/records' +import type { UsageListRecord } from '@/api' + import { Archive, ArrowDown, ArrowUp } from '@lucide/vue' import { computed } from 'vue' -import { usageTokenDetails } from '../utils/records' -import UsageDetailPopover from './UsageDetailPopover.vue' +import UsageDetailPopover from '@/components/usage/UsageDetailPopover.vue' const props = defineProps<{ - record: Pick + record: Pick }>() -const tokenDetails = computed(() => usageTokenDetails(props.record)) +const tokenDetails = computed(() => props.record.tokenDetails) const tokenItems = computed(() => [ { label: '输入 Token', value: tokenDetails.value.inputTokensDisplay }, { label: '输出 Token', value: tokenDetails.value.outputTokensDisplay }, diff --git a/frontend/src/views/usage/components/UsageTransportBadge.vue b/frontend/src/components/usage/UsageTransportBadge.vue similarity index 80% rename from frontend/src/views/usage/components/UsageTransportBadge.vue rename to frontend/src/components/usage/UsageTransportBadge.vue index e3fcba961..5bc9f7058 100644 --- a/frontend/src/views/usage/components/UsageTransportBadge.vue +++ b/frontend/src/components/usage/UsageTransportBadge.vue @@ -1,5 +1,5 @@ diff --git a/frontend/src/views/keys/components/ApiKeyCreatedModal.vue b/frontend/src/views/keys/components/ApiKeyCreatedModal.vue new file mode 100644 index 000000000..75f74dddd --- /dev/null +++ b/frontend/src/views/keys/components/ApiKeyCreatedModal.vue @@ -0,0 +1,62 @@ + + + diff --git a/frontend/src/views/keys/components/ApiKeyCreateModal.vue b/frontend/src/views/keys/components/ApiKeyFormModal.vue similarity index 60% rename from frontend/src/views/keys/components/ApiKeyCreateModal.vue rename to frontend/src/views/keys/components/ApiKeyFormModal.vue index a14852b9d..09b9c0022 100644 --- a/frontend/src/views/keys/components/ApiKeyCreateModal.vue +++ b/frontend/src/views/keys/components/ApiKeyFormModal.vue @@ -1,9 +1,9 @@ - + + pluginContributionEntries(props.metadata)) +const entries = computed(() => Object.entries(props.metadata.contributes)) const visible = computed(() => entries.value.slice(0, 2)) const hidden = computed(() => entries.value.slice(2)) diff --git a/frontend/src/views/plugins/components/PluginCatalogPanel.vue b/frontend/src/views/plugins/components/PluginCatalogPanel.vue index ccd2b09ea..cfb6698c5 100644 --- a/frontend/src/views/plugins/components/PluginCatalogPanel.vue +++ b/frontend/src/views/plugins/components/PluginCatalogPanel.vue @@ -3,7 +3,8 @@ import type { InstalledPlugin } from '../utils/catalog' import { BaseButton, BaseCard, BaseEmpty, BaseIconButton, BaseInput, BaseScrollbar, BaseSegmented, BaseSelect, BaseTable, BaseTablePagination, BaseTag, defineTableColumns } from '@codex-proxy/ui' import { CircleAlert, LayoutGrid, List, Puzzle, Search, Settings2 } from '@lucide/vue' import { computed, shallowRef, watch } from 'vue' -import { currentPluginInstance, PLUGIN_STATUS_LABELS, pluginStatus, pluginStatusType } from '../utils/catalog' +import { PLUGIN_STATUS_LABELS } from '../constants' +import { currentPluginInstance, pluginStatus, pluginStatusType } from '../utils/catalog' import PluginCapabilityTags from './PluginCapabilityTags.vue' import PluginCompatibilityWarning from './PluginCompatibilityWarning.vue' import PluginIcon from './PluginIcon.vue' diff --git a/frontend/src/views/plugins/components/PluginConfigurationFields.vue b/frontend/src/views/plugins/components/PluginConfigurationFields.vue index ea14aa1ec..f8309d64d 100644 --- a/frontend/src/views/plugins/components/PluginConfigurationFields.vue +++ b/frontend/src/views/plugins/components/PluginConfigurationFields.vue @@ -1,11 +1,12 @@ diff --git a/frontend/src/views/settings/components/backup/BackupScheduleCard.vue b/frontend/src/views/settings/components/backup/BackupScheduleCard.vue index d5c0d89a5..01e6d0f46 100644 --- a/frontend/src/views/settings/components/backup/BackupScheduleCard.vue +++ b/frontend/src/views/settings/components/backup/BackupScheduleCard.vue @@ -11,7 +11,7 @@ interface ScheduleForm { } defineProps<{ - loading: boolean + disabled: boolean saving: boolean storageReady: boolean }>() @@ -21,6 +21,10 @@ const emit = defineEmits<{ }>() const schedule = defineModel('schedule', { required: true }) + +function updateSchedule(key: Key, value: ScheduleForm[Key]) { + schedule.value = { ...schedule.value, [key]: value } +}