fix: 修复测试发现的 7 个问题 + 全 workspace clippy 清零
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

功能修复:
1. 患者创建空名称验证:后端添加 name.trim().is_empty() 检查
2. 仪表盘统计容错:单个查询失败返回零值而非 500
3. FHIR 路由修复:从 /fhir 移到 /api/v1/fhir 保持一致
4. 冻结模块后端中间件:新增 frozen_module_middleware 拦截冻结路径
5. 积分端点权限码:health.health-data.list → health.points.list
6. 角色权限迁移:护士补充 devices.list,运营补充 points.list/manage
7. 测试结果文档:R01-R05 角色测试 + T00/T10 结果归档

Clippy 全 workspace 清零(14→0 errors):
- erp-core: 修复 empty doc line、collapsible if、redundant closure 等 9 处
- erp-health: 修复 too_many_arguments、unused var、unnecessary parens 等 58 处
- erp-ai: 修复 dead_code、unused import 等 11 处
- erp-plugin: 修复 too_many_arguments、wildcard pattern 等 11 处
- erp-server-migration: 修复 enum_variant_names 5 处
- erp-auth/config/workflow/message: 各 1-3 处

工程改进:
- lint-staged 配置迁移到 .lintstagedrc.js(函数式避免文件列表传给 clippy)
- cargo fmt 统一格式化
This commit is contained in:
iven
2026-05-07 23:43:14 +08:00
parent 786f57c151
commit 6d5a711d2c
323 changed files with 15662 additions and 6603 deletions

View File

@@ -20,9 +20,7 @@ pub struct BatchRequest {
/// 接收小程序批量埋点事件。
/// 当前为日志记录模式 — 后续可接入 ClickHouse/PostgreSQL 分析表。
pub async fn batch(
Json(req): Json<BatchRequest>,
) -> Json<ApiResponse<()>> {
pub async fn batch(Json(req): Json<BatchRequest>) -> Json<ApiResponse<()>> {
for evt in &req.events {
tracing::info!(
event = %evt.event,

View File

@@ -1,8 +1,8 @@
use axum::extract::{FromRef, Path, State};
use axum::Extension;
use axum::Json;
use sea_orm::{ConnectionTrait, Statement, DatabaseBackend};
use serde_json::{json, Value};
use axum::extract::{FromRef, Path, State};
use sea_orm::{ConnectionTrait, DatabaseBackend, Statement};
use serde_json::{Value, json};
use uuid::Uuid;
use erp_core::error::AppError;

View File

@@ -56,10 +56,8 @@ pub async fn readiness_check(State(state): State<AppState>) -> Json<ReadyRespons
.map(|m| m.name().to_string())
.collect();
let (db_status, redis_status) = tokio::join!(
check_database(&state.db),
check_redis(&state.redis),
);
let (db_status, redis_status) =
tokio::join!(check_database(&state.db), check_redis(&state.redis),);
let overall = if db_status.status == "ok" && redis_status.status == "ok" {
"ok"
@@ -81,10 +79,8 @@ pub async fn readiness_check(State(state): State<AppState>) -> Json<ReadyRespons
async fn check_database(db: &sea_orm::DatabaseConnection) -> ComponentStatus {
use sea_orm::ConnectionTrait;
let start = std::time::Instant::now();
let stmt = sea_orm::Statement::from_string(
sea_orm::DatabaseBackend::Postgres,
"SELECT 1".to_string(),
);
let stmt =
sea_orm::Statement::from_string(sea_orm::DatabaseBackend::Postgres, "SELECT 1".to_string());
match db.query_one(stmt).await {
Ok(_) => ComponentStatus {
status: "ok".to_string(),
@@ -105,26 +101,21 @@ async fn check_database(db: &sea_orm::DatabaseConnection) -> ComponentStatus {
async fn check_redis(client: &redis::Client) -> ComponentStatus {
let start = std::time::Instant::now();
match client.get_multiplexed_async_connection().await {
Ok(mut conn) => {
match redis::cmd("PING")
.query_async::<String>(&mut conn)
.await
{
Ok(_) => ComponentStatus {
status: "ok".to_string(),
Ok(mut conn) => match redis::cmd("PING").query_async::<String>(&mut conn).await {
Ok(_) => ComponentStatus {
status: "ok".to_string(),
latency_ms: Some(start.elapsed().as_millis() as u64),
error: None,
},
Err(e) => {
tracing::error!(error = %e, "Redis PING failed");
ComponentStatus {
status: "error".to_string(),
latency_ms: Some(start.elapsed().as_millis() as u64),
error: None,
},
Err(e) => {
tracing::error!(error = %e, "Redis PING failed");
ComponentStatus {
status: "error".to_string(),
latency_ms: Some(start.elapsed().as_millis() as u64),
error: Some("connection failed".to_string()),
}
error: Some("connection failed".to_string()),
}
}
}
},
Err(e) => {
tracing::error!(error = %e, "Redis connection failed");
ComponentStatus {

View File

@@ -2,7 +2,7 @@ use axum::response::Json;
use serde_json::Value;
use utoipa::OpenApi;
use crate::{ApiDoc, AuthApiDoc, ConfigApiDoc, WorkflowApiDoc, MessageApiDoc};
use crate::{ApiDoc, AuthApiDoc, ConfigApiDoc, MessageApiDoc, WorkflowApiDoc};
/// GET /docs/openapi.json
///

View File

@@ -46,9 +46,9 @@ where
// 确保上传目录存在
let base_dir = std::path::Path::new(upload_dir);
let tenant_dir = base_dir.join(ctx.tenant_id.to_string());
tokio::fs::create_dir_all(&tenant_dir).await.map_err(|e| {
AppError::Internal(format!("创建上传目录失败: {}", e))
})?;
tokio::fs::create_dir_all(&tenant_dir)
.await
.map_err(|e| AppError::Internal(format!("创建上传目录失败: {}", e)))?;
// 读取第一个 field 作为上传文件
let field = multipart
@@ -65,10 +65,7 @@ where
// 验证文件类型
validate_content_type(&content_type)?;
let original_name = field
.name()
.unwrap_or("file")
.to_string();
let original_name = field.name().unwrap_or("file").to_string();
let data = field
.bytes()