多维数据折线图比对组件接入指南

组件功能

组件UI

功能描述

该组件以全屏弹窗的形式打开,"数据控制面板"中默认有一块空数据,用户在选择了"点位"、"开始时间"、"结束时间"(其中"点位"选择后不可更改,"开始时间"和"结束时间"可以通过右侧时间范围选择器选择预设好的几个时间段来快速计算,计算规则参考)后,组件会获取该点位(设备)对应时间段的对应监测因子的数据值变化趋势,通过点击"添加点位+"来同步对比多个设备相同监测因子在各时段范围内的变化趋势,便于分析数据

前端使用教程

组件props

属性名 说明 类型 是否必传 可选值 默认值
title 组件显示的标题 string ------ ------
pointsList 下拉选择点位(设备)的数据源,其中每一项数据包含点位(设备)名和对应的主键(一般为 id array ------ ------
pointKeyName pointsList 中用于存放点位(设备)名的 key 名,用于绑定下拉组件的展示 label string ------ 'name'
pointKeyValue pointsList 中用于存放点位(设备)唯一主键的 key 名,用于绑定下拉组件的展示 value string ------ 'id'
getChartDataFun 用于获取点位(设备)在某个时间段内对因子的监测数据 function ------ ------
getChartParams 获取数据方法的自定义参数 object ------ ------
defaultTimeRange 默认的时间范围数组,索引 0 处为开始时间,索引 1 处为结束时间,格式支持同 JavaScript 中的 Date构造函数参数,当结束时间大于当前时间时,组件默认取当前时间 array ------ ------
defaultPointList 默认点位名称列表,传入后刚进入组件时即展示这些点位数据信息 array ------ ------

使用组件

javascript 复制代码
<template>
  <div>
    <el-button type="primary" size="mini" @click="showMultiContrastLineChart"></el-button>
    <component
      :is="'MultiContrastLineChart'" v-if="multiContrastLineChartShow" ref="MultiContrastLineChartRef"
      v-bind="MultiContrastLineChartProps" @close="multiContrastLineChartShow = false"
    />
  </div>
</template>

<script>
import { 
  listNoPage, // 获取点位(设备)列表接口
  getTowerAnalysis // 获取设备监测数据接口
} from '@/api/tower/towerDevice' 
 
export default {
  data() {
    return {
      // 控制组件显隐
      multiContrastLineChartShow: false,
      // 组件属性
      MultiContrastLineChartProps: {
        title: '',
        pointKeyName: 'devNo',
        pointKeyValue: 'id',
        getChartDataFun: getTowerAnalysis,
        getChartParams: {
          selectIndex: '',
          projectId: ''
        },
        defaultTimeRange: [],
        pointsList: []
      }
    }
  },
  methods: {
    showMultiContrastLineChart() {
      // 获取点位(设备)列表
      const res = await listNoPage({ projectId: this.queryParams.projectId /* this.$cache.local.get('projectId') */ })
      // 为组件 props 赋值
      this.MultiContrastLineChartProps.pointsList = res.data
      this.MultiContrastLineChartProps.title = `xxxx数据监测`
      this.MultiContrastLineChartProps.getChartParams.projectId = this.queryParams.projectId /* this.$cache.local.get('projectId') */
      // 显示组件
      this.multiContrastLineChartShow = true
      // 等待 Dom 渲染后初始化组件
      this.$nextTick(() => {
        this.$refs.MultiContrastLineChartRef.init()
      })
    }
  }
}
</script>

需后端配合内容

该组件为了适配多种场景,对后端做出一些限制:

  1. 提供两个接口,一是获取所有点位(设备)列表的接口 A,一是获取指定点位(设备)在指定时间段内对某因子的监测数据的接口 B

  2. 第二个接口限制:

入参必须包括:params.beginTime(接收开始时间),params.endTime(接收结束时间),点位或设备名称( key 名需与接口 A 中点位或设备名相同)

返回格式:

json 复制代码
{
"msg": "操作成功",
"code": 200,
"data": {
  "devNo": "6066636", // 点位(设备)名, key 名需与接口 A 中点位或设备名相同,这里 "devNo" 不固定
  "lowLowLimit": 0, // 低低限
  "lowLimit": 0, // 低限
  "highHighLimit": 100, // 高高限
  "highLimit": 100, // 高限
  "max": 100, // 最大值
  "min": 0, // 最小值
  "average": 13.72, // 平均值
  "dataMount": 57, // 数据量
  "unit": "m", // 单位
  "data": [
    { 
      "time": "2023-09-04 10:00:18", // 数据采集时间
      "value": 0 // 数据值
    },
    { "time": "2023-09-04 10:00:38", "value": 0.7 },
    { "time": "2023-09-04 10:00:58", "value": 17.7 }
  ]
}
}

时间计算规则

用户选择时间的场景和对应场景下的完整时间范围计算方式如下:

  1. 只选择了开始时间,和时间小时范围,则结束时间根据它们计算,如果早于当前时间,使用该时间,否则使用当前时间

  2. 只选择了结束时间,和时间小时范围,则开始时间根据它们计算

  3. 开始时间和结束时间都选了或者都没选,直接根据选取得时间小时范围,动态计算开始时间和结束时间

注:当用户只选择了开始时间和结束时间时,则计算时间间隔,等于右侧小时范围预设中某一个,则右侧小时范围显示,否则不显示。预设的小时范围数组为:

json 复制代码
[
  { text: '2小时', minute: 2 * 60 },
  { text: '4小时', minute: 4 * 60 },
  { text: '6小时', minute: 6 * 60 },
  { text: '8小时', minute: 8 * 60 },
  { text: '12小时', minute: 12 * 60 },
  { text: '16小时', minute: 16 * 60 },
  { text: '24小时', minute: 24 * 60 }
]

源代码

index.vue

javascript 复制代码
<template>
  <el-dialog
    :visible.sync="visible"
    fullscreen
    append-to-body
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    @close="$emit('close')"
  >
    <template slot="title">
      <h2 style="text-align:center;">{{ title }}</h2>
    </template>
    <div class="wrap">
      <el-collapse :value="'数据控制面板'">
        <el-collapse-item title="数据控制面板" name="数据控制面板">
          <div class="control-panel">
            <div v-for="(item, index) in controlPanelList" :key="item.id">
              <ControlPanel
                :data-obj="item"
                :points="points"
                :key-name="pointKeyName"
                :key-value="pointKeyValue"
                :default-time-range="defaultTimeRange"
                :default-point-name="defaultPointList[index]"
                @pointSelected="pointSelectedHandle"
                @controlDataChange="getChartData($event, index)"
                @close="removeControlPanel($event, index)"
              />
              <el-divider v-if="index < controlPanelList.length - 1" />
            </div>
            <el-divider content-position="center">
              <el-button
                type="text" @click="addControlPanel"
              >添加点位+</el-button>
            </el-divider>
          </div>
        </el-collapse-item>
      </el-collapse>

      <div id="muti-chart">图表区</div>
    </div>
  </el-dialog>
</template>

<script>
import echarts from 'echarts'
require('echarts/theme/macarons')
import resize from '@/views/dashboard/mixins/resize'
import ControlPanel from './ControlPanel.vue'
import { formatDate } from '@/utils'

export default {
  name: 'MultiContrastLineChart',
  components: {
    ControlPanel
  },
  mixins: [resize],
  props: {
    // 标题
    title: {
      type: String,
      default: '多维数据折线图比对'
    },
    // 点位(设备)列表
    pointsList: {
      type: Array,
      default: () => []
    },
    // 点位(设备)显示名对应 key
    pointKeyName: {
      type: String,
      default: 'name'
    },
    // 点位(设备)值对应 key
    pointKeyValue: {
      type: String,
      default: 'id'
    },
    // 获取数据方法
    getChartDataFun: {
      type: Function,
      required: true
    },
    //  获取数据方法的其他参数
    getChartParams: {
      type: Object,
      default: () => {}
    },
    defaultTimeRange: {
      type: Array,
      default: () => []
    },
    defaultPointList: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      chart: null,
      visible: false,
      points: [
        /* { name: '点位1', value: '01', selected: false },
        { name: '点位2', value: '02', selected: false },
        { name: '点位3', value: '03', selected: false } */
      ],
      controlPanelList: [{
        id: Date.now().toString(),
        lowLowLimit: '',
        lowLimit: '',
        highHighLimit: '',
        highLimit: '',
        max: '',
        min: '',
        average: '',
        dataMount: ''
      }/* , {
        id: '2',
        lowLowLimit: '反显结果',
        lowLimit: '反显结果',
        highHighLimit: '反显结果',
        highLimit: '反显结果',
        max: 0.09,
        min: 0.01,
        average: 0.04,
        dataMount: 5.21
      } */]
    }
  },
  watch: {
    pointsList: {
      handler(nV, oV) {
        if (nV && nV.length) {
          this.points = nV.map(item => {
            return {
              ...item,
              selected: false
            }
          })
        }
      },
      immediate: true
    },
    defaultPointList: {
      handler(nV, oV) {
        if (nV.length > 0) {
          this.controlPanelList = nV.map(item => {
            return {
              id: Date.now().toString(),
              lowLowLimit: '',
              lowLimit: '',
              highHighLimit: '',
              highLimit: '',
              max: '',
              min: '',
              average: '',
              dataMount: ''
            }
          })
        }
      },
      immediate: true
    }
  },
  beforeDestroy() {
    if (!this.chart) return
    this.chart.dispose()
    this.chart = null
  },

  methods: {
    /* 初始化 */
    init() {
      this.visible = true
      this.$nextTick(() => {
        this.initChart()
      })
    },
    /* 某个点位已被选中 */
    pointSelectedHandle(value, isSetFalse) {
      const pointIndex = this.points.findIndex((item) => item[this.pointKeyValue] === value)
      this.$set(this.points[pointIndex], 'selected', !isSetFalse)
    },
    /* 增加控制面板 */
    addControlPanel() {
      if (this.controlPanelList.length === this.points.length) {
        this.$message.warning('点位数量不足')
      } else {
        this.controlPanelList.push({
          id: Date.now().toString(),
          lowLowLimit: '',
          lowLimit: '',
          highHighLimit: '',
          highLimit: '',
          max: '',
          min: '',
          average: '',
          dataMount: ''
        })
      }
    },
    removeControlPanel(event, index) {
      // 删除对应数据面板
      if (event) this.pointSelectedHandle(event, true)
      this.controlPanelList.splice(index, 1)

      // 重绘 chart
      const option = this.chart.getOption()
      const pointName = this.points.find(item => item[this.pointKeyValue] == event)[this.pointKeyName]
      option.series = option.series.filter(item => {
        return item.name != pointName
      })
      this.chart.setOption(option, {
        notMerge: true
      })
    },
    initChart() {
      const chartbox = document.getElementById('muti-chart')
      this.chart = echarts.init(chartbox)
      this.chart.setOption({
        grid: {
          top: 70,
          bottom: 70
        },
        legend: {
          top: 30
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'line' // cross
          },
          backgroundColor: '#fff',
          formatter: params => {
            let html = ''
            params.forEach(item => {
              html += generateSingleItem(item)
            })
            return `<div style="width:220px;padding:10px;background-color:#fff;border-radius:10px;box-shadow:5px 5px 10px rgba(0, 0, 0, 0.3);">${html}</div>`

            function generateSingleItem(item) {
              return `<div>
                        <div style="height: 35px;background-color:${item.color};border-radius:10px;text-align:center;line-height:35px;color:#fff;">${item.seriesName}</div>
                        <div style="padding:10px;width:100%;display:flex;color:#262626;justify-content: space-around;">
                          <div>
                            <div>时间:</div>
                            <div><strong>${formatDate(item.data[0]).split(' ')[1]}</strong></div>
                          </div>
                          <div>
                            <div>数值:</div>
                            <div><strong>${item.data[1]}</strong></div>
                          </div>
                        </div>
                      </div>`
            }
          }
        },
        dataZoom: [{
          type: 'slider',
          bottom: 30,
          backgroundColor: '#F4F4F4',
          dataBackground: {
            areaStyle: {
              color: '#3D9FFE'
            }
          },
          handleStyle: {
            color: '#fff',
            borderColor: '#3D9FFE'
          }
        }],
        xAxis: {
          show: true,
          type: 'time',
          name: '时间',
          // 配置坐标轴标签的时间格式
          axisLabel: {
            formatter: value => this.getFormattedTime(value) /* formatDate(value).split(' ')[1] */
            // rotate: 30
          },
          offset: 45
        },
        yAxis: {
          type: 'value'
          // name: '单位:'
        },
        series: [
          /* {
            name: '点位一',
            data: [
              [1672924800000, 1000], [1672928400000, 2000], [1672932000000, 3000], [1672935600000, 1500], [1672939200000, 2200], [1672942800000, 1800], [1672946400000, 2600], [1672950000000, 2400], [1672953600000, 2900], [1672957200000, 2500], [1672960800000, 3200], [1672964400000, 3400], [1672968000000, 3100], [1672971600000, 3500], [1672975200000, 3600], [1672978800000, 1500], [1672982400000, 1400], [1672986000000, 1800], [1672989600000, 1200], [1672993200000, 1400], [1672996800000, 1500], [1673000400000, 2600], [1673004000000, 1900], [1673007600000, 2500]
            ],
            type: 'line',
            smooth: true
          },
          {
            name: '点位二',
            data: [
              [1672924800000, 1500], [1672928400000, 3000], [1672932000000, 3000], [1672935600000, 2500], [1672939200000, 2200], [1672942800000, 1900], [1672946400000, 5600], [1672950000000, 5400], [1672953600000, 1900], [1672957200000, 3500], [1672960800000, 3800], [1672964400000, 4400], [1672968000000, 2100], [1672971600000, 2500], [1672975200000, 2600], [1672978800000, 1600], [1672982400000, 2400], [1672986000000, 3800], [1672989600000, 2200], [1672993200000, 2400], [1672996800000, 1800], [1673000400000, 1600], [1673004000000, 2900], [1673007600000, 3500]
            ],
            type: 'line',
            smooth: true
          },
          {
            name: '点位三',
            data: [
              [1672924800000, 1600], [1672928400000, 3800], [1672932000000, 3400], [1672935600000, 2500], [1672939200000, 1200], [1672942800000, 1600], [1672946400000, 5800], [1672950000000, 5400], [1672953600000, 1900], [1672957200000, 3200], [1672960800000, 3600], [1672964400000, 4800], [1672968000000, 2400], [1672971600000, 2500], [1672975200000, 2900], [1672978800000, 1600], [1672982400000, 2800], [1672986000000, 3400], [1672989600000, 2600], [1672993200000, 2600], [1672996800000, 1600], [1673000400000, 1800], [1673004000000, 2400], [1673007600000, 3800]
            ],
            type: 'line',
            smooth: true
          } */
        ]
      })
    },
    /*
     * event: {startDateTime, endDateTime, pointName, pointValue}
     */
    async getChartData(event, index) {
      const res = await this.getChartDataFun({
        params: {
          beginTime: event.startDateTime,
          endTime: event.endDateTime
        },
        [this.pointKeyName]: event.pointName, // 需要获取数据的点位(设备)的名称
        ...this.getChartParams
      })
      const { data } = res
      this.chart.setOption({
        yAxis: {
          name: `单位:${data.unit}`
        },
        series: [{
          id: data[this.pointKeyName],
          name: data[this.pointKeyName],
          type: 'line',
          smooth: true,
          showSymbol: false,
          data: data.data.map(item => {
            return [new Date(item.time).getTime(), item.value]
          })
        }]
      })
      this.$set(this.controlPanelList, index, {
        id: this.controlPanelList[index].id,
        lowLowLimit: data.lowLowLimit,
        lowLimit: data.lowLimit,
        highHighLimit: data.highHighLimit,
        highLimit: data.highLimit,
        max: data.max,
        min: data.min,
        average: data.average,
        dataMount: data.dataMount
      })
    },
    getFormattedTime(input) {
      let date
      if (typeof input === 'number') {
        date = new Date(input)
      } else if (input instanceof Date) {
        date = input
      } else {
        return null
      }

      const hour = String(date.getHours()).padStart(2, '0')
      const minute = String(date.getMinutes()).padStart(2, '0')

      return `${hour}:${minute}`
    }
  }
}
</script>

