mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 00:53:33 +00:00
refactor: 优化账户过期检查逻辑和代码一致性
## 主要改进 ### 1. 添加缺失的过期检查方法 - 在 `claudeConsoleAccountService` 中添加 `isSubscriptionExpired()` 方法 - 在 `ccrAccountService` 中添加 `isSubscriptionExpired()` 方法 - 与其他 7 个账户服务保持一致的实现方式 ### 2. 统一过期检查逻辑 - 重构 `unifiedClaudeScheduler` 中的 5 处手动日期检查代码 - 统一调用服务层的 `isSubscriptionExpired()` 方法 - 消除重复代码,提升可维护性 ### 3. 统一字段映射顺序 - 调整 Claude 账户更新端点的 `mapExpiryField()` 调用时机 - 与其他账户类型保持一致的处理顺序 - 提升代码可读性和一致性 ## 技术细节 **修改文件**: - `src/services/claudeConsoleAccountService.js`: 添加 `isSubscriptionExpired()` - `src/services/ccrAccountService.js`: 添加 `isSubscriptionExpired()` - `src/services/unifiedClaudeScheduler.js`: 5 处调用统一为服务方法 - `src/routes/admin.js`: 统一字段映射顺序 **改进效果**: - ✅ 代码一致性提升:所有账户服务统一实现 - ✅ 可维护性提升:过期逻辑集中管理 - ✅ 减少重复代码:消除 4 处重复实现 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -2361,16 +2361,24 @@ router.put('/claude-accounts/:accountId', authenticateAdmin, async (req, res) =>
|
|||||||
const { accountId } = req.params
|
const { accountId } = req.params
|
||||||
const updates = req.body
|
const updates = req.body
|
||||||
|
|
||||||
|
// ✅ 【修改】映射字段名:前端的 expiresAt -> 后端的 subscriptionExpiresAt(提前到参数验证之前)
|
||||||
|
const mappedUpdates = mapExpiryField(updates, 'Claude', accountId)
|
||||||
|
|
||||||
// 验证priority的有效性
|
// 验证priority的有效性
|
||||||
if (
|
if (
|
||||||
updates.priority !== undefined &&
|
mappedUpdates.priority !== undefined &&
|
||||||
(typeof updates.priority !== 'number' || updates.priority < 1 || updates.priority > 100)
|
(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' })
|
return res.status(400).json({ error: 'Priority must be a number between 1 and 100' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证accountType的有效性
|
// 验证accountType的有效性
|
||||||
if (updates.accountType && !['shared', 'dedicated', 'group'].includes(updates.accountType)) {
|
if (
|
||||||
|
mappedUpdates.accountType &&
|
||||||
|
!['shared', 'dedicated', 'group'].includes(mappedUpdates.accountType)
|
||||||
|
) {
|
||||||
return res
|
return res
|
||||||
.status(400)
|
.status(400)
|
||||||
.json({ error: 'Invalid account type. Must be "shared", "dedicated" or "group"' })
|
.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
|
// 如果更新为分组类型,验证groupId或groupIds
|
||||||
if (
|
if (
|
||||||
updates.accountType === 'group' &&
|
mappedUpdates.accountType === 'group' &&
|
||||||
!updates.groupId &&
|
!mappedUpdates.groupId &&
|
||||||
(!updates.groupIds || updates.groupIds.length === 0)
|
(!mappedUpdates.groupIds || mappedUpdates.groupIds.length === 0)
|
||||||
) {
|
) {
|
||||||
return res
|
return res
|
||||||
.status(400)
|
.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') {
|
if (currentAccount.accountType === 'group') {
|
||||||
await accountGroupService.removeAccountFromAllGroups(accountId)
|
await accountGroupService.removeAccountFromAllGroups(accountId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果新类型是分组,添加到新分组
|
// 如果新类型是分组,添加到新分组
|
||||||
if (updates.accountType === 'group') {
|
if (mappedUpdates.accountType === 'group') {
|
||||||
// 处理多分组/单分组的兼容性
|
// 处理多分组/单分组的兼容性
|
||||||
if (Object.prototype.hasOwnProperty.call(updates, 'groupIds')) {
|
if (Object.prototype.hasOwnProperty.call(mappedUpdates, 'groupIds')) {
|
||||||
if (updates.groupIds && updates.groupIds.length > 0) {
|
if (mappedUpdates.groupIds && mappedUpdates.groupIds.length > 0) {
|
||||||
// 使用多分组设置
|
// 使用多分组设置
|
||||||
await accountGroupService.setAccountGroups(accountId, updates.groupIds, 'claude')
|
await accountGroupService.setAccountGroups(accountId, mappedUpdates.groupIds, 'claude')
|
||||||
} else {
|
} else {
|
||||||
// groupIds 为空数组,从所有分组中移除
|
// groupIds 为空数组,从所有分组中移除
|
||||||
await accountGroupService.removeAccountFromAllGroups(accountId)
|
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)
|
await claudeAccountService.updateAccount(accountId, mappedUpdates)
|
||||||
|
|
||||||
logger.success(`📝 Admin updated Claude account: ${accountId}`)
|
logger.success(`📝 Admin updated Claude account: ${accountId}`)
|
||||||
|
|||||||
@@ -913,6 +913,19 @@ class CcrAccountService {
|
|||||||
throw error
|
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()
|
module.exports = new CcrAccountService()
|
||||||
|
|||||||
@@ -1254,6 +1254,19 @@ class ClaudeConsoleAccountService {
|
|||||||
throw error
|
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()
|
module.exports = new ClaudeConsoleAccountService()
|
||||||
|
|||||||
@@ -546,15 +546,11 @@ class UnifiedClaudeScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查订阅是否过期
|
// 检查订阅是否过期
|
||||||
if (account.subscriptionExpiresAt) {
|
if (claudeConsoleAccountService.isSubscriptionExpired(account)) {
|
||||||
const expiryDate = new Date(account.subscriptionExpiresAt)
|
logger.debug(
|
||||||
const now = new Date()
|
`⏰ Claude Console account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}`
|
||||||
if (expiryDate <= now) {
|
)
|
||||||
logger.debug(
|
continue
|
||||||
`⏰ Claude Console account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}`
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主动触发一次额度检查,确保状态即时生效
|
// 主动触发一次额度检查,确保状态即时生效
|
||||||
@@ -655,15 +651,11 @@ class UnifiedClaudeScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查订阅是否过期
|
// 检查订阅是否过期
|
||||||
if (account.subscriptionExpiresAt) {
|
if (ccrAccountService.isSubscriptionExpired(account)) {
|
||||||
const expiryDate = new Date(account.subscriptionExpiresAt)
|
logger.debug(
|
||||||
const now = new Date()
|
`⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}`
|
||||||
if (expiryDate <= now) {
|
)
|
||||||
logger.debug(
|
continue
|
||||||
`⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}`
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否被限流
|
// 检查是否被限流
|
||||||
@@ -799,15 +791,11 @@ class UnifiedClaudeScheduler {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// 检查订阅是否过期
|
// 检查订阅是否过期
|
||||||
if (account.subscriptionExpiresAt) {
|
if (claudeConsoleAccountService.isSubscriptionExpired(account)) {
|
||||||
const expiryDate = new Date(account.subscriptionExpiresAt)
|
logger.debug(
|
||||||
const now = new Date()
|
`⏰ Claude Console account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)`
|
||||||
if (expiryDate <= now) {
|
)
|
||||||
logger.debug(
|
return false
|
||||||
`⏰ Claude Console account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)`
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 检查是否超额
|
// 检查是否超额
|
||||||
try {
|
try {
|
||||||
@@ -868,15 +856,11 @@ class UnifiedClaudeScheduler {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// 检查订阅是否过期
|
// 检查订阅是否过期
|
||||||
if (account.subscriptionExpiresAt) {
|
if (ccrAccountService.isSubscriptionExpired(account)) {
|
||||||
const expiryDate = new Date(account.subscriptionExpiresAt)
|
logger.debug(
|
||||||
const now = new Date()
|
`⏰ CCR account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)`
|
||||||
if (expiryDate <= now) {
|
)
|
||||||
logger.debug(
|
return false
|
||||||
`⏰ CCR account ${account.name} (${accountId}) expired at ${account.subscriptionExpiresAt} (session check)`
|
|
||||||
)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 检查是否超额
|
// 检查是否超额
|
||||||
try {
|
try {
|
||||||
@@ -1400,15 +1384,11 @@ class UnifiedClaudeScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查订阅是否过期
|
// 检查订阅是否过期
|
||||||
if (account.subscriptionExpiresAt) {
|
if (ccrAccountService.isSubscriptionExpired(account)) {
|
||||||
const expiryDate = new Date(account.subscriptionExpiresAt)
|
logger.debug(
|
||||||
const now = new Date()
|
`⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}`
|
||||||
if (expiryDate <= now) {
|
)
|
||||||
logger.debug(
|
continue
|
||||||
`⏰ CCR account ${account.name} (${account.id}) expired at ${account.subscriptionExpiresAt}`
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否被限流或超额
|
// 检查是否被限流或超额
|
||||||
|
|||||||
Reference in New Issue
Block a user