4227浏览
查看: 4227|回复: 1

[2019参赛作品] 【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)

[复制链接]
    作为IoT云平台的数据交互PC客户端,对平台的数据进行展示,实现本地与远程终端的数据交互,进而展现出依赖云平台的应用使用的具体场景,进一步展现云品台的优势。
    1、项目结构
    整个使用常规的传统的三层架构,同时引入MVVM架构模式,属于混合型架构设计,将各个层次之间实现理论解耦,提高了系统各个层次之间的独立性和可拓展性。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图1
    结构说明如下:
    HandyC.HW:项目实际入口,表现层,实际用户操作逻辑的输入输出部分。
    HandyC.HW.ViewModels:与表现层与之对应的视图实体类部分,对用户交互逻辑的主要实现处理模块,同时在该项目中进行相关数据实体和视图实体的相互转换工作。
    HandyC.HW.Data:用于处理来自于IoT平台的数据源,为业务层提供需求的数据结果。
    HandyC.HW.Service:项目的实际业务逻辑处理,组织数据层提供的数据。
    HandyC.HW.Tools:项目整体结构中需要使用到的基础辅助类集合,包括网络请求相关类,缓存,数据序列化和反序列化,特殊数据格式处理等。
  对应测试项目与之对应,前缀为Test.*,此处忽略
  2、系统组织架构
  系统组织架构分为两个大的功能模块,平台监管以及数据采集两个模块,平台监管主要是对设备实时动态进行监管,数据采集,处理来自IOT云平台的历史相关数据并展示。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图2
    3、使用技术
  • 网络通信相关技术(数据接口请求)
  • WPF(UI框架)
  • MvvmLight(MVVM框架)
  • 依赖注入
  • 简单缓存
  • LiveCharts(图标框架)
  • HandyControl(WPF组件框架)
  • 非对称双向认证(Https)
  • AutoMapper(DTO转换框架)
    4、开发环境与工具
  • 开发环境:Windows7 sp1、.Net Framework 4.7.2
  • 开发语言:C#
  • 开发工具:MicrosoftVisual Studio professional 2019(VS 2019)
    5、功能介绍
设备管理页面的主页面,红框区域内为设备统计,包含了对当前设备的设备类型、设备状态、设备的协议类型的相关统计信息,属于设备总体的一个统计信息。设备列表中展示的是当前的存在的设备,以卡片的方式展示出来,包括设备的名称、设备的型号、设备的编号等预览。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图4
  显示设备的详细信息。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图3
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图5
  设备的实时数据显示页面,能够动态实时请求道IoT平台上的设备下发的最近历史信息。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图6
  云平台联动主页中的卡片为一卡片一设备,点击设备卡片,可以对设备进行联动模式控制,可支持三种联动模式,终端联控模式、自动调光模式和分段定时模式。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图7
默认手动模式,可以通过手动直接下发指令到IoT平台,通过平台将命令通知对应的设备执行,点击控制按钮进行云平台挂载设备的开启和关闭。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图8
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图9
    用户可以通过点击切换至定时模式,设定时间后,将点击发送定时设备,等待设定的命令发送至IoT平台。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图10
    命令下发成功是接收到的反馈信息。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图11
    自动模式与手动模式的操作类似,用户通过开启和关闭实现对IoT平台上挂载的设备的执行模式的设定,关闭时,设备默认执行,为上一次的模式运行状态,开启时,变更为根据实际的自动条件进行自身状态的控制。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图12
    设备历史数据显示页面,主要功能为查询功能,用于显示从IoT平台获取到的当前设备对应的历史记录信息,可通过查询条件进行更加细致数据查找。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图13
    点击每条记录的操作列按钮,能够获取到该条记录的详细信息。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图14
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图15
    下图的页面为命令历史数据的主页面,默认显示第一个设备的相关历史数据,能够查询到多端给设备发送的相关命令指令历史信息。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图16
    通过点击每条记录末尾的数据明细,可以查看到当前命令记录的具体信息。
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图17
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图18
    6、核心代码
    PC端主要分为两个部分,一个是通过https请求双向认证获取到来自于IoT平台提供的相关Api接口的目标数据,将数据进行处理根据View的需求进行相关的ViewModel处理之后展示到页面中;一个是需要PC端与IoT平台上的挂载设备进行数据交互时,实现本地命令的发送,进而间接控制设备的数据响应。
    鉴定权限代码如下:
