绘制关键指标概览页面

This commit is contained in:
guanj
2026-05-29 16:23:56 +08:00
parent 7bcc68a9df
commit 276ef60389
28 changed files with 2202 additions and 1234 deletions

View File

@@ -34,8 +34,8 @@
item.devType == 'Direct_Connected_Device' ? '治理设备' : '监测设备' }}</text>
</view>
<view class="event-desc">
<text>工程名称{{ item.engineeringName }}</text>
<text>项目名称{{ item.projectName }}</text>
<text>工程{{ item.engineeringName }}</text>
<text>项目{{ item.projectName }}</text>
<!-- <text v-if="item.dataDetails.onlineRate.isAbnormal">在线率{{
item.dataDetails.onlineRate.value }}% 限值{{ item.dataDetails.onlineRate.threshold
}}% </text> -->
@@ -55,7 +55,7 @@
数据完整性
<view class="data-table">
<view class="table-header">
<text>监测点名称</text>
<text>监测点</text>
<text>完整性</text>
</view>
<view class="table-row"

View File

@@ -7,10 +7,10 @@
</view>
<view class="detail-content">
<view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 工程名称{{ detail.engineeringName }} </view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view>
<view class="mb5"> 设备名称{{ detail.devName }} </view>
<view class="mb5"> 监测点名称{{ detail.lineName }}</view>
<view class="mb5"> 工程{{ detail.engineeringName }} </view>
<view class="mb5"> 项目{{ detail.projectName }} </view>
<view class="mb5"> 设备{{ detail.devName }} </view>
<view class="mb5"> 监测点{{ detail.lineName }}</view>
<view class="mb5" style="display: flex">
越限详情
<view style="flex: 1" class="details">{{ detail.overLimitDesc }}</view>

View File

