修改上报
This commit is contained in:
parent
2495d39e9e
commit
425ac307bb
|
|
@ -428,6 +428,7 @@ public class AllocationsController : BaseApiController
|
|||
cumulativeAmount = r.CumulativeAmount,
|
||||
remarks = r.Remarks,
|
||||
reportedByUserName = r.ReportedByUser?.DisplayName,
|
||||
reportedByUnitId = r.ReportedByUnitId,
|
||||
reportedAt = r.ReportedAt
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,334 @@
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MilitaryTrainingManagement.Data;
|
||||
using MilitaryTrainingManagement.Models.Entities;
|
||||
using MilitaryTrainingManagement.Models.Enums;
|
||||
|
||||
namespace MilitaryTrainingManagement.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 消耗记录删改申请控制器
|
||||
/// </summary>
|
||||
[Authorize]
|
||||
public class ConsumptionChangeRequestsController : BaseApiController
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ILogger<ConsumptionChangeRequestsController> _logger;
|
||||
|
||||
public ConsumptionChangeRequestsController(
|
||||
ApplicationDbContext context,
|
||||
ILogger<ConsumptionChangeRequestsController> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建删改申请
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create([FromBody] CreateChangeRequestDto request)
|
||||
{
|
||||
var unitId = GetCurrentUnitId();
|
||||
var userId = GetCurrentUserId();
|
||||
if (unitId == null || userId == null)
|
||||
return Unauthorized();
|
||||
|
||||
// 验证消耗记录存在且属于当前单位
|
||||
var report = await _context.ConsumptionReports
|
||||
.Include(r => r.ReportedByUnit)
|
||||
.FirstOrDefaultAsync(r => r.Id == request.ConsumptionReportId);
|
||||
|
||||
if (report == null)
|
||||
return NotFound(new { message = "消耗记录不存在" });
|
||||
|
||||
if (report.ReportedByUnitId != unitId.Value)
|
||||
return BadRequest(new { message = "只能申请删改本单位的上报记录" });
|
||||
|
||||
// 检查是否已有待处理的申请
|
||||
var existingRequest = await _context.ConsumptionReportChangeRequests
|
||||
.AnyAsync(r => r.ConsumptionReportId == request.ConsumptionReportId
|
||||
&& r.Status == ChangeRequestStatus.Pending);
|
||||
|
||||
if (existingRequest)
|
||||
return BadRequest(new { message = "该记录已有待处理的删改申请" });
|
||||
|
||||
var changeRequest = new ConsumptionReportChangeRequest
|
||||
{
|
||||
ConsumptionReportId = request.ConsumptionReportId,
|
||||
RequestType = request.RequestType,
|
||||
Reason = request.Reason,
|
||||
Status = ChangeRequestStatus.Pending,
|
||||
RequestedByUnitId = unitId.Value,
|
||||
RequestedByUserId = userId.Value,
|
||||
RequestedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_context.ConsumptionReportChangeRequests.Add(changeRequest);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("单位 {UnitId} 创建了消耗记录 {ReportId} 的{Type}申请",
|
||||
unitId, request.ConsumptionReportId, request.RequestType);
|
||||
|
||||
return Ok(new { message = "申请已提交", id = changeRequest.Id });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取待处理的申请列表(上级单位查看下级的申请)
|
||||
/// </summary>
|
||||
[HttpGet("pending")]
|
||||
public async Task<IActionResult> GetPendingRequests()
|
||||
{
|
||||
var unitId = GetCurrentUnitId();
|
||||
if (unitId == null)
|
||||
return Unauthorized();
|
||||
|
||||
// 获取下级单位的ID列表
|
||||
var subordinateIds = await GetSubordinateUnitIds(unitId.Value);
|
||||
|
||||
var requests = await _context.ConsumptionReportChangeRequests
|
||||
.Include(r => r.ConsumptionReport)
|
||||
.ThenInclude(cr => cr.AllocationDistribution)
|
||||
.ThenInclude(d => d.Allocation)
|
||||
.Include(r => r.RequestedByUnit)
|
||||
.Include(r => r.RequestedByUser)
|
||||
.Where(r => r.Status == ChangeRequestStatus.Pending
|
||||
&& subordinateIds.Contains(r.RequestedByUnitId))
|
||||
.OrderByDescending(r => r.RequestedAt)
|
||||
.Select(r => new
|
||||
{
|
||||
r.Id,
|
||||
r.ConsumptionReportId,
|
||||
RequestType = r.RequestType.ToString(),
|
||||
r.Reason,
|
||||
Status = r.Status.ToString(),
|
||||
r.RequestedAt,
|
||||
RequestedByUnitName = r.RequestedByUnit.Name,
|
||||
RequestedByUserName = r.RequestedByUser.DisplayName,
|
||||
ConsumptionReport = new
|
||||
{
|
||||
r.ConsumptionReport.Id,
|
||||
r.ConsumptionReport.ReportedAmount,
|
||||
r.ConsumptionReport.ReportedAt,
|
||||
r.ConsumptionReport.Remarks,
|
||||
MaterialName = r.ConsumptionReport.AllocationDistribution.Allocation.MaterialName,
|
||||
Unit = r.ConsumptionReport.AllocationDistribution.Allocation.Unit
|
||||
}
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(requests);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取本单位的申请列表
|
||||
/// </summary>
|
||||
[HttpGet("my")]
|
||||
public async Task<IActionResult> GetMyRequests()
|
||||
{
|
||||
var unitId = GetCurrentUnitId();
|
||||
if (unitId == null)
|
||||
return Unauthorized();
|
||||
|
||||
var requests = await _context.ConsumptionReportChangeRequests
|
||||
.Include(r => r.ConsumptionReport)
|
||||
.Include(r => r.ProcessedByUnit)
|
||||
.Where(r => r.RequestedByUnitId == unitId.Value)
|
||||
.OrderByDescending(r => r.RequestedAt)
|
||||
.Select(r => new
|
||||
{
|
||||
r.Id,
|
||||
r.ConsumptionReportId,
|
||||
RequestType = r.RequestType.ToString(),
|
||||
r.Reason,
|
||||
Status = r.Status.ToString(),
|
||||
r.RequestedAt,
|
||||
r.ProcessedAt,
|
||||
ProcessedByUnitName = r.ProcessedByUnit != null ? r.ProcessedByUnit.Name : null,
|
||||
r.ProcessComments
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(requests);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理申请(同意或拒绝)
|
||||
/// </summary>
|
||||
[HttpPost("{id}/process")]
|
||||
public async Task<IActionResult> ProcessRequest(int id, [FromBody] ProcessChangeRequestDto request)
|
||||
{
|
||||
var unitId = GetCurrentUnitId();
|
||||
var userId = GetCurrentUserId();
|
||||
if (unitId == null || userId == null)
|
||||
return Unauthorized();
|
||||
|
||||
var changeRequest = await _context.ConsumptionReportChangeRequests
|
||||
.Include(r => r.ConsumptionReport)
|
||||
.ThenInclude(cr => cr.AllocationDistribution)
|
||||
.Include(r => r.RequestedByUnit)
|
||||
.FirstOrDefaultAsync(r => r.Id == id);
|
||||
|
||||
if (changeRequest == null)
|
||||
return NotFound(new { message = "申请不存在" });
|
||||
|
||||
if (changeRequest.Status != ChangeRequestStatus.Pending)
|
||||
return BadRequest(new { message = "该申请已处理" });
|
||||
|
||||
// 验证是否有权限处理(必须是申请单位的上级)
|
||||
var isParent = await IsParentUnit(unitId.Value, changeRequest.RequestedByUnitId);
|
||||
if (!isParent)
|
||||
return StatusCode(403, new { message = "您没有权限处理此申请" });
|
||||
|
||||
changeRequest.Status = request.Approved ? ChangeRequestStatus.Approved : ChangeRequestStatus.Rejected;
|
||||
changeRequest.ProcessedByUnitId = unitId.Value;
|
||||
changeRequest.ProcessedByUserId = userId.Value;
|
||||
changeRequest.ProcessedAt = DateTime.UtcNow;
|
||||
changeRequest.ProcessComments = request.Comments;
|
||||
|
||||
// 如果同意删除,执行删除操作
|
||||
if (request.Approved && changeRequest.RequestType == ChangeRequestType.Delete)
|
||||
{
|
||||
var report = changeRequest.ConsumptionReport;
|
||||
var distribution = report.AllocationDistribution;
|
||||
|
||||
// 更新分配的实际完成数量
|
||||
distribution.ActualCompletion -= report.ReportedAmount;
|
||||
if (distribution.ActualCompletion < 0)
|
||||
distribution.ActualCompletion = 0;
|
||||
|
||||
// 删除消耗记录
|
||||
_context.ConsumptionReports.Remove(report);
|
||||
|
||||
_logger.LogInformation("消耗记录 {ReportId} 已被删除,分配 {DistributionId} 的实际完成数量已更新",
|
||||
report.Id, distribution.Id);
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var action = request.Approved ? "同意" : "拒绝";
|
||||
_logger.LogInformation("单位 {UnitId} {Action}了消耗记录删改申请 {RequestId}",
|
||||
unitId, action, id);
|
||||
|
||||
return Ok(new { message = $"已{action}该申请" });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改消耗记录(上级单位在同意修改申请后执行)
|
||||
/// </summary>
|
||||
[HttpPost("{id}/modify")]
|
||||
public async Task<IActionResult> ModifyReport(int id, [FromBody] ModifyReportDto request)
|
||||
{
|
||||
var unitId = GetCurrentUnitId();
|
||||
if (unitId == null)
|
||||
return Unauthorized();
|
||||
|
||||
var changeRequest = await _context.ConsumptionReportChangeRequests
|
||||
.Include(r => r.ConsumptionReport)
|
||||
.ThenInclude(cr => cr.AllocationDistribution)
|
||||
.FirstOrDefaultAsync(r => r.Id == id);
|
||||
|
||||
if (changeRequest == null)
|
||||
return NotFound(new { message = "申请不存在" });
|
||||
|
||||
if (changeRequest.Status != ChangeRequestStatus.Approved)
|
||||
return BadRequest(new { message = "只能修改已同意的申请" });
|
||||
|
||||
if (changeRequest.RequestType != ChangeRequestType.Modify)
|
||||
return BadRequest(new { message = "该申请不是修改类型" });
|
||||
|
||||
// 验证是否有权限(必须是处理单位)
|
||||
if (changeRequest.ProcessedByUnitId != unitId.Value)
|
||||
return StatusCode(403, new { message = "只有处理单位才能修改" });
|
||||
|
||||
var report = changeRequest.ConsumptionReport;
|
||||
var distribution = report.AllocationDistribution;
|
||||
var oldAmount = report.ReportedAmount;
|
||||
|
||||
// 更新消耗记录
|
||||
report.ReportedAmount = request.NewAmount;
|
||||
report.Remarks = request.NewRemarks ?? report.Remarks;
|
||||
|
||||
// 更新分配的实际完成数量
|
||||
distribution.ActualCompletion = distribution.ActualCompletion - oldAmount + request.NewAmount;
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_logger.LogInformation("消耗记录 {ReportId} 已被修改,数量从 {OldAmount} 改为 {NewAmount}",
|
||||
report.Id, oldAmount, request.NewAmount);
|
||||
|
||||
return Ok(new { message = "修改成功" });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查消耗记录是否有待处理的申请
|
||||
/// </summary>
|
||||
[HttpGet("check/{consumptionReportId}")]
|
||||
public async Task<IActionResult> CheckPendingRequest(int consumptionReportId)
|
||||
{
|
||||
var hasPending = await _context.ConsumptionReportChangeRequests
|
||||
.AnyAsync(r => r.ConsumptionReportId == consumptionReportId
|
||||
&& r.Status == ChangeRequestStatus.Pending);
|
||||
|
||||
return Ok(new { hasPendingRequest = hasPending });
|
||||
}
|
||||
|
||||
private async Task<List<int>> GetSubordinateUnitIds(int unitId)
|
||||
{
|
||||
var result = new List<int>();
|
||||
var children = await _context.OrganizationalUnits
|
||||
.Where(u => u.ParentId == unitId)
|
||||
.Select(u => u.Id)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var childId in children)
|
||||
{
|
||||
result.Add(childId);
|
||||
var grandChildren = await GetSubordinateUnitIds(childId);
|
||||
result.AddRange(grandChildren);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<bool> IsParentUnit(int parentUnitId, int childUnitId)
|
||||
{
|
||||
var childUnit = await _context.OrganizationalUnits
|
||||
.FirstOrDefaultAsync(u => u.Id == childUnitId);
|
||||
|
||||
if (childUnit == null) return false;
|
||||
|
||||
var currentParentId = childUnit.ParentId;
|
||||
while (currentParentId.HasValue)
|
||||
{
|
||||
if (currentParentId.Value == parentUnitId)
|
||||
return true;
|
||||
|
||||
var parent = await _context.OrganizationalUnits
|
||||
.FirstOrDefaultAsync(u => u.Id == currentParentId.Value);
|
||||
currentParentId = parent?.ParentId;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class CreateChangeRequestDto
|
||||
{
|
||||
public int ConsumptionReportId { get; set; }
|
||||
public ChangeRequestType RequestType { get; set; }
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ProcessChangeRequestDto
|
||||
{
|
||||
public bool Approved { get; set; }
|
||||
public string? Comments { get; set; }
|
||||
}
|
||||
|
||||
public class ModifyReportDto
|
||||
{
|
||||
public decimal NewAmount { get; set; }
|
||||
public string? NewRemarks { get; set; }
|
||||
}
|
||||
|
|
@ -551,7 +551,8 @@ public class PersonnelController : BaseApiController
|
|||
public async Task<IActionResult> Reject(int id, [FromBody] RejectPersonnelRequest request)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null)
|
||||
var unitId = GetCurrentUnitId();
|
||||
if (userId == null || unitId == null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
|
@ -563,8 +564,8 @@ public class PersonnelController : BaseApiController
|
|||
return StatusCode(403, new { message = "您没有权限拒绝此人员" });
|
||||
}
|
||||
|
||||
var personnel = await _personnelService.RejectAsync(id, userId.Value);
|
||||
return Ok(personnel);
|
||||
var personnel = await _personnelService.RejectAsync(id, userId.Value, unitId.Value, request.Reason);
|
||||
return Ok(MapToResponse(personnel));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -604,7 +605,8 @@ public class PersonnelController : BaseApiController
|
|||
public async Task<IActionResult> BatchReject([FromBody] BatchRejectPersonnelRequest request)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null)
|
||||
var unitId = GetCurrentUnitId();
|
||||
if (userId == null || unitId == null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
|
@ -612,7 +614,7 @@ public class PersonnelController : BaseApiController
|
|||
try
|
||||
{
|
||||
var rejectedPersonnel = await _personnelService.BatchRejectPersonnelAsync(
|
||||
request.PersonnelIds, userId.Value, request.Reason);
|
||||
request.PersonnelIds, userId.Value, unitId.Value, request.Reason);
|
||||
|
||||
return Ok(new {
|
||||
rejectedCount = rejectedPersonnel.Count(),
|
||||
|
|
@ -687,7 +689,25 @@ public class PersonnelController : BaseApiController
|
|||
}
|
||||
|
||||
var history = await _personnelService.GetPersonnelApprovalHistoryAsync(id);
|
||||
return Ok(history);
|
||||
|
||||
// 映射为简化的响应对象,避免循环引用
|
||||
var response = history.Select(h => new
|
||||
{
|
||||
h.Id,
|
||||
h.PersonnelId,
|
||||
Action = h.Action.ToString(),
|
||||
PreviousStatus = h.PreviousStatus?.ToString(),
|
||||
NewStatus = h.NewStatus.ToString(),
|
||||
PreviousLevel = h.PreviousLevel?.ToString(),
|
||||
NewLevel = h.NewLevel?.ToString(),
|
||||
h.ReviewedByUserId,
|
||||
h.ReviewedByUnitId,
|
||||
ReviewedByUnitName = h.ReviewedByUnit?.Name,
|
||||
h.Comments,
|
||||
h.ReviewedAt
|
||||
});
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ public class ApplicationDbContext : DbContext
|
|||
public DbSet<ApprovalRequest> ApprovalRequests => Set<ApprovalRequest>();
|
||||
public DbSet<AuditLog> AuditLogs => Set<AuditLog>();
|
||||
public DbSet<ConsumptionReport> ConsumptionReports => Set<ConsumptionReport>();
|
||||
public DbSet<ConsumptionReportChangeRequest> ConsumptionReportChangeRequests => Set<ConsumptionReportChangeRequest>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
|
@ -205,8 +206,44 @@ public class ApplicationDbContext : DbContext
|
|||
.WithMany()
|
||||
.HasForeignKey(e => e.ReportedByUserId)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
entity.HasOne(e => e.ReportedByUnit)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.ReportedByUnitId)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
entity.HasIndex(e => e.AllocationDistributionId);
|
||||
entity.HasIndex(e => e.ReportedAt);
|
||||
entity.HasIndex(e => e.ReportedByUnitId);
|
||||
});
|
||||
|
||||
// ConsumptionReportChangeRequest 配置
|
||||
modelBuilder.Entity<ConsumptionReportChangeRequest>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.Property(e => e.Reason).IsRequired().HasMaxLength(500);
|
||||
entity.Property(e => e.ProcessComments).HasMaxLength(500);
|
||||
entity.HasOne(e => e.ConsumptionReport)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.ConsumptionReportId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
entity.HasOne(e => e.RequestedByUnit)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.RequestedByUnitId)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
entity.HasOne(e => e.RequestedByUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.RequestedByUserId)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
entity.HasOne(e => e.ProcessedByUnit)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.ProcessedByUnitId)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
entity.HasOne(e => e.ProcessedByUser)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.ProcessedByUserId)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
entity.HasIndex(e => e.ConsumptionReportId);
|
||||
entity.HasIndex(e => e.Status);
|
||||
entity.HasIndex(e => e.RequestedByUnitId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
874
src/MilitaryTrainingManagement/Migrations/20260116180324_AddConsumptionReportChangeRequests.Designer.cs
generated
Normal file
874
src/MilitaryTrainingManagement/Migrations/20260116180324_AddConsumptionReportChangeRequests.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,874 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using MilitaryTrainingManagement.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MilitaryTrainingManagement.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20260116180324_AddConsumptionReportChangeRequests")]
|
||||
partial class AddConsumptionReportChangeRequests
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AllocationDistribution", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal?>("ActualCompletion")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<int>("AllocationId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("ApprovedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ApprovedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsApproved")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ReportedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ReportedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("TargetUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("UnitQuota")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AllocationId");
|
||||
|
||||
b.HasIndex("ApprovedByUserId");
|
||||
|
||||
b.HasIndex("ReportedByUserId");
|
||||
|
||||
b.HasIndex("TargetUnitId");
|
||||
|
||||
b.ToTable("AllocationDistributions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ApprovalRequest", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("OriginalData")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("RequestedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("RequestedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RequestedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("RequestedChanges")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ReviewComments")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime?>("ReviewedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ReviewedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("TargetEntityId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RequestedByUnitId");
|
||||
|
||||
b.HasIndex("RequestedByUserId");
|
||||
|
||||
b.HasIndex("ReviewedByUserId");
|
||||
|
||||
b.ToTable("ApprovalRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AuditLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Action")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("ChangedFields")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("EntityId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("EntityType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("ErrorMessage")
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("nvarchar(2000)");
|
||||
|
||||
b.Property<string>("IpAddress")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<bool>("IsSuccess")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("NewValues")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("OldValues")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int?>("OrganizationalUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("RequestPath")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime>("Timestamp")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("UserAgent")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int?>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Action");
|
||||
|
||||
b.HasIndex("EntityId");
|
||||
|
||||
b.HasIndex("EntityType");
|
||||
|
||||
b.HasIndex("OrganizationalUnitId");
|
||||
|
||||
b.HasIndex("Timestamp");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AuditLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ConsumptionReport", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AllocationDistributionId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("CumulativeAmount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<string>("Remarks")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<decimal>("ReportedAmount")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<DateTime>("ReportedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("ReportedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ReportedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AllocationDistributionId");
|
||||
|
||||
b.HasIndex("ReportedAt");
|
||||
|
||||
b.HasIndex("ReportedByUnitId");
|
||||
|
||||
b.HasIndex("ReportedByUserId");
|
||||
|
||||
b.ToTable("ConsumptionReports");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ConsumptionReportChangeRequest", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("ConsumptionReportId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ProcessComments")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime?>("ProcessedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ProcessedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ProcessedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("RequestType")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("RequestedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("RequestedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RequestedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ConsumptionReportId");
|
||||
|
||||
b.HasIndex("ProcessedByUnitId");
|
||||
|
||||
b.HasIndex("ProcessedByUserId");
|
||||
|
||||
b.HasIndex("RequestedByUnitId");
|
||||
|
||||
b.HasIndex("RequestedByUserId");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
||||
b.ToTable("ConsumptionReportChangeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Category")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("CreatedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("MaterialName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<decimal>("TotalQuota")
|
||||
.HasPrecision(18, 2)
|
||||
.HasColumnType("decimal(18,2)");
|
||||
|
||||
b.Property<string>("Unit")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreatedByUnitId");
|
||||
|
||||
b.ToTable("MaterialAllocations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialCategory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("nvarchar(200)");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int>("SortOrder")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Name")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("MaterialCategories");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("Level")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<int?>("ParentId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ParentId");
|
||||
|
||||
b.ToTable("OrganizationalUnits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.Personnel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Achievements")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("Age")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime?>("ApprovedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ApprovedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ApprovedLevel")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("BirthDate")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ContactInfo")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EducationLevel")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EnlistmentDate")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Ethnicity")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.IsRequired()
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("nvarchar(10)");
|
||||
|
||||
b.Property<decimal?>("Height")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.Property<string>("Hometown")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("IdNumber")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int?>("PendingUpgradeByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PhotoPath")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PoliticalStatus")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Position")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<string>("ProfessionalTitle")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Rank")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("Specialty")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("SubmittedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("SubmittedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("SupportingDocuments")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("TrainingParticipation")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Unit")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApprovedByUnitId");
|
||||
|
||||
b.HasIndex("PendingUpgradeByUnitId");
|
||||
|
||||
b.HasIndex("SubmittedByUnitId");
|
||||
|
||||
b.ToTable("Personnel");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.PersonnelApprovalHistory", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("Action")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Comments")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int?>("NewLevel")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("NewStatus")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("PersonnelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("PreviousLevel")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("PreviousStatus")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("ReviewedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ReviewedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ReviewedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("PersonnelId");
|
||||
|
||||
b.HasIndex("ReviewedByUnitId");
|
||||
|
||||
b.HasIndex("ReviewedByUserId");
|
||||
|
||||
b.ToTable("PersonnelApprovalHistories");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.UserAccount", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("nvarchar(100)");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("OrganizationalUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PlainPassword")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("OrganizationalUnitId");
|
||||
|
||||
b.HasIndex("Username")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("UserAccounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AllocationDistribution", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", "Allocation")
|
||||
.WithMany("Distributions")
|
||||
.HasForeignKey("AllocationId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ApprovedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ApprovedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReportedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "TargetUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("TargetUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Allocation");
|
||||
|
||||
b.Navigation("ApprovedByUser");
|
||||
|
||||
b.Navigation("ReportedByUser");
|
||||
|
||||
b.Navigation("TargetUnit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ApprovalRequest", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "RequestedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "RequestedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReviewedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReviewedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.Navigation("RequestedByUnit");
|
||||
|
||||
b.Navigation("RequestedByUser");
|
||||
|
||||
b.Navigation("ReviewedByUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.AuditLog", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "OrganizationalUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("OrganizationalUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.Navigation("OrganizationalUnit");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ConsumptionReport", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.AllocationDistribution", "AllocationDistribution")
|
||||
.WithMany()
|
||||
.HasForeignKey("AllocationDistributionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ReportedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReportedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AllocationDistribution");
|
||||
|
||||
b.Navigation("ReportedByUnit");
|
||||
|
||||
b.Navigation("ReportedByUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ConsumptionReportChangeRequest", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.ConsumptionReport", "ConsumptionReport")
|
||||
.WithMany()
|
||||
.HasForeignKey("ConsumptionReportId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ProcessedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProcessedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ProcessedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProcessedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "RequestedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "RequestedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ConsumptionReport");
|
||||
|
||||
b.Navigation("ProcessedByUnit");
|
||||
|
||||
b.Navigation("ProcessedByUser");
|
||||
|
||||
b.Navigation("RequestedByUnit");
|
||||
|
||||
b.Navigation("RequestedByUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "CreatedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreatedByUnitId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("CreatedByUnit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "Parent")
|
||||
.WithMany("Children")
|
||||
.HasForeignKey("ParentId")
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
b.Navigation("Parent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.Personnel", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ApprovedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("ApprovedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "PendingUpgradeByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("PendingUpgradeByUnitId");
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "SubmittedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("SubmittedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ApprovedByUnit");
|
||||
|
||||
b.Navigation("PendingUpgradeByUnit");
|
||||
|
||||
b.Navigation("SubmittedByUnit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.PersonnelApprovalHistory", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.Personnel", "Personnel")
|
||||
.WithMany()
|
||||
.HasForeignKey("PersonnelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ReviewedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReviewedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReviewedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReviewedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Personnel");
|
||||
|
||||
b.Navigation("ReviewedByUnit");
|
||||
|
||||
b.Navigation("ReviewedByUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.UserAccount", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "OrganizationalUnit")
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("OrganizationalUnitId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("OrganizationalUnit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
|
||||
{
|
||||
b.Navigation("Distributions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", b =>
|
||||
{
|
||||
b.Navigation("Accounts");
|
||||
|
||||
b.Navigation("Children");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MilitaryTrainingManagement.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddConsumptionReportChangeRequests : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "PendingUpgradeByUnitId",
|
||||
table: "Personnel",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "ReportedByUnitId",
|
||||
table: "ConsumptionReports",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ConsumptionReportChangeRequests",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
ConsumptionReportId = table.Column<int>(type: "int", nullable: false),
|
||||
RequestType = table.Column<int>(type: "int", nullable: false),
|
||||
Reason = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
Status = table.Column<int>(type: "int", nullable: false),
|
||||
RequestedByUnitId = table.Column<int>(type: "int", nullable: false),
|
||||
RequestedByUserId = table.Column<int>(type: "int", nullable: false),
|
||||
RequestedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ProcessedByUnitId = table.Column<int>(type: "int", nullable: true),
|
||||
ProcessedByUserId = table.Column<int>(type: "int", nullable: true),
|
||||
ProcessedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ProcessComments = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ConsumptionReportChangeRequests", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ConsumptionReportChangeRequests_ConsumptionReports_ConsumptionReportId",
|
||||
column: x => x.ConsumptionReportId,
|
||||
principalTable: "ConsumptionReports",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_ConsumptionReportChangeRequests_OrganizationalUnits_ProcessedByUnitId",
|
||||
column: x => x.ProcessedByUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_ConsumptionReportChangeRequests_OrganizationalUnits_RequestedByUnitId",
|
||||
column: x => x.RequestedByUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_ConsumptionReportChangeRequests_UserAccounts_ProcessedByUserId",
|
||||
column: x => x.ProcessedByUserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_ConsumptionReportChangeRequests_UserAccounts_RequestedByUserId",
|
||||
column: x => x.RequestedByUserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Personnel_PendingUpgradeByUnitId",
|
||||
table: "Personnel",
|
||||
column: "PendingUpgradeByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ConsumptionReports_ReportedByUnitId",
|
||||
table: "ConsumptionReports",
|
||||
column: "ReportedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ConsumptionReportChangeRequests_ConsumptionReportId",
|
||||
table: "ConsumptionReportChangeRequests",
|
||||
column: "ConsumptionReportId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ConsumptionReportChangeRequests_ProcessedByUnitId",
|
||||
table: "ConsumptionReportChangeRequests",
|
||||
column: "ProcessedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ConsumptionReportChangeRequests_ProcessedByUserId",
|
||||
table: "ConsumptionReportChangeRequests",
|
||||
column: "ProcessedByUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ConsumptionReportChangeRequests_RequestedByUnitId",
|
||||
table: "ConsumptionReportChangeRequests",
|
||||
column: "RequestedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ConsumptionReportChangeRequests_RequestedByUserId",
|
||||
table: "ConsumptionReportChangeRequests",
|
||||
column: "RequestedByUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ConsumptionReportChangeRequests_Status",
|
||||
table: "ConsumptionReportChangeRequests",
|
||||
column: "Status");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ConsumptionReports_OrganizationalUnits_ReportedByUnitId",
|
||||
table: "ConsumptionReports",
|
||||
column: "ReportedByUnitId",
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Personnel_OrganizationalUnits_PendingUpgradeByUnitId",
|
||||
table: "Personnel",
|
||||
column: "PendingUpgradeByUnitId",
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ConsumptionReports_OrganizationalUnits_ReportedByUnitId",
|
||||
table: "ConsumptionReports");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Personnel_OrganizationalUnits_PendingUpgradeByUnitId",
|
||||
table: "Personnel");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ConsumptionReportChangeRequests");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Personnel_PendingUpgradeByUnitId",
|
||||
table: "Personnel");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_ConsumptionReports_ReportedByUnitId",
|
||||
table: "ConsumptionReports");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "PendingUpgradeByUnitId",
|
||||
table: "Personnel");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ReportedByUnitId",
|
||||
table: "ConsumptionReports");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -236,6 +236,9 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
b.Property<DateTime>("ReportedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("ReportedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("ReportedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
|
@ -245,11 +248,74 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
|
||||
b.HasIndex("ReportedAt");
|
||||
|
||||
b.HasIndex("ReportedByUnitId");
|
||||
|
||||
b.HasIndex("ReportedByUserId");
|
||||
|
||||
b.ToTable("ConsumptionReports");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ConsumptionReportChangeRequest", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("ConsumptionReportId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ProcessComments")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<DateTime?>("ProcessedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int?>("ProcessedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ProcessedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("nvarchar(500)");
|
||||
|
||||
b.Property<int>("RequestType")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("RequestedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("RequestedByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RequestedByUserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ConsumptionReportId");
|
||||
|
||||
b.HasIndex("ProcessedByUnitId");
|
||||
|
||||
b.HasIndex("ProcessedByUserId");
|
||||
|
||||
b.HasIndex("RequestedByUnitId");
|
||||
|
||||
b.HasIndex("RequestedByUserId");
|
||||
|
||||
b.HasIndex("Status");
|
||||
|
||||
b.ToTable("ConsumptionReportChangeRequests");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
|
@ -412,6 +478,9 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<int?>("PendingUpgradeByUnitId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PhotoPath")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
|
|
@ -456,6 +525,8 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
|
||||
b.HasIndex("ApprovedByUnitId");
|
||||
|
||||
b.HasIndex("PendingUpgradeByUnitId");
|
||||
|
||||
b.HasIndex("SubmittedByUnitId");
|
||||
|
||||
b.ToTable("Personnel");
|
||||
|
|
@ -641,6 +712,12 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ReportedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ReportedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportedByUserId")
|
||||
|
|
@ -649,9 +726,52 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
|
||||
b.Navigation("AllocationDistribution");
|
||||
|
||||
b.Navigation("ReportedByUnit");
|
||||
|
||||
b.Navigation("ReportedByUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.ConsumptionReportChangeRequest", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.ConsumptionReport", "ConsumptionReport")
|
||||
.WithMany()
|
||||
.HasForeignKey("ConsumptionReportId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "ProcessedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProcessedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "ProcessedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("ProcessedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "RequestedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.UserAccount", "RequestedByUser")
|
||||
.WithMany()
|
||||
.HasForeignKey("RequestedByUserId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ConsumptionReport");
|
||||
|
||||
b.Navigation("ProcessedByUnit");
|
||||
|
||||
b.Navigation("ProcessedByUser");
|
||||
|
||||
b.Navigation("RequestedByUnit");
|
||||
|
||||
b.Navigation("RequestedByUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("MilitaryTrainingManagement.Models.Entities.MaterialAllocation", b =>
|
||||
{
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "CreatedByUnit")
|
||||
|
|
@ -680,6 +800,10 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
.HasForeignKey("ApprovedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "PendingUpgradeByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("PendingUpgradeByUnitId");
|
||||
|
||||
b.HasOne("MilitaryTrainingManagement.Models.Entities.OrganizationalUnit", "SubmittedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("SubmittedByUnitId")
|
||||
|
|
@ -688,6 +812,8 @@ namespace MilitaryTrainingManagement.Migrations
|
|||
|
||||
b.Navigation("ApprovedByUnit");
|
||||
|
||||
b.Navigation("PendingUpgradeByUnit");
|
||||
|
||||
b.Navigation("SubmittedByUnit");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,12 @@ public class ConsumptionReport
|
|||
[ForeignKey(nameof(AllocationDistributionId))]
|
||||
public AllocationDistribution AllocationDistribution { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 配额分配(别名,用于兼容)
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public AllocationDistribution Distribution => AllocationDistribution;
|
||||
|
||||
/// <summary>
|
||||
/// 本次上报数量
|
||||
/// </summary>
|
||||
|
|
@ -55,6 +61,18 @@ public class ConsumptionReport
|
|||
[ForeignKey(nameof(ReportedByUserId))]
|
||||
public UserAccount ReportedByUser { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 上报单位ID
|
||||
/// </summary>
|
||||
[Required]
|
||||
public int ReportedByUnitId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上报单位
|
||||
/// </summary>
|
||||
[ForeignKey(nameof(ReportedByUnitId))]
|
||||
public OrganizationalUnit ReportedByUnit { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 上报时间
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
using MilitaryTrainingManagement.Models.Enums;
|
||||
|
||||
namespace MilitaryTrainingManagement.Models.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 消耗记录删改申请
|
||||
/// </summary>
|
||||
public class ConsumptionReportChangeRequest
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的消耗记录ID
|
||||
/// </summary>
|
||||
public int ConsumptionReportId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 关联的消耗记录
|
||||
/// </summary>
|
||||
public ConsumptionReport ConsumptionReport { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 申请类型:Delete(删除)或 Modify(修改)
|
||||
/// </summary>
|
||||
public ChangeRequestType RequestType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 申请原因
|
||||
/// </summary>
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 申请状态
|
||||
/// </summary>
|
||||
public ChangeRequestStatus Status { get; set; } = ChangeRequestStatus.Pending;
|
||||
|
||||
/// <summary>
|
||||
/// 申请单位ID
|
||||
/// </summary>
|
||||
public int RequestedByUnitId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 申请单位
|
||||
/// </summary>
|
||||
public OrganizationalUnit RequestedByUnit { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 申请人用户ID
|
||||
/// </summary>
|
||||
public int RequestedByUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 申请人
|
||||
/// </summary>
|
||||
public UserAccount RequestedByUser { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 申请时间
|
||||
/// </summary>
|
||||
public DateTime RequestedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary>
|
||||
/// 处理单位ID
|
||||
/// </summary>
|
||||
public int? ProcessedByUnitId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理单位
|
||||
/// </summary>
|
||||
public OrganizationalUnit? ProcessedByUnit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理人用户ID
|
||||
/// </summary>
|
||||
public int? ProcessedByUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理人
|
||||
/// </summary>
|
||||
public UserAccount? ProcessedByUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理时间
|
||||
/// </summary>
|
||||
public DateTime? ProcessedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理意见
|
||||
/// </summary>
|
||||
public string? ProcessComments { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
namespace MilitaryTrainingManagement.Models.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// 删改申请状态
|
||||
/// </summary>
|
||||
public enum ChangeRequestStatus
|
||||
{
|
||||
/// <summary>待处理</summary>
|
||||
Pending = 1,
|
||||
/// <summary>已同意</summary>
|
||||
Approved = 2,
|
||||
/// <summary>已拒绝</summary>
|
||||
Rejected = 3
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
namespace MilitaryTrainingManagement.Models.Enums;
|
||||
|
||||
/// <summary>
|
||||
/// 删改申请类型
|
||||
/// </summary>
|
||||
public enum ChangeRequestType
|
||||
{
|
||||
/// <summary>删除</summary>
|
||||
Delete = 1,
|
||||
/// <summary>修改</summary>
|
||||
Modify = 2
|
||||
}
|
||||
|
|
@ -293,6 +293,62 @@ using (var scope = app.Services.CreateScope())
|
|||
Console.WriteLine($"创建 ConsumptionReports 表时出错: {ex.Message}");
|
||||
}
|
||||
|
||||
// 添加 ConsumptionReports.ReportedByUnitId 列(如果不存在)
|
||||
try
|
||||
{
|
||||
context.Database.ExecuteSqlRaw(@"
|
||||
IF NOT EXISTS (SELECT * FROM sys.columns WHERE object_id = OBJECT_ID('ConsumptionReports') AND name = 'ReportedByUnitId')
|
||||
ALTER TABLE ConsumptionReports ADD ReportedByUnitId INT NOT NULL DEFAULT 1;
|
||||
");
|
||||
Console.WriteLine("ConsumptionReports.ReportedByUnitId 列检查完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"添加 ConsumptionReports.ReportedByUnitId 列时出错: {ex.Message}");
|
||||
}
|
||||
|
||||
// 创建 ConsumptionReportChangeRequests 表(如果不存在)
|
||||
try
|
||||
{
|
||||
context.Database.ExecuteSqlRaw(@"
|
||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'ConsumptionReportChangeRequests')
|
||||
BEGIN
|
||||
CREATE TABLE ConsumptionReportChangeRequests (
|
||||
Id INT IDENTITY(1,1) PRIMARY KEY,
|
||||
ConsumptionReportId INT NOT NULL,
|
||||
RequestType INT NOT NULL,
|
||||
Reason NVARCHAR(500) NOT NULL,
|
||||
Status INT NOT NULL,
|
||||
RequestedByUnitId INT NOT NULL,
|
||||
RequestedByUserId INT NOT NULL,
|
||||
RequestedAt DATETIME2 NOT NULL,
|
||||
ProcessedByUnitId INT NULL,
|
||||
ProcessedByUserId INT NULL,
|
||||
ProcessedAt DATETIME2 NULL,
|
||||
ProcessComments NVARCHAR(500) NULL,
|
||||
CONSTRAINT FK_ConsumptionReportChangeRequests_ConsumptionReports
|
||||
FOREIGN KEY (ConsumptionReportId) REFERENCES ConsumptionReports(Id) ON DELETE CASCADE,
|
||||
CONSTRAINT FK_ConsumptionReportChangeRequests_RequestedByUnit
|
||||
FOREIGN KEY (RequestedByUnitId) REFERENCES OrganizationalUnits(Id),
|
||||
CONSTRAINT FK_ConsumptionReportChangeRequests_RequestedByUser
|
||||
FOREIGN KEY (RequestedByUserId) REFERENCES UserAccounts(Id),
|
||||
CONSTRAINT FK_ConsumptionReportChangeRequests_ProcessedByUnit
|
||||
FOREIGN KEY (ProcessedByUnitId) REFERENCES OrganizationalUnits(Id),
|
||||
CONSTRAINT FK_ConsumptionReportChangeRequests_ProcessedByUser
|
||||
FOREIGN KEY (ProcessedByUserId) REFERENCES UserAccounts(Id)
|
||||
);
|
||||
CREATE INDEX IX_ConsumptionReportChangeRequests_ConsumptionReportId ON ConsumptionReportChangeRequests(ConsumptionReportId);
|
||||
CREATE INDEX IX_ConsumptionReportChangeRequests_Status ON ConsumptionReportChangeRequests(Status);
|
||||
CREATE INDEX IX_ConsumptionReportChangeRequests_RequestedByUnitId ON ConsumptionReportChangeRequests(RequestedByUnitId);
|
||||
END
|
||||
");
|
||||
Console.WriteLine("ConsumptionReportChangeRequests 表检查完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"创建 ConsumptionReportChangeRequests 表时出错: {ex.Message}");
|
||||
}
|
||||
|
||||
// 如果没有物资类别,创建默认类别
|
||||
if (!context.MaterialCategories.Any())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -316,6 +316,7 @@ public class AllocationService : IAllocationService
|
|||
CumulativeAmount = actualCompletion,
|
||||
Remarks = remarks,
|
||||
ReportedByUserId = userId,
|
||||
ReportedByUnitId = unitId,
|
||||
ReportedAt = DateTime.UtcNow
|
||||
};
|
||||
_context.ConsumptionReports.Add(consumptionReport);
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ public class PersonnelService : IPersonnelService
|
|||
};
|
||||
}
|
||||
|
||||
public async Task<Personnel> RejectAsync(int personnelId, int reviewedByUserId)
|
||||
public async Task<Personnel> RejectAsync(int personnelId, int reviewedByUserId, int reviewedByUnitId, string? comments = null)
|
||||
{
|
||||
var personnel = await _context.Personnel.FindAsync(personnelId);
|
||||
if (personnel == null)
|
||||
|
|
@ -193,7 +193,7 @@ public class PersonnelService : IPersonnelService
|
|||
// 记录审批历史
|
||||
await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.Rejected,
|
||||
previousStatus, PersonnelStatus.Rejected, null, null,
|
||||
reviewedByUserId, null, "审批拒绝");
|
||||
reviewedByUserId, reviewedByUnitId, comments ?? "审批拒绝");
|
||||
|
||||
_logger.LogInformation("人员 {PersonnelId} 已被用户 {UserId} 拒绝", personnelId, reviewedByUserId);
|
||||
|
||||
|
|
@ -532,7 +532,7 @@ public class PersonnelService : IPersonnelService
|
|||
return approvedPersonnel;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Personnel>> BatchRejectPersonnelAsync(int[] personnelIds, int reviewedByUserId, string reason)
|
||||
public async Task<IEnumerable<Personnel>> BatchRejectPersonnelAsync(int[] personnelIds, int reviewedByUserId, int reviewedByUnitId, string reason)
|
||||
{
|
||||
var rejectedPersonnel = new List<Personnel>();
|
||||
|
||||
|
|
@ -540,13 +540,8 @@ public class PersonnelService : IPersonnelService
|
|||
{
|
||||
try
|
||||
{
|
||||
var personnel = await RejectAsync(personnelId, reviewedByUserId);
|
||||
var personnel = await RejectAsync(personnelId, reviewedByUserId, reviewedByUnitId, reason);
|
||||
rejectedPersonnel.Add(personnel);
|
||||
|
||||
// 记录审批历史
|
||||
await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.Rejected,
|
||||
PersonnelStatus.Pending, PersonnelStatus.Rejected, null, null,
|
||||
reviewedByUserId, null, reason);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public interface IPersonnelService
|
|||
Task<Personnel> CreateAsync(Personnel personnel);
|
||||
Task<Personnel> UpdateAsync(Personnel personnel);
|
||||
Task<Personnel> ApproveAsync(int personnelId, int approvedByUnitId, PersonnelLevel? level = null);
|
||||
Task<Personnel> RejectAsync(int personnelId, int reviewedByUserId);
|
||||
Task<Personnel> RejectAsync(int personnelId, int reviewedByUserId, int reviewedByUnitId, string? comments = null);
|
||||
Task DeleteAsync(int id);
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -64,7 +64,7 @@ public interface IPersonnelService
|
|||
/// <summary>
|
||||
/// 批量拒绝人员
|
||||
/// </summary>
|
||||
Task<IEnumerable<Personnel>> BatchRejectPersonnelAsync(int[] personnelIds, int reviewedByUserId, string reason);
|
||||
Task<IEnumerable<Personnel>> BatchRejectPersonnelAsync(int[] personnelIds, int reviewedByUserId, int reviewedByUnitId, string reason);
|
||||
|
||||
/// <summary>
|
||||
/// 获取人员审批历史
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ export interface ConsumptionReport {
|
|||
cumulativeAmount: number
|
||||
remarks?: string
|
||||
reportedByUserName?: string
|
||||
reportedByUnitId?: number
|
||||
reportedAt: string
|
||||
}
|
||||
|
||||
|
|
@ -76,3 +77,68 @@ export interface UnitReportSummary {
|
|||
reportCount: number
|
||||
lastReportedAt?: string
|
||||
}
|
||||
|
||||
// 消耗记录删改申请相关
|
||||
export interface ChangeRequest {
|
||||
id: number
|
||||
consumptionReportId: number
|
||||
requestType: 'Delete' | 'Modify'
|
||||
reason: string
|
||||
status: 'Pending' | 'Approved' | 'Rejected'
|
||||
requestedAt: string
|
||||
requestedByUnitName?: string
|
||||
requestedByUserName?: string
|
||||
processedAt?: string
|
||||
processedByUnitName?: string
|
||||
processComments?: string
|
||||
consumptionReport?: {
|
||||
id: number
|
||||
reportedAmount: number
|
||||
reportedAt: string
|
||||
remarks?: string
|
||||
materialName?: string
|
||||
unit?: string
|
||||
}
|
||||
}
|
||||
|
||||
export const changeRequestsApi = {
|
||||
// 创建删改申请
|
||||
async create(data: { consumptionReportId: number; requestType: 'Delete' | 'Modify'; reason: string }): Promise<{ message: string; id: number }> {
|
||||
const response = await apiClient.post<{ message: string; id: number }>('/ConsumptionChangeRequests', {
|
||||
consumptionReportId: data.consumptionReportId,
|
||||
requestType: data.requestType === 'Delete' ? 1 : 2,
|
||||
reason: data.reason
|
||||
})
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 获取待处理的申请(上级查看下级的)
|
||||
async getPending(): Promise<ChangeRequest[]> {
|
||||
const response = await apiClient.get<ChangeRequest[]>('/ConsumptionChangeRequests/pending')
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 获取本单位的申请
|
||||
async getMy(): Promise<ChangeRequest[]> {
|
||||
const response = await apiClient.get<ChangeRequest[]>('/ConsumptionChangeRequests/my')
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 处理申请
|
||||
async process(id: number, data: { approved: boolean; comments?: string }): Promise<{ message: string }> {
|
||||
const response = await apiClient.post<{ message: string }>(`/ConsumptionChangeRequests/${id}/process`, data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 修改消耗记录
|
||||
async modify(id: number, data: { newAmount: number; newRemarks?: string }): Promise<{ message: string }> {
|
||||
const response = await apiClient.post<{ message: string }>(`/ConsumptionChangeRequests/${id}/modify`, data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 检查是否有待处理的申请
|
||||
async checkPending(consumptionReportId: number): Promise<{ hasPendingRequest: boolean }> {
|
||||
const response = await apiClient.get<{ hasPendingRequest: boolean }>(`/ConsumptionChangeRequests/check/${consumptionReportId}`)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
export { authApi } from './auth'
|
||||
export { organizationsApi } from './organizations'
|
||||
export { allocationsApi, type UnitReportSummary } from './allocations'
|
||||
export { allocationsApi, changeRequestsApi, type UnitReportSummary, type ConsumptionReport, type ChangeRequest } from './allocations'
|
||||
export { materialCategoriesApi } from './materialCategories'
|
||||
export { reportsApi } from './reports'
|
||||
export { personnelApi } from './personnel'
|
||||
|
|
|
|||
|
|
@ -81,5 +81,27 @@ export const personnelApi = {
|
|||
async directUpgrade(personnelId: number): Promise<Personnel> {
|
||||
const response = await apiClient.post<Personnel>(`/personnel/${personnelId}/direct-upgrade`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
// 获取审批历史
|
||||
async getApprovalHistory(personnelId: number): Promise<PersonnelApprovalHistory[]> {
|
||||
const response = await apiClient.get<PersonnelApprovalHistory[]>(`/personnel/${personnelId}/approval-history`)
|
||||
return response.data
|
||||
}
|
||||
}
|
||||
|
||||
// 审批历史类型
|
||||
export interface PersonnelApprovalHistory {
|
||||
id: number
|
||||
personnelId: number
|
||||
action: string
|
||||
previousStatus: string | null
|
||||
newStatus: string
|
||||
previousLevel: string | null
|
||||
newLevel: string | null
|
||||
reviewedByUserId: number
|
||||
reviewedByUnitId: number | null
|
||||
reviewedByUnitName?: string
|
||||
comments: string | null
|
||||
reviewedAt: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
</template>
|
||||
<el-menu-item index="/allocations">配额列表</el-menu-item>
|
||||
<el-menu-item v-if="authStore.canCreateAllocations" index="/allocations/create">创建配额</el-menu-item>
|
||||
<el-menu-item index="/allocations/change-requests">删改申请</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-sub-menu index="personnel">
|
||||
|
|
|
|||
|
|
@ -59,6 +59,12 @@ const routes: RouteRecordRaw[] = [
|
|||
component: () => import('@/views/allocations/AllocationReport.vue'),
|
||||
meta: { title: '上报消耗' }
|
||||
},
|
||||
{
|
||||
path: 'allocations/change-requests',
|
||||
name: 'ChangeRequests',
|
||||
component: () => import('@/views/allocations/ChangeRequestList.vue'),
|
||||
meta: { title: '删改申请' }
|
||||
},
|
||||
{
|
||||
path: 'reports',
|
||||
name: 'Reports',
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ export const useAuthStore = defineStore('auth', () => {
|
|||
isAuthenticated,
|
||||
organizationalLevel: computed(() => user.value?.organizationalLevel),
|
||||
organizationalLevelNum,
|
||||
unitId: computed(() => user.value?.organizationalUnitId),
|
||||
canManageSubordinates,
|
||||
canCreateAllocations,
|
||||
canApprove,
|
||||
|
|
|
|||
|
|
@ -123,17 +123,6 @@
|
|||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="描述" :span="2">{{ selectedLog.description || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="请求路径" :span="2">{{ selectedLog.requestPath || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="User Agent" :span="2">{{ selectedLog.userAgent || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item v-if="selectedLog.oldValues" label="原始值" :span="2">
|
||||
<pre class="json-content">{{ formatJson(selectedLog.oldValues) }}</pre>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="selectedLog.newValues" label="新值" :span="2">
|
||||
<pre class="json-content">{{ formatJson(selectedLog.newValues) }}</pre>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="selectedLog.changedFields" label="变更字段" :span="2">
|
||||
<pre class="json-content">{{ formatJson(selectedLog.changedFields) }}</pre>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item v-if="selectedLog.errorMessage" label="错误信息" :span="2">
|
||||
<el-text type="danger">{{ selectedLog.errorMessage }}</el-text>
|
||||
</el-descriptions-item>
|
||||
|
|
|
|||
|
|
@ -596,6 +596,8 @@ function getTotalConsumed(): number {
|
|||
}
|
||||
|
||||
function canReportConsumption(distribution: AllocationDistribution): boolean {
|
||||
// 师级(Division)是配额创建者,不需要上报消耗
|
||||
if (authStore.organizationalLevelNum === 1) return false
|
||||
// 当前用户所属单位或其上级单位的分配都可以上报消耗
|
||||
if (!authStore.user) return false
|
||||
// 营部及以下账号可以上报所属团的配额
|
||||
|
|
|
|||
|
|
@ -188,9 +188,84 @@
|
|||
<span class="remarks-text">{{ row.remarks || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="canRequestChange(row)"
|
||||
type="warning"
|
||||
size="small"
|
||||
link
|
||||
@click="openChangeRequestDialog(row)"
|
||||
>
|
||||
申请删改
|
||||
</el-button>
|
||||
<el-tag v-else-if="row.hasPendingRequest" type="info" size="small">
|
||||
申请中
|
||||
</el-tag>
|
||||
<span v-else class="no-action">-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-else description="暂无上报记录" :image-size="80" />
|
||||
</div>
|
||||
|
||||
<!-- 申请删改对话框 -->
|
||||
<el-dialog
|
||||
v-model="changeRequestDialogVisible"
|
||||
title="申请删改"
|
||||
width="500px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<div v-if="selectedReport" class="change-request-info">
|
||||
<el-descriptions :column="1" border size="small">
|
||||
<el-descriptions-item label="上报时间">
|
||||
{{ formatDate(selectedReport.reportedAt) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="上报数量">
|
||||
{{ formatNumber(selectedReport.reportedAmount) }} {{ allocation?.unit }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="备注">
|
||||
{{ selectedReport.remarks || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<el-form
|
||||
ref="changeRequestFormRef"
|
||||
:model="changeRequestForm"
|
||||
:rules="changeRequestRules"
|
||||
label-width="100px"
|
||||
style="margin-top: 20px"
|
||||
>
|
||||
<el-form-item label="申请类型" prop="requestType">
|
||||
<el-radio-group v-model="changeRequestForm.requestType" class="change-request-radio-group">
|
||||
<el-radio value="Delete">
|
||||
<el-tag type="danger" size="small">删除</el-tag>
|
||||
<span class="radio-desc">申请删除此条记录</span>
|
||||
</el-radio>
|
||||
<el-radio value="Modify">
|
||||
<el-tag type="warning" size="small">修改</el-tag>
|
||||
<span class="radio-desc">申请修改此条记录</span>
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="申请原因" prop="reason">
|
||||
<el-input
|
||||
v-model="changeRequestForm.reason"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入申请原因"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="changeRequestDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="changeRequestSubmitting" @click="submitChangeRequest">
|
||||
提交申请
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
<el-empty v-else description="未找到配额分配信息" />
|
||||
|
|
@ -203,10 +278,15 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
|||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
|
||||
import { DocumentAdd, Back, Check, Close, Clock } from '@element-plus/icons-vue'
|
||||
import { allocationsApi, type ConsumptionReport } from '@/api'
|
||||
import { allocationsApi, changeRequestsApi, type ConsumptionReport } from '@/api'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import type { MaterialAllocation, AllocationDistribution } from '@/types'
|
||||
|
||||
interface ConsumptionReportWithPending extends ConsumptionReport {
|
||||
hasPendingRequest?: boolean
|
||||
reportedByUnitId?: number
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const authStore = useAuthStore()
|
||||
|
|
@ -215,9 +295,29 @@ const loading = ref(false)
|
|||
const submitting = ref(false)
|
||||
const allocation = ref<MaterialAllocation | null>(null)
|
||||
const distribution = ref<AllocationDistribution | null>(null)
|
||||
const consumptionReports = ref<ConsumptionReport[]>([])
|
||||
const consumptionReports = ref<ConsumptionReportWithPending[]>([])
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
// 申请删改相关
|
||||
const changeRequestDialogVisible = ref(false)
|
||||
const changeRequestSubmitting = ref(false)
|
||||
const selectedReport = ref<ConsumptionReportWithPending | null>(null)
|
||||
const changeRequestFormRef = ref<FormInstance>()
|
||||
const changeRequestForm = reactive({
|
||||
requestType: 'Delete' as 'Delete' | 'Modify',
|
||||
reason: ''
|
||||
})
|
||||
|
||||
const changeRequestRules: FormRules = {
|
||||
requestType: [
|
||||
{ required: true, message: '请选择申请类型', trigger: 'change' }
|
||||
],
|
||||
reason: [
|
||||
{ required: true, message: '请输入申请原因', trigger: 'blur' },
|
||||
{ min: 5, message: '申请原因至少5个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
|
||||
const form = reactive({
|
||||
actualCompletion: 0,
|
||||
remarks: '',
|
||||
|
|
@ -431,12 +531,70 @@ async function loadData() {
|
|||
|
||||
async function loadConsumptionReports(distributionId: number) {
|
||||
try {
|
||||
consumptionReports.value = await allocationsApi.getConsumptionReports(distributionId)
|
||||
const reports = await allocationsApi.getConsumptionReports(distributionId)
|
||||
// 检查每条记录是否有待处理的申请
|
||||
consumptionReports.value = await Promise.all(
|
||||
reports.map(async (report) => {
|
||||
try {
|
||||
const { hasPendingRequest } = await changeRequestsApi.checkPending(report.id)
|
||||
return { ...report, hasPendingRequest }
|
||||
} catch {
|
||||
return { ...report, hasPendingRequest: false }
|
||||
}
|
||||
})
|
||||
)
|
||||
} catch {
|
||||
console.error('加载上报历史失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否可以申请删改(只有本单位的记录才能申请)
|
||||
function canRequestChange(report: ConsumptionReportWithPending): boolean {
|
||||
// 如果已有待处理的申请,不能再申请
|
||||
if (report.hasPendingRequest) return false
|
||||
// 只有本单位的记录才能申请删改
|
||||
// 通过 reportedByUnitId 判断,如果没有这个字段,则通过 reportedByUserName 判断
|
||||
// 这里简化处理:如果记录的上报单位是当前用户的单位,则可以申请
|
||||
return report.reportedByUnitId === authStore.unitId
|
||||
}
|
||||
|
||||
// 打开申请删改对话框
|
||||
function openChangeRequestDialog(report: ConsumptionReportWithPending) {
|
||||
selectedReport.value = report
|
||||
changeRequestForm.requestType = 'Delete'
|
||||
changeRequestForm.reason = ''
|
||||
changeRequestDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 提交申请删改
|
||||
async function submitChangeRequest() {
|
||||
if (!changeRequestFormRef.value || !selectedReport.value) return
|
||||
|
||||
try {
|
||||
await changeRequestFormRef.value.validate()
|
||||
|
||||
changeRequestSubmitting.value = true
|
||||
|
||||
await changeRequestsApi.create({
|
||||
consumptionReportId: selectedReport.value.id,
|
||||
requestType: changeRequestForm.requestType,
|
||||
reason: changeRequestForm.reason
|
||||
})
|
||||
|
||||
ElMessage.success('申请已提交,等待上级审批')
|
||||
changeRequestDialogVisible.value = false
|
||||
|
||||
// 刷新上报历史
|
||||
if (distribution.value) {
|
||||
await loadConsumptionReports(distribution.value.id)
|
||||
}
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.message || '提交申请失败')
|
||||
} finally {
|
||||
changeRequestSubmitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
|
|
@ -629,16 +787,25 @@ onMounted(() => {
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
:deep(.el-radio-group) {
|
||||
.change-request-radio-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
:deep(.el-radio) {
|
||||
.change-request-radio-group :deep(.el-radio) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: auto;
|
||||
padding: 8px 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.no-action {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.change-request-info {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
369
src/frontend/src/views/allocations/ChangeRequestList.vue
Normal file
369
src/frontend/src/views/allocations/ChangeRequestList.vue
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
<template>
|
||||
<div class="change-request-list">
|
||||
<el-card shadow="hover">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div class="header-title">
|
||||
<el-icon class="title-icon" :size="22"><Document /></el-icon>
|
||||
<span>消耗记录删改申请</span>
|
||||
</div>
|
||||
<el-radio-group v-model="viewMode" size="small">
|
||||
<el-radio-button value="pending">待处理</el-radio-button>
|
||||
<el-radio-button value="my">我的申请</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-if="loading" class="loading-container">
|
||||
<el-skeleton :rows="6" animated />
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<!-- 待处理申请列表(上级查看下级的) -->
|
||||
<div v-if="viewMode === 'pending'">
|
||||
<el-empty v-if="pendingRequests.length === 0" description="暂无待处理的申请" />
|
||||
<el-table v-else :data="pendingRequests" stripe>
|
||||
<el-table-column label="申请时间" width="170" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.requestedAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请单位" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.requestedByUnitName }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请类型" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.requestType === 'Delete' ? 'danger' : 'warning'" size="small">
|
||||
{{ row.requestType === 'Delete' ? '删除' : '修改' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="物资名称" width="120">
|
||||
<template #default="{ row }">
|
||||
{{ row.consumptionReport?.materialName || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上报数量" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.consumptionReport?.reportedAmount }} {{ row.consumptionReport?.unit }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请原因" min-width="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.reason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="success" size="small" @click="handleApprove(row)">
|
||||
同意
|
||||
</el-button>
|
||||
<el-button type="danger" size="small" @click="handleReject(row)">
|
||||
拒绝
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 我的申请列表 -->
|
||||
<div v-else>
|
||||
<el-empty v-if="myRequests.length === 0" description="暂无申请记录" />
|
||||
<el-table v-else :data="myRequests" stripe>
|
||||
<el-table-column label="申请时间" width="170" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.requestedAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请类型" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.requestType === 'Delete' ? 'danger' : 'warning'" size="small">
|
||||
{{ row.requestType === 'Delete' ? '删除' : '修改' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="申请原因" min-width="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.reason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getStatusTagType(row.status)" size="small">
|
||||
{{ getStatusText(row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="处理时间" width="170" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.processedAt ? formatDate(row.processedAt) : '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="处理单位" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ row.processedByUnitName || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="处理意见" min-width="150">
|
||||
<template #default="{ row }">
|
||||
{{ row.processComments || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</el-card>
|
||||
|
||||
<!-- 拒绝原因对话框 -->
|
||||
<el-dialog v-model="rejectDialogVisible" title="拒绝申请" width="400px">
|
||||
<el-form :model="rejectForm" label-width="80px">
|
||||
<el-form-item label="拒绝原因">
|
||||
<el-input
|
||||
v-model="rejectForm.comments"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入拒绝原因(可选)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="rejectDialogVisible = false">取消</el-button>
|
||||
<el-button type="danger" :loading="processing" @click="confirmReject">
|
||||
确认拒绝
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 修改数据对话框 -->
|
||||
<el-dialog v-model="modifyDialogVisible" title="修改消耗记录" width="500px">
|
||||
<div v-if="selectedRequest?.consumptionReport" class="modify-info">
|
||||
<el-descriptions :column="1" border size="small">
|
||||
<el-descriptions-item label="物资名称">
|
||||
{{ selectedRequest.consumptionReport.materialName }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="原上报数量">
|
||||
{{ selectedRequest.consumptionReport.reportedAmount }} {{ selectedRequest.consumptionReport.unit }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="原备注">
|
||||
{{ selectedRequest.consumptionReport.remarks || '-' }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
<el-form :model="modifyForm" label-width="100px" style="margin-top: 20px">
|
||||
<el-form-item label="新数量" required>
|
||||
<el-input-number
|
||||
v-model="modifyForm.newAmount"
|
||||
:min="0"
|
||||
:precision="2"
|
||||
style="width: 200px"
|
||||
/>
|
||||
<span style="margin-left: 8px">{{ selectedRequest?.consumptionReport?.unit }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="新备注">
|
||||
<el-input
|
||||
v-model="modifyForm.newRemarks"
|
||||
type="textarea"
|
||||
:rows="2"
|
||||
placeholder="请输入新备注(可选)"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="modifyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="processing" @click="confirmModify">
|
||||
确认修改
|
||||
</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Document } from '@element-plus/icons-vue'
|
||||
import { changeRequestsApi, type ChangeRequest } from '@/api'
|
||||
|
||||
const loading = ref(false)
|
||||
const processing = ref(false)
|
||||
const viewMode = ref<'pending' | 'my'>('pending')
|
||||
const pendingRequests = ref<ChangeRequest[]>([])
|
||||
const myRequests = ref<ChangeRequest[]>([])
|
||||
|
||||
const rejectDialogVisible = ref(false)
|
||||
const modifyDialogVisible = ref(false)
|
||||
const selectedRequest = ref<ChangeRequest | null>(null)
|
||||
const rejectForm = reactive({ comments: '' })
|
||||
const modifyForm = reactive({ newAmount: 0, newRemarks: '' })
|
||||
|
||||
function formatDate(dateStr: string): string {
|
||||
return new Date(dateStr).toLocaleString('zh-CN')
|
||||
}
|
||||
|
||||
function getStatusTagType(status: string): 'success' | 'warning' | 'danger' | 'info' {
|
||||
switch (status) {
|
||||
case 'Approved': return 'success'
|
||||
case 'Rejected': return 'danger'
|
||||
case 'Pending': return 'warning'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
function getStatusText(status: string): string {
|
||||
switch (status) {
|
||||
case 'Approved': return '已同意'
|
||||
case 'Rejected': return '已拒绝'
|
||||
case 'Pending': return '待处理'
|
||||
default: return status
|
||||
}
|
||||
}
|
||||
|
||||
async function loadPendingRequests() {
|
||||
try {
|
||||
pendingRequests.value = await changeRequestsApi.getPending()
|
||||
} catch (error: any) {
|
||||
console.error('加载待处理申请失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMyRequests() {
|
||||
try {
|
||||
myRequests.value = await changeRequestsApi.getMy()
|
||||
} catch (error: any) {
|
||||
console.error('加载我的申请失败', error)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true
|
||||
try {
|
||||
await Promise.all([loadPendingRequests(), loadMyRequests()])
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function handleApprove(request: ChangeRequest) {
|
||||
if (request.requestType === 'Delete') {
|
||||
// 删除类型直接确认
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
'同意后将自动删除该消耗记录,确定同意吗?',
|
||||
'确认同意',
|
||||
{ type: 'warning' }
|
||||
)
|
||||
processing.value = true
|
||||
await changeRequestsApi.process(request.id, { approved: true })
|
||||
ElMessage.success('已同意删除申请')
|
||||
await loadData()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error.response?.data?.message || '操作失败')
|
||||
}
|
||||
} finally {
|
||||
processing.value = false
|
||||
}
|
||||
} else {
|
||||
// 修改类型需要填写新数据
|
||||
selectedRequest.value = request
|
||||
modifyForm.newAmount = request.consumptionReport?.reportedAmount || 0
|
||||
modifyForm.newRemarks = request.consumptionReport?.remarks || ''
|
||||
modifyDialogVisible.value = true
|
||||
}
|
||||
}
|
||||
|
||||
function handleReject(request: ChangeRequest) {
|
||||
selectedRequest.value = request
|
||||
rejectForm.comments = ''
|
||||
rejectDialogVisible.value = true
|
||||
}
|
||||
|
||||
async function confirmReject() {
|
||||
if (!selectedRequest.value) return
|
||||
|
||||
processing.value = true
|
||||
try {
|
||||
await changeRequestsApi.process(selectedRequest.value.id, {
|
||||
approved: false,
|
||||
comments: rejectForm.comments
|
||||
})
|
||||
ElMessage.success('已拒绝申请')
|
||||
rejectDialogVisible.value = false
|
||||
await loadData()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.message || '操作失败')
|
||||
} finally {
|
||||
processing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function confirmModify() {
|
||||
if (!selectedRequest.value) return
|
||||
|
||||
if (modifyForm.newAmount <= 0) {
|
||||
ElMessage.warning('新数量必须大于0')
|
||||
return
|
||||
}
|
||||
|
||||
processing.value = true
|
||||
try {
|
||||
// 先同意申请
|
||||
await changeRequestsApi.process(selectedRequest.value.id, { approved: true })
|
||||
// 再执行修改
|
||||
await changeRequestsApi.modify(selectedRequest.value.id, {
|
||||
newAmount: modifyForm.newAmount,
|
||||
newRemarks: modifyForm.newRemarks
|
||||
})
|
||||
ElMessage.success('修改成功')
|
||||
modifyDialogVisible.value = false
|
||||
await loadData()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.message || '操作失败')
|
||||
} finally {
|
||||
processing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch(viewMode, () => {
|
||||
// 切换视图时不需要重新加载,数据已经加载
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
loadData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.change-request-list {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.title-icon {
|
||||
margin-right: 8px;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.modify-info {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
</div>
|
||||
<div class="status-badge">
|
||||
<el-tag :type="getStatusTagType(person.status)" size="large">
|
||||
{{ getStatusName(person.status) }}
|
||||
{{ person.pendingUpgradeByUnitId ? '待上级审批' : getStatusName(person.status) }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -71,6 +71,36 @@
|
|||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 审批历史 -->
|
||||
<el-divider content-position="left">审批历史</el-divider>
|
||||
<el-timeline v-if="approvalHistory.length > 0">
|
||||
<el-timeline-item
|
||||
v-for="item in approvalHistory"
|
||||
:key="item.id"
|
||||
:timestamp="formatDate(item.reviewedAt)"
|
||||
:type="getActionType(item.action)"
|
||||
placement="top"
|
||||
>
|
||||
<el-card shadow="hover" class="history-card">
|
||||
<div class="history-content">
|
||||
<div class="history-action">
|
||||
<el-tag :type="getActionType(item.action)" size="small">{{ getActionName(item.action) }}</el-tag>
|
||||
<span v-if="item.reviewedByUnitName" class="history-unit">{{ item.reviewedByUnitName }}</span>
|
||||
</div>
|
||||
<div v-if="item.newLevel" class="history-level">
|
||||
<span v-if="item.previousLevel">{{ getLevelName(item.previousLevel) }} → </span>
|
||||
<el-tag :type="getLevelTagType(item.newLevel)" size="small">{{ getLevelName(item.newLevel) }}</el-tag>
|
||||
</div>
|
||||
<div v-if="item.comments" class="history-comments">
|
||||
<el-icon><ChatDotRound /></el-icon>
|
||||
<span>{{ item.comments }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-timeline-item>
|
||||
</el-timeline>
|
||||
<el-empty v-else description="暂无审批记录" :image-size="60" />
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
|
@ -80,14 +110,16 @@
|
|||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { User, Document } from '@element-plus/icons-vue'
|
||||
import { User, Document, ChatDotRound } from '@element-plus/icons-vue'
|
||||
import { personnelApi } from '@/api'
|
||||
import type { PersonnelApprovalHistory } from '@/api/personnel'
|
||||
import type { Personnel } from '@/types'
|
||||
import { PersonnelStatus, PersonnelLevel } from '@/types'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const person = ref<Personnel | null>(null)
|
||||
const approvalHistory = ref<PersonnelApprovalHistory[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
function getStatusName(status: PersonnelStatus): string {
|
||||
|
|
@ -108,22 +140,48 @@ function getStatusTagType(status: PersonnelStatus): string {
|
|||
}
|
||||
}
|
||||
|
||||
function getLevelName(level: PersonnelLevel): string {
|
||||
function getLevelName(level: PersonnelLevel | string | null): string {
|
||||
switch (level) {
|
||||
case PersonnelLevel.Division: return '师级人才'
|
||||
case PersonnelLevel.Regiment: return '团级人才'
|
||||
case PersonnelLevel.Battalion: return '营级人才'
|
||||
case PersonnelLevel.Company: return '连级人才'
|
||||
case PersonnelLevel.Division:
|
||||
case 'Division': return '师级人才'
|
||||
case PersonnelLevel.Regiment:
|
||||
case 'Regiment': return '团级人才'
|
||||
case PersonnelLevel.Battalion:
|
||||
case 'Battalion': return '营级人才'
|
||||
case PersonnelLevel.Company:
|
||||
case 'Company': return '连级人才'
|
||||
default: return ''
|
||||
}
|
||||
}
|
||||
|
||||
function getLevelTagType(level: PersonnelLevel): string {
|
||||
function getLevelTagType(level: PersonnelLevel | string | null): string {
|
||||
switch (level) {
|
||||
case PersonnelLevel.Division: return 'danger'
|
||||
case PersonnelLevel.Regiment: return 'warning'
|
||||
case PersonnelLevel.Battalion: return 'success'
|
||||
case PersonnelLevel.Company: return 'info'
|
||||
case PersonnelLevel.Division:
|
||||
case 'Division': return 'danger'
|
||||
case PersonnelLevel.Regiment:
|
||||
case 'Regiment': return 'warning'
|
||||
case PersonnelLevel.Battalion:
|
||||
case 'Battalion': return 'success'
|
||||
case PersonnelLevel.Company:
|
||||
case 'Company': return 'info'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
||||
function getActionName(action: string): string {
|
||||
switch (action) {
|
||||
case 'Approved': return '审批通过'
|
||||
case 'Rejected': return '审批拒绝'
|
||||
case 'LevelUpgraded': return '等级升级'
|
||||
default: return action
|
||||
}
|
||||
}
|
||||
|
||||
function getActionType(action: string): string {
|
||||
switch (action) {
|
||||
case 'Approved': return 'success'
|
||||
case 'Rejected': return 'danger'
|
||||
case 'LevelUpgraded': return 'primary'
|
||||
default: return 'info'
|
||||
}
|
||||
}
|
||||
|
|
@ -135,7 +193,16 @@ function formatDate(dateStr: string): string {
|
|||
async function loadPersonnel() {
|
||||
loading.value = true
|
||||
try {
|
||||
person.value = await personnelApi.getById(Number(route.params.id))
|
||||
const id = Number(route.params.id)
|
||||
person.value = await personnelApi.getById(id)
|
||||
|
||||
// 加载审批历史
|
||||
try {
|
||||
approvalHistory.value = await personnelApi.getApprovalHistory(id)
|
||||
} catch {
|
||||
// 审批历史加载失败不影响主要信息显示
|
||||
approvalHistory.value = []
|
||||
}
|
||||
} catch {
|
||||
ElMessage.error('加载人员信息失败')
|
||||
} finally {
|
||||
|
|
@ -198,6 +265,56 @@ onMounted(() => {
|
|||
color: #303133;
|
||||
}
|
||||
|
||||
/* 审批历史样式 */
|
||||
.history-card {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.history-card :deep(.el-card__body) {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.history-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.history-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.history-unit {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.history-level {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.history-comments {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
padding: 8px 12px;
|
||||
background-color: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.history-comments .el-icon {
|
||||
margin-top: 2px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
/* 缩短标签列宽度 */
|
||||
:deep(.el-descriptions__label) {
|
||||
width: 120px !important;
|
||||
|
|
|
|||
|
|
@ -20,10 +20,13 @@
|
|||
<el-icon><Search /></el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-select v-model="statusFilter" placeholder="状态筛选" clearable style="width: 120px; margin-right: 12px">
|
||||
<el-select v-model="statusFilter" placeholder="状态筛选" clearable style="width: 140px; margin-right: 12px">
|
||||
<el-option label="待审批" value="Pending">
|
||||
<el-tag type="warning" size="small">待审批</el-tag>
|
||||
</el-option>
|
||||
<el-option label="待上级审批" value="PendingUpgrade">
|
||||
<el-tag type="primary" size="small">待上级审批</el-tag>
|
||||
</el-option>
|
||||
<el-option label="已批准" value="Approved">
|
||||
<el-tag type="success" size="small">已批准</el-tag>
|
||||
</el-option>
|
||||
|
|
@ -314,13 +317,24 @@ function handleSearch() {
|
|||
async function loadPersonnel() {
|
||||
loading.value = true
|
||||
try {
|
||||
// 处理状态筛选:PendingUpgrade 是前端特殊状态,需要单独处理
|
||||
const isPendingUpgradeFilter = statusFilter.value === 'PendingUpgrade'
|
||||
const backendStatus = isPendingUpgradeFilter ? undefined : (statusFilter.value || undefined)
|
||||
|
||||
const response = await personnelApi.getAll({
|
||||
pageNumber: pagination.pageNumber,
|
||||
pageSize: pagination.pageSize,
|
||||
status: statusFilter.value || undefined
|
||||
status: backendStatus
|
||||
})
|
||||
// 前端搜索过滤
|
||||
|
||||
let items = response.items
|
||||
|
||||
// 前端过滤:待上级审批(有 pendingUpgradeByUnitId 的记录)
|
||||
if (isPendingUpgradeFilter) {
|
||||
items = items.filter(p => p.pendingUpgradeByUnitId)
|
||||
}
|
||||
|
||||
// 前端搜索过滤
|
||||
if (searchKeyword.value) {
|
||||
const keyword = searchKeyword.value.toLowerCase()
|
||||
items = items.filter(p =>
|
||||
|
|
@ -329,7 +343,7 @@ async function loadPersonnel() {
|
|||
)
|
||||
}
|
||||
personnel.value = items
|
||||
pagination.total = response.totalCount
|
||||
pagination.total = isPendingUpgradeFilter ? items.length : response.totalCount
|
||||
} catch {
|
||||
ElMessage.error('加载人才列表失败')
|
||||
} finally {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user