报告增强: 环境/目标/时间线/emoji, 129测试通过
This commit is contained in:
parent
e3486e5bdf
commit
2d1243f729
@ -9,68 +9,105 @@ namespace CounterDrone.Core.Services
|
|||||||
{
|
{
|
||||||
public class ReportGenerator
|
public class ReportGenerator
|
||||||
{
|
{
|
||||||
/// <summary>根据仿真结果生成报告内容</summary>
|
|
||||||
public string Generate(TaskFullConfig config, List<SimEvent> events,
|
public string Generate(TaskFullConfig config, List<SimEvent> events,
|
||||||
Simulation.DroneStatus finalDroneStatus, float simulationDuration)
|
Simulation.DroneStatus finalDroneStatus, float simulationDuration)
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
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();
|
sb.AppendLine();
|
||||||
sb.AppendLine($"**任务名称**:{config.Task.Name}");
|
sb.AppendLine($"| 项目 | 值 |");
|
||||||
sb.AppendLine($"**任务编号**:{config.Task.TaskNumber}");
|
sb.AppendLine($"|------|-----|");
|
||||||
sb.AppendLine($"**仿真耗时**:{simulationDuration:F1} 秒");
|
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($"|------|-----|---|------|-----|");
|
||||||
|
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();
|
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("## 二、我方部署");
|
||||||
sb.AppendLine($"| 目标数量 | {config.Targets.Sum(t => t.Quantity)} |");
|
sb.AppendLine();
|
||||||
|
sb.AppendLine($"| 装备 | 数量 |");
|
||||||
|
sb.AppendLine($"|------|------|");
|
||||||
sb.AppendLine($"| 发射平台 | {platforms.Sum(p => p.Quantity)} 台 |");
|
sb.AppendLine($"| 发射平台 | {platforms.Sum(p => p.Quantity)} 台 |");
|
||||||
sb.AppendLine($"| 探测设备 | {detections.Sum(d => d.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();
|
sb.AppendLine();
|
||||||
sb.AppendLine("| 时间(s) | 事件 | 描述 |");
|
sb.AppendLine("| 时间(s) | 事件 | 详情 |");
|
||||||
sb.AppendLine("|---------|------|------|");
|
sb.AppendLine("|---------|------|------|");
|
||||||
|
int munitionIdx = 0, cloudIdx = 0;
|
||||||
foreach (var e in events.OrderBy(e => e.OccurredAt))
|
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();
|
||||||
|
|
||||||
// === 仿真后:统计分析 ===
|
// === 四、时间线分析 ===
|
||||||
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();
|
sb.AppendLine();
|
||||||
|
|
||||||
|
// === 五、统计 ===
|
||||||
var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed);
|
var destroyed = events.Count(e => e.Type == SimEventType.DroneDestroyed);
|
||||||
var reached = events.Count(e => e.Type == SimEventType.DroneReachedTarget);
|
var reached = events.Count(e => e.Type == SimEventType.DroneReachedTarget);
|
||||||
var intruded = events.Count(e => e.Type == SimEventType.ZoneIntruded);
|
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 totalDrones = config.Targets.Sum(t => t.Quantity);
|
||||||
|
var result = DetermineInterceptResult(destroyed, reached + intruded, totalDrones);
|
||||||
|
|
||||||
|
sb.AppendLine("## 五、结果统计");
|
||||||
|
sb.AppendLine();
|
||||||
sb.AppendLine($"| 统计项 | 值 |");
|
sb.AppendLine($"| 统计项 | 值 |");
|
||||||
sb.AppendLine($"|--------|-----|");
|
sb.AppendLine($"|--------|-----|");
|
||||||
sb.AppendLine($"| 无人机总数 | {totalDrones} |");
|
sb.AppendLine($"| 无人机总数 | {totalDrones} |");
|
||||||
sb.AppendLine($"| 被摧毁 | {destroyed} |");
|
sb.AppendLine($"| 被摧毁 | {destroyed} |");
|
||||||
sb.AppendLine($"| 到达目标 | {reached} |");
|
sb.AppendLine($"| 到达目标 | {reached} |");
|
||||||
sb.AppendLine($"| 侵入管控区 | {intruded} |");
|
sb.AppendLine($"| 侵入管控区 | {intruded} |");
|
||||||
sb.AppendLine($"| 弹药发射次数 | {launchCount} |");
|
sb.AppendLine($"| 弹药发射 | {events.Count(e => e.Type == SimEventType.MunitionLaunched)} |");
|
||||||
sb.AppendLine($"| 云团生成次数 | {cloudCount} |");
|
sb.AppendLine($"| 云团生成 | {events.Count(e => e.Type == SimEventType.CloudGenerated)} |");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
// 对抗结果
|
|
||||||
var result = DetermineInterceptResult(destroyed, reached + intruded, totalDrones);
|
|
||||||
sb.AppendLine($"**对抗结果**:{TranslateResult(result)}");
|
sb.AppendLine($"**对抗结果**:{TranslateResult(result)}");
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
|
|
||||||
@ -87,10 +124,49 @@ namespace CounterDrone.Core.Services
|
|||||||
|
|
||||||
private static string TranslateResult(InterceptResult r) => r switch
|
private static string TranslateResult(InterceptResult r) => r switch
|
||||||
{
|
{
|
||||||
InterceptResult.Success => "成功拦截",
|
InterceptResult.Success => "✅ 成功拦截",
|
||||||
InterceptResult.Partial => "部分拦截",
|
InterceptResult.Partial => "⚠️ 部分拦截",
|
||||||
InterceptResult.Failed => "拦截失败",
|
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(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -130,7 +130,7 @@ namespace CounterDrone.Core.Tests
|
|||||||
{
|
{
|
||||||
var detail = _scenario.GetTaskDetail(_taskId)!;
|
var detail = _scenario.GetTaskDetail(_taskId)!;
|
||||||
var report = new ReportGenerator().Generate(detail, eng.Events.ToList(), drone.Status, eng.SimulationTime);
|
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);
|
Assert.Contains(detail.Task.Name, report);
|
||||||
|
|
||||||
var svc = new ReportService(_mainDb, _paths);
|
var svc = new ReportService(_mainDb, _paths);
|
||||||
|
|||||||
@ -56,7 +56,7 @@ namespace CounterDrone.Core.Tests
|
|||||||
|
|
||||||
Assert.Contains("仿真评估报告", content);
|
Assert.Contains("仿真评估报告", content);
|
||||||
Assert.Contains("测试任务", content);
|
Assert.Contains("测试任务", content);
|
||||||
Assert.Contains("成功拦截", content);
|
Assert.Contains("✅ 成功拦截", content);
|
||||||
Assert.Contains("发射", content);
|
Assert.Contains("发射", content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user