物联网平台 +Web 组态
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

860 lines
40 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="shortcut icon" href="../../image/oss/iot/favicon2.ico" type="image/x-icon">
<link rel="stylesheet" href="../../lib/element-ui/index.css">
<link rel="stylesheet" href="./css/index.css">
<script src="../common/util.js"></script>
<script src="../../lib/bigscreen/lib/jquery/jquery-1.9.1.min.js"></script>
<script src="../../lib/bigscreen/js/vue.min.js"></script>
<script src="../../lib/element-ui/index.js"></script>
<script type="text/javascript" src="../../lib/layer/layer.js"></script>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=3.0&ak=q5uqiBY29eEu0wNIAPoCXwq1HvUmDzqP"></script>
<script>
var map;
var scene_id='';
var showDevId='';
var myGeo = new BMap.Geocoder();
function selfLocation(lon,lat,obj){
// 显示文本
setTextShowMap(lon,lat,obj);
//单独设定图标的样式
var str_name = 'location2.png' ;
if(obj.iot_node_status != 16){
str_name = 'location2_red.png' ;
}
var icon = new BMap.Icon(baseurl+'/image/oss/iot/' + str_name , new BMap.Size(32, 32), {
anchor: new BMap.Size(32, 32)
});
//创建一个图像标注实例。point参数指定了图像标注所在的地理位置
var mkr = new BMap.Marker(new BMap.Point(lon,lat), {
icon: icon
});
mkr.addEventListener("click", function () {
layer.open({
type: 2,
title: '设备详情',
shadeClose: true,
shade: 0.7,
maxmin: true, //开启最大化最小化按钮
area: ['90%', '90%'],
content: baseurl + "/page/devicedetail/index.html?id="
+ obj.id+"&ucode=" + ucode
});
});
mkr.addEventListener("mouseover", function (e) {
});
mkr.addEventListener("mouseout", function (e) {
$(".show_index").hide();
});
//将覆盖物添加到地图中
map.addOverlay(mkr);
//将地图的中心点更改为给定的点
map.panTo(lon,lat);
}
function setTextShowMap(lon,lat ,obj){
var point = new BMap.Point(lon,lat);
var opts = {
position : point, // 指定文本标注所在的地理位置
offset : new BMap.Size(2, -27) //设置文本偏移量
}
var label = new BMap.Label(obj.name , opts);
label.setStyle({
color : "black",
fontSize : "14px",
fontFamily:"微软雅黑"
});
map.addOverlay(label);
}
</script>
<script src="../../lib/bigscreen/lib/echarts/echarts.min.js"></script>
<title>中控管理平台数据统计</title>
</head>
<body>
<div id="app">
<div class="header">
<el-row>
<el-col class="left" :span="9">
</el-col>
<el-col :span="6">
<div style="padding:10px 0;font-size:28px;text-align:center;color:#a2c9fe" v-text='screen_title'></div>
<el-row type="flex" v-show="showProject" justify="center" class="sel-wrap">
<span style="color:#fff;padding-right:10px;padding-top:3px">当前项目:</span>
<el-select size="mini" @change="prochange" v-model="nowproject" clearable placeholder="请选择">
<el-option
v-for="item in project"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-row>
</el-col>
<el-col class="right" :span="9">
</el-col>
</el-row>
</div>
<el-row class="page">
<div :span="7" class="left-bar">
<div class="common-wrap device-wrap">
<div class="left-t"></div>
<div class="left-b"></div>
<div class="right-t"></div>
<div class="right-b"></div>
<div class="common-inner">
<el-row :gutter="10" class="force-one">
<el-col :span="12" class="force-one">
<div class="title-active">设备概括</div>
<div class="over-aut">
<div class="sub-title">
在线总数
</div>
<el-row type="flex" justify="center">
<div class="item-card" v-cloak>
{{online.substring(0,1)}}
</div>
<div class="item-card" v-cloak>
{{online.substring(1,2)}}
</div>
<div class="item-card" v-cloak>
{{online.substring(2,3)}}
</div>
<div class="item-card" v-cloak>
{{online.substring(3,4)}}
</div>
</el-row>
<div class="sub-title">
离线总数
</div>
<el-row type="flex" justify="center">
<div class="item-card" v-cloak>
{{offline.substring(0,1)}}
</div>
<div class="item-card" v-cloak>
{{offline.substring(1,2)}}
</div>
<div class="item-card" v-cloak>
{{offline.substring(2,3)}}
</div>
<div class="item-card" v-cloak>
{{offline.substring(3,4)}}
</div>
</el-row>
</div>
</el-col>
<el-col :span="12" style="position:absolute;left:120px;right:0;top:0;bottom:0">
<div class="status-wrap">
<div class="present">
<div v-cloak style="color:#00abec">在线率</div>
<div v-cloak>{{drate}}</div>
</div>
<div id="devstatus" style="height:100%"></div>
</div>
</el-col>
</el-row>
</div>
</div>
<div class="common-wrap device-list">
<div class="left-t"></div>
<div class="left-b"></div>
<div class="right-t"></div>
<div class="right-b"></div>
<div class="common-inner">
<el-row type="flex" justify="space-between">
<el-col :span="8">
<div class="title-active" style="padding-top:6px;">设备列表</div>
</el-col>
<el-col :span="16">
<el-row class="search-wrap">
<input v-model="device_code" placeholder="设备号检索" type="text" class="search-box">
<div @click="serachDev" class="button-s"></div>
</el-row>
</el-col>
</el-row>
<div class="list-real-wrap">
<div class="list-wrap" v-for="item in devLeft">
<div v-if="item.data.iot_node_status=='在线'" class="label is-online">在线</div>
<div v-if="item.data.iot_node_status!=='在线'" class="label no-online">离线</div>
<div class="content" v-cloak>{{item.name.substring(0,12)}}</div>
<div class="right" @click="opendialog(item)">详情</div>
</div>
</div>
</div>
<div class="page-wrap">
<span v-if="nowpage==1"><i class="el-icon-arrow-left inactive" @click="pagePre"></i></span>
<span v-if="nowpage!==1"><i class="el-icon-arrow-left active" @click="pagePre"></i></span>
<span v-if="nowpage==totalpage"><i class="el-icon-arrow-right inactive" @click="pageAdd"></i></span>
<span v-if="nowpage!==totalpage"><i class="el-icon-arrow-right active" @click="pageAdd"></i></span>
<div v-cloak>当前第{{nowpage}}页/共{{totalpage}}页</div>
</div>
</div>
</div>
<div :span="10" class="main-content">
<div id="map" style="width:100%;height:100%"></div>
<div class="search-box-map">
<el-input v-model="city" size="mini" placeholder="输入地址名 查询">
<el-button @click="enterCity" slot="append" icon="el-icon-search"></el-button>
</el-input>
</div>
</div>
<div :span="7" class="right-bar">
<div class="common-wrap alerm">
<div class="left-t"></div>
<div class="left-b"></div>
<div class="right-t"></div>
<div class="right-b"></div>
<div class="common-inner">
<el-row :gutter="20" class="force-one">
<el-col :span="12" class="force-one">
<div class="title-active">今日报警</div>
<div class="over-aut">
<div class="sub-title">
已处理
</div>
<el-row type="flex" justify="center">
<div class="item-card" v-cloak>
{{hasdo.substring(0,1)}}
</div>
<div class="item-card" v-cloak>
{{hasdo.substring(1,2)}}
</div>
<div class="item-card" v-cloak>
{{hasdo.substring(2,3)}}
</div>
<div class="item-card" v-cloak>
{{hasdo.substring(3,4)}}
</div>
</el-row>
<div class="sub-title">
未处理
</div>
<el-row type="flex" justify="center">
<div class="item-card" v-cloak>
{{nodo.substring(0,1)}}
</div>
<div class="item-card" v-cloak>
{{nodo.substring(1,2)}}
</div>
<div class="item-card" v-cloak>
{{nodo.substring(2,3)}}
</div>
<div class="item-card" v-cloak>
{{nodo.substring(3,4)}}
</div>
</el-row>
</div>
</el-col>
<el-col :span="12" style="position:absolute;left:120px;right:0;top:0;bottom:0">
<div class="status-wrap">
<div class="present">
<div v-cloak style="color:#00abec">处理率</div>
<div v-cloak>{{inforate}}</div>
</div>
<div id="alarmsummary" style="height:100%"></div>
</div>
</el-col>
</el-row>
</div>
</div>
<div class="common-wrap alerm-info">
<div class="left-t"></div>
<div class="left-b"></div>
<div class="right-t"></div>
<div class="right-b"></div>
<div class="common-inner">
<div class="title-active">未读报警</div>
<div class="list-wrap">
<div class="info-wrap" v-for="item in noreadAlerm">
<div v-if="item.iot_trigger_alarm_level==41" class="name name-yellow" v-cloak>{{item.name}}</div>
<div v-if="item.iot_trigger_alarm_level==40" class="name name-orange" v-cloak>{{item.name}}</div>
<div v-if="item.iot_trigger_alarm_level==39" class="name name-red" v-cloak>{{item.name}}</div>
<div><i style="padding-right:5px" class="el-icon-warning" v-cloak></i>{{item.atimestr}}</div>
<div class="content" v-cloak>{{item.description}}</div>
</div>
</div>
</div>
</div>
</div>
</el-row>
<el-dialog
title="设备详情"
:visible.sync="log"
width="75"
>
<iframe style="width:100%;height:500px" :src ="detailUrl" frameborder="0"></iframe>
</iframe>
</el-dialog>
</div>
<script>
new Vue({
el: '#app',
data: function() {
return {
inforate:'',
drate:'',
city:'',
device_code:'',
project:[],
devLeft:[],
nowpage:1,
totalpage:1,
nodo:'0000',
hasdo:'0000',
noreadAlerm:[],
online:'0000',
offline:'0000',
nowproject: '',
log:false,
detailUrl:"",
showProject:false,
screen_title:""
}
},
methods: {
opendialog(item){
layer.open({
type: 2,
title: '设备详情',
shadeClose: true,
shade: 0.7,
maxmin: true, //开启最大化最小化按钮
area: ['90%', '90%'],
content: baseurl + "/page/devicedetail/index.html?id="
+ item.id+"&ucode=" + ucode
});
},
enterCity(){
let that=this
map.centerAndZoom(that.city,11);
},
serachDev(){
this.nowpage=1;
this.totalpage=1;
this.getLeftDev();
},
prochange(){
this.nowpage=1;
this.totalpage=1;
this.getLeftDev();
this.device_code='' ;
this.getAlermData()
this.getProject()
this.statusDevice()
this.getDevStaData()
},
getProject(){
var that=this
$.ajax({
type:'POST',
url:baseurl+'/service/page/scene?paged=1',
contentType: 'application/json',
dataType: "json",
data:JSON.stringify({
}),
headers : {'USER-KEY':ucode},
success: function (e) {
if(e.status==2){
var data=e.data.data
var sdata=[]
for(var i=0;i<data.length;i++){
var obj={
value:data[i].id,
label:data[i].name
}
sdata.push(obj)
}
that.project=sdata
}else{
that.project=[]
}
},
error: function (e) {
}
});
},
//获取系统参数
getSysConfig(){
var that=this
$.ajax({
type:'GET',
url:baseurl+'/service/sys/confog/info/sys_web_screen_name',
contentType: 'application/json',
dataType: "json",
headers : {'USER-KEY':ucode},
success: function (e) {
if(e.status==2){
var data=e.data
that.screen_title=data.value
}
},
error: function (e) {
}
});
},
pagePre(){
if(this.nowpage===1){
return
}
this.nowpage--;
this.getLeftDev()
},
pageAdd(){
if(this.nowpage===this.totalpage){
return
}
this.nowpage++;
this.getLeftDev()
},
//报警统计
statusDevice(){
var that=this
$.ajax({
type:'POST',
url:baseurl+'/service/alarm/info/statistic.json',
contentType: 'application/json',
dataType: "json",
data:JSON.stringify({
scene_id:that.nowproject
}),
headers : {'USER-KEY':ucode},
success: function (e) {
var nodo=0;
var hasdo=0;
var option={
tooltip: {
trigger: 'item',
formatter: ''
},
series: [
{
name: '报警统计',
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
},
normal:{
color:function(params) {
//自定义颜色
var colorList = [
'#01b0f1','red','red','#E87C25','#27727B',
'#FE8463','#9BCA63','#FAD860','#F3A43B','#60C0DD',
'#D7504B','#C6E579','#F4E001','#F0805A','#26C0C0'
];
return colorList[params.dataIndex]
}
}
},
type: 'pie',
radius: ['50%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '0',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{value: hasdo, name: '已处理'},
{value: nodo, name: '未处理'}
]
}
]
}
if(e.status==2){
var datasum=e.data
for(var i=0;i<datasum.length;i++){
if(datasum[i].statistic_type==46){
nodo+=datasum[i].num
}else{
hasdo+=datasum[i].num
}
}
that.inforate=String((hasdo/(hasdo+nodo)).toFixed(4)*100)
var index=that.inforate.indexOf('.')
// that.inforate=that.inforate.substring(0,index+3)+'%'
if(index==-1){
that.inforate=that.inforate+'%'
}else{
that.inforate=that.inforate.substring(0,index+3)+'%'
}
option.series[0].data[0].value=hasdo
option.series[0].data[1].value=nodo
if(hasdo<10){
hasdo='000'+hasdo
}else{
if(hasdo<100){
hasdo='00'+hasdo
}else{
if(hasdo<1000){
hasdo='0'+hasdo
}
}
}
if(nodo<10){
nodo='000'+nodo
}else{
if(nodo<100){
nodo='00'+nodo
}else{
if(nodo<1000){
nodo='0'+nodo
}
}
}
that.hasdo=String(hasdo);
that.nodo=String(nodo)
var myChart = echarts.init(document.getElementById('alarmsummary'))
myChart.setOption(option)
}else{
that.hasdo='0000';
that.nodo='0000';
var myChart = echarts.init(document.getElementById('alarmsummary'))
myChart.setOption(option)
}
},
error: function (e) {
}
});
},
//设备概括
getDevStaData(){
var that=this
$.ajax({
type:'POST',
url:baseurl+'/service/node/statistic.json',
contentType: 'application/json',
dataType: "json",
data:JSON.stringify({
scene_id:that.nowproject
}),
headers : {'USER-KEY':ucode},
success: function (e) {
var online=0;
var offline=0;
var option={
tooltip: {
trigger: 'item',
formatter: ''
},
series: [
{
name: '设备概括',
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
},
normal:{
color:function(params) {
//自定义颜色
var colorList = [
'#01b0f1','#153d5e','#FCCE10','#E87C25','#27727B',
'#FE8463','#9BCA63','#FAD860','#F3A43B','#60C0DD',
'#D7504B','#C6E579','#F4E001','#F0805A','#26C0C0'
];
return colorList[params.dataIndex]
}
}
},
type: 'pie',
radius: ['50%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '0',
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{value: online, name: '在线'},
{value: offline, name: '离线'}
]
}
]
}
if(e.status==2){
var online=0;
var offline=0;
var datasum=e.data
for(var i=0;i<datasum.length;i++){
if(datasum[i].statistic_type==16){
online+=datasum[i].num
}else{
offline+=datasum[i].num
}
}
that.drate=String((online/(online+offline)).toFixed(4)*100)
var index=that.drate.indexOf('.')
if(index==-1){
that.drate=that.drate+'%'
}else{
that.drate=that.drate.substring(0,index+3)+'%'
}
option.series[0].data[0].value=online
option.series[0].data[1].value=offline
if(online<10){
online='000'+online
}else{
if(online<100){
online='00'+online
}else{
if(online<1000){
online='0'+online
}
}
}
if(offline<10){
offline='000'+offline
}else{
if(offline<100){
offline='00'+offline
}else{
if(offline<1000){
offline='0'+offline
}
}
}
that.online=String(online);
that.offline=String(offline)
var myChart = echarts.init(document.getElementById('devstatus'))
myChart.setOption(option)
}else{
that.online='0000'
that.offline='0000'
var myChart = echarts.init(document.getElementById('devstatus'))
myChart.setOption(option)
}
},
error: function (e) {
}
});
},
//未处理报警
getAlermData(){
var that=this
$.ajax({
type:'POST',
url:baseurl+'/service/page/alarm?paged=1&pageSize=50',
contentType: 'application/json',
dataType: "json",
data:JSON.stringify({
scene_id:that.nowproject,
iot_alarm_process_status: 46
}),
headers : {'USER-KEY':ucode},
success: function (e) {
if(e.status==2){
var data=e.data.data
that.noreadAlerm=data.filter(item=>{
return item.iot_alarm_process_status==46
})
}else{
that.noreadAlerm=[]
}
},
error: function (e) {
}
});
},
//获取地图数据
getMapData(){
var that=this
$.ajax({
type:'POST',
url:baseurl+'/service/page/node.json?paged=1&pageSize=1000',
contentType: 'application/json',
dataType: "json",
data:JSON.stringify({
scene_id:that.nowproject
}),
headers : {'USER-KEY':ucode},
success: function (e) {
if(e.status==2){
var dataT = e.data.data ;
dataCache = dataT ;
for(var i=0;i<dataT.length;i++){
if(!dataT[i].lonLat){
dataT[i].lonLat=''
}
var lonLat=dataT[i].lonLat.split(',')
selfLocation(lonLat[0],lonLat[1],dataT[i]);
if(i==0){
map.panTo(lonLat[0],lonLat[1]);
}
}
}else{
map.clearOverlays();
}
},
error: function (e) {
}
});
},
mapinit() {
var area = "中国"; // '湖北省钟祥市'
var mapcenter = "郑州";
map = new BMap.Map("map"); // 创建Map实例
map.setMapStyle({
features: ["building", "water", "land"],
style: "midnight"
});
map.centerAndZoom(mapcenter, 5); // 初始化地图,设置中心点坐标和地图级别
map.addControl(new BMap.MapTypeControl({
mapTypes:[
BMAP_NORMAL_MAP,
BMAP_HYBRID_MAP
]}));
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
var bdary = new BMap.Boundary();
bdary.get(area, function (rs) { //获取行政区域
//网上查了下,东西经南北纬的范围
var EN_JW = "180, 90;"; //东北角
var NW_JW = "-180, 90;"; //西北角
var WS_JW = "-180, -90;"; //西南角
var SE_JW = "180, -90;"; //东南角
//4.添加环形遮罩层
var ply1 = new BMap.Polygon(rs.boundaries[0] + SE_JW + SE_JW + WS_JW + NW_JW + EN_JW + SE_JW, { strokeColor: "none", fillColor: "rgb(246,246,246,0.2)", fillOpacity:0.5, strokeOpacity: 0.5 }); //建立多边形覆盖物
map.addOverlay(ply1);
//5. 给目标行政区划添加边框,其实就是给目标行政区划添加一个没有填充物的遮罩层
var ply = new BMap.Polygon(rs.boundaries[0], { strokeWeight: 2, strokeColor: "#00f",fillColor: "" });
map.addOverlay(ply);
});
this.getMapData()
},
//
getLeftDev(){
var that=this
$.ajax({
type:'POST',
url:baseurl+'/service/page/node.json?paged='+that.nowpage+'&pageSize=10',
contentType: 'application/json',
dataType: "json",
data:JSON.stringify({
scene_id:that.nowproject,
device_code:that.device_code
}),
headers : {'USER-KEY':ucode},
success: function (e) {
if(e.status==2){
that.devLeft=e.data.data
that.totalpage=e.data.totalPage
}else{
that.devLeft=[]
}
},
error: function (e) {
}
});
}
},
created() {
// 如果传递过来项目id,则使用项目id
this.nowproject = getQueryString("scene_id") ;
if( this.nowproject == null) {
this.showProject=true ;
}
this.getAlermData()
this.getLeftDev()
this.getProject()
this.getSysConfig()//获取系统参数
var that = this ;
setInterval(function() {
that.getLeftDev();
that.getAlermData()
that.getProject()
that.statusDevice()
that.getDevStaData()
}, 20*1000);
},
mounted() {
let that = this
this.mapinit()
this.statusDevice()
this.getDevStaData()
}
})
</script>
</body>
</html>