用 Fleck 实现 websocket 通信

<html lang="en">
<head>
    <meta charset="utf-8">
    <title>rfid</title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta content="width=device-width, initial-scale=1" name="viewport">
    <meta content="" name="description">
    <meta content="" name="author">
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css">
    <link href="css/components-rounded.css" rel="stylesheet" id="style_components" type="text/css">
    <link href="css/layout.css" rel="stylesheet" type="text/css">
    <script type="text/javascript" src="echarts.min.js"></script>
    <script type="text/javascript" src="jquery-3.3.1.min.js"></script>
    <script type="text/javascript">
    </script>
</head>
<body class="page-container-bg-solid page-boxed" style="overflow-x:hidden;">
    <div class="page-container">
        <div class="page-content-wrapper">
            <div class="page-content">
                <div class="container">
                    <div class="page-content-inner">
                        <div class="row" style="background-color:lightblue;">
                            <div class="caption font-blue-dark" style="font-size:16px;">
                                <span class="caption-subject bold uppercase" style="margin-left:5px;">综合概况</span>
                            </div>
                        </div>
                        <div class="row" style="padding:5px;background-color:lightblue;">
                            <div class="col-md-6 col-sm-6" style="25%;">
                                <div class="portlet light ">
                                    <div class="portlet-title">
                                        <div class="caption font_blue">
                                            <span class="caption-md"></span>
                                            <span class="caption-desc">按部门(%)</span>
                                        </div>
                                        <div class="actions">
                                        </div>
                                    </div>
                                    <div class="portlet-body">
                                        <div id="dashboard_amchart_4" class="CSSAnimationChart">
                                            <div class="amcharts-main-div">
                                                <div class="amcharts-chart-div">
                                                    <div id="div1" onclick="sendMessage('10');" style="height:300px;margin-top:-20px;"></div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                            <div class="col-md-6 col-sm-6" style="25%;">
                                <div class="portlet light ">
                                    <div class="portlet-title">
                                        <div class="caption font_blue">
                                            <span class="caption-md"></span>
                                            <span class="caption-desc">按类别(%)</span>
                                        </div>
                                        <div class="actions">
                                        </div>
                                    </div>
                                    <div class="portlet-body">
                                        <div id="dashboard_amchart_4" class="CSSAnimationChart">
                                            <div class="amcharts-main-div">
                                                <div class="amcharts-chart-div">
                                                    <div id="div2" onclick="sendMessage('11');" style="height:300px;margin-top:-20px;"></div>
                                                </div>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div class="row" style="padding:5px;background-color:lightgray;">
                            <div class="row" style="margin-left:-15px;margin-right:-15px;">
                                <div class="portlet light" style="background-color:#556422;height:290px;margin-left:15px;margin-right:15px;">
                                    <div class="col-md-6" style="400px;">
                                        <table id="tableData" class="table table-bordered table-hover">
                                            <thead>
                                                <tr style="background-color:#31753c;">
                                                    <td>楼层</td>
                                                    <td>
                                                        <img src="../监控数.png" />
                                                        <label>监控数</label>
                                                    </td>
                                                    <td>
                                                        <img src="../丢失数.png" />
                                                        <label>缺失数</label>
                                                    </td>
                                                </tr>
                                            </thead>
                                            <tbody>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                                <tr></tr>
                                            </tbody>
                                        </table>
                                    </div>
                                    <div style="float:right;">
                                        <img id="imgbg" style="800px;height:290px;" src="../bgpart0.png" />
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script type="text/javascript">
        //echart params
        var echartDiv1 = echarts.init(document.getElementById('div1'));
        var echartDiv2 = echarts.init(document.getElementById('div2'));

        //websocket
        var ws = new WebSocket('ws://localhost:7181/');
        //连接上服务端后触发
        ws.onopen = function () { console.log('Connection to server opened'); }
        //收到服务端发来的消息后触发
        ws.onmessage = function (evt) {
            var data = JSON.parse(evt.data);

            echartDiv1.setOption(data.chartOption1);
            echartDiv2.setOption(data.chartOption2);

            //位置实时统计数据
            var realTimeMonitorData = data.realTimeMonitors;
            var len = realTimeMonitorData.length;
            for (var i = 0; i < len; i++) {
                var flooNo = realTimeMonitorData[i].FloorNo;
                var floorNo1 = flooNo + 400;
                var floorNo2 = flooNo + 500;
                var trStr = "";
                trStr += "<td onclick="sendMessage('" + floorNo1 + "'); "> " + flooNo + " </td>";
                trStr += "<td onclick="sendMessage('" + floorNo2 + "1'); ">" + realTimeMonitorData[i].MonitorSum + "</td>";
                trStr += "<td onclick="sendMessage('" + floorNo2 + "2'); ">" + realTimeMonitorData[i].LossSum + "</td>";

                //注意:tr绑定的事件不能失效
                $(".table-hover > tbody > tr").eq(i).html(trStr);
            }

        }
        //当服务端关闭后触发
        ws.onclose = function () { console.log("Connection closed"); }

        //发送消息给服务器端
        function sendMessage(msg) {
            if (ws.readyState == WebSocket.OPEN) {
                ws.send(msg);
            }
        }
        //断开与服务器端的连接
        function disConnect() {
            ws.close();
        }
        
        //page navigate
        $(".table-hover > tbody > tr").mouseover(function () {
            var idx = $(this).index();
            $("#imgbg").attr("src", "../bgpart" + (10 - idx) + ".png");
        });
        $(".table-hover").mouseleave(function () {
            $("#imgbg").attr("src", "../bgpart0.png");
        });
    </script>
