添加项目文件。

This commit is contained in:
2025-09-15 17:59:48 +08:00
parent 872f090cc2
commit e7adae128e
91 changed files with 14260 additions and 0 deletions

24
MoviconHub.App/App.config Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
<appSettings>
<add key="connecting1" value="Data Source=192.168.40.2;user instance=false;Initial Catalog=DissColorMachine;User ID=sa;Password=ABCabc123" />
<add key="connecting" value="Data Source=CT-PC;user instance=false;Initial Catalog=MoviconDb;User ID=sa;Password=12345678" />
<add key="RemoteConnecting" value="Data Source=CT-PC;user instance=false;Initial Catalog=MoviconDb;User ID=sa;Password=12345678" />
<add key="PLCIP" value="127.0.0.1" />
<add key="PLCPort" value="6000" />
<add key="PLCScan" value="600" />
<add key="InsCheckPort" value="COM10" />
<add key="InsCheckRate" value="9600" />
</appSettings>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@@ -0,0 +1,69 @@
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Com
{
/// <summary>
/// API配置类
/// </summary>
public class ApiConfig
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private const string ConfigFileName = "apiconfig.json";
public string ServerAddress { get; set; } = "172.16.3.203";
public int ServerPort { get; set; } = 2324;
public string SecretKey { get; set; } = "";
/// <summary>
/// 保存配置到文件
/// </summary>
public void SaveConfig()
{
try
{
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFileName);
string json = JsonConvert.SerializeObject(this, Formatting.Indented);
File.WriteAllText(configPath, json);
Logger.Info("API配置已保存");
}
catch (Exception ex)
{
Logger.Error(ex, "保存API配置时发生错误");
}
}
/// <summary>
/// 从文件加载配置
/// </summary>
/// <returns>API配置对象</returns>
public static ApiConfig LoadConfig()
{
try
{
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFileName);
if (File.Exists(configPath))
{
string json = File.ReadAllText(configPath);
var config = JsonConvert.DeserializeObject<ApiConfig>(json);
Logger.Info("已成功加载API配置");
return config;
}
}
catch (Exception ex)
{
Logger.Error(ex, "加载API配置时发生错误");
}
// 如果配置文件不存在或加载失败,则返回默认配置
Logger.Info("使用默认API配置");
return new ApiConfig();
}
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Com
{
public class ConfigHelper
{
Configuration cfa = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
/// <summary>
/// 根据Key取Value值
/// </summary>
/// <param name="key"></param>
public static string GetValue(string key)
{
return ConfigurationManager.AppSettings[key].ToString().Trim();
}
/// <summary>
/// 根据Key修改Value
/// </summary>
/// <param name="key">要修改的Key</param>
/// <param name="value">要修改为的值</param>
public static void SetValue(string key, string value)
{
//ConfigurationManager.AppSettings.Set(key, value);
//cfa.AppSettings.Settings[key].Value = value;
//cfa.Save();
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
configuration.AppSettings.Settings[key].Value = value;
configuration.Save();
ConfigurationManager.RefreshSection("appSettings");
}
/// <summary>
/// 添加新的Key Value键值对
/// </summary>
/// <param name="key">Key</param>
/// <param name="value">Value</param>
public static void Add(string key, string value)
{
ConfigurationManager.AppSettings.Add(key, value);
}
/// <summary>
/// 根据Key删除项
/// </summary>
/// <param name="key">Key</param>
public static void Remove(string key)
{
ConfigurationManager.AppSettings.Remove(key);
}
}
}

View File

@@ -0,0 +1,81 @@
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Com
{
/// <summary>
/// WebSocket客户端配置类
/// </summary>
public class WebSocketConfig
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private const string ConfigFileName = "websocket_config.json";
// WebSocket客户端配置
public string ServerAddress { get; set; } = "127.0.0.1"; // 服务器地址默认使用与API相同的地址
public int ServerPort { get; set; } = 8303; // 服务器端口
public bool AutoReconnect { get; set; } = true; // 自动重连
public int ReconnectInterval { get; set; } = 5000; // 重连间隔(毫秒)
public int HeartbeatInterval { get; set; } = 30000; // 心跳间隔(毫秒)
public int ConnectionTimeout { get; set; } = 5000; // 连接超时(毫秒)
public string DeviceCode { get; set; } = ""; // 设备编码
public string SecretKey { get; set; } = ""; // 安全密钥
public string Url { get; set; } = ""; // 安全密钥
/// <summary>
/// 循环周期数据
/// </summary>
public int Cycle { get; set; } = 1;
/// <summary>
/// 保存配置到文件
/// </summary>
public void SaveConfig()
{
try
{
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFileName);
string json = JsonConvert.SerializeObject(this, Formatting.Indented);
File.WriteAllText(configPath, json);
Logger.Info("WebSocket客户端配置已保存");
}
catch (Exception ex)
{
Logger.Error(ex, "保存WebSocket客户端配置时发生错误");
}
}
/// <summary>
/// 从文件加载配置
/// </summary>
/// <returns>WebSocket配置对象</returns>
public static WebSocketConfig LoadConfig()
{
try
{
string configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFileName);
if (File.Exists(configPath))
{
string json = File.ReadAllText(configPath);
var config = JsonConvert.DeserializeObject<WebSocketConfig>(json);
Logger.Info("已成功加载WebSocket客户端配置");
return config;
}
}
catch (Exception ex)
{
Logger.Error(ex, "加载WebSocket客户端配置时发生错误");
}
// 如果配置文件不存在或加载失败,则返回默认配置
Logger.Info("使用默认WebSocket客户端配置");
return new WebSocketConfig();
}
}
}

View File

@@ -0,0 +1,20 @@
using MoviconHub.App.Com;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App
{
/// <summary>
/// 远程的数据库
/// </summary>
public class FRemoteSqlContext
{
public static IFreeSql FDb = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.SqlServer, ConfigHelper.GetValue("RemoteConnecting"))
.UseAutoSyncStructure(true) //自动同步实体结构到数据库
.Build(); //请务必定义成 Singleton 单例模式
}
}

View File

