mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
feat: api-stats页面查询专属账号会话窗口
This commit is contained in:
@@ -518,6 +518,60 @@ class ClaudeAccountService {
|
||||
}
|
||||
}
|
||||
|
||||
// 📋 获取单个账号的概要信息(用于前端展示会话窗口等状态)
|
||||
async getAccountOverview(accountId) {
|
||||
try {
|
||||
const accountData = await redis.getClaudeAccount(accountId)
|
||||
|
||||
if (!accountData || Object.keys(accountData).length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const [sessionWindowInfo, rateLimitInfo] = await Promise.all([
|
||||
this.getSessionWindowInfo(accountId),
|
||||
this.getAccountRateLimitInfo(accountId)
|
||||
])
|
||||
|
||||
const sessionWindow = sessionWindowInfo || {
|
||||
hasActiveWindow: false,
|
||||
windowStart: null,
|
||||
windowEnd: null,
|
||||
progress: 0,
|
||||
remainingTime: null,
|
||||
lastRequestTime: accountData.lastRequestTime || null,
|
||||
sessionWindowStatus: accountData.sessionWindowStatus || null
|
||||
}
|
||||
|
||||
const rateLimitStatus = rateLimitInfo
|
||||
? {
|
||||
isRateLimited: !!rateLimitInfo.isRateLimited,
|
||||
rateLimitedAt: rateLimitInfo.rateLimitedAt || null,
|
||||
minutesRemaining: rateLimitInfo.minutesRemaining || 0,
|
||||
rateLimitEndAt: rateLimitInfo.rateLimitEndAt || null
|
||||
}
|
||||
: {
|
||||
isRateLimited: false,
|
||||
rateLimitedAt: null,
|
||||
minutesRemaining: 0,
|
||||
rateLimitEndAt: null
|
||||
}
|
||||
|
||||
return {
|
||||
id: accountData.id,
|
||||
name: accountData.name,
|
||||
accountType: accountData.accountType || 'shared',
|
||||
platform: accountData.platform || 'claude',
|
||||
isActive: accountData.isActive === 'true',
|
||||
schedulable: accountData.schedulable !== 'false',
|
||||
sessionWindow,
|
||||
rateLimitStatus
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`❌ Failed to build Claude account overview for ${accountId}:`, error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 📝 更新Claude账户
|
||||
async updateAccount(accountId, updates) {
|
||||
try {
|
||||
|
||||
@@ -808,6 +808,48 @@ async function getAllAccounts() {
|
||||
return accounts
|
||||
}
|
||||
|
||||
// 获取单个账户的概要信息(用于外部展示基本状态)
|
||||
async function getAccountOverview(accountId) {
|
||||
const client = redisClient.getClientSafe()
|
||||
const accountData = await client.hgetall(`${OPENAI_ACCOUNT_KEY_PREFIX}${accountId}`)
|
||||
|
||||
if (!accountData || Object.keys(accountData).length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
const codexUsage = buildCodexUsageSnapshot(accountData)
|
||||
const rateLimitInfo = await getAccountRateLimitInfo(accountId)
|
||||
|
||||
if (accountData.proxy) {
|
||||
try {
|
||||
accountData.proxy = JSON.parse(accountData.proxy)
|
||||
} catch (error) {
|
||||
accountData.proxy = null
|
||||
}
|
||||
}
|
||||
|
||||
const scopes =
|
||||
accountData.scopes && accountData.scopes.trim() ? accountData.scopes.split(' ') : []
|
||||
|
||||
return {
|
||||
id: accountData.id,
|
||||
name: accountData.name,
|
||||
accountType: accountData.accountType || 'shared',
|
||||
platform: accountData.platform || 'openai',
|
||||
isActive: accountData.isActive === 'true',
|
||||
schedulable: accountData.schedulable !== 'false',
|
||||
rateLimitStatus: rateLimitInfo || {
|
||||
status: 'normal',
|
||||
isRateLimited: false,
|
||||
rateLimitedAt: null,
|
||||
rateLimitResetAt: null,
|
||||
minutesRemaining: 0
|
||||
},
|
||||
codexUsage,
|
||||
scopes
|
||||
}
|
||||
}
|
||||
|
||||
// 选择可用账户(支持专属和共享账户)
|
||||
async function selectAvailableAccount(apiKeyId, sessionHash = null) {
|
||||
// 首先检查是否有粘性会话
|
||||
@@ -1175,6 +1217,7 @@ async function updateCodexUsageSnapshot(accountId, usageSnapshot) {
|
||||
module.exports = {
|
||||
createAccount,
|
||||
getAccount,
|
||||
getAccountOverview,
|
||||
updateAccount,
|
||||
deleteAccount,
|
||||
getAllAccounts,
|
||||
|
||||
Reference in New Issue
Block a user