//! 合规报告生成器模块 //! //! 实现报告生成、存储、查询和导出 use crate::compliance_layer::*; use crate::error::*; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::{Path, PathBuf}; /// 报告生成器 pub struct ReportGenerator { /// 报告存储路径 storage_path: PathBuf, /// 报告缓存 cache: HashMap, } impl ReportGenerator { /// 创建新的报告生成器 pub fn new() -> Self { Self { storage_path: std::env::temp_dir().join("nac_compliance_reports"), cache: HashMap::new(), } } /// 设置存储路径 pub fn with_storage_path(mut self, path: PathBuf) -> Self { self.storage_path = path; self } /// 生成报告 pub fn generate(&self, results: &[ComplianceResult]) -> Result { let report_id = self.generate_report_id(); // 计算总体状态 let overall_status = self.calculate_overall_status(results); // 计算总体风险等级 let overall_risk = self.calculate_overall_risk(results); // 计算平均置信度 let avg_confidence = if results.is_empty() { 0.0 } else { results.iter().map(|r| r.confidence).sum::() / results.len() as f64 }; // 收集所有问题 let all_issues: Vec = results .iter() .flat_map(|r| r.issues.clone()) .collect(); // 收集所有建议 let all_recommendations: Vec = results .iter() .flat_map(|r| r.recommendations.clone()) .collect(); // 生成摘要 let summary = self.generate_summary(results); Ok(ComplianceReport { id: report_id, results: results.to_vec(), overall_status, overall_risk, average_confidence: avg_confidence, total_issues: all_issues.len(), total_recommendations: all_recommendations.len(), summary, generated_at: chrono::Utc::now(), }) } /// 保存报告 pub fn save(&mut self, report: &ComplianceReport) -> Result<()> { // 创建存储目录 std::fs::create_dir_all(&self.storage_path)?; // 序列化报告 let json = serde_json::to_string_pretty(report)?; // 写入文件 let file_path = self.storage_path.join(format!("{}.json", report.id)); std::fs::write(&file_path, json)?; // 添加到缓存 self.cache.insert(report.id.clone(), report.clone()); Ok(()) } /// 加载报告 pub fn load(&mut self, report_id: &str) -> Result { // 先检查缓存 if let Some(report) = self.cache.get(report_id) { return Ok(report.clone()); } // 从文件加载 let file_path = self.storage_path.join(format!("{}.json", report_id)); let json = std::fs::read_to_string(&file_path)?; let report: ComplianceReport = serde_json::from_str(&json)?; // 添加到缓存 self.cache.insert(report_id.to_string(), report.clone()); Ok(report) } /// 查询报告 pub fn query(&self, filter: ReportFilter) -> Result> { let mut reports = Vec::new(); // 遍历存储目录 if !self.storage_path.exists() { return Ok(reports); } for entry in std::fs::read_dir(&self.storage_path)? { let entry = entry?; let path = entry.path(); if path.extension().and_then(|s| s.to_str()) != Some("json") { continue; } // 读取报告 let json = std::fs::read_to_string(&path)?; let report: ComplianceReport = serde_json::from_str(&json)?; // 应用过滤器 if filter.matches(&report) { reports.push(report); } } Ok(reports) } /// 导出报告 pub fn export(&self, report: &ComplianceReport, format: ExportFormat) -> Result> { match format { ExportFormat::Json => { let json = serde_json::to_string_pretty(report)?; Ok(json.into_bytes()) } ExportFormat::Csv => { self.export_csv(report) } ExportFormat::Pdf => { // 简化实现:返回JSON // 实际实现需要使用PDF生成库 let json = serde_json::to_string_pretty(report)?; Ok(json.into_bytes()) } ExportFormat::Html => { self.export_html(report) } } } /// 导出为CSV fn export_csv(&self, report: &ComplianceReport) -> Result> { let mut csv = String::new(); // 表头 csv.push_str("Layer,Status,Confidence,Risk Level,Issues,Recommendations\n"); // 数据行 for result in &report.results { csv.push_str(&format!( "{},{:?},{:.2},{:?},{},{}\n", result.layer.name(), result.status, result.confidence, result.risk_level, result.issues.len(), result.recommendations.len() )); } Ok(csv.into_bytes()) } /// 导出为HTML fn export_html(&self, report: &ComplianceReport) -> Result> { let mut html = String::new(); html.push_str("\n"); html.push_str("\n\n"); html.push_str("\n"); html.push_str("合规报告\n"); html.push_str("\n"); html.push_str("\n\n"); html.push_str(&format!("

合规报告 #{}

\n", report.id)); html.push_str(&format!("

生成时间: {}

\n", report.generated_at)); html.push_str(&format!("

总体状态: {:?}

\n", report.overall_status)); html.push_str(&format!("

总体风险: {:?}

\n", report.overall_risk)); html.push_str(&format!("

平均置信度: {:.2}

\n", report.average_confidence)); html.push_str("

验证结果

