use sea_orm::{EntityTrait, ColumnTrait, QueryFilter, PaginatorTrait, ActiveModelTrait, Set, QueryOrder}; use sea_orm::prelude::DateTimeWithTimeZone; use crate::{db::Db, models::role, error::AppError}; #[derive(Clone, Debug, serde::Serialize)] pub struct RoleInfo { pub id: i64, pub name: String, pub code: String, pub description: Option, pub status: i32, pub created_at: DateTimeWithTimeZone } impl From for RoleInfo { fn from(m: role::Model) -> Self { Self { id: m.id, name: m.name, code: m.code, description: m.description, status: m.status, created_at: m.created_at } } } #[derive(Clone, Debug, serde::Serialize)] pub struct PageResp { pub items: Vec, pub total: u64, pub page: u64, pub page_size: u64 } pub async fn list(db: &Db, page: u64, page_size: u64, keyword: Option) -> Result, AppError> { let mut selector = role::Entity::find(); if let Some(k) = keyword { let like = format!("%{}%", k); selector = selector.filter(role::Column::Name.like(like.clone()).or(role::Column::Code.like(like))); } let paginator = selector.order_by_desc(role::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 }) } #[derive(serde::Deserialize)] pub struct CreateRoleInput { pub name: String, pub code: String, pub description: Option, pub status: Option } pub async fn create(db: &Db, input: CreateRoleInput) -> Result { if role::Entity::find().filter(role::Column::Code.eq(input.code.clone())).one(db).await?.is_some() { return Err(AppError::BadRequest("role code already exists".into())); } let mut am: role::ActiveModel = Default::default(); am.name = Set(input.name); am.code = Set(input.code); am.description = Set(input.description); am.status = Set(input.status.unwrap_or(1)); let m = am.insert(db).await?; Ok(m.into()) } #[derive(serde::Deserialize)] pub struct UpdateRoleInput { pub name: Option, pub description: Option, pub status: Option } pub async fn update(db: &Db, id: i64, input: UpdateRoleInput) -> Result { let m = role::Entity::find_by_id(id).one(db).await?.ok_or(AppError::NotFound)?; let mut am: role::ActiveModel = m.into(); if let Some(v) = input.name { am.name = Set(v); } if let Some(v) = input.description { am.description = Set(Some(v)); } if let Some(v) = input.status { am.status = Set(v); } let m = am.update(db).await?; Ok(m.into()) } // --- Role assignments: menus only --- use crate::models::{role_menu, user_role}; use sea_orm::{TransactionTrait, QuerySelect}; pub async fn get_menu_ids(db: &Db, role_id: i64) -> Result, AppError> { let ids = role_menu::Entity::find() .filter(role_menu::Column::RoleId.eq(role_id)) .select_only() .column(role_menu::Column::MenuId) .into_tuple::() .all(db) .await?; Ok(ids) } pub async fn set_menu_ids(db: &Db, role_id: i64, ids: Vec) -> Result<(), AppError> { let txn = db.begin().await?; role_menu::Entity::delete_many() .filter(role_menu::Column::RoleId.eq(role_id)) .exec(&txn) .await?; if !ids.is_empty() { let mut items: Vec = Vec::with_capacity(ids.len()); for mid in ids { let mut am: role_menu::ActiveModel = Default::default(); am.role_id = Set(role_id); am.menu_id = Set(mid); items.push(am); } role_menu::Entity::insert_many(items).exec(&txn).await?; } txn.commit().await?; Ok(()) } pub async fn get_role_ids_by_user_id(db: &Db, user_id: i64) -> Result, AppError> { let ids = user_role::Entity::find() .filter(user_role::Column::UserId.eq(user_id)) .select_only() .column(user_role::Column::RoleId) .into_tuple::() .all(db) .await?; Ok(ids) } pub async fn get_menu_ids_by_user_id(db: &Db, user_id: i64) -> Result, AppError> { let role_ids = get_role_ids_by_user_id(db, user_id).await?; if role_ids.is_empty() { return Ok(vec![]); } let mut ids = role_menu::Entity::find() .filter(role_menu::Column::RoleId.is_in(role_ids)) .select_only() .column(role_menu::Column::MenuId) .into_tuple::() .all(db) .await?; ids.sort_unstable(); ids.dedup(); Ok(ids) } pub async fn set_role_ids_by_user_id(db: &Db, user_id: i64, role_ids: Vec) -> Result<(), AppError> { let txn = db.begin().await?; user_role::Entity::delete_many() .filter(user_role::Column::UserId.eq(user_id)) .exec(&txn) .await?; if !role_ids.is_empty() { let mut items: Vec = Vec::with_capacity(role_ids.len()); for rid in role_ids { let mut am: user_role::ActiveModel = Default::default(); am.user_id = Set(user_id); am.role_id = Set(rid); items.push(am); } user_role::Entity::insert_many(items).exec(&txn).await?; } txn.commit().await?; Ok(()) } // 新增:删除角色(清理用户与权限、菜单关联) pub async fn delete(db: &Db, id: i64) -> Result<(), AppError> { let _ = role::Entity::find_by_id(id).one(db).await?.ok_or(AppError::NotFound)?; let txn = db.begin().await?; role_menu::Entity::delete_many().filter(role_menu::Column::RoleId.eq(id)).exec(&txn).await?; user_role::Entity::delete_many().filter(user_role::Column::RoleId.eq(id)).exec(&txn).await?; let _ = role::Entity::delete_by_id(id).exec(&txn).await?; txn.commit().await?; Ok(()) }