<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CursorPro 管理后台</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
    <style>
        body { font-family: 'Inter', sans-serif; }
        .fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease; }
        .fade-enter-from, .fade-leave-to { opacity: 0; }
    </style>
</head>
<body class="bg-gray-100">
    <div id="app">
        <!-- 登录页面 -->
        <div v-if="!isLoggedIn" class="min-h-screen flex items-center justify-center">
            <div class="bg-white p-8 rounded-lg shadow-lg w-96">
                <h1 class="text-2xl font-bold text-center mb-6 text-gray-800">CursorPro 管理后台</h1>
                <form @submit.prevent="login">
                    <div class="mb-4">
                        <label class="block text-sm font-medium text-gray-700 mb-2">用户名</label>
                        <input v-model="loginForm.username" type="text"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                            placeholder="请输入用户名">
                    </div>
                    <div class="mb-6">
                        <label class="block text-sm font-medium text-gray-700 mb-2">密码</label>
                        <input v-model="loginForm.password" type="password"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                            placeholder="请输入密码">
                    </div>
                    <button type="submit"
                        class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 transition">
                        登录
                    </button>
                </form>
                <p v-if="loginError" class="mt-4 text-red-500 text-sm text-center">{{ loginError }}</p>
            </div>
        </div>

        <!-- 主界面 -->
        <div v-else class="min-h-screen">
            <!-- 顶部导航 -->
            <nav class="bg-white shadow-sm">
                <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
                    <div class="flex justify-between h-16">
                        <div class="flex items-center">
                            <h1 class="text-xl font-bold text-gray-800">CursorPro 管理后台</h1>
                        </div>
                        <div class="flex items-center space-x-4">
                            <span class="text-gray-600">{{ currentUser }}</span>
                            <button @click="logout" class="text-red-600 hover:text-red-800">退出</button>
                        </div>
                    </div>
                </div>
            </nav>

            <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
                <!-- 标签页 -->
                <div class="mb-6">
                    <nav class="flex space-x-4">
                        <button @click="currentTab = 'dashboard'"
                            :class="currentTab === 'dashboard' ? 'bg-blue-100 text-blue-700' : 'text-gray-500 hover:text-gray-700'"
                            class="px-3 py-2 font-medium text-sm rounded-md">
                            仪表盘
                        </button>
                        <button @click="currentTab = 'accounts'"
                            :class="currentTab === 'accounts' ? 'bg-blue-100 text-blue-700' : 'text-gray-500 hover:text-gray-700'"
                            class="px-3 py-2 font-medium text-sm rounded-md">
                            账号管理
                        </button>
                        <button @click="currentTab = 'keys'"
                            :class="currentTab === 'keys' ? 'bg-blue-100 text-blue-700' : 'text-gray-500 hover:text-gray-700'"
                            class="px-3 py-2 font-medium text-sm rounded-md">
                            激活码管理
                        </button>
                        <button @click="currentTab = 'settings'; loadSettings()"
                            :class="currentTab === 'settings' ? 'bg-blue-100 text-blue-700' : 'text-gray-500 hover:text-gray-700'"
                            class="px-3 py-2 font-medium text-sm rounded-md">
                            全局设置
                        </button>
                        <button @click="currentTab = 'compensate'"
                            :class="currentTab === 'compensate' ? 'bg-blue-100 text-blue-700' : 'text-gray-500 hover:text-gray-700'"
                            class="px-3 py-2 font-medium text-sm rounded-md">
                            批量补偿
                        </button>
                        <button @click="currentTab = 'announcements'; loadAnnouncements()"
                            :class="currentTab === 'announcements' ? 'bg-blue-100 text-blue-700' : 'text-gray-500 hover:text-gray-700'"
                            class="px-3 py-2 font-medium text-sm rounded-md">
                            公告管理
                        </button>
                        <button @click="currentTab = 'logs'; loadLogs()"
                            :class="currentTab === 'logs' ? 'bg-blue-100 text-blue-700' : 'text-gray-500 hover:text-gray-700'"
                            class="px-3 py-2 font-medium text-sm rounded-md">
                            使用日志
                        </button>
                    </nav>
                </div>

                <!-- 仪表盘 -->
                <div v-if="currentTab === 'dashboard'">
                    <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
                        <div class="bg-white rounded-lg shadow p-6">
                            <div class="text-sm font-medium text-gray-500">总账号数</div>
                            <div class="mt-2 text-3xl font-semibold text-gray-900">{{ stats.total_accounts }}</div>
                            <div class="mt-1 text-sm text-green-600">{{ stats.active_accounts }} 可用</div>
                        </div>
                        <div class="bg-white rounded-lg shadow p-6">
                            <div class="text-sm font-medium text-gray-500">总激活码</div>
                            <div class="mt-2 text-3xl font-semibold text-gray-900">{{ stats.total_keys }}</div>
                            <div class="mt-1 text-sm text-green-600">{{ stats.active_keys }} 有效</div>
                        </div>
                        <div class="bg-white rounded-lg shadow p-6">
                            <div class="text-sm font-medium text-gray-500">今日使用</div>
                            <div class="mt-2 text-3xl font-semibold text-gray-900">{{ stats.today_usage }}</div>
                            <div class="mt-1 text-sm text-blue-600">Pro账号: {{ stats.pro_accounts }}</div>
                        </div>
                    </div>
                </div>

                <!-- 账号管理 -->
                <div v-if="currentTab === 'accounts'">
                    <!-- 外部API说明 -->
                    <div class="bg-blue-50 border border-blue-200 rounded-lg p-4 mb-4">
                        <div class="flex items-start">
                            <div class="flex-shrink-0">
                                <svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
                                </svg>
                            </div>
                            <div class="ml-3 flex-1">
                                <h3 class="text-sm font-medium text-blue-800">外部系统批量上传接口</h3>
                                <div class="mt-2 text-sm text-blue-700">
                                    <p class="font-mono bg-blue-100 px-2 py-1 rounded mb-2">POST /admin/external/accounts/batch</p>
                                    <p class="mb-1"><strong>Header:</strong> X-API-Token: hb-api-token-change-in-production</p>
                                    <details class="cursor-pointer">
                                        <summary class="text-blue-800 hover:text-blue-900">查看请求格式 ▼</summary>
                                        <pre class="mt-2 bg-gray-800 text-green-400 p-3 rounded text-xs overflow-x-auto">{
  "accounts": [
    {
      "email": "user@example.com",
      "access_token": "eyJhbG...",
      "refresh_token": "xxx",           // 可选
      "workos_session_token": "xxx",    // 可选
      "membership_type": "free",        // free=Free账号, pro=Pro账号
      "remark": "备注"                  // 可选
    }
  ],
  "update_existing": true  // 是否更新已存在的账号
}</pre>
                                    </details>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div class="bg-white rounded-lg shadow">
                        <div class="px-6 py-4 border-b border-gray-200">
                            <div class="flex justify-between items-center mb-4">
                                <h2 class="text-lg font-medium text-gray-900">账号列表 (共 {{ accountsTotal }} 条)</h2>
                                <div class="space-x-2">
                                    <button v-if="selectedAccounts.length > 0" @click="batchEnableAccounts"
                                        class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 text-sm">
                                        批量启用 ({{ selectedAccounts.length }})
                                    </button>
                                    <button v-if="selectedAccounts.length > 0" @click="batchDisableAccounts"
                                        class="px-4 py-2 bg-orange-600 text-white rounded-md hover:bg-orange-700 text-sm">
                                        批量禁用 ({{ selectedAccounts.length }})
                                    </button>
                                    <button v-if="selectedAccounts.length > 0" @click="batchDeleteAccounts"
                                        class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 text-sm">
                                        批量删除 ({{ selectedAccounts.length }})
                                    </button>
                                    <button @click="showImportModal = true"
                                        class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 text-sm">
                                        批量导入
                                    </button>
                                    <button @click="openCreateAccountModal"
                                        class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-sm">
                                        添加账号
                                    </button>
                                </div>
                            </div>
                        </div>
                        <div class="overflow-x-auto">
                            <table class="min-w-full divide-y divide-gray-200">
                                <thead class="bg-gray-50">
                                    <tr>
                                        <th class="px-6 py-3 text-left">
                                            <input type="checkbox" @change="toggleSelectAll" :checked="isAllSelected"
                                                class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
                                        </th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">邮箱</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">类型</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">Token</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">状态</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">使用次数</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">操作</th>
                                    </tr>
                                </thead>
                                <tbody class="bg-white divide-y divide-gray-200">
                                    <tr v-for="account in accounts" :key="account.id">
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <input type="checkbox" :value="account.id" v-model="selectedAccounts"
                                                class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ account.email }}</td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <span :class="account.membership_type === 'pro' ? 'bg-purple-100 text-purple-800' : 'bg-gray-100 text-gray-800'"
                                                class="px-2 py-1 text-xs font-medium rounded-full">
                                                {{ formatMembershipLabel(account.membership_type) }}
                                            </span>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm space-x-1">
                                            <button @click="copyToken(account.access_token, 'AccessToken')"
                                                class="px-2 py-1 bg-blue-100 text-blue-700 rounded text-xs hover:bg-blue-200" title="复制 Access Token">
                                                AT
                                            </button>
                                            <button v-if="account.refresh_token" @click="copyToken(account.refresh_token, 'RefreshToken')"
                                                class="px-2 py-1 bg-green-100 text-green-700 rounded text-xs hover:bg-green-200" title="复制 Refresh Token">
                                                RT
                                            </button>
                                            <button v-if="account.workos_session_token" @click="copyToken(account.workos_session_token, 'WorkosSessionToken')"
                                                class="px-2 py-1 bg-purple-100 text-purple-700 rounded text-xs hover:bg-purple-200" title="复制 Workos Session Token">
                                                WT
                                            </button>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <span @click="toggleAccountStatus(account)" :class="getStatusClass(account.status)"
                                                class="px-2 py-1 text-xs font-medium rounded-full cursor-pointer hover:opacity-80 transition"
                                                :title="'点击切换状态'">
                                                {{ getStatusText(account.status) }}
                                            </span>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ account.usage_count }}</td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm space-x-2">
                                            <button @click="openAnalyzeModal(account)"
                                                class="text-green-600 hover:text-green-900">
                                                手动检测
                                            </button>
                                            <span class="text-gray-300">|</span>
                                            <button @click="editAccount(account)" class="text-blue-600 hover:text-blue-900">编辑</button>
                                            <button @click="deleteAccount(account.id)" class="text-red-600 hover:text-red-900">删除</button>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                        <!-- 分页 -->
                        <div class="px-6 py-4 border-t border-gray-200 flex items-center justify-between">
                            <div class="flex items-center space-x-2">
                                <span class="text-sm text-gray-700">每页显示</span>
                                <select v-model="accountsPagination.pageSize" @change="loadAccounts"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    <option :value="10">10</option>
                                    <option :value="20">20</option>
                                    <option :value="50">50</option>
                                    <option :value="100">100</option>
                                </select>
                                <span class="text-sm text-gray-700">条</span>
                            </div>
                            <div class="flex items-center space-x-2">
                                <button @click="accountsPagination.currentPage = 1; loadAccounts()"
                                    :disabled="accountsPagination.currentPage === 1"
                                    :class="accountsPagination.currentPage === 1 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    首页
                                </button>
                                <button @click="accountsPagination.currentPage--; loadAccounts()"
                                    :disabled="accountsPagination.currentPage === 1"
                                    :class="accountsPagination.currentPage === 1 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    上一页
                                </button>
                                <span class="text-sm text-gray-700">
                                    第 {{ accountsPagination.currentPage }} / {{ accountsPagination.totalPages }} 页
                                </span>
                                <button @click="accountsPagination.currentPage++; loadAccounts()"
                                    :disabled="accountsPagination.currentPage >= accountsPagination.totalPages"
                                    :class="accountsPagination.currentPage >= accountsPagination.totalPages ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    下一页
                                </button>
                                <button @click="accountsPagination.currentPage = accountsPagination.totalPages; loadAccounts()"
                                    :disabled="accountsPagination.currentPage >= accountsPagination.totalPages"
                                    :class="accountsPagination.currentPage >= accountsPagination.totalPages ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    末页
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 激活码管理 -->
                <div v-if="currentTab === 'keys'">
                    <div class="bg-white rounded-lg shadow">
                        <div class="px-6 py-4 border-b border-gray-200">
                            <div class="flex justify-between items-center mb-4">
                                <h2 class="text-lg font-medium text-gray-900">激活码列表 (共 {{ keysTotal }} 条)</h2>
                                <div class="space-x-2">
                                    <button v-if="selectedKeys.length > 0" @click="batchCopyKeys"
                                        class="px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700 text-sm">
                                        批量复制 ({{ selectedKeys.length }})
                                    </button>
                                    <button v-if="selectedKeys.length > 0" @click="batchEnableKeys"
                                        class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 text-sm">
                                        批量启用 ({{ selectedKeys.length }})
                                    </button>
                                    <button v-if="selectedKeys.length > 0" @click="batchDisableKeys"
                                        class="px-4 py-2 bg-orange-600 text-white rounded-md hover:bg-orange-700 text-sm">
                                        批量禁用 ({{ selectedKeys.length }})
                                    </button>
                                    <button v-if="selectedKeys.length > 0" @click="batchDeleteKeys"
                                        class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 text-sm">
                                        批量删除 ({{ selectedKeys.length }})
                                    </button>
                                    <button @click="showKeyModal = true; editingKey = null; resetKeyForm()"
                                        class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-sm">
                                        生成激活码
                                    </button>
                                </div>
                            </div>
                            <!-- 搜索和筛选 -->
                            <div class="flex flex-wrap gap-3">
                                <input v-model="keySearch.search" @input="searchKeys" type="text" placeholder="搜索激活码..."
                                    class="px-3 py-2 border border-gray-300 rounded-md text-sm w-64 focus:outline-none focus:ring-2 focus:ring-blue-500">
                                <select v-model="keySearch.status" @change="searchKeys"
                                    class="px-3 py-2 border border-gray-300 rounded-md text-sm">
                                    <option value="">全部状态</option>
                                    <option value="active">有效</option>
                                    <option value="disabled">禁用</option>
                                </select>
                                <select v-model="keySearch.activated" @change="searchKeys"
                                    class="px-3 py-2 border border-gray-300 rounded-md text-sm">
                                    <option value="">全部</option>
                                    <option value="true">已激活</option>
                                    <option value="false">未激活</option>
                                </select>
                                <select v-model="keySearch.membership_type" @change="searchKeys"
                                    class="px-3 py-2 border border-gray-300 rounded-md text-sm">
                                    <option value="">全部类型</option>
                                    <option value="pro">Pro (高级模型)</option>
                                    <option value="auto">Auto (无限换号)</option>
                                </select>
                                <button @click="resetKeySearch" class="px-3 py-2 text-gray-600 hover:text-gray-800 text-sm">
                                    重置
                                </button>
                            </div>
                        </div>
                        <div class="overflow-x-auto">
                            <table class="min-w-full divide-y divide-gray-200">
                                <thead class="bg-gray-50">
                                    <tr>
                                        <th class="px-6 py-3 text-left">
                                            <input type="checkbox" @change="toggleSelectAllKeys" :checked="isAllKeysSelected"
                                                class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
                                        </th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">激活码</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">类型</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">额度/天数</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">有效期</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">状态</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">操作</th>
                                    </tr>
                                </thead>
                                <tbody class="bg-white divide-y divide-gray-200">
                                    <tr v-for="key in keys" :key="key.id">
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <input type="checkbox" :value="key.id" v-model="selectedKeys"
                                                class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <code class="text-sm bg-gray-100 px-2 py-1 rounded">{{ key.key }}</code>
                                            <button @click="copyKey(key.key)" class="ml-2 text-gray-400 hover:text-gray-600">
                                                <svg class="w-4 h-4 inline" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
                                                </svg>
                                            </button>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <span :class="key.membership_type === 'pro' ? 'bg-purple-100 text-purple-800' : 'bg-blue-100 text-blue-800'"
                                                class="px-2 py-1 text-xs font-medium rounded-full">
                                                {{ key.membership_type === 'pro' ? '高级模型' : '无限Auto' }}
                                            </span>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm">
                                            <template v-if="key.membership_type === 'pro'">
                                                <span class="text-green-600 font-medium">{{ key.quota - key.quota_used }}</span>
                                                <span class="text-gray-400"> / {{ key.quota }}</span>
                                            </template>
                                            <template v-else>
                                                <span class="text-blue-600">{{ key.valid_days }}天</span>
                                            </template>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
                                            <template v-if="key.first_activated_at">
                                                {{ key.expire_at ? formatDate(key.expire_at) : '永久' }}
                                            </template>
                                            <template v-else>
                                                <span class="text-yellow-600">{{ key.valid_days }}天 (未激活)</span>
                                            </template>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <span :class="key.status === 'active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'"
                                                class="px-2 py-1 text-xs font-medium rounded-full">
                                                {{ key.status === 'active' ? '有效' : '禁用' }}
                                            </span>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm space-x-2">
                                            <button @click="viewKeyDetail(key)" class="text-purple-600 hover:text-purple-900">查看</button>
                                            <button v-if="key.membership_type === 'pro'" @click="addQuota(key)" class="text-green-600 hover:text-green-900">充值</button>
                                            <button @click="extendKey(key)" class="text-yellow-600 hover:text-yellow-900">延期</button>
                                            <button v-if="key.status === 'active'" @click="disableKey(key)" class="text-orange-600 hover:text-orange-900">禁用</button>
                                            <button v-else @click="enableKey(key)" class="text-green-600 hover:text-green-900">启用</button>
                                            <button @click="editKey(key)" class="text-blue-600 hover:text-blue-900">编辑</button>
                                            <button @click="deleteKey(key.id)" class="text-red-600 hover:text-red-900">删除</button>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                        <!-- 分页 -->
                        <div class="px-6 py-4 border-t border-gray-200 flex items-center justify-between">
                            <div class="flex items-center space-x-2">
                                <span class="text-sm text-gray-700">每页显示</span>
                                <select v-model="keysPagination.pageSize" @change="searchKeys"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    <option :value="10">10</option>
                                    <option :value="20">20</option>
                                    <option :value="50">50</option>
                                    <option :value="100">100</option>
                                </select>
                                <span class="text-sm text-gray-700">条</span>
                            </div>
                            <div class="flex items-center space-x-2">
                                <button @click="keysPagination.currentPage = 1; searchKeys()"
                                    :disabled="keysPagination.currentPage === 1"
                                    :class="keysPagination.currentPage === 1 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    首页
                                </button>
                                <button @click="keysPagination.currentPage--; searchKeys()"
                                    :disabled="keysPagination.currentPage === 1"
                                    :class="keysPagination.currentPage === 1 ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    上一页
                                </button>
                                <span class="text-sm text-gray-700">
                                    第 {{ keysPagination.currentPage }} / {{ keysPagination.totalPages }} 页
                                </span>
                                <button @click="keysPagination.currentPage++; searchKeys()"
                                    :disabled="keysPagination.currentPage >= keysPagination.totalPages"
                                    :class="keysPagination.currentPage >= keysPagination.totalPages ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    下一页
                                </button>
                                <button @click="keysPagination.currentPage = keysPagination.totalPages; searchKeys()"
                                    :disabled="keysPagination.currentPage >= keysPagination.totalPages"
                                    :class="keysPagination.currentPage >= keysPagination.totalPages ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-100'"
                                    class="px-3 py-1 border border-gray-300 rounded-md text-sm">
                                    末页
                                </button>
                            </div>
                        </div>
                    </div>
                </div>

                <!-- 全局设置 -->
                <div v-if="currentTab === 'settings'">
                    <div class="bg-white rounded-lg shadow p-6">
                        <h2 class="text-lg font-medium text-gray-900 mb-6">全局设置</h2>

                        <!-- 说明 -->
                        <div class="bg-gray-50 border border-gray-200 rounded-md p-4 mb-6">
                            <p class="text-sm text-gray-700">
                                <strong>Auto密钥</strong>：按时间限制，全局控制换号频率<br>
                                <strong>Pro密钥</strong>：按额度限制，全局控制每次扣费
                            </p>
                        </div>

                        <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                            <div class="space-y-4">
                                <h3 class="font-medium text-gray-700 border-b pb-2">Auto密钥 (无限换号)</h3>
                                <div>
                                    <label class="block text-sm font-medium text-gray-700 mb-1">换号最小间隔 (分钟)</label>
                                    <input v-model.number="globalSettings.auto_switch_interval" type="number" min="0"
                                        class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                    <p class="text-xs text-gray-500 mt-1">两次换号之间至少等待的时间，0表示无限制</p>
                                </div>
                                <div>
                                    <label class="block text-sm font-medium text-gray-700 mb-1">每天最大换号次数</label>
                                    <input v-model.number="globalSettings.auto_daily_switches" type="number" min="1"
                                        class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                    <p class="text-xs text-gray-500 mt-1">每天0点重置计数</p>
                                </div>
                            </div>
                            <div class="space-y-4">
                                <h3 class="font-medium text-gray-700 border-b pb-2">Pro密钥 (高级模型)</h3>
                                <div>
                                    <label class="block text-sm font-medium text-gray-700 mb-1">每次换号扣除额度</label>
                                    <input v-model.number="globalSettings.pro_quota_per_switch" type="number" min="1"
                                        class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                    <p class="text-xs text-gray-500 mt-1">例如：50点/次，500点总额度可换10次</p>
                                </div>
                            </div>
                        </div>
                        <div class="mt-6 flex justify-end">
                            <button @click="saveSettings" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">
                                保存设置
                            </button>
                        </div>
                    </div>
                </div>

                <!-- 批量补偿 -->
                <div v-if="currentTab === 'compensate'">
                    <div class="bg-white rounded-lg shadow p-6">
                        <h2 class="text-lg font-medium text-gray-900 mb-4">批量补偿</h2>

                        <!-- 说明 -->
                        <div class="bg-blue-50 border border-blue-200 rounded-md p-4 mb-6">
                            <p class="text-sm text-blue-800 font-medium mb-2">补偿逻辑说明：</p>
                            <ul class="text-sm text-blue-700 list-disc list-inside space-y-1">
                                <li>筛选：在指定日期之前激活 且 在指定日期还未过期的密钥</li>
                                <li>未过期的卡：直接在过期时间上增加天数</li>
                                <li>已过期的卡（符合条件）：恢复使用，过期时间 = 今天 + 补偿天数</li>
                            </ul>
                        </div>

                        <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
                            <div>
                                <label class="block text-sm font-medium text-gray-700 mb-1">套餐类型</label>
                                <select v-model="compensateForm.membership_type"
                                    class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                    <option value="">全部</option>
                                    <option value="pro">Pro (高级模型)</option>
                                    <option value="auto">Auto (无限换号)</option>
                                </select>
                            </div>
                            <div>
                                <label class="block text-sm font-medium text-gray-700 mb-1">在此日期之前激活</label>
                                <input v-model="compensateForm.activated_before" type="date"
                                    class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                <p class="text-xs text-gray-500 mt-1">例如：12月4号之前激活 填 2024-12-05</p>
                            </div>
                            <div>
                                <label class="block text-sm font-medium text-gray-700 mb-1">在此日期还未过期</label>
                                <input v-model="compensateForm.not_expired_on" type="date"
                                    class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                <p class="text-xs text-gray-500 mt-1">例如：12月4号还没过期 填 2024-12-04</p>
                            </div>
                        </div>

                        <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
                            <div>
                                <label class="block text-sm font-medium text-gray-700 mb-1">延长天数</label>
                                <input v-model.number="compensateForm.extend_days" type="number" min="0"
                                    class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                <p class="text-xs text-gray-500 mt-1">Auto和Pro都可延长</p>
                            </div>
                            <div>
                                <label class="block text-sm font-medium text-gray-700 mb-1">增加额度 (仅Pro)</label>
                                <input v-model.number="compensateForm.add_quota" type="number" min="0"
                                    class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                                <p class="text-xs text-gray-500 mt-1">仅对Pro密钥有效</p>
                            </div>
                        </div>

                        <div class="flex space-x-4 mb-6">
                            <button @click="previewCompensate" class="px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700">
                                预览
                            </button>
                            <button @click="executeCompensate" class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700">
                                执行补偿
                            </button>
                        </div>

                        <!-- 预览结果 -->
                        <div v-if="compensatePreview" class="mt-4 p-4 bg-gray-50 rounded-md">
                            <p class="font-medium text-gray-700 mb-2">{{ compensatePreview.message }}</p>
                            <div v-if="compensatePreview.keys && compensatePreview.keys.length > 0" class="overflow-x-auto">
                                <table class="min-w-full text-sm">
                                    <thead>
                                        <tr class="text-left text-gray-500">
                                            <th class="py-1 pr-4">ID</th>
                                            <th class="py-1 pr-4">激活码</th>
                                            <th class="py-1 pr-4">类型</th>
                                            <th class="py-1 pr-4">激活时间</th>
                                            <th class="py-1 pr-4">到期时间</th>
                                            <th class="py-1">状态</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <tr v-for="k in compensatePreview.keys" :key="k.id">
                                            <td class="py-1 pr-4">{{ k.id }}</td>
                                            <td class="py-1 pr-4"><code class="bg-gray-200 px-1 rounded">{{ k.key }}</code></td>
                                            <td class="py-1 pr-4">{{ k.membership_type === 'pro' ? 'Pro' : 'Auto' }}</td>
                                            <td class="py-1 pr-4">{{ k.activated_at }}</td>
                                            <td class="py-1 pr-4">{{ k.expire_at }}</td>
                                            <td class="py-1">
                                                <span :class="k.is_expired ? 'text-red-600' : 'text-green-600'">
                                                    {{ k.is_expired ? '已过期' : '有效' }}
                                                </span>
                                            </td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </div>

                        <!-- 执行结果 -->
                        <div v-if="compensateResult" class="mt-4 p-4 rounded-md" :class="compensateResult.failed > 0 ? 'bg-yellow-50' : 'bg-green-50'">
                            <p class="font-medium">补偿完成</p>
                            <p class="text-sm">
                                匹配: {{ compensateResult.total_matched }} 个，
                                成功: {{ compensateResult.success }} 个，
                                失败: {{ compensateResult.failed }} 个
                                <span v-if="compensateResult.recovered > 0" class="text-blue-600">
                                    (其中 {{ compensateResult.recovered }} 个已过期卡被恢复使用)
                                </span>
                            </p>
                            <ul v-if="compensateResult.errors && compensateResult.errors.length > 0" class="text-sm text-red-600 mt-2">
                                <li v-for="err in compensateResult.errors" :key="err">{{ err }}</li>
                            </ul>
                        </div>
                    </div>
                </div>

                <!-- 公告管理 -->
                <div v-if="currentTab === 'announcements'">
                    <div class="bg-white rounded-lg shadow">
                        <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
                            <h2 class="text-lg font-medium text-gray-900">公告列表</h2>
                            <button @click="openCreateAnnouncementModal"
                                class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 text-sm">
                                发布公告
                            </button>
                        </div>
                        <div class="overflow-x-auto">
                            <table class="min-w-full divide-y divide-gray-200">
                                <thead class="bg-gray-50">
                                    <tr>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">标题</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">类型</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">状态</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">创建时间</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">操作</th>
                                    </tr>
                                </thead>
                                <tbody class="bg-white divide-y divide-gray-200">
                                    <tr v-for="ann in announcements" :key="ann.id">
                                        <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ ann.title }}</td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <span :class="announcementTypeClass(ann.type)"
                                                class="px-2 py-1 text-xs font-medium rounded-full">
                                                {{ announcementTypeLabel(ann.type) }}
                                            </span>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <button @click="toggleAnnouncement(ann)"
                                                :class="ann.is_active ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'"
                                                class="px-2 py-1 text-xs font-medium rounded-full cursor-pointer hover:opacity-80 transition">
                                                {{ ann.is_active ? '已启用' : '已禁用' }}
                                            </button>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ formatDate(ann.created_at) }}</td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm space-x-2">
                                            <button @click="editAnnouncement(ann)" class="text-blue-600 hover:text-blue-900">编辑</button>
                                            <button @click="deleteAnnouncement(ann.id)" class="text-red-600 hover:text-red-900">删除</button>
                                        </td>
                                    </tr>
                                    <tr v-if="announcements.length === 0">
                                        <td colspan="5" class="px-6 py-4 text-center text-gray-500">暂无公告</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>

                <!-- 使用日志 -->
                <div v-if="currentTab === 'logs'">
                    <div class="bg-white rounded-lg shadow">
                        <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
                            <h2 class="text-lg font-medium text-gray-900">使用日志</h2>
                            <div class="flex space-x-2">
                                <select v-model="logFilter.action" @change="loadLogs"
                                    class="px-3 py-2 border border-gray-300 rounded-md text-sm">
                                    <option value="">全部操作</option>
                                    <option value="verify">验证</option>
                                    <option value="switch">换号</option>
                                </select>
                                <button @click="loadLogs" class="px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700 text-sm">
                                    刷新
                                </button>
                            </div>
                        </div>
                        <div class="overflow-x-auto">
                            <table class="min-w-full divide-y divide-gray-200">
                                <thead class="bg-gray-50">
                                    <tr>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">时间</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">激活码</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">操作</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">IP</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">状态</th>
                                        <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase">消息</th>
                                    </tr>
                                </thead>
                                <tbody class="bg-white divide-y divide-gray-200">
                                    <tr v-for="log in logs" :key="log.id">
                                        <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ log.created_at }}</td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <code class="text-sm bg-gray-100 px-2 py-1 rounded">{{ log.key_preview }}</code>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <span :class="log.action === 'switch' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'"
                                                class="px-2 py-1 text-xs font-medium rounded-full">
                                                {{ log.action === 'switch' ? '换号' : '验证' }}
                                            </span>
                                        </td>
                                        <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ log.ip_address || '-' }}</td>
                                        <td class="px-6 py-4 whitespace-nowrap">
                                            <span :class="log.success ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'"
                                                class="px-2 py-1 text-xs font-medium rounded-full">
                                                {{ log.success ? '成功' : '失败' }}
                                            </span>
                                        </td>
                                        <td class="px-6 py-4 text-sm text-gray-500">{{ log.message || '-' }}</td>
                                    </tr>
                                    <tr v-if="logs.length === 0">
                                        <td colspan="6" class="px-6 py-4 text-center text-gray-500">暂无日志</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- 账号编辑弹窗 -->
        <div v-if="showAccountModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4">
                <div class="px-6 py-4 border-b border-gray-200">
                    <h3 class="text-lg font-medium text-gray-900">{{ editingAccount ? '编辑账号' : '添加账号' }}</h3>
                </div>
                <form @submit.prevent="saveAccount" class="p-6 space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">邮箱</label>
                        <input v-model="accountForm.email" type="email" required
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">Access Token</label>
                        <textarea v-model="accountForm.access_token" rows="3"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">Refresh Token</label>
                        <textarea v-model="accountForm.refresh_token" rows="2"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">WorkosCursorSessionToken</label>
                        <textarea v-model="accountForm.workos_session_token" rows="2" placeholder="可选，用于刷新 Token"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">备注</label>
                        <input v-model="accountForm.remark" type="text" placeholder="来源、部门等"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                    </div>
                    <div class="flex justify-end space-x-3 pt-4">
                        <button type="button" @click="showAccountModal = false"
                            class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">取消</button>
                        <button type="submit"
                            class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">保存</button>
                    </div>
                </form>
            </div>
        </div>

        <!-- 手动检测弹窗 -->
        <div v-if="showAnalyzeModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl mx-4">
                <div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
                    <div>
                        <h3 class="text-lg font-medium text-gray-900">手动检测账号</h3>
                        <p class="text-sm text-gray-500 mt-1">可粘贴最新的 WorkosCursorSessionToken 或 user_xxx::jwt 用于调试</p>
                        <p class="text-sm text-gray-600 mt-2">
                            当前账号: <span class="font-mono text-blue-600">{{ analyzeTarget ? analyzeTarget.email : '' }}</span>
                            <span class="ml-4">状态: {{ getStatusText(analyzeTarget ? analyzeTarget.status : null) }}</span>
                        </p>
                    </div>
                    <button @click="closeAnalyzeModal" class="text-gray-400 hover:text-gray-600">
                        ✕
                    </button>
                </div>
                <div class="p-6 space-y-4 max-h-[70vh] overflow-y-auto">
                    <div class="grid gap-3 md:grid-cols-3">
                        <div class="bg-gray-50 border border-gray-200 rounded-md px-3 py-2 text-sm">
                            <p class="text-gray-600">Workos Session</p>
                            <p class="mt-1 font-mono break-all text-gray-800">
                                {{ analyzeTarget && analyzeTarget.workos_session_token ? analyzeTarget.workos_session_token : '未保存' }}
                            </p>
                        </div>
                        <div class="bg-gray-50 border border-gray-200 rounded-md px-3 py-2 text-sm">
                            <p class="text-gray-600">Access Token</p>
                            <p class="mt-1 font-mono break-all text-gray-800">
                                {{ analyzeTarget && analyzeTarget.access_token ? analyzeTarget.access_token : '未保存' }}
                            </p>
                        </div>
                        <div class="bg-gray-50 border border-gray-200 rounded-md px-3 py-2 text-sm">
                            <p class="text-gray-600">Refresh Token</p>
                            <p class="mt-1 font-mono break-all text-gray-800">
                                {{ analyzeTarget && analyzeTarget.refresh_token ? analyzeTarget.refresh_token : '未保存' }}
                            </p>
                        </div>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">检测用 Token</label>
                        <textarea v-model="analyzeForm.token" rows="4"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                            placeholder="WorkosCursorSessionToken=... 或 user_xxx::jwt"></textarea>
                        <p class="text-xs text-gray-500 mt-1">若留空，将使用系统当前保存的 Token</p>
                    </div>
                    <label class="flex items-center space-x-2 text-sm text-gray-700">
                        <input type="checkbox" v-model="analyzeForm.saveToken"
                            class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
                        <span>检测成功后，将本次 Token 同步到账号</span>
                    </label>
                    <div v-if="analyzeResult" class="rounded-md border px-4 py-3"
                        :class="analyzeResult.success ? 'border-green-200 bg-green-50' : 'border-red-200 bg-red-50'">
                        <p class="font-medium" :class="analyzeResult.success ? 'text-green-700' : 'text-red-700'">
                            {{ analyzeResult.success ? '检测成功' : '检测失败' }}
                        </p>
                        <p v-if="analyzeResult.message" class="text-sm mt-1">{{ analyzeResult.message }}</p>
                        <pre v-if="analyzeResult.data" class="mt-3 text-xs bg-white border rounded p-2 overflow-auto max-h-48">{{ JSON.stringify(analyzeResult.data, null, 2) }}</pre>
                    </div>
                </div>
                <div class="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
                    <button @click="closeAnalyzeModal"
                        class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">取消</button>
                    <button @click="submitAnalyze" :disabled="analyzeLoading"
                        :class="analyzeLoading ? 'bg-blue-300 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700'"
                        class="px-4 py-2 text-white rounded-md">
                        {{ analyzeLoading ? '检测中...' : '开始检测' }}
                    </button>
                </div>
            </div>
        </div>

        <!-- 激活码编辑弹窗 -->
        <div v-if="showKeyModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-md mx-4 max-h-[90vh] overflow-y-auto">
                <div class="px-6 py-4 border-b border-gray-200">
                    <h3 class="text-lg font-medium text-gray-900">{{ editingKey ? '编辑激活码' : '生成激活码' }}</h3>
                </div>
                <form @submit.prevent="saveKey" class="p-6 space-y-4">
                    <div v-if="!editingKey">
                        <label class="block text-sm font-medium text-gray-700 mb-1">生成数量</label>
                        <input v-model.number="keyForm.count" type="number" min="1" max="100"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">套餐类型</label>
                        <select v-model="keyForm.membership_type"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                            <option value="pro">Pro (高级模型) - 按额度计费</option>
                            <option value="auto">Auto (无限换号) - 按时间计费</option>
                        </select>
                    </div>

                    <!-- Pro密钥: 只设置总额度 -->
                    <div v-if="keyForm.membership_type === 'pro'">
                        <label class="block text-sm font-medium text-gray-700 mb-1">总额度</label>
                        <input v-model.number="keyForm.quota" type="number" min="1"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                        <p class="text-xs text-gray-500 mt-1">每次换号扣除额度由全局设置控制</p>
                    </div>

                    <!-- Auto密钥: 只设置有效天数 -->
                    <div v-if="keyForm.membership_type === 'auto'">
                        <label class="block text-sm font-medium text-gray-700 mb-1">有效天数</label>
                        <select v-model.number="keyForm.valid_days"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                            <option :value="0">永久</option>
                            <option :value="1">1天</option>
                            <option :value="7">7天</option>
                            <option :value="30">30天</option>
                            <option :value="90">90天</option>
                            <option :value="365">365天</option>
                        </select>
                        <p class="text-xs text-gray-500 mt-1">首次使用激活码时开始计时，换号频率由全局设置控制</p>
                    </div>

                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">最大设备数</label>
                        <input v-model.number="keyForm.max_devices" type="number" min="1" max="10"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                        <p class="text-xs text-gray-500 mt-1">同一激活码最多绑定的设备数量</p>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">备注</label>
                        <input v-model="keyForm.remark" type="text"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                    </div>
                    <div class="flex justify-end space-x-3 pt-4">
                        <button type="button" @click="showKeyModal = false"
                            class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">取消</button>
                        <button type="submit"
                            class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">保存</button>
                    </div>
                </form>
            </div>
        </div>

        <!-- 充值额度弹窗 -->
        <div v-if="showQuotaModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-sm mx-4">
                <div class="px-6 py-4 border-b border-gray-200">
                    <h3 class="text-lg font-medium text-gray-900">充值额度</h3>
                </div>
                <div class="p-6 space-y-4">
                    <p class="text-sm text-gray-600">当前额度: {{ quotaTarget?.quota - quotaTarget?.quota_used }} / {{ quotaTarget?.quota }}</p>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">增加额度</label>
                        <input v-model.number="addQuotaAmount" type="number" min="1"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                    </div>
                    <div class="flex justify-end space-x-3 pt-4">
                        <button type="button" @click="showQuotaModal = false"
                            class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">取消</button>
                        <button @click="submitAddQuota"
                            class="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700">充值</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- 批量导入弹窗 -->
        <div v-if="showImportModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-2xl mx-4">
                <div class="px-6 py-4 border-b border-gray-200">
                    <h3 class="text-lg font-medium text-gray-900">批量导入账号</h3>
                </div>
                <div class="p-6">
                    <p class="text-sm text-gray-600 mb-4">请输入 JSON 格式的账号数据，每行一个账号对象：</p>
                    <textarea v-model="importData" rows="10" placeholder='[
  {"email": "xxx@example.com", "access_token": "...", "refresh_token": "...", "membership_type": "pro"},
  ...
]'
                        class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 font-mono text-sm"></textarea>
                    <div v-if="importResult" class="mt-4 p-3 rounded-md" :class="importResult.failed > 0 ? 'bg-yellow-50' : 'bg-green-50'">
                        <p class="text-sm">导入完成：成功 {{ importResult.success }} 个，失败 {{ importResult.failed }} 个</p>
                    </div>
                    <div class="flex justify-end space-x-3 mt-6">
                        <button @click="showImportModal = false; importResult = null"
                            class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">关闭</button>
                        <button @click="importAccounts"
                            class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">导入</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- 延期弹窗 -->
        <div v-if="showExtendModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-sm mx-4">
                <div class="px-6 py-4 border-b border-gray-200">
                    <h3 class="text-lg font-medium text-gray-900">延长有效期</h3>
                </div>
                <div class="p-6 space-y-4">
                    <p class="text-sm text-gray-600">
                        当前状态:
                        <span v-if="extendTarget?.expire_at">{{ formatDate(extendTarget.expire_at) }}</span>
                        <span v-else-if="extendTarget?.first_activated_at">{{ extendTarget.valid_days }}天 (已激活)</span>
                        <span v-else>{{ extendTarget?.valid_days }}天 (未激活)</span>
                    </p>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">延长天数</label>
                        <input v-model.number="extendDays" type="number" min="1"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                    </div>
                    <div class="flex justify-end space-x-3 pt-4">
                        <button type="button" @click="showExtendModal = false"
                            class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">取消</button>
                        <button @click="submitExtend"
                            class="px-4 py-2 bg-yellow-600 text-white rounded-md hover:bg-yellow-700">延期</button>
                    </div>
                </div>
            </div>
        </div>

        <!-- 激活码详情弹窗 -->
        <div v-if="showKeyDetailModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-3xl mx-4 max-h-[90vh] overflow-y-auto">
                <div class="px-6 py-4 border-b border-gray-200 flex justify-between items-center">
                    <h3 class="text-lg font-medium text-gray-900">激活码详情</h3>
                    <button @click="showKeyDetailModal = false" class="text-gray-400 hover:text-gray-600">
                        <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
                        </svg>
                    </button>
                </div>
                <div class="p-6" v-if="keyDetail">
                    <!-- 基本信息 -->
                    <div class="mb-6">
                        <h4 class="font-medium text-gray-700 mb-2">基本信息</h4>
                        <div class="bg-gray-50 rounded-md p-4 grid grid-cols-2 gap-4 text-sm">
                            <div><span class="text-gray-500">激活码：</span><code class="bg-gray-200 px-2 py-1 rounded">{{ keyDetail.key }}</code></div>
                            <div><span class="text-gray-500">类型：</span>{{ keyDetail.membership_type === 'pro' ? 'Pro (高级模型)' : 'Auto (无限换号)' }}</div>
                            <div><span class="text-gray-500">状态：</span>{{ keyDetail.status === 'active' ? '有效' : '禁用' }}</div>
                            <div><span class="text-gray-500">激活时间：</span>{{ keyDetail.first_activated_at ? formatDate(keyDetail.first_activated_at) : '未激活' }}</div>
                            <div><span class="text-gray-500">过期时间：</span>{{ keyDetail.expire_at ? formatDate(keyDetail.expire_at) : '永久' }}</div>
                            <div><span class="text-gray-500">换号次数：</span>{{ keyDetail.switch_count }}</div>
                        </div>
                    </div>

                    <!-- 绑定设备 -->
                    <div class="mb-6">
                        <h4 class="font-medium text-gray-700 mb-2">绑定设备 ({{ keyDevices.length }}/{{ keyDetail.max_devices }})</h4>
                        <div class="bg-gray-50 rounded-md overflow-hidden">
                            <table class="min-w-full text-sm" v-if="keyDevices.length > 0">
                                <thead class="bg-gray-100">
                                    <tr>
                                        <th class="px-4 py-2 text-left text-gray-600">设备ID</th>
                                        <th class="px-4 py-2 text-left text-gray-600">绑定时间</th>
                                        <th class="px-4 py-2 text-left text-gray-600">最后活跃</th>
                                        <th class="px-4 py-2 text-left text-gray-600">操作</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr v-for="device in keyDevices" :key="device.id" class="border-t border-gray-200">
                                        <td class="px-4 py-2"><code class="text-xs bg-gray-200 px-1 rounded">{{ device.device_id.slice(0, 16) }}...</code></td>
                                        <td class="px-4 py-2 text-gray-500">{{ device.created_at }}</td>
                                        <td class="px-4 py-2 text-gray-500">{{ device.last_active_at || '-' }}</td>
                                        <td class="px-4 py-2">
                                            <button @click="deleteDevice(device.id)" class="text-red-600 hover:text-red-900 text-xs">解绑</button>
                                        </td>
                                    </tr>
                                </tbody>
                            </table>
                            <p v-else class="px-4 py-3 text-gray-500 text-center">暂无绑定设备</p>
                        </div>
                    </div>

                    <!-- 使用记录 -->
                    <div>
                        <h4 class="font-medium text-gray-700 mb-2">使用记录</h4>
                        <div class="bg-gray-50 rounded-md overflow-hidden">
                            <table class="min-w-full text-sm" v-if="keyLogs.length > 0">
                                <thead class="bg-gray-100">
                                    <tr>
                                        <th class="px-4 py-2 text-left text-gray-600">时间</th>
                                        <th class="px-4 py-2 text-left text-gray-600">操作</th>
                                        <th class="px-4 py-2 text-left text-gray-600">IP</th>
                                        <th class="px-4 py-2 text-left text-gray-600">状态</th>
                                        <th class="px-4 py-2 text-left text-gray-600">消息</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr v-for="log in keyLogs" :key="log.id" class="border-t border-gray-200">
                                        <td class="px-4 py-2 text-gray-500">{{ log.created_at }}</td>
                                        <td class="px-4 py-2">
                                            <span :class="log.action === 'switch' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'" class="px-2 py-0.5 text-xs rounded-full">
                                                {{ log.action === 'switch' ? '换号' : '验证' }}
                                            </span>
                                        </td>
                                        <td class="px-4 py-2 text-gray-500">{{ log.ip_address || '-' }}</td>
                                        <td class="px-4 py-2">
                                            <span :class="log.success ? 'text-green-600' : 'text-red-600'">{{ log.success ? '成功' : '失败' }}</span>
                                        </td>
                                        <td class="px-4 py-2 text-gray-500">{{ log.message || '-' }}</td>
                                    </tr>
                                </tbody>
                            </table>
                            <p v-else class="px-4 py-3 text-gray-500 text-center">暂无使用记录</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <!-- 公告编辑弹窗 -->
        <div v-if="showAnnouncementModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
            <div class="bg-white rounded-lg shadow-xl w-full max-w-lg mx-4">
                <div class="px-6 py-4 border-b border-gray-200">
                    <h3 class="text-lg font-medium text-gray-900">{{ editingAnnouncement ? '编辑公告' : '发布公告' }}</h3>
                </div>
                <form @submit.prevent="saveAnnouncement" class="p-6 space-y-4">
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">标题</label>
                        <input v-model="announcementForm.title" type="text" required
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                            placeholder="公告标题">
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">内容</label>
                        <textarea v-model="announcementForm.content" rows="5" required
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
                            placeholder="公告内容，支持换行"></textarea>
                    </div>
                    <div>
                        <label class="block text-sm font-medium text-gray-700 mb-1">类型</label>
                        <select v-model="announcementForm.type"
                            class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
                            <option value="info">信息 (info)</option>
                            <option value="warning">警告 (warning)</option>
                            <option value="error">错误 (error)</option>
                            <option value="success">成功 (success)</option>
                        </select>
                    </div>
                    <div class="flex items-center space-x-2">
                        <input type="checkbox" v-model="announcementForm.is_active" id="ann-active"
                            class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
                        <label for="ann-active" class="text-sm text-gray-700">启用</label>
                    </div>
                    <div class="flex justify-end space-x-3 pt-4">
                        <button type="button" @click="showAnnouncementModal = false"
                            class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50">取消</button>
                        <button type="submit"
                            class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700">保存</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <script>
    const { createApp, ref, reactive, computed, onMounted, watch } = Vue

    createApp({
        setup() {
            // 状态
            const isLoggedIn = ref(false)
            const currentUser = ref('')
            const token = ref('')
            const currentTab = ref('dashboard')
            const loginError = ref('')

            // 数据
            const stats = ref({ total_accounts: 0, active_accounts: 0, pro_accounts: 0, total_keys: 0, active_keys: 0, today_usage: 0 })
            const accounts = ref([])
            const accountsTotal = ref(0)
            const selectedAccounts = ref([])
            const accountsPagination = reactive({
                currentPage: 1,
                pageSize: 20,
                totalPages: 1
            })
            const keys = ref([])
            const keysTotal = ref(0)
            const selectedKeys = ref([])
            const keysPagination = reactive({
                currentPage: 1,
                pageSize: 20,
                totalPages: 1
            })
            const logs = ref([])
            const logFilter = reactive({ action: '' })

            // 搜索
            const keySearch = reactive({ search: '', status: '', activated: '', membership_type: '' })

            // 表单
            const loginForm = reactive({ username: '', password: '' })
            const accountForm = reactive({
                email: '',
                access_token: '',
                refresh_token: '',
                workos_session_token: '',
                remark: ''
            })
            const keyForm = reactive({
                count: 1,
                membership_type: 'pro',
                quota: 500,       // Pro用
                valid_days: 30,   // Auto用
                max_devices: 2,
                remark: ''
            })

            // 弹窗
            const showAccountModal = ref(false)
            const showAnalyzeModal = ref(false)
            const showKeyModal = ref(false)
            const showImportModal = ref(false)
            const showQuotaModal = ref(false)
            const showExtendModal = ref(false)
            const editingAccount = ref(null)
            const analyzeTarget = ref(null)
            const editingKey = ref(null)
            const importData = ref('')
            const importResult = ref(null)
            const quotaTarget = ref(null)
            const addQuotaAmount = ref(100)
            const extendTarget = ref(null)
            const extendDays = ref(7)

            // 激活码详情
            const showKeyDetailModal = ref(false)
            const keyDetail = ref(null)
            const keyDevices = ref([])
            const keyLogs = ref([])

            // 公告管理
            const announcements = ref([])
            const showAnnouncementModal = ref(false)
            const editingAnnouncement = ref(null)
            const announcementForm = reactive({
                title: '',
                content: '',
                type: 'info',
                is_active: true
            })

            // 全局设置
            const globalSettings = reactive({
                auto_switch_interval: 0,
                auto_daily_switches: 999,
                pro_quota_per_switch: 1
            })

            // 批量补偿
            const compensateForm = reactive({
                membership_type: '',
                activated_before: '',
                not_expired_on: '',
                extend_days: 0,
                add_quota: 0
            })
            const compensatePreview = ref(null)
            const compensateResult = ref(null)

            // API 请求封装
            const api = axios.create({ baseURL: '/admin' })
            api.interceptors.request.use(config => {
                if (token.value) {
                    config.headers.Authorization = `Bearer ${token.value}`
                }
                return config
            })

            // 登录
            const login = async () => {
                try {
                    const res = await axios.post('/admin/login', loginForm)
                    token.value = res.data.access_token
                    localStorage.setItem('token', token.value)
                    isLoggedIn.value = true
                    currentUser.value = loginForm.username
                    loginError.value = ''
                    loadData()
                } catch (e) {
                    loginError.value = e.response?.data?.detail || '登录失败'
                }
            }

            // 登出
            const logout = () => {
                token.value = ''
                localStorage.removeItem('token')
                isLoggedIn.value = false
            }

            // 加载数据
            const loadData = async () => {
                try {
                    const statsRes = await api.get('/dashboard')
                    stats.value = statsRes.data
                    await Promise.all([loadAccounts(), searchKeys()])
                } catch (e) {
                    console.error('加载数据失败', e)
                }
            }

            // 加载账号列表（分页）
            const loadAccounts = async () => {
                try {
                    const skip = (accountsPagination.currentPage - 1) * accountsPagination.pageSize
                    const [accountsRes, countRes] = await Promise.all([
                        api.get(`/accounts?skip=${skip}&limit=${accountsPagination.pageSize}`),
                        api.get('/accounts/count')
                    ])
                    accounts.value = accountsRes.data
                    accountsTotal.value = countRes.data.total
                    accountsPagination.totalPages = Math.ceil(accountsTotal.value / accountsPagination.pageSize)
                    selectedAccounts.value = []
                } catch (e) {
                    console.error('加载账号失败', e)
                }
            }

            // 全选/取消全选
            const isAllSelected = computed(() => {
                return accounts.value.length > 0 && selectedAccounts.value.length === accounts.value.length
            })

            const toggleSelectAll = (event) => {
                if (event.target.checked) {
                    selectedAccounts.value = accounts.value.map(a => a.id)
                } else {
                    selectedAccounts.value = []
                }
            }

            // 账号操作
            const openCreateAccountModal = () => {
                editingAccount.value = null
                resetAccountForm()
                showAccountModal.value = true
            }

            const editAccount = (account) => {
                editingAccount.value = account
                prepareAccountForm(account)
                showAccountModal.value = true
            }

            const buildAccountPayload = () => {
                const workosToken = accountForm.workos_session_token?.trim() || ''
                const accessToken = accountForm.access_token?.trim() || ''
                if (!workosToken && !accessToken) {
                    throw new Error('请至少填写 Access Token 或 Workos Token')
                }
                return {
                    email: accountForm.email,
                    token: workosToken || accessToken,
                    workos_session_token: workosToken || null,
                    access_token: accessToken || null,
                    refresh_token: accountForm.refresh_token?.trim() || null,
                    remark: accountForm.remark?.trim() || ''
                }
            }

            const saveAccount = async () => {
                try {
                    const payload = buildAccountPayload()
                    if (editingAccount.value) {
                        await api.put(`/accounts/${editingAccount.value.id}`, payload)
                    } else {
                        await api.post('/accounts', payload)
                    }
                    showAccountModal.value = false
                    loadAccounts()
                } catch (e) {
                    const message = e.message || e.response?.data?.detail
                    alert(message || '保存失败')
                }
            }

            const deleteAccount = async (id) => {
                if (!confirm('确定删除此账号？')) return
                try {
                    await api.delete(`/accounts/${id}`)
                    loadAccounts()
                } catch (e) {
                    alert('删除失败')
                }
            }

            // 手动分析单个账号
            const analyzeForm = reactive({
                token: '',
                saveToken: false
            })
            const analyzeResult = ref(null)
            const analyzeLoading = ref(false)

            const resetAccountForm = () => {
                accountForm.email = ''
                accountForm.access_token = ''
                accountForm.refresh_token = ''
                accountForm.workos_session_token = ''
                accountForm.remark = ''
            }

            const prepareAccountForm = (account) => {
                accountForm.email = account.email || ''
                accountForm.access_token = account.access_token || ''
                accountForm.refresh_token = account.refresh_token || ''
                accountForm.workos_session_token = account.workos_session_token || account.token || ''
                accountForm.remark = account.remark || ''
            }

            const openAnalyzeModal = (account) => {
                analyzeTarget.value = account
                analyzeForm.token = account?.workos_session_token || account?.access_token || account?.token || ''
                analyzeForm.saveToken = false
                analyzeResult.value = null
                showAnalyzeModal.value = true
            }

            const closeAnalyzeModal = () => {
                showAnalyzeModal.value = false
                analyzeTarget.value = null
                analyzeForm.token = ''
                analyzeForm.saveToken = false
                analyzeResult.value = null
            }

            const submitAnalyze = async () => {
                if (!analyzeTarget.value) return
                analyzeLoading.value = true
                analyzeResult.value = null
                try {
                    const payload = {
                        save_token: analyzeForm.saveToken
                    }
                    if (analyzeForm.token?.trim()) {
                        payload.token = analyzeForm.token.trim()
                    }
                    const res = await api.post(`/accounts/${analyzeTarget.value.id}/analyze`, payload)
                    analyzeResult.value = res.data
                    if (res.data?.success) {
                        await loadAccounts()
                    }
                } catch (e) {
                    analyzeResult.value = {
                        success: false,
                        message: e.response?.data?.detail || '分析失败'
                    }
                } finally {
                    analyzeLoading.value = false
                }
            }

            // 快捷切换账号状态
            const toggleAccountStatus = async (account) => {
                const statusMap = { 'active': '可用', 'in_use': '使用中', 'disabled': '禁用', 'expired': '过期' }
                const nextMap = { 'in_use': 'active', 'active': 'disabled', 'disabled': 'active', 'expired': 'active' }
                const nextStatus = nextMap[account.status] || 'active'
                const msg = `确定将账号状态从「${statusMap[account.status]}」切换为「${statusMap[nextStatus]}」？`
                if (!confirm(msg)) return
                try {
                    const res = await api.post(`/accounts/${account.id}/toggle-status`)
                    loadAccounts()
                } catch (e) {
                    alert(e.response?.data?.detail || '切换失败')
                }
            }

            // 批量启用账号
            const batchEnableAccounts = async () => {
                if (selectedAccounts.value.length === 0) return
                if (!confirm(`确定启用选中的 ${selectedAccounts.value.length} 个账号？`)) return
                try {
                    const res = await api.post('/accounts/batch-enable', selectedAccounts.value)
                    alert(res.data.message)
                    loadAccounts()
                } catch (e) {
                    alert(e.response?.data?.detail || '批量启用失败')
                }
            }

            // 批量禁用账号
            const batchDisableAccounts = async () => {
                if (selectedAccounts.value.length === 0) return
                if (!confirm(`确定禁用选中的 ${selectedAccounts.value.length} 个账号？`)) return
                try {
                    const res = await api.post('/accounts/batch-disable', selectedAccounts.value)
                    alert(res.data.message)
                    loadAccounts()
                } catch (e) {
                    alert(e.response?.data?.detail || '批量禁用失败')
                }
            }

            // 批量删除账号
            const batchDeleteAccounts = async () => {
                if (selectedAccounts.value.length === 0) return
                if (!confirm(`确定删除选中的 ${selectedAccounts.value.length} 个账号？此操作不可撤销！`)) return
                try {
                    const res = await api.post('/accounts/batch-delete', selectedAccounts.value)
                    alert(res.data.message)
                    loadAccounts()
                } catch (e) {
                    alert(e.response?.data?.detail || '批量删除失败')
                }
            }

            const importAccounts = async () => {
                try {
                    const data = JSON.parse(importData.value)
                    const res = await api.post('/accounts/import', { accounts: data })
                    importResult.value = res.data
                    loadAccounts()
                } catch (e) {
                    alert('导入失败: ' + (e.response?.data?.detail || e.message))
                }
            }

            // 激活码操作
            const resetKeyForm = () => {
                Object.assign(keyForm, {
                    count: 1,
                    membership_type: 'pro',
                    quota: 500,
                    valid_days: 30,
                    max_devices: 2,
                    remark: ''
                })
            }

            const editKey = (key) => {
                editingKey.value = key
                Object.assign(keyForm, key)
                showKeyModal.value = true
            }

            const saveKey = async () => {
                try {
                    if (editingKey.value) {
                        await api.put(`/keys/${editingKey.value.id}`, keyForm)
                    } else {
                        await api.post('/keys', keyForm)
                    }
                    showKeyModal.value = false
                    searchKeys()
                } catch (e) {
                    alert(e.response?.data?.detail || '保存失败')
                }
            }

            const deleteKey = async (id) => {
                if (!confirm('确定删除此激活码？')) return
                try {
                    await api.delete(`/keys/${id}`)
                    searchKeys()
                } catch (e) {
                    alert('删除失败')
                }
            }

            const addQuota = (key) => {
                quotaTarget.value = key
                addQuotaAmount.value = 100
                showQuotaModal.value = true
            }

            const submitAddQuota = async () => {
                try {
                    await api.post(`/keys/${quotaTarget.value.id}/add-quota?add_quota=${addQuotaAmount.value}`)
                    showQuotaModal.value = false
                    searchKeys()
                    alert('充值成功')
                } catch (e) {
                    alert(e.response?.data?.detail || '充值失败')
                }
            }

            const copyKey = (key) => {
                navigator.clipboard.writeText(key)
                alert('已复制')
            }

            const copyToken = (token, name) => {
                navigator.clipboard.writeText(token)
                alert(`${name} 已复制`)
            }

            // 延期操作
            const extendKey = (key) => {
                extendTarget.value = key
                extendDays.value = 7
                showExtendModal.value = true
            }

            const submitExtend = async () => {
                try {
                    await api.post('/keys/batch-extend', {
                        key_ids: [extendTarget.value.id],
                        extend_days: extendDays.value,
                        add_quota: 0
                    })
                    showExtendModal.value = false
                    searchKeys()
                    alert('延期成功')
                } catch (e) {
                    alert(e.response?.data?.detail || '延期失败')
                }
            }

            // 全局设置
            const loadSettings = async () => {
                try {
                    const res = await api.get('/settings')
                    Object.assign(globalSettings, res.data)
                } catch (e) {
                    console.error('加载设置失败', e)
                }
            }

            const saveSettings = async () => {
                try {
                    await api.put('/settings', globalSettings)
                    alert('设置已保存')
                } catch (e) {
                    alert(e.response?.data?.detail || '保存失败')
                }
            }

            // 批量补偿
            const previewCompensate = async () => {
                try {
                    const params = new URLSearchParams()
                    if (compensateForm.membership_type) params.append('membership_type', compensateForm.membership_type)
                    if (compensateForm.activated_before) params.append('activated_before', compensateForm.activated_before)
                    if (compensateForm.not_expired_on) params.append('not_expired_on', compensateForm.not_expired_on)

                    const res = await api.get('/keys/preview-compensate?' + params.toString())
                    compensatePreview.value = res.data
                    compensateResult.value = null
                } catch (e) {
                    alert(e.response?.data?.detail || '预览失败')
                }
            }

            const executeCompensate = async () => {
                if (!confirm('确定执行批量补偿？此操作不可撤销！')) return
                try {
                    const params = new URLSearchParams()
                    if (compensateForm.membership_type) params.append('membership_type', compensateForm.membership_type)
                    if (compensateForm.activated_before) params.append('activated_before', compensateForm.activated_before)
                    if (compensateForm.not_expired_on) params.append('not_expired_on', compensateForm.not_expired_on)
                    params.append('extend_days', compensateForm.extend_days)
                    params.append('add_quota', compensateForm.add_quota)

                    const res = await api.post('/keys/batch-compensate?' + params.toString())
                    compensateResult.value = res.data
                    compensatePreview.value = null
                    searchKeys()
                } catch (e) {
                    alert(e.response?.data?.detail || '补偿失败')
                }
            }

            // 日志
            const loadLogs = async () => {
                try {
                    const params = new URLSearchParams()
                    if (logFilter.action) params.append('action', logFilter.action)
                    const res = await api.get('/logs?' + params.toString())
                    logs.value = res.data
                } catch (e) {
                    console.error('加载日志失败', e)
                }
            }

            // 激活码详情
            const viewKeyDetail = async (key) => {
                keyDetail.value = key
                showKeyDetailModal.value = true
                try {
                    const [devicesRes, logsRes] = await Promise.all([
                        api.get(`/keys/${key.id}/devices`),
                        api.get(`/keys/${key.id}/logs`)
                    ])
                    keyDevices.value = devicesRes.data
                    keyLogs.value = logsRes.data
                } catch (e) {
                    console.error('加载详情失败', e)
                }
            }

            const deleteDevice = async (deviceId) => {
                if (!confirm('确定解绑此设备？')) return
                try {
                    await api.delete(`/devices/${deviceId}`)
                    keyDevices.value = keyDevices.value.filter(d => d.id !== deviceId)
                } catch (e) {
                    alert(e.response?.data?.detail || '解绑失败')
                }
            }

            // 搜索激活码（支持分页）
            let searchTimeout = null
            const searchKeys = () => {
                clearTimeout(searchTimeout)
                searchTimeout = setTimeout(async () => {
                    try {
                        const skip = (keysPagination.currentPage - 1) * keysPagination.pageSize

                        // 构建激活码列表查询参数
                        const listParams = new URLSearchParams()
                        listParams.append('skip', skip)
                        listParams.append('limit', keysPagination.pageSize)
                        if (keySearch.search) listParams.append('search', keySearch.search)
                        if (keySearch.status) listParams.append('status', keySearch.status)
                        if (keySearch.activated) listParams.append('activated', keySearch.activated)
                        if (keySearch.membership_type) listParams.append('membership_type', keySearch.membership_type)

                        // 构建计数查询参数（不包含skip和limit）
                        const countParams = new URLSearchParams()
                        if (keySearch.search) countParams.append('search', keySearch.search)
                        if (keySearch.status) countParams.append('status', keySearch.status)
                        if (keySearch.activated) countParams.append('activated', keySearch.activated)
                        if (keySearch.membership_type) countParams.append('membership_type', keySearch.membership_type)

                        const [keysRes, countRes] = await Promise.all([
                            api.get('/keys?' + listParams.toString()),
                            api.get('/keys/count' + (countParams.toString() ? '?' + countParams.toString() : ''))
                        ])
                        keys.value = keysRes.data
                        keysTotal.value = countRes.data.total
                        keysPagination.totalPages = Math.ceil(keysTotal.value / keysPagination.pageSize)
                        selectedKeys.value = []
                    } catch (e) {
                        console.error('搜索失败', e)
                    }
                }, 300)
            }

            const resetKeySearch = () => {
                keySearch.search = ''
                keySearch.status = ''
                keySearch.activated = ''
                keySearch.membership_type = ''
                keysPagination.currentPage = 1
                searchKeys()
            }

            // 全选/取消全选激活码
            const isAllKeysSelected = computed(() => {
                return keys.value.length > 0 && selectedKeys.value.length === keys.value.length
            })

            const toggleSelectAllKeys = (event) => {
                if (event.target.checked) {
                    selectedKeys.value = keys.value.map(k => k.id)
                } else {
                    selectedKeys.value = []
                }
            }

            // 批量复制激活码
            const batchCopyKeys = async () => {
                if (selectedKeys.value.length === 0) return
                try {
                    // 获取选中的激活码
                    const selectedKeyObjects = keys.value.filter(k => selectedKeys.value.includes(k.id))
                    const keyStrings = selectedKeyObjects.map(k => k.key).join('\n')
                    await navigator.clipboard.writeText(keyStrings)
                    alert(`已复制 ${selectedKeys.value.length} 个激活码到剪贴板`)
                } catch (e) {
                    alert('复制失败: ' + e.message)
                }
            }

            // 批量启用激活码
            const batchEnableKeys = async () => {
                if (selectedKeys.value.length === 0) return
                if (!confirm(`确定启用选中的 ${selectedKeys.value.length} 个激活码？`)) return
                try {
                    const res = await api.post('/keys/batch-enable', selectedKeys.value)
                    alert(res.data.message)
                    searchKeys()
                } catch (e) {
                    alert(e.response?.data?.detail || '批量启用失败')
                }
            }

            // 批量禁用激活码
            const batchDisableKeys = async () => {
                if (selectedKeys.value.length === 0) return
                if (!confirm(`确定禁用选中的 ${selectedKeys.value.length} 个激活码？`)) return
                try {
                    const res = await api.post('/keys/batch-disable', selectedKeys.value)
                    alert(res.data.message)
                    searchKeys()
                } catch (e) {
                    alert(e.response?.data?.detail || '批量禁用失败')
                }
            }

            // 批量删除激活码
            const batchDeleteKeys = async () => {
                if (selectedKeys.value.length === 0) return
                if (!confirm(`确定删除选中的 ${selectedKeys.value.length} 个激活码？此操作不可撤销！`)) return
                try {
                    const res = await api.post('/keys/batch-delete', selectedKeys.value)
                    alert(res.data.message)
                    searchKeys()
                } catch (e) {
                    alert(e.response?.data?.detail || '批量删除失败')
                }
            }

            // 禁用/启用激活码
            const disableKey = async (key) => {
                try {
                    const res = await api.get(`/keys/${key.id}/usage-info`)
                    const info = res.data
                    const msg = `确定禁用此激活码？\n\n` +
                        `激活码: ${info.key}\n` +
                        `类型: ${info.membership_type === 'pro' ? 'Pro' : 'Auto'}\n` +
                        `激活时间: ${info.first_activated_at || '未激活'}\n` +
                        `已使用: ${info.used_days} 天\n` +
                        `换号次数: ${info.switch_count} 次\n` +
                        (info.membership_type === 'pro' ? `已用额度: ${info.quota_used}/${info.quota}\n` : '') +
                        `绑定设备: ${info.device_count}/${info.max_devices}`

                    if (confirm(msg)) {
                        const disableRes = await api.post(`/keys/${key.id}/disable`)
                        alert(`禁用成功！\n已使用 ${disableRes.data.used_days} 天，换号 ${disableRes.data.switch_count} 次`)
                        searchKeys()
                    }
                } catch (e) {
                    alert(e.response?.data?.detail || '操作失败')
                }
            }

            const enableKey = async (key) => {
                if (!confirm('确定启用此激活码？')) return
                try {
                    await api.post(`/keys/${key.id}/enable`)
                    searchKeys()
                } catch (e) {
                    alert(e.response?.data?.detail || '操作失败')
                }
            }

            // 公告管理
            const loadAnnouncements = async () => {
                try {
                    const res = await api.get('/announcements')
                    announcements.value = res.data
                } catch (e) {
                    console.error('加载公告失败', e)
                }
            }

            const openCreateAnnouncementModal = () => {
                editingAnnouncement.value = null
                announcementForm.title = ''
                announcementForm.content = ''
                announcementForm.type = 'info'
                announcementForm.is_active = true
                showAnnouncementModal.value = true
            }

            const editAnnouncement = (ann) => {
                editingAnnouncement.value = ann
                announcementForm.title = ann.title
                announcementForm.content = ann.content
                announcementForm.type = ann.type
                announcementForm.is_active = ann.is_active
                showAnnouncementModal.value = true
            }

            const saveAnnouncement = async () => {
                try {
                    if (editingAnnouncement.value) {
                        await api.put(`/announcements/${editingAnnouncement.value.id}`, announcementForm)
                    } else {
                        await api.post('/announcements', announcementForm)
                    }
                    showAnnouncementModal.value = false
                    loadAnnouncements()
                } catch (e) {
                    alert(e.response?.data?.detail || '保存失败')
                }
            }

            const deleteAnnouncement = async (id) => {
                if (!confirm('确定删除此公告？')) return
                try {
                    await api.delete(`/announcements/${id}`)
                    loadAnnouncements()
                } catch (e) {
                    alert(e.response?.data?.detail || '删除失败')
                }
            }

            const toggleAnnouncement = async (ann) => {
                try {
                    await api.post(`/announcements/${ann.id}/toggle`)
                    loadAnnouncements()
                } catch (e) {
                    alert(e.response?.data?.detail || '操作失败')
                }
            }

            const announcementTypeClass = (type) => {
                const map = {
                    'info': 'bg-blue-100 text-blue-800',
                    'warning': 'bg-yellow-100 text-yellow-800',
                    'error': 'bg-red-100 text-red-800',
                    'success': 'bg-green-100 text-green-800'
                }
                return map[type] || 'bg-gray-100 text-gray-800'
            }

            const announcementTypeLabel = (type) => {
                const map = { 'info': '信息', 'warning': '警告', 'error': '错误', 'success': '成功' }
                return map[type] || type
            }

            // 辅助函数
            const getStatusClass = (status) => {
                const map = {
                    'active': 'bg-green-100 text-green-800',
                    'in_use': 'bg-blue-100 text-blue-800',
                    'disabled': 'bg-red-100 text-red-800',
                    'expired': 'bg-gray-100 text-gray-800'
                }
                return map[status] || 'bg-gray-100 text-gray-800'
            }

            const formatMembershipLabel = (type) => {
                if (!type) return '未知'
                return String(type).toUpperCase()
            }

            const getStatusText = (status) => {
                const map = { 'active': '可用', 'in_use': '使用中', 'disabled': '禁用', 'expired': '过期' }
                return map[status] || status
            }

            const formatDate = (date) => {
                return new Date(date).toLocaleString('zh-CN')
            }

            // 初始化
            onMounted(() => {
                const savedToken = localStorage.getItem('token')
                if (savedToken) {
                    token.value = savedToken
                    isLoggedIn.value = true
                    currentUser.value = 'admin'
                    loadData()
                }
            })

            // 监听标签页切换
            watch(currentTab, (newTab) => {
                if (newTab === 'announcements') {
                    loadAnnouncements()
                } else if (newTab !== 'settings' && newTab !== 'compensate') {
                    loadData()
                }
            })

            return {
                isLoggedIn, currentUser, currentTab, loginError, loginForm,
                stats, accounts, accountsTotal, selectedAccounts, accountsPagination, isAllSelected,
                keys, keysTotal, selectedKeys, keysPagination, isAllKeysSelected,
                logs, logFilter, keySearch,
                accountForm, keyForm,
                showAccountModal, showAnalyzeModal, showKeyModal, showImportModal, showQuotaModal, showExtendModal,
                showKeyDetailModal, keyDetail, keyDevices, keyLogs,
                editingAccount, editingKey, analyzeTarget,
                importData, importResult,
                quotaTarget, addQuotaAmount,
                extendTarget, extendDays,
                globalSettings,
                compensateForm, compensatePreview, compensateResult,
                announcements, showAnnouncementModal, editingAnnouncement, announcementForm,
                loadAnnouncements, openCreateAnnouncementModal, editAnnouncement, saveAnnouncement,
                deleteAnnouncement, toggleAnnouncement, announcementTypeClass, announcementTypeLabel,
                login, logout, loadData, loadAccounts, loadLogs, searchKeys, resetKeySearch,
                toggleSelectAll, batchEnableAccounts, batchDisableAccounts, batchDeleteAccounts,
                toggleSelectAllKeys, batchCopyKeys, batchEnableKeys, batchDisableKeys, batchDeleteKeys,
                openCreateAccountModal, editAccount, saveAccount, deleteAccount, importAccounts, toggleAccountStatus,
                openAnalyzeModal, closeAnalyzeModal, submitAnalyze,
                resetKeyForm, editKey, saveKey, deleteKey, addQuota, submitAddQuota, copyKey, copyToken,
                viewKeyDetail, deleteDevice, disableKey, enableKey,
                extendKey, submitExtend,
                analyzeForm, analyzeResult, analyzeLoading,
                loadSettings, saveSettings,
                previewCompensate, executeCompensate,
                getStatusClass, getStatusText, formatDate, formatMembershipLabel
            }
        }
    }).mount('#app')
    </script>
</body>
</html>
