+
+
+
+
+
+
+
+
+
+
+
+ |
+ 平台类型
+ |
+
+ 正常
+ |
+
+ 限流≤1h
+ |
+
+ 限流≤5h
+ |
+
+ 限流≤12h
+ |
+
+ 限流≤1d
+ |
+
+ 异常
+ |
+
+ 合计
+ |
+
+
+
+
+ |
+ {{ stat.platformLabel }}
+ |
+
+ {{ stat.normal }}
+ |
+
+ {{ stat.rateLimit1h }}
+ |
+
+ {{ stat.rateLimit5h }}
+ |
+
+ {{ stat.rateLimit12h }}
+ |
+
+ {{ stat.rateLimit1d }}
+ |
+
+ {{ stat.abnormal }}
+ |
+
+ {{ stat.total }}
+ |
+
+
+ | 合计 |
+
+ {{
+ accountStatsTotal.normal
+ }}
+ |
+
+ {{
+ accountStatsTotal.rateLimit1h
+ }}
+ |
+
+ {{
+ accountStatsTotal.rateLimit5h
+ }}
+ |
+
+ {{
+ accountStatsTotal.rateLimit12h
+ }}
+ |
+
+ {{
+ accountStatsTotal.rateLimit1d
+ }}
+ |
+
+ {{
+ accountStatsTotal.abnormal
+ }}
+ |
+
+ {{ accountStatsTotal.total }}
+ |
+
+
+
+
+
+ 注:限流时间列表示剩余限流时间在指定范围内的账户数量
+
+
+
@@ -1880,6 +2038,8 @@ const bindingCounts = ref({}) // 轻量级绑定计数,用于显示"绑定: X
const accountGroups = ref([])
const groupFilter = ref('all')
const platformFilter = ref('all')
+const statusFilter = ref('normal') // 新增:状态过滤 (normal/abnormal/all)
+const rateLimitFilter = ref('all') // 新增:限流时间过滤 (all/1h/5h/12h/1d)
const searchKeyword = ref('')
const PAGE_SIZE_STORAGE_KEY = 'accountsPageSize'
const getInitialPageSize = () => {
@@ -1929,6 +2089,9 @@ const expiryEditModalRef = ref(null)
const showAccountTestModal = ref(false)
const testingAccount = ref(null)
+// 账户统计弹窗状态
+const showAccountStatsModal = ref(false)
+
// 表格横向滚动检测
const tableContainerRef = ref(null)
const needsHorizontalScroll = ref(false)
@@ -1963,6 +2126,20 @@ const platformOptions = ref([
{ value: 'droid', label: 'Droid', icon: 'fa-robot' }
])
+const statusOptions = ref([
+ { value: 'normal', label: '正常', icon: 'fa-check-circle' },
+ { value: 'abnormal', label: '异常', icon: 'fa-exclamation-triangle' },
+ { value: 'all', label: '全部状态', icon: 'fa-list' }
+])
+
+const rateLimitOptions = ref([
+ { value: 'all', label: '全部限流', icon: 'fa-infinity' },
+ { value: '1h', label: '限流≤1小时', icon: 'fa-hourglass-start' },
+ { value: '5h', label: '限流≤5小时', icon: 'fa-hourglass-half' },
+ { value: '12h', label: '限流≤12小时', icon: 'fa-hourglass-end' },
+ { value: '1d', label: '限流≤1天', icon: 'fa-calendar-day' }
+])
+
const groupOptions = computed(() => {
const options = [
{ value: 'all', label: '所有账户', icon: 'fa-globe' },
@@ -2199,6 +2376,47 @@ const sortedAccounts = computed(() => {
)
}
+ // 状态过滤 (normal/abnormal/all)
+ if (statusFilter.value !== 'all') {
+ sourceAccounts = sourceAccounts.filter((account) => {
+ const isNormal =
+ account.isActive &&
+ account.status !== 'blocked' &&
+ account.status !== 'unauthorized' &&
+ account.schedulable !== false &&
+ !isAccountRateLimited(account)
+
+ if (statusFilter.value === 'normal') {
+ return isNormal
+ } else if (statusFilter.value === 'abnormal') {
+ return !isNormal
+ }
+ return true
+ })
+ }
+
+ // 限流时间过滤 (all/1h/5h/12h/1d)
+ if (rateLimitFilter.value !== 'all') {
+ sourceAccounts = sourceAccounts.filter((account) => {
+ const rateLimitMinutes = getRateLimitRemainingMinutes(account)
+ if (!rateLimitMinutes || rateLimitMinutes <= 0) return false
+
+ const minutes = Math.floor(rateLimitMinutes)
+ switch (rateLimitFilter.value) {
+ case '1h':
+ return minutes <= 60
+ case '5h':
+ return minutes <= 300
+ case '12h':
+ return minutes <= 720
+ case '1d':
+ return minutes <= 1440
+ default:
+ return true
+ }
+ })
+ }
+
if (!accountsSortBy.value) return sourceAccounts
const sorted = [...sourceAccounts].sort((a, b) => {
@@ -2242,6 +2460,101 @@ const totalPages = computed(() => {
return Math.ceil(total / pageSize.value) || 0
})
+// 账户统计数据(按平台和状态分类)
+const accountStats = computed(() => {
+ const platforms = [
+ { value: 'claude', label: 'Claude' },
+ { value: 'claude-console', label: 'Claude Console' },
+ { value: 'gemini', label: 'Gemini' },
+ { value: 'gemini-api', label: 'Gemini API' },
+ { value: 'openai', label: 'OpenAI' },
+ { value: 'azure_openai', label: 'Azure OpenAI' },
+ { value: 'bedrock', label: 'Bedrock' },
+ { value: 'openai-responses', label: 'OpenAI-Responses' },
+ { value: 'ccr', label: 'CCR' },
+ { value: 'droid', label: 'Droid' }
+ ]
+
+ return platforms
+ .map((p) => {
+ const platformAccounts = accounts.value.filter((acc) => acc.platform === p.value)
+
+ const normal = platformAccounts.filter((acc) => {
+ return (
+ acc.isActive &&
+ acc.status !== 'blocked' &&
+ acc.status !== 'unauthorized' &&
+ acc.schedulable !== false &&
+ !isAccountRateLimited(acc)
+ )
+ }).length
+
+ const abnormal = platformAccounts.filter((acc) => {
+ return !acc.isActive || acc.status === 'blocked' || acc.status === 'unauthorized'
+ }).length
+
+ const rateLimitedAccounts = platformAccounts.filter((acc) => isAccountRateLimited(acc))
+
+ const rateLimit1h = rateLimitedAccounts.filter((acc) => {
+ const minutes = getRateLimitRemainingMinutes(acc)
+ return minutes > 0 && minutes <= 60
+ }).length
+
+ const rateLimit5h = rateLimitedAccounts.filter((acc) => {
+ const minutes = getRateLimitRemainingMinutes(acc)
+ return minutes > 0 && minutes <= 300
+ }).length
+
+ const rateLimit12h = rateLimitedAccounts.filter((acc) => {
+ const minutes = getRateLimitRemainingMinutes(acc)
+ return minutes > 0 && minutes <= 720
+ }).length
+
+ const rateLimit1d = rateLimitedAccounts.filter((acc) => {
+ const minutes = getRateLimitRemainingMinutes(acc)
+ return minutes > 0 && minutes <= 1440
+ }).length
+
+ return {
+ platform: p.value,
+ platformLabel: p.label,
+ normal,
+ rateLimit1h,
+ rateLimit5h,
+ rateLimit12h,
+ rateLimit1d,
+ abnormal,
+ total: platformAccounts.length
+ }
+ })
+ .filter((stat) => stat.total > 0) // 只显示有账户的平台
+})
+
+// 账户统计合计
+const accountStatsTotal = computed(() => {
+ return accountStats.value.reduce(
+ (total, stat) => {
+ total.normal += stat.normal
+ total.rateLimit1h += stat.rateLimit1h
+ total.rateLimit5h += stat.rateLimit5h
+ total.rateLimit12h += stat.rateLimit12h
+ total.rateLimit1d += stat.rateLimit1d
+ total.abnormal += stat.abnormal
+ total.total += stat.total
+ return total
+ },
+ {
+ normal: 0,
+ rateLimit1h: 0,
+ rateLimit5h: 0,
+ rateLimit12h: 0,
+ rateLimit1d: 0,
+ abnormal: 0,
+ total: 0
+ }
+ )
+})
+
const pageNumbers = computed(() => {
const total = totalPages.value
const current = currentPage.value
@@ -3014,6 +3327,45 @@ const formatRateLimitTime = (minutes) => {
}
}
+// 检查账户是否被限流
+const isAccountRateLimited = (account) => {
+ if (!account) return false
+
+ // 检查 rateLimitStatus
+ if (account.rateLimitStatus) {
+ if (typeof account.rateLimitStatus === 'string' && account.rateLimitStatus === 'limited') {
+ return true
+ }
+ if (
+ typeof account.rateLimitStatus === 'object' &&
+ account.rateLimitStatus.isRateLimited === true
+ ) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// 获取限流剩余时间(分钟)
+const getRateLimitRemainingMinutes = (account) => {
+ if (!account || !account.rateLimitStatus) return 0
+
+ if (typeof account.rateLimitStatus === 'object' && account.rateLimitStatus.remainingMinutes) {
+ return account.rateLimitStatus.remainingMinutes
+ }
+
+ // 如果有 rateLimitUntil 字段,计算剩余时间
+ if (account.rateLimitUntil) {
+ const now = new Date().getTime()
+ const untilTime = new Date(account.rateLimitUntil).getTime()
+ const diff = untilTime - now
+ return diff > 0 ? Math.ceil(diff / 60000) : 0
+ }
+
+ return 0
+}
+
// 打开创建账户模态框
const openCreateAccountModal = () => {
newAccountPlatform.value = null // 重置选择的平台