@@ -0,0 +1,12 @@
using MoviconHub.App.Com;
namespace MoviconHub.App
{
public class FSqlContext
{
public static IFreeSql FDb = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.SqlServer, ConfigHelper.GetValue("connecting"))
.UseAutoSyncStructure(false) //自动同步实体结构到数据库
.Build(); //请务必定义成 Singleton 单例模式
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 报警模型
/// </summary>
public class AlarmModel
{
private readonly IFreeSql _fsql;
private bool _isActive;
private DateTime _startTime;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="fsql">FreeSql实例</param>
public AlarmModel(IFreeSql fsql)
{
_fsql = fsql;
_isActive = false;
DeviceCode = string.Empty;
DeviceName = string.Empty;
AlarmMessage = string.Empty;
DeviceState = 0;
}
/// <summary>
/// 设备编号
/// </summary>
public string DeviceCode { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public string DeviceName { get; set; }
/// <summary>
/// 报警信息
/// </summary>
public string AlarmMessage { get; set; }
/// <summary>
/// 设备状态码
/// </summary>
public int DeviceState { get; set; }
/// <summary>
/// Index
/// </summary>
public int Index { get; set; }
/// <summary>
/// 报警是否激活
/// </summary>
public bool IsActive
{
get => _isActive;
set
{
// 如果报警状态从激活变为不激活,保存报警记录
if (_isActive && !value)
{
SaveAlarmRecord();
}
// 如果报警状态从不激活变为激活,记录开始时间
else if (!_isActive && value)
{
_startTime = DateTime.Now;
}
_isActive = value;
}
}
/// <summary>
/// 更新设备码数据
/// </summary>
public void UpdateDeviceInfo(string deviceName, string DeviceCode)
{
this.DeviceName = deviceName;
this.DeviceCode= DeviceCode;
}
/// <summary>
/// 保存报警记录到数据库
/// </summary>
private void SaveAlarmRecord()
{
try
{
var endTime = DateTime.Now;
// 创建设备报警记录
var deviceAlarm = new DeviceAlarm
{
DeviceCode = this.DeviceCode,
DeviceName = this.DeviceName,
DeviceState = this.DeviceState,
AlarmMessage = this.AlarmMessage,
StartTime = _startTime,
EndTime = endTime
};
// 保存到数据库
_fsql.Insert(deviceAlarm).ExecuteAffrows();
Console.WriteLine($"报警记录已保存: {DeviceCode}, 开始时间: {_startTime}, 结束时间: {endTime}");
}
catch (Exception ex)
{
Console.WriteLine($"保存报警记录失败: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 清洗动作
/// </summary>
public class ClearAction
{
/// <summary>
/// 清洗事件
/// </summary>
public event EventHandler<string> ClearActionEvent;
private bool _ClearEnd;
/// <summary>
/// 清洗完成信号
/// </summary>
public bool ClearEnd
{
get { return _ClearEnd; }
set
{
if (_ClearEnd != value)
{
_ClearEnd = value;
//清洗完成
if (_ClearEnd)
{
ClearActionEvent.BeginInvoke(this, "清洗完成", null, null);
}
}
}
}
private bool _DeviceClose;
/// <summary>
/// 设备关机信号
/// </summary>
public bool DeviceClose
{
get { return _DeviceClose; }
set
{
if (_DeviceClose != value)
{
_DeviceClose = value;
//清洗完成
if (_DeviceClose)
{
ClearActionEvent.BeginInvoke(this, "设备关机", null, null);
}
}
}
}
}
}

View File

@@ -0,0 +1,190 @@
using FreeSql.DataAnnotations;
using System;
namespace MoviconHub.App.Models
{
/// <summary>
/// 清洗数据
/// </summary>
[Table(Name = "ClearData")]
public class ClearData
{
/// <summary>
/// 主键ID
/// </summary>
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 设备码
/// </summary>
[Column(Name = "DeviceCode", StringLength = 100, IsNullable = true)]
public string DeviceCode { get; set; }
/// <summary>
/// 设备名称
/// </summary>
[Column(Name = "DeviceName", StringLength = 100, IsNullable = true)]
public string DeviceName { get; set; }
/// <summary>
/// 程序进程
/// </summary>
[Column(Name = "program_process", StringLength = 100, IsNullable = true)]
public string program_process { get; set; }
/// <summary>
/// 车型
/// </summary>
[Column(Name = "vehicle_model", StringLength = 100, IsNullable = true)]
public string vehicle_model { get; set; }
/// <summary>
/// 下车号
/// </summary>
[Column(Name = "locomotive_number", StringLength = 100, IsNullable = true)]
public string locomotive_number { get; set; }
/// <summary>
/// 修程
/// </summary>
[Column(Name = "repair_process", StringLength = 100, IsNullable = true)]
public string repair_process { get; set; }
/// <summary>
/// 部件名称
/// </summary>
[Column(Name = "component_name", StringLength = 100, IsNullable = true)]
public string component_name { get; set; }
/// <summary>
/// 位别
/// </summary>
[Column(Name = "part_position", StringLength = 100, IsNullable = true)]
public string part_position { get; set; }
/// <summary>
/// 部件编号
/// </summary>
[Column(Name = "part_num", StringLength = 100, IsNullable = true)]
public string part_num { get; set; }
/// <summary>
/// 部件二维码
/// </summary>
[Column(Name = "part_qrid", StringLength = 100, IsNullable = true)]
public string part_qrid { get; set; }
/// <summary>
/// 程序进程百分比​
/// </summary>
[Column(Name = "Test_FrameworkProgramProcessPercentage", StringLength = 100, IsNullable = true)]
public string Test_FrameworkProgramProcessPercentage { get; set; }
/// <summary>
/// 程序进程​
/// </summary>
[Column(Name = "Test_FrameworkProgramProcess", StringLength = 100, IsNullable = true)]
public string Test_FrameworkProgramProcess { get; set; }
/// <summary>
/// 构架单个机型清洗时长
/// </summary>
[Column(Name = "Test_FrameworkPerModelCleaningDuration", StringLength = 100, IsNullable = true)]
public string Test_FrameworkPerModelCleaningDuration { get; set; }
/// <summary>
/// 构架单个机型用清洗剂量
/// </summary>
[Column(Name = "Test_FrameworkPerModelCleaningAgentUsage", StringLength = 100, IsNullable = true)]
public string Test_FrameworkPerModelCleaningAgentUsage { get; set; }
/// <summary>
/// 构架单个机型用水量
/// </summary>
[Column(Name = "Test_FrameworkPerModelWaterUsage", StringLength = 100, IsNullable = true)]
public string Test_FrameworkPerModelWaterUsage { get; set; }
/// <summary>
/// 水罐温度
/// </summary>
[Column(Name = "WaterTank_Temp", StringLength = 100, IsNullable = true)]
public string WaterTank_Temp { get; set; }
/// <summary>
/// 清洗剂罐温度
/// </summary>
[Column(Name = "AgentTank_Temp", StringLength = 100, IsNullable = true)]
public string AgentTank_Temp { get; set; }
/// <summary>
/// 水罐液位
/// </summary>
[Column(Name = "WaterTank_Level", StringLength = 100, IsNullable = true)]
public string WaterTank_Level { get; set; }
/// <summary>
/// 清洗剂罐液位
/// </summary>
[Column(Name = "AgentTank_Level", StringLength = 100, IsNullable = true)]
public string AgentTank_Level { get; set; }
/// <summary>
/// 浸泡池1温度
/// </summary>
[Column(Name = "SoakingTank1_Temp", StringLength = 100, IsNullable = true)]
public string SoakingTank1_Temp { get; set; }
/// <summary>
/// 浸泡池2温度
/// </summary>
[Column(Name = "SoakingTank2_Temp", StringLength = 100, IsNullable = true)]
public string SoakingTank2_Temp { get; set; }
/// <summary>
/// ​热水罐加热模式运行​​
/// </summary>
[Column(Name = "Test_WaterTankHeat", StringLength = 100, IsNullable = true)]
public string Test_WaterTankHeat { get; set; }
/// <summary>
/// ​热水罐补水模式运行​​
/// </summary>
[Column(Name = "Test_WaterTankAdd", StringLength = 100, IsNullable = true)]
public string Test_WaterTankAdd { get; set; }
/// <summary>
/// ​清洗剂罐加热模式运行
/// </summary>
[Column(Name = "Test_CleaningAgentTankHeat", StringLength = 100, IsNullable = true)]
public string Test_CleaningAgentTankHeat { get; set; }
/// <summary>
/// ​清洗剂罐补水模式运行​​
/// </summary>
[Column(Name = "Test_CleaningAgentTankAdd", StringLength = 100, IsNullable = true)]
public string Test_CleaningAgentTankAdd { get; set; }
/// <summary>
/// ​电能监控​​
/// </summary>
[Column(Name = "Test_ElectricSurveillance", StringLength = 100, IsNullable = true)]
public string Test_ElectricSurveillance { get; set; }
/// <summary>
/// ​蒸汽监控​​
/// </summary>
[Column(Name = "Test_SteamSurveillance", StringLength = 100, IsNullable = true)]
public string Test_SteamSurveillance { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; }
}
}

View File

@@ -0,0 +1,58 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 不论多部件还是单部件均采用数组,若为单部件则数组中仅有一个对象
/// </summary>
public class ComponentsInfo
{
/// <summary>
/// 车型
/// </summary>
[JsonProperty("part_Vehicle_model")]
public string part_Vehicle_model { get; set; }
/// <summary>
/// 车号
/// </summary>
[JsonProperty("part_locomotive_number")]
public string part_locomotive_number { get; set; }
/// <summary>
/// 修程
/// </summary>
[JsonProperty("part_repair_process")]
public string part_repair_process { get; set; }
/// <summary>
/// 位别
/// </summary>
[JsonProperty("part_position")]
public string part_position { get; set; }
/// <summary>
/// 部件名称
/// </summary>
[JsonProperty("component_name")]
public string part_name { get; set; }
/// <summary>
/// 部件编号
/// </summary>
[JsonProperty("part_num")]
public string part_num { get; set; }
/// <summary>
/// 二维码id
/// </summary>
[JsonProperty("part_qrid")]
public string part_qrid { get; set; }
}
}

View File

@@ -0,0 +1,199 @@
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 当前运行的清洗状态
/// </summary>
[Table(Name = "CurRunClearState")]
public class CurRunClearState
{
/// <summary>
/// 主键ID
/// </summary>
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 设备码
/// </summary>
[Column(Name = "DeviceCode", StringLength = 100, IsNullable = true)]
public string DeviceCode { get; set; }
/// <summary>
/// 设备名称
/// </summary>
[Column(Name = "DeviceName", StringLength = 100, IsNullable = true)]
public string DeviceName { get; set; }
/// <summary>
/// 程序进程
/// </summary>
[Column(Name = "program_process", StringLength = 100, IsNullable = true)]
public string program_process { get; set; }
/// <summary>
/// 车型
/// </summary>
[Column(Name = "vehicle_model", StringLength = 100, IsNullable = true)]
public string vehicle_model { get; set; }
/// <summary>
/// 下车号
/// </summary>
[Column(Name = "locomotive_number", StringLength = 100, IsNullable = true)]
public string locomotive_number { get; set; }
/// <summary>
/// 修程
/// </summary>
[Column(Name = "repair_process", StringLength = 100, IsNullable = true)]
public string repair_process { get; set; }
/// <summary>
/// 部件名称
/// </summary>
[Column(Name = "component_name", StringLength = 100, IsNullable = true)]
public string component_name { get; set; }
/// <summary>
/// 位别
/// </summary>
[Column(Name = "part_position", StringLength = 100, IsNullable = true)]
public string part_position { get; set; }
/// <summary>
/// 部件编号
/// </summary>
[Column(Name = "part_num", StringLength = 100, IsNullable = true)]
public string part_num { get; set; }
/// <summary>
/// 部件二维码
/// </summary>
[Column(Name = "part_qrid", StringLength = 100, IsNullable = true)]
public string part_qrid { get; set; }
/// <summary>
/// 程序进程百分比​
/// </summary>
[Column(Name = "Test_FrameworkProgramProcessPercentage", StringLength = 100, IsNullable = true)]
public string Test_FrameworkProgramProcessPercentage { get; set; }
/// <summary>
/// 程序进程​
/// </summary>
[Column(Name = "Test_FrameworkProgramProcess", StringLength = 100, IsNullable = true)]
public string Test_FrameworkProgramProcess { get; set; }
/// <summary>
/// 零部件设备状态
/// </summary>
[Column(Name = "Test_PartsEquipmentStatus", StringLength = 100, IsNullable = true)]
public string Test_PartsEquipmentStatus { get; set; }
/// <summary>
/// 构架单个机型清洗时长
/// </summary>
[Column(Name = "Test_FrameworkPerModelCleaningDuration", StringLength = 100, IsNullable = true)]
public string Test_FrameworkPerModelCleaningDuration { get; set; }
/// <summary>
/// 构架单个机型用清洗剂量
/// </summary>
[Column(Name = "Test_FrameworkPerModelCleaningAgentUsage", StringLength = 100, IsNullable = true)]
public string Test_FrameworkPerModelCleaningAgentUsage { get; set; }
/// <summary>
/// 构架单个机型用水量
/// </summary>
[Column(Name = "Test_FrameworkPerModelWaterUsage", StringLength = 100, IsNullable = true)]
public string Test_FrameworkPerModelWaterUsage { get; set; }
/// <summary>
/// 水罐温度
/// </summary>
[Column(Name = "WaterTank_Temp", StringLength = 100, IsNullable = true)]
public string WaterTank_Temp { get; set; }
/// <summary>
/// 清洗剂罐温度
/// </summary>
[Column(Name = "AgentTank_Temp", StringLength = 100, IsNullable = true)]
public string AgentTank_Temp { get; set; }
/// <summary>
/// 水罐液位
/// </summary>
[Column(Name = "WaterTank_Level", StringLength = 100, IsNullable = true)]
public string WaterTank_Level { get; set; }
/// <summary>
/// 清洗剂罐液位
/// </summary>
[Column(Name = "AgentTank_Level", StringLength = 100, IsNullable = true)]
public string AgentTank_Level { get; set; }
/// <summary>
/// 浸泡池1温度
/// </summary>
[Column(Name = "SoakingTank1_Temp", StringLength = 100, IsNullable = true)]
public string SoakingTank1_Temp { get; set; }
/// <summary>
/// 浸泡池2温度
/// </summary>
[Column(Name = "SoakingTank2_Temp", StringLength = 100, IsNullable = true)]
public string SoakingTank2_Temp { get; set; }
/// <summary>
/// ​热水罐加热模式运行​​
/// </summary>
[Column(Name = "Test_WaterTankHeat", StringLength = 100, IsNullable = true)]
public string Test_WaterTankHeat { get; set; }
/// <summary>
/// ​热水罐补水模式运行​​
/// </summary>
[Column(Name = "Test_WaterTankAdd", StringLength = 100, IsNullable = true)]
public string Test_WaterTankAdd { get; set; }
/// <summary>
/// ​清洗剂罐加热模式运行
/// </summary>
[Column(Name = "Test_CleaningAgentTankHeat", StringLength = 100, IsNullable = true)]
public string Test_CleaningAgentTankHeat { get; set; }
/// <summary>
/// ​清洗剂罐补水模式运行​​
/// </summary>
[Column(Name = "Test_CleaningAgentTankAdd", StringLength = 100, IsNullable = true)]
public string Test_CleaningAgentTankAdd { get; set; }
/// <summary>
/// ​电能监控​​
/// </summary>
[Column(Name = "Test_ElectricSurveillance", StringLength = 100, IsNullable = true)]
public string Test_ElectricSurveillance { get; set; }
/// <summary>
/// ​蒸汽监控​​
/// </summary>
[Column(Name = "Test_SteamSurveillance", StringLength = 100, IsNullable = true)]
public string Test_SteamSurveillance { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; }
}
}

View File

@@ -0,0 +1,62 @@
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 设备报警
/// </summary>
[Table(Name = "DeviceAlarm")]
public class DeviceAlarm
{
/// <summary>
/// 主键ID
/// </summary>
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 设备码
/// </summary>
[Column(Name = "DeviceCode", StringLength = 100, IsNullable = true)]
public string DeviceCode { get; set; }
/// <summary>
/// 设备名称
/// </summary>
[Column(Name = "DeviceName", StringLength = 100, IsNullable = true)]
public string DeviceName { get; set; }
/// <summary>
/// 设备状态
/// </summary>
[Column(Name = "DeviceState", IsNullable = true)]
public int? DeviceState { get; set; }
/// <summary>
/// 报警信息
/// </summary>
[Column(Name = "AlarmMessage", StringLength = 180, IsNullable = true)]
public string AlarmMessage { get; set; }
/// <summary>
/// 开始时间
/// </summary>
//[Column(CanUpdate = false)]
public DateTime StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
//[Column(CanUpdate = false)]
public DateTime EndTime { get; set; }
}
}

View File

@@ -0,0 +1,97 @@
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 设备状态
/// </summary>
[Table(Name = "DeviceState")]
public class DeviceState
{
/// <summary>
/// 主键ID
/// </summary>
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
/// <summary>
/// 设备码
/// </summary>
[Column(Name = "DeviceCode", StringLength = 100, IsNullable = true)]
public string DeviceCode { get; set; }
/// <summary>
/// 设备名称
/// </summary>
[Column(Name = "DeviceName", StringLength = 100, IsNullable = true)]
public string DeviceName { get; set; }
/// <summary>
/// 开机时长status为1
/// </summary>
[Column(Name = "PowerOnTime", IsNullable = true)]
public int PowerOnTime { get; set; }
/// <summary>
/// 运行时长status为2
/// </summary>
[Column(Name = "RunTime", IsNullable = true)]
public int RunTime { get; set; }
/// <summary>
/// 待机时长status为3
/// </summary>
[Column(Name = "StandbyTime", IsNullable = true)]
public int StandbyTime { get; set; }
/// <summary>
/// 故障时长status为4
/// </summary>
[Column(Name = "FaultTime", IsNullable = true)]
public int FaultTime { get; set; }
/// <summary>
/// 关机时长status为5
/// </summary>
[Column(Name = "ShutdownTime", IsNullable = true)]
public int ShutdownTime { get; set; }
///// <summary>
///// 使用率(PowerOnTime+ RunTime+ StandbyTime+ FaultTime)/( EndTime- StartTime) 从ts_sh_device_status_change_log中计算
///// </summary>
//[Column(Name = "UseRatio", IsNullable = true)]
//public int UseRatio { get; set; }
/// <summary>
/// 使用率(PowerOnTime+ RunTime+ StandbyTime+ FaultTime)/( EndTime- StartTime) 从ts_sh_device_status_change_log中计算
/// </summary>
[Column(Name = "UseRatio", StringLength = 100, IsNullable = true)]
public string UseRatio { get; set; }
/// <summary>
/// 故障次数
/// </summary>
[Column(Name = "FaultNum", IsNullable = true)]
public int FaultNum { get; set; }
/// <summary>
/// 作业次数,建议从作业数据表中取数据
/// </summary>
[Column(Name = "JobNum", IsNullable = true)]
public int JobNum { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[Column(ServerTime = DateTimeKind.Local, CanUpdate = false)]
public DateTime CreateTime { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 设备状态统计模型
/// </summary>
public class DeviceStateStaticModel
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public int Value { get; set; }
/// <summary>
/// Index
/// </summary>
public int Index { get; set; }
}
}

View File

@@ -0,0 +1,64 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 设备状态数据模型
/// Websocket数据格式
/// </summary>
public class DeviceStatusData
{
/// <summary>
/// 设备ID
/// </summary>
[JsonProperty("device_id")]
public string DeviceId { get; set; }
/// <summary>
/// 设备名称
/// </summary>
[JsonProperty("device_name")]
public string DeviceName { get; set; }
/// <summary>
/// 设备状态(开启/关闭/运行中/待机)
/// </summary>
[JsonProperty("status")]
public string Status { get; set; }
/// <summary>
/// 电压值
/// </summary>
[JsonProperty("voltage")]
public double Voltage { get; set; }
/// <summary>
/// 电流值
/// </summary>
[JsonProperty("current")]
public double Current { get; set; }
/// <summary>
/// 温度值
/// </summary>
[JsonProperty("temperature")]
public double Temperature { get; set; }
/// <summary>
/// 其他自定义状态参数
/// </summary>
[JsonProperty("parameters")]
public Dictionary<string, object> Parameters { get; set; } = new Dictionary<string, object>();
/// <summary>
/// 记录时间
/// </summary>
[JsonProperty("record_time")]
public DateTime RecordTime { get; set; } = DateTime.Now;
}
}

View File

@@ -0,0 +1,40 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 环境数据模型
/// </summary>
public class EnvironmentData
{
/// <summary>
/// 环境温度
/// </summary>
[JsonProperty("env_temperature")]
public double Temperature { get; set; }
/// <summary>
/// 环境湿度
/// </summary>
[JsonProperty("env_humidity")]
public double Humidity { get; set; }
/// <summary>
/// VOC浓度
/// </summary>
[JsonProperty("voc_concentration")]
public double VocConcentration { get; set; }
/// <summary>
/// 粉尘指数
/// </summary>
[JsonProperty("dust_index")]
public double DustIndex { get; set; }
}
}

View File

@@ -0,0 +1,35 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 设备故障数据模型
/// </summary>
public class FaultDetails
{
/// <summary>
///错误代码, 无错误为空
/// </summary>
[JsonProperty("Fault_Code")]
public string Fault_Code { get; set; }
/// <summary>
/// 错误发生时间,无错误为空
/// </summary>
[JsonProperty("Fault_Time")]
public DateTime Fault_Time { get; set; } = DateTime.Now;
/// <summary>
/// 错误描述,无错误为空
/// </summary>
[JsonProperty("Fault_Description")]
public string Fault_Description { get; set; }
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// WebSocket消息类型枚举
/// </summary>
public enum MessageType
{
/// <summary>
/// 心跳消息
/// </summary>
Heartbeat = 0,
/// <summary>
/// 设备状态数据
/// </summary>
DeviceStatus = 1,
/// <summary>
/// 试验测试数据
/// </summary>
TestData = 2,
/// <summary>
/// 设备故障信息
/// </summary>
DeviceFault = 3,
/// <summary>
/// 认证消息
/// </summary>
Authentication = 4,
/// <summary>
/// 系统消息
/// </summary>
SystemMessage = 99
}
}

View File

@@ -0,0 +1,55 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 部件信息数据模型
/// </summary>
public class PartInfo
{
[JsonProperty("part_id")]
public string PartId { get; set; }
[JsonProperty("order_id")]
public string OrderId { get; set; }
[JsonProperty("vehicle_model")]
public string VehicleModel { get; set; }
[JsonProperty("locomotive_number")]
public string LocomotiveNumber { get; set; }
[JsonProperty("repair_process")]
public string RepairProcess { get; set; }
[JsonProperty("component_name")]
public string ComponentName { get; set; }
[JsonProperty("part_position")]
public string PartPosition { get; set; }
[JsonProperty("part_num")]
public string PartNum { get; set; }
[JsonProperty("order_type_id")]
public string OrderTypeId { get; set; }
[JsonProperty("product_type_id")]
public string ProductTypeId { get; set; }
[JsonProperty("part_qrCode")]
public string PartQrCode { get; set; }
[JsonProperty("traceable_code")]
public string TraceableCode { get; set; }
[JsonProperty("part_code")]
public string PartCode { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 部件信息响应模型
/// </summary>
public class PartInfoResponse
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("msg")]
public string Message { get; set; }
[JsonProperty("data")]
public PartInfo Data { get; set; }
}
}

View File

@@ -0,0 +1,33 @@
using FreeSql.DataAnnotations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 试验箱湿度 表设置
/// </summary>
public class RTVar
{
/// <summary>
/// Name
/// </summary>
[Column(Name = "Name",StringLength =255)]
public string Name { get; set; }
/// <summary>
/// Val
/// </summary>
[Column(Name = "Val", StringLength = 255)]
public string Val { get; set; }
/// <summary>
/// LastTime
/// </summary>
[Column(Name = "LastTime")]
public DateTime LastTime { get; set; }
}
}

View File

