From 2d1243f72910239a3633bb03ad23a99113fdce57 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Fri, 12 Jun 2026 11:41:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=A5=E5=91=8A=E5=A2=9E=E5=BC=BA:=20?= =?UTF-8?q?=E7=8E=AF=E5=A2=83/=E7=9B=AE=E6=A0=87/=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E7=BA=BF/emoji,=20129=E6=B5=8B=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/ReportGenerator.cs | 134 ++++++++++++++---- .../FullPipelineTests.cs | 2 +- .../ReportGeneratorTests.cs | 2 +- 3 files changed, 107 insertions(+), 31 deletions(-) diff --git a/src/CounterDrone.Core/Services/ReportGenerator.cs b/src/CounterDrone.Core/Services/ReportGenerator.cs index ad4584f..345f4bc 100644 --- a/src/CounterDrone.Core/Services/ReportGenerator.cs +++ b/src/CounterDrone.Core/Services/ReportGenerator.cs @@ -9,68 +9,105 @@ namespace CounterDrone.Core.Services { public class ReportGenerator { - /// 根据仿真结果生成报告内容 public string Generate(TaskFullConfig config, List events, Simulation.DroneStatus finalDroneStatus, float simulationDuration) { var sb = new StringBuilder(); + var platforms = config.Equipment.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform).ToList(); + var detections = config.Equipment.Where(e => e.EquipmentRole == (int)EquipmentRole.Detection).ToList(); + var target = config.Targets.FirstOrDefault(); + var scene = config.Scene; - // === 仿真前:我方配置 === + // === 头部 === sb.AppendLine("# 仿真评估报告"); sb.AppendLine(); - sb.AppendLine($"**任务名称**:{config.Task.Name}"); - sb.AppendLine($"**任务编号**:{config.Task.TaskNumber}"); - sb.AppendLine($"**仿真耗时**:{simulationDuration:F1} 秒"); + sb.AppendLine($"| 项目 | 值 |"); + sb.AppendLine($"|------|-----|"); + sb.AppendLine($"| 任务名称 | {config.Task.Name} |"); + sb.AppendLine($"| 任务编号 | {config.Task.TaskNumber} |"); + sb.AppendLine($"| 仿真耗时 | {simulationDuration:F1} 秒 |"); + sb.AppendLine($"| 气溶胶类型 | {TranslateAerosol((AerosolType)config.Cloud.AerosolType)} |"); + sb.AppendLine($"| 拦截概率(算法估计) | {(config.Cloud.Source == "Algorithm" ? "见推荐方案" : "手动配置")} |"); sb.AppendLine(); - sb.AppendLine("## 一、仿真前 — 我方配置"); + // === 一、环境与目标 === + sb.AppendLine("## 一、环境与目标"); + sb.AppendLine(); + sb.AppendLine($"| 环境 | 值 | | 目标 | 值 |"); + sb.AppendLine($"|------|-----|---|------|-----|"); + sb.AppendLine($"| 天气 | {TranslateWeather((WeatherType)scene.WeatherType)} | | 类型 | {TranslateTarget((TargetType)(target?.TargetType ?? 0))} |"); + sb.AppendLine($"| 风速 | {scene.WindSpeed} m/s | | 数量 | {config.Targets.Sum(t => t.Quantity)} 架 |"); + sb.AppendLine($"| 风向 | {scene.WindDirection} | | 速度 | {target?.TypicalSpeed ?? 0} km/h |"); + sb.AppendLine($"| 温度 | {scene.Temperature}°C | | 高度 | {target?.TypicalAltitude ?? 0} m |"); + sb.AppendLine($"| 能见度 | {scene.Visibility} m | | 动力 | {TranslatePower((PowerType)(target?.PowerType ?? 0))} |"); sb.AppendLine(); - var deployment = config.Equipment; - var platforms = deployment.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform).ToList(); - var detections = deployment.Where(e => e.EquipmentRole == (int)EquipmentRole.Detection).ToList(); - sb.AppendLine($"| 配置项 | 值 |"); - sb.AppendLine($"|--------|-----|"); - sb.AppendLine($"| 目标数量 | {config.Targets.Sum(t => t.Quantity)} |"); + // === 二、我方部署 === + sb.AppendLine("## 二、我方部署"); + sb.AppendLine(); + sb.AppendLine($"| 装备 | 数量 |"); + sb.AppendLine($"|------|------|"); sb.AppendLine($"| 发射平台 | {platforms.Sum(p => p.Quantity)} 台 |"); sb.AppendLine($"| 探测设备 | {detections.Sum(d => d.Quantity)} 台 |"); - sb.AppendLine($"| 气溶胶类型 | {(AerosolType)config.Cloud.AerosolType} |"); + sb.AppendLine($"| 云团位置 | ({config.Cloud.PositionX:F0}, {config.Cloud.PositionY:F0}, {config.Cloud.PositionZ:F0}) |"); + sb.AppendLine($"| 释放高度 | {config.Cloud.DisperseHeight:F0} m |"); sb.AppendLine(); - // === 仿真中:关键事件时序 === - sb.AppendLine("## 二、仿真中 — 关键事件时序"); + // === 三、事件时序 === + sb.AppendLine("## 三、事件时序"); sb.AppendLine(); - sb.AppendLine("| 时间(s) | 事件 | 描述 |"); + sb.AppendLine("| 时间(s) | 事件 | 详情 |"); sb.AppendLine("|---------|------|------|"); + int munitionIdx = 0, cloudIdx = 0; foreach (var e in events.OrderBy(e => e.OccurredAt)) { - sb.AppendLine($"| {e.OccurredAt:F1} | {e.Type} | {e.Description} |"); + var desc = e.Type switch + { + SimEventType.MunitionLaunched => $"第 {++munitionIdx} 发", + SimEventType.CloudGenerated => $"云团 #{++cloudIdx}", + SimEventType.DroneDestroyed => "目标被摧毁", + SimEventType.DroneReachedTarget => "目标抵达终点", + SimEventType.ZoneIntruded => "侵入管控区", + SimEventType.SimulationEnd => "仿真结束", + _ => e.Description, + }; + sb.AppendLine($"| {e.OccurredAt:F1} | {TranslateEvent(e.Type)} | {desc} |"); } sb.AppendLine(); - // === 仿真后:统计分析 === - sb.AppendLine("## 三、仿真后 — 数据统计"); + // === 四、时间线分析 === + var launchTime = events.Where(e => e.Type == SimEventType.MunitionLaunched).Select(e => e.OccurredAt).DefaultIfEmpty(0).Min(); + var cloudTime = events.Where(e => e.Type == SimEventType.CloudGenerated).Select(e => e.OccurredAt).DefaultIfEmpty(0).Min(); + var destroyTime = events.Where(e => e.Type == SimEventType.DroneDestroyed).Select(e => e.OccurredAt).DefaultIfEmpty(0).Min(); + sb.AppendLine("## 四、时间线"); + sb.AppendLine(); + sb.AppendLine($"| 阶段 | 时间 | 耗时 |"); + sb.AppendLine($"|------|------|------|"); + if (launchTime > 0) + sb.AppendLine($"| 发射 → 云团生成 | {launchTime:F1}s → {cloudTime:F1}s | {(cloudTime - launchTime):F1}s(弹药飞行) |"); + if (destroyTime > 0) + sb.AppendLine($"| 云团生成 → 击毁 | {cloudTime:F1}s → {destroyTime:F1}s | {(destroyTime - cloudTime):F1}s(暴露毁伤) |"); + sb.AppendLine($"| 总耗时 | 0 → {simulationDuration:F1}s | {simulationDuration:F1}s |"); sb.AppendLine(); + // === 五、统计 === var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed); var reached = events.Count(e => e.Type == SimEventType.DroneReachedTarget); var intruded = events.Count(e => e.Type == SimEventType.ZoneIntruded); - var cloudCount = events.Count(e => e.Type == SimEventType.CloudGenerated); - var launchCount = events.Count(e => e.Type == SimEventType.MunitionLaunched); var totalDrones = config.Targets.Sum(t => t.Quantity); + var result = DetermineInterceptResult(destroyed, reached + intruded, totalDrones); + sb.AppendLine("## 五、结果统计"); + sb.AppendLine(); sb.AppendLine($"| 统计项 | 值 |"); sb.AppendLine($"|--------|-----|"); sb.AppendLine($"| 无人机总数 | {totalDrones} |"); sb.AppendLine($"| 被摧毁 | {destroyed} |"); sb.AppendLine($"| 到达目标 | {reached} |"); sb.AppendLine($"| 侵入管控区 | {intruded} |"); - sb.AppendLine($"| 弹药发射次数 | {launchCount} |"); - sb.AppendLine($"| 云团生成次数 | {cloudCount} |"); + sb.AppendLine($"| 弹药发射 | {events.Count(e => e.Type == SimEventType.MunitionLaunched)} |"); + sb.AppendLine($"| 云团生成 | {events.Count(e => e.Type == SimEventType.CloudGenerated)} |"); sb.AppendLine(); - - // 对抗结果 - var result = DetermineInterceptResult(destroyed, reached + intruded, totalDrones); sb.AppendLine($"**对抗结果**:{TranslateResult(result)}"); sb.AppendLine(); @@ -87,10 +124,49 @@ namespace CounterDrone.Core.Services private static string TranslateResult(InterceptResult r) => r switch { - InterceptResult.Success => "成功拦截", - InterceptResult.Partial => "部分拦截", - InterceptResult.Failed => "拦截失败", + InterceptResult.Success => "✅ 成功拦截", + InterceptResult.Partial => "⚠️ 部分拦截", + InterceptResult.Failed => "❌ 拦截失败", _ => "未知", }; + + private static string TranslateAerosol(AerosolType t) => t switch + { + AerosolType.InertGas => "惰性气体(吸入式灭火)", + AerosolType.ActiveMaterial => "活性材料(爆燃式)", + AerosolType.ActiveFuel => "活性燃料(吸入式爆炸)", + _ => t.ToString(), + }; + + private static string TranslateWeather(WeatherType w) => w switch + { + WeatherType.Sunny => "晴天", WeatherType.Overcast => "阴天", + WeatherType.Fog => "雾天", WeatherType.Rain => "雨天", + WeatherType.Night => "夜间", _ => w.ToString(), + }; + + private static string TranslateTarget(TargetType t) => t switch + { + TargetType.Rotor => "旋翼", TargetType.FixedWing => "固定翼", + TargetType.Electric => "电推", TargetType.Piston => "活塞", + TargetType.HighSpeed => "高速目标", _ => t.ToString(), + }; + + private static string TranslatePower(PowerType p) => p switch + { + PowerType.Electric => "电推式", PowerType.Piston => "活塞式", + PowerType.Jet => "喷吸气式", _ => p.ToString(), + }; + + private static string TranslateEvent(SimEventType t) => t switch + { + SimEventType.MunitionLaunched => "🚀 弹药发射", + SimEventType.CloudGenerated => "☁️ 云团生成", + SimEventType.DroneDestroyed => "💥 目标击毁", + SimEventType.DroneReachedTarget => "🏁 抵达目标", + SimEventType.ZoneIntruded => "🚨 侵入管控区", + SimEventType.SimulationEnd => "⏹️ 仿真结束", + _ => t.ToString(), + }; } } diff --git a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs index 795f427..b9ad891 100644 --- a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs +++ b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs @@ -130,7 +130,7 @@ namespace CounterDrone.Core.Tests { var detail = _scenario.GetTaskDetail(_taskId)!; var report = new ReportGenerator().Generate(detail, eng.Events.ToList(), drone.Status, eng.SimulationTime); - Assert.Contains("仿真评估报告", report); + Assert.Contains("对抗结果", report); Assert.Contains(detail.Task.Name, report); var svc = new ReportService(_mainDb, _paths); diff --git a/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs b/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs index f5defac..136b418 100644 --- a/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs +++ b/test/unit/CounterDrone.Core.Tests/ReportGeneratorTests.cs @@ -56,7 +56,7 @@ namespace CounterDrone.Core.Tests Assert.Contains("仿真评估报告", content); Assert.Contains("测试任务", content); - Assert.Contains("成功拦截", content); + Assert.Contains("✅ 成功拦截", content); Assert.Contains("发射", content); } }