Initial commit

This commit is contained in:
2026-07-03 16:37:12 +07:00
commit 63b8c1ea8b
1931 changed files with 640587 additions and 0 deletions

View File

@@ -0,0 +1,187 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using RobotNet10.RobotApp.Data;
using RobotNet10.RobotApp.Shared.DockStation;
using RobotNet10.Shared.Enum;
using RobotNet10.Shared.Numbers;
using System.Text.Json;
namespace RobotNet10.RobotApp.Controllers;
[Route("api/dock-station-config")]
[ApiController]
[Authorize]
public class DockStationConfigController(ApplicationDbContext dbContext) : ControllerBase
{
[HttpGet]
public async Task<ActionResult<List<DockStationConfigSummaryDto>>> GetAll()
{
var configs = await dbContext.DockStationConfigs
.Include(d => d.MarkerEntries)
.OrderByDescending(d => d.UpdatedAt)
.ToListAsync();
return Ok(configs.Select(MapToSummaryDto).ToList());
}
[HttpGet("{id:guid}")]
public async Task<ActionResult<DockStationConfigDto>> GetById(Guid id)
{
var config = await dbContext.DockStationConfigs
.Include(d => d.MarkerEntries)
.FirstOrDefaultAsync(d => d.Id == id);
if (config is null) return NotFound();
return Ok(MapToDto(config));
}
[HttpGet("station/{stationId}")]
public async Task<ActionResult<DockStationConfigDto>> GetByStationId(string stationId)
{
var config = await dbContext.DockStationConfigs
.Include(d => d.MarkerEntries)
.FirstOrDefaultAsync(d => d.StationId == stationId);
if (config is null) return NotFound();
return Ok(MapToDto(config));
}
[HttpPost]
public async Task<ActionResult<DockStationConfigDto>> Create(
[FromBody] CreateDockStationConfigRequest request)
{
if (await dbContext.DockStationConfigs.AnyAsync(d => d.StationId == request.StationId))
return BadRequest($"StationId '{request.StationId}' already exists.");
var entity = new DockStationConfig
{
StationId = request.StationId,
ConfigName = request.ConfigName ?? string.Empty,
Description = request.Description ?? string.Empty,
X = request.X,
Y = request.Y,
Yaw = request.Yaw,
Width = request.Width,
Length = request.Length,
IsActive = request.IsActive,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow,
MarkerEntries = request.MarkerEntries.Select(MapFromEntryDto).ToList()
};
dbContext.DockStationConfigs.Add(entity);
await dbContext.SaveChangesAsync();
return CreatedAtAction(nameof(GetById), new { id = entity.Id }, MapToDto(entity));
}
[HttpPut("{id:guid}")]
public async Task<ActionResult<DockStationConfigDto>> Update(
Guid id, [FromBody] UpdateDockStationConfigRequest request)
{
var entity = await dbContext.DockStationConfigs
.Include(d => d.MarkerEntries)
.FirstOrDefaultAsync(d => d.Id == id);
if (entity is null) return NotFound();
if (request.StationId is not null)
{
if (request.StationId != entity.StationId &&
await dbContext.DockStationConfigs.AnyAsync(d => d.StationId == request.StationId))
return BadRequest($"StationId '{request.StationId}' already exists.");
entity.StationId = request.StationId;
}
if (request.ConfigName is not null) entity.ConfigName = request.ConfigName;
if (request.Description is not null) entity.Description = request.Description;
if (request.X.HasValue) entity.X = request.X.Value;
if (request.Y.HasValue) entity.Y = request.Y.Value;
if (request.Yaw.HasValue) entity.Yaw = request.Yaw.Value;
if (request.Width.HasValue) entity.Width = request.Width.Value;
if (request.Length.HasValue) entity.Length = request.Length.Value;
if (request.IsActive.HasValue) entity.IsActive = request.IsActive.Value;
entity.UpdatedAt = DateTime.UtcNow;
if (request.MarkerEntries is not null)
{
dbContext.DockStationMarkerEntries.RemoveRange(entity.MarkerEntries);
entity.MarkerEntries = request.MarkerEntries.Select(MapFromEntryDto).ToList();
}
await dbContext.SaveChangesAsync();
return Ok(MapToDto(entity));
}
[HttpDelete("{id:guid}")]
public async Task<IActionResult> Delete(Guid id)
{
var entity = await dbContext.DockStationConfigs.FindAsync(id);
if (entity is null) return NotFound();
dbContext.DockStationConfigs.Remove(entity);
await dbContext.SaveChangesAsync();
return NoContent();
}
#region Mapping Helpers
private static DockStationConfigDto MapToDto(DockStationConfig entity) => new()
{
Id = entity.Id,
StationId = entity.StationId,
ConfigName = entity.ConfigName,
Description = entity.Description,
X = entity.X,
Y = entity.Y,
Yaw = entity.Yaw,
Width = entity.Width,
Length = entity.Length,
CreatedAt = entity.CreatedAt,
UpdatedAt = entity.UpdatedAt,
IsActive = entity.IsActive,
MarkerEntries = entity.MarkerEntries?.Select(MapToEntryDto).ToList() ?? []
};
private static DockStationConfigSummaryDto MapToSummaryDto(DockStationConfig entity) => new()
{
Id = entity.Id,
StationId = entity.StationId,
ConfigName = entity.ConfigName,
Description = entity.Description,
IsActive = entity.IsActive,
MarkerEntryCount = entity.MarkerEntries?.Count ?? 0,
CreatedAt = entity.CreatedAt,
UpdatedAt = entity.UpdatedAt
};
private static DockStationMarkerEntryDto MapToEntryDto(DockStationMarkerEntry entity) => new()
{
Id = entity.Id,
MarkerId = entity.MarkerId,
Type = (MarkerType)entity.Type,
Priority = entity.Priority,
DeviceId = entity.DeviceId,
Code = entity.Code,
ReferencePoints = DeserializeReferencePoints(entity.ReferencePointsJson)
};
private static DockStationMarkerEntry MapFromEntryDto(DockStationMarkerEntryDto dto) => new()
{
MarkerId = dto.MarkerId,
Type = (int)dto.Type,
Priority = dto.Priority,
DeviceId = dto.DeviceId ?? string.Empty,
Code = dto.Code ?? string.Empty,
ReferencePointsJson = JsonSerializer.Serialize(dto.ReferencePoints ?? [])
};
private static List<Vector2> DeserializeReferencePoints(string? json)
{
if (string.IsNullOrWhiteSpace(json)) return [];
try { return JsonSerializer.Deserialize<List<Vector2>>(json) ?? []; }
catch { return []; }
}
#endregion
}