[mw_shl_code=csharp,true]using HandyC.HW.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace HandyC.HW.Data
{
/// <summary>
/// 鉴权数据处理类
/// </summary>
public class Authentication:IAuthentication
{
private readonly string accessTokenName = "Authentication";
private ICacheAdapter cache;
public Authentication(ICacheAdapter adapter)
{
cache = adapter;
}

/// <summary>
/// 获取鉴权的数据实例
/// </summary>
/// <param name="ErrorCallBack">异常时执行回调</param>
/// <returns>权限信息</returns>
public ApiAuthInfo GetApiAuth(Action<object> ErrorCallBack)
{
//判定缓存中是否存在用户项目信息
ApiAuthInfo apiAuthInfo = GetCertificateCache();
if (apiAuthInfo != null)
{
return apiAuthInfo;
}
//获取证书
var cer = AuthContext.SSLConfig.X509Certificate2;
#region 设定当前请请求
Dictionary<string, string> dataDic = new Dictionary<string, string> {
{ "appId",AuthContext.ClientInfo.AppId },
{"secret",AuthContext.ClientInfo.Secret }
};
//实例化RequestMessage
HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, ApiUrls.Login, "POST", dataDic,null);
requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
#endregion
//获取实例请求
apiAuthInfo = HttpHelper.PostResponse<ApiAuthInfo>(requestMessage,cer);
if (apiAuthInfo == null)
{
//处理异常信息
ErrorCallBack(HttpHelper.ApiException);
return apiAuthInfo;
}
//添加实例类到缓存中
cache.Set(accessTokenName, apiAuthInfo,DateTime.Now.AddSeconds(apiAuthInfo.ExpiresIn));
return apiAuthInfo;
}
/// <summary>
/// 刷新Token值-服务端异常
/// </summary>
/// <param name="ErrorCallBack">异常时执行回调</param>
/// <returns>权限信息</returns>
public ApiAuthInfo RefreshApiAuth(Action<object> ErrorCallBack)
{
//判定缓存中是否存在用户项目信息
ApiAuthInfo apiAuthInfo = GetCertificateCache();
//若当前缓存中不存在鉴权
if (apiAuthInfo == null)
{
return null;
}
//获取证书
var cer = AuthContext.SSLConfig.X509Certificate2;
#region 设定当前请请求
Dictionary<string, string> dataDic = new Dictionary<string, string> {
{"appId",AuthContext.ClientInfo.AppId },
{"secret",AuthContext.ClientInfo.Secret },
{ "refreshToken",apiAuthInfo.RefreshToken}
};
//实例化
HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, ApiUrls.RefreshToken, "POST", dataDic, null);
//此处为智障代码切记小心
if (requestMessage.Content != null)
{
requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
}

#endregion
//获取实例请求
apiAuthInfo = HttpHelper.GetResponse<ApiAuthInfo>(requestMessage, cer);
if (apiAuthInfo == null)
{
//处理异常信息
ErrorCallBack(HttpHelper.ApiException);
return apiAuthInfo;
}
//添加实例类到缓存中
cache.Set(accessTokenName, apiAuthInfo, DateTime.Now.AddSeconds(apiAuthInfo.ExpiresIn));
return apiAuthInfo;
}
/// <summary>
///刷新密钥
///校验当前密钥是否过期
/// </summary>
/// <returns>权限信息</returns>
public ApiAuthInfo GetCertificateCache()
{
ApiAuthInfo apiAuth = cache.Get<ApiAuthInfo>(accessTokenName);
return apiAuth;
}
}
}
[/mw_shl_code]
    获取设备信息代码如下:[mw_shl_code=csharp,true]using HandyC.HW.Tools;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace HandyC.HW.Data
{
    /// <summary>
    /// 数据采集操作实体
    /// </summary>
    public class DataCollection: IDataCollection
    {
        private IAuthentication _authentication;
        public DataCollection(IAuthentication authentication)
        {
            _authentication = authentication;
        }
        //查询单个设备信息
        public QuerySingleDeviceInfoOutDTO QuerySingleDeviceInfo(string deviceId, Action<object> ErrorCallBack)
        {
            if (string.IsNullOrEmpty(deviceId))
            {
                throw new NullReferenceException("deviceId 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> dataDic = new Dictionary<string, string>();

            string localPath = ApiUrls.queryDeviceInfo.Replace("{deviceId}", deviceId);


            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "GET", dataDic, headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.PostResponse<QuerySingleDeviceInfoOutDTO>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }
        //批量查询设备信息列表
        public QueryBatchDevicesInfoOutDTO QueryBatchDevicesInfo(QueryBatchDevicesInfoInDTO filter, Action<object> ErrorCallBack)
        {
            if (filter is null)
            {
                throw new NullReferenceException("filter 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                //处理异常信息
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> pathDic = new Dictionary<string, string>();
            //遍历获取对应实体的所有当前类自身属性
            Type type = filter.GetType();
            System.Reflection.PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var value = property.GetValue(filter);
                if (!(value is null))
                {
                    var customAttribute = property.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(Newtonsoft.Json.JsonPropertyAttribute));
                    if (customAttribute != null)
                    {
                        //获取到符合条件的参数信息
                        var namedArgument = customAttribute.NamedArguments.FirstOrDefault(x => x.MemberName == "PropertyName");
                        //判定参数名称参数对应的别名名称不为空
                        if (namedArgument != null && namedArgument.TypedValue.Value != null)
                        {
                            pathDic.Add(namedArgument.TypedValue.Value.ToString(), value.ToString());
                        }
                    }
                    else
                    {
                        pathDic.Add(property.Name, value.ToString());
                    }
                }
            }
            string strPath = pathDic.DictionaryToString();
            string localPath = ApiUrls.queryDevices.Replace("?", $"?{strPath}");
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "GET", new Dictionary<string, string>(), headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }

            //requestMessage.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Postman/6.5.2 Chrome/59.0.3071.115 Electron/1.8.4 Safari/537.36");
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<QueryBatchDevicesInfoOutDTO>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }
        //查询设备历史信息
        public DeviceDataSource QueryDeviceDataHistory(QueryDeviceDataHistoryInDTO filter, Action<object> ErrorCallBack)
        {
            if (filter is null)
            {
                throw new NullReferenceException("filter 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> pathDic = new Dictionary<string, string>();
            //遍历获取对应实体的所有当前类自身属性
            Type type = filter.GetType();
            System.Reflection.PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var value = property.GetValue(filter);
                if (!(value is null))
                {
                    var customAttribute = property.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(Newtonsoft.Json.JsonPropertyAttribute));
                    if (customAttribute != null)
                    {
                        //获取到符合条件的参数信息
                        var namedArgument = customAttribute.NamedArguments.FirstOrDefault(x => x.MemberName == "PropertyName");
                        //判定参数名称参数对应的别名名称不为空
                        if (namedArgument != null && namedArgument.TypedValue.Value != null)
                        {
                            pathDic.Add(namedArgument.TypedValue.Value.ToString(), value.ToString());
                        }
                    }
                    else
                    {
                        pathDic.Add(property.Name, value.ToString());
                    }
                }
            }
            string strPath = pathDic.DictionaryToString();
            string localPath = ApiUrls.queryHistoryDevice.Replace("?", $"?{strPath}");
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "GET", new Dictionary<string, string>(), headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<DeviceDataSource>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }
        //查询影子历史数据信息
        public DeviceDesiredSource QueryDeviceDesiredHistory(QueryDeviceDesiredHistoryInDTO filter, Action<object> ErrorCallBack)
        {
            if (filter is null)
            {
                throw new NullReferenceException("filter 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> pathDic = new Dictionary<string, string>();
            //遍历获取对应实体的所有当前类自身属性
            Type type = filter.GetType();
            System.Reflection.PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var value = property.GetValue(filter);
                if (!(value is null))
                {
                    var customAttribute = property.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(Newtonsoft.Json.JsonPropertyAttribute));
                    if (customAttribute != null)
                    {
                        //获取到符合条件的参数信息
                        var namedArgument = customAttribute.NamedArguments.FirstOrDefault(x => x.MemberName == "PropertyName");
                        //判定参数名称参数对应的别名名称不为空
                        if (namedArgument != null && namedArgument.TypedValue.Value != null)
                        {
                            pathDic.Add(namedArgument.TypedValue.Value.ToString(), value.ToString());
                        }
                    }
                    else
                    {
                        pathDic.Add(property.Name, value.ToString());
                    }
                }
            }
            string strPath = pathDic.DictionaryToString();
            string localPath = ApiUrls.queryHistoryShadowDevice.Replace("?", $"?{strPath}");
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "GET", new Dictionary<string, string>(), headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<DeviceDesiredSource>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }

        //查询设备服务信息
        public DeviceCapabilitySource QueryDeviceCapability(QueryDeviceCapabilitiesInDTO filter, Action<object> ErrorCallBack)
        {
            if (filter is null)
            {
                throw new NullReferenceException("filter 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> pathDic = new Dictionary<string, string>();
            //遍历获取对应实体的所有当前类自身属性
            Type type = filter.GetType();
            System.Reflection.PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var value = property.GetValue(filter);
                if (!(value is null))
                {
                    var customAttribute = property.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(Newtonsoft.Json.JsonPropertyAttribute));
                    if (customAttribute != null)
                    {
                        //获取到符合条件的参数信息
                        var namedArgument = customAttribute.NamedArguments.FirstOrDefault(x => x.MemberName == "PropertyName");
                        //判定参数名称参数对应的别名名称不为空
                        if (namedArgument != null && namedArgument.TypedValue.Value != null)
                        {
                            pathDic.Add(namedArgument.TypedValue.Value.ToString(), value.ToString());
                        }
                    }
                    else
                    {
                        pathDic.Add(property.Name, value.ToString());
                    }
                }
            }
            string strPath = pathDic.DictionaryToString();
            string localPath = ApiUrls.queryDeviceServices.Replace("?", $"?{strPath}");
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "GET", new Dictionary<string, string>(), headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<DeviceCapabilitySource>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }
    }
}[/mw_shl_code]
    下发命令代码如下:[mw_shl_code=csharp,true]using HandyC.HW.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace HandyC.HW.Data
{
    /// <summary>
    /// 设备命令数据处理类
    /// </summary>
    public class DeviceCommand: IDeviceCommand
    {
        private IAuthentication _authentication;
        public DeviceCommand(IAuthentication authentication)
        {
            _authentication = authentication;
        }
        //创建设备命令
        public PostDeviceCommandOutDTO2 CreateDeviceCommand(PostDeviceCommandInDTO2 dataComand, Action<object> ErrorCallBack)
        {
            if (dataComand is null)
            {
                throw new NullReferenceException("dataComand 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            string strJson = dataComand.ObjectToJson();
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, ApiUrls.createDeviceCmd, "POST", strJson, headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<PostDeviceCommandOutDTO2>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }

        //查询设备命令
        public QueryDeviceCommandOutDTO2 QueryDeviceCommand(QueryDeviceCommandInDTO2 filter, Action<object> ErrorCallBack)
        {
            if (filter is null)
            {
                throw new NullReferenceException("filter 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> dataDic = new Dictionary<string, string>();
            //Queries
            Dictionary<string, string> pathDic = new Dictionary<string, string>();
            //遍历获取对应实体的所有当前类自身属性
            Type type = filter.GetType();
            System.Reflection.PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var value = property.GetValue(filter);
                if (!(value is null))
                {
                    var customAttribute = property.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(Newtonsoft.Json.JsonPropertyAttribute));
                    if (customAttribute != null)
                    {
                        //获取到符合条件的参数信息
                        var namedArgument = customAttribute.NamedArguments.FirstOrDefault(x => x.MemberName == "PropertyName");
                        //判定参数名称参数对应的别名名称不为空
                        if (namedArgument != null && namedArgument.TypedValue.Value != null)
                        {
                            pathDic.Add(namedArgument.TypedValue.Value.ToString(), value.ToString());
                        }
                    }
                    else
                    {
                        pathDic.Add(property.Name, value.ToString());
                    }
                }
            }
            string queryStr = pathDic.DictionaryToString();
            string localPath = ApiUrls.queryDeviceCmd.Replace("?", $"?{queryStr}");
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "GET", dataDic, headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<QueryDeviceCommandOutDTO2>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }

        //修改设备命令
        public ModifyDeviceCommandOutDTO ModifyDeviceCommand(ModifyDeviceCommandInDTO filter,string deviceCommandId, Action<object> ErrorCallBack)
        {
            if (filter is null)
            {
                throw new NullReferenceException("filter 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            string strJson = filter.ObjectToJson();
            string localPath = ApiUrls.modifyDeviceCmd.Replace("{deviceCommandId}", deviceCommandId);
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "PUT", strJson, headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<ModifyDeviceCommandOutDTO>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }

        //查询特定设备命令状态
        public DeviceCommandRespV4 QueryDeviceCommandStatus(string deviceId, string commandId, Action<object> ErrorCallBack)
        {
            if (string.IsNullOrEmpty(deviceId))
            {
                throw new NullReferenceException("deviceId 不能为Null");
            }
            if (string.IsNullOrEmpty(commandId))
            {
                throw new NullReferenceException("commandId 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> dataDic = new Dictionary<string, string>();
            //Path
            string localPath = ApiUrls.queryDeviceCmdStatus.Replace("{deviceId}", deviceId).Replace("{commandId}",commandId);
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, localPath, "GET", dataDic, headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<DeviceCommandRespV4>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }
        //批量创建设备命令

        //创建设备命令撤销任务
        public CreateDeviceCmdCancelTaskOutDTO CreateDeviceCmdCancelTask(CreateDeviceCmdCancelTaskInDTO dataComand, Action<object> ErrorCallBack)
        {
            if (dataComand is null)
            {
                throw new NullReferenceException("dataComand 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            string strJson = dataComand.ObjectToJson();
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, ApiUrls.createDeviceCancleTasks, "POST", strJson, headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<CreateDeviceCmdCancelTaskOutDTO>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }
        //查询设备命令撤销任务
        public QueryDeviceCmdCancelTaskOutDTO2 QueryDeviceCommandTask(QueryDeviceCmdCancelTaskInDTO2 filter,Action<object> ErrorCallBack)
        {
            if (filter is null)
            {
                throw new NullReferenceException("filter 不能为Null");
            }
            //获取accessToken信息
            ApiAuthInfo apiAuthInfo = _authentication.GetApiAuth(ErrorCallBack);
            if (apiAuthInfo == null)
            {
                return null;
            }
            //构建请求需要的header和body
            //Headers
            Dictionary<string, string> headerDic = new Dictionary<string, string>
            {
                { "app_key",AuthContext.ClientInfo.AppId},
                { "Authorization",$"{apiAuthInfo.TokenType} {apiAuthInfo.AccessToken}"}
            };
            //Body
            Dictionary<string, string> dataDic = new Dictionary<string, string>();
            //遍历获取对应实体的所有当前类自身属性
            Type type = filter.GetType();
            System.Reflection.PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var value = property.GetValue(filter);
                if (!(value is null))
                {
                    dataDic.Add(property.Name, value.ToString());
                }
            }
            HttpRequestMessage requestMessage = HttpHelper.SetRequestMessage(AuthContext.ClientInfo.Host, ApiUrls.queryDeviceCancleTasks, "GET", dataDic, headerDic);
            //此处为智障代码切记小心
            if (requestMessage.Content != null)
            {
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
            }
            //获取证书
            var cer = AuthContext.SSLConfig.X509Certificate2;
            var result = HttpHelper.GetResponse<QueryDeviceCmdCancelTaskOutDTO2>(requestMessage, cer);
            if (result == null)
            {
                //处理异常信息
                ErrorCallBack(HttpHelper.ApiException);
                return null;
            }
            return result;
        }
        //设备服务调用
    }
}
[/mw_shl_code]

    设备历史信息查询代码如下:
[mw_shl_code=csharp,true]<Grid x:Class="HandyC.HW.Views.DeviceManage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mv="clr-namespace:HandyC.HW.ViewModels;assembly=HandyC.HW.ViewModels"
xmlns:uc="clr-namespace:HandyC.HW.Views"
xmlns:hc="https://handyorg.github.io/handycontrol"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Margin="10"
DataContext="{Binding DeviceManage, Mode=OneWay, Source={StaticResource Locator}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<GroupBox Effect="{StaticResource EffectShadow2}" Grid.Row="0" Header="设备统计"
Padding="10,10,0,10"
Background="{DynamicResource RegionBrush}"
Style="{DynamicResource GroupBoxStyle}">
<UniformGrid Rows="1">
<Border Padding="20,10" CornerRadius="2"
Background="{DynamicResource BackgroundBrush}" Margin="30,0">
<DockPanel>
<TextBlock Text="设备类型" DockPanel.Dock="Top" Margin="0,10" FontSize="14"></TextBlock>
<TextBlock Text="{Binding DeviceSummary.DeviceTypes.Count}" Margin="20,0" FontSize="36" VerticalAlignment="Center" DockPanel.Dock="Left"></TextBlock>
<ItemsControl DockPanel.Dock="Right"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
ItemsSource="{Binding DeviceSummary.DeviceTypes,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<UniformGrid Rows="1" HorizontalAlignment="Center">
<TextBlock Text="{Binding PropertyName, StringFormat=\{0\}:}" FontSize="10"></TextBlock>
<TextBlock Text="{Binding Count}" FontSize="10"></TextBlock>
</UniformGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>
</Border>
<Border Padding="20,10" CornerRadius="2"
Background="{DynamicResource BackgroundBrush}"
Margin="30,0">
<DockPanel>
<TextBlock Text="设备状态" DockPanel.Dock="Top" Margin="0,10" FontSize="14"></TextBlock>
<TextBlock Text="{Binding DeviceSummary.DeviceStatus.Count}" Margin="20,0" FontSize="36" VerticalAlignment="Center" DockPanel.Dock="Left"></TextBlock>
<ItemsControl DockPanel.Dock="Right"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
ItemsSource="{Binding DeviceSummary.DeviceStatus,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<UniformGrid Rows="1" HorizontalAlignment="Center">
<TextBlock Text="{Binding PropertyName, StringFormat=\{0\}:}" FontSize="10"></TextBlock>
<TextBlock Text="{Binding Count}" FontSize="10"></TextBlock>
</UniformGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>
</Border>
<Border Padding="20,10" CornerRadius="2"
Background="{DynamicResource BackgroundBrush}"
Margin="30,0">
<DockPanel>
<TextBlock Text="协议类型" DockPanel.Dock="Top" Margin="0,10" FontSize="14"></TextBlock>
<TextBlock Text="{Binding DeviceSummary.DeviceProtocolType.Count}" Margin="20,0" FontSize="36" VerticalAlignment="Center" DockPanel.Dock="Left"></TextBlock>
<ItemsControl DockPanel.Dock="Right"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Center"
ItemsSource="{Binding DeviceSummary.DeviceProtocolType,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<UniformGrid Rows="1" HorizontalAlignment="Center">
<TextBlock Text="{Binding PropertyName, StringFormat=\{0\}:}" FontSize="10"></TextBlock>
<TextBlock Text="{Binding Count}" FontSize="10"></TextBlock>
</UniformGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>
</Border>
</UniformGrid>
</GroupBox>
<GroupBox Effect="{StaticResource EffectShadow2}" Grid.Row="1"  Header="设备列表"
Background="{DynamicResource RegionBrush}"
Style="{DynamicResource GroupBoxStyle}">
<ItemsControl ItemsSource="{Binding DeviceInfos}" Margin="10">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type mv:DeviceInfoViewModel}">
<uc:DeviceInfo DataContext="{Binding}"></uc:DeviceInfo>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</GroupBox>
</Grid>[/mw_shl_code]
[mw_shl_code=csharp,true]using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using HandyC.HW.Data;
using HandyC.HW.Datas;
using HandyC.HW.Service;
using HandyC.HW.Tools;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using CommonServiceLocator;

namespace HandyC.HW.ViewModels
{
    /// <summary>
    /// 设备管理视图实体
    /// </summary>
    public class DeviceManageViewModel : ViewModelBase
    {
        private readonly IDeviceInfoService _deviceInfoService;
        public DeviceManageViewModel(IDeviceInfoService deviceInfo)
        {
            _deviceInfoService = deviceInfo;
            //获取初始化构造数据
            InitialData();
        }

        /// <summary>
        /// 初始化设定页面数据
        /// </summary>
        private void InitialData()
        {
            var filter = new QueryBatchDevicesInfoInDTO
            {
                PageNo = 0,
                PageSize = 20
            };
            //开启加载
            Messenger.Default.Send(true, MessageToken.LoadingToken);
            Task.Factory.StartNew(() =>
            {
                //实例化
                var datas = _deviceInfoService.QueryBatchDevicesInfo(filter, ErrorCellbackMethod);
                if (datas != null)
                {
                    //数据转化
                    DeviceInfos = AutoMapper.Mapper.Map<List<QuerySingleDeviceInfoOutDTO>, List<DeviceInfoViewModel>>(datas.Devices);
                    DeviceSummary.GetSummaryData(DeviceInfos);
                }
                //关闭加载
                Messenger.Default.Send(false, MessageToken.LoadingToken);
            });

            ContextMenus = new List<ContextMenuViewModel>
            {
                new ContextMenuViewModel(new RelayCommand<DeviceInfoViewModel>(QueryDeviceInfo))
                {
                    Header="查看",
                    IsEnable = true
                },
                //new ContextMenuViewModel(new RelayCommand<DeviceInfoViewModel>(QueryDeviceInfo))
                //{
                //    Header="编辑",
                //    IsEnable = true
                //},
                new ContextMenuViewModel(new RelayCommand<DeviceInfoViewModel>(QueryLastest))
                {
                    Header="动态",
                    IsEnable = true
                }
            };
        }

        /// <summary>
        /// 查询设备对应的最新数据
        /// </summary>
        /// <param name="obj"></param>
        private void QueryLastest(DeviceInfoViewModel obj)
        {
            if (obj != null)
            {
                DeviceDynamicViewModel dyVm = (DeviceDynamicViewModel)ServiceLocator.Current.GetInstance(typeof(DeviceDynamicViewModel));
                if (dyVm != null)
                {
                    dyVm.InitialDeviceId(obj);
                }
                Messenger.Default.Send(obj, MessageToken.QueryLastestDeviceData);
            }
        }

        /// <summary>
        /// 网络请求服务异常结果处理
        /// </summary>
        /// <param name="obj"></param>
        private void ErrorCellbackMethod(object obj)
        {
            string result = $"{this.GetType().Name} InitialData:{obj.ToString()}";
            OperationResult operation = new OperationResult(result);
            Messenger.Default.Send(operation, MessageToken.MsgToken);
        }

        private List<DeviceInfoViewModel> deviceInfos;
        /// <summary>
        /// 设备列表
        /// </summary>
        public List<DeviceInfoViewModel> DeviceInfos
        {
            get
            {
                if (deviceInfos == null)
                {
                    deviceInfos = new List<DeviceInfoViewModel>();
                }
                return deviceInfos;
            }
            set
            {
                deviceInfos = value;
                RaisePropertyChanged();
            }
        }

        private DeviceSummaryViewModel deviceSummary;
        /// <summary>
        /// 设备信息汇总
        /// </summary>
        public DeviceSummaryViewModel DeviceSummary
        {
            get
            {
                if (deviceSummary == null)
                {
                    deviceSummary = new DeviceSummaryViewModel();
                }
                return deviceSummary;
            }
            set
            {
                deviceSummary = value;
                RaisePropertyChanged();
            }
        }

        private List<ContextMenuViewModel> contextMenus;
        /// <summary>
        /// 设备信息菜单实体
        /// </summary>
        public List<ContextMenuViewModel> ContextMenus
        {
            get
            {
                if (contextMenus == null)
                {
                    contextMenus = new List<ContextMenuViewModel>();
                }
                return contextMenus;
            }
            set
            {
                contextMenus = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// 查询设备详信息
        /// </summary>
        /// <param name="entity">设备实体</param>
        private void QueryDeviceInfo(DeviceInfoViewModel entity)
        {
            if (entity != null)
            {
                Messenger.Default.Send(entity, MessageToken.NewDeviceDialog);
            }
        }

    }
}[/mw_shl_code]
[mw_shl_code=csharp,true]<GroupBox x:Class="HandyC.HW.Views.DataHistory"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:hc="https://handyorg.github.io/handycontrol"
             mc:Ignorable="d"
             Header="设备历史数据"
             Style="{DynamicResource GroupBoxStyle}"
             d:DesignHeight="450" d:DesignWidth="800"
             DataContext="{Binding DataHistory, Mode=OneWay, Source={StaticResource Locator}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0">
            <DockPanel Margin="0,10">
                <hc:ComboBox hc:BorderElement.CornerRadius="2"
                             Padding="3"
                             hc:InfoElement.ContentHeight="34"
                             hc:TitleElement.Title="设备名称:"
                             hc:TitleElement.TitleAlignment="Left"
                             hc:TitleElement.TitleWidth="Auto"
                             IsEditable="False"
                              hc:InfoElement.Placeholder="请选择设备名称"
                              DockPanel.Dock="Left" Width="Auto"
                             ItemsSource="{Binding Devices}"
                             DisplayMemberPath="Name"
                             SelectedValuePath="DeviceId"
                             SelectedItem="{Binding SelectedDevice}" Style="{DynamicResource ComboBoxExtend}"></hc:ComboBox>
                <hc:ComboBox  hc:BorderElement.CornerRadius="2"
                             hc:InfoElement.ContentHeight="34"
                             hc:TitleElement.TitleAlignment="Left"
                             hc:TitleElement.TitleWidth="Auto"
                             IsEditable="False"
                             hc:TitleElement.Title="服务类型:"
                             hc:InfoElement.Placeholder="请选择服务类型"
                             DockPanel.Dock="Left" Width="Auto"
                             ItemsSource="{Binding DeviceServices}"
                             DisplayMemberPath="ServiceType"
                             SelectedValuePath="ServiceId"
                             SelectedItem="{Binding SelectedService}"></hc:ComboBox>
                <hc:SearchBar hc:BorderElement.CornerRadius="2"
                             Margin="10,0,0,0" Command="{Binding SearchCmd}" Cursor="Hand"></hc:SearchBar>
            </DockPanel>
        </StackPanel>
        <DataGrid Effect="{StaticResource EffectShadow2}" Grid.Row="1" hc:BorderElement.CornerRadius="2" Background="{DynamicResource RegionBrush}" AutoGenerateColumns="False" ItemsSource="{Binding DeviceDataSource}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="设备标识" Binding="{Binding DeviceId}" IsReadOnly="True"/>
                <DataGridTextColumn Header="服务标识" Binding="{Binding ServiceId}" IsReadOnly="True"/>
                <DataGridTextColumn Header="光照(Lux)" Binding="{Binding SensorData.Illumination}" IsReadOnly="True"/>
                <DataGridTextColumn Header="电压(V)" Binding="{Binding SensorData.Voltage}" IsReadOnly="True"/>
                <DataGridTextColumn Header="采集时间" Binding="{Binding Timestamp}" IsReadOnly="True"/>
                <DataGridTemplateColumn Header="操作">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Button Content="数据明细" Cursor="Hand" Command="{Binding SearchDataDetailsCmd}" CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
        <Border Effect="{StaticResource EffectShadow2}" hc:BorderElement.CornerRadius="2" Margin="0,5,0,0" BorderThickness="0"  Grid.Row="2" Background="{DynamicResource RegionBrush}">
            <hc:Pagination
                       MaxPageInterval="2"
                       MaxPageCount="{Binding MaxPageCount,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                       PageIndex="{Binding PageNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                       DataCountPerPage="{Binding PageSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                <hc:Interaction.Triggers>
                    <hc:EventTrigger EventName="PageUpdated">
                        <hc:EventToCommand Command="{Binding PageChangedCmd}" PassEventArgsToCommand="True" />
                    </hc:EventTrigger>
                </hc:Interaction.Triggers>
            </hc:Pagination>
        </Border>
    </Grid>
</GroupBox>[/mw_shl_code]
[mw_shl_code=csharp,true]using GalaSoft.MvvmLight.Messaging;
using HandyC.HW.Datas;
using HandyC.HW.ViewModels;
using HandyControl.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace HandyC.HW.Views
{
    /// <summary>
    /// DataHistory.xaml 的交互逻辑
    /// </summary>
    public partial class DataHistory
    {
        public DataHistory()
        {
            InitializeComponent();
            InitialMsg();
        }

        private void InitialMsg()
        {
            //避免token值重名使用
            this.Loaded += (e, arg) => {
                Messenger.Default.Register<DeviceDataViewModel>(this, MessageToken.NewDeviceDataDetails, NewDeviceDataDialog);
            };
            this.Unloaded += (e, arg) => Messenger.Default.Unregister<DeviceDataViewModel>(this, MessageToken.NewDeviceDataDetails);
        }
        /// <summary>
        /// 显示数据信息明细
        /// </summary>
        /// <param name="obj"></param>
        private void NewDeviceDataDialog(DeviceDataViewModel obj)
        {
            if (obj != null)
            {
                Dialog.Show(new DeviceDataInfo(obj), MessageToken.MainToken);
            }
        }
    }
}[/mw_shl_code]
[mw_shl_code=csharp,true]using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using HandyC.HW.Data;
using HandyC.HW.Datas;
using HandyC.HW.Service;
using HandyC.HW.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace HandyC.HW.ViewModels
{
    /// <summary>
    /// 历史数据实体实体
    /// </summary>
    public class DataHistoryViewModel : ViewModelBase
    {
        private readonly IDataCollectionService _collectionService;
        public DataHistoryViewModel(IDataCollectionService collectionService)
        {
            _collectionService = collectionService;
            InitialData();
        }
        /// <summary>
        /// 初始化数据
        /// </summary>
        private void InitialData()
        {
            Task.Factory.StartNew(() =>
            {
                //获取设备信息
                Devices = GetDevices();
                //默认获取第一个设备的历史数据
                if (Devices.Count > 0)
                {
                    SelectedDevice = Devices.FirstOrDefault();
                    //获取设备服务列表
                    DeviceServices = GetDeviceServices(SelectedDevice);
                    pageSize = 10;//默认设定为10  
                    PageNo = 1;//设定默认起始页码
                }
            });
            //设定当前默认数据列表配置值
        }
        /// <summary>
        /// 获取设备服务列表
        /// </summary>
        /// <param name="selectedDevice">当前设备</param>
        /// <returns></returns>
        private List<ServiceCapabilityDTO> GetDeviceServices(DeviceInfoViewModel selectedDevice)
        {
            List<ServiceCapabilityDTO> services = new List<ServiceCapabilityDTO>();
            List<DeviceCapabilityViewModel> deviceCapabilitys;
            var filter = new QueryDeviceCapabilitiesInDTO
            {
                DeviceId = selectedDevice.DeviceId,
                GatewayId = selectedDevice.GatewayId
            };
            var datas = _collectionService.QueryDeviceCapability(filter, ErrorCellbackMethod);
            if (datas != null)
            {
                deviceCapabilitys = AutoMapper.Mapper.Map<List<DeviceCapabilityDTO>, List<DeviceCapabilityViewModel>>(datas.DeviceCapabilities);
            }
            else
            {
                deviceCapabilitys = new List<DeviceCapabilityViewModel>();
            }
            if (deviceCapabilitys == null || deviceCapabilitys.Count < 0)
            {
                return services;
            }

            DeviceCapabilityViewModel deviceCapability = deviceCapabilitys.FirstOrDefault(x => x.DeviceId == selectedDevice.DeviceId);
            if (deviceCapability != null)
            {
                services = deviceCapability.ServiceCapabilities;
            }

            return services;
        }

        /// <summary>
        /// 获取当前设备列表信息
        /// </summary>
        /// <returns></returns>
        private List<DeviceInfoViewModel> GetDevices()
        {
            List<DeviceInfoViewModel> result;
            //获取当前默认设备对应的数据信息
            var filter = new QueryBatchDevicesInfoInDTO
            {
                PageNo = 0,
                PageSize = 1000//默认获取0-1000范围内的设备记录信息
            };
            //实例化
            var datas = _collectionService.QueryBatchDevicesInfo(filter, ErrorCellbackMethod);
            if (datas != null)
            {
                //数据转化
                result = AutoMapper.Mapper.Map<List<QuerySingleDeviceInfoOutDTO>, List<DeviceInfoViewModel>>(datas.Devices);
            }
            else
            {
                result = new List<DeviceInfoViewModel>();
            }
            return result;
        }

        /// <summary>
        /// 网络请求服务异常结果处理
        /// </summary>
        /// <param name="obj"></param>
        private void ErrorCellbackMethod(object obj)
        {
            string result = $"{this.GetType().Name} InitialData:{obj.ToString()}";
            OperationResult operation = new OperationResult(result);
            Messenger.Default.Send(operation, MessageToken.MsgToken);
        }
        #region 页面数据
        private List<DeviceInfoViewModel> devices;
        /// <summary>
        /// 设备集合
        /// </summary>
        public List<DeviceInfoViewModel> Devices
        {
            get
            {
                if (devices == null)
                {
                    devices = new List<DeviceInfoViewModel>();
                }
                return devices;
            }
            set
            {
                devices = value;
                RaisePropertyChanged();
            }
        }

        #endregion
        //Cmds
        private ICommand pageChangedCmd;
        /// <summary>
        /// 当前页变更命令
        /// </summary>
        public ICommand PageChangedCmd
        {
            get
            {
                if (pageChangedCmd == null)
                {
                    pageChangedCmd = new RelayCommand<object>(PageChanged);
                }
                return pageChangedCmd;
            }
            set => pageChangedCmd = value;
        }

        private ICommand searchCmd;
        public ICommand SearchCmd
        {
            get
            {
                if (searchCmd == null)
                {
                    searchCmd = new RelayCommand(SearchData);
                }
                return searchCmd;
            }
        }

        /// <summary>
        /// 查询设备函数
        /// </summary>
        private void SearchData()
        {
            if (PageNo != 1)
            {
                PageNo = 1;
            }
            else
            {
                //获取当前默认设备对应的数据信息
                var filter = new QueryDeviceDataHistoryInDTO
                {
                    PageNo = 0,
                    PageSize = PageSize,
                    DeviceId = SelectedDevice.DeviceId,
                    GatewayId = SelectedDevice.GatewayId,
                    ServiceId = SelectedService.ServiceId
                };
                Refresh(filter);
            }
        }

        #region 分页控件相关属性和函数
        /// <summary>
        /// 当前页变更触发事件
        /// </summary>
        /// <param name="obj"></param>
        private void PageChanged(object obj)
        {
            //获取当前默认设备对应的数据信息
            var filter = new QueryDeviceDataHistoryInDTO
            {
                PageNo = PageNo - 1,
                PageSize = PageSize,
                DeviceId = SelectedDevice.DeviceId,
                GatewayId = SelectedDevice.GatewayId,
                ServiceId = SelectedService.ServiceId
            };
            Refresh(filter);
        }
        /// <summary>
        /// 刷新当前数据列表
        /// </summary>
        public void Refresh(QueryDeviceDataHistoryInDTO filter)
        {
            Task.Factory.StartNew(() =>
            {
                //实例化
                var datas = _collectionService.QueryDeviceDataHistory(filter, ErrorCellbackMethod);
                if (datas != null)
                {
                    TotalCount = datas.TotalCount;
                    MaxPageCount = GetMaxPageCount();
                    DeviceDataSource = AutoMapper.Mapper.Map<IEnumerable<DeviceDataHistoryDTO>, List<DeviceDataViewModel>>(datas.DeviceDataHistoryDTOs).ToList();
                }
            });
        }
        /// <summary>
        /// 获取当前最大记录条数
        /// </summary>
        private long GetMaxPageCount()
        {
            long pageCount;
            pageCount = TotalCount / PageSize;
            int result = Convert.ToInt32(TotalCount % PageSize);
            if (result != 0)
            {
                pageCount += 1;
            }

            return pageCount;
        }

        /// <summary>
        /// 查询的记录数量
        /// </summary>
        private long totalCount;
        private long pageNo;
        private long pageSize;
        /// <summary>
        /// 最大显示记录数量
        /// </summary>
        public long MaxPageCount
        {
            get => maxPageCount;
            set
            {
                maxPageCount = value;
                RaisePropertyChanged();
            }
        }
        /// <summary>
        /// 查询的记录数量
        /// </summary>
        public long TotalCount
        {
            get { return totalCount; }
            set
            {
                totalCount = value;
                RaisePropertyChanged();
            }
        }

        /// <summary>
        /// 查询的页码
        /// </summary>
        public long PageNo
        {
            get => pageNo;
            set
            {
                pageNo = value;
                RaisePropertyChanged();
            }
        }
        /// <summary>
        /// 查询每页信息的数量
        /// </summary>
        public long PageSize
        {
            get => pageSize;
            set
            {
                pageSize = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region 设备列表
        private List<DeviceDataViewModel> deviceDataSource;
        private DeviceInfoViewModel selectedDevice;
        private long maxPageCount;

        /// <summary>
        /// 设备数据信息集合
        /// </summary>
        public List<DeviceDataViewModel> DeviceDataSource
        {
            get
            {
                if (deviceDataSource == null)
                {
                    deviceDataSource = new List<DeviceDataViewModel>();
                }
                return deviceDataSource;
            }
            set
            {
                deviceDataSource = value;
                RaisePropertyChanged();
            }
        }
        //选中项设备记录
        public DeviceInfoViewModel SelectedDevice
        {
            get => selectedDevice;
            set
            {
                selectedDevice = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region 设备服务列表
        private List<ServiceCapabilityDTO> deviceServices;
        /// <summary>
        /// 设备服务能力列表
        /// </summary>
        public List<ServiceCapabilityDTO> DeviceServices
        {
            get
            {
                if (deviceServices == null)
                {
                    deviceServices = new List<ServiceCapabilityDTO>();
                }
                return deviceServices;
            }
            set
            {
                deviceServices = value;
                RaisePropertyChanged();
            }
        }

        private ServiceCapabilityDTO selectedService;

        /// <summary>
        /// 选中设备服务
        /// </summary>
        public ServiceCapabilityDTO SelectedService
        {
            get
            {
                if (selectedService == null)
                {
                    selectedService = new ServiceCapabilityDTO();
                }
                return selectedService;
            }
            set
            {
                selectedService = value;
                RaisePropertyChanged();
            }
        }
        #endregion

    }
}[/mw_shl_code]
    【脑洞大赛】基于NB-IoT的智慧路灯监控系统(手机应用开发):https://mc.dfrobot.com.cn/thread-297186-1-1.html#pid423131
【脑洞大赛】基于NB-IoT的智慧路灯监控系统(PC应用开发)图19


安卓机器人  中级技神

发表于 2019-8-8 08:34:55

脑洞超量啊,看不完,不如直接来个视频吧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail