feat: 实现Claude账户专属绑定功能

- 添加账户类型(dedicated/shared)支持
- API Key可绑定专属账户,优先使用绑定账户
- 未绑定的API Key继续使用共享池和粘性会话
- 修复专属账户下拉框显示问题(isActive类型不匹配)
- 修复getBoundAccountName方法未定义错误
- 添加删除账户前的API Key绑定检查
- 完全保留原有粘性会话机制

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-17 08:50:12 +08:00
parent a64ced0e36
commit ee9bd4aea4
5 changed files with 293 additions and 28 deletions

View File

@@ -78,9 +78,9 @@ router.post('/api-keys', authenticateAdmin, async (req, res) => {
router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
try {
const { keyId } = req.params;
const { tokenLimit, concurrencyLimit } = req.body;
const { tokenLimit, concurrencyLimit, claudeAccountId } = req.body;
// 只允许更新tokenLimitconcurrencyLimit
// 只允许更新tokenLimitconcurrencyLimit和claudeAccountId
const updates = {};
if (tokenLimit !== undefined && tokenLimit !== null && tokenLimit !== '') {
@@ -97,6 +97,11 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => {
updates.concurrencyLimit = Number(concurrencyLimit);
}
if (claudeAccountId !== undefined) {
// 空字符串表示解绑null或空字符串都设置为空字符串
updates.claudeAccountId = claudeAccountId || '';
}
await apiKeyService.updateApiKey(keyId, updates);
logger.success(`📝 Admin updated API key: ${keyId}`);
@@ -244,13 +249,19 @@ router.post('/claude-accounts', authenticateAdmin, async (req, res) => {
password,
refreshToken,
claudeAiOauth,
proxy
proxy,
accountType
} = req.body;
if (!name) {
return res.status(400).json({ error: 'Name is required' });
}
// 验证accountType的有效性
if (accountType && !['shared', 'dedicated'].includes(accountType)) {
return res.status(400).json({ error: 'Invalid account type. Must be "shared" or "dedicated"' });
}
const newAccount = await claudeAccountService.createAccount({
name,
description,
@@ -258,10 +269,11 @@ router.post('/claude-accounts', authenticateAdmin, async (req, res) => {
password,
refreshToken,
claudeAiOauth,
proxy
proxy,
accountType: accountType || 'shared' // 默认为共享类型
});
logger.success(`🏢 Admin created new Claude account: ${name}`);
logger.success(`🏢 Admin created new Claude account: ${name} (${accountType || 'shared'})`);
res.json({ success: true, data: newAccount });
} catch (error) {
logger.error('❌ Failed to create Claude account:', error);