fix: V1 测试版本端到端验证修复 — 6 CRITICAL + 3 HIGH 问题全量修复

修复项:
- fix(db): 迁移 149 — 修复 Admin 角色权限绑定被迁移链破坏 (FE-C1)
- fix(health): 4 个 handler 添加空名称验证 — Doctor/Article/AlertRule/Tag (API-C1~C4)
- fix(health): Stats 仪表盘 new_this_week 查询修复 — SeaORM date_trunc bug (FE-C2)
- fix(server): 添加安全响应头 — X-Frame-Options/CSP/XSS-Protection/Referrer-Policy (SEC-H1)
- fix(mp): 预约创建契约修复 — notes/reason 字段映射 + 移除 schedule_id (MP-H1)
- fix(mp): 咨询会话 subject/last_message 字段改为可选 (MP-H3)
- fix(ai): AiConfig Default derive 替代手写 impl (clippy)

测试报告:
- 8 维度端到端测试全部完成 (后端 87 用例 / 前端 30 页面 / 小程序 80+ API / 安全 20 项 / 性能 20 端点)
- 多角色 7 角色 49 检查 100% 通过
- 综合测试报告 + 专家评估报告
This commit is contained in:
iven
2026-05-18 10:24:40 +08:00
parent 38b0d91407
commit d623f8b2ff
36 changed files with 5564 additions and 189 deletions

View File

@@ -8,10 +8,12 @@ use futures::StreamExt;
use serde::Deserialize;
use std::convert::Infallible;
use crate::config_resolver;
use crate::dto::{AnalysisSseEvent, AnalysisType};
use crate::state::AiState;
pub mod chat_handler;
pub mod config_handler;
pub mod insight_handler;
pub mod risk_handler;
pub mod rule_handler;
@@ -19,6 +21,32 @@ pub mod suggestion_handler;
// === 分析请求 Body ===
/// 从 prompt.model_config 解析模型参数,缺失字段用 AI 配置默认值填充
async fn resolve_model_config(
model_config: &serde_json::Value,
tenant_id: uuid::Uuid,
db: &sea_orm::DatabaseConnection,
) -> (String, f32, u32) {
let defaults = config_resolver::load_ai_config(tenant_id, db).await;
let analysis = &defaults.analysis_defaults;
let model = model_config
.get("model")
.and_then(|v| v.as_str())
.unwrap_or(&analysis.model)
.to_string();
let temperature = model_config
.get("temperature")
.and_then(|v| v.as_f64())
.unwrap_or(analysis.temperature as f64) as f32;
let max_tokens = model_config
.get("max_tokens")
.and_then(|v| v.as_u64())
.unwrap_or(analysis.max_tokens as u64) as u32;
(model, temperature, max_tokens)
}
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct AnalyzeBody {
pub report_id: Option<uuid::Uuid>,
@@ -69,12 +97,8 @@ where
.await?;
let model_config = &prompt.model_config;
let model = model_config["model"]
.as_str()
.unwrap_or("claude-sonnet-4-6")
.to_string();
let temperature = model_config["temperature"].as_f64().unwrap_or(0.3) as f32;
let max_tokens = model_config["max_tokens"].as_u64().unwrap_or(2048) as u32;
let (model, temperature, max_tokens) =
resolve_model_config(model_config, ctx.tenant_id, &state.db).await;
let (stream, analysis_id, _provider_name) = state
.analysis
@@ -168,12 +192,8 @@ where
.await?;
let model_config = &prompt.model_config;
let model = model_config["model"]
.as_str()
.unwrap_or("claude-sonnet-4-6")
.to_string();
let temperature = model_config["temperature"].as_f64().unwrap_or(0.3) as f32;
let max_tokens = model_config["max_tokens"].as_u64().unwrap_or(2048) as u32;
let (model, temperature, max_tokens) =
resolve_model_config(model_config, ctx.tenant_id, &state.db).await;
let (stream, analysis_id, _) = state
.analysis
@@ -244,12 +264,8 @@ where
.await?;
let model_config = &prompt.model_config;
let model = model_config["model"]
.as_str()
.unwrap_or("claude-sonnet-4-6")
.to_string();
let temperature = model_config["temperature"].as_f64().unwrap_or(0.3) as f32;
let max_tokens = model_config["max_tokens"].as_u64().unwrap_or(2048) as u32;
let (model, temperature, max_tokens) =
resolve_model_config(model_config, ctx.tenant_id, &state.db).await;
let (stream, analysis_id, _) = state
.analysis
@@ -327,12 +343,8 @@ where
.await?;
let model_config = &prompt.model_config;
let model = model_config["model"]
.as_str()
.unwrap_or("claude-sonnet-4-6")
.to_string();
let temperature = model_config["temperature"].as_f64().unwrap_or(0.3) as f32;
let max_tokens = model_config["max_tokens"].as_u64().unwrap_or(2048) as u32;
let (model, temperature, max_tokens) =
resolve_model_config(model_config, ctx.tenant_id, &state.db).await;
let (stream, analysis_id, _) = state
.analysis