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;
}
}
}
}