Prechádzať zdrojové kódy

Merge branch 'dev' of http://123.60.180.165:4647/ZZYDOP/DOPCore into dev

Murphy 2 rokov pred
rodič
commit
82d682142c

+ 39 - 0
MicroServices/Business/Business.Application.Contracts/Dto/LineWorkPointDto.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Business.Dto
+{
+    /// <summary>
+    /// 产线工作段Dto
+    /// </summary>
+    public class LineWorkPointDto
+    {
+        /// <summary>
+        /// 层级
+        /// </summary>
+        public int Level { get; set; }
+
+        /// <summary>
+        /// 产线
+        /// </summary>
+        public string Line { get; set; }
+
+        /// <summary>
+        /// 周几
+        /// </summary>
+        public int WeekDay { get; set; }
+
+        /// <summary>
+        /// 开始时间点
+        /// </summary>
+        public DateTime StartPoint { get; set; }
+
+        /// <summary>
+        /// 结束时间点
+        /// </summary>
+        public DateTime EndPoint { get; set; }
+    }
+}

+ 33 - 6
MicroServices/Business/Business.Application.Contracts/Dto/WorkOrdRoutingDto.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Runtime.CompilerServices;
 using System.Text;
 using System.Threading.Tasks;
 
@@ -11,11 +12,6 @@ namespace Business.Business.Dto
     /// </summary>
     public class WorkOrdRoutingDto
     {
-        /// <summary>
-        /// 工序
-        /// </summary>
-        public int Op { get; set; }
-
         /// <summary>
         /// 父级工序
         /// </summary>
@@ -26,9 +22,40 @@ namespace Business.Business.Dto
         /// </summary>
         public int level { get; set; }
 
+        /// <summary>
+        /// 工序(当前产线的关键工序)
+        /// </summary>
+        public int Op { get; set; }
+
         /// <summary>
         /// 标准节拍(小时/个)
         /// </summary>
-        public decimal RunTime { get; set; }
+        public List<LineDto> lines { get; set; }
+    }
+
+    /// <summary>
+    /// 产线Dto
+    /// </summary>
+    public class LineDto 
+    {
+        /// <summary>
+        /// 产线
+        /// </summary>
+        public string Line { get; set; }
+
+        /// <summary>
+        /// 单位时间标准产能
+        /// </summary>
+        public decimal Rate { get; set; }
+
+        /// <summary>
+        /// 产线提前期
+        /// </summary>
+        public decimal SetupTime { get; set; }
+
+        /// <summary>
+        /// 产线可开工日期
+        /// </summary>
+        public DateTime StartTime { get; set; }
     }
 }

+ 1 - 1
MicroServices/Business/Business.Application/PriorityManagement/PriorityAppService.cs

@@ -29,7 +29,7 @@ namespace Business.PriorityManagement
                 id = p.Id,
                 urgent = p.urgent.GetValueOrDefault(),
                 level = p.custom_level.GetValueOrDefault()
-            }).AsQueryable<PriorityDto>().ToList(); ;
+            }).AsQueryable<PriorityDto>().ToList(); 
             
             //子表数据处理:根据订单id分组取出客户要求交期交期最大的数据
             var entrys = from t in sentrys

+ 355 - 47
MicroServices/Business/Business.Application/Quartz/ProductionScheduleAppService.cs

@@ -1,10 +1,16 @@
 using Business.Business.Dto;
+using Business.Core.Utilities;
+using Business.Dto;
+using Business.ResourceExamineManagement.Dto;
 using Bussiness.EntityFrameworkCore.SqlRepositories;
 using Bussiness.Model.MES.IC;
 using Bussiness.Model.Production;
 using Bussiness.Model.SRM;
