组件功能
组件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>
需后端配合内容
该组件为了适配多种场景,对后端做出一些限制:
-
提供两个接口,一是获取所有点位(设备)列表的接口
A
,一是获取指定点位(设备)在指定时间段内对某因子的监测数据的接口B
-
第二个接口限制:
入参必须包括: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 }
]
}
}
时间计算规则
用户选择时间的场景和对应场景下的完整时间范围计算方式如下:
-
只选择了开始时间,和时间小时范围,则结束时间根据它们计算,如果早于当前时间,使用该时间,否则使用当前时间
-
只选择了结束时间,和时间小时范围,则开始时间根据它们计算
-
开始时间和结束时间都选了或者都没选,直接根据选取得时间小时范围,动态计算开始时间和结束时间
注:当用户只选择了开始时间和结束时间时,则计算时间间隔,等于右侧小时范围预设中某一个,则右侧小时范围显示,否则不显示。预设的小时范围数组为:
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>