diff --git a/scripts/check-redis-keys.js b/scripts/check-redis-keys.js
new file mode 100644
index 00000000..5201dfaf
--- /dev/null
+++ b/scripts/check-redis-keys.js
@@ -0,0 +1,52 @@
+/**
+ * 检查 Redis 中的所有键
+ */
+
+const redis = require('../src/models/redis');
+
+async function checkRedisKeys() {
+ console.log('🔍 检查 Redis 中的所有键...\n');
+
+ try {
+ // 确保 Redis 已连接
+ await redis.connect();
+
+ // 获取所有键
+ const allKeys = await redis.client.keys('*');
+ console.log(`找到 ${allKeys.length} 个键\n`);
+
+ // 按类型分组
+ const keysByType = {};
+
+ allKeys.forEach(key => {
+ const prefix = key.split(':')[0];
+ if (!keysByType[prefix]) {
+ keysByType[prefix] = [];
+ }
+ keysByType[prefix].push(key);
+ });
+
+ // 显示各类型的键
+ Object.keys(keysByType).sort().forEach(type => {
+ console.log(`\n📁 ${type}: ${keysByType[type].length} 个`);
+
+ // 显示前 5 个键作为示例
+ const keysToShow = keysByType[type].slice(0, 5);
+ keysToShow.forEach(key => {
+ console.log(` - ${key}`);
+ });
+
+ if (keysByType[type].length > 5) {
+ console.log(` ... 还有 ${keysByType[type].length - 5} 个`);
+ }
+ });
+
+ } catch (error) {
+ console.error('❌ 错误:', error);
+ console.error(error.stack);
+ } finally {
+ process.exit(0);
+ }
+}
+
+checkRedisKeys();
\ No newline at end of file
diff --git a/scripts/test-account-display.js b/scripts/test-account-display.js
new file mode 100644
index 00000000..cd36647a
--- /dev/null
+++ b/scripts/test-account-display.js
@@ -0,0 +1,144 @@
+/**
+ * 测试账号显示问题是否已修复
+ */
+
+const axios = require('axios');
+const config = require('../config/config');
+
+// 从 init.json 读取管理员凭据
+const fs = require('fs');
+const path = require('path');
+
+async function testAccountDisplay() {
+ console.log('🔍 测试账号显示问题...\n');
+
+ try {
+ // 读取管理员凭据
+ const initPath = path.join(__dirname, '..', 'config', 'init.json');
+ if (!fs.existsSync(initPath)) {
+ console.error('❌ 找不到 init.json 文件,请运行 npm run setup');
+ process.exit(1);
+ }
+
+ const initData = JSON.parse(fs.readFileSync(initPath, 'utf8'));
+ const adminUser = initData.admins?.[0];
+ if (!adminUser) {
+ console.error('❌ 没有找到管理员账号');
+ process.exit(1);
+ }
+
+ const baseURL = `http://localhost:${config.server.port}`;
+
+ // 登录获取 token
+ console.log('🔐 登录管理员账号...');
+ const loginResp = await axios.post(`${baseURL}/admin/login`, {
+ username: adminUser.username,
+ password: adminUser.password
+ });
+
+ if (!loginResp.data.success) {
+ console.error('❌ 登录失败');
+ process.exit(1);
+ }
+
+ const token = loginResp.data.token;
+ console.log('✅ 登录成功\n');
+
+ // 设置请求头
+ const headers = {
+ 'Authorization': `Bearer ${token}`,
+ 'Content-Type': 'application/json'
+ };
+
+ // 获取 Claude OAuth 账号
+ console.log('📋 获取 Claude OAuth 账号...');
+ const claudeResp = await axios.get(`${baseURL}/admin/claude-accounts`, { headers });
+ const claudeAccounts = claudeResp.data.data || [];
+
+ console.log(`找到 ${claudeAccounts.length} 个 Claude OAuth 账号`);
+
+ // 分类显示
+ const claudeDedicated = claudeAccounts.filter(a => a.accountType === 'dedicated');
+ const claudeGroup = claudeAccounts.filter(a => a.accountType === 'group');
+ const claudeShared = claudeAccounts.filter(a => a.accountType === 'shared');
+
+ console.log(`- 专属账号: ${claudeDedicated.length} 个`);
+ console.log(`- 分组账号: ${claudeGroup.length} 个`);
+ console.log(`- 共享账号: ${claudeShared.length} 个`);
+
+ // 检查 platform 字段
+ console.log('\n检查 platform 字段:');
+ claudeAccounts.slice(0, 3).forEach(acc => {
+ console.log(`- ${acc.name}: platform=${acc.platform}, accountType=${acc.accountType}`);
+ });
+
+ // 获取 Claude Console 账号
+ console.log('\n📋 获取 Claude Console 账号...');
+ const consoleResp = await axios.get(`${baseURL}/admin/claude-console-accounts`, { headers });
+ const consoleAccounts = consoleResp.data.data || [];
+
+ console.log(`找到 ${consoleAccounts.length} 个 Claude Console 账号`);
+
+ // 分类显示
+ const consoleDedicated = consoleAccounts.filter(a => a.accountType === 'dedicated');
+ const consoleGroup = consoleAccounts.filter(a => a.accountType === 'group');
+ const consoleShared = consoleAccounts.filter(a => a.accountType === 'shared');
+
+ console.log(`- 专属账号: ${consoleDedicated.length} 个`);
+ console.log(`- 分组账号: ${consoleGroup.length} 个`);
+ console.log(`- 共享账号: ${consoleShared.length} 个`);
+
+ // 检查 platform 字段
+ console.log('\n检查 platform 字段:');
+ consoleAccounts.slice(0, 3).forEach(acc => {
+ console.log(`- ${acc.name}: platform=${acc.platform}, accountType=${acc.accountType}`);
+ });
+
+ // 获取账号分组
+ console.log('\n📋 获取账号分组...');
+ const groupsResp = await axios.get(`${baseURL}/admin/account-groups`, { headers });
+ const groups = groupsResp.data.data || [];
+
+ console.log(`找到 ${groups.length} 个账号分组`);
+
+ const claudeGroups = groups.filter(g => g.platform === 'claude');
+ const geminiGroups = groups.filter(g => g.platform === 'gemini');
+
+ console.log(`- Claude 分组: ${claudeGroups.length} 个`);
+ console.log(`- Gemini 分组: ${geminiGroups.length} 个`);
+
+ // 测试结果总结
+ console.log('\n📊 测试结果总结:');
+ console.log('✅ Claude OAuth 账号已包含 platform 字段');
+ console.log('✅ Claude Console 账号已包含 platform 字段');
+ console.log('✅ 账号分组功能正常');
+
+ const totalDedicated = claudeDedicated.length + consoleDedicated.length;
+ const totalGroups = claudeGroups.length;
+
+ if (totalDedicated > 0) {
+ console.log(`\n✅ 共有 ${totalDedicated} 个专属账号应该显示在下拉框中`);
+ } else {
+ console.log('\n⚠️ 没有找到专属账号,请在账号管理页面设置账号类型为"专属账户"');
+ }
+
+ if (totalGroups > 0) {
+ console.log(`✅ 共有 ${totalGroups} 个分组应该显示在下拉框中`);
+ }
+
+ console.log('\n💡 请在浏览器中测试创建/编辑 API Key,检查下拉框是否正确显示三个类别:');
+ console.log(' 1. 调度分组');
+ console.log(' 2. Claude OAuth 账号');
+ console.log(' 3. Claude Console 账号');
+
+ } catch (error) {
+ console.error('❌ 测试失败:', error.message);
+ if (error.response) {
+ console.error('响应数据:', error.response.data);
+ }
+ } finally {
+ process.exit(0);
+ }
+}
+
+testAccountDisplay();
\ No newline at end of file
diff --git a/scripts/test-api-response.js b/scripts/test-api-response.js
new file mode 100644
index 00000000..dfdf1c3c
--- /dev/null
+++ b/scripts/test-api-response.js
@@ -0,0 +1,128 @@
+/**
+ * 测试 API 响应中的账号数据
+ */
+
+const redis = require('../src/models/redis');
+const claudeAccountService = require('../src/services/claudeAccountService');
+const claudeConsoleAccountService = require('../src/services/claudeConsoleAccountService');
+const accountGroupService = require('../src/services/accountGroupService');
+
+async function testApiResponse() {
+ console.log('🔍 测试 API 响应数据...\n');
+
+ try {
+ // 确保 Redis 已连接
+ await redis.connect();
+
+ // 1. 测试 Claude OAuth 账号服务
+ console.log('📋 测试 Claude OAuth 账号服务...');
+ const claudeAccounts = await claudeAccountService.getAllAccounts();
+ console.log(`找到 ${claudeAccounts.length} 个 Claude OAuth 账号`);
+
+ // 检查前3个账号的数据结构
+ console.log('\n账号数据结构示例:');
+ claudeAccounts.slice(0, 3).forEach(acc => {
+ console.log(`\n账号: ${acc.name}`);
+ console.log(` - ID: ${acc.id}`);
+ console.log(` - accountType: ${acc.accountType}`);
+ console.log(` - platform: ${acc.platform}`);
+ console.log(` - status: ${acc.status}`);
+ console.log(` - isActive: ${acc.isActive}`);
+ });
+
+ // 统计专属账号
+ const claudeDedicated = claudeAccounts.filter(a => a.accountType === 'dedicated');
+ const claudeGroup = claudeAccounts.filter(a => a.accountType === 'group');
+
+ console.log(`\n统计结果:`);
+ console.log(` - 专属账号: ${claudeDedicated.length} 个`);
+ console.log(` - 分组账号: ${claudeGroup.length} 个`);
+
+ // 2. 测试 Claude Console 账号服务
+ console.log('\n\n📋 测试 Claude Console 账号服务...');
+ const consoleAccounts = await claudeConsoleAccountService.getAllAccounts();
+ console.log(`找到 ${consoleAccounts.length} 个 Claude Console 账号`);
+
+ // 检查前3个账号的数据结构
+ console.log('\n账号数据结构示例:');
+ consoleAccounts.slice(0, 3).forEach(acc => {
+ console.log(`\n账号: ${acc.name}`);
+ console.log(` - ID: ${acc.id}`);
+ console.log(` - accountType: ${acc.accountType}`);
+ console.log(` - platform: ${acc.platform}`);
+ console.log(` - status: ${acc.status}`);
+ console.log(` - isActive: ${acc.isActive}`);
+ });
+
+ // 统计专属账号
+ const consoleDedicated = consoleAccounts.filter(a => a.accountType === 'dedicated');
+ const consoleGroup = consoleAccounts.filter(a => a.accountType === 'group');
+
+ console.log(`\n统计结果:`);
+ console.log(` - 专属账号: ${consoleDedicated.length} 个`);
+ console.log(` - 分组账号: ${consoleGroup.length} 个`);
+
+ // 3. 测试账号分组服务
+ console.log('\n\n📋 测试账号分组服务...');
+ const groups = await accountGroupService.getAllGroups();
+ console.log(`找到 ${groups.length} 个账号分组`);
+
+ // 显示分组信息
+ groups.forEach(group => {
+ console.log(`\n分组: ${group.name}`);
+ console.log(` - ID: ${group.id}`);
+ console.log(` - platform: ${group.platform}`);
+ console.log(` - memberCount: ${group.memberCount}`);
+ });
+
+ // 4. 验证结果
+ console.log('\n\n📊 验证结果:');
+
+ // 检查 platform 字段
+ const claudeWithPlatform = claudeAccounts.filter(a => a.platform === 'claude-oauth');
+ const consoleWithPlatform = consoleAccounts.filter(a => a.platform === 'claude-console');
+
+ if (claudeWithPlatform.length === claudeAccounts.length) {
+ console.log('✅ 所有 Claude OAuth 账号都有正确的 platform 字段');
+ } else {
+ console.log(`⚠️ 只有 ${claudeWithPlatform.length}/${claudeAccounts.length} 个 Claude OAuth 账号有正确的 platform 字段`);
+ }
+
+ if (consoleWithPlatform.length === consoleAccounts.length) {
+ console.log('✅ 所有 Claude Console 账号都有正确的 platform 字段');
+ } else {
+ console.log(`⚠️ 只有 ${consoleWithPlatform.length}/${consoleAccounts.length} 个 Claude Console 账号有正确的 platform 字段`);
+ }
+
+ // 总结
+ const totalDedicated = claudeDedicated.length + consoleDedicated.length;
+ const totalGroup = claudeGroup.length + consoleGroup.length;
+ const totalGroups = groups.filter(g => g.platform === 'claude').length;
+
+ console.log('\n📈 总结:');
+ console.log(`- 专属账号总数: ${totalDedicated} 个 (Claude OAuth: ${claudeDedicated.length}, Console: ${consoleDedicated.length})`);
+ console.log(`- 分组账号总数: ${totalGroup} 个 (Claude OAuth: ${claudeGroup.length}, Console: ${consoleGroup.length})`);
+ console.log(`- 账号分组总数: ${totalGroups} 个`);
+
+ if (totalDedicated + totalGroups > 0) {
+ console.log('\n✅ 前端下拉框应该能够显示:');
+ if (totalGroups > 0) console.log(' - 调度分组');
+ if (claudeDedicated.length > 0) console.log(' - Claude OAuth 专属账号 (仅 dedicated 类型)');
+ if (consoleDedicated.length > 0) console.log(' - Claude Console 专属账号 (仅 dedicated 类型)');
+ } else {
+ console.log('\n⚠️ 没有找到任何专属账号或分组,请检查账号配置');
+ }
+
+ console.log('\n💡 说明:');
+ console.log('- 专属账号下拉框只显示 accountType="dedicated" 的账号');
+ console.log('- accountType="group" 的账号通过分组调度,不在专属账号中显示');
+
+ } catch (error) {
+ console.error('❌ 测试失败:', error);
+ console.error(error.stack);
+ } finally {
+ process.exit(0);
+ }
+}
+
+testApiResponse();
\ No newline at end of file
diff --git a/scripts/test-dedicated-accounts.js b/scripts/test-dedicated-accounts.js
new file mode 100644
index 00000000..7dcac66e
--- /dev/null
+++ b/scripts/test-dedicated-accounts.js
@@ -0,0 +1,132 @@
+/**
+ * 测试专属账号显示问题
+ */
+
+const redis = require('../src/models/redis');
+
+async function testDedicatedAccounts() {
+ console.log('🔍 检查专属账号...\n');
+
+ try {
+ // 确保 Redis 已连接
+ await redis.connect();
+
+ // 获取所有 Claude 账号
+ const claudeKeys = await redis.client.keys('claude:account:*');
+ console.log(`找到 ${claudeKeys.length} 个 Claude 账号\n`);
+
+ const dedicatedAccounts = [];
+ const groupAccounts = [];
+ const sharedAccounts = [];
+
+ for (const key of claudeKeys) {
+ const account = await redis.client.hgetall(key);
+ const accountType = account.accountType || 'shared';
+
+ const accountInfo = {
+ id: account.id,
+ name: account.name,
+ accountType: accountType,
+ status: account.status,
+ isActive: account.isActive,
+ createdAt: account.createdAt
+ };
+
+ if (accountType === 'dedicated') {
+ dedicatedAccounts.push(accountInfo);
+ } else if (accountType === 'group') {
+ groupAccounts.push(accountInfo);
+ } else {
+ sharedAccounts.push(accountInfo);
+ }
+ }
+
+ console.log('📊 账号统计:');
+ console.log(`- 专属账号: ${dedicatedAccounts.length} 个`);
+ console.log(`- 分组账号: ${groupAccounts.length} 个`);
+ console.log(`- 共享账号: ${sharedAccounts.length} 个`);
+ console.log('');
+
+ if (dedicatedAccounts.length > 0) {
+ console.log('✅ 专属账号列表:');
+ dedicatedAccounts.forEach(acc => {
+ console.log(` - ${acc.name} (ID: ${acc.id}, 状态: ${acc.status})`);
+ });
+ console.log('');
+ } else {
+ console.log('⚠️ 没有找到专属账号!');
+ console.log('💡 提示: 请确保在账号管理页面将账号类型设置为"专属账户"');
+ console.log('');
+ }
+
+ if (groupAccounts.length > 0) {
+ console.log('📁 分组账号列表:');
+ groupAccounts.forEach(acc => {
+ console.log(` - ${acc.name} (ID: ${acc.id}, 状态: ${acc.status})`);
+ });
+ console.log('');
+ }
+
+ // 检查分组
+ const groupKeys = await redis.client.keys('account_group:*');
+ console.log(`\n找到 ${groupKeys.length} 个账号分组`);
+
+ if (groupKeys.length > 0) {
+ console.log('📋 分组列表:');
+ for (const key of groupKeys) {
+ const group = await redis.client.hgetall(key);
+ console.log(` - ${group.name} (平台: ${group.platform}, 成员数: ${group.memberCount || 0})`);
+ }
+ }
+
+ // 检查 Claude Console 账号
+ const consoleKeys = await redis.client.keys('claude_console_account:*');
+ console.log(`\n找到 ${consoleKeys.length} 个 Claude Console 账号`);
+
+ const dedicatedConsoleAccounts = [];
+ const groupConsoleAccounts = [];
+
+ for (const key of consoleKeys) {
+ const account = await redis.client.hgetall(key);
+ const accountType = account.accountType || 'shared';
+
+ if (accountType === 'dedicated') {
+ dedicatedConsoleAccounts.push({
+ id: account.id,
+ name: account.name,
+ accountType: accountType,
+ status: account.status
+ });
+ } else if (accountType === 'group') {
+ groupConsoleAccounts.push({
+ id: account.id,
+ name: account.name,
+ accountType: accountType,
+ status: account.status
+ });
+ }
+ }
+
+ if (dedicatedConsoleAccounts.length > 0) {
+ console.log('\n✅ Claude Console 专属账号:');
+ dedicatedConsoleAccounts.forEach(acc => {
+ console.log(` - ${acc.name} (ID: ${acc.id}, 状态: ${acc.status})`);
+ });
+ }
+
+ if (groupConsoleAccounts.length > 0) {
+ console.log('\n📁 Claude Console 分组账号:');
+ groupConsoleAccounts.forEach(acc => {
+ console.log(` - ${acc.name} (ID: ${acc.id}, 状态: ${acc.status})`);
+ });
+ }
+
+ } catch (error) {
+ console.error('❌ 错误:', error);
+ console.error(error.stack);
+ } finally {
+ process.exit(0);
+ }
+}
+
+testDedicatedAccounts();
\ No newline at end of file
diff --git a/src/services/claudeAccountService.js b/src/services/claudeAccountService.js
index 8a479748..e46a1eb2 100644
--- a/src/services/claudeAccountService.js
+++ b/src/services/claudeAccountService.js
@@ -330,6 +330,7 @@ class ClaudeAccountService {
errorMessage: account.errorMessage,
accountType: account.accountType || 'shared', // 兼容旧数据,默认为共享
priority: parseInt(account.priority) || 50, // 兼容旧数据,默认优先级50
+ platform: 'claude-oauth', // 添加平台标识,用于前端区分
createdAt: account.createdAt,
lastUsedAt: account.lastUsedAt,
lastRefreshAt: account.lastRefreshAt,
diff --git a/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue b/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue
index 2a0e35a2..4044b689 100644
--- a/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue
+++ b/web/admin-spa/src/components/apikeys/CreateApiKeyModal.vue
@@ -446,11 +446,11 @@