+using MongoDB.Driver;
+using MongoDB.Driver.Linq;
 using System;
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -19,6 +25,7 @@ namespace Business.Quartz
     /// </summary>
     public class ProductionScheduleAppService : ApplicationService
     {
+        #region 服务
         /// <summary>
         /// 物料
         /// </summary>
@@ -59,6 +66,49 @@ namespace Business.Quartz
         /// </summary>
         private ISqlRepository<ScheduleResultOpMaster> _scheduleResultOpMaster;
 
+        /// <summary>
+        /// 工作日历数据
+        /// </summary>
+        private ISqlRepository<ShopCalendarWorkCtr> _shopCalendarWorkCtr;
+
+        /// <summary>
+        /// 排产异常记录表
+        /// </summary>
+        private ISqlRepository<ScheduleExceptionMaster> _scheduleExceptionMaster;
+
+        /// <summary>
+        /// 产线休息时间记录表
+        /// </summary>
+        private ISqlRepository<QualityLineWorkDetail> _qualityLineWorkDetail;
+
+        /// <summary>
+        /// 节假日记录表
+        /// </summary>
+        private ISqlRepository<HolidayMaster> _holidayMaster;
+
+        /// <summary>
+        /// 雪花算法
+        /// </summary>
+        SnowFlake help = new SnowFlake();
+
+        /// <summary>
+        /// 工作日历数据
+        /// </summary>
+        private List<ShopCalendarWorkCtr> calendars;
+
+        /// <summary>
+        /// 产线休息记录数据
+        /// </summary>
+        private List<QualityLineWorkDetail> qualityLines;
+
+        /// <summary>
+        /// 节假日记录数据
+        /// </summary>
+        private List<HolidayMaster> holidays;
+
+        #endregion
+
+        #region 构造函数
         /// <summary>
         /// 构造函数
         /// </summary>
@@ -70,7 +120,11 @@ namespace Business.Quartz
             ISqlRepository<ProdLineDetail> prodLineDetail,
             ISqlRepository<PeriodSequenceDet> periodSequenceDet,
             ISqlRepository<ScheduleResultOpMaster> scheduleResultOpMaster,
-            ISqlRepository<InvMaster> invMaster
+            ISqlRepository<InvMaster> invMaster,
+            ISqlRepository<ShopCalendarWorkCtr> shopCalendarWorkCtr,
+            ISqlRepository<ScheduleExceptionMaster> scheduleExceptionMaster,
+            ISqlRepository<QualityLineWorkDetail> qualityLineWorkDetail,
+            ISqlRepository<HolidayMaster> holidayMaster
             )
         { 
             _itemMaster= itemMaster;
@@ -81,7 +135,12 @@ namespace Business.Quartz
             _periodSequenceDet = periodSequenceDet;
             _scheduleResultOpMaster= scheduleResultOpMaster;
             _invMaster= invMaster;
+            _shopCalendarWorkCtr= shopCalendarWorkCtr;
+            _scheduleExceptionMaster= scheduleExceptionMaster;
+            _qualityLineWorkDetail= qualityLineWorkDetail;
+            _holidayMaster = holidayMaster;
         }
+        #endregion
 
         /// <summary>
         /// 执行生产排产
