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.Contracts.Services.Time; using NPP.SmartSchedue.Api.Contracts.Services.Time.Input; using ZhonTai.DynamicApi; using ZhonTai.DynamicApi.Attributes; namespace NPP.SmartSchedue.Api.Services.Personnel; /// /// 人员综合服务 /// [DynamicApi(Area = "app")] public class PersonService : BaseService, IPersonService, IDynamicApi { private readonly IPersonnelWorkLimitService _personnelWorkLimitService; private readonly IPersonnelQualificationService _personnelQualificationService; private readonly IQualificationService _qualificationService; private readonly IEmployeeLeaveService _employeeLeaveService; private readonly IShiftService _shiftService; public PersonService( IPersonnelWorkLimitService personnelWorkLimitService, IPersonnelQualificationService personnelQualificationService, IQualificationService qualificationService, IEmployeeLeaveService employeeLeaveService, IShiftService shiftService) { _personnelWorkLimitService = personnelWorkLimitService; _personnelQualificationService = personnelQualificationService; _qualificationService = qualificationService; _employeeLeaveService = employeeLeaveService; _shiftService = shiftService; } /// /// 根据资质IDs、班次ID、工作日期,查询非请假的、有资质的人员 /// /// 资质ID列表 /// 班次ID /// 工作日期(将结合班次时间计算实际工作时间段) /// public async Task> GetAvailablePersonnelAsync( string qualificationIds, long shiftId, DateTime workStartTime) { var availablePersonnel = new List(); // 获取班次信息 var shift = await _shiftService.GetAsync(shiftId); if (shift == null) { return availablePersonnel; // 如果班次不存在,返回空列表 } // 计算实际工作时间段 var workDate = workStartTime.Date; // 取日期部分 var actualWorkStartTime = workDate.Add(shift.StartTime); var actualWorkEndTime = workDate.Add(shift.EndTime); // 处理跨天班次(如夜班:22:00-06:00) if (shift.EndTime < shift.StartTime) { actualWorkEndTime = actualWorkEndTime.AddDays(1); } // 获取所有有指定资质的人员基础信息 var qualifiedPersonnelList = await _personnelQualificationService.GetPersonnelIdsByQualificationIdsAsync(qualificationIds); // 检查每个有资质的人员是否在指定时间段内请假 foreach (var personnel in qualifiedPersonnelList) { // 注意:这里假设PersonnelId对应EmployeeId,如果不是需要添加映射逻辑 var isOnLeave = await _employeeLeaveService.HasApprovedLeaveInTimeRangeAsync( personnel.Id, actualWorkStartTime, actualWorkEndTime); // 如果没有请假,则添加到可用人员列表 if (!isOnLeave) { // 获取人员资质信息 var qualifications = await _personnelQualificationService.GetActiveQualificationsByPersonnelIdAsync(personnel.Id); availablePersonnel.Add(new AvailablePersonnelOutput { PersonnelId = personnel.Id, PersonnelName = personnel.Name, ShiftId = shiftId, AvailableStartTime = actualWorkStartTime, AvailableEndTime = actualWorkEndTime, Qualifications = qualifications, }); } } return availablePersonnel; } /// /// 检查人员是否具备指定资质 /// /// 人员ID /// 资质ID /// public async Task HasQualificationAsync(long personnelId, long qualificationId) { var input = new PageInput { Filter = new PersonnelQualificationGetPageInput { PersonnelId = personnelId, QualificationId = qualificationId, IsActive = true }, PageSize = 1, CurrentPage = 1 }; var result = await _personnelQualificationService.GetPageAsync(input); return result.Total > 0; } /// /// 获取所有人员池(用于智能分配) /// 深度业务思考:从资质表获取所有关联人员并去重,确保五层决策模型的完整性 /// /// 是否包含资质信息 /// 完整的人员池,用于后续的五层决策筛选 public async Task> GetAllPersonnelPoolAsync(bool includeQualifications = false) { try { // 从资质表获取所有有资质的人员ID,然后去重 // 这确保了获取的人员池都是有资质记录的人员 var allQualificationPersonnel = await _personnelQualificationService.GetAllPersonnelWithQualificationsAsync(); if (allQualificationPersonnel == null || !allQualificationPersonnel.Any()) { return new List(); } // 按人员ID去重分组,获取人员基础信息 var groupedByPersonnel = allQualificationPersonnel .Where(pq => pq.PersonnelId > 0) .GroupBy(pq => pq.PersonnelId) .Select(g => g.First()) // 每个人员只取一条记录来获取基础信息 .ToList(); var personnelPoolOutputs = new List(); foreach (var qualificationRecord in groupedByPersonnel) { var poolOutput = new PersonnelPoolOutput { Id = qualificationRecord.PersonnelId, PersonnelName = qualificationRecord.PersonnelName, IsActive = true, }; // 如果需要包含资质信息 if (includeQualifications) { poolOutput.Qualifications = await _personnelQualificationService.GetActiveQualificationsByPersonnelIdAsync( qualificationRecord.PersonnelId); } personnelPoolOutputs.Add(poolOutput); } return personnelPoolOutputs.OrderBy(p => p.PersonnelCode).ToList(); } catch (Exception ex) { return new List(); } } }