318 lines
11 KiB
C#
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
|
|
};
|
|
}
|
|
}
|