@@ -0,0 +1,38 @@
using System;
namespace MoviconHub.App.Models
{
/// <summary>
/// 信号模型
/// </summary>
public class SglModel
{
public event EventHandler<string> SglModelChanged;
private string _CodeReady;
/// <summary>
/// 条码信息OK
/// </summary>
public string CodeReady
{
get
{
return _CodeReady;
}
set
{
if (value != _CodeReady)
{
if (!string.IsNullOrEmpty(value))
{
SglModelChanged(this, "CodeReady");//开始动作
}
_CodeReady = value;
}
}
}
}
}

View File

@@ -0,0 +1,220 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 测试数据模型 - 可根据实际测试数据结构进行扩展
/// </summary>
public class TestData
{
/// <summary>
/// 程序进程百分比​
/// </summary>
[JsonProperty("Test_FrameworkProgramProcessPercentage")]
public string Test_FrameworkProgramProcessPercentage { get; set; }
/// <summary>
/// 程序进程​
/// </summary>
[JsonProperty("Test_FrameworkProgramProcess")]
public string Test_FrameworkProgramProcess { get; set; }
/// <summary>
/// 构架设备状态​
/// </summary>
[JsonProperty("Test_FrameworkEquipmentStatus")]
public string Test_FrameworkEquipmentStatus { get; set; }
/// <summary>
/// 零部件设备状态​
/// </summary>
[JsonProperty("Test_PartsEquipmentStatus")]
public string Test_PartsEquipmentStatus { get; set; }
/// <summary>
/// ​构架累计用清洗剂量​
/// </summary>
[JsonProperty("Test_FrameworkCumulativeCleaningAgentUsage")]
public string Test_FrameworkCumulativeCleaningAgentUsage { get; set; }
/// <summary>
/// 构架累计用水量​
/// </summary>
[JsonProperty("Test_FrameworkCumulativeWaterUsage")]
public string Test_FrameworkCumulativeWaterUsage { get; set; }
/// <summary>
/// 构架累计清洗时长​
/// </summary>
[JsonProperty("Test_FrameworkCumulativeCleaningDuration")]
public string Test_FrameworkCumulativeCleaningDuration { get; set; }
/// <summary>
/// 零部件累计用水量
/// </summary>
[JsonProperty("Test_PartsCumulativeWaterUsage")]
public string Test_PartsCumulativeWaterUsage { get; set; }
/// <summary>
/// ​零部件累计清洗时长​
/// </summary>
[JsonProperty("Test_PartsCumulativeCleaningDuration")]
public string Test_PartsCumulativeCleaningDuration { get; set; }
/// <summary>
/// 累计检修数量​
/// </summary>
[JsonProperty("Test_CumulativeMaintenanceCount")]
public string Test_CumulativeMaintenanceCount { get; set; }
/// <summary>
/// 机器人1状态
/// </summary>
[JsonProperty("Test_Robot1Status")]
public string Test_Robot1Status { get; set; }
/// <summary>
/// 机器人2状态
/// </summary>
[JsonProperty("Test_Robot2Status")]
public string Test_Robot2Status { get; set; }
/// <summary>
/// 构架清洗数量
/// </summary>
[JsonProperty("Test_FrameworkCleaningCount")]
public string Test_FrameworkCleaningCount { get; set; }
/// <summary>
/// 构架单个机型清洗时长​
/// </summary>
[JsonProperty("Test_FrameworkPerModelCleaningDuration")]
public string Test_FrameworkPerModelCleaningDuration { get; set; }
/// <summary>
/// ​​构架单个机型用清洗剂量​
/// </summary>
[JsonProperty("Test_FrameworkPerModelCleaningAgentUsage")]
public string Test_FrameworkPerModelCleaningAgentUsage { get; set; }
/// <summary>
/// ​构架单个机型用水量​
/// </summary>
[JsonProperty("Test_FrameworkPerModelWaterUsage")]
public string Test_FrameworkPerModelWaterUsage { get; set; }
/// <summary>
/// ​​零部件单次清洗时长​
/// </summary>
[JsonProperty("Test_PartsSingleCleaningDuration")]
public string Test_PartsSingleCleaningDuration { get; set; }
/// <summary>
/// 零部件单次用水量​
/// </summary>
[JsonProperty("Test_PartsSingleWaterUsage")]
public string Test_PartsSingleWaterUsage { get; set; }
/// <summary>
/// ​水罐温度​
/// </summary>
[JsonProperty("Test_WaterTankTemperature")]
public string Test_WaterTankTemperature { get; set; }
/// <summary>
/// ​​清洗剂罐温度​
/// </summary>
[JsonProperty("Test_CleaningAgentTankTemperature")]
public string Test_CleaningAgentTankTemperature { get; set; }
/// <summary>
/// 浸泡池1温度
/// </summary>
[JsonProperty("Test_SoakingTank1Temperature")]
public string Test_SoakingTank1Temperature { get; set; }
/// <summary>
/// 浸泡池2温度
/// </summary>
[JsonProperty("Test_SoakingTank2Temperature")]
public string Test_SoakingTank2Temperature { get; set; }
/// <summary>
/// ​水罐液位​​
/// </summary>
[JsonProperty("Test_WaterTankLevel")]
public string Test_WaterTankLevel { get; set; }
/// <summary>
/// ​清洗剂罐液位​​
/// </summary>
[JsonProperty("Test_CleaningAgentTankLevel")]
public string Test_CleaningAgentTankLevel { get; set; }
/// <summary>
/// ​热水罐加热模式运行​​
/// </summary>
[JsonProperty("Test_WaterTankHeat")]
public string Test_WaterTankHeat { get; set; }
/// <summary>
/// ​热水罐补水模式运行​​
/// </summary>
[JsonProperty("Test_WaterTankAdd")]
public string Test_WaterTankAdd { get; set; }
/// <summary>
/// ​清洗剂罐加热模式运行
/// </summary>
[JsonProperty("Test_CleaningAgentTankHeat")]
public string Test_CleaningAgentTankHeat { get; set; }
/// <summary>
/// ​清洗剂罐补水模式运行​​
/// </summary>
[JsonProperty("Test_CleaningAgentTankAdd")]
public string Test_CleaningAgentTankAdd { get; set; }
/// <summary>
/// ​电能监控​​
/// </summary>
[JsonProperty("Test_ElectricSurveillance")]
public string Test_ElectricSurveillance { get; set; }
/// <summary>
/// ​蒸汽监控​​
/// </summary>
[JsonProperty("Test_SteamSurveillance")]
public string Test_SteamSurveillance { get; set; }
/// <summary>
/// 测试数据值集合
/// </summary>
[JsonProperty("test_values")]
public Dictionary<string, object> TestValues { get; set; } = new Dictionary<string, object>();
}
}

View File

@@ -0,0 +1,24 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// 试验数据响应模型
/// </summary>
public class TestDataResponse
{
[JsonProperty("status")]
public int Status { get; set; }
[JsonProperty("msg")]
public string Message { get; set; }
[JsonProperty("data")]
public Dictionary<string, object> Data { get; set; }
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// WebSocket连接事件参数
/// </summary>
public class WebSocketConnectEventArgs : EventArgs
{
/// <summary>
/// 服务器地址
/// </summary>
public string ServerAddress { get; set; }
/// <summary>
/// 服务器端口
/// </summary>
public int ServerPort { get; set; }
/// <summary>
/// 是否是重新连接
/// </summary>
public bool IsReconnection { get; set; }
/// <summary>
/// 连接时间
/// </summary>
public DateTime ConnectTime { get; set; } = DateTime.Now;
}
}

View File

@@ -0,0 +1,60 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// WebSocket数据模型
/// </summary>
public class WebSocketData
{
/// <summary>
/// 设备编号
/// </summary>
[JsonProperty("DeviceCode")]
public string Device_Code { get; set; } = "";
/// <summary>
/// 设备名称
/// </summary>
[JsonProperty("DeviceName")]
public string Device_Name { get; set; } = "";
/// <summary>
/// 设备厂商
/// </summary>
[JsonProperty("DeviceManufacturer")]
public string Device_Manufacturer { get; set; } = "";
/// <summary>
/// 设备状态, 代码含义自定
/// </summary>
[JsonProperty("Status")]
public string Device_Status { get; set; } = "";
/// <summary>
/// 设备错误
/// </summary>
[JsonProperty("FaultDetails")]
public FaultDetails FaultDetails { get; set; } = new FaultDetails();
/// <summary>
/// 部件信息列表
/// </summary>
[JsonProperty("ComponentsInfo")]
public List<ComponentsInfo> ListComponentsInfo { get; set; }
/// <summary>
/// 测试数据
/// </summary>
[JsonProperty("TestData")]
public TestData TestData { get; set; } = new TestData();
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// WebSocket错误事件参数
/// </summary>
public class WebSocketErrorEventArgs : EventArgs
{
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// 异常对象
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// 错误时间
/// </summary>
public DateTime ErrorTime { get; set; } = DateTime.Now;
}
}

View File

