chore: apply cargo fmt across workspace and update docs

- Run cargo fmt on all Rust crates for consistent formatting
- Update CLAUDE.md with WASM plugin commands and dev.ps1 instructions
- Update wiki: add WASM plugin architecture, rewrite dev environment docs
- Minor frontend cleanup (unused imports)
This commit is contained in:
iven
2026-04-15 00:49:20 +08:00
parent e16c1a85d7
commit 9568dd7875
113 changed files with 4355 additions and 937 deletions

View File

@@ -1,7 +1,5 @@
use chrono::Utc;
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set,
};
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set};
use uuid::Uuid;
use crate::dto::{DictionaryItemResp, DictionaryResp};
@@ -133,15 +131,25 @@ impl DictionaryService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
event_bus.publish(erp_core::events::DomainEvent::new(
"dictionary.created",
tenant_id,
serde_json::json!({ "dictionary_id": id, "code": code }),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"dictionary.created",
tenant_id,
serde_json::json!({ "dictionary_id": id, "code": code }),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "dictionary.create", "dictionary")
.with_resource_id(id),
AuditLog::new(
tenant_id,
Some(operator_id),
"dictionary.create",
"dictionary",
)
.with_resource_id(id),
db,
)
.await;
@@ -198,8 +206,13 @@ impl DictionaryService {
let items = Self::fetch_items(updated.id, tenant_id, db).await?;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "dictionary.update", "dictionary")
.with_resource_id(id),
AuditLog::new(
tenant_id,
Some(operator_id),
"dictionary.update",
"dictionary",
)
.with_resource_id(id),
db,
)
.await;
@@ -244,15 +257,25 @@ impl DictionaryService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
event_bus.publish(erp_core::events::DomainEvent::new(
"dictionary.deleted",
tenant_id,
serde_json::json!({ "dictionary_id": id }),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"dictionary.deleted",
tenant_id,
serde_json::json!({ "dictionary_id": id }),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "dictionary.delete", "dictionary")
.with_resource_id(id),
AuditLog::new(
tenant_id,
Some(operator_id),
"dictionary.delete",
"dictionary",
)
.with_resource_id(id),
db,
)
.await;
@@ -315,8 +338,13 @@ impl DictionaryService {
.map_err(|e| ConfigError::Validation(e.to_string()))?;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "dictionary_item.create", "dictionary_item")
.with_resource_id(id),
AuditLog::new(
tenant_id,
Some(operator_id),
"dictionary_item.create",
"dictionary_item",
)
.with_resource_id(id),
db,
)
.await;
@@ -376,8 +404,13 @@ impl DictionaryService {
.map_err(|e| ConfigError::Validation(e.to_string()))?;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "dictionary_item.update", "dictionary_item")
.with_resource_id(item_id),
AuditLog::new(
tenant_id,
Some(operator_id),
"dictionary_item.update",
"dictionary_item",
)
.with_resource_id(item_id),
db,
)
.await;
@@ -423,8 +456,13 @@ impl DictionaryService {
.map_err(|e| ConfigError::Validation(e.to_string()))?;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "dictionary_item.delete", "dictionary_item")
.with_resource_id(item_id),
AuditLog::new(
tenant_id,
Some(operator_id),
"dictionary_item.delete",
"dictionary_item",
)
.with_resource_id(item_id),
db,
)
.await;

View File