</body>
</html>
using DevExpress.XtraBars.Ribbon;
using Fleck;
using IMS.DBHelper;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using WHC.Framework.Commons;
using RfidPositioning.Common;
using IMS.BaseFramework;
using System.Threading;

namespace IMS.WfmClient
{
    public partial class WebMonitor : RibbonForm
    {
        static System.Timers.Timer _refreshDataTimer = new System.Timers.Timer();
        static List<IWebSocketConnection> _connections = new List<IWebSocketConnection>();
        DataPackage _dataPackage = new DataPackage();
        WebSocketServer _wsServer = new WebSocketServer("ws://0.0.0.0:7181");

        public WebMonitor()
        {
            InitializeComponent();

            //启动线程开始从数据库获取页面所需的数据
            Thread th = new Thread(GetDataForChart);
            th.IsBackground = true;
            th.Start();

            //设置监控界面对应的网页
            string appPath = AppDomain.CurrentDomain.BaseDirectory;
            string chartsPath = "file:///" + appPath + "Resources/eCharts/sample.html";
            webBrowser1.Navigate(new Uri(chartsPath));

            //启动webSocket侦听服务
            _wsServer.Start(item =>
            {
                //与客户端建立连接后触发
                item.OnOpen = () =>
                {
                    _connections.Add(item);

                    //首次建立连接后立刻发送一次数据,之后由定时器来刷新数据
                    string jsonData = _dataPackage.ToJson();
                    _connections.ToList().ForEach(s => s.Send(jsonData));
                };

                //收到客户端发来的消息后触发
                item.OnMessage = message =>
                {
                    int msg = 0;
                    int.TryParse(message, out msg);

                    ClientMessageHandler(msg);
                };

                //客户端关闭连接后触发
                item.OnClose = () =>
                {
                    _connections.Remove(item);
                };
            });
        }

        private void FrmIndex_Load(object sender, EventArgs e)
        {
            // 启动定时器
            _refreshDataTimer.Enabled = true;
            _refreshDataTimer.Interval = 5 * 60 * 1000;
            _refreshDataTimer.Elapsed += new System.Timers.ElapsedEventHandler(timersTimer_Elapsed);
            _refreshDataTimer.Start();
        }

        private void timersTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            GetDataForChart();

