翠屏区智慧广电示范区
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.
 
 
 
 

999 lines
39 KiB

<template>
<!-- 应急广播数据中心 -->
<div class="eb-container" ref="appRef">
<!-- 背景框 -->
<div class="bg">
<MainTitle class="title" :title="title"></MainTitle>
</div>
<gis-map class="gismap" pointType="应急广播" :point-list="pointList" :lngLat="lngLat" list-item-key="ebrName"
@currentPoint="currentPointFn">
<template v-slot:content>
<div class="left-box">
<div class="left-one">
<div class="title-box-samll">
<span>设备状态展示</span>
</div>
<div class="databox">
<div class="line-title-box">
<div class="line-title-box-item" v-for="(item, index) in statusItemList" :key="index">
<div class="line-item-box">
<div class="line-item-color" :style="{
background:
index % 2 === 0
? '#01FF94'
: '#01A4FF',
}"></div>
<div class="line-item-white"></div>
</div>
<div class="line-item-title">
{{ item.title }}
</div>
<div class="line-item-number">
<CountTo :startVal="0" :endVal="Number(item.number)" :duration="2000" />
</div>
</div>
</div>
<div class="table-box">
<Treeselect placeholder="请选择区域" v-model="currentArea" :options="areaData"
@select="selectNode" />
<div id="bar_chart" style="width: 450px;height: 350px;margin-top: 10px;"></div>
</div>
</div>
</div>
<div class="left-two">
<div class="title-box-samll">
<span>设备终端</span>
</div>
<div class="databox">
<div class="table-body-box" style="height: 100%">
<vue-seamless-scroll :class-option="optionHoverVertical" :data="deviceList">
<div class="data-item-box" v-for="(item, index) in deviceList" :key="index"
@click="currentPointFn(item)">
<div style="display: flex">
<div class="data-name">
{{ item.ebrName }}
</div>
</div>
<div class="data-status">
<div class="point" :style="{
backgroundColor:
item.ebrState == '2'
? 'red'
: 'green',
}"></div>
<div class="status">
{{
item.ebrState == "2"
? "离线"
: "在线"
}}
</div>
</div>
</div>
</vue-seamless-scroll>
</div>
</div>
</div>
</div>
<div class="right">
<div class="right-one">
<div class="title-box-samll">
<span>广播类型统计</span>
</div>
<div class="databox"
style="padding-left: 20px;display: flex;flex-direction: row;width: 100%;height: 100%;">
<div id="r_barChart1" style="width: 200px;height: 300px;"></div>
<div id="r_barChart2" style="width: 200px;height: 300px;"></div>
</div>
</div>
<div class="right-two">
<div class="title-box-samll">
<span>广播级别统计</span>
</div>
<div class="databox"
style="padding-left: 20px;display: flex;flex-direction: row;width: 100%;height: 100%;">
<div id="r_barChart3" style="width: 200px;height: 300px;"></div>
<div id="r_barChart4" style="width: 200px;height: 300px;"></div>
</div>
</div>
<div class="right-three">
<div class="title-box-samll">
<span>最新应急信息</span>
</div>
<div class="databox">
<div class="table-title-box">
<div class="table-title-item" style="width: 20%; text-align: left">
事件类别
</div>
<div class="table-title-item" style="width: 30%">
事件标题
</div>
<div class="table-title-item" style="width: 30%">
发布单位
</div>
<div class="table-title-item" style="width: 20%; text-align: right">
播发状态
</div>
</div>
<div class="table-body-box" style="height: 394px">
<vue-seamless-scroll :data="infoTableData" :class-option="optionHoverVertical">
<div>
<div v-for="(
item, index
) in infoTableData" :key="index" class="table-body-item"
@click="currentInfo = item; infoState = true">
<div class="table-info-item" style="
width: 20%;
text-align: left;
">
{{ item.eventTypeName }}
</div>
<div class="table-info-item" style="width: 30%">
{{ item.msgTitle }}
</div>
<div class="table-info-item" style="width: 30%">
{{ item.sendName }}
</div>
<div class="table-info-item" style="
width: 20%;
text-align: right;
" :style="{
color:
item.broadcastState == 3
? 'green'
: 'red',
}">
{{
item.broadcastStateName
}}
</div>
</div>
</div>
</vue-seamless-scroll>
</div>
</div>
</div>
</div>
<div class="page-bottom-bg"></div>
<div class="page-left-bg"></div>
<div class="page-right-bg"></div>
</template>
</gis-map>
<CommonModal v-model="pointState" title="设备详情" width="500">
<div style="
width: 100%;
display: flex;
flex-direction: column;
padding: 10px;
">
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">名称:{{ currentPoint.name }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">资源编码:{{ currentPoint.ebrId }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">安装位置:{{ currentPoint.location }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">安装时间:{{ currentPoint.installTime }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">经度:{{ currentPoint.longitude }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">纬度:{{ currentPoint.latitude }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">在线状态:</span>
<Tag :color="currentPoint.status == '3' ? 'red' : 'green'">{{ currentPoint.status == "3" ? "离线" :
"在线" }}
</Tag>
</div>
</div>
</CommonModal>
<!-- 应急信息详情 -->
<CommonModal v-model="infoState" title="应急信息详情" width="500">
<div style="
width: 100%;
display: flex;
flex-direction: column;
padding: 10px;
">
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">事件类别:{{ currentInfo.eventTypeName }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">事件标题:{{ currentInfo.msgTitle }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">发布单位:{{ currentInfo.sendName }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">发布时间:{{ currentInfo.sendTime }}</span>
</div>
<!-- 开始时间 -->
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">开始时间:{{ currentInfo.startTime }}</span>
</div>
<!-- 结束时间 -->
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">结束时间:{{ currentInfo.endTime }}</span>
</div>
<div style="
display: flex;
align-items: center;
margin-bottom: 20px;
">
<span style="font-size: 20px">播发状态:</span>
<Tag :color="currentInfo.broadcastState == '3' ? 'green' : 'red'">
{{ currentInfo.broadcastStateName }}
</Tag>
</div>
</div>
</CommonModal>
</div>
</template>
<script>
import { useIndex } from "../../utils/utilsDramAdmin";
import MainTitle from "./components/MainTitle.vue";
import gisMap from "./components/gisMapOfCounty.vue";
import vueSeamlessScroll from "vue-seamless-scroll";
import CountTo from "vue-count-to";
import * as echarts from "echarts";
import { echartsFocus, echartsClear } from "@/utils/autoEcharts";
import CommonModal from "@/views/common-components/common-modal.vue";
import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';
export default {
name: "EmergencyScreen",
components: { MainTitle, gisMap, vueSeamlessScroll, CountTo, CommonModal, Treeselect },
data() {
return {
title: "应急广播数据中心",
pointList: [],
pointState: false,
currentPoint: {},
lngLat: [],
lineChartData: {},
statusItemList: [
{ title: "设备在线(个)", number: 0 },
{ title: "设备在线率(%)", number: 0 },
{ title: "设备离线(个)", number: 0 },
{ title: "设备离线率(%)", number: 0 },
],
statusTableData: [],
deviceList: [],
infoTableData: [],
optionHoverVertical: {
step: 0.3,
limitMoveNum: 2,
hoverStop: false,
direction: 1,
openWatch: true,
singleHeight: 0,
singleWidth: 0,
waitTime: 1000,
},
currentArea: null,
areaData: [],
barChart: null,
r_barChart1: null,
r_barChart2: null,
r_barChart3: null,
r_barChart4: null,
infoState: false,
currentInfo: {},
};
},
mounted() {
const { calcRate, windowDraw } = useIndex(this.$refs.appRef);
calcRate();
windowDraw();
this.getDeviceListByArea();
this.getAreaListByParentId();
this.getBroadcastStatistics();
this.getDeviceList();
},
beforeDestroy() {
echartsClear();
this.barChart.dispose();
this.r_barChart1.dispose();
this.r_barChart2.dispose();
this.r_barChart3.dispose();
this.r_barChart4.dispose();
},
methods: {
currentPointFn(data) {
this.currentPoint = data;
this.pointState = true;
},
assembleData(data) {
let list = [];
if (data && data.length > 0) {
data.forEach((item) => {
if (item.children && item.children.length > 0) {
this.assembleData(item.children);
} else {
let dataItem = { ...item };
dataItem.lnglat = [item.longitude, item.latitude];
list.push(dataItem);
}
});
}
return list;
},
// 查询指定区域下的设备信息
getDeviceListByArea() {
// /emergencyBroadcast/safeRest/ebrView/gis/show
this.$http
.post(
'/emergencyBroadcast/safeRest/ebrView/gis/show',
this.common.request({})
).then(res => {
if (res.data.code == 200) {
this.deviceList = res.data.data.map(d => ({
...d,
name: d.ebrName,
}));
this.pointList = this.assembleData(this.deviceList);
}
}
)
},
buildTree(data) {
const tree = [];
const map = {};
data.forEach(item => {
map[item.areaCode] = item;
});
data.forEach(item => {
const parent = map[item.parentAreaCode];
if (parent) {
(parent.children || (parent.children = [])).push(item);
} else {
tree.push(item);
}
});
return tree;
},
// 获取指定行政区域的下级区域
getAreaListByParentId(parentId) {
this.$http
.post(
'/emergencyBroadcast/safeRest/area/getByParentAreaCode',
this.common.request({ parentAreaCode: parentId })
).then(res => {
if (res.data.code == 200) {
this.areaData = this.buildTree(res.data.data.map(item => {
return {
id: item.areaCode,
label: item.areaName,
parentAreaCode: item.parentAreaCode,
areaCode: item.areaCode
};
}));
this.currentArea = this.areaData[0].id;
this.getTerminalOnlineRateAndTypeRate(this.currentArea);
}
}
)
},
// 获取终端在线率和类型占比
getTerminalOnlineRateAndTypeRate(areaCode) {
this.$http
.post(
'/emergencyBroadcast/safeRest/statistics/terminal/type',
this.common.request({ areaCode })
).then(res => {
if (res.data.code == 200) {
const data = res.data.data;
this.statusItemList = [
{ title: "设备在线(个)", number: data.totalOnlineCount },
{ title: "设备在线率(%)", number: data.totalOnlinePercent.split('%')[0] },
{ title: "设备离线(个)", number: data.totalOutlineCount },
{ title: "设备离线率(%)", number: data.totalOutlinePercent.split('%')[0] },
];
this.statusTableData = data.areaList;
this.initBarChart({
id: "bar_chart",
name: '设备统计',
one: {
name: "设备在线",
value: data.totalOnlineCount,
color: '#01FF94'
},
two: {
name: "设备离线",
value: data.totalOutlineCount,
color: '#01A4FF'
}
});
}
}
)
},
blendColor(color, blend, percentage) {
const f = parseInt(color.slice(1), 16),
t = parseInt(blend.slice(1), 16),
R1 = f >> 16,
G1 = (f >> 8) & 0x00FF,
B1 = f & 0x0000FF;
const R2 = t >> 16,
G2 = (t >> 8) & 0x00FF,
B2 = t & 0x0000FF;
return `#${((1 << 24) + (Math.round((R2 - R1) * percentage) + R1 << 16) + (Math.round((G2 - G1) * percentage) + G1 << 8) + (Math.round((B2 - B1) * percentage) + B1)).toString(16).slice(1)}`;
},
// initBarChart
initBarChart(config) {
this[config.id] = echarts.init(document.getElementById(config.id));
const option = {
tooltip: {
trigger: 'item'
},
legend: {
left: 'center',
textStyle: {
color: '#fff'
},
},
series: [
{
name: config.name,
type: 'pie',
radius: '50%',
data: config.more ? [
{ value: config.one.value, name: config.one.name, itemStyle: { color: this.blendColor(config.one.color, '#223455', 0.5) } },
{ value: config.two.value, name: config.two.name, itemStyle: { color: this.blendColor(config.two.color, '#223455', 0.5) } },
{ value: config.three.value, name: config.three.name, itemStyle: { color: this.blendColor(config.three.color, '#223455', 0.5) } },
{ value: config.four.value, name: config.four.name, itemStyle: { color: this.blendColor(config.four.color, '#223455', 0.5) } },
] : [
{ value: config.one.value, name: config.one.name, itemStyle: { color: this.blendColor(config.one.color, '#223455', 0.5) } },
{ value: config.two.value, name: config.two.name, itemStyle: { color: this.blendColor(config.two.color, '#223455', 0.5) } },
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
this[config.id].setOption(option);
echartsFocus(this[config.id], 2);
},
selectNode(node) {
this.getTerminalOnlineRateAndTypeRate(node.areaCode);
},
// 4.广播统计综合性统计
getBroadcastStatistics() {
this.$http
.post(
'/emergencyBroadcast/safeRest/statistics/broadcast/infoByType',
this.common.request({})
).then(res => {
if (res.data.code == 200) {
const data = res.data.data;
data.broadcastByTypeList.forEach((item, index) => {
this.initBarChart({
id: `r_barChart${index + 1}`,
name: '广播类型统计',
one: {
name: "应急广播",
value: item.emergency,
color: '#01FF94'
},
two: {
name: "日常广播",
value: item.daily,
color: '#01A4FF'
}
});
})
data.broadcastByLevelList.forEach((item, index) => {
this.initBarChart({
id: `r_barChart${index + 3}`,
name: '广播级别统计',
one: {
name: "一级",
value: item.broadcastLevelList[0].statistic,
color: '#01FF94'
},
two: {
name: "二级",
value: item.broadcastLevelList[1].statistic,
color: '#01A4FF'
},
three: {
name: "三级",
value: item.broadcastLevelList[2].statistic,
color: '#01A494'
},
four: {
name: "四级",
value: item.broadcastLevelList[3].statistic,
color: '#02FDE4'
},
more: true
});
})
}
}
)
},
// 广播设备列表(设备终端列表)
getDeviceList() {
this.$http
.post(
'/emergencyBroadcast/safeRest/ebm/page',
this.common.request({
"broadcastState": "",
"endTime": "",
"pageNum": 1,
"pageSize": 1000,
"sendFlag": "1",
"senderCode": "",
"severity": "",
"startTime": ""
})
).then(res => {
if (res.data.code == 200) {
this.infoTableData = res.data.data;
}
}
)
},
}
};
</script>
<style lang="less" scoped>
@import "../../styles/pbStyle.less";
/deep/ .vue-treeselect__control {
background: transparent !important;
}
/deep/ .vue-treeselect__single-value {
color: #fff !important;
}
/deep/ .vue-treeselect__menu {
background: transparent !important;
}
/deep/ .vue-treeselect--single .vue-treeselect__option--selected {
background: #687b89 !important;
}
/deep/ .vue-treeselect--single .vue-treeselect__option:hover {
background: #74818b !important;
}
/deep/.ivu-tree {
width: 340px;
height: 848px;
}
/deep/.ivu-tree-arrow {
color: #d6e2f2;
}
/deep/.ivu-tree-title {
font-family: "PingFang SC";
font-size: 14px;
font-weight: 400;
line-height: 20px;
letter-spacing: 0em;
text-align: left;
color: #ffffff;
}
.eb-container {
width: 1920px;
height: 1080px;
transform: scale(var(--scale)) translate(-50%, -50%);
transform-origin: 0 0;
position: absolute;
left: 50%;
top: 50%;
background-image: url("../../assets/largeScreen/page-bg.png");
background-size: 100%;
.gismap {
.left-box {
position: fixed;
top: 100px;
left: 50px;
width: 458px;
height: 920px;
display: flex;
flex-direction: column;
.left-one {
width: 100%;
height: 50%;
display: flex;
flex-direction: column;
.databox {
.content-pub-style(100%, calc(100% - 44px));
color: #ffffff;
display: flex;
flex-direction: column;
.line-title-box {
width: 100%;
height: 80px;
display: flex;
flex-direction: row;
.line-title-box-item {
width: 25%;
height: 100%;
padding: 10px;
font-family: shiShangHeiTi;
.line-item-box {
width: 100%;
height: 5px;
display: flex;
flex-direction: row;
.line-item-color {
width: 30%;
height: 100%;
border-radius: 5px;
}
.line-item-white {
width: 60%;
height: 100%;
border-radius: 5px;
background-color: rgba(1, 206, 255, 0.16);
margin-left: 5px;
}
}
.line-item-title {
width: 100%;
margin-top: 5px;
font-size: 14px;
line-height: 22px;
}
.line-item-number {
width: 100%;
font-size: 32px;
line-height: 40px;
text-shadow: 0px 3px 4px #ffffff;
}
}
}
.table-box {
width: 100%;
padding: 10px 10px 10px 15px;
font-family: shiShangHeiTi;
}
}
}
.left-two {
width: 100%;
height: 50%;
display: flex;
flex-direction: column;
.databox {
.content-pub-style(100%, calc(100% - 44px));
color: #ffffff;
font-family: shiShangHeiTi;
padding: 15px;
}
}
}
.table-title-box {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
.table-title-item {
text-align: center;
font-size: 12px;
line-height: 28px;
color: #c2c4c7;
letter-spacing: 2px;
}
}
.table-body-box {
width: 100%;
overflow: hidden;
.data-item-box {
width: 100%;
height: 40px;
display: flex;
justify-content: space-between;
flex-direction: row;
cursor: pointer;
}
.data-name {
/*margin-left: 16px;*/
font-size: 14px;
line-height: 40px;
}
.data-status {
display: flex;
.point {
width: 6px;
height: 6px;
margin-top: 17px;
border-radius: 3px;
background-color: red;
}
.status {
margin-left: 10px;
font-size: 14px;
line-height: 40px;
}
}
.table-body-item {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
cursor: pointer;
.table-info-item {
text-align: center;
font-size: 14px;
line-height: 36px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.right {
width: 458px;
// height: 922px;
position: fixed;
top: 100px;
right: 50px;
z-index: 1;
display: flex;
flex-direction: column;
align-items: center;
.right-one {
width: 100%;
height: 300px;
display: flex;
flex-direction: column;
align-items: center;
.databox {
.content-pub-style(100%, calc(100% - 44px));
display: flex;
padding-top: 20px;
flex-direction: column;
align-items: center;
}
}
.right-two {
width: 100%;
height: 300px;
display: flex;
flex-direction: column;
align-items: center;
.databox {
.content-pub-style(100%, calc(100% - 44px));
display: flex;
padding-top: 20px;
flex-direction: column;
align-items: center;
}
}
.right-three {
width: 100%;
height: 320px;
display: flex;
flex-direction: column;
align-items: center;
.databox {
.content-pub-style(100%, calc(100% - 44px));
display: flex;
flex-direction: column;
align-items: center;
font-family: shiShangHeiTi;
color: #ffffff;
padding: 10px 15px;
}
}
// .right-three {
// margin-top: 10px;
// width: 100%;
// height: 300px;
// display: flex;
// flex-direction: column;
// justify-content: space-between;
// align-items: center;
// .min-title {
// width: 100%;
// height: 46px;
// background: url("../../assets/screenView/minTitle.png") no-repeat;
// background-size: 100% 100%;
// display: flex;
// align-items: center;
// span {
// font-family: "YouSheBiaoTiHei";
// font-size: 22px;
// font-weight: 400;
// line-height: 29px;
// letter-spacing: 0em;
// text-align: left;
// background: linear-gradient(to top, #5982B5, #ECF4FE);
// -webkit-background-clip: text;
// color: transparent;
// margin-left: 44px;
// }
// }
// .databox {
// flex: 1;
// width: 100%;
// margin-top: 10px;
// border: 1px solid #556b7c;
// background-color: rgba(29, 37, 47, 0.5);
// display: flex;
// padding-top: 20px;
// flex-direction: column;
// align-items: center;
// .titleBox {
// width: 100%;
// height: 40px;
// display: grid;
// background-color: #072e5b;
// grid-template-columns: repeat(4, 25%);
// grid-template-rows: 100%;
// span {
// display: flex;
// justify-content: center;
// align-items: center;
// font-size: 16px;
// color: #ffffff;
// }
// }
// .scrollBox {
// width: 100%;
// flex: 1;
// overflow: hidden;
// .contentList {
// width: 100%;
// display: flex;
// flex-direction: column;
// .content-item {
// width: 100%;
// height: 30px;
// display: grid;
// grid-template-columns: repeat(4, 25%);
// grid-template-rows: 100%;
// padding: 0 3px;
// span {
// text-align: center;
// line-height: 30px;
// color: #ffffff;
// font-size: 14px;
// display: inline-block;
// white-space: nowrap;
// overflow: hidden;
// text-overflow: ellipsis;
// }
// }
// }
// }
// }
// }
}
}
.bg {
width: 1920px;
height: 1080px;
display: flex;
flex-direction: column;
align-items: center;
pointer-events: none;
.title {
pointer-events: all;
}
}
}
</style>