Files
admin-govern/src/views/govern/device/control/tabs/components/realtrend.vue
2024-10-18 16:24:44 +08:00

534 lines
17 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 实时数据 - 实时趋势 -->
<template>
<div class="realtrend" v-loading="loading">
<el-tabs type="border-card" v-if="tabsList.length!=0" v-model="activeName" @tab-click="handleClick">
<el-tab-pane v-for="(item, index) in tabsList" :label="item.groupName" :name="index" :key="index">
<div>
<div class="realtrend_top">
<!-- <div class="thead">
<ul v-for="(table, tableIndex) in newTableList" :key="tableIndex">
<li>
{{ table[0].value }}
</li>
</ul>
</div>
<div class="table">
<ul v-for="(table, tableIndex) in newTableList" :key="tableIndex">
<span v-for="(key, keys) in table">
<li v-if="keys != 0">
{{ key?.value }}
</li>
</span>
</ul>
</div> -->
<div class="realtrend_table" v-if="Object.keys(tableData).length != 0">
<div class="thead_left">
<p>次数</p>
<p>{{ item.groupName }}</p>
</div>
<div class="thead_right">
<div class="right_cell" v-for="(value, key, index) in tableData" :key="index">
<p>
<span>{{ String(key).replace('data', ' ') }}</span>
</p>
<p>
<span
v-if="
String(key).includes('data') &&
String(key) != 'dataLevel' &&
String(key) != 'dataTime'
"
>
{{ value }}
</span>
</p>
</div>
</div>
</div>
</div>
<div class="tab_info" v-if="Object.keys(tableData).length != 0">
<div class="charts">
<MyEchart ref="barCharts" :options="echartsData" :isInterVal="true"></MyEchart>
</div>
</div>
<el-empty v-else style="margin: 0 auto" />
</div>
</el-tab-pane>
</el-tabs>
<el-empty v-else/>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive, nextTick, defineEmits } from 'vue'
import { VxeGridProps, VxeGridPropTypes } from 'vxe-table'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { Platform, TrendCharts, DataLine } from '@element-plus/icons-vue'
import { getDeviceTrendDataGroup, getDeviceTrendData } from '@/api/cs-device-boot/EquipmentDelivery.ts'
import Index from '@/components/wangEditor/index.vue'
const activeName = ref(0)
const emit = defineEmits(['changeTrendType'])
const tableList: any = []
interface RowVO {
[key: string]: any
}
//谐波电压含有率
const gridOptions = ref<VxeGridProps<RowVO>>({
border: true,
showOverflow: true,
showHeader: false,
columns: [],
data: [],
columnConfig: {
resizable: true
},
align: 'center'
})
gridOptions.value = { ...defaultAttribute, ...gridOptions.value }
const myColumns: any = ref([
// { field: 'name', title: '次数' }
// { field: 'value', title: '谐波电压含有率(%)' }
])
const myData = tableList
const tabsList = ref([])
//接收参数
const params = ref({})
const open = async (val: any) => {
//获取指标tab
loading.value = true
await getDeviceTrendDataGroup().then(res => {
tabsList.value = res.data
if (tabsList.value.length != 0) {
// activeName.value = tabsList.value[0]?.id
activeName.value = val.activeTrendName || 0
}
params.value = { groupId: tabsList.value[activeName.value]?.id, ...val }
})
init()
return
}
const newTableList: any = ref([])
//根据指标tab查询实时趋势
const loading: any = ref(false)
//echarts数据
const chartsData: any = ref([])
const chartsYxiasData: any = ref([])
const findRealTrendDataByGroupId = (obj: any) => {
return
chartsData.value = []
chartsYxiasData.value = []
getDeviceTrendData(obj).then(res => {
let list: any = []
let countList: any = []
myColumns.value = [{ field: 'name', title: '次数' }]
chartsData.value = res.data[0].thdDataTdVODatas
//处理实时趋势表格
let arr = res.data[0].thdDataVOS
arr.map((item: any, index: any) => {
myColumns.value.push({ field: item.phase, title: item.name })
chartsYxiasData.value.push({ phase: item.phase, title: item.name, phaseList: [], gbList: [] })
//循环第二层数据
item.list = []
item.data.map((vv: any, vvs: any) => {
if (!(vv.statisticalData + '')) {
vv.statisticalData = '/'
}
item.list.push({ value: vv.statisticalData, count: vv.frequency - 0 })
})
list[index + 1] = item.list
const minCount = Math.min(...item.list.map((item: any) => item.count))
const maxCount = Math.max(...item.list.map((item: any) => item.count))
for (let i = 0; i < 50; i++) {
countList[i] = { value: i + minCount + '次', count: i + minCount }
}
countList.map((item: any, index: any) => {
if (item.value.replace('次', '') - 0 > 50) {
countList.splice(index, 1)
}
})
list[0] = countList
if (item.list.length == 0) {
for (let i = 0; i < countList.length; i++) {
item.list.push({
value: '/',
count: index
})
}
}
if (item.list.length != 0) {
const maxCount1 = Math.max(...countList.map((item: any) => item.count))
const maxCount2 = Math.max(...item.list.map((item: any) => item.count))
if (maxCount2 < maxCount1) {
for (let i = 0; i < maxCount1 - maxCount2; i++) {
item.list.push({
value: '/',
count: index
})
}
}
}
})
// 转换为对象数组
list.map((item: any, index: any) => {
item.unshift({ value: myColumns.value[index].title, count: '' })
})
newTableList.value = list
loading.value = false
init()
})
}
//反转表格
const reverseTable = () => {
const buildData = myColumns.value.map(column => {
const item: any = { col0: column.title }
myData.forEach((row, index) => {
item[`col${index + 1}`] = row[column.field]
})
return item
})
const buildColumns: VxeGridPropTypes.Columns = [
{
field: 'col0',
fixed: 'left',
width: 200
}
]
myData.forEach((item, index) => {
buildColumns.push({
field: `col${index + 1}`,
minWidth: 120
})
})
gridOptions.value.data = buildData
gridOptions.value.columns = buildColumns
}
reverseTable()
const echartsData: any = ref([])
const barCharts = ref()
//加载echarts
const init = () => {
let trendData: any = []
for (let key in tableData.value) {
console.log(key, ',,,,,')
trendData.push({
name: key,
value: tableData.value[key],
count: String(key).replace('data', '')
})
}
let gbData: any = []
for (let key in limitData.value) {
gbData.push({
name: key,
value: limitData.value[key]
})
}
let xAxisList: any = []
chartsData.value.map((item: any, index: any) => {
chartsYxiasData.value.map((vv: any, vvs: any) => {
if (item.phase == vv.phase) {
if (vvs == 0) {
vv.gbList.push(item.internationalValue)
}
vv.phaseList.push(item.statisticalData)
}
})
xAxisList.push(item.frequency + '次')
})
xAxisList = [...new Set(xAxisList)]
echartsData.value = {
options: {
// backgroundColor: '#0f375f',
dataZoom: [
{
type: 'inside',
height: 13,
start: 0,
bottom: '20px',
end: 20
},
{
start: 0,
height: 13,
bottom: '20px',
end: 20
}
],
grid: {
top: '14%',
bottom: '70px', //也可设置left和right设置距离来控制图表的大小
left: '3%',
right: '5%'
},
// tooltip: {
// trigger: 'axis',
// axisPointer: {
// type: 'cross',
// label: {
// show: false
// }
// }
// },
legend: {
data: [],
itemGap: 15,
type: 'scroll', // 开启滚动分页
// orient: 'vertical', // 垂直排列
right: '3%', // 位置调整
top: 0,
bottom: 20,
width: 400,
height: 50
},
xAxis: {
name: '次数',
data: trendData.map((item: any) => {
return item.count+'次'
}),
axisLine: {
show: true, //隐藏X轴轴线
lineStyle: {
color: '#000'
}
},
axisTick: {
show: true //隐藏X轴刻度
},
axisPointer: {
type: 'shadow'
},
axisLabel: {
show: true,
textStyle: {
color: '#000' //X轴文字颜色
}
}
},
yAxis: [
{
type: 'value',
name: '',
splitLine: {
show: false
},
axisTick: {
show: true
},
axisLine: {
show: true,
lineStyle: {
color: '#000'
}
}
}
],
series: []
}
}
let list: any = [
gbData.map((item: any) => {
return item.value
}),
trendData.map((item: any) => {
return item.value
})
]
let legendList = ['国标限值', tabsList.value[activeName.value]?.groupName]
echartsData.value.options.legend.data = legendList
list.map((item: any, index: any) => {
echartsData.value.options.series.push({
name: legendList[index],
type: 'bar',
barMaxWidth: 16, //使用的 y 轴的 index在单个图表实例中存在多个 y轴的时候有用
itemStyle: {
// normal: {
barBorderRadius: [3, 3, 0, 0],
// color: '#00CC99'
// }e
color: colorList[index]
},
data: item
})
})
if (barCharts.value) {
barCharts.value[activeName.value]?.initChart()
}
loading.value = false
return
}
const handleClick = (tab: any, event: any) => {
params.value.groupId = tabsList.value[tab.index].id
emit('changeTrendType', tab.index)
activeName.value = tab.index
init()
}
//获取mqtt传送的实时数据
const mqttMessage: any = ref()
const tableData: any = ref({})
const colorList = ['#0e8780', '#FFCC00', '#009900', '#CC0000']
const setRealTrendData = (val: any) => {
tableData.value = {}
mqttMessage.value = val
loading.value = true
for (let key in val) {
if (String(key).includes('data') && String(key) != 'dataLevel' && String(key) != 'dataTime') {
tableData.value[key] = val[key]
delete tableData.value.data1
}
}
loading.value = false
init()
}
//获取国标限值
const limitData: any = ref()
const setOverLimitData = (val: any) => {
limitData.value = {}
for (let key in val) {
if (String(key).includes('uharm')) {
limitData.value[key] = val[key]
}
}
}
onMounted(() => {})
defineExpose({ open, setRealTrendData, setOverLimitData })
</script>
<style lang="scss" scoped>
.realtrend {
width: 100%;
height: 100%;
.realtrend_top {
width: 100%;
height: auto;
display: flex;
justify-content: space-between;
align-items: center;
.table {
flex: 1;
// min-height: 80px;
cursor: pointer;
min-height: 90px;
max-height: 170px;
border: 1px solid #eee;
overflow-x: auto;
overflow-y: hidden;
position: relative;
ul {
width: auto;
height: 40px;
display: flex;
li {
flex: none;
width: 100px;
line-height: 40px;
border: 1px solid #eee;
text-align: center;
list-style: none;
}
}
ul:nth-child(1) {
li {
font-weight: 800;
background: #f4f6f9;
}
}
}
// .table::-webkit-scrollbar {
// display: none;
// }
.realtrend_table {
width: 100%;
height: auto;
max-height: 150px;
display: flex;
border: 2px solid #eee;
cursor: pointer;
.thead_left {
width: 150px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
line-height: 50px;
font-weight: 800;
p {
width: 100%;
height: 100%;
text-align: center;
border: 1px solid #eee;
line-height: 50px;
margin: 0 !important;
}
}
.thead_right {
flex: 1;
align-items: center;
overflow-x: auto;
overflow-y: hidden;
display: flex;
.right_cell {
width: 100%;
display: flex;
flex-direction: column;
p {
flex: none;
width: 90px;
height: 100%;
text-align: center;
border: 1px solid #eee;
line-height: 50px;
margin: 0 !important;
}
p:nth-child(1) {
font-weight: 800;
}
}
}
}
}
}
.reverse-table .vxe-body--row .vxe-body--column:first-child {
background-color: #f8f8f9;
}
::v-deep .vxe-table--render-wrapper {
height: 90px !important;
max-height: 90px !important;
overflow-x: auto !important;
min-height: 0 !important;
}
::v-deep .body--wrapper {
height: 90px !important;
max-height: 90px !important;
min-height: 0 !important;
}
.tab_info {
width: 100%;
height: calc(100vh - 450px);
// overflow: auto;
// padding-bottom: 20px;
.charts {
width: 100%;
margin-top: 10px;
height: calc(100vh - 600px);
}
}
</style>