"vscode:/vscode.git/clone" did not exist on "2a3ef0be06ef50ee071ae3f9728649d4fa4b4a93"
Commit 16131c3d authored by yangjianbo's avatar yangjianbo
Browse files
parents 836ba14b 7d66f7ff
<template> <template>
<AppLayout> <AppLayout>
<TablePageLayout> <TablePageLayout>
<template #actions>
<div class="flex justify-end gap-3">
<button
@click="loadCodes"
:disabled="loading"
class="btn btn-secondary"
:title="t('common.refresh')"
>
<Icon name="refresh" size="md" :class="loading ? 'animate-spin' : ''" />
</button>
<button @click="showGenerateDialog = true" class="btn btn-primary">
{{ t('admin.redeem.generateCodes') }}
</button>
</div>
</template>
<template #filters> <template #filters>
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between"> <div class="flex flex-wrap items-center gap-3">
<div class="max-w-md flex-1"> <!-- Left: Search + Filters -->
<input <div class="flex-1 sm:max-w-64">
v-model="searchQuery" <input
type="text" v-model="searchQuery"
:placeholder="t('admin.redeem.searchCodes')" type="text"
class="input" :placeholder="t('admin.redeem.searchCodes')"
@input="handleSearch" class="input"
/> @input="handleSearch"
/>
</div> </div>
<div class="flex gap-2">
<Select <Select
v-model="filters.type" v-model="filters.type"
:options="filterTypeOptions" :options="filterTypeOptions"
...@@ -41,9 +25,23 @@ ...@@ -41,9 +25,23 @@
class="w-36" class="w-36"
@change="loadCodes" @change="loadCodes"
/> />
<button @click="handleExportCodes" class="btn btn-secondary">
{{ t('admin.redeem.exportCsv') }} <!-- Right: Action buttons -->
</button> <div class="flex flex-1 flex-wrap items-center justify-end gap-2">
<button
@click="loadCodes"
:disabled="loading"
class="btn btn-secondary"
:title="t('common.refresh')"
>
<Icon name="refresh" size="md" :class="loading ? 'animate-spin' : ''" />
</button>
<button @click="handleExportCodes" class="btn btn-secondary">
{{ t('admin.redeem.exportCsv') }}
</button>
<button @click="showGenerateDialog = true" class="btn btn-primary">
{{ t('admin.redeem.generateCodes') }}
</button>
</div> </div>
</div> </div>
</template> </template>
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
<TablePageLayout> <TablePageLayout>
<!-- Single Row: Search, Filters, and Actions --> <!-- Single Row: Search, Filters, and Actions -->
<template #filters> <template #filters>
<div class="flex w-full flex-col gap-3 md:flex-row md:flex-wrap-reverse md:items-center md:justify-between md:gap-4"> <div class="flex flex-wrap items-center gap-3">
<!-- Left: Search + Active Filters --> <!-- Left: Search + Active Filters -->
<div class="flex min-w-[280px] flex-1 flex-wrap content-start items-center gap-3 md:order-1"> <div class="flex flex-1 flex-wrap items-center gap-3">
<!-- Search Box --> <!-- Search Box -->
<div class="relative w-full md:w-64"> <div class="relative w-full md:w-64">
<Icon <Icon
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
</div> </div>
<!-- Right: Actions and Settings --> <!-- Right: Actions and Settings -->
<div class="flex w-full items-center justify-between gap-2 md:order-2 md:ml-auto md:max-w-full md:flex-wrap md:justify-end md:gap-3"> <div class="flex flex-wrap items-center justify-end gap-2">
<!-- Mobile: Secondary buttons (icon only) --> <!-- Mobile: Secondary buttons (icon only) -->
<div class="flex items-center gap-2 md:contents"> <div class="flex items-center gap-2 md:contents">
<!-- Refresh Button --> <!-- Refresh Button -->
...@@ -342,8 +342,11 @@ ...@@ -342,8 +342,11 @@
</div> </div>
</template> </template>
<template #cell-concurrency="{ value }"> <template #cell-concurrency="{ row }">
<span class="text-sm text-gray-700 dark:text-gray-300">{{ value }}</span> <UserConcurrencyCell
:current="row.current_concurrency ?? 0"
:max="row.concurrency"
/>
</template> </template>
<template #cell-status="{ value }"> <template #cell-status="{ value }">
...@@ -535,6 +538,7 @@ import EmptyState from '@/components/common/EmptyState.vue' ...@@ -535,6 +538,7 @@ import EmptyState from '@/components/common/EmptyState.vue'
import GroupBadge from '@/components/common/GroupBadge.vue' import GroupBadge from '@/components/common/GroupBadge.vue'
import Select from '@/components/common/Select.vue' import Select from '@/components/common/Select.vue'
import UserAttributesConfigModal from '@/components/user/UserAttributesConfigModal.vue' import UserAttributesConfigModal from '@/components/user/UserAttributesConfigModal.vue'
import UserConcurrencyCell from '@/components/user/UserConcurrencyCell.vue'
import UserCreateModal from '@/components/admin/user/UserCreateModal.vue' import UserCreateModal from '@/components/admin/user/UserCreateModal.vue'
import UserEditModal from '@/components/admin/user/UserEditModal.vue' import UserEditModal from '@/components/admin/user/UserEditModal.vue'
import UserApiKeysModal from '@/components/admin/user/UserApiKeysModal.vue' import UserApiKeysModal from '@/components/admin/user/UserApiKeysModal.vue'
......
...@@ -56,7 +56,6 @@ interface SummaryRow { ...@@ -56,7 +56,6 @@ interface SummaryRow {
total_accounts: number total_accounts: number
available_accounts: number available_accounts: number
rate_limited_accounts: number rate_limited_accounts: number
scope_rate_limit_count?: Record<string, number>
error_accounts: number error_accounts: number
// 并发统计 // 并发统计
total_concurrency: number total_concurrency: number
...@@ -122,7 +121,7 @@ const platformRows = computed((): SummaryRow[] => { ...@@ -122,7 +121,7 @@ const platformRows = computed((): SummaryRow[] => {
total_accounts: totalAccounts, total_accounts: totalAccounts,
available_accounts: availableAccounts, available_accounts: availableAccounts,
rate_limited_accounts: safeNumber(avail.rate_limit_count), rate_limited_accounts: safeNumber(avail.rate_limit_count),
scope_rate_limit_count: avail.scope_rate_limit_count,
error_accounts: safeNumber(avail.error_count), error_accounts: safeNumber(avail.error_count),
total_concurrency: totalConcurrency, total_concurrency: totalConcurrency,
used_concurrency: usedConcurrency, used_concurrency: usedConcurrency,
...@@ -162,7 +161,7 @@ const groupRows = computed((): SummaryRow[] => { ...@@ -162,7 +161,7 @@ const groupRows = computed((): SummaryRow[] => {
total_accounts: totalAccounts, total_accounts: totalAccounts,
available_accounts: availableAccounts, available_accounts: availableAccounts,
rate_limited_accounts: safeNumber(avail.rate_limit_count), rate_limited_accounts: safeNumber(avail.rate_limit_count),
scope_rate_limit_count: avail.scope_rate_limit_count,
error_accounts: safeNumber(avail.error_count), error_accounts: safeNumber(avail.error_count),
total_concurrency: totalConcurrency, total_concurrency: totalConcurrency,
used_concurrency: usedConcurrency, used_concurrency: usedConcurrency,
...@@ -329,14 +328,6 @@ function formatDuration(seconds: number): string { ...@@ -329,14 +328,6 @@ function formatDuration(seconds: number): string {
return `${hours}h` return `${hours}h`
} }
function formatScopeName(scope: string): string {
const names: Record<string, string> = {
claude: 'Claude',
gemini_text: 'Gemini',
gemini_image: 'Image'
}
return names[scope] || scope
}
watch( watch(
() => realtimeEnabled.value, () => realtimeEnabled.value,
...@@ -505,18 +496,6 @@ watch( ...@@ -505,18 +496,6 @@ watch(
{{ t('admin.ops.concurrency.rateLimited', { count: row.rate_limited_accounts }) }} {{ t('admin.ops.concurrency.rateLimited', { count: row.rate_limited_accounts }) }}
</span> </span>
<!-- Scope 限流 ( Antigravity) -->
<template v-if="row.scope_rate_limit_count && Object.keys(row.scope_rate_limit_count).length > 0">
<span
v-for="(count, scope) in row.scope_rate_limit_count"
:key="scope"
class="rounded-full bg-orange-100 px-1.5 py-0.5 font-semibold text-orange-700 dark:bg-orange-900/30 dark:text-orange-400"
:title="t('admin.ops.concurrency.scopeRateLimitedTooltip', { scope, count })"
>
{{ formatScopeName(scope as string) }} {{ count }}
</span>
</template>
<!-- 异常账号 --> <!-- 异常账号 -->
<span <span
v-if="row.error_accounts > 0" v-if="row.error_accounts > 0"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment