use axum::Extension; use axum::extract::{FromRef, Json, Path, State}; use axum::response::Json as JsonResponse; use erp_core::error::AppError; use erp_core::rbac::require_permission; use erp_core::types::{ApiResponse, Pagination, TenantContext}; use crate::config_state::ConfigState; use crate::dto::{LanguageResp, SetSettingParams, UpdateLanguageReq}; use crate::service::setting_service::SettingService; #[utoipa::path( get, path = "/api/v1/languages", responses( (status = 200, description = "成功", body = ApiResponse>), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "语言管理" )] /// GET /api/v1/languages /// /// 获取当前租户的语言配置列表。 /// 查询 scope 为 "platform" 的设置,过滤 key 以 "language." 开头的记录。 /// 需要 `language.list` 权限。 pub async fn list_languages( State(state): State, Extension(ctx): Extension, ) -> Result>>, AppError> where ConfigState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "language.list")?; let pagination = Pagination { page: Some(1), page_size: Some(100), }; let (settings, _total) = SettingService::list_by_scope("platform", &None, ctx.tenant_id, &pagination, &state.db) .await?; let languages: Vec = settings .into_iter() .filter(|s| s.setting_key.starts_with("language.")) .filter_map(|s| { let code = s.setting_key.strip_prefix("language.")?.to_string(); let name = s .setting_value .get("name") .and_then(|v| v.as_str()) .unwrap_or(&code) .to_string(); let is_active = s .setting_value .get("is_active") .and_then(|v| v.as_bool()) .unwrap_or(true); Some(LanguageResp { code, name, is_active, }) }) .collect(); Ok(JsonResponse(ApiResponse::ok(languages))) } #[utoipa::path( put, path = "/api/v1/languages/{code}", params(("code" = String, Path, description = "语言编码")), request_body = UpdateLanguageReq, responses( (status = 200, description = "成功", body = ApiResponse), (status = 401, description = "未授权"), (status = 403, description = "权限不足"), ), security(("bearer_auth" = [])), tag = "语言管理" )] /// PUT /api/v1/languages/:code /// /// 更新指定语言配置的激活状态。 /// 语言配置存储在 settings 表中,key 为 "language.{code}",scope 为 "platform"。 /// 需要 `language.update` 权限。 pub async fn update_language( State(state): State, Extension(ctx): Extension, Path(code): Path, Json(req): Json, ) -> Result>, AppError> where ConfigState: FromRef, S: Clone + Send + Sync + 'static, { require_permission(&ctx, "language.update")?; let key = format!("language.{}", code); let mut value = serde_json::json!({"is_active": req.is_active}); if let Some(ref name) = req.name { value["name"] = serde_json::Value::String(name.clone()); } SettingService::set( SetSettingParams { key: key.clone(), scope: "platform".to_string(), scope_id: None, value, version: None, }, ctx.tenant_id, ctx.user_id, &state.db, &state.event_bus, ) .await?; // 从返回的 SettingResp 中读取实际值 let updated = SettingService::get(&key, "platform", &None, ctx.tenant_id, &state.db).await?; // 尝试从 value 中提取 name,否则用 code 作为默认名称 let name = updated .setting_value .get("name") .and_then(|v| v.as_str()) .unwrap_or(&code) .to_string(); Ok(JsonResponse(ApiResponse::ok(LanguageResp { code, name, is_active: req.is_active, }))) }