Przeglądaj źródła

瑞贝排产合并

Pengxy 6 miesięcy temu
rodzic
commit
637674d3de
18 zmienionych plików z 1942 dodań i 19 usunięć
  1. 50 0
      MicroServices/Business/Business.Application.Contracts/Dto/LineStartDto.cs
  2. 625 0
      MicroServices/Business/Business.Application/ResourceExamineManagement/GetAvailableEquipmentAppService.cs
  3. 649 19
      MicroServices/Business/Business.Application/ResourceExamineManagement/ProductionScheduleAppService.cs
  4. 6 0
      MicroServices/Business/Business.Domain/StructuredDB/MES/IC/PurOrdDetail.cs
  5. 12 0
      MicroServices/Business/Business.Domain/StructuredDB/MES/IC/PurOrdMaster.cs
  6. 51 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/EmpSkills.cs
  7. 66 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/EquipmentList.cs
  8. 55 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/MoldToolList.cs
  9. 6 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/PeriodSequenceDet.cs
  10. 42 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/ProdLineDetail.cs
  11. 65 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/ProductScheduleControl.cs
  12. 63 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/ScheduleResultOpMaster.cs
  13. 12 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/ShopCalendarWorkCtr.cs
  14. 12 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/WorkOrdMaster.cs
  15. 120 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/WorkOrdRouting.cs
  16. 55 0
      MicroServices/Business/Business.Domain/StructuredDB/Production/sim_andon.cs
  17. 5 0
      MicroServices/Business/Business.EntityFrameworkCore/EntityFrameworkCore/DOP/BusinessDbContext.cs
  18. 48 0
      MicroServices/Business/QuartzSettings/logs/logs.txt

+ 50 - 0
MicroServices/Business/Business.Application.Contracts/Dto/LineStartDto.cs

@@ -42,13 +42,63 @@ namespace Business.Dto
         public DateTime StartTime { get; set; }
 
         /// <summary>
+        /// 上一个产线UPH
+        /// </summary>
+        public decimal OldRate { get; set; }
+
+        /// <summary>
         /// 产线UPH
         /// </summary>
         public decimal Rate { get; set; }
 
         /// <summary>
+        /// 可用设备数
+        /// </summary>
+        public int equipmentNum { get; set; }
+
+        /// <summary>
+        /// 下一序单班排产数量
+        /// </summary>
+        public decimal OneQty { get; set; }
+
+        /// <summary>
         /// 工序剩余待排产数量
         /// </summary>
         public decimal QtyRemain { get; set; }
+
+        /// <summary>
+        /// 设备编码
+        /// </summary>
+        public string InternalEquipmentCode { get; set; }
+
+        /// <summary>
+        /// 模具编码
+        /// </summary>
+        public string MoldTypeCode { get; set; }
+
+        /// <summary>
+        /// 工作中心
+        /// </summary>
+        public string WorkCtr { get; set; }
+
+        /// <summary>
+        /// 人员技能编码
+        /// </summary>
+        public string SkillNo { get; set; }
+
+        /// <summary>
+        /// 标准人数
+        /// </summary>
+        public decimal StandardStaffCount { get; set; }
+
+        /// <summary>
+        /// 可用员工账号
+        /// </summary>
+        public string AssignedEmployees { get; set; }
+
+        /// <summary>
+        /// 工序类型
+        /// </summary>
+        public string OpType { get; set; }
     }
 }

+ 625 - 0
MicroServices/Business/Business.Application/ResourceExamineManagement/GetAvailableEquipmentAppService.cs

@@ -0,0 +1,625 @@
+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 服务
+        /// <summary>
+        /// 模具清单
+        /// </summary>
+        private ISqlRepository<MoldToolList> _moldToolList;
+
+
+        /// <summary>
+        /// 设备清单
+        /// </summary>
+        private ISqlRepository<EquipmentList> _equipmentList;
+        // private ISqlRepository<EquipmentUsageLog> _equipmentUsageLog;
+        /// <summary>
+        /// 工作日历
+        /// </summary>
+        private ISqlRepository<ShopCalendarWorkCtr> _shopCalendarWorkCtr;
+        /// <summary>
+        /// 排产结果明细
+        /// </summary>
+        private ISqlRepository<ScheduleResultOpMaster> _scheduleResultOpMaster;
+        /// <summary>
+        /// Andon 模具异常记录
+        /// </summary>
+        private ISqlRepository<sim_andon> _sim_andon;
+        /// <summary>
+        /// 人员技能矩阵
+        /// </summary>
+        private ISqlRepository<EmpSkills> _EmpSkills;
+        /// <summary>
+        /// 产线物料维护
+        /// </summary>
+        private ISqlRepository<ProdLineDetail> _ProdLineDetail;
+        #endregion
+
+        #region 构造函数
+        public GetAvailableEquipmentAppService(
+           ISqlRepository<MoldToolList> moldToolList,
+           ISqlRepository<EquipmentList> equipmentList,
+           ISqlRepository<ShopCalendarWorkCtr> shopCalendarWorkCtr,
+           ISqlRepository<ScheduleResultOpMaster> scheduleResultOpMaster,
+           ISqlRepository<sim_andon> sim_andon,
+           ISqlRepository<EmpSkills> EmpSkills,
+           ISqlRepository<ProdLineDetail> 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
+        {
+            /// <summary>
+            /// 厂内设备编码
+            /// </summary>
+            [Comment("厂内设备编码")]
+            public string InternalEquipmentCode { get; set; }
+            /// <summary>
+            /// 可用设备数量
+            /// </summary>
+            [Comment("可用设备数量")]
+            public decimal AvailableEquipmentCount { get; set; }
+            /// <summary>
+            /// 可用设备列表
+            /// </summary>
+            [Comment("可用设备列表")]
+            public List<Equipment> AvailableEquipmentList { get; set; }
+        }
+        public class FilterTimeRange
+        {
+            //筛选开始时间
+            public DateTime FilterStartTime { get; set; }
+            //筛选结束时间
+            public DateTime FilterEndTime { get; set; }
+        }
+
+
+        //获取可排产设备
+        public List<string> GetAvailableEquipment(string InternalEquipmentCode, DateTime? QueryMoment, List<ScheduleResultOpMaster> scheduleMaster)
+        {
+            List<string> EquipmentDetails = new List<string>();
+            if (string.IsNullOrEmpty(InternalEquipmentCode) || QueryMoment == null)
+            { return new List<string>(); }
+            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<string> GetAvailableEquipmentForCurrentTeam(string InternalEquipmentCode, DateTime? QueryMoment, List<ScheduleResultOpMaster> scheduleMaster, string MoldTypeCode=null)
+        {
+            //if (string.IsNullOrEmpty(InternalEquipmentCode) || QueryMoment == null)
+            //{ 
+            //    return new List<string>() {"-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<string> OpResult = new List<string>();
+                    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<string>() { "-99", $"模具类型编码[{MoldTypeCode}]无对应模具,请维护模具台账信息" };
+            }
+            else
+            {
+                return EquipmentDetails;
+            }
+        }
+        //获取当前班组的可用模具
+        public List<string> GetAvailableMold(string MoldTypeCode, DateTime? QueryMoment, List<ScheduleResultOpMaster> scheduleMaster)
+        {
+            if (string.IsNullOrEmpty(MoldTypeCode) || QueryMoment == null)
+            { return new List<string>(); }
+            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<string>() { "-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<string> MoldResult = new List<string>();
+            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<string> GetEquipmentCountBySkillRestrictions(string SkillNo, string MoldTypeCode, string InternalEquipmentCode, DateTime? QueryMoment, List<ScheduleResultOpMaster> scheduleMaster,decimal StandardStaffCount)
+        {
+            List<string> OpResult = new List<string>();
+            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<string, decimal> totals = new Dictionary<string, decimal>();
+                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;
+            }
+        }
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+

+ 649 - 19
MicroServices/Business/Business.Application/ResourceExamineManagement/ProductionScheduleAppService.cs

@@ -56,6 +56,12 @@ namespace Business.ResourceExamineManagement
         private ISqlRepository<WorkOrdRouting> _workOrdRouting;
 
         /// <summary>
+        /// 采购订单
+        /// </summary>
+        private ISqlRepository<PurOrdMaster> _purOrdMaster;
+        private ISqlRepository<PurOrdDetail> _purOrdDetail;
+
+        /// <summary>
         /// 库存主数据
         /// </summary>
         private ISqlRepository<InvMaster> _invMaster;
@@ -111,6 +117,11 @@ namespace Business.ResourceExamineManagement
         private ISqlRepository<ScheduleExceptionMaster> _scheduleExceptionMaster;
 
         /// <summary>
+        /// 排产结果明细
+        /// </summary>
+        private ISqlRepository<ProductScheduleControl> _productScheduleControl;
+
+        /// <summary>
         /// 雪花算法
         /// </summary>
         SnowFlake help = new SnowFlake();
@@ -186,6 +197,11 @@ namespace Business.ResourceExamineManagement
         /// 排产任务执行时间
         /// </summary>
         private DateTime scheTime;
+
+        /// <summary>
+        /// 可用设备数
+        /// </summary>
+        private readonly GetAvailableEquipmentAppService _getAvailableEquipmentAppService;
         #endregion
 
         #region 构造函数
@@ -212,6 +228,9 @@ namespace Business.ResourceExamineManagement
             ISqlRepository<NbrMaster> nbrMaster,
             IRepository<mes_morder, long> mysql_mes_morder,
             ISqlRepository<WorkOrdSetupTimeRecord> workOrdSetupTimeRecord,
+            ISqlRepository<ProductScheduleControl> productScheduleControl,
+            ISqlRepository<PurOrdMaster> purOrdMaster,
+            ISqlRepository<PurOrdDetail> purOrdDetail,
             ISqlRepository<NbrDetail> nbrDetail
             )
         {
@@ -232,9 +251,12 @@ namespace Business.ResourceExamineManagement
             _generalizedCodeMaster = generalizedCodeMaster;
             _currentTenant = currentTenant;
             _scheduleExceptionMaster = scheduleExceptionMaster;
+            _productScheduleControl = productScheduleControl;
             _mysql_mes_morder = mysql_mes_morder;
             _workOrdSetupTimeRecord = workOrdSetupTimeRecord;
             _nbrDetail = nbrDetail;
+            _purOrdMaster = purOrdMaster;
+            _purOrdDetail = purOrdDetail;
         }
         #endregion
 
@@ -370,11 +392,18 @@ namespace Business.ResourceExamineManagement
             prodLineDetailRunCrews = _prodLineDetailRunCrew.Select(x => prodLines.Select(p => p.RecID).Contains(x.ProdLineDetailRecID) && x.IsActive && x.Domain == domain).ToList();
             //获取加班设置
             resourceOccupancyTimes = _resourceOccupancyTime.Select(x => prodLines.Select(p => p.Line).Contains(x.Resource) && x.IsActive && x.Domain == domain && x.StartTime.Value > DateTime.Now).ToList();
-     
+            //获取当前日期往后的排产记录数据
+            List<ItemMaster> itemMasters = _itemMaster.Select(p => p.Domain == domain && p.IsActive);
             //获取工作日历数据:产线的工作日历+默认的工作日历
             calendars = _shopCalendarWorkCtr.Select(p => (lines.Contains(p.ProdLine) || string.IsNullOrEmpty(p.ProdLine)) && p.Domain == domain && p.IsActive);
             //获取产线休息记录数据
             qualityLines = _qualityLineWorkDetail.Select(p => lines.Contains(p.ProdLine) && p.Domain == domain && p.IsActive);
+            //外协采购订单
+            var pur = _purOrdMaster.Select(p => p.Potype == "PW" && workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd)).ToList();
+            List<string> purs = pur?.Select(p => p.PurOrd).Distinct().ToList();
+            var purd = _purOrdDetail.Select(p => purs.Contains(p.PurOrd)).ToList();
+            //历史排产记录
+            List<ScheduleResultOpMaster> previouslyOP = _scheduleResultOpMaster.Select(s => workOrds.Select(m => m.WorkOrd).Contains(s.WorkOrd) && s.WorkEndTime < scheTime.Date);
             //获取节假日记录数据
             holidays = _holidayMaster.Select(p => p.Domain == domain && p.IsActive && p.Dated >= scheTime.Date);
             //获取工单的准备开始时间记录
