feat: initialize Nuanji (Warm Notes) project

- Base platform from base.git (ERP base: auth, core, config, message, workflow, plugin)
- Created erp-diary module skeleton (lib.rs, dto.rs, error.rs, event.rs, state.rs)
- Integrated erp-diary into workspace and erp-server
- Added DiaryModule registration in main.rs
- Added DiaryState FromRef in state.rs
- Diary routes mounted (empty routes, ready for implementation)
- Product design spec v1.2 preserved in docs/
- Implementation plan preserved in plans/

Cargo check: OK
Cargo test: OK (78+ base tests passing)
This commit is contained in:
iven
2026-05-31 20:52:19 +08:00
commit c539e6fd83
285 changed files with 59156 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
use erp_core::error::AppError;
/// 消息中心模块错误类型。
#[derive(Debug, thiserror::Error)]
pub enum MessageError {
#[error("验证失败: {0}")]
Validation(String),
#[error("未找到: {0}")]
NotFound(String),
#[error("模板编码已存在: {0}")]
DuplicateTemplateCode(String),
#[error("渲染失败: {0}")]
TemplateRenderError(String),
#[error("版本冲突: 数据已被其他操作修改,请刷新后重试")]
VersionMismatch,
}
impl From<MessageError> for AppError {
fn from(err: MessageError) -> Self {
match err {
MessageError::Validation(msg) => AppError::Validation(msg),
MessageError::NotFound(msg) => AppError::NotFound(msg),
MessageError::DuplicateTemplateCode(msg) => AppError::Conflict(msg),
MessageError::TemplateRenderError(msg) => AppError::Internal(msg),
MessageError::VersionMismatch => AppError::VersionMismatch,
}
}
}
impl From<sea_orm::TransactionError<MessageError>> for MessageError {
fn from(err: sea_orm::TransactionError<MessageError>) -> Self {
match err {
sea_orm::TransactionError::Connection(db_err) => {
MessageError::Validation(db_err.to_string())
}
sea_orm::TransactionError::Transaction(msg_err) => msg_err,
}
}
}
pub type MessageResult<T> = Result<T, MessageError>;
#[cfg(test)]
mod tests {
use super::*;
use erp_core::error::AppError;
#[test]
fn validation_maps_to_app_validation() {
let app: AppError = MessageError::Validation("标题不能为空".to_string()).into();
match app {
AppError::Validation(msg) => assert_eq!(msg, "标题不能为空"),
other => panic!("Expected AppError::Validation, got {:?}", other),
}
}
#[test]
fn not_found_maps_to_app_not_found() {
let app: AppError = MessageError::NotFound("消息不存在".to_string()).into();
match app {
AppError::NotFound(msg) => assert_eq!(msg, "消息不存在"),
other => panic!("Expected AppError::NotFound, got {:?}", other),
}
}
#[test]
fn duplicate_template_code_maps_to_app_conflict() {
let app: AppError = MessageError::DuplicateTemplateCode("WELCOME".to_string()).into();
match app {
AppError::Conflict(msg) => assert_eq!(msg, "WELCOME"),
other => panic!("Expected AppError::Conflict, got {:?}", other),
}
}
#[test]
fn template_render_error_maps_to_app_internal() {
let app: AppError = MessageError::TemplateRenderError("变量缺失".to_string()).into();
match app {
AppError::Internal(msg) => assert_eq!(msg, "变量缺失"),
other => panic!("Expected AppError::Internal, got {:?}", other),
}
}
#[test]
fn version_mismatch_maps_to_app_version_mismatch() {
let app: AppError = MessageError::VersionMismatch.into();
match app {
AppError::VersionMismatch => {}
other => panic!("Expected AppError::VersionMismatch, got {:?}", other),
}
}
#[test]
fn error_display_format() {
assert_eq!(
MessageError::Validation("字段为空".to_string()).to_string(),
"验证失败: 字段为空"
);
assert_eq!(
MessageError::NotFound("id=123".to_string()).to_string(),
"未找到: id=123"
);
assert_eq!(
MessageError::DuplicateTemplateCode("CODE".to_string()).to_string(),
"模板编码已存在: CODE"
);
assert_eq!(
MessageError::TemplateRenderError("解析失败".to_string()).to_string(),
"渲染失败: 解析失败"
);
assert_eq!(
MessageError::VersionMismatch.to_string(),
"版本冲突: 数据已被其他操作修改,请刷新后重试"
);
}
#[test]
fn transaction_connection_error_maps_to_validation() {
let db_err = sea_orm::DbErr::Conn(sea_orm::RuntimeErr::Internal("连接超时".to_string()));
let tx_err: sea_orm::TransactionError<MessageError> =
sea_orm::TransactionError::Connection(db_err);
let msg_err: MessageError = tx_err.into();
match msg_err {
MessageError::Validation(msg) => assert!(msg.contains("连接超时")),
other => panic!("期望 Validation得到 {:?}", other),
}
}
#[test]
fn transaction_inner_error_passthrough() {
let inner = MessageError::NotFound("模板不存在".to_string());
let tx_err: sea_orm::TransactionError<MessageError> =
sea_orm::TransactionError::Transaction(inner);
let msg_err: MessageError = tx_err.into();
match msg_err {
MessageError::NotFound(msg) => assert_eq!(msg, "模板不存在"),
other => panic!("期望 NotFound得到 {:?}", other),
}
}
}