Răsfoiți Sursa

物联看板

jiawuxian 1 an în urmă
părinte
comite
7fd980e10d

+ 84 - 0
src/api/iot/board.js

@@ -0,0 +1,84 @@
+import request from "@/utils/request";
+
+/**
+ * 设备数量
+ * @param {} orgId
+ */
+export function deviceCount(orgId) {
+  return request({
+    url: "/iot/board/deviceCount/" + orgId,
+    method: "get",
+  });
+}
+
+/**
+ * 防区信息
+ * @param {*} orgId
+ * @returns
+ */
+export function protectionInfo(orgId) {
+  return request({
+    url: "/iot/board/protection/" + orgId,
+    method: "get",
+  });
+}
+
+/**
+ * 设备在线率
+ * @param {*} orgId
+ * @returns
+ */
+export function deviceOnline(orgId) {
+  return request({
+    url: "/iot/board/deviceOnline/" + orgId,
+    method: "get",
+  });
+}
+
+/**
+ * 设备健康状态
+ * @param {*} orgId
+ * @returns
+ */
+export function deviceHealth(orgId) {
+  return request({
+    url: "/iot/board/deviceHealth/" + orgId,
+    method: "get",
+  });
+}
+
+/**
+ * 设备告警趋势
+ * @param {*} orgId
+ * @returns
+ */
+export function alarmTrend(orgId) {
+  return request({
+    url: "/iot/board/alarmTrend/" + orgId,
+    method: "get",
+  });
+}
+
+/**
+ * 设备实时告警率
+ * @param {*} orgId
+ * @returns
+ */
+export function alarmRate(orgId) {
+  return request({
+    url: "/iot/board/alarmRate/" + orgId,
+    method: "get",
+  });
+}
+
+/**
+ * 设备告警列表
+ * @param {*} orgId
+ * @returns
+ */
+export function alarmList(orgId) {
+  return request({
+    url: "/iot/board/alarmList/" + orgId,
+    method: "get",
+  });
+}

+ 14 - 0
src/router/index.js

@@ -135,6 +135,20 @@ export const constantRoutes = [
       },
     ],
   },
+  {
+    path: "/iot",
+    component: Layout,
+    hidden: true,
+    redirect: "noredirect",
+    children: [
+      {
+        path: "board",
+        component: () => import("@/views/iot/board/index"),
+        name: "iot_board",
+        meta: { title: "物联看板", icon: "user" },
+      },
+    ],
+  },
 ];
 
 // 动态路由,基于用户权限动态去加载

+ 2 - 1
src/views/board/index.vue