@@ -409,6 +438,11 @@ namespace Business.ResourceExamineManagement
             List<ScheduleResultOpMaster> allResults = new List<ScheduleResultOpMaster>();
             //按照优先级排序
             workOrds = workOrds.OrderBy(p=>p.Priority).ToList();
+
+            var scheduleControl = _productScheduleControl.Select().FirstOrDefault();
+
+            var waitWork = workOrds.Where(w => !string.IsNullOrEmpty(w.WorkOrd)).ToList();
+
             for (int i = 0; i < workOrds.Count; i++)
             {
                 //记录产线占用情况
@@ -417,8 +451,51 @@ namespace Business.ResourceExamineManagement
                 var curRoutings = workOrdRoutings.Where(p => p.WorkOrd == workOrds[i].WorkOrd && p.ItemNum == workOrds[i].ItemNum && p.ParentOp == 0 && p.MilestoneOp).OrderBy(p => p.OP).ToList();
                 //当前工单的产线明细
                 var curProdLines = prodLines.Where(p => p.Part == workOrds[i].ItemNum).ToList();
+                //当前工单的物料主数据
+                var itemlist = itemMasters.Where(p => p.ItemNum == workOrds[i].ItemNum).ToList();
+                var check = new ItemMaster();
+                if (!itemlist.Any())
+                {
+                    ScheduleExceptionMaster entity = new ScheduleExceptionMaster();
+                    entity.Domain = workOrds[i].Domain;
+                    entity.WorkOrd = workOrds[i].WorkOrd;
+                    entity.ItemNum = workOrds[i].ItemNum;
+                    entity.CreateTime = DateTime.Now;
+                    entity.Remark = "排产异常:工单主物料在物料主数据中不存在,请维护后再操作!";
+                    entity.Type = type == 1 ? "自动排产" : "手动排产";
+                    entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                    exceptions.Add(entity);
+                    continue;
+                }
+                else
+                {
+                    check = itemMasters.First(p => p.ItemNum == workOrds[i].ItemNum);
+                }
                 //产线排产
-                LineSchedule(workOrds[i], curRoutings, curProdLines, periodSequenceDtls, scheduleMasters, allResults);
+                LineSchedule(workOrds[i], curRoutings, curProdLines, periodSequenceDtls, scheduleMasters, allResults, exceptions, previouslyOP,pur,purd, true, true);
+                waitWork.Remove(workOrds[i]);
+                if (scheduleMasters.Count > 0)
+                {
+                    var isy = scheduleMasters.Where(s => s.WorkOrd == workOrds[i].WorkOrd).Count() > 0;
+                    //当前工单未排产
+                    if (!isy) { continue; }
+                    var endTime = scheduleMasters.Where(s => s.WorkOrd == workOrds[i].WorkOrd).Max(s => s.WorkEndTime);
+                    //换型优先级提前排产工单
+                    var advanceWorkOrdNo = GetShortSetUpTimeWorkOrdNo(endTime, workOrds[i], curRoutings, curProdLines, waitWork, workOrdRoutings, prodLines);
+                    if (!string.IsNullOrEmpty(advanceWorkOrdNo))
+                    {
+                        var advanceWorkOrd = workOrds.Where(w => w.WorkOrd == advanceWorkOrdNo).FirstOrDefault();
+                        if (advanceWorkOrd != null && i != workOrds.Count - 1)
+                        {
+                            var curWork = workOrds[i];
+                            //更改顺序为下一个
+                            workOrds.Remove(advanceWorkOrd);
+                            var index = workOrds.IndexOf(curWork);
+                            i = index;
+                            workOrds.Insert(index + 1, advanceWorkOrd);
+                        }
+                    }
+                }
             }
             //回写工单优先级
             foreach (var item in workOrds)
@@ -621,6 +698,44 @@ namespace Business.ResourceExamineManagement
             return "OK";
         }
 
+        //换型最短工单优先排产
+        public string GetShortSetUpTimeWorkOrdNo(DateTime startTime, WorkOrdMaster workOrd, List<WorkOrdRouting> curRoutings, List<ProdLineDetail> curProdLines, List<WorkOrdMaster> workOrds, List<WorkOrdRouting> workOrdRoutings, List<ProdLineDetail> prodLines)
+        {
+            //三天内的工单
+            var scopeWork = workOrds.Where(p => p.OrdDate >= startTime && p.OrdDate <= startTime.AddDays(3) && p.Priority > workOrd.Priority).ToList();
+            if (scopeWork.Any())
+            {
+                //相同物料的工单
+                var equalWork = scopeWork.Where(p => p.ItemNum == workOrd.ItemNum).OrderBy(p => p.Priority).FirstOrDefault();
+                if (equalWork == null)
+                {
+                    //三天范围内工序
+                    var scopeWorkNo = scopeWork.Select(p => p.WorkOrd).ToList();
+                    var scopeRoutings = workOrdRoutings.Join(prodLines, r => new { ItemNum = r.ItemNum, OP = r.OP }, p => new { ItemNum = p.Part, OP = p.Op }, (r, p) => new { r, p.InternalEquipmentCode, p.MoldTypeCode, p.SetupTime }).Where(n => scopeWorkNo.Contains(n.r.WorkOrd)).ToList();
+                    if (!scopeRoutings.Any()) { return ""; }
+                    //本工单所有模具
+                    var molds = curProdLines.Where(c => !string.IsNullOrEmpty(c.MoldTypeCode)).Select(c => c.MoldTypeCode).Distinct().ToList();
+                    if (!molds.Any()) { return ""; }
+                    //删除相同模具的准备时间
+                    scopeRoutings.RemoveAll(r => molds.Contains(r.MoldTypeCode));
+                    if (!scopeRoutings.Any()) { return ""; }
+                    //计算剩下工序的总准备时间,取出最小值
+                    var routings = scopeRoutings.GroupBy(s => s.r.WorkOrd).Select(g => new { WorkOrd = g.Key, SumTime = g.Sum(p => p.SetupTime) }).OrderBy(g => g.SumTime).ToList();
+                    equalWork = scopeWork.Where(s => s.WorkOrd == routings[0].WorkOrd).First();
+                    //物料不一样但工序一样导致全部删除的工单换型时间为0
+                    if (routings.Count < scopeWorkNo.Count && scopeWorkNo.Count > 0 && routings.Count > 0)
+                    {
+                        var works = routings.Select(p => p.WorkOrd).ToList();
+                        scopeWorkNo.RemoveAll(p => works.Contains(p));
+                        equalWork = workOrds.Where(w => scopeWorkNo.Contains(w.WorkOrd)).OrderBy(w => w.Priority).First();
+                    }
+                }
+                return equalWork == null ? "" : equalWork.WorkOrd;
+            }
+            return "";
+        }
+
+
         /// <summary>
         /// 排产前校验
         /// </summary>
@@ -710,7 +825,65 @@ namespace Business.ResourceExamineManagement
                         exceptions.Add(entity);
                     }
                 }
