109 lines
3.2 KiB
Rust
109 lines
3.2 KiB
Rust
use axum::Extension;
|
||
use axum::extract::{FromRef, Json, State};
|
||
use axum::response::Json as JsonResponse;
|
||
|
||
use erp_core::error::AppError;
|
||
use erp_core::rbac::require_permission;
|
||
use erp_core::types::{ApiResponse, TenantContext};
|
||
|
||
use crate::config_state::ConfigState;
|
||
use crate::dto::{SetSettingParams, ThemeResp};
|
||
use crate::error::ConfigError;
|
||
use crate::service::setting_service::SettingService;
|
||
|
||
/// 默认主题配置。
|
||
fn default_theme() -> ThemeResp {
|
||
ThemeResp {
|
||
primary_color: None,
|
||
logo_url: None,
|
||
sidebar_style: None,
|
||
}
|
||
}
|
||
|
||
#[utoipa::path(
|
||
get,
|
||
path = "/api/v1/themes",
|
||
responses(
|
||
(status = 200, description = "成功", body = ApiResponse<ThemeResp>),
|
||
(status = 401, description = "未授权"),
|
||
(status = 403, description = "权限不足"),
|
||
),
|
||
security(("bearer_auth" = [])),
|
||
tag = "主题设置"
|
||
)]
|
||
/// GET /api/v1/theme
|
||
///
|
||
/// 获取当前租户的主题配置。
|
||
/// 主题配置存储在 settings 表中,key 为 "theme",scope 为 "tenant"。
|
||
/// 当没有任何主题配置时,返回默认主题(所有字段为 null)。
|
||
/// 需要 `theme.read` 权限。
|
||
pub async fn get_theme<S>(
|
||
State(state): State<ConfigState>,
|
||
Extension(ctx): Extension<TenantContext>,
|
||
) -> Result<JsonResponse<ApiResponse<ThemeResp>>, AppError>
|
||
where
|
||
ConfigState: FromRef<S>,
|
||
S: Clone + Send + Sync + 'static,
|
||
{
|
||
require_permission(&ctx, "theme.read")?;
|
||
|
||
let theme = match SettingService::get("theme", "tenant", &None, ctx.tenant_id, &state.db).await
|
||
{
|
||
Ok(setting) => serde_json::from_value(setting.setting_value)
|
||
.map_err(|e| AppError::Validation(format!("主题配置解析失败: {e}")))?,
|
||
Err(ConfigError::NotFound(_)) => default_theme(),
|
||
Err(e) => return Err(e.into()),
|
||
};
|
||
|
||
Ok(JsonResponse(ApiResponse::ok(theme)))
|
||
}
|
||
|
||
#[utoipa::path(
|
||
put,
|
||
path = "/api/v1/themes",
|
||
request_body = ThemeResp,
|
||
responses(
|
||
(status = 200, description = "成功", body = ApiResponse<ThemeResp>),
|
||
(status = 401, description = "未授权"),
|
||
(status = 403, description = "权限不足"),
|
||
),
|
||
security(("bearer_auth" = [])),
|
||
tag = "主题设置"
|
||
)]
|
||
/// PUT /api/v1/theme
|
||
///
|
||
/// 更新当前租户的主题配置。
|
||
/// 将主题配置序列化为 JSON 存储到 settings 表。
|
||
/// 需要 `theme.update` 权限。
|
||
pub async fn update_theme<S>(
|
||
State(state): State<ConfigState>,
|
||
Extension(ctx): Extension<TenantContext>,
|
||
Json(req): Json<ThemeResp>,
|
||
) -> Result<JsonResponse<ApiResponse<ThemeResp>>, AppError>
|
||
where
|
||
ConfigState: FromRef<S>,
|
||
S: Clone + Send + Sync + 'static,
|
||
{
|
||
require_permission(&ctx, "theme.update")?;
|
||
|
||
let value = serde_json::to_value(&req)
|
||
.map_err(|e| AppError::Validation(format!("主题配置序列化失败: {e}")))?;
|
||
|
||
SettingService::set(
|
||
SetSettingParams {
|
||
key: "theme".to_string(),
|
||
scope: "tenant".to_string(),
|
||
scope_id: None,
|
||
value,
|
||
version: None,
|
||
},
|
||
ctx.tenant_id,
|
||
ctx.user_id,
|
||
&state.db,
|
||
&state.event_bus,
|
||
)
|
||
.await?;
|
||
|
||
Ok(JsonResponse(ApiResponse::ok(req)))
|
||
}
|