use axum::Extension; use axum::extract::{FromRef, Path, State}; use axum::response::Json; use validator::Validate; use erp_core::error::AppError; use erp_core::types::{ApiResponse, TenantContext}; use uuid::Uuid; use crate::auth_state::AuthState; use crate::dto::{ CreateDepartmentReq, CreateOrganizationReq, CreatePositionReq, DepartmentResp, OrganizationResp, PositionResp, UpdateDepartmentReq, UpdateOrganizationReq, UpdatePositionReq, }; use crate::service::dept_service::DeptService; use crate::service::org_service::OrgService; use crate::service::position_service::PositionService; use erp_core::rbac::require_permission; // --- Organization handlers --- #[utoipa::path( get, path = "/api/v1/organizations", responses( (status = 200, description = "成功", body = ApiResponse>), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// GET /api/v1/organizations /// /// List all organizations within the current tenant as a nested tree. /// Requires the `organization.list` permission. pub async fn list_organizations( State(state): State, Extension(ctx): Extension, ) -> Result>>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "organization.list")?; let tree = OrgService::get_tree(ctx.tenant_id, &state.db).await?; Ok(Json(ApiResponse::ok(tree))) } #[utoipa::path( post, path = "/api/v1/organizations", request_body = CreateOrganizationReq, responses( (status = 200, description = "创建成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// POST /api/v1/organizations /// /// Create a new organization within the current tenant. /// Requires the `organization.create` permission. pub async fn create_organization( State(state): State, Extension(ctx): Extension, Json(req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "organization.create")?; req.validate() .map_err(|e| AppError::Validation(e.to_string()))?; let org = OrgService::create( ctx.tenant_id, ctx.user_id, &req, &state.db, &state.event_bus, ) .await?; Ok(Json(ApiResponse::ok(org))) } #[utoipa::path( put, path = "/api/v1/organizations/{id}", params(("id" = Uuid, Path, description = "组织ID")), request_body = UpdateOrganizationReq, responses( (status = 200, description = "更新成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "组织不存在"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// PUT /api/v1/organizations/{id} /// /// Update editable organization fields (name, code, sort_order). /// Requires the `organization.update` permission. pub async fn update_organization( State(state): State, Extension(ctx): Extension, Path(id): Path, Json(req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "organization.update")?; let org = OrgService::update(id, ctx.tenant_id, ctx.user_id, &req, &state.db).await?; Ok(Json(ApiResponse::ok(org))) } #[utoipa::path( delete, path = "/api/v1/organizations/{id}", params(("id" = Uuid, Path, description = "组织ID")), responses( (status = 200, description = "组织已删除"), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "组织不存在"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// DELETE /api/v1/organizations/{id} /// /// Soft-delete an organization by ID. /// Requires the `organization.delete` permission. pub async fn delete_organization( State(state): State, Extension(ctx): Extension, Path(id): Path, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "organization.delete")?; OrgService::delete(id, ctx.tenant_id, ctx.user_id, &state.db, &state.event_bus).await?; Ok(Json(ApiResponse { success: true, data: None, message: Some("组织已删除".to_string()), })) } // --- Department handlers --- #[utoipa::path( get, path = "/api/v1/organizations/{org_id}/departments", params(("org_id" = Uuid, Path, description = "组织ID")), responses( (status = 200, description = "成功", body = ApiResponse>), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// GET /api/v1/organizations/{org_id}/departments /// /// List all departments for an organization as a nested tree. /// Requires the `department.list` permission. pub async fn list_departments( State(state): State, Extension(ctx): Extension, Path(org_id): Path, ) -> Result>>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "department.list")?; let tree = DeptService::list_tree(org_id, ctx.tenant_id, &state.db).await?; Ok(Json(ApiResponse::ok(tree))) } #[utoipa::path( post, path = "/api/v1/organizations/{org_id}/departments", params(("org_id" = Uuid, Path, description = "组织ID")), request_body = CreateDepartmentReq, responses( (status = 200, description = "创建成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// POST /api/v1/organizations/{org_id}/departments /// /// Create a new department under the specified organization. /// Requires the `department.create` permission. pub async fn create_department( State(state): State, Extension(ctx): Extension, Path(org_id): Path, Json(req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "department.create")?; req.validate() .map_err(|e| AppError::Validation(e.to_string()))?; let dept = DeptService::create( org_id, ctx.tenant_id, ctx.user_id, &req, &state.db, &state.event_bus, ) .await?; Ok(Json(ApiResponse::ok(dept))) } #[utoipa::path( put, path = "/api/v1/departments/{id}", params(("id" = Uuid, Path, description = "部门ID")), request_body = UpdateDepartmentReq, responses( (status = 200, description = "更新成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "部门不存在"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// PUT /api/v1/departments/{id} /// /// Update editable department fields (name, code, manager_id, sort_order). /// Requires the `department.update` permission. pub async fn update_department( State(state): State, Extension(ctx): Extension, Path(id): Path, Json(req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "department.update")?; let dept = DeptService::update(id, ctx.tenant_id, ctx.user_id, &req, &state.db).await?; Ok(Json(ApiResponse::ok(dept))) } #[utoipa::path( delete, path = "/api/v1/departments/{id}", params(("id" = Uuid, Path, description = "部门ID")), responses( (status = 200, description = "部门已删除"), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "部门不存在"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// DELETE /api/v1/departments/{id} /// /// Soft-delete a department by ID. /// Requires the `department.delete` permission. pub async fn delete_department( State(state): State, Extension(ctx): Extension, Path(id): Path, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "department.delete")?; DeptService::delete(id, ctx.tenant_id, ctx.user_id, &state.db, &state.event_bus).await?; Ok(Json(ApiResponse { success: true, data: None, message: Some("部门已删除".to_string()), })) } // --- Position handlers --- #[utoipa::path( get, path = "/api/v1/departments/{dept_id}/positions", params(("dept_id" = Uuid, Path, description = "部门ID")), responses( (status = 200, description = "成功", body = ApiResponse>), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// GET /api/v1/departments/{dept_id}/positions /// /// List all positions for a department. /// Requires the `position.list` permission. pub async fn list_positions( State(state): State, Extension(ctx): Extension, Path(dept_id): Path, ) -> Result>>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "position.list")?; let positions = PositionService::list(dept_id, ctx.tenant_id, &state.db).await?; Ok(Json(ApiResponse::ok(positions))) } #[utoipa::path( post, path = "/api/v1/departments/{dept_id}/positions", params(("dept_id" = Uuid, Path, description = "部门ID")), request_body = CreatePositionReq, responses( (status = 200, description = "创建成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// POST /api/v1/departments/{dept_id}/positions /// /// Create a new position under the specified department. /// Requires the `position.create` permission. pub async fn create_position( State(state): State, Extension(ctx): Extension, Path(dept_id): Path, Json(req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "position.create")?; req.validate() .map_err(|e| AppError::Validation(e.to_string()))?; let pos = PositionService::create( dept_id, ctx.tenant_id, ctx.user_id, &req, &state.db, &state.event_bus, ) .await?; Ok(Json(ApiResponse::ok(pos))) } #[utoipa::path( put, path = "/api/v1/positions/{id}", params(("id" = Uuid, Path, description = "岗位ID")), request_body = UpdatePositionReq, responses( (status = 200, description = "更新成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "岗位不存在"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// PUT /api/v1/positions/{id} /// /// Update editable position fields (name, code, level, sort_order). /// Requires the `position.update` permission. pub async fn update_position( State(state): State, Extension(ctx): Extension, Path(id): Path, Json(req): Json, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "position.update")?; let pos = PositionService::update(id, ctx.tenant_id, ctx.user_id, &req, &state.db).await?; Ok(Json(ApiResponse::ok(pos))) } #[utoipa::path( delete, path = "/api/v1/positions/{id}", params(("id" = Uuid, Path, description = "岗位ID")), responses( (status = 200, description = "岗位已删除"), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), (status = 404, description = "岗位不存在"), ), security(("bearer_auth" = [])), tag = "组织管理" )] /// DELETE /api/v1/positions/{id} /// /// Soft-delete a position by ID. /// Requires the `position.delete` permission. pub async fn delete_position( State(state): State, Extension(ctx): Extension, Path(id): Path, ) -> Result>, AppError> where AuthState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "position.delete")?; PositionService::delete(id, ctx.tenant_id, ctx.user_id, &state.db, &state.event_bus).await?; Ok(Json(ApiResponse { success: true, data: None, message: Some("岗位已删除".to_string()), })) }