-                
+
+                //获取当前工单物料对应的产线信息
+                var curRoutingss = workOrdRoutings.Where(p => p.WorkOrd == item.WorkOrd && p.ItemNum == item.ItemNum && p.MilestoneOp && p.ProcessOut != 1).ToList();
+                lineDetails = prodLines.Where(x => x.Part == item.ItemNum && curRoutingss.Select(c => c.OP).ToList().Contains(x.Op)).ToList();
+                if (exceptions.FindIndex(e => e.WorkOrd == item.WorkOrd) < 0)
+                {
+                    if (!lineDetails.Any() || lineDetails?.Count == 0)
+                    {
+                        //产线物料中找不到时检查工单工序表是否有维护
+                        var curRoutingsOp = workOrdRoutings.Where(r => curRoutingss.Select(c => c.OP).ToList().Contains(r.OP) && r.MachBdnRate != 0 && (r.WorkCode != "P" && !string.IsNullOrEmpty(r.Machine) || r.WorkCode == "P")).ToList();
+                        if (!curRoutingsOp.Any() || curRoutingsOp?.Count == 0)
+                        {
+                            entity = new ScheduleExceptionMaster();
+                            entity.Domain = item.Domain;
+                            entity.WorkOrd = item.WorkOrd;
+                            entity.ItemNum = item.ItemNum;
+                            entity.CreateTime = DateTime.Now;
+                            entity.Remark = "排产异常:工单的关键工序没有维护产线数据,请维护后再操作!";
+                            entity.Type = type == 1 ? "自动排产" : "手动排产";
+                            entity.OptTime = optTime;
+                            exceptions.Add(entity);
+                            continue;
+                        }
+                        else
+                        {
+                            var Routings = curRoutingsOp.Where(p => (p.WorkCode != "P" && string.IsNullOrEmpty(p.Machine)) || (p.Engineer != "" && p.Engineer != "/" && p.RunCrew == 0)).ToList();
+                            if (Routings.Any())
+                            {
+                                entity = new ScheduleExceptionMaster();
+                                entity.Domain = item.Domain;
+                                entity.WorkOrd = item.WorkOrd;
+                                entity.ItemNum = item.ItemNum;
+                                entity.CreateTime = DateTime.Now;
+                                entity.Remark = "排产异常:工单的关键工序没有维护产线数据,请维护后再操作!";
+                                entity.Type = type == 1 ? "自动排产" : "手动排产";
+                                entity.OptTime = optTime;
+                                exceptions.Add(entity);
+                                continue;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        var line = lineDetails.Where(p => (p.OpType != "P" && string.IsNullOrEmpty(p.InternalEquipmentCode)) || (p.SkillNo != "" && p.SkillNo != "/" && p.StandardStaffCount == 0)).ToList();
+                        if (line.Any())
+                        {
+                            entity = new ScheduleExceptionMaster();
+                            entity.Domain = item.Domain;
+                            entity.WorkOrd = item.WorkOrd;
+                            entity.ItemNum = item.ItemNum;
+                            entity.CreateTime = DateTime.Now;
+                            entity.Remark = "排产异常:工单的关键工序没有维护产线数据,请维护后再操作!";
+                            entity.Type = type == 1 ? "自动排产" : "手动排产";
+                            entity.OptTime = optTime;
+                            exceptions.Add(entity);
+                            continue;
+                        }
+                    }
+                }
                 //校验主产线关键工序对应的产线是否维护了工作日历
                 var curCalendars = calendars.Where(x => lineDetails.Select(p => p.Line).Contains(x.ProdLine) || string.IsNullOrEmpty(x.ProdLine)).ToList();
                 foreach (var rut in lineDetails)
@@ -759,7 +932,7 @@ namespace Business.ResourceExamineManagement
         /// <param name="periodsDet">生产周期</param>
         /// <param name="scheduleResults">排产结果</param>
         /// <param name="allResults">产线占用记录</param>
-        public void LineSchedule(WorkOrdMaster workOrd, List<WorkOrdRouting> workOrdRoutings, List<ProdLineDetail> prodLines,List<PeriodSequenceDet> periodsDet, List<ScheduleResultOpMaster> scheduleResults, List<ScheduleResultOpMaster> allResults)
+        public void LineSchedule(WorkOrdMaster workOrd, List<WorkOrdRouting> workOrdRoutings, List<ProdLineDetail> prodLines,List<PeriodSequenceDet> periodsDet, List<ScheduleResultOpMaster> scheduleResults, List<ScheduleResultOpMaster> allResults, List<ScheduleExceptionMaster> exceptions, List<ScheduleResultOpMaster> previouslyOP,List<PurOrdMaster> pur,List<PurOrdDetail> purd, bool Check = false, bool UseSkill = true)
         {
             //生产周期
             List<PeriodSequenceDet> curSequences = new List<PeriodSequenceDet>();
@@ -770,28 +943,333 @@ namespace Business.ResourceExamineManagement
             //产线开工时间默认为当前时间
             lineStart.StartTime = scheTime;
             TimeSpan span = TimeSpan.Zero;
+            var remainNum = 0m;
             //第一层级工序有几个关键工序,就有几条产线
             for (int i = 0; i < workOrdRoutings.Count; i++)
             {
+                var Maxednum = 0;
+                List<ScheduleResultOpMaster> LastcurScheduleRsts = new List<ScheduleResultOpMaster>();
+                //获取工序对应的产线,根据优先级排序
+                var lines = prodLines.Where(p => p.Part == workOrd.ItemNum && p.Op == workOrdRoutings[i].OP && p.Bom == workOrd.Refs).OrderBy(p => p.Sequence).ToList();
+                //没有对应工艺且工序表无记录
+                if (!lines.Any() && workOrdRoutings[i].MachBdnRate == 0)
+                {
+                    lines = prodLines.Where(p => p.Part == workOrd.ItemNum && p.Op == workOrdRoutings[i].OP).OrderBy(p => p.Sequence).ToList();
+                }
+                var Line = !string.IsNullOrEmpty(workOrdRoutings[i].ProdLine) ? workOrdRoutings[i].ProdLine : (lines.Count > 0 ? lines[0].Line : workOrdRoutings[i].ProdLine);
+                //当前产线的工作日历
+                var mLCalendars = calendars.Where(p => p.WorkCtr == Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
+                //当前产线的休息时间设置
+                var mlqtyWorkDtls = qualityLines.Where(p => p.ProdLine == Line).ToList();
+                var Rate = workOrdRoutings[i].MachBdnRate > 0 ? workOrdRoutings[i].MachBdnRate : (lines.Count > 0 ? lines[0].Rate : workOrdRoutings[i].MachBdnRate);
+                var OpType = !string.IsNullOrEmpty(workOrdRoutings[i].WorkCode) ? workOrdRoutings[i].WorkCode : (lines.Count > 0 ? lines[0].OpType : workOrdRoutings[i].WorkCode);
+                decimal ScaleNum = 1m;
+                if (!Check && lineStart.Rate < Rate && lineStart.Rate != 0 && i != 0)
+                {
+                    ScaleNum = lineStart.Rate / Rate;
+                }
+                //var lines = prodLines.Where(p => p.Part == workOrd.ItemNum && p.Op == workOrdRoutings[i].OP).OrderBy(p => p.Sequence).ToList();
+                //外协工序特殊处理,不进入产能计算
+                if (workOrdRoutings[i].ProcessOut == 1)
+                {
+                    //对应外协采购订单
+                    var curpur = pur.Where(p => p.Potype == "PW" && p.WorkOrd == workOrd.WorkOrd).First();
+                    List<string> purs = pur?.Select(p => p.PurOrd).Distinct().ToList();
+                    PurOrdDetail curpurd = purd.Where(p => purs.Contains(p.PurOrd) && p.ItemNum == workOrdRoutings[i].ItemNum && p.Op == workOrdRoutings[i].OP).Count() > 0 ? _purOrdDetail.Select(p => purs.Contains(p.PurOrd) && p.ItemNum == workOrdRoutings[i].ItemNum && p.Op == workOrdRoutings[i].OP).First() : null;
+                    //前序排产记录
+                    LastcurScheduleRsts = curScheduleRsts?.Where(c => c.Op == lineStart.Op).ToList();
+                    //如果有采购订单则取订单日期,没有则取上序的开始时间,再没有则取当前日期
+                    //DateTime StartTime = purd != null ? pur.Where(p => p.PurOrd == purd.PurOrd).First().OrdDate.GetValueOrDefault() :
+                    DateTime StartTime = LastcurScheduleRsts != null && LastcurScheduleRsts.Count > 0 ? LastcurScheduleRsts[LastcurScheduleRsts.Count - 1].WorkStartTime : scheTime;
+                    //判断是否工作日
+                    var isworkday = CheckIsWorkDay(StartTime);
+                    while (!isworkday)
+                    {
+                        StartTime = StartTime.AddDays(1);
+                        isworkday = CheckIsWorkDay(StartTime);
+                    }
+                    var line = pur.Count > 0 ? pur.Where(p => p.PurOrd == curpur.PurOrd).First().Supp : workOrdRoutings[i].ProcessOutSupp;
+                    var qty = purd != null ? curpurd.QtyOrded : workOrd.QtyOrded;
+                    //记录生产周期
+                    curSequences.Add(new PeriodSequenceDet
+                    {
+                        Domain = domain,
+                        Line = line,
+                        ItemNum = workOrd.ItemNum,
+                        PlanDate = StartTime.Date,
+                        Period = 1,
+                        OrdQty = qty,
+                        WorkOrds = workOrd.WorkOrd,
+                        Op = workOrdRoutings[i].OP,
+                        IsActive = true,
+                        Status = "",
+                        CreateTime = DateTime.Now,
+                        UDate2 = StartTime
+                    });
+                    //记录排产记录
+                    curScheduleRsts.Add(new ScheduleResultOpMaster
+                    {
+                        Domain = domain,
+                        WorkOrd = workOrd.WorkOrd,
+                        WorkCtr = "",
+                        OpDescr = workOrdRoutings[i].Descr,
+                        Line = line,
+                        ItemNum = workOrd.ItemNum,
+                        Op = workOrdRoutings[i].OP,
+                        WorkDate = StartTime.Date,
+                        WorkQty = qty,
+                        WorkStartTime = StartTime,
+                        WorkEndTime = curpurd != null ? (curpurd.DueDate.GetValueOrDefault() < StartTime.Date ? StartTime.AddDays(7) : curpurd.DueDate.GetValueOrDefault()) : StartTime.AddDays(7),//默认七天后到
+                        CreateTime = DateTime.Now,
+                        WorkActivateTime = StartTime,
+                        SetupTime = 0,
+                        DeviceAllocationCount = 0,
+                        InternalEquipmentCode = "",
+                        MoldTypeCode = "",
+                        MoldAllocationCount = 0
+                    });
+                    //修改后序开始时间
+                    lineStart.QtyRemain = qty;
+                    lineStart.StartTime = StartTime;
+                    lineStart.OneQty = qty;
+                    lineStart.Op = workOrdRoutings[i].OP;
+                    lineStart.Line = line;
+                    lineStart.Rate = qty;
+                    lineStart.setupTime = 0;
+                    lineStart.WaitTime = 0;
+                    continue;
+                }
+                //委外工序两边不同步
+                if (OpType == "M" && Rate == 0)
+                {
+                    var entity = new ScheduleExceptionMaster();
+                    entity.Domain = workOrd.Domain;
+                    entity.WorkOrd = workOrd.WorkOrd;
+                    entity.ItemNum = workOrd.ItemNum;
+                    entity.CreateTime = DateTime.Now;
+                    entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}-机器工序未维护单位产能!";
+                    entity.Type = "手动排产";
+                    entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                    exceptions.Add(entity);
+                    return;
+                }
+                if (OpType == "P" && Rate == 0)
+                {
+                    var entity = new ScheduleExceptionMaster();
+                    entity.Domain = workOrd.Domain;
+                    entity.WorkOrd = workOrd.WorkOrd;
+                    entity.ItemNum = workOrd.ItemNum;
+                    entity.CreateTime = DateTime.Now;
+                    entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}-人工工序未维护单位产能!";
+                    entity.Type = "手动排产";
+                    entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                    exceptions.Add(entity);
+                    return;
+                }
+                if (Rate == 0)
+                {
+                    var entity = new ScheduleExceptionMaster();
+                    entity.Domain = workOrd.Domain;
+                    entity.WorkOrd = workOrd.WorkOrd;
+                    entity.ItemNum = workOrd.ItemNum;
+                    entity.CreateTime = DateTime.Now;
+                    entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}-工序未维护单位产能!";
+                    entity.Type = "手动排产";
+                    entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                    exceptions.Add(entity);
+                    return;
+                }
                 //产线实际排产开始时间
                 if (i == 0)//第一条产线
                 {
-                    lineStart = DealStartTime(workOrd, workOrdRoutings[i], prodLines, allResults);
+                    lineStart = DealStartTime(workOrd, workOrdRoutings[i], lines, allResults, exceptions, mLCalendars, mlqtyWorkDtls, Check, UseSkill);
+                    //var s = _scheduleResultOpMaster.Select(p => p.WorkOrd == workOrd.WorkOrd).ToList();
+                    if (lineStart.equipmentNum == 0 && lineStart.OpType != "P" && exceptions.FindIndex(e => e.WorkOrd == workOrd.WorkOrd) < 0)
+                    {
+                        var entity = new ScheduleExceptionMaster();
+                        entity.Domain = workOrd.Domain;
+                        entity.WorkOrd = workOrd.WorkOrd;
+                        entity.ItemNum = workOrd.ItemNum;
+                        entity.CreateTime = DateTime.Now;
+                        entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}-{lineStart.InternalEquipmentCode}无可用设备!";
+                        entity.Type = "手动排产";
+                        entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                        exceptions.Add(entity);
+                        return;
+                    }
+                    //工单剩余制程(产能最小的工序使用最低设备数的时长+1天),排除人工工序和外协工序
+                    var minrate = 0m;
+                    var rcount = workOrdRoutings.Where(r => r.WorkCode != "P" && r.MachBdnRate > 0).ToList().Count;
+                    if (rcount > 0)
+                    {
+                        minrate = workOrdRoutings.Where(r => r.WorkCode != "P" && r.MachBdnRate > 0).Min(r => r.MachBdnRate);
+                    }
+                    else
+                    {
+                        if (prodLines.Where(p => p.Rate > 0).ToList().Count > 0)
+                        {
+                            rcount = prodLines.Where(p => p.OpType != "P" && p.Rate > 0).ToList().Count;
+                            if (rcount > 0)
+                            {
+                                minrate = prodLines.Where(p => p.OpType != "P" && p.Rate > 0).Min(p => p.Rate);
+                            }
+                            else
+                            {
+                                minrate = prodLines.Where(p => p.Rate > 0).Min(p => p.Rate);
+                            }
+                        }
+                        else
+                        {
+                            rcount = workOrdRoutings.Where(r => r.MachBdnRate > 0).ToList().Count;
+                            if (rcount > 0)
+                            {
+                                minrate = workOrdRoutings.Where(r => r.MachBdnRate > 0).Min(p => p.MachBdnRate);
+                            }
+                        }
+                    }
+                    //>0? workOrdRoutings.Where(r => r.WorkCode != "P" && r.MachBdnRate != 0).Min(r=>r.MachBdnRate) : (prodLines.Where(p => p.OpType != "P" && p.Rate != 0).ToList().Count>0?prodLines.Where(p => p.OpType != "P" && p.Rate != 0).Min(p => p.Rate): prodLines.Where(p => p.Rate > 0).Min(p => p.Rate));
+                    //var minrate = prodLines.Where(p => p.OpType != "P" && p.Rate != 0).Min(p => p.Rate);
+                    var workMaxTime = (lineStart.QtyRemain / minrate) + 24;
+                    //工单预计剩余生产天数
+                    var wkspan = workOrd.DueDate.GetValueOrDefault() - lineStart.StartTime;
+                    if (wkspan.TotalHours < 0)
+                    {
+                        wkspan = lineStart.StartTime.AddDays(1) - lineStart.StartTime;
+                    }
+                    var remainDay = ((decimal)wkspan.TotalHours - workMaxTime) / 2;
+                    if (remainDay <= 0)
+                    {
+                        //remainDay = workMaxTime;
+                        remainDay = (decimal)wkspan.TotalHours;
+                    }
+                    //预估每天生产量
+                    remainNum = lineStart.QtyRemain / remainDay * 24;
                 }
                 else
                 {
-                    //获取前一产线排产开始时间,通过提前期计算当前产线排产开始时间
-                    lineStart = DealNextStartTime(workOrd, lineStart, workOrdRoutings[i], prodLines, allResults);
+                    decimal lastsumqty = 0m;
+                    int j = 0;
+                    bool ispc = true;
+                    //前序排产记录
+                    LastcurScheduleRsts = curScheduleRsts.Where(c => c.Op == lineStart.Op).ToList();
+                    if (LastcurScheduleRsts.Count == 0)
+                    {
+                        var entity = new ScheduleExceptionMaster();
+                        entity.Domain = workOrd.Domain;
+                        entity.WorkOrd = workOrd.WorkOrd;
+                        entity.ItemNum = workOrd.ItemNum;
+                        entity.CreateTime = DateTime.Now;
+                        entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}前序准备时间未刷新!";
+                        entity.Type = "手动排产";
+                        entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                        exceptions.Add(entity);
+                        return;
+                    }
+                    //每天所需设备数(向上圆整)
+                    Maxednum = OpType == "P" && remainNum > 0 ? Convert.ToInt32(Math.Ceiling(remainNum / (Rate * 24))) : (remainNum <= 0 ? 1 : Convert.ToInt32(Math.Ceiling(remainNum / (Rate * 24) / 2)));
+                    //非人工工序要获取可用设备数量
+                    if (OpType != "P")
+                    {
+                        //可用数量
+                        var numList = new List<string>();
+                        //可插班的明细
+                        ScheduleResultOpMaster schedule = null;
+                        //维修结束时间
+                        DateTime wxEndTime = lineStart.StartTime;
+                        LineStartDto startDto = new LineStartDto();
+                        startDto.InternalEquipmentCode = !string.IsNullOrEmpty(workOrdRoutings[i].Machine) ? workOrdRoutings[i].Machine : (lines.Count > 0 ? lines[0].InternalEquipmentCode : workOrdRoutings[i].Machine);
+                        startDto.MoldTypeCode = !string.IsNullOrEmpty(workOrdRoutings[i].ToolCode) ? workOrdRoutings[i].ToolCode : (lines.Count > 0 ? lines[0].MoldTypeCode : workOrdRoutings[i].ToolCode);
+                        startDto.WorkCtr = !string.IsNullOrEmpty(workOrdRoutings[i].WorkCtr) ? workOrdRoutings[i].WorkCtr : (lines.Count > 0 ? (lines[0].Site != workOrdRoutings[i].WorkCtr && !string.IsNullOrEmpty(workOrdRoutings[i].WorkCtr) ? workOrdRoutings[i].WorkCtr : lines[0].Site) : workOrdRoutings[i].WorkCtr);
+                        startDto.RecID = lines.Count > 0 ? lines[0].RecID : 0;
+                        startDto.Line = !string.IsNullOrEmpty(workOrdRoutings[i].ProdLine) ? workOrdRoutings[i].ProdLine : (lines.Count > 0 ? (lines[0].Line != workOrdRoutings[i].ProdLine && !string.IsNullOrEmpty(workOrdRoutings[i].ProdLine) ? workOrdRoutings[i].ProdLine : lines[0].Line) : workOrdRoutings[i].ProdLine);
+                        startDto.setupTime = workOrdRoutings[i].StdSetupTime > 0 ? workOrdRoutings[i].StdSetupTime : (lines.Count > 0 ? lines[0].SetupTime : workOrdRoutings[i].StdSetupTime);
+                        startDto.SkillNo = !string.IsNullOrEmpty(workOrdRoutings[i].Engineer) ? workOrdRoutings[i].Engineer : (lines.Count > 0 ? lines[0].SkillNo : workOrdRoutings[i].Engineer);
+                        startDto.StandardStaffCount = workOrdRoutings[i].RunCrew > 0 ? workOrdRoutings[i].RunCrew : (lines.Count > 0 ? lines[0].StandardStaffCount : workOrdRoutings[i].RunCrew);
+                        startDto.Rate = Rate;
+                        startDto.OpType = OpType;
+                        startDto.Op = workOrdRoutings[i].OP;
+                        //设备可用数量和可用时间
+                        AvailableQuantity(workOrd, lineStart.StartTime, startDto, lines, allResults, exceptions, out numList, out schedule, out wxEndTime, UseSkill);
+                        Maxednum = numList.Count > 0 ? (numList[0].ToInt() > Maxednum ? Maxednum : numList[0].ToInt()) : Maxednum;
+                    }
+                    //true:按班次,false:按小时
+                    var hourNum = Check ? 8 : 1;
+                    var NowQty = lines.Count > 0 ? Maxednum * lines[0].Rate * hourNum * ScaleNum : Maxednum * workOrdRoutings[i].MachBdnRate * hourNum * ScaleNum;
+
+                    while (ispc)
+                    {
+                        //前序满足本序产量
+                        lineStart.StartTime = j >= LastcurScheduleRsts.Count ? LastcurScheduleRsts[j - 1].WorkEndTime : LastcurScheduleRsts[j].WorkEndTime;
+                        lastsumqty += j == LastcurScheduleRsts.Count ? LastcurScheduleRsts[j - 1].WorkQty : LastcurScheduleRsts[j].WorkQty;
+                        if (lastsumqty > NowQty || j == LastcurScheduleRsts.Count || i == workOrdRoutings.Count - 1)
+                        {
+                            if (!Check)
+                            {
+                                var hours = Math.Ceiling(NowQty / lineStart.Rate);
+                                lineStart.StartTime = j == LastcurScheduleRsts.Count ? (LastcurScheduleRsts[j - 1].WorkEndTime > LastcurScheduleRsts[j - 1].WorkActivateTime.AddHours((double)hours) ? LastcurScheduleRsts[j - 1].WorkActivateTime.AddHours((double)hours) : LastcurScheduleRsts[j - 1].WorkEndTime) : (LastcurScheduleRsts[j].WorkEndTime > LastcurScheduleRsts[j].WorkActivateTime.AddHours((double)hours) ? LastcurScheduleRsts[j].WorkActivateTime.AddHours((double)hours) : LastcurScheduleRsts[j].WorkEndTime);
+                            }
+                            lineStart = DealNextStartTime(workOrd, lineStart, workOrdRoutings[i], lines, allResults, calendars, exceptions, mLCalendars, mlqtyWorkDtls, Check, UseSkill);
+                            ispc = false;
+                        }
+                        j++;
+                    }
+                    if (lineStart.equipmentNum == 0 && lineStart.OpType != "P" && exceptions.FindIndex(e => e.WorkOrd == workOrd.WorkOrd) < 0)
+                    {
+                        var entity = new ScheduleExceptionMaster();
+                        entity.Domain = workOrd.Domain;
+                        entity.WorkOrd = workOrd.WorkOrd;
+                        entity.ItemNum = workOrd.ItemNum;
+                        entity.CreateTime = DateTime.Now;
+                        entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}-{lineStart.InternalEquipmentCode}无可用设备!";
+                        entity.Type = "手动排产";
+                        entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                        exceptions.Add(entity);
+                        return;
+                    }
+                }
+                if (exceptions.FindIndex(e => e.WorkOrd == workOrd.WorkOrd) >= 0)
+                {
+                    return;
                 }
                 //如果当前工序已经生产完成,则跳过
                 if (lineStart.QtyRemain == 0)
                 {
                     continue;
                 }