@@ -96,61 +155,296 @@ namespace Business.Quartz
         /// </summary>
         public async Task DoProductShcedule()
         {
-            ////1、获取需要排产的工单:Status为空且IsActive==1
-            //List<WorkOrdMaster> workOrds = _workOrdMaster.GetListAsync(p => string.IsNullOrEmpty(p.Status) && p.IsActive ==1).Result;
-            //if (workOrds.Count == 0)
-            //{
-            //    return;
-            //}
-            ////2、获取数据
-            ////获取工单工艺路径数据
-            //List<WorkOrdRouting> workOrdRoutings = _workOrdRouting.GetListAsync(p => workOrds.Select(m=>m.WorkOrd).Contains(p.WorkOrd) && p.Domain == "1001" && p.Status != "C" && p.IsActive == 1).Result;
-            ////获取物料对应的生产线信息:物料、工序对应的生产线
-            //List<ProdLineDetail> prodLineDetails = _prodLineDetail.GetListAsync(p => workOrds.Select(m => m.ItemNum).Contains(p.Part) && p.Domain == "1001" && p.Status != "C" && p.IsActive == 1).Result;
-            ////获取当前日期往后的排产记录数据
-            //List<ScheduleResultOpMaster> schedules = _scheduleResultOpMaster.GetListAsync(p=>workOrds.Select(m=>m.ItemNum).Contains(p.ItemNum) && p.Domain == "1001").Result;
-
-            ////3、工序预处理
-            //List<WorkOrdRoutingDto> routingDtos = ProcPretreatment(workOrdRoutings);
-
-            ////3、排产
-            ////排产结果(记录所有工序的排产情况)
-            //List<ScheduleResultOpMaster> scheduleResults = new List<ScheduleResultOpMaster>();
-            ////生产周期(记录最后一个工序的排产情况)
-            //List<PeriodSequenceDet> periodsDet = new List<PeriodSequenceDet>();
-            //foreach (var item in workOrds)
-            //{
-
-            //}
+            //1、获取需要排产的工单:Status为空且IsActive==1
+            List<WorkOrdMaster> workOrds = _workOrdMaster.Select(p => string.IsNullOrEmpty(p.Status) && p.IsActive == 1).Result;
+            if (workOrds.Count == 0)
+            {
+                return;
+            }
+            //获取排产工单的最早计划开工日期
+            DateTime earlist = workOrds.Min(p => p.OrdDate.GetValueOrDefault()).Date;
+            //2、获取数据
+            //获取工单工艺路径数据
+            List<WorkOrdRouting> workOrdRoutings = _workOrdRouting.Select(p => workOrds.Select(m => m.WorkOrd).Contains(p.WorkOrd) && p.Domain == "1001" && p.Status != "C" && p.IsActive == 1).Result;
+            //获取物料对应的生产线信息:物料、工序对应的生产线
+            List<ProdLineDetail> prodLines = _prodLineDetail.Select(p => workOrds.Select(m => m.ItemNum).Contains(p.Part) && p.Domain == "1001" && p.IsActive == 1).Result;
+            //获取生产周期数据
+            List<PeriodSequenceDet> periodSequences = _periodSequenceDet.Select(p=> workOrds.Select(m => m.ItemNum).Contains(p.ItemNum) && p.PlanDate >= earlist && p.Domain == "1001" && p.IsActive == 1).Result;
+            //获取当前日期往后的排产记录数据
+            List<ScheduleResultOpMaster> schedules = _scheduleResultOpMaster.Select(p => workOrds.Select(m => m.ItemNum).Contains(p.ItemNum) && p.WorkDate >= earlist && p.Domain == "1001").Result;
+            //获取工作日历数据
+            calendars = _shopCalendarWorkCtr.Select(p=>p.Domain == "1001" && p.IsActive == 1).Result;
+            //获取产线休息记录数据
+            qualityLines = _qualityLineWorkDetail.Select(p => p.Domain == "1001" && p.IsActive == 1).Result;
+            //获取节假日记录数据
+            holidays = _holidayMaster.Select(p => p.Domain == "1001" && p.IsActive == 1 && p.Dated >= earlist).Result;
+
+            //3、排产
+            //排产异常记录
+            List<ScheduleExceptionMaster> scheduleExceptions = new List<ScheduleExceptionMaster>();
+            //生产周期
+            List<PeriodSequenceDet> periodsDet = new List<PeriodSequenceDet>();
+            //排产记录表
+            List<ScheduleResultOpMaster> scheduleResults = new List<ScheduleResultOpMaster>();
+            foreach (var item in workOrds)
+            {
+                DateTime planStart = item.OrdDate.GetValueOrDefault().Date;
+                //工序预处理
+                List<WorkOrdRoutingDto> routingDtos = ProcPretreatment(workOrdRoutings, prodLines);
+                
+                //获取主工序对应的产线
+                var first = routingDtos.Where(p => p.level == 1).FirstOrDefault();
+                if (first == null)
+                {
+                    //记录排产异常原因
+                    scheduleExceptions.Add(new ScheduleExceptionMaster
+                    {
+                        RecID = help.NextId(),
+                        Domain = "1001",
+                        WorkOrd = item.WorkOrd,
+                        Remark = "工单没有维护工序数据",
+                        CreatTime = DateTime.Now.Date
+                    }); 
+                    continue;
+                }
+                if (first.lines.Count() == 0)
+                {
+                    //记录排产异常原因
+                    scheduleExceptions.Add(new ScheduleExceptionMaster
+                    {
+                        RecID = help.NextId(),
+                        Domain = "1001",
+                        WorkOrd = item.WorkOrd,
+                        Remark = "工单没有维护产线数据",
+                        CreatTime = DateTime.Now.Date
+                    });
+                    continue;
+                }
+                //确定主工序排产产线以及排产开始时间
+                LineDto line = ConfirmLine(first.Op, planStart, first.lines, schedules);
+                //产线排产
+                LineSchedule(item, line, routingDtos, periodsDet, scheduleResults, scheduleExceptions);
+            }
+        }
+
+        /// <summary>
+        /// 排产
+        /// </summary>
+        /// <param name="workOrd">工单</param>
+        /// <param name="line">主工序对应的产线</param>
+        /// <param name="routingDtos">每层级工序对应的产线信息</param>
+        /// <param name="periodsDet">生产周期</param>
+        /// <param name="scheduleResults">排产结果</param>
+        /// <param name="scheduleExceptions">排产异常记录</param>
+        public void LineSchedule(WorkOrdMaster workOrd, LineDto line, List<WorkOrdRoutingDto> routingDtos,List<PeriodSequenceDet> periodsDet, List<ScheduleResultOpMaster> scheduleResults, List<ScheduleExceptionMaster> scheduleExceptions)
+        {
+            //生产周期
+            List<PeriodSequenceDet> curSequences = new List<PeriodSequenceDet>();
+            //排产明细
+            List< ScheduleResultOpMaster > curScheduleRsts = new List<ScheduleResultOpMaster >();
+            //获取当前产线的工作日历
+            var curCalendars = calendars.Where(p => p.ProdLine == line.Line).ToList();
+            //获取当前产线的休息记录
+            var curQtyDtls = qualityLines.Where(p => p.ProdLine == line.Line).OrderBy(m => m.Line).ToList();
+            if (curCalendars.Count() == 0 || curCalendars.Select(p=>p.WeekDay).Distinct().Count() != 7)
+            {
+                //记录排产异常原因
+                scheduleExceptions.Add(new ScheduleExceptionMaster
+                {
+                    RecID = help.NextId(),
+                    Domain = "1001",
+                    WorkOrd = workOrd.WorkOrd,
+                    Remark = "工单对应产线工作日历数据错误",
+                    CreatTime = DateTime.Now.Date
+                });
+                return;
+            }
+            //产线可排产开始日期
+            DateTime workStartTime = DealStartTime(line.StartTime, curCalendars, curQtyDtls);
+
+        }
         
