12
This commit is contained in:
commit
1d74e8a589
|
|
@ -280,7 +280,7 @@ public class AllocationsController : BaseApiController
|
||||||
quotaValid = isValid,
|
quotaValid = isValid,
|
||||||
targetUnitsExist = targetUnitsExist,
|
targetUnitsExist = targetUnitsExist,
|
||||||
isValid = isValid && targetUnitsExist,
|
isValid = isValid && targetUnitsExist,
|
||||||
message = !isValid ? "分配配额总和超过总配额指标" :
|
message = !isValid ? "有配额未分配,无法提交" :
|
||||||
!targetUnitsExist ? "目标单位不存在" : "验证通过"
|
!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<UserAccount> UserAccounts => Set<UserAccount>();
|
||||||
public DbSet<MaterialAllocation> MaterialAllocations => Set<MaterialAllocation>();
|
public DbSet<MaterialAllocation> MaterialAllocations => Set<MaterialAllocation>();
|
||||||
public DbSet<AllocationDistribution> AllocationDistributions => Set<AllocationDistribution>();
|
public DbSet<AllocationDistribution> AllocationDistributions => Set<AllocationDistribution>();
|
||||||
|
public DbSet<MaterialCategory> MaterialCategories => Set<MaterialCategory>();
|
||||||
public DbSet<Personnel> Personnel => Set<Personnel>();
|
public DbSet<Personnel> Personnel => Set<Personnel>();
|
||||||
public DbSet<PersonnelApprovalHistory> PersonnelApprovalHistories => Set<PersonnelApprovalHistory>();
|
public DbSet<PersonnelApprovalHistory> PersonnelApprovalHistories => Set<PersonnelApprovalHistory>();
|
||||||
public DbSet<ApprovalRequest> ApprovalRequests => Set<ApprovalRequest>();
|
public DbSet<ApprovalRequest> ApprovalRequests => Set<ApprovalRequest>();
|
||||||
|
|
@ -65,6 +66,15 @@ public class ApplicationDbContext : DbContext
|
||||||
.OnDelete(DeleteBehavior.Restrict);
|
.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 配置
|
// AllocationDistribution 配置
|
||||||
modelBuilder.Entity<AllocationDistribution>(entity =>
|
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();
|
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())
|
if (!context.OrganizationalUnits.Any())
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ public class AllocationService : IAllocationService
|
||||||
throw new ArgumentException("单位配额不能为负数");
|
throw new ArgumentException("单位配额不能为负数");
|
||||||
|
|
||||||
if (!await ValidateDistributionQuotasAsync(totalQuota, distributions))
|
if (!await ValidateDistributionQuotasAsync(totalQuota, distributions))
|
||||||
throw new ArgumentException("分配配额总和超过总配额指标");
|
throw new ArgumentException("有配额未分配,无法提交");
|
||||||
|
|
||||||
// 验证目标单位存在
|
// 验证目标单位存在
|
||||||
if (!await ValidateTargetUnitsExistAsync(distributions.Keys))
|
if (!await ValidateTargetUnitsExistAsync(distributions.Keys))
|
||||||
|
|
@ -203,7 +203,7 @@ public class AllocationService : IAllocationService
|
||||||
throw new ArgumentException("单位配额不能为负数");
|
throw new ArgumentException("单位配额不能为负数");
|
||||||
|
|
||||||
if (!await ValidateDistributionQuotasAsync(allocation.TotalQuota, distributions))
|
if (!await ValidateDistributionQuotasAsync(allocation.TotalQuota, distributions))
|
||||||
throw new ArgumentException("分配配额总和超过总配额指标");
|
throw new ArgumentException("有配额未分配,无法提交");
|
||||||
|
|
||||||
// 验证目标单位存在
|
// 验证目标单位存在
|
||||||
if (!await ValidateTargetUnitsExistAsync(distributions.Keys))
|
if (!await ValidateTargetUnitsExistAsync(distributions.Keys))
|
||||||
|
|
@ -242,10 +242,10 @@ public class AllocationService : IAllocationService
|
||||||
public Task<bool> ValidateDistributionQuotasAsync(decimal totalQuota, Dictionary<int, decimal> distributions)
|
public Task<bool> ValidateDistributionQuotasAsync(decimal totalQuota, Dictionary<int, decimal> distributions)
|
||||||
{
|
{
|
||||||
if (distributions == null || distributions.Count == 0)
|
if (distributions == null || distributions.Count == 0)
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(false); // 必须有分配
|
||||||
|
|
||||||
var sum = distributions.Values.Sum();
|
var sum = distributions.Values.Sum();
|
||||||
return Task.FromResult(sum <= totalQuota);
|
return Task.FromResult(sum == totalQuota); // 必须完全分配,不能多也不能少
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ValidateTargetUnitsExistAsync(IEnumerable<int> targetUnitIds)
|
public async Task<bool> ValidateTargetUnitsExistAsync(IEnumerable<int> targetUnitIds)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
export { authApi } from './auth'
|
export { authApi } from './auth'
|
||||||
export { organizationsApi } from './organizations'
|
export { organizationsApi } from './organizations'
|
||||||
export { allocationsApi } from './allocations'
|
export { allocationsApi } from './allocations'
|
||||||
|
export { materialCategoriesApi } from './materialCategories'
|
||||||
export { reportsApi } from './reports'
|
export { reportsApi } from './reports'
|
||||||
export { personnelApi } from './personnel'
|
export { personnelApi } from './personnel'
|
||||||
export { approvalsApi } from './approvals'
|
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'),
|
component: () => import('@/views/allocations/AllocationList.vue'),
|
||||||
meta: { title: '物资配额' }
|
meta: { title: '物资配额' }
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'allocations/categories',
|
||||||
|
name: 'MaterialCategories',
|
||||||
|
component: () => import('@/views/allocations/MaterialCategoryManagement.vue'),
|
||||||
|
meta: { title: '物资类别管理', minLevel: 1 }
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'allocations/create',
|
path: 'allocations/create',
|
||||||
name: 'AllocationCreate',
|
name: 'AllocationCreate',
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,14 @@
|
||||||
|
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" v-loading="loading">
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px" v-loading="loading">
|
||||||
<el-form-item label="物资类别" prop="category">
|
<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>
|
||||||
<el-form-item label="物资名称" prop="materialName">
|
<el-form-item label="物资名称" prop="materialName">
|
||||||
<el-input v-model="form.materialName" placeholder="请输入物资名称" />
|
<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 { useRoute, useRouter } from 'vue-router'
|
||||||
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
import { ElMessage, FormInstance, FormRules } from 'element-plus'
|
||||||
import { Plus, Delete } from '@element-plus/icons-vue'
|
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 { useAuthStore } from '@/stores/auth'
|
||||||
import type { OrganizationalUnit, DistributionRequest } from '@/types'
|
import type { OrganizationalUnit, DistributionRequest } from '@/types'
|
||||||
|
import type { MaterialCategory } from '@/api/materialCategories'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
@ -77,6 +85,7 @@ const formRef = ref<FormInstance>()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
const subordinateUnits = ref<OrganizationalUnit[]>([])
|
const subordinateUnits = ref<OrganizationalUnit[]>([])
|
||||||
|
const categories = ref<MaterialCategory[]>([])
|
||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
category: '',
|
category: '',
|
||||||
|
|
@ -114,6 +123,14 @@ async function loadSubordinateUnits() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadCategories() {
|
||||||
|
try {
|
||||||
|
categories.value = await materialCategoriesApi.getAll(true) // 只加载启用的类别
|
||||||
|
} catch {
|
||||||
|
ElMessage.error('加载物资类别失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadAllocation() {
|
async function loadAllocation() {
|
||||||
if (!isEdit.value) return
|
if (!isEdit.value) return
|
||||||
|
|
||||||
|
|
@ -146,6 +163,11 @@ async function handleSubmit() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (distributedTotal.value < form.totalQuota) {
|
||||||
|
ElMessage.error('有配额未分配,无法提交')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
saving.value = true
|
saving.value = true
|
||||||
try {
|
try {
|
||||||
if (isEdit.value) {
|
if (isEdit.value) {
|
||||||
|
|
@ -178,6 +200,7 @@ async function handleSubmit() {
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadSubordinateUnits()
|
loadSubordinateUnits()
|
||||||
|
loadCategories()
|
||||||
loadAllocation()
|
loadAllocation()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,10 @@
|
||||||
<el-option label="物资" value="物资" />
|
<el-option label="物资" value="物资" />
|
||||||
<el-option label="器材" value="器材" />
|
<el-option label="器材" value="器材" />
|
||||||
</el-select>
|
</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-button v-if="authStore.canCreateAllocations" type="primary" @click="$router.push('/allocations/create')">
|
||||||
<el-icon><Plus /></el-icon>
|
<el-icon><Plus /></el-icon>
|
||||||
创建配额
|
创建配额
|
||||||
|
|
@ -208,7 +212,7 @@
|
||||||
import { ref, reactive, computed, onMounted } from 'vue'
|
import { ref, reactive, computed, onMounted } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
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 { useAuthStore } from '@/stores/auth'
|
||||||
import { allocationsApi } from '@/api'
|
import { allocationsApi } from '@/api'
|
||||||
import type { MaterialAllocation, AllocationDistribution } from '@/types'
|
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