use sea_orm::{EntityTrait, ColumnTrait, QueryFilter, ActiveModelTrait, Set, QueryOrder}; use sea_orm::prelude::DateTimeWithTimeZone; use crate::{db::Db, models::menu, error::AppError}; use sea_orm::PaginatorTrait; #[derive(Clone, Debug, serde::Serialize)] pub struct MenuInfo { pub id: i64, pub parent_id: Option, pub name: String, pub path: Option, pub component: Option, pub r#type: i32, pub icon: Option, pub order_no: i32, pub visible: bool, pub status: i32, pub keep_alive: bool, pub perms: Option, pub created_at: DateTimeWithTimeZone } impl From for MenuInfo { fn from(m: menu::Model) -> Self { Self { id: m.id, parent_id: m.parent_id, name: m.name, path: m.path, component: m.component, r#type: m.r#type, icon: m.icon, order_no: m.order_no, visible: m.visible, status: m.status, keep_alive: m.keep_alive, perms: m.perms, created_at: m.created_at } } } pub async fn list_all(db: &Db, keyword: Option) -> Result, AppError> { let mut selector = menu::Entity::find(); if let Some(k) = keyword { let like = format!("%{}%", k); selector = selector.filter(menu::Column::Name.like(like)); } let models = selector.order_by_asc(menu::Column::OrderNo).order_by_asc(menu::Column::Id).all(db).await?; Ok(models.into_iter().map(Into::into).collect()) } #[derive(serde::Deserialize)] pub struct CreateMenuInput { pub parent_id: Option, pub name: String, pub path: Option, pub component: Option, pub r#type: i32, pub icon: Option, pub order_no: Option, pub visible: Option, pub status: Option, pub keep_alive: Option, pub perms: Option } pub async fn create(db: &Db, input: CreateMenuInput) -> Result { let mut am: menu::ActiveModel = Default::default(); am.parent_id = Set(input.parent_id); am.name = Set(input.name); am.path = Set(input.path); am.component = Set(input.component); am.r#type = Set(input.r#type); am.icon = Set(input.icon); am.order_no = Set(input.order_no.unwrap_or(0)); am.visible = Set(input.visible.unwrap_or(true)); am.status = Set(input.status.unwrap_or(1)); am.keep_alive = Set(input.keep_alive.unwrap_or(true)); am.perms = Set(input.perms); let m = am.insert(db).await?; Ok(m.into()) } #[derive(serde::Deserialize)] pub struct UpdateMenuInput { pub parent_id: Option, pub name: Option, pub path: Option, pub component: Option, pub r#type: Option, pub icon: Option, pub order_no: Option, pub visible: Option, pub status: Option, pub keep_alive: Option, pub perms: Option } pub async fn update(db: &Db, id: i64, input: UpdateMenuInput) -> Result { let m = menu::Entity::find_by_id(id).one(db).await?.ok_or(AppError::NotFound)?; let mut am: menu::ActiveModel = m.into(); if let Some(v) = input.parent_id { am.parent_id = Set(Some(v)); } if let Some(v) = input.name { am.name = Set(v); } if let Some(v) = input.path { am.path = Set(Some(v)); } if let Some(v) = input.component { am.component = Set(Some(v)); } if let Some(v) = input.r#type { am.r#type = Set(v); } if let Some(v) = input.icon { am.icon = Set(Some(v)); } if let Some(v) = input.order_no { am.order_no = Set(v); } if let Some(v) = input.visible { am.visible = Set(v); } if let Some(v) = input.status { am.status = Set(v); } if let Some(v) = input.keep_alive { am.keep_alive = Set(v); } if let Some(v) = input.perms { am.perms = Set(Some(v)); } let m = am.update(db).await?; Ok(m.into()) } pub async fn list_by_ids(db: &Db, ids: Vec) -> Result, AppError> { if ids.is_empty() { return Ok(vec![]); } let models = menu::Entity::find() .filter(menu::Column::Id.is_in(ids)) .filter(menu::Column::Visible.eq(true)) .filter(menu::Column::Status.eq(1)) .order_by_asc(menu::Column::OrderNo) .order_by_asc(menu::Column::Id) .all(db) .await?; Ok(models.into_iter().map(Into::into).collect()) } // 新增:删除菜单(禁止删除存在子菜单的项),并清理角色关联 use crate::models::role_menu; use sea_orm::TransactionTrait; pub async fn delete(db: &Db, id: i64) -> Result<(), AppError> { let _ = menu::Entity::find_by_id(id).one(db).await?.ok_or(AppError::NotFound)?; let child_count = menu::Entity::find().filter(menu::Column::ParentId.eq(Some(id))).count(db).await?; if child_count > 0 { return Err(AppError::BadRequest("请先删除子菜单".into())); } let txn = db.begin().await?; role_menu::Entity::delete_many().filter(role_menu::Column::MenuId.eq(id)).exec(&txn).await?; let _ = menu::Entity::delete_by_id(id).exec(&txn).await?; txn.commit().await?; Ok(()) }