+        /// <summary>
+        /// 计算主产线实际排产开始时间
+        /// </summary>
+        /// <param name="startTime">开始时间</param>
+        /// <param name="curCalendars">当前产线工作日历</param>
+        /// <param name="curQtyDtls">当前产线休息记录</param>
+        /// <returns></returns>
+        public DateTime DealStartTime(DateTime startTime,List<ShopCalendarWorkCtr> curCalendars, List<QualityLineWorkDetail> curQtyDtls)
+        { 
+            //实际排产开始时间
+            DateTime actStart = startTime;
+            //开始时间是周几
+            int weekDay = (int)startTime.DayOfWeek;
+            //当天的工作日历
+            var shopCal = curCalendars.Where(p => p.WeekDay == weekDay).First();
+            //当前日期的工作时间段
+            List<LineWorkPointDto> workPoints = DealWorkDayToLevels(startTime, shopCal,curQtyDtls);
+            //计算starttime处于那个工作时间段
+            var curPoint = workPoints.Where(p => startTime >= p.StartPoint && startTime <= p.EndPoint).FirstOrDefault();
+            if (startTime != curPoint.EndPoint)
+            {
+                return startTime;
+            }
+            //查询下一时间段的开始时间点
+            var nextPoint = workPoints.Where(p => p.Level == curPoint.Level + 1).FirstOrDefault();
+            if (nextPoint != null)
+            {
+                return nextPoint.StartPoint;
+            }
+            //开始时间为今天下班时间,实际排产开始时间为下一个工作日的开始时间
+            actStart = GetNextWorkDay(weekDay, startTime, curCalendars);
+            return actStart;
+        }
+
+        /// <summary>
+        /// 获取下一个工作日开始时间
+        /// </summary>
+        /// <param name="weekDay">当前周几</param>
+        /// <param name="startTime">开始时间</param>
+        /// <param name="curCalendars">当前产线的工作日历</param>
+        /// <returns></returns>
+        public DateTime GetNextWorkDay(int weekDay, DateTime startTime, List<ShopCalendarWorkCtr> curCalendars)
+        {
+            DateTime rtnData = startTime;
+            //下一天
+            DateTime nextDate = startTime.Date.AddDays(1);
+            //下一天是周几
+            int nextWeekDay = (weekDay + 1) % 7;
+            var calendar = curCalendars.FirstOrDefault(p=>p.WeekDay == nextWeekDay);
+            //判断下一天是否是工作日
+            if (nextWeekDay == 0 || nextWeekDay == 6)//下一天是周六或者周日,需要判断是否调休,需要加班
+            {
+                if (!holidays.Exists(p => p.Dated.GetValueOrDefault().Date == nextDate && p.Ufld1 == "调休"))//下一天是周末
+                {
+                    //递归继续找下一个工作日
+                    GetNextWorkDay(nextWeekDay, nextDate, curCalendars);
+                }
+                rtnData = nextDate.AddHours((double)calendar.ShiftsStart1);
+                return rtnData;
+            }
+            //下一天不是周六周日,需要判断是不是节假日
+            if (holidays.Exists(p => p.Dated.GetValueOrDefault().Date == nextDate && p.Ufld1 == "休假"))//是节假日
+            {
+                //递归继续找下一个工作日
+                GetNextWorkDay(nextWeekDay, nextDate, curCalendars);
+            }
+            rtnData = nextDate.AddHours((double)calendar.ShiftsStart1);
+            return rtnData;
+        }
+
+        /// <summary>
+        /// 处理当前日期的工作时间段
+        /// </summary>
+        /// <param name="startTime"></param>
+        /// <param name="shopCal">当前产线的工作日历-周几</param>
+        /// <param name="curQtyDtls">每天休息记录</param>
+        /// <returns></returns>
+        public List<LineWorkPointDto> DealWorkDayToLevels(DateTime startTime, ShopCalendarWorkCtr shopCal, List<QualityLineWorkDetail> curQtyDtls)
+        {
+            //年-月-日
+            string date = startTime.Date.ToString("yyyy-MM-dd");
+            //排产记录结束日期是周几
+            int weekDay = (int)startTime.DayOfWeek;
+            //计算当天的开工时间点,停工时间点
+            DateTime dayStartPoint = startTime.Date.AddHours(Convert.ToDouble(shopCal.ShiftsStart1));
+            DateTime dayEndPoint = dayStartPoint.AddHours(Convert.ToDouble(shopCal.ShiftsHours1));
+            //工作时间段
+            List<LineWorkPointDto> workPoints = new List<LineWorkPointDto>();
+            LineWorkPointDto dto = new LineWorkPointDto();
+            dto.Level = 1;
+            dto.Line = shopCal.ProdLine;
+            dto.WeekDay = weekDay;
+            dto.StartPoint = dayStartPoint;
+            int level = 1;
+            foreach (var item in curQtyDtls)
+            {
+                DateTime endPoint = Convert.ToDateTime(date + " " + item.RestTimePoint);
+                workPoints.Add(dto);
+                level++;
+                dto = new LineWorkPointDto();
+                dto.Level = level;
+                dto.Line = shopCal.ProdLine;
+                dto.WeekDay = weekDay;
+                dto.StartPoint = endPoint.AddMinutes(item.RestTime);
+            }
+            dto.EndPoint = dayEndPoint;
+            workPoints.Add(dto);
+
+            return workPoints;
+        }
+
+        /// <summary>
+        /// 确定工序排产对应的产线
+        /// </summary>
+        /// <param name="op">主产线的最后一道工序</param>
+        /// <param name="planStart">当前工单计划开始时间</param>
+        /// <param name="lines">主工序对应的产线</param>
+        /// <param name="scheduleResults"></param>
+        /// <returns></returns>
+        public LineDto ConfirmLine(int op, DateTime planStart, List<LineDto> lines, List<ScheduleResultOpMaster> scheduleResults)
+        {
+            LineDto rtn = new LineDto();
+            //多条产线确认最优产线:按开工时间升序,产能倒叙排序
+            foreach (var item in lines)
+            {
+                //获取当前产线的排产最晚结束时间
+                var schedule = scheduleResults.Where(p => p.Line == item.Line && p.Op == op).OrderByDescending(p => p.WorkEndTime).FirstOrDefault();
+                //当前产线没有排产记录,开始日期= planStart;
+                //当前产线有排产记录,如果产线排产最晚结束时间≤planStart 开始日期=planStart,反之 开始日期 = WorkEndTime
+                var latest = schedule == null ? planStart : (schedule.WorkEndTime <= planStart ? planStart : schedule.WorkEndTime);
+                if (rtn == null)
+                {
+                    rtn.Line = item.Line;
+                    rtn.Rate = item.Rate;
+                    rtn.StartTime = latest;
+                }
+                if (latest < rtn.StartTime || (latest == rtn.StartTime && item.Rate > rtn.Rate))
+                {//当前产线最早开工时间早于之前的产线或者产线开工时间相同且当前产线产能大于之前的产线,则当前产线为优先选择产线
+                    rtn.Line = item.Line;
+                    rtn.Rate = item.Rate;
+                    rtn.StartTime = latest;
+                }
+            }
+            return rtn;
         }
 
         /// <summary>
         /// 工单工艺路线预处理
         /// </summary>
