- CORS: replace permissive() with configurable whitelist (default.toml) - Auth store: synchronously restore state at creation to eliminate flash-of-login-page on refresh - MainLayout: menu highlight now tracks current route via useLocation - Add extractErrorMessage() utility to reduce repeated error parsing - Fix all clippy warnings across 4 crates (erp-auth, erp-config, erp-workflow, erp-message): remove unnecessary casts, use div_ceil, collapse nested ifs, reduce function arguments with DTOs
227 lines
6.3 KiB
Rust
227 lines
6.3 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use utoipa::ToSchema;
|
|
use uuid::Uuid;
|
|
use validator::Validate;
|
|
|
|
// --- Dictionary DTOs ---
|
|
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct DictionaryItemResp {
|
|
pub id: Uuid,
|
|
pub dictionary_id: Uuid,
|
|
pub label: String,
|
|
pub value: String,
|
|
pub sort_order: i32,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub color: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct DictionaryResp {
|
|
pub id: Uuid,
|
|
pub name: String,
|
|
pub code: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub description: Option<String>,
|
|
pub items: Vec<DictionaryItemResp>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
|
pub struct CreateDictionaryReq {
|
|
#[validate(length(min = 1, max = 100, message = "字典名称不能为空"))]
|
|
pub name: String,
|
|
#[validate(length(min = 1, max = 50, message = "字典编码不能为空"))]
|
|
pub code: String,
|
|
pub description: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, ToSchema)]
|
|
pub struct UpdateDictionaryReq {
|
|
pub name: Option<String>,
|
|
pub description: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
|
pub struct CreateDictionaryItemReq {
|
|
#[validate(length(min = 1, max = 100, message = "标签不能为空"))]
|
|
pub label: String,
|
|
#[validate(length(min = 1, max = 100, message = "值不能为空"))]
|
|
pub value: String,
|
|
pub sort_order: Option<i32>,
|
|
pub color: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, ToSchema)]
|
|
pub struct UpdateDictionaryItemReq {
|
|
pub label: Option<String>,
|
|
pub value: Option<String>,
|
|
pub sort_order: Option<i32>,
|
|
pub color: Option<String>,
|
|
}
|
|
|
|
// --- Menu DTOs ---
|
|
|
|
#[derive(Debug, Serialize, ToSchema, Clone)]
|
|
pub struct MenuResp {
|
|
pub id: Uuid,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub parent_id: Option<Uuid>,
|
|
pub title: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub path: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub icon: Option<String>,
|
|
pub sort_order: i32,
|
|
pub visible: bool,
|
|
pub menu_type: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub permission: Option<String>,
|
|
pub children: Vec<MenuResp>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
|
pub struct CreateMenuReq {
|
|
pub parent_id: Option<Uuid>,
|
|
#[validate(length(min = 1, max = 100, message = "菜单标题不能为空"))]
|
|
pub title: String,
|
|
pub path: Option<String>,
|
|
pub icon: Option<String>,
|
|
pub sort_order: Option<i32>,
|
|
pub visible: Option<bool>,
|
|
#[validate(length(min = 1, message = "菜单类型不能为空"))]
|
|
pub menu_type: Option<String>,
|
|
pub permission: Option<String>,
|
|
pub role_ids: Option<Vec<Uuid>>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, ToSchema)]
|
|
pub struct UpdateMenuReq {
|
|
pub title: Option<String>,
|
|
pub path: Option<String>,
|
|
pub icon: Option<String>,
|
|
pub sort_order: Option<i32>,
|
|
pub visible: Option<bool>,
|
|
pub permission: Option<String>,
|
|
pub role_ids: Option<Vec<Uuid>>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
|
pub struct BatchSaveMenusReq {
|
|
#[validate(length(min = 1, message = "菜单列表不能为空"))]
|
|
pub menus: Vec<MenuItemReq>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Validate, ToSchema)]
|
|
pub struct MenuItemReq {
|
|
pub id: Option<Uuid>,
|
|
pub parent_id: Option<Uuid>,
|
|
#[validate(length(min = 1, max = 100, message = "菜单标题不能为空"))]
|
|
pub title: String,
|
|
pub path: Option<String>,
|
|
pub icon: Option<String>,
|
|
pub sort_order: Option<i32>,
|
|
pub visible: Option<bool>,
|
|
pub menu_type: Option<String>,
|
|
pub permission: Option<String>,
|
|
pub role_ids: Option<Vec<Uuid>>,
|
|
}
|
|
|
|
// --- Setting DTOs ---
|
|
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct SettingResp {
|
|
pub id: Uuid,
|
|
pub scope: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub scope_id: Option<Uuid>,
|
|
pub setting_key: String,
|
|
pub setting_value: serde_json::Value,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
|
pub struct UpdateSettingReq {
|
|
pub setting_value: serde_json::Value,
|
|
}
|
|
|
|
/// 内部参数结构体,用于减少 SettingService::set 的参数数量。
|
|
pub struct SetSettingParams {
|
|
pub key: String,
|
|
pub scope: String,
|
|
pub scope_id: Option<Uuid>,
|
|
pub value: serde_json::Value,
|
|
}
|
|
|
|
// --- Numbering Rule DTOs ---
|
|
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct NumberingRuleResp {
|
|
pub id: Uuid,
|
|
pub name: String,
|
|
pub code: String,
|
|
pub prefix: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub date_format: Option<String>,
|
|
pub seq_length: i32,
|
|
pub seq_start: i32,
|
|
pub seq_current: i64,
|
|
pub separator: String,
|
|
pub reset_cycle: String,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub last_reset_date: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Validate, ToSchema)]
|
|
pub struct CreateNumberingRuleReq {
|
|
#[validate(length(min = 1, max = 100, message = "规则名称不能为空"))]
|
|
pub name: String,
|
|
#[validate(length(min = 1, max = 50, message = "规则编码不能为空"))]
|
|
pub code: String,
|
|
pub prefix: Option<String>,
|
|
pub date_format: Option<String>,
|
|
pub seq_length: Option<i32>,
|
|
pub seq_start: Option<i32>,
|
|
pub separator: Option<String>,
|
|
pub reset_cycle: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, ToSchema)]
|
|
pub struct UpdateNumberingRuleReq {
|
|
pub name: Option<String>,
|
|
pub prefix: Option<String>,
|
|
pub date_format: Option<String>,
|
|
pub seq_length: Option<i32>,
|
|
pub separator: Option<String>,
|
|
pub reset_cycle: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct GenerateNumberResp {
|
|
pub number: String,
|
|
}
|
|
|
|
// --- Theme DTOs (stored via settings) ---
|
|
|
|
#[derive(Debug, Serialize, Deserialize, ToSchema, Clone)]
|
|
pub struct ThemeResp {
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub primary_color: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub logo_url: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub sidebar_style: Option<String>,
|
|
}
|
|
|
|
// --- Language DTOs (stored via settings) ---
|
|
|
|
#[derive(Debug, Serialize, ToSchema)]
|
|
pub struct LanguageResp {
|
|
pub code: String,
|
|
pub name: String,
|
|
pub is_active: bool,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, ToSchema)]
|
|
pub struct UpdateLanguageReq {
|
|
pub is_active: bool,
|
|
}
|