using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
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<Dt_BoxingDetail, IRepository<Dt_BoxingDetail>>, 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<Dt_BoxingDetail> 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<Dt_BoxingDetail> Repository => BaseDal;
|
|
/// <summary>
|
/// 比较零件是否齐全
|
/// </summary>
|
/// <param name="boxingDetails">实际装箱的零件集合</param>
|
/// <param name="formulaDetails">配方要求的零件集合</param>
|
/// <returns>是否完全匹配</returns>
|
public bool CheckComponentsMatchExactly(List<string> boxingDetails, List<string> 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<string, int>();
|
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;
|
}
|
|
|
/// <summary>
|
/// 检查零件
|
/// </summary>
|
/// <param name="boxingDetails"></param>
|
/// <param name="formulaDetails"></param>
|
/// <returns></returns>
|
public string IsComponentCodesEqual(List<string> boxingDetails, List<string> formulaDetails)
|
{
|
|
// 处理null集合,规避空指针异常
|
var boxList = boxingDetails ?? new List<string>();
|
var formulaList = formulaDetails ?? new List<string>();
|
|
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;
|
}
|
|
|
/// <summary>
|
/// 添加/修改组盘信息(一体化接口:传工装板编号存在则修改,不存在则新增)
|
/// </summary>
|
/// <param name="toolingBoardSubmitDto"></param>
|
/// <returns></returns>
|
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;
|
|
if (!string.IsNullOrWhiteSpace(productCode))
|
{
|
|
var proCodeMatch = System.Text.RegularExpressions.Regex.Match(productCode, @"TX(\d+)(?=\s|\||$)", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
|
if (proCodeMatch.Success)
|
{
|
proCode = $"TX{proCodeMatch.Groups[1].Value.Trim()}";
|
}
|
|
// 正则2:匹配连续的10位纯数字(全局匹配,取第一个符合的即可)
|
var proOtherMatch = System.Text.RegularExpressions.Regex.Match(productCode, @"\d{10}");
|
if (proOtherMatch.Success)
|
{
|
proOther = proOtherMatch.Value.Trim();
|
}
|
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_FormulaDetail> dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == formulaModel.Id && x.IsScanned == 1);
|
List<string> 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.BoxingNo = proOther;
|
|
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<Dt_BoxingDetail> detailList = new List<Dt_BoxingDetail>();
|
// 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<Dt_BoxingDetail> 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<Dt_BoxingDetail> detailList = new List<Dt_BoxingDetail>();
|
// 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> 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}");
|
}
|
}
|
}
|
|
|
|
/// <summary>
|
/// 获取成品编号和零件编号
|
/// </summary>
|
/// <param name="palletCode"></param>
|
/// <returns></returns>
|
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_BoxingDetail> dt_BoxingDetails = BaseDal.QueryData(x => x.BoxingId == dt_Boxing.Id)?.ToList() ?? new List<Dt_BoxingDetail>();
|
// 取零件编号
|
List<string> partsList = dt_BoxingDetails.Select(d => d.ComponentCode).ToList();
|
List<string> resultPartsList = new List<string>();
|
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}");
|
}
|
}
|
}
|
}
|