@@ -0,0 +1,107 @@
using Newtonsoft.Json;
using System;
namespace MoviconHub.App.Models
{
/// <summary>
/// WebSocket消息模型
/// </summary>
public class WebSocketMessage
{
/// <summary>
/// 状态码, 200表示成功
/// </summary>
[JsonProperty("status")]
public string Status { get; set; } = "200";
/// <summary>
/// 状态信息
/// </summary>
[JsonProperty("msg")]
public string Msg { get; set; } = "200";
/// <summary>
/// 消息数据
/// </summary>
[JsonProperty("data")]
public object Data { get; set; }
/// <summary>
/// 快速创建设备状态消息
/// </summary>
public static WebSocketMessage CreateDeviceData(object DeviceData)
{
return new WebSocketMessage
{
Msg = "success",
Status = "200",
Data = DeviceData
};
}
/// <summary>
/// 快速创建设备状态消息
/// </summary>
public static WebSocketMessage CreateDeviceStatusMessage(string deviceCode, object statusData)
{
return new WebSocketMessage
{
Msg = "success",
Status = "200",
Data = statusData
};
}
/// <summary>
/// 快速创建测试数据消息
/// </summary>
public static WebSocketMessage CreateTestDataMessage(string deviceCode, object testData)
{
return new WebSocketMessage
{
Msg = "success",
Status = "200",
Data = testData
};
}
/// <summary>
/// 快速创建故障信息消息
/// </summary>
public static WebSocketMessage CreateFaultMessage(string deviceCode, object faultData)
{
return new WebSocketMessage
{
Msg = "success",
Status = "200",
Data = faultData
};
}
/// <summary>
/// 创建心跳消息
/// </summary>
public static WebSocketMessage CreateHeartbeat(string deviceCode)
{
return new WebSocketMessage
{
Msg = "success",
Status = "200",
Data = new { status = "online" }
};
}
/// <summary>
/// 创建认证消息
/// </summary>
public static WebSocketMessage CreateAuthMessage(string deviceCode, string secretKey)
{
return new WebSocketMessage
{
Msg = "success",
Status = "200",
Data = new { code = deviceCode, key = secretKey }
};
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Models
{
/// <summary>
/// WebSocket消息事件参数
/// </summary>
public class WebSocketMessageEventArgs : EventArgs
{
/// <summary>
/// 解析后的消息对象
/// </summary>
public WebSocketMessage Message { get; set; }
/// <summary>
/// 原始消息内容
/// </summary>
public string RawMessage { get; set; }
}
}

BIN
MoviconHub.App/Movicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -0,0 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8888B1D2-AAD3-4BD5-B934-20C0E6E84DD9}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>MoviconHub.App</RootNamespace>
<AssemblyName>MoviconHub.App</AssemblyName>
<TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Movicon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<StartupObject>MoviconHub.App.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="FreeSql, Version=3.5.202.0, Culture=neutral, PublicKeyToken=a33928e5d4a4b39c, processorArchitecture=MSIL">
<HintPath>..\packages\FreeSql.3.5.202\lib\net451\FreeSql.dll</HintPath>
</Reference>
<Reference Include="FreeSql.Provider.SqlServer, Version=3.5.202.0, Culture=neutral, PublicKeyToken=d313b98af285bd88, processorArchitecture=MSIL">
<HintPath>..\packages\FreeSql.Provider.SqlServer.3.5.202\lib\net451\FreeSql.Provider.SqlServer.dll</HintPath>
</Reference>
<Reference Include="HslCommunication, Version=12.3.0.0, Culture=neutral, PublicKeyToken=3d72ad3b6b5ec0e3, processorArchitecture=MSIL">
<HintPath>..\packages\HslCommunication.12.3.0\lib\net451\HslCommunication.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=5.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.5.4.0\lib\net46\NLog.dll</HintPath>
</Reference>
<Reference Include="ReaLTaiizor, Version=3.8.1.2, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ReaLTaiizor.3.8.1.2\lib\net481\ReaLTaiizor.dll</HintPath>
</Reference>
<Reference Include="RestSharp, Version=112.1.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
<HintPath>..\packages\RestSharp.112.1.0\lib\net48\RestSharp.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SqlClient, Version=4.6.1.6, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Data.SqlClient.4.8.6\lib\net461\System.Data.SqlClient.dll</HintPath>
</Reference>
<Reference Include="System.Design" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Text.Json, Version=8.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Json.8.0.4\lib\net462\System.Text.Json.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Com\ApiConfig.cs" />
<Compile Include="Com\ConfigHelper.cs" />
<Compile Include="Com\WebSocketConfig.cs" />
<Compile Include="FRemoteSqlContext.cs" />
<Compile Include="frmMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="frmMain.Designer.cs">
<DependentUpon>frmMain.cs</DependentUpon>
</Compile>
<Compile Include="FSqlContext.cs" />
<Compile Include="Models\AlarmModel.cs" />
<Compile Include="Models\ClearAction.cs" />
<Compile Include="Models\ClearData.cs" />
<Compile Include="Models\ComponentsInfo.cs" />
<Compile Include="Models\CurRunClearState.cs" />
<Compile Include="Models\DeviceAlarm.cs" />
<Compile Include="Models\DeviceState.cs" />
<Compile Include="Models\DeviceStateStaticModel.cs" />
<Compile Include="Models\FaultDetails.cs" />
<Compile Include="Models\DeviceStatusData.cs" />
<Compile Include="Models\EnvironmentData.cs" />
<Compile Include="Models\MessageType.cs" />
<Compile Include="Models\PartInfo.cs" />
<Compile Include="Models\PartInfoResponse.cs" />
<Compile Include="Models\RTVar.cs" />
<Compile Include="Models\SglModel.cs" />
<Compile Include="Models\TestData.cs" />
<Compile Include="Models\TestDataResponse.cs" />
<Compile Include="Models\WebSocketConnectEventArgs.cs" />
<Compile Include="Models\WebSocketData.cs" />
<Compile Include="Models\WebSocketErrorEventArgs.cs" />
<Compile Include="Models\WebSocketMessage.cs" />
<Compile Include="Models\WebSocketMessageEventArgs.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\ApiHelper.cs" />
<Compile Include="Services\ApiService.cs" />
<Compile Include="Services\DBServices.cs" />
<Compile Include="Services\WebSocketClient.cs" />
<Compile Include="Services\WebSocketClientHelper.cs" />
<EmbeddedResource Include="frmMain.resx">
<DependentUpon>frmMain.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Content Include="NLog.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="NLog.xsd">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<None Include="websocket_config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Content Include="Movicon.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
autoReload="true"
throwExceptions="false"
internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">
<!-- optional, add some variables
https://github.com/nlog/NLog/wiki/Configuration-file#variables
-->
<variable name="logDirectory" value="${basedir}/Log/${shortdate}"/>
<variable name="ActionDirectory" value="${basedir}/OperationLogs/${shortdate}"/>
<variable name="myvar" value="myvalue"/>
<!--
See https://github.com/nlog/nlog/wiki/Configuration-file
for information on customizing logging rules and outputs.
-->
<targets>
<!--
add your targets here
See https://github.com/nlog/NLog/wiki/Targets for possible targets.
See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
-->
<target xsi:type="File" name="MoviconHubApp" fileName="${logDirectory}/ErrorMessage.txt" maxArchiveDays="30" archiveAboveSize="10240000" maxArchiveFiles="200"
layout="${longdate} ■${level}${newline} ▲${stacktrace}${newline} ◆${message}${newline}${newline}***************************************************************************" />
<target xsi:type="File" name="MoviconHubAppOperation" fileName="${ActionDirectory}/OperationLog.txt" maxArchiveDays="30" archiveAboveSize="10240000" maxArchiveFiles="500"
layout="${longdate} ■${level}${newline} ◆${message}${newline}***************************************************************************" />
<!--
Write events to a file with the date in the filename.
<target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
layout="${longdate} ${uppercase:${level}} ${message}" />
-->
</targets>
<rules>
<!-- add your logging rules here -->
<logger name="*" minlevel="Error" writeTo="MoviconHubApp" />
<logger name="*" minlevel="Info" maxlevel="Info" writeTo="MoviconHubAppOperation" />
<!--
Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace) to "f"
<logger name="*" minlevel="Debug" writeTo="f" />
-->
</rules>
</nlog>

3728
MoviconHub.App/NLog.xsd Normal file

File diff suppressed because it is too large Load Diff

66
MoviconHub.App/Program.cs Normal file
View File

@@ -0,0 +1,66 @@
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MoviconHub.App
{
static class Program
{
//日志的实例化
private static Logger logger = LogManager.GetCurrentClassLogger();
public static bool IsActive { get; private set; }
public static DateTime StartTime = DateTime.Now;
public static string SystemName = "";
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
bool isAppRunning = false;
Mutex mutex = new Mutex(true, System.Diagnostics.Process.GetCurrentProcess().ProcessName, out isAppRunning);
if (!isAppRunning)
{
MessageBox.Show("程序已运行,不能再次打开!");
Environment.Exit(1);
}
// 授权 12.3
//V12.3.0: d8868ab9 - 4494 - 4056 - 98c6 - b669e2434e25
//V12.2.0: fe49cdb6 - b388 - 4c05 - 9b66 - 0e3f1ad3627f
//V12.1.3: 2fb771c7 - 4c29 - 445d - bddd - a7b8a75de397
//V12.1.2: b23b00e2 - ce46 - 4bfc - b33c - 71c47c2c11c2
//V12.1.1: 95057912 - 579c - 42d1 - ad31 - eb598f73706f
//V11.8.2: b980977c - 3323 - 4876 - b633 - c0bef93d75c1
if (!HslCommunication.Authorization.SetAuthorizationCode("d8868ab9-4494-4056-98c6-b669e2434e25"))
{
//active failed
MessageBox.Show("授权失败当前程序只能使用8小时");
// return;
}
else
{
IsActive = true;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Exception ex = e.ExceptionObject as Exception;
logger.Error(String.Format("ErrSource : {0} ErrMsg : {1}", ex.StackTrace.ToString(), ex.Message.ToString()));
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("MoviconHub.App")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MoviconHub.App")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("8888b1d2-aad3-4bd5-b934-20c0e6e84dd9")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace MoviconHub.App.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MoviconHub.App.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace MoviconHub.App.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@@ -0,0 +1,77 @@
using MoviconHub.App.Com;
using MoviconHub.App.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Services
{
public static class ApiHelper
{
private static ApiService _apiService;
private static ApiConfig _apiConfig;
/// <summary>
/// 初始化API帮助类
/// </summary>
public static void Initialize()
{
//_apiConfig = ApiConfig.LoadConfig();
//string baseUrl = $"http://{_apiConfig.ServerAddress}:{_apiConfig.ServerPort}/";
string baseUrl = $"http://172.16.3.203:8000";
_apiService = new ApiService(baseUrl);
}
/// <summary>
/// 获取部件信息
/// </summary>
/// <param name="partQrCodeId">二维码零件ID</param>
/// <param name="deviceCode">设备编码</param>
/// <returns>部件信息</returns>
public static async Task<PartInfoResponse> GetPartInfoAsync(string partQrCodeId, string deviceCode)
{
if (_apiService == null)
{
Initialize();
}
//当前不需要设备条码
return await _apiService.GetPartInfoAsync(partQrCodeId, deviceCode);
}
/// <summary>
/// 获取测试数据
/// </summary>
/// <param name="partQrCodeId">二维码零件ID</param>
/// <param name="deviceCode">设备编码</param>
/// <returns>测试数据</returns>
public static async Task<TestDataResponse> GetTestDataAsync(string partQrCodeId, string deviceCode)
{
if (_apiService == null)
{
Initialize();
}
return await _apiService.GetTestDataAsync(partQrCodeId, deviceCode);
}
/// <summary>
/// 更新服务器配置
/// </summary>
/// <param name="serverAddress">服务器地址</param>
/// <param name="port">端口号</param>
public static void UpdateServerConfig(string serverAddress, int port)
{
if (_apiService == null || _apiConfig == null)
{
Initialize();
}
_apiConfig.ServerAddress = serverAddress;
_apiConfig.ServerPort = port;
_apiConfig.SaveConfig();
_apiService.ConfigureServerAddress(serverAddress, port);
}
}
}

View File

@@ -0,0 +1,155 @@
using MoviconHub.App.Models;
using Newtonsoft.Json;
using NLog;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Services
{
/// <summary>
/// Api 服务类
/// </summary>
public class ApiService
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly string _baseUrl;
private readonly RestClient _client;
/// <summary>
/// 实例化函数
/// </summary>
/// <param name="baseUrl"></param>
public ApiService(string baseUrl)
{
_baseUrl = baseUrl;
_client = new RestClient(baseUrl);
}
private string GetFullRequestUrl(RestRequest request)
{
var resource = request.Resource;
var queryParams = string.Join("&", request.Parameters
.Where(p => p.Type == ParameterType.QueryString)
.Select(p => $"{p.Name}={Uri.EscapeDataString(p.Value?.ToString() ?? "")}"));
return $"{_baseUrl.TrimEnd('/')}/{resource.TrimStart('/')}{(string.IsNullOrEmpty(queryParams) ? "" : "?" + queryParams)}";
}
/// <summary>
/// 获取部件信息
/// </summary>
/// <param name="partQrCodeId">二维码零件ID</param>
/// <param name="deviceCode">设备编码</param>
/// <returns>部件信息</returns>
public async Task<PartInfoResponse> GetPartInfoAsync(string partQrCodeId, string deviceCode)
{
try
{
var request = new RestRequest("/mes/order/iotPartInfo/getPartInfo", Method.Get);
request.AddParameter("PartQRCodeId", partQrCodeId);
//request.AddParameter("DeviceCode", deviceCode);
var response = await _client.ExecuteAsync(request);
if (response.IsSuccessful)
{
Logger.Info($"{response.Content}");
var Data = JsonConvert.DeserializeObject<PartInfoResponse>(response.Content);
Logger.Info($"{Data.ToString()}");
return JsonConvert.DeserializeObject<PartInfoResponse>(response.Content);
}
else
{
Logger.Error($"获取部件信息失败:{response.ErrorMessage}, 状态码:{response.StatusCode}");
return new PartInfoResponse
{
Status = (int)response.StatusCode,
Message = response.ErrorMessage,
Data = null
};
}
}
catch (Exception ex)
{
Logger.Error(ex, "获取部件信息时发生异常");
return new PartInfoResponse
{
Status = 500,
Message = $"发生异常:{ex.Message}",
Data = null
};
}
}
/// <summary>
/// 获取测试数据
/// </summary>
/// <param name="partQrCodeId">二维码零件ID</param>
/// <param name="deviceCode">设备编码</param>
/// <returns>测试数据</returns>
public async Task<TestDataResponse> GetTestDataAsync(string partQrCodeId, string deviceCode)
{
try
{
var request = new RestRequest("getTestdata", Method.Get);
request.AddParameter("PartQRCodeId", partQrCodeId);
request.AddParameter("DeviceCode", deviceCode);
var response = await _client.ExecuteAsync(request);
if (response.IsSuccessful)
{
return JsonConvert.DeserializeObject<TestDataResponse>(response.Content);
}
else
{
Logger.Error($"获取测试数据失败:{response.ErrorMessage}, 状态码:{response.StatusCode}");
return new TestDataResponse
{
Status = (int)response.StatusCode,
Message = response.ErrorMessage,
Data = null
};
}
}
catch (Exception ex)
{
Logger.Error(ex, "获取测试数据时发生异常");
return new TestDataResponse
{
Status = 500,
Message = $"发生异常:{ex.Message}",
Data = null
};
}
}
/// <summary>
/// 配置服务器地址和端口
/// </summary>
/// <param name="serverAddress">服务器地址</param>
/// <param name="port">端口号</param>
public void ConfigureServerAddress(string serverAddress, int port)
{
string newBaseUrl = $"http://{serverAddress}:{port}/";
// 创建新的RestClient实例
var newClient = new RestClient(newBaseUrl);
// 使用反射替换私有字段因为RestClient实例不能直接修改BaseUrl
var clientType = _client.GetType();
var baseUrlField = clientType.GetField("_baseUrl", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (baseUrlField != null)
{
baseUrlField.SetValue(_client, newBaseUrl);
}
Logger.Info($"服务器地址已更新为:{newBaseUrl}");
}
}
}

View File

@@ -0,0 +1,510 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MoviconHub.App.Models;
using NLog;
namespace MoviconHub.App.Services
{
/// <summary>
/// Db Server
/// </summary>
public class DBServices : IDisposable
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private Timer _dataPollingTimer;
private readonly object _lockObject = new object();
private bool _isRunning = false;
private int _pollingInterval = 1000; // 默认轮询间隔1秒
private WebSocketData _realtimeData;
private CancellationTokenSource _cancellationTokenSource;
/// <summary>
/// 实时数据对象用于缓存从RTVar表中读取的数据
/// </summary>
public WebSocketData RealtimeData
{
get { return _realtimeData; }
}
public SglModel SglModel { get; }
/// <summary>
/// 实时数据更新事件
/// </summary>
public event EventHandler<WebSocketData> DataUpdated;
/// <summary>
/// 初始化数据库服务
/// </summary>
public DBServices(SglModel sglModel)
{
_realtimeData = new WebSocketData();
_cancellationTokenSource = new CancellationTokenSource();
SglModel = sglModel;
}
/// <summary>
/// 开始实时数据轮询
/// </summary>
/// <param name="interval">轮询间隔,单位毫秒</param>
/// <returns>是否成功启动</returns>
public bool StartPolling(int interval = 2000)
{
if (_isRunning)
return false;
lock (_lockObject)
{
if (_isRunning)
return false;
_pollingInterval = interval;
_isRunning = true;
_cancellationTokenSource = new CancellationTokenSource();
// 使用Task来轮询数据
Task.Run(async () => await PollDataAsync(_cancellationTokenSource.Token), _cancellationTokenSource.Token);
Logger.Info($"实时数据轮询已启动,间隔: {_pollingInterval}ms");
return true;
}
}
/// <summary>
/// 停止实时数据轮询
/// </summary>
public void StopPolling()
{
if (!_isRunning)
return;
lock (_lockObject)
{
if (!_isRunning)
return;
_cancellationTokenSource.Cancel();
_isRunning = false;
Logger.Info("实时数据轮询已停止");
}
}
/// <summary>
/// 异步轮询数据任务
/// </summary>
/// <param name="cancellationToken">取消标记</param>
private async Task PollDataAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
// 读取RTVar表数据
await ReadRTVarDataAsync();
// 等待指定的轮询间隔
await Task.Delay(_pollingInterval, cancellationToken);
}
catch (TaskCanceledException)
{
// 任务被取消,正常退出
break;
}
catch (Exception ex)
{
Logger.Error(ex, "轮询RTVar数据时发生错误");
// 发生错误时,等待一段时间后重试
await Task.Delay(5000, cancellationToken);
}
}
}
/// <summary>
/// 异步读取RTVar表数据
/// </summary>
private async Task ReadRTVarDataAsync()
{
try
{
// 使用FSqlContext封装的FreeSql调用DB数据
var rtVars = await FSqlContext.FDb.Select<RTVar>().ToListAsync();
// 更新实时数据对象
UpdateWebSocketData(rtVars);
// 触发数据更新事件
//DataUpdated?.Invoke(this, _realtimeData);
}
catch (Exception ex)
{
Logger.Error(ex, "读取RTVar数据时发生错误");
throw;
}
}
/// <summary>
/// 使用RTVar数据更新WebSocketData模型
/// </summary>
/// <param name="rtVars">RTVar数据列表</param>
private void UpdateWebSocketData(List<RTVar> rtVars)
{
if (rtVars == null || rtVars.Count == 0)
return;
lock (_lockObject)
{
// 更新设备状态信息
var deviceCodeVar = rtVars.FirstOrDefault(v => v.Name == "Device_Code");
if (deviceCodeVar != null)
_realtimeData.Device_Code = deviceCodeVar.Val;
var deviceNameVar = rtVars.FirstOrDefault(v => v.Name == "Device_Name");
if (deviceNameVar != null)
_realtimeData.Device_Name = deviceNameVar.Val;
var deviceManufacturerVar = rtVars.FirstOrDefault(v => v.Name == "Device_Manufacturer");
if (deviceManufacturerVar != null)
_realtimeData.Device_Manufacturer = deviceManufacturerVar.Val;
var statusVar = rtVars.FirstOrDefault(v => v.Name == "Device_Status");
if (statusVar != null)
_realtimeData.Device_Status = statusVar.Val;
// 解析故障信息
UpdateFaultDetails(rtVars);
// 解析组件信息
UpdateComponentsInfo(rtVars);
// 解析测试数据
UpdateTestData(rtVars);
//获取条码信息,确定是否需要搜索数据
SglModel.CodeReady = rtVars.FirstOrDefault(v => v.Name == "part_qrid").Val;
UpdateRemoteDb(RealtimeData);
//把最新的数据赋值给WebSocketClient中
WebSocketClientHelper.CurWebSocketData = RealtimeData;
//更新数据到远程数据库
// 记录日志
Logger.Debug("实时数据已更新");
}
}
/// <summary>
/// 更新远程数据库
/// </summary>
/// <param name="webSocketData"></param>
private void UpdateRemoteDb(WebSocketData webSocketData)
{
// 获取组件信息
var component = webSocketData.ListComponentsInfo?.FirstOrDefault();
// 创建CurRunClearState对象并映射数据
var curRunClearState = new CurRunClearState()
{
//只有一个,更新数据
Id = 1,
// 基本信息
DeviceCode = webSocketData.Device_Code,
DeviceName = webSocketData.Device_Name,
// 组件信息
part_qrid = component?.part_qrid,
part_num = component?.part_num,
part_position = component?.part_position,
component_name = component?.part_name,
vehicle_model = component?.part_Vehicle_model,
locomotive_number = component?.part_locomotive_number,
repair_process = component?.part_repair_process,
program_process = webSocketData.TestData.Test_FrameworkProgramProcess,
// 程序进程
Test_FrameworkProgramProcess = webSocketData.TestData.Test_FrameworkProgramProcess,
Test_FrameworkProgramProcessPercentage = webSocketData.TestData.Test_FrameworkProgramProcessPercentage,
// 设备状态
Test_PartsEquipmentStatus = webSocketData.TestData.Test_PartsEquipmentStatus,
// 清洗时长和用量
Test_FrameworkPerModelCleaningDuration = webSocketData.TestData.Test_FrameworkPerModelCleaningDuration,
Test_FrameworkPerModelCleaningAgentUsage = webSocketData.TestData.Test_FrameworkPerModelCleaningAgentUsage,
Test_FrameworkPerModelWaterUsage = webSocketData.TestData.Test_FrameworkPerModelWaterUsage,
// 水箱和清洗剂罐信息
WaterTank_Temp = webSocketData.TestData.Test_WaterTankTemperature,
AgentTank_Temp = webSocketData.TestData.Test_CleaningAgentTankTemperature,
WaterTank_Level = webSocketData.TestData.Test_WaterTankLevel,
AgentTank_Level = webSocketData.TestData.Test_CleaningAgentTankLevel,
// 浸泡池温度
SoakingTank1_Temp = webSocketData.TestData.Test_SoakingTank1Temperature,
SoakingTank2_Temp = webSocketData.TestData.Test_SoakingTank2Temperature,
// 运行模式
Test_WaterTankHeat = webSocketData.TestData.Test_WaterTankHeat,
Test_WaterTankAdd = webSocketData.TestData.Test_WaterTankAdd,
Test_CleaningAgentTankHeat = webSocketData.TestData.Test_CleaningAgentTankHeat,
Test_CleaningAgentTankAdd = webSocketData.TestData.Test_CleaningAgentTankAdd,
// 监控信息
Test_ElectricSurveillance = webSocketData.TestData.Test_ElectricSurveillance,
Test_SteamSurveillance = webSocketData.TestData.Test_SteamSurveillance
};
var Data = FRemoteSqlContext.FDb
.InsertOrUpdate<CurRunClearState>()
.SetSource(curRunClearState)
.ExecuteAffrows();
if (Data > 0)
{
Logger.Debug("实时数据已更新到远程数据库");
}
}
/// <summary>
/// 更新故障信息
/// </summary>
/// <param name="rtVars">RTVar数据列表</param>
private void UpdateFaultDetails(List<RTVar> rtVars)
{
var hasFault = rtVars.FirstOrDefault(v => v.Name.Contains("Fault_"));
if (hasFault != null && !string.IsNullOrEmpty(hasFault.Val))
{
if (_realtimeData.FaultDetails == null)
_realtimeData.FaultDetails = new FaultDetails();
var faultDevice = rtVars.FirstOrDefault(v => v.Name == "Fault_Code");
if (faultDevice != null)
_realtimeData.FaultDetails.Fault_Code = faultDevice.Val;
var faultTime = rtVars.FirstOrDefault(v => v.Name == "Fault_Time");
if (faultTime != null && DateTime.TryParse(faultTime.Val, out DateTime time))
_realtimeData.FaultDetails.Fault_Time = time;
var faultDescription = rtVars.FirstOrDefault(v => v.Name == "Fault_Description");
if (faultDescription != null)
_realtimeData.FaultDetails.Fault_Description = faultDescription.Val;
}
else
{
// 没有故障时,置空故障信息
_realtimeData.FaultDetails = null;
}
}
/// <summary>
/// 更新组件信息
/// </summary>
/// <param name="rtVars">RTVar数据列表</param>
private void UpdateComponentsInfo(List<RTVar> rtVars)
{
var componentsCountVar = rtVars.FirstOrDefault(v => v.Name.Contains("part_"));
if (componentsCountVar != null)
{
if (_realtimeData.ListComponentsInfo == null) _realtimeData.ListComponentsInfo = new List<ComponentsInfo>() { new ComponentsInfo() };
//else
// _realtimeData.ListComponentsInfo.Clear();
var component = _realtimeData.ListComponentsInfo.FirstOrDefault();
//var partQRCode = rtVars.FirstOrDefault(v => v.Name == $"part_qrid");
//if (partQRCode != null)
// component.part_qrid = partQRCode.Val;
var partNum = rtVars.FirstOrDefault(v => v.Name == $"part_num");
if (partNum != null)
component.part_num = partNum.Val;
var partPosition = rtVars.FirstOrDefault(v => v.Name == $"part_position");
if (partPosition != null)
component.part_position = partPosition.Val;
var componentName = rtVars.FirstOrDefault(v => v.Name == $"part_name");
if (componentName != null)
component.part_name = componentName.Val;
// 车型
var vehicleModel = rtVars.FirstOrDefault(v => v.Name == $"part_Vehicle_model");
if (vehicleModel != null)
component.part_Vehicle_model = vehicleModel.Val;
// 车号
var locomotiveNumber = rtVars.FirstOrDefault(v => v.Name == $"part_locomotive_number");
if (locomotiveNumber != null)
component.part_locomotive_number = locomotiveNumber.Val;
// 修程
var repairProcess = rtVars.FirstOrDefault(v => v.Name == $"part_repair_process");
if (repairProcess != null)
component.part_repair_process = repairProcess.Val;
// Id
var part_qrid = rtVars.FirstOrDefault(v => v.Name == $"part_qrid");
if (part_qrid != null)
component.part_qrid = part_qrid.Val;
}
else
{
// 没有组件信息时,初始化空列表
if (_realtimeData.ListComponentsInfo == null)
_realtimeData.ListComponentsInfo = new List<ComponentsInfo>() { new ComponentsInfo() };
//else
// _realtimeData.ListComponentsInfo.Clear();
}
}
///// <summary>
///// 更新组件信息
///// </summary>
///// <param name="rtVars">RTVar数据列表</param>
//private void UpdateComponentsInfoMulit(List<RTVar> rtVars)
//{
// var componentsCountVar = rtVars.FirstOrDefault(v => v.Name == "ComponentsCount");
// if (componentsCountVar != null && int.TryParse(componentsCountVar.Val, out int count) && count > 0)
// {
// if (_realtimeData.ListComponentsInfo == null)
// _realtimeData.ListComponentsInfo = new List<ComponentsInfo>();
// else
// _realtimeData.ListComponentsInfo.Clear();
// // 解析多个组件信息
// for (int i = 0; i < count; i++)
// {
// var component = new ComponentsInfo();
// var partQRCode = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_PartQRCode");
// if (partQRCode != null)
// component.part_qrid = partQRCode.Val;
// var partNum = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_PartNum");
// if (partNum != null)
// component.part_num = partNum.Val;
// var partPosition = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_PartPosition");
// if (partPosition != null && int.TryParse(partPosition.Val, out int position))
// component.part_position = position;
// var componentName = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_ComponentName");
// if (componentName != null)
// component.component_name = componentName.Val;
// // 车型
// var vehicleModel = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_VehicleModel");
// if (vehicleModel != null)
// component.Vehicle_model = vehicleModel.Val;
// // 车号
// var locomotiveNumber = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_LocomotiveNumber");
// if (locomotiveNumber != null)
// component.locomotive_number = locomotiveNumber.Val;
// // 修程
// var repairProcess = rtVars.FirstOrDefault(v => v.Name == $"Component_{i}_RepairProcess");
// if (repairProcess != null)
// component.repair_process = repairProcess.Val;
// // 添加到列表
// _realtimeData.ListComponentsInfo.Add(component);
// }
// }
// else
// {
// // 没有组件信息时,初始化空列表
// if (_realtimeData.ListComponentsInfo == null)
// _realtimeData.ListComponentsInfo = new List<ComponentsInfo>();
// else
// _realtimeData.ListComponentsInfo.Clear();
// }
//}
/// <summary>
/// 更新测试数据
/// </summary>
/// <param name="rtVars">RTVar数据列表</param>
private void UpdateTestData(List<RTVar> rtVars)
{
var hasTestData = rtVars.FirstOrDefault(v => v.Name.Contains("Test_"));
if (hasTestData != null && !string.IsNullOrEmpty(hasTestData.Val))
{
if (_realtimeData.TestData == null)
_realtimeData.TestData = new TestData();
// 从RTVar中提取测试数据
var testItems = rtVars.Where(v => v.Name.StartsWith("Test_")).ToList();
foreach (var item in testItems)
{
// 根据命名规则解析测试数据项
string itemName = item.Name;
// 使用反射设置属性
var property = typeof(TestData).GetProperty(itemName);
if (property != null && property.CanWrite)
{
if (property.PropertyType == typeof(string))
{
property.SetValue(_realtimeData.TestData, item.Val);
}
else if (property.PropertyType == typeof(int) && int.TryParse(item.Val, out int intValue))
{
property.SetValue(_realtimeData.TestData, intValue);
}
else if (property.PropertyType == typeof(double) && double.TryParse(item.Val, out double doubleValue))
{
property.SetValue(_realtimeData.TestData, doubleValue);
}
else if (property.PropertyType == typeof(DateTime) && DateTime.TryParse(item.Val, out DateTime dateValue))
{
property.SetValue(_realtimeData.TestData, dateValue);
}
else if (property.PropertyType == typeof(bool) && bool.TryParse(item.Val, out bool boolValue))
{
property.SetValue(_realtimeData.TestData, boolValue);
}
}
}
}
else
{
// 没有测试数据时,置空测试数据对象
_realtimeData.TestData = null;
}
}
/// <summary>
/// 获取最新的RTVar数据可在外部直接调用
/// </summary>
/// <returns>WebSocketData对象</returns>
public async Task<WebSocketData> GetLatestDataAsync()
{
await ReadRTVarDataAsync();
return _realtimeData;
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
StopPolling();
_cancellationTokenSource?.Dispose();
_dataPollingTimer?.Dispose();
}
}
}