<style lang="scss" scoped>
.wrap {
  height: 100%;

  #muti-chart {
    height: 570px;
    // background-color: pink;
  }
}

::v-deep .el-dialog {
  overflow: hidden;
  overflow-y: scroll;
}
::v-deep .el-dialog__body {
  padding: 10px 20px;
}

::v-deep .el-divider {
  margin: 14px 0;
}

::v-deep .el-dialog__close {
  font-weight: bold;
}
</style>

ControlPanel.vue

javascript 复制代码
<template>
  <div>
    <el-collapse accordion>
      <el-collapse-item>
        <template slot="title">
          <!-- @click.native.prevent="": 阻止点击输入框或者选择框就展开折叠面板 -->
          <el-row :gutter="60" style="width: 100%;">
            <el-col :span="5">
              <el-row type="flex" align="middle">
                <el-col :span="4">点位</el-col>
                <el-col :span="20">
                  <el-select
                    v-model="point" filterable style="width: 100%;"
                    :disabled="point!=''" placeholder="请选择点位或搜索筛选" @change="value => $emit('pointSelected', value)"
                  >
                    <el-option
                      v-for="m in points" :key="m[keyValue]" :label="m[keyName]"
                      :value="m[keyValue]" :disabled="m.selected"
                    />
                  </el-select>
                </el-col>
              </el-row>
            </el-col>
            <el-col :span="6">
              <el-row type="flex" align="middle">
                <el-col :span="4">开始时间</el-col>
                <el-col :span="20">
                  <el-date-picker
                    v-model="modelStartDateTime" type="datetime" placeholder="选择日期时间"
                    value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%;" :picker-options="pickerOptions('modelStartDateTime')"
                    @change="e => startDateTime = e" @click.native.stop
                  />
                </el-col>
              </el-row>
            </el-col>
            <el-col :span="6">
              <el-row type="flex" align="middle">
                <el-col :span="4">结束时间</el-col>
                <el-col :span="20">
                  <el-date-picker
                    v-model="modelEndDateTime" type="datetime" placeholder="选择日期时间"
                    value-format="yyyy-MM-dd HH:mm:ss" style="width: 100%;" :picker-options="pickerOptions('modelEndDateTime')"
                    @change="e => endDateTime = e" @click.native.stop
                  />
                </el-col>
              </el-row>
            </el-col>
            <el-col :span="4">
              <el-select v-model="hour" style="width: 100%;" placeholder="请选择时间范围" @change="hourChangeHandle">
                <el-option
                  v-for="h in hours" :key="h.text" :label="h.text"
                  :value="h.minute"
                />
              </el-select>
            </el-col>
            <el-col :span="3">
              <el-button type="danger" size="mini" @click="$emit('close', point)">移除</el-button>

            </el-col>
          </el-row>
        </template>
        <el-row :gutter="60" style="margin-bottom: 10px;">
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">低低限</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.lowLowLimit" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">低限</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.lowLimit" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">高高限</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.highHighLimit" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">高限</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.highLimit" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
        </el-row>
        <el-row :gutter="60" style="margin-bottom: 10px;">
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">最大值</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.max" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">最小值</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.min" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">平均值</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.average" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
          <el-col :span="6">
            <el-row type="flex" align="middle">
              <el-col :span="4">数据量</el-col>
              <el-col :span="20">
                <el-input :value="dataObj.dataMount" disabled size="normal" style="width: 100%;" />
              </el-col>
            </el-row>
          </el-col>
        </el-row>
      </el-collapse-item>
    </el-collapse>

  </div>
