he wei
2025-05-08 84ff051d5c6bbf10e71f6f8d1d57740c26619d9e
src/views/home/home-szdt.vue
@@ -1,162 +1,94 @@
<template>
  <div class="p-main">
    <div class="row">
      <card>
        <big-screen-card title="告警统计">
          <template #tools>
            <el-radio-group size="mini" v-model="alarmType" @input="alarmTypeChangede">
              <el-radio-button :label="0">告警类型</el-radio-button>
              <el-radio-button :label="1">告警等级</el-radio-button>
            </el-radio-group>
          </template>
          <div class="chart-wrap">
            <div class="inner">
              <bar-chart-alarm v-if="alarmType == 1" ref="chart_alarm"></bar-chart-alarm>
              <pie-chart ref="alarmPieChart" :values="alarms" v-else></pie-chart>
            </div>
          </div>
        </big-screen-card>
      </card>
    </div>
    <div class="row">
      <card>
        <big-screen-card title="设备工作状态">
          <div class="dev-wrap">
            <circle-box class="item" :type="0" :value="workState[0]" @click.native="goDevWorkState(4)"></circle-box>
            <circle-box ref="devWorkState1" class="item" :type="1" :value="workState[1]"
              @click.native="goDevWorkState(2)"></circle-box>
            <circle-box ref="devWorkState2" class="item" :type="2" :value="workState[2]"
              @click.native="goDevWorkState(0)"></circle-box>
            <circle-box ref="devWorkState3" class="item" :type="3" :value="workState[3]"
              @click.native="goDevAlarm"></circle-box>
          </div>
        </big-screen-card>
      </card>
    </div>
    <div class="row">
      <card>
        <big-screen-card title="整组容量">
          <div class="mon-box-container">
            <div class="mon-info-box">
              <div class="mon-info-title">大于95%比例:</div>
              <div class="mon-info-value">{{ cap.level0 }}</div>
            </div>
            <div class="mon-info-box box2">
              <div class="mon-info-title">95%~85%比例:</div>
              <div class="mon-info-value">{{ cap.level1 }}</div>
            </div>
            <div class="mon-info-box box3">
              <div class="mon-info-title">85%~60%比例:</div>
              <div class="mon-info-value">{{ cap.level2 }}</div>
            </div>
          </div>
          <div class="mon-box-container mgt16">
            <div class="mon-info-box box2">
              <div class="mon-info-title">60%~50%比例:</div>
              <div class="mon-info-value">{{ cap.level3 }}</div>
            </div>
            <div class="mon-info-box box3">
              <div class="mon-info-title">小于50%:</div>
              <div class="mon-info-value">{{ cap.level4 }}</div>
            </div>
          </div>
        </big-screen-card>
      </card>
    <div class="p-side p-left">
      <div class="row">
          <home-card title="统计电池告警">
            <template #tools>
              <el-select v-model="lineSelect0" size="mini" @change="testLevelChange(0)">
                <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option>
              </el-select>
            </template>
            <!-- <div class="chart-wrap">
              <div class="inner">
                <bar-chart-alarm v-if="alarmType == 1" ref="chart_alarm"></bar-chart-alarm>
                <pie-chart ref="alarmPieChart" :values="alarms" v-else></pie-chart>
              </div>
            </div> -->
            <bar3d ref="bar3d0"></bar3d>
          </home-card>
      </div>
      <div class="row">
          <home-card title="故障类型统计">
            <template #tools>
              <el-select v-model="lineSelect1" size="mini" @change="testLevelChange(1)">
                <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option>
              </el-select>
            </template>
            <pie-chart ref="pie"></pie-chart>
          </home-card>
      </div>
    </div>
    <div class="wraper">
      <div class="row row1">
        <card :miniCor="true">
          <div class="info">
            <div class="item" @click="goStations">
              <div class="name">站点</div>
              <div class="name">机房个数</div>
              <div class="num">
                <led-num color="#f00" :num="stationNum"></led-num>
                {{ stationNum }}
              </div>
            </div>
            <div class="item">
              <div class="name">设备</div>
              <div class="name">设备个数</div>
              <div class="num">
                <led-num color="#f00" :num="devCount"></led-num>
                {{ devCount }}
              </div>
            </div>
            <div class="item" @click="goBatt">
              <div class="name">电池节数</div>
              <div class="num bits5">
                <led-num color="#f00" :bits='5' :num="battGroupMonCount"></led-num>
              </div>
            </div>
            <div class="item" @click="goBatt">
              <div class="name">电池组</div>
              <div class="name">电池组个数</div>
              <div class="num">
                <led-num color="#f00" :num="battGroupCount"></led-num>
                {{ battGroupCount }}
              </div>
            </div>
          </div>
        </card>
      </div>
      <div class="row row2">
        <card :inside="false">
          <div class="flex-map-contain">
            <div class="inner">
              <map-chart ref="map" subway="suzhou">
                <map-mark-list slot="tools"></map-mark-list>
              </map-chart>
              <svg-subway :lines="lineList.filter(v=> v != 0)" :status="statusList" @legend-change="legendChange"></svg-subway>
            </div>
          </div>
        </card>
      </div>
    </div>
    <div class="row alarm">
      <card>
        <big-screen-card title="实时告警信息">
          <div class="scroller-wrap">
            <div class="inner">
              <el-table ref="elTbl" stripe size="small" :data="tbl.data" height="100%" :row-class-name="
                    (row) =>'cursor-pointer'
                  " @row-dblclick="goRealTime" class="tableCent">
                <el-table-column v-for="header in tbl.headers" :key="header.prop" :prop="header.prop"
                  :label="header.label" :width="header.width" :min-width="header.minWidth" :sortable="header.sortable"
                  align="center"></el-table-column>
                <el-table-column label="操作" width="110" align="center">
                  <template slot-scope="scope">
                    <el-button type="primary" size="mini" @click="goRealTime(scope.row)">实时</el-button>
                  </template>
                </el-table-column>
              </el-table>
              <!-- <div class="empty-msg" v-else>最近一周无记录</div> -->
    <div class="p-side p-right">
      <div class="row alarm">
          <home-card title="电池状态">
            <template #tools>
              <el-select v-model="lineSelect2" size="mini" @change="testLevelChange(2)">
                <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option>
              </el-select>
            </template>
            <bar3d ref="bar3d1"></bar3d>
          </home-card>
      </div>
      <div class="row test-info">
          <home-card title="实时电池告警滚动">
            <template #tools>
              <el-select v-model="lineSelect3" size="mini" @change="testLevelChange(3)">
                <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item == 0 ? '全部' : item + '号线'" :value="item"></el-option>
              </el-select>
            </template>
            <div class="scroller-wraper">
              <marquee-top :sendVal="newItems" v-if="showMarquee"></marquee-top>
              <div class="no-warning-msg" v-else>最近24小时内无告警</div>
            </div>
          </div>
        </big-screen-card>
      </card>
    </div>
    <div class="row test-info">
      <card>
        <big-screen-card title="线路告警">
          <template #tools>
            <!-- :disabled="!chartData.test.length" -->
            <!-- <el-radio-group
                size="mini"
                @input="testLevelChange"
                v-model="testLevel"
              >
                <el-radio-button :label="0">总线路</el-radio-button>
                <el-radio-button :label="1">1号线</el-radio-button>
                <el-radio-button :label="2">2号线</el-radio-button>
              </el-radio-group> -->
            <el-select v-model="testLevel" size="small" @change="testLevelChange">
              <el-option v-for="(item, idx) in lineList" :key="'select_' + idx" :label="item" :value="item"></el-option>
            </el-select>
          </template>
          <bar3d ref="bar3d"></bar3d>
        </big-screen-card>
      </card>
          </home-card>
      </div>
    </div>
  </div>
