corps/src/MilitaryTrainingManagement/Controllers/AllocationsController.cs
2026-01-13 14:36:01 +08:00

318 lines
11 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MilitaryTrainingManagement.Authorization;
using MilitaryTrainingManagement.Models.DTOs;
using MilitaryTrainingManagement.Models.Enums;
using MilitaryTrainingManagement.Services.Interfaces;
namespace MilitaryTrainingManagement.Controllers;
/// <summary>
/// 物资配额控制器
/// </summary>
[Authorize]
public class AllocationsController : BaseApiController
{
private readonly IAllocationService _allocationService;
private readonly IOrganizationalAuthorizationService _authorizationService;
public AllocationsController(
IAllocationService allocationService,
IOrganizationalAuthorizationService authorizationService)
{
_allocationService = allocationService;
_authorizationService = authorizationService;
}
/// <summary>
/// 获取当前用户可见的所有物资配额
/// </summary>
[HttpGet]
public async Task<IActionResult> GetAll()
{
var unitId = GetCurrentUnitId();
var unitLevel = GetCurrentUnitLevel();
if (unitId == null || unitLevel == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
// 师团级可以看到所有配额,其他级别只能看到分配给自己及下级的配额
IEnumerable<Models.Entities.MaterialAllocation> allocations;
if (unitLevel == OrganizationalLevel.Division)
{
allocations = await _allocationService.GetAllAsync();
}
else
{
allocations = await _allocationService.GetVisibleToUnitAsync(unitId.Value);
}
var response = allocations.Select(MapToResponse);
return Ok(response);
}
/// <summary>
/// 获取当前单位创建的物资配额
/// </summary>
[HttpGet("my")]
public async Task<IActionResult> GetMyAllocations()
{
var unitId = GetCurrentUnitId();
if (unitId == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
var allocations = await _allocationService.GetByUnitAsync(unitId.Value);
var response = allocations.Select(MapToResponse);
return Ok(response);
}
/// <summary>
/// 获取分配给当前单位的配额分配记录
/// </summary>
[HttpGet("distributions")]
public async Task<IActionResult> GetMyDistributions()
{
var unitId = GetCurrentUnitId();
if (unitId == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
var distributions = await _allocationService.GetDistributionsForUnitAsync(unitId.Value);
var response = distributions.Select(MapDistributionToResponse);
return Ok(response);
}
/// <summary>
/// 根据ID获取物资配额
/// </summary>
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var unitId = GetCurrentUnitId();
if (unitId == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
var allocation = await _allocationService.GetByIdAsync(id);
if (allocation == null)
return NotFound(new { message = "配额不存在" });
// 检查访问权限:只能查看自己创建的或分配给自己及下级的配额
var canAccess = allocation.CreatedByUnitId == unitId.Value ||
allocation.Distributions.Any(d =>
_authorizationService.CanAccessUnitAsync(unitId.Value, d.TargetUnitId).GetAwaiter().GetResult());
if (!canAccess)
return Forbid();
return Ok(MapToResponse(allocation));
}
/// <summary>
/// 创建物资配额
/// 需求2.1:师团管理员可以创建物资类别
/// 需求2.2:创建配额需要物资名称、单位、总配额和目标单位
/// 需求2.4:创建后自动分发给目标单位
/// </summary>
[HttpPost]
[Authorize(Policy = "DivisionLevel")]
public async Task<IActionResult> Create([FromBody] CreateAllocationRequest request)
{
var unitId = GetCurrentUnitId();
if (unitId == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
// 验证必填字段
if (!ModelState.IsValid)
return BadRequest(ModelState);
try
{
var allocation = await _allocationService.CreateAsync(
request.Category,
request.MaterialName,
request.Unit,
request.TotalQuota,
unitId.Value,
request.Distributions);
return CreatedAtAction(nameof(GetById), new { id = allocation.Id }, MapToResponse(allocation));
}
catch (ArgumentException ex)
{
return BadRequest(new { message = ex.Message });
}
}
/// <summary>
/// 更新物资配额基本信息
/// </summary>
[HttpPut("{id}")]
[Authorize(Policy = "DivisionLevel")]
public async Task<IActionResult> Update(int id, [FromBody] UpdateAllocationRequest request)
{
var unitId = GetCurrentUnitId();
if (unitId == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
// 验证必填字段
if (!ModelState.IsValid)
return BadRequest(ModelState);
// 检查配额是否存在
var existingAllocation = await _allocationService.GetByIdAsync(id);
if (existingAllocation == null)
return NotFound(new { message = "配额不存在" });
// 检查是否有权限修改(只能修改自己创建的配额)
if (existingAllocation.CreatedByUnitId != unitId.Value)
return Forbid();
try
{
var allocation = await _allocationService.UpdateAsync(
id,
request.Category,
request.MaterialName,
request.Unit,
request.TotalQuota);
return Ok(MapToResponse(await _allocationService.GetByIdAsync(id) ?? allocation));
}
catch (ArgumentException ex)
{
return BadRequest(new { message = ex.Message });
}
}
/// <summary>
/// 更新配额分配记录
/// </summary>
[HttpPut("{id}/distributions")]
[Authorize(Policy = "DivisionLevel")]
public async Task<IActionResult> UpdateDistributions(int id, [FromBody] Dictionary<int, decimal> distributions)
{
var unitId = GetCurrentUnitId();
if (unitId == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
// 检查配额是否存在
var existingAllocation = await _allocationService.GetByIdAsync(id);
if (existingAllocation == null)
return NotFound(new { message = "配额不存在" });
// 检查是否有权限修改
if (existingAllocation.CreatedByUnitId != unitId.Value)
return Forbid();
try
{
var allocation = await _allocationService.UpdateDistributionsAsync(id, distributions);
return Ok(MapToResponse(allocation));
}
catch (ArgumentException ex)
{
return BadRequest(new { message = ex.Message });
}
}
/// <summary>
/// 删除物资配额
/// </summary>
[HttpDelete("{id}")]
[Authorize(Policy = "DivisionLevel")]
public async Task<IActionResult> Delete(int id)
{
var unitId = GetCurrentUnitId();
if (unitId == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
// 检查配额是否存在
var existingAllocation = await _allocationService.GetByIdAsync(id);
if (existingAllocation == null)
return NotFound(new { message = "配额不存在" });
// 检查是否有权限删除
if (existingAllocation.CreatedByUnitId != unitId.Value)
return Forbid();
try
{
await _allocationService.DeleteAsync(id);
return NoContent();
}
catch (ArgumentException ex)
{
return BadRequest(new { message = ex.Message });
}
}
/// <summary>
/// 验证配额分配是否有效
/// </summary>
[HttpPost("validate")]
public async Task<IActionResult> ValidateDistributions([FromBody] CreateAllocationRequest request)
{
var isValid = await _allocationService.ValidateDistributionQuotasAsync(
request.TotalQuota,
request.Distributions);
var targetUnitsExist = await _allocationService.ValidateTargetUnitsExistAsync(
request.Distributions.Keys);
return Ok(new
{
quotaValid = isValid,
targetUnitsExist = targetUnitsExist,
isValid = isValid && targetUnitsExist,
message = !isValid ? "分配配额总和超过总配额指标" :
!targetUnitsExist ? "目标单位不存在" : "验证通过"
});
}
/// <summary>
/// 映射实体到响应DTO
/// </summary>
private static AllocationResponse MapToResponse(Models.Entities.MaterialAllocation allocation)
{
return new AllocationResponse
{
Id = allocation.Id,
Category = allocation.Category,
MaterialName = allocation.MaterialName,
Unit = allocation.Unit,
TotalQuota = allocation.TotalQuota,
CreatedByUnitId = allocation.CreatedByUnitId,
CreatedByUnitName = allocation.CreatedByUnit?.Name ?? string.Empty,
CreatedAt = allocation.CreatedAt,
Distributions = allocation.Distributions.Select(d => new AllocationDistributionResponse
{
Id = d.Id,
TargetUnitId = d.TargetUnitId,
TargetUnitName = d.TargetUnit?.Name ?? string.Empty,
UnitQuota = d.UnitQuota,
ActualCompletion = d.ActualCompletion,
CompletionRate = d.CompletionRate,
ReportedAt = d.ReportedAt,
ReportedByUserName = d.ReportedByUser?.DisplayName
}).ToList()
};
}
/// <summary>
/// 映射分配记录到响应DTO
/// </summary>
private static AllocationDistributionResponse MapDistributionToResponse(Models.Entities.AllocationDistribution distribution)
{
return new AllocationDistributionResponse
{
Id = distribution.Id,
TargetUnitId = distribution.TargetUnitId,
TargetUnitName = distribution.TargetUnit?.Name ?? string.Empty,
UnitQuota = distribution.UnitQuota,
ActualCompletion = distribution.ActualCompletion,
CompletionRate = distribution.CompletionRate,
ReportedAt = distribution.ReportedAt,
ReportedByUserName = distribution.ReportedByUser?.DisplayName
};
}
}