fix: 修复账号过期时间的一系列bug

This commit is contained in:
shaw
2025-10-12 18:35:05 +08:00
parent f513be4328
commit 40b7c68694
2 changed files with 113 additions and 13 deletions

View File

@@ -2795,7 +2795,14 @@ router.put('/claude-console-accounts/:accountId', authenticateAdmin, async (req,
}
}
await claudeConsoleAccountService.updateAccount(accountId, updates)
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt
const mappedUpdates = { ...updates }
if ('expiresAt' in mappedUpdates) {
mappedUpdates.subscriptionExpiresAt = mappedUpdates.expiresAt
delete mappedUpdates.expiresAt
}
await claudeConsoleAccountService.updateAccount(accountId, mappedUpdates)
logger.success(`📝 Admin updated Claude Console account: ${accountId}`)
return res.json({ success: true, message: 'Claude Console account updated successfully' })
@@ -3205,7 +3212,14 @@ router.put('/ccr-accounts/:accountId', authenticateAdmin, async (req, res) => {
}
}
await ccrAccountService.updateAccount(accountId, updates)
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt
const mappedUpdates = { ...updates }
if ('expiresAt' in mappedUpdates) {
mappedUpdates.subscriptionExpiresAt = mappedUpdates.expiresAt
delete mappedUpdates.expiresAt
}
await ccrAccountService.updateAccount(accountId, mappedUpdates)
logger.success(`📝 Admin updated CCR account: ${accountId}`)
return res.json({ success: true, message: 'CCR account updated successfully' })
@@ -3566,7 +3580,14 @@ router.put('/bedrock-accounts/:accountId', authenticateAdmin, async (req, res) =
})
}
const result = await bedrockAccountService.updateAccount(accountId, updates)
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt
const mappedUpdates = { ...updates }
if ('expiresAt' in mappedUpdates) {
mappedUpdates.subscriptionExpiresAt = mappedUpdates.expiresAt
delete mappedUpdates.expiresAt
}
const result = await bedrockAccountService.updateAccount(accountId, mappedUpdates)
if (!result.success) {
return res
@@ -3891,6 +3912,8 @@ router.get('/gemini-accounts', authenticateAdmin, async (req, res) => {
return {
...account,
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
expiresAt: account.subscriptionExpiresAt || null,
groupInfos,
usage: {
daily: usageStats.daily,
@@ -3908,6 +3931,8 @@ router.get('/gemini-accounts', authenticateAdmin, async (req, res) => {
const groupInfos = await accountGroupService.getAccountGroups(account.id)
return {
...account,
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
expiresAt: account.subscriptionExpiresAt || null,
groupInfos,
usage: {
daily: { tokens: 0, requests: 0, allTokens: 0 },
@@ -4032,7 +4057,14 @@ router.put('/gemini-accounts/:accountId', authenticateAdmin, async (req, res) =>
}
}
const updatedAccount = await geminiAccountService.updateAccount(accountId, updates)
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt
const mappedUpdates = { ...updates }
if ('expiresAt' in mappedUpdates) {
mappedUpdates.subscriptionExpiresAt = mappedUpdates.expiresAt
delete mappedUpdates.expiresAt
}
const updatedAccount = await geminiAccountService.updateAccount(accountId, mappedUpdates)
logger.success(`📝 Admin updated Gemini account: ${accountId}`)
return res.json({ success: true, data: updatedAccount })
@@ -7539,6 +7571,13 @@ router.put('/openai-accounts/:id', authenticateAdmin, async (req, res) => {
: currentAccount.emailVerified
}
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt (订阅过期时间)
// 注意:这里不影响上面 OAuth token 的 expiresAt 字段
if ('expiresAt' in updates && !updates.openaiOauth?.expires_in) {
updateData.subscriptionExpiresAt = updates.expiresAt
delete updateData.expiresAt
}
const updatedAccount = await openaiAccountService.updateAccount(id, updateData)
// 如果需要刷新但不强制成功(非关键更新)
@@ -7925,7 +7964,14 @@ router.put('/azure-openai-accounts/:id', authenticateAdmin, async (req, res) =>
const { id } = req.params
const updates = req.body
const account = await azureOpenaiAccountService.updateAccount(id, updates)
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt
const mappedUpdates = { ...updates }
if ('expiresAt' in mappedUpdates) {
mappedUpdates.subscriptionExpiresAt = mappedUpdates.expiresAt
delete mappedUpdates.expiresAt
}
const account = await azureOpenaiAccountService.updateAccount(id, mappedUpdates)
res.json({
success: true,
@@ -8298,7 +8344,14 @@ router.put('/openai-responses-accounts/:id', authenticateAdmin, async (req, res)
updates.priority = priority.toString()
}
const result = await openaiResponsesAccountService.updateAccount(id, updates)
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt
const mappedUpdates = { ...updates }
if ('expiresAt' in mappedUpdates) {
mappedUpdates.subscriptionExpiresAt = mappedUpdates.expiresAt
delete mappedUpdates.expiresAt
}
const result = await openaiResponsesAccountService.updateAccount(id, mappedUpdates)
if (!result.success) {
return res.status(400).json(result)
@@ -8664,6 +8717,9 @@ router.get('/droid-accounts', authenticateAdmin, async (req, res) => {
return {
...account,
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
// OAuth token 的原始 expiresAt 保留在内部使用
expiresAt: account.subscriptionExpiresAt || null,
schedulable: account.schedulable === 'true',
boundApiKeysCount,
groupInfos,
@@ -8677,6 +8733,8 @@ router.get('/droid-accounts', authenticateAdmin, async (req, res) => {
logger.warn(`Failed to get stats for Droid account ${account.id}:`, error.message)
return {
...account,
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
expiresAt: account.subscriptionExpiresAt || null,
boundApiKeysCount: 0,
groupInfos: [],
usage: {
@@ -8791,7 +8849,14 @@ router.put('/droid-accounts/:id', authenticateAdmin, async (req, res) => {
updates.accountType = targetAccountType
}
const account = await droidAccountService.updateAccount(id, updates)
// 映射字段名前端的expiresAt -> 后端的subscriptionExpiresAt
const mappedUpdates = { ...updates }
if ('expiresAt' in mappedUpdates) {
mappedUpdates.subscriptionExpiresAt = mappedUpdates.expiresAt
delete mappedUpdates.expiresAt
}
const account = await droidAccountService.updateAccount(id, mappedUpdates)
try {
if (currentAccount.accountType === 'group' && targetAccountType !== 'group') {

View File

@@ -3724,20 +3724,55 @@ const closeAccountExpiryEdit = () => {
editingExpiryAccount.value = null
}
// 根据账户平台解析更新端点
const resolveAccountUpdateEndpoint = (account) => {
switch (account.platform) {
case 'claude':
return `/admin/claude-accounts/${account.id}`
case 'claude-console':
return `/admin/claude-console-accounts/${account.id}`
case 'bedrock':
return `/admin/bedrock-accounts/${account.id}`
case 'openai':
return `/admin/openai-accounts/${account.id}`
case 'azure_openai':
return `/admin/azure-openai-accounts/${account.id}`
case 'openai-responses':
return `/admin/openai-responses-accounts/${account.id}`
case 'ccr':
return `/admin/ccr-accounts/${account.id}`
case 'gemini':
return `/admin/gemini-accounts/${account.id}`
case 'droid':
return `/admin/droid-accounts/${account.id}`
default:
throw new Error(`Unsupported platform: ${account.platform}`)
}
}
// 保存账户过期时间
const handleSaveAccountExpiry = async ({ accountId, expiresAt }) => {
try {
const data = await apiClient.put(`/admin/claude-accounts/${accountId}`, {
// 找到对应的账户以获取平台信息
const account = accounts.value.find((acc) => acc.id === accountId)
if (!account) {
showToast('账户不存在', 'error')
if (expiryEditModalRef.value) {
expiryEditModalRef.value.resetSaving()
}
return
}
// 根据平台动态选择端点
const endpoint = resolveAccountUpdateEndpoint(account)
const data = await apiClient.put(endpoint, {
expiresAt: expiresAt || null
})
if (data.success) {
showToast('账户到期时间已更新', 'success')
// 更新本地数据
const account = accounts.value.find((acc) => acc.id === accountId)
if (account) {
account.expiresAt = expiresAt || null
}
closeAccountExpiryEdit()
} else {
showToast(data.message || '更新失败', 'error')
@@ -3747,7 +3782,7 @@ const handleSaveAccountExpiry = async ({ accountId, expiresAt }) => {
}
}
} catch (error) {
showToast('更新失败', 'error')
showToast(error.message || '更新失败', 'error')
// 重置保存状态
if (expiryEditModalRef.value) {
expiryEditModalRef.value.resetSaving()