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:
千羽
2025-08-07 18:19:31 +09:00
parent 4a0eba117c
commit 8a74bf5afe
124 changed files with 20878 additions and 18757 deletions

View File

@@ -3,20 +3,20 @@
/**
* 历史数据生成脚本
* 用于测试不同时间范围的Token统计功能
*
*
* 使用方法:
* node scripts/generate-test-data.js [--clean]
*
*
* 选项:
* --clean: 清除所有测试数据
*/
const redis = require('../src/models/redis');
const logger = require('../src/utils/logger');
const redis = require('../src/models/redis')
const logger = require('../src/utils/logger')
// 解析命令行参数
const args = process.argv.slice(2);
const shouldClean = args.includes('--clean');
const args = process.argv.slice(2)
const shouldClean = args.includes('--clean')
// 模拟的模型列表
const models = [
@@ -24,41 +24,41 @@ const models = [
'claude-3-5-sonnet-20241022',
'claude-3-5-haiku-20241022',
'claude-3-opus-20240229'
];
]
// 生成指定日期的数据
async function generateDataForDate(apiKeyId, date, dayOffset) {
const client = redis.getClientSafe();
const dateStr = date.toISOString().split('T')[0];
const month = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
const client = redis.getClientSafe()
const dateStr = date.toISOString().split('T')[0]
const month = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`
// 根据日期偏移量调整数据量(越近的日期数据越多)
const requestCount = Math.max(5, 20 - dayOffset * 2); // 5-20个请求
logger.info(`📊 Generating ${requestCount} requests for ${dateStr}`);
const requestCount = Math.max(5, 20 - dayOffset * 2) // 5-20个请求
logger.info(`📊 Generating ${requestCount} requests for ${dateStr}`)
for (let i = 0; i < requestCount; i++) {
// 随机选择模型
const model = models[Math.floor(Math.random() * models.length)];
const model = models[Math.floor(Math.random() * models.length)]
// 生成随机Token数据
const inputTokens = Math.floor(Math.random() * 2000) + 500; // 500-2500
const outputTokens = Math.floor(Math.random() * 3000) + 1000; // 1000-4000
const cacheCreateTokens = Math.random() > 0.7 ? Math.floor(Math.random() * 1000) : 0; // 30%概率有缓存创建
const cacheReadTokens = Math.random() > 0.5 ? Math.floor(Math.random() * 500) : 0; // 50%概率有缓存读取
const coreTokens = inputTokens + outputTokens;
const allTokens = inputTokens + outputTokens + cacheCreateTokens + cacheReadTokens;
const inputTokens = Math.floor(Math.random() * 2000) + 500 // 500-2500
const outputTokens = Math.floor(Math.random() * 3000) + 1000 // 1000-4000
const cacheCreateTokens = Math.random() > 0.7 ? Math.floor(Math.random() * 1000) : 0 // 30%概率有缓存创建
const cacheReadTokens = Math.random() > 0.5 ? Math.floor(Math.random() * 500) : 0 // 50%概率有缓存读取
const coreTokens = inputTokens + outputTokens
const allTokens = inputTokens + outputTokens + cacheCreateTokens + cacheReadTokens
// 更新各种统计键
const totalKey = `usage:${apiKeyId}`;
const dailyKey = `usage:daily:${apiKeyId}:${dateStr}`;
const monthlyKey = `usage:monthly:${apiKeyId}:${month}`;
const modelDailyKey = `usage:model:daily:${model}:${dateStr}`;
const modelMonthlyKey = `usage:model:monthly:${model}:${month}`;
const keyModelDailyKey = `usage:${apiKeyId}:model:daily:${model}:${dateStr}`;
const keyModelMonthlyKey = `usage:${apiKeyId}:model:monthly:${model}:${month}`;
const totalKey = `usage:${apiKeyId}`
const dailyKey = `usage:daily:${apiKeyId}:${dateStr}`
const monthlyKey = `usage:monthly:${apiKeyId}:${month}`
const modelDailyKey = `usage:model:daily:${model}:${dateStr}`
const modelMonthlyKey = `usage:model:monthly:${model}:${month}`
const keyModelDailyKey = `usage:${apiKeyId}:model:daily:${model}:${dateStr}`
const keyModelMonthlyKey = `usage:${apiKeyId}:model:monthly:${model}:${month}`
await Promise.all([
// 总计数据
client.hincrby(totalKey, 'totalTokens', coreTokens),
@@ -68,7 +68,7 @@ async function generateDataForDate(apiKeyId, date, dayOffset) {
client.hincrby(totalKey, 'totalCacheReadTokens', cacheReadTokens),
client.hincrby(totalKey, 'totalAllTokens', allTokens),
client.hincrby(totalKey, 'totalRequests', 1),
// 每日统计
client.hincrby(dailyKey, 'tokens', coreTokens),
client.hincrby(dailyKey, 'inputTokens', inputTokens),
@@ -77,7 +77,7 @@ async function generateDataForDate(apiKeyId, date, dayOffset) {
client.hincrby(dailyKey, 'cacheReadTokens', cacheReadTokens),
client.hincrby(dailyKey, 'allTokens', allTokens),
client.hincrby(dailyKey, 'requests', 1),
// 每月统计
client.hincrby(monthlyKey, 'tokens', coreTokens),
client.hincrby(monthlyKey, 'inputTokens', inputTokens),
@@ -86,7 +86,7 @@ async function generateDataForDate(apiKeyId, date, dayOffset) {
client.hincrby(monthlyKey, 'cacheReadTokens', cacheReadTokens),
client.hincrby(monthlyKey, 'allTokens', allTokens),
client.hincrby(monthlyKey, 'requests', 1),
// 模型统计 - 每日
client.hincrby(modelDailyKey, 'totalInputTokens', inputTokens),
client.hincrby(modelDailyKey, 'totalOutputTokens', outputTokens),
@@ -94,7 +94,7 @@ async function generateDataForDate(apiKeyId, date, dayOffset) {
client.hincrby(modelDailyKey, 'totalCacheReadTokens', cacheReadTokens),
client.hincrby(modelDailyKey, 'totalAllTokens', allTokens),
client.hincrby(modelDailyKey, 'requests', 1),
// 模型统计 - 每月
client.hincrby(modelMonthlyKey, 'totalInputTokens', inputTokens),
client.hincrby(modelMonthlyKey, 'totalOutputTokens', outputTokens),
@@ -102,7 +102,7 @@ async function generateDataForDate(apiKeyId, date, dayOffset) {
client.hincrby(modelMonthlyKey, 'totalCacheReadTokens', cacheReadTokens),
client.hincrby(modelMonthlyKey, 'totalAllTokens', allTokens),
client.hincrby(modelMonthlyKey, 'requests', 1),
// API Key级别的模型统计 - 每日
// 同时存储带total前缀和不带前缀的字段保持兼容性
client.hincrby(keyModelDailyKey, 'inputTokens', inputTokens),
@@ -116,7 +116,7 @@ async function generateDataForDate(apiKeyId, date, dayOffset) {
client.hincrby(keyModelDailyKey, 'totalCacheReadTokens', cacheReadTokens),
client.hincrby(keyModelDailyKey, 'totalAllTokens', allTokens),
client.hincrby(keyModelDailyKey, 'requests', 1),
// API Key级别的模型统计 - 每月
client.hincrby(keyModelMonthlyKey, 'inputTokens', inputTokens),
client.hincrby(keyModelMonthlyKey, 'outputTokens', outputTokens),
@@ -128,27 +128,27 @@ async function generateDataForDate(apiKeyId, date, dayOffset) {
client.hincrby(keyModelMonthlyKey, 'totalCacheCreateTokens', cacheCreateTokens),
client.hincrby(keyModelMonthlyKey, 'totalCacheReadTokens', cacheReadTokens),
client.hincrby(keyModelMonthlyKey, 'totalAllTokens', allTokens),
client.hincrby(keyModelMonthlyKey, 'requests', 1),
]);
client.hincrby(keyModelMonthlyKey, 'requests', 1)
])
}
}
// 清除测试数据
async function cleanTestData() {
const client = redis.getClientSafe();
const apiKeyService = require('../src/services/apiKeyService');
logger.info('🧹 Cleaning test data...');
const client = redis.getClientSafe()
const apiKeyService = require('../src/services/apiKeyService')
logger.info('🧹 Cleaning test data...')
// 获取所有API Keys
const allKeys = await apiKeyService.getAllApiKeys();
const allKeys = await apiKeyService.getAllApiKeys()
// 找出所有测试 API Keys
const testKeys = allKeys.filter(key => key.name && key.name.startsWith('Test API Key'));
const testKeys = allKeys.filter((key) => key.name && key.name.startsWith('Test API Key'))
for (const testKey of testKeys) {
const apiKeyId = testKey.id;
const apiKeyId = testKey.id
// 获取所有相关的键
const patterns = [
`usage:${apiKeyId}`,
@@ -156,32 +156,29 @@ async function cleanTestData() {
`usage:monthly:${apiKeyId}:*`,
`usage:${apiKeyId}:model:daily:*`,
`usage:${apiKeyId}:model:monthly:*`
];
]
for (const pattern of patterns) {
const keys = await client.keys(pattern);
const keys = await client.keys(pattern)
if (keys.length > 0) {
await client.del(...keys);
logger.info(`🗑️ Deleted ${keys.length} keys matching pattern: ${pattern}`);
await client.del(...keys)
logger.info(`🗑️ Deleted ${keys.length} keys matching pattern: ${pattern}`)
}
}
// 删除 API Key 本身
await apiKeyService.deleteApiKey(apiKeyId);
logger.info(`🗑️ Deleted test API Key: ${testKey.name} (${apiKeyId})`);
await apiKeyService.deleteApiKey(apiKeyId)
logger.info(`🗑️ Deleted test API Key: ${testKey.name} (${apiKeyId})`)
}
// 清除模型统计
const modelPatterns = [
'usage:model:daily:*',
'usage:model:monthly:*'
];
const modelPatterns = ['usage:model:daily:*', 'usage:model:monthly:*']
for (const pattern of modelPatterns) {
const keys = await client.keys(pattern);
const keys = await client.keys(pattern)
if (keys.length > 0) {
await client.del(...keys);
logger.info(`🗑️ Deleted ${keys.length} keys matching pattern: ${pattern}`);
await client.del(...keys)
logger.info(`🗑️ Deleted ${keys.length} keys matching pattern: ${pattern}`)
}
}
}
@@ -189,17 +186,17 @@ async function cleanTestData() {
// 主函数
async function main() {
try {
await redis.connect();
logger.success('✅ Connected to Redis');
await redis.connect()
logger.success('✅ Connected to Redis')
// 创建测试API Keys
const apiKeyService = require('../src/services/apiKeyService');
let testApiKeys = [];
let createdKeys = [];
const apiKeyService = require('../src/services/apiKeyService')
const testApiKeys = []
const createdKeys = []
// 总是创建新的测试 API Keys
logger.info('📝 Creating test API Keys...');
logger.info('📝 Creating test API Keys...')
for (let i = 1; i <= 3; i++) {
const newKey = await apiKeyService.generateApiKey({
name: `Test API Key ${i}`,
@@ -208,77 +205,76 @@ async function main() {
concurrencyLimit: 10,
rateLimitWindow: 60,
rateLimitRequests: 100
});
testApiKeys.push(newKey.id);
createdKeys.push(newKey);
logger.success(`✅ Created test API Key: ${newKey.name} (${newKey.id})`);
logger.info(` 🔑 API Key: ${newKey.apiKey}`);
})
testApiKeys.push(newKey.id)
createdKeys.push(newKey)
logger.success(`✅ Created test API Key: ${newKey.name} (${newKey.id})`)
logger.info(` 🔑 API Key: ${newKey.apiKey}`)
}
if (shouldClean) {
await cleanTestData();
logger.success('✅ Test data cleaned successfully');
return;
await cleanTestData()
logger.success('✅ Test data cleaned successfully')
return
}
// 生成历史数据
const now = new Date();
const now = new Date()
for (const apiKeyId of testApiKeys) {
logger.info(`\n🔄 Generating data for API Key: ${apiKeyId}`);
logger.info(`\n🔄 Generating data for API Key: ${apiKeyId}`)
// 生成过去30天的数据
for (let dayOffset = 0; dayOffset < 30; dayOffset++) {
const date = new Date(now);
date.setDate(date.getDate() - dayOffset);
await generateDataForDate(apiKeyId, date, dayOffset);
const date = new Date(now)
date.setDate(date.getDate() - dayOffset)
await generateDataForDate(apiKeyId, date, dayOffset)
}
logger.success(`✅ Generated 30 days of historical data for API Key: ${apiKeyId}`);
logger.success(`✅ Generated 30 days of historical data for API Key: ${apiKeyId}`)
}
// 显示统计摘要
logger.info('\n📊 Test Data Summary:');
logger.info('='.repeat(60));
logger.info('\n📊 Test Data Summary:')
logger.info('='.repeat(60))
for (const apiKeyId of testApiKeys) {
const totalKey = `usage:${apiKeyId}`;
const totalData = await redis.getClientSafe().hgetall(totalKey);
const totalKey = `usage:${apiKeyId}`
const totalData = await redis.getClientSafe().hgetall(totalKey)
if (totalData && Object.keys(totalData).length > 0) {
logger.info(`\nAPI Key: ${apiKeyId}`);
logger.info(` Total Requests: ${totalData.totalRequests || 0}`);
logger.info(` Total Tokens (Core): ${totalData.totalTokens || 0}`);
logger.info(` Total Tokens (All): ${totalData.totalAllTokens || 0}`);
logger.info(` Input Tokens: ${totalData.totalInputTokens || 0}`);
logger.info(` Output Tokens: ${totalData.totalOutputTokens || 0}`);
logger.info(` Cache Create Tokens: ${totalData.totalCacheCreateTokens || 0}`);
logger.info(` Cache Read Tokens: ${totalData.totalCacheReadTokens || 0}`);
logger.info(`\nAPI Key: ${apiKeyId}`)
logger.info(` Total Requests: ${totalData.totalRequests || 0}`)
logger.info(` Total Tokens (Core): ${totalData.totalTokens || 0}`)
logger.info(` Total Tokens (All): ${totalData.totalAllTokens || 0}`)
logger.info(` Input Tokens: ${totalData.totalInputTokens || 0}`)
logger.info(` Output Tokens: ${totalData.totalOutputTokens || 0}`)
logger.info(` Cache Create Tokens: ${totalData.totalCacheCreateTokens || 0}`)
logger.info(` Cache Read Tokens: ${totalData.totalCacheReadTokens || 0}`)
}
}
logger.info('\n' + '='.repeat(60));
logger.success('\n✅ Test data generation completed!');
logger.info('\n📋 Created API Keys:');
logger.info(`\n${'='.repeat(60)}`)
logger.success('\n✅ Test data generation completed!')
logger.info('\n📋 Created API Keys:')
for (const key of createdKeys) {
logger.info(`- ${key.name}: ${key.apiKey}`);
logger.info(`- ${key.name}: ${key.apiKey}`)
}
logger.info('\n💡 Tips:');
logger.info('- Check the admin panel to see the different time ranges');
logger.info('- Use --clean flag to remove all test data and API Keys');
logger.info('- The script generates more recent data to simulate real usage patterns');
logger.info('\n💡 Tips:')
logger.info('- Check the admin panel to see the different time ranges')
logger.info('- Use --clean flag to remove all test data and API Keys')
logger.info('- The script generates more recent data to simulate real usage patterns')
} catch (error) {
logger.error('❌ Error:', error);
logger.error('❌ Error:', error)
} finally {
await redis.disconnect();
await redis.disconnect()
}
}
// 运行脚本
main().catch(error => {
logger.error('💥 Unexpected error:', error);
process.exit(1);
});
main().catch((error) => {
logger.error('💥 Unexpected error:', error)
process.exit(1)
})