using System; using System.Globalization; using System.Linq; using System.Text.Json; using System.Text.RegularExpressions; using System.Transactions; using Aliyun.OSS; using AutoMapper; using Infrastructure.Attribute; using Infrastructure.Extensions; using JinianNet.JNTemplate; using Microsoft.AspNetCore.Http.HttpResults; using SqlSugar; 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 { /// /// 质量GP12工单业务模块Service业务层处理 /// [AppService(ServiceType = typeof(IQcGp12Service), ServiceLifetime = LifeTime.Transient)] public class QcGp12Service : BaseService, IQcGp12Service { public QcGp12LabelAnalysisDto AnalyzeLabelToDto(string label, int type) { QcGp12LabelAnalysisDto 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() .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() .And(it => it.Code == "PartNumber") .And(it => it.Status == "1"); List analysisList = Context .Queryable() .Where(predicate.ToExpression()) .ToList(); foreach (QcGp12BaseLabelAnalysis 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 int DoAnalyzeQuantity(string label) { int result = 0; // 标签零件号抓取 var predicate = Expressionable .Create() .And(it => it.Code == "Quantity") .And(it => it.Status == "1"); List analysisList = Context .Queryable() .Where(predicate.ToExpression()) .ToList(); foreach (QcGp12BaseLabelAnalysis 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 GetDefectInitOptions() { List defectList = new(); var predicate = Expressionable.Create().And(it => it.Status == "1"); List groupList = Context .Queryable() .Where(predicate.ToExpression()) .GroupBy(it => it.Group) .Select(it => it.Group) .ToList(); foreach (string group in groupList) { QcGp12AlterationDefectDto defectDto = new(); defectDto.GroupName = group; List children = Context .Queryable() .Where(it => it.Group == group) .Where(predicate.ToExpression()) .Select(it => new QcGp12ChildrenDefectDto { Name = it.Name, Code = it.Code, Type = it.Type, Num = 0 }) .ToList(); defectDto.Children = children; defectList.Add(defectDto); } return defectList; } public List GetDefectTableOptions() { List defectList = new(); var predicate = Expressionable .Create() .And(it => it.Type == "打磨") .And(it => it.Status == "1"); List groupList = Context .Queryable() .Where(predicate.ToExpression()) .GroupBy(it => it.Group) .Select(it => it.Group) .ToList(); foreach (string group in groupList) { QcGp12AlterationDefectDto defectDto = new(); defectDto.GroupName = group; List children = Context .Queryable() .Where(it => it.Group == group) .Where(predicate.ToExpression()) .Select(it => new QcGp12ChildrenDefectDto { 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 GetGroupOptions() { var predicate = Expressionable.Create().And(it => it.Status == "1"); var response = Context .Queryable() .Where(predicate.ToExpression()) .Select(it => new QcGp12BaseGroupDto()) .ToList(); return response; } public List GetStieOptions() { var predicate = Expressionable.Create().And(it => it.Status == "1"); var response = Context .Queryable() .Where(predicate.ToExpression()) .Select(it => new QcGp12BaseSiteDto()) .ToList(); return response; } public QcGp12ServiceWorkorder StartGP12WorkOrder(QcGp12WorkorderDetailDto data) { // 检查是否是已扫过的外箱标签 QcGp12ServiceWorkorder oldWorkOrder = Context .Queryable() .Where(it => it.Label == data.Label) .First(); if (oldWorkOrder != null) { return oldWorkOrder; } // 没有旧记录则开启新的记录 try { // 检查箱标签是否当内标签扫过 bool isInnerLabelScan = Context .Queryable() .Where(it => it.Label == data.Label) .Where(it => it.LabelType == 2) .Any(); if (isInnerLabelScan) { throw new Exception("标签异常,该标签已经当内标签扫过!"); } Context.Ado.BeginTran(); DateTime nowTime = DateTime.Now; // 创建新工单号 QcGp12WorkorderDetailDto workorderInfo = GetNewWorkOrderCreate(data); // 赋值 data.WorkOrder = workorderInfo.WorkOrder; data.SerialNumber = workorderInfo.SerialNumber; data.StartTime = nowTime; QcGp12ServiceWorkorder newModel = GetNewWorkOrderInfo(data); QcGp12ServiceWorkorder result = Context.Insertable(newModel).ExecuteReturnEntity(); if (result == null) { Context.Ado.RollbackTran(); throw new Exception("插入新工单异常"); } // 工单开始记录 QcGp12RecordLabelScan 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("插入标签记录异常"); } QcGp12LogWorkorder qcGp12Log = 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(qcGp12Log).ExecuteCommand(); Context.Ado.CommitTran(); return result; } catch (Exception ex) { Context.Ado.RollbackTran(); throw new Exception(ex.Message); } } // 创建新工单号 public QcGp12WorkorderDetailDto GetNewWorkOrderCreate(QcGp12WorkorderDetailDto data) { QcGp12WorkorderDetailDto result = new(); string newWorkOrder = ""; DateTime today = DateTime.Today; // 检查是否是已扫过的外箱标签 QcGp12ServiceWorkorder lastWorkOrder = Context .Queryable() .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 QcGp12ServiceWorkorder GetNewWorkOrderInfo(QcGp12WorkorderDetailDto data) { // 新工单 QcGp12ServiceWorkorder 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 QcGp12ServiceWorkorder ChangeWorkOrderDefect(QcGp12WorkorderDefectDto data) { try { Context.Ado.BeginTran(); DateTime nowTime = DateTime.Now; // 获取缺陷信息 QcGp12BaseDefect defect = Context .Queryable() .Where(it => it.Code == data.DefectCode && it.Status == "1") .First(); if (defect == null) { throw new Exception("缺陷项不在缺陷清单中!"); } // 工单信息修改 QcGp12ServiceWorkorder qcGp12Workorder = Context .Queryable() .Where(it => it.WorkOrder == data.WorkOrder) .First(); if (qcGp12Workorder == null) { throw new Exception("工单不存在!"); } // 获取当前工作单缺陷记录 QcGp12RecordWorkorderDefect workOrderDefect = Context .Queryable() .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 QcGp12RecordWorkorderDefect { Id = SnowFlakeSingle.Instance.NextId().ToString(), WorkOrder = data.WorkOrder, PartNumber = qcGp12Workorder.PartNumber, Team = qcGp12Workorder.Team, SiteNo = qcGp12Workorder.SiteNo, ComNo = qcGp12Workorder.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 QcGp12RecordWorkorderDefect { Id = SnowFlakeSingle.Instance.NextId().ToString(), WorkOrder = data.WorkOrder, PartNumber = qcGp12Workorder.PartNumber, Team = qcGp12Workorder.Team, SiteNo = qcGp12Workorder.SiteNo, ComNo = qcGp12Workorder.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 qcGp12Workorder; } catch (Exception ex) { // 回滚事务 Context.Ado.RollbackTran(); throw new Exception("操作失败!", ex); } } public List GetWorkOrderDefectList(string workorder) { return Context .Queryable() .Where(it => it.WorkOrder == workorder) .ToList(); } public QcGp12ServiceWorkorder UpdateWorkOrderDetail(string workorder) { QcGp12ServiceWorkorder qcGp12Workorder = Context .Queryable() .Where(it => it.WorkOrder == workorder) // .Where(it=>it.Status == "1") .First(); // 更新工单中的统计数据 qcGp12Workorder.QualifiedNumber = Context .Queryable() .Where(it => it.WorkOrder == workorder) .Where(it => it.LabelType == 2) .Count(); qcGp12Workorder.PolishNumber = Context .Queryable() .Where(it => it.WorkOrder == workorder && it.DefectType == "抛光") .Sum(it => it.DefectNum) ?? 0; qcGp12Workorder.DamoNumber = Context .Queryable() .Where(it => it.WorkOrder == workorder && it.DefectType == "打磨") .Sum(it => it.DefectNum) ?? 0; qcGp12Workorder.BaofeiNumber = Context .Queryable() .Where(it => it.WorkOrder == workorder && it.DefectType == "报废") .Sum(it => it.DefectNum) ?? 0; qcGp12Workorder.RequireNumber = qcGp12Workorder.PolishNumber + qcGp12Workorder.DamoNumber + qcGp12Workorder.BaofeiNumber + (qcGp12Workorder.QualifiedNumber ?? 0); // 更新工单统计信息到数据库 Context .Updateable(qcGp12Workorder) .UpdateColumns(it => new { it.RequireNumber, it.QualifiedNumber, it.PolishNumber, it.DamoNumber, it.BaofeiNumber }) .ExecuteCommand(); return qcGp12Workorder; } public string ScanInnerLabel(QcGp12LabelScanDto data) { DateTime nowTime = DateTime.Now; // 标签防错 (内标签零件号) string partNumber = DoAnalyzePartnumber(data.Label); // 内标签包含外标签 if (!partNumber.Contains(data.PartNumber)) { return "内标签零件号与外箱标签不一致!"; } bool hasAny = Context .Queryable() .Where(it => it.Label == data.Label) .Any(); if (hasAny) { return "重复扫码!"; } // 标签录入 int sort = 0; QcGp12RecordLabelScan labelScan = Context .Queryable() .Where(it => it.WorkOrder == data.WorkOrder) .Where(it => it.LabelType == 2) .OrderByDescending(it => it.LabelSort) .First(); if (labelScan != null) { sort = labelScan.LabelSort ?? 0; } QcGp12RecordLabelScan 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) { return "标签录入系统失败!"; } return "ok"; } public string EndGP12WorkOrderAndCreateStatistics(string workorder) { try { Context.Ado.BeginTran(); DateTime nowTime = DateTime.Now; // 工单信息修改 QcGp12ServiceWorkorder qcGp12Workorder = Context .Queryable() .Where(it => it.WorkOrder == workorder) .First(); if (qcGp12Workorder == null) { throw new Exception("工单不存在!"); } qcGp12Workorder.EndTime = nowTime; qcGp12Workorder.Type = "2"; qcGp12Workorder.Remark += "已生成过报表"; Context.Updateable(qcGp12Workorder).ExecuteCommand(); // 生成报表记录 List addList = new(); string groupCode = SnowFlakeSingle.Instance.NextId().ToString(); addList.Add(CreateNewStatistics(qcGp12Workorder, groupCode, 1)); addList.Add(CreateNewStatistics(qcGp12Workorder, groupCode, 2)); addList.Add(CreateNewStatistics(qcGp12Workorder, groupCode, 3)); Context .Deleteable() .Where(it => it.WorkOrder == workorder) .ExecuteCommand(); Context.Insertable(addList).ExecuteCommand(); QcGp12LogWorkorder qcGp12Log = 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(qcGp12Log).ExecuteCommand(); // 提交事务 Context.Ado.CommitTran(); return "ok"; } catch (Exception ex) { // 回滚事务 Context.Ado.RollbackTran(); return ex.Message; } } public QcGp12ServiceStatistics CreateNewStatistics( QcGp12ServiceWorkorder data, string groupCode, int groupSort ) { List defectList = Context .Queryable() .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; QcGp12ServiceStatistics 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(QcGp12ServiceWorkorder data) { if (data == null || data.RequireNumber <= 0) { return "0%"; } double qualifiedRate = (double)data.QualifiedNumber.Value / data.RequireNumber.Value * 100; return $"{qualifiedRate:F1}%"; } public QcGp12ServiceWorkorder GenerateVirtualLabel(QcGp12WorkorderDetailDto 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() .Where(it => it.WorkOrder == workOrder && it.LabelType == 2) .Count(); } private void GenerateVirtualLabels(QcGp12WorkorderDetailDto workOrderDetail, int countToGenerate) { List virtualLabels = new List(); int nextLabelNumber = GetNextLabelNumber(workOrderDetail.WorkOrder); for (int i = 0; i < countToGenerate; i++) { string uniqueLabel = GenerateUniqueSequentialLabel(workOrderDetail.WorkOrder, nextLabelNumber++); virtualLabels.Add(new QcGp12RecordLabelScan { 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() .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() .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() .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 } } }