@@ -6,14 +6,15 @@
</view>
<view class="detail-content">
<view class="detail-content-title mb20">基础信息</view>
<view class="mb5"> 工程名称{{ detail.engineeringName }} </view>
<view class="mb5"> 项目名称{{ detail.projectName }} </view>
<view class="mb5"> 设备名称{{ detail.equipmentName }}</view>
<view class="mb5"> 监测点名称{{ detail.lineName }}</view>
<view class="mb5"> 工程{{ detail.engineeringName }} </view>
<view class="mb5"> 项目{{ detail.projectName }} </view>
<view class="mb5"> 设备{{ detail.equipmentName }}</view>
<view class="mb5"> 监测点{{ detail.lineName }}</view>
<view class="mb5"> 暂态类型{{ detail.showName }}</view>
<view class="mb5" v-if="detail.evtParamTm"> 持续时间{{ detail.evtParamTm }}s</view>
<view class="mb5" v-if="detail.evtParamVVaDepth"> 幅值{{ detail.evtParamVVaDepth }}%</view>
<view class="mb5" v-if="detail.evtParamPhase"> 相别{{ detail.evtParamPhase }}</view>
<view class="mb5" v-if="detail.landPoint"> 落点区域{{ detail.landPoint }}</view>
</view>
<view class="detail-tabs">
<uni-segmented-control :current="detailTab" active-color="#376cf3" :values="['波形图', 'ITIC', 'F47']"
@@ -22,14 +23,24 @@
<view v-if="detailTab == 0">
<view class="detail-content">
<view class="detail-content-title mb20">瞬时波形图</view>
<image style="width: 100%" :src="detail.instantPics" mode="widthFix" v-if="detail.instantPics"
<!-- <image style="width: 100%" :src="detail.instantPics" mode="widthFix" v-if="detail.instantPics"
@click="previewImage(detail.instantPics)" />
<text v-else>暂无</text> -->
<view v-if="listWaveData.length > 0">
<waveform v-for="(value, ind) in listWaveData" :index="ind" :unit="unit" :data="value"
style="height: 150px;" />
</view>
<text v-else>暂无</text>
</view>
<view class="detail-content">
<view class="detail-content-title mb20">RMS波形图</view>
<image style="width: 100%" :src="detail.rmsPics" mode="widthFix" v-if="detail.rmsPics"
<!-- <image style="width: 100%" :src="detail.rmsPics" mode="widthFix" v-if="detail.rmsPics"
@click="previewImage(detail.rmsPics)" />
<text v-else>暂无</text> -->
<view v-if="listRmsData.length > 0">
<waveform v-for="(value, ind) in listRmsData" :index="ind" :unit="unit" :data="value"
style="height: 150px;" />
</view>
<text v-else>暂无</text>
</view>
</view>
@@ -46,14 +57,21 @@
import { updateStatus } from '@/common/api/message'
import ITIC from './ITIC.vue'
import F47 from './F47.vue'
import waveform from './waveform.vue'
import { analyseWave } from '@/common/api/harmonic.js';
export default {
components: { ITIC, F47 },
components: { ITIC, F47, waveform },
data() {
return {
loading: true,
detail: {},
detailTab: 0,
listWaveData: [],
listRmsData: [],
unit: [],
list: {},
}
},
computed: {
@@ -74,6 +92,7 @@ export default {
},
},
onLoad(options) {
console.log("🚀 ~ options:", options)
this.detail = JSON.parse(decodeURIComponent(options.detail).replace(/百分比/g, '%'))
this.detail.rmsPics && (this.detail.rmsPics = this.$config.static + this.detail.rmsPics)
this.detail.instantPics && (this.detail.instantPics = this.$config.static + this.detail.instantPics)
@@ -84,6 +103,31 @@ export default {
eventIds: [this.detail.id],
})
}
analyseWave({
eventId: this.detail.id,
isApp: true
}).then(res => {
this.list = res.data
this.uni = []
// 数据
this.listWaveData = this.bindChartClickEvent(this.list.listWaveData)
this.listRmsData = this.bindChartClickEvent(this.list.listRmsData)
// 单位
this.unit = this.list.waveTitle.slice(1).reduce((acc, _, i, arr) => {
if (i % 3 === 0) {
const group = arr.slice(i, i + 3);
const type = group[0]?.startsWith('U') ? 'kV' :
group[0]?.startsWith('I') ? 'A' : '';
acc.push(type);
}
return acc;
}, []);
})
},
methods: {
onDetailTabChange(e) {
@@ -94,6 +138,44 @@ export default {
url: `/pages/message1/comp/preview?url=${encodeURIComponent(url)}`,
})
},
bindChartClickEvent(data) {
let unit = this.list.waveTitle.slice(1).reduce((acc, _, i, arr) => {
const group = arr.slice(i, i + 3);
const type = group[0]?.startsWith('U') ? 'kV' :
group[0]?.startsWith('I') ? 'A' : '';
acc.push(type);
return acc;
}, []);
const result = [];
// 从第2列开始遍历索引1每3个一列分组
for (let i = 1; i < data[0].length; i += 3) {
const group = {
A: data.map(row => [row[0], this.calculate(row[i], unit[i])]), // 每组第1个 → A
B: data.map(row => [row[0], this.calculate(row[i + 1], unit[i])]), // 每组第2个 → B
C: data.map(row => [row[0], this.calculate(row[i + 2], unit[i])]), // 每组第3个 → C
};
result.push(group);
}
return result;
},
calculate(num, key) {
if (num === null) return null
let nums = ''
switch (key) {
case 'kV':
nums = num * Number(this.list.pt) / 1000
break
case 'A':
nums = num * Number(this.list.ct)
break
}
return nums
}
},
}
</script>

View File