            string jsonData = _dataPackage.ToJson();
            _connections.ToList().ForEach(s => s.Send(jsonData));
        }

        private void ClientMessageHandler(int msg)
        {
            if (msg >= 500)
            {
                SysConfig.FloorNumber = (msg % 100).ToString();
                this.Invoke(new Action(() =>
                {
                    ChildWinManagement.LoadMdiForm(SysConfig.mainform, typeof(frmTracePlayback));
                }));
            }
            else if (msg >= 400)
            {
                SysConfig.FloorNumber = (msg / 10 % 100).ToString();
                if (msg % 10 == 1)
                {
                    SysConfig.WarningType = "正常";
                }
                if (msg % 10 == 2)
                {
                    SysConfig.WarningType = "缺失报警";
                }                
                this.Invoke(new Action(() =>
                {
                    ChildWinManagement.LoadMdiForm(SysConfig.mainform, typeof(AssetWatchDetail));
                }));
            }
            else
            {
                StaticsTypeEnum type = (StaticsTypeEnum)msg;

                int typeScale = 0;
                int typeChecks = 0;
                int typePosition = 0;
                int typeInstrument = 0;
                getStaticsType(out typeScale, out typeChecks, out typePosition, out typeInstrument);

                switch (msg)
                {
                    case 10:
                    case 11:
                        SysConfig.ReportByAssetsType = msg == 10 ? false : true;
                        NavigateToForm(typePosition, typeof(FrmAssetsValueReport));
                        break;
                    case 12:
                    case 13:
                        SysConfig.ReportByAssetsType = msg == 12 ? false : true;
                        NavigateToForm(typePosition, typeof(FrmInventoryReport));
                        break;                    
                    case 30:
                        webBrowser1.Refresh();
                        break;
                    case 31:
                        this.Invoke(new Action(() =>
                        {
                            Form form = new SetStaticsType();
                            form.Owner = this;
                            form.StartPosition = FormStartPosition.CenterScreen;
                            form.ShowDialog();
                        }));
                        break;
                    default:
                        break;
                }
            }
        }

        private void getStaticsType(out int typeScale, out int typeChecks, out int typePosition, out int typeInstrument)
        {
            typeScale = 0;
            typeChecks = 0;
            typePosition = 0;
            typeInstrument = 0;

            //查询默认选择的统计方式(从数据库获取已设置过的数据)            
            string strsql = "select * from HT_MonitorStaticsType;";
            DataSet ds = SQLHelper.Query(SQLHelper._connstr, strsql);
            if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
            {
                typeScale = Convert.ToInt32(ds.Tables[0].Rows[0]["Monitor"].ToString());
                typeChecks = Convert.ToInt32(ds.Tables[0].Rows[0]["Checks"].ToString());
                typePosition = Convert.ToInt32(ds.Tables[0].Rows[0]["Position"].ToString());
                typeInstrument = Convert.ToInt32(ds.Tables[0].Rows[0]["Instrument"].ToString());
            }
        }

        private void NavigateToForm(int type, Type formType)
        {
            if (type == 1) //按月
            {
                SysConfig.ReportStartDate = DateTime.Now.ToString("yyyyMM") + "01";
                SysConfig.ReportEndDate = DateTime.Now.AddMonths(1).ToString("yyyyMM") + "01";
            }
            else
            {
                SysConfig.ReportStartDate = DateTime.Now.AddYears(-1).ToString("yyyyMMdd");
                SysConfig.ReportEndDate = DateTime.Now.ToString("yyyyMMdd");
            }

            this.Invoke(new Action(() =>
            {
                ChildWinManagement.LoadMdiForm(SysConfig.mainform, formType);
            }));
        }

        #region 图表数据

        class RealTimeMonitor
        {
            public string FloorNo { get; set; }
            public string MonitorSum { get; set; }
            public string LossSum { get; set; }
            public string PositionSum { get; set; }
            public string LowSum { get; set; }
        }

