using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using ZhonTai.Admin.Core.Dto; using ZhonTai.Admin.Services; using NPP.SmartSchedue.Api.Contracts.Services.Personnel; using NPP.SmartSchedue.Api.Contracts.Services.Personnel.Input; using NPP.SmartSchedue.Api.Contracts.Services.Personnel.Output; using NPP.SmartSchedue.Api.Repositories.Personnel; using NPP.SmartSchedue.Api.Contracts.Domain.Personnel; using ZhonTai.Admin.Core.Consts; using ZhonTai.DynamicApi; using ZhonTai.DynamicApi.Attributes; using ZhonTai.Admin.Domain.User; namespace NPP.SmartSchedue.Api.Services.Personnel; /// /// 人员资质绑定服务 /// [DynamicApi(Area = "app")] public class PersonnelQualificationService : BaseService, IPersonnelQualificationService, IDynamicApi { private readonly PersonnelQualificationRepository _personnelQualificationRepository; private readonly QualificationRepository _qualificationRepository; public PersonnelQualificationService( PersonnelQualificationRepository personnelQualificationRepository, QualificationRepository qualificationRepository) { _personnelQualificationRepository = personnelQualificationRepository; _qualificationRepository = qualificationRepository; } /// /// 查询 /// /// /// public async Task GetAsync(long id) { var output = await _personnelQualificationRepository.Select .WhereDynamic(id) .ToOneAsync(); return output; } /// /// 查询分页 /// /// /// [HttpPost] public async Task> GetPageAsync(PageInput input) { var list = await _personnelQualificationRepository.Select .WhereIf(input.Filter?.PersonnelId.HasValue == true, a => a.PersonnelId == input.Filter.PersonnelId) .WhereIf(input.Filter?.QualificationId.HasValue == true, a => a.QualificationId == input.Filter.QualificationId) .WhereIf(input.Filter?.IsActive.HasValue == true, a => a.IsActive == input.Filter.IsActive) .Count(out var total) .OrderByDescending(a => a.Id) .Page(input.CurrentPage, input.PageSize) .ToListAsync(); var data = new PageOutput() { List = list, Total = total }; return data; } /// /// 添加 /// /// /// public async Task AddAsync(PersonnelQualificationAddInput input) { var entity = Mapper.Map(input); var result = await _personnelQualificationRepository.InsertAsync(entity); return result.Id; } /// /// 修改 /// /// /// public async Task UpdateAsync(PersonnelQualificationUpdateInput input) { var entity = await _personnelQualificationRepository.GetAsync(input.Id); Mapper.Map(input, entity); await _personnelQualificationRepository.UpdateAsync(entity); } /// /// 删除 /// /// /// public async Task DeleteAsync(long id) { await _personnelQualificationRepository.DeleteAsync(id); } /// /// 软删除 /// /// /// public async Task SoftDeleteAsync(long id) { await _personnelQualificationRepository.SoftDeleteAsync(id); } /// /// 批量软删除 /// /// /// public async Task BatchSoftDeleteAsync(long[] ids) { await _personnelQualificationRepository.SoftDeleteAsync(ids); } /// /// 根据资质ID列表获取具有这些资质的人员基础信息列表(ID + 姓名) /// /// 资质ID列表 /// public async Task> GetPersonnelIdsByQualificationIdsAsync(long[] qualificationIds) { var personnelInfoMap = new Dictionary(); var qualifiedPersonnel = await _personnelQualificationRepository.Select .Where(pq => qualificationIds.Contains(pq.QualificationId) && pq.IsActive) .ToListAsync(p => new PersonnelBasicInfo { Id = p.PersonnelId, Name = p.PersonnelName // 临时使用默认格式 }); // 去重处理 foreach (var personnel in qualifiedPersonnel) { personnelInfoMap[personnel.Id] = personnel; } return personnelInfoMap.Values.ToList(); } /// /// 根据资质ID字符串(逗号分隔)获取具有这些资质的人员基础信息列表(ID + 姓名) /// /// 资质ID字符串,使用逗号分隔 /// public async Task> GetPersonnelIdsByQualificationIdsAsync(string qualificationIds) { // 检查输入参数的有效性 if (string.IsNullOrWhiteSpace(qualificationIds)) { return new List(); } try { // 解析逗号分隔的字符串为long数组 var qualificationIdArray = qualificationIds .Split(',', StringSplitOptions.RemoveEmptyEntries) .Select(id => id.Trim()) .Where(id => !string.IsNullOrWhiteSpace(id)) .Select(long.Parse) .ToArray(); // 调用原有的数组版本方法 return await GetPersonnelIdsByQualificationIdsAsync(qualificationIdArray); } catch (FormatException) { // 如果解析失败,返回空列表而不是抛出异常 return new List(); } catch (OverflowException) { // 如果数值超出范围,返回空列表而不是抛出异常 return new List(); } } /// /// 根据人员ID获取其所有有效资质信息 /// /// 人员ID /// public async Task> GetActiveQualificationsByPersonnelIdAsync(long personnelId) { var input = new PageInput { Filter = new PersonnelQualificationGetPageInput { PersonnelId = personnelId, IsActive = true }, PageSize = 1000, CurrentPage = 1 }; var result = await GetPageAsync(input); return result.List?.ToList() ?? new List(); } /// /// 获取所有有资质记录的人员列表(用于人员池构建) /// 深度业务思考:从资质表获取所有关联人员,确保智能分配系统的人员池完整性 /// /// 所有有资质记录的人员资质信息 public async Task> GetAllPersonnelWithQualificationsAsync() { try { // 获取所有有效的人员资质记录 // 这里不分页,获取全量数据用于构建人员池 var entities = await _personnelQualificationRepository.Select .Where(pq => pq.PersonnelId > 0) // 确保有有效的人员ID .OrderBy(pq => pq.PersonnelId) .ToListAsync(); // 手动映射确保PersonnelName字段被正确传递 var results = entities.Select(entity => new PersonnelQualificationGetPageOutput { Id = entity.Id, PersonnelId = entity.PersonnelId, PersonnelName = entity.PersonnelName, // 【关键修复】确保人员姓名被正确映射 QualificationId = entity.QualificationId, QualificationLevel = entity.QualificationLevel, ExpiryDate = entity.ExpiryDate, ExpiryWarningDays = entity.ExpiryWarningDays, RenewalDate = entity.RenewalDate, IsActive = entity.IsActive }).ToList(); return results; } catch (Exception ex) { return new List(); } } /// /// 根据人员ID获取其所有资质记录(包括无效的) /// /// 人员ID /// 人员的所有资质记录 public async Task> GetByPersonnelIdAsync(long personnelId) { try { // 获取指定人员的所有资质记录,不论是否有效 var entities = await _personnelQualificationRepository.Select .Where(pq => pq.PersonnelId == personnelId) .OrderBy(pq => pq.QualificationId) .ToListAsync(); // 手动映射确保PersonnelName字段被正确传递 var results = entities.Select(entity => new PersonnelQualificationGetPageOutput { Id = entity.Id, PersonnelId = entity.PersonnelId, PersonnelName = entity.PersonnelName, // 【关键修复】确保人员姓名被正确映射 QualificationId = entity.QualificationId, QualificationLevel = entity.QualificationLevel, ExpiryDate = entity.ExpiryDate, ExpiryWarningDays = entity.ExpiryWarningDays, RenewalDate = entity.RenewalDate, IsActive = entity.IsActive }).ToList(); return results; } catch (Exception ex) { return new List(); } } /// /// 根据人员ID获取其所有有效的资质实体列表(用于智能分配系统资质匹配) /// 深度业务思考:智能分配系统需要完整的资质实体信息进行精确匹配计算 /// 1. 只获取有效状态的资质记录(IsActive = true) /// 2. 检查资质有效期,排除已过期资质 /// 3. 返回完整实体信息供复杂业务逻辑使用 /// 4. 异常处理确保系统稳定性 /// /// 人员ID /// 人员有效资质实体列表 public async Task> GetPersonnelQualificationsAsync(long personnelId) { try { // 深度思考:智能分配系统需要精确的资质匹配 // 必须同时满足:1. 状态有效 2. 未过期 3. 有效的人员关联 var currentTime = DateTime.Now; var qualificationEntities = await _personnelQualificationRepository.Select .Where(pq => pq.PersonnelId == personnelId && pq.IsActive && // 必须是激活状态 (pq.ExpiryDate == null || pq.ExpiryDate > currentTime)) // 未过期或永久有效 .OrderBy(pq => pq.QualificationId) .ToListAsync(); return qualificationEntities ?? new List(); } catch (Exception ex) { return new List(); } } /// /// 获取人员资质统计信息(横坐标为资质,纵坐标为人员数量) /// /// 人员资质统计结果 public async Task GetPersonnelQualificationStatisticsAsync() { try { // 获取所有有效的人员资质记录 var activeQualifications = await _personnelQualificationRepository.Select .Where(pq => pq.IsActive && (pq.ExpiryDate == null || pq.ExpiryDate > DateTime.Now)) .ToListAsync(pq => new { pq.QualificationId, pq.PersonnelId }); // 按资质ID分组并统计每个资质的人员数量 var qualificationStatistics = activeQualifications .GroupBy(q => q.QualificationId) .Select(g => new { QualificationId = g.Key, PersonnelCount = g.Select(x => x.PersonnelId).Distinct().Count() }) .ToList(); // 获取所有资质的名称 var qualificationIds = qualificationStatistics.Select(q => q.QualificationId).ToArray(); var qualifications = await _qualificationRepository.Select .Where(q => qualificationIds.Contains(q.Id)) .ToListAsync(q => new { q.Id, q.Name }); var qualificationsDict = qualifications.ToDictionary(q => q.Id, q => q.Name); // 构建统计结果 var statistics = qualificationStatistics .Select(stat => new PersonnelQualificationStatistics { QualificationId = stat.QualificationId, QualificationName = qualificationsDict.ContainsKey(stat.QualificationId) ? qualificationsDict[stat.QualificationId] : $"未知资质({stat.QualificationId})", PersonnelCount = stat.PersonnelCount }) .ToList(); return new PersonnelQualificationStatisticsResult { Statistics = statistics, GeneratedTime = DateTime.Now }; } catch (Exception ex) { // 发生异常时返回空的统计结果 return new PersonnelQualificationStatisticsResult { Statistics = new List(), GeneratedTime = DateTime.Now }; } } /// /// 获取预警期内即将到期的人员资质清单 /// /// 基准日期(通常为 DateTime.Today) /// 限定人员范围(可选) /// 是否包含已过期记录 /// public async Task> GetExpiringAsync(DateTime today, IList personnelIds = null, bool includeExpired = false) { var baseDate = today.Date; var select = _personnelQualificationRepository.Select .Where(pq => pq.IsActive) .Where(pq => pq.ExpiryDate != null) .Where(pq => pq.ExpiryWarningDays != null && pq.ExpiryWarningDays > 0); if (personnelIds != null && personnelIds.Count > 0) { select = select.Where(pq => personnelIds.Contains(pq.PersonnelId)); } var list = await select.ToListAsync(); // 批量查询资质名称,避免 N+1 var qIds = list.Select(x => x.QualificationId).Distinct().ToArray(); var qNameMap = qIds.Length == 0 ? new Dictionary() : (await _qualificationRepository.Select .Where(q => qIds.Contains(q.Id)) .ToListAsync(q => new { q.Id, q.Name })) .ToDictionary(x => x.Id, x => x.Name ?? string.Empty); var result = new List(list.Count); foreach (var it in list) { var expiry = it.ExpiryDate.Value.Date; var daysLeft = (int)Math.Floor((expiry - baseDate).TotalDays); bool inWindow = includeExpired ? daysLeft <= it.ExpiryWarningDays.Value : daysLeft >= 0 && daysLeft <= it.ExpiryWarningDays.Value; if (!inWindow) continue; result.Add(new ExpiringQualificationItemOutput { PersonnelId = it.PersonnelId, PersonnelName = it.PersonnelName, PersonnelCode = it.PersonnelCode, QualificationId = it.QualificationId, QualificationLevel = it.QualificationLevel, ExpiryDate = it.ExpiryDate, DaysLeft = daysLeft, QualificationName = qNameMap.TryGetValue(it.QualificationId, out var qn) ? qn : string.Empty }); } return result .OrderBy(x => x.DaysLeft) .ThenBy(x => x.ExpiryDate) .ToList(); } }