@@ -0,0 +1,237 @@
<template>
<!-- ITIC -->
<view>
<l-echart ref="echartRef" @finished="initChart"></l-echart>
</view>
</template>
<script>
const echarts = require('../../../uni_modules/lime-echart/static/echarts.min')
export default {
components: {},
props: {
data: {
type: [Object],
},
index: {
type: [Number],
},
unit: {
type: [Array],
}
},
data() {
return {
option: {
backgroundColor: '#fff',
grid: {
left: '0px',
right: '10rpx',
bottom: '0rpx',
top: '25px',
containLabel: true,
},
legend: {
right: '10px',
top: '0px',
icon: 'rect',
itemWidth: 20,
itemHeight: 2,
itemGap: 8,
itemStyle: {
borderWidth: 0,
},
textStyle: {
fontSize: 10,
},
padding: [5, 5, 5, 10],
},
xAxis: {
type: 'category',
boundaryGap: false,
splitLine: { show: false },
axisLine: { show: true },
axisTick: { show: false },
axisLabel: {
fontSize: 10,
interval: 0,
},
},
yAxis: {
type: 'value',
name: '',
nameLocation: 'end',
nameGap: 10,
minInterval: 1,
nameTextStyle: {
fontSize: 12,
padding: [28, 10, 0, 0],
},
axisLine: {
show: true,
},
axisTick: {
show: true,
},
},
series: [
{
name: 'A相',
type: 'line',
data: [
],
showSymbol: false,
smooth: true,
tooltips: {
show: false,
},
color: '#DAA520',
},
{
name: 'B相',
type: 'line',
data: [
],
showSymbol: false,
smooth: true,
tooltips: {
show: false,
},
color: '#2E8B57',
},
{
name: 'C相',
type: 'line',
data: [
],
showSymbol: false,
smooth: true,
tooltips: {
show: false,
},
color: '#A52a2a',
},
],
},
status: 'loading',
echartRef: null,
pointI: [],
xLabelShowIndices: new Set(),
}
},
mounted() {
// this.initChart()
// console.log('🚀 ~ props.data:', this.props.data)
},
methods: {
init() { },
async initChart() {
if (!this.$refs.echartRef) return
try {
this.echartRef = await this.$refs.echartRef.init(echarts)
this.setOption()
this.echartRef.setOption(this.option, true)
} catch (error) {
console.error('图表初始化失败:', error)
}
},
formatXAxisLabel(val, index) {
return this.xLabelShowIndices.has(index) ? String(val) : ''
},
getYAxisRange() {
const values = []
;['A', 'B', 'C'].forEach((key) => {
; (this.data[key] || []).forEach((p) => {
const v = p[1]
if (v !== null && v !== undefined && !Number.isNaN(Number(v))) {
values.push(Number(v))
}
})
})
if (!values.length) return {}
const dataMax = Math.max(...values)
const dataMin = Math.min(...values)
let min = 0
let max = 0
if (dataMin > 0) {
min = Math.floor(dataMin / 1.3)
} else {
min = Math.floor(dataMin * 1.3)
}
if (dataMax > 0) {
max = Math.ceil(dataMax * 1.3)
} else {
max = Math.ceil(dataMax / 1.3)
}
if (min === max) {
min -= 1
max += 1
}
return { min, max }
},
buildXLabelShowIndices(xLabels) {
const len = xLabels.length
if (len === 0) return new Set()
const showIndices = new Set([0, len - 1])
const zeroIdx = xLabels.findIndex((x) => Number(x) === 0)
if (zeroIdx >= 0) {
showIndices.add(zeroIdx)
} else if (len > 2) {
showIndices.add(Math.floor((len - 1) / 2))
}
return showIndices
},
setOption() {
if (!this.data) return
if (this.index == 0) {
this.option.legend.show = true
} else {
this.option.legend.show = false
}
this.option.yAxis.name = this.unit[this.index]
const points = this.data.A || []
const xLabels = points.map((p) => p[0])
this.xLabelShowIndices = this.buildXLabelShowIndices(xLabels)
this.option.xAxis.data = xLabels
this.option.xAxis.axisLabel.formatter = (val, index) => this.formatXAxisLabel(val, index)
this.option.series[0].data = points.map((p) => p[1])
this.option.series[1].data = (this.data.B || []).map((p) => p[1])
this.option.series[2].data = (this.data.C || []).map((p) => p[1])
const { min, max } = this.getYAxisRange()
this.option.yAxis.min = min
this.option.yAxis.max = max
},
},
computed: {},
watch: {
},
}
</script>
<style lang="scss" scoped></style>