-                //当前产线的工作日历
-                var mLCalendars = calendars.Where(p => p.ProdLine == lineStart.Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
-                //当前产线的休息时间设置
-                var mlqtyWorkDtls = qualityLines.Where(p => p.ProdLine == lineStart.Line).ToList();
+
+                if (lineStart.StartTime == DateTime.MinValue)
+                {
+                    var entity = new ScheduleExceptionMaster();
+                    entity.Domain = workOrd.Domain;
+                    entity.WorkOrd = workOrd.WorkOrd;
+                    entity.ItemNum = workOrd.ItemNum;
+                    entity.CreateTime = DateTime.Now;
+                    entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}-{lineStart.InternalEquipmentCode}工序准备记录的产线错误!";
+                    entity.Type = "手动排产";
+                    entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                    exceptions.Add(entity);
+                    return;
+                }
+                if (lineStart.setupTime > 240)
+                {
+                    var entity = new ScheduleExceptionMaster();
+                    entity.Domain = workOrd.Domain;
+                    entity.WorkOrd = workOrd.WorkOrd;
+                    entity.ItemNum = workOrd.ItemNum;
+                    entity.CreateTime = DateTime.Now;
+                    entity.Remark = $"{workOrd.WorkOrd}排产异常:{workOrdRoutings[i].OP}-{lineStart.InternalEquipmentCode}工序生产准备时长超过10天!";
+                    entity.Type = "手动排产";
+                    entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                    exceptions.Add(entity);
+                    return;
+                }
+                //每天所需设备数(向上圆整)
+                Maxednum = lineStart.OpType == "P" && remainNum > 0 ? Convert.ToInt32(Math.Ceiling(remainNum / (lineStart.Rate * 24))) : (remainNum <= 0 ? 1 : Convert.ToInt32(Math.Ceiling(remainNum / (lineStart.Rate * 24) / 2)));
+                //当前班次可用设备数,无模具取设备数,有模具取模具数
+                lineStart.equipmentNum = lineStart.OpType == "P" ? Maxednum : lineStart.equipmentNum;
+                //实际使用设备数,Maxednum=0代表所需时长超过剩余时长,直接使用所有设备生产
+                lineStart.equipmentNum = Maxednum == 0 ? lineStart.equipmentNum : (lineStart.equipmentNum > Maxednum ? Maxednum : (lineStart.equipmentNum == 0 ? Maxednum : lineStart.equipmentNum));
+
                 //产线排产开始时间
                 DateTime workStartTime = lineStart.StartTime;
                 //正常工单排产
