zhuangpei-mesbackend/DOAN.Service/MES/andon/AndonInteractionService.cs

327 lines
13 KiB
C#
Raw Normal View History

2024-06-20 13:37:46 +08:00
using Infrastructure.Attribute;
2024-06-21 14:10:17 +08:00
using Infrastructure.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using SqlSugar.IOC;
2024-06-20 13:37:46 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
2024-07-01 16:04:10 +08:00
using DOAN.Common;
using DOAN.Model.Dto;
using DOAN.Model.MES.andon;
using DOAN.Service.MES.andon.IService;
2025-02-25 13:52:50 +08:00
using DOAN.Model.MES.base_;
2025-11-13 15:30:44 +08:00
using System.Net.Sockets;
using MimeKit;
using Infrastructure;
using NPOI.HPSF;
using DOAN.Common.SocketHelper;
using NPOI.OpenXml4Net.OPC;
using DOAN.ServiceCore.MyMatchPush;
2024-06-20 13:37:46 +08:00
2024-07-01 16:04:10 +08:00
namespace DOAN.Service.MES.andon
2024-06-20 13:37:46 +08:00
{
[AppService(ServiceType = typeof(IAndonInteractionService), ServiceLifetime = LifeTime.Transient)]
public class AndonInteractionService : BaseService<AndonFaultRecord>, IAndonInteractionService
{
2024-06-21 14:10:17 +08:00
private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private OptionsSetting OptionsSetting;
2025-11-13 15:30:44 +08:00
private readonly SocketGatewayServer _socketGateway;
public AndonInteractionService(IOptions<OptionsSetting> options, SocketGatewayServer socketGateway)
{
OptionsSetting = options.Value;
_socketGateway=socketGateway;
}
2024-06-21 14:10:17 +08:00
2025-02-25 13:52:50 +08:00
/// <summary>
/// 获取线
/// </summary>
/// <returns></returns>
2025-11-13 15:30:44 +08:00
public string[] GetLine()
2025-02-25 13:52:50 +08:00
{
2025-11-13 15:30:44 +08:00
return Context.Queryable<BaseWorkRoute>().Where(it => it.Status == 1).Select(it => it.Code).ToArray();
2025-02-25 13:52:50 +08:00
}
2024-06-20 13:37:46 +08:00
/// <summary>
/// 呼叫请求
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
2025-11-13 15:30:44 +08:00
private static int PackageSort=1;
2024-06-20 15:47:00 +08:00
public int CallHandle(AndonFaultRecord record)
2024-06-20 13:37:46 +08:00
{
2025-11-13 15:30:44 +08:00
//发送报警信息
string message = $"产线:{record.LineCode},\n故障类型{record.FaultDict},\n故障内容:{record.FaultContext},\n报警人:{record.AskPerson}";
2025-11-24 11:04:05 +08:00
//发送手表
2025-11-13 15:30:44 +08:00
Watchup.StartPush(message, _socketGateway);
2024-06-20 15:47:00 +08:00
record.Id = SnowFlakeSingle.Instance.NextId().ToString();
record.StartTime = DateTime.Now;
record.Status = 1;
2025-11-13 15:30:44 +08:00
record.CreatedBy = "system";
record.CreatedTime = DateTime.Now;
2024-06-20 15:47:00 +08:00
return Context.Insertable(record).ExecuteCommand();
2025-11-13 15:30:44 +08:00
// return 0;
}
/// <summary>
/// test手表
/// </summary>
/// <returns></returns>
//public int TestWatch1()
//{
// string serverIp = "192.168.1.22";
// int port = 4021;
// try
// {
// // 1. 创建并连接 Socket
// Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// socket.Connect(serverIp, port);
// Console.WriteLine($"已连接到服务器 {serverIp}:{port}");
// // 2. 使用工具类发送字符串报文
// //分步构造 byte[],然后发送
// //包头
// byte[] packageHeader = { 0x5A };
// //包序号
// byte[] packsort = { 1 };
// // 地址
// byte[] IPaddress = { 0xff, 0xff, 0xff, 0xff };
// //命令码
// byte[] CommandCode = { 0xE0 };
// //数据长
// string message = "你好 hello 123";
// byte[] MessageData = Encoding.GetEncoding("GBK").GetBytes(message);
// byte[] MessageLength = { (byte)MessageData.Length };
// // === 先拼接除 CRC 之外的所有部分 ===
// byte[] dataWithoutCRC =
// packageHeader
// .Concat(packsort)
// .Concat(IPaddress)
// .Concat(CommandCode)
// .Concat(MessageLength)
// .Concat(MessageData).ToArray();
// //CRC : 校验和CRC 前面所有数据之和除 256 的余数
// byte[] CRC = { SocketSenderHelper.CalculateChecksum(dataWithoutCRC) };
// byte[] Body = dataWithoutCRC.Concat(CRC).ToArray();
// // SocketSenderHelper.SendBytesMessage(socket, Body);
// Console.WriteLine($"已发送消息: {message}");
// // 3. 关闭连接
// socket.Shutdown(SocketShutdown.Both);
// socket.Close();
// }
// catch (Exception ex)
// {
// throw new CustomException($"发生错误: {ex.Message}");
// Console.WriteLine($"发生错误: {ex.Message}");
// }
// return 0;
//}
public int TestWatch()
{
// 2. 使用工具类发送字符串报文
//分步构造 byte[],然后发送
//包头
byte[] packageHeader = { 0x5A };
//包序号
byte[] packsort = { 1 };
// 地址
byte[] IPaddress = { 0xff, 0xff, 0xff, 0xff };
//命令码
byte[] CommandCode = { 0xE0 };
//数据长
string message = "你好 hello 123";
byte[] MessageData = Encoding.GetEncoding("GBK").GetBytes(message);
byte[] MessageLength = { (byte)MessageData.Length };
// === 先拼接除 CRC 之外的所有部分 ===
byte[] dataWithoutCRC =
packageHeader
.Concat(packsort)
.Concat(IPaddress)
.Concat(CommandCode)
.Concat(MessageLength)
.Concat(MessageData).ToArray();
//CRC : 校验和CRC 前面所有数据之和除 256 的余数
byte[] CRC = { SocketSenderHelper.CalculateChecksum(dataWithoutCRC) };
byte[] Body = dataWithoutCRC.Concat(CRC).ToArray();
// 创建服务端,监听本机 8888 端口
var server = new SocketGatewayServer("192.168.1.11", 4021);
server.Start();
// 启动接收线程(可选,如果你想接收网关发来的字节数据)
server.StartReceiving();
Console.WriteLine("服务端已启动,等待网关(客户端)连接...");
// 模拟等待网关连接(你可以等几秒,或者根据实际情况判断)
Console.WriteLine("等待网关连接中5秒后尝试发送字节数据...");
global::System.Threading.Thread.Sleep(5000);
// 构造一个字节数据报文,比如 0x01 0x02 0x03 ...
//byte[] testData = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 };
server.SendToGateway(Body);
return 1;
2024-06-20 15:47:00 +08:00
}
public int SignIn(AndonFaultRecord record)
{
2025-11-13 15:30:44 +08:00
record.StartTime = Context.Queryable<AndonFaultRecord>().Where(it => it.Id == record.Id).Select(it => it.StartTime).First();
2024-07-01 17:30:47 +08:00
2024-06-20 17:17:38 +08:00
record.EndTime = DateTime.Now;
2024-06-21 14:10:17 +08:00
2026-01-22 17:48:26 +08:00
TimeSpan timeDifference = (record.EndTime ?? DateTime.MinValue) - (record.StartTime ?? DateTime.MinValue);
2025-11-13 15:30:44 +08:00
2024-07-06 08:38:52 +08:00
record.Duration = Math.Round((decimal)timeDifference.TotalMinutes, 2);
2024-06-20 17:17:38 +08:00
record.Status = 2;
2024-06-20 15:47:00 +08:00
return Update(record, true);
}
2024-06-21 14:10:17 +08:00
2024-06-20 15:47:00 +08:00
/// <summary>
/// 获取待响应的 记录
/// </summary>
/// <returns></returns>
public List<AndonFaultRecord> WaitingResponse()
{
2024-06-21 14:10:17 +08:00
return Context.Queryable<AndonFaultRecord>().Where(it => it.Status == 1).ToList();
}
private static List<AndonFaultDict> GetFaultDicts()
{
return DbScoped.SugarScope.CopyNew().Queryable<AndonFaultDict>().ToList();
}
/// <summary>
/// 监测超时发送邮件
/// </summary>
/// <returns></returns>
2024-07-01 17:30:47 +08:00
public string[] MonitoringMails()
2024-06-21 14:10:17 +08:00
{
2024-07-01 17:30:47 +08:00
string[] result = null;
2024-06-21 14:10:17 +08:00
// 获取异常字典
List<AndonFaultDict> andonFaults = GetFaultDicts();
// 获取超时记录
DateTime Overtime = DateTime.Now.AddHours(-1);
2024-07-12 15:17:33 +08:00
// 获取没有被响应的故障
2024-06-21 14:10:17 +08:00
List<AndonFaultRecord> AlarmRecord = Context.Queryable<AndonFaultRecord>().Where(it => it.Status == 1).Where(it => it.StartTime <= Overtime).ToList();
2025-11-13 15:30:44 +08:00
if (AlarmRecord != null && AlarmRecord.Count > 0 && andonFaults.Count > 0)
2024-06-21 14:10:17 +08:00
{
result = new string[AlarmRecord.Count];
foreach (var alarm in AlarmRecord)
{
2024-07-01 17:30:47 +08:00
2024-06-21 14:10:17 +08:00
foreach (var fault in andonFaults)
{
if (alarm.FaultDict == fault.Name)
{
2024-07-01 17:30:47 +08:00
double overSpan = Math.Round((DateTime.Now - alarm.StartTime.Value).TotalHours, 2);
2024-06-21 14:10:17 +08:00
SendEmailDto sendEmailVo = new SendEmailDto();
sendEmailVo.Subject = "上海干巷总装车间 Andon [报警升级]通知";
// 邮箱责任
2024-07-01 17:30:47 +08:00
sendEmailVo.ToUser = fault.Email ?? "qianhao.xu@doan-tech.com";
StringBuilder msg = new StringBuilder();
2024-06-21 14:10:17 +08:00
msg.Append($"Dear [{fault.Director}]经理:");
msg.Append("\n");
msg.Append("\n");
msg.Append($"[{alarm.LineCode}]产线发生[{alarm.FaultDict}]类型异常, [{alarm.AskPerson}]报警人 在{alarm.StartTime.Value.ToString("yyyy-MM-dd HH:mm:ss")}时间发起报警,已经超过{overSpan}小时未处理,请立刻到现场扫码签到并处理异常,报警内容如下:\n");
msg.Append("\n");
2024-07-01 17:30:47 +08:00
msg.Append($"{alarm.FaultContext ?? "[]"}。");
2024-06-21 14:10:17 +08:00
msg.Append("\n");
msg.Append("\n");
msg.Append("\n");
msg.Append($"Andon系统将每10分钟发送一次邮件直至[{alarm.FaultDict}]类型异常,被签到并处理!");
msg.Append("\n");
msg.Append("\n");
msg.Append("\n");
2024-07-12 15:17:33 +08:00
msg.Append("如果邮件中有任务不清楚的地方或者需要我们提供任何帮助请联系苏州道安自动化有限公司IT部门邮件地址为qianhao.xu@doan-tech.com\n");
msg.Append($"故障id {alarm.Id}");
2024-06-21 14:10:17 +08:00
sendEmailVo.Content = msg.ToString();
sendEmailVo.SendMe = true;
sendEmailVo.AddTime = DateTime.Now;
result[AlarmRecord.IndexOf(alarm)] = SendEmail(sendEmailVo);
continue;
}
}
}
}
return result;
2025-11-13 15:30:44 +08:00
}
/// <summary>
/// 定时 触发手表推送任务
/// </summary>
public void WatchPushAndon()
{
//获取没有被响应的故障
List<AndonFaultRecord> AlarmRecord = Context.Queryable<AndonFaultRecord>().Where(it => it.Status == 1).ToList();
//推送手表
StringBuilder stringBuilder = new StringBuilder();
foreach (var record in AlarmRecord)
{
stringBuilder.Append($"产线:{record.LineCode},故障类型:{record.FaultDict}\n");
}
Watchup.StartPush(stringBuilder.ToString(), _socketGateway);
2024-06-21 14:10:17 +08:00
}
/// <summary>
/// 发送邮件任务
/// </summary>
/// <param name="sendEmailVo"></param>
/// <returns></returns>
private string SendEmail(SendEmailDto sendEmailVo)
{
if (sendEmailVo == null)
{
return "请求参数不完整";
}
if (string.IsNullOrEmpty(OptionsSetting.MailOptions.FromEmail) || string.IsNullOrEmpty(OptionsSetting.MailOptions.Password))
{
return "请配置邮箱信息";
}
MailHelper mailHelper = new();
string[] toUsers = sendEmailVo.ToUser.Split(",", StringSplitOptions.RemoveEmptyEntries);
if (sendEmailVo.SendMe)
{
toUsers.Append(mailHelper.FromEmail);
}
string result = mailHelper.SendMail(toUsers, sendEmailVo.Subject, sendEmailVo.Content, sendEmailVo.FileUrl, sendEmailVo.HtmlContent);
logger.Info($"发送邮件{JsonConvert.SerializeObject(sendEmailVo)}, 结果{result}");
return result;
2024-06-20 13:37:46 +08:00
}
}
}