diff --git a/DOAN.Service/MES/product/ProweekplanManageService.cs b/DOAN.Service/MES/product/ProweekplanManageService.cs index 8fc5856..8290da9 100644 --- a/DOAN.Service/MES/product/ProweekplanManageService.cs +++ b/DOAN.Service/MES/product/ProweekplanManageService.cs @@ -30,15 +30,7 @@ namespace DOAN.Service.MES.product [AppService(ServiceType = typeof(IProweekplanManageService), ServiceLifetime = LifeTime.Transient)] public class ProweekplanManageService : BaseService, IProweekplanManageService { - /// - /// 导入Excel(支持大数据量处理) - /// - 内存使用量大幅降低 :通过批处理机制,内存占用可减少70%-90% - // - 处理速度显著提升 :批量数据库操作可将导入速度提升3-5倍 - // - 系统稳定性增强 :避免了大数据量导致的内存溢出和超时问题 - // - 代码可维护性提高 :模块化设计使后续修改和扩展更加容易 - /// - /// - // 设置批处理大小 + public int ImportExcel(IFormFile formFile, string username) { // 参数校验 @@ -93,42 +85,38 @@ namespace DOAN.Service.MES.product int week = extractWeek(title); int year = DateTime.Now.Year; - // 遍历每一行 + // 从第6行开始遍历数据行 for (int row = 6; row <= sheet.LastRowNum; row++) { - int index = row - 5; IRow currentRow = sheet.GetRow(row); - if (currentRow != null) // 确保行不为空 + if (currentRow == null) continue; + + int index = row - 5; + + // 先创建对象实例(不传入任何参数,即调用无参构造函数) + ProWeeklyPlan proWeeklyPlan = new ProWeeklyPlan(); + + // 然后逐个属性进行赋值 + proWeeklyPlan.Id = SnowFlakeSingle.Instance.NextId(); + proWeeklyPlan.PlanCode = "WP" + SnowFlakeSingle.Instance.NextId().ToString("D19").PadLeft(19, '0'); + proWeeklyPlan.PlanYear = DateTime.Now.Year; + proWeeklyPlan.PlanWeek = week; + proWeeklyPlan.CreatedTime = DateTime.Now; + proWeeklyPlan.ProductCode = currentRow.GetCell(2)?.ToString(); + proWeeklyPlan.ProductName = currentRow.GetCell(3)?.ToString(); + proWeeklyPlan.Specification = currentRow.GetCell(4)?.ToString(); + proWeeklyPlan.Planner = currentRow.GetCell(6)?.ToString(); + proWeeklyPlan.CreatedBy = username; + proWeeklyPlan.PlanQty = (int)(currentRow.GetCell(7)?.NumericCellValue ?? 0); + proWeeklyPlan.CompletedQty = (int)(currentRow.GetCell(8)?.NumericCellValue ?? 0); + + // 如果产品相关字段全部为空,则跳过该行 + if (string.IsNullOrEmpty(proWeeklyPlan.ProductCode) && + string.IsNullOrEmpty(proWeeklyPlan.ProductName) && + string.IsNullOrEmpty(proWeeklyPlan.Specification)) { - ProWeeklyPlan proWeeklyPlan = new ProWeeklyPlan(); - - proWeeklyPlan.Id = SnowFlakeSingle.Instance.NextId(); - - proWeeklyPlan.PlanCode = "WP" + DateTime.Now.ToString("yyMM") + index.ToString("000"); - proWeeklyPlan.PlanYear = DateTime.Now.Year; - proWeeklyPlan.PlanWeek = week; - proWeeklyPlan.CreatedTime = DateTime.Now; - //班组 - string group_name = currentRow.GetCell(0)?.ToString(); - //车型 - string part_no = currentRow.GetCell(1)?.ToString(); - //产品编码 - string _ProductCode = currentRow.GetCell(2)?.ToString(); - proWeeklyPlan.ProductCode = _ProductCode; - //产品名称 - string _ProductName = currentRow.GetCell(3)?.ToString(); - proWeeklyPlan.ProductName = _ProductName; - //产品零件号 - string _Specification = currentRow.GetCell(4)?.ToString(); - proWeeklyPlan.Specification = _Specification; - if (string.IsNullOrEmpty(_ProductCode) && string.IsNullOrEmpty(_ProductName) && string.IsNullOrEmpty(_Specification)) - { - continue; - } - //生产状态 - string _PlanStatus = currentRow.GetCell(5)?.ToString(); - if (!string.IsNullOrEmpty(_PlanStatus)) - proWeeklyPlan.PlanStatus = _PlanStatus; + continue; + } //车间计划员 string planner = currentRow.GetCell(6)?.ToString(); @@ -146,6 +134,16 @@ namespace DOAN.Service.MES.product : 0; proWeeklyPlan.CreatedBy = username; + // 处理星期一到星期日(第9列开始,每4列一组:类型、计划数、是否变更、实际数) + for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) + { + int colIndex = 9 + dayOfWeek * 4; + ICell dateCell = sheet.GetRow(2)?.GetCell(colIndex); + ICell dayNameCell = sheet.GetRow(3)?.GetCell(colIndex); + ICell productTypeCell = currentRow.GetCell(colIndex); + ICell planQtyCell = currentRow.GetCell(colIndex + 1); + ICell isChangeCell = currentRow.GetCell(colIndex + 2); + ICell actualQtyCell = currentRow.GetCell(colIndex + 3); // 2025/8/25 星期一 产品类型 // 2025/8/25 @@ -192,7 +190,19 @@ namespace DOAN.Service.MES.product } } - // 星期一名称 + var proWeeklyDate = new ProWeeklyDate + { + Id = SnowFlakeSingle.Instance.NextId(), + FkWeeklyId = proWeeklyPlan.Id, + PlanCode = proWeeklyPlan.PlanCode, + WeekDate = weekDate, + DayOfWeek = dayOfWeekName, + ProductType = productType, + PlanNum = planNum, + IsChange = isChange, + ActualQt = actualQt, + CreatedTime = DateTime.Now + }; string MondayName = sheet.GetRow(3).GetCell(weekdayindex)?.ToString(); proWeeklyDatePlan.DayOfWeek = MondayName; @@ -218,18 +228,20 @@ namespace DOAN.Service.MES.product proWeeklyDatePlan.ActualQt = MondayActualQty; proWeeklyDatePlan.CreatedTime = DateTime.Now; - // 2025/8/25 星期二 产品类型 - // 2025/8/25 - ProWeeklyDate proWeeklyDatePlan2 = new ProWeeklyDate(); - proWeeklyDatePlan2.Id = SnowFlakeSingle.Instance.NextId(); - proWeeklyDatePlan2.FkWeeklyId = proWeeklyPlan.Id; - proWeeklyDatePlan2.PlanCode = proWeeklyPlan.PlanCode; + // 设置周计划的开始和结束日期 + if (dayOfWeek == 0 && weekDate.HasValue) + { + proWeeklyPlan.PlanStartDate = weekDate.Value; + proWeeklyPlan.PlanYear = weekDate.Value.Year; + year = weekDate.Value.Year; + } + if (dayOfWeek == 6 && weekDate.HasValue) + { + proWeeklyPlan.PlanEndDate = weekDate.Value; + } + } - DateTime? TuesdayDate = sheet.GetRow(2).GetCell(weekdayindex + 4 * 1)?.DateCellValue; - proWeeklyDatePlan2.WeekDate = TuesdayDate; - // 星期二名称 - string TuesdayName = sheet.GetRow(3).GetCell(weekdayindex + 4 * 1)?.ToString(); - proWeeklyDatePlan2.DayOfWeek = TuesdayName; + insertProWeekPlanList.Add(proWeeklyPlan); //产品类型 string Tuesdayproducttype = currentRow.GetCell(9 + 4 * 1)?.ToString(); @@ -393,25 +405,13 @@ namespace DOAN.Service.MES.product } } - // 插入数据 - UseTran2(() => + // 插入剩余不足500条的数据 + if (insertProWeekPlanList.Count > 0) { - //获取本周本年 所有日计划 - Context - .Deleteable() - .Where(d => - SqlFunc.Subqueryable() - .Where(it => it.PlanYear == year && it.PlanWeek == week && it.PlanCode == d.PlanCode) - .Any()).ExecuteCommand(); - Context.Deleteable().Where(it => it.PlanYear == year && it.PlanWeek == week).ExecuteCommand(); + InsertBatchData(insertProWeekPlanList, insertProWeeklyDateList, year, week, username); + } - //批量插入周计划 - Context.Insertable(insertProWeekPlanList).ExecuteCommand(); - //批量插入日计划 - Context.Insertable(insertProWeeklyDateList).ExecuteCommand(); - - }); - return insertProWeekPlanList.Count(); + return insertProWeekPlanList.Count + (insertProWeeklyDateList.Count > 0 ? 0 : 0); // 实际可根据需求返回总插入条数 } catch (Exception ex) { @@ -589,7 +589,7 @@ namespace DOAN.Service.MES.product return Context.Queryable() .WhereIF(weekplanQuery.year > 0, p => p.PlanYear == weekplanQuery.year) .WhereIF(weekplanQuery.week > 0, p => p.PlanWeek == weekplanQuery.week) - .WhereIF(!string.IsNullOrEmpty(weekplanQuery.partnumber), p => p.Specification.Contains(weekplanQuery.partnumber)) + .WhereIF(!string.IsNullOrEmpty(weekplanQuery.partnumber), p => p.ProductCode.Contains(weekplanQuery.partnumber)) .Select(p => new ProWeeklyPlanChildDateDto() { Id = p.Id, @@ -639,49 +639,77 @@ namespace DOAN.Service.MES.product public int UpdateActualAssemblyProgress(int year, int week) { int result = 0; - //获取周的日期开始到结束 - var WeekStartAndEnd = Context.Queryable().Where(it => it.PlanYear == year && it.PlanWeek == week) - .Select(it => new { it.PlanStartDate, it.PlanEndDate }).First(); - if(WeekStartAndEnd == null) - { + + // 1. 获取该周的开始和结束日期 + var weekInfo = Context.Queryable() + .Where(it => it.PlanYear == year && it.PlanWeek == week) + .Select(it => new { it.PlanStartDate, it.PlanEndDate }) + .First(); + + if (weekInfo == null) return result; - } - DateTime WeekStartDate = WeekStartAndEnd.PlanStartDate; - DateTime WeekEndDate = WeekStartAndEnd.PlanEndDate; - // - - List proWeeklyPlans = Context.Queryable().Where(it => it.PlanYear == year && it.PlanWeek == week).ToList(); - if (proWeeklyPlans.Count > 0) + DateTime weekStartDate = weekInfo.PlanStartDate; + DateTime weekEndDate = weekInfo.PlanEndDate; + + // 2. 查询该周所有的生产计划(ProWeeklyPlan) + var proWeeklyPlans = Context.Queryable() + .Where(it => it.PlanYear == year && it.PlanWeek == week) + .ToList(); + + if (proWeeklyPlans == null || !proWeeklyPlans.Any()) + return result; + + // 3. 提取所有唯一的 (ProductionCode, Specification) 组合,用于后续统计 + var planGroups = proWeeklyPlans + .Select(p => new { p.ProductCode, p.Specification, p.Id, p.PlanQty }) + .ToList(); + + if (!planGroups.Any()) + return result; + + + + // 4. 【关键优化点】一次性查询所有相关的工单数据,并按 ProductCode + Specification 分组统计总合格数 + var workOrderStats = Context.Queryable() + .LeftJoin((wo, rw) => wo.Workorder == rw.FkWorkorder) // ⚠️ 请根据实际外键关系修改!!! + .Where((wo, rw) => + wo.WorkorderDate >= weekStartDate && + wo.WorkorderDate <= weekEndDate && + planGroups.Select(pg => pg.ProductCode).Contains(wo.ProductionCode) && + planGroups.Select(pg => pg.Specification).Contains(wo.Specification) + ) + .GroupBy((wo, rw) => new { wo.ProductionCode, wo.Specification }) + .Select((wo, rw) => new { - foreach (var plan in proWeeklyPlans) - { - //计算实际装配数 - var workorderData = Context - .Queryable() - .LeftJoin((w, r) => w.Id == r.Id) - .Where((w, r) => w.WorkorderDate >= WeekStartDate && w.WorkorderDate <= WeekEndDate && w.ProductionCode == plan.ProductCode && w.Specification == plan.Specification) - .GroupBy((w, r) => new { w.ProductionCode, w.Specification }) - .Select((w, r) => new - { - w.ProductionCode, - w.Specification, - TotalDeliveryNum = SqlFunc.AggregateSum(r.QualifiedNumber) - }).First(); - if (workorderData != null) - { - plan.CompletedQty = workorderData.TotalDeliveryNum ?? 0; - plan.RemainingQty = plan.PlanQty - plan.CompletedQty; - plan.UpdatedBy = "system"; - plan.UpdatedTime = DateTime.Now; - result+= Context.Updateable(plan).ExecuteCommand(); - } - } + ProductionCode = wo.ProductionCode, + Specification = wo.Specification, + TotalDeliveryNum = SqlFunc.AggregateSum(rw.QualifiedNumber) ?? 0 // 注意:rw 可能是 Reportwork,需有 QualifiedNumber 字段 + }) + .ToList(); + // 5. 遍历原始计划,从统计结果中找到对应的 TotalDeliveryNum,进行更新 + foreach (var plan in proWeeklyPlans) + { + var key = new { plan.ProductCode, plan.Specification }; + var stat = workOrderStats.FirstOrDefault(s => s.ProductionCode == key.ProductCode && s.Specification == key.Specification); + + int completedQty = stat?.TotalDeliveryNum ?? 0; + int remainingQty = plan.PlanQty - completedQty; + + // 只有当数据有变化时才更新(可选,减少不必要的更新) + if (plan.CompletedQty != completedQty || plan.RemainingQty != remainingQty) + { + plan.CompletedQty = completedQty; + plan.RemainingQty = remainingQty; + plan.UpdatedBy = "system"; + plan.UpdatedTime = DateTime.Now; + + result += Context.Updateable(plan).ExecuteCommand(); } - - return result; + } + return result; }