配额
This commit is contained in:
parent
e1da1f9ae7
commit
adef288429
|
|
@ -280,7 +280,7 @@ public class AllocationsController : BaseApiController
|
|||
quotaValid = isValid,
|
||||
targetUnitsExist = targetUnitsExist,
|
||||
isValid = isValid && targetUnitsExist,
|
||||
message = !isValid ? "分配配额总和超过总配额指标" :
|
||||
message = !isValid ? "有配额未分配,无法提交" :
|
||||
!targetUnitsExist ? "目标单位不存在" : "验证通过"
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MilitaryTrainingManagement.Data;
|
||||
using MilitaryTrainingManagement.Models.DTOs;
|
||||
using MilitaryTrainingManagement.Models.Entities;
|
||||
|
||||
namespace MilitaryTrainingManagement.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 物资类别管理控制器
|
||||
/// </summary>
|
||||
[Authorize]
|
||||
public class MaterialCategoriesController : BaseApiController
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
public MaterialCategoriesController(ApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有物资类别
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll([FromQuery] bool? activeOnly = true)
|
||||
{
|
||||
var query = _context.MaterialCategories.AsQueryable();
|
||||
|
||||
if (activeOnly == true)
|
||||
{
|
||||
query = query.Where(c => c.IsActive);
|
||||
}
|
||||
|
||||
var categories = await query
|
||||
.OrderBy(c => c.SortOrder)
|
||||
.ThenBy(c => c.Name)
|
||||
.ToListAsync();
|
||||
|
||||
return Ok(categories);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取物资类别
|
||||
/// </summary>
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetById(int id)
|
||||
{
|
||||
var category = await _context.MaterialCategories.FindAsync(id);
|
||||
if (category == null)
|
||||
{
|
||||
return NotFound(new { message = "物资类别不存在" });
|
||||
}
|
||||
return Ok(category);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建物资类别
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create([FromBody] CreateMaterialCategoryRequest request)
|
||||
{
|
||||
// 检查名称是否已存在
|
||||
var exists = await _context.MaterialCategories
|
||||
.AnyAsync(c => c.Name == request.Name);
|
||||
if (exists)
|
||||
{
|
||||
return BadRequest(new { message = "物资类别名称已存在" });
|
||||
}
|
||||
|
||||
var category = new MaterialCategory
|
||||
{
|
||||
Name = request.Name,
|
||||
Description = request.Description,
|
||||
SortOrder = request.SortOrder,
|
||||
IsActive = true,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_context.MaterialCategories.Add(category);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return CreatedAtAction(nameof(GetById), new { id = category.Id }, category);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新物资类别
|
||||
/// </summary>
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> Update(int id, [FromBody] UpdateMaterialCategoryRequest request)
|
||||
{
|
||||
var category = await _context.MaterialCategories.FindAsync(id);
|
||||
if (category == null)
|
||||
{
|
||||
return NotFound(new { message = "物资类别不存在" });
|
||||
}
|
||||
|
||||
// 检查名称是否与其他类别重复
|
||||
var exists = await _context.MaterialCategories
|
||||
.AnyAsync(c => c.Name == request.Name && c.Id != id);
|
||||
if (exists)
|
||||
{
|
||||
return BadRequest(new { message = "物资类别名称已存在" });
|
||||
}
|
||||
|
||||
category.Name = request.Name;
|
||||
category.Description = request.Description;
|
||||
category.SortOrder = request.SortOrder;
|
||||
category.IsActive = request.IsActive;
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return Ok(category);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除物资类别
|
||||
/// </summary>
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> Delete(int id)
|
||||
{
|
||||
var category = await _context.MaterialCategories.FindAsync(id);
|
||||
if (category == null)
|
||||
{
|
||||
return NotFound(new { message = "物资类别不存在" });
|
||||
}
|
||||
|
||||
// 检查是否有配额使用此类别
|
||||
var hasAllocations = await _context.MaterialAllocations
|
||||
.AnyAsync(a => a.Category == category.Name);
|
||||
if (hasAllocations)
|
||||
{
|
||||
return BadRequest(new { message = "该类别已被使用,无法删除" });
|
||||
}
|
||||
|
||||
_context.MaterialCategories.Remove(category);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return Ok(new { message = "删除成功" });
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,7 @@ public class ApplicationDbContext : DbContext
|
|||
public DbSet<UserAccount> UserAccounts => Set<UserAccount>();
|
||||
public DbSet<MaterialAllocation> MaterialAllocations => Set<MaterialAllocation>();
|
||||
public DbSet<AllocationDistribution> AllocationDistributions => Set<AllocationDistribution>();
|
||||
public DbSet<MaterialCategory> MaterialCategories => Set<MaterialCategory>();
|
||||
public DbSet<Personnel> Personnel => Set<Personnel>();
|
||||
public DbSet<PersonnelApprovalHistory> PersonnelApprovalHistories => Set<PersonnelApprovalHistory>();
|
||||
public DbSet<ApprovalRequest> ApprovalRequests => Set<ApprovalRequest>();
|
||||
|
|
@ -65,6 +66,15 @@ public class ApplicationDbContext : DbContext
|
|||
.OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
// MaterialCategory 配置
|
||||
modelBuilder.Entity<MaterialCategory>(entity =>
|
||||
{
|
||||
entity.HasKey(e => e.Id);
|
||||
entity.Property(e => e.Name).IsRequired().HasMaxLength(50);
|
||||
entity.HasIndex(e => e.Name).IsUnique();
|
||||
entity.Property(e => e.Description).HasMaxLength(200);
|
||||
});
|
||||
|
||||
// AllocationDistribution 配置
|
||||
modelBuilder.Entity<AllocationDistribution>(entity =>
|
||||
{
|
||||
|
|
|
|||
672
src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.Designer.cs
generated
Normal file
672
src/MilitaryTrainingManagement/Migrations/20260114141545_AddMaterialCategory.Designer.cs
generated
Normal file
|
|
@ -0,0 +1,672 @@
|
|||
// <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("20260114141545_AddMaterialCategory")]
|
||||
partial class AddMaterialCategory
|
||||
{
|
||||
/// <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.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>("ContactInfo")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EducationLevel")
|
||||
.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")
|
||||
.IsRequired()
|
||||
.HasMaxLength(18)
|
||||
.HasColumnType("nvarchar(18)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("PhotoPath")
|
||||
.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<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.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApprovedByUnitId");
|
||||
|
||||
b.HasIndex("IdNumber")
|
||||
.IsUnique();
|
||||
|
||||
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>("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.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", "SubmittedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("SubmittedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ApprovedByUnit");
|
||||
|
||||
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,456 @@
|
|||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MilitaryTrainingManagement.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddMaterialCategory : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "MaterialCategories",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: true),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
SortOrder = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_MaterialCategories", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "OrganizationalUnits",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
Level = table.Column<int>(type: "int", nullable: false),
|
||||
ParentId = table.Column<int>(type: "int", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_OrganizationalUnits", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_OrganizationalUnits_OrganizationalUnits_ParentId",
|
||||
column: x => x.ParentId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "MaterialAllocations",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Category = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
MaterialName = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
||||
Unit = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
TotalQuota = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
CreatedByUnitId = table.Column<int>(type: "int", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_MaterialAllocations", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_MaterialAllocations_OrganizationalUnits_CreatedByUnitId",
|
||||
column: x => x.CreatedByUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Personnel",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
PhotoPath = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Position = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
Rank = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
Gender = table.Column<string>(type: "nvarchar(10)", maxLength: 10, nullable: false),
|
||||
IdNumber = table.Column<string>(type: "nvarchar(18)", maxLength: 18, nullable: false),
|
||||
ProfessionalTitle = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
EducationLevel = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Age = table.Column<int>(type: "int", nullable: false),
|
||||
Height = table.Column<decimal>(type: "decimal(5,2)", precision: 5, scale: 2, nullable: true),
|
||||
ContactInfo = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Hometown = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
TrainingParticipation = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
Achievements = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
SupportingDocuments = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
SubmittedByUnitId = table.Column<int>(type: "int", nullable: false),
|
||||
ApprovedLevel = table.Column<int>(type: "int", nullable: true),
|
||||
ApprovedByUnitId = table.Column<int>(type: "int", nullable: true),
|
||||
Status = table.Column<int>(type: "int", nullable: false),
|
||||
SubmittedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ApprovedAt = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Personnel", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Personnel_OrganizationalUnits_ApprovedByUnitId",
|
||||
column: x => x.ApprovedByUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_Personnel_OrganizationalUnits_SubmittedByUnitId",
|
||||
column: x => x.SubmittedByUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "UserAccounts",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Username = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
DisplayName = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
OrganizationalUnitId = table.Column<int>(type: "int", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
LastLoginAt = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_UserAccounts", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_UserAccounts_OrganizationalUnits_OrganizationalUnitId",
|
||||
column: x => x.OrganizationalUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AllocationDistributions",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
AllocationId = table.Column<int>(type: "int", nullable: false),
|
||||
TargetUnitId = table.Column<int>(type: "int", nullable: false),
|
||||
UnitQuota = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: false),
|
||||
ActualCompletion = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true),
|
||||
ReportedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ReportedByUserId = table.Column<int>(type: "int", nullable: true),
|
||||
IsApproved = table.Column<bool>(type: "bit", nullable: false),
|
||||
ApprovedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
ApprovedByUserId = table.Column<int>(type: "int", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AllocationDistributions", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AllocationDistributions_MaterialAllocations_AllocationId",
|
||||
column: x => x.AllocationId,
|
||||
principalTable: "MaterialAllocations",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AllocationDistributions_OrganizationalUnits_TargetUnitId",
|
||||
column: x => x.TargetUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_AllocationDistributions_UserAccounts_ApprovedByUserId",
|
||||
column: x => x.ApprovedByUserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_AllocationDistributions_UserAccounts_ReportedByUserId",
|
||||
column: x => x.ReportedByUserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ApprovalRequests",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
Type = table.Column<int>(type: "int", nullable: false),
|
||||
TargetEntityId = table.Column<int>(type: "int", nullable: false),
|
||||
RequestedByUserId = table.Column<int>(type: "int", nullable: false),
|
||||
RequestedByUnitId = table.Column<int>(type: "int", nullable: false),
|
||||
Reason = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: false),
|
||||
OriginalData = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
RequestedChanges = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
Status = table.Column<int>(type: "int", nullable: false),
|
||||
ReviewedByUserId = table.Column<int>(type: "int", nullable: true),
|
||||
ReviewComments = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
RequestedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ReviewedAt = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ApprovalRequests", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ApprovalRequests_OrganizationalUnits_RequestedByUnitId",
|
||||
column: x => x.RequestedByUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_ApprovalRequests_UserAccounts_RequestedByUserId",
|
||||
column: x => x.RequestedByUserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_ApprovalRequests_UserAccounts_ReviewedByUserId",
|
||||
column: x => x.ReviewedByUserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AuditLogs",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
EntityType = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
|
||||
EntityId = table.Column<int>(type: "int", nullable: false),
|
||||
Action = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
||||
Description = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
OldValues = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
NewValues = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ChangedFields = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
UserId = table.Column<int>(type: "int", nullable: true),
|
||||
OrganizationalUnitId = table.Column<int>(type: "int", nullable: true),
|
||||
Timestamp = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
IpAddress = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
|
||||
UserAgent = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
RequestPath = table.Column<string>(type: "nvarchar(500)", maxLength: 500, nullable: true),
|
||||
IsSuccess = table.Column<bool>(type: "bit", nullable: false),
|
||||
ErrorMessage = table.Column<string>(type: "nvarchar(2000)", maxLength: 2000, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AuditLogs", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AuditLogs_OrganizationalUnits_OrganizationalUnitId",
|
||||
column: x => x.OrganizationalUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_AuditLogs_UserAccounts_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "PersonnelApprovalHistories",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
PersonnelId = table.Column<int>(type: "int", nullable: false),
|
||||
Action = table.Column<int>(type: "int", nullable: false),
|
||||
PreviousStatus = table.Column<int>(type: "int", nullable: true),
|
||||
NewStatus = table.Column<int>(type: "int", nullable: false),
|
||||
PreviousLevel = table.Column<int>(type: "int", nullable: true),
|
||||
NewLevel = table.Column<int>(type: "int", nullable: true),
|
||||
ReviewedByUserId = table.Column<int>(type: "int", nullable: false),
|
||||
ReviewedByUnitId = table.Column<int>(type: "int", nullable: true),
|
||||
Comments = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
ReviewedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_PersonnelApprovalHistories", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_PersonnelApprovalHistories_OrganizationalUnits_ReviewedByUnitId",
|
||||
column: x => x.ReviewedByUnitId,
|
||||
principalTable: "OrganizationalUnits",
|
||||
principalColumn: "Id");
|
||||
table.ForeignKey(
|
||||
name: "FK_PersonnelApprovalHistories_Personnel_PersonnelId",
|
||||
column: x => x.PersonnelId,
|
||||
principalTable: "Personnel",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_PersonnelApprovalHistories_UserAccounts_ReviewedByUserId",
|
||||
column: x => x.ReviewedByUserId,
|
||||
principalTable: "UserAccounts",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AllocationDistributions_AllocationId",
|
||||
table: "AllocationDistributions",
|
||||
column: "AllocationId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AllocationDistributions_ApprovedByUserId",
|
||||
table: "AllocationDistributions",
|
||||
column: "ApprovedByUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AllocationDistributions_ReportedByUserId",
|
||||
table: "AllocationDistributions",
|
||||
column: "ReportedByUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AllocationDistributions_TargetUnitId",
|
||||
table: "AllocationDistributions",
|
||||
column: "TargetUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApprovalRequests_RequestedByUnitId",
|
||||
table: "ApprovalRequests",
|
||||
column: "RequestedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApprovalRequests_RequestedByUserId",
|
||||
table: "ApprovalRequests",
|
||||
column: "RequestedByUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApprovalRequests_ReviewedByUserId",
|
||||
table: "ApprovalRequests",
|
||||
column: "ReviewedByUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AuditLogs_Action",
|
||||
table: "AuditLogs",
|
||||
column: "Action");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AuditLogs_EntityId",
|
||||
table: "AuditLogs",
|
||||
column: "EntityId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AuditLogs_EntityType",
|
||||
table: "AuditLogs",
|
||||
column: "EntityType");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AuditLogs_OrganizationalUnitId",
|
||||
table: "AuditLogs",
|
||||
column: "OrganizationalUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AuditLogs_Timestamp",
|
||||
table: "AuditLogs",
|
||||
column: "Timestamp");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AuditLogs_UserId",
|
||||
table: "AuditLogs",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_MaterialAllocations_CreatedByUnitId",
|
||||
table: "MaterialAllocations",
|
||||
column: "CreatedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_MaterialCategories_Name",
|
||||
table: "MaterialCategories",
|
||||
column: "Name",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_OrganizationalUnits_ParentId",
|
||||
table: "OrganizationalUnits",
|
||||
column: "ParentId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Personnel_ApprovedByUnitId",
|
||||
table: "Personnel",
|
||||
column: "ApprovedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Personnel_IdNumber",
|
||||
table: "Personnel",
|
||||
column: "IdNumber",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Personnel_SubmittedByUnitId",
|
||||
table: "Personnel",
|
||||
column: "SubmittedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PersonnelApprovalHistories_PersonnelId",
|
||||
table: "PersonnelApprovalHistories",
|
||||
column: "PersonnelId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PersonnelApprovalHistories_ReviewedByUnitId",
|
||||
table: "PersonnelApprovalHistories",
|
||||
column: "ReviewedByUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_PersonnelApprovalHistories_ReviewedByUserId",
|
||||
table: "PersonnelApprovalHistories",
|
||||
column: "ReviewedByUserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserAccounts_OrganizationalUnitId",
|
||||
table: "UserAccounts",
|
||||
column: "OrganizationalUnitId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_UserAccounts_Username",
|
||||
table: "UserAccounts",
|
||||
column: "Username",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AllocationDistributions");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ApprovalRequests");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AuditLogs");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "MaterialCategories");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "PersonnelApprovalHistories");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "MaterialAllocations");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Personnel");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "UserAccounts");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "OrganizationalUnits");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,669 @@
|
|||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using MilitaryTrainingManagement.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace MilitaryTrainingManagement.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(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.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>("ContactInfo")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EducationLevel")
|
||||
.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")
|
||||
.IsRequired()
|
||||
.HasMaxLength(18)
|
||||
.HasColumnType("nvarchar(18)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("nvarchar(50)");
|
||||
|
||||
b.Property<string>("PhotoPath")
|
||||
.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<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.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApprovedByUnitId");
|
||||
|
||||
b.HasIndex("IdNumber")
|
||||
.IsUnique();
|
||||
|
||||
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>("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.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", "SubmittedByUnit")
|
||||
.WithMany()
|
||||
.HasForeignKey("SubmittedByUnitId")
|
||||
.OnDelete(DeleteBehavior.NoAction)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ApprovedByUnit");
|
||||
|
||||
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,35 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace MilitaryTrainingManagement.Models.DTOs;
|
||||
|
||||
/// <summary>
|
||||
/// 创建物资类别请求
|
||||
/// </summary>
|
||||
public class CreateMaterialCategoryRequest
|
||||
{
|
||||
[Required(ErrorMessage = "类别名称不能为空")]
|
||||
[StringLength(50, ErrorMessage = "类别名称长度不能超过50个字符")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(200, ErrorMessage = "描述长度不能超过200个字符")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
public int SortOrder { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新物资类别请求
|
||||
/// </summary>
|
||||
public class UpdateMaterialCategoryRequest
|
||||
{
|
||||
[Required(ErrorMessage = "类别名称不能为空")]
|
||||
[StringLength(50, ErrorMessage = "类别名称长度不能超过50个字符")]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[StringLength(200, ErrorMessage = "描述长度不能超过200个字符")]
|
||||
public string? Description { get; set; }
|
||||
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
namespace MilitaryTrainingManagement.Models.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 物资类别
|
||||
/// </summary>
|
||||
public class MaterialCategory
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 类别名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 类别描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用
|
||||
/// </summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序顺序
|
||||
/// </summary>
|
||||
public int SortOrder { get; set; }
|
||||
}
|
||||
|
|
@ -158,6 +158,73 @@ using (var scope = app.Services.CreateScope())
|
|||
|
||||
// 确保数据库已创建
|
||||
context.Database.EnsureCreated();
|
||||
|
||||
// 手动创建 MaterialCategories 表(如果不存在)
|
||||
try
|
||||
{
|
||||
var tableExists = context.Database.ExecuteSqlRaw(@"
|
||||
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'MaterialCategories')
|
||||
BEGIN
|
||||
CREATE TABLE MaterialCategories (
|
||||
Id INT PRIMARY KEY IDENTITY(1,1),
|
||||
Name NVARCHAR(50) NOT NULL,
|
||||
Description NVARCHAR(200),
|
||||
IsActive BIT NOT NULL DEFAULT 1,
|
||||
CreatedAt DATETIME2 NOT NULL,
|
||||
SortOrder INT NOT NULL DEFAULT 0
|
||||
);
|
||||
CREATE UNIQUE INDEX IX_MaterialCategories_Name ON MaterialCategories(Name);
|
||||
END
|
||||
");
|
||||
Console.WriteLine("MaterialCategories 表检查完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"创建 MaterialCategories 表时出错: {ex.Message}");
|
||||
}
|
||||
|
||||
// 如果没有物资类别,创建默认类别
|
||||
if (!context.MaterialCategories.Any())
|
||||
{
|
||||
var categories = new[]
|
||||
{
|
||||
new MilitaryTrainingManagement.Models.Entities.MaterialCategory
|
||||
{
|
||||
Name = "弹药",
|
||||
Description = "各类训练弹药",
|
||||
IsActive = true,
|
||||
SortOrder = 1,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
},
|
||||
new MilitaryTrainingManagement.Models.Entities.MaterialCategory
|
||||
{
|
||||
Name = "装备",
|
||||
Description = "训练装备器材",
|
||||
IsActive = true,
|
||||
SortOrder = 2,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
},
|
||||
new MilitaryTrainingManagement.Models.Entities.MaterialCategory
|
||||
{
|
||||
Name = "物资",
|
||||
Description = "训练保障物资",
|
||||
IsActive = true,
|
||||
SortOrder = 3,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
},
|
||||
new MilitaryTrainingManagement.Models.Entities.MaterialCategory
|
||||
{
|
||||
Name = "器材",
|
||||
Description = "训练辅助器材",
|
||||
IsActive = true,
|
||||
SortOrder = 4,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
}
|
||||
};
|
||||
context.MaterialCategories.AddRange(categories);
|
||||
await context.SaveChangesAsync();
|
||||
Console.WriteLine("默认物资类别已创建!");
|
||||
}
|
||||
|
||||
// 如果没有组织单位,创建种子数据
|
||||
if (!context.OrganizationalUnits.Any())
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ public class AllocationService : IAllocationService
|
|||
throw new ArgumentException("单位配额不能为负数");
|
||||
|
||||
if (!await ValidateDistributionQuotasAsync(totalQuota, distributions))
|
||||
throw new ArgumentException("分配配额总和超过总配额指标");
|
||||
throw new ArgumentException("有配额未分配,无法提交");
|
||||
|
||||
// 验证目标单位存在
|
||||
if (!await ValidateTargetUnitsExistAsync(distributions.Keys))
|
||||
|
|
@ -203,7 +203,7 @@ public class AllocationService : IAllocationService
|
|||
throw new ArgumentException("单位配额不能为负数");
|
||||
|
||||
if (!await ValidateDistributionQuotasAsync(allocation.TotalQuota, distributions))
|
||||
throw new ArgumentException("分配配额总和超过总配额指标");
|
||||
throw new ArgumentException("有配额未分配,无法提交");
|
||||
|
||||
// 验证目标单位存在
|
||||
if (!await ValidateTargetUnitsExistAsync(distributions.Keys))
|
||||
|
|
@ -242,10 +242,10 @@ public class AllocationService : IAllocationService
|
|||
public Task<bool> ValidateDistributionQuotasAsync(decimal totalQuota, Dictionary<int, decimal> distributions)
|
||||
{
|
||||
if (distributions == null || distributions.Count == 0)
|
||||
return Task.FromResult(true);
|
||||
return Task.FromResult(false); // 必须有分配
|
||||
|
||||
var sum = distributions.Values.Sum();
|
||||
return Task.FromResult(sum <= totalQuota);
|
||||
return Task.FromResult(sum == totalQuota); // 必须完全分配,不能多也不能少
|
||||
}
|
||||
|
||||
public async Task<bool> ValidateTargetUnitsExistAsync(IEnumerable<int> targetUnitIds)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
export { authApi } from './auth'
|
||||
export { organizationsApi } from './organizations'
|
||||
export { allocationsApi } from './allocations'
|
||||
export { materialCategoriesApi } from './materialCategories'
|
||||
export { reportsApi } from './reports'
|
||||
export { personnelApi } from './personnel'
|
||||
export { approvalsApi } from './approvals'
|
||||
|
|
|
|||
51
src/frontend/src/api/materialCategories.ts
Normal file
51
src/frontend/src/api/materialCategories.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import apiClient from './client'
|
||||
|
||||
export interface MaterialCategory {
|
||||
id: number
|
||||
name: string
|
||||
description?: string
|
||||
isActive: boolean
|
||||
createdAt: string
|
||||
sortOrder: number
|
||||
}
|
||||
|
||||
export interface CreateMaterialCategoryRequest {
|
||||
name: string
|
||||
description?: string
|
||||
sortOrder: number
|
||||
}
|
||||
|
||||
export interface UpdateMaterialCategoryRequest {
|
||||
name: string
|
||||
description?: string
|
||||
sortOrder: number
|
||||
isActive: boolean
|
||||
}
|
||||
|
||||
export const materialCategoriesApi = {
|
||||
async getAll(activeOnly: boolean = true): Promise<MaterialCategory[]> {
|
||||
const response = await apiClient.get<MaterialCategory[]>('/materialcategories', {
|
||||
params: { activeOnly }
|
||||
})
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getById(id: number): Promise<MaterialCategory> {
|
||||
const response = await apiClient.get<MaterialCategory>(`/materialcategories/${id}`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async create(data: CreateMaterialCategoryRequest): Promise<MaterialCategory> {
|
||||
const response = await apiClient.post<MaterialCategory>('/materialcategories', data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async update(id: number, data: UpdateMaterialCategoryRequest): Promise<MaterialCategory> {
|
||||
const response = await apiClient.put<MaterialCategory>(`/materialcategories/${id}`, data)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async delete(id: number): Promise<void> {
|
||||
await apiClient.delete(`/materialcategories/${id}`)
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,12 @@ const routes: RouteRecordRaw[] = [
|
|||
component: () => import('@/views/allocations/AllocationList.vue'),
|
||||
meta: { title: '物资配额' }
|
||||
},
|
||||
{
|
||||
path: 'allocations/categories',
|
||||
name: 'MaterialCategories',
|
||||
component: () => import('@/views/allocations/MaterialCategoryManagement.vue'),
|
||||
meta: { title: '物资类别管理', minLevel: 1 }
|
||||
},
|
||||
{
|
||||
path: 'allocations/create',
|
||||
name: 'AllocationCreate',
|
||||
|
|
|
|||
|
|
@ -7,7 +7,14 @@
|
|||
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" v-loading="loading">
|
||||
<el-form-item label="物资类别" prop="category">
|
||||
<el-input v-model="form.category" placeholder="请输入物资类别" />
|
||||
<el-select v-model="form.category" placeholder="请选择物资类别" style="width: 100%">
|
||||
<el-option
|
||||
v-for="cat in categories"
|
||||
:key="cat.id"
|
||||
:label="cat.name"
|
||||
:value="cat.name"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物资名称" prop="materialName">
|
||||
<el-input v-model="form.materialName" placeholder="请输入物资名称" />
|
||||
|
|
@ -64,9 +71,10 @@ import { ref, reactive, computed, onMounted } from 'vue'
|
|||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||
import { Plus, Delete } from '@element-plus/icons-vue'
|
||||
import { allocationsApi, organizationsApi } from '@/api'
|
||||
import { allocationsApi, organizationsApi, materialCategoriesApi } from '@/api'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import type { OrganizationalUnit, DistributionRequest } from '@/types'
|
||||
import type { MaterialCategory } from '@/api/materialCategories'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
|
@ -77,6 +85,7 @@ const formRef = ref<FormInstance>()
|
|||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const subordinateUnits = ref<OrganizationalUnit[]>([])
|
||||
const categories = ref<MaterialCategory[]>([])
|
||||
|
||||
const form = reactive({
|
||||
category: '',
|
||||
|
|
@ -114,6 +123,14 @@ async function loadSubordinateUnits() {
|
|||
}
|
||||
}
|
||||
|
||||
async function loadCategories() {
|
||||
try {
|
||||
categories.value = await materialCategoriesApi.getAll(true) // 只加载启用的类别
|
||||
} catch {
|
||||
ElMessage.error('加载物资类别失败')
|
||||
}
|
||||
}
|
||||
|
||||
async function loadAllocation() {
|
||||
if (!isEdit.value) return
|
||||
|
||||
|
|
@ -146,6 +163,11 @@ async function handleSubmit() {
|
|||
return
|
||||
}
|
||||
|
||||
if (distributedTotal.value < form.totalQuota) {
|
||||
ElMessage.error('有配额未分配,无法提交')
|
||||
return
|
||||
}
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
if (isEdit.value) {
|
||||
|
|
@ -178,6 +200,7 @@ async function handleSubmit() {
|
|||
|
||||
onMounted(() => {
|
||||
loadSubordinateUnits()
|
||||
loadCategories()
|
||||
loadAllocation()
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
<el-option label="物资" value="物资" />
|
||||
<el-option label="器材" value="器材" />
|
||||
</el-select>
|
||||
<el-button v-if="authStore.canCreateAllocations" @click="$router.push('/allocations/categories')">
|
||||
<el-icon><Setting /></el-icon>
|
||||
类别管理
|
||||
</el-button>
|
||||
<el-button v-if="authStore.canCreateAllocations" type="primary" @click="$router.push('/allocations/create')">
|
||||
<el-icon><Plus /></el-icon>
|
||||
创建配额
|
||||
|
|
@ -208,7 +212,7 @@
|
|||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Search, View, Edit, Delete, Box } from '@element-plus/icons-vue'
|
||||
import { Plus, Search, View, Edit, Delete, Box, Setting } from '@element-plus/icons-vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { allocationsApi } from '@/api'
|
||||
import type { MaterialAllocation, AllocationDistribution } from '@/types'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
<template>
|
||||
<div class="material-category-management">
|
||||
<el-card>
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>物资类别管理</span>
|
||||
<el-button type="primary" @click="handleAdd">
|
||||
<el-icon><Plus /></el-icon>
|
||||
添加类别
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-table :data="categories" v-loading="loading">
|
||||
<el-table-column prop="name" label="类别名称" min-width="150" />
|
||||
<el-table-column prop="description" label="描述" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="sortOrder" label="排序" width="100" align="center" />
|
||||
<el-table-column prop="isActive" label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.isActive ? 'success' : 'info'" size="small">
|
||||
{{ row.isActive ? '启用' : '禁用' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createdAt" label="创建时间" width="160">
|
||||
<template #default="{ row }">
|
||||
{{ formatDate(row.createdAt) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="180" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" text size="small" @click="handleEdit(row)">编辑</el-button>
|
||||
<el-button type="danger" text size="small" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<!-- Create/Edit Dialog -->
|
||||
<el-dialog v-model="showDialog" :title="dialogTitle" width="500px">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="类别名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入类别名称" maxlength="50" show-word-limit />
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input
|
||||
v-model="form.description"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
placeholder="请输入类别描述(可选)"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序" prop="sortOrder">
|
||||
<el-input-number v-model="form.sortOrder" :min="0" :max="9999" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="isActive" v-if="editingCategory">
|
||||
<el-switch v-model="form.isActive" active-text="启用" inactive-text="禁用" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="showDialog = false">取消</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="handleSave">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage, ElMessageBox, FormInstance, FormRules } from 'element-plus'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { materialCategoriesApi } from '@/api'
|
||||
import type { MaterialCategory } from '@/api/materialCategories'
|
||||
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const showDialog = ref(false)
|
||||
const categories = ref<MaterialCategory[]>([])
|
||||
const editingCategory = ref<MaterialCategory | null>(null)
|
||||
const formRef = ref<FormInstance>()
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
description: '',
|
||||
sortOrder: 0,
|
||||
isActive: true
|
||||
})
|
||||
|
||||
const dialogTitle = computed(() => editingCategory.value ? '编辑类别' : '添加类别')
|
||||
|
||||
const rules: FormRules = {
|
||||
name: [{ required: true, message: '请输入类别名称', trigger: 'blur' }],
|
||||
sortOrder: [{ required: true, message: '请输入排序', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
function formatDate(dateStr: string): string {
|
||||
return new Date(dateStr).toLocaleString('zh-CN')
|
||||
}
|
||||
|
||||
async function loadCategories() {
|
||||
loading.value = true
|
||||
try {
|
||||
categories.value = await materialCategoriesApi.getAll(false) // 加载所有类别,包括禁用的
|
||||
} catch {
|
||||
ElMessage.error('加载类别列表失败')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
editingCategory.value = null
|
||||
form.name = ''
|
||||
form.description = ''
|
||||
form.sortOrder = 0
|
||||
form.isActive = true
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
function handleEdit(category: MaterialCategory) {
|
||||
editingCategory.value = category
|
||||
form.name = category.name
|
||||
form.description = category.description || ''
|
||||
form.sortOrder = category.sortOrder
|
||||
form.isActive = category.isActive
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
async function handleDelete(category: MaterialCategory) {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定要删除类别"${category.name}"吗?`, '确认删除', {
|
||||
type: 'warning'
|
||||
})
|
||||
await materialCategoriesApi.delete(category.id)
|
||||
ElMessage.success('删除成功')
|
||||
await loadCategories()
|
||||
} catch (error: any) {
|
||||
if (error !== 'cancel') {
|
||||
ElMessage.error(error.response?.data?.message || '删除失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (!formRef.value) return
|
||||
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (!valid) return
|
||||
|
||||
saving.value = true
|
||||
try {
|
||||
if (editingCategory.value) {
|
||||
await materialCategoriesApi.update(editingCategory.value.id, {
|
||||
name: form.name,
|
||||
description: form.description || undefined,
|
||||
sortOrder: form.sortOrder,
|
||||
isActive: form.isActive
|
||||
})
|
||||
ElMessage.success('更新成功')
|
||||
} else {
|
||||
await materialCategoriesApi.create({
|
||||
name: form.name,
|
||||
description: form.description || undefined,
|
||||
sortOrder: form.sortOrder
|
||||
})
|
||||
ElMessage.success('创建成功')
|
||||
}
|
||||
showDialog.value = false
|
||||
await loadCategories()
|
||||
} catch (error: any) {
|
||||
ElMessage.error(error.response?.data?.message || '操作失败')
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadCategories()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user