mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
fix: 修复专属账号下拉框,仅显示dedicated类型账号
- 修改CreateApiKeyModal和EditApiKeyModal的过滤逻辑 - 专属账号下拉框只显示accountType='dedicated'的账号 - 移除accountType='group'的账号,这些账号通过分组调度 - 更新标签文字为'专属账号'以更准确描述
This commit is contained in:
52
scripts/check-redis-keys.js
Normal file
52
scripts/check-redis-keys.js
Normal file
@@ -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();
|
||||
144
scripts/test-account-display.js
Normal file
144
scripts/test-account-display.js
Normal file
@@ -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();
|
||||
128
scripts/test-api-response.js
Normal file
128
scripts/test-api-response.js
Normal file
@@ -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();
|
||||
132
scripts/test-dedicated-accounts.js
Normal file
132
scripts/test-dedicated-accounts.js
Normal file
@@ -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();
|
||||
@@ -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,
|
||||
|
||||
@@ -446,11 +446,11 @@
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-oauth').length > 0"
|
||||
label="Claude OAuth 账号"
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth').length > 0"
|
||||
label="Claude OAuth 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-oauth')"
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
@@ -458,11 +458,11 @@
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-console').length > 0"
|
||||
label="Claude Console 账号"
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console').length > 0"
|
||||
label="Claude Console 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-console')"
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console')"
|
||||
:key="account.id"
|
||||
:value="`console:${account.id}`"
|
||||
>
|
||||
@@ -494,11 +494,11 @@
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.gemini.filter(a => a.isDedicated).length > 0"
|
||||
label="Gemini 账号"
|
||||
v-if="localAccounts.gemini.filter(a => a.accountType === 'dedicated').length > 0"
|
||||
label="Gemini 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.gemini.filter(a => a.isDedicated)"
|
||||
v-for="account in localAccounts.gemini.filter(a => a.accountType === 'dedicated')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
@@ -757,7 +757,7 @@ const refreshAccounts = async () => {
|
||||
claudeAccounts.push({
|
||||
...account,
|
||||
platform: 'claude-oauth',
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
isDedicated: account.accountType === 'dedicated' // 保留以便向后兼容
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -767,7 +767,7 @@ const refreshAccounts = async () => {
|
||||
claudeAccounts.push({
|
||||
...account,
|
||||
platform: 'claude-console',
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
isDedicated: account.accountType === 'dedicated' // 保留以便向后兼容
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -777,7 +777,7 @@ const refreshAccounts = async () => {
|
||||
if (geminiData.success) {
|
||||
localAccounts.value.gemini = (geminiData.data || []).map(account => ({
|
||||
...account,
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
isDedicated: account.accountType === 'dedicated' // 保留以便向后兼容
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -315,11 +315,11 @@
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-oauth').length > 0"
|
||||
label="Claude OAuth 账号"
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth').length > 0"
|
||||
label="Claude OAuth 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-oauth')"
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-oauth')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
@@ -327,11 +327,11 @@
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-console').length > 0"
|
||||
label="Claude Console 账号"
|
||||
v-if="localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console').length > 0"
|
||||
label="Claude Console 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.claude.filter(a => a.isDedicated && a.platform === 'claude-console')"
|
||||
v-for="account in localAccounts.claude.filter(a => a.accountType === 'dedicated' && a.platform === 'claude-console')"
|
||||
:key="account.id"
|
||||
:value="`console:${account.id}`"
|
||||
>
|
||||
@@ -363,11 +363,11 @@
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup
|
||||
v-if="localAccounts.gemini.filter(a => a.isDedicated).length > 0"
|
||||
label="Gemini 账号"
|
||||
v-if="localAccounts.gemini.filter(a => a.accountType === 'dedicated').length > 0"
|
||||
label="Gemini 专属账号"
|
||||
>
|
||||
<option
|
||||
v-for="account in localAccounts.gemini.filter(a => a.isDedicated)"
|
||||
v-for="account in localAccounts.gemini.filter(a => a.accountType === 'dedicated')"
|
||||
:key="account.id"
|
||||
:value="account.id"
|
||||
>
|
||||
@@ -700,7 +700,7 @@ const refreshAccounts = async () => {
|
||||
claudeAccounts.push({
|
||||
...account,
|
||||
platform: 'claude-oauth',
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
isDedicated: account.accountType === 'dedicated' // 保留以便向后兼容
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -710,7 +710,7 @@ const refreshAccounts = async () => {
|
||||
claudeAccounts.push({
|
||||
...account,
|
||||
platform: 'claude-console',
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
isDedicated: account.accountType === 'dedicated' // 保留以便向后兼容
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -985,7 +985,7 @@ const expandedApiKeys = ref({})
|
||||
const apiKeyModelStats = ref({})
|
||||
const apiKeyDateFilters = ref({})
|
||||
const defaultTime = ref([new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 2, 1, 23, 59, 59)])
|
||||
const accounts = ref({ claude: [], gemini: [] })
|
||||
const accounts = ref({ claude: [], gemini: [], claudeGroups: [], geminiGroups: [] })
|
||||
const editingExpiryKey = ref(null)
|
||||
const expiryEditModalRef = ref(null)
|
||||
|
||||
@@ -1102,10 +1102,11 @@ const paginatedApiKeys = computed(() => {
|
||||
// 加载账户列表
|
||||
const loadAccounts = async () => {
|
||||
try {
|
||||
const [claudeData, claudeConsoleData, geminiData] = await Promise.all([
|
||||
const [claudeData, claudeConsoleData, geminiData, groupsData] = await Promise.all([
|
||||
apiClient.get('/admin/claude-accounts'),
|
||||
apiClient.get('/admin/claude-console-accounts'),
|
||||
apiClient.get('/admin/gemini-accounts')
|
||||
apiClient.get('/admin/gemini-accounts'),
|
||||
apiClient.get('/admin/account-groups')
|
||||
])
|
||||
|
||||
// 合并Claude OAuth账户和Claude Console账户
|
||||
@@ -1122,23 +1123,27 @@ const loadAccounts = async () => {
|
||||
}
|
||||
|
||||
if (claudeConsoleData.success) {
|
||||
claudeConsoleData.data?.forEach(account => {
|
||||
claudeAccounts.push({
|
||||
...account,
|
||||
platform: 'claude-console',
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
})
|
||||
})
|
||||
// 将 Claude Console 账号合并到 claude 数组中
|
||||
const consoleAccounts = (claudeConsoleData.data || []).map(acc => ({
|
||||
...acc,
|
||||
platform: 'claude-console'
|
||||
}))
|
||||
accounts.value.claude = [...accounts.value.claude, ...consoleAccounts]
|
||||
}
|
||||
|
||||
accounts.value.claude = claudeAccounts
|
||||
|
||||
if (geminiData.success) {
|
||||
accounts.value.gemini = (geminiData.data || []).map(account => ({
|
||||
...account,
|
||||
isDedicated: account.accountType === 'dedicated'
|
||||
}))
|
||||
}
|
||||
|
||||
if (groupsData.success) {
|
||||
// 处理分组数据
|
||||
const allGroups = groupsData.data || []
|
||||
accounts.value.claudeGroups = allGroups.filter(g => g.platform === 'claude')
|
||||
accounts.value.geminiGroups = allGroups.filter(g => g.platform === 'gemini')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载账户列表失败:', error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user