shgx_tz_mom/ZR.Service/mes/qc/backend/QcBackEndService.cs
2025-05-15 09:11:32 +08:00

1084 lines
43 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 System;
using System.Globalization;
using System.Linq;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Transactions;
using Aliyun.OSS;
using AutoMapper;
using Infrastructure.Attribute;
using Infrastructure.Extensions;
using JinianNet.JNTemplate;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.Extensions.Logging;
using MQTTnet.Protocol;
using SqlSugar;
using ZR.Common.MqttHelper;
using ZR.Model;
using ZR.Model.Business;
using ZR.Model.Dto;
using ZR.Model.MES.wms;
using ZR.Repository;
using ZR.Service.Business.IBusinessService;
using static System.Runtime.InteropServices.JavaScript.JSType;
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)
{
WmMaterial material = Context
.Queryable<WmMaterial>()
.Where(it => it.Partnumber == labelAnalysisDto.Partnumber)
.Where(it => it.Type == 1)
.Where(it => it.Status == 1)
.First();
if (material == null)
{
labelAnalysisDto.IsOk = false;
labelAnalysisDto.Msg = "物料清单内无此零件号!请检查物料清单:" + labelAnalysisDto.Partnumber;
}
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 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 = 1,
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 ScanInnerLabel(QcBackEndLabelScanDto data)
{
try
{
Context.Ado.BeginTran();
DateTime nowTime = DateTime.Now;
// 标签防错 (内标签零件号)
string partNumber = DoAnalyzePartnumber(data.Label);
// 内标签包含外标签
if (!partNumber.Contains(data.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 "内标签重复扫码!";
}
// 标签录入
int sort = 0;
QcBackEndRecordLabelScan labelScan = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == data.WorkOrder)
.Where(it => it.LabelType == 2)
.OrderByDescending(it => it.LabelSort)
.First();
if (labelScan != null)
{
sort = labelScan.LabelSort ?? 0;
}
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 = sort + 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 "标签录入系统失败!";
}
//TODO 触发箱标签判定
CheckAndPrintPackageLabel(newLabelScran);
Context.Ado.CommitTran();
return "ok";
}
catch (Exception e)
{
Context.Ado.RollbackTran();
return $"异常:{e.Message}";
}
}
/// <summary>
/// 判断是否需要自动出满箱标签
/// </summary>
/// <param name="workorder"></param>
public void CheckAndPrintPackageLabel(QcBackEndRecordLabelScan newLabelScran)
{
DateTime nowTime = DateTime.Now;
// 找到最大箱容量与模板
QcBackEndServiceWorkorder workorder = Context
.Queryable<QcBackEndServiceWorkorder>()
.Where(it => it.WorkOrder == newLabelScran.WorkOrder)
.First();
QcBackendBaseOutpackage packageLabelConfig = Context
.Queryable<QcBackendBaseOutpackage>()
.Where(it => workorder.Description.Contains(it.CheckStr))
.First();
if (workorder == null)
{
throw new Exception("工单异常");
}
if (packageLabelConfig == null)
{
throw new Exception("该标签打印参数未配置");
}
int checkSort = newLabelScran.LabelSort ?? 0;
int maxPackage = packageLabelConfig.PackageNum ?? 0;
if (checkSort >= maxPackage && checkSort % maxPackage == 0)
{
int packageSort = 0;
QcBackEndRecordLabelScan packagelabelScan = Context
.Queryable<QcBackEndRecordLabelScan>()
.Where(it => it.WorkOrder == newLabelScran.WorkOrder)
.Where(it => it.LabelType == 1)
.OrderByDescending(it => it.LabelSort)
.First();
if (packagelabelScan != null)
{
packageSort = packagelabelScan.LabelSort ?? 0;
}
QcBackEndRecordLabelScan newPackagePrintLabel =
new()
{
Id = SnowFlakeSingle.Instance.NextId().ToString(),
WorkOrder = newLabelScran.WorkOrder,
PartNumber = newLabelScran.PartNumber,
Team = newLabelScran.Team,
SiteNo = newLabelScran.SiteNo,
ComNo = newLabelScran.ComNo,
Label =
$"Code=BN{newLabelScran.WorkOrder}_{newLabelScran.Team}{packageSort + 1}^ItemNumber={newLabelScran.PartNumber}^Order={newLabelScran.WorkOrder}^Qty={maxPackage}^Type=packageLabel",
LabelType = 1,
LabelSort = packageSort + 1,
ScanTime = $"{nowTime:yyyy-MM-dd HH:mm:ss}",
Type = "1",
Status = "1",
Remark = "自动出满箱标签",
CreatedBy = newLabelScran.CreatedBy,
CreatedTime = newLabelScran.CreatedTime,
};
int res = Context.Insertable(newPackagePrintLabel).ExecuteCommand();
if (res > 0)
{
SendPrintPackageLabelAsync(newLabelScran, packageLabelConfig.FileUrl).Wait();
}
}
}
/// <summary>
/// 发送打印后道外箱标签的mqtt信息
/// </summary>
public async Task SendPrintPackageLabelAsync(
QcBackEndRecordLabelScan newLabelScran,
string path
)
{
try
{
// 构造主题和消息内容
string topic = $"shgg_mes/backEnd/print/{newLabelScran.SiteNo}";
QcBackEndPrintMqttEventDto mqttEventDto =
new()
{
Path = path,
SiteNo = newLabelScran.SiteNo,
Name = newLabelScran.PartNumber,
WorkOrder = newLabelScran.WorkOrder,
Team = newLabelScran.Team,
Sort = (newLabelScran.LabelSort + 1) ?? 1,
BatchCode = DateTime.Now.ToString("yyyyMMdd"),
PackageNum = 24,
LabelType = newLabelScran.LabelType ?? 1,
CreatedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
};
var payload = JsonSerializer.Serialize(mqttEventDto);
// 调用MqttService的发布方法支持异步调用
await _mqttService.PublishAsync(
topic,
payload,
MqttQualityOfServiceLevel.ExactlyOnce,
// 可选:设置消息保留
retain: false
);
_logger.LogInformation($"发送后道外箱标签打印成功:{topic}");
}
catch (Exception ex)
{
_logger.LogError(ex, $"发送后道外箱标签打印失败:{ex.Message}");
throw; // 或根据业务需求处理异常
}
}
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
}
}
}