</template>

<script>
export default {
  name: 'ControlPanel',
  props: {
    // 显示数据
    dataObj: {
      type: Object,
      required: true
    },
    // 点位(设备)列表
    points: {
      type: Array,
      default: () => []
    },
    // 点位(设备)显示名对应 key
    keyName: {
      type: String,
      required: true
    },
    // 点位(设备)显示值对应 key
    keyValue: {
      type: String,
      required: true
    },
    // 默认时间范围
    defaultTimeRange: {
      type: Array,
      default: () => []
    },
    defaultPointName: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      point: '',
      hour: '',
      modelStartDateTime: '',
      modelEndDateTime: '',
      startDateTime: '',
      endDateTime: '',
      hours: [
        { text: '2小时', minute: 2 * 60 },
        { text: '4小时', minute: 4 * 60 },
        { text: '6小时', minute: 6 * 60 },
        { text: '8小时', minute: 8 * 60 },
        { text: '12小时', minute: 12 * 60 },
        { text: '16小时', minute: 16 * 60 },
        { text: '24小时', minute: 24 * 60 }
      ]
    }
  },
  computed: {
    interval() {
      return new Date(this.endDateTime).getTime() - new Date(this.startDateTime).getTime()
    },
    pickerOptions: {
      get() {
        return type => {
          return {
            disabledDate: now => {
              let flag = false
              switch (type) {
                case 'modelStartDateTime':
                  flag = this.modelEndDateTime ? now.getTime() > Date.now() || now.getTime() > new Date(this.modelEndDateTime).getTime() : now.getTime() > Date.now()
                  break
                case 'modelEndDateTime':
                  flag = this.modelStartDateTime ? now.getTime() > Date.now() || now.getTime() < new Date(this.modelStartDateTime).getTime() : now.getTime() > Date.now()
                  break
              }
              return flag
            }
          }
        }
      }
    }
  },
  watch: {
    defaultPointName: {
      handler(nV, oV) {
        if (nV) {
          this.point = this.points.find(item => item[this.keyName] == nV)[this.keyValue]
        }
      },
      immediate: true
    },
    defaultTimeRange: {
      handler(nV, oV) {
        if (nV && nV.length) {
          this.startDateTime = this.modelStartDateTime = this.formatTime(new Date(nV[0]))
          this.endDateTime = this.modelEndDateTime = new Date(nV[1]).getTime() > Date.now() ? this.formatTime(new Date()) : this.formatTime(new Date(nV[1]))
        }
      },
      immediate: true
    },
    startDateTime(nV, oV) {
      if (nV && this.endDateTime && this.interval > 0) {
        this.calculateHour(nV, this.endDateTime)
        if (this.point) this.emitEvent()
      }
    },
    endDateTime(nV, oV) {
      if (nV && this.startDateTime && this.interval > 0) {
        this.calculateHour(this.startDateTime, nV)
        if (this.point) this.emitEvent()
      }
    },
    point(nV, oV) {
      if (nV && this.startDateTime && this.endDateTime && this.interval > 0) this.emitEvent()
    },
    interval(nV, oV) {
      if (nV && nV < 0) {
        this.$message.warning('开始时间不能大于结束时间')
        this.startDateTime = this.modelStartDateTime = ''
        this.endDateTime = this.modelEndDateTime = ''
      }
    }
  },

  mounted() {

  },

  methods: {
    hourChangeHandle(value) {
      // 获取当前时间戳
      const currentDateTime = Date.now()
      // 计算前面的时间戳
      const previousDateTime = new Date(currentDateTime - value * 60 * 1000)
      // console.log('计算得到的之前时间:', previousDateTime.getTime(), '计算得到的当前时间:', currentDateTime)

      // 只选择了开始时间,则结束时间根据其和选择的时间范围计算,如果早于当前时间,使用该时间,否则使用当前时间
      if (this.startDateTime && !this.endDateTime) {
        const endDateTimeout = new Date(new Date(this.startDateTime).getTime() + value * 60 * 1000)
        // console.log('计算出的结束时间戳:', endDateTimeout.getTime())
        this.endDateTime = this.modelEndDateTime = endDateTimeout.getTime() > currentDateTime ? this.formatTime(currentDateTime) : this.formatTime(endDateTimeout)
      } else if (!this.startDateTime && this.endDateTime) {
        // 只选择了结束时间,则开始时间根据其和选择的时间范围计算
        const startDateTimeout = new Date(new Date(this.endDateTime).getTime() - value * 60 * 1000)
        // console.log('计算出的开始时间戳:', startDateTimeout.getTime())
        this.startDateTime = this.modelStartDateTime = this.formatTime(startDateTimeout)
      } else {
        // 开始时间和结束时间都选了或者都没选,直接根据选取得时间范围,动态计算当前时间和选择的时间范围之前的起始时间
        this.startDateTime = this.modelStartDateTime = this.formatTime(previousDateTime)
        this.endDateTime = this.modelEndDateTime = this.formatTime(currentDateTime)
      }
    },
    // 格式化时间为 'yyyy-MM-dd HH:mm:ss'
    formatTime(date) {
      const pad = (n) => (n < 10 ? '0' + n : n)
      return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
    },
    // 用户选择时间后,计算时间间隔是否在定义好的 hours 枚举中,在的话就为右侧时间范围赋值,否则不管
    calculateHour(startTime, endTime) {
      // 计算出间隔的分钟数
      const intervalMinute = (new Date(endTime).getTime() - new Date(startTime).getTime()) / 1000 / 60
      const item = this.hours.find(item => item.minute == intervalMinute)
      if (item) this.hour = item.minute
    },
    emitEvent() {
      this.$emit('controlDataChange', {
        startDateTime: this.startDateTime,
        endDateTime: this.endDateTime,
        pointName: this.points.find(item => item[this.keyValue] == this.point)[this.keyName],
        pointValue: this.point
      })
    }
  }
}
</script>

