using Business.Domain; using Business.EntityFrameworkCore.SqlRepositories; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.EntityFrameworkCore; using SixLabors.ImageSharp; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Volo.Abp.Application.Services; using Business.Core.Utilities; using Quartz; namespace Business.ResourceExamineManagement { public class GetAvailableEquipmentAppService : ApplicationService { #region 服务 /// /// 模具清单 /// private ISqlRepository _moldToolList; /// /// 设备清单 /// private ISqlRepository _equipmentList; // private ISqlRepository _equipmentUsageLog; /// /// 工作日历 /// private ISqlRepository _shopCalendarWorkCtr; /// /// 排产结果明细 /// private ISqlRepository _scheduleResultOpMaster; /// /// Andon 模具异常记录 /// private ISqlRepository _sim_andon; /// /// 人员技能矩阵 /// private ISqlRepository _EmpSkills; /// /// 产线物料维护 /// private ISqlRepository _ProdLineDetail; #endregion #region 构造函数 public GetAvailableEquipmentAppService( ISqlRepository moldToolList, ISqlRepository equipmentList, ISqlRepository shopCalendarWorkCtr, ISqlRepository scheduleResultOpMaster, ISqlRepository sim_andon, ISqlRepository EmpSkills, ISqlRepository ProdLineDetail ) { _moldToolList = moldToolList; _equipmentList = equipmentList; _shopCalendarWorkCtr = shopCalendarWorkCtr; _scheduleResultOpMaster = scheduleResultOpMaster; _sim_andon = sim_andon; _EmpSkills = EmpSkills; _ProdLineDetail = ProdLineDetail; } #endregion public class Equipment { //设备名称 public string MachineName { get; set; } //资产编码 public string EquipmentAssetID { get; set; } //设别可用时间 public DateTime AvailableTime { get; set; } } public class AvailableEquipmentResult { /// /// 厂内设备编码 /// [Comment("厂内设备编码")] public string InternalEquipmentCode { get; set; } /// /// 可用设备数量 /// [Comment("可用设备数量")] public decimal AvailableEquipmentCount { get; set; } /// /// 可用设备列表 /// [Comment("可用设备列表")] public List AvailableEquipmentList { get; set; } } public class FilterTimeRange { //筛选开始时间 public DateTime FilterStartTime { get; set; } //筛选结束时间 public DateTime FilterEndTime { get; set; } } //获取可排产设备 public List GetAvailableEquipment(string InternalEquipmentCode, DateTime? QueryMoment, List scheduleMaster) { List EquipmentDetails = new List(); if (string.IsNullOrEmpty(InternalEquipmentCode) || QueryMoment == null) { return new List(); } if (InternalEquipmentCode.Contains('+')) { var codes = InternalEquipmentCode.Split('+'); int minAvailableCount = int.MaxValue; string minEquipmentCode = ""; string minEstimatedMaintenanceReleaseTime = ""; string minStandardRepairDays = ""; var AllavailableEquipmentList = _equipmentList .Select(p => codes.Contains(p.InternalEquipmentCode) && (p.IsSchedulable == 1 || (p.EstimatedMaintenanceReleaseTime.HasValue && p.EstimatedMaintenanceReleaseTime <= QueryMoment && p.IsSchedulable == 0))) .ToList(); foreach (var singleCode in codes) { var availableEquipmentList = AllavailableEquipmentList.Where(c => c.InternalEquipmentCode == singleCode).ToList(); int availableCount = availableEquipmentList.Count; // 计算该设备编码的可用设备数量 //for (int i = 0; i < availableEquipmentList.Count; i++) //{ // if (availableEquipmentList[i].IsSchedulable == 1) // { // availableCount++; // } // else // { // if (availableEquipmentList[i].EstimatedMaintenanceReleaseTime <= QueryMoment) // { // availableCount++; // } // } //} // 查询当前设备编码的已排产设备数量 int usedEquipmentCountForCode = scheduleMaster .Where(p => p.InternalEquipmentCode == singleCode && QueryMoment >= p.WorkStartTime && QueryMoment < p.WorkEndTime) .Sum(p => p.DeviceAllocationCount); // 从该设备编码的可用数量中减去对应的已排产数量 availableCount -= usedEquipmentCountForCode; availableCount = availableCount < 0 ? 0 : availableCount; // 确保数量不为负 // 更新最小的 AvailableCount if (availableCount < minAvailableCount) { minAvailableCount = availableCount; var nonSchedulableEquipmentList = availableEquipmentList .Where(p => p.IsSchedulable == 0 && p.EstimatedMaintenanceReleaseTime.HasValue) .OrderBy(p => p.EstimatedMaintenanceReleaseTime) .ToList(); if (nonSchedulableEquipmentList.Count > 0) { minEquipmentCode = $"{nonSchedulableEquipmentList[0].InternalEquipmentCode}"; minEstimatedMaintenanceReleaseTime = $"{nonSchedulableEquipmentList[0].EstimatedMaintenanceReleaseTime}"; minStandardRepairDays = $"{nonSchedulableEquipmentList[0].StandardRepairDays}"; } else { minEquipmentCode = " "; minEstimatedMaintenanceReleaseTime = " "; minStandardRepairDays = " "; } } } EquipmentDetails.Add($"{minAvailableCount}"); EquipmentDetails.Add(minEquipmentCode); EquipmentDetails.Add(minEstimatedMaintenanceReleaseTime); EquipmentDetails.Add(minStandardRepairDays); return EquipmentDetails; } else { var codes = InternalEquipmentCode.Split('/'); var availableEquipmentList = _equipmentList .Select(p => codes.Contains(p.InternalEquipmentCode) && (p.IsSchedulable == 1 || (p.EstimatedMaintenanceReleaseTime.HasValue && p.EstimatedMaintenanceReleaseTime <= QueryMoment && p.IsSchedulable == 0))) .ToList(); //int availableCount = _equipmentList // .Select(p => codes.Contains(p.InternalEquipmentCode) && (p.IsSchedulable == 1 || (p.EstimatedMaintenanceReleaseTime.HasValue && p.EstimatedMaintenanceReleaseTime <= QueryMoment && p.IsSchedulable == 0))) // .Count(); //for (int i = 0; i < availableEquipmentList.Count; i++) //{ // if (availableEquipmentList[i].IsSchedulable == 1) // { // availableCount++; // } // else // { // if (availableEquipmentList[i].EstimatedMaintenanceReleaseTime <= QueryMoment) // { // availableCount++; // } // } //} // 查询所有设备编码的已排产设备数量 int usedEquipmentCount = scheduleMaster .Where(p => p.InternalEquipmentCode == InternalEquipmentCode && QueryMoment >= p.WorkStartTime && QueryMoment < p.WorkEndTime) .Sum(p => p.DeviceAllocationCount); int availableCount = availableEquipmentList.Count(); // 从总可用设备数量中减去已排产设备数量 availableCount -= usedEquipmentCount; availableCount = availableCount <= 0 ? 0 : availableCount; EquipmentDetails.Add($"{availableCount}"); var nonSchedulableEquipmentList = availableEquipmentList .Where(p => p.IsSchedulable == 0 && p.EstimatedMaintenanceReleaseTime.HasValue) .OrderBy(p => p.EstimatedMaintenanceReleaseTime) .ToList(); if (nonSchedulableEquipmentList.Count <= 0) { EquipmentDetails.Add(" "); EquipmentDetails.Add(" "); EquipmentDetails.Add(" "); } else { EquipmentDetails.Add($"{nonSchedulableEquipmentList[0].InternalEquipmentCode}"); EquipmentDetails.Add($"{nonSchedulableEquipmentList[0].EstimatedMaintenanceReleaseTime}"); EquipmentDetails.Add($"{nonSchedulableEquipmentList[0].StandardRepairDays}"); } return EquipmentDetails; } } //确认时刻所在班组 public FilterTimeRange GetFilterTimeRange(DateTime QueryMoment) { var calendars1 = _shopCalendarWorkCtr.Select(p => p.TeamType == 'M' && p.WeekDay == (int)QueryMoment.DayOfWeek).ToList(); FilterTimeRange timeRange = new FilterTimeRange { }; int Qhour = QueryMoment.Hour; switch (Qhour) { //Qhour在当天班组前 case int h when (h < calendars1[0].ShiftsStart1): int adjustedDayOfWeek = (int)QueryMoment.DayOfWeek - 1; //周末的衔接 if (adjustedDayOfWeek < 0) { adjustedDayOfWeek = 6; } var calendars2 = _shopCalendarWorkCtr.Select(p => p.TeamType == 'M' && p.WeekDay == adjustedDayOfWeek).ToList(); int hour = (int)calendars1[0].ShiftsStart2; int day = QueryMoment.Day - 1; int month = QueryMoment.Month; int year = QueryMoment.Year; // 如果日期减去 1 后小于 1,则需要调整月份和年份 if (day < 1) { // 将月份减去 1 month--; // 如果月份小于 1,则需要将月份设为上一年的 12 月,并将年份减去 1 if (month < 1) { month = 12; year--; } // 获取新月份的最后一天,作为新的日期 day = DateTime.DaysInMonth(year, month); } DateTime start = new DateTime( year, // 处理过后的年份 month, // 处理过后的月份 day, // 处理过后的日期 hour, // 小时数 0, // 分钟数 0 // 秒数 ); hour = hour + (int)calendars1[0].ShiftsHours2; DateTime end = new DateTime( year, // 处理过后的年份 month, // 处理过后的月份 day, // 处理过后的日期 hour, // 小时数 0, // 分钟数 0 // 秒数 ); timeRange.FilterStartTime = start; timeRange.FilterEndTime = end; break; //Qhour在当天第一班组内 case int h when (h >= calendars1[0].ShiftsStart1 && h < calendars1[0].ShiftsStart1 + calendars1[0].ShiftsHours1): start = new DateTime( QueryMoment.Year, // 处理过后的年份 QueryMoment.Month, // 处理过后的月份 QueryMoment.Day, // 处理过后的日期 (int)calendars1[0].ShiftsStart1, // 小时数 0, // 分钟数 0 // 秒数 ); int totalHours = (int)calendars1[0].ShiftsStart1 + (int)calendars1[0].ShiftsHours1; int extraDays = totalHours / 24; // 计算多出的天数 int adjustedHours = totalHours % 24; // 剩余的小时数 // 计算新的日期,包括跨月份和跨年份的处理 int newDay = QueryMoment.Day + extraDays; int newMonth = QueryMoment.Month; int newYear = QueryMoment.Year; // 处理跨月份的情况 while (newDay > DateTime.DaysInMonth(newYear, newMonth)) { newDay -= DateTime.DaysInMonth(newYear, newMonth); // 减去当前月的天数 newMonth++; // 增加月份 if (newMonth > 12) // 处理跨年的情况 { newMonth = 1; newYear++; } } end = new DateTime( newYear, // 处理过后的年份 newMonth, // 处理过后的月份 newDay, // 处理过后的日期 adjustedHours, // 调整后的小时数 0, // 分钟数 0 // 秒数 ); timeRange.FilterStartTime = start; timeRange.FilterEndTime = end; break; //Qhour在当天第一班组外 ,自动延伸到第二班组 //Qhour在当天第二班组 default: start = new DateTime( QueryMoment.Year, // 处理过后的年份 QueryMoment.Month, // 处理过后的月份 QueryMoment.Day, // 处理过后的日期 (int)calendars1[0].ShiftsStart2, // 小时数 0, // 分钟数 0 // 秒数 ); totalHours = (int)calendars1[0].ShiftsStart2 + (int)calendars1[0].ShiftsHours2; extraDays = totalHours / 24; // 计算多出的天数 adjustedHours = totalHours % 24; // 剩余的小时数 // 计算新的日期,包括跨月份和跨年份的处理 newDay = QueryMoment.Day + extraDays; newMonth = QueryMoment.Month; newYear = QueryMoment.Year; // 处理跨月份的情况 while (newDay > DateTime.DaysInMonth(newYear, newMonth)) { newDay -= DateTime.DaysInMonth(newYear, newMonth); // 减去当前月的天数 newMonth++; // 增加月份 if (newMonth > 12) // 处理跨年的情况 { newMonth = 1; newYear++; } } end = new DateTime( newYear, // 处理过后的年份 newMonth, // 处理过后的月份 newDay, // 处理过后的日期 adjustedHours, // 调整后的小时数 0, // 分钟数 0 // 秒数 ); timeRange.FilterStartTime = start; timeRange.FilterEndTime = end; break; } return timeRange; } //获取当前班组的可用设备 public List GetAvailableEquipmentForCurrentTeam(string InternalEquipmentCode, DateTime? QueryMoment, List scheduleMaster, string MoldTypeCode=null) { //if (string.IsNullOrEmpty(InternalEquipmentCode) || QueryMoment == null) //{ // return new List() {"-99",$"设备类型编码[{InternalEquipmentCode}]无对应设备,请维护设备台账信息" }; //} //设备清单中可用于排产的设备 var EquipmentDetails = GetAvailableEquipment(InternalEquipmentCode, QueryMoment, scheduleMaster); var MoldDetails= GetAvailableMold(MoldTypeCode, QueryMoment, scheduleMaster); if (MoldDetails.Count > 0 || EquipmentDetails.Count > 0) { var mnum = MoldDetails.Count > 0? MoldDetails[0].ToInt():0; var eqnum = EquipmentDetails.Count > 0? EquipmentDetails[0].ToInt():0; if (mnum > 0 || eqnum > 0) { var AvailableNum = eqnum < mnum ? (eqnum>0? eqnum: mnum) : (mnum>0? mnum: eqnum); List OpResult = new List(); OpResult.Add($"{AvailableNum}"); OpResult.Add(EquipmentDetails.Count > 0 ? EquipmentDetails[1] :""); OpResult.Add(EquipmentDetails.Count >= 3 ? EquipmentDetails[2] : ""); OpResult.Add(EquipmentDetails.Count > 3 ? EquipmentDetails[3] : ""); //4-模具数量;5-最早释放模具编码;6-模具释放时间;7-释放数量 OpResult.Add($"{AvailableNum}"); OpResult.Add(MoldDetails.Count > 0 ? MoldDetails[1] : ""); OpResult.Add(MoldDetails.Count >=3 ? MoldDetails[2] : ""); OpResult.Add(MoldDetails.Count > 3 ? MoldDetails[3] : ""); return OpResult; } else if (mnum == -99) { return MoldDetails; } else if (eqnum == -99) { return EquipmentDetails; } else if(eqnum>0 && mnum==0) { return MoldDetails; } else { return EquipmentDetails; } } else if (!string.IsNullOrEmpty(MoldTypeCode) && (MoldDetails.Count == 0|| MoldDetails.Count<4)) { return new List() { "-99", $"模具类型编码[{MoldTypeCode}]无对应模具,请维护模具台账信息" }; } else { return EquipmentDetails; } } //获取当前班组的可用模具 public List GetAvailableMold(string MoldTypeCode, DateTime? QueryMoment, List scheduleMaster) { if (string.IsNullOrEmpty(MoldTypeCode) || QueryMoment == null) { return new List(); } string[] MoldTypeCodes; //筛选该编码的模具清单 if (MoldTypeCode.Contains('/')) { MoldTypeCodes = MoldTypeCode.Split('/'); } else { MoldTypeCodes = MoldTypeCode.Split('+'); } var availableMoldList = _moldToolList .Select(p => MoldTypeCodes.Contains(p.MoldTypeCode)).ToList(); //获得模具数量总数 int TotalMoldCount = availableMoldList.Any() ? availableMoldList[0].MoldCount : 0; //模具清单无该模具 if (TotalMoldCount == 0) { return new List() { "-99", $"模具类型编码[{MoldTypeCode}]无对应模具,请维护模具台账信息" }; } int AvailableNum = 0; int UnAvailableNum = 0; var scheduleResultOpMaster = scheduleMaster .Where(p => (p.MoldTypeCode == MoldTypeCode || MoldTypeCodes.Contains(p.MoldTypeCode)) && QueryMoment >= p.WorkStartTime && QueryMoment < p.WorkEndTime) .ToList(); int UsedMoldCount = scheduleResultOpMaster.Sum(p=>p.MoldAllocationCount); //for (int i = 0; i < scheduleResultOpMaster.Count; i++) //{ // if (QueryMoment >= scheduleResultOpMaster[i].WorkStartTime && QueryMoment < scheduleResultOpMaster[i].WorkEndTime) // { // UsedMoldCount = UsedMoldCount + scheduleResultOpMaster[i].MoldAllocationCount; // } //} var res = 0; List MoldResult = new List(); var MoldExceptionHistory = _sim_andon .Select(p => MoldTypeCodes.Contains( p.Mold)&& p.RestorationTime == null && p.EstimatedMaintenanceReleaseTime1 != null) .OrderBy(p => p.EstimatedMaintenanceReleaseTime1) .ToList(); //返回最早开工的模具,内容有 {"可用数量"," 最早释放模具编码","释放时间" ,"释放数量" } if (MoldExceptionHistory.Count <= 0) { DateTime? newDate = QueryMoment?.AddDays(3); res = TotalMoldCount - UsedMoldCount; MoldResult.Add($"{res}"); MoldResult.Add($"{MoldTypeCode}"); MoldResult.Add($"{newDate}"); MoldResult.Add("0"); return MoldResult; } else { //sim_andon模具异常情况记录 for (int i = 0; i < MoldExceptionHistory.Count; i++) { //释放时间<=当前时刻,则该时刻模具都可用 if (MoldExceptionHistory[i].EstimatedMaintenanceReleaseTime1 <= QueryMoment) { AvailableNum += (int)MoldExceptionHistory[i].ToolRepairQuantity; } //释放时间>当前时刻,则要去掉维修模具数量 else { UnAvailableNum += (int)MoldExceptionHistory[i].ToolRepairQuantity; } } //返回最早开工的模具,内容有 "可用数量"," 最早释放模具编码","释放时间" ,"释放数量" res = TotalMoldCount - UnAvailableNum - UsedMoldCount; MoldResult.Add($"{res}"); MoldResult.Add($"{MoldExceptionHistory[0].Mold}"); MoldResult.Add($"{MoldExceptionHistory[0].EstimatedMaintenanceReleaseTime1}"); MoldResult.Add($"{MoldExceptionHistory[0].ToolRepairQuantity}"); return MoldResult; } } //获取当前可用工人,并对设备 ,模具再分配 public List GetEquipmentCountBySkillRestrictions(string SkillNo, string MoldTypeCode, string InternalEquipmentCode, DateTime? QueryMoment, List scheduleMaster,decimal StandardStaffCount) { List OpResult = new List(); var AvailableEquipmentCountForCurrentOp = 0; var equipmentList = GetAvailableEquipmentForCurrentTeam(InternalEquipmentCode, QueryMoment, scheduleMaster, MoldTypeCode); if (equipmentList.Count > 0) { AvailableEquipmentCountForCurrentOp = equipmentList[0].ToInt(); } if (AvailableEquipmentCountForCurrentOp > 0) { //int RequiredPersonnelForEquipment = ; var PersonSkillList = _EmpSkills .Select(p => p.SkillNo == SkillNo && p.SkillLevel > 0 && !string.IsNullOrEmpty(p.EmployeeID)) .OrderByDescending(p => p.SkillLevel) .ToList(); int employeeCount = PersonSkillList.Count; var personEmployeeIDs = PersonSkillList.Select(p => p.EmployeeID.ToString()).Distinct().ToList(); Dictionary totals = new Dictionary(); personEmployeeIDs.ForEach(x => { totals.Add(x, 0); }); var ProdLineDetail = _ProdLineDetail.Select().ToList(); var scheduleResultOpMaster = scheduleMaster.Where(p => QueryMoment >= p.WorkStartTime && QueryMoment < p.WorkEndTime && !string.IsNullOrEmpty(p.InternalEquipmentCode) && !string.IsNullOrEmpty(p.AssignedEmployeeID)).ToList(); foreach (var schedule in scheduleResultOpMaster) { //已排产账号 var assignedEmployeeIDs = schedule.AssignedEmployeeID.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).ToList(); //查询是否包含 var equals = assignedEmployeeIDs.Where(x => personEmployeeIDs.Contains(x)).ToList(); if (equals.Count > 0) { var data = ProdLineDetail.FirstOrDefault(p => p.Part == schedule.ItemNum && p.Op == schedule.Op); if (data != null && data.StandardStaffCount > 0) { equals.ForEach(e => { var scale = data.StandardStaffCount * schedule.DeviceAllocationCount / schedule.AssignedPersonnelCount; totals[e] += scale; }); } } } var removes = totals.Where(x => x.Value >= 1 || x.Value + StandardStaffCount > 1).Select(x => x.Key).ToList(); if (removes.Count > 0) personEmployeeIDs.RemoveAll(x => removes.Contains(x)); int RequiredPersonnelForEquipment = (int)Math.Ceiling(AvailableEquipmentCountForCurrentOp * StandardStaffCount); int AvailablePersonnelForOp = Math.Min(personEmployeeIDs.Count, RequiredPersonnelForEquipment); if (personEmployeeIDs.Count > RequiredPersonnelForEquipment) RequiredPersonnelForEquipment = AvailableEquipmentCountForCurrentOp; else RequiredPersonnelForEquipment = (int)(personEmployeeIDs.Count / StandardStaffCount); string uncountedEmployeeIDString = string.Join("/", personEmployeeIDs); if (!string.IsNullOrEmpty(MoldTypeCode) && equipmentList.Count>4) { OpResult.Add($"{RequiredPersonnelForEquipment}"); OpResult.Add(equipmentList[1]); OpResult.Add(equipmentList[2]); OpResult.Add(equipmentList[3]); //4-模具数量;5-最早释放模具编码;6-模具释放时间;7-释放数量 OpResult.Add($"{RequiredPersonnelForEquipment}"); OpResult.Add(equipmentList[5]); OpResult.Add(equipmentList[6]); OpResult.Add(equipmentList[7]); //8-工序可用人数;9-工人工号字符串 OpResult.Add($"{AvailablePersonnelForOp}"); OpResult.Add($"{uncountedEmployeeIDString}"); return OpResult; } else { OpResult.Add($"{RequiredPersonnelForEquipment}"); OpResult.Add(equipmentList[1]); OpResult.Add(equipmentList[2]); OpResult.Add(equipmentList[3]); OpResult.Add(" "); OpResult.Add(" "); OpResult.Add(" "); OpResult.Add(" "); OpResult.Add($"{AvailablePersonnelForOp}"); OpResult.Add($"{uncountedEmployeeIDString}"); return OpResult; } } else { return equipmentList; } } } }