using DataLinkMesWork;
using MesDataFunction;
using MesServerWork;
using MesWork.PLC;
using MQTTnet;
using MQTTnet.Client.Connecting;
using MQTTnet.Client.Disconnecting;
using MQTTnet.Client.Receiving;
using MQTTnet.Extensions.ManagedClient;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using SystemFramework;
using System.IO;
using System.Net;
using System.Text;
using MesServerFunctions;
using System.Threading.Tasks;
using MesWork;
using System.Drawing;
using MES_SIGNAL_CONF;
using SlMesDbIterface;
using System.Net.NetworkInformation;
using ExternalDataSync;
using OpcBasic;
using System.Collections.Concurrent;
using MisDataFunDll;
using DataLinkMesWork2;
using System.Linq;
using WebApi;

namespace MisDataSaveDate
{
    /// <summary>
    /// 
    /// </summary>
    public partial class MesServerMisDataFun : Form
    {
        public static string WebSvrUrlPort = ConfigurationManager.AppSettings["Url_WebApi"];
        public static int IsWriteMonitorLog = Convert.ToInt32(ConfigurationManager.AppSettings["IsWriteMonitorLog"]);
        public static string OnlineCheckDataUrl = ConfigurationManager.AppSettings["OnlineCheckDataUrl"].ToString();
        public static string ConnectionString_MES = ConfigurationManager.AppSettings["ConnectionString_MES"];
        public static int IsDemoMesServer = Convert.ToInt32(ConfigurationManager.AppSettings["IsDemoMesServer"]);
        public static string IsRecordTagStatus = ConfigurationManager.AppSettings["IsRecordTagStatus"];
        public static string BasicDataTableFile = ConfigurationManager.AppSettings["BasicDataTableFile"];
        public static string PrintURL = ConfigurationManager.AppSettings["PrintURL"];
        public static int webApiPort = Convert.ToInt32(ConfigurationManager.AppSettings["WebSvrPort"]);
        public static string webapi_MesIP = ConfigurationManager.AppSettings["Webapi_MesIP"];


        WebApi.InitServer initServer = null;
        static Hashtable hashtableTopicList = new Hashtable();
        // 同一工位的状态日志按顺序串行执行，避免多线程下写表顺序错乱。
        private static readonly ConcurrentDictionary<string, object> DeviceStatusLogLocks = new ConcurrentDictionary<string, object>(StringComparer.OrdinalIgnoreCase);

        // IOT 设备状态枚举：文字 → 代码（0~7）
        private static readonly Dictionary<string, string> DeviceStatusMap = new Dictionary<string, string>
        {
            { "关机",      "0" },
            { "开机启动中", "1" },
            { "重报警停机", "2" },
            { "重故障停机", "3" },
            { "运行",      "4" },
            { "待机",      "5" },
            { "轻报警运行", "6" },
            { "维护停机",   "7" },
        };

        // MES 报警异常类型枚举：文字 → 代码（1~4）
        private static readonly Dictionary<string, string> AlarmExceptionTypeMap = new Dictionary<string, string>
        {
            { "设备异常", "1" },
            { "物料异常", "2" },
            { "生产异常", "3" },
            { "质量异常", "4" },
        };

        static bool OnLineMqtt = false;
        static bool OnLine_SQL = false;
        static bool OnLine_Mes = false;
        static bool OnLine_Mes_Cache = false;
        static bool OnLine_Print = false;
        static bool IsLoopReadShow = false;

        /// <summary>
        /// 允许使用附加功能的变量，只有在系统开始加载Tag时，才允许读取PLC数据
        /// </summary>
        public static bool AllowLoad;
        /// <summary>
        /// 
        /// </summary>
        MesWork.OpcForm opcForm = null;
        /// <summary>
        /// 
        /// </summary>
        public static string WorkStationNum_Now;
        /// <summary>
        /// 
        /// </summary>
        DateTime StartTime;

        public static Color color_Faw = Color.FromArgb(0, 44, 101);//蓝色，大众：0,44,101

        public static Color color_Good = Color.FromArgb(132, 185, 235);//浅蓝，自定义
        public static Color color_Wait = Color.FromArgb(240, 230, 140);//淡黄，显示等待状态
        public static Color color_Bad = SystemColors.ActiveBorder;//灰色，显示操作过程
        public static Color color_Control = SystemColors.Control;//控件默认颜色
        public static Color color_Grey = Color.FromArgb(192, 192, 192);//灰色，Table底色

        public static Color color_Green = Color.FromArgb(22, 161, 136);//绿色
        public static Color color_Yellow = Color.FromArgb(246, 227, 74);//黄色
        public static Color color_Red = Color.FromArgb(255, 0, 0);//红色

        [STAThread]
        static void Main()
        {
            new System.Threading.Mutex(true, "MES_ZK_SVR", out bool bCanRun);
            if (!bCanRun)
            {
                MessageBox.Show("MES中控程序 已经在运行！不可重复启动！");
                return;
            }
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //new MES_CONF().ShowDialog();

            Application.Run(new MesServerMisDataFun());
        }



        public MesServerMisDataFun()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;
            Never_Know.Hello_You_All_Never_Know = Hello_You_All_Never_Know;

            PP.ConnectionString_MES = ConnectionString_MES;
            PP.PrintURL = PrintURL;
            PP.IsDemoMesServer = IsDemoMesServer;
            ApplicationConfig.ConnectionString_MES = ConnectionString_MES;

            CommunicationCheckOnLine();
            MisData01();
            Init_dataGridView_CheckOpName();
            MIS_BASE.InitHashtable_MesServerCode();
            InitMesSerVerCode();
            initServer = new WebApi.InitServer(webApiPort);
            // 工位在线状态监控
            OpWorkStatusWatch();

            // 在这里调用开启线程方法 进行消费请求失败接口请求 每分钟消费一次 先读取 后重试
            StartFailedInterfaceRetryThread();
            StartElectricityThread();

