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<Dt_ScanStation, IRepository<Dt_ScanStation>>, IScanStationService
|
{
|
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()
|
{
|
|
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 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);
|
}
|
catch (Exception ex)
|
{
|
return WebResponseContent.Instance.Error(ex.Message);
|
}
|
}
|
|
/// <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);
|
|
// 新增leftPartSupplierCodes字段存储供方代码
|
var responseData = new
|
{
|
finishedProductId = dt_Formula.Id,
|
finishedProduct = dt_Formula.ProductCode,
|
leftPartCodes = new List<string>(),
|
leftPartIds = new List<int>(),
|
leftPartChecked = new List<int>(),
|
// 存储每个零件的供方代码
|
leftPartSupplierCodes = new List<string>()
|
};
|
|
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}】");
|
}
|
}
|
|
/// <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()
|
{
|
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_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 = "☑ 是 □ 否";
|
|
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_ProcessInfoDetail> 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);
|
}
|
}
|
|
|
// <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;
|
}
|
}
|
}
|
}
|