diff --git a/src/routes/admin.js b/src/routes/admin.js index e1ff4804..c09450c8 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -2361,16 +2361,24 @@ router.put('/claude-accounts/:accountId', authenticateAdmin, async (req, res) => const { accountId } = req.params const updates = req.body + // ✅ 【修改】映射字段名:前端的 expiresAt -> 后端的 subscriptionExpiresAt(提前到参数验证之前) + const mappedUpdates = mapExpiryField(updates, 'Claude', accountId) + // 验证priority的有效性 if ( - updates.priority !== undefined && - (typeof updates.priority !== 'number' || updates.priority < 1 || updates.priority > 100) + mappedUpdates.priority !== undefined && + (typeof mappedUpdates.priority !== 'number' || + mappedUpdates.priority < 1 || + mappedUpdates.priority > 100) ) { return res.status(400).json({ error: 'Priority must be a number between 1 and 100' }) } // 验证accountType的有效性 - if (updates.accountType && !['shared', 'dedicated', 'group'].includes(updates.accountType)) { + if ( + mappedUpdates.accountType && + !['shared', 'dedicated', 'group'].includes(mappedUpdates.accountType) + ) { return res .status(400) .json({ error: 'Invalid account type. Must be "shared", "dedicated" or "group"' }) @@ -2378,9 +2386,9 @@ router.put('/claude-accounts/:accountId', authenticateAdmin, async (req, res) => // 如果更新为分组类型,验证groupId或groupIds if ( - updates.accountType === 'group' && - !updates.groupId && - (!updates.groupIds || updates.groupIds.length === 0) + mappedUpdates.accountType === 'group' && + !mappedUpdates.groupId && + (!mappedUpdates.groupIds || mappedUpdates.groupIds.length === 0) ) { return res .status(400) @@ -2394,33 +2402,30 @@ router.put('/claude-accounts/:accountId', authenticateAdmin, async (req, res) => } // 处理分组的变更 - if (updates.accountType !== undefined) { + if (mappedUpdates.accountType !== undefined) { // 如果之前是分组类型,需要从所有分组中移除 if (currentAccount.accountType === 'group') { await accountGroupService.removeAccountFromAllGroups(accountId) } // 如果新类型是分组,添加到新分组 - if (updates.accountType === 'group') { + if (mappedUpdates.accountType === 'group') { // 处理多分组/单分组的兼容性 - if (Object.prototype.hasOwnProperty.call(updates, 'groupIds')) { - if (updates.groupIds && updates.groupIds.length > 0) { + if (Object.prototype.hasOwnProperty.call(mappedUpdates, 'groupIds')) { + if (mappedUpdates.groupIds && mappedUpdates.groupIds.length > 0) { // 使用多分组设置 - await accountGroupService.setAccountGroups(accountId, updates.groupIds, 'claude') + await accountGroupService.setAccountGroups(accountId, mappedUpdates.groupIds, 'claude') } else { // groupIds 为空数组,从所有分组中移除 await accountGroupService.removeAccountFromAllGroups(accountId) } - } else if (updates.groupId) { + } else if (mappedUpdates.groupId) { // 兼容单分组模式 - await accountGroupService.addAccountToGroup(accountId, updates.groupId, 'claude') + await accountGroupService.addAccountToGroup(accountId, mappedUpdates.groupId, 'claude') } } } - // 映射字段名:前端的expiresAt -> 后端的subscriptionExpiresAt - const mappedUpdates = mapExpiryField(updates, 'Claude', accountId) - await claudeAccountService.updateAccount(accountId, mappedUpdates) logger.success(`📝 Admin updated Claude account: ${accountId}`) diff --git a/src/services/ccrAccountService.js b/src/services/ccrAccountService.js index 4eff1812..fa967d58 100644 --- a/src/services/ccrAccountService.js +++ b/src/services/ccrAccountService.js @@ -913,6 +913,19 @@ class CcrAccountService { throw error } } + + /** + * ⏰ 检查账户订阅是否过期 + * @param {Object} account - 账户对象 + * @returns {boolean} - true: 已过期, false: 未过期 + */ + isSubscriptionExpired(account) { + if (!account.subscriptionExpiresAt) { + return false // 未设置视为永不过期 + } + const expiryDate = new Date(account.subscriptionExpiresAt) + return expiryDate <= new Date() + } } module.exports = new CcrAccountService() diff --git a/src/services/claudeConsoleAccountService.js b/src/services/claudeConsoleAccountService.js index 33dc5acc..dbdee522 100644 --- a/src/services/claudeConsoleAccountService.js +++ b/src/services/claudeConsoleAccountService.js @@ -1254,6 +1254,19 @@ class ClaudeConsoleAccountService { throw error } } + + /** + * ⏰ 检查账户订阅是否过期 + * @param {Object} account - 账户对象 + * @returns {boolean} - true: 已过期, false: 未过期 + */ + isSubscriptionExpired(account) { + if (!account.subscriptionExpiresAt) { + return false // 未设置视为永不过期 + } + const expiryDate = new Date(account.subscriptionExpiresAt) + return expiryDate <= new Date() + } } module.exports = new ClaudeConsoleAccountService() diff --git a/src/services/unifiedClaudeScheduler.js b/src/services/unifiedClaudeScheduler.js index 264f8737..42ab7546 100644 --- a/src/services/unifiedClaudeScheduler.js +++ b/src/services/unifiedClaudeScheduler.js @@ -546,15 +546,11 @@ class UnifiedClaudeScheduler { } // 检查订阅是否过期 - if (account.subscriptionExpiresAt) { - const expiryDate = new Date(account.subscriptionExpiresAt) - const now = new Date() - if (expiryDate <= now) { - logger.debug( - `⏰ Claude Console account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}` - ) - continue - } + if (claudeConsoleAccountService.isSubscriptionExpired(account)) { + logger.debug( + `⏰ Claude Console account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}` + ) + continue } // 主动触发一次额度检查,确保状态即时生效 @@ -655,15 +651,11 @@ class UnifiedClaudeScheduler { } // 检查订阅是否过期 - if (account.subscriptionExpiresAt) { - const expiryDate = new Date(account.subscriptionExpiresAt) - const now = new Date() - if (expiryDate <= now) { - logger.debug( - `⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}` - ) - continue - } + if (ccrAccountService.isSubscriptionExpired(account)) { + logger.debug( + `⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}` + ) + continue } // 检查是否被限流 @@ -799,15 +791,11 @@ class UnifiedClaudeScheduler { return false } // 检查订阅是否过期 - if (account.subscriptionExpiresAt) { - const expiryDate = new Date(account.subscriptionExpiresAt) - const now = new Date() - if (expiryDate <= now) { - logger.debug( - `⏰ Claude Console account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)` - ) - return false - } + if (claudeConsoleAccountService.isSubscriptionExpired(account)) { + logger.debug( + `⏰ Claude Console account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)` + ) + return false } // 检查是否超额 try { @@ -868,15 +856,11 @@ class UnifiedClaudeScheduler { return false } // 检查订阅是否过期 - if (account.subscriptionExpiresAt) { - const expiryDate = new Date(account.subscriptionExpiresAt) - const now = new Date() - if (expiryDate <= now) { - logger.debug( - `⏰ CCR account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)` - ) - return false - } + if (ccrAccountService.isSubscriptionExpired(account)) { + logger.debug( + `⏰ CCR account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)` + ) + return false } // 检查是否超额 try { @@ -1400,15 +1384,11 @@ class UnifiedClaudeScheduler { } // 检查订阅是否过期 - if (account.subscriptionExpiresAt) { - const expiryDate = new Date(account.subscriptionExpiresAt) - const now = new Date() - if (expiryDate <= now) { - logger.debug( - `⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}` - ) - continue - } + if (ccrAccountService.isSubscriptionExpired(account)) { + logger.debug( + `⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}` + ) + continue } // 检查是否被限流或超额