@@ -799,6 +1277,8 @@ namespace Business.ResourceExamineManagement
                 decimal sumQty = 0m;
                 //产线准备时间(分钟)
                 decimal sumTimes = 0m;
+                //之前的排产记录
+                var previouslyOPNum = previouslyOP.Where(s => s.WorkOrd == workOrd.WorkOrd && s.Op == lineStart.Op && s.WorkStartTime < lineStart.StartTime && s.SetupTime > 0).Count();
                 while (sumQty < lineStart.QtyRemain)
                 {
                     //获取当天的产能
@@ -1274,13 +1754,27 @@ namespace Business.ResourceExamineManagement
         /// <param name="prodLines">生产线明细</param>
         /// <param name="allResults">产线占用记录</param>
         /// <returns></returns>
-        public LineStartDto DealStartTime(WorkOrdMaster workOrd,WorkOrdRouting routing,List<ProdLineDetail> prodLines, List<ScheduleResultOpMaster> allResults)
+        public LineStartDto DealStartTime(WorkOrdMaster workOrd,WorkOrdRouting routing,List<ProdLineDetail> prodLines, List<ScheduleResultOpMaster> allResults, List<ScheduleExceptionMaster> exceptions, List<ShopCalendarWorkCtr> curCalendars, List<QualityLineWorkDetail> curQtyDtls, bool Check = false, bool UseSkill = true)
         {
             LineStartDto lineStart = new LineStartDto();
             //排产工序
             int op = routing.OP;
             //排产任务执行时间
             DateTime actStart = scheTime;
+
+            lineStart.WorkCtr = !string.IsNullOrEmpty(routing.WorkCtr) ? routing.WorkCtr : (prodLines.Count > 0 ? (prodLines[0].Site != routing.WorkCtr && !string.IsNullOrEmpty(routing.WorkCtr) ? routing.WorkCtr : prodLines[0].Site) : routing.WorkCtr);
+            lineStart.SkillNo = !string.IsNullOrEmpty(routing.Engineer) ? routing.Engineer : (prodLines.Count > 0 ? prodLines[0].SkillNo : routing.Engineer);
+            lineStart.StandardStaffCount = routing.RunCrew > 0 ? routing.RunCrew : (prodLines.Count > 0 ? prodLines[0].StandardStaffCount : routing.RunCrew);
+            lineStart.OpType = !string.IsNullOrEmpty(routing.WorkCode) ? routing.WorkCode : (prodLines.Count > 0 ? prodLines[0].OpType : routing.WorkCode);
+            lineStart.Op = routing.OP;
+            lineStart.InternalEquipmentCode = lineStart.OpType == "P" ? "" : (!string.IsNullOrEmpty(routing.Machine) ? routing.Machine : (prodLines.Count > 0 ? prodLines[0].InternalEquipmentCode : routing.Machine));
+            lineStart.MoldTypeCode = lineStart.OpType == "P" ? "" : (!string.IsNullOrEmpty(routing.ToolCode) ? routing.ToolCode : (prodLines.Count > 0 ? prodLines[0].MoldTypeCode : routing.ToolCode));
+            lineStart.RecID = prodLines.Count > 0 ? prodLines[0].RecID : 0;
+            lineStart.Line = !string.IsNullOrEmpty(routing.ProdLine) ? routing.ProdLine : (prodLines.Count > 0 ? (prodLines[0].Line != routing.ProdLine && !string.IsNullOrEmpty(routing.ProdLine) ? routing.ProdLine : prodLines[0].Line) : routing.ProdLine);
+            lineStart.setupTime = routing.StdSetupTime > 0 ? routing.StdSetupTime : (prodLines.Count > 0 ? prodLines[0].SetupTime : routing.StdSetupTime);
+            lineStart.Rate = routing.MachBdnRate > 0 ? routing.MachBdnRate : (prodLines.Count > 0 ? prodLines[0].Rate : routing.MachBdnRate);
+            lineStart.OldRate = routing.MachBdnRate > 0 ? routing.MachBdnRate : (prodLines.Count > 0 ? prodLines[0].Rate : routing.MachBdnRate);
+
             if (!string.IsNullOrEmpty(workOrd.JointTyped) && workOrd.JointTyped.ToUpper() == "B")
             {
                 actStart = workOrd.OrdDate.GetValueOrDefault();
@@ -1297,8 +1791,8 @@ namespace Business.ResourceExamineManagement
                 {
                     //计算产线实际开始时间
                     //产线工作日历:当前产线的工作日历 + 默认工作日历
-                    var curCalendars = calendars.Where(p => p.ProdLine == curLine.Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
-                    var curQtyDtls = qualityLines.Where(p => p.ProdLine == curLine.Line).ToList();
+                    //var curCalendars = calendars.Where(p => p.ProdLine == curLine.Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
+                    //var curQtyDtls = qualityLines.Where(p => p.ProdLine == curLine.Line).ToList();
                     actStart = CalcActStartTime(curLine.Line, actStart, curCalendars, curQtyDtls);
                     lineStart.RecID = curLine.RecID;
                     lineStart.Line = curLine.Line;
@@ -1313,8 +1807,8 @@ namespace Business.ResourceExamineManagement
                 actStart = schedule == null ? actStart : (schedule.WorkEndTime >= actStart ? schedule.WorkEndTime : actStart);
                 //计算实际开工时间
                 //产线工作日历:当前产线的工作日历+默认工作日历
-                var curCalendars = calendars.Where(p => p.ProdLine == lines[0].Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
-                var curQtyDtls = qualityLines.Where(p => p.ProdLine == lines[0].Line).ToList();
+                //var curCalendars = calendars.Where(p => p.ProdLine == lines[0].Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
+                //var curQtyDtls = qualityLines.Where(p => p.ProdLine == lines[0].Line).ToList();
                 actStart = CalcActStartTime(lines[0].Line, actStart, curCalendars, curQtyDtls);
                 lineStart.RecID = lines[0].RecID;
                 lineStart.Line = lines[0].Line;
@@ -1707,7 +2201,7 @@ namespace Business.ResourceExamineManagement
         /// <param name="prodLines">产线明细</param>
         /// <param name="allResults">产线占用记录</param>
         /// <returns></returns>
-        public LineStartDto DealNextStartTime(WorkOrdMaster workOrd,LineStartDto lineStart,WorkOrdRouting routing, List<ProdLineDetail> prodLines, List<ScheduleResultOpMaster> allResults)
+        public LineStartDto DealNextStartTime(WorkOrdMaster workOrd,LineStartDto lineStart,WorkOrdRouting routing, List<ProdLineDetail> prodLines, List<ScheduleResultOpMaster> allResults, List<ShopCalendarWorkCtr> calendars, List<ScheduleExceptionMaster> exceptions, List<ShopCalendarWorkCtr> curCalendars, List<QualityLineWorkDetail> curQtyDtls, bool Check = false, bool UseSkill = true)
         {
             //本序工序编码
             int op = routing.OP;
@@ -1730,8 +2224,8 @@ namespace Business.ResourceExamineManagement
                 var curLine = lines.FirstOrDefault(p => p.Line == curRecord.Line);
                 if (curLine != null) {
                     //产线工作日历:当前产线的工作日历 + 默认工作日历
-                    var curCalendars = calendars.Where(p => p.ProdLine == curLine.Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
-                    var curQtyDtls = qualityLines.Where(p => p.ProdLine == curLine.Line).ToList();
+                    //var curCalendars = calendars.Where(p => p.ProdLine == curLine.Line || string.IsNullOrEmpty(p.ProdLine)).ToList();
+                    //var curQtyDtls = qualityLines.Where(p => p.ProdLine == curLine.Line).ToList();
                     DateTime startTime = CalcActStartTime(curLine.Line, scheTime, curCalendars, curQtyDtls);
                     startDto.RecID = curLine.RecID;
                     startDto.Line = curLine.Line;
@@ -1847,6 +2341,142 @@ namespace Business.ResourceExamineManagement
         }
 
         /// <summary>
+        /// 可用数量和可用时间
+        /// </summary>
+        /// <param name="actStart">开始时间</param>
+        /// <param name="lineStart">工序</param>
+        /// <param name="schedule">可插班明细</param>
+        /// <param name="lines">生产线明细</param>
+        /// <param name="allResults">产线占用记录</param>
+        /// <param name="numList">可用数量</param>
+        /// <returns></returns>
+        public void AvailableQuantity(WorkOrdMaster workOrd, DateTime actStart, LineStartDto lineStart, List<ProdLineDetail> lines, List<ScheduleResultOpMaster> allResults, List<ScheduleExceptionMaster> exceptions, out List<string> numList, out ScheduleResultOpMaster schedule, out DateTime wxEndTime, bool UseSkill = true)
+        {
+            wxEndTime = actStart;
+            numList = new List<string>();
+            schedule = null;
+            var num = 0;
+            var scheduleList = lineStart.OpType == "P" ? new List<ScheduleResultOpMaster>() : allResults.Where(p => p.InternalEquipmentCode == lineStart.InternalEquipmentCode && ((p.WorkStartTime <= actStart && p.WorkEndTime > actStart) || p.WorkStartTime >= actStart)).OrderBy(p => p.WorkStartTime).ToList();
+            if (scheduleList.Any())
+            {
+                schedule = null;
+                for (int i = 0; i < scheduleList.Count(); i++)
+                {
+                    if (!string.IsNullOrEmpty(lineStart.SkillNo) && UseSkill)
+                        numList = _getAvailableEquipmentAppService.GetEquipmentCountBySkillRestrictions(lineStart.SkillNo, lineStart.MoldTypeCode, lineStart.InternalEquipmentCode, actStart, allResults, lineStart.StandardStaffCount);
+                    else if (!string.IsNullOrEmpty(lineStart.MoldTypeCode))
+                        numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, actStart, allResults, lineStart.MoldTypeCode);
+                    else if (!string.IsNullOrEmpty(lineStart.InternalEquipmentCode))
+                        numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, actStart, allResults);
+                    if (numList.Any() && numList.Count > 0)
+                    {
+                        if (Convert.ToInt32(numList[0]) > 0)
+                        {
+                            schedule = scheduleList[i];
+                            break;
+                        }
+                        else
+                        {
+                            actStart = scheduleList[i].WorkEndTime;
+                        }
+                    }
+                }
+                //没有可插班时间
+                if (schedule == null)
+                {
+                    schedule = scheduleList[scheduleList.Count - 1];
+                }
+            }
+            else
+            {
+                if (!string.IsNullOrEmpty(lineStart.SkillNo) && UseSkill)
+                    numList = _getAvailableEquipmentAppService.GetEquipmentCountBySkillRestrictions(lineStart.SkillNo, lineStart.MoldTypeCode, lineStart.InternalEquipmentCode, actStart, allResults, lineStart.StandardStaffCount);
+                else if (!string.IsNullOrEmpty(lineStart.MoldTypeCode))
+                    numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, actStart, allResults, lineStart.MoldTypeCode);
+                else if (!string.IsNullOrEmpty(lineStart.InternalEquipmentCode))
+                    numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, actStart, allResults);
+            }
+            //占用时间过后依然无可用设备
+            if (scheduleList.Any() && numList.Any() && numList.Count > 0 || (scheduleList.Any() && num == 0 && numList.Count == 0))
+            {
+                num = numList.Count > 0 ? Convert.ToInt32(numList[0]) : 0;
+                //无可用设备
+                if (num <= 0)
+                {
+                    if (num == -99)
+                    {
+                        var entity = new ScheduleExceptionMaster();
+                        entity.Domain = workOrd.Domain;
+                        entity.WorkOrd = workOrd.WorkOrd;
+                        entity.ItemNum = workOrd.ItemNum;
+                        entity.CreateTime = DateTime.Now;
+                        entity.Remark = $"{workOrd.WorkOrd}排产异常:{lineStart.Op}-{numList[1]}";
+                        entity.Type = "手动排产";
+                        entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                        exceptions.Add(entity);
+                    }
+                    else
+                    {
+                        //是否是维修
+                        wxEndTime = num < 0 ? (numList.Count >= 3 ? Convert.ToDateTime(numList[2]) : schedule.WorkEndTime) : schedule.WorkEndTime;
+                        if (!string.IsNullOrEmpty(lineStart.SkillNo) && UseSkill)
+                            numList = _getAvailableEquipmentAppService.GetEquipmentCountBySkillRestrictions(lineStart.SkillNo, lineStart.MoldTypeCode, lineStart.InternalEquipmentCode, wxEndTime, allResults, lineStart.StandardStaffCount);
+                        else if (!string.IsNullOrEmpty(lineStart.MoldTypeCode))
+                            numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, wxEndTime, allResults, lineStart.MoldTypeCode);
+                        else if (!string.IsNullOrEmpty(lineStart.InternalEquipmentCode))
+                            numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, wxEndTime, allResults);
+
+                    }
+                }
+            }
+            if (numList.Count > 0)
+            {
+                if (Convert.ToInt32(numList[0]) == -99 && exceptions.FindIndex(e => e.WorkOrd == workOrd.WorkOrd) < 0)
+                {
+                    var entity = new ScheduleExceptionMaster();
+                    entity.Domain = workOrd.Domain;
+                    entity.WorkOrd = workOrd.WorkOrd;
+                    entity.ItemNum = workOrd.ItemNum;
+                    entity.CreateTime = DateTime.Now;
+                    entity.Remark = $"{workOrd.WorkOrd}排产异常:{lineStart.Op}-{numList[1]}";
+                    entity.Type = "手动排产";
+                    entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                    exceptions.Add(entity);
+                }
+                else if (Convert.ToInt32(numList[0]) == 0)
+                {
+                    for (int i = 1; i < 10; i++)
+                    {
+                        var newtime = actStart.AddHours(12 * i);
+                        if (!string.IsNullOrEmpty(lineStart.SkillNo) && UseSkill)
+                            numList = _getAvailableEquipmentAppService.GetEquipmentCountBySkillRestrictions(lineStart.SkillNo, lineStart.MoldTypeCode, lineStart.InternalEquipmentCode, newtime, allResults, lineStart.StandardStaffCount);
+                        else if (!string.IsNullOrEmpty(lineStart.MoldTypeCode))
+                            numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, newtime, allResults, lineStart.MoldTypeCode);
+                        else if (!string.IsNullOrEmpty(lineStart.InternalEquipmentCode))
+                            numList = _getAvailableEquipmentAppService.GetAvailableEquipmentForCurrentTeam(lineStart.InternalEquipmentCode, newtime, allResults);
+                        if (Convert.ToInt32(numList[0]) > 0)
+                        {
+                            break;
+                        }
+                    }
+                    if (Convert.ToInt32(numList[0]) == -99)
+                    {
+                        var entity = new ScheduleExceptionMaster();
+                        entity.Domain = workOrd.Domain;
+                        entity.WorkOrd = workOrd.WorkOrd;
+                        entity.ItemNum = workOrd.ItemNum;
+                        entity.CreateTime = DateTime.Now;
+                        entity.Remark = $"{workOrd.WorkOrd}排产异常:{lineStart.Op}-{numList[1]}";
+                        entity.Type = "手动排产";
+                        entity.OptTime = DateTime.Now.ToString("yyyyMMddHHmmss");
+                        exceptions.Add(entity);
+                    }
+                }
+            }
+        }
+
+
+        /// <summary>
         /// 通过提前期计算产线排产开始时间
         /// </summary>
         /// <param name="line">产线</param>

+ 6 - 0
MicroServices/Business/Business.Domain/StructuredDB/MES/IC/PurOrdDetail.cs

@@ -186,5 +186,11 @@ namespace Business.Domain
         [Comment("图号")]
         public string Drawing { get; set; }
 
+        /// <summary>
+        /// 工序号
+        /// </summary>
+        [Comment("工序号")]
+        public int Op { get; set; }
+
     }
 }