View File

@@ -0,0 +1,561 @@
using HslCommunication;
using MoviconHub.App.Com;
using MoviconHub.App.Models;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MoviconHub.App.Services
{
/// <summary>
/// WebSocket客户端类基于HslCommunication库实现
/// </summary>
public class WebSocketClient : IDisposable
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly WebSocketConfig _config;
private HslCommunication.WebSocket.WebSocketClient _client;
private Timer _heartbeatTimer;
private Timer _reconnectTimer;
private bool _isConnected = false;
private bool _reconnecting = false;
private bool _disposed = false;
private int _reconnectAttempts = 0;
private readonly int _maxReconnectInterval = 300000; // 最大重连间隔默认5分钟
private readonly object _lockObject = new object();
// 事件定义
public event EventHandler<MoviconHub.App.Models.WebSocketMessageEventArgs> MessageReceived;
public event EventHandler<WebSocketConnectEventArgs> Connected;
public event EventHandler<WebSocketConnectEventArgs> Disconnected;
public event EventHandler<WebSocketErrorEventArgs> Error;
/// <summary>
/// 初始化WebSocket客户端
/// </summary>
public WebSocketClient()
{
_config = WebSocketConfig.LoadConfig();
InitializeClient();
}
/// <summary>
/// 初始化WebSocket客户端
/// </summary>
private void InitializeClient()
{
try
{
// 初始化客户端并设置服务器地址和端口
_client = new HslCommunication.WebSocket.WebSocketClient(_config.ServerAddress, _config.ServerPort, _config.Url);
// 设置日志记录器
_client.LogNet = new HslCommunication.LogNet.LogNetSingle("websocket_logs.txt");
// 注册消息接收事件处理
_client.OnClientApplicationMessageReceive += (message) =>
{
try
{
Logger.Debug($"收到消息: {message.ToString()}");
// 尝试解析消息
MoviconHub.App.Models.WebSocketMessage wsMessage =
JsonConvert.DeserializeObject<MoviconHub.App.Models.WebSocketMessage>(message.ToString());
if (wsMessage != null)
{
// 触发消息接收事件
MessageReceived?.Invoke(this, new MoviconHub.App.Models.WebSocketMessageEventArgs
{
Message = wsMessage,
RawMessage = message.ToString()
});
}
}
catch (Exception ex)
{
Logger.Error(ex, "处理接收到的WebSocket消息时发生错误");
}
};
// 注册连接成功事件
_client.OnClientConnected += () =>
{
Logger.Info($"已成功连接到WebSocket服务器 {_config.ServerAddress}:{_config.ServerPort}");
_isConnected = true;
// 启动心跳定时器
//StartHeartbeatTimer();
// 触发连接事件
Connected?.Invoke(this, new WebSocketConnectEventArgs
{
ServerAddress = _config.ServerAddress,
ServerPort = _config.ServerPort,
IsReconnection = _reconnectAttempts > 0
});
};
// 注册网络错误事件 - 根据文档示例调整参数
_client.OnNetworkError += (sender, e) =>
{
string errorMessage = "WebSocket网络连接错误";
Logger.Error(errorMessage);
HandleDisconnection();
Error?.Invoke(this, new WebSocketErrorEventArgs { ErrorMessage = errorMessage });
};
}
catch (Exception ex)
{
Logger.Error(ex, "初始化WebSocket客户端时发生错误");
}
}
/// <summary>
/// 连接到WebSocket服务器
/// </summary>
/// <returns>连接结果</returns>
public async Task<bool> ConnectAsync()
{
if (_disposed)
throw new ObjectDisposedException(nameof(WebSocketClient));
if (_isConnected)
return true;
try
{
lock (_lockObject)
{
if (_isConnected)
return true;
_reconnecting = false;
_reconnectAttempts = 0;
}
// 确保设置了服务器地址和端口
_client.IpAddress = _config.ServerAddress;
_client.Port = _config.ServerPort;
Logger.Info($"正在连接到WebSocket服务器: ws://{_config.ServerAddress}:{_config.ServerPort}");
// 创建一个任务来包装同步连接方法
var tcs = new TaskCompletionSource<bool>();
var connectTask = Task.Run(() =>
{
try
{
var result = _client.ConnectServer();
if (result.IsSuccess)
{
tcs.SetResult(true);
}
else
{
Logger.Warn($"WebSocket连接失败: {result.Message}");
tcs.SetResult(false);
}
}
catch (Exception ex)
{
Logger.Error(ex, "WebSocket连接过程中发生异常");
tcs.SetResult(false);
}
});
// 添加超时控制
var timeoutTask = Task.Delay(_config.ConnectionTimeout);
var completedTask = await Task.WhenAny(tcs.Task, timeoutTask);
if (completedTask == timeoutTask)
{
Logger.Warn($"连接到WebSocket服务器 {_config.ServerAddress}:{_config.ServerPort} 超时");
Error?.Invoke(this, new WebSocketErrorEventArgs
{
Exception = new TimeoutException("WebSocket连接超时"),
ErrorMessage = "连接超时"
});
if (_config.AutoReconnect)
StartReconnectTimer();
return false;
}
bool connectionSuccess = await tcs.Task;
if (!connectionSuccess && _config.AutoReconnect)
{
StartReconnectTimer();
}
return connectionSuccess;
}
catch (Exception ex)
{
Logger.Error(ex, $"连接到WebSocket服务器 {_config.ServerAddress}:{_config.ServerPort} 时发生错误");
Error?.Invoke(this, new WebSocketErrorEventArgs { Exception = ex, ErrorMessage = ex.Message });
if (_config.AutoReconnect)
StartReconnectTimer();
return false;
}
}
/// <summary>
/// 断开与WebSocket服务器的连接
/// </summary>
public void Disconnect()
{
if (_disposed)
return;
try
{
// 停止定时器
StopHeartbeatTimer();
StopReconnectTimer();
if (_isConnected)
{
_client.ConnectClose();
_isConnected = false;
Logger.Info("已断开与WebSocket服务器的连接");
Disconnected?.Invoke(this, new WebSocketConnectEventArgs
{
ServerAddress = _config.ServerAddress,
ServerPort = _config.ServerPort,
IsReconnection = false
});
}
}
catch (Exception ex)
{
Logger.Error(ex, "断开WebSocket连接时发生错误");
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message">要发送的消息</param>
/// <returns>是否发送成功</returns>
public bool SendMessage(MoviconHub.App.Models.WebSocketMessage message)
{
if (_disposed)
throw new ObjectDisposedException(nameof(WebSocketClient));
if (!_isConnected)
{
Logger.Warn("未连接到WebSocket服务器无法发送消息");
return false;
}
try
{
string json = JsonConvert.SerializeObject(message);
var sendResult = _client.SendServer(json);
if (sendResult.IsSuccess)
{
Logger.Debug($"消息已发送: {json}");
return true;
}
else
{
Logger.Warn($"发送消息失败: {sendResult.Message}");
HandleDisconnection();
return false;
}
}
catch (Exception ex)
{
Logger.Error(ex, "发送WebSocket消息时发生错误");
HandleDisconnection();
return false;
}
}
/// <summary>
/// 发送设备数据
/// 全量数据
/// </summary>
/// <param name="statusData">状态数据</param>
/// <returns>是否发送成功</returns>
public bool SendDeviceData(WebSocketData webSocketData)
{
MoviconHub.App.Models.WebSocketMessage message =
MoviconHub.App.Models.WebSocketMessage.CreateDeviceData( webSocketData);
return SendMessage(message);
}
/// <summary>
/// 发送设备状态数据
/// </summary>
/// <param name="statusData">状态数据</param>
/// <returns>是否发送成功</returns>
public bool SendDeviceStatus(DeviceStatusData statusData)
{
MoviconHub.App.Models.WebSocketMessage message =
MoviconHub.App.Models.WebSocketMessage.CreateDeviceStatusMessage(_config.DeviceCode, statusData);
return SendMessage(message);
}
/// <summary>
/// 发送设备故障信息
/// </summary>
/// <param name="faultData">故障数据</param>
/// <returns>是否发送成功</returns>
public bool SendDeviceFault(FaultDetails faultData)
{
MoviconHub.App.Models.WebSocketMessage message =
MoviconHub.App.Models.WebSocketMessage.CreateFaultMessage(_config.DeviceCode, faultData);
return SendMessage(message);
}
/// <summary>
/// 发送测试数据
/// </summary>
/// <param name="testData">测试数据</param>
/// <returns>是否发送成功</returns>
public bool SendTestData(TestData testData)
{
MoviconHub.App.Models.WebSocketMessage message =
MoviconHub.App.Models.WebSocketMessage.CreateTestDataMessage(_config.DeviceCode, testData);
return SendMessage(message);
}
/// <summary>
/// 更新配置
/// </summary>
/// <param name="serverAddress">服务器地址</param>
/// <param name="port">端口</param>
/// <param name="deviceCode">设备编码</param>
/// <param name="reconnect">是否重连</param>
public async Task UpdateConfig(string serverAddress, int port, string deviceCode, bool reconnect = true)
{
bool wasConnected = _isConnected;
if (wasConnected)
Disconnect();
_config.ServerAddress = serverAddress;
_config.ServerPort = port;
_config.DeviceCode = deviceCode;
_config.SaveConfig();
// 重新创建客户端
_client.ConnectClose();
InitializeClient();
if (wasConnected && reconnect)
await ConnectAsync();
}
/// <summary>
/// 处理断开连接情况
/// </summary>
private void HandleDisconnection()
{
if (!_isConnected)
return;
lock (_lockObject)
{
if (!_isConnected)
return;
_isConnected = false;
StopHeartbeatTimer();
Logger.Warn("WebSocket连接已断开");
Disconnected?.Invoke(this, new WebSocketConnectEventArgs
{
ServerAddress = _config.ServerAddress,
ServerPort = _config.ServerPort,
IsReconnection = false
});
if (_config.AutoReconnect && !_reconnecting)
{
StartReconnectTimer();
}
}
}
/// <summary>
/// 启动心跳定时器
/// </summary>
private void StartHeartbeatTimer()
{
StopHeartbeatTimer();
_heartbeatTimer = new Timer(SendHeartbeat, null,
_config.HeartbeatInterval,
_config.HeartbeatInterval);
Logger.Debug($"心跳定时器已启动,间隔: {_config.HeartbeatInterval}毫秒");
}
/// <summary>
/// 停止心跳定时器
/// </summary>
private void StopHeartbeatTimer()
{
_heartbeatTimer?.Dispose();
_heartbeatTimer = null;
}
/// <summary>
/// 发送心跳消息
/// </summary>
private void SendHeartbeat(object state)
{
if (!_isConnected)
return;
try
{
MoviconHub.App.Models.WebSocketMessage heartbeat =
MoviconHub.App.Models.WebSocketMessage.CreateHeartbeat(_config.DeviceCode);
SendMessage(heartbeat);
Logger.Debug("已发送心跳消息");
}
catch (Exception ex)
{
Logger.Error(ex, "发送心跳消息时发生错误");
}
}
/// <summary>
/// 启动重连定时器
/// </summary>
private void StartReconnectTimer()
{
lock (_lockObject)
{
if (_reconnecting)
return;
_reconnecting = true;
StopReconnectTimer();
_reconnectTimer = new Timer(ReconnectCallback, null,
_config.ReconnectInterval,
Timeout.Infinite); // 只执行一次,在重连方法中再次设置定时器
Logger.Info($"重连定时器已启动,间隔: {_config.ReconnectInterval}毫秒");
}
}
/// <summary>
/// 重连回调方法
/// </summary>
private void ReconnectCallback(object stateObj)
{
if (_isConnected || _disposed)
return;
// 使用Task执行异步重连
Task.Run(async () =>
{
await ReconnectAsync();
});
}
/// <summary>
/// 停止重连定时器
/// </summary>
private void StopReconnectTimer()
{
_reconnectTimer?.Dispose();
_reconnectTimer = null;
}
/// <summary>
/// 执行重连
/// </summary>
private async Task ReconnectAsync()
{
if (_isConnected || _disposed)
return;
_reconnectAttempts++;
Logger.Info($"正在尝试重连,第 {_reconnectAttempts} 次");
bool success = await ConnectAsync();
if (!success && _config.AutoReconnect && !_disposed)
{
lock (_lockObject)
{
if (!_isConnected && !_disposed)
{
// 计算指数退避重连间隔
int nextInterval = Math.Min(
_config.ReconnectInterval * (int)Math.Pow(2, Math.Min(9, _reconnectAttempts - 1)), // 最多512倍避免间隔过长
_maxReconnectInterval); // 最大重试间隔
Logger.Info($"重连失败,{nextInterval}毫秒后将再次重试");
_reconnectTimer = new Timer(ReconnectCallback, null, nextInterval, Timeout.Infinite);
}
}
}
else if (success)
{
_reconnecting = false;
}
}
/// <summary>
/// 是否已连接
/// </summary>
public bool IsConnected => _isConnected;
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 释放资源
/// </summary>
/// <param name="disposing">是否由Dispose调用</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
// 释放托管资源
Disconnect();
_heartbeatTimer?.Dispose();
_reconnectTimer?.Dispose();
_client?.Dispose();
}
_disposed = true;
}
}
}

