zmc
2023-10-12 f3acb8ce787f3df0eda633031473be4e6a9ff448
油烟 更新了实时监控页面
已修改25个文件
已删除1个文件
已添加2个文件
3369 ■■■■ 文件已修改
dist.zip 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/login.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/login.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/layout/AppAside.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/layout/AppLayout.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/ExceptionText.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/ExceptionType.vue 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/ExceptionTypeLineChart.vue 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/FanPurifierChart.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/FumeConcentrationChart.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/ShopNameAndID.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/ShopNameSelect.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/sfc/TimeSelect.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/TestDrawer.vue 1154 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/test/TestSelect.vue 1763 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/request.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/requestPy.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ExceedingFume.vue 177 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/HistoryFume.vue 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/IndexView.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/LoginInterface.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/analysis/DataShow.vue 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/analysis/HomePage.vue 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/analysis/graph/AllRate.vue 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/analysis/graph/DayData.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/getdata/GetData.vue 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vue3-project-1.zip 补丁 | 查看 | 原始文档 | blame | 历史
dist.zip
Binary files differ
src/assets/login.jpg
Binary files differ
src/assets/login.png
src/components/layout/AppAside.vue
@@ -54,7 +54,7 @@
        <!--  :collapse="isCollapse" -->
        <a href="/hdata" class="logo" >
          <!-- <img src="@/assets/companylogo.png" alt="" /> -->
          <h1 style="margin-left: 30px;">油烟在线监测</h1>
          <h1 style="margin-left: 30px;">餐饮油烟在线监测</h1>
        </a>
      </el-space>
src/components/layout/AppLayout.vue
@@ -22,7 +22,7 @@
      <el-container class="header-and-main">
        <AppHeader/>
        <el-main class="main-content">
          <RouterView/>
            <RouterView/>
        </el-main>
      </el-container>
    </el-container>
src/router/index.ts
@@ -1,7 +1,6 @@
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
  // history: createWebHistory(import.meta.env.BASE_URL),
  history: createWebHashHistory(),
  routes: [
    {
src/sfc/ExceptionText.vue
@@ -17,7 +17,7 @@
    methods: {
        
        requestExceptionData(){
            axiosInstance.get('/fume/abnormaltwo',{params:{"devId":this.devId,"exceptionValue":this.exceptionValue,"beginTime":this.beginTime,"endTime":this.endTime }}).then(result =>{
            axiosInstance.get('/fume/abnormalthree',{params:{"devId":this.devId,"exceptionValue":this.exceptionValue,"beginTime":this.beginTime,"endTime":this.endTime }}).then(result =>{
                //将返回的结果传递给父组件
                this.$emit('submitExceptionData',result.data.data)
            })
src/sfc/ExceptionType.vue
@@ -27,9 +27,6 @@
  },
  mounted(){
    this.getShopName()
    setTimeout(() => {
        console.log(this.exceptionType);
    }, 1000);
  }
};
</script>
src/sfc/ExceptionTypeLineChart.vue
@@ -2,7 +2,11 @@
子组件有基本的样式 
使用同一个图形实例,接受父组件传入的折线图option
**父组件
 <ExceptionTypeLineChart
        :option="option"
        :is-open-dialog="centerDialogVisible"
        v-loading="chartLoading"
      ></ExceptionTypeLineChart>
 -->
<template>
  <div  id="main" class="line-chart"></div>
@@ -21,7 +25,8 @@
    },
    isOpenDialog:{
      type:Boolean
    }
    },
  },
  data() {
    return {
@@ -29,6 +34,8 @@
    };
  },
  mounted() {
     // 获取页面宽度的一半
    this.initChart();
    this.chart.clear
    this.chart.setOption(this.option,true)
@@ -44,8 +51,7 @@
    },
    isOpenDialog(){
      window.addEventListener('resize', this.resizeChart);
      console.log('调用了');
    }
    },
  },
  beforeUnmount() {
    if (this.chart) {
@@ -97,7 +103,12 @@
    // 跟页面响应式变化
    resizeChart() {
      this.chart.resize();
      this.$nextTick(() => {
        if (this.chart) {
          this.chart.resize();
        }
      });
      // this.chart.resize();
    }
  }
};
@@ -106,10 +117,10 @@
<style>
.line-chart {
  width: 100%;
  width:920px;
  height: 300px;
  margin-bottom: 20px;
  margin-left: 10px;
  min-width: 350px;
  /* margin-left: 10px; */
  min-width: 600px;
}
</style>
src/sfc/FanPurifierChart.vue
@@ -18,7 +18,6 @@
  methods: {
    //写好后端对应即可
    drawChart() {
      console.log('传递数据为风机店', this.minuteData);
      // x轴日期时间
      let dateList = [];
       // 历史风机电
src/sfc/FumeConcentrationChart.vue
@@ -20,7 +20,6 @@
  methods: {
    //写好后端对应即可
    drawChart() {
      console.log('传递数据为', this.minuteData);
      // x轴日期时间
      let dateList = [];
      // 历史油烟浓度
src/sfc/ShopNameAndID.vue
@@ -52,7 +52,6 @@
              ]
            };
          });
          console.log(this.optionsShop);
        });
        
        // 打开时默认展示一个店铺
src/sfc/ShopNameSelect.vue
@@ -22,7 +22,6 @@
                    this.shopNames.push(item.diName)
                 }
                 );
                console.log(response.data.data);
            })
        }
     }
src/sfc/TimeSelect.vue
@@ -34,7 +34,7 @@
  methods:{
    initOneWeekAgoTime(){
      // 给时间选择器设置默认时间为一周前
    this.time[0] = dayjs().subtract(3, 'week').format('YYYY-MM-DD HH:mm:ss');
    this.time[0] = dayjs().subtract(4, 'week').format('YYYY-MM-DD HH:mm:ss');
    this.time[1] = dayjs().format('YYYY-MM-DD HH:mm:ss');
    }
  }
