leiqunqing
2026-02-06 15b3879cd259108e7ebb755fe02c190f28f1e20c
´úÂë¹ÜÀí/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_BasicInfoService/ScanStationService.cs
@@ -1,20 +1,385 @@
using System;
using Autofac.Core;
using OfficeOpenXml;
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<Dt_ScanStation, IRepository<Dt_ScanStation>>, IScanStationService
    {
        public ScanStationService(IRepository<Dt_ScanStation> BaseDal) : base(BaseDal)
        private readonly IFormulaService _formulaService;
        private readonly IFormulaDetailService _formulaDetailService;
        private readonly IProcessInfoService _processInfoService;
        private readonly IProcessInfoDetailService _processInfoDetailService;
        public ScanStationService(IRepository<Dt_ScanStation> BaseDal,
            IFormulaService formulaService,
            IFormulaDetailService formulaDetailService,
            IProcessInfoService processInfoService,
            IProcessInfoDetailService processInfoDetailService
            ) : base(BaseDal)
        {
            _formulaService = formulaService;
            _formulaDetailService = formulaDetailService;
            _processInfoService = processInfoService;
            _processInfoDetailService = processInfoDetailService;
        }
        public IRepository<Dt_ScanStation> Repository => BaseDal;
        /// <summary>
        /// å¯åЍPLC
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        /// <summary>
        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, bool>(R_PLCDBName.rboolHeart);
                var EMG = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolEMG);
                var OnlineExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolOnlineExecuting);
                var Error = device.GetValue<R_PLCDBName, bool>(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);
            }
        }
        /// <summary>
        /// æš‚停/恢复PLC(双向控制)
        /// </summary>
        /// <param name="isPause">是否为暂停操作:true=暂停,false=恢复</param>
        /// <returns>统一格式的响应结果</returns>
        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, bool>(R_PLCDBName.rboolHeart);
                var EMG = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolEMG);
                var Error = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolError);
                if (!device.GetValue<W_PLCDBName, bool>(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);
            }
        }
        /// <summary>
        /// è¿”回信号
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public WebResponseContent GetSignalStates()
        {
            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, bool>(R_PLCDBName.rboolHeart);
            var EMG = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolEMG);
            var AutoExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolAutoExecuting);
            var OnlineExecuting = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolOnlineExecuting);
            var Error = device.GetValue<R_PLCDBName, bool>(R_PLCDBName.rboolError);
            //获取启动暂停状态
            var IsStarted = device.GetValue<W_PLCDBName, bool>(W_PLCDBName.wboolAutoStart);
            var IsPaused = device.GetValue<W_PLCDBName, bool>(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);
        }
        /// <summary>
        /// èŽ·å–æˆå“ä¿¡æ¯
        /// </summary>
        /// <returns></returns>
        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_FormulaDetail> dt_FormulaDetails = _formulaDetailService.Repository.QueryData(x => x.FormulaId == dt_Formula.Id);
                var responseData = new
                {
                    finishedProductId = dt_Formula.Id,
                    finishedProduct = dt_Formula.ProductCode,
                    leftPartCodes = new List<string>(),
                    leftPartIds = new List<int>(),
                    leftPartChecked = new List<int>()
                };
                foreach (var detail in dt_FormulaDetails.Take(10))
                {
                    responseData.leftPartCodes.Add(detail.ComponentCode ?? "");
                    responseData.leftPartIds.Add(detail.Id);
                    responseData.leftPartChecked.Add(detail.IsScanned);
                }
                int needFillCount = 10 - responseData.leftPartCodes.Count;
                for (int i = 0; i < needFillCount; i++)
                {
                    responseData.leftPartCodes.Add("");
                    responseData.leftPartIds.Add(0);
                    responseData.leftPartChecked.Add(0);
                }
                return WebResponseContent.Instance.OK("获取左侧初始数据成功", responseData);
            }
            catch (Exception ex)
            {
                return WebResponseContent.Instance.Error($"获取左侧初始数据失败,请稍后重试【{ex.Message}】");
            }
        }
        /// <summary>
        /// æ›´æ–°æ˜¯å¦æ‰«ç 
        /// </summary>
        /// <param name="updatePartScannedStatusRequest"></param>
        /// <returns></returns>
        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("获取数据失败");
            }
        }
        /// <summary>
        /// ä¸‹è½½æµç¨‹å¡
        /// </summary>
        /// <param name="dt_ProcessInfo"></param>
        /// <returns></returns>
        public WebResponseContent ExportData(Dt_ScanStation dt_ScanStation)
        {
            string fileName = $"{DateTime.Now.ToString("yyyyMMddHHssmm")}.xlsx";
            string templatePath = $"{AppDomain.CurrentDomain.BaseDirectory}ExprotTemplate\\发电机弹性支撑信息化流程卡.xlsx";//模板路径
            string savePath = $"{AppDomain.CurrentDomain.BaseDirectory}Download\\{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_FormulaDetail> 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 = "☑ æ˜¯     â–¡ å¦";
            List<Dt_ProcessInfoDetail> dt_ProcessInfoDetails = _processInfoDetailService.Repository
                .QueryData(x => x.ProductCode == dt_ScanStation.StationEndProduct
                && x.ProductSn.CompareTo(dt_ScanStation.LastProductSn) >= 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. å¤åˆ¶åˆå¹¶è§„则(原有逻辑保留)
                    this.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.Height2;
                worksheet.Cells[row, 13].Value = item.Height1;
                worksheet.Cells[row, 19].Value = item.PressPressure;
                worksheet.Cells[row, 25].Value = item.ScrewTorque;
                if (item.PressTightenUnfinished == 1)
                {
                    worksheet.Cells[row, 31].Value = "压装拧紧异常";
                }
                else if (item.CheckUnfinished == 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")}.pdf";
            string pdfPath = $"{AppDomain.CurrentDomain.BaseDirectory}Download\\{pdfFileName}";
            Workbook workbook = new Workbook();
            workbook.LoadFromFile(savePath);
            // è½¬æ¢ç¬¬ä¸€ä¸ªå·¥ä½œè¡¨åˆ°PDF
            workbook.SaveToFile(pdfPath, FileFormat.PDF);
            return WebResponseContent.Instance.OK(data: new { path = pdfPath, fileName = pdfFileName });
        }
        // <summary>
        /// è‡ªå®šä¹‰Excel单元格合并规则复制方法(兼容低版本EPPlus)
        /// </summary>
        /// <param name="worksheet">Excel工作表</param>
        /// <param name="sourceRange">源单元格范围</param>
        /// <param name="targetRange">目标单元格范围</param>
        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<string>();
            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;
            }
        }
    }
}