View File

@@ -0,0 +1,193 @@
using MoviconHub.App.Com;
using MoviconHub.App.Models;
using NLog;
using ReaLTaiizor.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MoviconHub.App.Services
{
/// <summary>
/// WebSocket客户端辅助类
/// </summary>
public static class WebSocketClientHelper
{
private static WebSocketClient _webSocketClient;
private static WebSocketConfig _webSocketConfig;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
/// <summary>
/// ScanTask扫描Task
/// </summary>
private static Task ScanTask { get; set; }
/// <summary>
/// 扫描线程使能
/// </summary>
public static bool ThreadEnable { get; set; } = true;
public static WebSocketData CurWebSocketData { get; set; }
/// <summary>
/// 初始化WebSocket客户端
/// </summary>
public static async void Initialize()
{
_webSocketConfig = WebSocketConfig.LoadConfig();
_webSocketClient = new WebSocketClient();
// 注册事件处理程序
_webSocketClient.MessageReceived += OnMessageReceived;
_webSocketClient.Connected += OnConnected;
_webSocketClient.Disconnected += OnDisconnected;
_webSocketClient.Error += OnError;
await ConnectAsync();
Logger.Info("WebSocket客户端辅助类已初始化");
}
/// <summary>
///发布实时数据
/// </summary>
public static void PubRtDataStart()
{
ScanTask = Task.Run(async () =>
{
while (ThreadEnable)
{
try
{
await Task.Delay(_webSocketConfig.Cycle * 1000);
if (SendDeviceData(CurWebSocketData))
{
}
else
{
Logger.Info("WebSocket客户端发送设备");
}
//SendDeviceData(CurWebSocketData);
}
catch (Exception ex)
{
}
}
});
}
/// <summary>
/// 消息接收事件
/// </summary>
public static event EventHandler<WebSocketMessageEventArgs> MessageReceived;
/// <summary>
/// 连接事件
/// </summary>
public static event EventHandler<WebSocketConnectEventArgs> Connected;
/// <summary>
/// 断开连接事件
/// </summary>
public static event EventHandler<WebSocketConnectEventArgs> Disconnected;
/// <summary>
/// 错误事件
/// </summary>
public static event EventHandler<WebSocketErrorEventArgs> Error;
/// <summary>
/// 连接到WebSocket服务器
/// </summary>
/// <returns>连接结果</returns>
public static async Task<bool> ConnectAsync()
{
if (_webSocketClient == null)
{
Initialize();
}
return await _webSocketClient.ConnectAsync();
}
/// <summary>
/// 断开连接
/// </summary>
public static void Disconnect()
{
ThreadEnable = false;
_webSocketClient?.Disconnect();
}
/// <summary>
/// 发送设备状态数据
/// </summary>
/// <param name="statusData">状态数据</param>
/// <returns>是否发送成功</returns>
public static bool SendDeviceData(WebSocketData webSocketData)
{
if (_webSocketClient == null)
{
Initialize();
}
return _webSocketClient.SendDeviceData(webSocketData);
}
/// <summary>
/// 更新配置
/// </summary>
/// <param name="serverAddress">服务器地址</param>
/// <param name="port">端口</param>
/// <param name="deviceCode">设备编码</param>
/// <param name="reconnect">是否重连</param>
public static async Task UpdateConfig(string serverAddress, int port, string deviceCode, bool reconnect = true)
{
if (_webSocketClient == null)
{
Initialize();
}
await _webSocketClient.UpdateConfig(serverAddress, port, deviceCode, reconnect);
}
/// <summary>
/// 客户端是否已连接
/// </summary>
public static bool IsConnected => _webSocketClient?.IsConnected ?? false;
// 内部事件处理方法
private static void OnMessageReceived(object sender, WebSocketMessageEventArgs e)
{
Logger.Debug($"接收到消息:{e.RawMessage}");
MessageReceived?.Invoke(sender, e);
}
private static void OnConnected(object sender, WebSocketConnectEventArgs e)
{
Logger.Info($"已连接到WebSocket服务器 {e.ServerAddress}:{e.ServerPort}");
Connected?.Invoke(sender, e);
}
private static void OnDisconnected(object sender, WebSocketConnectEventArgs e)
{
Logger.Info($"已断开与WebSocket服务器 {e.ServerAddress}:{e.ServerPort} 的连接");
Disconnected?.Invoke(sender, e);
}
private static void OnError(object sender, WebSocketErrorEventArgs e)
{
Logger.Error(e.Exception, $"WebSocket错误: {e.ErrorMessage}");
Error?.Invoke(sender, e);
}
}
}

220
MoviconHub.App/frmMain.Designer.cs generated Normal file
View File