            // 自监控心跳
            //InitAllOpHeartBeat();
        }
        public void MisData01()
        {
            var dt_Signal = MisDataFunDll.MisDataFun.dt_Signal();
            var dt_Device = MisDataFunDll.MisDataFun.dt_Device();
            var dt_TagTypeDataType = MisDataFunDll.MisDataFun.dt_TagTypeDataType();

            var sql =
                $" SELECT [工位号],[工位名称],[PLC],[PLC代码],[MesDll]" +
                $" FROM [MES_计划BOM_工位与名称] WHERE [是否启用MES] = 1" +
                $" ORDER BY [工位号]";
            SqlOperation.ExecuteSql(sql, out DataTable dt_SqlOp, out string errorSqlOp);
            dgv_OpName.DataSource = dt_SqlOp;

            var mp = new MesWorkPlc();

            StartTime = Convert.ToDateTime(toolStripStatusLabel_StartTime.Text = DateTime.Now.ToString());
            Runtime_Thread();

            if (mp.LoadOPCData(dt_Signal, dt_Device, IsDemoMesServer, IsWriteMonitorLog, true, false, out string error))
            {
                MesDataFunction.LoadTagTypeCodeID.Load(dt_TagTypeDataType);

                //查询出“全部原始基本数据列表”
                var drs = MesWork.PlcLinkForm.dt_BasicData.Select($"是否启用 = 1 and 变量类型代码=101 or 变量类型代码 = 102  or 变量类型代码 = 105");
                if (drs.Length > 1)
                {
                    MIS_BASE.BasicDataTagValue = MesWork.PlcLinkForm.dt_BasicData.Select($"是否启用 = 1 and 变量类型代码=101 or 变量类型代码 = 102  or 变量类型代码 = 105").CopyToDataTable<DataRow>();
                    if (MIS_BASE.BasicDataTagValue.Columns.Contains("上限值"))
                    {
                        MIS_BASE.BasicDataTagValue.Columns["上限值"].ColumnName = "值上限";
                    }
                    if (MIS_BASE.BasicDataTagValue.Columns.Contains("下限值"))
                    {
                        MIS_BASE.BasicDataTagValue.Columns["下限值"].ColumnName = "值下限";
                    }
                }

                // BasicDataTagValue = MesWork.PlcLinkForm.dt_BasicData.Select($"是否启用 = 1 and 监控属性代码 = '{DataLinkMesWork.ApplicationConfig.MES_Code.ToString()}'").CopyToDataTable<DataRow>();
                //查询出“MES_基本数据_测量范围”
                MesServerWork.MIS_BASE.BasicDataTagValueUpDown = MesWork.PlcLinkForm.dt_BasicData;
                if (MesServerWork.MIS_BASE.BasicDataTagValueUpDown.Columns.Contains("上限值"))
                {
                    MesServerWork.MIS_BASE.BasicDataTagValueUpDown.Columns["上限值"].ColumnName = "值上限";
                }
                if (MesServerWork.MIS_BASE.BasicDataTagValueUpDown.Columns.Contains("下限值"))
                {
                    MesServerWork.MIS_BASE.BasicDataTagValueUpDown.Columns["下限值"].ColumnName = "值下限";
                }
                // 模拟时，写入质量数据
                if (IsDemoMesServer == 1)
                {
                    InitBasicDataTagValue();
                }

                // 变量代码与其他字段的对应关系
                MesServerWork.MIS_BASE.InitHashtableTagID();
                toolStripStatusLabel_WorkStationNum.Text = MesWork.PlcLinkForm.opNameList.Count.ToString();

                AllowLoad = true;
                if (IsDemoMesServer == 1)
                {
                    toolStripStatusLabel_RunningStatus.Text = "变量模拟";
                    toolStripStatusLabel_RunningStatus.BackColor = System.Drawing.Color.Yellow;
                }
                else
                {
                    toolStripStatusLabel_RunningStatus.Text = "PLC";
                    toolStripStatusLabel_RunningStatus.BackColor = System.Drawing.Color.Green;
                }
                MesWorkPlc.D_OPCTagData_TagDataOnChangeMIS -= OPCTagData_TagDataOnChange;
                MesWorkPlc.D_OPCTagData_TagDataOnChangeMIS += OPCTagData_TagDataOnChange;
            }
        }



        private void OpWorkStatusWatch()
        {
            List<string> opNameList = PlcLinkForm.opNameList;
            new Thread(new ThreadStart(delegate () {
                while (true)
                {
                    Thread.Sleep(1000 * 60);
                    foreach (string OpName in opNameList)
                    {
                        if (OpName.IndexOf("-0") == -1 && OpName.IndexOf("-10") == -1 && OpName.IndexOf("-11") == -1 && OpName.IndexOf("-12") == -1 && OpName.IndexOf("ET") == -1)
                        {
                            // 查询各状态点位值
                            int toolPowered = Convert.ToInt32(MIS_BASE.ReadPLC(1000, OpName)); // 机床上电
                            int toolStart = Convert.ToInt32(MIS_BASE.ReadPLC(1001, OpName));  // 循环开始
                            int toolErr = Convert.ToInt32(MIS_BASE.ReadPLC(1002, OpName));  // 循环开始
                            float energy = 0; //能耗
                            // 单独记录OEE统计的表
                            OpWorkRunStatusSave(OpName, toolPowered, toolStart, toolErr, energy);
                        }
                    }
                }
            }))
            { IsBackground = true }.Start();

            new Thread(new ThreadStart(delegate () {
                while (true)
                {
                    NetState_MES();
                    Thread.Sleep(1000 * 10);
                }
            }))
            { IsBackground = true }.Start();
        }

        public static async Task NetState_MES()
        {
            Ping ping = new Ping();
            try
            {
                PingReply reply = await ping.SendPingAsync(webapi_MesIP);

                if (reply.Status == IPStatus.Success)
                {
                    OnLine_Mes = true;
                }
                else
                {
                    OnLine_Mes = false;
                }
                StateVariable.online_Mes = OnLine_Mes;
            }
            catch
            {
                OnLine_Mes = false;
            }
        }

        /// <summary>
        /// 获得Function调用信息
        /// </summary>
        private void InitMesSerVerCode()
        {
            MisDataFunDll.MisDataFun.GetMesServerCodeAndMesDll(out MisDataFunDll.MisDataFun.hashtable_MesServerCode, out MisDataFunDll.MisDataFun.hashtable_MesDll);
            MisDataFunDll.MisDataFun.GetBaseData_tagTable_TagName(out MisDataFunDll.MisDataFun.hashtable_TagName, out MisDataFunDll.MisDataFun.hashtable_TagTypeTagName);

            FuntionMesRead.GetAlarmInit();
        }

        public void SaveData_Load(object sender, EventArgs e)
        {
            MyLog4Net.MyLogHelper.LogCommit += MyLogHelper_LogCommit;
            MqttLink();
            Thread.Sleep(200);
            MesWorkPlc.StartServer();      //开启监控服务
            new TaskFactory().StartNew(delegate ()
            {
                DataTable dt;
                MisDataFunDll.MisDataFun.Alarm_Moby_Search(out dt);
                DataTable dt1 = MisDataFunDll.MisDataFun.GetCheckOpName();
                for (int i = 0; i < dt1.Rows.Count; i++)
                {
                    string opName = dt1.Rows[i]["工位号"].ToString();
                    FuntionMesRead.Alarm_Insert_Init(opName);
                }
            });
        }
        /// <summary>
        /// 模拟时，写入质量数据
        /// </summary>
        private void InitBasicDataTagValue()
        {
            string tagID;
            double tagValue;
            //写工位总合格标志  变量类型代码=21
            for (int i = 0; i < MesWork.PlcLinkForm.dt_BasicData.Rows.Count; i++)
            {
                if (MesWork.PlcLinkForm.dt_BasicData.Rows[i]["变量类型代码"].ToString() == "21")
                {
                    tagID = MesWork.PlcLinkForm.dt_BasicData.Rows[i]["TagID"].ToString();
                    MesServerWork.MIS_BASE.Write_TagID(tagID, 1);
                }
            }
            if (MesServerWork.MIS_BASE.BasicDataTagValue != null)
            {
                for (int i = 0; i < MesServerWork.MIS_BASE.BasicDataTagValue.Rows.Count; i++)
                {
                    try
                    {
                        switch (Convert.ToInt32(MesServerWork.MIS_BASE.BasicDataTagValue.Rows[i]["变量排序"]))
                        {

                            case 0:
                                tagID = MesServerWork.MIS_BASE.BasicDataTagValue.Rows[i]["TagID"].ToString();
                                MesServerWork.MIS_BASE.Write_TagID(tagID, 1);
                                break;
                            case 1:
                            case 2:
                            case 3:
                                tagID = MesServerWork.MIS_BASE.BasicDataTagValue.Rows[i]["TagID"].ToString();
                                tagValue = Convert.ToDouble(MesServerWork.MIS_BASE.BasicDataTagValue.Rows[i]["列位置"]) * 100
                                    + Convert.ToDouble(MesServerWork.MIS_BASE.BasicDataTagValue.Rows[i]["变量排序"]) / 100;
                                MesServerWork.MIS_BASE.Write_TagID(tagID, tagValue);
                                break;

                        }
                    }
                    catch { }

                }
            }

        }