+ 12 - 0
MicroServices/Business/Business.Domain/StructuredDB/MES/IC/PurOrdMaster.cs

@@ -153,5 +153,17 @@ namespace Business.Domain
         /// </summary>
         [Comment("类型")]
         public string Typed { get; set; }
+
+        /// <summary>
+        /// 工单号
+        /// </summary>
+        [Comment("工单号")]
+        public string WorkOrd { get; set; }
+
+        /// <summary>
+        /// ERP工单号
+        /// </summary>
+        [Comment("ERP工单号")]
+        public string ERPWorkOrd { get; set; }
     }
 }

+ 51 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/EmpSkills.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.ComponentModel.DataAnnotations;
+using Microsoft.EntityFrameworkCore;
+
+namespace Business.Domain
+{
+    /// <summary>
+    /// 人员技能矩阵
+    /// </summary>
+    [Comment("人员技能矩阵")]
+    public class EmpSkills
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public long RecID { get; set; }
+
+        /// <summary>
+        /// 雇员名称
+        /// </summary>
+        [Comment("雇员名称")]
+        public string EmployeeName { get; set; }
+
+        /// <summary>
+        /// 技能编码
+        /// </summary>
+        [Comment("技能编码")]
+        public string SkillNo { get; set; }
+        /// <summary>
+        /// 雇员工号
+        /// </summary>
+        [Comment("雇员工号")]
+        public string EmployeeID { get; set; }
+        /// <summary>
+        /// 技能描述
+        /// </summary>
+        [Comment("技能描述")]
+        public string SkillDescription { get; set; }
+        /// <summary>
+        /// 技能等级
+        /// </summary>
+        [Comment("技能等级")]
+        public decimal SkillLevel { get; set; }
+    }
+}

