corps/src/MilitaryTrainingManagement/Services/Implementations/PersonnelService.cs
2026-01-17 00:37:13 +08:00

782 lines
31 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using MilitaryTrainingManagement.Data;
using MilitaryTrainingManagement.Models.Entities;
using MilitaryTrainingManagement.Models.Enums;
using MilitaryTrainingManagement.Services.Interfaces;
namespace MilitaryTrainingManagement.Services.Implementations;
/// <summary>
/// 人员管理服务实现
/// </summary>
public class PersonnelService : IPersonnelService
{
private readonly ApplicationDbContext _context;
private readonly IOrganizationService _organizationService;
private readonly IFileUploadService _fileUploadService;
private readonly IWorkflowService _workflowService;
private readonly ILogger<PersonnelService> _logger;
public PersonnelService(
ApplicationDbContext context,
IOrganizationService organizationService,
IFileUploadService fileUploadService,
IWorkflowService workflowService,
ILogger<PersonnelService> logger)
{
_context = context;
_organizationService = organizationService;
_fileUploadService = fileUploadService;
_workflowService = workflowService;
_logger = logger;
}
public async Task<Personnel?> GetByIdAsync(int id)
{
return await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.FirstOrDefaultAsync(p => p.Id == id);
}
public async Task<IEnumerable<Personnel>> GetByUnitAsync(int unitId, bool includeSubordinates = false)
{
if (includeSubordinates)
{
var subordinates = await _organizationService.GetSubordinatesAsync(unitId);
var unitIds = subordinates.Select(s => s.Id).ToList();
unitIds.Add(unitId);
return await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.Where(p => unitIds.Contains(p.SubmittedByUnitId))
.OrderByDescending(p => p.SubmittedAt)
.ToListAsync();
}
return await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.Where(p => p.SubmittedByUnitId == unitId)
.OrderByDescending(p => p.SubmittedAt)
.ToListAsync();
}
public async Task<Personnel> CreateAsync(Personnel personnel)
{
personnel.Status = PersonnelStatus.Pending;
personnel.SubmittedAt = DateTime.UtcNow;
_context.Personnel.Add(personnel);
await _context.SaveChangesAsync();
return personnel;
}
public async Task<Personnel> UpdateAsync(Personnel personnel)
{
_context.Personnel.Update(personnel);
await _context.SaveChangesAsync();
return personnel;
}
public async Task<Personnel> ApproveAsync(int personnelId, int approvedByUnitId, PersonnelLevel? level = null)
{
var personnel = await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.FirstOrDefaultAsync(p => p.Id == personnelId);
if (personnel == null)
throw new ArgumentException("人员记录不存在");
var approvedByUnit = await _context.OrganizationalUnits.FindAsync(approvedByUnitId);
if (approvedByUnit == null)
throw new ArgumentException("审批单位不存在");
var previousStatus = personnel.Status;
var previousLevel = personnel.ApprovedLevel;
PersonnelLevel actualLevel;
if (level.HasValue)
{
actualLevel = level.Value;
}
else
{
// 区分首次审批和向上申报两种场景
if (previousStatus == PersonnelStatus.Pending)
{
// 首次审批:人员等级根据提交单位的层级确定
// 例如:营级单位提交的人才,团级审批后应为"营级人才"
actualLevel = (PersonnelLevel)(int)personnel.SubmittedByUnit!.Level;
// 验证审批单位层级必须高于提交单位层级(数值越小层级越高)
var unitLevelValue = (int)approvedByUnit.Level;
var submittedUnitLevelValue = (int)personnel.SubmittedByUnit!.Level;
if (unitLevelValue >= submittedUnitLevelValue)
throw new ArgumentException("审批单位层级必须高于提交单位层级");
}
else if (previousStatus == PersonnelStatus.Approved)
{
// 向上申报:人员等级升级为上报单位(即之前的审批单位)的层级
// 例如:营级人才由团级向上申报,师级审批后应为"团级人才"
if (personnel.ApprovedByUnit == null)
throw new ArgumentException("无法确定上报单位");
actualLevel = (PersonnelLevel)(int)personnel.ApprovedByUnit.Level;
// 验证审批单位层级必须高于当前审批单位层级(数值越小层级越高)
var unitLevelValue = (int)approvedByUnit.Level;
var currentApprovedUnitLevelValue = (int)personnel.ApprovedByUnit.Level;
if (unitLevelValue >= currentApprovedUnitLevelValue)
throw new ArgumentException("审批单位层级必须高于当前审批单位层级");
}
else
{
throw new ArgumentException("该人员状态不允许审批");
}
}
personnel.Status = PersonnelStatus.Approved;
personnel.ApprovedByUnitId = approvedByUnitId;
personnel.ApprovedLevel = actualLevel;
personnel.ApprovedAt = DateTime.UtcNow;
await _context.SaveChangesAsync();
// 记录审批历史
var userId = await GetUserIdByUnitAsync(approvedByUnitId);
var actionType = previousStatus == PersonnelStatus.Approved
? PersonnelApprovalAction.LevelUpgraded
: PersonnelApprovalAction.Approved;
var comments = previousStatus == PersonnelStatus.Approved
? $"向上申报通过,等级从{GetLevelName(previousLevel)}升级为{GetLevelName(actualLevel)}"
: "审批通过";
await RecordApprovalHistoryAsync(personnelId, actionType,
previousStatus, PersonnelStatus.Approved, previousLevel, actualLevel,
userId, approvedByUnitId, comments);
_logger.LogInformation("人员 {PersonnelId} 已被单位 {UnitId} 审批通过,等级:{Level}",
personnelId, approvedByUnitId, actualLevel);
return personnel;
}
/// <summary>
/// 获取等级名称
/// </summary>
private static string GetLevelName(PersonnelLevel? level)
{
return level switch
{
PersonnelLevel.Division => "师级人才",
PersonnelLevel.Regiment => "团级人才",
PersonnelLevel.Battalion => "营级人才",
PersonnelLevel.Company => "连级人才",
_ => "未定级"
};
}
public async Task<Personnel> RejectAsync(int personnelId, int reviewedByUserId)
{
var personnel = await _context.Personnel.FindAsync(personnelId);
if (personnel == null)
throw new ArgumentException("人员记录不存在");
var previousStatus = personnel.Status;
personnel.Status = PersonnelStatus.Rejected;
await _context.SaveChangesAsync();
// 记录审批历史
await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.Rejected,
previousStatus, PersonnelStatus.Rejected, null, null,
reviewedByUserId, null, "审批拒绝");
_logger.LogInformation("人员 {PersonnelId} 已被用户 {UserId} 拒绝", personnelId, reviewedByUserId);
return personnel;
}
public async Task DeleteAsync(int id)
{
var personnel = await _context.Personnel.FindAsync(id);
if (personnel == null)
throw new ArgumentException("人员记录不存在");
// 删除关联的文件
if (!string.IsNullOrEmpty(personnel.PhotoPath))
{
await _fileUploadService.DeleteFileAsync(personnel.PhotoPath);
}
if (!string.IsNullOrEmpty(personnel.SupportingDocuments))
{
await _fileUploadService.DeleteFileAsync(personnel.SupportingDocuments);
}
_context.Personnel.Remove(personnel);
await _context.SaveChangesAsync();
_logger.LogInformation("人员记录 {PersonnelId} 已删除", id);
}
public async Task<Personnel> SubmitPersonnelAsync(Personnel personnel, IFormFile? photo, IFormFile? supportingDocument)
{
// 验证人员数据完整性
var validation = await ValidatePersonnelDataAsync(personnel);
if (!validation.IsValid)
{
throw new ArgumentException($"人员数据验证失败:{string.Join(", ", validation.Errors)}");
}
// 处理照片上传
if (photo != null)
{
try
{
personnel.PhotoPath = await _fileUploadService.UploadPhotoAsync(photo);
_logger.LogInformation("人员照片上传成功:{PhotoPath}", personnel.PhotoPath);
}
catch (Exception ex)
{
_logger.LogError(ex, "人员照片上传失败");
throw new InvalidOperationException($"照片上传失败:{ex.Message}");
}
}
// 处理支持文档上传
if (supportingDocument != null)
{
try
{
personnel.SupportingDocuments = await _fileUploadService.UploadDocumentAsync(supportingDocument);
_logger.LogInformation("支持文档上传成功:{DocumentPath}", personnel.SupportingDocuments);
}
catch (Exception ex)
{
_logger.LogError(ex, "支持文档上传失败");
throw new InvalidOperationException($"支持文档上传失败:{ex.Message}");
}
}
// 设置提交状态和时间
personnel.Status = PersonnelStatus.Pending;
personnel.SubmittedAt = DateTime.UtcNow;
_context.Personnel.Add(personnel);
await _context.SaveChangesAsync();
_logger.LogInformation("人员数据提交成功ID{PersonnelId},提交单位:{UnitId}",
personnel.Id, personnel.SubmittedByUnitId);
return personnel;
}
public async Task<PersonnelValidationResult> ValidatePersonnelDataAsync(Personnel personnel)
{
var errors = new List<string>();
// 验证必填字段
if (string.IsNullOrWhiteSpace(personnel.Name))
errors.Add("姓名不能为空");
if (string.IsNullOrWhiteSpace(personnel.Position))
errors.Add("职位不能为空");
if (string.IsNullOrWhiteSpace(personnel.Rank))
errors.Add("军衔不能为空");
// Gender和Age已设置默认值不需要验证
// IdNumber士兵证号是可选的不需要验证必填
if (personnel.SubmittedByUnitId <= 0)
errors.Add("提交单位不能为空");
// 验证士兵证号格式(如果提供了)
// 注意士兵证号不是身份证号格式可能不同这里移除18位的限制
// if (!string.IsNullOrWhiteSpace(personnel.IdNumber))
// {
// if (personnel.IdNumber.Length != 18)
// errors.Add("身份证号必须为18位");
// }
// 验证士兵证号唯一性(如果提供了)
if (!string.IsNullOrWhiteSpace(personnel.IdNumber))
{
var existingPersonnel = await _context.Personnel
.FirstOrDefaultAsync(p => p.IdNumber == personnel.IdNumber && p.Id != personnel.Id);
if (existingPersonnel != null)
errors.Add("士兵证号已存在");
}
// 验证提交单位是否存在
if (personnel.SubmittedByUnitId > 0)
{
var unit = await _context.OrganizationalUnits.FindAsync(personnel.SubmittedByUnitId);
if (unit == null)
errors.Add("提交单位不存在");
}
return errors.Any() ? PersonnelValidationResult.Failure(errors.ToArray()) : PersonnelValidationResult.Success();
}
public async Task<OrganizationalUnit> GetApprovalTargetUnitAsync(int submittingUnitId)
{
var submittingUnit = await _context.OrganizationalUnits
.Include(u => u.Parent)
.FirstOrDefaultAsync(u => u.Id == submittingUnitId);
if (submittingUnit == null)
throw new ArgumentException("提交单位不存在");
// 审批路由逻辑:提交给上级单位审批
if (submittingUnit.Parent != null)
{
return submittingUnit.Parent;
}
// 如果是师团级别,则自己审批
if (submittingUnit.Level == OrganizationalLevel.Division)
{
return submittingUnit;
}
throw new InvalidOperationException("无法确定审批目标单位");
}
public async Task<bool> CanModifyPersonnelAsync(int personnelId)
{
var personnel = await _context.Personnel.FindAsync(personnelId);
if (personnel == null)
return false;
// 只有待审批状态的人员可以直接修改
if (personnel.Status == PersonnelStatus.Pending)
return true;
// 已审批的人员需要通过工作流修改
return false;
}
public async Task<ApprovalRequest> RequestPersonnelModificationAsync(int personnelId, int requestedByUserId, string reason, Personnel modifiedPersonnel)
{
var originalPersonnel = await _context.Personnel
.Include(p => p.SubmittedByUnit)
.FirstOrDefaultAsync(p => p.Id == personnelId);
if (originalPersonnel == null)
throw new ArgumentException("人员记录不存在");
if (originalPersonnel.Status != PersonnelStatus.Approved)
throw new InvalidOperationException("只能修改已审批的人员记录");
var user = await _context.UserAccounts
.Include(u => u.OrganizationalUnit)
.FirstOrDefaultAsync(u => u.Id == requestedByUserId);
if (user == null)
throw new ArgumentException("请求用户不存在");
// 序列化原始数据和修改数据
var originalData = JsonSerializer.Serialize(new
{
originalPersonnel.Name,
originalPersonnel.Position,
originalPersonnel.Rank,
originalPersonnel.Gender,
originalPersonnel.IdNumber,
originalPersonnel.ProfessionalTitle,
originalPersonnel.EducationLevel,
originalPersonnel.Age,
originalPersonnel.Height,
originalPersonnel.ContactInfo,
originalPersonnel.Hometown,
originalPersonnel.TrainingParticipation,
originalPersonnel.Achievements
});
var requestedChanges = JsonSerializer.Serialize(new
{
modifiedPersonnel.Name,
modifiedPersonnel.Position,
modifiedPersonnel.Rank,
modifiedPersonnel.Gender,
modifiedPersonnel.IdNumber,
modifiedPersonnel.ProfessionalTitle,
modifiedPersonnel.EducationLevel,
modifiedPersonnel.Age,
modifiedPersonnel.Height,
modifiedPersonnel.ContactInfo,
modifiedPersonnel.Hometown,
modifiedPersonnel.TrainingParticipation,
modifiedPersonnel.Achievements
});
var request = await _workflowService.CreateModificationRequestAsync(
ApprovalRequestType.PersonnelModification,
personnelId,
requestedByUserId,
user.OrganizationalUnitId,
reason,
originalData,
requestedChanges);
_logger.LogInformation("人员修改请求已创建ID{RequestId}人员ID{PersonnelId}",
request.Id, personnelId);
return request;
}
public async Task<IEnumerable<Personnel>> GetVisiblePersonnelAsync(int unitId, OrganizationalLevel userLevel)
{
// 根据组织层级获取可见的人员
// 用户只能查看当前和下级组织单位的人员
var subordinates = await _organizationService.GetSubordinatesAsync(unitId);
var visibleUnitIds = subordinates.Select(s => s.Id).ToList();
visibleUnitIds.Add(unitId);
var query = _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.Where(p => visibleUnitIds.Contains(p.SubmittedByUnitId));
// 根据人员等级进一步过滤
// 用户只能查看等级不高于自己组织层级的人员
var maxPersonnelLevel = (PersonnelLevel)(int)userLevel;
query = query.Where(p => p.ApprovedLevel == null || p.ApprovedLevel >= maxPersonnelLevel);
return await query.OrderByDescending(p => p.SubmittedAt).ToListAsync();
}
public async Task<Personnel> TransferPersonnelAsync(int personnelId, int targetUnitId, int approvedByUnitId)
{
var personnel = await _context.Personnel
.Include(p => p.SubmittedByUnit)
.FirstOrDefaultAsync(p => p.Id == personnelId);
if (personnel == null)
throw new ArgumentException("人员记录不存在");
if (personnel.Status != PersonnelStatus.Approved)
throw new InvalidOperationException("只能转移已审批的人员");
var targetUnit = await _context.OrganizationalUnits.FindAsync(targetUnitId);
if (targetUnit == null)
throw new ArgumentException("目标单位不存在");
var approvedByUnit = await _context.OrganizationalUnits.FindAsync(approvedByUnitId);
if (approvedByUnit == null)
throw new ArgumentException("审批单位不存在");
// 验证审批单位有权限进行跨层级转移
// 审批单位层级必须高于或等于目标单位层级
if ((int)approvedByUnit.Level > (int)targetUnit.Level)
throw new UnauthorizedAccessException("审批单位层级不足以进行此转移");
// 更新人员所属单位
personnel.SubmittedByUnitId = targetUnitId;
// 根据新的审批单位重新设置人员等级
var newLevel = (PersonnelLevel)(int)approvedByUnit.Level;
personnel.ApprovedLevel = newLevel;
personnel.ApprovedByUnitId = approvedByUnitId;
personnel.ApprovedAt = DateTime.UtcNow;
await _context.SaveChangesAsync();
_logger.LogInformation("人员 {PersonnelId} 已从单位 {FromUnitId} 转移到单位 {ToUnitId},审批单位:{ApprovedByUnitId}",
personnelId, personnel.SubmittedByUnit.Id, targetUnitId, approvedByUnitId);
return personnel;
}
public async Task<IEnumerable<Personnel>> GetPendingApprovalPersonnelAsync(int unitId)
{
// 获取需要当前单位审批的人员(来自下级单位的提交)
var subordinates = await _organizationService.GetSubordinatesAsync(unitId);
var subordinateIds = subordinates.Select(s => s.Id).ToList();
return await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Where(p => subordinateIds.Contains(p.SubmittedByUnitId) && p.Status == PersonnelStatus.Pending)
.OrderBy(p => p.SubmittedAt)
.ToListAsync();
}
public async Task<IEnumerable<Personnel>> BatchApprovePersonnelAsync(int[] personnelIds, int approvedByUnitId, PersonnelLevel level)
{
var approvedPersonnel = new List<Personnel>();
foreach (var personnelId in personnelIds)
{
try
{
var personnel = await ApproveAsync(personnelId, approvedByUnitId, level);
approvedPersonnel.Add(personnel);
// 记录审批历史
await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.Approved,
PersonnelStatus.Pending, PersonnelStatus.Approved, null, level,
await GetUserIdByUnitAsync(approvedByUnitId), approvedByUnitId, "批量审批通过");
}
catch (Exception ex)
{
_logger.LogError(ex, "批量审批人员 {PersonnelId} 失败", personnelId);
// 继续处理其他人员,不中断整个批量操作
}
}
return approvedPersonnel;
}
public async Task<IEnumerable<Personnel>> BatchRejectPersonnelAsync(int[] personnelIds, int reviewedByUserId, string reason)
{
var rejectedPersonnel = new List<Personnel>();
foreach (var personnelId in personnelIds)
{
try
{
var personnel = await RejectAsync(personnelId, reviewedByUserId);
rejectedPersonnel.Add(personnel);
// 记录审批历史
await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.Rejected,
PersonnelStatus.Pending, PersonnelStatus.Rejected, null, null,
reviewedByUserId, null, reason);
}
catch (Exception ex)
{
_logger.LogError(ex, "批量拒绝人员 {PersonnelId} 失败", personnelId);
// 继续处理其他人员,不中断整个批量操作
}
}
return rejectedPersonnel;
}
public async Task<IEnumerable<PersonnelApprovalHistory>> GetPersonnelApprovalHistoryAsync(int personnelId)
{
return await _context.PersonnelApprovalHistories
.Include(h => h.ReviewedByUser)
.Include(h => h.ReviewedByUnit)
.Where(h => h.PersonnelId == personnelId)
.OrderByDescending(h => h.ReviewedAt)
.ToListAsync();
}
public async Task<bool> CanApprovePersonnelAsync(int userId, int personnelId)
{
var user = await _context.UserAccounts
.Include(u => u.OrganizationalUnit)
.FirstOrDefaultAsync(u => u.Id == userId);
if (user == null)
return false;
var personnel = await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.FirstOrDefaultAsync(p => p.Id == personnelId);
if (personnel == null)
return false;
// 已拒绝的人员不能审批
if (personnel.Status == PersonnelStatus.Rejected)
return false;
// 本单位不能审批自己提交的人员,必须由上级单位审批
if (user.OrganizationalUnitId == personnel.SubmittedByUnitId)
return false;
// 如果是已审批的人员(向上申报场景)
if (personnel.Status == PersonnelStatus.Approved && personnel.ApprovedByUnitId.HasValue)
{
// 用户单位层级必须高于已审批单位层级(数值越小层级越高)
if ((int)user.OrganizationalUnit!.Level >= (int)personnel.ApprovedByUnit!.Level)
return false;
// 向上申报场景:检查用户单位是否是当前审批单位的上级
var isParentOfApprovedUnit = await _organizationService.IsParentUnitAsync(
user.OrganizationalUnitId, personnel.ApprovedByUnitId.Value);
return isParentOfApprovedUnit;
}
// 首次审批场景:检查用户的组织单位是否是提交单位的上级
var isParent = await _organizationService.IsParentUnitAsync(user.OrganizationalUnitId, personnel.SubmittedByUnitId);
return isParent;
}
/// <summary>
/// 记录人员审批历史
/// </summary>
private async Task RecordApprovalHistoryAsync(int personnelId, PersonnelApprovalAction action,
PersonnelStatus? previousStatus, PersonnelStatus newStatus,
PersonnelLevel? previousLevel, PersonnelLevel? newLevel,
int reviewedByUserId, int? reviewedByUnitId, string? comments)
{
var history = new PersonnelApprovalHistory
{
PersonnelId = personnelId,
Action = action,
PreviousStatus = previousStatus,
NewStatus = newStatus,
PreviousLevel = previousLevel,
NewLevel = newLevel,
ReviewedByUserId = reviewedByUserId,
ReviewedByUnitId = reviewedByUnitId,
Comments = comments,
ReviewedAt = DateTime.UtcNow
};
_context.PersonnelApprovalHistories.Add(history);
await _context.SaveChangesAsync();
}
/// <summary>
/// 根据单位ID获取用户ID用于审批历史记录
/// </summary>
private async Task<int> GetUserIdByUnitAsync(int unitId)
{
var user = await _context.UserAccounts
.FirstOrDefaultAsync(u => u.OrganizationalUnitId == unitId);
return user?.Id ?? 0; // 如果找不到用户返回0作为系统操作
}
/// <summary>
/// 发起向上申报请求
/// </summary>
public async Task<Personnel> RequestUpgradeAsync(int personnelId, int requestByUnitId)
{
var personnel = await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.FirstOrDefaultAsync(p => p.Id == personnelId);
if (personnel == null)
throw new ArgumentException("人员记录不存在");
if (personnel.Status != PersonnelStatus.Approved)
throw new ArgumentException("只有已审批的人员才能向上申报");
if (personnel.PendingUpgradeByUnitId.HasValue)
throw new ArgumentException("该人员已有待处理的向上申报请求");
var requestByUnit = await _context.OrganizationalUnits.FindAsync(requestByUnitId);
if (requestByUnit == null)
throw new ArgumentException("申报单位不存在");
// 师级人才不能再向上申报
if (personnel.ApprovedLevel == PersonnelLevel.Division)
throw new ArgumentException("师级人才不能再向上申报");
// 特殊情况:师部可以直接升级团级人才为师级
// 此时师部既是申报单位也是审批单位
if (requestByUnit.Level == OrganizationalLevel.Division &&
personnel.ApprovedLevel == PersonnelLevel.Regiment)
{
// 师部直接升级团级人才,不需要验证是否是审批单位
// 标记为待向上申报(由师部自己审批)
personnel.PendingUpgradeByUnitId = requestByUnitId;
await _context.SaveChangesAsync();
_logger.LogInformation("团级人才 {PersonnelId} 已由师部 {UnitId} 发起直接升级请求",
personnelId, requestByUnitId);
return personnel;
}
// 验证申报单位必须是当前审批单位
if (personnel.ApprovedByUnitId != requestByUnitId)
throw new ArgumentException("只有当前审批单位才能发起向上申报");
// 标记为待向上申报
personnel.PendingUpgradeByUnitId = requestByUnitId;
await _context.SaveChangesAsync();
_logger.LogInformation("人员 {PersonnelId} 已由单位 {UnitId} 发起向上申报请求",
personnelId, requestByUnitId);
return personnel;
}
/// <summary>
/// 审批向上申报请求
/// </summary>
public async Task<Personnel> ApproveUpgradeAsync(int personnelId, int approvedByUnitId)
{
var personnel = await _context.Personnel
.Include(p => p.SubmittedByUnit)
.Include(p => p.ApprovedByUnit)
.Include(p => p.PendingUpgradeByUnit)
.FirstOrDefaultAsync(p => p.Id == personnelId);
if (personnel == null)
throw new ArgumentException("人员记录不存在");
if (!personnel.PendingUpgradeByUnitId.HasValue)
throw new ArgumentException("该人员没有待处理的向上申报请求");
var approvedByUnit = await _context.OrganizationalUnits.FindAsync(approvedByUnitId);
if (approvedByUnit == null)
throw new ArgumentException("审批单位不存在");
_logger.LogInformation("ApproveUpgrade: personnelId={PersonnelId}, approvedByUnitId={ApprovedByUnitId}, pendingUpgradeByUnitId={PendingUpgradeByUnitId}, approvedByUnitLevel={Level}, personnelApprovedLevel={PersonnelLevel}",
personnelId, approvedByUnitId, personnel.PendingUpgradeByUnitId.Value, approvedByUnit.Level, personnel.ApprovedLevel);
var previousLevel = personnel.ApprovedLevel;
PersonnelLevel newLevel;
// 特殊情况:师部直接升级团级人才为师级
var isDivisionUnit = approvedByUnit.Level == OrganizationalLevel.Division;
var isRegimentPersonnel = personnel.ApprovedLevel == PersonnelLevel.Regiment;
_logger.LogInformation("检查条件: isDivisionUnit={IsDivision}, isRegimentPersonnel={IsRegiment}",
isDivisionUnit, isRegimentPersonnel);
if (isDivisionUnit && isRegimentPersonnel)
{
// 师部直接升级团级人才为师级
newLevel = PersonnelLevel.Division;
_logger.LogInformation("师部直接升级团级人才为师级");
}
else
{
// 验证审批单位必须是申报单位的上级
var isParent = await _organizationService.IsParentUnitAsync(approvedByUnitId, personnel.PendingUpgradeByUnitId.Value);
_logger.LogInformation("检查上级关系: isParent={IsParent}", isParent);
if (!isParent)
throw new ArgumentException("审批单位必须是申报单位的上级");
// 人才等级升级为申报单位的等级
newLevel = (PersonnelLevel)(int)personnel.PendingUpgradeByUnit!.Level;
}
personnel.ApprovedLevel = newLevel;
personnel.ApprovedByUnitId = approvedByUnitId;
personnel.ApprovedAt = DateTime.UtcNow;
personnel.PendingUpgradeByUnitId = null; // 清除待申报标记
await _context.SaveChangesAsync();
// 记录审批历史
var userId = await GetUserIdByUnitAsync(approvedByUnitId);
await RecordApprovalHistoryAsync(personnelId, PersonnelApprovalAction.LevelUpgraded,
PersonnelStatus.Approved, PersonnelStatus.Approved, previousLevel, newLevel,
userId, approvedByUnitId, $"向上申报通过,等级从{GetLevelName(previousLevel)}升级为{GetLevelName(newLevel)}");
_logger.LogInformation("人员 {PersonnelId} 向上申报已被单位 {UnitId} 审批通过,等级升级为 {Level}",
personnelId, approvedByUnitId, newLevel);
return personnel;
}
}