-        /// <param name="WoRuntings"></param>
+        /// <param name="woRuntings">工单工序</param>
+        /// <param name="prodLines">产线</param>
         /// <returns></returns>
-        public List<WorkOrdRoutingDto> ProcPretreatment(List<WorkOrdRouting> woRuntings)
+        public List<WorkOrdRoutingDto> ProcPretreatment(List<WorkOrdRouting> woRuntings, List<ProdLineDetail> prodLines)
         {
             List<WorkOrdRoutingDto> routingDtos = new List<WorkOrdRoutingDto>();
             //取主工序(第一层级工序)
-            var firsts = woRuntings.Where(p=>p.ParentOp == 0).ToList();
+            var firsts = woRuntings.Where(p =>p.ParentOp == 0).ToList();
             if (firsts.Count == 0)
             {
                 return routingDtos;
             }
-            WorkOrdRoutingDto dto;
-            foreach (var item in firsts)
-            {
-                dto = new WorkOrdRoutingDto();
-                dto.Op = item.OP;
-                dto.ParentOp= item.ParentOp;
+            WorkOrdRoutingDto dto = new WorkOrdRoutingDto();
+            //当前层级的关键工序/报工工序(当前层级工序Op最大的工序)
+            var lastOp = firsts.OrderByDescending(p => p.OP).FirstOrDefault();
+            if (lastOp != null) {
+                dto.ParentOp = lastOp.ParentOp;
                 dto.level = 1;
-                dto.RunTime = item.RunTime;
+                dto.Op = lastOp.OP;
+                //当前层级工序对应的产线
+                var curLines = prodLines.Where(p => p.Part == lastOp.WorkOrd && p.Op == lastOp.OP).Select(m => new LineDto
+                {
+                    Line = m.Line,
+                    Rate = m.Rate,
+                    SetupTime = m.SetupTime
+                }).AsQueryable<LineDto>().ToList();
+                dto.lines = curLines;
                 routingDtos.Add(dto);
             }
+            
             //递归处理其他层级工序
-            RecursionProc(woRuntings, firsts, 1, routingDtos);
+            RecursionProc(woRuntings, firsts, 1, routingDtos, prodLines);
 
             return routingDtos;
         }
@@ -159,10 +453,11 @@ namespace Business.Quartz
         /// 递归处理工序
         /// </summary>
         /// <param name="woRuntings">工单工序</param>
-        /// <param name="curLevels">上-层级工序</param>
+        /// <param name="preLevels">上-层级工序</param>
         /// <param name="level">层级</param>
         /// <param name="routingDtos">返回结果</param>
-        public void RecursionProc(List<WorkOrdRouting> woRuntings, List<WorkOrdRouting> preLevels, int level, List<WorkOrdRoutingDto> routingDtos)
+        /// <param name="prodLines">产线</param>
+        public void RecursionProc(List<WorkOrdRouting> woRuntings, List<WorkOrdRouting> preLevels, int level, List<WorkOrdRoutingDto> routingDtos, List<ProdLineDetail> prodLines)
         {
             //获取当前层级工序
             var curLevels = woRuntings.Where(p => preLevels.Select(m=>m.OP).Contains(p.ParentOp)).ToList();
@@ -170,16 +465,29 @@ namespace Business.Quartz
             {
                 return;
             }
-            foreach (var item in curLevels)
+            //获取父级Op
+            var parentOps = curLevels.Select(m => m.ParentOp).Distinct().ToList();
+            foreach (var item in parentOps)
             {
                 var dto = new WorkOrdRoutingDto();
-                dto.Op = item.OP;
-                dto.ParentOp = item.ParentOp;
-                dto.level = level + 1;
-                dto.RunTime = item.RunTime;
-                routingDtos.Add(dto);
+                var lastOp = curLevels.Where(p=>p.ParentOp == item).OrderByDescending(m=>m.OP).FirstOrDefault();
+                if (lastOp != null){
+                    dto.Op = lastOp.OP;
+                    dto.ParentOp = lastOp.ParentOp;
+                    dto.level = level + 1;
+                    //当前层级工序对应的产线
+                    var curLines = prodLines.Where(p => p.Part == lastOp.WorkOrd && p.Op == lastOp.OP).Select(m => new LineDto
+                    {
+                        Line = m.Line,
+                        Rate = m.Rate,
+                        SetupTime = m.SetupTime
+                    }).AsQueryable<LineDto>().ToList();
+                    dto.lines = curLines;
+                    routingDtos.Add(dto);
+                }
             }
-            RecursionProc(woRuntings, curLevels, level + 1, routingDtos);
+            //递归
+            RecursionProc(woRuntings, curLevels, level + 1, routingDtos,prodLines);
         }
     }
 }

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

