This commit is contained in:
SunSeekerX
2026-01-19 20:24:47 +08:00
parent 12fd5e1cb4
commit 76ecbe18a5
98 changed files with 8182 additions and 1896 deletions

View File

@@ -761,4 +761,166 @@ router.get('/admin/ldap-test', authenticateUserOrAdmin, requireAdmin, async (req
}
})
// ═══════════════════════════════════════════════════════════════════════════
// 额度卡核销相关路由
// ═══════════════════════════════════════════════════════════════════════════
const quotaCardService = require('../services/quotaCardService')
// 🎫 核销额度卡
router.post('/redeem-card', authenticateUser, async (req, res) => {
try {
const { code, apiKeyId } = req.body
if (!code) {
return res.status(400).json({
error: 'Missing card code',
message: 'Card code is required'
})
}
if (!apiKeyId) {
return res.status(400).json({
error: 'Missing API key ID',
message: 'API key ID is required'
})
}
// 验证 API Key 属于当前用户
const keyData = await redis.getApiKey(apiKeyId)
if (!keyData || Object.keys(keyData).length === 0) {
return res.status(404).json({
error: 'API key not found',
message: 'The specified API key does not exist'
})
}
if (keyData.userId !== req.user.id) {
return res.status(403).json({
error: 'Forbidden',
message: 'You can only redeem cards to your own API keys'
})
}
// 执行核销
const result = await quotaCardService.redeemCard(code, apiKeyId, req.user.id, req.user.username)
logger.success(`🎫 User ${req.user.username} redeemed card ${code} to key ${apiKeyId}`)
res.json({
success: true,
data: result
})
} catch (error) {
logger.error('❌ Redeem card error:', error)
res.status(400).json({
error: 'Redeem failed',
message: error.message
})
}
})
// 📋 获取用户的核销历史
router.get('/redemption-history', authenticateUser, async (req, res) => {
try {
const { limit = 50, offset = 0 } = req.query
const result = await quotaCardService.getRedemptions({
userId: req.user.id,
limit: parseInt(limit),
offset: parseInt(offset)
})
res.json({
success: true,
data: result
})
} catch (error) {
logger.error('❌ Get redemption history error:', error)
res.status(500).json({
error: 'Failed to get redemption history',
message: error.message
})
}
})
// 📊 获取用户的额度信息
router.get('/quota-info', authenticateUser, async (req, res) => {
try {
const { apiKeyId } = req.query
if (!apiKeyId) {
return res.status(400).json({
error: 'Missing API key ID',
message: 'API key ID is required'
})
}
// 验证 API Key 属于当前用户
const keyData = await redis.getApiKey(apiKeyId)
if (!keyData || Object.keys(keyData).length === 0) {
return res.status(404).json({
error: 'API key not found',
message: 'The specified API key does not exist'
})
}
if (keyData.userId !== req.user.id) {
return res.status(403).json({
error: 'Forbidden',
message: 'You can only view your own API key quota'
})
}
// 检查是否为聚合 Key
if (keyData.isAggregated !== 'true') {
return res.json({
success: true,
data: {
isAggregated: false,
message: 'This is a traditional API key, not using quota system'
}
})
}
// 解析聚合 Key 数据
let permissions = []
let serviceQuotaLimits = {}
let serviceQuotaUsed = {}
try {
permissions = JSON.parse(keyData.permissions || '[]')
} catch (e) {
permissions = [keyData.permissions]
}
try {
serviceQuotaLimits = JSON.parse(keyData.serviceQuotaLimits || '{}')
serviceQuotaUsed = JSON.parse(keyData.serviceQuotaUsed || '{}')
} catch (e) {
// 解析失败使用默认值
}
res.json({
success: true,
data: {
isAggregated: true,
quotaLimit: parseFloat(keyData.quotaLimit || 0),
quotaUsed: parseFloat(keyData.quotaUsed || 0),
quotaRemaining: parseFloat(keyData.quotaLimit || 0) - parseFloat(keyData.quotaUsed || 0),
permissions,
serviceQuotaLimits,
serviceQuotaUsed,
expiresAt: keyData.expiresAt
}
})
} catch (error) {
logger.error('❌ Get quota info error:', error)
res.status(500).json({
error: 'Failed to get quota info',
message: error.message
})
}
})
module.exports = router