Merge branch 'main' of http://118.25.48.201:3000/RIZO/shgx_tz_mom
This commit is contained in:
commit
28a23e6493
1
.gitignore
vendored
1
.gitignore
vendored
@ -264,3 +264,4 @@ __pycache__/
|
||||
/ZR.Admin.WebApi/wwwroot/2025/1213
|
||||
/.gitignore
|
||||
/ZR.Admin.WebApi/wwwroot/Generatecode
|
||||
/.trae
|
||||
|
||||
35
.vscode/launch.json
vendored
Normal file
35
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
// 使用 IntelliSense 找出 C# 调试存在哪些属性
|
||||
// 将悬停用于现有属性的说明
|
||||
// 有关详细信息,请访问 https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md。
|
||||
"name": ".NET Core Launch (web)",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"preLaunchTask": "build",
|
||||
// 如果已更改目标框架,请确保更新程序路径。
|
||||
"program": "${workspaceFolder}/ZR.Admin.WebApi/bin/Debug/net7.0/ZR.Admin.WebApi.dll",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}/ZR.Admin.WebApi",
|
||||
"stopAtEntry": false,
|
||||
// 启用在启动 ASP.NET Core 时启动 Web 浏览器。有关详细信息: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
|
||||
"serverReadyAction": {
|
||||
"action": "openExternally",
|
||||
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
|
||||
},
|
||||
"env": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/Views": "${workspaceFolder}/Views"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": ".NET Core Attach",
|
||||
"type": "coreclr",
|
||||
"request": "attach"
|
||||
}
|
||||
]
|
||||
}
|
||||
41
.vscode/tasks.json
vendored
Normal file
41
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "build",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/ZR.Admin.WebApi/ZR.Admin.WebApi.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "publish",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"publish",
|
||||
"${workspaceFolder}/ZR.Admin.WebApi/ZR.Admin.WebApi.csproj",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "watch",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"watch",
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/ZR.Admin.WebApi/ZR.Admin.WebApi.csproj"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<key id="168e1cde-e622-4ff7-a1b4-6130c0cf779b" version="1">
|
||||
<creationDate>2026-02-12T05:40:06.6830819Z</creationDate>
|
||||
<activationDate>2026-02-12T05:40:06.655139Z</activationDate>
|
||||
<expirationDate>2026-05-13T05:40:06.655139Z</expirationDate>
|
||||
<descriptor deserializerType="Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.ConfigurationModel.AuthenticatedEncryptorDescriptorDeserializer, Microsoft.AspNetCore.DataProtection, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60">
|
||||
<descriptor>
|
||||
<encryption algorithm="AES_256_CBC" />
|
||||
<validation algorithm="HMACSHA256" />
|
||||
<masterKey p4:requiresEncryption="true" xmlns:p4="http://schemas.asp.net/2015/03/dataProtection">
|
||||
<!-- Warning: the key below is in an unencrypted form. -->
|
||||
<value>NCpSClOTA2Ukw8w2WJ8oXpw0xP6UPgALGnpWUcujYVjZht+UGKueBJnWKhzmFvUoX4WQiS0J8ie/rbUPGhGXIA==</value>
|
||||
</masterKey>
|
||||
</descriptor>
|
||||
</descriptor>
|
||||
</key>
|
||||
@ -42,6 +42,9 @@ builder.Services.AddSingleton<MyMqttConfig>();
|
||||
builder.Services.AddSingleton<MqttService>();
|
||||
builder.Services.AddHostedService(sp => sp.GetRequiredService<MqttService>());
|
||||
/// ===============================================================================
|
||||
|
||||
// 注册TCP服务器服务
|
||||
builder.Services.AddHostedService<ZR.Service.tcp.TcpServerService>();
|
||||
// 跨域配置
|
||||
builder.Services.AddCors(builder.Configuration);
|
||||
// 显示logo
|
||||
|
||||
@ -5,7 +5,7 @@ namespace ZR.Model.MES.wms.Dto
|
||||
/// <summary>
|
||||
/// 查询对象
|
||||
/// </summary>
|
||||
public class WmMaterialPackageQueryDto : PagerInfo
|
||||
public class WmMaterialPackageQueryDto : PagerInfo
|
||||
{
|
||||
}
|
||||
|
||||
@ -33,6 +33,10 @@ namespace ZR.Model.MES.wms.Dto
|
||||
|
||||
public int? PackageProductionPolishPalletNum { get; set; }
|
||||
|
||||
public int? PackageGP12PolishPalletNum { get; set; }
|
||||
|
||||
public int? PackageBackendPolishPalletNum { get; set; }
|
||||
|
||||
public DateTime? CreateTime { get; set; }
|
||||
|
||||
public string CreateBy { get; set; }
|
||||
|
||||
@ -58,6 +58,18 @@ namespace ZR.Model.MES.wms
|
||||
[SugarColumn(ColumnName = "package_production_polish_pallet_num")]
|
||||
public int? PackageProductionPolishPalletNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 产线包装抛光品托盘产品数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "pacakge_gp12_polish_pallet_num")]
|
||||
public int? PackageGP12PolishPalletNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 产线包装抛光品托盘产品数
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnName = "package_backend_polish_pallet_num")]
|
||||
public int? PackageBackendPolishPalletNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
|
||||
@ -18,7 +18,6 @@ namespace ZR.Service.Business
|
||||
[AppService(ServiceType = typeof(IProFinishedProductReceiptService), ServiceLifetime = LifeTime.Transient)]
|
||||
public class ProFinishedProductReceiptService : BaseService<ProFinishedProductReceipt>, IProFinishedProductReceiptService
|
||||
{
|
||||
private readonly IProFinishedProductReceiptLogService _receiptLogService;
|
||||
|
||||
/// <summary>
|
||||
/// 查询MES成品入库单主表(含产品信息及标签打印状态)列表
|
||||
@ -61,7 +60,7 @@ namespace ZR.Service.Business
|
||||
/// <returns></returns>
|
||||
public ProFinishedProductReceipt AddProFinishedProductReceipt(ProFinishedProductReceipt model)
|
||||
{
|
||||
|
||||
ProFinishedProductReceiptLogService _receiptLogService = new ();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Infrastructure.Attribute;
|
||||
@ -36,7 +38,6 @@ namespace ZR.Service.mes.qc
|
||||
/// </summary>
|
||||
/// <param name="workorderID"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public CheckItemTableDTO GetCheckItemTable_first(string workorderID)
|
||||
{
|
||||
CheckItemTableDTO checkItem = new CheckItemTableDTO();
|
||||
@ -157,7 +158,6 @@ namespace ZR.Service.mes.qc
|
||||
/// <param name="time">首检结束时间</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
|
||||
public int WriteProcessFlow_first(string workorderID, DateTime time)
|
||||
{
|
||||
ProWorkordertimeStep step = new ProWorkordertimeStep();
|
||||
@ -177,7 +177,6 @@ namespace ZR.Service.mes.qc
|
||||
/// </summary>
|
||||
/// <param name="workorderID"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public CheckItemTableDTO GetCheckItemTable_again(string workorderID)
|
||||
{
|
||||
CheckItemTableDTO checkItem = new CheckItemTableDTO();
|
||||
@ -296,7 +295,6 @@ namespace ZR.Service.mes.qc
|
||||
/// </summary>
|
||||
/// <param name="workorderID"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
public CheckItemTableDTO GetCheckItemTable_thirty(string workorderID)
|
||||
{
|
||||
CheckItemTableDTO checkItem = new CheckItemTableDTO();
|
||||
@ -439,7 +437,7 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
it.FKInpectionId,
|
||||
it.FKWorkorderId,
|
||||
it.InspectionModule
|
||||
it.InspectionModule,
|
||||
})
|
||||
.ToStorage();
|
||||
|
||||
@ -456,8 +454,6 @@ namespace ZR.Service.mes.qc
|
||||
// scrap.ProductName = "";
|
||||
// scrap.Number= 1;
|
||||
|
||||
|
||||
|
||||
//}
|
||||
|
||||
////更新初检xiazi表
|
||||
@ -496,7 +492,7 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
it.FkInpectionId,
|
||||
it.FkWorkorderId,
|
||||
it.InspectionModule
|
||||
it.InspectionModule,
|
||||
})
|
||||
.ToStorage();
|
||||
|
||||
@ -513,8 +509,6 @@ namespace ZR.Service.mes.qc
|
||||
// scrap.ProductName = "";
|
||||
// scrap.Number= 1;
|
||||
|
||||
|
||||
|
||||
//}
|
||||
|
||||
////更新初检xiazi表
|
||||
@ -553,7 +547,7 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
it.FkInpectionId,
|
||||
it.FkWorkorderId,
|
||||
it.InspectionModule
|
||||
it.InspectionModule,
|
||||
})
|
||||
.ToStorage();
|
||||
|
||||
@ -562,7 +556,7 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
it.UpdatedBy,
|
||||
it.UpdatedTime,
|
||||
it.Counter
|
||||
it.Counter,
|
||||
})
|
||||
.ExecuteCommandAsync(); //执行更新
|
||||
|
||||
@ -576,8 +570,6 @@ namespace ZR.Service.mes.qc
|
||||
// scrap.ProductName = "";
|
||||
// scrap.Number= 1;
|
||||
|
||||
|
||||
|
||||
//}
|
||||
|
||||
////更新初检xiazi表
|
||||
@ -614,7 +606,6 @@ namespace ZR.Service.mes.qc
|
||||
|
||||
//TODO 1. 处理首检
|
||||
|
||||
|
||||
//1.1 首检合格数=投入数-抛光数-打磨数-报废数
|
||||
List<QcFirstinspectionRecord> qcFirstinspections = Context
|
||||
.Queryable<QcFirstinspectionRecord>()
|
||||
@ -776,7 +767,6 @@ namespace ZR.Service.mes.qc
|
||||
/// <param name="num1"></param>
|
||||
/// <param name="num2"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
static double CalculatePercentage(int num1, int num2)
|
||||
{
|
||||
double percentage = ((double)num1 / num2) * 100;
|
||||
@ -818,7 +808,7 @@ namespace ZR.Service.mes.qc
|
||||
FirstPassRate = 0.0,
|
||||
PolisheNumber = 0,
|
||||
ScrapNumber = 0,
|
||||
DefectNumber = 0
|
||||
DefectNumber = 0,
|
||||
}
|
||||
);
|
||||
;
|
||||
@ -900,14 +890,79 @@ namespace ZR.Service.mes.qc
|
||||
else if (Now_producting_Workorder_thirty == null)
|
||||
{
|
||||
Now_producting_Workorder_thirty = Now_producting_WorkorderList[0];
|
||||
// 发送TCP消息
|
||||
if (
|
||||
Now_producting_Workorder_thirty != null
|
||||
&& !string.IsNullOrEmpty(Now_producting_Workorder_thirty.FinishedPartNumber)
|
||||
)
|
||||
{
|
||||
string message =
|
||||
$"shgx/cx/gz/{Now_producting_Workorder_thirty.FinishedPartNumber}";
|
||||
_ = SendTcpMessageAsync(message);
|
||||
}
|
||||
return Now_producting_Workorder_thirty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 发送TCP消息
|
||||
if (!string.IsNullOrEmpty(Now_producting_Workorder_thirty.FinishedPartNumber))
|
||||
{
|
||||
string message =
|
||||
$"shgx/cx/gz/{Now_producting_Workorder_thirty.FinishedPartNumber}";
|
||||
_ = SendTcpMessageAsync(message);
|
||||
}
|
||||
return Now_producting_Workorder_thirty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送TCP消息到TCP服务器
|
||||
/// </summary>
|
||||
/// <param name="message">要发送的消息</param>
|
||||
private async Task SendTcpMessageAsync(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TCP服务器地址和端口
|
||||
string serverAddress = "127.0.0.1";
|
||||
int serverPort = 9090;
|
||||
|
||||
// 创建TCP客户端
|
||||
using (TcpClient client = new TcpClient())
|
||||
{
|
||||
// 连接到服务器
|
||||
await client.ConnectAsync(serverAddress, serverPort);
|
||||
_logger.LogInformation($"成功连接到TCP服务器: {serverAddress}:{serverPort}");
|
||||
|
||||
// 获取网络流
|
||||
using (NetworkStream stream = client.GetStream())
|
||||
{
|
||||
// 将消息转换为字节数组
|
||||
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
|
||||
|
||||
// 发送消息
|
||||
await stream.WriteAsync(messageBytes, 0, messageBytes.Length);
|
||||
_logger.LogInformation($"已发送TCP消息: {message}");
|
||||
|
||||
// 等待服务器响应(可选)
|
||||
byte[] responseBuffer = new byte[4096];
|
||||
int bytesRead = await stream.ReadAsync(
|
||||
responseBuffer,
|
||||
0,
|
||||
responseBuffer.Length
|
||||
);
|
||||
string response = Encoding.UTF8.GetString(responseBuffer, 0, bytesRead);
|
||||
_logger.LogInformation($"收到TCP服务器响应: {response}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "发送TCP消息时发生错误");
|
||||
Console.WriteLine($"[FirstFQCService] 发送TCP消息时发生错误: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取下一个生产工单 一检
|
||||
/// </summary>
|
||||
@ -945,7 +1000,6 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
// 已经是最后一个了没有
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
@ -993,7 +1047,6 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
// 已经是最后一个了没有
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
@ -1035,18 +1088,36 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
// 逻辑异常
|
||||
Now_producting_Workorder_thirty = Now_producting_WorkorderList[0];
|
||||
// 发送TCP消息
|
||||
if (
|
||||
Now_producting_Workorder_thirty != null
|
||||
&& !string.IsNullOrEmpty(Now_producting_Workorder_thirty.FinishedPartNumber)
|
||||
)
|
||||
{
|
||||
string message =
|
||||
$"shgx/cx/gz/{Now_producting_Workorder_thirty.FinishedPartNumber}";
|
||||
_ = SendTcpMessageAsync(message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (index == Now_producting_WorkorderList.Count() - 1)
|
||||
{
|
||||
// 已经是最后一个了没有
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
Now_producting_Workorder_thirty = Now_producting_WorkorderList[index + 1];
|
||||
// 发送TCP消息
|
||||
if (
|
||||
Now_producting_Workorder_thirty != null
|
||||
&& !string.IsNullOrEmpty(Now_producting_Workorder_thirty.FinishedPartNumber)
|
||||
)
|
||||
{
|
||||
string message =
|
||||
$"shgx/cx/gz/{Now_producting_Workorder_thirty.FinishedPartNumber}";
|
||||
_ = SendTcpMessageAsync(message);
|
||||
}
|
||||
return Now_producting_Workorder_thirty;
|
||||
}
|
||||
}
|
||||
@ -1086,7 +1157,6 @@ namespace ZR.Service.mes.qc
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref=""></exception>
|
||||
|
||||
public QcCurrentWorkorderDto GetcurrentWorkorder_previous_first()
|
||||
{
|
||||
//获取状态为1的生产工单列表
|
||||
@ -1133,7 +1203,6 @@ namespace ZR.Service.mes.qc
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref=""></exception>
|
||||
|
||||
public QcCurrentWorkorderDto GetcurrentWorkorder_previous_again()
|
||||
{
|
||||
//获取状态为1的生产工单列表
|
||||
@ -1180,7 +1249,6 @@ namespace ZR.Service.mes.qc
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref=""></exception>
|
||||
|
||||
public QcCurrentWorkorderDto GetcurrentWorkorder_previous_thirty()
|
||||
{
|
||||
//获取状态为1的生产工单列表
|
||||
@ -1207,6 +1275,16 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
// 逻辑异常
|
||||
Now_producting_Workorder_thirty = Now_producting_WorkorderList[0];
|
||||
// 发送TCP消息
|
||||
if (
|
||||
Now_producting_Workorder_thirty != null
|
||||
&& !string.IsNullOrEmpty(Now_producting_Workorder_thirty.FinishedPartNumber)
|
||||
)
|
||||
{
|
||||
string message =
|
||||
$"shgx/cx/gz/{Now_producting_Workorder_thirty.FinishedPartNumber}";
|
||||
_ = SendTcpMessageAsync(message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (index == 0)
|
||||
@ -1217,6 +1295,16 @@ namespace ZR.Service.mes.qc
|
||||
else
|
||||
{
|
||||
Now_producting_Workorder_thirty = Now_producting_WorkorderList[index - 1];
|
||||
// 发送TCP消息
|
||||
if (
|
||||
Now_producting_Workorder_thirty != null
|
||||
&& !string.IsNullOrEmpty(Now_producting_Workorder_thirty.FinishedPartNumber)
|
||||
)
|
||||
{
|
||||
string message =
|
||||
$"shgx/cx/gz/{Now_producting_Workorder_thirty.FinishedPartNumber}";
|
||||
_ = SendTcpMessageAsync(message);
|
||||
}
|
||||
return Now_producting_Workorder_thirty;
|
||||
}
|
||||
}
|
||||
@ -1434,7 +1522,6 @@ namespace ZR.Service.mes.qc
|
||||
/// <param name="workorder_id"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
|
||||
public int CalculatePackagingInvestment(string workorder_id)
|
||||
{
|
||||
int OnePassNumber = 0;
|
||||
@ -2731,7 +2818,6 @@ namespace ZR.Service.mes.qc
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region 三检
|
||||
#region 三捡-抛光
|
||||
QcQualityStatisticsFinal final1 = new QcQualityStatisticsFinal();
|
||||
@ -2769,7 +2855,8 @@ namespace ZR.Service.mes.qc
|
||||
.Queryable<QcFinalinspectionRecord>()
|
||||
.Where(it => it.FkWorkorderId == workorderID)
|
||||
.Where(it => SqlFunc.Contains(it.FkInpectionId, "_1_"))
|
||||
.Sum(it => it.Counter) ?? 0;
|
||||
.Sum(it => it.Counter)
|
||||
?? 0;
|
||||
|
||||
if (finalrecordList != null && finalrecordList.Count > 0)
|
||||
{
|
||||
@ -3788,7 +3875,6 @@ namespace ZR.Service.mes.qc
|
||||
//XXX:修改合格数公式:包装数
|
||||
// total2.QualifiedNumber = (again2.RequireNumber ?? 0) - qualifiedNumber_No_all_total;
|
||||
|
||||
|
||||
// 总报表-抛光记录插入
|
||||
total1.QualifiedNumber = final1.QualifiedNumber;
|
||||
if (total1.RequireNumber == 0)
|
||||
@ -3830,7 +3916,6 @@ namespace ZR.Service.mes.qc
|
||||
// total2.DamoTotal = damo_total_again + damo_total_final;
|
||||
// total2.BaofeiTotal = baofei_total_again3 + baofei_total_final;
|
||||
|
||||
|
||||
var x_total_2 = Context
|
||||
.Storageable(total2)
|
||||
.WhereColumns(it => new { it.WorkorderId, it.Remark2 })
|
||||
@ -3858,7 +3943,6 @@ namespace ZR.Service.mes.qc
|
||||
// total3.DamoTotal = damo_total_again + damo_total_final;
|
||||
// total3.BaofeiTotal = baofei_total_again3 + baofei_total_final;
|
||||
|
||||
|
||||
var x_total_3 = Context
|
||||
.Storageable(total3)
|
||||
.WhereColumns(it => new { it.WorkorderId, it.Remark2 })
|
||||
@ -3870,7 +3954,6 @@ namespace ZR.Service.mes.qc
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
//TODO 20241023 不再变动抛光盘点后的数据
|
||||
|
||||
try
|
||||
@ -3886,96 +3969,130 @@ namespace ZR.Service.mes.qc
|
||||
string polishLabelPath = "D:\\RIZO\\label\\抛光送货单.btw";
|
||||
string polishingLabelPath = "D:\\RIZO\\label\\打磨送货单.btw";
|
||||
//TODO 20251027 检查是否存在产线产品托盘配置
|
||||
WmMaterialPackage packageConfig = Context.Queryable<WmMaterialPackage>()
|
||||
WmMaterialPackage packageConfig = Context
|
||||
.Queryable<WmMaterialPackage>()
|
||||
.Where(it => it.RecordType == "零件")
|
||||
.Where(it => it.PartNumber == first.FinishedPartNumber)
|
||||
.First();
|
||||
//TODO 20251027 计算合格数是否超出合格托盘
|
||||
if (packageConfig != null && packageConfig.PackageProductionQualifiedPalletNum != null)
|
||||
if (
|
||||
packageConfig != null
|
||||
&& packageConfig.PackageProductionQualifiedPalletNum != null
|
||||
)
|
||||
{
|
||||
// 合格数超额分段出标签
|
||||
if (qualifiedNumber > packageConfig.PackageProductionQualifiedPalletNum)
|
||||
{
|
||||
// 分批次出多个合格品满箱标签和零头箱标签
|
||||
int qualifiedPalletCapacity = packageConfig.PackageProductionQualifiedPalletNum.Value;
|
||||
int qualifiedPalletCapacity = packageConfig
|
||||
.PackageProductionQualifiedPalletNum
|
||||
.Value;
|
||||
int fullPalletCount = qualifiedNumber / qualifiedPalletCapacity;
|
||||
int remainderCount = qualifiedNumber % qualifiedPalletCapacity;
|
||||
|
||||
// 出满箱标签
|
||||
for (int i = 1; i <= fullPalletCount; i++)
|
||||
{
|
||||
PrintDeliveryNoteDto qualifiedFullPalletDto = CreateQualifiedFullPalletLabelDto(first, qualifiedPalletCapacity, i);
|
||||
PrintDeliveryNoteDto qualifiedFullPalletDto =
|
||||
CreateQualifiedFullPalletLabelDto(
|
||||
first,
|
||||
qualifiedPalletCapacity,
|
||||
i
|
||||
);
|
||||
SendMqttLabelMessage(mqttTopic, qualifiedFullPalletDto);
|
||||
}
|
||||
|
||||
// 出零头箱标签
|
||||
if (remainderCount > 0)
|
||||
{
|
||||
PrintDeliveryNoteDto qualifiedRemainderDto = CreateQualifiedRemainderLabelDto(first, remainderCount, fullPalletCount);
|
||||
PrintDeliveryNoteDto qualifiedRemainderDto =
|
||||
CreateQualifiedRemainderLabelDto(
|
||||
first,
|
||||
remainderCount,
|
||||
fullPalletCount
|
||||
);
|
||||
SendMqttLabelMessage(mqttTopic, qualifiedRemainderDto);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 正常出单个标签
|
||||
PrintDeliveryNoteDto qualifiedSingleLabelDto = CreateQualifiedSingleLabelDto(first, first.QualifiedNumber.Value);
|
||||
PrintDeliveryNoteDto qualifiedSingleLabelDto =
|
||||
CreateQualifiedSingleLabelDto(first, first.QualifiedNumber.Value);
|
||||
SendMqttLabelMessage(mqttTopic, qualifiedSingleLabelDto);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有配置时使用默认的单个标签打印
|
||||
PrintDeliveryNoteDto qualifiedSingleLabelDto = CreateQualifiedSingleLabelDto(first, first.QualifiedNumber.Value);
|
||||
SendMqttLabelMessage(mqttTopic, qualifiedSingleLabelDto);
|
||||
}
|
||||
{
|
||||
// 没有配置时使用默认的单个标签打印
|
||||
PrintDeliveryNoteDto qualifiedSingleLabelDto =
|
||||
CreateQualifiedSingleLabelDto(first, first.QualifiedNumber.Value);
|
||||
SendMqttLabelMessage(mqttTopic, qualifiedSingleLabelDto);
|
||||
}
|
||||
|
||||
if (packageConfig != null && packageConfig.PackageProductionPolishPalletNum != null)
|
||||
if (
|
||||
packageConfig != null
|
||||
&& packageConfig.PackageProductionPolishPalletNum != null
|
||||
)
|
||||
{
|
||||
// 抛光数超额分段
|
||||
if (paoguangTotal > packageConfig.PackageProductionPolishPalletNum)
|
||||
{
|
||||
// 分批次出多个抛光品满箱标签和零头箱标签
|
||||
int polishPalletCapacity = packageConfig.PackageProductionPolishPalletNum.Value;
|
||||
int polishPalletCapacity = packageConfig
|
||||
.PackageProductionPolishPalletNum
|
||||
.Value;
|
||||
int fullPalletCount = paoguangTotal / polishPalletCapacity;
|
||||
int remainderCount = paoguangTotal % polishPalletCapacity;
|
||||
|
||||
// 出满箱标签
|
||||
for (int i = 1; i <= fullPalletCount; i++)
|
||||
{
|
||||
PrintDeliveryNoteDto polishFullPalletDto = CreatePolishFullPalletLabelDto(first, polishPalletCapacity, i);
|
||||
PrintDeliveryNoteDto polishFullPalletDto =
|
||||
CreatePolishFullPalletLabelDto(first, polishPalletCapacity, i);
|
||||
SendMqttLabelMessage(mqttTopic, polishFullPalletDto);
|
||||
}
|
||||
|
||||
// 出零头箱标签
|
||||
if (remainderCount > 0)
|
||||
{
|
||||
PrintDeliveryNoteDto polishRemainderDto = CreatePolishRemainderLabelDto(first, remainderCount, fullPalletCount);
|
||||
PrintDeliveryNoteDto polishRemainderDto =
|
||||
CreatePolishRemainderLabelDto(
|
||||
first,
|
||||
remainderCount,
|
||||
fullPalletCount
|
||||
);
|
||||
SendMqttLabelMessage(mqttTopic, polishRemainderDto);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 正常出单个标签
|
||||
PrintDeliveryNoteDto polishSingleLabelDto = CreatePolishSingleLabelDto(first, first.PaoguangTotal.Value);
|
||||
PrintDeliveryNoteDto polishSingleLabelDto = CreatePolishSingleLabelDto(
|
||||
first,
|
||||
first.PaoguangTotal.Value
|
||||
);
|
||||
SendMqttLabelMessage(mqttTopic, polishSingleLabelDto);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有配置时使用默认的单个标签打印
|
||||
PrintDeliveryNoteDto polishSingleLabelDto = CreatePolishSingleLabelDto(first, first.PaoguangTotal.Value);
|
||||
SendMqttLabelMessage(mqttTopic, polishSingleLabelDto);
|
||||
}
|
||||
|
||||
{
|
||||
// 没有配置时使用默认的单个标签打印
|
||||
PrintDeliveryNoteDto polishSingleLabelDto = CreatePolishSingleLabelDto(
|
||||
first,
|
||||
first.PaoguangTotal.Value
|
||||
);
|
||||
SendMqttLabelMessage(mqttTopic, polishSingleLabelDto);
|
||||
}
|
||||
|
||||
// 使用辅助方法创建打磨标签
|
||||
PrintDeliveryNoteDto polishingLabelDto = CreatePolishingLabelDto(first, first.DamoTotal.Value);
|
||||
PrintDeliveryNoteDto polishingLabelDto = CreatePolishingLabelDto(
|
||||
first,
|
||||
first.DamoTotal.Value
|
||||
);
|
||||
SendMqttLabelMessage(mqttTopic, polishingLabelDto);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
return 1;
|
||||
// 以下代码暂时停用
|
||||
@ -3984,17 +4101,19 @@ namespace ZR.Service.mes.qc
|
||||
{
|
||||
// 1.抛光品入库
|
||||
WmPolishInventoryService wmPolishInventoryService = new();
|
||||
WmPolishInventory warehousingInfo =
|
||||
new()
|
||||
{
|
||||
Partnumber = workorder_item.FinishedPartNumber,
|
||||
WorkOrder = workorder_item.ClientWorkorder,
|
||||
Type = workorder_item.Remark1.Contains("返工") ? 2 : 1,
|
||||
Quantity = paoguang_by_first + paoguang_final,
|
||||
ActionTime = DateTime.Now.ToLocalTime(),
|
||||
CreatedBy = "包装" + team + "组",
|
||||
Remark = "产线抛光件,自动入库。来源工单号:[" + workorder_item.ClientWorkorder + "]"
|
||||
};
|
||||
WmPolishInventory warehousingInfo = new()
|
||||
{
|
||||
Partnumber = workorder_item.FinishedPartNumber,
|
||||
WorkOrder = workorder_item.ClientWorkorder,
|
||||
Type = workorder_item.Remark1.Contains("返工") ? 2 : 1,
|
||||
Quantity = paoguang_by_first + paoguang_final,
|
||||
ActionTime = DateTime.Now.ToLocalTime(),
|
||||
CreatedBy = "包装" + team + "组",
|
||||
Remark =
|
||||
"产线抛光件,自动入库。来源工单号:["
|
||||
+ workorder_item.ClientWorkorder
|
||||
+ "]",
|
||||
};
|
||||
wmPolishInventoryService.DoWmPolishWarehousing(warehousingInfo);
|
||||
// 2.成品入一次合格品库
|
||||
// 合格品检查是否是门把手或倒车雷达,是进入成品库(仅出库),不是进入一次合格品库
|
||||
@ -4010,7 +4129,7 @@ namespace ZR.Service.mes.qc
|
||||
"B02",
|
||||
"V71",
|
||||
"T1EJ ",
|
||||
"倒车雷达"
|
||||
"倒车雷达",
|
||||
};
|
||||
var isDoorknobCheck = Expressionable.Create<WmMaterial>();
|
||||
foreach (string checkStr in checkStrArray)
|
||||
@ -4028,22 +4147,23 @@ namespace ZR.Service.mes.qc
|
||||
if (!isDoorknob)
|
||||
{
|
||||
WmOneTimeInventoryService oneTimeService = new();
|
||||
WmOneTimeInventory wmOneTimeInventoryWarehousing =
|
||||
new()
|
||||
{
|
||||
Partnumber = workorder_item.FinishedPartNumber,
|
||||
WorkOrder = workorder_item.ClientWorkorder,
|
||||
Type = workorder_item.Remark1.Contains("返工") ? 2 : 1,
|
||||
Quantity = total3.QualifiedNumber,
|
||||
CreatedBy = "包装" + team + "组",
|
||||
ActionTime = DateTime.Now.ToLocalTime(),
|
||||
Remark =
|
||||
"包装合格品入库,合格数:"
|
||||
+ total3.QualifiedNumber
|
||||
+ "、工单号:"
|
||||
+ workorder_item.ClientWorkorder
|
||||
?? "未填写工单号" + "。记录时间:" + DateTime.Now.ToLocalTime().ToString()
|
||||
};
|
||||
WmOneTimeInventory wmOneTimeInventoryWarehousing = new()
|
||||
{
|
||||
Partnumber = workorder_item.FinishedPartNumber,
|
||||
WorkOrder = workorder_item.ClientWorkorder,
|
||||
Type = workorder_item.Remark1.Contains("返工") ? 2 : 1,
|
||||
Quantity = total3.QualifiedNumber,
|
||||
CreatedBy = "包装" + team + "组",
|
||||
ActionTime = DateTime.Now.ToLocalTime(),
|
||||
Remark =
|
||||
"包装合格品入库,合格数:"
|
||||
+ total3.QualifiedNumber
|
||||
+ "、工单号:"
|
||||
+ workorder_item.ClientWorkorder
|
||||
?? "未填写工单号"
|
||||
+ "。记录时间:"
|
||||
+ DateTime.Now.ToLocalTime().ToString(),
|
||||
};
|
||||
oneTimeService.DoWmOneTimeWarehousing(wmOneTimeInventoryWarehousing);
|
||||
}
|
||||
}
|
||||
@ -4054,7 +4174,7 @@ namespace ZR.Service.mes.qc
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 发送MQTT标签打印消息
|
||||
/// </summary>
|
||||
@ -4070,11 +4190,15 @@ namespace ZR.Service.mes.qc
|
||||
)
|
||||
.Wait();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建合格品满箱标签DTO
|
||||
/// </summary>
|
||||
private PrintDeliveryNoteDto CreateQualifiedFullPalletLabelDto(QcQualityStatisticsFirst first, int qualifiedPalletNum, int batchIndex)
|
||||
private PrintDeliveryNoteDto CreateQualifiedFullPalletLabelDto(
|
||||
QcQualityStatisticsFirst first,
|
||||
int qualifiedPalletNum,
|
||||
int batchIndex
|
||||
)
|
||||
{
|
||||
return new PrintDeliveryNoteDto
|
||||
{
|
||||
@ -4092,16 +4216,21 @@ namespace ZR.Service.mes.qc
|
||||
ProductionTime = first.WorkorderId,
|
||||
BatchCode = first.WorkorderId,
|
||||
PackageNum = qualifiedPalletNum,
|
||||
LabelCode = $"Type=DeNoHG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={qualifiedPalletNum}^Batch={batchIndex}",
|
||||
LabelCode =
|
||||
$"Type=DeNoHG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={qualifiedPalletNum}^Batch={batchIndex}",
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
CreatedTime = DateTime.Now.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建合格品零头箱标签DTO
|
||||
/// </summary>
|
||||
private PrintDeliveryNoteDto CreateQualifiedRemainderLabelDto(QcQualityStatisticsFirst first, int remainderCount, int fullPalletCount)
|
||||
private PrintDeliveryNoteDto CreateQualifiedRemainderLabelDto(
|
||||
QcQualityStatisticsFirst first,
|
||||
int remainderCount,
|
||||
int fullPalletCount
|
||||
)
|
||||
{
|
||||
int remainderBatchIndex = fullPalletCount + 1;
|
||||
return new PrintDeliveryNoteDto
|
||||
@ -4120,16 +4249,20 @@ namespace ZR.Service.mes.qc
|
||||
ProductionTime = first.WorkorderId,
|
||||
BatchCode = first.WorkorderId,
|
||||
PackageNum = remainderCount,
|
||||
LabelCode = $"Type=DeNoHG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={remainderCount}^Batch={remainderBatchIndex}_remainder",
|
||||
LabelCode =
|
||||
$"Type=DeNoHG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={remainderCount}^Batch={remainderBatchIndex}_remainder",
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
CreatedTime = DateTime.Now.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建合格品单个标签DTO
|
||||
/// </summary>
|
||||
private PrintDeliveryNoteDto CreateQualifiedSingleLabelDto(QcQualityStatisticsFirst first, int qualifiedNumber)
|
||||
private PrintDeliveryNoteDto CreateQualifiedSingleLabelDto(
|
||||
QcQualityStatisticsFirst first,
|
||||
int qualifiedNumber
|
||||
)
|
||||
{
|
||||
return new PrintDeliveryNoteDto
|
||||
{
|
||||
@ -4147,16 +4280,21 @@ namespace ZR.Service.mes.qc
|
||||
ProductionTime = first.WorkorderId,
|
||||
BatchCode = first.WorkorderId,
|
||||
PackageNum = qualifiedNumber,
|
||||
LabelCode = $"Type=DeNoHG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={qualifiedNumber}",
|
||||
LabelCode =
|
||||
$"Type=DeNoHG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={qualifiedNumber}",
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
CreatedTime = DateTime.Now.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建抛光品满箱标签DTO
|
||||
/// </summary>
|
||||
private PrintDeliveryNoteDto CreatePolishFullPalletLabelDto(QcQualityStatisticsFirst first, int polishPalletNum, int batchIndex)
|
||||
private PrintDeliveryNoteDto CreatePolishFullPalletLabelDto(
|
||||
QcQualityStatisticsFirst first,
|
||||
int polishPalletNum,
|
||||
int batchIndex
|
||||
)
|
||||
{
|
||||
return new PrintDeliveryNoteDto
|
||||
{
|
||||
@ -4174,16 +4312,21 @@ namespace ZR.Service.mes.qc
|
||||
ProductionTime = first.WorkorderId,
|
||||
BatchCode = first.WorkorderId,
|
||||
PackageNum = polishPalletNum,
|
||||
LabelCode = $"Type=DeNoPG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={polishPalletNum}^Batch={batchIndex}",
|
||||
LabelCode =
|
||||
$"Type=DeNoPG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={polishPalletNum}^Batch={batchIndex}",
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
CreatedTime = DateTime.Now.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建抛光品零头箱标签DTO
|
||||
/// </summary>
|
||||
private PrintDeliveryNoteDto CreatePolishRemainderLabelDto(QcQualityStatisticsFirst first, int remainderCount, int fullPalletCount)
|
||||
private PrintDeliveryNoteDto CreatePolishRemainderLabelDto(
|
||||
QcQualityStatisticsFirst first,
|
||||
int remainderCount,
|
||||
int fullPalletCount
|
||||
)
|
||||
{
|
||||
int remainderBatchIndex = fullPalletCount + 1;
|
||||
return new PrintDeliveryNoteDto
|
||||
@ -4202,16 +4345,20 @@ namespace ZR.Service.mes.qc
|
||||
ProductionTime = first.WorkorderId,
|
||||
BatchCode = first.WorkorderId,
|
||||
PackageNum = remainderCount,
|
||||
LabelCode = $"Type=DeNoPG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={remainderCount}^Batch={remainderBatchIndex}_remainder",
|
||||
LabelCode =
|
||||
$"Type=DeNoPG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={remainderCount}^Batch={remainderBatchIndex}_remainder",
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
CreatedTime = DateTime.Now.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建抛光品单个标签DTO
|
||||
/// </summary>
|
||||
private PrintDeliveryNoteDto CreatePolishSingleLabelDto(QcQualityStatisticsFirst first, int polishTotal)
|
||||
private PrintDeliveryNoteDto CreatePolishSingleLabelDto(
|
||||
QcQualityStatisticsFirst first,
|
||||
int polishTotal
|
||||
)
|
||||
{
|
||||
return new PrintDeliveryNoteDto
|
||||
{
|
||||
@ -4229,16 +4376,20 @@ namespace ZR.Service.mes.qc
|
||||
ProductionTime = first.WorkorderId,
|
||||
BatchCode = first.WorkorderId,
|
||||
PackageNum = polishTotal,
|
||||
LabelCode = $"Type=DeNoPG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={polishTotal}",
|
||||
LabelCode =
|
||||
$"Type=DeNoPG^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={polishTotal}",
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
CreatedTime = DateTime.Now.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建打磨品标签DTO
|
||||
/// </summary>
|
||||
private PrintDeliveryNoteDto CreatePolishingLabelDto(QcQualityStatisticsFirst first, int polishingTotal)
|
||||
private PrintDeliveryNoteDto CreatePolishingLabelDto(
|
||||
QcQualityStatisticsFirst first,
|
||||
int polishingTotal
|
||||
)
|
||||
{
|
||||
return new PrintDeliveryNoteDto
|
||||
{
|
||||
@ -4256,9 +4407,10 @@ namespace ZR.Service.mes.qc
|
||||
ProductionTime = first.WorkorderId,
|
||||
BatchCode = first.WorkorderId,
|
||||
PackageNum = polishingTotal,
|
||||
LabelCode = $"Type=DeNoDM^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={polishingTotal}",
|
||||
LabelCode =
|
||||
$"Type=DeNoDM^ItemNumber={first.FinishedPartNumber}^Order={first.WorkorderId}^Qty={polishingTotal}",
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
CreatedTime = DateTime.Now.ToString(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
||||
using ZR.Common.MqttHelper;
|
||||
using ZR.Model.Business;
|
||||
using ZR.Model.Dto;
|
||||
using ZR.Model.MES.qc.DTO;
|
||||
using ZR.Model.MES.wms;
|
||||
using ZR.Model.MES.wms.Dto;
|
||||
using ZR.Service.Business.IBusinessService;
|
||||
@ -25,11 +26,13 @@ namespace ZR.Service.Business
|
||||
{
|
||||
private readonly MqttService _mqttService; // 注入MqttService
|
||||
private readonly ILogger<QcBackEndService> _logger;
|
||||
private readonly IProFinishedProductReceiptService _proFinishedProductReceiptService;
|
||||
|
||||
public QcBackEndService(MqttService mqttService, ILogger<QcBackEndService> logger)
|
||||
public QcBackEndService(MqttService mqttService, ILogger<QcBackEndService> logger, IProFinishedProductReceiptService proFinishedProductReceiptService)
|
||||
{
|
||||
_mqttService = mqttService;
|
||||
_logger = logger;
|
||||
_proFinishedProductReceiptService = proFinishedProductReceiptService;
|
||||
}
|
||||
|
||||
public QcBackEndLabelAnalysisDto AnalyzeLabelToDto(string label, int type)
|
||||
@ -1237,6 +1240,19 @@ namespace ZR.Service.Business
|
||||
Context.Insertable(qcBackEndLog).ExecuteCommand();
|
||||
// 提交事务
|
||||
Context.Ado.CommitTran();
|
||||
|
||||
// 发送mqtt消息通知打印抛光/打磨标签
|
||||
// 发送抛光标签打印消息
|
||||
if (qcBackEndWorkorder.PolishNumber > 0)
|
||||
{
|
||||
SendLabelPrintMqttMessage(qcBackEndWorkorder, 1, qcBackEndWorkorder.PolishNumber.Value);
|
||||
}
|
||||
// 发送打磨标签打印消息
|
||||
if (qcBackEndWorkorder.DamoNumber > 0)
|
||||
{
|
||||
SendLabelPrintMqttMessage(qcBackEndWorkorder, 2, qcBackEndWorkorder.DamoNumber.Value);
|
||||
}
|
||||
|
||||
// 插入成品入库单
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
@ -1519,6 +1535,188 @@ namespace ZR.Service.Business
|
||||
return Guid.NewGuid().ToString("N").Substring(0, 10); // Generate a 10-character unique ID
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送标签打印MQTT消息
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="labelType">标签类型:1-抛光,2-打磨</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <summary>
|
||||
/// 发送标签打印MQTT消息
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="labelType">标签类型:1-抛光,2-打磨</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
private void SendLabelPrintMqttMessage(QcBackEndServiceWorkorder workorder, int labelType, int quantity)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (quantity <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 基本配置
|
||||
string mqttTopic = "shgg_mes/backEnd/label_print/print/PGDM";
|
||||
string labelCode = labelType == 1 ? "Type=DeNoPG" : "Type=DeNoDM";
|
||||
string path = labelType == 1 ? "C:\\Program Files\\MES\\label\\送货单\\抛光送货单.btw" : "C:\\Program Files\\MES\\label\\送货单\\打磨送货单.btw";
|
||||
string name = labelType == 1 ? "后道抛光送货单标签打印" : "后道打磨送货单标签打印";
|
||||
|
||||
// 2. 抛光标签特殊处理:检查托盘配置
|
||||
if (labelType == 1)
|
||||
{
|
||||
// 查询零件的托盘配置
|
||||
WmMaterialPackage packageConfig = Context.Queryable<WmMaterialPackage>()
|
||||
.Where(it => it.RecordType == "零件")
|
||||
.Where(it => it.PartNumber == workorder.PartNumber)
|
||||
.First();
|
||||
|
||||
// 检查是否有后道抛光托盘配置
|
||||
if (packageConfig != null && packageConfig.PackageBackendPolishPalletNum != null)
|
||||
{
|
||||
int polishPalletCapacity = packageConfig.PackageBackendPolishPalletNum.Value;
|
||||
if (quantity > polishPalletCapacity)
|
||||
{
|
||||
// 分批次打印多个标签
|
||||
SendBatchPrintLabels(workorder, mqttTopic, labelCode, path, name, quantity, polishPalletCapacity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 默认打印单个标签
|
||||
SendSinglePrintLabel(workorder, mqttTopic, labelCode, path, name, quantity, 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录异常但不影响主流程
|
||||
_logger.LogError(ex, "发送后道标签打印MQTT消息失败");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分批次打印标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="totalQuantity">总数量</param>
|
||||
/// <param name="palletCapacity">托盘容量</param>
|
||||
private void SendBatchPrintLabels(QcBackEndServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int totalQuantity, int palletCapacity)
|
||||
{
|
||||
int fullPalletCount = totalQuantity / palletCapacity;
|
||||
int remainderCount = totalQuantity % palletCapacity;
|
||||
|
||||
// 打印满托盘标签
|
||||
for (int i = 1; i <= fullPalletCount; i++)
|
||||
{
|
||||
SendFullPalletPrintLabel(workorder, mqttTopic, labelCode, path, name, palletCapacity, i);
|
||||
}
|
||||
|
||||
// 打印剩余标签
|
||||
if (remainderCount > 0)
|
||||
{
|
||||
SendRemainderPrintLabel(workorder, mqttTopic, labelCode, path, name, remainderCount, fullPalletCount);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印单个标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="batchIndex">批次索引</param>
|
||||
private void SendSinglePrintLabel(QcBackEndServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int quantity, int batchIndex)
|
||||
{
|
||||
var printDto = CreatePrintDeliveryNoteDto(workorder, path, name, quantity, workorder.WorkOrder, batchIndex, labelCode);
|
||||
string message = JsonSerializer.Serialize(printDto);
|
||||
_mqttService.PublishAsync(mqttTopic, message, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
_logger.LogInformation($"发送后道标签打印MQTT消息成功: {mqttTopic}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印满托盘标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="batchIndex">批次索引</param>
|
||||
private void SendFullPalletPrintLabel(QcBackEndServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int quantity, int batchIndex)
|
||||
{
|
||||
var printDto = CreatePrintDeliveryNoteDto(workorder, path, $"{name}(满箱)第{batchIndex}箱", quantity, $"{workorder.WorkOrder}_{batchIndex}", batchIndex, labelCode, batchIndex);
|
||||
string message = JsonSerializer.Serialize(printDto);
|
||||
_mqttService.PublishAsync(mqttTopic, message, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
_logger.LogInformation($"发送后道抛光满箱标签打印MQTT消息成功: {mqttTopic}, 第{batchIndex}箱");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印剩余标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="fullPalletCount">满托盘数量</param>
|
||||
private void SendRemainderPrintLabel(QcBackEndServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int quantity, int fullPalletCount)
|
||||
{
|
||||
int batchIndex = fullPalletCount + 1;
|
||||
var printDto = CreatePrintDeliveryNoteDto(workorder, path, $"{name}(零头箱)", quantity, $"{workorder.WorkOrder}_零头", batchIndex, labelCode, batchIndex);
|
||||
string message = JsonSerializer.Serialize(printDto);
|
||||
_mqttService.PublishAsync(mqttTopic, message, MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
_logger.LogInformation($"发送后道抛光零头箱标签打印MQTT消息成功: {mqttTopic}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建打印送货单DTO
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="packageCode">包装代码</param>
|
||||
/// <param name="sort">排序</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="batchIndex">批次索引(可选,用于生成标签代码)</param>
|
||||
/// <returns>打印送货单DTO</returns>
|
||||
private PrintDeliveryNoteDto CreatePrintDeliveryNoteDto(QcBackEndServiceWorkorder workorder, string path, string name, int quantity, string packageCode, int sort, string labelCode, int? batchIndex = null)
|
||||
{
|
||||
string finalLabelCode = batchIndex.HasValue
|
||||
? $"{labelCode}^ItemNumber={workorder.PartNumber}^Order={workorder.WorkOrder}^Qty={quantity}^Batch={batchIndex}"
|
||||
: $"{labelCode}^ItemNumber={workorder.PartNumber}^Order={workorder.WorkOrder}^Qty={quantity}";
|
||||
|
||||
return new PrintDeliveryNoteDto
|
||||
{
|
||||
Path = path,
|
||||
SiteNo = workorder.SiteNo,
|
||||
Name = name,
|
||||
PartNumber = workorder.PartNumber,
|
||||
Description = workorder.Description,
|
||||
Color = workorder.Color,
|
||||
Specification = workorder.Specification,
|
||||
WorkOrder = workorder.WorkOrder,
|
||||
PackageCode = packageCode,
|
||||
Team = workorder.Team,
|
||||
Sort = sort,
|
||||
ProductionTime = workorder.WorkOrder,
|
||||
BatchCode = workorder.WorkOrder,
|
||||
PackageNum = quantity,
|
||||
LabelCode = finalLabelCode,
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印特殊包装标签
|
||||
/// </summary>
|
||||
|
||||
@ -6,10 +6,12 @@ using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using ZR.Model.Business;
|
||||
using ZR.Model.Dto;
|
||||
using ZR.Model.MES.qc.DTO;
|
||||
using ZR.Model.MES.wms;
|
||||
using ZR.Model.MES.wms.Dto;
|
||||
using ZR.Service.Business.IBusinessService;
|
||||
using ZR.Service.Utils;
|
||||
using ZR.Service.mqtt;
|
||||
|
||||
namespace ZR.Service.Business
|
||||
{
|
||||
@ -19,6 +21,13 @@ namespace ZR.Service.Business
|
||||
[AppService(ServiceType = typeof(IQcGp12Service), ServiceLifetime = LifeTime.Transient)]
|
||||
public class QcGp12Service : BaseService<QcGp12ServiceWorkorder>, IQcGp12Service
|
||||
{
|
||||
private readonly MqttService _mqttService;
|
||||
|
||||
public QcGp12Service(MqttService mqttService)
|
||||
{
|
||||
_mqttService = mqttService;
|
||||
}
|
||||
|
||||
public QcGp12LabelAnalysisDto AnalyzeLabelToDto(string label, int type)
|
||||
{
|
||||
QcGp12LabelAnalysisDto labelAnalysisDto =
|
||||
@ -736,22 +745,35 @@ namespace ZR.Service.Business
|
||||
Context.Insertable(qcGp12Log).ExecuteCommand();
|
||||
// 提交事务
|
||||
Context.Ado.CommitTran();
|
||||
|
||||
// 发送mqtt消息通知打印抛光/打磨标签
|
||||
// 发送抛光标签打印消息
|
||||
if (qcGp12Workorder.PolishNumber > 0)
|
||||
{
|
||||
SendLabelPrintMqttMessage(qcGp12Workorder, 1, qcGp12Workorder.PolishNumber.Value);
|
||||
}
|
||||
// 发送打磨标签打印消息
|
||||
if (qcGp12Workorder.DamoNumber > 0)
|
||||
{
|
||||
SendLabelPrintMqttMessage(qcGp12Workorder, 2, qcGp12Workorder.DamoNumber.Value);
|
||||
}
|
||||
|
||||
// 插入成品入库单
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
ProFinishedProductReceiptService proFinishedProductReceiptService = new ProFinishedProductReceiptService();
|
||||
|
||||
|
||||
// 生成ReceiptNo:GP+日期YYYYMMDD+0001顺序递增
|
||||
string today = nowTime.ToString("yyyyMMdd");
|
||||
string receiptNoPrefix = $"GP{today}";
|
||||
|
||||
|
||||
// 查询今天已存在的最大单号
|
||||
var lastReceipt = Context
|
||||
.Queryable<ProFinishedProductReceipt>()
|
||||
.Where(it => it.ReceiptNo.StartsWith(receiptNoPrefix))
|
||||
.OrderBy(it => it.ReceiptNo, OrderByType.Desc)
|
||||
.First();
|
||||
|
||||
|
||||
string newReceiptNo;
|
||||
if (lastReceipt != null && !string.IsNullOrEmpty(lastReceipt.ReceiptNo))
|
||||
{
|
||||
@ -771,7 +793,7 @@ namespace ZR.Service.Business
|
||||
newReceiptNo = $"{receiptNoPrefix}0001";
|
||||
}
|
||||
// 箱数
|
||||
int _packageCount = Context.Queryable<QcGp12RecordLabelScan>().Where(it=>it.WorkOrder == qcGp12Workorder.WorkOrder).Where(it => it.LabelType == 1).Count();
|
||||
int _packageCount = Context.Queryable<QcGp12RecordLabelScan>().Where(it => it.WorkOrder == qcGp12Workorder.WorkOrder).Where(it => it.LabelType == 1).Count();
|
||||
// 工单号
|
||||
MaterialUtils materialUtils = new MaterialUtils();
|
||||
ResultionPackageCodeDto packageCodeDto = materialUtils.ResolutionPackage(qcGp12Workorder.Label);
|
||||
@ -781,7 +803,8 @@ namespace ZR.Service.Business
|
||||
_workOrder = packageCodeDto.WorkoderID;
|
||||
}
|
||||
|
||||
ProFinishedProductReceipt newModel = new() {
|
||||
ProFinishedProductReceipt newModel = new()
|
||||
{
|
||||
ReceiptNo = newReceiptNo,
|
||||
SiteNo = qcGp12Workorder.SiteNo,
|
||||
WorkOrder = _workOrder,
|
||||
@ -1002,5 +1025,178 @@ namespace ZR.Service.Business
|
||||
return Guid.NewGuid().ToString("N").Substring(0, 10); // Generate a 10-character unique ID
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送标签打印MQTT消息
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="labelType">标签类型:1-抛光,2-打磨</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
private void SendLabelPrintMqttMessage(QcGp12ServiceWorkorder workorder, int labelType, int quantity)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (quantity <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 基本配置
|
||||
string mqttTopic = $"shgg_mes/gp12/label_print/print/PGDM";
|
||||
string labelCode = labelType == 1 ? "Type=DeNoPG" : "Type=DeNoDM";
|
||||
string path = labelType == 1 ? "D:\\RIZO\\label\\抛光送货单.btw" : "D:\\RIZO\\label\\打磨送货单.btw";
|
||||
string name = labelType == 1 ? "GP12抛光送货单标签打印" : "GP12打磨送货单标签打印";
|
||||
|
||||
// 2. 抛光标签特殊处理:检查托盘配置
|
||||
if (labelType == 1)
|
||||
{
|
||||
// 查询零件的托盘配置
|
||||
WmMaterialPackage packageConfig = Context.Queryable<WmMaterialPackage>()
|
||||
.Where(it => it.RecordType == "零件")
|
||||
.Where(it => it.PartNumber == workorder.PartNumber)
|
||||
.First();
|
||||
|
||||
// 检查是否有GP12抛光托盘配置
|
||||
if (packageConfig != null && packageConfig.PackageGP12PolishPalletNum != null)
|
||||
{
|
||||
int polishPalletCapacity = packageConfig.PackageGP12PolishPalletNum.Value;
|
||||
if (quantity > polishPalletCapacity)
|
||||
{
|
||||
// 分批次打印多个标签
|
||||
SendBatchPrintLabels(workorder, mqttTopic, labelCode, path, name, quantity, polishPalletCapacity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 默认打印单个标签
|
||||
SendSinglePrintLabel(workorder, mqttTopic, labelCode, path, name, quantity, 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录异常但不影响主流程
|
||||
Console.WriteLine($"发送标签打印MQTT消息失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分批次打印标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="totalQuantity">总数量</param>
|
||||
/// <param name="palletCapacity">托盘容量</param>
|
||||
private void SendBatchPrintLabels(QcGp12ServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int totalQuantity, int palletCapacity)
|
||||
{
|
||||
int fullPalletCount = totalQuantity / palletCapacity;
|
||||
int remainderCount = totalQuantity % palletCapacity;
|
||||
|
||||
// 打印满托盘标签
|
||||
for (int i = 1; i <= fullPalletCount; i++)
|
||||
{
|
||||
SendFullPalletPrintLabel(workorder, mqttTopic, labelCode, path, name, palletCapacity, i);
|
||||
}
|
||||
|
||||
// 打印剩余标签
|
||||
if (remainderCount > 0)
|
||||
{
|
||||
SendRemainderPrintLabel(workorder, mqttTopic, labelCode, path, name, remainderCount, fullPalletCount);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印单个标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="batchIndex">批次索引</param>
|
||||
private void SendSinglePrintLabel(QcGp12ServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int quantity, int batchIndex)
|
||||
{
|
||||
var printDto = CreatePrintDeliveryNoteDto(workorder, path, name, quantity, workorder.WorkOrder, batchIndex, labelCode);
|
||||
string message = JsonSerializer.Serialize(printDto);
|
||||
_mqttService.PublishAsync(mqttTopic, message, MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印满托盘标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="batchIndex">批次索引</param>
|
||||
private void SendFullPalletPrintLabel(QcGp12ServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int quantity, int batchIndex)
|
||||
{
|
||||
var printDto = CreatePrintDeliveryNoteDto(workorder, path, $"{name}(满箱)第{batchIndex}箱", quantity, $"{workorder.WorkOrder}_{batchIndex}", batchIndex, labelCode, batchIndex);
|
||||
string message = JsonSerializer.Serialize(printDto);
|
||||
_mqttService.PublishAsync(mqttTopic, message, MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打印剩余标签
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="mqttTopic">MQTT主题</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="fullPalletCount">满托盘数量</param>
|
||||
private void SendRemainderPrintLabel(QcGp12ServiceWorkorder workorder, string mqttTopic, string labelCode, string path, string name, int quantity, int fullPalletCount)
|
||||
{
|
||||
int batchIndex = fullPalletCount + 1;
|
||||
var printDto = CreatePrintDeliveryNoteDto(workorder, path, $"{name}(零头箱)", quantity, $"{workorder.WorkOrder}_零头", batchIndex, labelCode, batchIndex);
|
||||
string message = JsonSerializer.Serialize(printDto);
|
||||
_mqttService.PublishAsync(mqttTopic, message, MQTTnet.Protocol.MqttQualityOfServiceLevel.AtLeastOnce);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建打印送货单DTO
|
||||
/// </summary>
|
||||
/// <param name="workorder">工单信息</param>
|
||||
/// <param name="path">标签模板路径</param>
|
||||
/// <param name="name">标签名称</param>
|
||||
/// <param name="quantity">数量</param>
|
||||
/// <param name="packageCode">包装代码</param>
|
||||
/// <param name="sort">排序</param>
|
||||
/// <param name="labelCode">标签代码</param>
|
||||
/// <param name="batchIndex">批次索引(可选,用于生成标签代码)</param>
|
||||
/// <returns>打印送货单DTO</returns>
|
||||
private PrintDeliveryNoteDto CreatePrintDeliveryNoteDto(QcGp12ServiceWorkorder workorder, string path, string name, int quantity, string packageCode, int sort, string labelCode, int? batchIndex = null)
|
||||
{
|
||||
string finalLabelCode = batchIndex.HasValue
|
||||
? $"{labelCode}^ItemNumber={workorder.PartNumber}^Order={workorder.WorkOrder}^Qty={quantity}^Batch={batchIndex}"
|
||||
: $"{labelCode}^ItemNumber={workorder.PartNumber}^Order={workorder.WorkOrder}^Qty={quantity}";
|
||||
|
||||
return new PrintDeliveryNoteDto
|
||||
{
|
||||
Path = path,
|
||||
SiteNo = workorder.SiteNo,
|
||||
Name = name,
|
||||
PartNumber = workorder.PartNumber,
|
||||
Description = workorder.Description,
|
||||
Color = workorder.Color,
|
||||
Specification = workorder.Specification,
|
||||
WorkOrder = workorder.WorkOrder,
|
||||
PackageCode = packageCode,
|
||||
Team = workorder.Team,
|
||||
Sort = sort,
|
||||
ProductionTime = workorder.WorkOrder,
|
||||
BatchCode = workorder.WorkOrder,
|
||||
PackageNum = quantity,
|
||||
LabelCode = finalLabelCode,
|
||||
LabelType = 1,
|
||||
CreatedTime = DateTime.Now.ToString()
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
441
ZR.Service/tcp/TcpServerService.cs
Normal file
441
ZR.Service/tcp/TcpServerService.cs
Normal file
@ -0,0 +1,441 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ZR.Service.tcp
|
||||
{
|
||||
/// <summary>
|
||||
/// 信号去重记录
|
||||
/// </summary>
|
||||
public class SignalDeduplicationRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// 信号唯一标识
|
||||
/// </summary>
|
||||
public string SignalId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收时间戳(毫秒)
|
||||
/// </summary>
|
||||
public long Timestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TCP服务器服务
|
||||
/// 基于BackgroundService实现,支持多客户端并发连接
|
||||
/// 监听端口:9090
|
||||
/// </summary>
|
||||
public class TcpServerService : BackgroundService
|
||||
{
|
||||
private readonly ILogger<TcpServerService> _logger;
|
||||
private TcpListener _tcpListener;
|
||||
private CancellationTokenSource _cts;
|
||||
private readonly int _port = 9090;
|
||||
private readonly string _ipAddress = "0.0.0.0"; // 监听所有网络接口
|
||||
|
||||
// 线程安全的客户端连接列表,用于管理所有已连接的客户端
|
||||
private ConcurrentDictionary<string, TcpClient> _connectedClients;
|
||||
|
||||
// 信号去重相关
|
||||
private ConcurrentDictionary<string, long> _recentSignals; // 键:信号唯一标识,值:时间戳
|
||||
private long _deduplicationCount; // 去重统计计数
|
||||
private object _deduplicationLock = new object(); // 用于统计计数的锁
|
||||
private readonly int _timeWindowMs = 1000; // 时间窗口:1000毫秒
|
||||
private readonly int _cleanupIntervalMs = 5000; // 清理间隔:5000毫秒
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="logger">日志服务</param>
|
||||
public TcpServerService(ILogger<TcpServerService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_connectedClients = new ConcurrentDictionary<string, TcpClient>();
|
||||
_recentSignals = new ConcurrentDictionary<string, long>();
|
||||
_deduplicationCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行TCP服务器逻辑
|
||||
/// </summary>
|
||||
/// <param name="stoppingToken">停止令牌</param>
|
||||
/// <returns></returns>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
// 创建与停止令牌关联的取消令牌源
|
||||
_cts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
|
||||
|
||||
try
|
||||
{
|
||||
// 初始化TCP监听器
|
||||
IPAddress localAddr = IPAddress.Parse(_ipAddress);
|
||||
_tcpListener = new TcpListener(localAddr, _port);
|
||||
|
||||
// 启动监听器
|
||||
_tcpListener.Start();
|
||||
_logger.LogInformation($"TCP服务器启动成功,监听地址: {_ipAddress}:{_port}");
|
||||
Console.WriteLine($"[TCP服务器] 启动成功,监听地址: {_ipAddress}:{_port}");
|
||||
|
||||
// 启动定期清理任务
|
||||
_ = Task.Run(() => CleanupExpiredSignalsAsync(_cts.Token), _cts.Token);
|
||||
|
||||
// 启动统计报告任务
|
||||
_ = Task.Run(() => ReportDeduplicationStatsAsync(_cts.Token), _cts.Token);
|
||||
|
||||
// 循环接受客户端连接
|
||||
while (!_cts.Token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否有挂起的连接
|
||||
if (_tcpListener.Pending())
|
||||
{
|
||||
// 接受客户端连接
|
||||
TcpClient client = await _tcpListener.AcceptTcpClientAsync();
|
||||
string clientEndPoint = client.Client.RemoteEndPoint?.ToString() ?? "未知客户端";
|
||||
|
||||
// 将客户端添加到连接列表
|
||||
_connectedClients.TryAdd(clientEndPoint, client);
|
||||
_logger.LogInformation($"客户端连接成功: {clientEndPoint},当前连接数: {_connectedClients.Count}");
|
||||
Console.WriteLine($"[TCP服务器] 客户端连接成功: {clientEndPoint},当前连接数: {_connectedClients.Count}");
|
||||
|
||||
// 异步处理客户端连接,避免阻塞主线程
|
||||
_ = HandleClientAsync(client, clientEndPoint, _cts.Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 避免CPU占用过高,添加适当延迟
|
||||
await Task.Delay(100, _cts.Token);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 正常停止,无需处理
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "接受客户端连接时发生错误");
|
||||
Console.WriteLine($"[TCP服务器] 接受客户端连接时发生错误: {ex.Message}");
|
||||
// 继续运行,不影响服务器整体
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "TCP服务器启动失败");
|
||||
Console.WriteLine($"[TCP服务器] 启动失败: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 清理所有客户端连接
|
||||
foreach (var client in _connectedClients.Values)
|
||||
{
|
||||
try
|
||||
{
|
||||
client.Close();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
_connectedClients.Clear();
|
||||
|
||||
// 清理信号记录
|
||||
_recentSignals.Clear();
|
||||
|
||||
// 停止监听器
|
||||
_tcpListener?.Stop();
|
||||
_logger.LogInformation("TCP服务器已停止");
|
||||
Console.WriteLine("[TCP服务器] 已停止");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定期清理过期的信号记录
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <returns></returns>
|
||||
private async Task CleanupExpiredSignalsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
long currentTime = GetCurrentTimestampMs();
|
||||
int removedCount = 0;
|
||||
|
||||
// 清理过期的信号记录
|
||||
foreach (var signalEntry in _recentSignals)
|
||||
{
|
||||
if (currentTime - signalEntry.Value > _timeWindowMs)
|
||||
{
|
||||
if (_recentSignals.TryRemove(signalEntry.Key, out _))
|
||||
{
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (removedCount > 0)
|
||||
{
|
||||
_logger.LogInformation($"清理了 {removedCount} 条过期信号记录,剩余 {_recentSignals.Count} 条");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "清理过期信号记录时发生错误");
|
||||
}
|
||||
|
||||
// 等待下一次清理
|
||||
await Task.Delay(_cleanupIntervalMs, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 报告去重统计信息
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <returns></returns>
|
||||
private async Task ReportDeduplicationStatsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
long currentCount = Interlocked.Exchange(ref _deduplicationCount, 0);
|
||||
if (currentCount > 0)
|
||||
{
|
||||
_logger.LogInformation($"过去5秒内去重了 {currentCount} 条信号");
|
||||
Console.WriteLine($"[TCP服务器] 过去5秒内去重了 {currentCount} 条信号");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "报告去重统计信息时发生错误");
|
||||
}
|
||||
|
||||
// 每5秒报告一次
|
||||
await Task.Delay(5000, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查信号是否需要去重
|
||||
/// </summary>
|
||||
/// <param name="signalData">信号数据</param>
|
||||
/// <returns>是否需要去重(true:需要去重,false:不需要去重)</returns>
|
||||
private bool ShouldDeduplicate(string signalData)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 生成信号唯一标识
|
||||
string signalId = GenerateSignalId(signalData);
|
||||
long currentTime = GetCurrentTimestampMs();
|
||||
|
||||
// 检查是否存在近期相同的信号
|
||||
if (_recentSignals.TryGetValue(signalId, out long existingTime))
|
||||
{
|
||||
// 检查是否在时间窗口内
|
||||
if (currentTime - existingTime <= _timeWindowMs)
|
||||
{
|
||||
// 记录去重计数
|
||||
Interlocked.Increment(ref _deduplicationCount);
|
||||
_logger.LogInformation($"信号去重:{signalId},时间差:{currentTime - existingTime}ms");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新或添加信号记录
|
||||
_recentSignals[signalId] = currentTime;
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "信号去重检查时发生错误");
|
||||
// 发生错误时,允许信号通过,避免影响主流程
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成信号唯一标识
|
||||
/// </summary>
|
||||
/// <param name="signalData">信号数据</param>
|
||||
/// <returns>信号唯一标识</returns>
|
||||
private string GenerateSignalId(string signalData)
|
||||
{
|
||||
// 对于shgx/production/changePackagePrevention/XXXX格式的信号,使用完整字符串作为唯一标识
|
||||
// 对于其他信号,可以根据具体格式生成唯一标识
|
||||
return signalData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前时间戳(毫秒)
|
||||
/// </summary>
|
||||
/// <returns>时间戳(毫秒)</returns>
|
||||
private long GetCurrentTimestampMs()
|
||||
{
|
||||
// 使用DateTime.UtcNow确保时间一致性,减少系统时间跳变的影响
|
||||
return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理客户端连接
|
||||
/// </summary>
|
||||
/// <param name="client">TCP客户端</param>
|
||||
/// <param name="clientEndPoint">客户端端点信息</param>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <returns></returns>
|
||||
private async Task HandleClientAsync(TcpClient client, string clientEndPoint, CancellationToken cancellationToken)
|
||||
{
|
||||
using (client)
|
||||
using (NetworkStream stream = client.GetStream())
|
||||
{
|
||||
try
|
||||
{
|
||||
// 设置读取超时
|
||||
client.ReceiveTimeout = 30000; // 30秒
|
||||
client.SendTimeout = 30000; // 30秒
|
||||
|
||||
// 缓冲区大小
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
|
||||
// 循环读取客户端数据
|
||||
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 解析接收到的数据
|
||||
string receivedData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
|
||||
_logger.LogInformation($"从客户端 {clientEndPoint} 接收到数据: {receivedData}");
|
||||
Console.WriteLine($"[TCP服务器] 从客户端 {clientEndPoint} 接收到数据: {receivedData}");
|
||||
|
||||
// 检查是否是需要广播的消息格式
|
||||
if (receivedData.StartsWith("shgx/cx/gz/"))
|
||||
{
|
||||
// 检查是否需要去重
|
||||
if (!ShouldDeduplicate(receivedData))
|
||||
{
|
||||
// 向所有已连接的客户端广播消息
|
||||
await BroadcastMessageAsync(receivedData, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 信号已去重,记录日志
|
||||
Console.WriteLine($"[TCP服务器] 信号已去重: {receivedData}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理数据并生成响应
|
||||
string response = ProcessData(receivedData);
|
||||
byte[] responseBytes = Encoding.UTF8.GetBytes(response);
|
||||
|
||||
// 发送响应
|
||||
await stream.WriteAsync(responseBytes, 0, responseBytes.Length, cancellationToken);
|
||||
_logger.LogInformation($"向客户端 {clientEndPoint} 发送响应: {response}");
|
||||
Console.WriteLine($"[TCP服务器] 向客户端 {clientEndPoint} 发送响应: {response}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"处理客户端 {clientEndPoint} 数据时发生错误");
|
||||
Console.WriteLine($"[TCP服务器] 处理客户端 {clientEndPoint} 数据时发生错误: {ex.Message}");
|
||||
|
||||
// 发送错误响应
|
||||
string errorResponse = $"Error: {ex.Message}";
|
||||
byte[] errorBytes = Encoding.UTF8.GetBytes(errorResponse);
|
||||
await stream.WriteAsync(errorBytes, 0, errorBytes.Length, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
// 客户端断开连接
|
||||
_connectedClients.TryRemove(clientEndPoint, out _);
|
||||
_logger.LogInformation($"客户端 {clientEndPoint} 断开连接,当前连接数: {_connectedClients.Count}");
|
||||
Console.WriteLine($"[TCP服务器] 客户端 {clientEndPoint} 断开连接,当前连接数: {_connectedClients.Count}");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 正常停止,无需处理
|
||||
_connectedClients.TryRemove(clientEndPoint, out _);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"处理客户端 {clientEndPoint} 连接时发生错误");
|
||||
Console.WriteLine($"[TCP服务器] 处理客户端 {clientEndPoint} 连接时发生错误: {ex.Message}");
|
||||
_connectedClients.TryRemove(clientEndPoint, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 向所有已连接的客户端广播消息
|
||||
/// </summary>
|
||||
/// <param name="message">要广播的消息</param>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <returns></returns>
|
||||
private async Task BroadcastMessageAsync(string message, CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation($"开始广播消息: {message},目标客户端数: {_connectedClients.Count}");
|
||||
Console.WriteLine($"[TCP服务器] 开始广播消息: {message},目标客户端数: {_connectedClients.Count}");
|
||||
|
||||
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
|
||||
int broadcastCount = 0;
|
||||
|
||||
// 遍历所有客户端并发送消息
|
||||
foreach (var clientEntry in _connectedClients)
|
||||
{
|
||||
string clientEndPoint = clientEntry.Key;
|
||||
TcpClient client = clientEntry.Value;
|
||||
|
||||
try
|
||||
{
|
||||
if (client.Connected)
|
||||
{
|
||||
// 直接获取网络流,不要使用using块,避免重复释放
|
||||
NetworkStream stream = client.GetStream();
|
||||
await stream.WriteAsync(messageBytes, 0, messageBytes.Length, cancellationToken);
|
||||
broadcastCount++;
|
||||
_logger.LogInformation($"向客户端 {clientEndPoint} 广播消息成功");
|
||||
Console.WriteLine($"[TCP服务器] 向客户端 {clientEndPoint} 广播消息成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 移除已断开的客户端
|
||||
_connectedClients.TryRemove(clientEndPoint, out _);
|
||||
_logger.LogInformation($"客户端 {clientEndPoint} 已断开,从连接列表中移除");
|
||||
Console.WriteLine($"[TCP服务器] 客户端 {clientEndPoint} 已断开,从连接列表中移除");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"向客户端 {clientEndPoint} 广播消息时发生错误");
|
||||
Console.WriteLine($"[TCP服务器] 向客户端 {clientEndPoint} 广播消息时发生错误: {ex.Message}");
|
||||
// 移除失败的客户端
|
||||
_connectedClients.TryRemove(clientEndPoint, out _);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation($"广播完成,成功发送到 {broadcastCount} 个客户端");
|
||||
Console.WriteLine($"[TCP服务器] 广播完成,成功发送到 {broadcastCount} 个客户端");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理接收到的数据
|
||||
/// </summary>
|
||||
/// <param name="data">接收到的数据</param>
|
||||
/// <returns>响应数据</returns>
|
||||
private string ProcessData(string data)
|
||||
{
|
||||
// 这里可以根据实际业务需求处理数据
|
||||
// 示例:简单回显接收到的数据
|
||||
return $"Server response: {data}";
|
||||
}
|
||||
}
|
||||
}
|
||||
6
global.json
Normal file
6
global.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "7.0.410",
|
||||
"rollForward": "latestFeature"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user