        private void Init_dataGridView_CheckOpName()
        {
            try
            {
                var dt1 = MisDataFunDll.MisDataFun.GetCheckOpName();
                comboBox_OpNameList.DataSource = dt1;
                comboBox_OpNameList.ValueMember = "工位号";
                comboBox_OpNameList.DisplayMember = "工位号";
            }
            catch (Exception ex) { }
        }


        #region mqtt相关
        private async Task MqttLink()
        {
            List<MqttTopicFilter> TopicFilterList = new List<MqttTopicFilter>();
            string url;
            //string topicMqttTargetTopicPLC;
            //string topicMqttTargetTopicTagTypeCodeID;
            string TopicList;
            string[] TopicListFunItems;
            string[] TopicListItems;
            url = ConfigurationManager.AppSettings["MqttUrl"];
            TopicList = ConfigurationManager.AppSettings["TopicList"];
            TopicListItems = TopicList.Split('|');
            for (int i = 0; i < TopicListItems.Length; i++)
            {
                TopicListFunItems = TopicListItems[i].Split(',');
                hashtableTopicList.Add(TopicListFunItems[0], TopicListFunItems[1]);
            }

            await Mqtt.StartAsync();

            foreach (var topic in TopicListItems)
            {
                TopicListFunItems = topic.Split(',');

                Mqtt.mqttClient.SubscribeAsync(new MqttTopicFilter { Topic = TopicListFunItems[0] });
            }
            Mqtt.mqttClient.ConnectedHandler = new MqttClientConnectedHandlerDelegate(OnSubscriberConnected);
            Mqtt.mqttClient.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(OnSubscriberDisconnected);
            Mqtt.mqttClient.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(OnSubscriberMessageReceived);

        }
        private string Hello_You_All_Never_Know(string[] args)
        {
            return Guid.NewGuid().ToString() + Guid.NewGuid().ToString();
            //return string.Empty;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        private void OnSubscriberConnected(MqttClientConnectedEventArgs x)
        {
            MyLog4Net.MyLogHelper.Info("Mqtt：", "Mqtt连接成功！");
            OnLineMqtt = true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        private void OnSubscriberDisconnected(MqttClientDisconnectedEventArgs x)
        {
            try
            {
                MyLog4Net.MyLogHelper.Error("Mqtt：", "Mqtt断开连接！Reason：" + x.Reason);
                OnLineMqtt = false;
            }
            catch (Exception err)
            {
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="x"></param>
        public void OnSubscriberMessageReceived(MqttApplicationMessageReceivedEventArgs x)
        {
            ThreadPool.QueueUserWorkItem(MIS_Funtion_WEB, x);
        }
        #endregion

        /// <summary>
        /// mqtt 接收web和barcode数据
        /// </summary>
        /// <param name="e"></param>
        public void MIS_Funtion_WEB(object e)
        {
            try
            {
                MqttApplicationMessageReceivedEventArgs x = (MqttApplicationMessageReceivedEventArgs)e;
                var rec = x.ApplicationMessage.ConvertPayloadToString();
                MisDataFunDll.MisDataFun.TransferInfToMES(rec);
            }
            catch (Exception ex)
            {
                //MIS_Funtion(topicFunItem, "Exception:" + ex.Message);
            }
        }
        /// <summary>
        /// 接收内部PLC数据变化 
        /// </summary>
        /// <param name="e"></param>
        public void MIS_Funtion_PLC(object e)
        {
            var rec = e.ToString();
            try
            {
                MisDataFunDll.MisDataFun.TransferInfToMES(rec);
            }
            catch (Exception ex)
            {
                //MIS_Funtion(topicFunItem, "Exception:" + ex.Message);A
            }
        }


        static public void TagTypeCodeID_Insert(string opName, string TagTypeCodeID, string TagID, string TagValue, DateTime arrivedTime, DateTime leavedTime, int TimeDiff)
        {
            string procedureName;
            procedureName = "测量数据设备状态日志_增加数据";
            SqlParameter[] thisParms = new SqlParameter[7];
            thisParms[0] = new System.Data.SqlClient.SqlParameter("@工位号", opName);
            thisParms[1] = new System.Data.SqlClient.SqlParameter("@信号类型代码", TagTypeCodeID);
            thisParms[2] = new System.Data.SqlClient.SqlParameter("@TagID", TagID);
            thisParms[3] = new System.Data.SqlClient.SqlParameter("@TagValue", TagValue);
            thisParms[4] = new System.Data.SqlClient.SqlParameter("@到达时间", arrivedTime);
            thisParms[5] = new System.Data.SqlClient.SqlParameter("@离开时间", leavedTime);
            thisParms[6] = new System.Data.SqlClient.SqlParameter("@在线时间", TimeDiff);
            DataAccess.ExecuteStoredProcedure(procedureName, ref thisParms);
        }

        public static bool OpWorkRunStatusSave(string opName, int kj, int yx, int gz, float energy)
        {
            string produceName = "XD_工位运行状态_增加";
            SqlParameter[] thisParms = new SqlParameter[5];
            thisParms[0] = new System.Data.SqlClient.SqlParameter("@工位号", opName);
            thisParms[1] = new System.Data.SqlClient.SqlParameter("@开机", kj);
            thisParms[2] = new System.Data.SqlClient.SqlParameter("@运行", yx);
            thisParms[3] = new System.Data.SqlClient.SqlParameter("@故障", gz);
            thisParms[4] = new System.Data.SqlClient.SqlParameter("@能耗", energy);
            return DataAccess.ExecuteStoredProcedure(produceName, ref thisParms);
        }

        private void MisDataFun_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (MessageBox.Show("您确认要退出MES程序吗？该操作会停止MES进行数据处理！", "", MessageBoxButtons.OKCancel) == DialogResult.OK)
            {
                Process.GetCurrentProcess().Kill();
            }
            else
            {
                e.Cancel = true;
            }
        }

        private void timer_Status_Tick(object sender, EventArgs e)
        {
            timer_Status.Enabled = false;
            Show_OnLineState();

            if (!AllowLoad) return;
            Runtime_Thread();

            timer_Status.Enabled = true;
        }

        private void Show_OnLineState()
        {
            OnLineState_C(pb_OnLine_Print, OnLine_Print);
            OnLineState_C(pb_OnLine_SQL, OnLine_SQL);
            OnLineState_C(pb_OnLine_MQTT, OnLineMqtt);
        }
        private void CommunicationCheckOnLine()
        {

            new Thread(new ThreadStart(delegate ()
            {
                while (true)
                {
                    try
                    {
                        OnLine_SQL = DataLinkMesWork.SQLCommon.ExecuteDataTable("select getdate()", ConnectionString_MES, out DataTable dt, out string err);
                    }
                    catch (Exception) { }
                    Thread.Sleep(5000);
                }
            }))
            { IsBackground = true }.Start();

            new Thread(new ThreadStart(delegate ()
            {
                var ip = PrintURL.Split(':')[0];
                while (true)
                {
                    try
                    {
                        OnLine_Print = new System.Net.NetworkInformation.Ping().Send(ip).Status == System.Net.NetworkInformation.IPStatus.Success;
                    }
                    catch (Exception) { }
                    Thread.Sleep(5000);
                }
            }))
            { IsBackground = true }.Start();

        }
        private void OnLineState_C(PictureBox pb, bool onLine)
        {
            pb.Image = onLine ? global::MisDataFun.Properties.Resources.连接状态
                    : global::MisDataFun.Properties.Resources.断开状态;
        }
        private void MyLogHelper_LogCommit(object sender, MyLog4Net.MyLogEventArgs e)
        {
            var module = e.Module;
            var message = e.Message;

            var log = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + " " + module + " " + message + "\r\n";
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(() =>
                {
                    this.richTextBox1_mqtt.AppendText(log);
                    this.richTextBox1_mqtt.Focus();
                }));
            }
            else
            {
                this.richTextBox1_mqtt.AppendText(log);
                this.richTextBox1_mqtt.Focus();
            }

        }


        public void OPCTagData_TagDataOnChange(DeviceDriver_BasicData.CustomeEvetnArgs e)
        {

            // 处理MIS业务 保存数据
            // ThreadPool.QueueUserWorkItem(Function.MIS_Funtion, e);
            // 处理MES业务 Function
            ThreadPool.QueueUserWorkItem(TagData_MisData_TagDataOnChangeCustomeEvetnArgs, e);
            //ThreadPool.QueueUserWorkItem(TagData_MisData_TagDataOnChange, e);
            // 设备状态日志
            ThreadPool.QueueUserWorkItem(TagTypeCodeID_TagDataOnChange, e);
            //发送通讯服务器  MES web界面显示用 加工位号
            ThreadPool.QueueUserWorkItem(TransferInfToWebServer, e);
            //改变控件状态
            //showMessagePLCInvoke(e);
            //更新状态窗口控件状态
            //ExcutePlcChange(e);
        }
        /// <summary>
        /// 发送信号变化到function
        /// </summary>
        /// <param name="msgEvent"></param>
        private void TagData_MisData_TagDataOnChangeCustomeEvetnArgs(object msgEvent)
        {
            try
            {
                DeviceDriver_BasicData.CustomeEvetnArgs e = (DeviceDriver_BasicData.CustomeEvetnArgs)msgEvent;
                string OpName = e.OpName.ToString();//工位号
                string MesCode = e.TagType.ToString();//变量类型代码
                object tagValue = e.TagValue;//变量（0或者1）
                string TagTypeCodeID = e.TagTypeCodeID.ToString();//变量类型代码
                string TagID = e.TagID.ToString();
                string cmd = "";
                cmd = MIS_BASE.hashtable_TagTypeTagName[MesCode];
                string mesServerdllName;

                mesServerdllName = GetMesServeDllByOpName(OpName);
                string fun = "fun_" + cmd;
                int mesServerCode;
                mesServerCode = GetMesServerCodeByOpName(OpName);
                string rvMsg = Newtonsoft.Json.JsonConvert.SerializeObject(e);

                string msg;
                if (cmd == null)
                {
                    cmd = MesCode;
                    msg = $"PLC|{cmd}|{OpName}|{rvMsg}";
                }
                else
                {
                    msg = $"PLC|{cmd}|{OpName}|{rvMsg}";
                }
                try
                {
                    if (HandleTagChangeSideEffects(e, OpName, TagTypeCodeID, TagID, tagValue))
                    {
                        return;
                    }
                }
                catch (Exception err)
                {
                    return;
                }
                MIS_Funtion_PLC(msg);
                // asyncSendMessagePLC(mesServerdllName, msg, OpName);
            }
            catch (Exception err)
            {
                ApplicationLog.WriteLog(err, "TagData_Lable_TagDataOnChange");
            }
        }

        // 统一处理 Tag 变化带出的附加动作：14 写镜像点位，103 发报警消息，1000/1001/103 记录设备状态日志。
        private bool HandleTagChangeSideEffects(DeviceDriver_BasicData.CustomeEvetnArgs e, string opName, string tagTypeCodeID, string tagID, object tagValue)
        {
            if (tagTypeCodeID == "14")
            {
                MIS_BASE.Write_TagValueByTagTypeID(15, opName, tagValue);
                return true;
            }

            if (tagTypeCodeID == "103")
            {
                DataRow errDt = FuntionMesRead.Send_AlarmMsg(tagID, Convert.ToInt32(tagValue).ToString());
                // 报警产生时上报 MES 接口（仅重故障停机类型上报工厂MES）
                if (errDt != null && Convert.ToInt32(tagValue) == 1 && errDt["测量位置"].ToString() == "重故障停机")
                {
                    string mesAlarmType = errDt["测量单位"].ToString();
                    if (AlarmExceptionTypeMap.ContainsKey(mesAlarmType)) mesAlarmType = AlarmExceptionTypeMap[mesAlarmType];
                    WebApi.CALL_Inerface_DataHandle.CALL_Inerface_DeviceAlarm(opName, tagID, mesAlarmType, errDt["测量项目"].ToString());
                }
            }

            if (tagTypeCodeID == "1000" || tagTypeCodeID == "1001" || tagTypeCodeID == "103")
            {
                ExecuteDeviceStatusLogInOrder(opName, () => HandleDeviceStatusLog(e, opName, tagTypeCodeID));
            }

            return false;
        }

        // 设备状态日志业务集中放在这里，按点位类型分别处理上电、循环、报警。
        private void HandleDeviceStatusLog(DeviceDriver_BasicData.CustomeEvetnArgs e, string opName, string tagTypeCodeID)
        {
            if (tagTypeCodeID == "1000")
            {
                errorPortSave(opName, Convert.ToBoolean(e.TagValue) ? DeviceStatusMap["待机"] : DeviceStatusMap["关机"]);
                return;
            }

            if (tagTypeCodeID == "1001")
            {
                errorPortSave(opName, Convert.ToBoolean(e.TagValue) ? DeviceStatusMap["运行"] : DeviceStatusMap["待机"]);
                return;
            }

            if (tagTypeCodeID == "103")
            {
                // 通过 IOT类型（测量位置）文本自动匹配状态码
                string iotType = e.ShaftID?.ToString() ?? "";
                DeviceStatusMap.TryGetValue(iotType, out string alarmStatusCode);
                alarmStatusCode = alarmStatusCode ?? "6"; // 未匹配默认轻报警运行

                string errorCode = e.TagID?.ToString();
                string malfunctionName = e.ItemName?.ToString();
                if (!string.IsNullOrEmpty(errorCode) && errorCode.Length > 4)
                    errorCode = errorCode.Substring(errorCode.Length - 4);

                // 报警产生=1 / 报警解除=0
                int alarmRemove = Convert.ToInt32(e.TagValue) == 1 ? 1 : 0;
                errorPortSave(opName, alarmStatusCode, errorCode, malfunctionName, null, null, alarmRemove);

                // 报警解除后处理
                if (alarmRemove == 0)
                {
                    // 1. 先补写当前设备实际状态（运行/待机/关机）
                    string restoreStatus = Convert.ToInt32(MIS_BASE.ReadPLC(1001, opName)) == 1 ? DeviceStatusMap["运行"]
                                         : Convert.ToInt32(MIS_BASE.ReadPLC(1000, opName)) == 1 ? DeviceStatusMap["待机"]
                                         : DeviceStatusMap["关机"];
                    errorPortSave(opName, restoreStatus);

                    // 2. 查找仍然活跃的报警，如果有则补写一条，确保最新记录反映真实报警状态
                    var rtList = MIS_BASE.ReadPLC_OpName(opName);
                    var json = JsonConvert.SerializeObject(rtList);
                    var tagValues = JsonConvert.DeserializeObject<ConcurrentDictionary<string, TagFormat>>(json);
                    if (tagValues != null)
                    {
                        var activeAlarm = tagValues.FirstOrDefault(kvp =>
                            kvp.Value.TagTypeCodeID.ToString() == "103" &&
                            string.Equals(kvp.Value.TagValue?.ToString(), bool.TrueString, StringComparison.OrdinalIgnoreCase));

                        if (activeAlarm.Key != null)
                        {
                            // 从报警缓存中获取报警详情并补写
                            string activeTagID = activeAlarm.Key;
                            DataRow alarmDt = FuntionMesRead.Base_ObjList[activeTagID] as DataRow;
                            if (alarmDt != null)
                            {
                                string activeIotType = alarmDt["测量位置"].ToString();
                                DeviceStatusMap.TryGetValue(activeIotType, out string activeStatus);
                                activeStatus = activeStatus ?? "6";

                                string activeCode = activeTagID;
                                if (!string.IsNullOrEmpty(activeCode) && activeCode.Length > 4)
                                    activeCode = activeCode.Substring(activeCode.Length - 4);

                                errorPortSave(opName, activeStatus, activeCode, alarmDt["测量项目"].ToString(), null, null, 1);
                            }
                        }
                    }
                }
            }
        }

        // 同一工位串行、不同工位并行，避免报警解除与运行/待机补写互相穿插。
        private void ExecuteDeviceStatusLogInOrder(string opName, Action action)
        {
            string lockKey = opName ?? string.Empty;
            object syncRoot = DeviceStatusLogLocks.GetOrAdd(lockKey, key => new object());
            lock (syncRoot)
            {
                action();
            }
        }

        public static bool errorPortSave(string opName, string DeviceStatus, string MalfunctionCode = null, string MalfunctionName = null, string Malfunctionexplain = null, string Remark = null, int? alarmRemove = null)
        {
            string produceName = "接口_工位运行状态_增加";
            SqlParameter[] thisParms = new SqlParameter[7];
            thisParms[0] = new System.Data.SqlClient.SqlParameter("@工位号", opName);
            thisParms[1] = new System.Data.SqlClient.SqlParameter("@状态代码", DeviceStatus);
            thisParms[2] = new System.Data.SqlClient.SqlParameter("@故障代码", MalfunctionCode);
            thisParms[3] = new System.Data.SqlClient.SqlParameter("@故障名称", MalfunctionName);
            thisParms[4] = new System.Data.SqlClient.SqlParameter("@故障说明", Malfunctionexplain);
            thisParms[5] = new System.Data.SqlClient.SqlParameter("@备注", Remark);
            thisParms[6] = new System.Data.SqlClient.SqlParameter("@alarmRemove", (object)alarmRemove ?? DBNull.Value);
            return DataAccess2.ExecuteStoredProcedure(produceName, ref thisParms, out string errorMessage);
        }

        /// <summary>
        /// 根据工位号获取MesServerCode
        /// </summary>
        /// <param name="OpName"></param>
        /// <returns></returns>
        private static int GetMesServerCodeByOpName(string OpName)
        {
            try
            {
                if (MesServerWork.MIS_BASE.hashtable_MesServerCode.ContainsKey(OpName))
                {
                    return Convert.ToInt32(MesServerWork.MIS_BASE.hashtable_MesServerCode[OpName]);
                }
                return 0;
            }
            catch
            {
                return 0;
            }
        }
        /// <summary>
        /// 根据工位号获取MesServerDll
        /// </summary>
        /// <param name="OpName"></param>
        /// <returns></returns>
        private static string GetMesServeDllByOpName(string OpName)
        {
            try
            {
                if (MesServerWork.MIS_BASE.hashtable_MesDll.ContainsKey(OpName))
                {
                    return MesServerWork.MIS_BASE.hashtable_MesDll[OpName].ToString();
                }
                return "";
            }
            catch (Exception err)
            {
                ApplicationLog.WriteLog(err, "GetMesServeDllByOpName");
                return "";
            }
        }
        /// <summary>
        /// 数据库记录信号变化
        /// </summary>
        /// <param name="msg"></param>
        private void TagTypeCodeID_TagDataOnChange(object msgEvent)
        {
            if (IsRecordTagStatus != "1") return;

            try
            {
                DeviceDriver_BasicData.CustomeEvetnArgs e = (DeviceDriver_BasicData.CustomeEvetnArgs)msgEvent;

                string tagValue;
                if (e.TagValue == null) return;

                switch (e.TagValue.ToString().ToLower())
                {
                    case "1":
                    case "true":
                        tagValue = "1";
                        break;
                    default:
                        tagValue = "0";
                        break;
                }

                string TagTypeCodeID;
                string opName;
                string TagID;
                string TagValue;
                DateTime arrivedTime;
                DateTime leavedTime;
                int TimeDiff;
                opName = e.OpName.ToString();
                TagValue = tagValue;
                TagTypeCodeID = e.TagTypeCodeID.ToString();
                TagID = e.TagID.ToString();
                leavedTime = Convert.ToDateTime(e.TimeStamp);
                arrivedTime = Convert.ToDateTime(e.TimeStampBefore);
                TimeDiff = Convert.ToInt32(e.TagKeepTime);

                if (TagTypeCodeID != "14" && TagTypeCodeID != "15")
                {
                    TagTypeCodeID_Insert(opName, TagTypeCodeID, TagID, TagValue, arrivedTime, leavedTime, TimeDiff);
                }
            }
            catch (Exception err)
            {
                ApplicationLog.WriteLog(err, "TagTypeCodeID_TagDataOnChange");
            }

        }
        /// <summary>
        /// 向MES通讯服务器发送消息
        /// </summary>
        /// <param name="msg"></param>
        private void TransferInfToWebServer(object msg1)
        {
            int tagType;
            string opName;
            DeviceDriver_BasicData.CustomeEvetnArgs msgEvent = (DeviceDriver_BasicData.CustomeEvetnArgs)msg1;
            //e值不能为空
            if (msgEvent.TagValue == null) return;
            tagType = Convert.ToInt32(msgEvent.TagType);
            opName = msgEvent.OpName.ToString();

            if (!MesServerWork.MIS_BASE.m_WorkStart_OpName.ContainsKey(opName)) return;  //当前系统是否存在该工位 

            string cmd;
            string tagValue;
            string msgSvr;
            try
            {
                switch (Convert.ToInt32(msgEvent.TagValueType))
                {
                    case 11:
                        tagValue = (Convert.ToInt32(msgEvent.TagValue)).ToString();
                        break;
                    default:
                        tagValue = msgEvent.TagValue.ToString();
                        break;
                }
                cmd = MIS_BASE.hashtable_TagTypeTagName[tagType.ToString()];
                if (Convert.ToInt32(MIS_BASE.hashtable_WebTagTypeChange[cmd]) == 0 && MIS_BASE.hashtable_WebTagTypeChange[cmd] != null) return;

                if (cmd != "" && cmd != null)
                {
                    msgSvr = "MES|" + cmd + "|" + opName + "|" + tagValue;
                }
                else
                {
                    return;
                }
                //MES web界面显示用
                MIS_SendMessage.asyncSendMessageQos0(msgSvr);
            }
            catch (Exception err)
            {
                ApplicationLog.WriteLog(err, "TransferInfToWebServer");
            }
        }

        private void button_ReadData_Click(object sender, EventArgs e)
        {

        }


        private void ToolStripMenuItem_PlcDebug_Click(object sender, EventArgs e)
        {
            if (opcForm != null)
            {
                opcForm.Close();
                opcForm.Dispose();
                opcForm = null;
            }

            opcForm = new MesWork.OpcForm(IsDemoMesServer);
            opcForm.Show();
        }
        /// <summary>
        /// 关于迈思按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 关于迈思ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.meswork.com");
        }
        /// <summary>
        /// 版本信息按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 版本信息ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            VersionsInformation VersionForm = new VersionsInformation();
            VersionForm.ShowDialog();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            FuntionMesRead.GetAlarmInit();
            MyLog4Net.MyLogHelper.Info($"报警更新：", "报警信息更新完成！");
        }

        private void WritePLCBoolData_Click(int TagTypeCodeId)
        {
            string OpName = WorkStationNum_Now;
            string tagValue = MIS_BASE.Read_TagValueByTagTypeID(TagTypeCodeId, OpName).ToString();
            bool tagValueBool = false;
            if (tagValue.ToLower() == "true" || tagValue == "1")
            {
                tagValueBool = false;
            }
            else
            {
                tagValueBool = true;
            }

            MIS_BASE.Write_TagValueByTagTypeID(TagTypeCodeId, OpName, tagValueBool);
        }
        private void WorkStartPLC_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(2);
        }

        private void PartLoadPLC_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(43);
        }

        private void EngineGetOverMES_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(5);
        }

        private void EngineGetOverPLC_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(44);
        }

        private void allowWorkMES_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(66);
        }

        private void allowSavePLC_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(19);
        }

        private void saveOverMES_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(20);
        }

        private void workOverMES_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(7);
        }

        private void toolPoweredPLC_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(1000);
        }

        private void toolStartPLC_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(1001);
        }

        private void toolErrorPLC_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(1002);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MIS_BASE.Write_TagValueByTagTypeID(200, WorkStationNum_Now, "001MBE0700000QF3D0000001");
            MIS_BASE.Write_TagValueByTagTypeID(201, WorkStationNum_Now, "001MBE0700000QF3D0000002");
            MIS_BASE.Write_TagValueByTagTypeID(202, WorkStationNum_Now, "001MBE0700000QF3D0000003");
            MIS_BASE.Write_TagValueByTagTypeID(203, WorkStationNum_Now, "001MBE0700000QF3D0000004");
            MIS_BASE.Write_TagValueByTagTypeID(204, WorkStationNum_Now, "001MBE0700000QF3D0000005");
            MIS_BASE.Write_TagValueByTagTypeID(205, WorkStationNum_Now, "001MBE0700000QF3D0000006");
            MIS_BASE.Write_TagValueByTagTypeID(206, WorkStationNum_Now, "001MBE0700000QF3D0000007");
            MIS_BASE.Write_TagValueByTagTypeID(207, WorkStationNum_Now, "001MBE0700000QF3D0000008");
        }

        private void button3_Click(object sender, EventArgs e)
        {
            try
            {
                string bodydata = @"
{
    ""MsgId"": ""745e296b-f277-4dd0-bf0b-5f3ccf97ab10"",
    ""OpCode"": ""OP430-1"",
    ""ProductionCode"": ""001PBE0700000Q17E0100001"",
    ""CheckTime"": ""2024-10-29 14:58:58"",
    ""CheckPerson"": ""张三"",
    ""QualityMark"": 1,
    ""CheckData"": [
        {
            ""CheckCode"": ""PL10_M0001_001"",
            ""CheckName"": ""12电芯电压"",
            ""Unit"": ""V"",
            ""StandardValue"": ""10"",
            ""MinValue"": ""10.1"",
            ""MaxValue"": ""9.8"",
            ""CheckValue"": ""10"",
            ""QualityMark"":1
        },
        {
            ""CheckCode"": ""PL10_M0001_002"",
            ""CheckName"": ""12电芯压差"",
            ""Unit"": ""mV"",
            ""StandardValue"": ""0.2"",
            ""MinValue"": ""0"",
            ""MaxValue"": ""0.3"",
            ""CheckValue"": ""0.16"",
            ""QualityMark"": 1
        },
        {
            ""CheckCode"": ""PL10_M0001_001"",
            ""CheckName"": ""23电芯电压"",
            ""Unit"": ""V"",
            ""StandardValue"": ""10"",
            ""MinValue"": ""10.1"",
            ""MaxValue"": ""9.8"",
            ""CheckValue"": ""9.96"",
            ""QualityMark"":1
        },
        {
            ""CheckCode"": ""PL10_M0001_002"",
            ""CheckName"": ""23电芯压差"",
            ""Unit"": ""mV"",
            ""StandardValue"": ""0.2"",
            ""MinValue"": ""0"",
            ""MaxValue"": ""0.3"",
            ""CheckValue"": ""0.17"",
            ""QualityMark"": 1
        }
    ]
}

";

                string retString;
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(OnlineCheckDataUrl);
                request.Method = "post";
                byte[] bytes = Encoding.UTF8.GetBytes(bodydata);
                request.Accept = "*/*";
                request.ContentType = "application/json;charset=utf-8";

                // 反序列化后先把JSON做接口记录
                //存储日志
                int AID = -1;
                var CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                //Event_MOM_Log_Insert,@创建时间,@内容
                var reqParam = new SqlParameter[] {
                new SqlParameter("@接口地址",OnlineCheckDataUrl),
                new SqlParameter("@接口类型",1), // 1. 主动调用接口  2. 被调用接口 
                new SqlParameter("@请求内容",bodydata),
                new SqlParameter("@请求时间",CreateTime)
                };
                DataLinkMesWork1.DataAccess.ExecuteStoredProcedure("接口_IOT接口交互日志_请求记录", ref reqParam, out DataTable reqDt, out string errorMessage);

                if (reqDt.Rows.Count > 0)
                {
                    AID = Convert.ToInt32(reqDt.Rows[0]["AID"]);
                }

                request.ContentLength = bytes.Length;

                // 准备请求体
                Stream myResponseStream = request.GetRequestStream();
                myResponseStream.Write(bytes, 0, bytes.Length);
                //发送webapi请求 等待相应
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                StreamReader myStreamReader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
                retString = myStreamReader.ReadToEnd();

                //响应结果
                CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                var resParam = new SqlParameter[] {
                new SqlParameter("@AID",AID),
                new SqlParameter("@响应时间",CreateTime),
                new SqlParameter("@响应内容",retString)
                };
                DataLinkMesWork1.DataAccess.ExecuteStoredProcedure("接口_IOT接口交互日志_响应记录", ref resParam, out DataTable dt, out errorMessage);

                // 序列化响应内容 
                msgResHeader mrh = JsonConvert.DeserializeObject<msgResHeader>(retString);
                int statusCode = (int)response.StatusCode;
                // 对响应内容进行处理 更新数据库标志 
                if (statusCode == 200)
                {
                    myStreamReader.Close();
                    myResponseStream.Close();
                    string msg = "请求发送成功！详细信息查看日志";
                    MyLog4Net.MyLogHelper.Error("EngineTypeGetOver", msg);
                    if (response != null)
                    {
                        // 失败
                        if (mrh.Code != "200")
                        {
                            MyLog4Net.MyLogHelper.Error("EngineTypeGetOver", "【接收上传质量数据接口】失败");
                        }
                        response.Close();
                    }
                    if (request != null)
                    {
                        request.Abort();
                    }
                }
            }
            catch (Exception err)
            {
                MyLog4Net.MyLogHelper.Error("EngineTypeGetOver", err.Message);
            }
        }

        private void button17_Click(object sender, EventArgs e)
        {
            MIS_BASE.Read_EngineID_MES(WorkStationNum_Now, out string EngineID_MES);
            MIS_BASE.Read_EngineTypeID_MES(WorkStationNum_Now, out int EngineTypeID_MES);
            MIS_BASE.Write_TagValueByTagTypeID(10, WorkStationNum_Now, EngineID_MES);
            MIS_BASE.Write_TagValueByTagTypeID(9, WorkStationNum_Now, EngineTypeID_MES);
            MIS_BASE.Write_TagValueByTagTypeID(80, WorkStationNum_Now, 12);
        }

        private void button18_Click(object sender, EventArgs e)
        {
            string EngineID = textBox1_EngineID.Text;
            string EngineTypeID = textBox2_EngineTypeID.Text;
            string palletCode = textBox3_palletCode.Text;

            MIS_BASE.Write_TagValueByTagTypeID(10, WorkStationNum_Now, EngineID);
            MIS_BASE.Write_TagValueByTagTypeID(9, WorkStationNum_Now, EngineTypeID);
            MIS_BASE.Write_TagValueByTagTypeID(80, WorkStationNum_Now, palletCode);
        }

        private void button19_Click(object sender, EventArgs e)
        {
            WritePLCBoolData_Click(59);
        }


        /// <summary>
        /// 界面上的开启时间
        /// </summary>
        void Runtime_Thread()
        {
            try
            {
                DateTime Now = DateTime.Now;
                TimeSpan x = Now.Subtract(StartTime);
                toolStripStatusLabel_RunTime.Text = x.Days.ToString() + "天" + x.Hours.ToString("00") + "小时" + x.Minutes.ToString("00") + "分" + x.Seconds.ToString("00") + "秒";
            }
            catch (Exception err)
            {
                ApplicationLog.WriteLog(err, err.Message);
            }
        }

        private void cb_F5_CheckedChanged(object sender, EventArgs e)
        {
            var interval = Convert.ToInt32(txt_Interval.Text);

            if (IsLoopReadShow = cb_F5.Checked)
            {
                var t = new Thread(new ParameterizedThreadStart(LoopReadShowTask));
                t.IsBackground = true;
                t.Start(interval);
            }
        }

        private void toolStripStatusLabel_RunTime_Click(object sender, EventArgs e)
        {
        }

        public void LoopReadShowTask(object _interval)
        {
            var interval = (int)_interval;
            while (true)
            {
                try
                {
                    if (IsLoopReadShow == false)
                    {
                        return;
                    }

                    ShowSignal(txt_PLC_9, WorkStationNum_Now);
                    ShowSignal(txt_PLC_10, WorkStationNum_Now);
                    ShowSignal(txt_PLC_11, WorkStationNum_Now);
                    ShowSignal(txt_PLC_39, WorkStationNum_Now);

                    ShowSignal(btn_PLC_2, WorkStationNum_Now);
                    ShowSignal(btn_PLC_43, WorkStationNum_Now);
                    ShowSignal(btn_MES_5, WorkStationNum_Now);

                    ShowSignal(btn_PLC_44, WorkStationNum_Now);
                    ShowSignal(btn_MES_66, WorkStationNum_Now);


                    ShowSignal(btn_PLC_19, WorkStationNum_Now);
                    ShowSignal(btn_MES_20, WorkStationNum_Now);
                    ShowSignal(btn_MES_7, WorkStationNum_Now);

                    ShowSignal(btn_PLC_1000, WorkStationNum_Now);
                    ShowSignal(btn_PLC_1001, WorkStationNum_Now);
                    ShowSignal(btn_PLC_1002, WorkStationNum_Now);
                    ShowSignal(btn_PLC_59, WorkStationNum_Now);

                }
                catch (Exception err)
                {
                }
                Thread.Sleep(interval);
            }

        }


        public void ShowSignal(Control c, string opName)
        {
            var tagTypeCodeID = Convert.ToInt32(c.Name.Split('_')[2]);
            if (c is TextBox)
            {
                try
                {
                    c.Text = PlcLinkForm.ReadPLC(tagTypeCodeID, opName).ToString();

                }
                catch (Exception err)
                {
                    c.Text = "不存在该信号！";
                }
            }
            if (c is Button)
            {
                try
                {
                    c.BackColor = PlcLinkForm.ReadPLC(tagTypeCodeID, opName).ToString().ToLower()
                      .Replace("true", "1").Replace("false", "0") == "1"
                      ? color_Green : color_Bad;
                }
                catch (Exception err)
                {
                    c.BackColor = color_Red;
                }
            }

        }

        private void panel_Signal_Conf_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            new MES_CONF().ShowDialog();
        }

        private void button20_Click(object sender, EventArgs e)
        {
            PrinterCommandCenter.PrintToPrinter(textBox1_EngineID.Text);
        }

        private void dgv_OpName_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex > -1)
            {
                if (AllowLoad)
                {
                    WorkStationNum_Now = dgv_OpName.CurrentRow.Cells["OpCode"].Value.ToString();
                }
            }
        }

        private void webAPI接口测试ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new SlMesDbIterface.Form_MoveSqlTable().Show();
        }

        private void MesEngineDataWritePlc_Click(object sender, EventArgs e)
        {
            // 把工件编号、订单号、产品型号代码、产品型号 写入PLC
            string OpName = WorkStationNum_Now;
            MIS_BASE.WritePLC(9, OpName, MIS_BASE.ReadPLC(73, OpName)); // 机型标志
            MIS_BASE.WritePLC(11, OpName, MIS_BASE.ReadPLC(75, OpName)); // 产品型号
            MIS_BASE.WritePLC(39, OpName, MIS_BASE.ReadPLC(116, OpName)); // 订单号
            MIS_BASE.WritePLC(10, OpName, MIS_BASE.ReadPLC(74, OpName)); // 机型标志
        }

        /// <summary>
        /// 启动失败接口重试线程
        /// </summary>
        private void StartFailedInterfaceRetryThread()
        {
            new Thread(new ThreadStart(delegate ()
            {
                while (true)
                {
                    try
                    {
                        ProcessFailedInterfaceRetry();
                    }
                    catch (Exception ex)
                    {
                        ApplicationLog.WriteLog(ex, "ProcessFailedInterfaceRetry异常");
                    }
                    Thread.Sleep(1000 * 60); // 每分钟执行一次
                }
            }))
            { IsBackground = true }.Start();
        }

        private void StartElectricityThread()
        {
            new Thread(new ThreadStart(delegate ()
            {
                List<string> opNames = new List<string> { };
                string lineName = ConfigurationManager.AppSettings["WebapiPostHeader_Systemcode"].ToString();
                //MES_ZHDQ_126GLKG MES_ZHDQ_126DLQ MES_ZHDQ_126ZZ
                if (lineName == "MES_ZHDQ_126GLKG") opNames = new List<string> { "AC09ET1", "AC09ET2", "AC09ET3" };
                if (lineName == "MES_ZHDQ_126DLQ") opNames = new List<string> { "AC06ET1", "AC06ET2", "AC06ET3" };
                if (lineName == "MES_ZHDQ_126ZZ") opNames = new List<string> { "AC1101" };
                while (true)
                {
                    try
                    {
                        foreach (string opName in opNames)
                        {
                            int kwh = Convert.ToInt32(PlcLinkForm.ReadPLC(501, opName));
                            string produceName = "XD_电能数据_增加";
                            SqlParameter[] thisParms = new SqlParameter[2];
                            thisParms[0] = new System.Data.SqlClient.SqlParameter("@工位号", opName);
                            thisParms[1] = new System.Data.SqlClient.SqlParameter("@正向有功", kwh);
                            DataAccess.ExecuteStoredProcedure(produceName, ref thisParms);

                            SaveElectricityHarmonicData(opName);
                        }
                    }
                    catch (Exception ex)
                    {
                        ApplicationLog.WriteLog(ex, "StartElectricityThread异常");
                    }
                    Thread.Sleep(1000 * 60); // 每分钟执行一次
                }
            }))
            { IsBackground = true }.Start();
        }

        /// <summary>
        /// 采集电能表谐波数据，点位 506-525，每分钟随电能数据一起保存。
        /// </summary>
        private void SaveElectricityHarmonicData(string opName)
        {
            string produceName = "XD_电能表谐波数据_增加";
            SqlParameter[] thisParms = new SqlParameter[]
            {
                new SqlParameter("@工位号", opName),
                new SqlParameter("@A相电压总谐波畸变", ReadElectricityHarmonicValue(506, opName)),
                new SqlParameter("@B相电压总谐波畸变", ReadElectricityHarmonicValue(507, opName)),
                new SqlParameter("@C相电压总谐波畸变", ReadElectricityHarmonicValue(508, opName)),
                new SqlParameter("@系统电压总谐波畸变", ReadElectricityHarmonicValue(509, opName)),
                new SqlParameter("@A相电流总谐波畸变", ReadElectricityHarmonicValue(510, opName)),
                new SqlParameter("@B相电流总谐波畸变", ReadElectricityHarmonicValue(511, opName)),
                new SqlParameter("@C相电流总谐波畸变", ReadElectricityHarmonicValue(512, opName)),
                new SqlParameter("@系统电流总谐波畸变", ReadElectricityHarmonicValue(513, opName)),
                new SqlParameter("@A相电压奇次谐波畸变", ReadElectricityHarmonicValue(514, opName)),
                new SqlParameter("@B相电压奇次谐波畸变", ReadElectricityHarmonicValue(515, opName)),
                new SqlParameter("@C相电压奇次谐波畸变", ReadElectricityHarmonicValue(516, opName)),
                new SqlParameter("@A相电流奇次谐波畸变", ReadElectricityHarmonicValue(517, opName)),
                new SqlParameter("@B相电流奇次谐波畸变", ReadElectricityHarmonicValue(518, opName)),
                new SqlParameter("@C相电流奇次谐波畸变", ReadElectricityHarmonicValue(519, opName)),
                new SqlParameter("@A相电压偶次谐波畸变", ReadElectricityHarmonicValue(520, opName)),
                new SqlParameter("@B相电压偶次谐波畸变", ReadElectricityHarmonicValue(521, opName)),
                new SqlParameter("@C相电压偶次谐波畸变", ReadElectricityHarmonicValue(522, opName)),
                new SqlParameter("@A相电流偶次谐波畸变", ReadElectricityHarmonicValue(523, opName)),
                new SqlParameter("@B相电流偶次谐波畸变", ReadElectricityHarmonicValue(524, opName)),
                new SqlParameter("@C相电流偶次谐波畸变", ReadElectricityHarmonicValue(525, opName))
            };
            DataAccess.ExecuteStoredProcedure(produceName, ref thisParms);
        }

        private object ReadElectricityHarmonicValue(int tagTypeCodeID, string opName)
        {
            try
            {
                object value = PlcLinkForm.ReadPLC(tagTypeCodeID, opName);
                if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
                {
                    return DBNull.Value;
                }

                return Convert.ToDouble(value);
            }
            catch
            {
                return DBNull.Value;
            }
        }

        /// <summary>
        /// 处理失败接口重试逻辑
        /// </summary>
        private void ProcessFailedInterfaceRetry()
        {
            try
            {
                // 读取失败记录
                var readParams = new SqlParameter[0];
                bool hasData = SqlOperation.ExecuteStoredProcedure("接口_IOT接口_上报失败记录_缓存表_读取", readParams, out DataTable dt, out string readError);

                if (hasData && dt != null && dt.Rows.Count > 0)
                {
                    var row = dt.Rows[0];
                    int aid = Convert.ToInt32(row["AID"]);
                    string interfaceName = row["接口名称"].ToString();
                    string interfaceUrl = row["接口地址"].ToString();
                    string requestContent = row["请求内容"].ToString();

                    // 重试接口调用
                    string responseContent = RetryInterfaceCall(interfaceUrl, requestContent);

                    // 判断重试结果
                    bool isSuccess = IsRetrySuccess(responseContent);
                    int resultType = isSuccess ? 1 : 2; // 1:成功删除记录, 2:失败更新记录

                    // 更新状态
                    var updateParams = new SqlParameter[]
                    {
                new SqlParameter("@AID", aid),
                new SqlParameter("@响应内容", responseContent),
                new SqlParameter("@result", resultType)
                    };
                    SqlOperation.ExecuteStoredProcedure("接口_IOT接口_上报失败记录_缓存表_更新状态", updateParams, out string updateError);

                    if (isSuccess)
                    {
                        ApplicationLog.WriteLog($"接口重试成功: {interfaceName}, AID: {aid}");
                    }
                    else
                    {
                        ApplicationLog.WriteLog($"接口重试失败: {interfaceName}, AID: {aid}, 响应: {responseContent}");
                    }
                }
            }
            catch (Exception ex)
            {
                ApplicationLog.WriteLog(ex, "ProcessFailedInterfaceRetry处理异常");
            }
        }

        /// <summary>
        /// 重试接口调用
        /// </summary>
        /// <param name="interfaceUrl">接口地址</param>
        /// <param name="requestContent">请求内容</param>
        /// <returns>响应内容</returns>
        private string RetryInterfaceCall(string interfaceUrl, string requestContent)
        {
            try
            {
                // 直接使用Post_Auto方法发送数据库读取的报文
                return Post.Post_XK(interfaceUrl, requestContent);
            }
            catch (Exception ex)
            {
                return JsonConvert.SerializeObject(new { code = 500, message = ex.Message, data = new object() });
            }
        }

        /// <summary>
        /// 判断重试是否成功
        /// </summary>
        /// <param name="responseContent">响应内容</param>
        /// <returns>是否成功</returns>
        private bool IsRetrySuccess(string responseContent)
        {
            try
            {
                var response = JsonConvert.DeserializeObject<dynamic>(responseContent);
                return response.code.ToString() == "200";
            }
            catch
            {
                return false;
            }
        }


    }


}
