//! 使用统计相关命令 use crate::error::AppError; use crate::services::usage_stats::*; use crate::store::AppState; use tauri::State; /// 获取使用量汇总 #[tauri::command] pub fn get_usage_summary( state: State<'_, AppState>, start_date: Option, end_date: Option, ) -> Result { state.db.get_usage_summary(start_date, end_date) } /// 获取每日趋势 #[tauri::command] pub fn get_usage_trends( state: State<'_, AppState>, start_date: Option, end_date: Option, ) -> Result, AppError> { state.db.get_daily_trends(start_date, end_date) } /// 获取 Provider 统计 #[tauri::command] pub fn get_provider_stats(state: State<'_, AppState>) -> Result, AppError> { state.db.get_provider_stats() } /// 获取模型统计 #[tauri::command] pub fn get_model_stats(state: State<'_, AppState>) -> Result, AppError> { state.db.get_model_stats() } /// 获取请求日志列表 #[tauri::command] pub fn get_request_logs( state: State<'_, AppState>, filters: LogFilters, page: u32, page_size: u32, ) -> Result { state.db.get_request_logs(&filters, page, page_size) } /// 获取单个请求详情 #[tauri::command] pub fn get_request_detail( state: State<'_, AppState>, request_id: String, ) -> Result, AppError> { state.db.get_request_detail(&request_id) } /// 获取模型定价列表 #[tauri::command] pub fn get_model_pricing(state: State<'_, AppState>) -> Result, AppError> { log::info!("获取模型定价列表"); state.db.ensure_model_pricing_seeded()?; let db = state.db.clone(); let conn = crate::database::lock_conn!(db.conn); // 检查表是否存在 let table_exists: bool = conn .query_row( "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='model_pricing'", [], |row| row.get::<_, i64>(0).map(|count| count > 0), ) .unwrap_or(false); if !table_exists { log::error!("model_pricing 表不存在,可能需要重启应用以触发数据库迁移"); return Ok(Vec::new()); } let mut stmt = conn.prepare( "SELECT model_id, display_name, input_cost_per_million, output_cost_per_million, cache_read_cost_per_million, cache_creation_cost_per_million FROM model_pricing ORDER BY display_name", )?; let rows = stmt.query_map([], |row| { Ok(ModelPricingInfo { model_id: row.get(0)?, display_name: row.get(1)?, input_cost_per_million: row.get(2)?, output_cost_per_million: row.get(3)?, cache_read_cost_per_million: row.get(4)?, cache_creation_cost_per_million: row.get(5)?, }) })?; let mut pricing = Vec::new(); for row in rows { pricing.push(row?); } log::info!("成功获取 {} 条模型定价数据", pricing.len()); Ok(pricing) } /// 更新模型定价 #[tauri::command] pub fn update_model_pricing( state: State<'_, AppState>, model_id: String, display_name: String, input_cost: String, output_cost: String, cache_read_cost: String, cache_creation_cost: String, ) -> Result<(), AppError> { let db = state.db.clone(); let conn = crate::database::lock_conn!(db.conn); conn.execute( "INSERT OR REPLACE INTO model_pricing ( model_id, display_name, input_cost_per_million, output_cost_per_million, cache_read_cost_per_million, cache_creation_cost_per_million ) VALUES (?1, ?2, ?3, ?4, ?5, ?6)", rusqlite::params![ model_id, display_name, input_cost, output_cost, cache_read_cost, cache_creation_cost ], ) .map_err(|e| AppError::Database(format!("更新模型定价失败: {e}")))?; Ok(()) } /// 检查 Provider 使用限额 #[tauri::command] pub fn check_provider_limits( state: State<'_, AppState>, provider_id: String, app_type: String, ) -> Result { state.db.check_provider_limits(&provider_id, &app_type) } /// 删除模型定价 #[tauri::command] pub fn delete_model_pricing(state: State<'_, AppState>, model_id: String) -> Result<(), AppError> { let db = state.db.clone(); let conn = crate::database::lock_conn!(db.conn); conn.execute( "DELETE FROM model_pricing WHERE model_id = ?1", rusqlite::params![model_id], ) .map_err(|e| AppError::Database(format!("删除模型定价失败: {e}")))?; log::info!("已删除模型定价: {model_id}"); Ok(()) } /// 模型定价信息 #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct ModelPricingInfo { pub model_id: String, pub display_name: String, pub input_cost_per_million: String, pub output_cost_per_million: String, pub cache_read_cost_per_million: String, pub cache_creation_cost_per_million: String, }