diff --git a/projects/IoTCenter/Api/DeviceController.cs b/projects/IoTCenter/Api/DeviceController.cs index 8ff76d98..83597a22 100644 --- a/projects/IoTCenter/Api/DeviceController.cs +++ b/projects/IoTCenter/Api/DeviceController.cs @@ -1,12 +1,18 @@ using Application.Domain.Entities; using Infrastructure.Data; using Infrastructure.Extensions; +using IoTCenter.ViewModels; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Drawing; +using System.Globalization; using System.Linq; +using Vibrant.InfluxDB.Client; +using Vibrant.InfluxDB.Client.Rows; namespace UserCenter.Controllers { @@ -45,5 +51,75 @@ namespace UserCenter.Controllers return Problem(ex.Message); } } + + [HttpPost] + public IActionResult GetChartData([FromBody]ChartDataRequest model) + { + try + { + var device = this._deviceRepo.ReadOnlyTable().Include(o => o.Data).FirstOrDefault(o => o.Number == model.Number); + var data = device.Data.FirstOrDefault(o => o.Key == model.Key); + var url = this._cfg["influxdb:url"]; + var usr = this._cfg["influxdb:usr"]; + var pwd = this._cfg["influxdb:pwd"]; + var dbName = "iot"; + var measurementName = "data"; + var datasets = new List(); + var labels = new List(); + var hours = Convert.ToInt32(DateTime.Now.ToString("%z")); + using (var client = new InfluxClient(new Uri(url), usr, pwd)) + { + var query = $"select { model.Key} from {measurementName} where time>now() - {model.Key} and DeviceNumber = '{model.Number}' limit 10000"; + var result = client.ReadAsync(dbName, query).Result; + var rows = result.Results.FirstOrDefault()? + .Series.FirstOrDefault()? + .Rows; + datasets.Add(new + { + label = data.Name, + data = rows != null ? rows.Select(o => o.GetField(data.Key)).ToList() : new List(), + backgroundColor = this.GetColor(data.Key), + fill = false + }); + if (rows != null) + { + var format = model.Time.StartsWith("1") ? "H:mm" : (model.Time.StartsWith("7") ? "ddd" : "MMM-d"); + labels = rows.Select(o => o.Timestamp.Value).Select(o => o.AddHours(hours).ToString(format, new CultureInfo("zh-CN"))).ToList(); + } + var response = new + { + datasets, + labels + }; + return Ok(response); + } + } + catch (Exception ex) + { + ex.PrintStack(); + return Problem(ex.Message); + } + } + private string GetColor(string key) + { + //var randomGen = new Random(); + //var names = (KnownColor[])Enum.GetValues(typeof(KnownColor)); + //var randomColorName = names[randomGen.Next(names.Length)]; + //var randomColor = Color.FromKnownColor(randomColorName); + //return randomColor.Name; + if (key == "Humidity") + { + return Color.FromKnownColor(KnownColor.Green).Name; + } + else if (key == "Electricity") + { + return Color.FromKnownColor(KnownColor.Red).Name; + } + else if (key == "Light") + { + return Color.FromKnownColor(KnownColor.Orange).Name; + } + return Color.FromKnownColor(KnownColor.DarkBlue).Name; + } } } \ No newline at end of file diff --git a/projects/IoTCenter/ViewModels/ChartDataRequest.cs b/projects/IoTCenter/ViewModels/ChartDataRequest.cs new file mode 100644 index 00000000..ca9c0c7f --- /dev/null +++ b/projects/IoTCenter/ViewModels/ChartDataRequest.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace IoTCenter.ViewModels +{ + public class ChartDataRequest + { + [Required] + public string Number { get; set; } + + [Required] + public string Key { get; set; } + + [Required] + public string Time { get; set; } + } +} \ No newline at end of file diff --git a/projects/WebApp/wwwroot/css/app.css b/projects/WebApp/wwwroot/css/app.css index 72eee0c4..133c1390 100644 --- a/projects/WebApp/wwwroot/css/app.css +++ b/projects/WebApp/wwwroot/css/app.css @@ -61,8 +61,12 @@ label > * { padding-left:0; padding-right:0; } -.card-body{ - padding:10px; +.card-header{ + line-height:27px; +} +.card-header,.card-body { + box-sizing:border-box; + padding: 10px; } [class^="weui"] { box-sizing: initial; diff --git a/projects/WebApp/wwwroot/pages/iot/device.html b/projects/WebApp/wwwroot/pages/iot/device.html index fd7c1d0e..d2fc5ff3 100644 --- a/projects/WebApp/wwwroot/pages/iot/device.html +++ b/projects/WebApp/wwwroot/pages/iot/device.html @@ -16,9 +16,36 @@ - - + + +
+ +
\ No newline at end of file diff --git a/projects/WebApp/wwwroot/pages/iot/device.js b/projects/WebApp/wwwroot/pages/iot/device.js index 5cd54401..0c7278d3 100644 --- a/projects/WebApp/wwwroot/pages/iot/device.js +++ b/projects/WebApp/wwwroot/pages/iot/device.js @@ -9,10 +9,15 @@ }; }, mounted: function () { + var vm = this; axios.post(this.url) .then(function (response) { store.commit('setDevice', response.data); $('title').text(response.data.displayName); + vm.$nextTick(function () { + weui.tab('.weui-tab'); + vm.updateChart(); + }); }) .catch(function (error) { }) @@ -23,11 +28,75 @@ destroyed: function () { store.commit('setDevice', null); }, - methods: { + methods: { + updateChart: function () { + var keys = Enumerable.from(this.device.data).where(function (o) { + return o.type === 10 || o.type === 20; + }).toArray(); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + this.changeTime(key, '1d'); + } + }, + changeTime: function (key, time) { + var url = '/IoTCenter/api/v1/Device/GetChartData'; + var data = { + number:this.device.number, + key: key, + time: time + }; + axios.post(url,data, { crossDomain: true }) + .then(function (response) { + var data = response.data; + UpdateChartInternal(key, data); + console.log('折线图更新成功'); + }) + .catch(function (error) { + console.log(error); + }); + }, + UpdateChartInternal(key, data) { + var canvas = document.getElementById(this.device.number + '-' + key); + var chart; + Chart.helpers.each(Chart.instances, function (instance) { + if (instance.chart.canvas.id === canvas.id) { + chart = instance; + } + }); + if (chart) { + chart.data = data; + chart.update(); + } + else { + var ctx = canvas.getContext('2d'); + var options = { + responsive: true, + legend: { + position: 'bottom' + }, + title: { + display: false, + text: title + }, + animation: { + duration: 0 + } + }; + chart = new Chart(ctx, { + type: 'line', + data: data, + options: options + }); + } + } }, computed: { device: function () { return store.state.device; + }, + hasChart: function () { + var o = this.device; + return o.name === '温湿度传感器' || o.name === 'PM2.5感应器' || o.name === '光强检测器' || o.name === '智能插座'; } } }); diff --git a/projects/WebApp/wwwroot/pages/iot/device/camera.html b/projects/WebApp/wwwroot/pages/iot/device/camera.html index d5146a91..78c897f3 100644 --- a/projects/WebApp/wwwroot/pages/iot/device/camera.html +++ b/projects/WebApp/wwwroot/pages/iot/device/camera.html @@ -4,7 +4,7 @@ {{device.displayName}}
-
+
-
+