From 6acd20f3f37e988488b681a1a394b37a32f3ffe6 Mon Sep 17 00:00:00 2001
From: web <candymxq888@outlook.com>
Date: 星期一, 07 四月 2025 16:17:41 +0800
Subject: [PATCH] feat:添加大屏页面

---
 src/views/screen/home/index.vue |  739 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 614 insertions(+), 125 deletions(-)

diff --git a/src/views/screen/home/index.vue b/src/views/screen/home/index.vue
index 5d8d975..8e19648 100644
--- a/src/views/screen/home/index.vue
+++ b/src/views/screen/home/index.vue
@@ -1,146 +1,635 @@
 <template>
-    <div class="home">
-        <div class="home-bg"></div>
-        <div class="home-c">
-            <div class="point">
-                <div class="point-address"></div>
-                <div class="point-message">
-                    <div class="video-box">
-                        <el-icon><VideoPlay /></el-icon>
-                    </div>
-                    <div class="info-box">
-                        <div class="info-t">水电站流量监测点</div>
-                        <div class="info-sw">水位:<span>500</span>m</div>
-                        <div class="info-ls">流速:<span>15</span>m/s</div>
-                        <div class="info-ssls">瞬时流速:<span>150</span>m/s</div>
-                        <div class="info-ljll">
-                            累计流量:
-                            <el-select
-                                v-model="selectll"
-                                class="m-2"
-                                placeholder="Select"
-                                size="small"
-                                style="width: 240px"
-                            >
-                                <el-option
-                                    v-for="(item, idx) in liuliangOptions"
-                                    :key="idx"
-                                    :label="item.label"
-                                    :value="idx"
-                                />
-                            </el-select>
-                            <span>{{ liuliangOptions[selectll].value }}</span>m/s
+    <div class="container">
+        <div class="left">
+            <div class="liuliang">
+                <div class="liuliang-title">流量统计</div>
+                <div class="liuliang-c">流量</div>
+            </div>
+            <div class="gongdian">
+                <div class="gongdian-title">流量统计</div>
+                <div class="gongdian-c">流量</div>
+            </div>
+        </div>
+        <div class="center" >
+            <!-- 地图窗口 -->
+            <div class="map">
+                <div class="point-box" v-if="tucengVal === 0">
+                    <div class="apoint" v-for="(item, index) in pointList" :key="index"
+                         :style="`left: ${item?.left}%; top: ${item?.top}%`" @click="clickMsgFun(index)">
+                        <img src="../../../assets/images_lc/a-point.png" alt="" />
+                        <div class="message" v-show="showMsg === index">
+                            <div class="message-item">
+                                <span class="name">泵房名称:</span>
+                                <span class="val">{{item.name}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">水浸状态:</span>
+                                <span class="val-status">{{item.shuijin}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">运行时长:</span>
+                                <span class="val-status">{{item.longtime}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">瞬时流量:</span>
+                                <span class="val-status">{{item.ssll}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">累计流量:</span>
+                                <span class="val-status">{{item.ljll}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">流速:</span>
+                                <span class="val-status">{{item.ls}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">启泵次数:</span>
+                                <span class="val-status">{{item.qdnumber}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">1号水池水位:</span>
+                                <span class="val-status">{{item.oneWater}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">2号水池水位:</span>
+                                <span class="val-status">{{item.twoWater}}</span>
+                            </div>
+                            <div class="message-item">
+                                <span class="name">其他详细信息:</span>
+                                <router-link class="val" to="/screen/pumpInfo">点击跳转</router-link>
+                            </div>
                         </div>
                     </div>
+                </div>
+            </div>
+        </div>
+        <div class="right">
+            <!-- 实时监控 -->
+            <div class="jiankong">
+                <div class="jiankong-t">实时监控</div>
+                <div class="jiankong-c">
+                    <div class="switch">
+                        <div class="switch-l">泵房监控</div>
+                        <div class="switch-r">
+                            <div class="more" :class="{active: selectType==='two'}" @click="changeType('two')">多屏模式 </div>
+                            <div class="single" :class="{active: selectType==='single'}" @click="changeType('single')">单屏模式</div>
+                        </div>
+                    </div>
+                    <div class="video-box">
+                        <div class="two" v-if="selectType==='two'">
+                            <div class="list" v-for="(item, index) in showList" :key="index">
+                                <div class="item" v-if="item?.deviceId">
+                                    <VideoPlayer :item="item" />
+                                </div>
+                                <div v-else class="item"></div>
+                            </div>
+                        </div>
+                        <div class="single" v-else>
+                            <div class="item" v-if="showList[0]?.deviceId">
+                                <VideoPlayer :item="showList[0]" />
+                            </div>
+                            <div v-else class="item"></div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <!-- 报警记录 -->
+            <div class="warnRecord">
+                <div class="warnRecord-title">报警记录</div>
+                <div class="warnRecord-info">
+                    <div class="into-t">报警信息</div>
+                    <div class="info-list">
+                        <div class="item" v-for="(item, index) in warnList" :key="index">
+                            <el-tooltip
+                                effect="dark"
+                                :content="item.pointName"
+                                placement="top"
+                            >
+                                {{item.pointName}}
+                            </el-tooltip>
+                            <el-tooltip
+                                effect="dark"
+                                :content="item.facilityName"
+                                placement="top"
+                            >
+                                {{item.facilityName}}
+                            </el-tooltip>
+                            <el-tooltip
+                                effect="dark"
+                                :content="item.description"
+                                placement="top"
+                            >
+                                {{item.description}}
+                            </el-tooltip>
+                        </div>
+                    </div>
+                </div>
+                <div class="warnRecord-datashow">
+                    <div ref="warningRef" class="warning" />
                 </div>
             </div>
         </div>
     </div>
 </template>
 
-
-<script setup>
-
-import {ref} from "vue";
-
-const selectll = ref(0)
-
-const liuliangOptions = [
-    { label: '总计流量', value: 500 },
-    { label: '日累计流量', value: 1000 },
-    { label: '周累计流量', value: 10000 },
-    { label: '月累计流量', value: 300000 },
-    { label: '年累计流量', value: 3600000 },
-]
-
-</script>
+<script setup lang="ts">
+import { use } from "echarts/core";
+import * as echarts from 'echarts/core';
+import {GridComponent, TooltipComponent, LegendComponent} from "echarts/components";
+import { LineChart, PieChart } from "echarts/charts";
+import { UniversalTransition, LabelLayout } from "echarts/features";
+import { CanvasRenderer } from "echarts/renderers";
+import {onMounted, reactive, ref} from "vue";
+import VideoPlayer from "@/components/VideoPlayer/VideoPlayer.vue";
 
 
-<style scoped lang="scss">
-.home{
-    height: 100%;
-    .home-bg{
-        position: absolute;
-        left: 0;
-        top: 0;
-        width: 100%;
-        height: 100%;
-        background: url("@/assets/images/map-bg.png") no-repeat;
-        background-size: 100% 100%;
-        z-index: 11;
+use([
+    GridComponent,
+    LineChart,
+    CanvasRenderer,
+    UniversalTransition,
+    TooltipComponent,
+    LegendComponent,
+    PieChart,
+    CanvasRenderer,
+    LabelLayout,
+]);
+
+const openStatus = reactive({
+    bengfang: false,
+    shuixiang: false,
+    jieguan: false
+})
+
+const mapSize = ref(90); // 初始化地图大小为100
+const gonghaoRef = ref();
+const liuliangRef = ref();
+const warningRef = ref();
+let gonghaoCharts = null;
+let liuliangCharts = null;
+let warningCharts = null;
+
+const tucengVal = ref(0);
+const selectType = ref('single')
+const videoList = ref([])
+const showList = ref([])
+const warnList = ref([])
+const showMsg = ref()
+const pointList = ref([
+    { name: '碧桂园', shuijin: '正常', longtime: '1280天13小时59分', ssll: '+10㎡/s', ljll: '㎡', ls: '10m/s', qdnumber: '10次', oneWater: '2.26m', twoWater: '4.26m', left: 40, top: 22 },
+    { name: '龙湖公馆', shuijin: '正常', longtime: '1280天13小时59分', ssll: '+10㎡/s', ljll: '㎡', ls: '10m/s', qdnumber: '10次', oneWater: '2.26m', twoWater: '4.26m', left: 52, top: 35 },
+])
+const tongjiTable = reactive({
+    selectName: '',
+    tongjiList: [],
+    namelist: []
+})
+
+const clickMsgFun = (index: number) => {
+    showMsg.value = showMsg.value === index ? null : index;
+}
+
+// 获取定位随机值
+const getRandom = (min, max) => {
+    return Math.floor(Math.random() * (max - min) + min);
+}
+
+const setOpenStatus = (type: string) => {
+    switch (type) {
+        case "bengfang":
+            openStatus.bengfang = openStatus.bengfang ? false : true;
+            break;
+        case "shuixiang":
+            openStatus.shuixiang = openStatus.shuixiang ? false : true;
+            break;
+        case "jieguan":
+            openStatus.jieguan = openStatus.jieguan ? false : true;
+            break
     }
-    .home-c{
-        width: 100%;
-        height: 100%;
-        position: relative;
-        z-index: 20;
-        .point{
-            position: absolute;
-            left: 58%;
-            top: 30%;
-            .point-address{
-                width: 35px;
-                height: 40px;
-                background: url("@/assets/images/point.png") no-repeat;
-                background-size: 100% 100%;
-            }
-            .point-message{
-                width: 600px;
-                height: 200px;
-                background: url("@/assets/images/messageInfo-box.png") no-repeat;
-                background-size: 100% 100%;
-                position: absolute;
-                left: -600px;
-                top: -100px;
-                padding: 30px 50px 30px 30px;
-                color: #fff;
-                display: flex;
-                align-items: center;
-                gap: 20px;
-                .video-box{
-                    flex-shrink: 0;
-                    width: 200px;
-                    height: 138px;
-                    line-height: 138px;
-                    text-align: center;
-                    font-size: 38px;
-                    background: #cccb40;
+}
+
+// 图表实例
+const setGonghaoCharts = (xData, sData) => {
+    if(gonghaoRef.value) {
+        gonghaoCharts = echarts.init(gonghaoRef.value);
+        const option = {
+            grid: {
+                top: 30,
+                bottom: 40,
+                left: 40
+            },
+            xAxis: {
+                type: 'category',
+                boundaryGap: false,
+                data: xData,
+                axisLabel: {
+                    color: '#fff',
+                    fontSize: '0.5rem',
+                    rotate: 30,
+                },
+            },
+            yAxis: {
+                type: 'value',
+                axisLabel: {
+                    color: '#fff',
+                    fontSize: '0.5rem',
                 }
-                .info-box{
-                    height: 100%;
-                    display: flex;
-                    flex-direction: column;
-                    justify-content: space-between;
-                    .info-t{
-                        font-size: 20px;
-                    }
-                    .info-ljll{
-                        display: flex;
-                        align-items: center;
-                        :deep(.el-select){
-                            width: 100px !important;
-                            .el-select__wrapper{
-                                color: #fff;
-                                background: transparent;
-                                .el-select__selected-item{
-                                    color: #fff;
-                                }
-                                .el-select__suffix .el-icon{
-                                    color: #fff;
-                                }
-                                &:hover{
-                                    box-shadow: none;
-                                }
-                            }
+            },
+            tooltip: {
+                show: true
+            },
+            series: [
+                {
+                    data: sData,
+                    type: 'line',
+                    areaStyle: {}
+                }
+            ]
+        };
+        gonghaoCharts.setOption(option);
+    }
+}
+const setLiuliangCharts = (xData, sData) => {
+    if(liuliangRef.value) {
+        liuliangCharts = echarts.init(liuliangRef.value);
+        const option = {
+            grid: {
+                top: 30,
+                bottom: 40,
+                left: 40
+            },
+            xAxis: {
+                type: 'category',
+                boundaryGap: false,
+                data: xData,
+                axisLabel: {
+                    color: '#fff',
+                    fontSize: '0.5rem',
+                    rotate: 30,
+                }
+            },
+            yAxis: {
+                type: 'value',
+                axisLabel: {
+                    color: '#fff',
+                    fontSize: '0.5rem',
+                }
+            },
+            tooltip: {
+                show: true
+            },
+            series: [
+                {
+                    data: sData,
+                    type: 'line',
+                    areaStyle: {}
+                }
+            ]
+        };
+        liuliangCharts.setOption(option);
+    }
+}
+const setWarningCharts = (data) => {
+    if(warningRef.value) {
+        warningCharts = echarts.init(warningRef.value);
+        const option = {
+            tooltip: {
+                trigger: 'item'
+            },
+            series: [
+                {
+                    type: 'pie',
+                    radius: '50%',
+                    data: data,
+                    emphasis: {
+                        itemStyle: {
+                            shadowBlur: 10,
+                            shadowOffsetX: 0,
+                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                         }
                     }
-                    span{
-                        display: inline-block;
-                        padding: 0 10px;
+                }
+            ]
+        }
+        warningCharts.setOption(option);
+    }
+}
+
+// 获取功耗数据
+const getGonghaoData = () => {
+    getHomeGonghao().then(res => {
+        let xdata = [];
+        let sdata = [];
+        let newArr = res.data.length > 5 ? res.data.slice(0,5) : res.data
+        newArr.forEach((item) => {
+            xdata.push(item.pointName)
+            sdata.push(item.value)
+        })
+        setGonghaoCharts(xdata, sdata)
+    })
+}
+// 获取流量统计
+const getLiuliangData = () => {
+    getHomeLiuliang().then(res => {
+        let xdata = [];
+        let sdata = [];
+        let newArr = res.data.length > 5 ? res.data.slice(0,5) : res.data
+        newArr.forEach((item) => {
+            xdata.push(item.pointName)
+            sdata.push(item.value)
+        })
+        setLiuliangCharts(xdata, sdata)
+    })
+}
+
+// 切换播放模式
+const changeType = (type) => {
+    selectType.value = type
+    showList.value = []
+    if(type === 'two') {
+        showList.value = videoList.value.slice(0, 2).concat(Array(4 - videoList.value.length).fill(null))
+    } else {
+        showList.value = videoList.value.slice(0, 1)
+    }
+}
+
+// 获取报警数据
+const getWarning = () => {
+    getHomeWarning().then(res => {
+        warnList.value = res.data.alarmHistoryVOList
+        let data = [
+            { value: res.data.facilityCount, name: '设备启动异常' },
+            { value: res.data.waterEnterCount, name: '进水压力异常' },
+            { value: res.data.waterOutCount, name: '出口压力异常' },
+        ]
+        setWarningCharts(data)
+    })
+}
+
+// 获取统计数据
+const getTongjiData = () => {
+    getHomeTongji().then(res => {
+        tongjiTable.tongjiList = res.data.statementValueList;
+        tongjiTable.namelist = res.data.statementNameList;
+    })
+}
+
+const clearName = () => {
+    tongjiTable.selectName = ''
+}
+
+onMounted(() => {
+    // getGonghaoData()
+    // getLiuliangData()
+    // getWarning()
+    // getTongjiData()
+})
+</script>
+
+<style lang="scss" scoped>
+
+// 地图动态变化样式 不能单独抽离到scss文件中
+.container {
+    background-image: url("@/assets/images_lc/map.png");
+    // 动态获取图片大小
+    background-size: v-bind('mapSize + "%"');
+    background-repeat: no-repeat;
+    background-position: 50% 50%;
+    transition: background-size 0.3s ease;
+}
+.homeSelectName{
+    .el-radio-group{
+        flex-direction: column;
+        align-items: flex-start;
+        .el-radio{
+            font-size: 1rem;
+        }
+    }
+    .clear{
+        margin: 5px 30px 10px 20px;
+        text-align: right;
+        color: #3aa8ef;
+        font-size: 0.8rem;
+        cursor: pointer;
+    }
+}
+
+.container {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    justify-content: space-between;
+    color: white;
+    overflow: hidden;
+
+    .left {
+        width: 20%;
+        flex-shrink: 0;
+        flex-grow: 0;
+        display: flex;
+        flex-direction: column;
+        gap: 1rem;
+        .liuliang{
+            height: 45%;
+            background: url("@/assets/images_lc/realTimeMonitoring.png") no-repeat;
+            background-size: 100% 100%;
+            &-title {
+                background-image: url('@/assets/images_lc/title_font.png');
+                padding-left: 16%;
+                font-size: 1.2rem;
+            }
+        }
+        .gongdian{
+            height: 55%;
+            background: url("@/assets/images_lc/warnRecord.png") no-repeat;
+            background-size: 100% 100%;
+            &-title {
+                background-image: url('@/assets/images_lc/title_font.png');
+                padding-left: 16%;
+                font-size: 1.2rem;
+            }
+        }
+    }
+
+    .center {
+        width: 58%;
+        display: flex;
+        flex-direction: column;
+        .map {
+            height: 100%;
+            .point-box{
+                width: 100%;
+                height: 100%;
+                position: relative;
+                .apoint{
+                    position: absolute;
+                    img{
+                        width: 1.5rem;
+                        height: 3rem
+                    }
+                    .message{
+                        width: 12rem;
+                        height: 16rem;
+                        background: url("@/assets/images_lc/point-message.png") no-repeat;
+                        background-size: 100% 100%;
+                        padding: 0 0.2rem;
+                        position: absolute;
+                        right: -12rem;
+                        top: 0;
+                        z-index: 100;
+                        .message-item{
+                            font-size: 0.7rem;
+                            padding: 0.3rem 0 0.3rem 0.9rem;
+                            .name{
+                                margin-right: 0.3rem;
+                            }
+                            .val-status{
+                                color: #22E195;
+                            }
+                        }
                     }
                 }
             }
         }
     }
+
+    .right {
+        width: 20%;
+        display: flex;
+        flex-direction: column;
+        gap: 1rem;
+        .jiankong {
+            height: 40%;
+            background-image: url('@/assets/images_lc/realTimeMonitoring.png');
+            background-repeat: no-repeat;
+            background-size: 100% 100%;
+            &-t {
+                background-image: url('@/assets/images_lc/title_font.png');
+                padding-left: 16%;
+                font-size: 1.2rem;
+            }
+
+            &-c {
+                height: 90%;
+                .switch {
+                    height: 15%;
+                    display: flex;
+                    align-items: center;
+                    justify-content: space-between;
+                    padding: 0 1.5rem;
+
+                    .switch-l {
+                        font-weight: 700;
+                    }
+                    .switch-r{
+                        display: flex;
+                        gap: 1rem;
+                    }
+                    .more {
+                        width: 6rem;
+                        height: 1.5rem;
+                        line-height: 1.5rem;
+                        text-align: center;
+                        background-image: url('@/assets/images_lc/switch.png');
+                        background-size: 100% 100%;
+                        color: #cfcfcf;
+                        font-size: 0.9rem;
+                    }
+
+                    .single {
+                        width: 6rem;
+                        height: 1.5rem;
+                        line-height: 1.5rem;
+                        text-align: center;
+                        background-image: url('@/assets/images_lc/switch.png');
+                        background-size: 100% 100%;
+                        color: #cfcfcf;
+                        font-size: 0.9rem;
+                    }
+                    .active{
+                        color: #fff;
+                    }
+                }
+                .video-box{
+                    height: 85%;
+                    padding: 0 1rem;
+                    .two{
+                        width: 100%;
+                        height: 100%;
+                        display: flex;
+                        flex-wrap: wrap;
+                        justify-content: space-between;
+                        .list{
+                            width: 49%;
+                            height: 100%;
+                            .item{
+                                height: 100%;
+                                background-color: #000;
+                            }
+                        }
+                    }
+                    .single{
+                        width: 100%;
+                        height: 100%;
+                        .item{
+                            height: 95%;
+                            width: 100%;
+                            background-color: #000;
+                        }
+                    }
+                }
+            }
+        }
+
+        .warnRecord {
+            height: 60%;
+            background-image: url('@/assets/images_lc/warnRecord.png');
+            background-repeat: no-repeat;
+            background-size: 100% 100%;
+            display: flex;
+            flex-direction: column;
+            .warnRecord-title {
+                background-image: url('@/assets/images_lc/title_font.png');
+                padding-left: 16%;
+                font-size: 1.3rem;
+            }
+            .warnRecord-info {
+                width: 90%;
+                height: 50%;
+                margin: auto;
+                overflow-y: scroll;
+                &::-webkit-scrollbar{
+                    display: none;
+                }
+                .into-t{
+                    height: 15%;
+                    font-size: 1.2rem;
+                    padding-top: 0.3rem;
+                }
+                .info-list{
+                    height: 85%;
+                    .item{
+                        padding: 0.5rem 0;
+                        display: flex;
+                        justify-content: space-between;
+                        font-size: 0.8rem;
+                        :deep(.el-only-child__content){
+                            width: 30%;
+                            overflow: hidden;
+                            text-overflow: ellipsis;
+                            white-space: nowrap;
+                        }
+                    }
+                }
+            }
+            .warnRecord-datashow {
+                height: 50%;
+                .warning {
+                    width: 100%;
+                    height: 100%;
+                }
+            }
+        }
+    }
 }
-</style>
\ No newline at end of file
+</style>

--
Gitblit v1.9.3