@@ -0,0 +1,220 @@
namespace MoviconHub.App
{
partial class frmMain
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmMain));
this.materialTabControl1 = new ReaLTaiizor.Controls.MaterialTabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.materialMultiLineTextBoxEditWs = new ReaLTaiizor.Controls.MaterialMultiLineTextBoxEdit();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.materialMultiLineTextBoxEditApi = new ReaLTaiizor.Controls.MaterialMultiLineTextBoxEdit();
this.tabPage4 = new System.Windows.Forms.TabPage();
this.imageList1 = new System.Windows.Forms.ImageList(this.components);
this.MainText = new System.Windows.Forms.TextBox();
this.materialTabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.tabPage3.SuspendLayout();
this.SuspendLayout();
//
// materialTabControl1
//
this.materialTabControl1.Controls.Add(this.tabPage1);
this.materialTabControl1.Controls.Add(this.tabPage2);
this.materialTabControl1.Controls.Add(this.tabPage3);
this.materialTabControl1.Controls.Add(this.tabPage4);
this.materialTabControl1.Depth = 0;
this.materialTabControl1.Dock = System.Windows.Forms.DockStyle.Fill;
this.materialTabControl1.ImageList = this.imageList1;
this.materialTabControl1.Location = new System.Drawing.Point(3, 64);
this.materialTabControl1.MouseState = ReaLTaiizor.Helper.MaterialDrawHelper.MaterialMouseState.HOVER;
this.materialTabControl1.Multiline = true;
this.materialTabControl1.Name = "materialTabControl1";
this.materialTabControl1.SelectedIndex = 0;
this.materialTabControl1.Size = new System.Drawing.Size(605, 453);
this.materialTabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.MainText);
this.tabPage1.ImageKey = "set2.png";
this.tabPage1.Location = new System.Drawing.Point(4, 31);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(597, 418);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "主界面";
this.tabPage1.UseVisualStyleBackColor = true;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.materialMultiLineTextBoxEditWs);
this.tabPage2.ImageKey = "set1.png";
this.tabPage2.Location = new System.Drawing.Point(4, 31);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(597, 418);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "WebSocket配置";
this.tabPage2.UseVisualStyleBackColor = true;
//
// materialMultiLineTextBoxEditWs
//
this.materialMultiLineTextBoxEditWs.AnimateReadOnly = false;
this.materialMultiLineTextBoxEditWs.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.materialMultiLineTextBoxEditWs.CharacterCasing = System.Windows.Forms.CharacterCasing.Normal;
this.materialMultiLineTextBoxEditWs.Cursor = System.Windows.Forms.Cursors.IBeam;
this.materialMultiLineTextBoxEditWs.Depth = 0;
this.materialMultiLineTextBoxEditWs.Dock = System.Windows.Forms.DockStyle.Bottom;
this.materialMultiLineTextBoxEditWs.HideSelection = true;
this.materialMultiLineTextBoxEditWs.Location = new System.Drawing.Point(3, 0);
this.materialMultiLineTextBoxEditWs.MaxLength = 32767;
this.materialMultiLineTextBoxEditWs.MouseState = ReaLTaiizor.Helper.MaterialDrawHelper.MaterialMouseState.OUT;
this.materialMultiLineTextBoxEditWs.Name = "materialMultiLineTextBoxEditWs";
this.materialMultiLineTextBoxEditWs.PasswordChar = '\0';
this.materialMultiLineTextBoxEditWs.ReadOnly = true;
this.materialMultiLineTextBoxEditWs.ScrollBars = System.Windows.Forms.ScrollBars.None;
this.materialMultiLineTextBoxEditWs.SelectedText = "";
this.materialMultiLineTextBoxEditWs.SelectionLength = 0;
this.materialMultiLineTextBoxEditWs.SelectionStart = 0;
this.materialMultiLineTextBoxEditWs.ShortcutsEnabled = true;
this.materialMultiLineTextBoxEditWs.Size = new System.Drawing.Size(591, 415);
this.materialMultiLineTextBoxEditWs.TabIndex = 2;
this.materialMultiLineTextBoxEditWs.TabStop = false;
this.materialMultiLineTextBoxEditWs.Text = "Msg";
this.materialMultiLineTextBoxEditWs.TextAlign = System.Windows.Forms.HorizontalAlignment.Left;
this.materialMultiLineTextBoxEditWs.UseSystemPasswordChar = false;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.materialMultiLineTextBoxEditApi);
this.tabPage3.ImageKey = "set3.png";
this.tabPage3.Location = new System.Drawing.Point(4, 31);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Size = new System.Drawing.Size(597, 418);
this.tabPage3.TabIndex = 2;
this.tabPage3.Text = "Api设置";
this.tabPage3.UseVisualStyleBackColor = true;
//
// materialMultiLineTextBoxEditApi
//
this.materialMultiLineTextBoxEditApi.AnimateReadOnly = false;
this.materialMultiLineTextBoxEditApi.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.materialMultiLineTextBoxEditApi.CharacterCasing = System.Windows.Forms.CharacterCasing.Normal;
this.materialMultiLineTextBoxEditApi.Cursor = System.Windows.Forms.Cursors.IBeam;
this.materialMultiLineTextBoxEditApi.Depth = 0;
this.materialMultiLineTextBoxEditApi.Dock = System.Windows.Forms.DockStyle.Bottom;
this.materialMultiLineTextBoxEditApi.HideSelection = true;
this.materialMultiLineTextBoxEditApi.Location = new System.Drawing.Point(0, 3);
this.materialMultiLineTextBoxEditApi.MaxLength = 32767;
this.materialMultiLineTextBoxEditApi.MouseState = ReaLTaiizor.Helper.MaterialDrawHelper.MaterialMouseState.OUT;
this.materialMultiLineTextBoxEditApi.Name = "materialMultiLineTextBoxEditApi";
this.materialMultiLineTextBoxEditApi.PasswordChar = '\0';
this.materialMultiLineTextBoxEditApi.ReadOnly = true;
this.materialMultiLineTextBoxEditApi.ScrollBars = System.Windows.Forms.ScrollBars.None;
this.materialMultiLineTextBoxEditApi.SelectedText = "";
this.materialMultiLineTextBoxEditApi.SelectionLength = 0;
this.materialMultiLineTextBoxEditApi.SelectionStart = 0;
this.materialMultiLineTextBoxEditApi.ShortcutsEnabled = true;
this.materialMultiLineTextBoxEditApi.Size = new System.Drawing.Size(597, 415);
this.materialMultiLineTextBoxEditApi.TabIndex = 1;
this.materialMultiLineTextBoxEditApi.TabStop = false;
this.materialMultiLineTextBoxEditApi.Text = "Msg";
this.materialMultiLineTextBoxEditApi.TextAlign = System.Windows.Forms.HorizontalAlignment.Left;
this.materialMultiLineTextBoxEditApi.UseSystemPasswordChar = false;
//
// tabPage4
//
this.tabPage4.ImageKey = "Log.png";
this.tabPage4.Location = new System.Drawing.Point(4, 31);
this.tabPage4.Name = "tabPage4";
this.tabPage4.Size = new System.Drawing.Size(597, 418);
this.tabPage4.TabIndex = 3;
this.tabPage4.Text = "运行日志";
this.tabPage4.UseVisualStyleBackColor = true;
//
// imageList1
//
this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
this.imageList1.Images.SetKeyName(0, "set2.png");
this.imageList1.Images.SetKeyName(1, "set1.png");
this.imageList1.Images.SetKeyName(2, "set3.png");
this.imageList1.Images.SetKeyName(3, "Log.png");
//
// MainText
//
this.MainText.Dock = System.Windows.Forms.DockStyle.Bottom;
this.MainText.Location = new System.Drawing.Point(3, 6);
this.MainText.Multiline = true;
this.MainText.Name = "MainText";
this.MainText.Size = new System.Drawing.Size(591, 409);
this.MainText.TabIndex = 1;
//
// frmMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(611, 520);
this.Controls.Add(this.materialTabControl1);
this.DrawerTabControl = this.materialTabControl1;
this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Margin = new System.Windows.Forms.Padding(4);
this.MaximizeBox = false;
this.Name = "frmMain";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "MoviconHub";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.frmMain_FormClosed);
this.Load += new System.EventHandler(this.frmMain_Load);
this.materialTabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage1.PerformLayout();
this.tabPage2.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private ReaLTaiizor.Controls.MaterialTabControl materialTabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.TabPage tabPage4;
private System.Windows.Forms.ImageList imageList1;
private ReaLTaiizor.Controls.MaterialMultiLineTextBoxEdit materialMultiLineTextBoxEditApi;
private ReaLTaiizor.Controls.MaterialMultiLineTextBoxEdit materialMultiLineTextBoxEditWs;
private System.Windows.Forms.TextBox MainText;
}
}

958
MoviconHub.App/frmMain.cs Normal file
View File