        class ChartAssetWatch
        {
            public string Name { get; set; }
            public string Value { get; set; }
            public string StaticsType { get; set; }
        }

        class ChartCheck
        {
            public string Name { get; set; }
            public string Value { get; set; }
            public string DataType { get; set; }
            public string StaticsType { get; set; }
        }

        class ChartPosition
        {
            public string Name { get; set; }
            public string Value { get; set; }
            public string DataType { get; set; }
            public string StaticsType { get; set; }
        }

        class ChartInstrument
        {
            public string Name { get; set; }
            public string Value { get; set; }
            public string StaticsType { get; set; }
        }

        class DataPackage
        {
            public ChartOptionForAssetWatch chartOption1 { get; set; }
            public ChartOptionForAssetWatch chartOption2 { get; set; }
            public ChartOption chartOption3 { get; set; }
            public ChartOption chartOption4 { get; set; }public List<RealTimeMonitor> realTimeMonitors { get; set; }
        }

        void GetDataForChart()
        {
            int typeScale = 0;
            int typeChecks = 0;
            int typePosition = 0;
            int typeInstrument = 0;
            getStaticsType(out typeScale, out typeChecks, out typePosition, out typeInstrument);

            _dataPackage.chartOption1 = getChartDataAssetWatch("HT_ChartAssetWatchDept", typeScale);
            _dataPackage.chartOption2 = getChartDataAssetWatch("HT_ChartAssetWatchType", typeScale);

            _dataPackage.chartOption3 = getChartDataCheck("HT_ChartCheckDept", typeChecks);
            _dataPackage.chartOption4 = getChartDataCheck("HT_ChartCheckType", typeChecks);

            List<RealTimeMonitor> realTimeMonitors = getRealTimeMonitorData();
            _dataPackage.realTimeMonitors = realTimeMonitors;
        }

        ChartOptionForAssetWatch getChartDataAssetWatch(string tableName, int staticsType)
        {
            ChartOptionForAssetWatch chartOption = new ChartOptionForAssetWatch();
            try
            {
                string sqlStr = @"SELECT [Name],[Value],[StaticsType] FROM XXX.[dbo].[" + tableName + "] WHERE StaticsType = " + staticsType + " order by Name desc;";
                DataSet ds = SQLHelper.Query(SQLHelper._connstr, sqlStr);

                List<ChartAssetWatch> chartData = ds.Tables[0].ConvertToModel<ChartAssetWatch>();

                //截取长度超出5的字符串
                chartData.ForEach(item =>
                {
                    if (item.Name.Length > 5)
                    {
                        item.Name = item.Name.Substring(0, 4) + "..";
                    }
                });

                //合并数量少的分组
                List<ChartAssetWatch> chartDataNew = new List<ChartAssetWatch>();
                chartDataNew.AddRange(chartData.OrderByDescending(p => p.Value).Take(5)); //取前5条数据
                chartDataNew.ForEach(p => { chartData.Remove(p); });
                chartDataNew.Add(new ChartAssetWatch { Name = "其他", Value = chartData.Sum(p => Convert.ToDecimal(p.Value)).ToString() });

                chartOption.tooltip = new tooltip();
                chartOption.tooltip.trigger = "item";
                chartOption.tooltip.formatter = "{a} <br/>{b}: {c} ({d}%)";
                chartOption.legend = new legend();
                chartOption.legend.type = "scroll";
                chartOption.legend.orient = "vertical";
                chartOption.legend.left = "0";
                chartOption.legend.top = "0";
                chartOption.legend.data = chartDataNew.Select(p => p.Name).ToArray();
                chartOption.series = new SeriesForAssetWatch[1];
                SeriesForAssetWatch series = new SeriesForAssetWatch();
                series.name = "";
                series.type = "pie";
                series.radius = new string[] { "60%", "30%" };
                series.center = new string[] { "55%", "55%" };
                series.avoidLabelOverlap = "false";
                series.label = new label();
                series.label.normal = new normal();
                series.label.normal.show = false;
                series.label.normal.position = "center";
                series.label.emphasis = new emphasis();
                series.label.emphasis.show = "true";
                series.label.emphasis.textStyle = new textStyle();
                series.label.emphasis.textStyle.fontSize = "20";
                series.labelLine = new labelLine();
                series.labelLine.normal = new normal();
                series.labelLine.normal.show = false;
                List<DataNew> d = new List<DataNew>();
                chartDataNew.ForEach(p => { d.Add(new DataNew { name = p.Name, value = p.Value }); });
                series.data = d.ToArray();
                chartOption.series = new SeriesForAssetWatch[1];
                chartOption.series[0] = series;

                return chartOption;
            }
            catch { return null; }
        }