src/test/TestDrawer.vue
@@ -1,429 +1,438 @@
<template>
  <el-row ref="h1">
  <el-col>
    <!-- 菜单读标题 -->
    <div ref="h1" class="header-container">
      <span class="describe-info">店铺名选择:</span>
      <!-- 店铺名  级联 -->
      <ShopNameAndID
        @submit-id="(n) => (deviceId[1] = n)"
      ></ShopNameAndID>
    <el-col>
      <!-- 菜单读标题 -->
      <div ref="h1" class="header-container">
        <span class="describe-info">店铺名选择:</span>
        <!-- 店铺名  级联 -->
        <ShopNameAndID @submit-id="(n) => (deviceId[1] = n)"></ShopNameAndID>
      <!-- 异常类型选择 -->
      <ExceptionType @submitExceptionType="(val) => (exceptionValue = val)">
      </ExceptionType>
        <!-- 异常类型选择 -->
        <ExceptionType @submitExceptionType="(val) => (exceptionValue = val)">
        </ExceptionType>
      <TimeSelect @submit-time="giveTime"></TimeSelect>
      <!-- </div> -->
    </div>
    <div
      ref="h2"
      style="display: flex; margin-top: 2px; justify-content: right"
    >
      <el-button
        type="primary"
        plain
        @click="showTable"
        style="margin-left: 20px"
        >查询</el-button
        <TimeSelect @submit-time="giveTime"></TimeSelect>
      </div>
      <div
        ref="h2"
        style="display: flex; margin-top: 2px; justify-content: right"
      >
      <el-tooltip
        class="box-item"
        effect="dark"
        content="点击可导出Excel文件"
        placement="top-start"
      >
        <!-- 做成函数js文件 -->
        <el-icon
          class="iconExcel clickable"
          title="导出Excel文件"
          @click="exportDom"
        <el-button
          type="primary"
          plain
          @click="showTable"
          style="margin-left: 20px"
          :loading="button.queryButton"
          >查询</el-button
        >
          <i-ep-Download />
          <!-- 导出为Excel -->
        </el-icon>
      </el-tooltip>
    </div>
    <div style="display: flex; justify-content: right;margin-right:40px">
      <span class="collapse-header-text">
        静安区 {{ beginTime }} —— {{ endTime }} 油烟检测异常信息汇总</span
      >
    </div>
    <br />
    <el-collapse ref="h3" v-model="activeNames">
      <el-collapse-item name="1">
        <template #title>
          <el-tooltip
            class="box-item"
            effect="dark"
            content="点击可折叠"
            placement="right-start"
        <el-tooltip
          class="box-item"
          effect="dark"
          content="点击可导出Excel文件"
          placement="top-start"
        >
          <!-- 做成函数js文件 -->
          <el-icon
            class="iconExcel clickable"
            title="导出Excel文件"
            @click="exportDom"
          >
            <h4 class="collapse-header">异常分析</h4>
            <el-icon class="header-icon">
              <i-ep-info-filled />
            </el-icon>
          </el-tooltip>
            <i-ep-Download />
            <!-- 导出为Excel -->
          </el-icon>
        </el-tooltip>
      </div>
      <div style="display: flex; justify-content: right; margin-right: 40px">
        <span class="collapse-header-text">
          静安区 {{ beginTime }} —— {{ endTime }} 油烟检测异常信息汇总</span
        >
      </div>
      <br />
          <el-tooltip
            class="box-item"
            effect="dark"
            content="点击可折叠"
            placement="right-start"
          >
      <el-collapse ref="h3" v-model="activeNames">
        <el-collapse-item name="1">
          <template #title>
            <el-tooltip
              class="box-item"
              effect="dark"
              content="点击可折叠"
              placement="right-start"
            >
              <h4 class="collapse-header">异常分析</h4>
              <el-icon class="header-icon">
                <i-ep-info-filled />
              </el-icon>
            </el-tooltip>
            <el-tooltip
              class="box-item"
              effect="dark"
              content="点击可折叠"
              placement="right-start"
            >
            </el-tooltip>
          </template>
          <el-card class="box-card">
            <el-row :gutter="25">
              <el-col :span="8">
                <div style="display: flex">
                  <img
                    src="@/assets/exceed.jpg"
                    style="width: 25px; height: 25px; margin-top: 5px"
                  />
                  <span
                    style="
                      font-size: 16px;
                      font-weight: bold;
                      margin-top: 4px;
                      margin-left: 4px;
                    "
                    >油烟浓度超标</span
                  >
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span style="font-size: 20px"
                      >{{ exception0.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception0.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    >
                  </el-scrollbar>
                </div>
                <hr />
                <div class="box-card-butcontainer">
                  <el-card class="sub-box-card">
                    <el-scrollbar max-height="70px">
                      <ExceptionText
                        v-for="(item, index) in exception0"
                        :key="item"
                        :devId="item.devId"
                        exception-value="0"
                        :begin-time="beginTime"
                        :end-time="endTime"
                        @submit-exception-data="getAbnormalDataByClick"
                      >
                        {{ item.diName }}
                        <span
                          v-if="index < exception0.length - 1"
                          class="text-blank"
                          >,</span
                        >
                      </ExceptionText>
                    </el-scrollbar>
                  </el-card>
                </div>
              </el-col>
              <el-col :span="8">
                <div style="display: flex">
                  <img
                    src="@/assets/exception.jpg"
                    style="width: 25px; height: 25px; margin-top: 5px"
                  />
                  <span
                    style="
                      font-size: 16px;
                      font-weight: bold;
                      margin-top: 5px;
                      margin-left: 4px;
                    "
                    >供电异常</span
                  >
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span style="font-size: 20px"
                      >{{ exception1.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception1.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    >
                  </el-scrollbar>
                </div>
                <hr />
                <div>
                  <el-card class="sub-box-card">
                    <el-scrollbar max-height="70px">
                      <ExceptionText
                        v-for="(item, index) in exception1"
                        :key="item"
                        :devId="item.devId"
                        exception-value="1"
                        :begin-time="beginTime"
                        :end-time="endTime"
                        @submit-exception-data="getAbnormalDataByClick"
                      >
                        {{ item.diName }}
                        <span
                          v-if="index < exception1.length - 1"
                          class="text-blank"
                          >,</span
                        >
                      </ExceptionText>
                    </el-scrollbar>
                  </el-card>
                </div>
              </el-col>
              <el-col :span="8">
                <div style="display: flex">
                  <img
                    src="@/assets/offline.jpg"
                    style="width: 25px; height: 25px; margin-top: 5px"
                  />
                  <span
                    style="
                      font-size: 16px;
                      font-weight: bold;
                      margin-top: 5px;
                      margin-left: 4px;
                    "
                    >掉线</span
                  >
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span style="font-size: 20px"
                      >{{ exception2.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception2.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    >
                  </el-scrollbar>
                </div>
                <hr />
                <div>
                  <el-card class="sub-box-card">
                    <el-scrollbar max-height="70px">
                      <ExceptionText
                        v-for="(item, index) in exception2"
                        :key="item"
                        :devId="item.devId"
                        exception-value="2"
                        :begin-time="beginTime"
                        :end-time="endTime"
                        @submit-exception-data="getAbnormalDataByClick"
                      >
                        {{ item.diName }}
                        <span
                          v-if="index < exception2.length - 1"
                          class="text-blank"
                          >,</span
                        >
                      </ExceptionText>
                    </el-scrollbar>
                  </el-card>
                </div>
              </el-col>
            </el-row>
          </el-card>
        </el-collapse-item>
      </el-collapse>
      <h4 class="table-text">异常数据</h4>
    </el-col>
  </el-row>
  <el-card class="table-page" v-show="!isNoData">
    <el-table
      ref="tableH"
      v-loading="loading"
      :data="displayData"
      style="width: 100%"
      border
      :height="tableHeight"
      :cell-class-name="tableCellClassName"
    >
      <el-table-column prop="diName" label="店铺名称">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.diName">
            <div class="cell ellipsis">{{ row.diName }}</div>
          </el-tooltip>
        </template>
        <el-card class="box-card">
          <el-row :gutter="25">
            <el-col :span="8">
              <div style="display: flex">
                <img
                  src="@/assets/exceed.jpg"
                  style="width: 25px; height: 25px; margin-top: 5px"
                />
                <span
                  style="
                    font-size: 16px;
                    font-weight: bold;
                    margin-top: 4px;
                    margin-left: 4px;
                  "
                  >油烟浓度超标</span
                >
              </div>
      </el-table-column>
              <div class="box-card-label">
                <el-scrollbar>
                  <span class="box-card-label">店铺数量:</span>
                  <span style="font-size: 20px"
                    >{{ exception0.length }} /{{ shopsTotal }}</span
                  >
                  <span style="margin-left: 150px; font-size: 14px">
                    占比:{{
                      ((exception0.length / shopsTotal) * 100).toFixed(1)
                    }}%</span
                  >
                </el-scrollbar>
              </div>
              <hr />
              <div class="box-card-butcontainer">
                <el-card class="sub-box-card">
                  <el-scrollbar max-height="70px">
                    <ExceptionText
                      v-for="(item, index) in exception0"
                      :key="item"
                      :devId="item.devId"
                      exception-value="0"
                      :begin-time="beginTime"
                      :end-time="endTime"
                      @submit-exception-data="getAbnormalDataByClick"
                    >
                      {{ item.diName }}
                      <span
                        v-if="index < exception0.length - 1"
                        class="text-blank"
                        >,</span
                      >
                    </ExceptionText>
                  </el-scrollbar>
                </el-card>
              </div>
            </el-col>
            <el-col :span="8">
              <div style="display: flex">
                <img
                  src="@/assets/exception.jpg"
                  style="width: 25px; height: 25px; margin-top: 5px"
                />
                <span
                  style="
                    font-size: 16px;
                    font-weight: bold;
                    margin-top: 5px;
                    margin-left: 4px;
                  "
                  >供电异常</span
                >
              </div>
              <div class="box-card-label">
                <el-scrollbar>
                  <span class="box-card-label">店铺数量:</span>
                  <span style="font-size: 20px"
                    >{{ exception1.length }} /{{ shopsTotal }}</span
                  >
                  <span style="margin-left: 150px; font-size: 14px">
                    占比:{{
                      ((exception1.length / shopsTotal) * 100).toFixed(1)
                    }}%</span
                  >
                </el-scrollbar>
              </div>
              <hr />
              <div>
                <el-card class="sub-box-card">
                  <el-scrollbar max-height="70px">
                    <ExceptionText
                      v-for="(item, index) in exception1"
                      :key="item"
                      :devId="item.devId"
                      exception-value="1"
                      :begin-time="beginTime"
                      :end-time="endTime"
                      @submit-exception-data="getAbnormalDataByClick"
                    >
                      {{ item.diName }}
                      <span
                        v-if="index < exception1.length - 1"
                        class="text-blank"
                        >,</span
                      >
                    </ExceptionText>
                  </el-scrollbar>
                </el-card>
              </div>
            </el-col>
            <el-col :span="8">
              <div style="display: flex">
                <img
                  src="@/assets/offline.jpg"
                  style="width: 25px; height: 25px; margin-top: 5px"
                />
                <span
                  style="
                    font-size: 16px;
                    font-weight: bold;
                    margin-top: 5px;
                    margin-left: 4px;
                  "
                  >掉线</span
                >
              </div>
              <div class="box-card-label">
                <el-scrollbar>
                  <span class="box-card-label">店铺数量:</span>
                  <span style="font-size: 20px"
                    >{{ exception2.length }} /{{ shopsTotal }}</span
                  >
                  <span style="margin-left: 150px; font-size: 14px">
                    占比:{{
                      ((exception2.length / shopsTotal) * 100).toFixed(1)
                    }}%</span
                  >
                </el-scrollbar>
              </div>
              <hr />
              <div>
                <el-card class="sub-box-card">
                  <el-scrollbar max-height="70px">
                    <ExceptionText
                      v-for="(item, index) in exception2"
                      :key="item"
                      :devId="item.devId"
                      exception-value="2"
                      :begin-time="beginTime"
                      :end-time="endTime"
                      @submit-exception-data="getAbnormalDataByClick"
                    >
                      {{ item.diName }}
                      <span
                        v-if="index < exception2.length - 1"
                        class="text-blank"
                        >,</span
                      >
                    </ExceptionText>
                  </el-scrollbar>
                </el-card>
              </div>
            </el-col>
          </el-row>
        </el-card>
      </el-collapse-item>
    </el-collapse>
    <!-- <hr/>
 <br> -->
    <h4 class="table-text">异常数据</h4>
    <!--  -->
  </el-col>
</el-row>
    <el-card class="table-page" v-show="!isNoData">
      <el-table
        ref="tableH"
        v-loading="loading"
        :data="displayData"
        style="width: 100%"
        stripe
        border
        :height="tableHeight"
      >
        <el-table-column fixed prop="diName" label="店铺名称" >
          <template #default="{ row }">
            <el-tooltip effect="dark" :content="row.diName">
              <div class="cell ellipsis">{{ row.diName }}</div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column prop="devId" label="设备编号" >
          <template #default="{ row }">
            <el-tooltip effect="dark" :content="row.devId">
              <div class="cell ellipsis">{{ row.devId }}</div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column prop="exception" label="异常分类" >
          <template #default="{ row }">
            <el-tooltip effect="dark" :content="row.exception">
              <div class="cell ellipsis">{{ row.exception }}</div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="异常类型" >
          <template #default="{ row }">
            <span v-if="row.exceptionType == '0'">油烟数据超标</span>
            <span v-else-if="row.exceptionType == '1'">疑似供电异常</span>
            <span v-else-if="row.exceptionType == '2'">掉线</span>
          </template>
        </el-table-column>
        <el-table-column prop="region" label="地区" >
          <template #default="{ row }">
            <el-tooltip effect="dark" :content="row.region">
              <div class="cell ellipsis">{{ row.region }}</div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column prop="beginTime" label="开始时间">
          <template #default="{ row }">
            <el-tooltip effect="dark" :content="row.beginTime">
              <div class="cell ellipsis">{{ row.beginTime }}</div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column prop="endTime" label="结束时间">
          <template #default="{ row }">
            <el-tooltip effect="dark" :content="row.endTime">
              <div class="cell ellipsis">{{ row.endTime }}</div>
            </el-tooltip>
          </template>
        </el-table-column>
        <el-table-column label="操作" >
          <template #default="{ row }">
            <el-button type="warning" @click="showDrawer(row)"
              >查看详情</el-button
            >
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        ref="h4"
        background
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :total="total"
        :page-size="pageSize"
        layout="total,prev, pager, next, jumper"
      />
    </el-card>
    <el-empty v-show="isNoData" :image-size="200" />
    <!-- 对话框 -->
    <div>
      <el-dialog  v-model="centerDialogVisible" draggable align-center>
        <template #header>
          <div style="font-size: 17px">
            店铺名:{{ rowShopName }}
            <span style="margin-left: 40px">异常类型:</span>
            <span v-if="rowExceptionType == '0'">油烟数据超标</span>
            <span v-else-if="rowExceptionType == '1'">供电异常</span>
            <span v-else-if="rowExceptionType == '2'">掉线</span>
            <div style="margin-top: 10px">
              异常时间段:{{ rowBeginTime }} ~
              {{ rowEndTime }}
            </div>
          </div>
          <div class="dialog-button-position">
            <el-button
              type="danger"
              :disabled="isPreCantouch"
              @click="getPreviousRowData"
              >上条异常</el-button
            >
            <el-button
              type="danger"
              :disabled="isNextCantouch"
              @click="getNextRowData"
              >下条异常</el-button
            >
          </div>
      <el-table-column prop="devId" label="设备编号">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.devId">
            <div class="cell ellipsis">{{ row.devId }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
        <!-- 超标数据时 -->
        <!-- 折线图 -->
      <el-table-column prop="exception" label="异常分类">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.exception">
            <div class="cell ellipsis">{{ row.exception }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column label="异常类型">
        <template #default="{ row }">
          <span v-if="row.exceptionType == '0'">油烟数据超标</span>
          <span v-else-if="row.exceptionType == '1'">疑似供电异常</span>
          <span v-else-if="row.exceptionType == '2'">掉线</span>
        </template>
      </el-table-column>
      <el-table-column prop="region" label="地区">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.region">
            <div class="cell ellipsis">{{ row.region }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
        <!-- 掉线 -->
        <!-- <div
          ref="ref"
          v-show="isOfflineShow"
      <el-table-column prop="beginTime" label="开始时间">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.beginTime">
            <div class="cell ellipsis">{{ row.beginTime }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="endTime" label="结束时间">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.endTime">
            <div class="cell ellipsis">{{ row.endTime }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button
            type="primary"
            class="table-button"
            @click="showDrawer(row)"
            >查看详情</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      ref="h4"
      background
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :total="total"
      :page-size="pageSize"
      layout="total,prev, pager, next, jumper"
    />
  </el-card>
  <el-empty v-show="isNoData" :image-size="200" />
  <!-- 对话框 -->
  <div>
    <el-dialog v-model="centerDialogVisible" draggable align-center>
      <template #header>
        <div style="font-size: 17px">
          店铺名:{{ rowShopName }}
          <span style="margin-left: 40px">异常类型:</span>
          <span v-if="rowExceptionType == '0'">油烟数据超标</span>
          <span v-else-if="rowExceptionType == '1'">供电异常</span>
          <span v-else-if="rowExceptionType == '2'">掉线</span>
          <div style="margin-top: 10px">
            异常时间段:{{ rowBeginTime }} ~
            {{ rowEndTime }}
          </div>
        </div>
        <div class="dialog-button-position">
          <el-button
            type="danger"
            :loading="button.preButton"
            :disabled="isPreCantouch || banTouch"
            @click="getPreviousRowData"
            >上条异常</el-button
          >
          <el-button
            type="danger"
            :loading="button.afterButton"
            :disabled="isNextCantouch || banTouch"
            @click="getNextRowData"
            >下条异常</el-button
          >
        </div>
      </template>
      <!-- 超标数据时 -->
      <!-- 折线图 -->
      <!-- 掉线 -->
      <div
          ref="lineChart"
          class="line-chart"
          style="
            width: 100%;
            height: 300px;
            /* min-width: 100px; */
            margin-bottom: 20px;
            margin-left: 10px;
            min-width: 350px;
            /* margin-left: 10px;
            min-width: 350px; */
          "
        ></div> -->
        ></div>
        <ExceptionTypeLineChart :option="option" :is-open-dialog="centerDialogVisible" ></ExceptionTypeLineChart>
      <!-- <ExceptionTypeLineChart
        :option="option"
        :is-open-dialog="centerDialogVisible"
        v-loading="chartLoading"
      ></ExceptionTypeLineChart> -->
        <!--  -->
        <div style="margin-top: 40px; margin-bottom: 5px; border: 1px">
          <el-table
            :data="exceedingData"
            height="360"
            border
            style="margin-top: 25px"
          >
            <el-table-column fixed prop="diName" label="店铺名称" />
            <el-table-column prop="mvStatCode" label="设备编号" />
      <!--  -->
      <div style="margin-top: 40px; margin-bottom: 5px; border: 1px">
        <el-table
          :data="exceedingData"
          height="360"
          border
          style="margin-top: 25px"
        >
          <el-table-column fixed prop="diName" label="店铺名称" />
          <el-table-column prop="mvStatCode" label="设备编号" />
            <el-table-column prop="mvDataTime" label="采集时间" />
            <el-table-column
              prop="mvFumeConcentration2"
              label="油烟浓度(mg/m³)"
            />
          </el-table>
        </div>
          <el-table-column prop="mvDataTime" label="采集时间" />
          <el-table-column
            prop="mvFumeConcentration2"
            label="油烟浓度(mg/m³)"
          />
        </el-table>
      </div>
        <el-tag type="success" class="mx-1" effect="dark" round
          ><span class="table-line-lable" v-show="rowExceptionType == '0'">异常记录: </span>
          <span v-show="rowExceptionType == '1' || rowExceptionType == '2'">缺失数据:</span>
          <span class="table-line-num">{{ exceptionTotal }}条</span>
          <span v-show="rowExceptionType === '1' || rowExceptionType === '2'">
            (逻辑计算)</span
          >
        </el-tag>
      </el-dialog>
    </div>
      <el-tag type="success" class="mx-1" effect="dark" round
        ><span class="table-line-lable" v-show="rowExceptionType == '0'"
          >异常记录:
        </span>
        <span v-show="rowExceptionType == '1' || rowExceptionType == '2'"
          >缺失数据:</span
        >
        <span class="table-line-num">{{ exceptionTotal }}条</span>
        <span v-show="rowExceptionType === '1' || rowExceptionType === '2'">
          (逻辑计算)</span
        >
      </el-tag>
    </el-dialog>
  </div>
</template>
<script>
import ExceptionType from '../sfc/ExceptionType.vue';
import TimeSelect from '../sfc/TimeSelect.vue';
import ExceptionText from '../sfc/ExceptionText.vue';
import * as echarts from 'echarts';
import * as XLSX from 'xlsx/xlsx.mjs';
import dayjs from 'dayjs';
import axiosInstanceInstance from '../utils/request.js';
import * as echarts from 'echarts';
const ShopNameAndID = defineAsyncComponent(() =>
  import('../sfc/../sfc/ShopNameAndID.vue')
@@ -440,10 +449,23 @@
    TimeSelect,
    ShopNameAndID,
    ExceptionText,
    ExceptionTypeLineChart
    // ExceptionTypeLineChart
  },
  data() {
    return {
      chart: null,
      // 折线图加载中
      chartLoading:false,
      button:{
        // 查询按钮
        queryButton:false,
        // 上一条按钮
        preButton:false,
        // 下一条按钮
        afterButton:false,
        //
        banTouch:0
      },
      // 异常折线图的配置
      option: {},
      // 折线图展示
@@ -553,7 +575,7 @@
      // 店铺名 级联选择器
      optionsShop: [],
      // 异常类型选择器
      exceptionValue: [],
      exceptionValue: []
    };
  },
  // 监听  判断按钮是否可点击
@@ -562,16 +584,16 @@
      // 处于表格的最后一条数据 设置‘上一条’按钮不可点
      if (newVaue === this.displayData.length - 1) {
        this.isPreCantouch = true;
       //用户先点了第一条,pre为true,然后点击最后一条,next为true。此时两个按钮都被封锁
       if (this.isNextCantouch == true) {
        //用户先点了第一条,pre为true,然后点击最后一条,next为true。此时两个按钮都被封锁
        if (this.isNextCantouch == true) {
          this.isNextCantouch = false;
        }
      }
      // 处于表格第一条数据 设置‘下一条’按钮不可点
      else if (newVaue === 0) {
        this.isNextCantouch = true;
         //用户先点了表格最后一条,next为true,然后点击第一条,pre为true。此时两个按钮都被封锁
         if (this.isPreCantouch == true) {
        //用户先点了表格最后一条,next为true,然后点击第一条,pre为true。此时两个按钮都被封锁
        if (this.isPreCantouch == true) {
          this.isPreCantouch = false;
        }
      }
@@ -590,6 +612,8 @@
      this.getShopNames();
    },
    centerDialogVisible() {
      // this.initChart();
      // this.chart.clear
      window.addEventListener('resize', this.updateChart);
    }
  },
@@ -601,19 +625,88 @@
    this.getRecentSevenDays();
    // 根据异常类型返回店铺名称和设备编号 渲染异常分析部分对应的店铺名
    this.getShopNames();
    this.calcTableHeight()
    this.calcTableHeight();
    window.addEventListener('resize', this.updateChart);
  },
  beforeUnmount() {
    if (this.chart) {
      this.chart.dispose;
    }
  },
  methods: {
     // 动态计算表格高度
     calcTableHeight(){
    calDialogWidth(){
    },
    // 功能:初始化折线图
    initChart() {
      // 创建echarts实例
      this.chart = echarts.init(this.$refs.lineChart);
      // 定义图表的配置项和数据
      const option = {
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        tooltip: {},
        toolbox: {
          // 工具栏
          feature: {
            // dataZoom: {
            //   // 区域缩放
            //   yAxisIndex: 'none'
            // },
            // 保存为图片
            saveAsImage: {}
          }
        },
        xAxis: {
          type: 'time',
          data: [],
        },
        yAxis: {
          type: 'value',
        },
        series: [
          {
            name: '油烟浓度',
            type: 'line',
            data: []
          }
        ]
      };
      // 使用刚指定的配置项和数据显示图表
      this.chart.setOption(option, true);
    },
    // 功能:跟页面响应式变化
    resizeChart() {
      this.chart.resize();
    },
    // 功能:改变表格某个单元格的颜色
    tableCellClassName({ row, column, rowIndex, columnIndex }) {
     if(columnIndex == 3){
        if (row.exceptionType == '0') {
          return 'exceeding-row';
        } else if (row.exceptionType == '1') {
          return 'abnormal-power-supply';
        } else if (row.exceptionType == '2') {
          return 'disconnect';
        }
     }
    },
    //功能: 动态计算表格高度
    calcTableHeight() {
      const h1 = this.$refs.h1.$el.offsetHeight;
      const h2 = this.$refs.h4.$el.offsetHeight;
      this.tableHeight =  `calc(100vh - ${h1}px - ${h2}px - 45px - var(--el-main-padding) * 2 - var(--el-card-padding))`;
      this.tableHeight = `calc(100vh - ${h1}px - ${h2}px - 45px - var(--el-main-padding) * 2 - var(--el-card-padding))`;
    },
    // 时间是否超过10分钟
    //功能: 时间是否超过10分钟
    isTimeDifferenceGreaterThan10Minutes(dateString1, dateString2) {
      const date1 = new Date(dateString1);
      const date2 = new Date(dateString2);
@@ -639,7 +732,6 @@
          let current = timePoints[i];
          let next = timePoints[i + 1];
          while (this.isTimeDifferenceGreaterThan10Minutes(current, next)) {
            console.log('generateTimePoints');
            current = dayjs(current)
              .add(10, 'minute')
              .format('YYYY-MM-DD HH:mm:ss');
@@ -668,7 +760,6 @@
      const year2 = date2.getFullYear();
      const month2 = date2.getMonth();
      const day2 = date2.getDate();
      console.log(month1, month2);
      // 判断两个日期是否相差一个月
      if (year1 === year2) {
@@ -698,16 +789,14 @@
    // 刚打开卡片时第一个图形不会自动伸缩 当点击上/下一条时会自动伸缩
    // 图形响应式变化
    // updateChart() {
    //   this.$nextTick(() => {
    //     if (this.chart1) {
    //       this.chart1.resize();
    //     }
    //     if (this.chart2) {
    //       this.chart2.resize();
    //     }
    //   });
    // },
    updateChart() {
      this.$nextTick(() => {
        if (this.chart) {
          this.chart.resize();
        }
      });
    },
    // 从时间选择器组件拿到开始和结束时间
    giveTime(val) {
      //将中国标准时间转为指定格式(该组件返回的标准时间的格式,所以必须的加这个函数)
@@ -719,9 +808,9 @@
    // 比如12:00:00-13:00:00 所以返回的数组元素是 12:10:00 ,12:20:00,12:30:00....13:00:00
    descTenTime(begin, end) {
      let time = [];
      if(begin == end){
        time.push(begin)
        return time
      if (begin == end) {
        time.push(begin);
        return time;
      }
      // 保留结果 00 10 20 30
      let temp = dayjs(begin).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss');
@@ -743,15 +832,15 @@
      this.rowMvStatCode = this.displayData[index].devId;
    },
    //功能: 供电异常和掉线时的表格数据
    //功能: 供电异常和掉线时的表格数据
    setExceptionData() {
        // 无数据时的时间数组 时间相差10分钟
        const abnormalTimeTenMinute = this.descTenTime(
      // 无数据时的时间数组 时间相差10分钟
      const abnormalTimeTenMinute = this.descTenTime(
        this.rowBeginTime,
        this.rowEndTime
      )
      );
      // 去除供电异常和掉线区间的第一个有元素的值
      this.exceedingData = []
      this.exceedingData = [];
      for (let i = 0; i < abnormalTimeTenMinute.length; i++) {
        this.exceedingData.push({
@@ -775,8 +864,11 @@
    // 获取获取表格下一行数据
    getNextRowData() {
      // 不是表格的第一行
      // 不是表格的第一行
      if (this.selectedRowIndex !== 0) {
        // 点击过程中 锁住上下条按钮  在设置完图形配置项后解锁
        this.banTouch = 1
        //得到上一行数据索引
        this.selectedRowIndex = this.selectedRowIndex - 1;
        //请求数据 改变exceedingData
@@ -792,32 +884,29 @@
        if (this.drawerData.endTime) {
          params['endTime'] = this.displayData[this.selectedRowIndex].endTime;
        }
        this.button.afterButton = true
        axiosInstanceInstance
          .get('/fume/exceed', { params: params })
          .then((response) => {
            // 保存返回的超标数据
            this.exceedingData = response.data.data;
            // this.chart = null;
            // this.drawChart();
            this.drawChartTest();
            this.exceptionTotal = this.exceedingData.length;
            this.button.afterButton = false
          });
      }
      //表格的第一行,则上一条无数据
      else{
        console.log(null);
      }
    },
    // 获取获取表格下一行数据
    getPreviousRowData() {
      // 不是表格的第一行
      // 不是表格的第一行
      if (this.selectedRowIndex < this.displayData.length - 1) {
        // 点击过程中 锁住上下条按钮  在设置完图形配置项后解锁
        this.banTouch = 1
        //得到上一行数据索引
        this.selectedRowIndex = this.selectedRowIndex + 1;
        console.log('上', this.selectedRowIndex);
        //请求数据 改变exceedingData
        this.setinfo(this.selectedRowIndex);
@@ -832,19 +921,16 @@
        if (this.drawerData.endTime) {
          params['endTime'] = this.displayData[this.selectedRowIndex].endTime;
        }
        this.button.preButton = true
        axiosInstanceInstance
          .get('/fume/exceed', { params: params })
          .then((response) => {
            // 保存返回的超标数据
            this.exceedingData = response.data.data;
            console.log(this.exceedingData);
            this.drawChartTest();
            this.exceptionTotal = this.exceedingData.length;
            this.button.preButton = false
          });
      }
      //表格的第一行,则上一条无数据
      else {
        console.log(null);
      }
    },
@@ -860,6 +946,10 @@
      this.centerDialogVisible = true;
      // 初始化折线图
      this.initChart();
      // this.chart.clear
      // 根据行数据请求详细超标数据渲染折线图
      let params = {};
      if (this.drawerData.devId) {
@@ -871,6 +961,7 @@
      if (this.drawerData.endTime) {
        params['endTime'] = this.drawerData.endTime;
      }
      axiosInstanceInstance
        .get('/fume/exceed', { params: params })
        .then((response) => {
@@ -895,8 +986,7 @@
      if (this.exceptionValue.length != 0) {
        params['exceptionValue'] = this.exceptionValue.join();
      }
      console.log('原', this.exceptionValue);
      console.log('处理', this.exceptionValue.join());
      if (this.beginTime) {
        params['beginTime'] = this.beginTime;
      }
@@ -904,12 +994,15 @@
        params['endTime'] = this.endTime;
      }
      this.loading = true;
      this.button.queryButton = true
      axiosInstanceInstance
        .get('/fume/abnormalthree', { params: params })
        .then((response) => {
          this.abnormalData = response.data.data;
          this.total = this.abnormalData.length;
          this.loading = false;
          this.button.queryButton = false
          if (response.data.data.length == 0) {
            ElMessage('该时段无数据');
            this.isNoData = true;
@@ -918,8 +1011,7 @@
          // 移除空数据状态
          this.isNoData = false;
          this.handleCurrentChange(1);
          console.log('返回的数据', this.abnormalData);
          console.log('长度', response.data.data.total);
        });
    },
    handleSizeChange(val) {
@@ -943,7 +1035,6 @@
      // 计算结束时间减去开始时间中间相差多少个十分钟
      const diffInMinutes = end.diff(start, 'minute');
      const diffInTenMinutes = Math.floor(diffInMinutes / 10);
      console.log('几个10分钟', diffInTenMinutes);
      return diffInTenMinutes;
    },
@@ -1022,8 +1113,8 @@
    // 功能:判断data中是否有该日期时间,存在返回该时间对应的浓度值,否则返回-1
    findTimeInExceptionData(data, time) {
      for (let i = 0; i < data.length; i++) {
        if(data[i]==null){
            continue
        if (data[i] == null) {
          continue;
        }
        if (data[i]['mvDataTime'] == time) {
          return data[i]['mvFumeConcentration2'];
@@ -1060,7 +1151,6 @@
        current = dayjs(current)
          .add(10, 'minute')
          .format('YYYY-MM-DD HH:mm:ss');
      }
      obj['xAxis'] = xAxis;
      obj['yAxis'] = yAxis;
@@ -1069,19 +1159,17 @@
    // 参数:超标数据前面区间的数据
    // 功能:返回除去最后一个元素的数组
    removeLastItemOfBeforeData(beforeDataOfExceeding){
    removeLastItemOfBeforeData(beforeDataOfExceeding) {
      let tempList = [];
      if(beforeDataOfExceeding.length ==1){
        return tempList
      }else{
        for(let i=0;i<beforeDataOfExceeding.length-1;i++){
        tempList.push({ ...beforeDataOfExceeding[i]})
      }
      return tempList;
      if (beforeDataOfExceeding.length == 1) {
        return tempList;
      } else {
        for (let i = 0; i < beforeDataOfExceeding.length - 1; i++) {
          tempList.push({ ...beforeDataOfExceeding[i] });
        }
        return tempList;
      }
    },
    // 设置option
    // 参数:x轴时间, y轴油烟浓度, 异常类别(0代表超标,1代表供电异常和掉线), 异常开始时间,异常结束时间,异常开始时间在整个区间的索引下标,异常结束时间在整个区间的索引下标
@@ -1094,21 +1182,21 @@
      beginIndex,
      endIndex
    ) {
      this.option = {}
      this.option = {};
      // 超标
      if (exceptionCategory == 0) {
        this.option = {
        this.chart.setOption({
          tooltip: {},
        toolbox: {
          // 工具栏
          feature: {
        //     dataZoom: {
        //   yAxisIndex: 'none'
        // },
            // 保存为图片
            saveAsImage: {}
          }
        },
          toolbox: {
            // 工具栏
            feature: {
              //     dataZoom: {
              //   yAxisIndex: 'none'
              // },
              // 保存为图片
              saveAsImage: {}
            }
          },
          xAxis: {
            type: 'category',
            data: xData,
@@ -1121,7 +1209,7 @@
          },
          yAxis: {
            type: 'value',
            name: 'mg/m³',
            name: 'mg/m³'
          },
          series: [
            {
@@ -1147,10 +1235,10 @@
                  [
                    {
                      name: '超标时间段',
                      xAxis: exceptionBeginTime,
                      xAxis: exceptionBeginTime
                    },
                    {
                      xAxis: exceptionEndTime,
                      xAxis: exceptionEndTime
                    }
                  ]
                ]
@@ -1205,23 +1293,23 @@
              }
            ]
          }
        };
        });
      }
      // 供电异常和掉线
      else if (exceptionCategory == 1) {
        this.option = {
        this.chart.setOption( {
          tooltip: {},
        toolbox: {
          // 工具栏
          feature: {
            // dataZoom: {
            //   // 区域缩放
            //   yAxisIndex: 'none'
            // },
            // 保存为图片
            saveAsImage: {}
          }
        },
          toolbox: {
            // 工具栏
            feature: {
              // dataZoom: {
              //   // 区域缩放
              //   yAxisIndex: 'none'
              // },
              // 保存为图片
              saveAsImage: {}
            }
          },
          xAxis: {
            type: 'category',
            data: xData,
@@ -1259,19 +1347,19 @@
              }
            }
          ]
        };
        });
      }
      this.banTouch = 0
    },
    // 功能:点击 ‘查看详情’, ‘下一条’按钮时会 先逻辑计算。最后展示图形
    drawChartTest() {
      this.beforeData = []
      this.afterData= []
      this.allExceptionTimeData = []
      this.beforeData = [];
      this.afterData = [];
      this.allExceptionTimeData = [];
      //异常的开始时间 结束时间
      let exceptionBeginTime =this.rowBeginTime
      let exceptionEndTime = this.rowEndTime
      let exceptionBeginTime = this.rowBeginTime;
      let exceptionEndTime = this.rowEndTime;
      // beforeAndAfterTime[0]:前30分钟的时间点
      // beforeAndAfterTime[1]:后10分钟的时间点
@@ -1295,18 +1383,18 @@
        beforeAndAfterTime[2]
      );
      // 折线图加载中效果
      this.chartLoading = true
      // 请求前半段
      axiosInstanceInstance
        .get('/fume/history', { params: paramsBefore })
        .then((result1) => {
          this.beforeData = result1.data.data;
          console.log('beforeData:',this.beforeData);
          // 请求后半段
          axiosInstanceInstance
            .get('/fume/history', { params: paramsAfter })
            .then((result2) => {
              this.afterData = result2.data.data;
              console.log('afterData:',this.afterData);
              //保存异常区间的值
              let tempArr = [];
              // 保存异常区间前后的值
@@ -1334,11 +1422,12 @@
                after = this.shallowCopyList(this.afterData);
                // after = this.afterData
                console.log('after:',after);
              }
              }
              // 超标
              else {
                let beforeTemp = this.removeLastItemOfBeforeData(this.beforeData)
                let beforeTemp = this.removeLastItemOfBeforeData(
                  this.beforeData
                );
                // 前后区间只显示距离超标区间时间最近的浓度小于1的时间点
                for (let i = beforeTemp.length - 1; i >= 0; i--) {
                  if (beforeTemp[i].mvFumeConcentration2 >= 1) {
@@ -1349,7 +1438,7 @@
                  }
                }
                for (let i = 0; i<this.afterData.length; i++) {
                for (let i = 0; i < this.afterData.length; i++) {
                  if (this.afterData[i].mvFumeConcentration2 >= 1) {
                    break;
                  }
@@ -1362,7 +1451,6 @@
              // 将前后区间数据 与 异常区间数据 合并
              this.allExceptionTimeData = [...before, ...tempArr, ...after];
              console.log('组合数据:',this.allExceptionTimeData);
              // x轴日期时间
              let dateList = [];
              // y轴 超标油烟浓度
@@ -1378,9 +1466,6 @@
              dateList = timeAndValue['xAxis'];
              fumeExceeding = timeAndValue['yAxis'];
              console.log('dateList:',dateList);
              console.log('fumeExceeding:',fumeExceeding);
              // 提取异常起始时间点在整个区间内的数据索引
              let startIndex = dateList.findIndex(
@@ -1389,7 +1474,7 @@
              let endIndex = dateList.findIndex(
                (item) => item === exceptionEndTime
              );
              // 供电异常和掉线情况 超标情况
              if (
                this.rowExceptionType === '1' ||
@@ -1416,6 +1501,7 @@
                  endIndex
                );
              }
              this.chartLoading = false
            });
        });
    },
@@ -1438,7 +1524,6 @@
            ]
          };
        });
        console.log(this.optionsShop);
      });
    },
    exportDom() {
@@ -1492,8 +1577,6 @@
        })
        .then((result) => {
          this.exception0 = result.data.data;
          console.log('异常0', this.exception0);
          console.log('异常0数量', this.exception0.length);
        });
      axiosInstanceInstance
        .get('/fume/shopname', {
@@ -1523,7 +1606,6 @@
    getRecentSevenDays() {
      // 给级联选择器设置默认的选择项
      this.devId = ['付小姐在成都', 'qinshi_31010320210010'];
      console.log(this.currentDateTime, this.oneWeekAgoDateTime);
      let params = {};
      params['beginTime'] = this.beginTime;
      params['endTime'] = this.endTime;
@@ -1548,13 +1630,7 @@
</script>
<style scoped>
/* .exception-root-container {
  margin: 20px;
  padding: 10px;
  border: 1px;
  height: 615px;
} */
.header-container {
  display: flex;
  margin-left: 20px;
@@ -1590,8 +1666,6 @@
/* 异常分析数据与按钮 */
.exception-container {
  display: flex;
  /* direction: column; */
  /* flex-grow: 2,1; */
}
.example-showcase .el-loading-mask {
  z-index: 9;
@@ -1613,7 +1687,6 @@
  font-size: 18px;
}
.collapse-header-text {
  /* margin-right: 150px; */
  margin-top: 5px;
  font-size: 14px;
  color: gray;
@@ -1622,7 +1695,6 @@
.box-card-label {
  font-size: 14px;
  white-space: nowrap;
  /* overflow-x: auto; */
}
:deep().el-card {
  border-radius: 9px;
@@ -1637,15 +1709,14 @@
.table-page {
  margin-left: 20px;
}
:deep().table-page .el-card__body {
  /* padding: 0px; */
}
.table-text {
  font-size: 18px;
  margin: 5px 0px 10px 20px;
}
.text-blank {
  margin-right: 10px;
  color: #000000;
}
/* 店铺名选择文本 */
.describe-info {
@@ -1677,16 +1748,12 @@
.box-card {
  height: 190px;
}
:deep().box-card .el-card__body {
  /* padding: 5px; */
}
.sub-box-card {
  height: 100px;
  border: 0px;
}
:deep().sub-box-card .el-card__body {
  /* padding: 0px; */
}
.mx-1 {
  margin-bottom: 0px;
}
@@ -1695,10 +1762,31 @@
  justify-content: right;
  margin-bottom: 10px;
}
.el-table .warning-row {
  --el-table-tr-bg-color: var(--el-color-warning-light-9);
:deep().el-table__row .exceeding-row{
  background-color:  #F53F3F;
}
.el-table .success-row {
  --el-table-tr-bg-color: var(--el-color-success-light-9);
:deep().el-table__row .abnormal-power-supply{
  background-color:  #FDF4BF;
}
:deep().el-table__row .disconnect{
  background-color:  #F7BA1E;
}
.el-table {
  color: #000000;
}
/* 表格的内边距 */
:deep().el-table .el-table__cell {
  padding: 2px;
}
/* 表格中的按钮宽度铺满 */
.table-button {
  width: 100%;
}
</style>
src/test/TestSelect.vue
@@ -1,75 +1,777 @@
<!-- 动态计算折线图宽度 -->
<template>
  <el-row ref="h1">
    <el-col>
   {{ windowWidth }}
      <!-- 菜单读标题 -->
      <div ref="h1" class="header-container">
        <span class="describe-info">店铺名选择:</span>
        <!-- 店铺名  级联 -->
        <ShopNameAndID @submit-id="(n) => (deviceId[1] = n)"></ShopNameAndID>
        <!-- 异常类型选择 -->
        <ExceptionType @submitExceptionType="(val) => (exceptionValue = val)">
        </ExceptionType>
        <TimeSelect @submit-time="giveTime"></TimeSelect>
      </div>
      <div
        ref="h2"
        style="display: flex; margin-top: 2px; justify-content: right"
      >
        <el-button
          type="primary"
          plain
          @click="showTable"
          style="margin-left: 20px"
          :loading="button.queryButton"
          >查询</el-button
        >
        <el-tooltip
          class="box-item"
          effect="dark"
          content="点击可导出Excel文件"
          placement="top-start"
        >
          <!-- 做成函数js文件 -->
          <el-icon
            class="iconExcel clickable"
            title="导出Excel文件"
            @click="exportDom"
          >
            <i-ep-Download />
            <!-- 导出为Excel -->
          </el-icon>
        </el-tooltip>
      </div>
      <div style="display: flex; justify-content: right; margin-right: 40px">
        <span class="collapse-header-text">
          静安区 {{ beginTime }} —— {{ endTime }} 油烟检测异常信息汇总</span
        >
      </div>
      <br />
      <el-collapse ref="h3" v-model="activeNames">
        <el-collapse-item name="1">
          <template #title>
            <el-tooltip
              class="box-item"
              effect="dark"
              content="点击可折叠"
              placement="right-start"
            >
              <h4 class="collapse-header">异常分析</h4>
              <el-icon class="header-icon">
                <i-ep-info-filled />
              </el-icon>
            </el-tooltip>
            <el-tooltip
              class="box-item"
              effect="dark"
              content="点击可折叠"
              placement="right-start"
            >
            </el-tooltip>
          </template>
          <el-card class="box-card">
            <el-row :gutter="25">
              <el-col :span="8">
                <div style="display: flex">
                  <img
                    src="@/assets/exceed.jpg"
                    style="width: 25px; height: 25px; margin-top: 5px"
                  />
                  <span
                    style="
                      font-size: 16px;
                      font-weight: bold;
                      margin-top: 4px;
                      margin-left: 4px;
                    "
                    >油烟浓度超标</span
                  >
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span style="font-size: 20px"
                      >{{ exception0.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception0.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    >
                  </el-scrollbar>
                </div>
                <hr />
                <div class="box-card-butcontainer">
                  <el-card class="sub-box-card">
                    <el-scrollbar max-height="70px">
                      <ExceptionText
                        v-for="(item, index) in exception0"
                        :key="item"
                        :devId="item.devId"
                        exception-value="0"
                        :begin-time="beginTime"
                        :end-time="endTime"
                        @submit-exception-data="getAbnormalDataByClick"
                      >
                        {{ item.diName }}
                        <span
                          v-if="index < exception0.length - 1"
                          class="text-blank"
                          >,</span
                        >
                      </ExceptionText>
                    </el-scrollbar>
                  </el-card>
                </div>
              </el-col>
              <el-col :span="8">
                <div style="display: flex">
                  <img
                    src="@/assets/exception.jpg"
                    style="width: 25px; height: 25px; margin-top: 5px"
                  />
                  <span
                    style="
                      font-size: 16px;
                      font-weight: bold;
                      margin-top: 5px;
                      margin-left: 4px;
                    "
                    >供电异常</span
                  >
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span style="font-size: 20px"
                      >{{ exception1.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception1.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    >
                  </el-scrollbar>
                </div>
                <hr />
                <div>
                  <el-card class="sub-box-card">
                    <el-scrollbar max-height="70px">
                      <ExceptionText
                        v-for="(item, index) in exception1"
                        :key="item"
                        :devId="item.devId"
                        exception-value="1"
                        :begin-time="beginTime"
                        :end-time="endTime"
                        @submit-exception-data="getAbnormalDataByClick"
                      >
                        {{ item.diName }}
                        <span
                          v-if="index < exception1.length - 1"
                          class="text-blank"
                          >,</span
                        >
                      </ExceptionText>
                    </el-scrollbar>
                  </el-card>
                </div>
              </el-col>
              <el-col :span="8">
                <div style="display: flex">
                  <img
                    src="@/assets/offline.jpg"
                    style="width: 25px; height: 25px; margin-top: 5px"
                  />
                  <span
                    style="
                      font-size: 16px;
                      font-weight: bold;
                      margin-top: 5px;
                      margin-left: 4px;
                    "
                    >掉线</span
                  >
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span style="font-size: 20px"
                      >{{ exception2.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception2.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    >
                  </el-scrollbar>
                </div>
                <hr />
                <div>
                  <el-card class="sub-box-card">
                    <el-scrollbar max-height="70px">
                      <ExceptionText
                        v-for="(item, index) in exception2"
                        :key="item"
                        :devId="item.devId"
                        exception-value="2"
                        :begin-time="beginTime"
                        :end-time="endTime"
                        @submit-exception-data="getAbnormalDataByClick"
                      >
                        {{ item.diName }}
                        <span
                          v-if="index < exception2.length - 1"
                          class="text-blank"
                          >,</span
                        >
                      </ExceptionText>
                    </el-scrollbar>
                  </el-card>
                </div>
              </el-col>
            </el-row>
          </el-card>
        </el-collapse-item>
      </el-collapse>
      <h4 class="table-text">异常数据</h4>
    </el-col>
  </el-row>
  <el-card class="table-page" v-show="!isNoData">
    <el-table
      ref="tableH"
      v-loading="loading"
      :data="displayData"
      style="width: 100%"
      border
      :height="tableHeight"
      :cell-class-name="tableCellClassName"
    >
      <el-table-column prop="diName" label="店铺名称">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.diName">
            <div class="cell ellipsis">{{ row.diName }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="devId" label="设备编号">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.devId">
            <div class="cell ellipsis">{{ row.devId }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="exception" label="异常分类">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.exception">
            <div class="cell ellipsis">{{ row.exception }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column label="异常类型">
        <template #default="{ row }">
          <span v-if="row.exceptionType == '0'">油烟数据超标</span>
          <span v-else-if="row.exceptionType == '1'">疑似供电异常</span>
          <span v-else-if="row.exceptionType == '2'">掉线</span>
        </template>
      </el-table-column>
      <el-table-column prop="region" label="地区">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.region">
            <div class="cell ellipsis">{{ row.region }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="beginTime" label="开始时间">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.beginTime">
            <div class="cell ellipsis">{{ row.beginTime }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="endTime" label="结束时间">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.endTime">
            <div class="cell ellipsis">{{ row.endTime }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column label="操作">
        <template #default="{ row }">
          <el-button
            type="primary"
            class="table-button"
            @click="showDrawer(row)"
            >查看详情</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      ref="h4"
      background
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :total="total"
      :page-size="pageSize"
      layout="total,prev, pager, next, jumper"
    />
  </el-card>
  <el-empty v-show="isNoData" :image-size="200" />
  <!-- 对话框 -->
  <div>
    <el-dialog ref="diag" v-model="centerDialogVisible" draggable align-center>
      <template #header>
        <div style="font-size: 17px">
          店铺名:{{ rowShopName }}
          <span style="margin-left: 40px">异常类型:</span>
          <span v-if="rowExceptionType == '0'">油烟数据超标</span>
          <span v-else-if="rowExceptionType == '1'">供电异常</span>
          <span v-else-if="rowExceptionType == '2'">掉线</span>
          <div style="margin-top: 10px">
            异常时间段:{{ rowBeginTime }} ~
            {{ rowEndTime }}
          </div>
        </div>
        <div class="dialog-button-position">
          <el-button
            type="danger"
            :loading="button.preButton"
            :disabled="isPreCantouch || banTouch"
            @click="getPreviousRowData"
            >上条异常</el-button
          >
          <el-button
            type="danger"
            :loading="button.afterButton"
            :disabled="isNextCantouch || banTouch"
            @click="getNextRowData"
            >下条异常</el-button
          >
        </div>
      </template>
      <!-- 超标数据时 -->
      <!-- 折线图 -->
      <!-- 掉线 -->
      <!-- <div
          ref="ref"
          v-show="isOfflineShow"
          style="
            width: 100%;
            height: 300px;
            /* min-width: 100px; */
            margin-bottom: 20px;
            margin-left: 10px;
            min-width: 350px;
          "
        ></div> -->
      <ExceptionTypeLineChart
        :option="option"
        :is-open-dialog="centerDialogVisible"
        v-loading="chartLoading"
      ></ExceptionTypeLineChart>
      <!--  -->
      <div style="margin-top: 40px; margin-bottom: 5px; border: 1px">
        <el-table
          :data="exceedingData"
          height="360"
          border
          style="margin-top: 25px"
        >
          <el-table-column fixed prop="diName" label="店铺名称" />
          <el-table-column prop="mvStatCode" label="设备编号" />
          <el-table-column prop="mvDataTime" label="采集时间" />
          <el-table-column
            prop="mvFumeConcentration2"
            label="油烟浓度(mg/m³)"
          />
        </el-table>
      </div>
      <el-tag type="success" class="mx-1" effect="dark" round
        ><span class="table-line-lable" v-show="rowExceptionType == '0'"
          >异常记录:
        </span>
        <span v-show="rowExceptionType == '1' || rowExceptionType == '2'"
          >缺失数据:</span
        >
        <span class="table-line-num">{{ exceptionTotal }}条</span>
        <span v-show="rowExceptionType === '1' || rowExceptionType === '2'">
          (逻辑计算)</span
        >
      </el-tag>
    </el-dialog>
  </div>
</template>
<script>
import ExceptionTypeLineChart from '../sfc/ExceptionTypeLineChart.vue';
import ExceptionType from '../sfc/ExceptionType.vue';
import TimeSelect from '../sfc/TimeSelect.vue';
import ExceptionText from '../sfc/ExceptionText.vue';
import * as XLSX from 'xlsx/xlsx.mjs';
import dayjs from 'dayjs';
import axiosInstanceInstance from '../utils/request.js';
const ShopNameAndID = defineAsyncComponent(() =>
  import('../sfc/../sfc/ShopNameAndID.vue')
);
//  异常图形异步组件
const ExceptionTypeLineChart = defineAsyncComponent(() =>
  import('../sfc/ExceptionTypeLineChart.vue')
);
export default {
  name: 'TablePage',
  components: {
    ExceptionType,
    TimeSelect,
    ShopNameAndID,
    ExceptionText,
    ExceptionTypeLineChart
  },
  data() {
    return {
      xAxis: [
        '2023-07-20 12:00:00',
        '2023-07-20 12:10:00',
        '2023-07-20 12:20:00',
        '2023-07-20 12:30:00',
        '2023-07-20 12:40:00'
      // 页面窗口宽度
      windowWidth:0,
      // 页面窗口高度
      windowHeight:0,
      // 对话框的宽度
      dialogW:'',
      // 折线图加载中
      chartLoading:false,
      button:{
        // 查询按钮
        queryButton:false,
        // 上一条按钮
        preButton:false,
        // 下一条按钮
        afterButton:false,
        //
        banTouch:0
      },
      // 异常折线图的配置
      option: {},
      // 折线图展示
      isChartShow: false,
      // table元素
      tableRef: null,
      // 异常表格数据
      tableHeight: 300,
      // 空数据状态
      isNoData: false,
      // 弹出框中表格条数
      exceptionTotal: 0,
      // 无数据时的时间数组,元素相差10分钟
      // abnormalTimeTenMinute: [],
      // 店铺总数
      shopsTotal: 0,
      // ’上一条‘按钮是否可以被点击状态
      isPreCantouch: false,
      // ’下一条‘按钮是否可以被点击状态
      isNextCantouch: false,
      // 对话框是否展示
      centerDialogVisible: false,
      // 抽屉头部信息
      // 折线图对应的当前表格行数据
      // 店铺名
      rowShopName: '',
      // 异常类型
      rowExceptionType: '',
      // 异常开始时间
      rowBeginTime: '',
      // 异常结束时间
      rowEndTime: '',
      // 异常的设备编号
      rowMvStatCode: '',
      // 表格的一行数据
      rowTable: [],
      //拼接的所有数据
      allExceptionTimeData: [],
      // 无数据时增加的前30分钟数据
      beforeData: [],
      // 无数据时增加的后40分钟数据
      afterData: [],
      // -1表示未选择表格的行
      selectedRowIndex: -1,
      // 默认选择的折叠面板编号
      activeNames: ['1'],
      // 异常时的表格
      abnormalTb: [],
      // 异常的起止时间
      abnormalBt: '',
      abnormalEt: '',
      // 是否展示时间轴  否
      isAbnormal: false,
      // 保存着异常类型0对应的店铺名称和设备编号
      exception0: [],
      // 保存着异常类型1对应的店铺名称和设备编号
      exception1: [],
      // 保存着异常类型2对应的店铺名称和设备编号
      exception2: [],
      // 加载动画
      loading: false,
      // 抽屉加载动画
      loadingDrawer: true,
      // 分页展示数据
      // 异常表的数据
      displayData: [],
      // 存放后端返回的json数据
      jsonData: [],
      // 分页的起始索引
      startIndex: 0,
      // 当前页
      currentPage: 1,
      // 每页条数
      pageSize: 10,
      total: 0,
      // 选择店铺名
      deviceId: [],
      deviceInfo: [],
      // 时间选择器开始时间
      beginTime: '',
      // 时间选择器结束时间
      endTime: '',
      // 异常表数据
      abnormalData: [],
      // 弹出的对话框中的异常表格数据
      exceedingData: [],
      drawerVisible: false,
      // 表格的一行数据
      drawerData: {},
      // 抽屉方向,从右向左打开
      drawerDirection: 'rtl',
      optionsTime: [
        // 时间颗粒度
        {
          value: '10',
          label: '10分钟数据',
          disabled: true
        }
      ],
      yAxis: [0.4, 0.9, 0.1, 1.5, 0.3]
      // 店铺名 级联选择器
      optionsShop: [],
      // 异常类型选择器
      exceptionValue: []
    };
  },
  // 监听  判断按钮是否可点击
  watch: {
    selectedRowIndex(newVaue) {
      // 处于表格的最后一条数据 设置‘上一条’按钮不可点
      if (newVaue === this.displayData.length - 1) {
        this.isPreCantouch = true;
        //用户先点了第一条,pre为true,然后点击最后一条,next为true。此时两个按钮都被封锁
        if (this.isNextCantouch == true) {
          this.isNextCantouch = false;
        }
      }
      // 处于表格第一条数据 设置‘下一条’按钮不可点
      else if (newVaue === 0) {
        this.isNextCantouch = true;
        //用户先点了表格最后一条,next为true,然后点击第一条,pre为true。此时两个按钮都被封锁
        if (this.isPreCantouch == true) {
          this.isPreCantouch = false;
        }
      }
      // 处于表格的中间行 将按钮设置为可点击状态
      else {
        this.isPreCantouch = false;
        this.isNextCantouch = false;
      }
    },
    // 当选择的时间发生变化时,异常分析部分的异常店铺数量同步变化
    beginTime() {
      this.getShopNames();
    },
    endTime() {
      this.getShopNames();
    },
    centerDialogVisible() {
      window.addEventListener('resize', this.updateChart);
    }
  },
  mounted() {
    this.descTenTime()
    // 从接口获取店铺名称 给级联下拉框
    this.getDeviceInfo();
    // 展示最近7天数据
    this.getRecentSevenDays();
    // 根据异常类型返回店铺名称和设备编号 渲染异常分析部分对应的店铺名
    this.getShopNames();
    this.calcTableHeight();
    window.addEventListener('resize', this.updateChart);
    window.onresize = () => {
    return (() => {
                //窗口缩放自动获取页面宽高
                this.windowWidth = document.documentElement.clientWidth; //宽
                this.windowHeight = document.documentElement.clientHeight;; //高
            })()
          }
  },
  methods: {
    findTimeInExceptionData(data,time){
     for(let i=0;i<data.length;i++){
      if(data[i]['mvDataTime'] == time) {
          return data[i]['mvFumeConcentration2']
    // 功能:改变表格某个单元格的颜色
    tableCellClassName({ row, column, rowIndex, columnIndex }) {
     if(columnIndex == 3){
        if (row.exceptionType == '0') {
          return 'exceeding-row';
        } else if (row.exceptionType == '1') {
          return 'abnormal-power-supply';
        } else if (row.exceptionType == '2') {
          return 'disconnect';
        }
     }
      return -1
    },
           // 参数:加上前后区间的异常数据,时间字符串
    // 功能:判断data中是否有该日期时间,存在返回该时间对应的浓度值,否则返回-1
    // 功能:动态计算对话框的宽度
    calDialogWidth(){
      // this.dialogW = `calc(100vw-)`
      // console.log('宽度为',w);
    },
    //功能: 动态计算表格高度
    calcTableHeight() {
      const h1 = this.$refs.h1.$el.offsetHeight;
      const h2 = this.$refs.h4.$el.offsetHeight;
      this.tableHeight = `calc(100vh - ${h1}px - ${h2}px - 45px - var(--el-main-padding) * 2 - var(--el-card-padding))`;
    },
    // 参数:前区间的开始时间, 后区间的结束时间, 加上前后区间的总时间段的异常数据的对象数组
    // 功能:根据开始和结束时间,返回以10分钟为间隔的时间和对应的值
  keepContinuousByEachTenMinutes(intervalStarTime,intervalEndTime,headAndTailExceptionData){
      let xAxis = []
      let yAxis = []
      let obj = {}
      let current = intervalStarTime
      let tail = dayjs(intervalEndTime).add(10,'minute').format('YYYY-MM-DD HH:mm:ss')
      while(current != tail){
        let value = this.findTimeInExceptionData(headAndTailExceptionData,current)
        if(value!= -1){
          xAxis.push(current)
          yAxis.push(value)
        }else {
          xAxis.push(current)
          yAxis.push(null)
    //功能: 时间是否超过10分钟
    isTimeDifferenceGreaterThan10Minutes(dateString1, dateString2) {
      const date1 = new Date(dateString1);
      const date2 = new Date(dateString2);
      // 计算两个日期的时间差(毫秒)
      const timeDifferenceMs = Math.abs(date1 - date2);
      // 转换为分钟
      const timeDifferenceMinutes = Math.floor(timeDifferenceMs / (1000 * 60));
      // 判断时间差是否大于10分钟
      return timeDifferenceMinutes > 10;
    },
    // 以10分钟为间隔返回时间字符串数组
    generateTimePoints(timePoints, yAxisData) {
      let updatedTimePoints = [];
      let yAxisDataAdressed = [];
      for (let i = 0; i < timePoints.length; i++) {
        updatedTimePoints.push(timePoints[i]);
        yAxisDataAdressed.push(yAxisData[i]);
        if (i < timePoints.length - 1) {
          let current = timePoints[i];
          let next = timePoints[i + 1];
          while (this.isTimeDifferenceGreaterThan10Minutes(current, next)) {
            current = dayjs(current)
              .add(10, 'minute')
              .format('YYYY-MM-DD HH:mm:ss');
            updatedTimePoints.push(current);
            yAxisDataAdressed.push(null);
          }
        }
        current = dayjs(current).add(10,'minute').format('YYYY-MM-DD HH:mm:ss')
      }
      obj['xAxis'] = xAxis
      obj['yAxis'] = yAxis
      return obj
      let obj = {};
      obj['time'] = updatedTimePoints;
      obj['data'] = yAxisDataAdressed;
      return obj;
    },
    test(){
      let data = [
      { mvDataTime: '2023-07-20 12:30:00', mvFumeConcentration2: '0.2' },
      { mvDataTime: '2023-07-20 12:40:00', mvFumeConcentration2: '0.3' },
      { mvDataTime: '2023-07-20 12:50:00', mvFumeConcentration2: '0.2' },
      { mvDataTime: '2023-07-20 13:10:00', mvFumeConcentration2: '0.9' },
    ];
let obj = this.keepContinuousByEachTenMinutes('2023-07-20 12:00:00','2023-07-20 13:50:00',data)
console.log(obj)
    isExceedOneMonth(dateStr1, dateStr2) {
      // 超过一个月,返回True,否则返回False
      // 将日期字符串转为日期对象
      const date1 = new Date(dateStr1);
      const date2 = new Date(dateStr2);
      // 获取两个日期的年、月、日
      const year1 = date1.getFullYear();
      const month1 = date1.getMonth();
      const day1 = date1.getDate();
      const year2 = date2.getFullYear();
      const month2 = date2.getMonth();
      const day2 = date2.getDate();
      // 判断两个日期是否相差一个月
      if (year1 === year2) {
        // 年份相等,比较月份差值
        if (Math.abs(month1 - month2) === 1) {
          // 月份差值为1,还需要判断具体日期
          if (
            (month1 < month2 && day1 < day2) ||
            (month1 > month2 && day1 > day2)
          ) {
            return true;
          }
        }
      } else if (Math.abs(year1 - year2) === 1) {
        // 年份差值为1,比较月份和日期
        if (
          (year1 < year2 && month1 === 11 && month2 === 0 && day1 < day2) ||
          (year1 > year2 && month1 === 0 && month2 === 11 && day1 > day2)
        ) {
          return true;
        }
      }
      // 默认返回false,表示两个日期字符串不相差一个月
      return false;
    },
    // 刚打开卡片时第一个图形不会自动伸缩 当点击上/下一条时会自动伸缩
    // 图形响应式变化
    updateChart() {
      this.$nextTick(() => {
        this.calDialogWidth()
      });
    },
    // 从时间选择器组件拿到开始和结束时间
    giveTime(val) {
      //将中国标准时间转为指定格式(该组件返回的标准时间的格式,所以必须的加这个函数)
      this.beginTime = dayjs(val[0]).format('YYYY-MM-DD HH:mm:ss');
      this.endTime = dayjs(val[1]).format('YYYY-MM-DD HH:mm:ss');
    },
    // 参数:异常的开始和结束时间。返回时间数组,从开始时间的后10分钟到结束时间为止。
    // 比如12:00:00-13:00:00 所以返回的数组元素是 12:10:00 ,12:20:00,12:30:00....13:00:00
    descTenTime(begin, end) {
      let time = [];
      if(begin == end){
        time.push(begin)
        return time
      if (begin == end) {
        time.push(begin);
        return time;
      }
      // 保留结果 00 10 20 30
      let temp = dayjs(begin).add(10, 'minute').format('YYYY-MM-DD HH:mm:ss');
@@ -81,19 +783,966 @@
      time.push(temp);
      return time;
    },
    // 保存当前选择的行所有信息
    setinfo(index) {
      this.rowShopName = this.displayData[index].diName;
      this.rowExceptionType = this.displayData[index].exceptionType;
      this.rowBeginTime = this.displayData[index].beginTime;
      this.rowEndTime = this.displayData[index].endTime;
      this.rowMvStatCode = this.displayData[index].devId;
    },
    //功能: 供电异常和掉线时的表格数据
    setExceptionData() {
      // 无数据时的时间数组 时间相差10分钟
      const abnormalTimeTenMinute = this.descTenTime(
        this.rowBeginTime,
        this.rowEndTime
      );
      // 去除供电异常和掉线区间的第一个有元素的值
      this.exceedingData = [];
      for (let i = 0; i < abnormalTimeTenMinute.length; i++) {
        this.exceedingData.push({
          mvStatCode: this.rowMvStatCode,
          diName: this.rowShopName,
          mvDataTime: abnormalTimeTenMinute[i],
          mvFumeConcentration2: ''
        });
      }
      // 保存无数据时表格条数
      this.exceptionTotal = abnormalTimeTenMinute.length;
    },
    // 点击表格的行时
    selectTableRow(row) {
      // 获取当前行的索引
      this.selectedRowIndex = this.displayData.indexOf(row);
      // 进入抽屉页面更新头部数据
      this.setinfo(this.selectedRowIndex);
    },
    // 获取获取表格下一行数据
    getNextRowData() {
      // 不是表格的第一行
      if (this.selectedRowIndex !== 0) {
        // 点击过程中 锁住上下条按钮  在设置完图形配置项后解锁
        this.banTouch = 1
        //得到上一行数据索引
        this.selectedRowIndex = this.selectedRowIndex - 1;
        //请求数据 改变exceedingData
        this.setinfo(this.selectedRowIndex);
        let params = {};
        if (this.drawerData.devId) {
          params['devId'] = this.displayData[this.selectedRowIndex].devId;
        }
        if (this.drawerData.beginTime) {
          params['beginTime'] =
            this.displayData[this.selectedRowIndex].beginTime;
        }
        if (this.drawerData.endTime) {
          params['endTime'] = this.displayData[this.selectedRowIndex].endTime;
        }
        this.button.afterButton = true
        axiosInstanceInstance
          .get('/fume/exceed', { params: params })
          .then((response) => {
            // 保存返回的超标数据
            this.exceedingData = response.data.data;
            this.drawChartTest();
            this.exceptionTotal = this.exceedingData.length;
            this.button.afterButton = false
          });
      }
    },
    // 获取获取表格下一行数据
    getPreviousRowData() {
      // 不是表格的第一行
      if (this.selectedRowIndex < this.displayData.length - 1) {
        // 点击过程中 锁住上下条按钮  在设置完图形配置项后解锁
        this.banTouch = 1
        //得到上一行数据索引
        this.selectedRowIndex = this.selectedRowIndex + 1;
        //请求数据 改变exceedingData
        this.setinfo(this.selectedRowIndex);
        let params = {};
        if (this.drawerData.devId) {
          params['devId'] = this.displayData[this.selectedRowIndex].devId;
        }
        if (this.drawerData.beginTime) {
          params['beginTime'] =
            this.displayData[this.selectedRowIndex].beginTime;
        }
        if (this.drawerData.endTime) {
          params['endTime'] = this.displayData[this.selectedRowIndex].endTime;
        }
        this.button.preButton = true
        axiosInstanceInstance
          .get('/fume/exceed', { params: params })
          .then((response) => {
            // 保存返回的超标数据
            this.exceedingData = response.data.data;
            this.drawChartTest();
            this.exceptionTotal = this.exceedingData.length;
            this.button.preButton = false
          });
      }
    },
    // ‘查看详情’ 弹出框部分
    showDrawer(row) {
      // 计算当前行的索引
      this.selectTableRow(row);
      this.rowTable = row;
      // 表格的行数据以对象形式给drawerData
      this.drawerData = row;
      this.centerDialogVisible = true;
      // 根据行数据请求详细超标数据渲染折线图
      let params = {};
      if (this.drawerData.devId) {
        params['devId'] = this.drawerData.devId;
      }
      if (this.drawerData.beginTime) {
        params['beginTime'] = this.drawerData.beginTime;
      }
      if (this.drawerData.endTime) {
        params['endTime'] = this.drawerData.endTime;
      }
      axiosInstanceInstance
        .get('/fume/exceed', { params: params })
        .then((response) => {
          // 保存返回的超标数据
          this.exceedingData = response.data.data;
          this.drawChartTest();
          this.exceptionTotal = this.exceedingData.length;
        });
    },
    // 用户根据输入的条件查询
    showTable() {
      if (this.isExceedOneMonth(this.beginTime, this.endTime)) {
        alert('时间跨度不能超过一个月');
        return;
      }
      let params = {};
      if (this.deviceId[1]) {
        params['devId'] = this.deviceId[1];
      }
      if (this.exceptionValue.length != 0) {
        params['exceptionValue'] = this.exceptionValue.join();
      }
      if (this.beginTime) {
        params['beginTime'] = this.beginTime;
      }
      if (this.endTime) {
        params['endTime'] = this.endTime;
      }
      this.loading = true;
      this.button.queryButton = true
      axiosInstanceInstance
        .get('/fume/abnormalthree', { params: params })
        .then((response) => {
          this.abnormalData = response.data.data;
          this.total = this.abnormalData.length;
          this.loading = false;
          this.button.queryButton = false
          if (response.data.data.length == 0) {
            ElMessage('该时段无数据');
            this.isNoData = true;
            return;
          }
          // 移除空数据状态
          this.isNoData = false;
          this.handleCurrentChange(1);
        });
    },
    handleSizeChange(val) {
      this.pageSize = val;
      // 改变每页显示数目时跳到第一页
      this.handleCurrentChange(1);
    },
    handleCurrentChange(val) {
      const startIndex = (val - 1) * this.pageSize;
      const endIndex = startIndex + this.pageSize;
      this.displayData = this.abnormalData.slice(startIndex, endIndex);
    },
    //相差多少个十分钟  计算中并不包括开始时间,但包括结束时间。
    diffTenMinutesNum(beginNormal, endNormal) {
      // 将开始时间和结束时间转换为dayjs对象
      const start = dayjs(beginNormal);
      const end = dayjs(endNormal);
      // 计算结束时间减去开始时间中间相差多少个十分钟
      const diffInMinutes = end.diff(start, 'minute');
      const diffInTenMinutes = Math.floor(diffInMinutes / 10);
      return diffInTenMinutes;
    },
    // 参数:异常的开始时间,异常的结束时间。
    // 功能:返回开始时间的前30分钟的时间点,结束时间后40分钟的时间点
    before30AndAfter40(begin, end) {
      let time = [];
      const before30MinBegin = dayjs(begin)
        .subtract(30, 'minute')
        .format('YYYY-MM-DD HH:mm:ss');
      // 后一段的开始时间
      const after10MinBegin = dayjs(end)
        .add(10, 'minute')
        .format('YYYY-MM-DD HH:mm:ss');
      // 往后40分钟
      const after40MinEnd = dayjs(end)
        .add(40, 'minute')
        .format('YYYY-MM-DD HH:mm:ss');
      time.push(before30MinBegin);
      time.push(after10MinBegin);
      time.push(after40MinEnd);
      return time;
    },
    // 参数:设备编号, 开始时间, 结束时间
    // 功能:返回某设备在该时段历史数据的get请求参数。
    requestGetParms(devnum, begin, end) {
      return {
        devId: devnum,
        beginTime: begin,
        endTime: end
      };
    },
    // 参数:对象数组(该对象中的属性不能是引用类型,否则拷贝的值还是会相互影响)
    // 功能:拷贝该对象数组。
    shallowCopyList(itemIsObjOfList) {
      let tempList = [];
      itemIsObjOfList.forEach((item) => {
        tempList.push({ ...item });
      });
      return tempList;
    },
    // 参数:添加首尾时间数据的异常数据数组(元素为对象)
    // 功能:对中间异常区间时间和值进行补充,返回处理后的结果
    // 详细描述:遍历数组,当发现数组元素为空时,设置该元素的时间为上一个元素时间的后10分钟,并把浓度值设置为null(上个元素的时间一定不为空,无需再去判断上个元素为空的情况)。
    addTenMinutes(exceptionDataArr) {
      // x轴 日期时间
      let dateList = [];
      // y轴 超标油烟浓度
      let fumeExceeding = [];
      let obj = {};
      for (let i = 0; i < exceptionDataArr.length; i++) {
        if (exceptionDataArr[i] == null) {
          //x轴日期。元素为null时, 设置该元素的时间为前一元素的时间后10分钟
          dateList.push(
            dayjs(dateList[dateList.length - 1])
              .add(10, 'minute')
              .format('YYYY-MM-DD HH:mm:ss')
          );
          // 超标油烟浓度
          fumeExceeding.push(null);
        } else {
          //x轴日期
          dateList.push(exceptionDataArr[i].mvDataTime);
          // 超标油烟浓度
          fumeExceeding.push(exceptionDataArr[i].mvFumeConcentration2);
        }
      }
      obj['dateList'] = dateList;
      obj['fumeExceeding'] = fumeExceeding;
      return obj;
    },
    // 参数:加上前后区间的异常数据,时间字符串
    // 功能:判断data中是否有该日期时间,存在返回该时间对应的浓度值,否则返回-1
    findTimeInExceptionData(data, time) {
      for (let i = 0; i < data.length; i++) {
        if (data[i] == null) {
          continue;
        }
        if (data[i]['mvDataTime'] == time) {
          return data[i]['mvFumeConcentration2'];
        }
      }
      return -1;
    },
    // 参数:前区间的开始时间, 后区间的结束时间, 加上前后区间的总时间段的异常数据的对象数组
    // 功能:根据开始和结束时间,返回以10分钟为间隔的时间和对应的值
    keepContinuousByEachTenMinutes(
      intervalStarTime,
      intervalEndTime,
      headAndTailExceptionData
    ) {
      let xAxis = [];
      let yAxis = [];
      let obj = {};
      let current = intervalStarTime;
      let tail = dayjs(intervalEndTime)
        .add(10, 'minute')
        .format('YYYY-MM-DD HH:mm:ss');
      while (current != tail) {
        let value = this.findTimeInExceptionData(
          headAndTailExceptionData,
          current
        );
        if (value != -1) {
          xAxis.push(current);
          yAxis.push(value);
        } else {
          xAxis.push(current);
          yAxis.push(null);
        }
        current = dayjs(current)
          .add(10, 'minute')
          .format('YYYY-MM-DD HH:mm:ss');
      }
      obj['xAxis'] = xAxis;
      obj['yAxis'] = yAxis;
      return obj;
    },
    // 参数:超标数据前面区间的数据
    // 功能:返回除去最后一个元素的数组
    removeLastItemOfBeforeData(beforeDataOfExceeding) {
      let tempList = [];
      if (beforeDataOfExceeding.length == 1) {
        return tempList;
      } else {
        for (let i = 0; i < beforeDataOfExceeding.length - 1; i++) {
          tempList.push({ ...beforeDataOfExceeding[i] });
        }
        return tempList;
      }
    },
    // 设置option
    // 参数:x轴时间, y轴油烟浓度, 异常类别(0代表超标,1代表供电异常和掉线), 异常开始时间,异常结束时间,异常开始时间在整个区间的索引下标,异常结束时间在整个区间的索引下标
    setOption(
      xData,
      yData,
      exceptionCategory,
      exceptionBeginTime,
      exceptionEndTime,
      beginIndex,
      endIndex
    ) {
      this.option = {};
      // 超标
      if (exceptionCategory == 0) {
        this.option = {
          tooltip: {},
          toolbox: {
            // 工具栏
            feature: {
              //     dataZoom: {
              //   yAxisIndex: 'none'
              // },
              // 保存为图片
              saveAsImage: {}
            }
          },
          xAxis: {
            type: 'category',
            data: xData,
            name: '时间',
            axisLabel: {
              formatter: function (value) {
                return value.slice(11, -3);
              }
            }
          },
          yAxis: {
            type: 'value',
            name: 'mg/m³'
          },
          series: [
            {
              name: '油烟浓度',
              type: 'line',
              data: yData.map((item) => {
                if (item >= 1) {
                  return {
                    value: item,
                    itemStyle: {
                      color: 'red'
                    }
                  };
                }
                return item;
              }),
              // 变换指定时间区间的背景颜色
              markArea: {
                itemStyle: {
                  color: 'rgba(255, 173, 177, 0.4)'
                },
                data: [
                  [
                    {
                      name: '超标时间段',
                      xAxis: exceptionBeginTime
                    },
                    {
                      xAxis: exceptionEndTime
                    }
                  ]
                ]
              },
              markLine: {
                symbol: 'none',
                itemStyle: {
                  // 基线公共样式
                  normal: {
                    lineStyle: {
                      type: 'dashed'
                    },
                    label: {
                      show: true,
                      position: 'end',
                      formatter: '{b}'
                    }
                  }
                },
                data: [
                  {
                    name: '超标',
                    type: 'average',
                    yAxis: 1,
                    lineStyle: {
                      // color: '#ff0000'
                      color: 'red'
                    }
                  }
                ]
              }
            }
          ],
          // 指定时间区间的线段变颜色
          visualMap: {
            show: false,
            dimension: 0,
            pieces: [
              {
                lte: beginIndex,
                color: 'green'
              },
              {
                gt: beginIndex,
                lte: endIndex,
                color: 'red'
              },
              {
                gt: endIndex,
                lte: xData.length - 1,
                color: 'green'
              }
            ]
          }
        };
      }
      // 供电异常和掉线
      else if (exceptionCategory == 1) {
        this.option = {
          tooltip: {},
          toolbox: {
            // 工具栏
            feature: {
              // dataZoom: {
              //   // 区域缩放
              //   yAxisIndex: 'none'
              // },
              // 保存为图片
              saveAsImage: {}
            }
          },
          xAxis: {
            type: 'category',
            data: xData,
            name: '时间',
            axisLabel: {
              formatter: function (value) {
                return value.slice(11, -3);
              }
            }
          },
          yAxis: {
            type: 'value',
            name: 'mg/m³'
          },
          series: [
            {
              name: '油烟数据',
              type: 'line',
              data: yData,
              markLine: {
                silent: true,
                data: [
                  // 标注无数据时间段的效果,将这个时间段的数轴部分变为红色
                  {
                    name: '无数据',
                    xAxis: exceptionBeginTime
                  },
                  {
                    xAxis: exceptionEndTime
                  }
                ],
                lineStyle: {
                  color: 'red'
                }
              }
            }
          ]
        };
      }
      this.banTouch = 0
    },
    // 功能:点击 ‘查看详情’, ‘下一条’按钮时会 先逻辑计算。最后展示图形
    drawChartTest() {
      this.beforeData = [];
      this.afterData = [];
      this.allExceptionTimeData = [];
      //异常的开始时间 结束时间
      let exceptionBeginTime = this.rowBeginTime;
      let exceptionEndTime = this.rowEndTime;
      // beforeAndAfterTime[0]:前30分钟的时间点
      // beforeAndAfterTime[1]:后10分钟的时间点
      // beforeAndAfterTime[2]:后40分钟的时间点
      let beforeAndAfterTime = this.before30AndAfter40(
        exceptionBeginTime,
        exceptionEndTime
      );
      // 构造异常时间前的区间数据请求参数
      let paramsBefore = this.requestGetParms(
        this.displayData[this.selectedRowIndex].devId,
        beforeAndAfterTime[0],
        this.displayData[this.selectedRowIndex].beginTime
      );
      // 构造异常时间后的区间数据请求参数
      let paramsAfter = this.requestGetParms(
        this.displayData[this.selectedRowIndex].devId,
        beforeAndAfterTime[1],
        beforeAndAfterTime[2]
      );
      // 折线图加载中效果
      this.chartLoading = true
      // 请求前半段
      axiosInstanceInstance
        .get('/fume/history', { params: paramsBefore })
        .then((result1) => {
          this.beforeData = result1.data.data;
          // 请求后半段
          axiosInstanceInstance
            .get('/fume/history', { params: paramsAfter })
            .then((result2) => {
              this.afterData = result2.data.data;
              //保存异常区间的值
              let tempArr = [];
              // 保存异常区间前后的值
              let before = [];
              let after = [];
              // 判断是否是供电异常或掉线
              if (
                this.rowExceptionType === '1' ||
                this.rowExceptionType === '2'
              ) {
                // 重构表格 缺失异常数据自动填充
                this.setExceptionData();
                //相差几个10分钟
                const TenMinuteNum = this.diffTenMinutesNum(
                  exceptionBeginTime,
                  exceptionEndTime
                );
                //用null填充中异常无数据的时间
                for (let i = 0; i < TenMinuteNum; i++) {
                  tempArr.push(null);
                }
                before = this.shallowCopyList(this.beforeData);
                after = this.shallowCopyList(this.afterData);
                // after = this.afterData
              }
              // 超标
              else {
                let beforeTemp = this.removeLastItemOfBeforeData(
                  this.beforeData
                );
                // 前后区间只显示距离超标区间时间最近的浓度小于1的时间点
                for (let i = beforeTemp.length - 1; i >= 0; i--) {
                  if (beforeTemp[i].mvFumeConcentration2 >= 1) {
                    break;
                  }
                  if (beforeTemp[i].mvFumeConcentration2 < 1) {
                    before.unshift(this.beforeData[i]);
                  }
                }
                for (let i = 0; i < this.afterData.length; i++) {
                  if (this.afterData[i].mvFumeConcentration2 >= 1) {
                    break;
                  }
                  if (this.afterData[i].mvFumeConcentration2 < 1) {
                    after.unshift(this.afterData[i]);
                  }
                }
                tempArr = this.shallowCopyList(this.exceedingData);
              }
              // 将前后区间数据 与 异常区间数据 合并
              this.allExceptionTimeData = [...before, ...tempArr, ...after];
              // x轴日期时间
              let dateList = [];
              // y轴 超标油烟浓度
              let fumeExceeding = [];
              let timeAndValue = {};
              // 从添加了首位区间的开始和结束时间进行遍历 保证时间以10分钟为间隔
              timeAndValue = this.keepContinuousByEachTenMinutes(
                beforeAndAfterTime[0],
                beforeAndAfterTime[2],
                this.allExceptionTimeData
              );
              dateList = timeAndValue['xAxis'];
              fumeExceeding = timeAndValue['yAxis'];
              // 提取异常起始时间点在整个区间内的数据索引
              let startIndex = dateList.findIndex(
                (item) => item === exceptionBeginTime
              );
              let endIndex = dateList.findIndex(
                (item) => item === exceptionEndTime
              );
              // 供电异常和掉线情况 超标情况
              if (
                this.rowExceptionType === '1' ||
                this.rowExceptionType === '2'
              ) {
                this.setOption(
                  dateList,
                  fumeExceeding,
                  1,
                  exceptionBeginTime,
                  exceptionEndTime,
                  startIndex,
                  endIndex
                );
              } else {
                // 超标情况
                this.setOption(
                  dateList,
                  fumeExceeding,
                  0,
                  exceptionBeginTime,
                  exceptionEndTime,
                  startIndex,
                  endIndex
                );
              }
              this.chartLoading = false
            });
        });
    },
    getDeviceInfo() {
      // 级联下拉框数据 从接口中动态获取
      axiosInstanceInstance.get('/fume/device').then((result) => {
        this.deviceInfo = result.data.data;
        // 获取到总的店铺数量
        this.shopsTotal = result.data.data.length;
        this.deviceInfo.forEach((item) => {
          this.optionsShop[this.optionsShop.length] = {
            value: item.diName,
            label: item.diName,
            children: [
              {
                value: item.diCode,
                label: item.diCode
              }
            ]
          };
        });
      });
    },
    exportDom() {
      // 导出为Excel文件
      const fields = [
        'devId',
        'exceptionType',
        'region',
        'beginTime',
        'endTime'
      ];
      const itemsFormatted = this.abnormalData.map((item) => {
        const newItem = {};
        fields.forEach((field) => {
          newItem[field] = item[field];
        });
        return newItem;
      });
      // 创建xlsx对象
      const xls = XLSX.utils.json_to_sheet(itemsFormatted);
      // 编辑表头行       修改表头
      xls['A1'].v = '设备编号';
      xls['B1'].v = '异常类型';
      xls['C1'].v = '地区';
      xls['D1'].v = '开始时间';
      xls['E1'].v = '结束时间';
      // 创建workbook,并把sheet添加进去
      const wb = XLSX.utils.book_new();
      XLSX.utils.book_append_sheet(wb, xls, 'Sheet1');
      // 将workbook转为二进制xlsx文件并下载
      XLSX.writeFile(wb, '分析数据.xlsx');
    },
    getAbnormalDataByClick(val) {
      this.abnormalData = val;
      this.total = this.abnormalData.length;
      // 默认显示第一页
      this.handleCurrentChange(1);
    },
    // 根据异常类型返回店铺名称和设备编号
    // 比如油烟超标对应的所有店铺名称和设备编号(已去除重复的店铺名)
    getShopNames() {
      axiosInstanceInstance
        .get('/fume/shopname', {
          params: {
            exceptionType: '0',
            beginTime: this.beginTime,
            endTime: this.endTime
          }
        })
        .then((result) => {
          this.exception0 = result.data.data;
        });
      axiosInstanceInstance
        .get('/fume/shopname', {
          params: {
            exceptionType: '1',
            beginTime: this.beginTime,
            endTime: this.endTime
          }
        })
        .then((result) => {
          this.exception1 = result.data.data;
        });
      axiosInstanceInstance
        .get('/fume/shopname', {
          params: {
            exceptionType: '2',
            beginTime: this.beginTime,
            endTime: this.endTime
          }
        })
        .then((result) => {
          this.exception2 = result.data.data;
        });
    },
    // 页面加载时默认展示7天异常表数据
    getRecentSevenDays() {
      // 给级联选择器设置默认的选择项
      this.devId = ['付小姐在成都', 'qinshi_31010320210010'];
      let params = {};
      params['beginTime'] = this.beginTime;
      params['endTime'] = this.endTime;
      axiosInstanceInstance
        .get('/fume/abnormalone', { params: params })
        .then((response) => {
          if (response.data.data.length == 0) {
            ElMessage('该时段无数据');
            return;
          }
          // 保存返回的
          this.abnormalData = response.data.data;
          // 分页
          this.total = this.abnormalData.length;
          // 默认显示第一页
          this.handleCurrentChange(1);
          this.loading = false;
        });
    }
  }
};
</script>
<template>
  <div>
    <ExceptionTypeLineChart
      :xData="xAxis"
      :yData="yAxis"
    ></ExceptionTypeLineChart>
  </div>
</template>
<style scoped>
<style lang="scss" scoped></style>
.header-container {
  display: flex;
  margin-left: 20px;
  /* flex-wrap: wrap;
    align-items: center; */
}
.ellipsis {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.iconExcel {
  font-size: 25px;
  margin-left: 20px;
  bottom: -6px;
}
/* 可鼠标箭头变为可点击状态 */
.clickable {
  cursor: pointer;
}
.card-header {
  margin: 0;
}
body {
  margin: 0;
}
.exception-divider-rowline {
  margin: 10px 0px;
}
/* 异常分析数据与按钮 */
.exception-container {
  display: flex;
}
.example-showcase .el-loading-mask {
  z-index: 9;
}
.scrollbar-demo-item {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 20px;
  margin: 10px;
  text-align: center;
  border-radius: 4px;
  background: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
}
.collapse-header {
  margin-left: 5px;
  font-size: 18px;
}
.collapse-header-text {
  margin-top: 5px;
  font-size: 14px;
  color: gray;
}
.box-card-label {
  font-size: 14px;
  white-space: nowrap;
}
:deep().el-card {
  border-radius: 9px;
}
/* ‘查看详情’ 的弹出框高度调整 */
:deep().el-dialog {
  height: 98%;
  /* 不出现滚动条 */
  overflow-y: hidden;
  border-radius: 9px;
}
.table-page {
  margin-left: 20px;
}
.table-text {
  font-size: 18px;
  margin: 5px 0px 10px 20px;
}
.text-blank {
  margin-right: 10px;
  color: #000000;
}
/* 店铺名选择文本 */
.describe-info {
  margin-top: 5px;
  font-weight: bold;
  white-space: nowrap;
}
/* 时间选择文本 */
.describe-time-text {
  margin-left: 30px;
  margin-top: 5px;
  font-weight: bold;
}
/* 异常表格下标签中的数组 */
.table-line-num {
  font-weight: bold;
  color: black;
}
.button_info.el-button_inner {
  text-align: left;
}
.el-collapse {
  margin-left: 20px;
}
:deep().el-collapse .el-collapse-item__content {
  padding-bottom: 0px;
}
.box-card {
  height: 190px;
}
.sub-box-card {
  height: 100px;
  border: 0px;
}
.mx-1 {
  margin-bottom: 0px;
}
.dialog-button-position {
  display: flex;
  justify-content: right;
  margin-bottom: 10px;
}
:deep().el-table__row .exceeding-row{
  background-color:  #F53F3F;
}
:deep().el-table__row .abnormal-power-supply{
  background-color:  #FDF4BF;
}
:deep().el-table__row .disconnect{
  background-color:  #F7BA1E;
}
.el-table {
  color: #000000;
}
/* 表格的内边距 */
:deep().el-table .el-table__cell {
  padding: 2px;
}
/* 表格中的按钮宽度铺满 */
.table-button {
  width: 100%;
}
</style>
src/utils/request.js
@@ -1,7 +1,10 @@
import axios from 'axios'
// const baseUrl = 'http://114.215.109.124:8803' // 基础URL
const baseUrl = 'http://localhost:8081' // 基础URL
// 部署URL
// const baseUrl = 'http://114.215.109.124:8803'
 // 本地URL
const baseUrl = 'http://localhost:8081'
const axiosInstance = axios.create({
  baseURL: baseUrl
src/utils/requestPy.js
@@ -1,7 +1,10 @@
import axios from 'axios'
const baseUrl = 'http://114.215.109.124:8805' // 基础URL
// const baseUrl = ' http://127.0.0.1:8089' // 基础URL
// 部署URL
// const baseUrl = 'http://114.215.109.124:8089'
// 本地URL
const baseUrl = 'http://127.0.0.1:8089'
const axiosInstancePy = axios.create({
  baseURL: baseUrl
src/views/ExceedingFume.vue
@@ -20,9 +20,9 @@
        <el-button
          type="primary"
          plain
          @click="showTable"
          style="margin-left: 20px"
          :loading="button.queryButton"
          @click="showTable"
          >查询</el-button
        >
@@ -45,7 +45,7 @@
      </div>
      <div style="display: flex; justify-content: right; margin-right: 40px">
        <span class="collapse-header-text">
          静安区 {{ beginTime }} —— {{ endTime }} 油烟检测异常信息汇总</span
          静安区 {{ beginTime }} —— {{ endTime }} 油烟监测异常信息汇总</span
        >
      </div>
      <br />
@@ -94,15 +94,20 @@
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span class="box-card-label">异常店铺占比:</span>
                    <span style="font-size: 20px"
                      >{{ exception0.length }} /{{ shopsTotal }}</span
                      >{{ exception0.length }} /{{ shopsTotal }}
                      </span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception0.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    <span style="font-size: 17px">
                      ({{
                        ((exception0.length/shopsTotal)*100).toFixed(1)
                      }}%)</span
                    >
                    {{  shopsTotal}}
                    <span class="right-text">
                      异常数占比:{{  ((exception0Num/exceptionAllNum) * 100).toFixed(1) }}%
                    </span>
                  </el-scrollbar>
                </div>
@@ -149,15 +154,18 @@
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span class="box-card-label">异常店铺占比:</span>
                    <span style="font-size: 20px"
                      >{{ exception1.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception1.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    <span style="font-size: 17px">
                      ({{
                        ((exception1.length/shopsTotal)*100).toFixed(1)
                      }}%)</span
                    >
                    <span class="right-text">
                      异常数占比:{{  ((exception1Num/exceptionAllNum) * 100).toFixed(1) }}%
                    </span>
                  </el-scrollbar>
                </div>
@@ -200,20 +208,23 @@
                      margin-top: 5px;
                      margin-left: 4px;
                    "
                    >掉线</span
                    >联网异常</span
                  >
                </div>
                <div class="box-card-label">
                  <el-scrollbar>
                    <span class="box-card-label">店铺数量:</span>
                    <span class="box-card-label">异常店铺占比:</span>
                    <span style="font-size: 20px"
                      >{{ exception2.length }} /{{ shopsTotal }}</span
                    >
                    <span style="margin-left: 150px; font-size: 14px">
                      占比:{{
                        ((exception2.length / shopsTotal) * 100).toFixed(1)
                      }}%</span
                    <span style="font-size: 17px">
                      ({{
                        (((exception2.length)/shopsTotal)*100).toFixed(1)
                      }}%)</span
                    >
                    <span class="right-text">
                      异常数占比:{{ connectException  }}%
                    </span>
                  </el-scrollbar>
                </div>
                <hr />
@@ -252,6 +263,7 @@
  <el-card class="table-page" v-show="!isNoData">
    <el-table
      ref="tableH"
      size="small"
      v-loading="loading"
      :data="displayData"
      style="width: 100%"
@@ -260,7 +272,7 @@
      :cell-class-name="tableCellClassName"
 
    >
      <el-table-column prop="diName" label="店铺名称">
      <el-table-column prop="diName" label="店铺名称" align="center">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.diName">
            <div class="cell ellipsis">{{ row.diName }}</div>
@@ -268,7 +280,7 @@
        </template>
      </el-table-column>
      <el-table-column prop="devId" label="设备编号">
      <el-table-column prop="devId" label="设备编号" align="center">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.devId">
            <div class="cell ellipsis">{{ row.devId }}</div>
@@ -276,21 +288,30 @@
        </template>
      </el-table-column>
      <el-table-column prop="exception" label="异常分类">
      <el-table-column prop="diSupplier" label="供应商" align="center">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.diSupplier">
            <div class="cell ellipsis">{{ row.diSupplier }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="exception" label="异常分类" align="center">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.exception">
            <div class="cell ellipsis">{{ row.exception }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column label="异常类型">
      <el-table-column label="异常类型" align="center">
        <template #default="{ row }">
          <span v-if="row.exceptionType == '0'">油烟数据超标</span>
          <span v-else-if="row.exceptionType == '1'">疑似供电异常</span>
          <span v-else-if="row.exceptionType == '2'">掉线</span>
        </template>
      </el-table-column>
      <el-table-column prop="region" label="地区">
      <el-table-column prop="region" label="地区" align="center">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.region">
            <div class="cell ellipsis">{{ row.region }}</div>
@@ -298,21 +319,21 @@
        </template>
      </el-table-column>
      <el-table-column prop="beginTime" label="开始时间">
      <el-table-column prop="beginTime" label="开始时间" align="center">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.beginTime">
            <div class="cell ellipsis">{{ row.beginTime }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column prop="endTime" label="结束时间">
      <el-table-column prop="endTime" label="结束时间" align="center">
        <template #default="{ row }">
          <el-tooltip effect="dark" :content="row.endTime">
            <div class="cell ellipsis">{{ row.endTime }}</div>
          </el-tooltip>
        </template>
      </el-table-column>
      <el-table-column label="操作">
      <el-table-column label="操作" align="center">
        <template #default="{ row }">
          <el-button
            type="primary"
@@ -350,6 +371,7 @@
            {{ rowEndTime }}
          </div>
        </div>
        <div class="dialog-button-position">
          <el-button
            type="danger"
@@ -399,13 +421,25 @@
          border
          style="margin-top: 25px"
        >
          <el-table-column fixed prop="diName" label="店铺名称" />
          <el-table-column prop="mvStatCode" label="设备编号" />
          <el-table-column prop="mvDataTime" label="采集时间" />
         <el-table-column
          type="index"
          label="序号"
          width="60px"
          align="center"
          fixed
          :index="indexMethod"
        ></el-table-column>
          <el-table-column fixed prop="diName" label="店铺名称"  show-overflow-tooltip/>
          <el-table-column prop="mvStatCode" label="设备编号" align="center" show-overflow-tooltip/>
          <el-table-column prop="diSupplier" label="供应商" align="center" show-overflow-tooltip/>
          <el-table-column prop="mvDataTime" label="采集时间" align="center" show-overflow-tooltip/>
          <el-table-column
            prop="mvFumeConcentration2"
            label="油烟浓度(mg/m³)"
            align="center"
            show-overflow-tooltip
          />
        </el-table>
      </div>
@@ -430,6 +464,7 @@
import ExceptionType from '../sfc/ExceptionType.vue';
import TimeSelect from '../sfc/TimeSelect.vue';
import ExceptionText from '../sfc/ExceptionText.vue';
import * as XLSX from 'xlsx/xlsx.mjs';
import dayjs from 'dayjs';
import axiosInstanceInstance from '../utils/request.js';
@@ -453,6 +488,9 @@
  },
  data() {
    return {
      exception0Num:0,
      exception1Num:0,
      exception2Num:0,
      // 折线图加载中
      chartLoading:false,
      button:{
@@ -502,7 +540,8 @@
      rowEndTime: '',
      // 异常的设备编号
      rowMvStatCode: '',
      // 供应商
      rowDiSupplier:'',
      // 表格的一行数据
      rowTable: [],
      //拼接的所有数据
@@ -614,7 +653,21 @@
      window.addEventListener('resize', this.updateChart);
    }
  },
  computed:{
    exceptionAllNum(){
      let sum = this.exception0Num+this.exception1Num+this.exception2Num
      return sum == 0?1:sum
    },
    connectException(){
      let sum = this.exception0Num+this.exception1Num+this.exception2Num
      if(sum == 0){
        return 0
      }
      else{
        return (100 - ((exception0Num/sum) * 100) - ((exception1Num/sum) * 100)).toFixed(1)
      }
    }
  },
  mounted() {
    // 从接口获取店铺名称 给级联下拉框
    this.getDeviceInfo();
@@ -626,9 +679,15 @@
    window.addEventListener('resize', this.updateChart);
  },
  methods: {
    // 功能:对话框表格序号递增
    // 时间:2023-8-17
    indexMethod(index) {
      return index + 1 ;
    },
    // 功能:改变表格某个单元格的颜色
    tableCellClassName({ row, column, rowIndex, columnIndex }) {
     if(columnIndex == 3){
     if(columnIndex == 4){
        if (row.exceptionType == '0') {
          return 'exceeding-row';
        } else if (row.exceptionType == '1') {
@@ -774,6 +833,7 @@
      this.rowBeginTime = this.displayData[index].beginTime;
      this.rowEndTime = this.displayData[index].endTime;
      this.rowMvStatCode = this.displayData[index].devId;
      this.rowDiSupplier = this.displayData[index].diSupplier
    },
    //功能: 供电异常和掉线时的表格数据
@@ -790,6 +850,7 @@
        this.exceedingData.push({
          mvStatCode: this.rowMvStatCode,
          diName: this.rowShopName,
          diSupplier:this.rowDiSupplier,
          mvDataTime: abnormalTimeTenMinute[i],
          mvFumeConcentration2: ''
        });
@@ -1540,6 +1601,41 @@
        .then((result) => {
          this.exception2 = result.data.data;
        });
        /* 异常数量 */
        axiosInstanceInstance
        .get('/fume/exceptionnum', {
          params: {
            exceptionType: '0',
            beginTime: this.beginTime,
            endTime: this.endTime
          }
        })
        .then((result) => {
          this.exception0Num = result.data.data;
        });
        axiosInstanceInstance
        .get('/fume/exceptionnum', {
          params: {
            exceptionType: '1',
            beginTime: this.beginTime,
            endTime: this.endTime
          }
        })
        .then((result) => {
          this.exception1Num = result.data.data;
        });
        axiosInstanceInstance
        .get('/fume/exceptionnum', {
          params: {
            exceptionType: '2',
            beginTime: this.beginTime,
            endTime: this.endTime
          }
        })
        .then((result) => {
          this.exception2Num = result.data.data;
        });
    },
    // 页面加载时默认展示7天异常表数据
@@ -1550,7 +1646,7 @@
      params['beginTime'] = this.beginTime;
      params['endTime'] = this.endTime;
      axiosInstanceInstance
        .get('/fume/abnormalone', { params: params })
        .get('/fume/abnormalthree', { params: params })
        .then((response) => {
          if (response.data.data.length == 0) {
            ElMessage('该时段无数据');
@@ -1636,9 +1732,16 @@
  font-size: 14px;
  white-space: nowrap;
}
.right-text {
  /* float :right; */
  /* text-align: right; */
  margin-left:80px;
}
:deep().el-card {
  border-radius: 9px;
}
/* ‘查看详情’ 的弹出框高度调整 */
:deep().el-dialog {
  height: 98%;
@@ -1716,10 +1819,6 @@
.el-table {
  color: #000000;
}
/* 表格的内边距 */
:deep().el-table .el-table__cell {
  padding: 2px;
}
src/views/HistoryFume.vue
@@ -5,7 +5,6 @@
import axiosInstanceInstance from '../utils/request.js'
import TimeSelect from '../sfc/TimeSelect.vue';
// import ShopNameAndID from '../sfc/TimeSelect.vue';
const ShopNameAndID = defineAsyncComponent(() =>
  import('../sfc/../sfc/ShopNameAndID.vue')
@@ -163,7 +162,6 @@
            }
          ]
        }
        console.log('option为:',this.options);
      }
      else if (this.radio == 2) {
         // x轴日期时间
@@ -201,7 +199,6 @@
         
        ]
        }
        console.log('option为:',this.options);
      }
      else {
        // x轴日期时间
@@ -245,11 +242,8 @@
        ]
        }
      }
      console.log('option为:',this.options);
      }
      else{
        console.log('exceedingData无数据');
      }
      
    
  },
@@ -266,7 +260,6 @@
    this.exportBeginTime =this.beginTime
    this.exportEndTime = this.endTime
    console.log(this.currentDateTime, this.oneWeekAgoDateTime);
    let params = {};
    params['devId'] = 'qinshi_31010320210010';
@@ -289,9 +282,6 @@
        this.total = this.exceedingData.length;
        // 默认显示第一页
        this.handleCurrentChange(1);
        // this.drawChart();
        this.loading = false;
        console.log('历史数据为:', this.exceedingData);
      })
  
  },
@@ -370,7 +360,6 @@
    axiosInstanceInstance.get('/fume/export', { params: params }).then((result) => {
      this.exportData = result.data.data;
      console.log(this.exportData);
    });
  },
  exportExcel() {
@@ -434,7 +423,6 @@
    const year2 = date2.getFullYear();
    const month2 = date2.getMonth();
    const day2 = date2.getDate();
    console.log(month1, month2);
    // 判断两个日期是否相差一个月
    if (year1 === year2) {
@@ -682,4 +670,8 @@
.el-table {
  color: #000000;
}
.chart-container {
  height: 60vh;
  width:80vw
}
</style>
src/views/IndexView.vue
@@ -240,10 +240,7 @@
          .get('/fume/lastest', { params: params })
          .then((result) => {
            this.outside.realTimeData = result.data.data;
            console.log('66', this.outside.realTimeData);
            // console.log('长度为:',this.outside.realTimeData.length);
            // 渲染折线图
            // this.updateCharts();
          });
      }
@@ -258,7 +255,6 @@
            this.inner.inFumeValue.push(item);
          }
        });
        console.log(this.inner.inFumeValue);
      }
      // 合并
@@ -268,10 +264,8 @@
          ...this.inner.inFumeValue,
          ...this.outside.realTimeData
        ];
        console.log('总选数据', this.totalData);
        console.log('长度为:', this.totalData.length);
      }, 200);
      console.log('调用了');
    },
    // 点击按钮触发
@@ -427,12 +421,7 @@
            <!-- </el-form-item> -->
          </el-form>
        </el-card>
      </el-collapse-item>
    </el-collapse>
  </div>
  <div>
          <div>
    <el-tooltip
      class="box-item"
      effect="dark"
@@ -452,6 +441,13 @@
    </el-switch>
  </div>
        </el-card>
      </el-collapse-item>
    </el-collapse>
  </div>
  <div>
    <el-row :gutter="20">
      <el-col
@@ -465,26 +461,35 @@
            <div class="card-header">{{ device.siteName }} 
              <img src="@/assets/inner_device.jpg" class="icon-inner"/>
            </div>
          </template>
          <div class="report-time-text">数据发布时间:{{ device.time }}</div>
          <DashBoard :data="device.value"></DashBoard>
          <div class="imag-container">
            <img src="@/assets/wind.jpg" class="image"/>
          <span class="chart-below-text"> 风机电流(A):0 </span>
          <span class="chart-below-text2">
            <img src="@/assets/purifier.jpg" class="image"/>
            净化器电流(A):0
          </span>
         </div>
         <div class="horizontal-line"></div>
          <div >设备编号:{{ device.mnCode }}</div>
          <div class="horizontal-line"></div>
          
          <div class="status" :class="{ exceed: device.value > 1 }">
            {{ device.value >= 1 ? '超标' : '' }}
          </div>
          <br />
          <br />
          <br />
        </el-card>
        <!-- 外部设备 -->
        <el-card v-else class="card-font-color">
          <template #header>
            <div class="card-header">
            <div class="card-header out-device">
              {{ device.diName }}
            </div>
          </template>
@@ -669,4 +674,7 @@
  height: 1px;
  background-color: rgb(221, 217, 217);
}
.out-device {
  margin-top:34px;
}
</style>
src/views/LoginInterface.vue
@@ -42,7 +42,7 @@
      if (this.username === 'admin' && this.password === 'admin123') {
         ElMessage.success('登录成功');
          // 登录成功,跳转到对应页面
          this.$router.push('/hdata') // 假设登录成功后跳转到 '/dashboard' 页面
          this.$router.push('/ndata') // 假设登录成功后跳转到 '/dashboard' 页面
        } else {
          // console.log('Login Failed!')
          ElMessage.error('账号或密码错误');
@@ -54,7 +54,7 @@
<style scoped>
.login-container {
  background-image: url('../assets/login.jpg');
  background-image: url('../assets/login.png');
                      /*用于为一个元素设置一个或者多个背景图像。 */
  background-size: cover;         /* 将背景图像等比缩放到完全覆盖容器,背景图像有可能超出容器。*/
  background-position: center;  /* 为每一个背景图片设置初始位置。这个位置是相对于由 background-origin 定义的位置图层的 键字 center,用来居中背景图片。*/
src/views/analysis/DataShow.vue
@@ -54,7 +54,7 @@
      <!-- <el-main> -->
        <div class="table">
        <el-table :data="displayData" border="" id="table" ref="table" table-layout="auto" >
          <!-- <el-table-column prop="id" label="序号" width="60"></el-table-column> -->
          <el-table-column
            type="index"
            label="序号"
@@ -88,7 +88,7 @@
            label="供应商"
            v-if="showColumn.privides"
          ></el-table-column>
          <!-- <el-table-column prop="smokePushDensity" label="进烟浓度mg/m³" width="130"> </el-table-column> -->
          <el-table-column
            prop="smokePopDensity"
            label="油烟浓度(mg)"
@@ -131,7 +131,7 @@
            v-if="showColumn.attributiontime"
          >
          </el-table-column>
          <!-- <el-table-column prop="reportingTime" label="上报时间" width="100"> </el-table-column> -->
          <el-table-column fixed="right" width="100" align="center">
            <template v-slot:header>
@@ -141,13 +141,7 @@
            @click="showColumnOption">
          </i-ep-setting>
          </template>
            <!-- <template v-slot:header>
              <i
                class="el-icon-setting"
                style="font-size: 22px; cursor: pointer"
                @click="showColumnOption"
              ></i>
            </template> -->
          </el-table-column>
        </el-table>
@@ -199,8 +193,7 @@
          </div>
        </transition>
      </div>
      <!-- </el-main> -->
    <!-- </el-container> -->
  </div>
</template>
@@ -387,17 +380,7 @@
      // 将workbook转为二进制xlsx文件并下载
      XLSX.writeFile(wb, '页面数据.xlsx');
      // this.jsonData=this.tableData
      // const sheetName = '数据表';
      // const worksheet = XLSX.utils.json_to_sheet(this.jsonData);
      // // 导出Excel文件
      // const workbook = XLSX.utils.book_new();
      // XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
      // const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
      // const fileName = '页面数据.xlsx';
      // const file = new Blob([excelBuffer], {type: 'application/octet-stream'});
      // saveAs(file, fileName);
    },
    handleSizeChange(val) {
      this.pageSize = val;
@@ -407,12 +390,10 @@
      const startIndex = (val - 1) * this.pageSize;
      const endIndex = startIndex + this.pageSize;
      this.displayData = this.tableData.slice(startIndex, endIndex);
      // this.indexMethod(this.pageSize)
    },
    //序号递增
    indexMethod(index) {
      // let limitpage = this.pageSize; // 每页条数
      // let curpage = this.currentPage; // 当前页码
      return index + 1 + (this.currentPage - 1) * this.pageSize;
    },
@@ -432,7 +413,6 @@
    // 监听复选框配置列所有的变化
    checkList: {
      handler: function (newnew) {
        // console.log(newnew);
        this.showColumn = newnew;
        // 这里需要让表格重新绘制一下,否则会产生固定列错位的情况
        this.$nextTick(() => {
@@ -449,7 +429,6 @@
<style>
/* 表格 */
.table {
  /* margin: 10px,0px,10px,10px; */
  margin: 10px;
}
.button-and-export {
src/views/analysis/HomePage.vue
@@ -2,7 +2,7 @@
<template>
  <div   class="page-header">
        <el-radio disabled v-model="radio" label="选中且禁用" >徐汇区 天耀桥 田上坊</el-radio>
        <el-radio disabled v-model="radio" label="选中且禁用" >徐汇区 天钥桥 田尚坊</el-radio>
  
        <div class="page-label" >
          <span class="shop-label">店铺名</span>
@@ -18,7 +18,6 @@
      </el-option>
    </el-select>
  </div>          
   <!-- <el-form-item label="开始日期"  class="form-time-lable1"> -->
    <div class="time-label"> 
    <span>开始日期 </span>
    <el-date-picker
@@ -29,9 +28,7 @@
  </el-date-picker>
</div>
<div class="time-label">
   <!-- </el-form-item> -->
   <span>结束日期 </span>
  <!-- <el-form-item label="结束日期" class="form-time-lable2"> -->
    <el-date-picker
    v-model="end"
    type="datetime"
@@ -47,12 +44,7 @@
</div>
  
  <!-- <span style="margin-left: 200px; ">分析耗时:{{gapT}}ms</span>
    <el-divider direction="vertical"></el-divider>
  <span>结果条数:{{total}}</span>
    <el-divider direction="vertical"></el-divider>
  <span>已写入数据库:{{isWrite}}</span> -->
  <!-- <br/> -->
  <div style="display: flex; justify-content: right; margin-right: 110px;">
  <span >分析耗时:{{gapT}}ms</span>
  <el-divider direction="vertical"></el-divider>
@@ -60,15 +52,12 @@
  <el-divider direction="vertical"></el-divider>
</div>
<br/>
   <!-- </el-form> -->
  <!-- </el-card> -->
  <!-- </el-header> -->
  <!-- <el-main> -->
    <div class="table" v-show="!isNoData" v-loading="loading">
      <el-table  :data="displayData" border="" id="table" ref="table" height="500px"  >
      <el-table-column type="index" label="序号" :index="indexMethod" v-if="showColumn.num"> </el-table-column> <!--绑定一个方法,将返回值赋给index,即表格每行数据的下标-->
      <el-table-column prop="fumeDevId" label="设备编号" v-if="showColumn.deviceid" fixed> </el-table-column>
      <el-table-column type="index" label="序号" :index="indexMethod" v-if="showColumn.num" fixed> </el-table-column> <!--绑定一个方法,将返回值赋给index,即表格每行数据的下标-->
      <el-table-column prop="diName" label="店铺名称" v-if="showColumn.diName"> </el-table-column>
      <el-table-column prop="fumeDevId" label="设备编号" v-if="showColumn.deviceid" > </el-table-column>
      <el-table-column prop="fumeDate"   label="日期"  v-if="showColumn.date"> </el-table-column>
      <el-table-column prop="fumeDayMin" label="日最小值"  v-if="showColumn.min"></el-table-column>
      <el-table-column prop="fumeDayMax" label="日最大值"  v-if="showColumn.max"> </el-table-column>
@@ -121,6 +110,7 @@
      <div class="head">选择显示字段</div>
      <div class="body">
        <el-checkbox v-model="checkList.num"  disabled>编号</el-checkbox>
        <el-checkbox v-model="checkList.diName" disabled>店铺名称</el-checkbox>
        <el-checkbox v-model="checkList.deviceid" disabled>设备编号</el-checkbox>
        <el-checkbox v-model="checkList.date">日期</el-checkbox>
        <el-checkbox v-model="checkList.min">日最小值</el-checkbox>
@@ -188,6 +178,7 @@
      checkList: {},
      showColumn: {
          num:true,
          diName:true,
          deviceid:true,
          date:true,
          min:true,
@@ -268,6 +259,7 @@
      this.checkList = {
        num:true,
        deviceid:true,
        diName:true,
        date:true,
        min:true,
        max:true,
@@ -326,6 +318,7 @@
        }
      // 移除空数据状态
      this.isNoData = false
      this.isRepeated = 0
    this.total = this.afterAnalysis.length;
    this.handleCurrentChange(1); // 默认显示第一页
@@ -334,6 +327,10 @@
  let endTime=new Date().getTime()
  this.gapT=endTime-startTime
},
getHasExisitedData(){
},
//是否重复
@@ -359,12 +356,21 @@
  this.loading=true
  this.button.statisticsButton = true
  axiosInstanceInstance.get('/data/search',{params:params}).then(response => {
      this.isRepeated=response.data.data
      if(this.isRepeated>0){
      // this.isRepeated=response.data.data
      if(response.data.data.length>0){
          alert('该店铺的时段已存在分析数据,请重新选择')
          this.isRepeated = 1
          this.loading=false
          this.isNoData = false
          this.button.statisticsButton = false
          this.afterAnalysis = response.data.data
          this.total = this.afterAnalysis.length;
          // 默认显示第一页
          this.handleCurrentChange(1);
          return
      }else{
      }
       // 请求已存在的数据
      else{
        this.analysisData()
        this.button.statisticsButton = false
      }
@@ -373,23 +379,27 @@
},
//写入MySql
toSql(){
  this.button.WarehousingButton = true
  this.afterAnalysis.forEach((item)=>{
    console.log(item);
    let jsonData=JSON.stringify(item)
    console.log(jsonData);
    axiosInstanceInstance.post('/data/tosql',jsonData,{headers:{
      'Content-Type':'application/json'
    }}).then((result)=>{
      console.log(result);
  if(this.isRepeated == 0){
      this.button.WarehousingButton = true
    this.afterAnalysis.forEach((item)=>{
      let jsonData=JSON.stringify(item)
      // axiosInstanceInstance.post('/data/tosql',jsonData,{headers:{
      //   'Content-Type':'application/json'
      // }}).then((result)=>{
      //   // console.log(result);
      // })
    })
  })
  alert('已成功写入数据库')
  this.button.WarehousingButton = fasle
  this.isWrite='是'
    alert('已成功写入数据库')
    this.button.WarehousingButton = fasle
    this.isWrite='是'
    }else{
      alert('重复值不可写入数据库')
    }
},
@@ -399,6 +409,7 @@
},
handleCurrentChange(val) {
const startIndex = (val - 1) * this.pageSize;
const endIndex = startIndex + this.pageSize;
this.displayData = this.afterAnalysis.slice(startIndex, endIndex);
@@ -450,7 +461,7 @@
</script>
<style>
<style lang="scss">
/* 卡片 */
.box-card {
  /* width: 1700px; */
src/views/analysis/graph/AllRate.vue
@@ -289,10 +289,7 @@
      this.chart = echarts.init(this.$refs.lineChart)
      this.chart.setOption({
        title: {
          text: '比率',
          //left: 'center'
        },
        grid: {
          left: '3%',
          right: '4%',
@@ -303,7 +300,7 @@
  
        legend: {
          data: ['净化器开启率','超标率','数据有效率','日在线率','中午在线率','晚上在线率','重点时段在线率','中午有效率','晚上有效率','重点时段有效率','中午开启率','晚上开启率','重点时段开启率','中午超标率','晚上超标率','重点时段超标率'],
          //type: "scroll"
        },
        toolbox: {    //工具栏
          top:20,
src/views/analysis/graph/DayData.vue
@@ -38,7 +38,7 @@
          </el-form-item>
          <el-form-item>
            <el-button type="primary" loading="button.showChartButton" @click="fetchData">展示图</el-button>
            <el-button type="primary" :loading="button.showChartButton" @click="fetchData">展示图</el-button>
          </el-form-item>
        </el-form>
src/views/getdata/GetData.vue
@@ -56,7 +56,6 @@
    autoLogin(){
      this.login_loading = true
      axiosInstancePy.get('/autologin').then(response =>{
          console.log('登陆结果为:',response.data);
          ElMessage.success(response.data)
          this.login_loading = false
        })
@@ -78,7 +77,6 @@
      this.loading = true;
      // 得到反馈信息 所有数据
      axiosInstancePy.post('/getData', form).then((response) => {
        console.log(response.data);
        if(response.data == '-1'){
          this.loading = false;
          // ElMessage.warning('请先点击登陆')
@@ -96,19 +94,13 @@
          this.result = this.result + item + '\n';
        });
        
        //  response.data.allData.forEach(item=>{
        //   this.allData =this.allData+item+'\n'
        //   this.allData =this.allData+'\n'
        //  });
        this.allData = response.data.allData;
        this.duplicateData = response.data.duplicate;
        console.log('重复的数据为:', this.duplicateData);
        this.newData = response.data.newData;
        console.log('新数据条数为:',this.newData.length);
        this.loading = false;
        this.displayData = this.arrToObject(this.duplicateData);
        console.log('转换后的对象数组为:',this.displayData);
        this.result=this.result+'\n重复的数量为:'+this.duplicateData.length
      });
@@ -146,7 +138,6 @@
      }
      this.openFullScreen()
      axiosInstancePy.post('/store', {'allData':this.allData}).then((response) => {
        console.log(response.data);
        ElMessage.success(response.data)
        this.loadingToMysql.close()
      })
@@ -164,7 +155,6 @@
      axiosInstancePy
        .post('/store', { 'allData': this.newData })
        .then((response) => {
          console.log(response.data);
          ElMessage.success(response.data)
          this.loadingToMysql.close()
        });
@@ -193,7 +183,6 @@
          axiosInstancePy
          .post('/store', { 'allData': this.newData })
          .then((response) => {
            console.log(response.data);
            ElMessage.success(response.data)
            this.loadingToMysql.close()
          });
@@ -221,11 +210,11 @@
    </div>
    <el-card>
      <!-- <ShopNameSelect @submit-shops="(n)=>selectedShopNames=n"></ShopNameSelect> -->
      <ShopNameCheckBox
        @submit-shops="(n) => (form.selectedShopNames = n)"
      ></ShopNameCheckBox>
      <!-- {{ selectedShopNames }} -->
    </el-card>
@@ -247,7 +236,7 @@
        placeholder="爬取结果"
        autosize
      ></el-input>
      <!--  rows="6" -->
    </div>
@@ -275,9 +264,7 @@
    <el-empty v-show="isNoData" :image-size="150" />
    </div>
    <!-- <div class="result-textarea">
      <span >重复数量为:{{ duplicateData.length }}</span>
    </div> -->
    <div class="store-button"  >
      <el-button
@@ -316,9 +303,7 @@
  margin-top: 20px;
  width: 50%;
}
// .result-textarea-textarea {
//   // width: 50%;
// }
.progress-percentage {
  width: 50%;
  margin-top: 20px;
vue3-project-1.zip
Binary files differ