From e2e621341cb42f4ec54465cce49406e9ea69ec4b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 1 Sep 2025 03:45:04 +0000 Subject: [PATCH 01/15] chore: sync VERSION file with release v1.1.124 [skip ci] --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 8c8b5087..59aa7594 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.123 +1.1.124 From 9c3fec7568c25fff9cc66116e1d30dda93e57ba0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 2 Sep 2025 06:49:02 +0000 Subject: [PATCH 02/15] chore: sync VERSION file with release v1.1.125 [skip ci] --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 59aa7594..599d6ff7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.1.124 +1.1.125 From e97315847273d3fc1d0571daf72b9aa82787aa52 Mon Sep 17 00:00:00 2001 From: Feng Yue <2525275@gmail.com> Date: Tue, 2 Sep 2025 16:16:43 +0800 Subject: [PATCH 03/15] show owner's name in apikey management page --- src/routes/admin.js | 25 +++++++++++++++++++++++++ web/admin-spa/src/views/ApiKeysView.vue | 10 ++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/routes/admin.js b/src/routes/admin.js index 9eac7135..36adfa73 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -63,6 +63,9 @@ router.get('/api-keys', authenticateAdmin, async (req, res) => { const { timeRange = 'all' } = req.query // all, 7days, monthly const apiKeys = await apiKeyService.getAllApiKeys() + // 获取用户服务来补充owner信息 + const userService = require('../services/userService') + // 根据时间范围计算查询模式 const now = new Date() const searchPatterns = [] @@ -313,6 +316,28 @@ router.get('/api-keys', authenticateAdmin, async (req, res) => { } } + // 为每个API Key添加owner的displayName + for (const apiKey of apiKeys) { + // 如果API Key有关联的用户ID,获取用户信息 + if (apiKey.userId) { + try { + const user = await userService.getUserById(apiKey.userId, false) + if (user) { + apiKey.ownerDisplayName = user.displayName || user.username || 'Unknown User' + } else { + apiKey.ownerDisplayName = 'Unknown User' + } + } catch (error) { + logger.debug(`无法获取用户 ${apiKey.userId} 的信息:`, error) + apiKey.ownerDisplayName = 'Unknown User' + } + } else { + // 如果没有userId,使用createdBy字段或默认为Admin + apiKey.ownerDisplayName = + apiKey.createdBy === 'admin' ? 'Admin' : apiKey.createdBy || 'Admin' + } + } + return res.json({ success: true, data: apiKeys }) } catch (error) { logger.error('❌ Failed to get API keys:', error) diff --git a/web/admin-spa/src/views/ApiKeysView.vue b/web/admin-spa/src/views/ApiKeysView.vue index 54a5b350..1499026c 100644 --- a/web/admin-spa/src/views/ApiKeysView.vue +++ b/web/admin-spa/src/views/ApiKeysView.vue @@ -402,6 +402,11 @@ 使用共享池 + +
+ + {{ key.ownerDisplayName }} +
@@ -1023,6 +1028,11 @@ 使用共享池 + +
+ + {{ key.ownerDisplayName }} +
From 7a9e4abdd574ae0a123990385053b54113a5aab1 Mon Sep 17 00:00:00 2001 From: Feng Yue <2525275@gmail.com> Date: Tue, 2 Sep 2025 17:17:06 +0800 Subject: [PATCH 04/15] admin now is able to reassign apikey to admin/user --- src/routes/admin.js | 86 ++++++++++++++++++- .../components/apikeys/EditApiKeyModal.vue | 63 +++++++++++++- 2 files changed, 144 insertions(+), 5 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index 36adfa73..954d2f98 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -24,6 +24,50 @@ const ProxyHelper = require('../utils/proxyHelper') const router = express.Router() +// 👥 用户管理 + +// 获取所有用户列表(用于API Key分配) +router.get('/users', authenticateAdmin, async (req, res) => { + try { + const userService = require('../services/userService') + const allUsers = await userService.getAllUsers() + + // 只返回活跃用户,并包含管理员选项 + const activeUsers = allUsers + .filter((user) => user.isActive) + .map((user) => ({ + id: user.id, + username: user.username, + displayName: user.displayName || user.username, + email: user.email, + role: user.role + })) + + // 添加Admin选项作为第一个 + const usersWithAdmin = [ + { + id: 'admin', + username: 'admin', + displayName: 'Admin', + email: '', + role: 'admin' + }, + ...activeUsers + ] + + return res.json({ + success: true, + data: usersWithAdmin + }) + } catch (error) { + logger.error('❌ Failed to get users list:', error) + return res.status(500).json({ + error: 'Failed to get users list', + message: error.message + }) + } +}) + // 🔑 API Keys 管理 // 调试:获取API Key费用详情 @@ -844,7 +888,8 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => { expiresAt, dailyCostLimit, weeklyOpusCostLimit, - tags + tags, + ownerId // 新增:所有者ID字段 } = req.body // 只允许更新指定字段 @@ -1014,6 +1059,45 @@ router.put('/api-keys/:keyId', authenticateAdmin, async (req, res) => { updates.isActive = isActive } + // 处理所有者变更 + if (ownerId !== undefined) { + const userService = require('../services/userService') + + if (ownerId === 'admin') { + // 分配给Admin + updates.userId = '' + updates.userUsername = '' + updates.createdBy = 'admin' + } else if (ownerId) { + // 分配给用户 + try { + const user = await userService.getUserById(ownerId, false) + if (!user) { + return res.status(400).json({ error: 'Invalid owner: User not found' }) + } + if (!user.isActive) { + return res.status(400).json({ error: 'Cannot assign to inactive user' }) + } + + // 设置新的所有者信息 + updates.userId = ownerId + updates.userUsername = user.username + updates.createdBy = user.username + + // 管理员重新分配时,不检查用户的API Key数量限制 + logger.info(`🔄 Admin reassigning API key ${keyId} to user ${user.username}`) + } catch (error) { + logger.error('Error fetching user for owner reassignment:', error) + return res.status(400).json({ error: 'Invalid owner ID' }) + } + } else { + // 清空所有者(分配给Admin) + updates.userId = '' + updates.userUsername = '' + updates.createdBy = 'admin' + } + } + await apiKeyService.updateApiKey(keyId, updates) logger.success(`📝 Admin updated API key: ${keyId}`) diff --git a/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue b/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue index f74b25f8..82e27447 100644 --- a/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue +++ b/web/admin-spa/src/components/apikeys/EditApiKeyModal.vue @@ -41,6 +41,26 @@

名称不可修改

+ +
+ + +

+ 分配此 API Key 给指定用户或管理员,管理员分配时不受用户 API Key 数量限制 +

+
+