\n"); html.push_str("\n"); html.push_str("\n"); for result in &report.results { html.push_str(&format!( "\n", result.layer.name(), result.status, result.confidence, result.risk_level, result.issues.len(), result.recommendations.len() )); } html.push_str("
层级状态置信度风险等级问题数建议数
{}{:?}{:.2}{:?}{}{}
\n"); html.push_str("\n"); Ok(html.into_bytes()) } /// 生成报告ID fn generate_report_id(&self) -> String { use std::time::{SystemTime, UNIX_EPOCH}; let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_millis(); format!("RPT{}", timestamp) } /// 计算总体状态 fn calculate_overall_status(&self, results: &[ComplianceResult]) -> ComplianceStatus { if results.iter().any(|r| r.status == ComplianceStatus::Failed) { ComplianceStatus::Failed } else if results.iter().any(|r| r.status == ComplianceStatus::ManualReview) { ComplianceStatus::ManualReview } else if results.iter().any(|r| r.status == ComplianceStatus::ConditionalPass) { ComplianceStatus::ConditionalPass } else if results.iter().all(|r| r.status == ComplianceStatus::Passed) { ComplianceStatus::Passed } else { ComplianceStatus::Pending } } /// 计算总体风险 fn calculate_overall_risk(&self, results: &[ComplianceResult]) -> RiskLevel { results .iter() .map(|r| r.risk_level) .max() .unwrap_or(RiskLevel::Low) } /// 生成摘要 fn generate_summary(&self, results: &[ComplianceResult]) -> String { let passed = results.iter().filter(|r| r.status == ComplianceStatus::Passed).count(); let failed = results.iter().filter(|r| r.status == ComplianceStatus::Failed).count(); let manual = results.iter().filter(|r| r.status == ComplianceStatus::ManualReview).count(); format!( "共验证{}个层级,通过{}个,失败{}个,需人工审核{}个", results.len(), passed, failed, manual ) } } impl Default for ReportGenerator { fn default() -> Self { Self::new() } } /// 合规报告 #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ComplianceReport { /// 报告ID pub id: String, /// 验证结果列表 pub results: Vec, /// 总体状态 pub overall_status: ComplianceStatus, /// 总体风险等级 pub overall_risk: RiskLevel, /// 平均置信度 pub average_confidence: f64, /// 总问题数 pub total_issues: usize, /// 总建议数 pub total_recommendations: usize, /// 摘要 pub summary: String, /// 生成时间 pub generated_at: chrono::DateTime, } /// 报告过滤器 #[derive(Debug, Clone, Default)] pub struct ReportFilter { /// 状态过滤 pub status: Option, /// 风险等级过滤 pub risk_level: Option, /// 开始时间 pub start_time: Option>, /// 结束时间 pub end_time: Option>, } impl ReportFilter { /// 检查报告是否匹配过滤器 pub fn matches(&self, report: &ComplianceReport) -> bool { if let Some(status) = self.status { if report.overall_status != status { return false; } } if let Some(risk_level) = self.risk_level { if report.overall_risk != risk_level { return false; } } if let Some(start_time) = self.start_time { if report.generated_at < start_time { return false; } } if let Some(end_time) = self.end_time { if report.generated_at > end_time { return false; } } true } } /// 导出格式 #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExportFormat { /// JSON格式 Json, /// CSV格式 Csv, /// PDF格式 Pdf, /// HTML格式 Html, } #[cfg(test)] mod tests { use super::*; #[test] fn test_report_generation() { let generator = ReportGenerator::new(); let results = vec![ ComplianceResult { layer: ComplianceLayer::IdentityVerification, status: ComplianceStatus::Passed, confidence: 0.9, risk_level: RiskLevel::Low, details: "Test".to_string(), issues: vec![], recommendations: vec![], timestamp: chrono::Utc::now(), } ]; let report = generator.generate(&results).unwrap(); assert_eq!(report.results.len(), 1); assert_eq!(report.overall_status, ComplianceStatus::Passed); } #[test] fn test_report_export_json() { let generator = ReportGenerator::new(); let results = vec![ ComplianceResult { layer: ComplianceLayer::IdentityVerification, status: ComplianceStatus::Passed, confidence: 0.9, risk_level: RiskLevel::Low, details: "Test".to_string(), issues: vec![], recommendations: vec![], timestamp: chrono::Utc::now(), } ]; let report = generator.generate(&results).unwrap(); let exported = generator.export(&report, ExportFormat::Json).unwrap(); assert!(!exported.is_empty()); } #[test] fn test_report_filter() { let filter = ReportFilter { status: Some(ComplianceStatus::Passed), ..Default::default() }; let report = ComplianceReport { id: "test".to_string(), results: vec![], overall_status: ComplianceStatus::Passed, overall_risk: RiskLevel::Low, average_confidence: 0.9, total_issues: 0, total_recommendations: 0, summary: "Test".to_string(), generated_at: chrono::Utc::now(), }; assert!(filter.matches(&report)); } }