using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using WIDESEAWCS_Common; using WIDESEAWCS_Common.PLCEnum; using WIDESEAWCS_Core; using WIDESEAWCS_Core.BaseRepository; using WIDESEAWCS_Core.BaseServices; using WIDESEAWCS_Core.Helper; using WIDESEAWCS_DTO.BasicInfo; using WIDESEAWCS_IBasicInfoService; using WIDESEAWCS_Model.Models; using WIDESEAWCS_QuartzJob; namespace WIDESEAWCS_BasicInfoService { public class BoxingDetailService : ServiceBase>, IBoxingDetailService { private readonly IBoxingService _boxingService; private readonly IFormulaService _formulaService; private readonly IFormulaDetailService _formulaDetailService; private readonly IProcessInfoDetailService _processInfoDetailService; private readonly IScanStationService _scanStationService; private readonly IUnitOfWorkManage _unitOfWorkManage; public BoxingDetailService( IRepository BaseDal, IFormulaService formulaService, IBoxingService boxingService, IFormulaDetailService formulaDetailService, IProcessInfoDetailService processInfoDetailService, IScanStationService scanStationService, IUnitOfWorkManage unitOfWorkManage ) : base(BaseDal) { _formulaService = formulaService; _boxingService = boxingService; _formulaDetailService = formulaDetailService; _processInfoDetailService = processInfoDetailService; _scanStationService = scanStationService; _unitOfWorkManage = unitOfWorkManage; } public IRepository Repository => BaseDal; /// /// 比较零件是否齐全 /// /// 实际装箱的零件集合 /// 配方要求的零件集合 /// 是否完全匹配 public bool CheckComponentsMatchExactly(List boxingDetails, List formulaDetails) { // 1. 基础校验:空值/数量不一致直接返回不匹配 if (boxingDetails == null || formulaDetails == null || boxingDetails.Count != formulaDetails.Count) { return false; } // 2. 两个空集合直接判定为匹配(无零件=零件齐全) if (boxingDetails.Count == 0) { return true; } // 3. 统计第一个集合的元素出现次数(严格键匹配,处理重复元素) var elementCountDict = new Dictionary(); foreach (var item in boxingDetails) { // 处理集合中的null元素,转为空字符串避免字典键为null报错 var key = item ?? string.Empty; if (elementCountDict.ContainsKey(key)) { elementCountDict[key]++; } else { elementCountDict[key] = 1; } } // 4. 遍历第二个集合,抵消计数:无此元素/数量不匹配直接返回false foreach (var item in formulaDetails) { var key = item ?? string.Empty; if (!elementCountDict.ContainsKey(key)) { return false; // 存在配方没有/装箱多出来的零件 } elementCountDict[key]--; if (elementCountDict[key] == 0) { elementCountDict.Remove(key); // 计数清零则移除,避免干扰最终判断 } } // 5. 字典为空 = 所有元素种类+数量完全匹配 return elementCountDict.Count == 0; } /// /// 检查零件 /// /// /// /// public string IsComponentCodesEqual(List boxingDetails, List formulaDetails) { // 处理null集合,规避空指针异常 var boxList = boxingDetails ?? new List(); var formulaList = formulaDetails ?? new List(); var validBoxCodes = boxList.Where(code => !string.IsNullOrEmpty(code)).ToList(); var validFormulaCodes = formulaList.Where(code => !string.IsNullOrEmpty(code)).ToList(); foreach (var group in validBoxCodes.GroupBy(code => code)) { string componentCode = group.Key; int boxCount = group.Count(); int formulaCount = validFormulaCodes.Count(code => code == componentCode); if (formulaCount == 0 || formulaCount < boxCount) { return componentCode; } } return null; } /// /// 添加/修改组盘信息(一体化接口:传工装板编号存在则修改,不存在则新增) /// /// /// public WebResponseContent SaveToolingBoardNo(ToolingBoardSubmitDto toolingBoardSubmitDto) { using (var uow = _unitOfWorkManage.CreateUnitOfWork()) { try { // 1. 参数校验 if (toolingBoardSubmitDto == null) { return WebResponseContent.Instance.Error("提交参数不能为空"); } string productCode = toolingBoardSubmitDto.FinishedProductCode.Trim(); string proCode = string.Empty; string proOther = string.Empty; string supplierCode = string.Empty; if (!string.IsNullOrWhiteSpace(productCode)) { string[] parts = productCode.Split(new char[] { ' ', '|' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 3) return WebResponseContent.Instance.Error("编码规则有误!"); proCode = parts[0]; proOther = parts[1]; supplierCode = parts[2]; #region 获取成品编号、流水号、供方代码 //var proCodeMatch = Regex.Match(productCode, @"TX(\d+)(?=\s|\||$)", RegexOptions.IgnoreCase); //if (proCodeMatch.Success) //{ // proCode = $"TX{proCodeMatch.Groups[1].Value.Trim()}"; //} //// 正则2:匹配连续的10位纯数字(全局匹配,取第一个符合的即可) //var proOtherMatch = Regex.Match(productCode, @"\d{10}"); //if (proOtherMatch.Success) //{ // proOther = proOtherMatch.Value.Trim(); //} //var supplierCodeMatch = Regex.Match(productCode, @"[A-Z]+$", RegexOptions.IgnoreCase); //if (supplierCodeMatch.Success) //{ // supplierCode = supplierCodeMatch.Value.Trim(); //} #endregion toolingBoardSubmitDto.PartsList = toolingBoardSubmitDto.PartsList.Where(code => !string.IsNullOrEmpty(code)).ToList(); // 2. 查询成品配方信息 Dt_Formula formulaModel = _formulaService.Repository.QueryFirst(x => x.ProductCode == proCode); if (formulaModel == null) { return WebResponseContent.Instance.Error("无成品配方,请核对成品编码"); } Dt_ScanStation dt_ScanStation = _scanStationService.Repository.QueryFirst(x => x.StationCode == "001"); if (dt_ScanStation.StationEndProduct != proCode) { return WebResponseContent.Instance.Error("成品编号错误"); } List dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == formulaModel.Id && x.IsScanned == 1); List Codelist = dt_FormulaDetails.Select(x => x.ComponentCode).ToList(); string IsCode = IsComponentCodesEqual(toolingBoardSubmitDto.PartsList, Codelist); if (IsCode != null) { return WebResponseContent.Instance.Error($"物料【{IsCode}】错误,请核对物料编号"); } //Dt_Boxing existBoxinModel = _boxingService.Repository.QueryFirst(x => x.PalletCode == PalletCode); //if (existBoxinModel == null) //{ // return WebResponseContent.Instance.Error($"托盘未添加,请稍后重试"); //} if (!CheckComponentsMatchExactly(toolingBoardSubmitDto.PartsList, Codelist)) { throw new InvalidOperationException("零件与配方表中不同"); } var PalletCode = TcpClientExample.Start("192.168.2.120", 2001); if (!PalletCode.IsNotEmptyOrNull() || PalletCode == "NoRead") { throw new InvalidOperationException("托盘码未扫到,请重试"); } Dt_Boxing dt_Boxing = _boxingService.Repository.QueryFirst(x => x.PalletCode == PalletCode); if (dt_Boxing != null) { throw new InvalidOperationException("托盘码重复扫描"); } Dt_Boxing existBoxinModel = new Dt_Boxing(); existBoxinModel.PalletCode = PalletCode; existBoxinModel.ProductCode = proCode; existBoxinModel.ProductName = formulaModel.ProductName; existBoxinModel.BoxingNo = proOther; existBoxinModel.SupplierCode = supplierCode; int id = _boxingService.Repository.AddData(existBoxinModel); foreach (var item in dt_FormulaDetails) { Dt_BoxingDetail dt_BoxingDetail = new Dt_BoxingDetail() { BoxingId = id, ComponentCode = item.ComponentCode, ComponentName = item.ComponentName, Creater = "admin", CreateDate = new DateTime() }; BaseDal.AddData(dt_BoxingDetail); } uow.Commit(); } OtherDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceName == "主控PLC") as OtherDevice; if (device == null) throw new Exception("未找到主控PLC设备信息"); if (!device.IsConnected) throw new Exception($"主控PLC设备通讯异常"); device.SetValue(W_PLCDBName.wboolLocation5ScanDone, true); Thread.Sleep(500); device.SetValue(W_PLCDBName.wboolLocation5ScanDone, false); // if (existBoxinModel == null) //{ // #region 新增逻辑 - 原逻辑优化版 // Dt_Boxing dt_boxin = new Dt_Boxing() // { // PalletCode = palletCode, // ProductCode = productCode, // ProductName = formulaModel.ProductName.Trim(), // Creater = "admin", // CreateDate = DateTime.Now // }; // int newBoxingId = _boxingService.Repository.AddData(dt_boxin); // // 批量添加明细表数据 // if (toolingBoardSubmitDto.PartsList != null && toolingBoardSubmitDto.PartsList.Count > 0) // { // List detailList = new List(); // foreach (string ComponentCode in toolingBoardSubmitDto.PartsList) // { // if (string.IsNullOrWhiteSpace(ComponentCode)) continue; // string ComponentCodeTrim = ComponentCode.Trim(); // Dt_FormulaDetail formulaDetail = _formulaDetailService.Repository.QueryFirst(x => x.FormulaId == formulaModel.Id && x.ComponentCode == ComponentCodeTrim); // if (formulaDetail == null) // { // return WebResponseContent.Instance.Error($"配方中无此物料【{ComponentCodeTrim}】,请核对物料编号"); // } // Dt_BoxingDetail detailModel = new Dt_BoxingDetail() // { // BoxingId = newBoxingId, // ComponentCode = ComponentCodeTrim, // ComponentName = formulaDetail.ComponentName, // Creater = "admin", // CreateDate = DateTime.Now // }; // detailList.Add(detailModel); // } // if (detailList.Count > 0) // { // BaseDal.AddData(detailList); // } // } // #endregion //} //else //{ // #region 修改逻辑 - 新增核心逻辑 // // 1. 更新主表数据 // existBoxinModel.ProductCode = productCode; // existBoxinModel.ProductName = formulaModel.ProductName.Trim(); // existBoxinModel.Modifier = "admin"; // existBoxinModel.ModifyDate = DateTime.Now; // _boxingService.Repository.UpdateData(existBoxinModel); // int boxingId = existBoxinModel.Id; // // 2. 删除该组盘下的【原有全部明细表数据】 // List oldDetailList = BaseDal.QueryData(x => x.BoxingId == boxingId); // if (oldDetailList != null && oldDetailList.Count > 0) // { // BaseDal.DeleteData(oldDetailList); // } // // 3. 重新插入修改后的明细表数据 // if (toolingBoardSubmitDto.PartsList != null && toolingBoardSubmitDto.PartsList.Count > 0) // { // List detailList = new List(); // foreach (string ComponentCode in toolingBoardSubmitDto.PartsList) // { // if (string.IsNullOrWhiteSpace(ComponentCode)) continue; // string ComponentCodeTrim = ComponentCode.Trim(); // Dt_FormulaDetail formulaDetail = _formulaDetailService.Repository.QueryFirst(x => x.FormulaId == formulaModel.Id && x.ComponentCode == ComponentCodeTrim); // if (formulaDetail == null) // { // return WebResponseContent.Instance.Error($"配方中无此物料【{ComponentCodeTrim}】,请核对物料名称"); // } // Dt_BoxingDetail detailModel = new Dt_BoxingDetail() // { // BoxingId = boxingId, // ComponentCode = ComponentCodeTrim, // ComponentName = formulaDetail.ComponentName, // Creater = "admin", // CreateDate = DateTime.Now // }; // detailList.Add(detailModel); // } // if (detailList.Count > 0) // { // BaseDal.AddData(detailList); // } // } // #endregion //} //uow.Commit(); string msg = null; List dt_ProcessInfoDetail = _processInfoDetailService.Repository .QueryData(x => x.ProductSn == proOther && x.ProductCode == proCode).ToList(); // 3. 判断查询结果,存在则赋值提示信息 if (dt_ProcessInfoDetail.Count <= 3 && dt_ProcessInfoDetail.Count != 0) { msg = "已有流水号"; } // 4. 返回响应(存在重复则msg是"已有流水号",不存在则msg为null) return WebResponseContent.Instance.OK(msg); } catch (Exception ex) { Console.WriteLine($"保存工装板组盘信息异常:{ex.Message},堆栈:{ex.StackTrace}"); return WebResponseContent.Instance.Error($"提交失败:{ex.Message}"); } } } /// /// 获取成品编号和零件编号 /// /// /// public WebResponseContent GetProductAndPartsByBoardNo(string palletCode) { try { if (string.IsNullOrWhiteSpace(palletCode)) { return WebResponseContent.Instance.OK("查询成功", new { finishedProductCode = "", partsList = Enumerable.Repeat("", 10).ToList() }); } Dt_Boxing dt_Boxing = _boxingService.Repository.QueryFirst(x => x.PalletCode == palletCode); if (dt_Boxing == null) { return WebResponseContent.Instance.OK("未查询到该工装板对应的成品信息", new { finishedProductCode = "", partsList = Enumerable.Repeat("", 10).ToList() }); } List dt_BoxingDetails = BaseDal.QueryData(x => x.BoxingId == dt_Boxing.Id)?.ToList() ?? new List(); // 取零件编号 List partsList = dt_BoxingDetails.Select(d => d.ComponentCode).ToList(); List resultPartsList = new List(); for (int i = 0; i < 10; i++) { if (i < partsList.Count) { resultPartsList.Add(partsList[i] ?? ""); } else { resultPartsList.Add(""); } } return WebResponseContent.Instance.OK("零件编号列表查询成功", new { finishedProductCode = dt_Boxing.ProductCode ?? "", partsList = resultPartsList }); } catch (Exception ex) { return WebResponseContent.Instance.Error($"查询零件编号列表异常:{ex.Message}"); } } } }