Files
udmin/backend/src/services/log_service.rs
ayou 214605d912 feat: 统一分页组件并添加批量删除功能
为多个页面组件添加统一的分页统计显示和批量删除功能
在日志管理页面添加批量删除接口和前端实现
优化表格分页配置,统一显示总条目数和分页选项
2025-09-25 23:52:01 +08:00

81 lines
3.6 KiB
Rust

use crate::{db::Db, models::request_log};
use sea_orm::{ActiveModelTrait, Set, EntityTrait, ColumnTrait, QueryFilter, PaginatorTrait, QueryOrder};
use chrono::{DateTime, FixedOffset, Utc};
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug)]
pub struct CreateLogInput {
pub path: String,
pub method: String,
pub request_params: Option<String>,
pub response_params: Option<String>,
pub status_code: i32,
pub user_id: Option<i64>,
pub username: Option<String>,
pub request_time: DateTime<FixedOffset>,
pub duration_ms: i64,
}
pub async fn create(db: &Db, input: CreateLogInput) -> anyhow::Result<i64> {
let am = request_log::ActiveModel {
id: Set(crate::utils::generate_request_log_id()),
path: Set(input.path),
method: Set(input.method),
request_params: Set(input.request_params),
response_params: Set(input.response_params),
status_code: Set(input.status_code),
user_id: Set(input.user_id),
username: Set(input.username),
request_time: Set(input.request_time),
duration_ms: Set(input.duration_ms),
created_at: Set(Utc::now().with_timezone(&FixedOffset::east_opt(0).unwrap())),
};
let m = am.insert(db).await?;
Ok(m.id)
}
#[derive(serde::Serialize, Clone, Debug)]
pub struct LogInfo {
pub id: i64,
pub path: String,
pub method: String,
pub request_params: Option<String>,
pub response_params: Option<String>,
pub status_code: i32,
pub user_id: Option<i64>,
pub username: Option<String>,
pub request_time: chrono::DateTime<FixedOffset>,
pub duration_ms: i64,
}
impl From<request_log::Model> for LogInfo {
fn from(m: request_log::Model) -> Self {
Self { id: m.id, path: m.path, method: m.method, request_params: m.request_params, response_params: m.response_params, status_code: m.status_code, user_id: m.user_id, username: m.username, request_time: m.request_time, duration_ms: m.duration_ms }
}
}
#[derive(serde::Serialize)]
pub struct PageResp<T> { pub items: Vec<T>, pub total: u64, pub page: u64, pub page_size: u64 }
#[derive(serde::Deserialize)]
pub struct ListParams { pub page: Option<u64>, pub page_size: Option<u64>, pub path: Option<String>, pub start_time: Option<String>, pub end_time: Option<String> }
pub async fn list(db: &Db, p: ListParams) -> anyhow::Result<PageResp<LogInfo>> {
let page = p.page.unwrap_or(1); let page_size = p.page_size.unwrap_or(10);
let mut selector = request_log::Entity::find();
if let Some(path) = p.path { let like = format!("%{}%", path); selector = selector.filter(request_log::Column::Path.like(like)); }
if let Some(start) = p.start_time.as_deref() { if let Ok(dt) = start.parse::<chrono::DateTime<FixedOffset>>() { selector = selector.filter(request_log::Column::RequestTime.gte(dt)); } }
if let Some(end) = p.end_time.as_deref() { if let Ok(dt) = end.parse::<chrono::DateTime<FixedOffset>>() { selector = selector.filter(request_log::Column::RequestTime.lte(dt)); } }
let paginator = selector.order_by_desc(request_log::Column::Id).paginate(db, page_size);
let total = paginator.num_items().await? as u64;
let models = paginator.fetch_page(if page>0 { page-1 } else { 0 }).await?;
Ok(PageResp { items: models.into_iter().map(Into::into).collect(), total, page, page_size })
}
// 新增:批量删除系统请求日志
pub async fn delete_many(db: &Db, ids: Vec<i64>) -> anyhow::Result<u64> {
if ids.is_empty() { return Ok(0); }
let res = request_log::Entity::delete_many()
.filter(request_log::Column::Id.is_in(ids))
.exec(db)
.await?;
Ok(res.rows_affected as u64)
}