CounterDroneBackend/src/CounterDrone.Core/Services/ScenarioService.cs

378 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using CounterDrone.Core.Models;
using CounterDrone.Core.Repository;
namespace CounterDrone.Core.Services
{
public class ScenarioService : IScenarioService
{
private readonly ScenarioRepository _scenarioRepo;
private readonly CombatSceneRepository _sceneRepo;
private readonly ControlZoneRepository _zoneRepo;
private readonly ScenarioDroneRepository _droneRepo;
private readonly ScenarioUnitRepository _unitRepo;
private readonly CloudDispersalRepository _cloudRepo;
private readonly RoutePlanRepository _routeRepo;
private readonly WaypointRepository _waypointRepo;
public ScenarioService(
ScenarioRepository scenarioRepo,
CombatSceneRepository sceneRepo,
ControlZoneRepository zoneRepo,
ScenarioDroneRepository targetRepo,
ScenarioUnitRepository equipRepo,
CloudDispersalRepository cloudRepo,
RoutePlanRepository routeRepo,
WaypointRepository waypointRepo)
{
_scenarioRepo = scenarioRepo;
_sceneRepo = sceneRepo;
_zoneRepo = zoneRepo;
_droneRepo = targetRepo;
_unitRepo = equipRepo;
_cloudRepo = cloudRepo;
_routeRepo = routeRepo;
_waypointRepo = waypointRepo;
}
// ========== scenario CRUD ==========
public Scenario CreateScenario(string name, string ScenarioNumber)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("任务名称不能为空");
if (string.IsNullOrWhiteSpace(ScenarioNumber))
ScenarioNumber = GenerateScenarioNumber();
var existing = _scenarioRepo.GetByScenarioNumber(ScenarioNumber);
if (existing != null)
throw new ArgumentException($"任务编号 {ScenarioNumber} 已存在");
var scenario = new Scenario
{
Name = name,
ScenarioNumber = ScenarioNumber,
Status = (int)ScenarioStatus.Configuring,
CurrentStep = 1,
};
_scenarioRepo.Insert(scenario);
return scenario;
}
public void DeleteScenario(string id)
{
_scenarioRepo.Delete(id);
}
public PagedResult<Scenario> SearchScenarios(string keyword, string? dateFrom, string? dateTo, int page, int pageSize)
{
if (page < 1) page = 1;
if (pageSize < 1) pageSize = 10;
var offset = (page - 1) * pageSize;
var items = _scenarioRepo.Search(keyword, dateFrom, dateTo, offset, pageSize, out var total);
return new PagedResult<Scenario>
{
Items = items,
TotalCount = total,
Page = page,
PageSize = pageSize,
};
}
public ScenarioConfig? GetScenarioDetail(string id)
{
var scenario = _scenarioRepo.GetById(id);
if (scenario == null) return null;
return new ScenarioConfig
{
Info = scenario,
Scene = _sceneRepo.GetById(id) ?? new CombatScene { ScenarioId = id },
ControlZones = _zoneRepo.GetByScenarioId(id),
Drones = _droneRepo.GetByScenarioId(id),
Units = _unitRepo.GetByScenarioId(id),
Cloud = _cloudRepo.GetById(id) ?? new CloudDispersal { ScenarioId = id },
Routes = _routeRepo.GetByScenarioId(id),
WaypointGroups = _waypointRepo.GetByScenarioId(id)
.GroupBy(w => w.WaveId)
.ToDictionary(g => g.Key, g => g.OrderBy(w => w.OrderIndex).ToList()),
};
}
// ========== Step Save ==========
public void SaveScene(string scenarioId, CombatScene scene)
{
scene.ScenarioId = scenarioId;
var existing = _sceneRepo.GetById(scenarioId);
if (existing != null)
_sceneRepo.Update(scene);
else
_sceneRepo.Insert(scene);
TouchScenario(scenarioId);
}
public void SaveControlZones(string scenarioId, List<ControlZone> zones)
{
_zoneRepo.DeleteByScenarioId(scenarioId);
for (int i = 0; i < zones.Count; i++)
{
zones[i].ScenarioId = scenarioId;
zones[i].OrderIndex = i;
}
_zoneRepo.InsertAll(zones);
TouchScenario(scenarioId);
}
public ScenarioDrone SaveScenarioDrone(string scenarioId, ScenarioDrone target)
{
target.ScenarioId = scenarioId;
if (string.IsNullOrEmpty(target.Id))
target.Id = Guid.NewGuid().ToString();
var existing = _droneRepo.GetById(target.Id);
if (existing != null)
_droneRepo.Update(target);
else
_droneRepo.Insert(target);
TouchScenario(scenarioId);
return target;
}
public void SaveDeployment(string scenarioId, List<ScenarioUnit> equips)
{
_unitRepo.DeleteByScenarioId(scenarioId);
foreach (var e in equips)
{
e.ScenarioId = scenarioId;
if (string.IsNullOrEmpty(e.Id))
e.Id = Guid.NewGuid().ToString();
}
_unitRepo.InsertAll(equips);
TouchScenario(scenarioId);
}
public void AddDetection(string scenarioId, ScenarioUnit detection)
{
detection.ScenarioId = scenarioId;
detection.EquipmentRole = (int)EquipmentRole.Detection;
if (string.IsNullOrEmpty(detection.Id))
detection.Id = Guid.NewGuid().ToString();
_unitRepo.Insert(detection);
TouchScenario(scenarioId);
}
public void DeleteDetection(string detectionId)
{
_unitRepo.Delete(detectionId);
}
public List<ScenarioUnit> GetDetections(string scenarioId)
{
return _unitRepo.GetByScenarioIdAndRole(scenarioId, (int)EquipmentRole.Detection);
}
public void SaveCloudDispersal(string scenarioId, CloudDispersal cloud)
{
cloud.ScenarioId = scenarioId;
var existing = _cloudRepo.GetById(scenarioId);
if (existing != null)
_cloudRepo.Update(cloud);
else
_cloudRepo.Insert(cloud);
TouchScenario(scenarioId);
}
public void SaveRoute(string scenarioId, string waveId, RoutePlan route, List<Waypoint> waypoints)
{
route.ScenarioId = scenarioId;
route.WaveId = waveId;
var existing = _routeRepo.GetByScenarioAndWave(scenarioId, waveId);
if (existing != null)
{
route.Id = existing.Id;
_routeRepo.Update(route);
}
else
_routeRepo.Insert(route);
// 删除该批次的旧航路点,插入新的
var oldWps = _waypointRepo.GetByScenarioAndWave(scenarioId, waveId);
foreach (var w in oldWps) _waypointRepo.Delete(w.Id);
for (int i = 0; i < waypoints.Count; i++)
{
waypoints[i].ScenarioId = scenarioId;
waypoints[i].WaveId = waveId;
waypoints[i].OrderIndex = i;
if (string.IsNullOrEmpty(waypoints[i].Id))
waypoints[i].Id = Guid.NewGuid().ToString();
}
_waypointRepo.InsertAll(waypoints);
TouchScenario(scenarioId);
}
public void UpdateStep(string scenarioId, int step)
{
var scenario = _scenarioRepo.GetById(scenarioId);
if (scenario == null) return;
if (step < 1) step = 1;
if (step > 5) step = 5;
scenario.CurrentStep = step;
_scenarioRepo.Update(scenario);
}
public EnumMetadata GetEnums()
{
return new EnumMetadata
{
DroneType = EnumToDict<Models.DroneType>(),
PowerType = EnumToDict<Models.PowerType>(),
PlatformType = EnumToDict<Models.PlatformType>(),
AerosolType = EnumToDict<Models.AerosolType>(),
WeatherType = EnumToDict<Models.WeatherType>(),
WindDirection = EnumToDict<Models.WindDirection>(),
SceneType = EnumToDict<Models.SceneType>(),
FormationMode = EnumToDict<Models.FormationMode>(),
TriggerMode = EnumToDict<Models.TriggerMode>(),
ReleaseMode = EnumToDict<Models.ReleaseMode>(),
EquipmentRole = EnumToDict<Models.EquipmentRole>(),
};
}
private static Dictionary<string, int> EnumToDict<T>() where T : Enum
{
var dict = new Dictionary<string, int>();
foreach (T v in Enum.GetValues(typeof(T)))
dict[v.ToString()] = Convert.ToInt32(v);
return dict;
}
// ========== Scenario CRUD ==========
public Scenario UpdateScenario(Scenario scenario)
{
var existing = _scenarioRepo.GetById(scenario.Id);
if (existing == null)
throw new ArgumentException($"想定 {scenario.Id} 不存在");
scenario.UpdatedAt = DateTime.UtcNow.ToString("o");
_scenarioRepo.Update(scenario);
return scenario;
}
// ========== CombatScene ==========
public CombatScene GetScene(string scenarioId)
{
return _sceneRepo.GetById(scenarioId) ?? new CombatScene { ScenarioId = scenarioId };
}
// ========== ControlZone ==========
public List<ControlZone> GetControlZones(string scenarioId)
=> _zoneRepo.GetByScenarioId(scenarioId);
public void DeleteControlZone(string id)
=> _zoneRepo.Delete(id);
// ========== ScenarioDrone ==========
public ScenarioDrone AddScenarioDrone(string scenarioId, ScenarioDrone drone)
=> SaveScenarioDrone(scenarioId, drone);
public void UpdateScenarioDrone(ScenarioDrone drone)
{
_droneRepo.Update(drone);
TouchScenario(drone.ScenarioId);
}
public void DeleteScenarioDrone(string id)
=> _droneRepo.Delete(id);
public List<ScenarioDrone> GetScenarioDrones(string scenarioId)
=> _droneRepo.GetByScenarioId(scenarioId);
// ========== ScenarioUnit ==========
public ScenarioUnit AddDeploymentUnit(string scenarioId, ScenarioUnit unit)
{
unit.ScenarioId = scenarioId;
if (string.IsNullOrEmpty(unit.Id))
unit.Id = Guid.NewGuid().ToString();
_unitRepo.Insert(unit);
TouchScenario(scenarioId);
return unit;
}
public void UpdateDeploymentUnit(ScenarioUnit unit)
=> _unitRepo.Update(unit);
public void DeleteDeploymentUnit(string id)
=> _unitRepo.Delete(id);
public List<ScenarioUnit> GetDeploymentUnits(string scenarioId)
=> _unitRepo.GetByScenarioId(scenarioId);
// ========== CloudDispersal ==========
public CloudDispersal GetCloudDispersal(string scenarioId)
=> _cloudRepo.GetById(scenarioId) ?? new CloudDispersal { ScenarioId = scenarioId };
public void DeleteCloudDispersal(string scenarioId)
=> _cloudRepo.Delete(scenarioId);
// ========== Route & Waypoint ==========
public List<RoutePlan> GetRoutes(string scenarioId)
=> _routeRepo.GetByScenarioId(scenarioId);
public void DeleteRoute(string id)
{
var r = _routeRepo.GetById(id);
if (r == null) return;
var wps = _waypointRepo.GetByScenarioAndWave(r.ScenarioId, r.WaveId);
foreach (var w in wps) _waypointRepo.Delete(w.Id);
_routeRepo.Delete(id);
}
public List<Waypoint> GetWaypoints(string scenarioId)
=> _waypointRepo.GetByScenarioId(scenarioId);
public List<Waypoint> GetWaypointsByWave(string scenarioId, string waveId)
=> _waypointRepo.GetByScenarioAndWave(scenarioId, waveId);
public void DeleteWaypoint(string id)
=> _waypointRepo.Delete(id);
// ========== Helpers ==========
private void TouchScenario(string scenarioId)
{
var scenario = _scenarioRepo.GetById(scenarioId);
if (scenario != null)
{
scenario.UpdatedAt = DateTime.UtcNow.ToString("o");
_scenarioRepo.Update(scenario);
}
}
private static int _counter;
public static string GenerateScenarioNumber()
{
var now = DateTime.Now;
var datePart = now.ToString("yyyyMMdd");
var seq = Interlocked.Increment(ref _counter);
return $"SIM-{datePart}-{seq:D3}";
}
}
}