shgx_tz_mom/ZR.Service/mes/qc/backend/QcBackEndService.cs
赵正易 8e459d0ccd feat(mqtt): 添加设备数据上传功能及相关服务
实现设备数据通过MQTT上传功能,包括:
1. 新增DeviceUploadData实体及DTO
2. 添加MQTT服务处理设备消息
3. 实现设备数据存储逻辑
4. 创建相关控制器和服务接口
2025-09-21 13:52:06 +08:00

1624 lines
66 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Infrastructure.Attribute;
using Microsoft.Extensions.Logging;
using MQTTnet.Protocol;
using SqlSugar;
using System;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ZR.Common.MqttHelper;
using ZR.Model.Business;
using ZR.Model.Dto;
using ZR.Model.MES.wms;
using ZR.Service.Business.IBusinessService;
using ZR.Service.mqtt;
namespace ZR.Service.Business
{
/// <summary>
/// 质量BackEnd工单业务模块Service业务层处理
/// </summary>
[AppService(ServiceType = typeof(IQcBackEndService), ServiceLifetime = LifeTime.Transient)]
public class QcBackEndService : BaseService<QcBackEndServiceWorkorder>, IQcBackEndService
{
private readonly MqttService _mqttService; // 注入MqttService
private readonly ILogger<QcBackEndService> _logger;
public QcBackEndService(MqttService mqttService, ILogger<QcBackEndService> logger)
{
_mqttService = mqttService;
_logger = logger;
}
public QcBackEndLabelAnalysisDto AnalyzeLabelToDto(string label, int type)
{
QcBackEndLabelAnalysisDto labelAnalysisDto =
new()
{
IsOk = true,
Msg = "解析成功!",
LabelCode = label,
};
// 判断内外箱标签
// 解析零件号
labelAnalysisDto.Partnumber = DoAnalyzePartnumber(label);
// 解析数量
labelAnalysisDto.Number = DoAnalyzeQuantity(label);
if (string.IsNullOrEmpty(labelAnalysisDto.Partnumber))
{
labelAnalysisDto.IsOk = false;
labelAnalysisDto.Msg = "标签,零件号解析异常!";
}
// TYPE === 1 时,同时根据物料清单获取详细信息
if (type == 1)
{
string checkPartnumber = labelAnalysisDto.Partnumber;
// 使用正则表达式匹配并移除特殊后缀
string processedPartnumber = Regex.Replace(
checkPartnumber,
@"-(FL|FR|RR|RL)$",
"",
RegexOptions.IgnoreCase
);
WmMaterial material = Context
.Queryable<WmMaterial>()
.Where(it => it.Partnumber == processedPartnumber)
.Where(it => it.Type == 1)
.Where(it => it.Status == 1)
.First();
if (material == null)
{
labelAnalysisDto.IsOk = false;
labelAnalysisDto.Msg = "物料清单内无此零件号!请检查物料清单:" + processedPartnumber;
}
else
{
labelAnalysisDto.Color = material.Color;
labelAnalysisDto.Specification = material.Specification;
labelAnalysisDto.Description = !string.IsNullOrEmpty(material.Description)
? material.Description
: material.ProductName;
}
}
return labelAnalysisDto;
}
// 标签的零件号解析
public string DoAnalyzePartnumber(string label)
{
// 通用规则下的标签零件号抓取
var predicate = Expressionable
.Create<QcBackEndBaseLabelAnalysis>()
.And(it => it.Code == "PartNumber")
.And(it => it.Status == "1");
List<QcBackEndBaseLabelAnalysis> analysisList = Context
.Queryable<QcBackEndBaseLabelAnalysis>()
.Where(predicate.ToExpression())
.ToList();
foreach (QcBackEndBaseLabelAnalysis analysis in analysisList)
{
if (string.IsNullOrEmpty(analysis.Expression))
{
continue;
}
// 零件号正则表达式
Regex pattern = new(@analysis.Expression);
Match match = pattern.Match(label);
if (match.Success && match.Groups.Count > 1)
{
return match.Groups[1].Value;
}
}
// 非通用规则下的标签零件号抓取
// 解析T58门把手产品标签
try
{
// 直接从标签中截取前 15 个字符作为零件号
if (!string.IsNullOrEmpty(label) && label.Length >= 40 && label.EndsWith('$'))
{
return label.Substring(0, 17);
}
}
catch (Exception)
{
return "";
}
return "";
}
// 标签的数量解析
public int DoAnalyzeQuantity(string label)
{
int result = 0;
// 标签零件号抓取
var predicate = Expressionable
.Create<QcBackEndBaseLabelAnalysis>()
.And(it => it.Code == "Quantity")
.And(it => it.Status == "1");
List<QcBackEndBaseLabelAnalysis> analysisList = Context
.Queryable<QcBackEndBaseLabelAnalysis>()
.Where(predicate.ToExpression())
.ToList();
foreach (QcBackEndBaseLabelAnalysis analysis in analysisList)
{
if (string.IsNullOrEmpty(analysis.Expression))
{
continue;
}
// 零件号正则表达式
Regex pattern = new(@analysis.Expression);
Match match = pattern.Match(label);
if (match.Success && match.Groups.Count > 1)
{
if (Int32.TryParse(match.Groups[1].Value, out result))
{
return result;
}
else
{
return -1;
}
}
}
return -1;
}
// 标签的批次号解析
public string DoAnalyzeBatchCode(string label)
{
// 标签批次号正则抓取
var predicate = Expressionable
.Create<QcBackEndBaseLabelAnalysis>()
.And(it => it.Code == "BatchCode")
.And(it => it.Status == "1");
List<QcBackEndBaseLabelAnalysis> analysisList = Context
.Queryable<QcBackEndBaseLabelAnalysis>()
.Where(predicate.ToExpression())
.ToList();
foreach (QcBackEndBaseLabelAnalysis analysis in analysisList)
{
if (string.IsNullOrEmpty(analysis.Expression))
{
continue;
}
// 零件号正则表达式
Regex pattern = new(@analysis.Expression);
Match match = pattern.Match(label);
if (match.Success && match.Groups.Count > 1)
{
return match.Groups[1].Value;
}
}
return "";
}
public List<QcBackEndAlterationDefectDto> GetDefectInitOptions()
{
List<QcBackEndAlterationDefectDto> defectList = new();
var predicate = Expressionable
.Create<QcBackEndBaseDefect>()
.And(it => it.Status == "1");
/*List<string> groupList = Context
.Queryable<QcBackEndBaseDefect>()
.Where(predicate.ToExpression())
.GroupBy(it => it.Group)
.Select(it => it.Group)
.ToList();*/
List<string> groupList = new() { "油漆", "设备", "毛坯", "程序", "班组操作" };
foreach (string group in groupList)
{
QcBackEndAlterationDefectDto defectDto = new();
defectDto.GroupName = group;
List<QcBackEndChildrenDefectDto> children = Context
.Queryable<QcBackEndBaseDefect>()
.Where(it => it.Group == group)
.Where(predicate.ToExpression())
.Select(it => new QcBackEndChildrenDefectDto
{
Name = it.Name,
Code = it.Code,
Type = it.Type,
Num = 0
})
.ToList();
defectDto.Children = children;
defectList.Add(defectDto);
}
return defectList;
}
public List<QcBackEndAlterationDefectDto> GetDefectTableOptions()
{
List<QcBackEndAlterationDefectDto> defectList = new();
var predicate = Expressionable
.Create<QcBackEndBaseDefect>()
.And(it => it.Type == "打磨")
.And(it => it.Status == "1");
/* List<string> groupList = Context
.Queryable<QcBackEndBaseDefect>()
.Where(predicate.ToExpression())
.GroupBy(it => it.Group)
.Select(it => it.Group)
.ToList();*/
List<string> groupList = new() { "油漆", "设备", "毛坯", "程序", "班组操作" };
foreach (string group in groupList)
{
QcBackEndAlterationDefectDto defectDto = new();
defectDto.GroupName = group;
List<QcBackEndChildrenDefectDto> children = Context
.Queryable<QcBackEndBaseDefect>()
.Where(it => it.Group == group)
.Where(predicate.ToExpression())
.Select(it => new QcBackEndChildrenDefectDto
{
Name = it.Name,
Code = SqlFunc.IIF(
SqlFunc.Length(it.Code) >= 2,
SqlFunc.MergeString(
SqlFunc.Substring(it.Code, 0, 1), // 获取第一个字符注意SQL 中索引通常从1开始
SqlFunc.Substring(it.Code, SqlFunc.Length(it.Code) - 1, 1) // 获取最后一个字符
),
it.Code
),
Type = it.Type,
Num = 0
})
.ToList();
defectDto.Children = children;
defectList.Add(defectDto);
}
return defectList;
}
public List<QcBackEndBaseGroupDto> GetGroupOptions()
{
var predicate = Expressionable.Create<QcBackEndBaseGroup>().And(it => it.Status == "1");
var response = Context
.Queryable<QcBackEndBaseGroup>()
.Where(predicate.ToExpression())
.Select(it => new QcBackEndBaseGroupDto())
.ToList();
return response;
}
public List<QcBackEndBaseSiteDto> GetStieOptions()
{
var predicate = Expressionable.Create<QcBackEndBaseSite>().And(it => it.Status == "1");
var response = Context
.Queryable<QcBackEndBaseSite>()
.Where(predicate.ToExpression())
.Select(it => new QcBackEndBaseSiteDto())
.ToList();
return response;
}
public QcBackEndServiceWorkorder StartBackEndWorkOrder(QcBackEndWorkorderDetailDto data)
{
// 检查是否是已扫过的外箱标签
QcBackEndServiceWorkorder oldWorkOrder = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.Label == data.Label)
.First();
// 有旧记录则返回旧记录
if (oldWorkOrder != null)
{
return oldWorkOrder;
}
// 没有旧记录则开启新的记录
try
{
// 检查箱标签是否当内标签扫过
/*bool isInnerLabelScan = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.Label == data.Label)
.Where(it => it.LabelType == 2)
.Any();
if (isInnerLabelScan)
{
throw new Exception("标签异常,该标签已经当内标签扫过!");
}*/
Context.Ado.BeginTran();
DateTime nowTime = DateTime.Now;
// 创建新工单号
QcBackEndWorkorderDetailDto workorderInfo = GetNewWorkOrderCreate(data);
// 赋值
data.WorkOrder = workorderInfo.WorkOrder;
data.SerialNumber = workorderInfo.SerialNumber;
data.StartTime = nowTime;
QcBackEndServiceWorkorder newModel = GetNewWorkOrderInfo(data);
QcBackEndServiceWorkorder result = Context
.Insertable(newModel)
.ExecuteReturnEntity();
if (result == null)
{
Context.Ado.RollbackTran();
throw new Exception("插入新工单异常");
}
// 工单开始记录
QcBackEndRecordLabelScan newScanLabelRecord =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = result.WorkOrder,
PartNumber = result.PartNumber,
Team = result.Team,
SiteNo = result.SiteNo,
ComNo = result.ComNo,
Label = result.Label,
LabelType = 1,
LabelSort = 0,
ScanTime = $"{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "1",
Status = "1",
Remark = "新工单创建扫描箱标签",
CreatedBy = "后台系统",
CreatedTime = nowTime,
};
int res = Context.Insertable(newScanLabelRecord).ExecuteCommand();
if (res == 0)
{
Context.Ado.RollbackTran();
throw new Exception("插入标签记录异常");
}
QcBackEndLogWorkorder qcBackEndLog =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
Name = "工单开始",
Content = $"工单:{result.WorkOrder}开始,开始时间{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "100",
Status = "1",
Remark = "触摸屏操作记录",
CreatedBy = "系统",
CreatedTime = nowTime
};
Context.Insertable(qcBackEndLog).ExecuteCommand();
Context.Ado.CommitTran();
return result;
}
catch (Exception ex)
{
Context.Ado.RollbackTran();
throw new Exception(ex.Message);
}
}
// 创建新工单号
public QcBackEndWorkorderDetailDto GetNewWorkOrderCreate(QcBackEndWorkorderDetailDto data)
{
QcBackEndWorkorderDetailDto result = new();
string newWorkOrder = "";
DateTime today = DateTime.Today;
// 检查是否是已扫过的外箱标签
QcBackEndServiceWorkorder lastWorkOrder = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.CreatedTime.Value.Date == today)
.OrderByDescending(it => it.SerialNumber)
.First();
if (lastWorkOrder != null)
{
// 递增序列号
int sequenceNumber = lastWorkOrder.SerialNumber + 1;
if (data.IsOnetime == 1)
{
newWorkOrder = $"W{today:yyyyMMdd}{sequenceNumber:D3}";
}
else if (data.IsPolish == 1)
{
newWorkOrder = $"P{today:yyyyMMdd}{sequenceNumber:D3}";
}
else
{
newWorkOrder = $"{today:yyyyMMdd}{sequenceNumber:D3}";
}
result.SerialNumber = sequenceNumber;
}
else
{
// 如果今天还没有创建过工单,则从 "001" 开始
if (data.IsOnetime == 1)
{
newWorkOrder = $"W{today:yyyyMMdd}001";
}
else if (data.IsPolish == 1)
{
newWorkOrder = $"P{today:yyyyMMdd}001";
}
else
{
newWorkOrder = $"{today:yyyyMMdd}001";
}
result.SerialNumber = 1;
}
result.WorkOrder = newWorkOrder;
return result;
}
public static QcBackEndServiceWorkorder GetNewWorkOrderInfo(
QcBackEndWorkorderDetailDto data
)
{
// 新工单
QcBackEndServiceWorkorder model =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = data.WorkOrder,
SerialNumber = data.SerialNumber,
PartNumber = data.PartNumber,
Specification = data.Specification,
Color = data.Color,
Description = data.Description,
Team = data.Team,
SiteNo = data.SiteNo,
ComNo = data.ComNo,
IsOnetime = data.IsOnetime,
IsPolish = data.IsPolish,
IsBack = data.IsBack,
IsOut = data.IsOut,
StartTime = data.StartTime,
EndTime = null,
Label = data.Label,
RequireNumber = 0,
QualifiedNumber = 0,
PolishNumber = 0,
DamoNumber = 0,
BaofeiNumber = 0,
Type = "1",
Status = "1",
Remark = "系统新增工单",
CreatedBy = data.CreatedBy,
CreatedTime = data.CreatedTime,
UpdatedBy = data.UpdatedBy,
UpdatedTime = data.UpdatedTime
};
return model;
}
public QcBackEndServiceWorkorder ChangeWorkOrderDefect(QcBackEndWorkorderDefectDto data)
{
try
{
if (string.IsNullOrEmpty(data.DefectCode))
{
throw new Exception("缺陷项传入为空!");
}
Context.Ado.BeginTran();
DateTime nowTime = DateTime.Now;
// 获取缺陷信息
QcBackEndBaseDefect defect = Context
.Queryable<QcBackEndBaseDefect>()
.Where(it => it.Code == data.DefectCode && it.Status == "1")
.First();
if (defect == null)
{
throw new Exception("缺陷项不在缺陷清单中!");
}
// 工单信息修改
QcBackEndServiceWorkorder qcBackEndWorkorder = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == data.WorkOrder)
.First();
if (qcBackEndWorkorder == null)
{
throw new Exception("工单不存在!");
}
// 获取当前工作单缺陷记录
QcBackEndRecordWorkorderDefect workOrderDefect = Context
.Queryable<QcBackEndRecordWorkorderDefect>()
.Where(it => it.WorkOrder == data.WorkOrder && it.DefectCode == data.DefectCode)
.First();
if (data.Type == "1")
{
// Type === 1 短按新增
if (workOrderDefect != null)
{
// 数据库中有记录DefectNum + 1
workOrderDefect.DefectNum += 1;
workOrderDefect.UpdatedTime = data.CreatedTime;
workOrderDefect.UpdatedBy = data.CreatedBy;
Context.Updateable(workOrderDefect).ExecuteCommand();
}
else
{
// 数据库中无记录,新增记录并设置 DefectNum = 1
workOrderDefect = new QcBackEndRecordWorkorderDefect
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = data.WorkOrder,
PartNumber = qcBackEndWorkorder.PartNumber,
Team = qcBackEndWorkorder.Team,
SiteNo = qcBackEndWorkorder.SiteNo,
ComNo = qcBackEndWorkorder.ComNo,
DefectName = defect.Name,
DefectCode = data.DefectCode,
DefectType = defect.Type,
ClickTime = $"{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "1",
Status = "1",
Remark = "",
CreatedBy = data.CreatedBy,
CreatedTime = data.CreatedTime,
DefectNum = 1
};
Context.Insertable(workOrderDefect).ExecuteCommand();
}
}
else if (data.Type == "2")
{
// Type == 2 长按修改
if (workOrderDefect != null)
{
// 数据库中有记录,直接赋值
workOrderDefect.UpdatedTime = data.CreatedTime;
workOrderDefect.UpdatedBy = data.CreatedBy;
workOrderDefect.DefectNum = data.DefectNum; // 假设 data.DefectNum 存在
Context.Updateable(workOrderDefect).ExecuteCommand();
}
else
{
// 数据库中无记录,新增记录
workOrderDefect = new QcBackEndRecordWorkorderDefect
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = data.WorkOrder,
PartNumber = qcBackEndWorkorder.PartNumber,
Team = qcBackEndWorkorder.Team,
SiteNo = qcBackEndWorkorder.SiteNo,
ComNo = qcBackEndWorkorder.ComNo,
DefectName = defect.Name,
DefectCode = data.DefectCode,
DefectType = defect.Type,
ClickTime = $"{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "1",
Status = "1",
Remark = "",
CreatedBy = data.CreatedBy,
CreatedTime = data.CreatedTime,
DefectNum = data.DefectNum // 假设 data.DefectNum 存在
};
Context.Insertable(workOrderDefect).ExecuteCommand();
}
}
UpdateWorkOrderDetail(data.WorkOrder);
// 提交事务
Context.Ado.CommitTran();
return qcBackEndWorkorder;
}
catch (Exception ex)
{
// 回滚事务
Context.Ado.RollbackTran();
throw new Exception("操作失败!", ex);
}
}
public List<QcBackEndRecordWorkorderDefect> GetWorkOrderDefectList(string workorder)
{
return Context
.Queryable<QcBackEndRecordWorkorderDefect>()
.Where(it => it.WorkOrder == workorder)
.ToList();
}
public QcBackEndServiceWorkorder UpdateWorkOrderDetail(string workorder)
{
QcBackEndServiceWorkorder qcBackEndWorkorder = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == workorder)
// .Where(it=>it.Status == "1")
.First();
// 更新工单中的统计数据
qcBackEndWorkorder.QualifiedNumber = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workorder)
.Where(it => it.LabelType == 2)
.Count();
qcBackEndWorkorder.PolishNumber =
Context
.Queryable<QcBackEndRecordWorkorderDefect>()
.Where(it => it.WorkOrder == workorder && it.DefectType == "抛光")
.Sum(it => it.DefectNum) ?? 0;
qcBackEndWorkorder.DamoNumber =
Context
.Queryable<QcBackEndRecordWorkorderDefect>()
.Where(it => it.WorkOrder == workorder && it.DefectType == "打磨")
.Sum(it => it.DefectNum) ?? 0;
qcBackEndWorkorder.BaofeiNumber =
Context
.Queryable<QcBackEndRecordWorkorderDefect>()
.Where(it => it.WorkOrder == workorder && it.DefectType == "报废")
.Sum(it => it.DefectNum) ?? 0;
qcBackEndWorkorder.RequireNumber =
qcBackEndWorkorder.PolishNumber
+ qcBackEndWorkorder.DamoNumber
+ qcBackEndWorkorder.BaofeiNumber
+ (qcBackEndWorkorder.QualifiedNumber ?? 0);
// 更新工单统计信息到数据库
Context
.Updateable(qcBackEndWorkorder)
.UpdateColumns(it => new
{
it.RequireNumber,
it.QualifiedNumber,
it.PolishNumber,
it.DamoNumber,
it.BaofeiNumber
})
.ExecuteCommand();
return qcBackEndWorkorder;
}
// 后道扫描箱标签
public string ScanPackageLabel(QcBackEndLabelScanDto data)
{
try
{
Context.Ado.BeginTran();
DateTime nowTime = DateTime.Now;
// 标签防错 (零件号)
QcBackEndServiceWorkorder workorderInfo = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == data.WorkOrder)
.First();
if (workorderInfo == null)
{
Context.Ado.RollbackTran();
return "工单号不存在!";
}
// 内外标签零件号不一致
string partnumber = DoAnalyzePartnumber(data.Label);
if (!(workorderInfo.PartNumber == partnumber))
{
Context.Ado.RollbackTran();
return "箱标签零件号与工单零件号不一致!";
}
bool hasAny = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.Label == data.Label)
.Where(it => it.LabelType == 1)
.Any();
if (hasAny)
{
Context.Ado.RollbackTran();
return "此外箱标签已扫过,禁止重复扫码!";
}
// 上一个内标签流水号检查
int oldPackageLabelSort = 1;
QcBackEndRecordLabelScan lastPackagelabelInfo = Context
.Queryable<QcBackEndRecordLabelScan>()
// TODO 加锁
.TranLock(DbLockType.Wait)
.Where(it => it.WorkOrder == data.WorkOrder)
.Where(it => it.LabelType == 1)
.OrderByDescending(it => it.LabelSort)
.Take(1)
.First();
if (lastPackagelabelInfo == null)
{
oldPackageLabelSort = 0;
}
else
{
oldPackageLabelSort = lastPackagelabelInfo.LabelSort.Value;
}
// 新箱标签录入
QcBackEndRecordLabelScan newLabelScran =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = data.WorkOrder,
PartNumber = data.PartNumber,
Team = data.Team,
SiteNo = data.SiteNo,
ComNo = data.ComNo,
Label = data.Label,
LabelType = 1,
LabelSort = oldPackageLabelSort + 1,
ScanTime = $"{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "1",
Status = "1",
Remark = "外箱标签",
CreatedBy = data.CreatedBy,
CreatedTime = data.CreatedTime,
};
int res = Context.Insertable(newLabelScran).ExecuteCommand();
if (res == 0)
{
Context.Ado.RollbackTran();
return "箱标签录入系统失败!";
}
Context.Ado.CommitTran();
return "ok";
}
catch (Exception)
{
Context.Ado.RollbackTran();
return "箱标签录入系统失败!";
}
}
// 后道扫内标签
public string ScanInnerLabel(QcBackEndLabelScanDto data)
{
try
{
Context.Ado.BeginTran();
DateTime nowTime = DateTime.Now;
// 标签防错 (零件号)
QcBackEndServiceWorkorder workorderInfo = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == data.WorkOrder)
.First();
if (workorderInfo == null)
{
Context.Ado.RollbackTran();
return "工单号不存在!";
}
// 内外标签零件号不一致
string partnumber = DoAnalyzePartnumber(data.Label);
if (!(workorderInfo.PartNumber == partnumber))
{
Context.Ado.RollbackTran();
return "产品标签零件号与工单零件号不一致!";
}
bool hasAny = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.Label == data.Label)
.Where(it => it.LabelType == 2)
.Any();
if (hasAny)
{
Context.Ado.RollbackTran();
return "此内标签已扫过,禁止重复扫码!";
}
bool hasAny2 = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.Label == data.Label)
.Where(it => it.LabelType == 1)
.Where(it => it.LabelSort > 0)
.Any();
if (hasAny2)
{
Context.Ado.RollbackTran();
return "此外箱标签已扫过,禁止重复扫码!";
}
// 内标签工单确认
QcBackEndServiceWorkorder workorder = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == data.WorkOrder)
.First();
if (workorder == null)
{
Context.Ado.RollbackTran();
return $"工单异常:工单不存在{data.WorkOrder}";
}
// 打印配置确认
QcBackendBaseOutpackage packageLabelConfig = Context
.Queryable<QcBackendBaseOutpackage>()
.Where(it => workorder.Description.Contains(it.CheckStr))
.First();
if (packageLabelConfig == null)
{
Context.Ado.RollbackTran();
return $"该产品内标签,未检测到对应打印参数:{data.PartNumber},{workorder.Description}";
}
// 上一个内标签流水号检查
int oldInnerLabelSort = 0;
QcBackEndRecordLabelScan labelScan = Context
.Queryable<QcBackEndRecordLabelScan>()
// TODO 加锁
.TranLock(DbLockType.Wait)
.Where(it => it.WorkOrder == data.WorkOrder)
.Where(it => it.LabelType == 2)
.OrderByDescending(it => it.LabelSort)
.Take(1)
.First();
if (labelScan != null)
{
oldInnerLabelSort = labelScan.LabelSort ?? 0;
}
// 新内标签流水号
int newInnerLabelSort = oldInnerLabelSort + 1;
// 新标签录入
QcBackEndRecordLabelScan newLabelScran =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = data.WorkOrder,
PartNumber = data.PartNumber,
Team = data.Team,
SiteNo = data.SiteNo,
ComNo = data.ComNo,
Label = data.Label,
LabelType = 2,
LabelSort = newInnerLabelSort,
ScanTime = $"{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "1",
Status = "1",
Remark = "",
CreatedBy = data.CreatedBy,
CreatedTime = data.CreatedTime,
};
int res2 = Context.Insertable(newLabelScran).ExecuteCommand();
if (res2 == 0)
{
Context.Ado.RollbackTran();
return "产标签录入系统失败!";
}
// 检查是否需要打印箱标签
CheckAndPrintPackageLabel(newLabelScran, packageLabelConfig);
Context.Ado.CommitTran();
return "ok";
}
catch (Exception e)
{
Context.Ado.RollbackTran();
return $"异常:{e.Message}";
}
}
// 判断是否满箱并且要出箱标签
public bool CheckPackageIsFullAndNeedScanPackageLabel(string workorder)
{
// 判断是否需要扫箱标签
bool neeedScan = false;
// 工单判断
QcBackEndServiceWorkorder workorderInfo = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == workorder)
.First();
if (workorderInfo == null)
{
throw new Exception($"异常:工单不存在{workorder}");
}
// 打印配置确认
QcBackendBaseOutpackage packageLabelConfig = Context
.Queryable<QcBackendBaseOutpackage>()
.Where(it => workorderInfo.Description.Contains(it.CheckStr))
.First();
if (packageLabelConfig == null)
{
throw new Exception($"异常:零件满箱配置不存在{workorder}");
}
int maxPackageNum = packageLabelConfig.PackageNum ?? 0;
// 内标签总数
int innerLabelCount = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workorder)
.Where(it => it.LabelType == 2)
.Count();
// 箱标签总数
int packageLabelCount = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workorder)
.Where(it => it.LabelType == 1)
.Count();
packageLabelCount -= 1;
if (packageLabelCount < 0)
{
packageLabelCount = 0;
}
// 是否满箱
bool isFull = (innerLabelCount > 0) && (innerLabelCount % maxPackageNum == 0);
// 是否需要扫箱标签
bool needScanPackageLabel = packageLabelCount * maxPackageNum < innerLabelCount;
// TODO额外附加标签
/* Console.WriteLine($"======= CheckPackageIsFullAndNeedScanPackageLabel,maxPackageNum:{maxPackageNum},innerLabelCount:{innerLabelCount},packageLabelCount:{packageLabelCount},isFull:{isFull},needScanPackageLabel:{needScanPackageLabel}");*/
neeedScan = isFull && needScanPackageLabel;
return neeedScan;
}
/// <summary>
/// 判断是否需要自动出满箱标签
/// </summary>
/// <param name="workorder"></param>
public void CheckAndPrintPackageLabel(
QcBackEndRecordLabelScan newLabelScran,
QcBackendBaseOutpackage packageLabelConfig
)
{
DateTime nowTime = DateTime.Now;
// 判断是否需要自动出满箱标签
int checkSort = newLabelScran.LabelSort ?? 0;
int maxPackage = packageLabelConfig.PackageNum ?? 0;
if (checkSort >= maxPackage && checkSort % maxPackage == 0)
{
// TODO额外附加标签
_logger.LogWarning($"=======> 需要打满箱标签{nowTime.ToString()},checkSort:{checkSort},maxPackage:{maxPackage}");
// 需要打外箱标签
SendPrintPackageLabelAsync(newLabelScran, packageLabelConfig.FileUrl, maxPackage)
.Wait();
}
}
/// <summary>
/// 发送打印后道外箱标签的MQTT信息
/// </summary>
/// <exception cref="ArgumentNullException">当输入参数为null时抛出</exception>
/// <exception cref="ArgumentException">当标签内容无效时抛出</exception>
/// <param name="specialPrintType">特殊标签 0-正常 1-补打 2-零头箱</param>
public async Task SendPrintPackageLabelAsync(
QcBackEndRecordLabelScan newLabelScran,
string path,
int maxPackage,
int specialPrintType = 0
)
{
// 参数验证
if (newLabelScran == null)
throw new ArgumentNullException(nameof(newLabelScran), "标签扫描信息不能为空");
if (string.IsNullOrWhiteSpace(newLabelScran.Label))
throw new ArgumentException("标签内容不能为空", nameof(newLabelScran.Label));
if (maxPackage <= 0)
throw new ArgumentException("包装数量必须大于0", nameof(maxPackage));
try
{
string topic = $"shgg_mes/backEnd/print/1站点";
QcBackEndPrintMqttEventDto mqttEventDto = CreateNewQcBackEndPrintMqttEventDto(
newLabelScran,
path,
maxPackage,
specialPrintType
);
var payload = JsonSerializer.Serialize(mqttEventDto);
// 添加打印记录
await AddBackendLabelPrintRecordAsync(mqttEventDto, newLabelScran.WorkOrder, maxPackage, specialPrintType);
// 保持原有PublishAsync调用方式
await _mqttService.PublishAsync(
topic,
payload,
MqttQualityOfServiceLevel.AtLeastOnce,
retain: false
);
_logger.LogInformation($"发送后道外箱标签打印成功:{topic}");
}
catch (JsonException ex)
{
_logger.LogError(ex, "序列化MQTT消息失败");
throw new InvalidOperationException("MQTT消息格式错误", ex);
}
catch (Exception ex)
{
_logger.LogError(ex, $"发送后道外箱标签打印失败:{ex.Message}");
throw;
}
}
/// <summary>
/// 异步添加后道箱标签打印记录
/// <param name="specialPrintType">特殊标签 0-正常 1-补打 2-零头箱</param>
/// </summary>
private async Task AddBackendLabelPrintRecordAsync(
QcBackEndPrintMqttEventDto labelScan,
string workOrder,
int maxPackage,
int specialPrintType = 0
)
{
try
{
string labelCode = labelScan.LabelCode ?? "";
string description = "";
string batchCode = "";
try
{
batchCode = DoAnalyzeBatchCode(labelCode);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "解析批次号失败");
}
// 上一个内标签流水号检查
/* int oldPackageLabelSort = 1;
QcBackendRecordLabelPrint lastPackagelabelInfo = Context
.Queryable<QcBackendRecordLabelPrint>()
.Where(it => it.PartNumber == labelScan.PartNumber)
.Where(it => it.BatchCode.Contains(batchCode))
.Where(it => it.LabelType == 1)
.OrderByDescending(it => it.SerialNumber)
.First();
if (lastPackagelabelInfo == null)
{
oldPackageLabelSort = 1;
}
else
{
oldPackageLabelSort = lastPackagelabelInfo.SerialNumber.Value;
}*/
QcBackendRecordLabelPrint printRecord =
new()
{
Id = SnowFlakeSingle.instance.NextId().ToString(),
MachineCode = labelScan.SiteNo ?? "未知站点",
LabelCode = labelCode,
WorkOrder = workOrder ?? "未知工单",
PartNumber = labelScan.PartNumber ?? "未知零件号",
Description = description,
Team = labelScan.Team ?? "未知班组",
BatchCode = batchCode,
SerialNumber = labelScan.Sort,
PartNum = maxPackage,
LabelType = 1,
BoxMaxNum = maxPackage,
IsFull = specialPrintType == 2 ? 0 : 1,
IsLcl = 0,
CreateBy = "后道标签打印系统",
CreateTime = DateTime.Now
};
// 使用异步数据库操作
await Context.Insertable(printRecord).ExecuteCommandAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "添加打印记录失败");
throw new Exception("保存打印记录失败", ex);
}
}
/// <summary>
/// 生成打印后道外箱标签的mqtt信息
/// </summary>
/// <param name="newLabelScran"></param>
/// <param name="path"></param>
/// <param name="specialPrintType">特殊标签 0-正常 1-补打 2-零头箱</param>
/// <returns></returns>
public QcBackEndPrintMqttEventDto CreateNewQcBackEndPrintMqttEventDto(
QcBackEndRecordLabelScan newLabelScran,
string path,
int maxPackage,
int specialPrintType = 0
)
{
// 解析产品批次号,如果没有,则生成最新批次号
string batchCode = DoAnalyzeBatchCode(newLabelScran.Label);
if (string.IsNullOrEmpty(batchCode))
{
batchCode = DateTime.Now.ToString("yyMMdd") + "000";
}
int packageSort = 1;
// 使用SqlSugar的事务处理
Context.Ado.BeginTran();
try
{
// 查询最新流水号
QcBackendRecordLabelPrint labelPrintRecord = Context
.Queryable<QcBackendRecordLabelPrint>()
.Where(it => it.PartNumber == newLabelScran.PartNumber)
.Where(it => it.BatchCode.Contains(batchCode))
.Where(it => it.LabelType == 1)
.OrderByDescending(it => it.SerialNumber)
.First();
packageSort = labelPrintRecord?.SerialNumber + 1 ?? 1;
Context.Ado.CommitTran();
}
catch (Exception)
{
Context.Ado.RollbackTran();
throw;
}
// 提取产品描述
string checkPartnumber = newLabelScran.PartNumber;
// 使用正则表达式匹配并移除特殊后缀
string processedPartnumber = Regex.Replace(
checkPartnumber,
@"-(FL|FR|RR|RL)$",
"",
RegexOptions.IgnoreCase
);
WmMaterial material = Context
.Queryable<WmMaterial>()
.Where(it => it.Partnumber == processedPartnumber)
.Where(it => it.Type == 1)
.Where(it => it.Status == 1)
.First();
if (material == null)
{
throw new Exception("生成打印后道外箱标签的信息:此零件号不在物料清单内!" + processedPartnumber);
}
// 生成工单号
string workOrder = $"{batchCode}_{packageSort}";
// 是否满箱 0-不满 1-满箱
int isFull = specialPrintType == 2 ? 0 : 1;
// 是否补打 0-非补打 1-补打
int isAgain = specialPrintType == 1 ? 1 : 0;
string newLabelCode =
$"Code=PGW{workOrder}^ItemNumber={newLabelScran.PartNumber}^Order=W{batchCode}^Qty={maxPackage}^LabelType=1^LabelBy=HD^Fu={isFull}^Ag={isAgain}";
string newPackageCode = $"BOX:PGW{workOrder}{newLabelScran.Team}1";
QcBackEndPrintMqttEventDto mqttEventDto =
new()
{
Path = path,
SiteNo = "1站点",
Name = "后道外箱标签打印",
PartNumber = processedPartnumber,
Description = material.Description ?? "",
Color = material.Color ?? "",
Specification = material.Specification ?? "",
WorkOrder = workOrder,
PackageCode = newPackageCode,
Team = newLabelScran.Team,
Sort = packageSort,
ProductionTime = "20" + batchCode.Substring(0, 6),
BatchCode = batchCode,
PackageNum = maxPackage,
LabelCode = newLabelCode,
LabelType = 1,
CreatedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
};
return mqttEventDto;
}
public string EndBackEndWorkOrderAndCreateStatistics(string workorder)
{
try
{
Context.Ado.BeginTran();
DateTime nowTime = DateTime.Now;
// 工单信息修改
QcBackEndServiceWorkorder qcBackEndWorkorder = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == workorder)
.First();
if (qcBackEndWorkorder == null)
{
throw new Exception("工单不存在!");
}
qcBackEndWorkorder.EndTime = nowTime;
qcBackEndWorkorder.Type = "2";
if (!qcBackEndWorkorder.Remark.Contains("已生成过报表"))
{
qcBackEndWorkorder.Remark += "已生成过报表";
}
Context.Updateable(qcBackEndWorkorder).ExecuteCommand();
// 生成报表记录
List<QcBackEndServiceStatistics> addList = new();
string groupCode = SnowFlakeSingle.Instance.NextId().ToString();
addList.Add(CreateNewStatistics(qcBackEndWorkorder, groupCode, 1));
addList.Add(CreateNewStatistics(qcBackEndWorkorder, groupCode, 2));
addList.Add(CreateNewStatistics(qcBackEndWorkorder, groupCode, 3));
Context
.Deleteable<QcBackEndServiceStatistics>()
.Where(it => it.WorkOrder == workorder)
.ExecuteCommand();
Context.Insertable(addList).ExecuteCommand();
QcBackEndLogWorkorder qcBackEndLog =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
Name = "工单结束",
Content = $"工单:{workorder}结束,结束时间{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "200",
Status = "1",
Remark = "触摸屏操作记录",
CreatedBy = "系统",
CreatedTime = nowTime
};
Context.Insertable(qcBackEndLog).ExecuteCommand();
// 提交事务
Context.Ado.CommitTran();
return "ok";
}
catch (Exception ex)
{
// 回滚事务
Context.Ado.RollbackTran();
return ex.Message;
}
}
public QcBackEndServiceStatistics CreateNewStatistics(
QcBackEndServiceWorkorder data,
string groupCode,
int groupSort
)
{
List<QcBackEndRecordWorkorderDefect> defectList = Context
.Queryable<QcBackEndRecordWorkorderDefect>()
.Where(it => it.WorkOrder == data.WorkOrder)
.WhereIF(groupSort == 1, it => it.DefectType == "抛光")
.WhereIF(groupSort == 2, it => it.DefectType == "打磨")
.WhereIF(groupSort == 3, it => it.DefectType == "报废")
.ToList();
string JsonString = JsonSerializer.Serialize(defectList);
// 计算合格率
string qualifiedRate = CalculateQualifiedRate(data);
DateTime nowTime = DateTime.Now;
QcBackEndServiceStatistics workorderStatistics =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = data.WorkOrder,
PartNumber = data.PartNumber,
Specification = data.Specification,
Color = data.Color,
Description = data.Description,
Team = data.Team,
SiteNo = data.SiteNo,
ComNo = data.ComNo,
IsOnetime = data.IsOnetime,
IsPolish = data.IsPolish,
IsBack = data.IsBack,
IsOut = data.IsOut,
StartTime = data.StartTime,
EndTime = data.EndTime,
Label = data.Label,
RequireNumber = data.RequireNumber,
QualifiedNumber = data.QualifiedNumber,
QualifiedRate = qualifiedRate,
PolishNumber = data.PolishNumber,
DamoNumber = data.DamoNumber,
BaofeiNumber = data.BaofeiNumber,
GroupCode = groupCode,
GroupSort = groupSort,
GroupDefectJson = JsonString,
Type = "1",
Status = "1",
Remark = "结束工单系统新增质量报表",
CreatedBy = "后端",
CreatedTime = nowTime,
};
return workorderStatistics;
}
public static string CalculateQualifiedRate(QcBackEndServiceWorkorder data)
{
if (data == null || data.RequireNumber <= 0)
{
return "0%";
}
double qualifiedRate =
(double)data.QualifiedNumber.Value / data.RequireNumber.Value * 100;
return $"{qualifiedRate:F1}%";
}
public QcBackEndServiceWorkorder GenerateVirtualLabel(
QcBackEndWorkorderDetailDto workorderDetail
)
{
try
{
Context.Ado.BeginTran();
// 检查当前工单已扫码合格数
int qualifiedNumber = workorderDetail.QualifiedNumber ?? -1;
if (qualifiedNumber < 0)
{
throw new ArgumentException(
"传入合格数异常!",
nameof(workorderDetail.QualifiedNumber)
);
}
int labelCount = GetLabelCountForWorkOrder(workorderDetail.WorkOrder);
if (labelCount < qualifiedNumber)
{
GenerateVirtualLabels(workorderDetail, qualifiedNumber - labelCount);
}
else if (labelCount > qualifiedNumber)
{
DeleteExcessLabels(workorderDetail.WorkOrder, labelCount - qualifiedNumber);
}
Context.Ado.CommitTran();
return UpdateWorkOrderDetail(workorderDetail.WorkOrder);
}
catch (Exception e)
{
Context.Ado.RollbackTran();
throw new Exception($"生成虚拟标签时出错: {e.Message}", e);
}
}
private int GetLabelCountForWorkOrder(string workOrder)
{
return Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 2)
.Count();
}
private void GenerateVirtualLabels(
QcBackEndWorkorderDetailDto workOrderDetail,
int countToGenerate
)
{
List<QcBackEndRecordLabelScan> virtualLabels = new List<QcBackEndRecordLabelScan>();
int nextLabelNumber = GetNextLabelNumber(workOrderDetail.WorkOrder);
for (int i = 0; i < countToGenerate; i++)
{
string uniqueLabel = GenerateUniqueSequentialLabel(
workOrderDetail.WorkOrder,
nextLabelNumber++
);
virtualLabels.Add(
new QcBackEndRecordLabelScan
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = workOrderDetail.WorkOrder,
PartNumber = workOrderDetail.PartNumber,
Team = workOrderDetail.Team,
SiteNo = workOrderDetail.SiteNo,
ComNo = workOrderDetail.ComNo,
ScanTime = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"),
Type = "2",
Status = "1",
Remark = "虚拟标签",
CreatedTime = DateTime.UtcNow,
CreatedBy = "系统",
LabelType = 2,
LabelSort = nextLabelNumber,
Label = uniqueLabel
}
);
}
Context.Insertable(virtualLabels).ExecuteCommand();
}
private void DeleteExcessLabels(string workOrder, int countToDelete)
{
var labelsToDelete = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 2)
.OrderByDescending(it => it.LabelSort)
.Take(countToDelete)
.ToList();
Context.Deleteable(labelsToDelete).ExecuteCommand();
}
private int GetNextLabelNumber(string workOrder)
{
return Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 2)
.Max(it => it.LabelSort ?? 0);
}
private string GenerateUniqueSequentialLabel(string workOrder, int number)
{
const string prefix = "VIRT";
string baseLabel = $"{prefix}-{GenerateUniqueId()}-{number:D5}";
string uniqueLabel = baseLabel;
while (IsLabelExists(workOrder, uniqueLabel))
{
uniqueLabel = $"{baseLabel}-{GenerateUniqueId()}";
}
return uniqueLabel;
}
private bool IsLabelExists(string workOrder, string label)
{
return Context
.Queryable<QcBackEndRecordLabelScan>()
.Any(it => it.WorkOrder == workOrder && it.LabelType == 2 && it.Label == label);
}
private string GenerateUniqueId()
{
return Guid.NewGuid().ToString("N").Substring(0, 10); // Generate a 10-character unique ID
}
/// <summary>
/// 打印特殊包装标签
/// </summary>
/// <param name="workorderDetail">工单信息</param>
/// <param name="specialPrintType">特殊打印类别 1-补打标签 2-打印零头箱</param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public string PrintSpecialPacakgeLabel(
QcBackEndWorkorderDetailDto workorderDetail,
int specialPrintType = 1,
int packageNum = 0
)
{
try
{
Context.Ado.BeginTran();
DateTime nowTime = DateTime.Now;
// 工单判断
QcBackEndServiceWorkorder workorderInfo = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == workorderDetail.WorkOrder)
.First();
if (workorderInfo == null)
{
Context.Ado.RollbackTran();
return $"异常:工单不存在,工单号:[{workorderDetail.WorkOrder}]";
}
// 打印配置确认
QcBackendBaseOutpackage packageLabelConfig = Context
.Queryable<QcBackendBaseOutpackage>()
.Where(it => workorderInfo.Description.Contains(it.CheckStr))
.First();
if (packageLabelConfig == null)
{
Context.Ado.RollbackTran();
return $"异常:零件满箱配置不存在,工单号[{workorderDetail.WorkOrder}]";
}
string remark = specialPrintType == 1 ? "补打标签" : "零头箱";
// 上一个内标签流水号检查
int oldInnerLabelSort = 0;
QcBackEndRecordLabelScan labelScan = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workorderDetail.WorkOrder)
.Where(it => it.LabelType == 2)
.OrderByDescending(it => it.LabelSort)
.First();
if (labelScan != null)
{
oldInnerLabelSort = labelScan.LabelSort ?? 0;
}
// 新内标签流水号
int newSort = oldInnerLabelSort + 1;
// 新标签生成
QcBackEndRecordLabelScan newLabelScran =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = workorderInfo.WorkOrder,
PartNumber = workorderInfo.PartNumber,
Team = workorderInfo.Team,
SiteNo = workorderInfo.SiteNo,
ComNo = workorderInfo.ComNo,
Label = workorderInfo.Label,
LabelType = 1,
LabelSort = newSort,
ScanTime = $"{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "1",
Status = "1",
Remark = remark,
CreatedBy = "特殊标签",
CreatedTime = nowTime,
};
int _pacakgeNum = packageLabelConfig.PackageNum.Value;
// 1.补打标签
if (specialPrintType == 1)
{
SendPrintPackageLabelAsync(
newLabelScran,
packageLabelConfig.FileUrl,
_pacakgeNum,
specialPrintType
)
.Wait();
}
// 2.打印零头箱
if (specialPrintType == 2)
{
_pacakgeNum = packageNum;
SendPrintPackageLabelAsync(
newLabelScran,
packageLabelConfig.FileUrl,
_pacakgeNum,
specialPrintType
)
.Wait();
//Context.Insertable(newLabelScran).ExecuteCommand();
}
Context.Ado.CommitTran();
return "ok";
}
catch (Exception ex)
{
Context.Ado.RollbackTran();
return $"系统异常{ex.Message}";
}
}
public QcBackEndWorkorderPrintLabelDetailDto SearchWorkOrderLabelDetail(string workOrder)
{
// 首先检查工单是否存在
var workorderInfo = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == workOrder)
.First();
if (workorderInfo == null)
{
throw new Exception($"异常:工单不存在{workOrder}");
}
// 检查打印配置
var packageLabelConfig = Context
.Queryable<QcBackendBaseOutpackage>()
.Where(it => workorderInfo.Description.Contains(it.CheckStr))
.First();
if (packageLabelConfig == null)
{
throw new Exception($"异常:零件满箱配置不存在{workOrder}");
}
// 验证配置有效性
int maxPackageNum = packageLabelConfig.PackageNum ?? 0;
if (maxPackageNum <= 0)
{
throw new ArgumentException($"无效的满箱数量:{maxPackageNum}", nameof(maxPackageNum));
}
QcBackEndWorkorderPrintLabelDetailDto result = new QcBackEndWorkorderPrintLabelDetailDto();
// 扫描零件计数LabelType=2合并查询条件
result.ScannedPartCount = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 2)
.Count();
// 扫描箱标签计数LabelType=1且LabelSort>0合并查询条件
result.ScannedBoxLabelCount = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 1 && it.LabelSort > 0)
.Count();
// 重新打印计数LabelType=1且LabelCode包含IsAgain(Ag)=1合并查询条件
result.RePrintCount = Context
.Queryable<QcBackendRecordLabelPrint>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 1 && it.LabelCode.Contains("Ag=1"))
.Count();
// 零头箱打印计数LabelType=1且未装满合并查询条件
result.RemainderBoxPrintCount = Context
.Queryable<QcBackendRecordLabelPrint>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 1 && it.IsFull == 0)
.Count();
// 当前箱标签最大序列号,合并查询条件并增加空值处理
result.CurrentBoxLabelSequence = Context
.Queryable<QcBackendRecordLabelPrint>()
.Where(it => it.WorkOrder == workOrder && it.LabelType == 1)
.Max(it => (int?)it.SerialNumber) ?? 0;
// 零头箱计算
result.PackageNum = result.ScannedPartCount > 0
? result.ScannedPartCount % maxPackageNum
: 0;
return result;
}
}
}