From 1d41f70b0d1c1756546dfa529786d810d7c8cccb Mon Sep 17 00:00:00 2001
From: 董国庆 <364620639@qq.com>
Date: 星期二, 08 四月 2025 15:02:57 +0800
Subject: [PATCH] 修改首页

---
 src/view/home/index.vue | 2593 ++++++++++++++++++++++++++++++----------------------------
 1 files changed, 1,324 insertions(+), 1,269 deletions(-)

diff --git a/src/view/home/index.vue b/src/view/home/index.vue
index f7ca11f..bcb3c75 100644
--- a/src/view/home/index.vue
+++ b/src/view/home/index.vue
@@ -1,1270 +1,1325 @@
-<template>
-  <div class="flex homePage">
-    <!-- 头部 -->
-    <div class="mapTop">
-      <!-- 车辆统计 -->
-      <div class="carCount">
-        <div class="title">车辆统计</div>
-        <div class="fir">
-          <div
-            class="countCard"
-            v-for="(item, index) in carCountData.slice(0, 3)"
-            :key="item.id"
-          >
-            <img class="iconImg" :src="imgList[index]" />
-            <div>
-              <div class="name">{{ item.name || "" }}(辆)</div>
-              <div class="num">{{ item.carNum || 0 }}</div>
-            </div>
-          </div>
-        </div>
-        <div class="sec">
-          <div
-            class="countCard"
-            v-for="(item, index) in carCountData.slice(3, 7)"
-            :key="item.id"
-          >
-            <img class="iconImg" :src="imgList[index + 3]" />
-            <div>
-              <div class="name">{{ item.name || "" }}(辆)</div>
-              <div class="num">{{ item.carNum || 0 }}</div>
-            </div>
-          </div>
-        </div>
-      </div>
-      <!-- 车辆状态 -->
-      <div class="carStatus">
-        <div class="title">车辆状态</div>
-        <div class="statusFir">
-          <div class="statusCard">
-            <div class="statusLeft">
-              <div class="name">在线</div>
-              <div class="num">{{ carStatusData.online || 0 }}</div>
-            </div>
-            <el-progress
-              type="circle"
-              :width="20"
-              :show-text="false"
-              stroke-linecap="butt"
-              :percentage="carStatusData.onlinePercent"
-              color="rgba(91, 143, 249, 1)"
-              define-back-color="rgba(91, 143, 249, 0.25)"
-              class="progressCard"
-            ></el-progress>
-          </div>
-          <div class="statusLine"></div>
-          <div class="statusCard">
-            <div class="statusLeft">
-              <div class="name">离线</div>
-              <div class="num">{{ carStatusData.offline || 0 }}</div>
-            </div>
-            <el-progress
-              type="circle"
-              :width="20"
-              :show-text="false"
-              stroke-linecap="butt"
-              :percentage="carStatusData.offlinePercent"
-              color="rgba(93, 112, 146, 1)"
-              define-back-color="rgba(93, 112, 146, 0.25)"
-              class="progressCard"
-            ></el-progress>
-          </div>
-        </div>
-        <div class="statusSec">
-          <div class="statusCard">
-            <div class="statusLeft">
-              <div class="name">故障</div>
-              <div class="num">{{ carStatusData.breakdown || 0 }}</div>
-            </div>
-            <el-progress
-              type="circle"
-              :width="20"
-              :show-text="false"
-              stroke-linecap="butt"
-              :percentage="carStatusData.breakdownPercent"
-              color="rgba(253, 83, 118, 1)"
-              define-back-color="rgba(253, 83, 118, 0.25)"
-              class="progressCard"
-            ></el-progress>
-          </div>
-          <div class="statusLine"></div>
-          <div class="statusCard">
-            <div class="statusLeft">
-              <div class="name">异常</div>
-              <div class="num">{{ carStatusData.abnormal || 0 }}</div>
-            </div>
-            <el-progress
-              type="circle"
-              :width="20"
-              :show-text="false"
-              stroke-linecap="butt"
-              :percentage="carStatusData.abnormalPercent"
-              color="rgba(246, 189, 22, 1)"
-              define-back-color="rgba(246, 189, 22, 0.25)"
-              class="progressCard"
-            ></el-progress>
-          </div>
-        </div>
-      </div>
-    </div>
-    <!-- 左边 地图 -->
-    <div class="leftMap">
-      <div class="mapContainer" id="mapContainer"></div>
-    </div>
-    <!-- 右边 内容 -->
-    <div class="right">
-      <div class="firCard">
-        <div class="companyCard">
-          <div class="lineCard"></div>
-          <div class="name">运营公司(家)</div>
-          <div class="value">{{ carStatusData.enterprise || 0 }}</div>
-        </div>
-        <div class="companyCard">
-          <div class="lineCard"></div>
-          <div class="name">运营车辆(辆)</div>
-          <div class="value">{{ carStatusData.car || 0 }}</div>
-        </div>
-        <div class="companyCard">
-          <div class="lineCard"></div>
-          <div class="name">驾驶员(人)</div>
-          <div class="value">{{ carStatusData.driver || 0 }}</div>
-        </div>
-      </div>
-      <!-- 今日预警 -->
-      <div class="todayWarn">
-        <div class="title">今日预警</div>
-        <div class="warnList" v-if="warnList.length > 0">
-          <div
-            class="warnItem"
-            v-for="(item, index) in warnList"
-            :key="index"
-            :class="
-              item.warnLevel
-                ? ['oneWarn', 'twoWarn', 'threeWarn', 'fourWarn'][
-                    item.warnLevel - 1
-                  ]
-                : 'fiveWarn'
-            "
-          >
-            <div class="grade">
-              {{
-                item.warnLevel
-                  ? ["一级", "二级", "三级", "四级"][item.warnLevel - 1]
-                  : "-"
-              }}
-            </div>
-            <div class="info">
-              {{ item.vehicleNumber }} {{ item.warnType }} {{ item.keepTime }}
-              {{ item.startTime }}
-            </div>
-          </div>
-        </div>
-        <div class="noData" v-else>
-          <el-empty description="暂无数据" :image-size="80"></el-empty>
-        </div>
-      </div>
-      <!-- 预警情况统计 -->
-      <div class="warnCount">
-        <div class="title">预警情况统计</div>
-        <div class="countChart" id="countChart"></div>
-        <div class="noData" v-if="countList.length == 0">
-          <el-empty description="暂无数据" :image-size="80"></el-empty>
-        </div>
-      </div>
-      <!-- 预警排行榜(前10) -->
-      <div class="warnRank">
-        <div class="title">预警排行榜(前10)</div>
-        <div class="rankChart" id="rankChart">
-          <div class="rankItem" v-for="(item, index) in rankList" :key="index">
-            <div class="left">{{ item.name }}</div>
-            <div
-              class="rankRight"
-              :class="[0, 1, 2].includes(index) ? 'rankColor' : ''"
-            >
-              <div class="rank" :style="{ width: item.percentage + '%' }"></div>
-            </div>
-          </div>
-        </div>
-        <div class="noData" v-if="rankList.length == 0">
-          <el-empty description="暂无数据" :image-size="80"></el-empty>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-import * as echarts from "echarts";
-import html2canvas from "html2canvas";
-import AMapLoader from "@amap/amap-jsapi-loader";
-import flvjs from "flv.js";
-import {
-  getCarCount,
-  getCarStatusCount,
-  getMapCarList,
-  getCarWarnList,
-  getWarnGroupCount,
-  getWarnGroupCountTop10,
-  getRealVideo,
-} from "./service";
-export default {
-  data() {
-    return {
-      flvPlayer: null,
-      activeIndex: "1",
-      activeIndex2: "1",
-      timer: null,
-      markers: [],
-      map: null,
-      AMap: null,
-      infoWindow: null,
-      imgList: [
-        require("../../assets//homeImg/img1.png"),
-        require("../../assets//homeImg/img2.png"),
-        require("../../assets//homeImg/img3.png"),
-        require("../../assets//homeImg/img4.png"),
-        require("../../assets//homeImg/img5.png"),
-        require("../../assets//homeImg/img6.png"),
-        require("../../assets//homeImg/img7.png"),
-      ],
-      countList: [], //预警情况统计数据
-      rankList: [], //预警排行榜数据
-      carList: [], //车辆列表数据
-      carCountData: [], //车辆统计数据
-      carStatusData: {}, //车辆状态数据
-      warnList: [], //预警列表数据
-    };
-  },
-  watch: {
-    map(val) {
-      if (val) {
-        HTMLCanvasElement.prototype.getContext = (function (origFn) {
-          return function (type, attributes) {
-            if (type.indexOf("webgl") > -1) {
-              attributes = Object.assign({}, attributes, {
-                preserveDrawingBuffer: true,
-              });
-            }
-            return origFn.call(this, type, attributes);
-          };
-        })(HTMLCanvasElement.prototype.getContext);
-      }
-    },
-  },
-  filters: {
-    
-  },
-
-  created() {
-    window.toCarDetail = (record) => {
-      this.toCarDetail(record);
-    };
-    window.fullScreen = () => {
-      this.fullScreen();
-    };
-    window.shotScreen = () => {
-      this.shotScreen();
-    };
-  },
-  mounted() {
-    // 调用所有接口
-    this.getCarCountData();
-    this.getCarStatusData();
-    // this.getMapCarData(); // 移除这里的调用,因为 initMap 中会调用
-    this.getWarnListData();
-    this.getWarnGroupData();
-    this.getWarnTop10Data();
-
-    this.initMap();
-    // 设置定时器,每分钟刷新一次数据
-    this.timer = setInterval(() => {
-      this.getCarCountData();
-      this.getCarStatusData();
-      this.getMapCarData(); // 保留定时器中的调用
-      this.getWarnListData();
-      this.getWarnGroupData();
-      this.getWarnTop10Data();
-    }, 60000);
-  },
-  beforeDestroy() {
-    if (this.timer) {
-      clearInterval(this.timer);
-    }
-    if (this.markers && this.markers.length > 0) {
-      this.markers.forEach((marker) => {
-        marker.setMap(null);
-      });
-      this.markers = [];
-    }
-    if (this.infoWindow) {
-      this.infoWindow.close();
-    }
-    if (this.flvPlayer) {
-      this.flvPlayer.destroy();
-      this.flvPlayer = null;
-    }
-  },
-  beforeRouteLeave(to, from, next) {
-    if (this.infoWindow) {
-      this.infoWindow.close();
-    }
-    if (this.flvPlayer) {
-      this.flvPlayer.destroy();
-      this.flvPlayer = null;
-    }
-    next();
-  },
-  methods: {
-    // 获取车辆统计数据
-    async getCarCountData() {
-      try {
-        const res = await getCarCount();
-        this.carCountData = res;
-      } catch (error) {
-        this.$message.error("获取车辆统计数据失败");
-      }
-    },
-    // 获取车辆状态数据
-    async getCarStatusData() {
-      try {
-        const res = await getCarStatusCount();
-        // 设置默认值为0,防止空值
-        const online = Number(res.online) || 0;
-        const offline = Number(res.offline) || 0;
-        const breakdown = Number(res.breakdown) || 0;
-        const abnormal = Number(res.abnormal) || 0;
-        const enterprise = Number(res.enterprise) || 0;
-        const car = Number(res.car) || 0;
-        const driver = Number(res.driver) || 0;
-
-        // 计算总数
-        const total = online + offline + breakdown + abnormal;
-
-        // 计算百分比,如果总数为0则百分比为0
-        const onlinePercent =
-          total > 0 ? Math.round((online / total) * 100) : 0;
-        const offlinePercent =
-          total > 0 ? Math.round((offline / total) * 100) : 0;
-        const breakdownPercent =
-          total > 0 ? Math.round((breakdown / total) * 100) : 0;
-        const abnormalPercent =
-          total > 0 ? Math.round((abnormal / total) * 100) : 0;
-        // 更新数据
-        this.carStatusData = {
-          online,
-          offline,
-          breakdown,
-          abnormal,
-          enterprise,
-          car,
-          driver,
-          total,
-          onlinePercent,
-          offlinePercent,
-          breakdownPercent,
-          abnormalPercent,
-        };
-      } catch (error) {
-        this.$message.error("获取车辆状态数据失败");
-        // 设置默认值
-        this.carStatusData = {
-          online: 0,
-          offline: 0,
-          breakdown: 0,
-          abnormal: 0,
-          enterprise: 0,
-          car: 0,
-          driver: 0,
-          total: 0,
-          onlinePercent: 0,
-          offlinePercent: 0,
-          breakdownPercent: 0,
-          abnormalPercent: 0,
-        };
-      }
-    },
-    // 获取地图车辆数据
-    async getMapCarData() {
-      try {
-        const res = await getMapCarList();
-        this.carList = res;
-        // 确保地图已初始化后再更新标记
-        if (this.AMap && this.map) {
-          this.updateMarkers(res);
-        }
-      } catch (error) {
-        this.$message.error("获取地图车辆数据失败");
-      }
-    },
-    // 获取预警列表数据
-    async getWarnListData() {
-      try {
-        const res = await getCarWarnList();
-        this.warnList = res.records;
-      } catch (error) {
-        this.$message.error("获取预警列表数据失败");
-      }
-    },
-    // 获取预警统计情况数据
-    async getWarnGroupData() {
-      try {
-        const res = await getWarnGroupCount();
-        this.countList = res;
-        this.getCountList();
-      } catch (error) {
-        this.$message.error("获取预警统计情况数据失败");
-      }
-    },
-    // 获取预警排行数据
-    async getWarnTop10Data() {
-      try {
-        const res = await getWarnGroupCountTop10();
-        // 判断返回的数组是否为空
-        if (!res || res.length === 0) {
-          this.rankList = [];
-          return;
-        }
-        // 计算所有num的总和
-        const total = res.reduce((sum, item) => sum + (item.num || 0), 0);
-        // 为每个数据项添加百分比属性
-        this.rankList = res.map((item) => ({
-          ...item,
-          percentage:
-            total > 0 ? (((item.num || 0) / total) * 100).toFixed(2) : 0,
-        }));
-      } catch (error) {
-        this.$message.error("获取预警排行数据失败");
-        this.rankList = [];
-      }
-    },
-    // 初始化地图
-    initMap() {
-      window._AMapSecurityConfig = {
-        securityJsCode: "37ce61ae86efa5ad82b649a277f5097c",
-      };
-      AMapLoader.load({
-        key: "67968c82f27c7e2cb9f40c1a9aa3042b",
-        version: "2.0",
-        plugins: [
-          "AMap.ToolBar",
-          "AMap.AutoComplete",
-          "AMap.Geocoder",
-          "AMap.MarkerCluster",
-          "AMap.Geocoder",
-        ],
-      })
-        .then((AMap) => {
-          this.AMap = AMap;
-          this.map = new AMap.Map("mapContainer", {
-            center: [105.574542, 30.5061493],
-            zoom: 8,
-          });
-          this.infoWindow = new AMap.InfoWindow({
-            offset: new AMap.Pixel(30, 30),
-            autoMove: true,
-            anchor: "top-center",
-          });
-          this.getMapCarData();
-        })
-        .catch((e) => {
-          this.$message.error("地图加载失败");
-        });
-    },
-    // 更新地图标记
-    updateMarkers(arr) {
-      if (!this.AMap) {
-        return;
-      }
-      if (this.markers && this.markers.length > 0) {
-        this.markers.forEach((marker) => {
-          marker.setMap(null);
-        });
-        this.markers = [];
-      }
-
-      if (arr.length > 0) {
-        const iconMap = {
-          出租车: {
-            icon: require("../../assets/homeImg/taxi.png"),
-            size: new this.AMap.Size(75, 37),
-          },
-          公交车: {
-            icon: require("../../assets/homeImg/bus.png"),
-            size: new this.AMap.Size(62, 34),
-          },
-          危险品: {
-            icon: require("../../assets/homeImg/risk.png"),
-            size: new this.AMap.Size(69, 32),
-          },
-          郊游: {
-            icon: require("../../assets/homeImg/outing.png"),
-            size: new this.AMap.Size(61, 31),
-          },
-          货运: {
-            icon: require("../../assets/homeImg/expressage.png"),
-            size: new this.AMap.Size(60, 31),
-          },
-          网约车: {
-            icon: require("../../assets/homeImg/online.png"),
-            size: new this.AMap.Size(75, 33),
-          },
-          客运: {
-            icon: require("../../assets/homeImg/passenger.png"),
-            size: new this.AMap.Size(69, 31),
-          },
-        };
-
-        arr.forEach((item, index) => {
-          // 检查必要字段
-          if (!item.operateType || !item.longitude || !item.latitude) {
-            return;
-          }
-
-          const iconConfig = iconMap[item.operateType];
-          if (!iconConfig) {
-            return;
-          }
-
-          let marker = new this.AMap.Marker({
-            position: [Number(item.longitude), Number(item.latitude)],
-            map: this.map,
-            icon: new this.AMap.Icon({
-              size: iconConfig.size,
-              image: iconConfig.icon,
-              imageSize: iconConfig.size,
-              imageOffset: new this.AMap.Pixel(0, 0),
-            }),
-          });
-
-          // 添加点击事件
-          marker.on("click", async (e) => {
-            // 如果已经有视频在播放,先销毁
-            if (this.flvPlayer) {
-              this.flvPlayer.destroy();
-              this.flvPlayer = null;
-            }
-
-            // 显示loading
-            this.infoWindow.setContent(
-              '<div style="padding: 20px;text-align: center;">加载中...</div>'
-            );
-            this.infoWindow.open(this.map, e.target.getPosition());
-
-            try {
-              // 使用高德地图API获取地址信息
-              const geocoder = new this.AMap.Geocoder();
-              const location = [Number(item.longitude), Number(item.latitude)];
-
-              const [addressResult, videoRes] = await Promise.all([
-                new Promise((resolve) => {
-                  geocoder.getAddress(location, (status, result) => {
-                    if (status === "complete" && result.regeocode) {
-                      console.log("result", result,'status',status);
-                      resolve(result.regeocode.formattedAddress);
-                    } else {
-                      resolve("未知地址");
-                    }
-                  });
-                }),
-                this.getVideoUrl(item.id),
-              ]);
-
-              // 更新弹窗内容
-              this.infoWindow.setContent(
-                this.listRender({
-                  ...item,
-                  drivingTime:this.formatterTime(item.drivingTime || 0) ,
-                  location: addressResult,
-                  videoUrl: videoRes.data.url,
-                })
-              );
-
-              // if (flvjs.isSupported()) {
-              //   this.flvPlayer = flvjs.createPlayer({
-              //     type: "flv",
-              //     isLive: true,
-              //     cors: true,
-              //     hasAudio: true,
-              //     hasVideo: true,
-              //     url: videoRes.data.url,
-              //     enableWorker: true,
-              //     enableStashBuffer: false,
-              //     seekType: "range",
-              //   });
-              //   let video = document.getElementById("monitoringCard");
-              //   this.flvPlayer.attachMediaElement(video);
-              //   this.flvPlayer.load();
-              //   this.flvPlayer.play();
-              // }
-            } catch (error) {
-              this.infoWindow.setContent(
-                '<div style="padding: 20px;text-align: center;color: red;">获取车辆信息失败</div>'
-              );
-            }
-          });
-
-          // 将marker添加到数组中
-          this.markers.push(marker);
-        });
-      }
-    },
-    // 获取视频地址
-    async getVideoUrl(carId) {
-      try {
-        const res = await getRealVideo({ id: carId });
-        return res;
-      } catch (error) {
-        return {
-          data: {
-            url: "",
-          },
-        };
-      }
-    },
-
-    listRender(record) {
-      return `<div style="background: #ffffff; padding: 24px 20px;z-index: 999">
-        <div style="position: relative; width: 460px; height: 330px">
-          <video
-            crossorigin="anonymous" 
-            style="width: 460px; height: 330px; border-radius: 9px" 
-            id="monitoringCard"
-            :controls="false"
-            autoplay
-            width="620">
-          </video>
-          <div style="position: absolute; right: 11px; top: 10px">
-            <div style="display: flex;flex-direction: column;align-items: center;justify-content: center;
-              background: #ffffff; padding: 3px 10px; border-radius: 6px;margin-bottom: 10px;" onclick="fullScreen()">
-              <img style="width: 20px; height: 20px" src="${require("../../assets//homeImg/full.png")}" />
-              <div style="font-size: 12px;font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);">全屏</div>
-            </div>
-            <div style="display: flex;flex-direction: column;align-items: center; justify-content: center;
-              background: #ffffff;padding: 3px 10px;border-radius: 6px;" onclick="shotScreen()">
-              <img style="width: 20px; height: 20px" src="${require("../../assets//homeImg/slot.png")}" />
-              <div style="font-size: 12px; font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);">截屏</div>
-            </div>
-          </div>
-        </div>
-        <div style="display: flex;justify-content: space-between;margin-top: 15px;margin-bottom: 12px;">
-          <div style="font-weight: 500;font-size: 18px;color: rgba(0, 0, 0, 0.85);line-height: 25px;">车牌号:${
-            record.vehicleNumber || ""
-          }</div>
-          <div style="font-weight: 500; font-size: 18px;color: rgba(0, 0, 0, 0.85);line-height: 25px;">驾驶员:${
-            record.driverName || ""
-          }</div>
-        </div>
-        <div style="display: flex; justify-content: space-between">
-          <div style="font-weight: 500; font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;width: 200px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;" title="${record.location}">位置:${
-            record.location
-          }</div>
-          <div style="font-weight: 500;font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;">经纬度:${
-            record.longitude + "," + record.latitude
-          }</div>
-        </div>
-        <div style="display: flex; justify-content: space-between">
-          <div style="font-weight: 500;font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;">当前时速:${
-            record.speed || ""
-          }${record.speed && "km/h"}</div>
-          <div style="font-weight: 500;font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;">驾驶时长:${
-            record.drivingTime
-          }</div>
-        </div>
-        <div style="margin-top: 14px;display: flex;justify-content: flex-end;align-items: center;cursor: pointer;" onclick="toCarDetail(${
-          record.id
-        })">
-          <div style="font-weight: 400;font-size: 18px; color: rgba(22, 119, 255, 1);line-height: 25px;">车辆详情</div>
-          <img style="width:18px;height: 18px;margin-left: 8px;" src="${require("../../assets//homeImg/right.png")}" />
-        </div>
-      </div>`;
-    },
-    formatterTime(value) {
-      if (!value) return "";
-      const hours = Math.floor(value / 60);
-      const minutes = value % 60;
-      if (hours > 0) {
-        return `${hours}小时${minutes}分钟`;
-      } else {
-        return `${minutes}分钟`;
-      }
-    },
-    // 获取预警情况统计
-    getCountList() {
-      echarts.dispose(document.getElementById("countChart"));
-      if (this.countList.length > 0) {
-        this.chartTnit();
-      }
-    },
-    chartTnit() {
-      // 基于准备好的dom,初始化echarts实例
-      const myChart = echarts.init(document.getElementById("countChart"));
-      // 绘制数量图表
-      myChart.setOption({
-        tooltip: {
-          trigger: "axis",
-          axisPointer: {
-            type: "shadow",
-          },
-        },
-        grid: {
-          width: "auto",
-          height: "auto",
-          top: "5%",
-          left: "3%",
-          right: "4%",
-          bottom: "0%",
-          containLabel: true,
-        },
-        xAxis: [
-          {
-            type: "category",
-            data: this.countList.map((item) => item.warnType),
-            axisTick: {
-              alignWithLabel: true,
-              lineStyle: {
-                color: "#777777",
-              },
-            },
-            axisLabel: {
-              color: "rgba(0, 0, 0, 0.45)",
-            },
-          },
-        ],
-        yAxis: [
-          {
-            type: "value",
-          },
-        ],
-        series: [
-          {
-            type: "bar",
-            barWidth: "20px",
-            itemStyle: {
-              borderRadius: [20, 20, 20, 20],
-              color: (params) => {
-                return ["#5B8FF9", "#5AD8A6", "#F6BD16", "#6DC8EC", "#945FB9"][
-                  params.dataIndex
-                ];
-              },
-            },
-            data: this.countList.map((item) => item.num),
-          },
-        ],
-      });
-      myChart.resize();
-    },
-
-    // 跳转车辆详情
-    toCarDetail(id) {
-      this.$router.push({
-        path: "/car-detail",
-        query: {
-          id: id,
-        },
-      });
-    },
-    fullScreen() {
-      const video = document.getElementById("monitoringCard");
-      if (video.requestFullscreen) {
-        video.requestFullscreen();
-      } else if (video.mozRequestFullScreen) {
-        // Firefox
-        video.mozRequestFullScreen();
-      } else if (video.webkitRequestFullscreen) {
-        // Chrome, Safari and Opera
-        video.webkitRequestFullscreen();
-      } else if (video.msRequestFullscreen) {
-        // IE/Edge
-        video.msRequestFullscreen();
-      }
-    },
-    shotScreen() {
-      // 获取video和canvas元素
-      const video = document.getElementById("monitoringCard");
-      const canvas = document.getElementById("myCanvas");
-      // 设置canvas的宽度和高度与video相同
-      canvas.width = video.videoWidth;
-      canvas.height = video.videoHeight;
-      // 获取canvas的2d绘图上下文
-      const context = canvas.getContext("2d");
-      // 将当前video帧绘制到canvas上
-      context.drawImage(video, 0, 0, canvas.width, canvas.height);
-
-      setTimeout(() => {
-        // 将canvas内容转换为图片
-        let dataURL = canvas.toDataURL("image/png");
-        this.downloadImage(dataURL);
-      }, 100);
-    },
-    downloadImage(base64) {
-      const link = document.createElement("a");
-      link.href = base64;
-      link.download = "screenshot.png"; // 你希望下载的文件名
-      document.body.appendChild(link);
-      link.click();
-      document.body.removeChild(link);
-    },
-  },
-};
-</script>
-
-<style scoped lang="less">
-.homePage {
-  display: flex;
-  height: 100vh;
-  position: relative;
-
-  .leftMap {
-    // width: 100%;
-    height: 100%;
-    flex: 1;
-    display: flex;
-    position: relative;
-
-    #mapContainer {
-      flex: 1;
-      width: 100%;
-      height: 100%;
-    }
-  }
-  .mapTop {
-    z-index: 99;
-    position: absolute;
-    top: 20px;
-    left: 20px;
-    right: 513px;
-    display: flex;
-    justify-content: space-between;
-    width: calc(100% - 570px);
-
-    .title {
-      font-weight: 600;
-      font-size: 18px;
-      color: #000000;
-      line-height: 25px;
-      text-transform: none;
-      text-align: center;
-    }
-
-    .carCount {
-      flex: 8;
-      background: #ffffff;
-      box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
-      border-radius: 10px;
-      padding: 14px 20px 20px 20px;
-      margin-right: 20px;
-
-      .fir {
-        display: flex;
-        justify-content: space-between;
-        margin-bottom: 10px;
-        margin-top: 11px;
-
-        .countCard {
-          margin-right: 20px;
-        }
-
-        .countCard:last-child {
-          margin-right: none;
-        }
-      }
-
-      .sec {
-        display: flex;
-        justify-content: space-between;
-
-        .countCard {
-          margin-right: 15px;
-        }
-
-        .countCard:last-child {
-          margin-right: none;
-        }
-      }
-
-      .countCard {
-        flex: 1;
-        background: linear-gradient(
-          180deg,
-          rgba(246, 246, 252, 0) 0%,
-          #f3f4f8 100%
-        );
-        box-shadow: inset 0px -1px 4px 0px #ffffff;
-        border-radius: 10px;
-        border: 1px solid #f1f1f1;
-        padding: 14px 20px 18px 14px;
-        display: flex;
-        justify-content: space-between;
-
-        .iconImg {
-          width: 30px;
-          height: 30px;
-          border-radius: 10px;
-        }
-
-        .iconImg:nth-child(1) {
-          box-shadow: 0px 7px 14px 0px rgba(14, 110, 253, 0.4);
-        }
-
-        .iconImg:nth-child(2) {
-          box-shadow: 0px 7px 14px 0px rgba(255, 102, 39, 0.5);
-        }
-
-        .iconImg:nth-child(3) {
-          box-shadow: 0px 7px 14px 0px rgba(254, 41, 94, 0.5);
-        }
-
-        .iconImg:nth-child(4) {
-          box-shadow: 0px 7px 14px 0px rgba(248, 204, 65, 0.5);
-        }
-
-        .iconImg:nth-child(5) {
-          box-shadow: 0px 7px 14px 0px rgba(2, 179, 118, 0.5);
-        }
-
-        .iconImg:nth-child(6) {
-          box-shadow: 0px 7px 14px 0px rgba(169, 14, 253, 0.4);
-        }
-
-        .iconImg:nth-child(7) {
-          box-shadow: 0px 7px 14px 0px rgba(109, 200, 236, 0.5);
-        }
-
-        .name {
-          font-weight: 500;
-          font-size: 12px;
-          color: rgba(0, 0, 0, 0.6);
-          line-height: 17px;
-          margin-top: 2px;
-        }
-
-        .num {
-          font-weight: 900;
-          font-size: 16px;
-          color: rgba(0, 0, 0, 0.8);
-          line-height: 19px;
-          text-align: right;
-          margin-top: 1px;
-        }
-      }
-    }
-
-    .carStatus {
-      flex: 5;
-      background: #ffffff;
-      box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
-      border-radius: 10px;
-      padding: 14px 84px 20px 84px;
-
-      .statusFir {
-        margin-top: 23px;
-        margin-bottom: 28px;
-        display: flex;
-        justify-content: space-between;
-        align-content: center;
-      }
-
-      .statusSec {
-        display: flex;
-        justify-content: space-between;
-        align-content: center;
-      }
-
-      .statusCard {
-        display: flex;
-        align-content: center;
-
-        .statusLeft {
-          margin-right: 9px;
-          display: flex;
-          flex-direction: column;
-          justify-content: center;
-
-          .name {
-            font-weight: 500;
-            font-size: 12px;
-            color: rgba(0, 0, 0, 0.6);
-            line-height: 17px;
-          }
-
-          .num {
-            font-weight: 900;
-            font-size: 16px;
-            color: rgba(0, 0, 0, 0.8);
-            line-height: 19px;
-          }
-        }
-
-        .progressCard {
-          width: 56px;
-          height: 56px;
-
-          ::v-deep .el-progress-circle {
-            width: 56px !important;
-            height: 56px !important;
-          }
-        }
-      }
-
-      .statusLine {
-        width: 1px;
-        height: 46px;
-        border: 1px solid #dedede;
-        box-sizing: border-box;
-      }
-    }
-  }
-
-  .right {
-    width: 493px;
-    height: calc(100% - 20px);
-    margin: 20px 17px 0 20px;
-    background: #ffffff;
-    box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
-    border-radius: 10px 10px 0px 0px;
-    padding: 20px;
-
-    .title {
-      margin-top: 30px;
-      font-weight: 600;
-      font-size: 18px;
-      color: rgba(0, 0, 0, 0.88);
-      line-height: 25px;
-      text-transform: none;
-      margin-bottom: 10px;
-    }
-
-    .firCard {
-      display: flex;
-      justify-content: space-between;
-
-      .companyCard {
-        width: 140px;
-        height: 90px;
-        background: #f4f4ff;
-        border-radius: 0px 10px 10px 0px;
-        position: relative;
-
-        .lineCard {
-          position: absolute;
-          left: 0;
-          top: 0;
-          width: 4px;
-          height: 90px;
-          background: #0e6efd;
-          border-radius: 2px;
-        }
-
-        .name {
-          margin: 18px 0 12px 19px;
-
-          font-size: 12px;
-          color: rgba(0, 0, 0, 0.6);
-          line-height: 17px;
-        }
-
-        .value {
-          margin-bottom: 22px;
-          text-align: center;
-          font-weight: 900;
-          font-size: 18px;
-          color: #0e6efd;
-          line-height: 21px;
-        }
-      }
-    }
-
-    .todayWarn {
-      .warnList {
-        height: 134px;
-        overflow-y: auto;
-
-        .warnItem {
-          height: 26px;
-          background: rgba(39, 129, 255, 0.06);
-          border-radius: 4px;
-          padding: 2px;
-          display: flex;
-          align-content: center;
-          margin-bottom: 10px;
-
-          .grade {
-            height: 22px;
-            background: #e6f4ff;
-            border-radius: 4px;
-            border: 1px solid #bae0ff;
-            margin-right: 11px;
-            box-sizing: border-box;
-            padding: 1px 8px;
-
-            font-weight: 400;
-            font-size: 12px;
-            color: #1677ff;
-            line-height: 20px;
-          }
-
-          .info {
-            font-size: 12px;
-            color: rgba(0, 0, 0, 0.8);
-            line-height: 26px;
-          }
-        }
-
-        .warnItem:last-child {
-          margin-bottom: 0 !important;
-        }
-
-        .oneWarn {
-          background: rgba(255, 77, 79, 0.06);
-
-          .grade {
-            background: #fff1f0;
-            border: 1px solid #ffccc7;
-            color: rgba(255, 77, 79, 1);
-          }
-        }
-
-        .twoWarn {
-          background: rgba(250, 173, 20, 0.06);
-
-          .grade {
-            background: #fffbe6;
-            border-radius: 4px;
-            border: 1px solid #fff1b8;
-            color: rgba(250, 173, 20, 1);
-          }
-        }
-
-        .threeWarn {
-          background: rgba(39, 129, 255, 0.06);
-
-          .grade {
-            background: #e6f4ff;
-            border: 1px solid #bae0ff;
-            color: #1677ff;
-          }
-        }
-
-        .fourWarn {
-          background: rgba(82, 196, 26, 0.06);
-
-          .grade {
-            background: #f6ffed;
-            border-radius: 4px;
-            border: 1px solid #d9f7be;
-            color: rgba(82, 196, 26, 1);
-          }
-        }
-        .fiveWarn {
-          background: rgba(214, 219, 228, 0.3);
-
-          .grade {
-            background: rgba(214, 219, 228, 0.3);
-            border-radius: 4px;
-            border: 1px solid rgba(214, 219, 228, 0.6);
-            color: rgba(0, 0, 0, 0.8);
-          }
-        }
-      }
-
-      .warnList::-webkit-scrollbar {
-        width: 8px;
-        height: 8px;
-        background-color: #f5f5f5;
-      }
-
-      .warnList::-webkit-scrollbar-thumb {
-        background-color: #ccc;
-        border-radius: 4px;
-      }
-
-      .warnList::-webkit-scrollbar-thumb:hover {
-        background-color: #aaa;
-      }
-    }
-
-    .warnCount {
-      position: relative;
-
-      #countChart {
-        width: 453px;
-        height: 150px;
-      }
-
-      .noData {
-        display: flex;
-        flex-direction: column;
-        align-content: center;
-        justify-content: center;
-        position: absolute;
-        bottom: 0;
-        left: 0;
-        width: 100%;
-        height: 150px;
-      }
-    }
-
-    .warnRank {
-      position: relative;
-
-      .rankChart {
-        width: 453px;
-        height: 300px;
-
-        .rankItem {
-          display: flex;
-          align-content: center;
-          margin-bottom: 14px;
-
-          .left {
-            flex: 2;
-            padding-right: 25px;
-            font-weight: 400;
-            font-size: 12px;
-            color: rgba(0, 0, 0, 0.45);
-            line-height: 17px;
-            text-align: right;
-          }
-
-          .rankRight {
-            flex: 5;
-            height: 15px;
-            background: rgba(93, 112, 146, 0.2);
-            border-radius: 8px;
-
-            .rank {
-              height: 15px;
-              border-radius: 8px;
-              background: rgba(93, 112, 146, 0.6);
-            }
-          }
-
-          .rankColor {
-            background: rgba(91, 143, 249, 0.2);
-
-            .rank {
-              background: rgba(91, 143, 249, 0.85);
-            }
-          }
-        }
-
-        .rankItem:last-child {
-          margin-bottom: 0 !important;
-        }
-      }
-
-      .noData {
-        display: flex;
-        flex-direction: column;
-        align-content: center;
-        justify-content: center;
-        position: absolute;
-        bottom: 0;
-        left: 0;
-        width: 100%;
-        height: 300px;
-      }
-    }
-  }
-}
+<template>
+  <div class="flex homePage">
+    <!-- 头部 -->
+    <div class="mapTop">
+      <!-- 车辆统计 -->
+      <div class="carCount">
+        <div class="title">车辆统计</div>
+        <div class="fir">
+          <div
+            class="countCard"
+            v-for="(item, index) in carCountData.slice(0, 3)"
+            :key="item.id"
+          >
+            <img class="iconImg" :src="imgList[index]" />
+            <div>
+              <div class="name">{{ item.name || "" }}(辆)</div>
+              <div class="num">{{ item.carNum || 0 }}</div>
+            </div>
+          </div>
+        </div>
+        <div class="sec">
+          <div
+            class="countCard"
+            v-for="(item, index) in carCountData.slice(3, 7)"
+            :key="item.id"
+          >
+            <img class="iconImg" :src="imgList[index + 3]" />
+            <div>
+              <div class="name">{{ item.name || "" }}(辆)</div>
+              <div class="num">{{ item.carNum || 0 }}</div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <!-- 车辆状态 -->
+      <div class="carStatus">
+        <div class="title">车辆状态</div>
+        <div class="statusFir">
+          <div class="statusCard">
+            <div class="statusLeft">
+              <div class="name">在线</div>
+              <div class="num">{{ carStatusData.online || 0 }}</div>
+            </div>
+            <el-progress
+              type="circle"
+              :width="20"
+              :show-text="false"
+              stroke-linecap="butt"
+              :percentage="carStatusData.onlinePercent"
+              color="rgba(91, 143, 249, 1)"
+              define-back-color="rgba(91, 143, 249, 0.25)"
+              class="progressCard"
+            ></el-progress>
+          </div>
+          <div class="statusLine"></div>
+          <div class="statusCard">
+            <div class="statusLeft">
+              <div class="name">离线</div>
+              <div class="num">{{ carStatusData.offline || 0 }}</div>
+            </div>
+            <el-progress
+              type="circle"
+              :width="20"
+              :show-text="false"
+              stroke-linecap="butt"
+              :percentage="carStatusData.offlinePercent"
+              color="rgba(93, 112, 146, 1)"
+              define-back-color="rgba(93, 112, 146, 0.25)"
+              class="progressCard"
+            ></el-progress>
+          </div>
+        </div>
+        <div class="statusSec">
+          <div class="statusCard">
+            <div class="statusLeft">
+              <div class="name">故障</div>
+              <div class="num">{{ carStatusData.breakdown || 0 }}</div>
+            </div>
+            <el-progress
+              type="circle"
+              :width="20"
+              :show-text="false"
+              stroke-linecap="butt"
+              :percentage="carStatusData.breakdownPercent"
+              color="rgba(253, 83, 118, 1)"
+              define-back-color="rgba(253, 83, 118, 0.25)"
+              class="progressCard"
+            ></el-progress>
+          </div>
+          <div class="statusLine"></div>
+          <div class="statusCard">
+            <div class="statusLeft">
+              <div class="name">异常</div>
+              <div class="num">{{ carStatusData.abnormal || 0 }}</div>
+            </div>
+            <el-progress
+              type="circle"
+              :width="20"
+              :show-text="false"
+              stroke-linecap="butt"
+              :percentage="carStatusData.abnormalPercent"
+              color="rgba(246, 189, 22, 1)"
+              define-back-color="rgba(246, 189, 22, 0.25)"
+              class="progressCard"
+            ></el-progress>
+          </div>
+        </div>
+      </div>
+    </div>
+    <!-- 左边 地图 -->
+    <div class="leftMap">
+      <div class="mapContainer" id="mapContainer"></div>
+    </div>
+    <!-- 右边 内容 -->
+    <div class="right">
+      <div class="firCard">
+        <div class="companyCard">
+          <div class="lineCard"></div>
+          <div class="name">运营公司(家)</div>
+          <div class="value">{{ carStatusData.enterprise || 0 }}</div>
+        </div>
+        <div class="companyCard">
+          <div class="lineCard"></div>
+          <div class="name">运营车辆(辆)</div>
+          <div class="value">{{ carStatusData.car || 0 }}</div>
+        </div>
+        <div class="companyCard">
+          <div class="lineCard"></div>
+          <div class="name">驾驶员(人)</div>
+          <div class="value">{{ carStatusData.driver || 0 }}</div>
+        </div>
+      </div>
+      <!-- 今日预警 -->
+      <div class="todayWarn">
+        <div class="title">今日预警</div>
+        <div class="warnList" v-if="warnList.length > 0">
+          <div
+            class="warnItem"
+            v-for="(item, index) in warnList"
+            :key="index"
+            :class="
+              item.warnLevel
+                ? ['oneWarn', 'twoWarn', 'threeWarn', 'fourWarn'][
+                    item.warnLevel - 1
+                  ]
+                : 'fiveWarn'
+            "
+          >
+            <div class="grade">
+              {{
+                item.warnLevel
+                  ? ["一级", "二级", "三级", "四级"][item.warnLevel - 1]
+                  : "-"
+              }}
+            </div>
+            <div class="info">
+              {{ item.vehicleNumber }} {{ item.warnType }} {{ item.keepTime }}
+              {{ item.startTime }}
+            </div>
+          </div>
+        </div>
+        <div class="noData" v-else>
+          <el-empty description="暂无数据" :image-size="80"></el-empty>
+        </div>
+      </div>
+      <!-- 预警情况统计 -->
+      <div class="warnCount">
+        <div class="title">预警情况统计</div>
+        <div class="countChart" id="countChart"></div>
+        <div class="noData" v-if="countList.length == 0">
+          <el-empty description="暂无数据" :image-size="80"></el-empty>
+        </div>
+      </div>
+      <!-- 预警排行榜(前10) -->
+      <div class="warnRank">
+        <div class="title">预警排行榜(前10)</div>
+        <div class="rankChart" id="rankChart">
+          <div class="rankItem" v-for="(item, index) in rankList" :key="index">
+            <div class="left">{{ item.name }}</div>
+            <div
+              class="rankRight"
+              :class="[0, 1, 2].includes(index) ? 'rankColor' : ''"
+            >
+              <div class="rank" :style="{ width: item.percentage + '%' }"></div>
+            </div>
+          </div>
+        </div>
+        <div class="noData" v-if="rankList.length == 0">
+          <el-empty description="暂无数据" :image-size="80"></el-empty>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as echarts from "echarts";
+import html2canvas from "html2canvas";
+import AMapLoader from "@amap/amap-jsapi-loader";
+import flvjs from "flv.js";
+import {
+  getCarCount,
+  getCarStatusCount,
+  getMapCarList,
+  getCarWarnList,
+  getWarnGroupCount,
+  getWarnGroupCountTop10,
+  getRealVideo,
+} from "./service";
+export default {
+  data() {
+    return {
+      flvPlayer: null,
+      activeIndex: "1",
+      activeIndex2: "1",
+      timer: null,
+      markers: [],
+      map: null,
+      AMap: null,
+      infoWindow: null,
+      imgList: [
+        require("../../assets//homeImg/img1.png"),
+        require("../../assets//homeImg/img2.png"),
+        require("../../assets//homeImg/img3.png"),
+        require("../../assets//homeImg/img4.png"),
+        require("../../assets//homeImg/img5.png"),
+        require("../../assets//homeImg/img6.png"),
+        require("../../assets//homeImg/img7.png"),
+      ],
+      countList: [], //预警情况统计数据
+      rankList: [], //预警排行榜数据
+      carList: [], //车辆列表数据
+      carCountData: [], //车辆统计数据
+      carStatusData: {}, //车辆状态数据
+      warnList: [], //预警列表数据
+    };
+  },
+  watch: {
+    map(val) {
+      if (val) {
+        HTMLCanvasElement.prototype.getContext = (function (origFn) {
+          return function (type, attributes) {
+            if (type.indexOf("webgl") > -1) {
+              attributes = Object.assign({}, attributes, {
+                preserveDrawingBuffer: true,
+              });
+            }
+            return origFn.call(this, type, attributes);
+          };
+        })(HTMLCanvasElement.prototype.getContext);
+      }
+    },
+  },
+  filters: {
+    
+  },
+
+  created() {
+    window.toCarDetail = (record) => {
+      this.toCarDetail(record);
+    };
+    window.fullScreen = () => {
+      this.fullScreen();
+    };
+    window.shotScreen = () => {
+      this.shotScreen();
+    };
+  },
+  mounted() {
+    // 调用所有接口
+    this.getCarCountData();
+    this.getCarStatusData();
+    // this.getMapCarData(); // 移除这里的调用,因为 initMap 中会调用
+    this.getWarnListData();
+    this.getWarnGroupData();
+    this.getWarnTop10Data();
+
+    this.initMap();
+    // 设置定时器,每分钟刷新一次数据
+    this.timer = setInterval(() => {
+      this.getCarCountData();
+      this.getCarStatusData();
+      this.getMapCarData(); // 保留定时器中的调用
+      this.getWarnListData();
+      this.getWarnGroupData();
+      this.getWarnTop10Data();
+    }, 60000);
+  },
+  beforeDestroy() {
+    if (this.timer) {
+      clearInterval(this.timer);
+    }
+    if (this.markers && this.markers.length > 0) {
+      this.markers.forEach((marker) => {
+        marker.setMap(null);
+      });
+      this.markers = [];
+    }
+    if (this.infoWindow) {
+      this.infoWindow.close();
+    }
+    if (this.flvPlayer) {
+      this.flvPlayer.destroy();
+      this.flvPlayer = null;
+    }
+  },
+  beforeRouteLeave(to, from, next) {
+    if (this.infoWindow) {
+      this.infoWindow.close();
+    }
+    if (this.flvPlayer) {
+      this.flvPlayer.destroy();
+      this.flvPlayer = null;
+    }
+    next();
+  },
+  methods: {
+    // 获取车辆统计数据
+    async getCarCountData() {
+      try {
+        const res = await getCarCount();
+        this.carCountData = res;
+      } catch (error) {
+        this.$message.error("获取车辆统计数据失败");
+      }
+    },
+    // 获取车辆状态数据
+    async getCarStatusData() {
+      try {
+        const res = await getCarStatusCount();
+        // 设置默认值为0,防止空值
+        const online = Number(res.online) || 0;
+        const offline = Number(res.offline) || 0;
+        const breakdown = Number(res.breakdown) || 0;
+        const abnormal = Number(res.abnormal) || 0;
+        const enterprise = Number(res.enterprise) || 0;
+        const car = Number(res.car) || 0;
+        const driver = Number(res.driver) || 0;
+
+        // 计算总数
+        const total = online + offline + breakdown + abnormal;
+
+        // 计算百分比,如果总数为0则百分比为0
+        const onlinePercent =
+          total > 0 ? Math.round((online / total) * 100) : 0;
+        const offlinePercent =
+          total > 0 ? Math.round((offline / total) * 100) : 0;
+        const breakdownPercent =
+          total > 0 ? Math.round((breakdown / total) * 100) : 0;
+        const abnormalPercent =
+          total > 0 ? Math.round((abnormal / total) * 100) : 0;
+        // 更新数据
+        this.carStatusData = {
+          online,
+          offline,
+          breakdown,
+          abnormal,
+          enterprise,
+          car,
+          driver,
+          total,
+          onlinePercent,
+          offlinePercent,
+          breakdownPercent,
+          abnormalPercent,
+        };
+      } catch (error) {
+        this.$message.error("获取车辆状态数据失败");
+        // 设置默认值
+        this.carStatusData = {
+          online: 0,
+          offline: 0,
+          breakdown: 0,
+          abnormal: 0,
+          enterprise: 0,
+          car: 0,
+          driver: 0,
+          total: 0,
+          onlinePercent: 0,
+          offlinePercent: 0,
+          breakdownPercent: 0,
+          abnormalPercent: 0,
+        };
+      }
+    },
+    // 获取地图车辆数据
+    async getMapCarData() {
+      try {
+        const res = await getMapCarList();
+        this.carList = res;
+        // 确保地图已初始化后再更新标记
+        if (this.AMap && this.map) {
+          this.updateMarkers(res);
+        }
+      } catch (error) {
+        this.$message.error("获取地图车辆数据失败");
+      }
+    },
+    // 获取预警列表数据
+    async getWarnListData() {
+      try {
+        const res = await getCarWarnList();
+        this.warnList = res.records;
+      } catch (error) {
+        this.$message.error("获取预警列表数据失败");
+      }
+    },
+    // 获取预警统计情况数据
+    async getWarnGroupData() {
+      try {
+        const res = await getWarnGroupCount();
+        this.countList = res;
+        this.getCountList();
+      } catch (error) {
+        this.$message.error("获取预警统计情况数据失败");
+      }
+    },
+    // 获取预警排行数据
+    async getWarnTop10Data() {
+      try {
+        const res = await getWarnGroupCountTop10();
+        // 判断返回的数组是否为空
+        if (!res || res.length === 0) {
+          this.rankList = [];
+          return;
+        }
+        // 计算所有num的总和
+        const total = res.reduce((sum, item) => sum + (item.num || 0), 0);
+        // 为每个数据项添加百分比属性
+        this.rankList = res.map((item) => ({
+          ...item,
+          percentage:
+            total > 0 ? (((item.num || 0) / total) * 100).toFixed(2) : 0,
+        }));
+      } catch (error) {
+        this.$message.error("获取预警排行数据失败");
+        this.rankList = [];
+      }
+    },
+    // 初始化地图
+    initMap() {
+      window._AMapSecurityConfig = {
+        securityJsCode: this.$secretKey,
+      };
+      AMapLoader.load({
+        key: this.$mapKey,
+        version: "2.0",
+        plugins: [
+          "AMap.ToolBar",
+          "AMap.AutoComplete",
+          "AMap.Geocoder",
+          "AMap.MarkerCluster",
+          "AMap.Geocoder",
+        ],
+      })
+        .then((AMap) => {
+          this.AMap = AMap;
+          this.map = new AMap.Map("mapContainer", {
+            center: [105.574542, 30.5061493],
+            zoom: 8,
+          });
+          this.infoWindow = new AMap.InfoWindow({
+            offset: new AMap.Pixel(30, 30),
+            autoMove: true,
+            anchor: "top-center",
+          });
+          this.getMapCarData();
+        })
+        .catch((e) => {
+          this.$message.error("地图加载失败");
+        });
+    },
+    // 更新地图标记
+    updateMarkers(arr) {
+      if (!this.AMap) {
+        return;
+      }
+      if (this.markers && this.markers.length > 0) {
+        this.markers.forEach((marker) => {
+          marker.setMap(null);
+        });
+        this.markers = [];
+      }
+
+      if (arr.length > 0) {
+        const iconMap = {
+          出租车: {
+            icon: require("../../assets/homeImg/taxi.png"),
+            size: new this.AMap.Size(75, 37),
+          },
+          公交车: {
+            icon: require("../../assets/homeImg/bus.png"),
+            size: new this.AMap.Size(62, 34),
+          },
+          危险品: {
+            icon: require("../../assets/homeImg/risk.png"),
+            size: new this.AMap.Size(69, 32),
+          },
+          郊游: {
+            icon: require("../../assets/homeImg/outing.png"),
+            size: new this.AMap.Size(61, 31),
+          },
+          货运: {
+            icon: require("../../assets/homeImg/expressage.png"),
+            size: new this.AMap.Size(60, 31),
+          },
+          网约车: {
+            icon: require("../../assets/homeImg/online.png"),
+            size: new this.AMap.Size(75, 33),
+          },
+          客运: {
+            icon: require("../../assets/homeImg/passenger.png"),
+            size: new this.AMap.Size(69, 31),
+          },
+        };
+
+        arr.forEach((item, index) => {
+          // 检查必要字段
+          if (!item.operateType || !item.longitude || !item.latitude) {
+            return;
+          }
+
+          const iconConfig = iconMap[item.operateType];
+          if (!iconConfig) {
+            return;
+          }
+
+          let marker = new this.AMap.Marker({
+            position: [Number(item.longitude), Number(item.latitude)],
+            map: this.map,
+            icon: new this.AMap.Icon({
+              size: iconConfig.size,
+              image: iconConfig.icon,
+              imageSize: iconConfig.size,
+              imageOffset: new this.AMap.Pixel(0, 0),
+            }),
+          });
+
+          // 添加点击事件
+          marker.on("click", async (e) => {
+            // 如果已经有视频在播放,先销毁
+            if (this.flvPlayer) {
+              this.flvPlayer.destroy();
+              this.flvPlayer = null;
+            }
+
+            // 显示loading
+            this.infoWindow.setContent(
+              '<div style="padding: 20px;text-align: center;">加载中...</div>'
+            );
+            this.infoWindow.open(this.map, e.target.getPosition());
+
+            try {
+              // 使用高德地图API获取地址信息
+              const geocoder = new this.AMap.Geocoder();
+              const location = [Number(item.longitude), Number(item.latitude)];
+
+              const [addressResult, videoRes] = await Promise.all([
+                new Promise((resolve) => {
+                  geocoder.getAddress(location, (status, result) => {
+                    if (status === "complete" && result.regeocode) {
+                      console.log("result", result,'status',status);
+                      resolve(result.regeocode.formattedAddress);
+                    } else {
+                      resolve("未知地址");
+                    }
+                  });
+                }),
+                this.getVideoUrl(item.id),
+              ]);
+
+              // 更新弹窗内容
+              this.infoWindow.setContent(
+                this.listRender({
+                  ...item,
+                  drivingTime:this.formatterTime(item.drivingTime || 0) ,
+                  location: addressResult,
+                  videoUrl: videoRes.url,
+                })
+              );
+
+              this.initVideoPlayer(videoRes.url);
+            } catch (error) {
+              this.infoWindow.setContent(
+                '<div style="padding: 20px;text-align: center;color: red;">获取车辆信息失败</div>'
+              );
+            }
+          });
+
+          // 将marker添加到数组中
+          this.markers.push(marker);
+        });
+      }
+    },
+    // 获取视频地址
+    async getVideoUrl(carId) {
+      try {
+        const res = await getRealVideo({ id: carId });
+        // 将RTSP流转换为FLV流
+        const flvUrl = this.convertRtspToFlv(res.url);
+        return {
+          url: flvUrl
+        };
+      } catch (error) {
+        console.error("获取视频地址失败", error);
+        return {
+          url: ""
+        };
+      }
+    },
+
+    // RTSP转FLV
+    convertRtspToFlv(rtspUrl) {
+      // 这里需要根据实际的流媒体服务器地址进行修改
+      // 假设流媒体服务器地址为 http://your-media-server:8080
+      const mediaServer = "http://101.206.211.65:18042";
+      // 从RTSP URL中提取流标识
+      const streamId = rtspUrl.split("/").pop();
+      // 返回FLV流地址
+      return `${mediaServer}/live/${streamId}.flv`;
+    },
+
+    // 初始化视频播放器
+    initVideoPlayer(videoUrl) {
+      // 先销毁之前的播放器
+      if (this.flvPlayer) {
+        this.flvPlayer.destroy();
+        this.flvPlayer = null;
+      }
+
+      // 获取video元素
+      const video = document.getElementById("monitoringCard");
+      if (!video) {
+        console.error("Video element not found");
+        return;
+      }
+
+      // 检查flv.js是否支持
+      if (flvjs.isSupported()) {
+        try {
+          this.flvPlayer = flvjs.createPlayer({
+            type: "flv",
+            isLive: true,
+            cors: true,
+            hasAudio: true,
+            hasVideo: true,
+            url: videoUrl,
+            enableWorker: true,
+            enableStashBuffer: false,
+            seekType: "range",
+          });
+
+          this.flvPlayer.attachMediaElement(video);
+          this.flvPlayer.load();
+          this.flvPlayer.play().catch(error => {
+            console.error("视频播放失败:", error);
+          });
+        } catch (error) {
+          console.error("创建播放器失败:", error);
+        }
+      } else {
+        console.error("当前浏览器不支持flv.js");
+      }
+    },
+
+    // 处理视频错误
+    handleVideoError(event) {
+      console.error("视频加载失败", event);
+      if (this.flvPlayer) {
+        this.flvPlayer.destroy();
+        this.flvPlayer = null;
+      }
+      this.infoWindow.setContent(
+        '<div style="padding: 20px;text-align: center;color: red;">视频加载失败,请稍后重试</div>'
+      );
+    },
+
+    listRender(record) {
+      return `<div style="background: #ffffff; padding: 24px 20px;z-index: 999">
+        <div style="position: relative; width: 460px; height: 330px">
+          <video
+            crossorigin="anonymous" 
+            style="width: 460px; height: 330px; border-radius: 9px" 
+            id="monitoringCard"
+            autoplay
+            playsinline
+            preload="auto"
+            @error="handleVideoError"
+            width="620">
+          </video>
+          <div style="position: absolute; right: 11px; top: 10px">
+            <div style="display: flex;flex-direction: column;align-items: center;justify-content: center;
+              background: #ffffff; padding: 3px 10px; border-radius: 6px;margin-bottom: 10px;" onclick="fullScreen()">
+              <img style="width: 20px; height: 20px" src="${require("../../assets//homeImg/full.png")}" />
+              <div style="font-size: 12px;font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);">全屏</div>
+            </div>
+            <div style="display: flex;flex-direction: column;align-items: center; justify-content: center;
+              background: #ffffff;padding: 3px 10px;border-radius: 6px;" onclick="shotScreen()">
+              <img style="width: 20px; height: 20px" src="${require("../../assets//homeImg/slot.png")}" />
+              <div style="font-size: 12px; font-weight: 400; line-height: 17px; color: rgba(0, 0, 0, 0.88);">截屏</div>
+            </div>
+          </div>
+        </div>
+        <div style="display: flex;justify-content: space-between;margin-top: 15px;margin-bottom: 12px;">
+          <div style="font-weight: 500;font-size: 18px;color: rgba(0, 0, 0, 0.85);line-height: 25px;">车牌号:${
+            record.vehicleNumber || ""
+          }</div>
+          <div style="font-weight: 500; font-size: 18px;color: rgba(0, 0, 0, 0.85);line-height: 25px;">驾驶员:${
+            record.driverName || ""
+          }</div>
+        </div>
+        <div style="display: flex; justify-content: space-between">
+          <div style="font-weight: 500; font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;width: 200px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;" title="${record.location}">位置:${
+            record.location
+          }</div>
+          <div style="font-weight: 500;font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;">经纬度:${
+            record.longitude + "," + record.latitude
+          }</div>
+        </div>
+        <div style="display: flex; justify-content: space-between">
+          <div style="font-weight: 500;font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;">当前时速:${
+            record.speed || ""
+          }${record.speed && "km/h"}</div>
+          <div style="font-weight: 500;font-size: 14px; color: rgba(0, 0, 0, 0.65);line-height: 26px;">驾驶时长:${
+            record.drivingTime
+          }</div>
+        </div>
+        <div style="margin-top: 14px;display: flex;justify-content: flex-end;align-items: center;cursor: pointer;" onclick="toCarDetail(${
+          record.id
+        })">
+          <div style="font-weight: 400;font-size: 18px; color: rgba(22, 119, 255, 1);line-height: 25px;">车辆详情</div>
+          <img style="width:18px;height: 18px;margin-left: 8px;" src="${require("../../assets//homeImg/right.png")}" />
+        </div>
+      </div>`;
+    },
+    formatterTime(value) {
+      if (!value) return "";
+      const hours = Math.floor(value / 60);
+      const minutes = value % 60;
+      if (hours > 0) {
+        return `${hours}小时${minutes}分钟`;
+      } else {
+        return `${minutes}分钟`;
+      }
+    },
+    // 获取预警情况统计
+    getCountList() {
+      echarts.dispose(document.getElementById("countChart"));
+      if (this.countList.length > 0) {
+        this.chartTnit();
+      }
+    },
+    chartTnit() {
+      // 基于准备好的dom,初始化echarts实例
+      const myChart = echarts.init(document.getElementById("countChart"));
+      // 绘制数量图表
+      myChart.setOption({
+        tooltip: {
+          trigger: "axis",
+          axisPointer: {
+            type: "shadow",
+          },
+        },
+        grid: {
+          width: "auto",
+          height: "auto",
+          top: "5%",
+          left: "3%",
+          right: "4%",
+          bottom: "0%",
+          containLabel: true,
+        },
+        xAxis: [
+          {
+            type: "category",
+            data: this.countList.map((item) => item.warnType),
+            axisTick: {
+              alignWithLabel: true,
+              lineStyle: {
+                color: "#777777",
+              },
+            },
+            axisLabel: {
+              color: "rgba(0, 0, 0, 0.45)",
+            },
+          },
+        ],
+        yAxis: [
+          {
+            type: "value",
+          },
+        ],
+        series: [
+          {
+            type: "bar",
+            barWidth: "20px",
+            itemStyle: {
+              borderRadius: [20, 20, 20, 20],
+              color: (params) => {
+                return ["#5B8FF9", "#5AD8A6", "#F6BD16", "#6DC8EC", "#945FB9"][
+                  params.dataIndex
+                ];
+              },
+            },
+            data: this.countList.map((item) => item.num),
+          },
+        ],
+      });
+      myChart.resize();
+    },
+
+    // 跳转车辆详情
+    toCarDetail(id) {
+      this.$router.push({
+        path: "/car-detail",
+        query: {
+          id: id,
+        },
+      });
+    },
+    fullScreen() {
+      const video = document.getElementById("monitoringCard");
+      if (video.requestFullscreen) {
+        video.requestFullscreen();
+      } else if (video.mozRequestFullScreen) {
+        // Firefox
+        video.mozRequestFullScreen();
+      } else if (video.webkitRequestFullscreen) {
+        // Chrome, Safari and Opera
+        video.webkitRequestFullscreen();
+      } else if (video.msRequestFullscreen) {
+        // IE/Edge
+        video.msRequestFullscreen();
+      }
+    },
+    shotScreen() {
+      // 获取video和canvas元素
+      const video = document.getElementById("monitoringCard");
+      const canvas = document.getElementById("myCanvas");
+      // 设置canvas的宽度和高度与video相同
+      canvas.width = video.videoWidth;
+      canvas.height = video.videoHeight;
+      // 获取canvas的2d绘图上下文
+      const context = canvas.getContext("2d");
+      // 将当前video帧绘制到canvas上
+      context.drawImage(video, 0, 0, canvas.width, canvas.height);
+
+      setTimeout(() => {
+        // 将canvas内容转换为图片
+        let dataURL = canvas.toDataURL("image/png");
+        this.downloadImage(dataURL);
+      }, 100);
+    },
+    downloadImage(base64) {
+      const link = document.createElement("a");
+      link.href = base64;
+      link.download = "screenshot.png"; // 你希望下载的文件名
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+    },
+  },
+};
+</script>
+
+<style scoped lang="less">
+.homePage {
+  display: flex;
+  height: 100vh;
+  position: relative;
+
+  .leftMap {
+    // width: 100%;
+    height: 100%;
+    flex: 1;
+    display: flex;
+    position: relative;
+
+    #mapContainer {
+      flex: 1;
+      width: 100%;
+      height: 100%;
+    }
+  }
+  .mapTop {
+    z-index: 99;
+    position: absolute;
+    top: 20px;
+    left: 20px;
+    right: 513px;
+    display: flex;
+    justify-content: space-between;
+    width: calc(100% - 570px);
+
+    .title {
+      font-weight: 600;
+      font-size: 18px;
+      color: #000000;
+      line-height: 25px;
+      text-transform: none;
+      text-align: center;
+    }
+
+    .carCount {
+      flex: 8;
+      background: #ffffff;
+      box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
+      border-radius: 10px;
+      padding: 14px 20px 20px 20px;
+      margin-right: 20px;
+
+      .fir {
+        display: flex;
+        justify-content: space-between;
+        margin-bottom: 10px;
+        margin-top: 11px;
+
+        .countCard {
+          margin-right: 20px;
+        }
+
+        .countCard:last-child {
+          margin-right: none;
+        }
+      }
+
+      .sec {
+        display: flex;
+        justify-content: space-between;
+
+        .countCard {
+          margin-right: 15px;
+        }
+
+        .countCard:last-child {
+          margin-right: none;
+        }
+      }
+
+      .countCard {
+        flex: 1;
+        background: linear-gradient(
+          180deg,
+          rgba(246, 246, 252, 0) 0%,
+          #f3f4f8 100%
+        );
+        box-shadow: inset 0px -1px 4px 0px #ffffff;
+        border-radius: 10px;
+        border: 1px solid #f1f1f1;
+        padding: 14px 20px 18px 14px;
+        display: flex;
+        justify-content: space-between;
+
+        .iconImg {
+          width: 30px;
+          height: 30px;
+          border-radius: 10px;
+        }
+
+        .iconImg:nth-child(1) {
+          box-shadow: 0px 7px 14px 0px rgba(14, 110, 253, 0.4);
+        }
+
+        .iconImg:nth-child(2) {
+          box-shadow: 0px 7px 14px 0px rgba(255, 102, 39, 0.5);
+        }
+
+        .iconImg:nth-child(3) {
+          box-shadow: 0px 7px 14px 0px rgba(254, 41, 94, 0.5);
+        }
+
+        .iconImg:nth-child(4) {
+          box-shadow: 0px 7px 14px 0px rgba(248, 204, 65, 0.5);
+        }
+
+        .iconImg:nth-child(5) {
+          box-shadow: 0px 7px 14px 0px rgba(2, 179, 118, 0.5);
+        }
+
+        .iconImg:nth-child(6) {
+          box-shadow: 0px 7px 14px 0px rgba(169, 14, 253, 0.4);
+        }
+
+        .iconImg:nth-child(7) {
+          box-shadow: 0px 7px 14px 0px rgba(109, 200, 236, 0.5);
+        }
+
+        .name {
+          font-weight: 500;
+          font-size: 12px;
+          color: rgba(0, 0, 0, 0.6);
+          line-height: 17px;
+          margin-top: 2px;
+        }
+
+        .num {
+          font-weight: 900;
+          font-size: 16px;
+          color: rgba(0, 0, 0, 0.8);
+          line-height: 19px;
+          text-align: right;
+          margin-top: 1px;
+        }
+      }
+    }
+
+    .carStatus {
+      flex: 5;
+      background: #ffffff;
+      box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
+      border-radius: 10px;
+      padding: 14px 84px 20px 84px;
+
+      .statusFir {
+        margin-top: 23px;
+        margin-bottom: 28px;
+        display: flex;
+        justify-content: space-between;
+        align-content: center;
+      }
+
+      .statusSec {
+        display: flex;
+        justify-content: space-between;
+        align-content: center;
+      }
+
+      .statusCard {
+        display: flex;
+        align-content: center;
+
+        .statusLeft {
+          margin-right: 9px;
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+
+          .name {
+            font-weight: 500;
+            font-size: 12px;
+            color: rgba(0, 0, 0, 0.6);
+            line-height: 17px;
+          }
+
+          .num {
+            font-weight: 900;
+            font-size: 16px;
+            color: rgba(0, 0, 0, 0.8);
+            line-height: 19px;
+          }
+        }
+
+        .progressCard {
+          width: 56px;
+          height: 56px;
+
+          ::v-deep .el-progress-circle {
+            width: 56px !important;
+            height: 56px !important;
+          }
+        }
+      }
+
+      .statusLine {
+        width: 1px;
+        height: 46px;
+        border: 1px solid #dedede;
+        box-sizing: border-box;
+      }
+    }
+  }
+
+  .right {
+    width: 493px;
+    height: calc(100% - 20px);
+    margin: 20px 17px 0 20px;
+    background: #ffffff;
+    box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
+    border-radius: 10px 10px 0px 0px;
+    padding: 20px;
+
+    .title {
+      margin-top: 30px;
+      font-weight: 600;
+      font-size: 18px;
+      color: rgba(0, 0, 0, 0.88);
+      line-height: 25px;
+      text-transform: none;
+      margin-bottom: 10px;
+    }
+
+    .firCard {
+      display: flex;
+      justify-content: space-between;
+
+      .companyCard {
+        width: 140px;
+        height: 90px;
+        background: #f4f4ff;
+        border-radius: 0px 10px 10px 0px;
+        position: relative;
+
+        .lineCard {
+          position: absolute;
+          left: 0;
+          top: 0;
+          width: 4px;
+          height: 90px;
+          background: #0e6efd;
+          border-radius: 2px;
+        }
+
+        .name {
+          margin: 18px 0 12px 19px;
+
+          font-size: 12px;
+          color: rgba(0, 0, 0, 0.6);
+          line-height: 17px;
+        }
+
+        .value {
+          margin-bottom: 22px;
+          text-align: center;
+          font-weight: 900;
+          font-size: 18px;
+          color: #0e6efd;
+          line-height: 21px;
+        }
+      }
+    }
+
+    .todayWarn {
+      .warnList {
+        height: 134px;
+        overflow-y: auto;
+
+        .warnItem {
+          height: 26px;
+          background: rgba(39, 129, 255, 0.06);
+          border-radius: 4px;
+          padding: 2px;
+          display: flex;
+          align-content: center;
+          margin-bottom: 10px;
+
+          .grade {
+            height: 22px;
+            background: #e6f4ff;
+            border-radius: 4px;
+            border: 1px solid #bae0ff;
+            margin-right: 11px;
+            box-sizing: border-box;
+            padding: 1px 8px;
+
+            font-weight: 400;
+            font-size: 12px;
+            color: #1677ff;
+            line-height: 20px;
+          }
+
+          .info {
+            font-size: 12px;
+            color: rgba(0, 0, 0, 0.8);
+            line-height: 26px;
+          }
+        }
+
+        .warnItem:last-child {
+          margin-bottom: 0 !important;
+        }
+
+        .oneWarn {
+          background: rgba(255, 77, 79, 0.06);
+
+          .grade {
+            background: #fff1f0;
+            border: 1px solid #ffccc7;
+            color: rgba(255, 77, 79, 1);
+          }
+        }
+
+        .twoWarn {
+          background: rgba(250, 173, 20, 0.06);
+
+          .grade {
+            background: #fffbe6;
+            border-radius: 4px;
+            border: 1px solid #fff1b8;
+            color: rgba(250, 173, 20, 1);
+          }
+        }
+
+        .threeWarn {
+          background: rgba(39, 129, 255, 0.06);
+
+          .grade {
+            background: #e6f4ff;
+            border: 1px solid #bae0ff;
+            color: #1677ff;
+          }
+        }
+
+        .fourWarn {
+          background: rgba(82, 196, 26, 0.06);
+
+          .grade {
+            background: #f6ffed;
+            border-radius: 4px;
+            border: 1px solid #d9f7be;
+            color: rgba(82, 196, 26, 1);
+          }
+        }
+        .fiveWarn {
+          background: rgba(214, 219, 228, 0.3);
+
+          .grade {
+            background: rgba(214, 219, 228, 0.3);
+            border-radius: 4px;
+            border: 1px solid rgba(214, 219, 228, 0.6);
+            color: rgba(0, 0, 0, 0.8);
+          }
+        }
+      }
+
+      .warnList::-webkit-scrollbar {
+        width: 8px;
+        height: 8px;
+        background-color: #f5f5f5;
+      }
+
+      .warnList::-webkit-scrollbar-thumb {
+        background-color: #ccc;
+        border-radius: 4px;
+      }
+
+      .warnList::-webkit-scrollbar-thumb:hover {
+        background-color: #aaa;
+      }
+    }
+
+    .warnCount {
+      position: relative;
+
+      #countChart {
+        width: 453px;
+        height: 150px;
+      }
+
+      .noData {
+        display: flex;
+        flex-direction: column;
+        align-content: center;
+        justify-content: center;
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        width: 100%;
+        height: 150px;
+      }
+    }
+
+    .warnRank {
+      position: relative;
+
+      .rankChart {
+        width: 453px;
+        height: 300px;
+
+        .rankItem {
+          display: flex;
+          align-content: center;
+          margin-bottom: 14px;
+
+          .left {
+            flex: 2;
+            padding-right: 25px;
+            font-weight: 400;
+            font-size: 12px;
+            color: rgba(0, 0, 0, 0.45);
+            line-height: 17px;
+            text-align: right;
+          }
+
+          .rankRight {
+            flex: 5;
+            height: 15px;
+            background: rgba(93, 112, 146, 0.2);
+            border-radius: 8px;
+
+            .rank {
+              height: 15px;
+              border-radius: 8px;
+              background: rgba(93, 112, 146, 0.6);
+            }
+          }
+
+          .rankColor {
+            background: rgba(91, 143, 249, 0.2);
+
+            .rank {
+              background: rgba(91, 143, 249, 0.85);
+            }
+          }
+        }
+
+        .rankItem:last-child {
+          margin-bottom: 0 !important;
+        }
+      }
+
+      .noData {
+        display: flex;
+        flex-direction: column;
+        align-content: center;
+        justify-content: center;
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        width: 100%;
+        height: 300px;
+      }
+    }
+  }
+}
 </style>
\ No newline at end of file

--
Gitblit v1.7.1