@@ -111,6 +111,26 @@ namespace Business.EntityFrameworkCore
         /// </summary>
         public DbSet<WorkOrdRouting> WorkOrdRouting { get; set; }
 
+        /// <summary>
+        /// 工作日历表
+        /// </summary>
+        public DbSet<ShopCalendarWorkCtr> ShopCalendarWorkCtr { get; set; }
+
+        /// <summary>
+        /// 排产异常记录表
+        /// </summary>
+        public DbSet<ScheduleExceptionMaster> ScheduleExceptionMaster { get; set; }
+
+        /// <summary>
+        /// 产线休息时间记录表
+        /// </summary>
+        public DbSet<QualityLineWorkDetail> QualityLineWorkDetail { get; set; }
+
+        /// <summary>
+        /// 节假日记录表
+        /// </summary>
+        public DbSet<HolidayMaster> HolidayMaster { get; set; }
+
         #endregion
 
         //Code generation...

+ 53 - 0
MicroServices/Business/Bussiness.Model/Production/HolidayMaster.cs

@@ -0,0 +1,53 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Bussiness.Model.Production
+{
+    /// <summary>
+    /// 节假日记录表
+    /// </summary>
+    public class HolidayMaster
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public int RecID { get; set; }
+
+        /// <summary>
+        /// 域名
+        /// </summary>
+        [Comment("域名")]
+        public string Domain { get; set; }
+
+        /// <summary>
+        /// 日期
+        /// </summary>
+        [Comment("日期")]
+        public DateTime? Dated { get; set; }
+
+        /// <summary>
+        /// 节假日描述
+        /// </summary>
+        [Comment("节假日描述")]
+        public string? Holiday { get; set; }
+
+        /// <summary>
+        /// 节假日类型:休假(不计算产能);调休(计算产能)
+        /// </summary>
+        [Comment("节假日类型")]
+        public string? Ufld1 { get; set; }
+
+        /// <summary>
+        /// 是否有效
+        /// </summary>
+        [Comment("是否有效")]
+        public int IsActive { get; set; }
+    }
+}