+ 66 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/EquipmentList.cs

@@ -0,0 +1,66 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.Domain
+{
+    /// <summary>
+    /// 设备清单
+    /// </summary>
+    [Comment("设备清单")]
+    public class EquipmentList
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public long id { get; set; }
+
+        /// <summary>
+        /// 设备名称
+        /// </summary>
+        [Comment("设备名称")]
+        public string MachineName { get; set; }
+
+        /// <summary>
+        /// 厂内设备类型编码
+        /// </summary>
+        [Comment("厂内设备类型编码")]
+        public string InternalEquipmentCode { get; set; }
+
+        /// <summary>
+        /// 资产编码
+        /// </summary>
+        [Comment("资产编码")]
+        public string EquipmentAssetID { get; set; }
+
+        /// <summary>
+        /// 设备是否可用 1-可用 0-不可用
+        /// </summary>
+        [Comment("设备是否可用")]
+        public int IsSchedulable { get; set; }
+
+
+        /// <summary>
+        /// 预计释放时间
+        /// </summary>
+        [Comment("预计释放时间")]
+        public DateTime? EstimatedMaintenanceReleaseTime { get; set; }
+
+        /// <summary>
+        /// 标准维修天数
+        /// </summary>
+        [Comment("标准维修天数")]
+        public decimal? StandardRepairDays { get; set; }
+
+
+
+
+    }
+}
+

+ 55 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/MoldToolList.cs

@@ -0,0 +1,55 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.Domain
+{
+    /// <summary>
+    /// 模具清单
+    /// </summary>
+    [Comment("模具清单")]
+    public  class MoldToolList
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public int id { get; set; }
+        /// <summary>
+        /// 模具名称
+        /// </summary>
+        [Comment("模具名称")]
+        public string MoldName { get; set; }
+
+        /// <summary>
+        /// 模具类型编码
+        /// </summary>
+        [Comment("模具类型编码")]
+        public string MoldTypeCode { get; set; }
+
+        /// <summary>
+        /// 模具总数
+        /// </summary>
+        [Comment("模具总数")]
+        public int MoldCount { get; set; }
+
+        /// <summary>
+        /// 模具维修数量
+        /// </summary>
+        [Comment("模具维修数量")]
+        public int? ActiveMaintenanceMoldCount { get; set; }
+
+
+        /// <summary>
+        /// 预计释放时间
+        /// </summary>
+        [Comment("预计释放时间")]
+        public DateTime? MoldMaintenanceReleaseTime { get; set; }
+
+    }
+}

+ 6 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/PeriodSequenceDet.cs

@@ -98,5 +98,11 @@ namespace Business.Domain
         /// </summary>
         [Comment("创建时间")]
         public DateTime? CreateTime { get; set; }
+
+        /// <summary>
+        /// 开工时间
+        /// </summary>
+        [Comment("开工时间")]
+        public DateTime? UDate2 { get; set; }
     }
 }

+ 42 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/ProdLineDetail.cs

@@ -74,5 +74,47 @@ namespace Business.Domain
         /// </summary>
         [Comment("优先级")]
         public decimal Sequence { get; set; }
+
+        /// <summary>
+        /// 设备编码
+        /// </summary>
+        [Comment("设备编码")]
+        public string InternalEquipmentCode { get; set; }
+
+        /// <summary>
+        /// 模具编码
+        /// </summary>
+        [Comment("模具编码")]
+        public string MoldTypeCode { get; set; }
+
+        /// <summary>
+        /// 工作中心编码
+        /// </summary>
+        [Comment("工作中心编码")]
+        public string Site { get; set; }
+
+        /// <summary>
+        /// 员工技能编码
+        /// </summary>
+        [Comment("员工技能编码")]
+        public string SkillNo { get; set; }
+
+        /// <summary>
+        /// 标准人数
+        /// </summary>
+        [Comment("标准人数")]
+        public decimal StandardStaffCount { get; set; }
+
+        /// <summary>
+        /// 工序类型:M机械,P人工
+        /// </summary>
+        [Comment("工序类型")]
+        public string OpType { get; set; }
+
+        /// <summary>
+        /// Bom版本
+        /// </summary>
+        [Comment("Bom版本")]
+        public string Bom { get; set; }
     }
 }

+ 65 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/ProductScheduleControl.cs

@@ -0,0 +1,65 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.StructuredDB.Production
+{
+    /// <summary>
+    /// 排产配置表
+    /// </summary>
+    [Comment("排产配置表")]
+    public class ProductScheduleControl    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public long RecID { get; set; }
+
+        /// <summary>
+        /// 邻近?天内此工序设备未开工的不换模工单,默认3天
+        /// </summary>
+        [Comment("邻近天数")]
+        public int AdjacentDays { get; set; }
+
+        /// <summary>
+        /// 当前工序产出不超过?个后序班次数量 小数,默认3班
+        /// </summary>
+        [Comment("前序最大产出")]
+        public int PreorderClassesMax { get; set; }
+
+        /// <summary>
+        /// 当前序排产及报工多于?个后序班次时,当前序后延生产,默认2班
+        /// </summary>
+        [Comment("延后生产")]
+        public int PreorderClassesPut { get; set; }
+
+        /// <summary>
+        /// 前序不满足当前序?个班次数量时,当前序不排产,默认1班
+        /// </summary>
+        [Comment("当前序满足班次")]
+        public int ClassesOut { get; set; }
+
+        /// <summary>
+        /// 一周排产天数
+        /// </summary>
+        [Comment("一周排产天数")]
+        public int WeekDay { get; set; }
+
+        /// <summary>
+        /// 工单尾数不超过?%时,不使用新的班次,默认4% 即30分钟
+        /// </summary>
+        [Comment("尾数")]
+        public decimal RemainScale { get; set; }
+
+        /// <summary>
+        /// 是否启用人员技能矩阵
+        /// </summary>
+        [Comment("是否启用人员技能矩阵")]
+        public bool IsSkill { get; set; }
+    }
+}

+ 63 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/ScheduleResultOpMaster.cs

@@ -40,6 +40,18 @@ namespace Business.Domain
         public string Line { get; set; }
 
         /// <summary>
+        /// 工作中心
+        /// </summary>
+        [Comment("工作中心")]
+        public string WorkCtr { get; set; }
+
+        /// <summary>
+        /// 工序名称
+        /// </summary>
+        [Comment("工序名称")]
+        public string OpDescr { get; set; }
+
+        /// <summary>
         /// 物料编号
         /// </summary>
         [Comment("物料编号")]
@@ -76,12 +88,24 @@ namespace Business.Domain
         public DateTime? SetupEndTime { get; set; }
 
         /// <summary>
+        /// 换型时间
+        /// </summary>
+        [Comment("换型时间")]
+        public decimal SetupTime { get; set; }
+
+        /// <summary>
         /// 开工时间
         /// </summary>
         [Comment("开工时间")]
         public DateTime WorkStartTime { get; set; }
 
         /// <summary>
