feat: 初始化ERP平台底座项目结构
- 添加基础crate结构(erp-core, erp-common) - 实现核心模块trait和事件总线 - 配置Docker开发环境(PostgreSQL+Redis) - 添加Tauri桌面端基础框架 - 设置CI/CD工作流 - 编写项目协作规范文档(CLAUDE.md)
This commit is contained in:
78
crates/erp-core/src/error.rs
Normal file
78
crates/erp-core/src/error.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::Json;
|
||||
use serde::Serialize;
|
||||
|
||||
/// 统一错误响应格式
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct ErrorResponse {
|
||||
pub error: String,
|
||||
pub message: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub details: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
/// 平台级错误类型
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum AppError {
|
||||
#[error("资源未找到: {0}")]
|
||||
NotFound(String),
|
||||
|
||||
#[error("验证失败: {0}")]
|
||||
Validation(String),
|
||||
|
||||
#[error("未授权")]
|
||||
Unauthorized,
|
||||
|
||||
#[error("禁止访问: {0}")]
|
||||
Forbidden(String),
|
||||
|
||||
#[error("冲突: {0}")]
|
||||
Conflict(String),
|
||||
|
||||
#[error("内部错误: {0}")]
|
||||
Internal(String),
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
let (status, message) = match &self {
|
||||
AppError::NotFound(_) => (StatusCode::NOT_FOUND, self.to_string()),
|
||||
AppError::Validation(_) => (StatusCode::BAD_REQUEST, self.to_string()),
|
||||
AppError::Unauthorized => (StatusCode::UNAUTHORIZED, "未授权".to_string()),
|
||||
AppError::Forbidden(_) => (StatusCode::FORBIDDEN, self.to_string()),
|
||||
AppError::Conflict(_) => (StatusCode::CONFLICT, self.to_string()),
|
||||
AppError::Internal(_) => (StatusCode::INTERNAL_SERVER_ERROR, "内部错误".to_string()),
|
||||
};
|
||||
|
||||
let body = ErrorResponse {
|
||||
error: status.canonical_reason().unwrap_or("Error").to_string(),
|
||||
message,
|
||||
details: None,
|
||||
};
|
||||
|
||||
(status, Json(body)).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for AppError {
|
||||
fn from(err: anyhow::Error) -> Self {
|
||||
AppError::Internal(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sea_orm::DbErr> for AppError {
|
||||
fn from(err: sea_orm::DbErr) -> Self {
|
||||
match err {
|
||||
sea_orm::DbErr::RecordNotFound(msg) => AppError::NotFound(msg),
|
||||
sea_orm::DbErr::Query(sea_orm::RuntimeErr::SqlxError(e))
|
||||
if e.to_string().contains("duplicate key") =>
|
||||
{
|
||||
AppError::Conflict("记录已存在".to_string())
|
||||
}
|
||||
_ => AppError::Internal(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type AppResult<T> = Result<T, AppError>;
|
||||
Reference in New Issue
Block a user