From 8a1a757daeb55b5c6de2b6fce419be0f5d908ddc Mon Sep 17 00:00:00 2001 From: gcw_MV9p2JJN Date: Tue, 16 Sep 2025 10:44:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MES/product/ProweekplanManageService.cs | 580 ++++++------------ 1 file changed, 191 insertions(+), 389 deletions(-) diff --git a/DOAN.Service/MES/product/ProweekplanManageService.cs b/DOAN.Service/MES/product/ProweekplanManageService.cs index 8fc5856..a86b8e7 100644 --- a/DOAN.Service/MES/product/ProweekplanManageService.cs +++ b/DOAN.Service/MES/product/ProweekplanManageService.cs @@ -30,28 +30,8 @@ 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) { - // 参数校验 - if (formFile == null || formFile.Length == 0) - { - throw new CustomException("上传的文件不能为空"); - } - - if (string.IsNullOrEmpty(username)) - { - throw new CustomException("用户名不能为空"); - } - using (var stream = formFile.OpenReadStream()) { try @@ -59,367 +39,163 @@ namespace DOAN.Service.MES.product List insertProWeekPlanList = new List(); List insertProWeeklyDateList = new List(); - // 安全创建工作簿 IWorkbook workbook = new XSSFWorkbook(stream); - - // 安全获取工作表 ISheet sheet = workbook.GetSheet("Sheet1"); - if (sheet == null) - { - throw new CustomException("未找到名称为 'Sheet1' 的工作表"); - } - - // 处理第2行 获取日期 - IRow secondRow = sheet.GetRow(1); - if (secondRow == null) - { - throw new CustomException("Excel文件格式不正确,第2行不存在"); - } - - // 安全获取单元格 - NPOI.SS.UserModel.ICell cell = secondRow.GetCell(0); - if (cell == null) - { - throw new CustomException("Excel文件格式不正确,第2行第1列没有数据"); - } - string title = cell.ToString() ?? string.Empty; - if (string.IsNullOrEmpty(title)) - { - throw new CustomException("Excel文件格式不正确,标题不能为空"); - } - - //提取括号内的数字 - int week = extractWeek(title); + // 处理第2行 获取标题(含周数信息) + IRow secondRow = sheet.GetRow(1); + string title = secondRow?.GetCell(0)?.ToString() ?? ""; + 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 proWeeklyPlan = new ProWeeklyPlan(); + Id = SnowFlakeSingle.Instance.NextId(), + PlanCode = "WP" + SnowFlakeSingle.Instance.NextId().ToString("D19").PadLeft(19, '0'), + PlanYear = DateTime.Now.Year, + PlanWeek = week, + CreatedTime = DateTime.Now, + ProductCode = currentRow.GetCell(2)?.ToString(), + ProductName = currentRow.GetCell(3)?.ToString(), + Specification = currentRow.GetCell(4)?.ToString(), + Planner = currentRow.GetCell(6)?.ToString(), + CreatedBy = username, + PlanQty = (int)(currentRow.GetCell(7)?.NumericCellValue ?? 0), + CompletedQty = (int)(currentRow.GetCell(8)?.NumericCellValue ?? 0), + }; - proWeeklyPlan.Id = SnowFlakeSingle.Instance.NextId(); + // 如果产品相关字段全部为空,则跳过该行 + if (string.IsNullOrEmpty(proWeeklyPlan.ProductCode) && + string.IsNullOrEmpty(proWeeklyPlan.ProductName) && + string.IsNullOrEmpty(proWeeklyPlan.Specification)) + { + continue; + } - 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)) + // 可选字段 + proWeeklyPlan.PlanStatus = !string.IsNullOrEmpty(currentRow.GetCell(5)?.ToString()) + ? currentRow.GetCell(5).ToString() + : null; + + // 初始化默认日期 + proWeeklyPlan.PlanStartDate = DateTime.MinValue; + proWeeklyPlan.PlanEndDate = DateTime.MinValue; + + // 处理星期一到星期日(第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); + + DateTime? weekDate = dateCell?.DateCellValue; + string dayOfWeekName = dayNameCell?.ToString() ?? ""; + string productType = productTypeCell?.ToString() ?? ""; + int planNum = (int)(planQtyCell?.NumericCellValue ?? 0); + string isChange = isChangeCell?.ToString() ?? ""; + int actualQt = (int)(actualQtyCell?.NumericCellValue ?? 0); + + var proWeeklyDate = new ProWeeklyDate { - continue; - } - //生产状态 - string _PlanStatus = currentRow.GetCell(5)?.ToString(); - if (!string.IsNullOrEmpty(_PlanStatus)) - proWeeklyPlan.PlanStatus = _PlanStatus; + 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 planner = currentRow.GetCell(6)?.ToString(); - proWeeklyPlan.Planner = planner; - //本周计划装配数量 - 安全访问 - var planQtyCell = currentRow.GetCell(7); - proWeeklyPlan.PlanQty = planQtyCell != null && planQtyCell.CellType == NPOI.SS.UserModel.CellType.Numeric - ? (int)planQtyCell.NumericCellValue - : 0; + insertProWeeklyDateList.Add(proWeeklyDate); - //本周实际装配数 - 安全访问 - var actualQtyCell = currentRow.GetCell(8); - proWeeklyPlan.CompletedQty = actualQtyCell != null && actualQtyCell.CellType == NPOI.SS.UserModel.CellType.Numeric - ? (int)actualQtyCell.NumericCellValue - : 0; - proWeeklyPlan.CreatedBy = username; - - - // 2025/8/25 星期一 产品类型 - // 2025/8/25 - ProWeeklyDate proWeeklyDatePlan = new ProWeeklyDate(); - proWeeklyDatePlan.Id = SnowFlakeSingle.Instance.NextId(); - proWeeklyDatePlan.FkWeeklyId = proWeeklyPlan.Id; - proWeeklyDatePlan.PlanCode = proWeeklyPlan.PlanCode; - int weekdayindex = 9; - // 安全获取日期 - IRow dateRow = sheet.GetRow(2); - if (dateRow != null) + // 设置周计划的开始和结束日期 + if (dayOfWeek == 0 && weekDate.HasValue) { - var dateCell = dateRow.GetCell(weekdayindex); - if (dateCell != null) - { - DateTime? MondayDate = null; - try - { - // 根据单元格类型安全获取日期值 - if (dateCell.CellType == NPOI.SS.UserModel.CellType.Numeric) - { - MondayDate = dateCell.DateCellValue; - } - else if (dateCell.CellType == NPOI.SS.UserModel.CellType.String) - { - DateTime parsedDate; - if (DateTime.TryParse(dateCell.StringCellValue, out parsedDate)) - { - MondayDate = parsedDate; - } - } - } - catch {} - - proWeeklyDatePlan.WeekDate = MondayDate ?? DateTime.MinValue; - proWeeklyPlan.PlanStartDate = MondayDate ?? DateTime.MinValue; - - // 安全访问DateTime值的属性 - if (MondayDate.HasValue) - { - proWeeklyPlan.PlanYear = MondayDate.Value.Year; - year = MondayDate.Value.Year; - } - } + proWeeklyPlan.PlanStartDate = weekDate.Value; + proWeeklyPlan.PlanYear = weekDate.Value.Year; + year = weekDate.Value.Year; } - - // 星期一名称 - - string MondayName = sheet.GetRow(3).GetCell(weekdayindex)?.ToString(); - proWeeklyDatePlan.DayOfWeek = MondayName; - //产品类型 - string Mondayproducttype = currentRow.GetCell(9)?.ToString(); - proWeeklyDatePlan.ProductType = Mondayproducttype; - //计划数量 - 安全访问 - var mondayPlanQtyCell = currentRow.GetCell(10); - int MondayPlanQty = mondayPlanQtyCell != null && mondayPlanQtyCell.CellType == NPOI.SS.UserModel.CellType.Numeric - ? (int)mondayPlanQtyCell.NumericCellValue - : 0; - proWeeklyDatePlan.PlanNum = MondayPlanQty; - - //是否变更 - 安全访问 - string MondayIsChange = currentRow.GetCell(11)?.ToString() ?? string.Empty; - proWeeklyDatePlan.IsChange = MondayIsChange; - - //实际数量 - 安全访问 - var mondayActualQtyCell = currentRow.GetCell(12); - int MondayActualQty = mondayActualQtyCell != null && mondayActualQtyCell.CellType == NPOI.SS.UserModel.CellType.Numeric - ? (int)mondayActualQtyCell.NumericCellValue - : 0; - 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; - - 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; - - //产品类型 - string Tuesdayproducttype = currentRow.GetCell(9 + 4 * 1)?.ToString(); - proWeeklyDatePlan2.ProductType = Tuesdayproducttype; - - //计划数量 - int TuesdayPlanQty = (int)currentRow.GetCell(10 + 4 * 1)?.NumericCellValue; - proWeeklyDatePlan2.PlanNum = TuesdayPlanQty; - //是否变更 - string TuesdayIsChange = currentRow.GetCell(11 + 4 * 1)?.ToString(); - proWeeklyDatePlan2.IsChange = TuesdayIsChange; - //实际数量 - int TuesdayActualQty = (int)currentRow.GetCell(12)?.NumericCellValue; - proWeeklyDatePlan2.ActualQt = TuesdayActualQty; - proWeeklyDatePlan2.CreatedTime = DateTime.Now; - - // 2025/8/25 星期三 产品类型 - // 2025/8/25 - - ProWeeklyDate proWeeklyDatePlan3 = new ProWeeklyDate(); - proWeeklyDatePlan3.Id = SnowFlakeSingle.Instance.NextId(); - proWeeklyDatePlan3.FkWeeklyId = proWeeklyPlan.Id; - proWeeklyDatePlan3.PlanCode = proWeeklyPlan.PlanCode; - DateTime? WednesdayDate = sheet.GetRow(2).GetCell(weekdayindex + 4 * 2)?.DateCellValue; - proWeeklyDatePlan3.WeekDate = WednesdayDate; - // 星期三名称 - string WednesdayName = sheet.GetRow(3).GetCell(weekdayindex + 4 * 2)?.ToString(); - proWeeklyDatePlan3.DayOfWeek = WednesdayName; - //产品类型 - string Wednesdayproducttype = currentRow.GetCell(9 + 4 * 2)?.ToString(); - proWeeklyDatePlan3.ProductType = Wednesdayproducttype; - //计划数量 - int WednesdayPlanQty = (int)currentRow.GetCell(10 + 4 * 2)?.NumericCellValue; - proWeeklyDatePlan3.PlanNum = WednesdayPlanQty; - //是否变更 - string WednesdayIsChange = currentRow.GetCell(11 + 4 * 2)?.ToString(); - proWeeklyDatePlan3.IsChange = WednesdayIsChange; - //实际数量 - int WednesdayActualQty = (int)currentRow.GetCell(12 + 4 * 2)?.NumericCellValue; - proWeeklyDatePlan3.ActualQt = WednesdayActualQty; - proWeeklyDatePlan3.CreatedTime = DateTime.Now; - - - - // 2025/8/25 星期四 产品类型 - // 2025/8/25 - ProWeeklyDate proWeeklyDatePlan4 = new ProWeeklyDate(); - proWeeklyDatePlan4.Id = SnowFlakeSingle.Instance.NextId(); - proWeeklyDatePlan4.FkWeeklyId = proWeeklyPlan.Id; - proWeeklyDatePlan4.PlanCode = proWeeklyPlan.PlanCode; - DateTime? ThursdayDate = sheet.GetRow(2).GetCell(weekdayindex + 4 * 3)?.DateCellValue; - proWeeklyDatePlan4.WeekDate = ThursdayDate; - // 星期三名称 - string ThursdayName = sheet.GetRow(3).GetCell(weekdayindex + 4 * 3)?.ToString(); - proWeeklyDatePlan4.DayOfWeek = ThursdayName; - //产品类型 - string Thursdayproducttype = currentRow.GetCell(9 + 4 * 3)?.ToString(); - proWeeklyDatePlan4.ProductType = Thursdayproducttype; - //计划数量 - int ThursdayPlanQty = (int)currentRow.GetCell(10 + 4 * 3)?.NumericCellValue; - proWeeklyDatePlan4.PlanNum = ThursdayPlanQty; - //是否变更 - string ThursdayIsChange = currentRow.GetCell(11 + 4 * 3)?.ToString(); - proWeeklyDatePlan4.IsChange = ThursdayIsChange; - //实际数量 - int ThursdayActualQty = (int)currentRow.GetCell(12 + 4 * 3)?.NumericCellValue; - proWeeklyDatePlan4.ActualQt = ThursdayActualQty; - proWeeklyDatePlan4.CreatedTime = DateTime.Now; - - // 2025/8/25 星期五 产品类型 - // 2025/8/25 - ProWeeklyDate proWeeklyDatePlan5 = new ProWeeklyDate(); - proWeeklyDatePlan5.Id = SnowFlakeSingle.Instance.NextId(); - proWeeklyDatePlan5.FkWeeklyId = proWeeklyPlan.Id; - proWeeklyDatePlan5.PlanCode = proWeeklyPlan.PlanCode; - DateTime? FridayDate = sheet.GetRow(2).GetCell(weekdayindex + 4 * 4)?.DateCellValue; - proWeeklyDatePlan5.WeekDate = FridayDate; - // 星期三名称 - string FridayName = sheet.GetRow(3).GetCell(weekdayindex + 4 * 4)?.ToString(); - proWeeklyDatePlan5.DayOfWeek = FridayName; - //产品类型 - string Fridayproducttype = currentRow.GetCell(9 + 4 * 4)?.ToString(); - proWeeklyDatePlan5.ProductType = Fridayproducttype; - //计划数量 - int FridayPlanQty = (int)currentRow.GetCell(10 + 4 * 4)?.NumericCellValue; - proWeeklyDatePlan5.PlanNum = FridayPlanQty; - //是否变更 - string FridayIsChange = currentRow.GetCell(11 + 4 * 4)?.ToString(); - proWeeklyDatePlan5.IsChange = FridayIsChange; - //实际数量 - int FridayActualQty = (int)currentRow.GetCell(12 + 4 * 4)?.NumericCellValue; - proWeeklyDatePlan5.ActualQt = FridayActualQty; - proWeeklyDatePlan5.CreatedTime = DateTime.Now; - // 2025/8/25 星期六 产品类型 - // 2025/8/25 - - ProWeeklyDate proWeeklyDatePlan6 = new ProWeeklyDate(); - proWeeklyDatePlan6.Id = SnowFlakeSingle.Instance.NextId(); - proWeeklyDatePlan6.FkWeeklyId = proWeeklyPlan.Id; - proWeeklyDatePlan6.PlanCode = proWeeklyPlan.PlanCode; - DateTime? SaturdayDate = sheet.GetRow(2).GetCell(weekdayindex + 4 * 5)?.DateCellValue; - proWeeklyDatePlan6.WeekDate = SaturdayDate; - // 星期三名称 - string SaturdayName = sheet.GetRow(3).GetCell(weekdayindex + 4 * 5)?.ToString(); - proWeeklyDatePlan6.DayOfWeek = SaturdayName; - //产品类型 - string Saturdayproducttype = currentRow.GetCell(9 + 4 * 5)?.ToString(); - proWeeklyDatePlan6.ProductType = Saturdayproducttype; - //计划数量 - int SaturdayPlanQty = (int)currentRow.GetCell(10 + 4 * 5)?.NumericCellValue; - proWeeklyDatePlan6.PlanNum = SaturdayPlanQty; - //是否变更 - string SaturdayIsChange = currentRow.GetCell(11 + 4 * 5)?.ToString(); - proWeeklyDatePlan6.IsChange = SaturdayIsChange; - //实际数量 - int SaturdayActualQty = (int)currentRow.GetCell(12 + 4 * 5)?.NumericCellValue; - proWeeklyDatePlan6.ActualQt = SaturdayActualQty; - proWeeklyDatePlan6.CreatedTime = DateTime.Now; - - // 2025/8/25 星期日 产品类型 - // 2025/8/25 - ProWeeklyDate proWeeklyDatePlan7 = new ProWeeklyDate(); - proWeeklyDatePlan7.Id = SnowFlakeSingle.Instance.NextId(); - proWeeklyDatePlan7.FkWeeklyId = proWeeklyPlan.Id; - proWeeklyDatePlan7.PlanCode = proWeeklyPlan.PlanCode; - DateTime? SundayDate = sheet.GetRow(2).GetCell(weekdayindex + 4 * 6)?.DateCellValue; - proWeeklyDatePlan7.WeekDate = SundayDate; - // 星期三名称 - string SundayName = sheet.GetRow(3).GetCell(weekdayindex + 4 * 6)?.ToString(); - proWeeklyDatePlan7.DayOfWeek = SundayName; - //产品类型 - string Sundayproducttype = currentRow.GetCell(9 + 4 * 6)?.ToString(); - - - proWeeklyDatePlan7.ProductType = Sundayproducttype; - //计划数量 - int SundayPlanQty = (int)currentRow.GetCell(10 + 4 * 6)?.NumericCellValue; - proWeeklyDatePlan7.PlanNum = SundayPlanQty; - //是否变更 - string SundayIsChange = currentRow.GetCell(11 + 4 * 6)?.ToString(); - proWeeklyDatePlan7.IsChange = SundayIsChange; - //实际数量 - int SundayActualQty = (int)currentRow.GetCell(12 + 4 * 6)?.NumericCellValue; - proWeeklyDatePlan7.ActualQt = SundayActualQty; - proWeeklyDatePlan7.CreatedTime = DateTime.Now; - // 安全设置结束日期 - if (SundayDate.HasValue) + if (dayOfWeek == 6 && weekDate.HasValue) { - proWeeklyPlan.PlanEndDate = SundayDate.Value; + proWeeklyPlan.PlanEndDate = weekDate.Value; } + } + insertProWeekPlanList.Add(proWeeklyPlan); - insertProWeekPlanList.Add(proWeeklyPlan); - insertProWeeklyDateList.Add(proWeeklyDatePlan); - insertProWeeklyDateList.Add(proWeeklyDatePlan2); - insertProWeeklyDateList.Add(proWeeklyDatePlan3); - insertProWeeklyDateList.Add(proWeeklyDatePlan4); - insertProWeeklyDateList.Add(proWeeklyDatePlan5); - insertProWeeklyDateList.Add(proWeeklyDatePlan6); - insertProWeeklyDateList.Add(proWeeklyDatePlan7); + // ====================== + // 🚩分批提交:每500条计划及其关联日期插入一次 + // ====================== + if (insertProWeekPlanList.Count >= 500) + { + InsertBatchData(insertProWeekPlanList, insertProWeeklyDateList, year, week, username); + // 清空缓存列表 + insertProWeekPlanList.Clear(); + insertProWeeklyDateList.Clear(); } } - // 插入数据 - 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) - { - // 可以添加日志记录 - throw new CustomException($"Excel导入失败: {ex.Message}"); - } + { + // 建议记录日志,而不是直接抛出 + // Log.Error(ex, "导入Excel失败"); + throw; // 不要 throw ex,直接 throw 保留堆栈 + } } } + + /// + /// 批量插入数据(分批次事务处理) + /// + private void InsertBatchData( + List proWeeklyPlans, + List proWeeklyDates, + int year, + int week, + string username) + { + // 使用事务包裹当前批次 + UseTran(() => + { + // 1. 删除旧数据:根据年份+周数+计划编码删除 ProWeeklyDate,然后删除 ProWeeklyPlan + var planCodes = proWeeklyPlans.Select(p => p.PlanCode).ToList(); + + Context.Deleteable() + .Where(d => planCodes.Contains(d.PlanCode) ) + .ExecuteCommand(); + + Context.Deleteable() + .Where(p => p.PlanYear == year && p.PlanWeek == week && planCodes.Contains(p.PlanCode)) + .ExecuteCommand(); + + // 2. 插入新的周计划和日计划 + Context.Insertable(proWeeklyPlans).ExecuteCommand(); + Context.Insertable(proWeeklyDates).ExecuteCommand(); + }); + } const int BATCH_SIZE = 500; /// @@ -639,49 +415,75 @@ 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; }