        ChartOption getChartDataCheck(string tableName, int staticsType)
        {
            ChartOption chartOption = new ChartOption();
            try
            {
                string sqlStr = @"SELECT [Name],[Value],[DataType],[StaticsType] FROM [Lonix_Fas_1].[dbo].[" + tableName + "] WHERE StaticsType = " + staticsType + " order by Name desc;";
                DataSet ds = SQLHelper.Query(SQLHelper._connstr, sqlStr);

                List<ChartCheck> chartData = ds.Tables[0].ConvertToModel<ChartCheck>();

                //截取长度超出5的字符串
                chartData.ForEach(item =>
                {
                    if (item.Name.Length > 5)
                    {
                        item.Name = item.Name.Substring(0, 4) + "..";
                    }
                });

                //合并数量少的分组
                List<ChartCheck> chartInstrumentsNew1 = new List<ChartCheck>();
                chartInstrumentsNew1.AddRange(chartData.Where(p => p.DataType == "1").OrderByDescending(p => p.Value).Take(5)); //取前5条数据
                chartInstrumentsNew1.ForEach(p => { chartData.Remove(p); });
                chartInstrumentsNew1.Add(new ChartCheck { Name = "其他", Value = chartData.Where(p => p.DataType == "1").Sum(p => Convert.ToDecimal(p.Value)).ToString() });

                List<ChartCheck> chartInstrumentsNew2 = new List<ChartCheck>();
                chartInstrumentsNew2.AddRange(chartData.Where(p => p.DataType == "2").OrderByDescending(p => p.Value).Take(5)); //取前5条数据
                chartInstrumentsNew2.ForEach(p => { chartData.Remove(p); });
                chartInstrumentsNew2.Add(new ChartCheck { Name = "其他", Value = chartData.Where(p => p.DataType == "2").Sum(p => Convert.ToDecimal(p.Value)).ToString() });

                chartOption.tooltip = new tooltip();
                chartOption.tooltip.trigger = "axis";
                chartOption.tooltip.axisPointer = new axisPointer();
                chartOption.tooltip.axisPointer.type = "shadow";

                chartOption.legend = new legend();
                chartOption.legend.orient = "horizontal";
                chartOption.legend.data = new string[] { "盘亏数", "已盘数" };

                chartOption.grid = new grid();
                chartOption.grid.top = "80";
                chartOption.grid.left = "3%";
                chartOption.grid.right = "6%";
                chartOption.grid.bottom = "30";
                chartOption.grid.containLabel = true;

                chartOption.xAxis = new Axis();
                chartOption.xAxis.type = "value";
                chartOption.xAxis.axisLabel = new axisLabel();
                chartOption.xAxis.axisLabel.interval = "0";
                chartOption.xAxis.axisLabel.rotate = "0";

                chartOption.yAxis = new Axis();
                chartOption.yAxis.type = "category";
                chartOption.yAxis.data = chartInstrumentsNew1.Select(p => p.Name).ToArray();
                chartOption.yAxis.axisLabel = new axisLabel();
                chartOption.yAxis.axisLabel.interval = "0";
                chartOption.yAxis.axisLabel.rotate = "0";

                chartOption.series = new Series[2];
                Series s1 = new Series();
                s1.name = "盘亏数";
                s1.type = "bar";
                s1.stack = "总量";
                s1.label = new label();
                s1.label.normal = new normal();
                s1.label.normal.show = true;
                s1.label.normal.position = "insideRight";
                s1.data = chartInstrumentsNew1.Select(p => p.Value).ToArray();
                chartOption.series[0] = s1;
                Series s2 = new Series();
                s2.name = "已盘数";
                s2.type = "bar";
                s2.stack = "总量";
                s2.label = new label();
                s2.label.normal = new normal();
                s2.label.normal.show = true;
                s2.label.normal.position = "insideRight";
                s2.data = chartInstrumentsNew2.Select(p => p.Value).ToArray();
                chartOption.series[1] = s2;

                return chartOption;
            }
            catch { return null; }
        }