+ 7 - 7
MicroServices/Business/Bussiness.Model/Production/ProdLineDetail.cs

@@ -44,7 +44,7 @@ namespace Bussiness.Model.Production
         /// 单位标准产能=Uph
         /// </summary>
         [Comment("单位标准产能")]
-        public decimal? Rate { get; set; }
+        public decimal Rate { get; set; }
 
         /// <summary>
         /// 工序
@@ -52,16 +52,16 @@ namespace Bussiness.Model.Production
         [Comment("工序")]
         public int? Op { get; set; }
 
-        /// <summary>
-        /// 状态:C为不可用状态
-        /// </summary>
-        [Comment("状态")]
-        public string? Status { get; set; }
-
         /// <summary>
         /// 是否有效:1-有效;0-无效
         /// </summary>
         [Comment("是否有效")]
         public int? IsActive { get; set; }
+
+        /// <summary>
+        /// 当前产线提前期(小时)
+        /// </summary>
+        [Comment("当前产线提前期")]
+        public decimal SetupTime { get; set; }
     }
 }

+ 59 - 0
MicroServices/Business/Bussiness.Model/Production/QualityLineWorkDetail.cs

@@ -0,0 +1,59 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Bussiness.Model.Production
+{
+    /// <summary>
+    /// 产线休息时间记录表
+    /// </summary>
+    public class QualityLineWorkDetail
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public int RecID { get; set; }
+
+        /// <summary>
+        /// 域名
+        /// </summary>
+        [Comment("域名")]
+        public string Domain { get; set; }
+
+        /// <summary>
+        /// 生产线
+        /// </summary>
+        [Comment("生产线")]
+        public string ProdLine { get; set; }
+
+        /// <summary>
+        /// 项次号
+        /// </summary>
+        [Comment("项次号")]
+        public string Line { get; set; }
+
+        /// <summary>
+        /// 休息开始时间点(例如 11:50)
+        /// </summary>
+        [Comment("休息开始时间点")]
+        public string RestTimePoint { get; set; }
+
+        /// <summary>
+        /// 休息时长(分钟)
+        /// </summary>
+        [Comment("休息时长")]
+        public int RestTime { get; set; }
+
+        /// <summary>
+        /// 是否有效
+        /// </summary>
+        [Comment("是否有效")]
+        public int IsActive { get; set; }
+    }
+}

+ 48 - 0
MicroServices/Business/Bussiness.Model/Production/ScheduleExceptionMaster.cs