</template>
<script>
   import card from "./components/card-corner";
   import BigScreenCard from "@/components/bigScreenPage/big_screen_card.vue";
   import homeCard from "./components/home_card.vue";
   import BatteryPieChart from "@/components/myCharts/BatteryPieChart.vue";
   import MapChart from "@/components/myCharts/MapChart.vue";
   import MapMarkList from "@/components/mapMarkList.vue";
@@ -165,28 +97,42 @@
   import circleBox from "./components/circle.vue";
   import BarChart from "@/components/myCharts/BarChart.vue";
   import LedNum from "@/components/ledNum";
   import pieChart from "./components/pieCharts";
   // import pieChart from "./components/pieCharts";
  import pieChart from "./components/pie-chart1";
   import BarChartAlarm from "./components/batt-chart-alarm";
   import PowerPieChart from "@/components/myCharts/PieRoseChart.vue";
   import { const_alarm_level } from "@/assets/js/const";
   import { getLabelByValue } from "@/assets/js/tools";
   import getNowStamp from "@/assets/js/tools/getNowStamp";
  import marqueeTop from './components/marqueeTop.vue';
  // import svgSubway from './components/test.vue';
  import svgSubway from './components/SubwayView.vue';
   import createWs from "@/assets/js/websocket/plus";
   import { sethoubeiTime, formatSeconds } from "@/assets/js/tools";
   const WSMixin = createWs("screen_sz", 'battAlarmFoot');
   const WSMixin = createWs("screen_sz2", 'battAlarmFoot');
   export default {
      name: "",
      mixins: [WSMixin],
      data() {
         return {
        nums: {},
        selectFlag: false,
        newItems: [],
        lineSelect0: '',
        lineSelect1: '',
        lineSelect2: '',
        lineSelect3: '',
            lineList: [],
            otherPwrProd: [],
            testData: {},
        faultData: {},
            workState: {},
        alarmRt: {},
        statusList: {},
            alarmData: [[], [], []],
            testLevel: '',
            workState: [0, 0, 0, 0],
            nxType: 0,
            alarmType: 0,
            alarms: [0, 0, 0],
@@ -238,19 +184,13 @@
                     label: "告警开始时间",
                     minWidth: 110,
                  },
                  // {
                  //   prop: "xuhang",
                  //   label: "预估续航时长",
                  //   minWidth: 110,
                  // },
               ],
               data: [],
            },
         };
      },
      components: {
         card,
         BigScreenCard,
         homeCard,
         BatteryPieChart,
         MapChart,
         MapMarkList,
@@ -262,6 +202,8 @@
         BarChartAlarm,
         bar3d,
         PowerPieChart,
      svgSubway,
      marqueeTop,
      },
      methods: {
         alarmTypeChangede(value) {
@@ -279,30 +221,19 @@
            res = JSON.parse(res.data);
            // console.log(res, "=====111data");
            let {
               devStates,
               stationCount,
               battGroupInfo,
               alarmsLevelWithStationName5,
               devCountMap,
               resTestdataInfAnalysis,
               groupCap,
               alarmsLevel,
               dischargingBattery,
               res_inf,
          res_battState,
          res_battAlarm,
          res_station,
            } = res.data;
            // 站点数量统计更新
            this.updateSiteDev(devCountMap);
            // 更新设备工作状态
            this.updateWorkState(devStates);
            // 更新整组容量
            this.updateGroupCap(groupCap);
            this.updateSiteDev(res_inf);
            // 测试信息 改为告警信息
            this.updateTestData(alarmsLevelWithStationName5);
            // 更新地图
            this.updateMap(devCountMap);
            // 更新告警统计
            this.updateAlarms(alarmsLevel);
            // // 实时放电信息
            // this.updateDischargeInfo(dischargingBattery);
            this.updateTestData(res_battAlarm);
            // 更新电池状态
            this.updateWorkState(res_battState);
            // // 更新地图
            this.updateMap(res_station);
         },
         onWSOpen2() {
            this.sendMessage2();
@@ -353,21 +284,56 @@
            // this.updateFlag = Math.random();
         },
      legendChange(data) {
        console.log('data, ', data, '=============');
        this.selectFlag = true;
        let stionNum = 0;
        let battNum = 0;
        let devNum = 0;
        let nums = this.nums;
        Object.keys(data).forEach(v => {
          if (data[v]) {
            stionNum += nums[v].stionNum;
            devNum += nums[v].devNum;
            battNum += nums[v].battNum;
          }
        });
        this.stationNum = stionNum;
        this.devCount = devNum;
        this.battGroupCount = battNum;
      },
         updateSiteDev(data) {
            const { devCount, stationNum, battGroupCount, battGroupMonCount } = data.data2;
            this.devCount = devCount;
            this.stationNum = stationNum;
            this.battGroupCount = battGroupCount;
            this.battGroupMonCount = battGroupMonCount;
            const { devNum, stionNum, battNum } = data.data2?.allmap || {};
        if (!this.selectFlag) {
          this.devCount = devNum || 0;
          this.stationNum = stionNum || 0;
          this.battGroupCount = battNum || 0;
        }
        let _data = data.data2;
        let res = {};
        Object.keys(_data).forEach(v => {
          if (v != 'allmap') {
            res[v + '号线'] = _data[v];
          }
        });
        this.nums = res;
         },
         updateWorkState(data) {
            data = data.data2;
            this.workState = [
               data["内阻测试数量"],
               data["核容测试数量"],
               data["直连充电数量"],
               data["通讯故障数量"],
            ];
        let workList = {};
        this.lineList.forEach(v => {
          let item = v == 0 ? data['allmap'] : data[v];
          let xLabel = [];
          let sData = [];
          Object.keys(item).forEach(vv => {
            xLabel.push(vv);
            sData.push(item[vv]);
          });
          workList[v] = {xLabel, sData};
        });
            this.workState = workList;
        this.$refs.bar3d1.setData(this.workState[this.lineSelect2]);
         },
         updateGroupCap(obj) {
            const { code, data, data3 } = obj;
@@ -389,123 +355,90 @@
            this.cap.level3 = level3;
            this.cap.level4 = level4;
         },
         // 电池统计
         updateBattInfo(obj) {
            // let { code, data, data2 } = obj;
            // let vol2 = 0,
            //   vol12 = 0,
            //   producer = [{ name: "电池品牌", value: 0 }];
            // if (code && data) {
            //   vol2 = data2.monVol["2.0"];
            //   vol12 = data2.monVol["12.0"];
            //   let arr = Object.keys(data2.producer)
            //     .map((v) => ({ name: v, value: data2.producer[v] }))
            //     .sort((a, b) => b.value - a.value);
            //   if (arr.length <= 5) {
            //     producer = arr;
            //   } else {
            //     let name = "其他";
            //     let value = 0;
            //     arr.splice(4).forEach((v) => {
            //       value += v.value * 1;
            //     });
            //     arr.push({ name, value });
            //     producer = arr;
            //   }
            // }
            // this.$refs.batteryChart.setData(vol2, vol12, producer);
         },
         updateTestData(obj) {
            let list_obj = obj.data2.data;
            let list_obj = obj.data2.level;
            let lineList = Object.keys(list_obj);
        lineList.unshift(0);
            if (!this.lineList.length) {
               this.lineList = lineList;
               this.testLevel = lineList[0];
               this.lineSelect0 = 0;
               this.lineSelect1 = 0;
               this.lineSelect2 = 0;
               this.lineSelect3 = 0;
            }
            let test = {};
            lineList.forEach((item) => {
               let _item = list_obj[item];
               let _item = item == 0 ? obj.data2.allLevel : list_obj[item];
               const {
                  level1,
                  level2,
                  level3,
                  level4,
                  1: level1,
                  2: level2,
                  3: level3,
                  4: level4,
               } = _item;
               test[item] = {
                  xLabel: ["一级告警", "二级告警", "三级告警", "四级告警"],
                  sData: [
                     level1.battAlarmCount + level1.powerAlarmCount + level1.deviceAlarmCount,
                     level2.battAlarmCount + level2.powerAlarmCount + level2.deviceAlarmCount,
                     level3.battAlarmCount + level3.powerAlarmCount + level3.deviceAlarmCount,
                     level4.battAlarmCount + level4.powerAlarmCount + level4.deviceAlarmCount
                     level1,
                     level2,
                     level3,
                     level4
                  ],
               };
            });
            this.testData = test;
            this.$refs.bar3d.setData(test[this.testLevel]);
        // 故障
        let fault = {};
        let _fault = obj.data2.type;
        lineList.forEach(v => {
          let _item = v == 0 ? obj.data2.allType : _fault[v];
          let arr = [];
          Object.keys(_item).forEach(vv => {
            arr.push({
              name: vv,
              value: _item[vv]
            });
          });
          fault[v] = arr;
        });
        this.faultData = fault;
            this.$refs.bar3d0.setData(test[this.lineSelect0]);
        this.$refs.pie.setData(fault[this.lineSelect1]);
        // 告警列表
        let alarmRt = {};
        let alarmList = obj.data2.list;
        lineList.forEach(v => {
          let _list = v == 0 ? alarmList['allList'] : alarmList[v];
          alarmRt[v] = _list;
        });
        this.alarmRt = alarmRt;
        this.newItems = alarmRt[this.lineSelect3];
         },
         testLevelChange(value) {
            this.$refs.bar3d.setData(this.testData[value]);
        // TODO
        switch(value) {
          case 0:
            this.$refs.bar3d0.setData(this.testData[this.lineSelect0]);
            break;
          case 1:
            this.$refs.pie.setData(this.faultData[this.lineSelect1]);
            break;
          case 2:
            this.$refs.bar3d1.setData(this.workState[this.lineSelect2]);
            break;
          case 3:
            this.newItems = this.alarmRt[this.lineSelect3];
            break;
        }
         },
         // 更新地图
         updateMap(obj) {
            let data = obj.data2.stationInfList;
            const getColor = (o) => {
               let res = 0;
               res = o.devWorkState <= 3 ? o.devWorkState : 0;
               return ["#0081ff", "#66f842", "#ff6b6c", "#7668f9"][res];
            };
            this.$refs.map.setData(
               data.map((v) => {
                  return {
                     ...v,
                     label: v.stationName3,
                     color: getColor(v),
                     points: [v.stationLongitude, v.stationLatitude],
                     // 无实际意义
                     value: 100,
                  };
               })
            );
         },
         // 更新告警统计
         updateAlarms(obj) {
            let { level1, level2, level3, level4 } = obj.data2.data;
            this.alarms = [
               level1.powerAlarmCount,
               level1.deviceAlarmCount,
               level1.battAlarmCount,
            ];
            this.alarmData = [
               [
                  level1.powerAlarmCount,
                  level2.powerAlarmCount,
                  level3.powerAlarmCount,
                  level4.powerAlarmCount,
               ],
               [
                  level1.deviceAlarmCount,
                  level2.deviceAlarmCount,
                  level3.deviceAlarmCount,
                  level4.deviceAlarmCount,
               ],
               [
                  level1.battAlarmCount,
                  level2.battAlarmCount,
                  level3.battAlarmCount,
                  level4.battAlarmCount,
               ],
            ];
            if (this.$refs.alarmPieChart) {
               this.$refs.alarmPieChart.update();
            }
            if (this.$refs.chart_alarm) {
               this.$refs.chart_alarm.setData(this.alarmData);
            }
            this.statusList = obj.data2 || {};
         },
         goDevWorkState(num) {
            let status = num;
@@ -526,29 +459,6 @@
               },
            });
         },
         // updateDischargeInfo(obj) {
         //   const { code, data, data2, msg } = obj;
         //   let list = [];
         //   if (code && data) {
         //     let outTime = 2 * 60; //设备超时时间(2分钟)
         //     let nowTime = new Date(msg).getTime(); //当前时间
         //     list = data2
         //       .filter((v) => {
         //         // 判断是否超时
         //         let record = new Date(v.battTestRecordtime).getTime();
         //         return Math.abs(nowTime - record) / 1000 <= outTime;
         //       })
         //       .map((v) => {
         //         // v.stationArea =
         //         //   v.stationName1 + " " + v.stationName2 + " " + v.stationName5;
         //         v.battTestTimelong = formatSeconds(v.battTestTlong);
         //         let xuhang = v.loadCurr ? v.battRealCap / v.loadCurr : 0;
         //         v.xuhang = xuhang ? sethoubeiTime(xuhang) : "---";
         //         return v;
         //       });
         //   }
         //   this.tbl.data = list;
         // },
         goDevAlarm() {
            this.$router.push({
               path: "/alarmMager/deviceTimequery",
@@ -585,12 +495,20 @@
            this.$router.push("/dataMager/battGroupMager");
         },
         initEvent() {
            this.$refs.map.getChart().on("click", (e) => {
               console.log('e', e, '=======123======');
            // this.$refs.map.getChart().on("click", (e) => {
            //    console.log('e', e, '=======123======');
            });
            // });
         },
      },
    computed: {
      showMarquee() {
        return typeof this.newItems == "undefined" || this.newItems.length == 0
          ? false
          : true;
      },
    },
      mounted() {
         if (this.$refs.alarmPieChart) {
@@ -604,18 +522,61 @@
<style scoped lang="less">
.p-main {
  height: 100%;
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: 1fr 1fr 1fr;
  grid-template-columns: 1fr 1.5fr 1fr;
  grid-gap: 8px;
  // display: grid;
  // grid-auto-flow: column;
  // grid-template-rows: 1fr;
  // grid-template-columns: 1fr 1.95fr 1fr;
  // grid-gap: 8px;
  display: flex;
  /deep/ .big-screen-card {
  .p-side {
    flex: 1;
    display: flex;
    flex-direction: column;
    padding-left: 36px;
    padding-right: 58px;
    position: relative;
    &::before {
      content: '';
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      background: url(./images/bg-side.png) left center / auto 100% no-repeat,
                url(./images/bg-card.png) left center / 100% 100% no-repeat;
    }
    &.p-right {
      padding-left:  68px;
      padding-right: 36px;
      &::before {
        transform: scaleX(-1);
      }
    }
    .row {
      margin-top: 50px;
      margin-bottom: 50px;
    }
    .row~.row {
      margin-top: 8px;
    }
  }
    .row {
      flex: 1;
      :deep(.el-select) {
        width: 8em;
      }
    }
  /deep/ .home-card {
    padding: 0;
  }
  .wraper {
    grid-row-start: span 2;
    flex: 2.4;
    // grid-row-start: span 2;
    display: flex;
    flex-direction: column;
@@ -626,15 +587,26 @@
    .row2 {
      flex: 1.8;
      margin-top: 8px;
      position: relative;
      &::before {
        content: '';
        position: absolute;
        left: 0;
        right: 0;
        top: 0;
        bottom: 0;
        background: url(./images/bg-map-sz.jpg) center center / cover no-repeat;
        opacity: 0.6;
      }
    }
  }
  .row.alarm {
    grid-column-start: span 2;
    // grid-column-start: span 2;
  }
  .row.test-info {
    grid-row-start: span 2;
    // grid-row-start: span 2;
  }
}
@@ -731,26 +703,36 @@
  .item {
    cursor: pointer;
    display: flex;
    flex-direction: column;
    // border-radius: 6px;
    align-items: center;
    justify-content: center;
    min-width: 10em;
    min-height: 4em;
    background: url(./images/bg-info.png) center center / contain no-repeat;
    .name {
      background: #0ff;
      border-radius: 6px;
      color: #333;
      font-size: 18px;
      font-weight: bold;
      padding: 0 10px;
      // background: #0ff;
      // border-radius: 6px;
      // color: #333;
      // font-size: 18px;
      // font-weight: bold;
      // padding: 0 10px;
      font-size: 14px;
      margin-top: 10px;
      color: #0ff;
      &::after {
        content: ':';
      }
    }
    .num {
      width: 3em;
      height: 1.5em;
      padding: 0 10px;
      &.bits5 {
        width: 5em;
      }
      // width: 3em;
      // height: 1.5em;
      // padding: 0 10px;
      color: #fbfc0d;
      font-weight: bold;
      font-size: 22px;
    }
  }
}
@@ -767,6 +749,14 @@
    bottom: 0;
  }
}
.scroller-wraper {
  position: absolute;
  left: 0;
  top: 30px;
  right: 0;
  bottom: 30px;
  overflow: hidden;
}
/deep/ .mark-list-container {
  bottom: 0.4rem;