@@ -367,7 +367,8 @@ export default {
     color: #8e949c;
     padding: 0 5px;
     font-size: 12px;
-
+    background-color:transparent;
+    display: inline-block;
     &:hover {
       color: #ffffff;
     }

+ 105 - 0
src/views/iot/board/components/alarmList.vue

@@ -0,0 +1,105 @@
+<template>
+    <div class="component_box" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
+        <h1 class="t_title">实时告警列表</h1>
+        <el-table :data="data" width="100%">
+            <el-table-column label="所在机构" prop="orgName" align="center"></el-table-column>
+            <el-table-column label="告警设备" prop="deviceName" align="center"></el-table-column>
+            <el-table-column label="告警时间" prop="alarmTime" align="center"></el-table-column>
+            <el-table-column label="告警信息" prop="alarmInfo" align="center"></el-table-column>
+        </el-table>       
+    </div>
+</template>
+<script>
+import { alarmList } from "@/api/iot/board";
+export default {
+    props: {
+        orgId: {
+            type: String,
+            isRequired: true,
+        },
+    },
+    data() {
+        return {
+            data: [],
+        };
+    },
+
+    components: {},
+
+    computed: {},
+
+    watch: {
+        orgId: {
+            deep: true,
+            handler(val) {
+                this.resetTimer();
+                this.getData();
+            },
+        },
+    },
+    created() {
+        this.refreshTime = 1 * 10 * 1000;
+        this.isMouseOver = false;
+    },
+    mounted() {
+
+    },
+    methods: {
+        async getData() {
+            let r = (await alarmList(this.orgId))
+                .data;
+            this.data = r;
+        },
+        resetTimer() {
+            this.timer && clearInterval(this.timer);
+            this.timer = setInterval(() => {
+                if (this.isMouseOver) {
+                    return;
+                }
+
+                this.getData();
+            }, this.refreshTime);
+        },
+    }
+}
+</script>
+<style scoped src="./../css/index.css"></style>
+<style lang="scss" scoped>
+.t_table {
+    font-size: 14px;
+    color: #fff;
+    width: 94%;
+    margin: 0 auto;
+    border-spacing: 0;
+    text-align: center;
+    box-sizing: border-box;
+    margin-top: 10%;
+}
+
+.t_table tr {
+    margin: 0;
+    padding: 0;
+    height: 40px;
+}
+
+.t_table thead tr {
+    background: #053a98;
+}
+
+.t_table tbody tr td:first-child {
+    border-left: 1px solid #053a98;
+}
+
+.t_table td {
+    border-bottom: 1px solid #053a98;
+    border-right: 1px solid #053a98;
+}
+
+.t_title {
+    position: absolute;
+    font-size: 20px;
+    color: #fff;
+    left: 5%;
+    top: 10%;
+}
+</style>

+ 157 - 0
src/views/iot/board/components/alarmRate.vue

@@ -0,0 +1,157 @@
+<template>
+    <div class="component_box">
+        <div ref="chart" style="width: 100%; height: 100%;" @mouseenter="handleMouseEnter"
+            @mouseleave="handleMouseLeave"></div>
+    </div>
+</template>
+<script>
+import { alarmRate } from '@/api/iot/board'
+export default {
+    props: {
+        orgId: {
+            type: String,
+            isRequired: true,
+        },
+    },
+    data() {
+        return {
+            data: {
+                normalCount: 0,
+                alarmCount: 0
+            },
+            // activeName: types[0].value,
+        };
+    },
+
+    components: {},
+
+    computed: {},
+
+    watch: {
+        orgId: {
+            deep: true,
+            handler(val) {
+                this.resetTimer();
+                this.getData();
+            },
+        },
+        data: {
+            deep: true,
+            handler() {
+                this.initMap();
+            },
+        },
+    },
+
+    created() {
+        this.refreshTime = 1 * 10 * 1000;
+        this.isMouseOver = false;
+    },
+
+    async mounted() {
+        window.addEventListener("resize", this.windowResize);
+    },
+    beforeDestroy() {
+        this.timer && clearInterval(this.timer);
+        this.timer = null;
+
+        window.removeEventListener("resize", this.windowResize);
+    },
+
+    methods: {
+        handleClick() {
+            this.resetTimer();
+            this.getData();
+        },
+        handleMouseEnter() {
+            this.isMouseOver = true;
+        },
+        handleMouseLeave() {
+            this.isMouseOver = false;
+        },
+        async getData() {
+            let r = (await alarmRate(this.orgId))
+                .data;
+            this.data = r;
+        },
+
+        windowResize() {
+            this.myChart && this.myChart.resize();
+        },
+        initMap() {
+            this.myChart && this.myChart.dispose();
+            let c = this.$refs["chart"];
+
+            // 基于准备好的dom,初始化echarts实例
+            this.myChart = echarts.init(
+                c
+            );
+            option = {
+                title: {
+                    text: "设备告警状态",
+                    top: 35,
+                    left: 20,
+                    textStyle: {
+                        fontSize: 18,
+                        color: "#fff",
+                    },
+                },
+                tooltip: {
+                    trigger: "item",
+                    formatter: "{a} <br/>{b}: {c} ({d}%)",
+                },
+                legend: {
+                    right: 20,
+                    top: 35,
+                    data: ["告警", "正常"],
+                    textStyle: {
+                        color: "#fff",
+                    },
+                },
+                series: [
+                    {
+                        name: "设备告警状态",
+                        type: "pie",
+                        radius: ["0", "60%"],
+                        center: ["50%", "60%"],
+                        // color: ['#e72325', '#98e002', '#2ca3fd'],
+                        color: ["#F6A645", "#13D0B2", "#2ca3fd"],
+                        label: {
+                            normal: {
+                                formatter: "{b}\n{d}%",
+                            },
+                        },
+                        data: [
+                            {
+                                value: this.data.alarmCount,
+                                name: "告警",
+                            },
+                            {
+                                value: this.data.normalCount,
+                                name: "正常",
+                                selected: true,
+                            },
+                        ],
+                    },
+                ],
+            };
+            // 使用刚指定的配置项和数据显示图表。
+            if (option && typeof option === "object") {
+                this.myChart.setOption(option);
+            }
+        },
+
+        resetTimer() {
+            this.timer && clearInterval(this.timer);
+            this.timer = setInterval(() => {
+                if (this.isMouseOver) {
+                    return;
+                }
+                // this.activeName = getNextPeriod(this.types, this.activeName);
+                this.getData();
+            }, this.refreshTime);
+        },
+    },
+};
+</script>
+<style scoped src="./../css/index.css"></style>

+ 377 - 0
src/views/iot/board/components/alarmTrend.vue

@@ -0,0 +1,377 @@
+<template>
+    <div class="component_box">
+        <div ref="chart" style="width: 100%; height: 100%;" @mouseenter="handleMouseEnter"
+            @mouseleave="handleMouseLeave"></div>
+    </div>
+</template>
+<script>
+import { alarmTrend } from '@/api/iot/board'
+export default {
+    props: {
+        orgId: {
+            type: String,
+            isRequired: true,
+        },
+    },
+    data() {
+        return {
+            data: {
+                date: [], //x轴的日期
+                total: [], //报警总数
+                countByType: [],//按分类统计的报警总数
+            },
+            isMouseOver: false,
+            // activeName: types[0].value,
+        };
+    },
+
+    components: {},
+
+    computed: {},
+
+    watch: {
+        orgId: {
+            deep: true,
+            handler(val) {
+                this.resetTimer();
+                this.getData();
+            },
+        },
+        data: {
+            deep: true,
+            handler() {
+                this.initMap();
+            },
+        },
+    },
+
+    created() {
+        this.types = types;
+        this.maxDisplay = 16;
+        this.refreshTime = 1 * 10 * 1000;
+        this.isMouseOver = false;
+    },
+
+    async mounted() {
+        window.addEventListener("resize", this.windowResize);
+    },
+    beforeDestroy() {
+        this.timer && clearInterval(this.timer);
+        this.timer = null;
+
+        window.removeEventListener("resize", this.windowResize);
+    },
+
+    methods: {
+        // handleClick() {
+        //     this.resetTimer();
+        //     this.getData();
+        // },
+        handleMouseEnter() {
+            this.isMouseOver = true;
+        },
+        handleMouseLeave() {
+            this.isMouseOver = false;
+        },
+        async getData() {
+            let r = (await alarmTrend(this.orgId))
+                .data;
+            let data = {
+                date: [], //x轴的日期
+                total: [], //报警总数
+                countByType: [],//按分类统计的报警总数
+            };
+
+            let monitorCount = [];
+            let fireCount = [];
+            let environmentCount = [];
+            for (let item of r) {
+                data.total.push(item.total);
+                monitorCount.push(item.monitorCount);
+                fireCount.push(item.fireCount);
+                environmentCount.push(item.environmentCount);
+
+                data.date.push(item.orgName);
+            }
+
+            data.countByType.push(monitorCount)
+            data.countByType.push(fireCount)
+            data.countByType.push(environmentCount);
+            this.data = data;
+        },
+
+        windowResize() {
+            this.myChart && this.myChart.resize();
+        },
+        initMap() {
+            this.myChart && this.myChart.dispose();
+            let c = this.$refs["chart"];
+
+            // 基于准备好的dom,初始化echarts实例
+            this.myChart = echarts.init(
+                c
+            );
+            var data = {
+                id: "multipleBarsLines",
+                title: "近7天告警趋势",
+                legendBar: ["报警总数"],
+                symbol: "", //数值是否带百分号        --默认为空 ''
+                legendLine: ["监控设备", "消防设备", "环境监测"],
+                // xAxis: ["9月19", "9月20", "9月21", "9月22", "9月23", "9月24", "9月25"],
+                // yAxis: [[8, 10, 10, 11, 4, 13, 8]],
+                // lines: [
+                //     [4, 3, 2, 4, 2, 1, 1],
+                //     [2, 1, 4, 2, 3, 2, 4],
+                //     [1, 0, 2, 1, 1, 2, 1],
+                // ],
+                barColor: ["#3FA7DC", "#7091C4", "#5170A2"], //柱子颜色 必填参数
+                lineColor: ["#D9523F"], // 折线颜色
+            };
+            /////////////end/////////
+
+            var myData = (function test() {
+                var yAxis = this.data.total || [];
+                var lines = this.data.countByType || [];
+                var legendBar = data.legendBar || [];
+                var legendLine = data.legendLine || [];
+                var symbol = data.symbol || " ";
+                var seriesArr = [];
+                var legendArr = [];
+                yAxis &&
+                    yAxis.forEach((item, index) => {
+                        legendArr.push({
+                            name: legendBar && legendBar.length > 0 && legendBar[index],
+                        });
+                        seriesArr.push({
+                            name: legendBar && legendBar.length > 0 && legendBar[index],
+                            type: "bar",
+                            barGap: "0.5px",
+                            data: item,
+                            barWidth: data.barWidth || 12,
+                            label: {
+                                normal: {
+                                    show: true,
+                                    formatter: "{c}" + symbol,
+                                    position: "top",
+                                    textStyle: {
+                                        color: "#fff",
+                                        fontStyle: "normal",
+                                        fontFamily: "微软雅黑",
+                                        textAlign: "left",
+                                        fontSize: 11,
+                                    },
+                                },
+                            },
+                            itemStyle: {
+                                //图形样式
+                                normal: {
+                                    barBorderRadius: 4,
+                                    color: data.barColor[index],
+                                },
+                            },
+                        });
+                    });
+
+                lines &&
+                    lines.forEach((item, index) => {
+                        legendArr.push({
+                            name: legendLine && legendLine.length > 0 && legendLine[index],
+                        });
+                        seriesArr.push({
+                            name: legendLine && legendLine.length > 0 && legendLine[index],
+                            type: "line",
+                            data: item,
+                            itemStyle: {
+                                normal: {
+                                    color: data.lineColor[index],
+                                    lineStyle: {
+                                        width: 3,
+                                        type: "solid",
+                                    },
+                                },
+                            },
+                            label: {
+                                normal: {
+                                    show: false, //折线上方label控制显示隐藏
+                                    position: "top",
+                                },
+                            },
+                            symbol: "circle",
+                            symbolSize: 10,
+                        });
+                    });
+
+                return {
+                    seriesArr,
+                    legendArr,
+                };
+            })();
+
+            option = {
+                title: {
+                    show: true,
+                    top: "10%",
+                    left: "3%",
+                    text: data.title,
+                    textStyle: {
+                        fontSize: 18,
+                        color: "#fff",
+                    },
+                    subtext: data.subTitle,
+                    link: "",
+                },
+                tooltip: {
+                    trigger: "axis",
+                    formatter: function (params) {
+                        var time = "";
+                        var str = "";
+                        for (var i of params) {
+                            time = i.name.replace(/\n/g, "") + "<br/>";
+                            if (i.data == "null" || i.data == null) {
+                                str += i.seriesName + ":无数据" + "<br/>";
+                            } else {
+                                str += i.seriesName + ":" + i.data + symbol + "%<br/>";
+                            }
+                        }
+                        return time + str;
+                    },
+                    axisPointer: {
+                        type: "none",
+                    },
+                },
+                legend: {
+                    right: data.legendRight || "30%",
+                    top: "12%",
+                    right: "5%",
+                    itemGap: 16,
+                    itemWidth: 10,
+                    itemHeight: 10,
+                    data: myData.legendArr,
+                    textStyle: {
+                        color: "#fff",
+                        fontStyle: "normal",
+                        fontFamily: "微软雅黑",
+                        fontSize: 12,
+                    },
+                },
+                grid: {
+                    x: 30,
+                    y: 80,
+                    x2: 30,
+                    y2: 60,
+                },
+                xAxis: {
+                    type: "category",
+                    data: this.data.date,
+                    axisTick: {
+                        show: false,
+                    },
+
+                    axisLine: {
+                        show: true,
+                        lineStyle: {
+                            color: "#1AA1FD",
+                        },
+                        symbol: ["none", "arrow"],
+                    },
+                    axisLabel: {
+                        show: true,
+                        interval: "0",
+                        textStyle: {
+                            lineHeight: 16,
+                            padding: [2, 2, 0, 2],
+                            height: 50,
+                            fontSize: 12,
+                        },
+                        rich: {
+                            Sunny: {
+                                height: 50,
+                                // width: 60,
+                                padding: [0, 5, 0, 5],
+                                align: "center",
+                            },
+                        },
+                        formatter: function (params, index) {
+                            var newParamsName = "";
+                            var splitNumber = 5;
+                            var paramsNameNumber = params && params.length;
+                            if (paramsNameNumber && paramsNameNumber <= 4) {
+                                splitNumber = 4;
+                            } else if (paramsNameNumber >= 5 && paramsNameNumber <= 7) {
+                                splitNumber = 4;
+                            } else if (paramsNameNumber >= 8 && paramsNameNumber <= 9) {
+                                splitNumber = 5;
+                            } else if (paramsNameNumber >= 10 && paramsNameNumber <= 14) {
+                                splitNumber = 5;
+                            } else {
+                                params = params && params.slice(0, 15);
+                            }
+
+                            var provideNumber = splitNumber; //一行显示几个字
+                            var rowNumber = Math.ceil(paramsNameNumber / provideNumber) || 0;
+                            if (paramsNameNumber > provideNumber) {
+                                for (var p = 0; p < rowNumber; p++) {
+                                    var tempStr = "";
+                                    var start = p * provideNumber;
+                                    var end = start + provideNumber;
+                                    if (p == rowNumber - 1) {
+                                        tempStr = params.substring(start, paramsNameNumber);
+                                    } else {
+                                        tempStr = params.substring(start, end) + "\n";
+                                    }
+                                    newParamsName += tempStr;
+                                }
+                            } else {
+                                newParamsName = params;
+                            }
+                            params = newParamsName;
+                            return "{Sunny|" + params + "}";
+                        },
+                        color: "#1AA1FD",
+                    },
+                },
+                yAxis: {
+                    axisLine: {
+                        show: true,
+                        lineStyle: {
+                            color: "#1AA1FD",
+                        },
+                        symbol: ["none", "arrow"],
+                    },
+                    type: "value",
+                    axisTick: {
+                        show: false,
+                    },
+                    axisLabel: {
+                        show: false,
+                    },
+                    splitLine: {
+                        show: false,
+                        lineStyle: {
+                            color: "#1AA1FD",
+                            type: "solid",
+                        },
+                    },
+                },
+                series: myData.seriesArr,
+            };
+            // 使用刚指定的配置项和数据显示图表。
+            if (option && typeof option === "object") {
+                this.myChart.setOption(option);
+            }
+        },
+
+        resetTimer() {
+            this.timer && clearInterval(this.timer);
+            this.timer = setInterval(() => {
+                if (this.isMouseOver) {
+                    return;
+                }
+                this.activeName = getNextPeriod(this.types, this.activeName);
+                this.getData();
+            }, this.refreshTime);
+        },
+    },
+};
+</script>
+<style scoped src="./../css/index.css"></style>

+ 185 - 0
src/views/iot/board/components/deviceCount.vue

@@ -0,0 +1,185 @@
+<template>
+    <div class="component_box">
+        <div class="t_mbox t_rbox">
+            <div>
+                <i></i>
+            </div>
+            <div>
+                <div>
+                    <span>视频监控设备</span>
+                    <span>{{ info.monitorCount }}</span>
+                </div>
+            </div>
+        </div>
+        <div class="t_mbox t_gbox">
+            <div>
+                <i></i>
+            </div>
+            <div>
+                <div>
+                    <span>消防预警设备</span>
+                    <span>{{ info.fireCount }}</span>
+                </div>
+            </div>
+        </div>
+        <div class="t_mbox t_ybox">
+            <div>
+                <i></i>
+            </div>
+            <div>
+                <div>
+                    <span>环境监测设备</span>
+                    <span>{{ info.environmentCount }}</span>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import { deviceCount } from "@/api/iot/board";
+export default {
+    data() {
+        return {
+            info: {
+                monitorCount: 0,
+                fireCount: 0,
+                environmentCount: 0
+            },
+        }
+    },
+    props: {
+        orgId: {
+            type: String,
+            isRequired: true,
+        }
+    },
+    watch: {
+        orgId: {
+            deep: true,
+            handler(val) {
+                this.resetTimer();
+                this.getData();
+            },
+        }
+    },
+    created() {
+        this.refreshTime = 1 * 10 * 1000;
+        this.isMouseOver = false;
+    },
+    methods: {
+        getData() {
+            deviceCount(this.orgId).then(r => {
+                this.info = r.data;
+            })
+        },
+        beforeDestroy() {
+            this.timer && clearInterval(this.timer);
+            this.timer = null;
+        },
+        resetTimer() {
+            this.timer && clearInterval(this.timer);
+            this.timer = setInterval(() => {
+                // if (this.isMouseOver) {
+                //     return;
+                // }
+                // this.activeName = getNextPeriod(this.types, this.activeName);
+                this.getData();
+            }, this.refreshTime);
+        },
+    }
+}
+</script>
+<style scoped src="./../css/index.css"></style>
+<style lang="scss" scoped>
+.t_mbox {
+    width: 90%;
+    height: 28.33%;
+    /* position: relative; */
+    margin: 0 auto;
+    margin-top: 5%;
+    display: flex;
+}
+
+.t_mbox>div {
+    height: 100%;
+    display: flex;
+    align-items: center;
+}
+
+.t_mbox>div:first-child {
+    width: 40%;
+    text-align: right;
+    padding-left: calc(40% - 50px - 10px);
+}
+
+.t_mbox>div:first-child>i {
+    display: block;
+    width: 50px;
+    height: 50px;
+    /* top: 0;
+    bottom: 0; */
+}
+
+.t_mbox>div:nth-child(2) {
+    width: 60%;
+    display: flex;
+    justify-content: center;
+}
+
+
+// .t_mbox>div:nth-child(2) h2 {
+//     font-size: 20px;
+//     color: #fff;
+//     // position: relative;
+//     // top: 50%;
+//     // left: 50%;
+// }
+.t_mbox>div:nth-child(2)>div {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+.t_mbox>div:nth-child(2)>div span {
+    font-size: 20px;
+    color: #fff;
+
+    // position: relative;
+    // top: 24%;
+    // left: 48%;
+}
+
+.t_mbox>div:nth-child(2)>div span:last-child {
+    margin-top: 10px;
+}
+
+.t_rbox {
+    background: #d9523f;
+    /* #44AFF0 */
+}
+
+.t_gbox {
+    background: #13d0b2;
+}
+
+.t_ybox {
+    background: #f6a645;
+    /* #4777F5 */
+}
+
+
+.t_rbox i {
+    background: url(../img/monitor.png) no-repeat;
+    background-size: 100% 100%;
+}
+
+.t_gbox i {
+    background: url(../img/fire.png) no-repeat;
+    background-size: 100% 100%;
+}
+
+.t_ybox i {
+    background: url(../img/environment.png) no-repeat;
+    background-size: 100% 100%;
+}
+</style>

+ 258 - 0
src/views/iot/board/components/deviceMap.vue

@@ -0,0 +1,258 @@
+
+
+
+<!--  -->
+<template>
+    <div class="component_box">
+      <div id="iot_map_Chart" style="height: 100%"></div>
+    </div>
+  </template>
+  
+  <script>
+
+  import * as echarts from "echarts";
+  import { getMap,mapInfo } from "@/api/board/cockpit.js";
+  
+  export default {
+    props: ["orgId", "orgName"],
+    data() {
+      return {
+        map: {},
+        coordinates: [],
+        icon: "image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAUCAYAAABvVQZ0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAF3SURBVDhPvZTBK4RBGIe/z56UklDay+6JkhM3RYo/wVlOrg4uTtyc3JSrg6Lc2CQHp5U7RyVylBBJXD7PO/PO7M43Y3OQp57mfd/fzOz6dlf2LxRFMYLr2hro63io7e/gQI53uKwjA303Cr06CujStcwV1rCHg3Kpgf4E1/CBtsraGTbN4wv24Q0K2/hsy2IFN/FJj6Rhw4zshg2ctGVxodkcfmET+/EVd8zBFISXKH+O1HtSQ92EQD2Bo1rfSggLJmyHoQvNZYK27nKXm3fDGu030I/ZsecDh/DIdCHy9Ti1peceK+6yFGeaLaE8q1UcxllMYR8HxYHtI4IHTO8+oDJvOOA2VfFTpgm2zCagfrejiIZuaaFBhGb+gZfYNYfLEKQeuFDBny7zX50IwvIn1emdTZlDSuq3ua+r41rX8jzL87ypZQyvVLMvGDCoseTuV+EI/kUFEB7bPZ5FjTw6b2dcoxYMGzbznGsUwHzaxp5Hjf6SLPsG2jnZyz2k38wAAAAASUVORK5CYII=",
+      };
+    },
+  
+    components: {},
+  
+    computed: {},
+  
+    watch: {
+      orgId: {
+        deep: true,
+        handler(val) {
+          //   this.resetTimer();
+          this.getData();
+        },
+      },
+      // map: {
+      //   deep: true,
+      //   handler() {
+      //     this.$nextTick(() => {
+      //       this.initMap();
+      //     });
+      //   },
+      // },
+    },
+  
+    created() {
+      //   this.types = types;
+      //   this.maxDisplay = 16;
+      //   this.refreshTime = 1 * 10 * 1000;
+      this.isMouseOver = false;
+    },
+  
+    async mounted() {
+      // console.info(this.fjMap)
+  
+      window.addEventListener("resize", this.windowResize);
+    },
+    beforeDestroy() {
+      this.timer && clearInterval(this.timer);
+      this.timer = null;
+  
+      window.removeEventListener("resize", this.windowResize);
+    },
+  
+    methods: {
+      // handleClick() {
+      //   this.resetTimer();
+      //   this.getData();
+      // },
+      handleMouseEnter() {
+        this.isMouseOver = true;
+      },
+      handleMouseLeave() {
+        this.isMouseOver = false;
+      },
+      async getData() {
+        let mapinfo= await mapInfo(this.orgId);
+  
+        let map = mapinfo.data.map;
+        let coordinates =mapinfo.data.sites.map(s=>({ name: s.orgName, value: [s.longitude,s.latitude, 10] })); 
+        this.map = map;
+        this.coordinates = coordinates;
+        this.$nextTick(() => {
+          this.initMap();
+        });
+      },
+      initMap() {
+        this.myChart && this.myChart.dispose();
+  
+        // 基于准备好的dom,初始化echarts实例
+        this.myChart = echarts.init(document.getElementById("iot_map_Chart"));
+        let t = this;
+  
+        getMap(this.map).then((data) => {
+          echarts.registerMap("map", data);
+  
+          let option = {
+            tooltip: {
+              trigger: "item",
+            },
+            geo: {
+              show: true,
+              map: "map",
+              zoom: 1.25,
+  
+              showLegendSymbol: false, // 存在legend时显示
+  
+              label: {
+                normal: {
+                  show: false,
+                  color: "#c1b496", //控制地图省市文字颜色
+                  fontSize: 14,
+                },
+                emphasis: {
+                  show: false,
+                  color: "#fff", //悬浮字体颜色
+                },
+              },
+  
+              roam: true,
+              selectedMode: "single", //选择模式,单选,只能选中一个地市
+              select: {
+                //这个就是鼠标点击后,地图想要展示的配置
+                disabled: false, //可以被选中
+                itemStyle: {
+                  //相关配置项很多,可以参考echarts官网
+                  borderWidth: 1, //区域边框宽度
+                  borderColor: "#2B91B7ff", //区域边框颜色
+                  areaColor: "#2B91B730", //选中
+                },
+                label: {
+                  show: false,
+                  color: "#fff", //悬浮字体颜色
+                },
+              },
+              itemStyle: {
+                normal: {
+                  borderWidth: 1, //区域边框宽度
+                  borderColor: "#3fdaffff", //区域边框颜色
+                  areaColor: "#3fdaff55", //区域颜色"rgba(23,107,221,0.7)",//
+                },
+                emphasis: {
+                  borderWidth: 1,
+                  borderColor: "#fff",
+                  areaColor: "#2B91B7",
+                },
+              },
+            },
+            legend: [
+              {
+                selectedMode: true, //取消图例上的点击事件
+              },
+            ],
+            series: [
+              {
+                map: "map",
+                type: "effectScatter",
+                // silent: true,
+                coordinateSystem: "geo",
+                // datasetIndex: 0,
+                // geoIndex: 0,
+                // selectedMode: false,
+                // focusNodeAdjacency: false,
+                // label: {
+                // 	show: true,
+                // 	width: 13,
+                // 	height: 15,
+                // 	fontSize: 0,
+                // 	color: "#1DF9FC",
+                // 	backgroundColor: {
+                // 		image: iconRQ
+                // 	},
+                // },
+                label: {
+                  formatter: (param) => {
+                    return param.name;
+                  },
+                  position: "top",
+                  fontSize: "10",
+                  color: "#fff",
+                  show: true,
+                },
+                tooltip: {
+                  show: false,
+                },
+                //  tooltip:{
+                //   position: "right",
+                //   textStyle:{
+                //     // color:'#fff',
+                //   },
+                //   // backgroundColor:'rgba(184,189,192,1)',
+                //   formatter:function(param){
+                //     return `<div >
+                //     <div> ${param.data.name} </div>
+                //     <div>履职总数:85 </div>
+                //     <div> 已完成:67 </div>
+                //     </div>`
+                //   }
+                // },
+                itemStyle: {
+                  color: "#ddb926",
+                },
+                symbol: this.icon, //自定义图标
+                symbolSize: [10, 10],
+                // encode: {
+                //   value: 2,
+                // },
+                // showEffectOn: "emphasis", //关闭涟漪
+                // hoverEffectOn: true,
+                rippleEffect: {
+                  brushType: "fill",
+                  period: 0,
+                  number: 0,
+                },
+                data: this.coordinates,
+              },
+            ],
+          };
+          if (option && typeof option === "object") {
+            this.myChart.setOption(option);
+          }
+        });
+      },
+      windowResize() {
+        this.myChart && this.myChart.resize();
+      },
+    },
+  };
+  </script>
+  <style scoped src="./../css/index.css"></style>
+  <style lang="scss" scoped>
+  .content {
+    display: flex;
+  
+    margin-bottom: 20px;
+    margin-left: 5px;
+    margin-right: 5px;
+    border: solid 1px #b8bdc088;
+  
+    & > span {
+      margin-right: 10px;
+      padding-top: 5px;
+      padding-bottom: 5px;
+      height: 30px;
+      color: rgb(245, 245, 245);
+      font-size: 14px;
+    }
+  
+    & > span:first-child {
+      width: 100px;
+      background-color: #b8bdc088;
+      text-align: center;
+    }
+  }
+  </style>
+  

+ 29 - 0
src/views/iot/board/components/layout.vue

@@ -0,0 +1,29 @@
+<template>
+    <div :class="className+ ' iot_board_layout'">
+        <img class="t_l_line" src="../img/left_line.png" alt="">
+        <slot></slot>
+        <img class="t_r_line" src="../img/right_line.png" alt="">
+    </div>
+</template>
+<script>
+    export default {
+        name: 'iot_board_layout',
+        props:["className"]
+    }
+</script>
+<style scoped>
+.iot_board_layout{
+    padding:18px;
+    position:relative;
+}
+.t_l_line {
+    position: absolute;
+    top: 18px;
+    left: 18px;
+}
+.t_r_line {
+    position: absolute;
+    bottom: 18px;
+    right: 18px;
+}
+</style>

+ 528 - 0
src/views/iot/board/components/onlineAndHealth.vue

@@ -0,0 +1,528 @@
+<template>
+    <div class="component_box" style="display: flex;" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
+        <div ref="chart" style="width: 50%; height: 100%; "></div>
+        <div class="health">
+            <header class="header">
+                <span>网点设备健康度检查</span>
+                <!-- <h3><span>网点数:100</span></h3> -->
+                <!-- <img src="img/end.png"></img> -->
+                <!-- <span>已检查:90</span> -->
+            </header>
+            <main class="banklet_main">
+                <!-- <img src="img/map.png" alt=""> -->
+                <div class="item_box">
+                    <span>网点数</span>
+                    <div>
+                        <i></i>
+                        <h2>{{ healthSummary.total }}</h2>
+                    </div>
+                </div>
+                <div class="item_box">
+                    <span>已检</span>
+
+                    <div>
+                        <i></i>
+                        <h2>{{ healthSummary.checkedCount }}</h2>
+                    </div>
+                </div>
+                <div class="item_box">
+                    <span>90分以上</span>
+                    <div>
+                        <i></i>
+                        <h2>{{ healthSummary.over90Count }}</h2>
+                    </div>
+                </div>
+                <div class="item_box">
+                    <span>90及以下</span>
+                    <div>
+                        <i></i>
+                        <h2>{{ healthSummary.notover90Count }}</h2>
+                    </div>
+                </div>
+            </main>
+
+            <header class="t_b_h_1">
+                <span>网点健康度检查TOP3</span>
+            </header>
+            <main class="t_b_m_1" style="top:70%">
+                <div v-for="(item, index) in healthRanking" :key="index">
+                    <i>
+                        <t>{{ index + 1 }}</t>
+                    </i> {{ item.orgName }} {{ parseFloat(item.score).toFixed(2) }}分
+                </div>
+            </main>
+        </div>
+    </div>
+</template>
+<script>
+import { deviceOnline, deviceHealth } from "@/api/iot/board";
+
+export default {
+    props: {
+        orgId: {
+            type: String,
+            isRequired: true,
+        },
+    },
+    data() {
+        return {
+            chartData: {
+                total: [],
+                onLineCount: [],
+                name: [],
+            },
+            healthSummary: {
+                total: 0,
+                checkedCount: 0,
+                over90Count: 0,
+                notover90Count: 0,
+            },
+            healthRanking: [],
+            isMouseOver: false
+        };
+    },
+
+    components: {},
+
+    computed: {},
+
+    watch: {
+        orgId: {
+            deep: true,
+            handler(val) {
+                this.resetTimer();
+                this.getData();
+            },
+        },
+        chartData: {
+            deep: true,
+            handler() {
+                this.initMap();
+            },
+        },
+    },
+
+    created() {
+        this.refreshTime = 1 * 10 * 1000;
+        this.isMouseOver = false;
+    },
+
+    async mounted() {
+        window.addEventListener("resize", this.windowResize);
+    },
+    beforeDestroy() {
+        this.timer && clearInterval(this.timer);
+        this.timer = null;
+
+        window.removeEventListener("resize", this.windowResize);
+    },
+
+    methods: {
+        handleMouseEnter() {
+            this.isMouseOver = true;
+        },
+        handleMouseLeave() {
+            this.isMouseOver = false;
+        },
+        async getData() {
+            deviceOnline(this.orgId).then(r => {
+                let data = r.data;
+                let chartData = {
+                    total: [],
+                    onLineCount: [],
+                    name: [],
+                };
+
+                for (let item of data) {
+                    chartData.total.push(item.deviceCount);
+                    chartData.onLineCount.push(item.completedCount);
+                    // chartData.rate.push((item.completedRate * 100).toFixed(2));
+                    chartData.name.push(item.orgName);
+                }
+                this.chartData = chartData;
+            });
+
+            deviceHealth(this.orgId).then(r => {
+                this.healthSummary = r.data.healthSummary;
+                this.healthRanking = r.data.healthRanking
+            })
+        },
+
+        windowResize() {
+            this.myChart && this.myChart.resize();
+        },
+        initMap() {
+            let c = this.$refs["chart"];
+
+            // 基于准备好的dom,初始化echarts实例
+            this.myChart = echarts.init(
+                c
+                // document.getElementById("commAlarmEvent_Chart")
+            );
+            // var data = [70, 34, 60, 78, 69];
+            // var titlename = [
+            //     "监控主机",
+            //     "报警主机",
+            //     "动环主机",
+            //     "对讲主机",
+            //     "门禁主机",
+            // ];
+            // var valdata = [702, 406, 664, 793, 505];
+            var myColor = ["#1089E7", "#F57474", "#56D0E3", "#F8B448"];
+            option = {
+                title: {
+                    text: "设备在线率",
+                    x: "center",
+                    textStyle: {
+                        color: "#FFF",
+                    },
+                    left: "6%",
+                    top: "10%",
+                },
+                //图标位置
+                grid: {
+                    top: "20%",
+                    left: "32%",
+                },
+                xAxis: {
+                    show: false,
+                },
+                yAxis: [
+                    {
+                        show: true,
+                        data: this.chartData.name,
+                        inverse: true,
+                        axisLine: {
+                            show: false,
+                        },
+                        splitLine: {
+                            show: false,
+                        },
+                        axisTick: {
+                            show: false,
+                        },
+                        axisLabel: {
+                            color: "#fff",
+                            formatter: (value, index) => {
+                                return [`{lg|${index + 1}}  ` + "{title|" + value + "} "].join(
+                                    "\n"
+                                );
+                            },
+                            rich: {
+                                lg: {
+                                    backgroundColor: "#339911",
+                                    color: "#fff",
+                                    borderRadius: 15,
+                                    // padding: 5,
+                                    align: "center",
+                                    width: 15,
+                                    height: 15,
+                                },
+                            },
+                        },
+                    },
+                    {
+                        show: true,
+                        inverse: true,
+                        data: this.chartData.total,
+                        axisLabel: {
+                            textStyle: {
+                                fontSize: 12,
+                                color: "#fff",
+                            },
+                        },
+                        axisLine: {
+                            show: false,
+                        },
+                        splitLine: {
+                            show: false,
+                        },
+                        axisTick: {
+                            show: false,
+                        },
+                    },
+                ],
+                series: [
+                    {
+                        name: "条",
+                        type: "bar",
+                        yAxisIndex: 0,
+                        data: this.chartData.onLineCount,
+                        barWidth: 10,
+                        itemStyle: {
+                            normal: {
+                                barBorderRadius: 20,
+                                color: function (params) {
+                                    var num = myColor.length;
+                                    return myColor[params.dataIndex % num];
+                                },
+                            },
+                        },
+                        label: {
+                            normal: {
+                                show: true,
+                                position: "inside",
+                                formatter: "{c}%",
+                            },
+                        },
+                    },
+                    {
+                        name: "框",
+                        type: "bar",
+                        yAxisIndex: 1,
+                        barGap: "-100%",
+                        data: [100, 100, 100, 100, 100],
+                        barWidth: 15,
+                        itemStyle: {
+                            normal: {
+                                color: "none",
+                                borderColor: "#00c1de",
+                                borderWidth: 3,
+                                barBorderRadius: 15,
+                            },
+                        },
+                    },
+                ],
+            };
+            // 使用刚指定的配置项和数据显示图表。
+            this.myChart.setOption(option);
+        },
+
+        resetTimer() {
+            this.timer && clearInterval(this.timer);
+            this.timer = setInterval(() => {
+                if (this.isMouseOver) {
+                    return;
+                }
+                this.getData();
+            }, this.refreshTime);
+        },
+    },
+};
+</script>
+<style scoped src="./../css/index.css"></style>
+<style lang="scss" scoped>
+.health {
+    width: 50%;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    padding: 0 3%;
+
+    ::v-deep .header {
+        color: #fff;
+        width: 100%;
+        height: 12%;
+        font-size: 20px;
+    }
+
+    ::v-deep .banklet_main {
+        height: 40%;
+        width: 100%;
+    }
+
+    ::v-deep .item_box {
+        border: 1px dotted #f0ff00;
+        border-radius: 5px;
+        margin-top: 5%;
+        height: 45%;
+        width: 45%;
+        float: left;
+        display: flex;
+        flex-direction: column;
+        font-size: 14px;
+    }
+
+
+    ::v-deep .item_box:nth-child(even) {
+        margin-left: 10%;
+    }
+
+    ::v-deep .item_box>span:first-child {
+        line-height: 20px;
+    }
+
+    ::v-deep .item_box>div:last-child {
+        // display: block;
+        width: 100%;
+        height: calc(100% - 20px);
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        position: relative;
+    }
+
+    ::v-deep .item_box>div:last-child>i {
+        width: 16px;
+        height: 16px;
+        display: inline-block;
+        position: absolute;
+        left: 20%;
+    }
+
+    ::v-deep .item_box:first-child>div:last-child>i {
+        background: url("../img/t.png") no-repeat;
+        background-size: 100% 100%;
+    }
+
+    ::v-deep .item_box:nth-child(2)>div:last-child>i {
+        background: url("../img/s.png") no-repeat;
+        background-size: 100% 100%;
+    }
+
+    ::v-deep .item_box:nth-child(3)>div:last-child>i {
+        background: url("../img/j.png") no-repeat;
+        background-size: 100% 100%;
+    }
+
+    ::v-deep .item_box:nth-child(4)>div:last-child>i {
+        background: url("../img/g.png") no-repeat;
+        background-size: 100% 100%;
+    }
+}
+
+.t_b_m img {
+    position: absolute;
+    left: 52%;
+    top: 22%;
+    border-top: 1px dotted #f0ff00;
+    padding: 0 0.18rem;
+    padding-top: 20px;
+    width: 3.19rem;
+    height: 1.67rem;
+}
+
+.t_b_h_1 {
+    position: absolute;
+    font-size: 0.16rem;
+    left: 54%;
+    width: 50%;
+    height: 2.1rem;
+    top: 60%;
+}
+
+.t_b_h_1 span {
+    position: absolute;
+    color: #fff;
+    top: 10%;
+    font-size: 20px;
+}
+
+.t_b_h_1 img {
+    position: absolute;
+    width: 0.53rem;
+    height: 0.53rem;
+    top: 6%;
+    left: 24%;
+}
+
+.t_b_h_1 h3 {
+    font-size: 0.36rem;
+    color: #f0ff00;
+    position: absolute;
+    left: 55%;
+    top: 8%;
+    width: 1rem;
+}
+
+.t_b_h_1 h3 span {
+    font-size: 0.2rem;
+    position: absolute;
+    left: 50%;
+    top: 28%;
+    color: #0072ff;
+}
+
+.t_b_m_1 {
+    position: absolute;
+    font-size: 0.16rem;
+    left: 54%;
+    width: 50%;
+    height: 2.1rem;
+    top: 70%;
+}
+
+.t_b_m_1 div {
+    margin-top: 15px;
+    height: 20px;
+    color: white;
+    font-size: 14px;
+}
+
+.t_b_m_1 div>i {
+    background-color: #339911;
+    font-family: 仿宋体;
+    width: 19px;
+    display: inline-block;
+    border-radius: 9.5px;
+}
+
+.t_b_m_1 div>i>t {
+    left: 3px;
+    position: relative;
+}
+
+.t_b_box,
+.t_b_box1,
+.t_b_box2,
+.t_b_box3 {
+    width: 35%;
+    height: 10%;
+
+    position: absolute;
+}
+
+.t_b_box {
+    top: 25%;
+    left: 56%;
+}
+
+.t_b_box span,
+.t_b_box1 span,
+.t_b_box2 span,
+.t_b_box3 span {
+    font-size: 0.14rem;
+    color: #fff;
+    position: absolute;
+    left: 10%;
+}
+
+.t_b_box i,
+.t_b_box1 i,
+.t_b_box2 i,
+.t_b_box3 i {
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    top: 50%;
+    left: 15%;
+}
+
+
+
+.t_b_box h2,
+.t_b_box1 h2,
+.t_b_box2 h2,
+.t_b_box3 h2 {
+    font-size: 0.18rem;
+    color: #fff;
+    position: absolute;
+    top: 30%;
+    left: 40%;
+}
+
+.t_b_box1 {
+    top: 25%;
+    left: 78%;
+}
+
+.t_b_box2 {
+    top: 45%;
+    left: 56%;
+}
+
+.t_b_box3 {
+    top: 45%;
+    left: 78%;
+}
+</style>

+ 114 - 0
src/views/iot/board/components/protection.vue

@@ -0,0 +1,114 @@
+<template>
+    <div class="component_box">
+        <ul class="t_nav">
+            <li>
+                <span>报警控制器</span>
+                <h1>{{ info.total }}</h1>
+                <i></i>
+            </li>
+            <li>
+                <span>布防数</span>
+                <h1>{{ info.on }}</h1>
+                <i></i>
+            </li>
+            <li>
+                <span>撤防数</span>
+                <h1>{{ info.off }}</h1>
+            </li>
+        </ul>
+    </div>
+</template>
+<script>
+import { protectionCount } from '@/api/iot/board'
+export default {
+    data() {
+        return {
+            info: {
+                total: 0,
+                on: 0,
+                off: 0
+            },
+        }
+    },
+    props: {
+        orgId: {
+            type: String,
+            isRequired: true,
+        }
+    },
+    watch: {
+        orgId: {
+            deep: true,
+            handler(val) {
+                this.resetTimer();
+                this.getData();
+            },
+        }
+    },
+    created() {
+        this.refreshTime = 1 * 10 * 1000;
+        this.isMouseOver = false;
+    },
+    methods: {
+        getData() {
+            protectionCount(this.orgId).then(r => {
+                this.info = r.data;
+            })
+        },
+        beforeDestroy() {
+            this.timer && clearInterval(this.timer);
+            this.timer = null;
+        },
+        resetTimer() {
+            this.timer && clearInterval(this.timer);
+            this.timer = setInterval(() => {
+                this.getData();
+            }, this.refreshTime);
+        },
+    }
+}
+</script>
+<style scoped src="./../css/index.css"></style>
+<style lang="css" scoped>
+.t_nav {
+    width: 100%;
+    height: 100%;
+}
+
+.t_nav li {
+    display: inline-block;
+    width: 30%;
+    height: 100%;
+    text-align: center;
+    position: relative;
+}
+
+.t_nav li span {
+    font-size: 20px;
+    color: #1aa1fd;
+    position: absolute;
+    left: 0;
+    right: 0;
+    margin: auto;
+    top: 20%;
+}
+
+.t_nav li h1 {
+    font-size: 20px;
+    color: #fff;
+    position: absolute;
+    left: 0;
+    right: 0;
+    margin: auto;
+    top: 70%;
+}
+
+.t_nav li i {
+    width: 1px;
+    height: 100%;
+    position: absolute;
+    right: 1px;
+    background: url("../img/sper.png") no-repeat;
+    background-size: 100% 100%;
+}
+</style>

+ 112 - 0
src/views/iot/board/css/index.css

@@ -0,0 +1,112 @@
+.body {
+    background-image: url("../img/true.png");
+    background-position: 100%;
+    background-color: rgba(8, 8, 8);
+    color: white;
+    /* text-shadow: 0 0 5px #252525; */
+    font-size: 18px;
+    width: 100%;
+    height: calc(100vh - 100px);
+    overflow: hidden;
+}
+
+.t_header {
+    width: 100%;
+    height: 80px;
+    background: url("../img/linx.png") no-repeat;
+    background-size: 100% 100%;
+}
+
+.t_header_title{
+    width: 400px;
+    height: 100%;
+    margin-left:80px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+}
+
+.t_header_title span {
+    color: #fff;
+    font-size: 40px;
+}
+.t_main {
+    width: 100%;
+    height: calc(100% - 80px);
+    margin: 0 auto;
+    margin-top: 0px;
+    margin-bottom: 0;
+}
+.t_main>div{
+    width: 100%;
+    height: 50%;
+    display: flex;
+    border:solid 1px #fff;
+}
+
+.t_left_box {
+    width: 18%;
+    height: 100%;
+    /* display: inline-block; */
+    /* text-align: center; */
+}
+.t_l_line {
+    position: relative;
+    top: 0;
+    left: 0;
+}
+.t_r_line {
+    position: relative;
+    bottom: 0;
+    right: 0;
+}
+.t_center_box {
+    width: 36.5%;
+    height: 100%;
+}
+
+.t_top_box {
+    width: 100%;
+    height: 110px;
+    /* height: 1.13rem; */
+    overflow: hidden;
+    /* margin-bottom: 0.2rem; */
+}
+.t_bottom_box {
+    width: 100%;
+
+    height: calc(100% - 110px);
+    overflow: hidden;
+    position: relative;
+}
+.t_right_box {
+    display: inline-block;
+    width: 45.5%;
+    height: 100%;
+    position: relative;
+}
+.b_left_box {
+    display: inline-block;
+    width: 31.6%;
+    height:100%;
+    position: relative;
+}
+.b_center_box {
+    display: inline-block;
+    width: 22.9%;
+    height: 100%;
+    position: relative;
+}
+.b_right_box {
+    display: inline-block;
+    width: 45.5%;
+    height:100%;
+    position: relative;
+}
+
+.component_box {
+    width: 100%;
+    height: calc(100% - 10px);
+}
+

BIN
src/views/iot/board/img/consumption.png


BIN
src/views/iot/board/img/end.png


BIN
src/views/iot/board/img/environment.png


BIN
src/views/iot/board/img/fire.png


BIN
src/views/iot/board/img/g.png


BIN
src/views/iot/board/img/indent.png


BIN
src/views/iot/board/img/j.png


BIN
src/views/iot/board/img/left_line.png


BIN
src/views/iot/board/img/linx.png


BIN
src/views/iot/board/img/map.png


BIN
src/views/iot/board/img/monitor.png


BIN
src/views/iot/board/img/org.png


BIN
src/views/iot/board/img/right_line.png


BIN
src/views/iot/board/img/s.png


BIN
src/views/iot/board/img/sper.png


BIN
src/views/iot/board/img/t.png


BIN
src/views/iot/board/img/true.png


BIN
src/views/iot/board/img/vip.png


+ 63 - 0
src/views/iot/board/index.vue

@@ -0,0 +1,63 @@
+<template>
+    <div class="body">
+        <header class="t_header">
+            <div class="t_header_title">
+                <span>物联监测看板</span>
+            </div>
+        </header>
+        <main class="t_main">
+            <div>
+                <layout :className="'t_left_box'">
+                    <deviceCount :orgId="orgId"></deviceCount>
+                </layout>
+                <div class="t_center_box">
+                    <layout :className="'t_top_box'" style="padding-bottom: 0px;">
+                        <protection />
+                    </layout>
+                    <layout :className="'t_bottom_box'" style="padding-top:0px">
+                        <device-map />
+                    </layout>
+                </div>
+                <layout :className="'t_right_box'">
+                    <online-and-health></online-and-health>
+                </layout>
+            </div>
+            <div>
+                <layout :className="'b_left_box'">
+                    <alarm-trend />
+                </layout>
+                <layout :className="'b_center_box'">
+                    <alarm-rate></alarm-rate>
+                </layout>
+                <layout :className="'b_right_box'">
+                    <alarm-list></alarm-list>
+                </layout>
+            </div>
+        </main>
+    </div>
+</template>
+<script>
+import { mapGetters } from "vuex";
+import layout from './components/layout.vue';
+import deviceCount from './components/deviceCount.vue';
+import protection from './components/protection.vue';
+import deviceMap from './components/deviceMap.vue';
+import onlineAndHealth from './components/onlineAndHealth.vue';
+import alarmTrend from './components/alarmTrend.vue';
+import alarmRate from './components/alarmRate.vue';
+import alarmList from './components/alarmList.vue';
+
+export default {
+    name: "iot_board",
+    components: { layout, deviceCount, protection, deviceMap, onlineAndHealth, alarmTrend, alarmRate, alarmList },
+    computed: {
+        ...mapGetters(["orgId", "depTree", "orgName",]),
+    },
+    data() {
+        return {
+            orgId: this.orgId,
+        }
+    }
+}
+</script>
+<style scoped src="./css/index.css"></style>