@@ -0,0 +1,48 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Bussiness.Model.Production
+{
+    /// <summary>
+    /// 排产异常记录表
+    /// </summary>
+    [Comment("排产异常记录表")]
+    public class ScheduleExceptionMaster
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public long RecID { get; set; }
+
+        /// <summary>
+        /// 域名
+        /// </summary>
+        [Comment("域名")]
+        public string Domain { get; set; }
+
+        /// <summary>
+        /// 工单
+        /// </summary>
+        [Comment("工单")]
+        public string WorkOrd { get; set; }
+
+        /// <summary>
+        /// 异常原因
+        /// </summary>
+        [Comment("异常原因")]
+        public string Remark { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [Comment("创建时间")]
+        public DateTime CreatTime { get; set; }
+    }
+}

+ 9 - 3
MicroServices/Business/Bussiness.Model/Production/ScheduleResultOpMaster.cs

@@ -20,7 +20,7 @@ namespace Bussiness.Model.Production
         /// </summary>
         [Comment("主键")]
         [Key]
-        public int RecID { get; set; }
+        public long RecID { get; set; }
 
         /// <summary>
         /// 域名
@@ -80,13 +80,19 @@ namespace Bussiness.Model.Production
         /// 开工时间
         /// </summary>
         [Comment("开工时间")]
-        public DateTime? WorkStartTime { get; set; }
+        public DateTime WorkStartTime { get; set; }
 
         /// <summary>
         /// 结束时间
         /// </summary>
         [Comment("结束时间")]
-        public DateTime? WorkEndTime { get; set; }
+        public DateTime WorkEndTime { get; set; }
+
+        /// <summary>
+        /// 创建时间
+        /// </summary>
+        [Comment("创建时间")]
+        public DateTime CreatTime { get; set; }
 
     }
 }

+ 102 - 0
MicroServices/Business/Bussiness.Model/Production/ShopCalendarWorkCtr.cs

@@ -0,0 +1,102 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Bussiness.Model.Production
+{
+    /// <summary>
+    /// 工作日历表
+    /// </summary>
+    [Comment("工单工艺流程表")]
+    public class ShopCalendarWorkCtr
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        [Comment("主键")]
+        [Key]
+        public int RecID { get; set; }
+
+        /// <summary>
+        /// 域名
+        /// </summary>
+        [Comment("域名")]
+        public string? Domain { get; set; }
+
+        /// <summary>
+        /// 产线
+        /// </summary>
+        [Comment("产线")]
+        public string? ProdLine { get; set; }
+
+        /// <summary>
+        /// 星期几
+        /// </summary>
+        [Comment("星期几")]
+        public int WeekDay { get; set; }
+
+        /// <summary>
+        /// 是否工作日
+        /// </summary>
+        [Comment("是否工作日")]
+        public int IsWorkDay { get; set; }
+
+        /// <summary>
+        /// 班次1开始时间
+        /// </summary>
+        [Comment("班次1开始时间")]
+        public decimal ShiftsStart1 { get; set; }
+
+        /// <summary>
+        /// 班次2开始时间
+        /// </summary>
+        [Comment("班次2开始时间")]
+        public decimal ShiftsStart2 { get; set; }
+
+        /// <summary>
+        /// 班次3开始时间
+        /// </summary>
+        [Comment("班次2开始时间")]
+        public decimal ShiftsStart3 { get; set; }
+
+        /// <summary>
+        /// 班次4开始时间
+        /// </summary>
+        [Comment("班次4开始时间")]
+        public decimal ShiftsStart4 { get; set; }
+
+        /// <summary>
+        /// 班次1工作时长
+        /// </summary>
+        [Comment("班次1工作时长")]
+        public decimal ShiftsHours1 { get; set; }
+
+        /// <summary>
+        /// 班次2工作时长
+        /// </summary>
+        [Comment("班次2工作时长")]
+        public decimal ShiftsHours2 { get; set; }
+
+        /// <summary>
+        /// 班次3工作时长
+        /// </summary>
+        [Comment("班次3工作时长")]
+        public decimal ShiftsHours3 { get; set; }
+
+        /// <summary>
+        /// 班次4工作时长
+        /// </summary>
+        [Comment("班次4工作时长")]
+        public decimal ShiftsHours4 { get; set; }
+
+        /// <summary>
+        /// 是否有效:1-有效;0-无效
+        /// </summary>
+        [Comment("是否有效")]
+        public int? IsActive { get; set; }
+    }
+}

+ 1 - 1
MicroServices/Business/Bussiness.Model/Production/WorkOrdMaster.cs

@@ -56,7 +56,7 @@ namespace Bussiness.Model.Production
         /// 订单数量
         /// </summary>
         [Comment("订单数量")]
-        public decimal? QtyOrded { get; set; }
+        public decimal QtyOrded { get; set; }
 
         /// <summary>
         /// 工艺路线编码