<style lang="scss" scoped>

::v-deep .el-collapse {
  border: none;
  .el-collapse-item__wrap {
    border: none;
  }

  .el-collapse-item__header {
    display: flex;
    align-items: center;
    border: none;

    .el-collapse-item__arrow {
      margin-left: 10px;
    }
  }

  .el-collapse-item__content {
    padding-bottom: 0;
  }
}
</style>
相关推荐
轻口味35 分钟前
【每日学点鸿蒙知识】AVCodec、SmartPerf工具、web组件加载、监听键盘的显示隐藏、Asset Store Kit
前端·华为·harmonyos
alikami38 分钟前
【若依】用 post 请求传 json 格式的数据下载文件
前端·javascript·json
wakangda1 小时前
React Native 集成原生Android功能
javascript·react native·react.js
吃杠碰小鸡1 小时前
lodash常用函数
前端·javascript
emoji1111111 小时前
前端对页面数据进行缓存
开发语言·前端·javascript
泰伦闲鱼1 小时前
nestjs:GET REQUEST 缓存问题
服务器·前端·缓存·node.js·nestjs
m0_748250031 小时前
Web 第一次作业 初探html 使用VSCode工具开发
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
m0_748235952 小时前
web复习(三)
前端
迷糊的『迷』2 小时前
vue-axios+springboot实现文件流下载
vue.js·spring boot