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;
///
/// 物资配额控制器
///
[Authorize]
public class AllocationsController : BaseApiController
{
private readonly IAllocationService _allocationService;
private readonly IOrganizationalAuthorizationService _authorizationService;
public AllocationsController(
IAllocationService allocationService,
IOrganizationalAuthorizationService authorizationService)
{
_allocationService = allocationService;
_authorizationService = authorizationService;
}
///
/// 获取当前用户可见的所有物资配额
///
[HttpGet]
public async Task GetAll(
[FromQuery] int pageNumber = 1,
[FromQuery] int pageSize = 10)
{
var unitId = GetCurrentUnitId();
var unitLevel = GetCurrentUnitLevel();
if (unitId == null || unitLevel == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
// 师团级可以看到所有配额,其他级别只能看到分配给自己及下级的配额
IEnumerable allAllocations;
if (unitLevel == OrganizationalLevel.Division)
{
allAllocations = await _allocationService.GetAllAsync();
}
else
{
allAllocations = await _allocationService.GetVisibleToUnitAsync(unitId.Value);
}
var totalCount = allAllocations.Count();
var items = allAllocations
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.Select(MapToResponse)
.ToList();
return Ok(new
{
items,
totalCount,
pageNumber,
pageSize,
totalPages = (int)Math.Ceiling(totalCount / (double)pageSize)
});
}
///
/// 获取当前单位创建的物资配额
///
[HttpGet("my")]
public async Task 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);
}
///
/// 获取分配给当前单位的配额分配记录
///
[HttpGet("distributions")]
public async Task 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);
}
///
/// 根据ID获取物资配额
/// 需求1.1, 1.2, 1.3:营部及以下级别用户只能查看本单位及直接下级的配额
///
[HttpGet("{id}")]
public async Task GetById(int id)
{
var unitId = GetCurrentUnitId();
var unitLevel = GetCurrentUnitLevel();
if (unitId == null || unitLevel == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
var allocation = await _allocationService.GetByIdAsync(id);
if (allocation == null)
return NotFound(new { message = "配额不存在" });
// 检查访问权限:
// 1. 可以查看自己创建的配额
// 2. 使用可见性过滤检查是否可以访问配额中的任何一个分配记录
var canAccess = allocation.CreatedByUnitId == unitId.Value;
if (!canAccess)
{
// 检查是否有任何分配记录在用户的可见范围内
foreach (var dist in allocation.Distributions)
{
if (await _allocationService.CanViewDistributionAsync(unitId.Value, unitLevel.Value, dist.TargetUnitId))
{
canAccess = true;
break;
}
}
}
if (!canAccess)
return Forbid();
// 过滤分配记录,只返回用户可见范围内的记录
var filteredAllocation = await FilterAllocationDistributions(allocation, unitId.Value, unitLevel.Value);
return Ok(MapToResponse(filteredAllocation));
}
///
/// 过滤配额的分配记录,只保留用户可见范围内的记录
///
private async Task FilterAllocationDistributions(
Models.Entities.MaterialAllocation allocation,
int userUnitId,
OrganizationalLevel userLevel)
{
var visibleDistributions = new List();
foreach (var dist in allocation.Distributions)
{
if (await _allocationService.CanViewDistributionAsync(userUnitId, userLevel, dist.TargetUnitId))
{
visibleDistributions.Add(dist);
}
}
// 创建一个新的配额对象,只包含可见的分配记录
return new Models.Entities.MaterialAllocation
{
Id = allocation.Id,
Category = allocation.Category,
MaterialName = allocation.MaterialName,
Unit = allocation.Unit,
TotalQuota = allocation.TotalQuota,
CreatedByUnitId = allocation.CreatedByUnitId,
CreatedByUnit = allocation.CreatedByUnit,
CreatedAt = allocation.CreatedAt,
Distributions = visibleDistributions
};
}
///
/// 创建物资配额
/// 需求2.1:师团管理员可以创建物资类别
/// 需求2.2:创建配额需要物资名称、单位、总配额和目标单位
/// 需求2.4:创建后自动分发给目标单位
///
[HttpPost]
[Authorize(Policy = "DivisionLevel")]
public async Task 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.GetDistributionsDictionary());
return CreatedAtAction(nameof(GetById), new { id = allocation.Id }, MapToResponse(allocation));
}
catch (ArgumentException ex)
{
return BadRequest(new { message = ex.Message });
}
}
///
/// 更新物资配额基本信息
///
[HttpPut("{id}")]
[Authorize(Policy = "DivisionLevel")]
public async Task 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 });
}
}
///
/// 更新配额分配记录
///
[HttpPut("{id}/distributions")]
[Authorize(Policy = "DivisionLevel")]
public async Task UpdateDistributions(int id, [FromBody] Dictionary 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 });
}
}
///
/// 上报消耗 - 更新单个分配记录的实际完成数量
/// 团部及以下单位可以上报自己的消耗数据
///
[HttpPut("distributions/{distributionId}")]
public async Task UpdateDistribution(int distributionId, [FromBody] UpdateDistributionRequest request)
{
var unitId = GetCurrentUnitId();
var userId = GetCurrentUserId();
if (unitId == null || userId == null)
return Unauthorized(new { message = "无法获取用户信息" });
try
{
var distribution = await _allocationService.UpdateDistributionCompletionAsync(
distributionId,
unitId.Value,
userId.Value,
request.ActualCompletion);
return Ok(MapDistributionToResponse(distribution));
}
catch (UnauthorizedAccessException ex)
{
return Forbid();
}
catch (ArgumentException ex)
{
return BadRequest(new { message = ex.Message });
}
}
///
/// 删除物资配额
///
[HttpDelete("{id}")]
[Authorize(Policy = "DivisionLevel")]
public async Task 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 });
}
}
///
/// 验证配额分配是否有效
///
[HttpPost("validate")]
public async Task ValidateDistributions([FromBody] CreateAllocationRequest request)
{
var distributions = request.GetDistributionsDictionary();
var isValid = await _allocationService.ValidateDistributionQuotasAsync(
request.TotalQuota,
distributions);
var targetUnitsExist = await _allocationService.ValidateTargetUnitsExistAsync(
distributions.Keys);
return Ok(new
{
quotaValid = isValid,
targetUnitsExist = targetUnitsExist,
isValid = isValid && targetUnitsExist,
message = !isValid ? "有配额未分配,无法提交" :
!targetUnitsExist ? "目标单位不存在" : "验证通过"
});
}
///
/// 获取配额分配的上报历史记录
/// 需求1.1, 1.2, 1.3:营部及以下级别用户只能查看本单位及直接下级的记录
///
[HttpGet("distributions/{distributionId}/reports")]
public async Task GetConsumptionReports(int distributionId)
{
var unitId = GetCurrentUnitId();
var unitLevel = GetCurrentUnitLevel();
if (unitId == null || unitLevel == null)
return Unauthorized(new { message = "无法获取用户组织信息" });
// 检查分配记录是否存在
var distribution = await _allocationService.GetDistributionByIdAsync(distributionId);
if (distribution == null)
return NotFound(new { message = "配额分配记录不存在" });
// 使用可见性过滤检查访问权限
// 营部及以下级别:只能查看本单位及直接下级的记录
// 师团/团级:可以查看所有下级的记录
var canAccess = await _allocationService.CanViewDistributionAsync(
unitId.Value,
unitLevel.Value,
distribution.TargetUnitId);
if (!canAccess)
return Forbid();
// 获取上报历史记录(带可见性过滤)
// 只返回用户可见范围内的单位的上报记录
var reports = await _allocationService.GetConsumptionReportsAsync(distributionId, unitId.Value, unitLevel.Value);
var response = reports.Select(r => new
{
id = r.Id,
reportedAmount = r.ReportedAmount,
cumulativeAmount = r.CumulativeAmount,
remarks = r.Remarks,
reportedByUserName = r.ReportedByUser?.DisplayName,
reportedAt = r.ReportedAt
});
return Ok(response);
}
///
/// 映射实体到响应DTO
///
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()
};
}
///
/// 映射分配记录到响应DTO
///
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
};
}
}