View File

@@ -0,0 +1,48 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace RobotNet10.RobotApp.Controllers;
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class LogsManagerController(Services.Logger<LogsManagerController> Logger) : ControllerBase
{
private readonly string LoggerDirectory = Path.Combine(AppContext.BaseDirectory, "logs");
[HttpGet]
public async Task<IEnumerable<string>> GetLogs([FromQuery(Name = "date")] DateTime date)
{
string temp = "";
try
{
string fileName = $"{date:yyyy-MM-dd}.log";
string path = Path.Combine(LoggerDirectory, fileName);
if (!Path.GetFullPath(path).StartsWith(Path.GetFullPath(LoggerDirectory)))
{
Logger.Warning($"GetLogs: Invalid path detected.");
return [];
}
if (!System.IO.File.Exists(path))
{
Logger.Warning($"GetLogs: Log file not found for date {date:d} - {path}.");
return [];
}
temp = Path.Combine(LoggerDirectory, $"{Guid.NewGuid()}.log");
System.IO.File.Copy(path, temp);
return await System.IO.File.ReadAllLinesAsync(temp);
}
catch (Exception ex)
{
Logger.Warning($"GetLogs: System error occurred - {ex.Message}");
return [];
}
finally
{
if (System.IO.File.Exists(temp)) System.IO.File.Delete(temp);
}
}
}

View File

@@ -0,0 +1,88 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using RobotNet10.RobotApp.Client.Shared.SLAM;
using RobotNet10.RobotApp.Shared;
using RobotNet10.RobotApp.SLAM;
namespace RobotNet10.RobotApp.Controllers;
/// <summary>
/// API Controller for map management operations
/// </summary>
[Route("api/[controller]")]
[ApiController]
[Authorize]
public class MapsController(ISLAMService slamService, ILogger<MapsController> logger) : ControllerBase
{
/// <summary>
/// Get map info by name
/// </summary>
/// <param name="mapName">Name of the map</param>
/// <returns>MapInfoDto if found, NotFound otherwise</returns>
[HttpGet("{mapName}")]
public ActionResult<MapInfoDto> GetMapInfo(string mapName)
{
try
{
var mapInfo = slamService.GetMapInfo(mapName);
if (mapInfo == null)
{
logger.LogWarning("MapsController: Map not found: {MapName}", mapName);
return NotFound($"Map '{mapName}' not found");
}
return Ok(MapMapInfoToDto(mapInfo));
}
catch (Exception ex)
{
logger.LogError(ex, "MapsController: Failed to get map info: {MapName}", mapName);
return StatusCode(500, "Failed to get map info");
}
}
/// <summary>
/// Get map image by name
/// </summary>
/// <param name="mapName">Name of the map</param>
/// <returns>PNG image file</returns>
[HttpGet("{mapName}/image")]
public IActionResult GetMapImage(string mapName)
{
try
{
var imagePath = slamService.GetMapImagePath(mapName);
if (imagePath == null)
{
logger.LogWarning("MapsController: Map image not found: {MapName}", mapName);
return NotFound($"Map image for '{mapName}' not found");
}
var contentType = imagePath.EndsWith(".png", StringComparison.OrdinalIgnoreCase)
? "image/png"
: "image/jpeg";
var fileStream = new FileStream(imagePath, FileMode.Open, FileAccess.Read, FileShare.Read);
return File(fileStream, contentType);
}
catch (Exception ex)
{
logger.LogError(ex, "MapsController: Failed to get map image: {MapName}", mapName);
return StatusCode(500, "Failed to get map image");
}
}
private static MapInfoDto MapMapInfoToDto(MapInfo mapInfo)
{
return new MapInfoDto
{
Name = mapInfo.Name,
CreatedDate = mapInfo.CreatedDate,
Resolution = mapInfo.Resolution,
Width = mapInfo.Size.Width,
Height = mapInfo.Size.Height,
TrajectoryNodeCount = mapInfo.TrajectoryNodeCount,
OriginX = mapInfo.Origin.Position.X,
OriginY = mapInfo.Origin.Position.Y,
};
}
}