mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-24 09:24:46 +00:00
fix: 修复账号过期时间的一系列bug
This commit is contained in:
@@ -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}`)
|
logger.success(`📝 Admin updated Claude Console account: ${accountId}`)
|
||||||
return res.json({ success: true, message: 'Claude Console account updated successfully' })
|
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}`)
|
logger.success(`📝 Admin updated CCR account: ${accountId}`)
|
||||||
return res.json({ success: true, message: 'CCR account updated successfully' })
|
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) {
|
if (!result.success) {
|
||||||
return res
|
return res
|
||||||
@@ -3891,6 +3912,8 @@ router.get('/gemini-accounts', authenticateAdmin, async (req, res) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...account,
|
...account,
|
||||||
|
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
|
||||||
|
expiresAt: account.subscriptionExpiresAt || null,
|
||||||
groupInfos,
|
groupInfos,
|
||||||
usage: {
|
usage: {
|
||||||
daily: usageStats.daily,
|
daily: usageStats.daily,
|
||||||
@@ -3908,6 +3931,8 @@ router.get('/gemini-accounts', authenticateAdmin, async (req, res) => {
|
|||||||
const groupInfos = await accountGroupService.getAccountGroups(account.id)
|
const groupInfos = await accountGroupService.getAccountGroups(account.id)
|
||||||
return {
|
return {
|
||||||
...account,
|
...account,
|
||||||
|
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
|
||||||
|
expiresAt: account.subscriptionExpiresAt || null,
|
||||||
groupInfos,
|
groupInfos,
|
||||||
usage: {
|
usage: {
|
||||||
daily: { tokens: 0, requests: 0, allTokens: 0 },
|
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}`)
|
logger.success(`📝 Admin updated Gemini account: ${accountId}`)
|
||||||
return res.json({ success: true, data: updatedAccount })
|
return res.json({ success: true, data: updatedAccount })
|
||||||
@@ -7539,6 +7571,13 @@ router.put('/openai-accounts/:id', authenticateAdmin, async (req, res) => {
|
|||||||
: currentAccount.emailVerified
|
: 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)
|
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 { id } = req.params
|
||||||
const updates = req.body
|
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({
|
res.json({
|
||||||
success: true,
|
success: true,
|
||||||
@@ -8298,7 +8344,14 @@ router.put('/openai-responses-accounts/:id', authenticateAdmin, async (req, res)
|
|||||||
updates.priority = priority.toString()
|
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) {
|
if (!result.success) {
|
||||||
return res.status(400).json(result)
|
return res.status(400).json(result)
|
||||||
@@ -8664,6 +8717,9 @@ router.get('/droid-accounts', authenticateAdmin, async (req, res) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...account,
|
...account,
|
||||||
|
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
|
||||||
|
// OAuth token 的原始 expiresAt 保留在内部使用
|
||||||
|
expiresAt: account.subscriptionExpiresAt || null,
|
||||||
schedulable: account.schedulable === 'true',
|
schedulable: account.schedulable === 'true',
|
||||||
boundApiKeysCount,
|
boundApiKeysCount,
|
||||||
groupInfos,
|
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)
|
logger.warn(`Failed to get stats for Droid account ${account.id}:`, error.message)
|
||||||
return {
|
return {
|
||||||
...account,
|
...account,
|
||||||
|
// 映射字段:使用 subscriptionExpiresAt 作为前端显示的 expiresAt
|
||||||
|
expiresAt: account.subscriptionExpiresAt || null,
|
||||||
boundApiKeysCount: 0,
|
boundApiKeysCount: 0,
|
||||||
groupInfos: [],
|
groupInfos: [],
|
||||||
usage: {
|
usage: {
|
||||||
@@ -8791,7 +8849,14 @@ router.put('/droid-accounts/:id', authenticateAdmin, async (req, res) => {
|
|||||||
updates.accountType = targetAccountType
|
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 {
|
try {
|
||||||
if (currentAccount.accountType === 'group' && targetAccountType !== 'group') {
|
if (currentAccount.accountType === 'group' && targetAccountType !== 'group') {
|
||||||
|
|||||||
@@ -3724,20 +3724,55 @@ const closeAccountExpiryEdit = () => {
|
|||||||
editingExpiryAccount.value = null
|
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 }) => {
|
const handleSaveAccountExpiry = async ({ accountId, expiresAt }) => {
|
||||||
try {
|
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
|
expiresAt: expiresAt || null
|
||||||
})
|
})
|
||||||
|
|
||||||
if (data.success) {
|
if (data.success) {
|
||||||
showToast('账户到期时间已更新', 'success')
|
showToast('账户到期时间已更新', 'success')
|
||||||
// 更新本地数据
|
// 更新本地数据
|
||||||
const account = accounts.value.find((acc) => acc.id === accountId)
|
account.expiresAt = expiresAt || null
|
||||||
if (account) {
|
|
||||||
account.expiresAt = expiresAt || null
|
|
||||||
}
|
|
||||||
closeAccountExpiryEdit()
|
closeAccountExpiryEdit()
|
||||||
} else {
|
} else {
|
||||||
showToast(data.message || '更新失败', 'error')
|
showToast(data.message || '更新失败', 'error')
|
||||||
@@ -3747,7 +3782,7 @@ const handleSaveAccountExpiry = async ({ accountId, expiresAt }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast('更新失败', 'error')
|
showToast(error.message || '更新失败', 'error')
|
||||||
// 重置保存状态
|
// 重置保存状态
|
||||||
if (expiryEditModalRef.value) {
|
if (expiryEditModalRef.value) {
|
||||||
expiryEditModalRef.value.resetSaving()
|
expiryEditModalRef.value.resetSaving()
|
||||||
|
|||||||
Reference in New Issue
Block a user