refactor: Antigravity/Codex 服务重构为插件化适配器架构

- 将 Antigravity 和 Codex 从独立模块迁移至 src/services/provider/adapters/ 插件体系
- 新增 provider_types 和 oauth_token 模块,移除 maintenance_scheduler 中的 OAuth 定时刷新
- 增强 admin API:扩展 keys 和 provider_query 端点,新增 dashboard 路由
- 大幅增强 ProviderDetailDrawer 组件,新增 AntigravityQuotaDialog
- 改进 handler 基类(chat/cli)和错误分类器
- 优化 fetch_scheduler 和 upstream_fetcher
- 前端 UI 组件清理和优化
- 更新测试以匹配新模块结构
This commit is contained in:
fawney19
2026-02-06 16:37:06 +08:00
parent e01dfee41d
commit b88fb6273b
112 changed files with 5193 additions and 1992 deletions

View File

@@ -39,7 +39,6 @@
<!-- 状态筛选 -->
<Select
v-model="filterStatus"
v-model:open="filterStatusOpen"
>
<SelectTrigger class="w-20 sm:w-28 h-8 text-xs border-border/60">
<SelectValue placeholder="全部状态" />
@@ -58,7 +57,6 @@
<!-- 余额类型筛选 -->
<Select
v-model="filterBalance"
v-model:open="filterBalanceOpen"
>
<SelectTrigger class="w-20 sm:w-28 h-8 text-xs border-border/60">
<SelectValue placeholder="全部类型" />
@@ -759,9 +757,7 @@ const EXPIRY_SOON_DAYS = 7
// 筛选相关
const searchQuery = ref('')
const filterStatus = ref<'all' | 'active' | 'inactive'>('all')
const filterStatusOpen = ref(false)
const filterBalance = ref<'all' | 'limited' | 'unlimited'>('all')
const filterBalanceOpen = ref(false)
const statusFilters = [
{ value: 'all' as const, label: '全部状态' },

View File

@@ -93,7 +93,6 @@
<div class="flex items-center gap-2">
<!-- 状态筛选 -->
<Select
v-model:open="statusSelectOpen"
v-model="filterStatus"
>
<SelectTrigger class="w-28 h-8 text-xs border-border/60">
@@ -895,7 +894,6 @@ const total = ref(0)
const currentPage = ref(1)
const pageSize = ref(20)
const filterStatus = ref('all')
const statusSelectOpen = ref(false)
const filterModel = ref('')
const showDetail = ref(false)
const selectedTask = ref<AsyncTaskDetail | null>(null)

View File

@@ -33,7 +33,6 @@
<!-- 事件类型筛选 -->
<Select
v-model="filters.eventType"
v-model:open="eventTypeSelectOpen"
@update:model-value="handleEventTypeChange"
>
<SelectTrigger class="w-24 sm:w-40 h-8 border-border/60">
@@ -78,7 +77,6 @@
<!-- 时间范围筛选 -->
<Select
v-model="filtersDaysString"
v-model:open="daysSelectOpen"
@update:model-value="handleDaysChange"
>
<SelectTrigger class="w-20 sm:w-28 h-8 border-border/60">
@@ -468,9 +466,6 @@ const selectedLog = ref<AuditLog | null>(null)
// 搜索查询
const searchQuery = ref('')
// Select open state
const eventTypeSelectOpen = ref(false)
const daysSelectOpen = ref(false)
const filters = ref({
username: '',

View File

@@ -46,7 +46,6 @@ const clearingRowAffinityKey = ref<string | null>(null)
const currentPage = ref(1)
const pageSize = ref(20)
const currentTime = ref(Math.floor(Date.now() / 1000))
const analysisHoursSelectOpen = ref(false)
// ==================== 模型映射缓存 ====================
@@ -1060,7 +1059,6 @@ onBeforeUnmount(() => {
<div class="flex flex-wrap items-center gap-2">
<Select
v-model="analysisHours"
v-model:open="analysisHoursSelectOpen"
>
<SelectTrigger class="w-24 sm:w-28 h-8">
<SelectValue placeholder="时间段" />

View File

@@ -159,7 +159,6 @@
</Label>
<Select
v-model="smtpEncryption"
v-model:open="smtpEncryptionSelectOpen"
>
<SelectTrigger
id="smtp-encryption"
@@ -239,7 +238,6 @@
</Label>
<Select
v-model="emailConfig.email_suffix_mode"
v-model:open="emailSuffixModeSelectOpen"
:disabled="!requireEmailVerification"
>
<SelectTrigger
@@ -509,8 +507,6 @@ interface EmailConfig {
const smtpSaveLoading = ref(false)
const emailVerificationSaveLoading = ref(false)
const smtpEncryptionSelectOpen = ref(false)
const emailSuffixModeSelectOpen = ref(false)
const testSmtpLoading = ref(false)
const smtpPasswordIsSet = ref(false)
const requireEmailVerification = ref(false) // 是否开启了邮箱验证

View File

@@ -565,6 +565,7 @@
<ProviderFormDialog
v-model="providerDialogOpen"
:provider="providerToEdit"
:max-priority="maxProviderPriority"
@provider-created="handleProviderAdded"
@provider-updated="handleProviderUpdated"
/>
@@ -672,6 +673,13 @@ const priorityModeConfig = computed(() => {
}
})
// 当前已有提供商的最大优先级
const maxProviderPriority = computed(() => {
if (providers.value.length === 0) return undefined
const priorities = providers.value.map(p => p.provider_priority).filter(v => typeof v === 'number' && Number.isFinite(v))
return priorities.length > 0 ? Math.max(...priorities) : undefined
})
// 筛选后的提供商列表
const filteredProviders = computed(() => {
let result = [...providers.value]

View File

@@ -234,7 +234,6 @@
</Label>
<Select
v-model="systemConfig.request_record_level"
v-model:open="logLevelSelectOpen"
>
<SelectTrigger
id="request-log-level"
@@ -539,7 +538,6 @@
>
<Clock class="w-4 h-4 text-muted-foreground" />
<Select
v-model:open="task.hourSelectOpen.value"
:model-value="task.hour"
@update:model-value="(val: string) => task.updateTime(val, task.minute)"
>
@@ -558,7 +556,6 @@
</Select>
<span class="text-sm text-muted-foreground">:</span>
<Select
v-model:open="task.minuteSelectOpen.value"
:model-value="task.minute"
@update:model-value="(val: string) => task.updateTime(task.hour, val)"
>
@@ -1050,7 +1047,6 @@ interface SystemConfig {
const basicConfigLoading = ref(false)
const logConfigLoading = ref(false)
const cleanupConfigLoading = ref(false)
const logLevelSelectOpen = ref(false)
// 导出/导入相关
const exportLoading = ref(false)
@@ -1382,8 +1378,6 @@ async function handleProviderCheckinToggle(enabled: boolean) {
const previousCheckinTime = ref('')
const checkinConfigLoading = ref(false)
const quotaResetConfigLoading = ref(false)
const checkinHourSelectOpen = ref(false)
const checkinMinuteSelectOpen = ref(false)
// 解析签到时间的小时和分钟
const checkinHour = computed(() => {
@@ -1444,14 +1438,8 @@ async function handleOAuthTokenRefreshToggle(enabled: boolean) {
}
}
// OAuth Token 刷新(无时间配置,占位 ref
const oauthRefreshHourSelectOpen = ref(false)
const oauthRefreshMinuteSelectOpen = ref(false)
// 用户配额重置时间相关
const previousUserQuotaResetTime = ref('')
const userQuotaResetHourSelectOpen = ref(false)
const userQuotaResetMinuteSelectOpen = ref(false)
const previousUserQuotaResetIntervalDays = ref(1)
const userQuotaResetHour = computed(() => {
@@ -1493,8 +1481,6 @@ const scheduledTasks = computed(() => [
hasTimeConfig: true,
hour: checkinHour.value,
minute: checkinMinute.value,
hourSelectOpen: checkinHourSelectOpen,
minuteSelectOpen: checkinMinuteSelectOpen,
updateTime: updateCheckinTime,
hasChanges: hasCheckinTimeChanged.value,
loading: checkinConfigLoading.value,
@@ -1510,8 +1496,6 @@ const scheduledTasks = computed(() => [
hasTimeConfig: true,
hour: userQuotaResetHour.value,
minute: userQuotaResetMinute.value,
hourSelectOpen: userQuotaResetHourSelectOpen,
minuteSelectOpen: userQuotaResetMinuteSelectOpen,
updateTime: updateUserQuotaResetTime,
hasChanges: hasQuotaResetConfigChanged.value,
loading: quotaResetConfigLoading.value,
@@ -1527,8 +1511,6 @@ const scheduledTasks = computed(() => [
hasTimeConfig: false,
hour: '',
minute: '',
hourSelectOpen: oauthRefreshHourSelectOpen,
minuteSelectOpen: oauthRefreshMinuteSelectOpen,
updateTime: () => {},
hasChanges: false,
loading: false,

View File

@@ -15,7 +15,6 @@
:allow-hourly="true"
/>
<Select
v-model:open="userSelectOpen"
v-model="selectedUserId"
>
<SelectTrigger class="h-8 text-xs w-52">
@@ -32,7 +31,6 @@
</SelectContent>
</Select>
<Select
v-model:open="compareUserSelectOpen"
v-model="compareUserId"
>
<SelectTrigger class="h-8 text-xs w-52">
@@ -164,8 +162,6 @@ const metric = ref<'requests' | 'tokens' | 'cost'>('requests')
const users = ref<User[]>([])
const selectedUserId = ref<string | null>(null)
const compareUserId = ref<string>('__none__')
const userSelectOpen = ref(false)
const compareUserSelectOpen = ref(false)
const leaderboard = ref<LeaderboardItem[]>([])
const leaderboardLoading = ref(false)

View File

@@ -45,7 +45,6 @@
</div>
<Select
v-model="filterRole"
v-model:open="filterRoleOpenMobile"
>
<SelectTrigger class="w-24 h-8 text-xs border-border/60">
<SelectValue placeholder="角色" />
@@ -64,7 +63,6 @@
</Select>
<Select
v-model="filterStatus"
v-model:open="filterStatusOpenMobile"
>
<SelectTrigger class="w-20 h-8 text-xs border-border/60">
<SelectValue placeholder="状态" />
@@ -110,7 +108,6 @@
<!-- 角色筛选 -->
<Select
v-model="filterRole"
v-model:open="filterRoleOpen"
>
<SelectTrigger class="w-32 h-8 text-xs border-border/60">
<SelectValue placeholder="全部角色" />
@@ -131,7 +128,6 @@
<!-- 状态筛选 -->
<Select
v-model="filterStatus"
v-model:open="filterStatusOpen"
>
<SelectTrigger class="w-28 h-8 text-xs border-border/60">
<SelectValue placeholder="全部状态" />
@@ -799,10 +795,6 @@ const loadingStats = ref(false)
const searchQuery = ref('')
const filterRole = ref('all')
const filterStatus = ref('all')
const filterRoleOpen = ref(false)
const filterStatusOpen = ref(false)
const filterRoleOpenMobile = ref(false)
const filterStatusOpenMobile = ref(false)
const currentPage = ref(1)
const pageSize = ref(20)

View File

@@ -379,7 +379,6 @@
>类型</Label>
<Select
v-model="formData.type"
v-model:open="typeSelectOpen"
>
<SelectTrigger
id="type"
@@ -597,7 +596,6 @@ const pageSize = ref(20)
const dialogOpen = ref(false)
const deleteDialogOpen = ref(false)
const detailDialogOpen = ref(false)
const typeSelectOpen = ref(false)
const editingAnnouncement = ref<Announcement | null>(null)
const deletingAnnouncement = ref<Announcement | null>(null)
const viewingAnnouncement = ref<Announcement | null>(null)