327 lines
12 KiB
C#
327 lines
12 KiB
C#
using Infrastructure.Attribute;
|
||
using Infrastructure.Model;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.Extensions.Options;
|
||
using Microsoft.Extensions.Primitives;
|
||
using SqlSugar.IOC;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using DOAN.Common;
|
||
using DOAN.Model.Dto;
|
||
using DOAN.Model.MES.andon;
|
||
using DOAN.Service.MES.andon.IService;
|
||
using DOAN.Model.MES.base_;
|
||
using System.Net.Sockets;
|
||
using MimeKit;
|
||
using Infrastructure;
|
||
using NPOI.HPSF;
|
||
|
||
using DOAN.Common.SocketHelper;
|
||
using NPOI.OpenXml4Net.OPC;
|
||
using DOAN.ServiceCore.MyMatchPush;
|
||
|
||
namespace DOAN.Service.MES.andon
|
||
{
|
||
[AppService(ServiceType = typeof(IAndonInteractionService), ServiceLifetime = LifeTime.Transient)]
|
||
public class AndonInteractionService : BaseService<AndonFaultRecord>, IAndonInteractionService
|
||
{
|
||
private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||
private OptionsSetting OptionsSetting;
|
||
private readonly SocketGatewayServer _socketGateway;
|
||
|
||
public AndonInteractionService(IOptions<OptionsSetting> options, SocketGatewayServer socketGateway)
|
||
{
|
||
OptionsSetting = options.Value;
|
||
_socketGateway=socketGateway;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取线
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public string[] GetLine()
|
||
{
|
||
return Context.Queryable<BaseWorkRoute>().Where(it => it.Status == 1).Select(it => it.Code).ToArray();
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 呼叫请求
|
||
/// </summary>
|
||
/// <param name="query"></param>
|
||
/// <returns></returns>
|
||
private static int PackageSort=1;
|
||
public int CallHandle(AndonFaultRecord record)
|
||
{
|
||
//发送报警信息
|
||
string message = $"产线:{record.LineCode},\n故障类型:{record.FaultDict},\n故障内容:{record.FaultContext},\n报警人:{record.AskPerson}";
|
||
//发送手表
|
||
Watchup.StartPush(message, _socketGateway);
|
||
|
||
record.Id = SnowFlakeSingle.Instance.NextId().ToString();
|
||
record.StartTime = DateTime.Now;
|
||
record.Status = 1;
|
||
record.CreatedBy = "system";
|
||
record.CreatedTime = DateTime.Now;
|
||
return Context.Insertable(record).ExecuteCommand();
|
||
// 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;
|
||
}
|
||
public int SignIn(AndonFaultRecord record)
|
||
{
|
||
record.StartTime = Context.Queryable<AndonFaultRecord>().Where(it => it.Id == record.Id).Select(it => it.StartTime).First();
|
||
|
||
record.EndTime = DateTime.Now;
|
||
|
||
TimeSpan timeDifference = record.EndTime.Value - record.StartTime.Value;
|
||
|
||
record.Duration = Math.Round((decimal)timeDifference.TotalMinutes, 2);
|
||
record.Status = 2;
|
||
return Update(record, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取待响应的 记录
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public List<AndonFaultRecord> WaitingResponse()
|
||
{
|
||
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>
|
||
public string[] MonitoringMails()
|
||
{
|
||
string[] result = null;
|
||
// 获取异常字典
|
||
List<AndonFaultDict> andonFaults = GetFaultDicts();
|
||
// 获取超时记录
|
||
DateTime Overtime = DateTime.Now.AddHours(-1);
|
||
// 获取没有被响应的故障
|
||
List<AndonFaultRecord> AlarmRecord = Context.Queryable<AndonFaultRecord>().Where(it => it.Status == 1).Where(it => it.StartTime <= Overtime).ToList();
|
||
|
||
if (AlarmRecord != null && AlarmRecord.Count > 0 && andonFaults.Count > 0)
|
||
{
|
||
result = new string[AlarmRecord.Count];
|
||
foreach (var alarm in AlarmRecord)
|
||
{
|
||
|
||
foreach (var fault in andonFaults)
|
||
{
|
||
|
||
if (alarm.FaultDict == fault.Name)
|
||
{
|
||
double overSpan = Math.Round((DateTime.Now - alarm.StartTime.Value).TotalHours, 2);
|
||
SendEmailDto sendEmailVo = new SendEmailDto();
|
||
sendEmailVo.Subject = "上海干巷总装车间 Andon [报警升级]通知";
|
||
// 邮箱责任
|
||
sendEmailVo.ToUser = fault.Email ?? "qianhao.xu@doan-tech.com";
|
||
StringBuilder msg = new StringBuilder();
|
||
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");
|
||
msg.Append($"{alarm.FaultContext ?? "[无报警内容]"}。");
|
||
msg.Append("\n");
|
||
msg.Append("\n");
|
||
msg.Append("\n");
|
||
msg.Append($"Andon系统将每10分钟发送一次邮件,直至[{alarm.FaultDict}]类型异常,被签到并处理!");
|
||
msg.Append("\n");
|
||
msg.Append("\n");
|
||
msg.Append("\n");
|
||
msg.Append("如果邮件中有任务不清楚的地方或者需要我们提供任何帮助,请联系苏州道安自动化有限公司IT部门,邮件地址为qianhao.xu@doan-tech.com\n");
|
||
msg.Append($"故障id {alarm.Id}");
|
||
sendEmailVo.Content = msg.ToString();
|
||
sendEmailVo.SendMe = true;
|
||
sendEmailVo.AddTime = DateTime.Now;
|
||
result[AlarmRecord.IndexOf(alarm)] = SendEmail(sendEmailVo);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
return result;
|
||
|
||
}
|
||
|
||
/// <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);
|
||
|
||
}
|
||
/// <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;
|
||
}
|
||
}
|
||
}
|