482 lines
18 KiB
Vue
482 lines
18 KiB
Vue
<template>
|
||
<div>
|
||
<!--指标越限概率分布 -->
|
||
<TableHeader :showReset="false" @selectChange="selectChange" datePicker v-if="fullscreen">
|
||
<template v-slot:select>
|
||
<el-form-item label="监测点">
|
||
<el-select size="small" v-model="tableStore.table.params.lineId">
|
||
<el-option
|
||
v-for="item in lineList"
|
||
:key="item.lineId"
|
||
:label="item.name"
|
||
:value="item.lineId"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
</template>
|
||
</TableHeader>
|
||
<div v-loading="tableStore.table.loading">
|
||
<my-echart
|
||
class="tall"
|
||
:options="echartList"
|
||
:style="{
|
||
width: prop.width,
|
||
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
|
||
}"
|
||
/>
|
||
<my-echart
|
||
class="mt10"
|
||
:options="echartList1"
|
||
:style="{
|
||
width: prop.width,
|
||
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
|
||
}"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
<script setup lang="ts">
|
||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||
import TableStore from '@/utils/tableStore'
|
||
import TableHeader from '@/components/table/header/index.vue'
|
||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||
import { limitProbabilityData, cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
|
||
|
||
const prop = defineProps({
|
||
w: { type: [String, Number] },
|
||
h: { type: [String, Number] },
|
||
width: { type: [String, Number] },
|
||
height: { type: [String, Number] },
|
||
timeKey: { type: [String, Number] },
|
||
timeValue: { type: Object }
|
||
})
|
||
|
||
// const options = ref(JSON.parse(window.localStorage.getItem('lineIdList') || '[]'))
|
||
|
||
const lineList = ref()
|
||
|
||
const headerHeight = ref(57)
|
||
|
||
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||
headerHeight.value = height
|
||
|
||
if (datePickerValue && datePickerValue.timeValue) {
|
||
// 更新时间参数
|
||
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||
}
|
||
}
|
||
|
||
// 计算是否全屏展示
|
||
const fullscreen = computed(() => {
|
||
const w = Number(prop.w)
|
||
const h = Number(prop.h)
|
||
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||
// 执行相应逻辑
|
||
return true
|
||
} else {
|
||
return false
|
||
}
|
||
})
|
||
|
||
const echartList = ref()
|
||
|
||
const echartList1 = ref()
|
||
|
||
const probabilityData = ref()
|
||
|
||
const initLineList = async () => {
|
||
cslineList({}).then(res => {
|
||
lineList.value = res.data
|
||
tableStore.table.params.lineId = lineList.value[0].lineId
|
||
tableStore.index()
|
||
})
|
||
}
|
||
|
||
// 越限程度概率分布
|
||
const initProbabilityData = () => {
|
||
// 只有当 lineList 已加载且有数据时才设置默认 lineId
|
||
if (!tableStore.table.params.lineId && lineList.value && lineList.value.length > 0) {
|
||
tableStore.table.params.lineId = lineList.value[0].lineId
|
||
}
|
||
const params = {
|
||
searchBeginTime: tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||
searchEndTime: tableStore.table.params.searchEndTime || prop.timeValue?.[1],
|
||
lineId: tableStore.table.params.lineId
|
||
}
|
||
limitProbabilityData(params).then((res: any) => {
|
||
probabilityData.value = res.data
|
||
|
||
// 处理接口返回的数据,转换为图表所需格式
|
||
if (res.data && Array.isArray(res.data)) {
|
||
// 定义指标类型顺序
|
||
const indicatorOrder = ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相电压不平衡度', '频率偏差']
|
||
// 按照指定顺序排序数据
|
||
const sortedData = [...res.data].sort((a, b) => {
|
||
return indicatorOrder.indexOf(a.indexName) - indicatorOrder.indexOf(b.indexName)
|
||
})
|
||
|
||
// 构造 series 数据
|
||
const seriesData: any = []
|
||
let maxValue: any = 0 // 用于存储数据中的最大值
|
||
// 遍历每个越限程度区间(0-20%, 20-40%, 40-60%, 60-80%, 80-100%)
|
||
for (let xIndex = 0; xIndex < 5; xIndex++) {
|
||
// 遍历每个指标类型
|
||
sortedData.forEach((item, yIndex) => {
|
||
// 从 extentGrades 中获取对应区间的值
|
||
const extentGrade = item.extentGrades[xIndex]
|
||
const value = extentGrade ? (Object.values(extentGrade)[0] as number) : 0
|
||
seriesData.push([xIndex, yIndex, value])
|
||
|
||
// 更新最大值
|
||
if (value > maxValue) {
|
||
maxValue = value
|
||
}
|
||
})
|
||
}
|
||
|
||
// 计算 z 轴最大值(最大值加 5)
|
||
const zAxisMax = Math.ceil(maxValue) + 5
|
||
// 构造 yAxis 数据(指标类型名称)
|
||
const yAxisData = sortedData.map(item => item.indexName)
|
||
|
||
echartList.value = {
|
||
options: {
|
||
backgroundColor: '#fff',
|
||
tooltip: {
|
||
textStyle: {
|
||
color: '#fff',
|
||
fontStyle: 'normal',
|
||
opacity: 0.35,
|
||
fontSize: 14
|
||
},
|
||
backgroundColor: 'rgba(0,0,0,0.55)',
|
||
borderWidth: 0,
|
||
formatter: function (params: any) {
|
||
var yIndex = params.value[1] //获取y轴索引
|
||
var tips = ''
|
||
tips += '指标类型: ' + yAxisData[yIndex] + '</br>'
|
||
tips += '越限程度: ' + params.seriesName + '</br>'
|
||
tips += '越限次数: ' + params.value[2] + '</br>'
|
||
return tips
|
||
}
|
||
},
|
||
title: {
|
||
text: '指标越限概率分布',
|
||
x: 'center',
|
||
textStyle: {
|
||
fontSize: 16,
|
||
fontWeight: 'normal'
|
||
}
|
||
},
|
||
// 移除或隐藏 visualMap 组件
|
||
visualMap: {
|
||
show: false, // 设置为 false 隐藏右侧颜色条
|
||
min: 0,
|
||
// max: 100,
|
||
max: zAxisMax, // 使用计算出的最大值加5
|
||
inRange: {
|
||
color: ['#313695', '#00BB00', '#ff8000', '#d73027', '#a50026']
|
||
}
|
||
},
|
||
// 添加 legend 配置并设置为不显示
|
||
legend: {
|
||
show: false // 隐藏图例
|
||
},
|
||
xAxis3D: {
|
||
type: 'category',
|
||
name: '越限程度',
|
||
nameLocation: 'middle',
|
||
nameGap: 30,
|
||
data: ['0-20%', '20-40%', '40-60%', '60-80%', '80-100%'],
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: '#111'
|
||
}
|
||
},
|
||
axisLabel: {
|
||
color: '#111',
|
||
margin: 15
|
||
},
|
||
nameTextStyle: {
|
||
color: '#111'
|
||
}
|
||
},
|
||
yAxis3D: {
|
||
type: 'category',
|
||
name: '指标类型',
|
||
nameLocation: 'middle',
|
||
nameGap: 30,
|
||
data: yAxisData,
|
||
nameTextStyle: {
|
||
color: '#111'
|
||
},
|
||
axisLine: {
|
||
show: true,
|
||
lineStyle: {
|
||
color: '#111'
|
||
}
|
||
},
|
||
axisLabel: {
|
||
color: '#111',
|
||
margin: 15
|
||
},
|
||
splitLine: {
|
||
lineStyle: {
|
||
color: ['#111'],
|
||
type: 'dashed',
|
||
opacity: 0.5
|
||
}
|
||
}
|
||
},
|
||
zAxis3D: {
|
||
type: 'value',
|
||
name: '越限次数',
|
||
nameLocation: 'middle',
|
||
nameGap: 30,
|
||
nameTextStyle: {
|
||
color: '#111'
|
||
},
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: '#111'
|
||
}
|
||
},
|
||
axisLabel: {
|
||
color: '#111'
|
||
},
|
||
min: 0,
|
||
max: zAxisMax // 使用计算出的最大值加5
|
||
// max: 100
|
||
},
|
||
grid3D: {
|
||
viewControl: {
|
||
projection: 'perspective',
|
||
distance: 250,
|
||
rotateSensitivity: 10,
|
||
zoomSensitivity: 2
|
||
},
|
||
boxWidth: 150,
|
||
boxDepth: 100,
|
||
boxHeight: 100,
|
||
light: {
|
||
main: {
|
||
intensity: 1.2
|
||
},
|
||
ambient: {
|
||
intensity: 0.4
|
||
}
|
||
}
|
||
},
|
||
series: [
|
||
{
|
||
type: 'bar3D',
|
||
name: '0-20%',
|
||
data: seriesData.filter((item: any) => item[0] === 0),
|
||
shading: 'realistic',
|
||
label: {
|
||
show: false
|
||
},
|
||
itemStyle: {
|
||
opacity: 0.9
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
show: true,
|
||
textStyle: {
|
||
fontSize: 14,
|
||
color: '#000'
|
||
}
|
||
},
|
||
itemStyle: {
|
||
color: '#ff8000'
|
||
}
|
||
}
|
||
},
|
||
{
|
||
type: 'bar3D',
|
||
name: '20-40%',
|
||
data: seriesData.filter((item: any) => item[0] === 1),
|
||
shading: 'realistic',
|
||
label: {
|
||
show: false
|
||
},
|
||
itemStyle: {
|
||
opacity: 0.9
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
show: true,
|
||
textStyle: {
|
||
fontSize: 14,
|
||
color: '#000'
|
||
}
|
||
},
|
||
itemStyle: {
|
||
color: '#ff8000'
|
||
}
|
||
}
|
||
},
|
||
{
|
||
type: 'bar3D',
|
||
name: '40-60%',
|
||
data: seriesData.filter((item: any) => item[0] === 2),
|
||
shading: 'realistic',
|
||
label: {
|
||
show: false
|
||
},
|
||
itemStyle: {
|
||
opacity: 0.9
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
show: true,
|
||
textStyle: {
|
||
fontSize: 14,
|
||
color: '#000'
|
||
}
|
||
},
|
||
itemStyle: {
|
||
color: '#ff8000'
|
||
}
|
||
}
|
||
},
|
||
{
|
||
type: 'bar3D',
|
||
name: '60-80%',
|
||
data: seriesData.filter((item: any) => item[0] === 3),
|
||
shading: 'realistic',
|
||
label: {
|
||
show: false
|
||
},
|
||
itemStyle: {
|
||
opacity: 0.9
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
show: true,
|
||
textStyle: {
|
||
fontSize: 14,
|
||
color: '#000'
|
||
}
|
||
},
|
||
itemStyle: {
|
||
color: '#ff8000'
|
||
}
|
||
}
|
||
},
|
||
{
|
||
type: 'bar3D',
|
||
name: '80-100%',
|
||
data: seriesData.filter((item: any) => item[0] === 4),
|
||
shading: 'realistic',
|
||
label: {
|
||
show: false
|
||
},
|
||
itemStyle: {
|
||
opacity: 0.9
|
||
},
|
||
emphasis: {
|
||
label: {
|
||
show: true,
|
||
textStyle: {
|
||
fontSize: 14,
|
||
color: '#000'
|
||
}
|
||
},
|
||
itemStyle: {
|
||
color: '#ff8000'
|
||
}
|
||
}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
const tableStore: any = new TableStore({
|
||
url: '/harmonic-boot/limitRateDetailD/limitTimeProbabilityData',
|
||
method: 'POST',
|
||
showPage: false,
|
||
column: [],
|
||
beforeSearchFun: () => {
|
||
tableStore.table.params.searchBeginTime = tableStore.table.params.searchBeginTime || prop.timeValue?.[0]
|
||
tableStore.table.params.searchEndTime = tableStore.table.params.searchEndTime || prop.timeValue?.[1]
|
||
// 只有当 lineList 已加载且有数据时才设置默认 lineId
|
||
if (!tableStore.table.params.lineId && lineList.value && lineList.value.length > 0) {
|
||
tableStore.table.params.lineId = lineList.value[0].lineId
|
||
}
|
||
},
|
||
loadCallback: () => {
|
||
// 处理返回的数据,将其转换为图表所需格式
|
||
const indexNames: any = [...new Set(tableStore.table.data.map((item: any) => item.indexName))]
|
||
const timePeriods = [...new Set(tableStore.table.data.map((item: any) => item.timePeriod))]
|
||
|
||
// 构建系列数据
|
||
const seriesData = indexNames.map((indexName: string) => {
|
||
const dataIndex = tableStore.table.data.filter((item: any) => item.indexName === indexName)
|
||
return {
|
||
name: indexName,
|
||
type: 'line',
|
||
symbol: 'none',
|
||
data: dataIndex.map((item: any) => [item.timePeriod, item.times])
|
||
}
|
||
})
|
||
|
||
echartList1.value = {
|
||
title: {
|
||
text: '越限时间概率分布'
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis'
|
||
},
|
||
legend: {
|
||
data: indexNames
|
||
},
|
||
xAxis: {
|
||
type: 'category',
|
||
name: '时间段',
|
||
data: timePeriods
|
||
},
|
||
yAxis: {
|
||
type: 'value'
|
||
// name: '次数'
|
||
},
|
||
series: seriesData
|
||
}
|
||
initProbabilityData()
|
||
}
|
||
})
|
||
|
||
provide('tableStore', tableStore)
|
||
|
||
onMounted(() => {
|
||
initLineList()
|
||
})
|
||
watch(
|
||
() => prop.timeKey,
|
||
val => {
|
||
tableStore.index()
|
||
}
|
||
)
|
||
watch(
|
||
() => prop.timeValue,
|
||
(newVal, oldVal) => {
|
||
// 当外部时间值变化时,更新表格的时间参数
|
||
if (newVal && (!oldVal || newVal[0] !== oldVal[0] || newVal[1] !== oldVal[1])) {
|
||
tableStore.table.params.searchBeginTime = newVal[0]
|
||
tableStore.table.params.searchEndTime = newVal[1]
|
||
tableStore.index()
|
||
}
|
||
},
|
||
{
|
||
deep: true
|
||
}
|
||
)
|
||
|
||
const addMenu = () => {}
|
||
</script>
|
||
<style lang="scss" scoped></style>
|