feat: separate active and deleted API keys display in user dashboard

- Replace single "API Keys" counter with separate "Active API Keys" and "Deleted API Keys"
- Add loadApiKeysStats function to count active vs deleted keys separately
- Update grid layout from lg:grid-cols-4 to lg:grid-cols-5 to accommodate new card
- Add green icon for active keys and trash icon for deleted keys
- Refresh API keys stats when switching to overview tab
- Change default tab to 'overview' for better UX

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Feng Yue
2025-08-14 15:46:54 +08:00
parent a7c6445f36
commit 65620a4cde

View File

@@ -30,7 +30,7 @@
? 'bg-blue-100 text-blue-700' ? 'bg-blue-100 text-blue-700'
: 'text-gray-500 hover:text-gray-700' : 'text-gray-500 hover:text-gray-700'
]" ]"
@click="activeTab = 'overview'" @click="handleTabChange('overview')"
> >
Overview Overview
</button> </button>
@@ -41,7 +41,7 @@
? 'bg-blue-100 text-blue-700' ? 'bg-blue-100 text-blue-700'
: 'text-gray-500 hover:text-gray-700' : 'text-gray-500 hover:text-gray-700'
]" ]"
@click="activeTab = 'api-keys'" @click="handleTabChange('api-keys')"
> >
API Keys API Keys
</button> </button>
@@ -52,7 +52,7 @@
? 'bg-blue-100 text-blue-700' ? 'bg-blue-100 text-blue-700'
: 'text-gray-500 hover:text-gray-700' : 'text-gray-500 hover:text-gray-700'
]" ]"
@click="activeTab = 'usage'" @click="handleTabChange('usage')"
> >
Usage Stats Usage Stats
</button> </button>
@@ -84,13 +84,13 @@
</div> </div>
<!-- Stats Cards --> <!-- Stats Cards -->
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-4"> <div class="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-5">
<div class="overflow-hidden rounded-lg bg-white shadow"> <div class="overflow-hidden rounded-lg bg-white shadow">
<div class="p-5"> <div class="p-5">
<div class="flex items-center"> <div class="flex items-center">
<div class="flex-shrink-0"> <div class="flex-shrink-0">
<svg <svg
class="h-6 w-6 text-gray-400" class="h-6 w-6 text-green-400"
fill="none" fill="none"
stroke="currentColor" stroke="currentColor"
viewBox="0 0 24 24" viewBox="0 0 24 24"
@@ -105,9 +105,39 @@
</div> </div>
<div class="ml-5 w-0 flex-1"> <div class="ml-5 w-0 flex-1">
<dl> <dl>
<dt class="truncate text-sm font-medium text-gray-500">API Keys</dt> <dt class="truncate text-sm font-medium text-gray-500">Active API Keys</dt>
<dd class="text-lg font-medium text-gray-900"> <dd class="text-lg font-medium text-gray-900">
{{ userProfile?.apiKeyCount || 0 }} {{ apiKeysStats.active }}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div class="overflow-hidden rounded-lg bg-white shadow">
<div class="p-5">
<div class="flex items-center">
<div class="flex-shrink-0">
<svg
class="h-6 w-6 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
/>
</svg>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="truncate text-sm font-medium text-gray-500">Deleted API Keys</dt>
<dd class="text-lg font-medium text-gray-900">
{{ apiKeysStats.deleted }}
</dd> </dd>
</dl> </dl>
</div> </div>
@@ -282,8 +312,9 @@ import UserUsageStats from '@/components/user/UserUsageStats.vue'
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
const activeTab = ref('api-keys') const activeTab = ref('overview')
const userProfile = ref(null) const userProfile = ref(null)
const apiKeysStats = ref({ active: 0, deleted: 0 })
const formatNumber = (num) => { const formatNumber = (num) => {
if (num >= 1000000) { if (num >= 1000000) {
@@ -305,6 +336,14 @@ const formatDate = (dateString) => {
}) })
} }
const handleTabChange = (tab) => {
activeTab.value = tab
// Refresh API keys stats when switching to overview tab
if (tab === 'overview') {
loadApiKeysStats()
}
}
const handleLogout = async () => { const handleLogout = async () => {
try { try {
await userStore.logout() await userStore.logout()
@@ -325,8 +364,26 @@ const loadUserProfile = async () => {
} }
} }
const loadApiKeysStats = async () => {
try {
const allApiKeys = await userStore.getUserApiKeys(true) // Include deleted keys
const activeCount = allApiKeys.filter(
(key) => !(key.isDeleted === 'true' || key.deletedAt) && key.isActive
).length
const deletedCount = allApiKeys.filter(
(key) => key.isDeleted === 'true' || key.deletedAt
).length
apiKeysStats.value = { active: activeCount, deleted: deletedCount }
} catch (error) {
console.error('Failed to load API keys stats:', error)
apiKeysStats.value = { active: 0, deleted: 0 }
}
}
onMounted(() => { onMounted(() => {
loadUserProfile() loadUserProfile()
loadApiKeysStats()
}) })
</script> </script>