@@ -1,9 +1,7 @@
use std::collections::HashMap;
use chrono::Utc;
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, Set,
};
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, Set};
use uuid::Uuid;
use crate::dto::{CreateMenuReq, MenuResp};
@@ -58,19 +56,13 @@ impl MenuService {
// 3. 按 parent_id 分组构建 HashMap
let filtered: Vec<&menu::Model> = match &visible_menu_ids {
Some(ids) => all_menus
.iter()
.filter(|m| ids.contains(&m.id))
.collect(),
Some(ids) => all_menus.iter().filter(|m| ids.contains(&m.id)).collect(),
None => all_menus.iter().collect(),
};
let mut children_map: HashMap<Option<Uuid>, Vec<&menu::Model>> = HashMap::new();
for m in &filtered {
children_map
.entry(m.parent_id)
.or_default()
.push(*m);
children_map.entry(m.parent_id).or_default().push(*m);
}
// 4. 递归构建树形结构(从 parent_id == None 的根节点开始)
@@ -152,15 +144,19 @@ impl MenuService {
Self::assign_roles(id, role_ids, tenant_id, operator_id, db).await?;
}
event_bus.publish(erp_core::events::DomainEvent::new(
"menu.created",
tenant_id,
serde_json::json!({ "menu_id": id, "title": req.title }),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"menu.created",
tenant_id,
serde_json::json!({ "menu_id": id, "title": req.title }),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "menu.create", "menu")
.with_resource_id(id),
AuditLog::new(tenant_id, Some(operator_id), "menu.create", "menu").with_resource_id(id),
db,
)
.await;
@@ -235,8 +231,7 @@ impl MenuService {
}
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "menu.update", "menu")
.with_resource_id(id),
AuditLog::new(tenant_id, Some(operator_id), "menu.update", "menu").with_resource_id(id),
db,
)
.await;
@@ -285,15 +280,19 @@ impl MenuService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
event_bus.publish(erp_core::events::DomainEvent::new(
"menu.deleted",
tenant_id,
serde_json::json!({ "menu_id": id }),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"menu.deleted",
tenant_id,
serde_json::json!({ "menu_id": id }),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "menu.delete", "menu")
.with_resource_id(id),
AuditLog::new(tenant_id, Some(operator_id), "menu.delete", "menu").with_resource_id(id),
db,
)
.await;
@@ -370,10 +369,7 @@ impl MenuService {
nodes
.iter()
.map(|m| {
let children = children_map
.get(&Some(m.id))
.cloned()
.unwrap_or_default();
let children = children_map.get(&Some(m.id)).cloned().unwrap_or_default();
MenuResp {
id: m.id,
parent_id: m.parent_id,

View File

@@ -1,7 +1,7 @@
use chrono::{Datelike, NaiveDate, Utc};
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set,
Statement, ConnectionTrait, DatabaseBackend, TransactionTrait,
ActiveModelTrait, ColumnTrait, ConnectionTrait, DatabaseBackend, EntityTrait, PaginatorTrait,
QueryFilter, Set, Statement, TransactionTrait,
};
use uuid::Uuid;
@@ -41,10 +41,7 @@ impl NumberingService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
let resps: Vec<NumberingRuleResp> = models
.iter()
.map(Self::model_to_resp)
.collect();
let resps: Vec<NumberingRuleResp> = models.iter().map(Self::model_to_resp).collect();
Ok((resps, total))
}
@@ -89,7 +86,10 @@ impl NumberingService {
seq_start: Set(seq_start),
seq_current: Set(seq_start as i64),
separator: Set(req.separator.clone().unwrap_or_else(|| "-".to_string())),
reset_cycle: Set(req.reset_cycle.clone().unwrap_or_else(|| "never".to_string())),
reset_cycle: Set(req
.reset_cycle
.clone()
.unwrap_or_else(|| "never".to_string())),
last_reset_date: Set(Some(Utc::now().date_naive())),
created_at: Set(now),
updated_at: Set(now),
@@ -103,15 +103,25 @@ impl NumberingService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
event_bus.publish(erp_core::events::DomainEvent::new(
"numbering_rule.created",
tenant_id,
serde_json::json!({ "rule_id": id, "code": req.code }),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"numbering_rule.created",
tenant_id,
serde_json::json!({ "rule_id": id, "code": req.code }),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "numbering_rule.create", "numbering_rule")
.with_resource_id(id),
AuditLog::new(
tenant_id,
Some(operator_id),
"numbering_rule.create",
"numbering_rule",
)
.with_resource_id(id),
db,
)
.await;
@@ -126,7 +136,10 @@ impl NumberingService {
seq_start,
seq_current: seq_start as i64,
separator: req.separator.clone().unwrap_or_else(|| "-".to_string()),
reset_cycle: req.reset_cycle.clone().unwrap_or_else(|| "never".to_string()),
reset_cycle: req
.reset_cycle
.clone()
.unwrap_or_else(|| "never".to_string()),
last_reset_date: Some(Utc::now().date_naive().to_string()),
version: 1,
})
@@ -181,8 +194,13 @@ impl NumberingService {
.map_err(|e| ConfigError::Validation(e.to_string()))?;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "numbering_rule.update", "numbering_rule")
.with_resource_id(id),
AuditLog::new(
tenant_id,
Some(operator_id),
"numbering_rule.update",
"numbering_rule",
)
.with_resource_id(id),
db,
)
.await;
@@ -219,15 +237,25 @@ impl NumberingService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
event_bus.publish(erp_core::events::DomainEvent::new(
"numbering_rule.deleted",
tenant_id,
serde_json::json!({ "rule_id": id }),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"numbering_rule.deleted",
tenant_id,
serde_json::json!({ "rule_id": id }),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "numbering_rule.delete", "numbering_rule")
.with_resource_id(id),
AuditLog::new(
tenant_id,
Some(operator_id),
"numbering_rule.delete",
"numbering_rule",
)
.with_resource_id(id),
db,
)
.await;

View File

@@ -1,7 +1,5 @@
use chrono::Utc;
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set,
};
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, Set};
use uuid::Uuid;
use crate::dto::SettingResp;
@@ -46,9 +44,7 @@ impl SettingService {
db: &sea_orm::DatabaseConnection,
) -> ConfigResult<SettingResp> {
// 1. Try exact match
if let Some(resp) =
Self::find_exact(key, scope, scope_id, tenant_id, db).await?
{
if let Some(resp) = Self::find_exact(key, scope, scope_id, tenant_id, db).await? {
return Ok(resp);
}
@@ -81,12 +77,18 @@ impl SettingService {
event_bus: &EventBus,
) -> ConfigResult<SettingResp> {
// Look for an existing non-deleted record
let existing = setting::Entity::find()
let mut query = setting::Entity::find()
.filter(setting::Column::TenantId.eq(tenant_id))
.filter(setting::Column::Scope.eq(&params.scope))
.filter(setting::Column::ScopeId.eq(params.scope_id))
.filter(setting::Column::SettingKey.eq(&params.key))
.filter(setting::Column::DeletedAt.is_null())
.filter(setting::Column::DeletedAt.is_null());
query = match params.scope_id {
Some(id) => query.filter(setting::Column::ScopeId.eq(id)),
None => query.filter(setting::Column::ScopeId.is_null()),
};
let existing = query
.one(db)
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
@@ -94,7 +96,9 @@ impl SettingService {
if let Some(model) = existing {
// Update existing record — 乐观锁校验
let next_version = match params.version {
Some(v) => check_version(v, model.version).map_err(|_| ConfigError::VersionMismatch)?,
Some(v) => {
check_version(v, model.version).map_err(|_| ConfigError::VersionMismatch)?
}
None => model.version + 1,
};
@@ -109,15 +113,20 @@ impl SettingService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
event_bus.publish(erp_core::events::DomainEvent::new(
"setting.updated",
tenant_id,
serde_json::json!({
"setting_id": updated.id,
"key": params.key,
"scope": params.scope,
}),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"setting.updated",
tenant_id,
serde_json::json!({
"setting_id": updated.id,
"key": params.key,
"scope": params.scope,
}),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "setting.upsert", "setting")
@@ -150,15 +159,20 @@ impl SettingService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
event_bus.publish(erp_core::events::DomainEvent::new(
"setting.created",
tenant_id,
serde_json::json!({
"setting_id": id,
"key": params.key,
"scope": params.scope,
}),
), db).await;
event_bus
.publish(
erp_core::events::DomainEvent::new(
"setting.created",
tenant_id,
serde_json::json!({
"setting_id": id,
"key": params.key,
"scope": params.scope,
}),
),
db,
)
.await;
audit_service::record(
AuditLog::new(tenant_id, Some(operator_id), "setting.upsert", "setting")
@@ -179,12 +193,17 @@ impl SettingService {
pagination: &Pagination,
db: &sea_orm::DatabaseConnection,
) -> ConfigResult<(Vec<SettingResp>, u64)> {
let paginator = setting::Entity::find()
let mut query = setting::Entity::find()
.filter(setting::Column::TenantId.eq(tenant_id))
.filter(setting::Column::Scope.eq(scope))
.filter(setting::Column::ScopeId.eq(*scope_id))
.filter(setting::Column::DeletedAt.is_null())
.paginate(db, pagination.limit());
.filter(setting::Column::DeletedAt.is_null());
query = match scope_id {
Some(id) => query.filter(setting::Column::ScopeId.eq(*id)),
None => query.filter(setting::Column::ScopeId.is_null()),
};
let paginator = query.paginate(db, pagination.limit());
let total = paginator
.num_items()
@@ -197,8 +216,7 @@ impl SettingService {
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
let resps: Vec<SettingResp> =
models.iter().map(Self::model_to_resp).collect();
let resps: Vec<SettingResp> = models.iter().map(Self::model_to_resp).collect();
Ok((resps, total))
}
@@ -214,20 +232,23 @@ impl SettingService {
version: i32,
db: &sea_orm::DatabaseConnection,
) -> ConfigResult<()> {
let model = setting::Entity::find()
let mut query = setting::Entity::find()
.filter(setting::Column::TenantId.eq(tenant_id))
.filter(setting::Column::Scope.eq(scope))
.filter(setting::Column::ScopeId.eq(*scope_id))
.filter(setting::Column::SettingKey.eq(key))
.filter(setting::Column::DeletedAt.is_null())
.filter(setting::Column::DeletedAt.is_null());
query = match scope_id {
Some(id) => query.filter(setting::Column::ScopeId.eq(*id)),
None => query.filter(setting::Column::ScopeId.is_null()),
};
let model = query
.one(db)
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?
.ok_or_else(|| {
ConfigError::NotFound(format!(
"设置 '{}' 在 '{}' 作用域下不存在",
key, scope
))
ConfigError::NotFound(format!("设置 '{}' 在 '{}' 作用域下不存在", key, scope))
})?;
let next_version =
@@ -264,12 +285,19 @@ impl SettingService {
tenant_id: Uuid,
db: &sea_orm::DatabaseConnection,
) -> ConfigResult<Option<SettingResp>> {
let model = setting::Entity::find()
let mut query = setting::Entity::find()
.filter(setting::Column::TenantId.eq(tenant_id))
.filter(setting::Column::Scope.eq(scope))
.filter(setting::Column::ScopeId.eq(*scope_id))
.filter(setting::Column::SettingKey.eq(key))
.filter(setting::Column::DeletedAt.is_null())
.filter(setting::Column::DeletedAt.is_null());
// SQL 中 `= NULL` 永远返回 false必须用 IS NULL 匹配 NULL 值
query = match scope_id {
Some(id) => query.filter(setting::Column::ScopeId.eq(*id)),
None => query.filter(setting::Column::ScopeId.is_null()),
};
let model = query
.one(db)
.await
.map_err(|e| ConfigError::Validation(e.to_string()))?;
@@ -301,9 +329,7 @@ impl SettingService {
(SCOPE_TENANT.to_string(), Some(tenant_id)),
(SCOPE_PLATFORM.to_string(), None),
]),
SCOPE_TENANT => {
Ok(vec![(SCOPE_PLATFORM.to_string(), None)])
}
SCOPE_TENANT => Ok(vec![(SCOPE_PLATFORM.to_string(), None)]),
SCOPE_PLATFORM => Ok(vec![]),
_ => Err(ConfigError::Validation(format!(
"不支持的作用域类型: '{}'",