@@ -0,0 +1,958 @@
using HslCommunication;
using HslCommunication.Profinet.Melsec;
using MoviconHub.App.Com;
using MoviconHub.App.Models;
using MoviconHub.App.Services;
using NLog;
using ReaLTaiizor.Forms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MoviconHub.App
{
public partial class frmMain : MaterialForm
{
public frmMain()
{
InitializeComponent();
}
/// <summary>
/// 当前的日志记录
/// </summary>
private Logger Logger { get; set; } = LogManager.GetCurrentClassLogger();
/// <summary>
/// 当前的信号模型
/// </summary>
public SglModel CurSglModel { get; set; }
/// <summary>
/// PLCScanTask扫描Task
/// </summary>
private static Task PLCScanTask { get; set; }
/// <summary>
/// 扫描线程使能
/// </summary>
public bool ThreadEnable { get; set; } = true;
/// <summary>
/// 三菱连接驱动程序
/// </summary>
public MelsecMcNet MelsecMcNetDrive { get; set; }
/// <summary>
/// DB连接服务
/// </summary>
public DBServices CurDBServices { get; set; }
private void frmMain_Load(object sender, EventArgs e)
{
CurSglModel = new SglModel();
CurSglModel.SglModelChanged += CurSglModel_SglModelChanged;
CurDBServices = new DBServices(CurSglModel);
CurDBServices.StartPolling();
// 初始化API服务
ApiHelper.Initialize();
WebSocketClientHelper.Initialize();
WebSocketClientHelper.PubRtDataStart();
ClearActionInstance = new ClearAction();
ClearActionInstance.ClearActionEvent += ClearActionInstance_ClearActionEvent;
ListAlarmModels = new List<AlarmModel>()
{
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="热水罐液位 H报警",
Index=0,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="热水罐液位 L报警",
Index=1,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="热水罐液位 LL报警",
Index=2,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="清洗剂罐液位 H报警",
Index=3,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="清洗剂罐液位 L报警",
Index=4,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="清洗剂罐液位 LL报警",
Index=5,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="桁架平移前进极限报警",
Index=6,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="桁架平移后退极限报警",
Index=7,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="桁架吊装上升极限报警",
Index=8,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="桁架吊装下降极限报警",
Index=9,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="漫射喷淋AXIS1 X1伺服报警",
Index=10,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="漫射喷淋AXIS2 伺服报警",
Index=11,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="漫射喷淋AXIS3 X2伺服报警",
Index=12,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="上位机 急停被按下报警",
Index=13,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="大部件 急停安全继电器未吸合报警",
Index=14,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="R08与FX3U 通讯丢失,请查看网线是否松动",
Index=15,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME02(零部件)变频器 CC LINK网络报警 站号:1",
Index=16,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME03(大部件)变频器 CC LINK网络报警 站号:2",
Index=17,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME04(ROB1高压泵)变频器 CC LINK网络报警 站号:3",
Index=18,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME05(ROB2高压泵)变频器 CC LINK网络报警 站号:4",
Index=19,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="机器人1 CC LINK网络报警 站号:5",
Index=20,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="机器人2 CC LINK网络报警 站号:9",
Index=21,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB03 A3119_1 远程IO从站 CC LINK网络报警 站号:13",
Index=22,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB03 A4119_1 远程IO从站 CC LINK网络报警 站号:14",
Index=23,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB01 A119_1 远程IO从站 CC LINK网络报警 站号:15",
Index=24,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB01 A124_1 远程IO从站 CC LINK网络报警 站号:16",
Index=25,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB01 A129_1 远程IO从站 CC LINK网络报警 站号:17",
Index=26,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB01 A200_1 远程IO从站 CC LINK网络报警 站号:18",
Index=27,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB01 A205_1 远程IO从站 CC LINK网络报警 站号:19",
Index=28,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="JCB02 A2119_1 远程IO从站 CC LINK网络报警 站号:20",
Index=29,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="ROB1 机器人故障报警",
Index=30,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="ROB2 机器人故障报警",
Index=31,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME02 变频器存在错误",
Index=32,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME03 变频器存在错误",
Index=33,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME04 变频器存在错误",
Index=34,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME05 变频器存在错误",
Index=35,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="ROB1第七轴伺服故障",
Index=36,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="ROB2第七轴伺服故障",
Index=37,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="零部件吊装伺服故障",
Index=38,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="零部件平移伺服故障",
Index=39,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME04 高压泵温度指示报警",
Index=40,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME04 高压泵压力指示报警",
Index=41,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME05 高压泵温度指示报警",
Index=42,
DeviceState=2,
},
new AlarmModel(FRemoteSqlContext.FDb){
DeviceName="机车构架及大部件自动化智能清洗设备",
DeviceCode="942010002",
AlarmMessage="N1C1 XME05 高压泵压力指示报警",
Index=43,
DeviceState=2,
},
};
ListDeviceStateStaticModels = new List<DeviceStateStaticModel>()
{
new DeviceStateStaticModel()
{
Name="开机时长",
Index=2
},
new DeviceStateStaticModel()
{
Name="运行时长",
Index=6
},
new DeviceStateStaticModel()
{
Name="待机时长",
Index=8
},
new DeviceStateStaticModel()
{
Name="关机时长",
Index=10
},
new DeviceStateStaticModel()
{
Name="故障时长",
Index=14
},
new DeviceStateStaticModel()
{
Name="使用率分子",
Index=18
},
new DeviceStateStaticModel()
{
Name="作业计次",
Index=100
},
new DeviceStateStaticModel()
{
Name="故障计次",
Index=102
},
};
InitCom();
//扫描线程成功
RtScanDeviceStart();
//dBServices.StartPolling();
//var data = ApiHelper.GetPartInfoAsync("df3976d89a8f482685d0fb2ba5ed11ba", "");
}
/// <summary>
/// 清洗动作实例信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void ClearActionInstance_ClearActionEvent(object sender, string Par)
{
switch (Par)
{
case "设备关机":
{
var Data = new DeviceState()
{
DeviceName = "机车构架及大部件自动化智能清洗设备",
DeviceCode = "942010002",
PowerOnTime = ListDeviceStateStaticModels.Find(a => a.Name == "开机时长").Value,
RunTime = ListDeviceStateStaticModels.Find(a => a.Name == "运行时长").Value,
StandbyTime = ListDeviceStateStaticModels.Find(a => a.Name == "待机时长").Value,
ShutdownTime = ListDeviceStateStaticModels.Find(a => a.Name == "关机时长").Value,
FaultTime = ListDeviceStateStaticModels.Find(a => a.Name == "故障时长").Value,
JobNum = ListDeviceStateStaticModels.Find(a => a.Name == "作业计次").Value,
FaultNum = ListDeviceStateStaticModels.Find(a => a.Name == "故障计次").Value,
//UseRatio = ListDeviceStateStaticModels.Find(a=>a.Name== "故障计次").Value,
};
var Result = FRemoteSqlContext.FDb.Insert<DeviceState>(Data).ExecuteInserted();
if (Result != null && Result.Count > 0)
{
Logger.Error("清洗时间统计数据完成");
BeginInvoke(new Action(() =>
{
MainText.AppendText($"时间:{DateTime.Now}-Msg:清洗时间统计数据完成 {Environment.NewLine}");
}));
}
}
break;
case "清洗完成":
{
// 获取组件信息
var component = CurDBServices.RealtimeData.ListComponentsInfo?.FirstOrDefault();
if (component != null)
{
// 创建CurRunClearState对象并映射数据
var curRunData = new ClearData()
{
// 基本信息
DeviceCode = CurDBServices.RealtimeData.Device_Code,
DeviceName = CurDBServices.RealtimeData.Device_Name,
// 组件信息
part_qrid = component?.part_qrid,
part_num = component?.part_num,
part_position = component?.part_position,
component_name = component?.part_name,
vehicle_model = component?.part_Vehicle_model,
locomotive_number = component?.part_locomotive_number,
repair_process = component?.part_repair_process,
program_process = CurDBServices.RealtimeData.TestData.Test_FrameworkProgramProcess,
// 程序进程
Test_FrameworkProgramProcess = CurDBServices.RealtimeData.TestData.Test_FrameworkProgramProcess,
Test_FrameworkProgramProcessPercentage = CurDBServices.RealtimeData.TestData.Test_FrameworkProgramProcessPercentage,
//// 设备状态
//Test_PartsEquipmentStatus = CurDBServices.RealtimeData.TestData.Test_PartsEquipmentStatus,
// 清洗时长和用量
Test_FrameworkPerModelCleaningDuration = CurDBServices.RealtimeData.TestData.Test_FrameworkPerModelCleaningDuration,
Test_FrameworkPerModelCleaningAgentUsage = CurDBServices.RealtimeData.TestData.Test_FrameworkPerModelCleaningAgentUsage,
Test_FrameworkPerModelWaterUsage = CurDBServices.RealtimeData.TestData.Test_FrameworkPerModelWaterUsage,
// 水箱和清洗剂罐信息
WaterTank_Temp = CurDBServices.RealtimeData.TestData.Test_WaterTankTemperature,
AgentTank_Temp = CurDBServices.RealtimeData.TestData.Test_CleaningAgentTankTemperature,
WaterTank_Level = CurDBServices.RealtimeData.TestData.Test_WaterTankLevel,
AgentTank_Level = CurDBServices.RealtimeData.TestData.Test_CleaningAgentTankLevel,
// 浸泡池温度
SoakingTank1_Temp = CurDBServices.RealtimeData.TestData.Test_SoakingTank1Temperature,
SoakingTank2_Temp = CurDBServices.RealtimeData.TestData.Test_SoakingTank2Temperature,
// 运行模式
Test_WaterTankHeat = CurDBServices.RealtimeData.TestData.Test_WaterTankHeat,
Test_WaterTankAdd = CurDBServices.RealtimeData.TestData.Test_WaterTankAdd,
Test_CleaningAgentTankHeat = CurDBServices.RealtimeData.TestData.Test_CleaningAgentTankHeat,
Test_CleaningAgentTankAdd = CurDBServices.RealtimeData.TestData.Test_CleaningAgentTankAdd,
// 监控信息
Test_ElectricSurveillance = CurDBServices.RealtimeData.TestData.Test_ElectricSurveillance,
Test_SteamSurveillance = CurDBServices.RealtimeData.TestData.Test_SteamSurveillance
};
var Result = FRemoteSqlContext.FDb.Insert<ClearData>(curRunData).ExecuteInserted();
if (Result != null && Result.Count > 0)
{
Logger.Error("清洗当时数据记录完成");
BeginInvoke(new Action(() =>
{
MainText.AppendText($"时间:{DateTime.Now}-Msg:清洗当时数据记录完成 {Environment.NewLine}");
}));
}
}
}
break;
default:
break;
}
}
/// <summary>
/// 报警集合
/// </summary>
public List<AlarmModel> ListAlarmModels { get; set; }
/// <summary>
/// 清洗动作实例
/// </summary>
public ClearAction ClearActionInstance { get; set; }
/// <summary>
/// 运行状态统计模型
/// </summary>
public List<DeviceStateStaticModel> ListDeviceStateStaticModels { get; set; }
/// <summary>
/// 报警结果集合
/// </summary>
private OperateResult<bool[]> OperateResultAlarm { get; set; }
/// <summary>
/// 清洗结束
/// </summary>
private OperateResult<bool> OperateResultClearEnd { get; set; }
/// <summary>
/// 设备关机
/// </summary>
private OperateResult<bool> OperateResultDeviceClose { get; set; }
private OperateResult<short> OperateResultClearAction { get; set; }
/// <summary>
/// 报警结果集合
/// </summary>
private OperateResult<Int16[]> OperateResultDeviceStateStatic { get; set; }
/// <summary>
/// 通信初始化
/// </summary>
private void InitCom()
{
try
{
var PLCIP = ConfigHelper.GetValue("PLCIP");
var PLCPort = 6000;
if (int.TryParse(ConfigHelper.GetValue("PLCPort"), out int PortResult))
{
PLCPort = PortResult;
}
//PLC通信的连接
MelsecMcNetDrive = new MelsecMcNet();
MelsecMcNetDrive.IpAddress = PLCIP;
MelsecMcNetDrive.Port = PLCPort;
MelsecMcNetDrive.ConnectClose();
MelsecMcNetDrive.ConnectTimeOut = 3000; // 连接3秒超时
OperateResult connect = MelsecMcNetDrive.ConnectServer();
if (connect.IsSuccess)//初始连接状态的显示判断
{
//MessageBox.Show(HslCommunication.StringResources.Language.ConnectedSuccess);
//MelsecMcNetDrive.Write("M504", true);
//MessageBox.Show("PLC连接成功");
}
else
{
Logger.Error("初始PLC通信失败");
//MessageBox.Show(connect.Message + Environment.NewLine + "ErrorCode: " + connect.ErrorCode);
}
}
catch (Exception)
{
}
}
/// <summary>
/// PLC扫描线程
/// </summary>
private void RtScanDeviceStart()
{
PLCScanTask = Task.Run(async () =>
{
while (ThreadEnable)
{
//await Task.CompletedTask;
await Task.Delay(50);
try
{
OperateResultAlarm = MelsecMcNetDrive.ReadBool("M150", 50);
if (OperateResultAlarm.IsSuccess)
{
foreach (var item in ListAlarmModels)
{
if (CurDBServices.RealtimeData != null && CurDBServices.RealtimeData.FaultDetails != null)
{
if (int.TryParse(CurDBServices.RealtimeData.FaultDetails.Fault_Code, out int FaultCodeResult))
{
item.DeviceState = FaultCodeResult;
}
}
item.IsActive = OperateResultAlarm.Content[item.Index];
}
}
OperateResultDeviceStateStatic = MelsecMcNetDrive.ReadInt16("D4500", 150);
if (OperateResultDeviceStateStatic.IsSuccess)
{
foreach (var itemDeviceStateStatic in ListDeviceStateStaticModels)
{
itemDeviceStateStatic.Value = OperateResultDeviceStateStatic.Content[itemDeviceStateStatic.Index];
}
}
//OperateResultClearEnd = MelsecMcNetDrive.ReadBool("M210");
//if (OperateResultClearEnd.IsSuccess)
//{
// ClearActionInstance.ClearEnd = OperateResultClearEnd.Content;
//}
OperateResultClearEnd = MelsecMcNetDrive.ReadBool("M211");
if (OperateResultClearEnd.IsSuccess)
{
ClearActionInstance.ClearEnd = OperateResultClearEnd.Content;
}
OperateResultDeviceClose = MelsecMcNetDrive.ReadBool("M210");
if (OperateResultDeviceClose.IsSuccess)
{
ClearActionInstance.DeviceClose = OperateResultDeviceClose.Content;
}
//OperateResultClearAction = MelsecMcNetDrive.ReadInt16("D5010");
//if (OperateResultClearAction.IsSuccess)
//{
// ClearActionInstance.ClearEnd = OperateResultClearAction.Content.GetBoolByIndex(12);
//}
}
catch (Exception ex)
{
//LogService.Info($"时间:{DateTime.Now.ToString()}-【Meter】-{ex.Message}");
}
}
});
}
/// <summary>
/// 信号信息改变事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void CurSglModel_SglModelChanged(object sender, string Par)
{
switch (Par)
{
case "CodeReady":
// 处理条码信息OK信号
// 这里可以添加您需要执行的操作
// 获取零件二维码ID
var partQrId = CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault()?.part_qrid;
if (string.IsNullOrEmpty(partQrId))
{
Logger.Error("二维码ID为空无法获取部件信息");
//MessageBox.Show("二维码ID为空无法获取部件信息", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
Logger.Error("开始进行API请求");
BeginInvoke(new Action(() =>
{
MainText.AppendText($"时间:{DateTime.Now}-Msg:开始进行API请求 {Environment.NewLine}");
}));
Task.Run(async () =>
{
try
{
var partInfoResponse = await ApiHelper.GetPartInfoAsync(CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_qrid, "");
BeginInvoke(new Action(() =>
{
materialMultiLineTextBoxEditApi.Text = $"Datetime:{DateTime.Now}-Msg:请求了 Api-{partInfoResponse.Message}";
}));
// 解析响应数据
if (partInfoResponse != null)
{
if (partInfoResponse.Status == 200) // 成功状态码
{
var partInfo = partInfoResponse.Data;
if (partInfo != null)
{
// 这里可以根据需要处理和显示部件信息
string partInfoDetails = $"车型: {partInfo.VehicleModel}\n" +
$"车号: {partInfo.LocomotiveNumber}\n" +
$"修程: {partInfo.RepairProcess}\n" +
$"部件名称: {partInfo.ComponentName}\n" +
$"位别: {partInfo.PartPosition}\n" +
$"部件编号: {partInfo.PartNum}\n" +
$"部件二维码: {partInfo.PartQrCode}";
// 显示或记录部件信息
Logger.Info($"成功获取部件信息: {partInfoDetails}");
if (CurDBServices.RealtimeData.ListComponentsInfo != null && CurDBServices.RealtimeData.ListComponentsInfo.Count > 0)
{
CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_Vehicle_model = partInfo.VehicleModel;
CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_locomotive_number = partInfo.LocomotiveNumber;
CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_repair_process = partInfo.RepairProcess;
CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_position = partInfo.PartPosition;
CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_name = partInfo.ComponentName;
CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_num = partInfo.PartNum;
CurDBServices.RealtimeData.ListComponentsInfo.FirstOrDefault().part_qrid = partInfo.PartQrCode;
}
//写个PLC
FSqlContext.FDb.Update<RTVar>()
.Set(a => a.Val, partInfo.VehicleModel)
.Where(a => a.Name == "part_Vehicle_model")
.ExecuteAffrows();
FSqlContext.FDb.Update<RTVar>()
.Set(a => a.Val, partInfo.LocomotiveNumber)
.Where(a => a.Name == "part_locomotive_number")
.ExecuteAffrows();
FSqlContext.FDb.Update<RTVar>()
.Set(a => a.Val, partInfo.RepairProcess)
.Where(a => a.Name == "part_repair_process")
.ExecuteAffrows();
FSqlContext.FDb.Update<RTVar>()
.Set(a => a.Val, partInfo.PartPosition)
.Where(a => a.Name == "part_position")
.ExecuteAffrows();
FSqlContext.FDb.Update<RTVar>()
.Set(a => a.Val, partInfo.ComponentName)
.Where(a => a.Name == "part_name")
.ExecuteAffrows();
FSqlContext.FDb.Update<RTVar>()
.Set(a => a.Val, partInfo.PartNum)
.Where(a => a.Name == "part_num")
.ExecuteAffrows();
//FSqlContext.FDb.Update<RTVar>()
// .Set(a => a.Val, partInfo.VehicleModel)
// .Where(a => a.Name == "part_qrid")
// .ExecuteAffrows();
// 读取数据后,关闭文件流
BeginInvoke(new Action(() =>
{
MainText.AppendText($"时间:{DateTime.Now}-Msg:{partInfoDetails} {Environment.NewLine}");
}));
// 根据UI设计可以将这些信息显示在相应的控件上
// 例如lblVehicleModel.Text = partInfo.VehicleModel;
// 或者可以将整个部件信息对象保存到某个属性中,供其他地方使用
// this.CurrentPartInfo = partInfo;
}
else
{
Logger.Error("API返回成功但部件信息为空");
//MessageBox.Show($"API返回成功但部件信息为空", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
else
{
Logger.Error($"获取部件信息失败: {partInfoResponse.Message}\n状态码: {partInfoResponse.Status}");
// 处理API返回的错误
//MessageBox.Show($"获取部件信息失败: {partInfoResponse.Message}\n状态码: {partInfoResponse.Status}",
//"API错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("API响应为空", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
Logger.Error(ex, "异步获取或解析部件信息时发生异常");
}
});
break;
default:
break;
}
}
private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
{
WebSocketClientHelper.Disconnect();
CurDBServices.StopPolling();
ThreadEnable = false;
}
//private Task Async ddd()
//{
// // 初始化
// WebSocketClientHelper.Initialize();
// // 注册消息接收事件
// WebSocketClientHelper.MessageReceived += (sender, e) =>
// {
// // 处理接收到的消息
// if (e.Message.MessageType == MessageType.DeviceStatus)
// {
// // 处理设备状态消息
// }
// };
// // 连接服务器
// WebSocketClientHelper.ConnectAsync();
// // 发送数据
// var statusData = new DeviceStatusData
// {
// DeviceId = "Device001",
// DeviceName = "测试设备",
// Status = "运行中",
// Voltage = 220.5,
// Current = 5.2,
// Temperature = 36.8
// };
// WebSocketClientHelper.SendDeviceStatus(statusData);
//}
//private void Request()
//{
// // 假设您从输入框获取二维码和设备编码
// string qrCode = txtQrCode.Text.Trim();
// string deviceCode = txtDeviceCode.Text.Trim();
// if (string.IsNullOrEmpty(qrCode) || string.IsNullOrEmpty(deviceCode))
// {
// MessageBox.Show("请输入二维码和设备编码", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
// return;
// }
// try
// {
// // 显示加载中状态
// SetControlsEnabled(false);
// lblStatus.Text = "正在获取数据...";
// // 调用API获取部件信息
// var result = await ApiHelper.GetPartInfoAsync(qrCode, deviceCode);
// if (result.Status == 200 && result.Data != null)
// {
// // 将获取到的数据填充到表单中
// txtVehicleModel.Text = result.Data.VehicleModel;
// txtLocomotiveNumber.Text = result.Data.LocomotiveNumber;
// txtRepairProcess.Text = result.Data.RepairProcess;
// txtComponentName.Text = result.Data.ComponentName;
// txtPartPosition.Text = result.Data.PartPosition;
// txtPartNum.Text = result.Data.PartNum;
// lblStatus.Text = "数据获取成功";
// }
// else
// {
// // 显示错误信息
// lblStatus.Text = $"获取数据失败:{result.Message}";
// MessageBox.Show($"获取数据失败:{result.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
// }
// }
// catch (Exception ex)
// {
// lblStatus.Text = $"发生异常:{ex.Message}";
// MessageBox.Show($"发生异常:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
// }
// finally
// {
// // 恢复控件状态
// SetControlsEnabled(true);
// }
//}
}
}

1570
MoviconHub.App/frmMain.resx Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FreeSql" version="3.5.202" targetFramework="net481" />
<package id="FreeSql.Provider.SqlServer" version="3.5.202" targetFramework="net481" />
<package id="HslCommunication" version="12.3.0" targetFramework="net481" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net481" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net481" />
<package id="NLog" version="5.4.0" targetFramework="net481" />
<package id="NLog.Config" version="4.7.15" targetFramework="net481" />
<package id="NLog.Schema" version="4.7.15" targetFramework="net481" />
<package id="ReaLTaiizor" version="3.8.1.2" targetFramework="net481" />
<package id="RestSharp" version="112.1.0" targetFramework="net481" />
<package id="System.Buffers" version="4.5.1" targetFramework="net481" />
<package id="System.Data.SqlClient" version="4.8.6" targetFramework="net481" />
<package id="System.Memory" version="4.5.5" targetFramework="net481" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net481" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net481" />
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net481" />
<package id="System.Text.Json" version="8.0.4" targetFramework="net481" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net481" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net481" />
</packages>

View File

@@ -0,0 +1,13 @@
{
"ServerAddress": "127.0.0.1",
"ServerPort": 1883,
"AutoReconnect": true,
"ReconnectInterval": 5000,
"HeartbeatInterval": 30000,
"ConnectionTimeout": 5000,
"Url": "/push/device/942010002",
"DeviceCode": "MOVICON_HUB_001",
"Cycle": 1,
"SecretKey": "your_secret_key_here"
}