using Autofac.Core; using OfficeOpenXml; using OfficeOpenXml.Style; using Spire.Xls; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; 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 ScanStationService : ServiceBase>, IScanStationService { private readonly IFormulaService _formulaService; private readonly IFormulaDetailService _formulaDetailService; private readonly IProcessInfoService _processInfoService; private readonly IProcessInfoDetailService _processInfoDetailService; public ScanStationService(IRepository BaseDal, IFormulaService formulaService, IFormulaDetailService formulaDetailService, IProcessInfoService processInfoService, IProcessInfoDetailService processInfoDetailService ) : base(BaseDal) { _formulaService = formulaService; _formulaDetailService = formulaDetailService; _processInfoService = processInfoService; _processInfoDetailService = processInfoDetailService; } public IRepository Repository => BaseDal; /// /// 启动PLC /// /// /// /// public WebResponseContent StartPLC(bool isStop) { try { 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设备通讯异常"); if (isStop) { device.SetValue(W_PLCDBName.wboolAutoStart, false); //暂停信号 device.SetValue(W_PLCDBName.wboolAutoPause, false); return WebResponseContent.Instance.OK(); } var Heart = device.GetValue(R_PLCDBName.rboolHeart); var EMG = device.GetValue(R_PLCDBName.rboolEMG); var OnlineExecuting = device.GetValue(R_PLCDBName.rboolOnlineExecuting); var Error = device.GetValue(R_PLCDBName.rboolError); if (Heart && !EMG && OnlineExecuting && !Error) { device.SetValue(W_PLCDBName.wboolAutoStart, true); //暂停信号 device.SetValue(W_PLCDBName.wboolAutoPause, false); return WebResponseContent.Instance.OK(); } return WebResponseContent.Instance.Error("设备不是在线状态"); } catch (Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } /// /// 暂停/恢复PLC(双向控制) /// /// 是否为暂停操作:true=暂停,false=恢复 /// 统一格式的响应结果 public WebResponseContent PausePLC(bool isPause) { try { 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设备通讯异常"); var Heart = device.GetValue(R_PLCDBName.rboolHeart); var EMG = device.GetValue(R_PLCDBName.rboolEMG); var Error = device.GetValue(R_PLCDBName.rboolError); if (!device.GetValue(W_PLCDBName.wboolAutoStart)) { return WebResponseContent.Instance.Error("设备未启动"); } if (!Heart || EMG || Error) { return WebResponseContent.Instance.Error("设备状态异常,无法执行暂停/恢复操作"); } device.SetValue(W_PLCDBName.wboolAutoPause, isPause); return WebResponseContent.Instance.OK(); } catch (Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } /// /// 返回信号 /// /// /// public WebResponseContent GetSignalStates() { try { 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设备通讯异常"); //获取信号灯状态 var Heart = device.GetValue(R_PLCDBName.rboolHeart); var EMG = device.GetValue(R_PLCDBName.rboolEMG); var AutoExecuting = device.GetValue(R_PLCDBName.rboolAutoExecuting); var OnlineExecuting = device.GetValue(R_PLCDBName.rboolOnlineExecuting); var Error = device.GetValue(R_PLCDBName.rboolError); //获取启动暂停状态 var IsStarted = device.GetValue(W_PLCDBName.wboolAutoStart); var IsPaused = device.GetValue(W_PLCDBName.wboolAutoPause); //返回对象 var responseData = new { // 信号灯状态数组(保持原有顺序) signalStates = new bool[] { Heart, EMG, AutoExecuting, OnlineExecuting, Error }, // PLC启动/暂停状态对象 plcStatus = new { isStarted = IsStarted, isPaused = IsPaused } }; return WebResponseContent.Instance.OK(data: responseData); } catch (Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } /// /// 获取成品信息 /// /// public WebResponseContent GetLeftInitialData() { try { Dt_ScanStation dt_ScanStation = BaseDal.QueryFirst(x => x.StationCode == "001"); if (dt_ScanStation == null) { return WebResponseContent.Instance.Error("未找到工位编码为001的工位信息"); } Dt_Formula dt_Formula = _formulaService.Repository.QueryFirst(x => x.ProductCode == dt_ScanStation.StationEndProduct); if (dt_Formula == null) { return WebResponseContent.Instance.Error($"未找到成品编号【{dt_ScanStation.StationEndProduct}】对应的配方信息"); } List dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == dt_Formula.Id); // 新增leftPartSupplierCodes字段存储供方代码 var responseData = new { finishedProductId = dt_Formula.Id, finishedProduct = dt_Formula.ProductCode, leftPartCodes = new List(), leftPartIds = new List(), leftPartChecked = new List(), // 存储每个零件的供方代码 leftPartSupplierCodes = new List() }; foreach (var detail in dt_FormulaDetails.Take(10)) { responseData.leftPartCodes.Add(detail.ComponentCode ?? ""); responseData.leftPartIds.Add(detail.Id); responseData.leftPartChecked.Add(detail.IsScanned); // 添加供方代码,为空时返回空字符串 responseData.leftPartSupplierCodes.Add(detail.SupplierCode ?? ""); } int needFillCount = 10 - responseData.leftPartCodes.Count; for (int i = 0; i < needFillCount; i++) { responseData.leftPartCodes.Add(""); responseData.leftPartIds.Add(0); responseData.leftPartChecked.Add(0); //补足10条数据,空的供方代码返回空字符串 responseData.leftPartSupplierCodes.Add(""); } return WebResponseContent.Instance.OK("获取左侧初始数据成功", responseData); } catch (Exception ex) { return WebResponseContent.Instance.Error($"获取左侧初始数据失败,请稍后重试【{ex.Message}】"); } } /// /// 更新是否扫码 /// /// /// public WebResponseContent UpdatePartScannedStatus(UpdatePartScannedStatusRequest updatePartScannedStatusRequest) { try { Dt_FormulaDetail dt_FormulaDetail = _formulaDetailService.Repository.QueryFirst(x => x.Id == updatePartScannedStatusRequest.Id); dt_FormulaDetail.IsScanned = updatePartScannedStatusRequest.IsScanned; bool flag = _formulaDetailService.Repository.UpdateData(dt_FormulaDetail); if (flag) { return WebResponseContent.Instance.OK(); } return WebResponseContent.Instance.Error("更新错误"); } catch (Exception ex) { return WebResponseContent.Instance.Error("获取数据失败"); } } /// /// 下载流程卡 /// /// /// public WebResponseContent ExportData() { try { Dt_ScanStation dt_ScanStation = BaseDal.QueryFirst(x => x.StationCode == "001"); string fileName = $"{DateTime.Now.ToString("yyyyMMddHHssmm")}" + $"{dt_ScanStation.StationEndProduct}.xlsx"; string templatePath = $"{AppDomain.CurrentDomain.BaseDirectory}ExprotTemplate\\发电机弹性支撑信息化流程卡.xlsx";//模板路径 // 获取系统桌面路径 string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\流程卡"; //string desktopPath = "C:\\Users\\Administrator\\Desktop"; string savePath = Path.Combine(desktopPath, fileName); using Stream templateStream = new FileStream(templatePath, FileMode.Open); using Stream saveStream = new FileStream(savePath, FileMode.Create); using ExcelPackage package = new ExcelPackage(saveStream, templateStream); ExcelWorksheet worksheet = package.Workbook.Worksheets["流程卡"]; Dt_Formula formula = _formulaService.Repository.QueryFirst(x => x.ProductCode == dt_ScanStation.StationEndProduct); List dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == formula.Id && x.IsScanned == 1).ToList(); for (int i = dt_FormulaDetails.Count; i < 10; i++) { dt_FormulaDetails.Add(new Dt_FormulaDetail()); } worksheet.Cells[3, 5].Value = dt_ScanStation.StationEndProduct;//成品编号 worksheet.Cells[3, 17].Value = dt_ScanStation.LastProductSn.ObjToInt() - dt_ScanStation.FirstProductSn.ObjToInt() + 1;//数量; worksheet.Cells[3, 29].Value = dt_ScanStation.FirstProductSn + "-" + dt_ScanStation.LastProductSn;//流水号 worksheet.Cells[4, 5].Value = DateTime.Now.ToString("yyyy/MM/dd");//组装日期 worksheet.Cells[4, 17].Value = dt_ScanStation.AssembleUser;//组装人员 int row = 7; for (int j = 0; j < 5; j++) { worksheet.Cells[row, 1].Value = dt_FormulaDetails[j].ComponentName; worksheet.Cells[row, 5].Value = dt_FormulaDetails[j].ComponentCode; worksheet.Cells[row, 12].Value = dt_FormulaDetails[j].SupplierCode; worksheet.Cells[row, 19].Value = dt_FormulaDetails[j + 5].ComponentName; worksheet.Cells[row, 23].Value = dt_FormulaDetails[j + 5].ComponentCode; worksheet.Cells[row, 30].Value = dt_FormulaDetails[j + 5].SupplierCode; row++; } row = 13; for (int j = 0; j < 4; j++) { worksheet.Cells[row + j, 12].Value = "☑ 是 □ 否"; worksheet.Cells[row + j, 30].Value = "☑ 是 □ 否"; } worksheet.Cells[17, 12].Value = "☑ 是 □ 否"; worksheet.Cells[23, 5].Value = "☑ 是 □ 否"; worksheet.Cells[26, 7].Value = formula.ProductHeight; worksheet.Cells[26, 13].Value = formula.ScrewTorqueOutput; worksheet.Cells[26, 19].Value = formula.ScrewDownsetDistance; worksheet.Cells[26, 25].Value = formula.PressFastenTorque; List dt_ProcessInfoDetails = _processInfoDetailService.Repository .QueryData(x => x.ProductCode == dt_ScanStation.StationEndProduct && x.ProductSn.CompareTo(dt_ScanStation.FirstProductSn) >= 0 && x.ProductSn.CompareTo(dt_ScanStation.LastProductSn) <= 0) .OrderBy(x => x.CreateDate) .ToList(); row = 27; ExcelRange baseStyleRow = worksheet.Cells[$"{row}:{row}"]; foreach (var item in dt_ProcessInfoDetails) { if (row > 61) { var sourceRange = worksheet.Cells[row - 1, 1, row - 1, 36]; var targetRange = worksheet.Cells[row, 1, row, 36]; // 1. 复制合并规则(原有逻辑保留) CopyCellMerge(worksheet, sourceRange, targetRange); // 2. 复制样式(兼容所有EPPlus版本) targetRange.StyleID = sourceRange.StyleID; // 3. 同步行高 worksheet.Row(row).Height = worksheet.Row(row - 1).Height; } worksheet.Cells[row, 1].Value = item.ProductSn; worksheet.Cells[row, 7].Value = item.ProductCheckHeight; worksheet.Cells[row, 7].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; worksheet.Cells[row, 7].Style.Fill.BackgroundColor.SetColor(SixLabors.ImageSharp.Color.Yellow); worksheet.Cells[row, 13].Value = item.ThreadPositionHeight; worksheet.Cells[row, 13].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; worksheet.Cells[row, 13].Style.Fill.BackgroundColor.SetColor(SixLabors.ImageSharp.Color.Yellow); worksheet.Cells[row, 19].Value = item.PressPressure; worksheet.Cells[row, 19].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; worksheet.Cells[row, 19].Style.Fill.BackgroundColor.SetColor(SixLabors.ImageSharp.Color.Yellow); worksheet.Cells[row, 25].Value = item.ScrewTorque; worksheet.Cells[row, 25].Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid; worksheet.Cells[row, 25].Style.Fill.BackgroundColor.SetColor(SixLabors.ImageSharp.Color.Yellow); worksheet.Cells[row, 31].Value = item.ProductStatus == 0 ? "不合格" : item.ProductStatus == 1 ? "合格" : "人工确认合格"; //if (item.PressTightenUnfinished == 1) //{ // worksheet.Cells[row, 31].Value = "压装拧紧异常"; //} //else //{ // worksheet.Cells[row, 31].Value = "正常"; //} row++; } //worksheet.DeleteRow(row, worksheet.Dimension.End.Row - row + 1); package.Save(); string pdfFileName = $"{DateTime.Now.ToString("yyyyMMddHHssmm")}" + $"{dt_ScanStation.StationEndProduct}.pdf"; //string pdfPath = $"{AppDomain.CurrentDomain.BaseDirectory}Download\\{pdfFileName}"; string pdfPath = Path.Combine(desktopPath, pdfFileName); Workbook workbook = new Workbook(); workbook.LoadFromFile(savePath); // 设置转换选项,包含所有工作表 workbook.ConverterSetting.SheetFitToPage = true; // 保存所有工作表到同一个PDF文件 workbook.SaveToFile(pdfPath, FileFormat.PDF); //// 转换第一个工作表到PDF //workbook.SaveToFile(pdfPath, FileFormat.PDF); return WebResponseContent.Instance.OK(data: new { path = pdfPath, fileName = pdfFileName }); } catch (Exception ex) { return WebResponseContent.Instance.Error(ex.Message); } } // /// 自定义Excel单元格合并规则复制方法(兼容低版本EPPlus) /// /// Excel工作表 /// 源单元格范围 /// 目标单元格范围 public void CopyCellMerge(ExcelWorksheet worksheet, ExcelRange sourceRange, ExcelRange targetRange) { if (sourceRange == null || targetRange == null) return; if (sourceRange.Worksheet != worksheet || targetRange.Worksheet != worksheet) return; // 1. 先将源范围内的合并区域提取到临时列表中 var sourceMergeList = new List(); foreach (var merge in worksheet.MergedCells) { var mergeRange = worksheet.Cells[merge]; if (mergeRange.Start.Row >= sourceRange.Start.Row && mergeRange.End.Row <= sourceRange.End.Row && mergeRange.Start.Column >= sourceRange.Start.Column && mergeRange.End.Column <= sourceRange.End.Column) { sourceMergeList.Add(merge); } } // 2. 遍历临时列表,安全地创建目标合并区域 foreach (var merge in sourceMergeList) { var mergeRange = worksheet.Cells[merge]; int rowOffset = targetRange.Start.Row - sourceRange.Start.Row; int colOffset = targetRange.Start.Column - sourceRange.Start.Column; var targetMergeRange = worksheet.Cells[ mergeRange.Start.Row + rowOffset, mergeRange.Start.Column + colOffset, mergeRange.End.Row + rowOffset, mergeRange.End.Column + colOffset ]; targetMergeRange.Merge = true; } } } }