mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
refactor: standardize code formatting and linting configuration
- Replace .eslintrc.js with .eslintrc.cjs for better ES module compatibility - Add .prettierrc configuration for consistent code formatting - Update package.json with new lint and format scripts - Add nodemon.json for development hot reloading configuration - Standardize code formatting across all JavaScript and Vue files - Update web admin SPA with improved linting rules and formatting - Add prettier configuration to web admin SPA 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,548 +5,557 @@
|
||||
* 用于调试、恢复和管理Claude账户的会话窗口
|
||||
*/
|
||||
|
||||
const redis = require('../src/models/redis');
|
||||
const claudeAccountService = require('../src/services/claudeAccountService');
|
||||
const logger = require('../src/utils/logger');
|
||||
const readline = require('readline');
|
||||
const redis = require('../src/models/redis')
|
||||
const claudeAccountService = require('../src/services/claudeAccountService')
|
||||
const readline = require('readline')
|
||||
|
||||
// 创建readline接口
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
})
|
||||
|
||||
// 辅助函数:询问用户输入
|
||||
function askQuestion(question) {
|
||||
return new Promise((resolve) => {
|
||||
rl.question(question, resolve);
|
||||
});
|
||||
rl.question(question, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
// 辅助函数:解析时间输入
|
||||
function parseTimeInput(input) {
|
||||
const now = new Date();
|
||||
|
||||
const now = new Date()
|
||||
|
||||
// 如果是 HH:MM 格式
|
||||
const timeMatch = input.match(/^(\d{1,2}):(\d{2})$/);
|
||||
const timeMatch = input.match(/^(\d{1,2}):(\d{2})$/)
|
||||
if (timeMatch) {
|
||||
const hour = parseInt(timeMatch[1]);
|
||||
const minute = parseInt(timeMatch[2]);
|
||||
|
||||
const hour = parseInt(timeMatch[1])
|
||||
const minute = parseInt(timeMatch[2])
|
||||
|
||||
if (hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59) {
|
||||
const time = new Date(now);
|
||||
time.setHours(hour, minute, 0, 0);
|
||||
return time;
|
||||
const time = new Date(now)
|
||||
time.setHours(hour, minute, 0, 0)
|
||||
return time
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 如果是相对时间(如 "2小时前")
|
||||
const relativeMatch = input.match(/^(\d+)(小时|分钟)前$/);
|
||||
const relativeMatch = input.match(/^(\d+)(小时|分钟)前$/)
|
||||
if (relativeMatch) {
|
||||
const amount = parseInt(relativeMatch[1]);
|
||||
const unit = relativeMatch[2];
|
||||
const time = new Date(now);
|
||||
|
||||
const amount = parseInt(relativeMatch[1])
|
||||
const unit = relativeMatch[2]
|
||||
const time = new Date(now)
|
||||
|
||||
if (unit === '小时') {
|
||||
time.setHours(time.getHours() - amount);
|
||||
time.setHours(time.getHours() - amount)
|
||||
} else if (unit === '分钟') {
|
||||
time.setMinutes(time.getMinutes() - amount);
|
||||
time.setMinutes(time.getMinutes() - amount)
|
||||
}
|
||||
|
||||
return time;
|
||||
|
||||
return time
|
||||
}
|
||||
|
||||
|
||||
// 如果是 ISO 格式或其他日期格式
|
||||
const parsedDate = new Date(input);
|
||||
const parsedDate = new Date(input)
|
||||
if (!isNaN(parsedDate.getTime())) {
|
||||
return parsedDate;
|
||||
return parsedDate
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// 辅助函数:显示可用的时间窗口选项
|
||||
function showTimeWindowOptions() {
|
||||
const now = new Date();
|
||||
console.log('\n⏰ 可用的5小时时间窗口:');
|
||||
|
||||
const now = new Date()
|
||||
console.log('\n⏰ 可用的5小时时间窗口:')
|
||||
|
||||
for (let hour = 0; hour < 24; hour += 5) {
|
||||
const start = hour;
|
||||
const end = hour + 5;
|
||||
const startStr = `${String(start).padStart(2, '0')}:00`;
|
||||
const endStr = `${String(end).padStart(2, '0')}:00`;
|
||||
|
||||
const currentHour = now.getHours();
|
||||
const isActive = currentHour >= start && currentHour < end;
|
||||
const status = isActive ? ' 🟢 (当前活跃)' : '';
|
||||
|
||||
console.log(` ${start/5 + 1}. ${startStr} - ${endStr}${status}`);
|
||||
const start = hour
|
||||
const end = hour + 5
|
||||
const startStr = `${String(start).padStart(2, '0')}:00`
|
||||
const endStr = `${String(end).padStart(2, '0')}:00`
|
||||
|
||||
const currentHour = now.getHours()
|
||||
const isActive = currentHour >= start && currentHour < end
|
||||
const status = isActive ? ' 🟢 (当前活跃)' : ''
|
||||
|
||||
console.log(` ${start / 5 + 1}. ${startStr} - ${endStr}${status}`)
|
||||
}
|
||||
console.log('');
|
||||
console.log('')
|
||||
}
|
||||
|
||||
const commands = {
|
||||
// 调试所有账户的会话窗口状态
|
||||
async debug() {
|
||||
console.log('🔍 开始调试会话窗口状态...\n');
|
||||
|
||||
const accounts = await redis.getAllClaudeAccounts();
|
||||
console.log(`📊 找到 ${accounts.length} 个Claude账户\n`);
|
||||
|
||||
console.log('🔍 开始调试会话窗口状态...\n')
|
||||
|
||||
const accounts = await redis.getAllClaudeAccounts()
|
||||
console.log(`📊 找到 ${accounts.length} 个Claude账户\n`)
|
||||
|
||||
const stats = {
|
||||
total: accounts.length,
|
||||
hasWindow: 0,
|
||||
hasLastUsed: 0,
|
||||
canRecover: 0,
|
||||
expired: 0
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
for (const account of accounts) {
|
||||
console.log(`🏢 ${account.name} (${account.id})`);
|
||||
console.log(` 状态: ${account.isActive === 'true' ? '✅ 活跃' : '❌ 禁用'}`);
|
||||
|
||||
console.log(`🏢 ${account.name} (${account.id})`)
|
||||
console.log(` 状态: ${account.isActive === 'true' ? '✅ 活跃' : '❌ 禁用'}`)
|
||||
|
||||
if (account.sessionWindowStart && account.sessionWindowEnd) {
|
||||
stats.hasWindow++;
|
||||
const windowStart = new Date(account.sessionWindowStart);
|
||||
const windowEnd = new Date(account.sessionWindowEnd);
|
||||
const now = new Date();
|
||||
const isActive = now < windowEnd;
|
||||
|
||||
console.log(` 会话窗口: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`);
|
||||
console.log(` 窗口状态: ${isActive ? '✅ 活跃' : '❌ 已过期'}`);
|
||||
|
||||
stats.hasWindow++
|
||||
const windowStart = new Date(account.sessionWindowStart)
|
||||
const windowEnd = new Date(account.sessionWindowEnd)
|
||||
const now = new Date()
|
||||
const isActive = now < windowEnd
|
||||
|
||||
console.log(` 会话窗口: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`)
|
||||
console.log(` 窗口状态: ${isActive ? '✅ 活跃' : '❌ 已过期'}`)
|
||||
|
||||
// 只有在窗口已过期时才显示可恢复窗口
|
||||
if (!isActive && account.lastUsedAt) {
|
||||
const lastUsed = new Date(account.lastUsedAt);
|
||||
const recoveredWindowStart = claudeAccountService._calculateSessionWindowStart(lastUsed);
|
||||
const recoveredWindowEnd = claudeAccountService._calculateSessionWindowEnd(recoveredWindowStart);
|
||||
|
||||
const lastUsed = new Date(account.lastUsedAt)
|
||||
const recoveredWindowStart = claudeAccountService._calculateSessionWindowStart(lastUsed)
|
||||
const recoveredWindowEnd =
|
||||
claudeAccountService._calculateSessionWindowEnd(recoveredWindowStart)
|
||||
|
||||
if (now < recoveredWindowEnd) {
|
||||
stats.canRecover++;
|
||||
console.log(` 可恢复窗口: ✅ ${recoveredWindowStart.toLocaleString()} - ${recoveredWindowEnd.toLocaleString()}`);
|
||||
stats.canRecover++
|
||||
console.log(
|
||||
` 可恢复窗口: ✅ ${recoveredWindowStart.toLocaleString()} - ${recoveredWindowEnd.toLocaleString()}`
|
||||
)
|
||||
} else {
|
||||
stats.expired++;
|
||||
console.log(` 可恢复窗口: ❌ 已过期 (${recoveredWindowStart.toLocaleString()} - ${recoveredWindowEnd.toLocaleString()})`);
|
||||
stats.expired++
|
||||
console.log(
|
||||
` 可恢复窗口: ❌ 已过期 (${recoveredWindowStart.toLocaleString()} - ${recoveredWindowEnd.toLocaleString()})`
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(` 会话窗口: ❌ 无`);
|
||||
|
||||
console.log(' 会话窗口: ❌ 无')
|
||||
|
||||
// 没有会话窗口时,检查是否有可恢复的窗口
|
||||
if (account.lastUsedAt) {
|
||||
const lastUsed = new Date(account.lastUsedAt);
|
||||
const now = new Date();
|
||||
const windowStart = claudeAccountService._calculateSessionWindowStart(lastUsed);
|
||||
const windowEnd = claudeAccountService._calculateSessionWindowEnd(windowStart);
|
||||
|
||||
const lastUsed = new Date(account.lastUsedAt)
|
||||
const now = new Date()
|
||||
const windowStart = claudeAccountService._calculateSessionWindowStart(lastUsed)
|
||||
const windowEnd = claudeAccountService._calculateSessionWindowEnd(windowStart)
|
||||
|
||||
if (now < windowEnd) {
|
||||
stats.canRecover++;
|
||||
console.log(` 可恢复窗口: ✅ ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`);
|
||||
stats.canRecover++
|
||||
console.log(
|
||||
` 可恢复窗口: ✅ ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`
|
||||
)
|
||||
} else {
|
||||
stats.expired++;
|
||||
console.log(` 可恢复窗口: ❌ 已过期 (${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()})`);
|
||||
stats.expired++
|
||||
console.log(
|
||||
` 可恢复窗口: ❌ 已过期 (${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()})`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (account.lastUsedAt) {
|
||||
stats.hasLastUsed++;
|
||||
const lastUsed = new Date(account.lastUsedAt);
|
||||
const now = new Date();
|
||||
const minutesAgo = Math.round((now - lastUsed) / (1000 * 60));
|
||||
|
||||
console.log(` 最后使用: ${lastUsed.toLocaleString()} (${minutesAgo}分钟前)`);
|
||||
stats.hasLastUsed++
|
||||
const lastUsed = new Date(account.lastUsedAt)
|
||||
const now = new Date()
|
||||
const minutesAgo = Math.round((now - lastUsed) / (1000 * 60))
|
||||
|
||||
console.log(` 最后使用: ${lastUsed.toLocaleString()} (${minutesAgo}分钟前)`)
|
||||
} else {
|
||||
console.log(` 最后使用: ❌ 无记录`);
|
||||
console.log(' 最后使用: ❌ 无记录')
|
||||
}
|
||||
|
||||
console.log('');
|
||||
|
||||
console.log('')
|
||||
}
|
||||
|
||||
console.log('📈 汇总统计:');
|
||||
console.log(` 总账户数: ${stats.total}`);
|
||||
console.log(` 有会话窗口: ${stats.hasWindow}`);
|
||||
console.log(` 有使用记录: ${stats.hasLastUsed}`);
|
||||
console.log(` 可以恢复: ${stats.canRecover}`);
|
||||
console.log(` 窗口已过期: ${stats.expired}`);
|
||||
|
||||
console.log('📈 汇总统计:')
|
||||
console.log(` 总账户数: ${stats.total}`)
|
||||
console.log(` 有会话窗口: ${stats.hasWindow}`)
|
||||
console.log(` 有使用记录: ${stats.hasLastUsed}`)
|
||||
console.log(` 可以恢复: ${stats.canRecover}`)
|
||||
console.log(` 窗口已过期: ${stats.expired}`)
|
||||
},
|
||||
|
||||
|
||||
// 初始化会话窗口(默认行为)
|
||||
async init() {
|
||||
console.log('🔄 初始化会话窗口...\n');
|
||||
const result = await claudeAccountService.initializeSessionWindows();
|
||||
|
||||
console.log('\n📊 初始化结果:');
|
||||
console.log(` 总账户数: ${result.total}`);
|
||||
console.log(` 成功初始化: ${result.initialized}`);
|
||||
console.log(` 已跳过(已有窗口): ${result.skipped}`);
|
||||
console.log(` 窗口已过期: ${result.expired}`);
|
||||
console.log(` 无使用数据: ${result.noData}`);
|
||||
|
||||
console.log('🔄 初始化会话窗口...\n')
|
||||
const result = await claudeAccountService.initializeSessionWindows()
|
||||
|
||||
console.log('\n📊 初始化结果:')
|
||||
console.log(` 总账户数: ${result.total}`)
|
||||
console.log(` 成功初始化: ${result.initialized}`)
|
||||
console.log(` 已跳过(已有窗口): ${result.skipped}`)
|
||||
console.log(` 窗口已过期: ${result.expired}`)
|
||||
console.log(` 无使用数据: ${result.noData}`)
|
||||
|
||||
if (result.error) {
|
||||
console.log(` 错误: ${result.error}`);
|
||||
console.log(` 错误: ${result.error}`)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// 强制重新计算所有会话窗口
|
||||
async force() {
|
||||
console.log('🔄 强制重新计算所有会话窗口...\n');
|
||||
const result = await claudeAccountService.initializeSessionWindows(true);
|
||||
|
||||
console.log('\n📊 强制重算结果:');
|
||||
console.log(` 总账户数: ${result.total}`);
|
||||
console.log(` 成功初始化: ${result.initialized}`);
|
||||
console.log(` 窗口已过期: ${result.expired}`);
|
||||
console.log(` 无使用数据: ${result.noData}`);
|
||||
|
||||
console.log('🔄 强制重新计算所有会话窗口...\n')
|
||||
const result = await claudeAccountService.initializeSessionWindows(true)
|
||||
|
||||
console.log('\n📊 强制重算结果:')
|
||||
console.log(` 总账户数: ${result.total}`)
|
||||
console.log(` 成功初始化: ${result.initialized}`)
|
||||
console.log(` 窗口已过期: ${result.expired}`)
|
||||
console.log(` 无使用数据: ${result.noData}`)
|
||||
|
||||
if (result.error) {
|
||||
console.log(` 错误: ${result.error}`);
|
||||
console.log(` 错误: ${result.error}`)
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// 清除所有会话窗口
|
||||
async clear() {
|
||||
console.log('🗑️ 清除所有会话窗口...\n');
|
||||
|
||||
const accounts = await redis.getAllClaudeAccounts();
|
||||
let clearedCount = 0;
|
||||
|
||||
console.log('🗑️ 清除所有会话窗口...\n')
|
||||
|
||||
const accounts = await redis.getAllClaudeAccounts()
|
||||
let clearedCount = 0
|
||||
|
||||
for (const account of accounts) {
|
||||
if (account.sessionWindowStart || account.sessionWindowEnd) {
|
||||
delete account.sessionWindowStart;
|
||||
delete account.sessionWindowEnd;
|
||||
delete account.lastRequestTime;
|
||||
|
||||
await redis.setClaudeAccount(account.id, account);
|
||||
clearedCount++;
|
||||
|
||||
console.log(`✅ 清除账户 ${account.name} (${account.id}) 的会话窗口`);
|
||||
delete account.sessionWindowStart
|
||||
delete account.sessionWindowEnd
|
||||
delete account.lastRequestTime
|
||||
|
||||
await redis.setClaudeAccount(account.id, account)
|
||||
clearedCount++
|
||||
|
||||
console.log(`✅ 清除账户 ${account.name} (${account.id}) 的会话窗口`)
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n📊 清除完成: 共清除 ${clearedCount} 个账户的会话窗口`);
|
||||
|
||||
console.log(`\n📊 清除完成: 共清除 ${clearedCount} 个账户的会话窗口`)
|
||||
},
|
||||
|
||||
|
||||
// 创建测试会话窗口(将lastUsedAt设置为当前时间)
|
||||
async test() {
|
||||
console.log('🧪 创建测试会话窗口...\n');
|
||||
|
||||
const accounts = await redis.getAllClaudeAccounts();
|
||||
console.log('🧪 创建测试会话窗口...\n')
|
||||
|
||||
const accounts = await redis.getAllClaudeAccounts()
|
||||
if (accounts.length === 0) {
|
||||
console.log('❌ 没有找到Claude账户');
|
||||
return;
|
||||
console.log('❌ 没有找到Claude账户')
|
||||
return
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
let updatedCount = 0;
|
||||
|
||||
|
||||
const now = new Date()
|
||||
let updatedCount = 0
|
||||
|
||||
for (const account of accounts) {
|
||||
if (account.isActive === 'true') {
|
||||
// 设置为当前时间(模拟刚刚使用)
|
||||
account.lastUsedAt = now.toISOString();
|
||||
|
||||
account.lastUsedAt = now.toISOString()
|
||||
|
||||
// 计算新的会话窗口
|
||||
const windowStart = claudeAccountService._calculateSessionWindowStart(now);
|
||||
const windowEnd = claudeAccountService._calculateSessionWindowEnd(windowStart);
|
||||
|
||||
account.sessionWindowStart = windowStart.toISOString();
|
||||
account.sessionWindowEnd = windowEnd.toISOString();
|
||||
account.lastRequestTime = now.toISOString();
|
||||
|
||||
await redis.setClaudeAccount(account.id, account);
|
||||
updatedCount++;
|
||||
|
||||
console.log(`✅ 为账户 ${account.name} 创建测试会话窗口:`);
|
||||
console.log(` 窗口时间: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`);
|
||||
console.log(` 最后使用: ${now.toLocaleString()}\n`);
|
||||
const windowStart = claudeAccountService._calculateSessionWindowStart(now)
|
||||
const windowEnd = claudeAccountService._calculateSessionWindowEnd(windowStart)
|
||||
|
||||
account.sessionWindowStart = windowStart.toISOString()
|
||||
account.sessionWindowEnd = windowEnd.toISOString()
|
||||
account.lastRequestTime = now.toISOString()
|
||||
|
||||
await redis.setClaudeAccount(account.id, account)
|
||||
updatedCount++
|
||||
|
||||
console.log(`✅ 为账户 ${account.name} 创建测试会话窗口:`)
|
||||
console.log(` 窗口时间: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`)
|
||||
console.log(` 最后使用: ${now.toLocaleString()}\n`)
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📊 测试完成: 为 ${updatedCount} 个活跃账户创建了测试会话窗口`);
|
||||
|
||||
console.log(`📊 测试完成: 为 ${updatedCount} 个活跃账户创建了测试会话窗口`)
|
||||
},
|
||||
|
||||
|
||||
// 手动设置账户的会话窗口
|
||||
async set() {
|
||||
console.log('🔧 手动设置会话窗口...\n');
|
||||
|
||||
console.log('🔧 手动设置会话窗口...\n')
|
||||
|
||||
// 获取所有账户
|
||||
const accounts = await redis.getAllClaudeAccounts();
|
||||
const accounts = await redis.getAllClaudeAccounts()
|
||||
if (accounts.length === 0) {
|
||||
console.log('❌ 没有找到Claude账户');
|
||||
return;
|
||||
console.log('❌ 没有找到Claude账户')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 显示账户列表
|
||||
console.log('📋 可用的Claude账户:');
|
||||
console.log('📋 可用的Claude账户:')
|
||||
accounts.forEach((account, index) => {
|
||||
const status = account.isActive === 'true' ? '✅' : '❌';
|
||||
const hasWindow = account.sessionWindowStart ? '🕐' : '➖';
|
||||
console.log(` ${index + 1}. ${status} ${hasWindow} ${account.name} (${account.id})`);
|
||||
});
|
||||
|
||||
const status = account.isActive === 'true' ? '✅' : '❌'
|
||||
const hasWindow = account.sessionWindowStart ? '🕐' : '➖'
|
||||
console.log(` ${index + 1}. ${status} ${hasWindow} ${account.name} (${account.id})`)
|
||||
})
|
||||
|
||||
// 让用户选择账户
|
||||
const accountIndex = await askQuestion('\n请选择账户 (输入编号): ');
|
||||
const selectedIndex = parseInt(accountIndex) - 1;
|
||||
|
||||
const accountIndex = await askQuestion('\n请选择账户 (输入编号): ')
|
||||
const selectedIndex = parseInt(accountIndex) - 1
|
||||
|
||||
if (selectedIndex < 0 || selectedIndex >= accounts.length) {
|
||||
console.log('❌ 无效的账户编号');
|
||||
return;
|
||||
console.log('❌ 无效的账户编号')
|
||||
return
|
||||
}
|
||||
|
||||
const selectedAccount = accounts[selectedIndex];
|
||||
console.log(`\n🎯 已选择账户: ${selectedAccount.name}`);
|
||||
|
||||
|
||||
const selectedAccount = accounts[selectedIndex]
|
||||
console.log(`\n🎯 已选择账户: ${selectedAccount.name}`)
|
||||
|
||||
// 显示当前会话窗口状态
|
||||
if (selectedAccount.sessionWindowStart && selectedAccount.sessionWindowEnd) {
|
||||
const windowStart = new Date(selectedAccount.sessionWindowStart);
|
||||
const windowEnd = new Date(selectedAccount.sessionWindowEnd);
|
||||
const now = new Date();
|
||||
const isActive = now >= windowStart && now < windowEnd;
|
||||
|
||||
console.log(`📊 当前会话窗口:`);
|
||||
console.log(` 时间: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`);
|
||||
console.log(` 状态: ${isActive ? '✅ 活跃' : '❌ 已过期'}`);
|
||||
const windowStart = new Date(selectedAccount.sessionWindowStart)
|
||||
const windowEnd = new Date(selectedAccount.sessionWindowEnd)
|
||||
const now = new Date()
|
||||
const isActive = now >= windowStart && now < windowEnd
|
||||
|
||||
console.log('📊 当前会话窗口:')
|
||||
console.log(` 时间: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`)
|
||||
console.log(` 状态: ${isActive ? '✅ 活跃' : '❌ 已过期'}`)
|
||||
} else {
|
||||
console.log(`📊 当前会话窗口: ❌ 无`);
|
||||
console.log('📊 当前会话窗口: ❌ 无')
|
||||
}
|
||||
|
||||
|
||||
// 显示设置选项
|
||||
console.log('\n🛠️ 设置选项:');
|
||||
console.log(' 1. 使用预设时间窗口');
|
||||
console.log(' 2. 自定义最后使用时间');
|
||||
console.log(' 3. 直接设置窗口时间');
|
||||
console.log(' 4. 清除会话窗口');
|
||||
|
||||
const option = await askQuestion('\n请选择设置方式 (1-4): ');
|
||||
|
||||
console.log('\n🛠️ 设置选项:')
|
||||
console.log(' 1. 使用预设时间窗口')
|
||||
console.log(' 2. 自定义最后使用时间')
|
||||
console.log(' 3. 直接设置窗口时间')
|
||||
console.log(' 4. 清除会话窗口')
|
||||
|
||||
const option = await askQuestion('\n请选择设置方式 (1-4): ')
|
||||
|
||||
switch (option) {
|
||||
case '1':
|
||||
await setPresetWindow(selectedAccount);
|
||||
break;
|
||||
await setPresetWindow(selectedAccount)
|
||||
break
|
||||
case '2':
|
||||
await setCustomLastUsed(selectedAccount);
|
||||
break;
|
||||
await setCustomLastUsed(selectedAccount)
|
||||
break
|
||||
case '3':
|
||||
await setDirectWindow(selectedAccount);
|
||||
break;
|
||||
await setDirectWindow(selectedAccount)
|
||||
break
|
||||
case '4':
|
||||
await clearAccountWindow(selectedAccount);
|
||||
break;
|
||||
await clearAccountWindow(selectedAccount)
|
||||
break
|
||||
default:
|
||||
console.log('❌ 无效的选项');
|
||||
return;
|
||||
console.log('❌ 无效的选项')
|
||||
return
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// 显示帮助信息
|
||||
help() {
|
||||
console.log('🔧 会话窗口管理脚本\n');
|
||||
console.log('用法: node scripts/manage-session-windows.js <command>\n');
|
||||
console.log('命令:');
|
||||
console.log(' debug - 调试所有账户的会话窗口状态');
|
||||
console.log(' init - 初始化会话窗口(跳过已有窗口的账户)');
|
||||
console.log(' force - 强制重新计算所有会话窗口');
|
||||
console.log(' test - 创建测试会话窗口(设置当前时间为使用时间)');
|
||||
console.log(' set - 手动设置特定账户的会话窗口 🆕');
|
||||
console.log(' clear - 清除所有会话窗口');
|
||||
console.log(' help - 显示此帮助信息\n');
|
||||
console.log('示例:');
|
||||
console.log(' node scripts/manage-session-windows.js debug');
|
||||
console.log(' node scripts/manage-session-windows.js set');
|
||||
console.log(' node scripts/manage-session-windows.js test');
|
||||
console.log(' node scripts/manage-session-windows.js force');
|
||||
console.log('🔧 会话窗口管理脚本\n')
|
||||
console.log('用法: node scripts/manage-session-windows.js <command>\n')
|
||||
console.log('命令:')
|
||||
console.log(' debug - 调试所有账户的会话窗口状态')
|
||||
console.log(' init - 初始化会话窗口(跳过已有窗口的账户)')
|
||||
console.log(' force - 强制重新计算所有会话窗口')
|
||||
console.log(' test - 创建测试会话窗口(设置当前时间为使用时间)')
|
||||
console.log(' set - 手动设置特定账户的会话窗口 🆕')
|
||||
console.log(' clear - 清除所有会话窗口')
|
||||
console.log(' help - 显示此帮助信息\n')
|
||||
console.log('示例:')
|
||||
console.log(' node scripts/manage-session-windows.js debug')
|
||||
console.log(' node scripts/manage-session-windows.js set')
|
||||
console.log(' node scripts/manage-session-windows.js test')
|
||||
console.log(' node scripts/manage-session-windows.js force')
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 设置函数实现
|
||||
|
||||
// 使用预设时间窗口
|
||||
async function setPresetWindow(account) {
|
||||
showTimeWindowOptions();
|
||||
|
||||
const windowChoice = await askQuestion('请选择时间窗口 (1-5): ');
|
||||
const windowIndex = parseInt(windowChoice) - 1;
|
||||
|
||||
showTimeWindowOptions()
|
||||
|
||||
const windowChoice = await askQuestion('请选择时间窗口 (1-5): ')
|
||||
const windowIndex = parseInt(windowChoice) - 1
|
||||
|
||||
if (windowIndex < 0 || windowIndex >= 5) {
|
||||
console.log('❌ 无效的窗口选择');
|
||||
return;
|
||||
console.log('❌ 无效的窗口选择')
|
||||
return
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const startHour = windowIndex * 5;
|
||||
|
||||
|
||||
const now = new Date()
|
||||
const startHour = windowIndex * 5
|
||||
|
||||
// 创建窗口开始时间
|
||||
const windowStart = new Date(now);
|
||||
windowStart.setHours(startHour, 0, 0, 0);
|
||||
|
||||
const windowStart = new Date(now)
|
||||
windowStart.setHours(startHour, 0, 0, 0)
|
||||
|
||||
// 创建窗口结束时间
|
||||
const windowEnd = new Date(windowStart);
|
||||
windowEnd.setHours(windowEnd.getHours() + 5);
|
||||
|
||||
const windowEnd = new Date(windowStart)
|
||||
windowEnd.setHours(windowEnd.getHours() + 5)
|
||||
|
||||
// 如果选择的窗口已经过期,则设置为明天的同一时间段
|
||||
if (windowEnd <= now) {
|
||||
windowStart.setDate(windowStart.getDate() + 1);
|
||||
windowEnd.setDate(windowEnd.getDate() + 1);
|
||||
windowStart.setDate(windowStart.getDate() + 1)
|
||||
windowEnd.setDate(windowEnd.getDate() + 1)
|
||||
}
|
||||
|
||||
|
||||
// 询问是否要设置为当前时间作为最后使用时间
|
||||
const setLastUsed = await askQuestion('是否设置当前时间为最后使用时间? (y/N): ');
|
||||
|
||||
const setLastUsed = await askQuestion('是否设置当前时间为最后使用时间? (y/N): ')
|
||||
|
||||
// 更新账户数据
|
||||
account.sessionWindowStart = windowStart.toISOString();
|
||||
account.sessionWindowEnd = windowEnd.toISOString();
|
||||
account.lastRequestTime = now.toISOString();
|
||||
|
||||
account.sessionWindowStart = windowStart.toISOString()
|
||||
account.sessionWindowEnd = windowEnd.toISOString()
|
||||
account.lastRequestTime = now.toISOString()
|
||||
|
||||
if (setLastUsed.toLowerCase() === 'y' || setLastUsed.toLowerCase() === 'yes') {
|
||||
account.lastUsedAt = now.toISOString();
|
||||
account.lastUsedAt = now.toISOString()
|
||||
}
|
||||
|
||||
await redis.setClaudeAccount(account.id, account);
|
||||
|
||||
console.log(`\n✅ 已设置会话窗口:`);
|
||||
console.log(` 账户: ${account.name}`);
|
||||
console.log(` 窗口: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`);
|
||||
console.log(` 状态: ${now >= windowStart && now < windowEnd ? '✅ 活跃' : '⏰ 未来窗口'}`);
|
||||
|
||||
await redis.setClaudeAccount(account.id, account)
|
||||
|
||||
console.log('\n✅ 已设置会话窗口:')
|
||||
console.log(` 账户: ${account.name}`)
|
||||
console.log(` 窗口: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`)
|
||||
console.log(` 状态: ${now >= windowStart && now < windowEnd ? '✅ 活跃' : '⏰ 未来窗口'}`)
|
||||
}
|
||||
|
||||
// 自定义最后使用时间
|
||||
async function setCustomLastUsed(account) {
|
||||
console.log('\n📝 设置最后使用时间:');
|
||||
console.log('支持的时间格式:');
|
||||
console.log(' - HH:MM (如: 14:30)');
|
||||
console.log(' - 相对时间 (如: 2小时前, 30分钟前)');
|
||||
console.log(' - ISO格式 (如: 2025-07-28T14:30:00)');
|
||||
|
||||
const timeInput = await askQuestion('\n请输入最后使用时间: ');
|
||||
const lastUsedTime = parseTimeInput(timeInput);
|
||||
|
||||
console.log('\n📝 设置最后使用时间:')
|
||||
console.log('支持的时间格式:')
|
||||
console.log(' - HH:MM (如: 14:30)')
|
||||
console.log(' - 相对时间 (如: 2小时前, 30分钟前)')
|
||||
console.log(' - ISO格式 (如: 2025-07-28T14:30:00)')
|
||||
|
||||
const timeInput = await askQuestion('\n请输入最后使用时间: ')
|
||||
const lastUsedTime = parseTimeInput(timeInput)
|
||||
|
||||
if (!lastUsedTime) {
|
||||
console.log('❌ 无效的时间格式');
|
||||
return;
|
||||
console.log('❌ 无效的时间格式')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 基于最后使用时间计算会话窗口
|
||||
const windowStart = claudeAccountService._calculateSessionWindowStart(lastUsedTime);
|
||||
const windowEnd = claudeAccountService._calculateSessionWindowEnd(windowStart);
|
||||
|
||||
const windowStart = claudeAccountService._calculateSessionWindowStart(lastUsedTime)
|
||||
const windowEnd = claudeAccountService._calculateSessionWindowEnd(windowStart)
|
||||
|
||||
// 更新账户数据
|
||||
account.lastUsedAt = lastUsedTime.toISOString();
|
||||
account.sessionWindowStart = windowStart.toISOString();
|
||||
account.sessionWindowEnd = windowEnd.toISOString();
|
||||
account.lastRequestTime = lastUsedTime.toISOString();
|
||||
|
||||
await redis.setClaudeAccount(account.id, account);
|
||||
|
||||
console.log(`\n✅ 已设置会话窗口:`);
|
||||
console.log(` 账户: ${account.name}`);
|
||||
console.log(` 最后使用: ${lastUsedTime.toLocaleString()}`);
|
||||
console.log(` 窗口: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`);
|
||||
|
||||
const now = new Date();
|
||||
console.log(` 状态: ${now >= windowStart && now < windowEnd ? '✅ 活跃' : '❌ 已过期'}`);
|
||||
account.lastUsedAt = lastUsedTime.toISOString()
|
||||
account.sessionWindowStart = windowStart.toISOString()
|
||||
account.sessionWindowEnd = windowEnd.toISOString()
|
||||
account.lastRequestTime = lastUsedTime.toISOString()
|
||||
|
||||
await redis.setClaudeAccount(account.id, account)
|
||||
|
||||
console.log('\n✅ 已设置会话窗口:')
|
||||
console.log(` 账户: ${account.name}`)
|
||||
console.log(` 最后使用: ${lastUsedTime.toLocaleString()}`)
|
||||
console.log(` 窗口: ${windowStart.toLocaleString()} - ${windowEnd.toLocaleString()}`)
|
||||
|
||||
const now = new Date()
|
||||
console.log(` 状态: ${now >= windowStart && now < windowEnd ? '✅ 活跃' : '❌ 已过期'}`)
|
||||
}
|
||||
|
||||
// 直接设置窗口时间
|
||||
async function setDirectWindow(account) {
|
||||
console.log('\n⏰ 直接设置窗口时间:');
|
||||
|
||||
const startInput = await askQuestion('请输入窗口开始时间 (HH:MM): ');
|
||||
const startTime = parseTimeInput(startInput);
|
||||
|
||||
console.log('\n⏰ 直接设置窗口时间:')
|
||||
|
||||
const startInput = await askQuestion('请输入窗口开始时间 (HH:MM): ')
|
||||
const startTime = parseTimeInput(startInput)
|
||||
|
||||
if (!startTime) {
|
||||
console.log('❌ 无效的开始时间格式');
|
||||
return;
|
||||
console.log('❌ 无效的开始时间格式')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 自动计算结束时间(开始时间+5小时)
|
||||
const endTime = new Date(startTime);
|
||||
endTime.setHours(endTime.getHours() + 5);
|
||||
|
||||
const endTime = new Date(startTime)
|
||||
endTime.setHours(endTime.getHours() + 5)
|
||||
|
||||
// 如果跨天,询问是否确认
|
||||
if (endTime.getDate() !== startTime.getDate()) {
|
||||
const confirm = await askQuestion(`窗口将跨天到次日 ${endTime.getHours()}:00,确认吗? (y/N): `);
|
||||
const confirm = await askQuestion(`窗口将跨天到次日 ${endTime.getHours()}:00,确认吗? (y/N): `)
|
||||
if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
|
||||
console.log('❌ 已取消设置');
|
||||
return;
|
||||
console.log('❌ 已取消设置')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
|
||||
|
||||
const now = new Date()
|
||||
|
||||
// 更新账户数据
|
||||
account.sessionWindowStart = startTime.toISOString();
|
||||
account.sessionWindowEnd = endTime.toISOString();
|
||||
account.lastRequestTime = now.toISOString();
|
||||
|
||||
account.sessionWindowStart = startTime.toISOString()
|
||||
account.sessionWindowEnd = endTime.toISOString()
|
||||
account.lastRequestTime = now.toISOString()
|
||||
|
||||
// 询问是否更新最后使用时间
|
||||
const updateLastUsed = await askQuestion('是否将最后使用时间设置为窗口开始时间? (y/N): ');
|
||||
const updateLastUsed = await askQuestion('是否将最后使用时间设置为窗口开始时间? (y/N): ')
|
||||
if (updateLastUsed.toLowerCase() === 'y' || updateLastUsed.toLowerCase() === 'yes') {
|
||||
account.lastUsedAt = startTime.toISOString();
|
||||
account.lastUsedAt = startTime.toISOString()
|
||||
}
|
||||
|
||||
await redis.setClaudeAccount(account.id, account);
|
||||
|
||||
console.log(`\n✅ 已设置会话窗口:`);
|
||||
console.log(` 账户: ${account.name}`);
|
||||
console.log(` 窗口: ${startTime.toLocaleString()} - ${endTime.toLocaleString()}`);
|
||||
console.log(` 状态: ${now >= startTime && now < endTime ? '✅ 活跃' : (now < startTime ? '⏰ 未来窗口' : '❌ 已过期')}`);
|
||||
|
||||
await redis.setClaudeAccount(account.id, account)
|
||||
|
||||
console.log('\n✅ 已设置会话窗口:')
|
||||
console.log(` 账户: ${account.name}`)
|
||||
console.log(` 窗口: ${startTime.toLocaleString()} - ${endTime.toLocaleString()}`)
|
||||
console.log(
|
||||
` 状态: ${now >= startTime && now < endTime ? '✅ 活跃' : now < startTime ? '⏰ 未来窗口' : '❌ 已过期'}`
|
||||
)
|
||||
}
|
||||
|
||||
// 清除账户会话窗口
|
||||
async function clearAccountWindow(account) {
|
||||
const confirm = await askQuestion(`确认清除账户 "${account.name}" 的会话窗口吗? (y/N): `);
|
||||
|
||||
const confirm = await askQuestion(`确认清除账户 "${account.name}" 的会话窗口吗? (y/N): `)
|
||||
|
||||
if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
|
||||
console.log('❌ 已取消操作');
|
||||
return;
|
||||
console.log('❌ 已取消操作')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 清除会话窗口相关数据
|
||||
delete account.sessionWindowStart;
|
||||
delete account.sessionWindowEnd;
|
||||
delete account.lastRequestTime;
|
||||
|
||||
await redis.setClaudeAccount(account.id, account);
|
||||
|
||||
console.log(`\n✅ 已清除账户 "${account.name}" 的会话窗口`);
|
||||
delete account.sessionWindowStart
|
||||
delete account.sessionWindowEnd
|
||||
delete account.lastRequestTime
|
||||
|
||||
await redis.setClaudeAccount(account.id, account)
|
||||
|
||||
console.log(`\n✅ 已清除账户 "${account.name}" 的会话窗口`)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const command = process.argv[2] || 'help';
|
||||
|
||||
const command = process.argv[2] || 'help'
|
||||
|
||||
if (!commands[command]) {
|
||||
console.error(`❌ 未知命令: ${command}`);
|
||||
commands.help();
|
||||
process.exit(1);
|
||||
console.error(`❌ 未知命令: ${command}`)
|
||||
commands.help()
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
|
||||
if (command === 'help') {
|
||||
commands.help();
|
||||
return;
|
||||
commands.help()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
// 连接Redis
|
||||
await redis.connect();
|
||||
|
||||
await redis.connect()
|
||||
|
||||
// 执行命令
|
||||
await commands[command]();
|
||||
|
||||
await commands[command]()
|
||||
} catch (error) {
|
||||
console.error('❌ 执行失败:', error);
|
||||
process.exit(1);
|
||||
console.error('❌ 执行失败:', error)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
await redis.disconnect();
|
||||
rl.close();
|
||||
await redis.disconnect()
|
||||
rl.close()
|
||||
}
|
||||
}
|
||||
|
||||
// 如果直接运行此脚本
|
||||
if (require.main === module) {
|
||||
main().then(() => {
|
||||
console.log('\n🎉 操作完成');
|
||||
process.exit(0);
|
||||
});
|
||||
console.log('\n🎉 操作完成')
|
||||
process.exit(0)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = { commands };
|
||||
module.exports = { commands }
|
||||
|
||||
Reference in New Issue
Block a user