use axum::Json; use axum::extract::FromRef; use axum::extract::{Extension, Path, Query, State}; use serde::Deserialize; use uuid::Uuid; use erp_core::error::AppError; use erp_core::rbac::require_permission; use erp_core::types::{ApiResponse, PaginatedResponse, TenantContext}; use validator::Validate; use crate::dto::{CreateTemplateReq, MessageTemplateResp, UpdateTemplateReq}; use crate::message_state::MessageState; use crate::service::template_service::TemplateService; #[derive(Debug, Deserialize, utoipa::IntoParams)] pub struct TemplateQuery { pub page: Option, pub page_size: Option, } #[utoipa::path( get, path = "/api/v1/message-templates", params(TemplateQuery), responses( (status = 200, description = "成功", body = ApiResponse>), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "消息模板" )] /// 查询消息模板列表。 pub async fn list_templates( State(_state): State, Extension(ctx): Extension, Query(query): Query, ) -> Result>>, AppError> where MessageState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "message.template.list")?; let page = query.page.unwrap_or(1).max(1); let page_size = query.page_size.unwrap_or(20).max(1); let (templates, total) = TemplateService::list(ctx.tenant_id, page, page_size, &_state.db).await?; let total_pages = total.div_ceil(page_size); Ok(Json(ApiResponse::ok(PaginatedResponse { data: templates, total, page, page_size, total_pages, }))) } #[utoipa::path( post, path = "/api/v1/message-templates", request_body = CreateTemplateReq, responses( (status = 200, description = "成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "消息模板" )] /// 创建消息模板。 pub async fn create_template( State(_state): State, Extension(ctx): Extension, Json(req): Json, ) -> Result>, AppError> where MessageState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "message.template.create")?; req.validate() .map_err(|e| AppError::Validation(e.to_string()))?; let resp = TemplateService::create(ctx.tenant_id, ctx.user_id, &req, &_state.db).await?; Ok(Json(ApiResponse::ok(resp))) } #[utoipa::path( put, path = "/api/v1/message-templates/{id}", request_body = UpdateTemplateReq, responses( (status = 200, description = "成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "消息模板" )] /// 更新消息模板。 pub async fn update_template( State(_state): State, Extension(ctx): Extension, Path(id): Path, Json(req): Json, ) -> Result>, AppError> where MessageState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "message.template.manage")?; req.validate() .map_err(|e| AppError::Validation(e.to_string()))?; let resp = TemplateService::update(id, ctx.tenant_id, ctx.user_id, &req, &_state.db).await?; Ok(Json(ApiResponse::ok(resp))) } /// 删除消息模板。 #[allow(clippy::type_complexity)] pub async fn delete_template( State(_state): State, Extension(ctx): Extension, Path(id): Path, ) -> Result>, AppError> where MessageState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "message.template.manage")?; TemplateService::delete(id, ctx.tenant_id, ctx.user_id, &_state.db).await?; Ok(Json(ApiResponse::ok(()))) }