        List<RealTimeMonitor> getRealTimeMonitorData()
        {
            string sqlStr = @"select [FloorNo],[MonitorSum],[LossSum],[PositionSum],[LowSum] from XXX.[dbo].[HT_RealTimeMonitor] order by FloorNo desc;";
            DataSet ds = SQLHelper.Query(SQLHelper._connstr, sqlStr);
            return ds.Tables[0].ConvertToModel<RealTimeMonitor>();
        }

        #endregion
    }
}
namespace IMS.WfmClient
{
    public class ChartOption
    {
        public tooltip tooltip { get; set; }
        public legend legend { get; set; }
        public grid grid { get; set; }
        public Axis xAxis { get; set; }
        public Axis yAxis { get; set; }
        public Series[] series { get; set; }
    }

    public class ChartOptionForAssetWatch
    {
        public tooltip tooltip { get; set; }
        public legend legend { get; set; }
        public grid grid { get; set; }
        public Axis xAxis { get; set; }
        public Axis yAxis { get; set; }
        public SeriesForAssetWatch[] series { get; set; }
    }

    public class tooltip
    {
        public string trigger { get; set; }
        public string formatter { get; set; }
        public axisPointer axisPointer { get; set; }
    }
    public class axisPointer
    {
        public string type { get; set; }
    }
    public class legend
    {
        public string type { get; set; }
        public string orient { get; set; }
        public string left { get; set; }
        public string top { get; set; }
        public string[] data { get; set; }
    }
    public class grid
    {
        public string top { get; set; }
        public string left { get; set; }
        public string right { get; set; }
        public string bottom { get; set; }
        public bool containLabel { get; set; }
    }
    public class Axis
    {
        public string type { get; set; }
        public axisLabel axisLabel { get; set; }
        public string[] data { get; set; }
    }
    public class axisLabel
    {
        public string interval { get; set; }
        public string rotate { get; set; }
    }
    public class Series
    {
        public string name { get; set; }
        public string type { get; set; }
        public string center { get; set; }
        public string avoidLabelOverlap { get; set; }
        public string stack { get; set; }
        public label label { get; set; }
        public string[] data { get; set; }
    }
    public class SeriesForAssetWatch
    {
        public string name { get; set; }
        public string type { get; set; }
        public string[] radius { get; set; }
        public string[] center { get; set; }
        public string avoidLabelOverlap { get; set; }
        public string stack { get; set; }
        public label label { get; set; }
        public labelLine labelLine { get; set; }
        public DataNew[] data { get; set; }
    }
    public class DataNew
    {
        public string value { get; set; }
        public string name { get; set; }
    }
    public class label
    {
        public normal normal { get; set; }
        public emphasis emphasis { get; set; }
    }
    public class normal
    {
        public bool show { get; set; }
        public string position { get; set; }
    }
    public class emphasis
    {
        public string show { get; set; }
        public textStyle textStyle { get; set; }
    }
    public class textStyle
    {
        public string fontSize { get; set; }
    }
    public class labelLine
    {
        public normal normal { get; set; }
    }
}
原文地址:https://www.cnblogs.com/hellowzl/p/10370581.html