From 4ebe6abd9643f30a4bfa50db0d8e1a71187a307e Mon Sep 17 00:00:00 2001 From: shaw Date: Tue, 5 Aug 2025 19:02:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E8=B4=A6=E6=88=B7=E6=97=B6=E5=88=86=E7=BB=84=E8=B0=83=E5=BA=A6?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E4=B8=8D=E7=94=9F=E6=95=88=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为 Claude Console 和 Gemini 账户的更新接口添加分组处理逻辑 - 处理账户类型变更时的分组关系(从旧分组移除,添加到新分组) - 修复前端编辑账户时分组 ID 的初始化问题 - 优化删除账户时自动从分组中移除的逻辑 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/routes/admin.js | 81 +++++++++++++++++++ .../src/components/accounts/AccountForm.vue | 23 +++--- 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index 45746eb5..843b3c6b 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -1252,6 +1252,38 @@ router.put('/claude-console-accounts/:accountId', authenticateAdmin, async (req, return res.status(400).json({ error: 'Priority must be between 1 and 100' }); } + // 验证accountType的有效性 + if (updates.accountType && !['shared', 'dedicated', 'group'].includes(updates.accountType)) { + return res.status(400).json({ error: 'Invalid account type. Must be "shared", "dedicated" or "group"' }); + } + + // 如果更新为分组类型,验证groupId + if (updates.accountType === 'group' && !updates.groupId) { + return res.status(400).json({ error: 'Group ID is required for group type accounts' }); + } + + // 获取账户当前信息以处理分组变更 + const currentAccount = await claudeConsoleAccountService.getAccount(accountId); + if (!currentAccount) { + return res.status(404).json({ error: 'Account not found' }); + } + + // 处理分组的变更 + if (updates.accountType !== undefined) { + // 如果之前是分组类型,需要从原分组中移除 + if (currentAccount.accountType === 'group') { + const oldGroup = await accountGroupService.getAccountGroup(accountId); + if (oldGroup) { + await accountGroupService.removeAccountFromGroup(accountId, oldGroup.id); + } + } + // 如果新类型是分组,添加到新分组 + if (updates.accountType === 'group' && updates.groupId) { + // Claude Console 账户在分组中被视为 'claude' 平台 + await accountGroupService.addAccountToGroup(accountId, updates.groupId, 'claude'); + } + } + await claudeConsoleAccountService.updateAccount(accountId, updates); logger.success(`📝 Admin updated Claude Console account: ${accountId}`); @@ -1267,6 +1299,15 @@ router.delete('/claude-console-accounts/:accountId', authenticateAdmin, async (r try { const { accountId } = req.params; + // 获取账户信息以检查是否在分组中 + const account = await claudeConsoleAccountService.getAccount(accountId); + if (account && account.accountType === 'group') { + const group = await accountGroupService.getAccountGroup(accountId); + if (group) { + await accountGroupService.removeAccountFromGroup(accountId, group.id); + } + } + await claudeConsoleAccountService.deleteAccount(accountId); logger.success(`🗑️ Admin deleted Claude Console account: ${accountId}`); @@ -1497,6 +1538,37 @@ router.put('/gemini-accounts/:accountId', authenticateAdmin, async (req, res) => const { accountId } = req.params; const updates = req.body; + // 验证accountType的有效性 + if (updates.accountType && !['shared', 'dedicated', 'group'].includes(updates.accountType)) { + return res.status(400).json({ error: 'Invalid account type. Must be "shared", "dedicated" or "group"' }); + } + + // 如果更新为分组类型,验证groupId + if (updates.accountType === 'group' && !updates.groupId) { + return res.status(400).json({ error: 'Group ID is required for group type accounts' }); + } + + // 获取账户当前信息以处理分组变更 + const currentAccount = await geminiAccountService.getAccount(accountId); + if (!currentAccount) { + return res.status(404).json({ error: 'Account not found' }); + } + + // 处理分组的变更 + if (updates.accountType !== undefined) { + // 如果之前是分组类型,需要从原分组中移除 + if (currentAccount.accountType === 'group') { + const oldGroup = await accountGroupService.getAccountGroup(accountId); + if (oldGroup) { + await accountGroupService.removeAccountFromGroup(accountId, oldGroup.id); + } + } + // 如果新类型是分组,添加到新分组 + if (updates.accountType === 'group' && updates.groupId) { + await accountGroupService.addAccountToGroup(accountId, updates.groupId, 'gemini'); + } + } + const updatedAccount = await geminiAccountService.updateAccount(accountId, updates); logger.success(`📝 Admin updated Gemini account: ${accountId}`); @@ -1512,6 +1584,15 @@ router.delete('/gemini-accounts/:accountId', authenticateAdmin, async (req, res) try { const { accountId } = req.params; + // 获取账户信息以检查是否在分组中 + const account = await geminiAccountService.getAccount(accountId); + if (account && account.accountType === 'group') { + const group = await accountGroupService.getAccountGroup(accountId); + if (group) { + await accountGroupService.removeAccountFromGroup(accountId, group.id); + } + } + await geminiAccountService.deleteAccount(accountId); logger.success(`🗑️ Admin deleted Gemini account: ${accountId}`); diff --git a/web/admin-spa/src/components/accounts/AccountForm.vue b/web/admin-spa/src/components/accounts/AccountForm.vue index 01ed2e69..4b674bbd 100644 --- a/web/admin-spa/src/components/accounts/AccountForm.vue +++ b/web/admin-spa/src/components/accounts/AccountForm.vue @@ -1395,15 +1395,20 @@ watch(() => props.account, (newAccount) => { if (newAccount.accountType === 'group') { // 先加载分组列表 loadGroups().then(() => { - // 查找账户所属的分组 - groups.value.forEach(group => { - apiClient.get(`/admin/account-groups/${group.id}/members`).then(response => { - const members = response.data || [] - if (members.some(m => m.id === newAccount.id)) { - form.value.groupId = group.id - } - }).catch(() => {}) - }) + // 如果账户有 groupInfo,直接使用它的 groupId + if (newAccount.groupInfo && newAccount.groupInfo.id) { + form.value.groupId = newAccount.groupInfo.id + } else { + // 否则查找账户所属的分组 + groups.value.forEach(group => { + apiClient.get(`/admin/account-groups/${group.id}/members`).then(response => { + const members = response.data || [] + if (members.some(m => m.id === newAccount.id)) { + form.value.groupId = group.id + } + }).catch(() => {}) + }) + } }) } }