+        /// 开工时间=开始时间+换型时间
+        /// </summary>
+        [Comment("开工时间")]
+        public DateTime WorkActivateTime { get; set; }
+
+        /// <summary>
         /// 结束时间
         /// </summary>
         [Comment("结束时间")]
@@ -93,5 +117,44 @@ namespace Business.Domain
         [Comment("创建时间")]
         public DateTime CreateTime { get; set; }
 
+        /// <summary>
+        /// 厂内设备编码
+        /// </summary>
+        [Comment("厂内设备编码")]
+        public string InternalEquipmentCode { get; set; }
+
+        /// <summary>
+        /// 排产设备数量
+        /// </summary>
+        [Comment("排产设备数量")]
+        public int DeviceAllocationCount { get; set; }
+
+        /// <summary>
+        /// 模具类型编码
+        /// </summary>
+        [Comment("模具类型编码")]
+        public string MoldTypeCode { get; set; }
+        /// <summary>
+        /// 排产模具数量
+        /// </summary>
+        [Comment("排产模具数量")]
+        public int MoldAllocationCount { get; set; }
+        /// <summary>
+        /// 分配人员数量
+        /// </summary>
+        [Comment("分配人员数量")]
+        public decimal AssignedPersonnelCount { get; set; }
+
+        /// <summary>
+        /// 分配人员工号
+        /// </summary>
+        [Comment("分配人员工号")]
+        public string AssignedEmployeeID { get; set; }
+        /// <summary>
+        ///人员技能编码
+        /// </summary>
+        [Comment("人员技能编码")]
+        public string SkillNo { get; set; }
+
     }
 }

+ 12 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/ShopCalendarWorkCtr.cs

@@ -98,5 +98,17 @@ namespace Business.Domain
         /// </summary>
         [Comment("是否有效")]
         public bool IsActive { get; set; }
+
+        /// <summary>
+        /// 班组类型 M-设备班组;P-人工班组
+        /// </summary>
+        [Comment("班组类型")]
+        public char TeamType { get; set; }
+
+        /// <summary>
+        /// 工作中心
+        /// </summary>
+        [Comment("工作中心")]
+        public string WorkCtr { get; set; }
     }
 }

+ 12 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/WorkOrdMaster.cs

@@ -234,5 +234,17 @@ namespace Business.Domain
         [Comment("优先级编号")]
         public string PriorityNo { get; set; }
 
+        /// <summary>
+        /// BOM版本
+        /// </summary>
+        [Comment("BOM版本")]
+        public string Refs { get; set; }
+
+        /// <summary>
+        /// 部门
+        /// </summary>
+        [Comment("部门")]
+        public string Department { get; set; }
+
     }
 }

+ 120 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/WorkOrdRouting.cs

@@ -146,5 +146,125 @@ namespace Business.Domain
         /// </summary>
         [Comment("SAP工序")]
         public string StdOp { get; set; }
+
+        /// <summary>
+        /// 工作中心
+        /// </summary>
+        [Comment("工作中心")]
+        public string WorkCtr { get; set; }
+
+        /// <summary>
+        /// 工艺路线编码
+        /// </summary>
+        [Comment("工艺路线编码")]
+        public string Ufld1 { get; set; }
+
+        /// <summary>
+        /// 生产车间
+        /// </summary>
+        [Comment("生产车间")]
+        public string Ufld2 { get; set; }
+
+        /// <summary>
+        /// 工序控制码
+        /// </summary>
+        [Comment("工序控制码")]
+        public string Ufld3 { get; set; }
+
+        /// <summary>
+        /// 工序委外
+        /// </summary>
+        [Comment("工序委外")]
+        public int ProcessOut { get; set; }
+
+        /// <summary>
+        /// 工序委外提前期
+        /// </summary>
+        [Comment("工序委外提前期")]
+        public decimal ProcessOutDay { get; set; }
+
+        /// <summary>
+        /// 工序委外供应商代码
+        /// </summary>
+        [Comment("工序委外供应商代码")]
+        public string ProcessOutSupp { get; set; }
+
+        /// <summary>
+        /// 设备编码
+        /// </summary>
+        [Comment("设备编码")]
+        public string Machine { get; set; }
+
+        /// <summary>
+        /// 模具编码
+        /// </summary>
+        [Comment("模具编码")]
+        public string ToolCode { get; set; }
+
+        /// <summary>
+        /// 人员技能编号
+        /// </summary>
+        [Comment("人员技能编号")]
+        public string Engineer { get; set; }
+
+        /// <summary>
+        /// 标准人数
+        /// </summary>
+        [Comment("标准人数")]
+        public decimal RunCrew { get; set; }
+
+        /// <summary>
+        /// 产线
+        /// </summary>
+        [Comment("产线")]
+        public string ProdLine { get; set; }
+
+        /// <summary>
+        /// 单位产能
+        /// </summary>
+        [Comment("单位产能")]
+        public decimal MachBdnRate { get; set; }
+
+        /// <summary>
+        /// 准备时间
+        /// </summary>
+        [Comment("准备时间")]
+        public decimal StdSetupTime { get; set; }
+
+        /// <summary>
+        /// 工序类型
+        /// </summary>
+        [Comment("工序类型")]
+        public string WorkCode { get; set; }
+
+        /// <summary>
+        /// 作业编码
+        /// </summary>
+        [Comment("作业编码")]
+        public string ChargeCode { get; set; }
+
+        /// <summary>
+        /// 作业编码
+        /// </summary>
+        [Comment("作业编码")]
+        public string ERPfld2 { get; set; }
+
+        /// <summary>
+        /// 机器时间
+        /// </summary>
+        [Comment("机器时间")]
+        public decimal MachinesperOp { get; set; }
+
+        /// <summary>
+        /// 准备时间
+        /// </summary>
+        [Comment("准备时间")]
+        public decimal Setup { get; set; }
+
+        /// <summary>
+        /// 人工时间
+        /// </summary>
+        [Comment("人工时间")]
+        public decimal Labor { get; set; }
     }
 }

+ 55 - 0
MicroServices/Business/Business.Domain/StructuredDB/Production/sim_andon.cs

@@ -0,0 +1,55 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.Domain
+{
+    /// <summary>
+    /// 模具异常记录
+    /// </summary>
+    [Comment("模具异常记录")]
+    public  class sim_andon
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public long id { get; set; }
+
+        /// <summary>
+        /// 模具类型编码
+        /// </summary>
+        [Comment("模具类型编码")]
+        public string Mold { get; set; }
+
+       
+
+        /// <summary>
+        /// 模具维修数量
+        /// </summary>
+        [Comment("模具维修数量")]
+        public int? ToolRepairQuantity { get; set; }
+
+
+        /// <summary>
+        /// 预计释放时间
+        /// </summary>
+        [Comment("预计释放时间")]
+        public DateTime? EstimatedMaintenanceReleaseTime1 { get; set; }
+
+        /// <summary>
+        /// 恢复时间
+        /// </summary>
+        [Comment("恢复时间")]
+        public DateTime? RestorationTime { get; set; }
+
+
+
+
+    }
+}

+ 5 - 0
MicroServices/Business/Business.EntityFrameworkCore/EntityFrameworkCore/DOP/BusinessDbContext.cs

@@ -111,6 +111,11 @@ namespace Business.EntityFrameworkCore
         public DbSet<ScheduleExceptionMaster> ScheduleExceptionMaster { get; set; }
 
         /// <summary>
+        /// 排产异常记录表
+        /// </summary>
+        public DbSet<ProductScheduleControl> ProductScheduleControl { get; set; }
+
+        /// <summary>
         /// 产线工序开始准备时间记录表
         /// </summary>
         public DbSet<WorkOrdSetupTimeRecord> WorkOrdSetupTimeRecord { get; set; }

+ 48 - 0
MicroServices/Business/QuartzSettings/logs/logs.txt

@@ -4528,3 +4528,51 @@
 {"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-07-28T14:24:56.8035392+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
 {"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-07-28T14:24:56.8075293+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
 {"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-07-28T14:24:56.8094639+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:04:35.8643884+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:04:35.9021073+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:04:35.9056677+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:04:35.9071937+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:04:35.9124112+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T14:04:35.9143596+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:20:50.3134335+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:20:50.3596501+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:20:50.3631136+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:20:50.3657362+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:20:50.3707626+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T14:20:50.3733441+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:37:56.9041888+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:37:56.9407199+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:37:56.9441453+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:37:56.9457973+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:37:56.9506594+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T14:37:56.9527546+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:49:44.917166+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:49:44.9528484+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:49:44.9557457+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:49:44.9573924+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T14:49:44.9621353+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T14:49:44.9645402+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:05:43.1820992+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:05:43.218426+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:05:43.2215303+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:05:43.2231203+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:05:43.2273953+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T15:05:43.2298087+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:12:53.9101434+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:12:53.947415+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:12:53.9506718+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:12:53.9524333+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T15:12:53.956786+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T15:12:53.9594169+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T17:10:13.6431508+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T17:10:13.6816171+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T17:10:13.6850331+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T17:10:13.6868145+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T17:10:13.6912652+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T17:10:13.6935084+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步WMS物料订单等基础数据到MySQL","GroupName":"systemquartzjob","BeginDate":"2025-10-09T18:01:49.64461+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时创建NLog日志按月分表","GroupName":"systemquartzjob","BeginDate":"2025-10-09T18:01:49.6817121+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"定时同步MySQL基础数据到MongoDB","GroupName":"systemquartzjob","BeginDate":"2025-10-09T18:01:49.6847725+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"长周期物料PR","GroupName":"systemquartzjob","BeginDate":"2025-10-09T18:01:49.6864559+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"TestTimeOut","GroupName":"systemquartzjob","BeginDate":"2025-10-09T18:01:49.690658+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}
+{"TaskName":"BOM预处理自动任务","GroupName":"BOM预处理自动任务","BeginDate":"2025-10-09T18:01:49.6925765+08:00","EndDate":null,"Msg":"任务初始化启动成功:6","id":0,"timeflag":null,"changetime":null}