device.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. <template>
  2. <!-- 设备种类
  3. 设备状态
  4. 设备告警
  5. 设备分布 -->
  6. <el-row>
  7. <el-col :span="18">
  8. <div style="padding:10px;position: relative;">
  9. <!-- 展示可搜索的地图 -->
  10. <div id="mapchart" style="position: relative;" :style="{height:(height-80 - 20)+'px'}"></div>
  11. </div>
  12. </el-col>
  13. <el-col :span="6">
  14. <div class="chart" :style="{height:((height-80)/3 - 40)+'px'}">
  15. <div class="itemtitle" style="">设备种类</div>
  16. <v-chart ref="categorychart" :style="{height:(((height-80)/3 - 20 - 35)+'px')}" :option="categorychart" />
  17. </div>
  18. <div class="chart" :style="{height:((height-80)/3 - 40)+'px'}">
  19. <div class="itemtitle" style="">设备状态</div>
  20. <v-chart ref="statuschart" :style="{height:(((height-80)/3 - 20 - 35)+'px')}" :option="statuschart" />
  21. </div>
  22. <div class="chart" :style="{height:((height-80)/3+15)+'px'}">
  23. <div class="itemtitle" style="">设备告警</div>
  24. <div :style="{height:(((height-80)/3)+'px')}">
  25. <div v-for="(item,index) in alerts" class="alertitem" >
  26. <div class="innner flex">
  27. <div><el-icon size="22" style="position: relative;top:2px;color:#FF5722"><warning /></el-icon></div>
  28. <div class="flex_item title">{{item.title}}</div>
  29. <div style="width:200px;font-size:12px;text-align: right;padding-right: 15px;">时间:{{item.date}}</div>
  30. </div>
  31. </div>
  32. </div>
  33. </div>
  34. </el-col>
  35. </el-row>
  36. </template>
  37. <script>
  38. import $ from 'jquery'
  39. import config from '/public/config.js'
  40. import utils from '/public/utils.js'
  41. import api from '/public/api.js'
  42. import VChart, {
  43. THEME_KEY
  44. } from "vue-echarts";
  45. import * as echarts from 'echarts';
  46. import 'echarts-extension-amap';
  47. import 'echarts-wordcloud';
  48. export default{
  49. components: {
  50. VChart
  51. },
  52. provide: {
  53. [THEME_KEY]: "dark"
  54. },
  55. data(){
  56. return{
  57. height: $(window).height(),
  58. categorychart: {},
  59. statuschart: {},
  60. charts: {},
  61. timer: null,
  62. alerts:[{
  63. id:1,
  64. title:'设备0011离线了',
  65. date:'2022-04-10 23:12:11'
  66. },{
  67. id:1,
  68. title:'设备002电量低',
  69. date:'2022-04-10 23:12:11'
  70. },{
  71. id:1,
  72. title:'设备003型号差',
  73. date:'2022-04-10 23:12:11'
  74. },{
  75. id:1,
  76. title:'设备005被拆卸',
  77. date:'2022-04-10 23:12:11'
  78. },{
  79. id:1,
  80. title:'设备006离线了',
  81. date:'2022-04-10 23:12:11'
  82. },{
  83. id:1,
  84. title:'设备0011离线了',
  85. date:'2022-04-10 23:12:11'
  86. },{
  87. id:1,
  88. title:'设备0011离线了',
  89. date:'2022-04-10 23:12:11'
  90. },{
  91. id:1,
  92. title:'设备0011离线了',
  93. date:'2022-04-10 23:12:11'
  94. },{
  95. id:1,
  96. title:'设备0011离线了',
  97. date:'2022-04-10 23:12:11'
  98. }]
  99. }
  100. },
  101. mounted:function(){
  102. var that = this;
  103. $(window).resize(function() {
  104. this.height = $(window).height() - this.titleheight;
  105. for (var key in that.charts) {
  106. that.charts[key].resize();
  107. }
  108. that.$refs['categorychart'].resize();
  109. that.$refs['statuschart'].resize();
  110. });
  111. this.loadData();
  112. //开始定时刷新报表数据
  113. this.startRefreshChart();
  114. },
  115. unmounted:function(){
  116. if (this.timer) {
  117. clearInterval(this.timer);
  118. }
  119. },
  120. methods: {
  121. /**
  122. * 定时刷新报表数据
  123. */
  124. startRefreshChart: function() {
  125. if (this.timer) {
  126. clearInterval(this.timer);
  127. }
  128. var that = this;
  129. //获取刷新周期,TODO 配置变动时,此处需自动更新
  130. var refreshtime = 60 * 1000;
  131. config.getConfig().forEach(function(item, index) {
  132. if (item.key == 'refreshtime') {
  133. refreshtime = item.value;
  134. }
  135. });
  136. this.timer = setInterval(function() {
  137. let echartData = [{
  138. name: "监控摄像头",
  139. value: (Math.random(100) * 100).toFixed(0)
  140. },
  141. {
  142. name: "雨水采集器",
  143. value: (Math.random(100) * 100).toFixed(0)
  144. },
  145. {
  146. name: "土壤湿度检测仪",
  147. value: (Math.random(100) * 100).toFixed(0)
  148. },
  149. {
  150. name: "温度检测器",
  151. value: (Math.random(100) * 100).toFixed(0)
  152. },
  153. {
  154. name: "土壤元素检测",
  155. value: (Math.random(100) * 100).toFixed(0)
  156. },
  157. {
  158. name: "空气湿度检测仪",
  159. value: (Math.random(100) * 100).toFixed(0)
  160. }];
  161. let total = echartData.reduce((a, b) => {
  162. return a + b.value * 1
  163. }, 0);
  164. that.categorychart.title[0].text = '{name|总量}\n{val|' + total + '}';
  165. that.categorychart.series[0].data = echartData;
  166. that.statuschart.series[0].data[0].value = [(Math.random(100) * 100).toFixed(0), (Math.random(100) * 100).toFixed(0), (Math.random(100) * 100).toFixed(0), (Math.random(100) * 100).toFixed(0), (Math.random(100) * 100).toFixed(0), (Math.random(100) * 100).toFixed(0)];
  167. }, refreshtime);
  168. },
  169. loadData: function() {
  170. var that = this;
  171. api.loadMapData(function(res) {
  172. if (!res || res.status != 200) {
  173. utils.showerror("数据加载失败!");
  174. return;
  175. }
  176. that.initMapChart(res);
  177. });
  178. this.categorychart = this.initcategorychart();
  179. this.statuschart = this.initstatuschart();
  180. },
  181. initcategorychart: function(res) {
  182. let bgColor = '#001037';
  183. let title = '总量';
  184. let color = ['#fac858', '#ee6666', '#91cc75', '#38cafb', '#4caff9', '#4adeca', '#2aa7ee', '#0270f2', '#488cf7','#38cafb', '#4caff9', '#4adeca', '#2aa7ee', '#0270f2', '#488cf7'];
  185. let echartData = [{
  186. name: "监控摄像头",
  187. value: (Math.random(100) * 100).toFixed(0)
  188. },
  189. {
  190. name: "雨水采集器",
  191. value: (Math.random(100) * 100).toFixed(0)
  192. },
  193. {
  194. name: "土壤湿度检测仪",
  195. value: (Math.random(100) * 100).toFixed(0)
  196. },
  197. {
  198. name: "温度检测器",
  199. value: (Math.random(100) * 100).toFixed(0)
  200. },
  201. {
  202. name: "土壤元素检测",
  203. value: (Math.random(100) * 100).toFixed(0)
  204. },
  205. {
  206. name: "空气湿度检测仪",
  207. value: (Math.random(100) * 100).toFixed(0)
  208. }];
  209. let total = echartData.reduce((a, b) => {
  210. return a + b.value * 1
  211. }, 0);
  212. return {
  213. backgroundColor: '#000000',//此处背景色需要共主题处获取
  214. color: color,
  215. title: [{
  216. text: '{name|' + title + '}\n{val|' + total + '}',
  217. top: 'center',
  218. left: 'center',
  219. textStyle: {
  220. rich: {
  221. name: {
  222. fontSize: 12,
  223. fontWeight: 'normal',
  224. color: '#fefefe',
  225. padding: [10, 0]
  226. },
  227. val: {
  228. fontSize: 16,
  229. fontWeight: 'bolder',
  230. color: '#fefefe',
  231. }
  232. }
  233. }
  234. }],
  235. series: [{
  236. type: 'pie',
  237. roseType: 'radius',
  238. radius: ['25%', '60%'],
  239. center: ['50%', '50%'],
  240. data: echartData,
  241. hoverAnimation: false,
  242. itemStyle: {
  243. normal: {
  244. borderColor: bgColor,
  245. borderWidth: 1
  246. }
  247. },
  248. labelLine: {
  249. normal: {
  250. length: 10,
  251. length2: 20
  252. }
  253. },
  254. label: {
  255. normal: {
  256. formatter: params => {
  257. return (
  258. '{icon|●}{name|' + params.name + '}\n{value|' +
  259. params.value + '}'
  260. );
  261. },
  262. rich: {
  263. icon: {
  264. fontSize: 12,
  265. color: 'inherit'
  266. },
  267. name: {
  268. fontSize: 12,
  269. padding: [0, 0, 0, 10],
  270. color: '#fefefe'
  271. },
  272. value: {
  273. fontSize: 12,
  274. fontWeight: 'bolder',
  275. padding: [10, 0, 0, 20],
  276. color: 'inherit'
  277. // color: '#333333'
  278. }
  279. }
  280. }
  281. },
  282. }]
  283. };
  284. },
  285. initstatuschart: function(res) {
  286. var indicator = [{
  287. text: '正常设备',
  288. max: 100,
  289. },
  290. {
  291. text: '故障设备',
  292. max: 100
  293. },
  294. {
  295. text: '报警设备',
  296. max: 100
  297. },
  298. {
  299. text: '离线设备',
  300. max: 100,
  301. // axisLabel: {show: true, textStyle: {fontSize: 18, color: '#333'}}
  302. }];
  303. var dataArr = [
  304. {
  305. value: [24, 35, 22, 33, 20, 16],
  306. itemStyle: {
  307. normal: {
  308. lineStyle: {
  309. width:1,
  310. color: '#FF8A26',
  311. },
  312. shadowColor: '#FF8A26',
  313. shadowBlur: 10,
  314. },
  315. },
  316. areaStyle: {
  317. normal: { // 单项区域填充样式
  318. color: {
  319. type: 'radial',
  320. x: 0.5, //右
  321. y: 0.5, //下
  322. r: 1,
  323. colorStops: [{
  324. offset: 1,
  325. color: '#FF8A26'
  326. }, {
  327. offset: 0,
  328. color: 'rgba(0,0,0,0)'
  329. }],
  330. globalCoord: false
  331. },
  332. opacity: 0.8 // 区域透明度
  333. }
  334. }
  335. }
  336. ];
  337. var colorArr = ['#FF8A26']; //颜色
  338. return {
  339. backgroundColor: '#000000',
  340. color: colorArr,
  341. radar: {
  342. shape: 'polygon',
  343. name: {
  344. textStyle: {
  345. color: '#fff',
  346. fontSize: 14
  347. },
  348. },
  349. label:{
  350. distance:5,
  351. },
  352. radius:'60%',
  353. indicator: indicator,
  354. splitNumber:3,
  355. splitArea: { // 坐标轴在 grid 区域中的分隔区域,默认不显示。
  356. show: true,
  357. areaStyle: { // 分隔区域的样式设置。
  358. color: ['rgba(24,60,108,.5)', 'rgba(15,36,80,.5)','rgba(12,25,59,.5)'], // 分隔区域颜色。分隔区域会按数组中颜色的顺序依次循环设置颜色。默认是一个深浅的间隔色。
  359. }
  360. },
  361. axisLine: { //指向外圈文本的分隔线样式
  362. lineStyle: {
  363. color: utils.getChartXColor()
  364. }
  365. },
  366. splitLine: {
  367. lineStyle: {
  368. color: utils.getChartXColor(), // 分隔线颜色
  369. width: 1, // 分隔线线宽
  370. }
  371. },
  372. },
  373. series: [{
  374. type: 'radar',
  375. symbolSize: 5,
  376. data: dataArr
  377. }]
  378. };
  379. },
  380. initMapChart: function(res) {
  381. var mapchart = this.$echarts.init(document.getElementById('mapchart'));
  382. var values1 = [];
  383. var values2 = [];
  384. for (var i = 0; i < res.data.geoCoordMap.length; i++) {
  385. if(i%2 == 0){
  386. values1.push([res.data.geoCoordMap[i][0], res.data.geoCoordMap[i][1]], (Math.random() * 1000)
  387. .toFixed(0));
  388. }else{
  389. values2.push([res.data.geoCoordMap[i][0], res.data.geoCoordMap[i][1]], (Math.random() * 1000)
  390. .toFixed(0));
  391. }
  392. }
  393. var option = {
  394. geoCoordMap: res.data.geoCoordMap,
  395. title: utils.createChartTitle('设备分布概览'),
  396. legend:{
  397. bottom:'0',
  398. x:'center',
  399. data:['正常设备','异常设备'],
  400. textStyle:{
  401. color:'#fff'
  402. }
  403. },
  404. amap: {
  405. rotateEnable: true,
  406. pitchEnable: true,
  407. pitch: 45,
  408. // rotation: -45,
  409. // 3D模式,无论你使用的是1.x版本还是2.x版本,都建议开启此项以获得更好的渲染体验
  410. viewMode: '3D',
  411. // 高德地图支持的初始化地图配置
  412. // 高德地图初始中心经纬度
  413. center: [116.436561, 39.897346],
  414. // 高德地图初始缩放级别
  415. zoom: 9,
  416. // 是否开启resize
  417. resizeEnable: true,
  418. // 自定义地图样式主题
  419. mapStyle: 'amap://styles/darkblue',
  420. // 移动过程中实时渲染 默认为true 如数据量较大 建议置为false
  421. renderOnMoving: true,
  422. // ECharts 图层的 zIndex 默认 2000
  423. // 从 v1.9.0 起 此配置项已被弃用 请使用 `echartsLayerInteractive` 代替
  424. echartsLayerZIndex: 2019,
  425. // 设置 ECharts 图层是否可交互 默认为 true
  426. // 设置为 false 可实现高德地图自身图层交互
  427. // 此配置项从 v1.9.0 起开始支持
  428. echartsLayerInteractive: true,
  429. // 是否启用大数据模式 默认为 false
  430. // 此配置项从 v1.9.0 起开始支持
  431. layers: [new AMap.TileLayer.Satellite()],
  432. largeMode: false
  433. // 说明:如果想要添加卫星、路网等图层
  434. // 暂时先不要使用layers配置,因为存在Bug
  435. // 建议使用amap.add的方式,使用方式参见最下方代码
  436. },
  437. series: [{
  438. name:'正常设备',
  439. type: 'effectScatter',
  440. // 使用百度地图坐标系
  441. coordinateSystem: 'amap',
  442. //设置图形 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
  443. // symbol: 'image://http://localhost:3000/src/assets/video.png',
  444. symbol: 'pin',
  445. // //标记的大小,可以设置成诸如 10 这样单一的数字,也可以用数组分开表示宽和高,例如 [20, 10] 表示标记宽为20,高为10
  446. symbolSize: [20, 20],
  447. itemStyle: {
  448. normal: {
  449. color: '#FF5252', //标志颜色
  450. }
  451. },
  452. // 数据格式跟在 geo 坐标系上一样,每一项都是 [经度,纬度,数值大小,其它维度...]
  453. data: values1,
  454. rippleEffect: {
  455. scale: 6,
  456. brushType: "stroke"
  457. },
  458. hoverAnimation: true, //是否开启鼠标 hover 的提示动画效果。
  459. },{
  460. name:'异常设备',
  461. type: 'effectScatter',
  462. // 使用百度地图坐标系
  463. coordinateSystem: 'amap',
  464. //设置图形 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow'
  465. // symbol: 'image://http://localhost:3000/src/assets/video.png',
  466. symbol: 'pin',
  467. // //标记的大小,可以设置成诸如 10 这样单一的数字,也可以用数组分开表示宽和高,例如 [20, 10] 表示标记宽为20,高为10
  468. symbolSize: [20, 20],
  469. itemStyle: {
  470. normal: {
  471. color: '#00FAC1', //标志颜色
  472. }
  473. },
  474. // 数据格式跟在 geo 坐标系上一样,每一项都是 [经度,纬度,数值大小,其它维度...]
  475. data: values2,
  476. rippleEffect: {
  477. scale: 6,
  478. brushType: "stroke"
  479. },
  480. hoverAnimation: true, //是否开启鼠标 hover 的提示动画效果。
  481. }]
  482. }
  483. // 使用刚指定的配置项和数据显示图表。
  484. mapchart.setOption(option);
  485. // 获取 ECharts 高德地图组件
  486. var amapComponent = mapchart.getModel().getComponent('amap');
  487. // 获取高德地图实例,使用高德地图自带的控件(需要在高德地图js API script标签手动引入)
  488. var amap = amapComponent.getAMap();
  489. // 添加控件
  490. amap.addControl(new AMap.Scale());
  491. amap.addControl(new AMap.ToolBar());
  492. amap.addControl(new AMap.ControlBar({
  493. position: {
  494. left: '10px',
  495. top: '10px'
  496. },
  497. showControlButton: true, // 是否显示倾斜、旋转按钮。默认为 true
  498. }));
  499. // amap.addControl(new AMap.MapType({
  500. // defaultType: 1,
  501. // position: {
  502. // right: '30px',
  503. // top: '10px'
  504. // }
  505. // }));
  506. // 禁用 ECharts 图层交互,从而使高德地图图层可以点击交互
  507. amapComponent.setEChartsLayerInteractive(false);
  508. var disProvince = new AMap.DistrictLayer.Province({
  509. zIndex: 1000,
  510. adcode: [110000],
  511. depth: 2,
  512. styles: {
  513. 'fill': function(properties) {
  514. // properties为可用于做样式映射的字段,包含
  515. // NAME_CHN:中文名称
  516. // adcode_pro
  517. // adcode_cit
  518. // adcode
  519. // console.log(properties)
  520. var adcode = properties.adcode;
  521. // var colors = {};
  522. // if (!colors[adcode]) {
  523. // var gb = Math.random() * 155 + 50;
  524. // colors[adcode] = 'rgb(' + gb + ',' + gb + ',255)';
  525. // }
  526. // return colors[adcode];
  527. var colors = ['#fac858', '#ee6666', '#91cc75', '#38cafb', '#4caff9', '#4adeca',
  528. '#2aa7ee', '#0270f2', '#488cf7'
  529. ];
  530. return colors[adcode % colors.length] + 'aa';
  531. // return 'red';
  532. },
  533. 'province-stroke': 'cornflowerblue',
  534. 'city-stroke': 'white', // 中国地级市边界
  535. 'county-stroke': 'rgba(255,255,255,0.5)' // 中国区县边界
  536. }
  537. });
  538. disProvince.setMap(amap);
  539. this.charts['mapchart'] = mapchart;
  540. // setTimeout(function(){
  541. // amap.setZoom(9,false,30000);
  542. // amap.setPitch(45,false,30000);
  543. // },1000);
  544. }
  545. }
  546. }
  547. </script>
  548. <style scoped="scoped">
  549. .chart {
  550. padding: 10px;
  551. overflow: hidden;
  552. }
  553. .itemtitle {
  554. background: linear-gradient(to right, #40a55f, #000, #000);
  555. height: 35px;
  556. line-height: 35px;
  557. padding-left: 10px;
  558. }
  559. .alertitem{
  560. line-height: 30px;
  561. height: 30px;
  562. font-size: 14px;
  563. color:#fff;
  564. background-color: #FF572233;
  565. padding-left: 15px;
  566. border-radius: 35px;
  567. margin-top: 10px;
  568. }
  569. .alertitem .title{
  570. margin-left: 5px;
  571. text-align: left;
  572. font-size: 14px;
  573. }
  574. </style>