统计分析

This commit is contained in:
geting 2024-11-26 15:17:53 +08:00
parent 02ad8ef072
commit eac0aadd87
5 changed files with 108 additions and 62 deletions

View File

@ -43,8 +43,12 @@
<div class="tabsPart"> <div class="tabsPart">
<el-table :data="alarmsTableData" class="tablePart" highlight-current-row> <el-table :data="alarmsTableData" class="tablePart" highlight-current-row>
<el-table-column prop="eventTimeFormate" :label="AlarmsFieldsEnums['alarmTime']" align="center"> </el-table-column> <el-table-column prop="eventTimeFormate" :label="AlarmsFieldsEnums['alarmTime']" align="center"> </el-table-column>
<el-table-column prop="deviceCode" :label="AlarmsFieldsEnums['airBlowerNumber']" align="center"> </el-table-column> <el-table-column prop="devicecodeName" :label="AlarmsFieldsEnums['airBlowerNumber']" align="center"> </el-table-column>
<el-table-column prop="eventText" :label="AlarmsFieldsEnums['faultDescription']" align="center"> </el-table-column> <el-table-column prop="eventText" :label="AlarmsFieldsEnums['faultDescription']" align="center">
<template #default="{ row }">
<span v-html="formatText(row.eventText)"></span>
</template>
</el-table-column>
<el-table-column prop="eventLevel" :label="AlarmsFieldsEnums['alarmType']" align="center"> <el-table-column prop="eventLevel" :label="AlarmsFieldsEnums['alarmType']" align="center">
<template #default="scope"> <template #default="scope">
<div class="tip" v-if="scope.row.eventLevel === 0">提示</div> <div class="tip" v-if="scope.row.eventLevel === 0">提示</div>
@ -199,6 +203,7 @@ const getalarmsList = () => {
return { return {
...item, ...item,
eventTimeFormate: timestampToTime(item.eventTime), eventTimeFormate: timestampToTime(item.eventTime),
devicecodeName: item.deviceName + item.deviceCode,
} }
}) })
} else { } else {
@ -209,6 +214,13 @@ const getalarmsList = () => {
ElMessage.error(err?.response?.data?.msg ?? '查询失败') ElMessage.error(err?.response?.data?.msg ?? '查询失败')
}) })
} }
const formatText = (text: any) => {
text = text.replace(/ 动作/g, '<span style="color:#a03b1d;"> 动作</span>')
text = text.replace(/复归/g, '<span style="color:#39baf4;">复归</span>')
return text
}
const timestampToTime = (timestamp: any) => { const timestampToTime = (timestamp: any) => {
timestamp = timestamp ? timestamp : null timestamp = timestamp ? timestamp : null
let date = new Date(timestamp) let date = new Date(timestamp)

View File

@ -1,7 +1,17 @@
<template> <template>
<div class="statAnalysis"> <div class="statAnalysis">
<el-menu :default-active="activeIndex" class="headerList" mode="horizontal" @select="handleSelect"> <el-menu :default-active="activeIndex" class="headerList" mode="horizontal" @select="handleSelect">
<el-menu-item v-for="(item, index) in headerList" :index="index" :key="index"> {{ item }} </el-menu-item> <el-menu-item index="0" key="0"> {{ headerList[0] }} </el-menu-item>
<el-popover placement="top-start" :width="200" popper-class="admin-info-box" trigger="hover" content="同一测点,不同时间段对比">
<template #reference>
<el-menu-item index="1" key="1"> {{ headerList[1] }} </el-menu-item>
</template>
</el-popover>
<el-popover placement="top-start" :width="200" popper-class="admin-info-box" trigger="hover" content="同一时间段,不同测点对比">
<template #reference>
<el-menu-item index="2" key="2"> {{ headerList[2] }} </el-menu-item>
</template>
</el-popover>
</el-menu> </el-menu>
<PowerCurveAnalysis v-if="activeIndex == 0"></PowerCurveAnalysis> <PowerCurveAnalysis v-if="activeIndex == 0"></PowerCurveAnalysis>
<TrendAnalysis v-if="activeIndex == 1"></TrendAnalysis> <TrendAnalysis v-if="activeIndex == 1"></TrendAnalysis>
@ -19,7 +29,6 @@ const config = useConfig()
const activeIndex = ref(0) const activeIndex = ref(0)
const { t } = useI18n() const { t } = useI18n()
const headerList = [t('statAnalysis.PowerCurveAnalysis'), t('statAnalysis.trendAnalysis'), t('statAnalysis.trendComparison')] const headerList = [t('statAnalysis.PowerCurveAnalysis'), t('statAnalysis.trendAnalysis'), t('statAnalysis.trendComparison')]
const handleSelect = (index: number) => { const handleSelect = (index: number) => {
activeIndex.value = index activeIndex.value = index
} }

View File

@ -54,7 +54,7 @@
</div> </div>
</div> </div>
</div> </div>
<div ref="chartContainer" style="width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div> <div ref="chartContainer" style="position: absolute; bottom: 0px; width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -199,7 +199,7 @@ const shortcuts = [
text: '今天', text: '今天',
value: () => { value: () => {
const start = getFormattedDate(0) + ' 00:00:00' const start = getFormattedDate(0) + ' 00:00:00'
const end = new Date() const end = getFormattedDate(0) + ' 23:59:59'
return [start, end] return [start, end]
}, },
}, },

View File

@ -34,7 +34,7 @@
<el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button> <el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button>
</div> </div>
</el-header> </el-header>
<div class="timeColumns" :class="{ expand: isExpand }"> <div class="timeColumns">
<div class="headerPart" v-for="(time, index) in times" :key="index"> <div class="headerPart" v-for="(time, index) in times" :key="index">
<div class="topLeft"> <div class="topLeft">
<div class="selectPart"> <div class="selectPart">
@ -75,10 +75,7 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="times.length > 2" class="ralIcon" @click="handleClick"> <div ref="chartContainer" style="position: absolute; bottom: 0px; width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
<el-icon :size="20" color="#0064AA"><DArrowRight /></el-icon>
</div>
<div ref="chartContainer" style="width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
<el-dialog v-model="showMeasure" title="测点名称" :width="800"> <el-dialog v-model="showMeasure" title="测点名称" :width="800">
<template #header> <template #header>
<div class="measureSlotHeader"> <div class="measureSlotHeader">
@ -131,10 +128,6 @@ const timechange = (value: any) => {
ElMessage.warning('查询时间点错误,请重新输入') ElMessage.warning('查询时间点错误,请重新输入')
} }
} }
const isExpand = ref(false)
const handleClick = () => {
isExpand.value = !isExpand.value
}
const iotModelId = ref('') const iotModelId = ref('')
const irn = ref('') const irn = ref('')
@ -258,7 +251,7 @@ const shortcuts = [
text: '今天', text: '今天',
value: () => { value: () => {
const start = getFormattedDate(0) + ' 00:00:00' const start = getFormattedDate(0) + ' 00:00:00'
const end = new Date() const end = getFormattedDate(0) + ' 23:59:59'
return [start, end] return [start, end]
}, },
}, },
@ -396,14 +389,27 @@ const historyDataReq = (promises: any) => {
const deviceId = statAnalysisSelect.deviceId const deviceId = statAnalysisSelect.deviceId
const attributeCode = statAnalysisSelect.attributeCode const attributeCode = statAnalysisSelect.attributeCode
results.forEach((res: any, index: number) => { results.forEach((res: any, index: number) => {
console.log(times[index])
const resData = (res && deviceId in res && res[deviceId][attributeCode]) || undefined const resData = (res && deviceId in res && res[deviceId][attributeCode]) || undefined
const xData = resData['times']
const yData = resData['values'] if (!resData['values'].length) {
if (!yData.length) {
ElMessage.info(`${customName[index]}数据为空`) ElMessage.info(`${customName[index]}数据为空`)
return return
} }
calculate.value[index] = calculateStats(yData) const alltimes = getTimestamps(
new Date(times[index][0]).getTime(),
new Date(times[index][1]).getTime(),
statAnalysisSelect.interval || '5m'
)
console.log(alltimes)
console.log('🚀 ~ results.forEach ~ resData:', resData)
const fillData = fillMissingData(alltimes, resData)
console.log('🚀 ~ results.forEach ~ fillData:', fillData)
const xData = fillData['times']
const yData = fillData['values']
console.log(xData)
calculate.value[index] = calculateStats(resData['values'])
xDatas.push({ xDatas.push({
series: String(customName[index]), series: String(customName[index]),
data: xData, data: xData,
@ -484,6 +490,52 @@ function calculateStats(numbers: any) {
average: average.toFixed(2), average: average.toFixed(2),
} }
} }
const getTimestamps = (start: any, end: any, interval: any) => {
let timestamps = []
let current = start
while (current < end) {
timestamps.push(current)
switch (interval) {
case '5m':
current += 5 * 60 * 1000
break
case '1d':
current += 24 * 60 * 60 * 1000
break
case '15m':
current += 15 * 60 * 1000
break
case 'NONE':
current += 40 * 1000
break
case '1h':
current += 60 * 60 * 1000
break
default:
throw new Error('Unsupported interval')
}
}
return timestamps
}
const fillMissingData = (intervals: any, data: any) => {
const { times, values } = data
const filledTimes: any = []
const filledValues: any = []
intervals.forEach((time: any) => {
const index = times.indexOf(time)
filledTimes.push(time)
if (index !== -1) {
filledValues.push(values[index])
} else {
filledValues.push('')
}
})
return { times: filledTimes, values: filledValues }
}
const timestampToTime = (timestamp: any) => { const timestampToTime = (timestamp: any) => {
timestamp = timestamp ? timestamp : null timestamp = timestamp ? timestamp : null
let date = new Date(timestamp) let date = new Date(timestamp)
@ -498,6 +550,9 @@ const timestampToTime = (timestamp: any) => {
<style scoped lang="scss"> <style scoped lang="scss">
.statAnalysis { .statAnalysis {
height: 100%; height: 100%;
.contain {
height: calc(100% - 60px);
}
.headerPart { .headerPart {
padding: 20px; padding: 20px;
display: flex; display: flex;
@ -572,24 +627,11 @@ const timestampToTime = (timestamp: any) => {
} }
} }
.timeColumns { .timeColumns {
max-height: 120px; height: calc(100% - 480px);
overflow: hidden; overflow-y: auto;
.headerPart { .headerPart {
padding: 10px 20px; padding: 2px 20px;
} }
&.expand {
max-height: max-content;
height: auto;
overflow: inherit;
}
}
.timeColumns.expand + div.ralIcon {
transform: rotate(-90deg);
}
.ralIcon {
width: 100%;
text-align: center;
transform: rotate(90deg);
} }
#myEChart { #myEChart {
width: 100%; width: 100%;

View File

@ -26,7 +26,7 @@
<el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button> <el-button style="color: #0064aa" @click="statAnalysisExport()">{{ t('statAnalysis.export') }}</el-button>
</div> </div>
</el-header> </el-header>
<div class="timeColumns" :class="{ expand: isExpand }"> <div class="timeColumns">
<div class="headerPart" v-for="(deviceId, index) in statAnalysisDeviceId" :key="index"> <div class="headerPart" v-for="(deviceId, index) in statAnalysisDeviceId" :key="index">
<div class="topLeft"> <div class="topLeft">
<div class="selectPart"> <div class="selectPart">
@ -81,10 +81,7 @@
</div> </div>
</div> </div>
</div> </div>
<div v-if="statAnalysisDeviceId.length > 2" class="ralIcon" @click="handleClick"> <div ref="chartContainer" style="position: absolute; bottom: 0px; width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
<el-icon :size="20" color="#0064AA"><DArrowRight /></el-icon>
</div>
<div ref="chartContainer" style="width: 100%; height: 400px; border: 1px solid rgb(217, 217, 217)"></div>
<el-dialog v-model="showMeasure" title="测点名称" :width="800"> <el-dialog v-model="showMeasure" title="测点名称" :width="800">
<template #header> <template #header>
<div class="measureSlotHeader"> <div class="measureSlotHeader">
@ -141,10 +138,6 @@ const switchDevice = (index: number) => {
calculate.value.splice(index, 1) calculate.value.splice(index, 1)
} }
const isExpand = ref(false)
const handleClick = () => {
isExpand.value = !isExpand.value
}
const iotModelId = ref('') const iotModelId = ref('')
const irn = ref('') const irn = ref('')
const selectAtteibutes = (index: number) => { const selectAtteibutes = (index: number) => {
@ -260,7 +253,7 @@ const shortcuts = [
text: '今天', text: '今天',
value: () => { value: () => {
const start = getFormattedDate(0) + ' 00:00:00' const start = getFormattedDate(0) + ' 00:00:00'
const end = new Date() const end = getFormattedDate(0) + ' 23:59:59'
return [start, end] return [start, end]
}, },
}, },
@ -457,6 +450,9 @@ const timestampToTime = (timestamp: any) => {
<style scoped lang="scss"> <style scoped lang="scss">
.statAnalysis { .statAnalysis {
height: 100%; height: 100%;
.contain {
height: calc(100% - 60px);
}
.headerPart { .headerPart {
padding: 20px; padding: 20px;
display: flex; display: flex;
@ -531,24 +527,11 @@ const timestampToTime = (timestamp: any) => {
} }
} }
.timeColumns { .timeColumns {
max-height: 120px; height: calc(100% - 480px);
overflow: hidden; overflow-y: auto;
.headerPart { .headerPart {
padding: 10px 20px; padding: 2px 20px;
} }
&.expand {
max-height: max-content;
height: auto;
overflow: inherit;
}
}
.timeColumns.expand + div.ralIcon {
transform: rotate(-90deg);
}
.ralIcon {
width: 100%;
text-align: center;
transform: rotate(90deg);
} }
#myEChart { #myEChart {
width: 100%; width: 100%;