feat: 新增告警、成本、配额、微信模块及缓存服务
All checks were successful
continuous-integration/drone/push Build is passing

- 新增告警模块 (alerts): 告警规则配置与触发
- 新增成本管理模块 (cost): 成本统计与分析
- 新增配额模块 (quota): 配额管理与限制
- 新增微信模块 (wechat): 微信相关功能接口
- 新增缓存服务 (cache): Redis 缓存封装
- 新增请求日志中间件 (request_logger)
- 新增异常处理和链路追踪中间件
- 更新 dashboard 前端展示
- 更新 SDK stats_client 功能
This commit is contained in:
111
2026-01-24 16:53:47 +08:00
parent eab2533c36
commit 6c6c48cf71
29 changed files with 4607 additions and 41 deletions

View File

@@ -7,6 +7,53 @@ const api = axios.create({
timeout: 30000
})
/**
* 解析 API 错误响应
*/
function parseApiError(error) {
const result = {
code: 'UNKNOWN_ERROR',
message: '发生了未知错误',
traceId: '',
status: 500
}
if (!error.response) {
result.code = 'NETWORK_ERROR'
result.message = '网络连接失败,请检查网络后重试'
return result
}
const { status, data, headers } = error.response
result.status = status
result.traceId = headers['x-trace-id'] || headers['X-Trace-ID'] || ''
if (data && data.error) {
result.code = data.error.code || result.code
result.message = data.error.message || result.message
result.traceId = data.error.trace_id || result.traceId
} else if (data && data.detail) {
result.message = typeof data.detail === 'string' ? data.detail : JSON.stringify(data.detail)
}
return result
}
/**
* 跳转到错误页面
*/
function navigateToErrorPage(errorInfo) {
router.push({
name: 'Error',
query: {
code: errorInfo.code,
message: errorInfo.message,
trace_id: errorInfo.traceId,
status: String(errorInfo.status)
}
})
}
// 请求拦截器
api.interceptors.request.use(
config => {
@@ -19,10 +66,15 @@ api.interceptors.request.use(
error => Promise.reject(error)
)
// 响应拦截器
// 响应拦截器(集成 TraceID 追踪)
api.interceptors.response.use(
response => response,
error => {
const errorInfo = parseApiError(error)
const traceLog = errorInfo.traceId ? ` (trace: ${errorInfo.traceId})` : ''
console.error(`[API Error] ${errorInfo.code}: ${errorInfo.message}${traceLog}`)
if (error.response?.status === 401) {
localStorage.removeItem('token')
localStorage.removeItem('user')
@@ -30,9 +82,14 @@ api.interceptors.response.use(
ElMessage.error('登录已过期,请重新登录')
} else if (error.response?.status === 403) {
ElMessage.error('没有权限执行此操作')
} else if (['INTERNAL_ERROR', 'SERVICE_UNAVAILABLE', 'GATEWAY_ERROR'].includes(errorInfo.code)) {
// 严重错误跳转到错误页面
navigateToErrorPage(errorInfo)
} else {
ElMessage.error(error.response?.data?.detail || error.message || '请求失败')
// 普通错误显示消息
ElMessage.error(errorInfo.message)
}
return Promise.reject(error)
}
)