实时数据:测点选择回显、添加高低频选项、实时曲线获取系统参数颜色、实时数据状态获取系统参数颜色

通讯链路:设备选择结构调整、接口修改超时时间1min、
历史数据:测点添加高低频选项,数据导出修改高低频分开导出
单风机:状态根据系统参数颜色修改为tag、去除无效内容,调整结构为5|12|5、修改数据始终保留两位小数、风频去除间隔、年发电量与总发电量修改为MWh、去除报警信息自动滚动、
This commit is contained in:
高云鹏 2025-01-16 16:47:01 +08:00
parent b4d9a5a7ff
commit f56833bde2
9 changed files with 478 additions and 201 deletions

View File

@ -116,6 +116,7 @@ export const saveMappingListReq = (data: any) => {
url: '/api/node/link/saveMappingList',
method: 'post',
data: data,
timeout: 60 * 1000
})
}
@ -124,6 +125,7 @@ export const bindDeviceMeasReq = (data: any) => {
url: '/api/node/link/bindDevices',
method: 'post',
data: data,
timeout: 60 * 1000
})
}

View File

@ -1,17 +1,21 @@
<template>
<div class="windBlower" ref="windBlower">
<el-row>
<el-col :md="24" :lg="6">
<el-col :md="24" :lg="5">
<div class="cardContentLeft">
<!--实时预览-->
<div class="overview">
<div class="cardLabel">
{{ '名称:' + route.query.name + '&nbsp;&nbsp;&nbsp;&nbsp;' + '型号:' + route.query.model }}
{{ '&nbsp;&nbsp;' + route.query.name }}
</div>
<div class="overviewDataSection" ref="listContainer">
<div class="overviewDataSectionItem">
<span class="realLeft">机组运行状态</span>
<span class="reafRight">{{ realTimeDataState }}</span>
<el-tag
:color="stateTag.backgroundColor"
:style="{ color: stateTag.color }"
>{{ realTimeDataState }}</el-tag
>
</div>
<div class="overviewDataSectionItem">
<span class="realLeft">风速</span>
@ -76,7 +80,7 @@
</div>
</el-col>
<el-col :md="24" :lg="12">
<el-col :md="24" :lg="14">
<div class="cardContentCenter">
<!--风机控制-->
<div class="controlBackgroundImg" ref="backgroundImgRef">
@ -157,7 +161,7 @@
</div>
</div>
</el-col>
<el-col :md="24" :lg="6" style="background: #f5f5f5">
<el-col :md="24" :lg="5" style="background: #f5f5f5">
<div class="cardContentRight">
<!--发电量概况-->
<div class="summarize">
@ -170,7 +174,11 @@
</div>
<div class="summarize-panel-base">
<div>
<span class="content-number">{{ realTimeDataForSingle.ikwhthisday }}</span>
<span class="content-number">{{
realTimeDataForSingle.ikwhthisday === '-'
? realTimeDataForSingle.ikwhthisday
: Math.ceil(realTimeDataForSingle.ikwhthisday)
}}</span>
&nbsp;
<span class="content-number">{{ realTimeDataForSingleUnit.ikwhthisday }}</span>
</div>
@ -184,7 +192,11 @@
</div>
<div class="summarize-panel-base">
<div>
<span class="content-number">{{ realTimeDataForSingle.monthprodenergy }}</span>
<span class="content-number">{{
realTimeDataForSingle.monthprodenergy === '-'
? realTimeDataForSingle.monthprodenergy
: Math.ceil(realTimeDataForSingle.monthprodenergy)
}}</span>
&nbsp;
<span class="content-number">{{ realTimeDataForSingleUnit.monthprodenergy }}</span>
</div>
@ -200,9 +212,13 @@
</div>
<div class="summarize-panel-base">
<div>
<span class="content-number">{{ realTimeDataForSingle.yearprodenergy }}</span>
<span class="content-number">{{
realTimeDataForSingle.yearprodenergy === '-'
? realTimeDataForSingle.yearprodenergy
: (Math.ceil(realTimeDataForSingle.yearprodenergy) / 1000).toFixed(2)
}}</span>
&nbsp;
<span class="content-number">{{ realTimeDataForSingleUnit.yearprodenergy }}</span>
<span class="content-number">MWh</span>
</div>
<!-- <div>{{ realTimeDataForSingleUnit.yearprodenergy }}</div> -->
<div>年发电量</div>
@ -214,9 +230,13 @@
</div>
<div class="summarize-panel-base">
<div>
<span class="content-number">{{ realTimeDataForSingle.ikwhoverall }}</span>
<span class="content-number">{{
realTimeDataForSingle.ikwhoverall === '-'
? realTimeDataForSingle.ikwhoverall
: (Math.ceil(realTimeDataForSingle.ikwhoverall) / 1000).toFixed(2)
}}</span>
&nbsp;
<span class="content-number">{{ realTimeDataForSingleUnit.ikwhoverall }}</span>
<span class="content-number">MWh</span>
</div>
<!-- <div>{{ realTimeDataForSingleUnit.ikwhoverall }}</div> -->
<div>总发电量</div>
@ -297,6 +317,8 @@ import { queryfaultCodeDict } from '/@/api/backend/theoreticalpowerCurve/request
import { useEnumStore } from '/@/stores/enums'
import { adminBaseRoutePath } from '/@/router/static/adminBase'
import { permission } from '/@/utils/directive'
import { getParamList } from '/@/api/backend/SystemParam/request'
const vPermission = permission()
const enumStore = useEnumStore()
@ -930,6 +952,8 @@ const initFrequencyChart = () => {
itemStyle: {
color: '#0277B3',
},
barGap: '0%',
barCategoryGap: '0%',
// label: {
// show: true,
// position: 'middle',
@ -1031,9 +1055,9 @@ const createRealTimeData = async () => {
realTimeData.value.processedoperationmode = getRealTimeState(realData)
realTimeData.value.locked = realData.locked
temperatureChartsData[0].value = getCutDecimalsValue(realData.itempoutdoor_1sec)
temperatureChartsData[1].value = getCutDecimalsValue(realData.itempnacelle_1sec)
temperatureChartsData[2].value = getCutDecimalsValue(realData.itempcabinettowerbase_1sec)
temperatureChartsData[0].value = getCutDecimalsValue(realData.itempoutdoor_1sec, 2, true)
temperatureChartsData[1].value = getCutDecimalsValue(realData.itempnacelle_1sec, 2, true)
temperatureChartsData[2].value = getCutDecimalsValue(realData.itempcabinettowerbase_1sec, 2, true)
const overviewDatakeys: any = Object.keys(overviewData)
const sigleDataKeys: any = Object.keys(realTimeDataForSingle.value)
@ -1045,12 +1069,12 @@ const createRealTimeData = async () => {
modelList.forEach((item: any) => {
const realVal = realData[item.attributeCode.toLowerCase()]
let val = getCutDecimalsValue(realVal)
let val = getCutDecimalsValue(realVal, 2, true)
if (enumStore.keys.includes(item.attributeCode)) {
val = enumStore.data[item.attributeCode][val]
val = enumStore.data[item.attributeCode][realVal]
}
if (malFunctionKeys.includes(item.attributeCode)) {
val = malFunctionEnums?.[val] ?? val
val = malFunctionEnums?.[realVal] ?? val
}
if (sigleDataKeys.includes(item.attributeCode.toLowerCase())) {
realTimeDataForSingle.value[item.attributeCode.toLowerCase()] = val === '-' ? val : val
@ -1443,15 +1467,54 @@ const switchAirblower = (type: 0 | 1) => {
query,
})
}
const processedoperationmodeList = ref<{ value: number; color: string; backgroundColor: string }[]>([])
const stateTag = computed(()=>{
return processedoperationmodeList.value.find(item=>item.value === realTimeData.value.processedoperationmode) ?? {color: 'rgb(2, 119, 179)', backgroundColor: 'rgba(2, 119, 179, 0.2)'}
})
const getColorList = () => {
getParamList().then((res) => {
if ((res as any).success) {
const colorData = res.data.find((item: any) => item.id === '1234569')?.paramValueJson
if (colorData) {
processedoperationmodeList.value = colorData.map((item: any) => {
const state = Math.ceil(item.state)
return {
value: state,
color: item.color,
backgroundColor: hexToRgba(item.color),
}
})
}
}
})
}
function hexToRgba(hex: string) {
hex = hex.replace('#', '')
if (hex.length === 3) {
hex = hex
.split('')
.map((hexPart: string) => {
return hexPart + hexPart
})
.join('')
}
let r = parseInt(hex.substring(0, 2), 16)
let g = parseInt(hex.substring(2, 4), 16)
let b = parseInt(hex.substring(4, 6), 16)
return `rgba(${r}, ${g}, ${b}, 0.2)`
}
getColorList()
onMounted(() => {
window.addEventListener('resize', sizeChange)
sizeChange()
getAllChartData()
useEventListener(window, 'resize', echartsResize)
autoUpdate()
getAlarmList().then(() => {
createScroll()
})
getAlarmList()
getAirBlowerList().then(() => {
getMalfunctionEnums()
})

View File

@ -89,42 +89,14 @@
<template v-if="item.custom === 'default'" #default="scope">
<div v-if="item.prop === 'processedoperationmode'">
<el-tag v-if="scope.row.locked === 1" color="rgba(254,55,49,0.20)" style="color: #fe3731">已锁定</el-tag>
<el-tag v-if="scope.row.processedoperationmode === 20" color="rgba(0,100,170,0.20)" style="color: #0064aa"
>并网</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 10" color="rgba(0,160,150,0.20)" style="color: #00a096"
>维护</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 8" color="rgba(255,126,0,0.20)" style="color: #ff7e00"
>限功率运行</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 0" color="rgba(153,153,153,0.20)" style="color: #666666"
>离线</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 16" color="rgba(6,180,41,0.20)" style="color: #06b429"
>启动</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 6" color="rgba(254,55,49,0.20)" style="color: #fe3731"
>正常停机</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 1" color="rgba(254,55,49,0.20)" style="color: #fe3731"
>外部因素导致停机</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 2" color="rgba(254,55,49,0.20)" style="color: #fe3731"
>停机</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 11" color="rgba(255,182,0,0.20)" style="color: #ffb600"
>待机</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 1110" color="rgba(153,153,153,0.20)" style="color: #666666"
>解缆状态</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 1111" color="rgba(254,55,49,0.20)" style="color: #fe3731"
>电网故障停机</el-tag
>
<el-tag v-if="scope.row.processedoperationmode === 33" color="rgba(153, 153, 153, 0.2)" style="color: #999999"
>通讯中断</el-tag
<template v-for="color in processedoperationmodeList" :key="color.value">
<el-tag
v-if="scope.row.processedoperationmode === color.value"
:color="color.backgroundColor"
:style="{ color: color.color }"
>{{ color.label }}</el-tag
>
</template>
</div>
<div v-if="item.prop === 'chart'" @click="openLineChart(scope.row)" class="operate">
<div class="chartIcon">
@ -210,6 +182,7 @@
:visible="realDataLineChartVisible"
:id="clickRow!.irn"
:iot-model-id="selectPointModelId"
:curveColorList="curveColorList"
></RealDataChart>
<template #header>
<div>
@ -237,7 +210,8 @@ import { getRealValueListReq } from '/@/api/backend/deviceModel/request'
import SelectPoint from '/@/views/backend/equipment/airBlower/selectPoint.vue'
import RealDataChart from '/@/views/backend/equipment/airBlower/realDataChart.vue'
import { permission } from '/@/utils/directive'
import { table } from 'console'
import { getParamList } from '/@/api/backend/SystemParam/request'
const vPermission = permission()
const router = useRouter()
@ -424,7 +398,7 @@ const defaultColumn: TableColumnType[] = [
width: 100,
},
]
let dynamicColumn: TableColumnType[] = [
let dynamicColumn = ref<TableColumnType[]>([
{
label: '风速 (m/s)',
prop: 'iwindspeed',
@ -522,16 +496,13 @@ let dynamicColumn: TableColumnType[] = [
custom: 'header',
width: 100,
},
]
const tableColumn = ref<TableColumnType[]>([...defaultColumn, ...dynamicColumn])
])
const tableColumn = ref<TableColumnType[]>([...defaultColumn, ...dynamicColumn.value])
const getSaveColumn = () => {
const saveColumn = localStorage.getItem('airBlowerTableColumnList')
console.log(saveColumn,'saveColumn');
if (saveColumn) {
tableColumn.value = JSON.parse(saveColumn)
console.log(tableColumn.value,'tableColumn.value');
dynamicColumn = tableColumn.value.slice(4)
dynamicColumn.value = tableColumn.value.slice(4)
}
}
getSaveColumn()
@ -713,8 +684,7 @@ const mutiTaskList = ref<
const selectPointDialogRef = ref()
const selectPointVisible = ref(false)
const defaultAttr = computed(() => {
return dynamicColumn.map((item) => {
tableColumn.value.length
return dynamicColumn.value.map((item) => {
return {
attributeName: item.label.split(' ')[0],
unit: item.label.split(' ')[1] ?? '',
@ -740,6 +710,7 @@ const saveSelectPoint = () => {
width: 100,
}
})
dynamicColumn.value = list
tableColumn.value = [...defaultColumn, ...addCoulmn]
localStorage.setItem('airBlowerTableColumnList', JSON.stringify(tableColumn.value))
getTableData()
@ -854,6 +825,49 @@ const saveLineChart = () => {
// realDataChartRef.value?.continueChart()
// linePause.value = false
// }
const processedoperationmodeList = ref<{ label: string; value: number; color: string; backgroundColor: string }[]>([])
const curveColorList = ref<string[]>()
const getColorList = () => {
getParamList().then((res) => {
if ((res as any).success) {
const colorData = res.data.find((item: any) => item.id === '1234569')?.paramValueJson
if (colorData) {
processedoperationmodeList.value = colorData.map((item: any) => {
const state = Math.ceil(item.state)
return {
label: airBlowerSelectOptions.processedoperationmode.find((i: any) => i.value === state)?.label ?? '',
value: state,
color: item.color,
backgroundColor: hexToRgba(item.color),
}
})
}
const curveColorData = res.data.find((item: any) => item.id === '1879776845197475842')?.paramValueJson
if( curveColorData){
curveColorList.value = curveColorData
}
}
})
}
function hexToRgba(hex: string) {
hex = hex.replace('#', '')
if (hex.length === 3) {
hex = hex
.split('')
.map((hexPart: string) => {
return hexPart + hexPart
})
.join('')
}
let r = parseInt(hex.substring(0, 2), 16)
let g = parseInt(hex.substring(2, 4), 16)
let b = parseInt(hex.substring(4, 6), 16)
return `rgba(${r}, ${g}, ${b}, 0.2)`
}
getColorList()
onUnmounted(() => {
autoUpdateInterval.value && clearInterval(autoUpdateInterval.value)

View File

@ -56,10 +56,11 @@ import { getRealValueListReq } from '/@/api/backend/deviceModel/request'
import { dayjs, ElMessage } from 'element-plus'
import { getCutDecimalsValue } from './utils'
const emits = defineEmits(['clearChart'])
const props = withDefaults(defineProps<{ id: string; visible: boolean; iotModelId: string }>(), {
const props = withDefaults(defineProps<{ id: string; visible: boolean; iotModelId: string; curveColorList: string[] }>(), {
id: '',
visible: false,
iotModelId: '',
curveColorList: () => [],
})
const showTimeInterval = ref(300)
//#region
@ -158,7 +159,7 @@ let realDataSeries: any = []
let realDataYAxis: any = []
let realDataLegend: any = []
const colorList = ['#ee1289', '#b8860b', '#ff00ff', '#ff0000', '#ff9912', '#8a2be2', '#000000', '#03a89e']
let colorList = ['#ee1289', '#b8860b', '#ff00ff', '#ff0000', '#ff9912', '#8a2be2', '#000000', '#03a89e']
const getRandomDarkColor = () => {
// if (index >= colorList.length) {
// let r = Math.floor(Math.random() * 200) // 0127
@ -219,9 +220,6 @@ const createChartData = (data: { [k: string]: number }, time: string) => {
realDataLegend.push({
name: info.name,
icon: 'rect',
textStyle: {
color: color,
},
customKey: item,
})
return {
@ -404,6 +402,7 @@ const createChart = () => {
],
legend: {
data: realDataLegend,
},
series: realDataSeries,
}
@ -426,10 +425,7 @@ const addPoint = () => {
selectPointVisible.value = true
}
const checkShowChart = (data: any) => {
console.log(realDataSeries)
const curCode = data.map((item: any) => item.prop)
console.log(curCode, 'curCode')
for (let i = selectList.value.length - 1; i >= 0; i--) {
if (!curCode.includes(selectList.value[i])) {
selectList.value.splice(i, 1)
@ -488,11 +484,17 @@ const saveChart = () => {
// })
// createTimer()
// }
const getCurveColor = () => {
colorList = props.curveColorList && props.curveColorList.length ? JSON.parse(JSON.stringify(props.curveColorList)) : colorList
}
defineExpose({
saveChart,
// continueChart,
})
onMounted(() => {
getCurveColor()
if (selectList.value.length > 0) {
createTimer()
}
@ -510,6 +512,8 @@ watch(
clearTimer()
chartInstance && chartInstance.clear()
selectList.value = []
} else {
getCurveColor()
}
}
)

View File

@ -15,6 +15,10 @@
<el-select v-model="subSystemVal" placeholder="请选择子系统" @change="search">
<el-option v-for="item in subSystemList" :key="item.value" :value="item.value" :label="item.label"></el-option>
</el-select>
<div class="colTitleSwitch">
<span>仅显示高频数据</span>
<el-switch v-model="highSpeed" :active-value="1" :inactive-value="0" @change="switchChange"></el-switch>
</div>
<!-- <span class="transferTitle">可添加的测点</span>
<el-radio-group v-model="radioActiveName" @change="typeChange">
<el-radio :value="138">模拟量</el-radio>
@ -124,6 +128,10 @@ const getAllSubSystem = () => {
})
}
const highSpeed = ref(0)
const switchChange = ()=>{
getTableData()
}
const attributeTableData = ref<{ attributeName: string; attributeCode: string }[]>([])
const selectTable = (section: any, row: any) => {
const hasSelect = section.find((item: any) => item.attributeCode === row.attributeCode)
@ -202,6 +210,7 @@ const getTableData = (customData = {}) => {
getModelAttributeListReq({
iotModelId: props.iotModelId,
// attributeType: radioActiveName.value,
highSpeed:highSpeed.value,
pageNum: pageSetting.current,
pageSize: pageSetting.pageSize,
subSystem: !subSystemVal.value || subSystemVal.value === ' ' ? null : subSystemVal.value,
@ -264,6 +273,7 @@ onMounted(() => {
width: 100%;
height: 100%;
.transferHeader {
position: relative;
height: 40px;
display: flex;
// justify-content: space-between;
@ -292,6 +302,17 @@ onMounted(() => {
:deep(.el-input__wrapper) {
width: 200px;
}
.colTitleSwitch {
position: absolute;
top: -40px;
right: 13px;
display: flex;
align-items: center;
height: 40px;
.el-switch{
margin-left: 5px;
}
}
}
.transferHeaderRight {
justify-content: space-between;

View File

@ -20,9 +20,10 @@ export const getRealTimeState = (data: any) => {
}
}
export const getCutDecimalsValue = (data: number, num = 3) => {
export const getCutDecimalsValue = (data: number, num = 2, padDecimal = false) => {
const n = Math.pow(10, num)
return data === 0 ? 0 : data ? (data % 1 === 0 ? data : Math.floor(data * n) / n) : '-'
const result = data === 0 ? 0 : data ? (data % 1 === 0 ? data : Math.floor(data * n) / n) : '-'
return result === '-' ? result : padDecimal ? result.toFixed(num) : result
}
export const getEnumToValue = (key: string, value: any) => {

View File

@ -87,6 +87,15 @@
<el-input v-model="pointDialogSearchData.inputValue" clearable @keyup.enter="pointDialogSearch"></el-input>
<el-button type="primary" @click="pointDialogSearch">查询</el-button>
</div>
<div class="pointDialogColTitleSwitch">
<span>仅显示高频数据</span>
<el-switch
v-model="pointDialogSearchData.highSpeed"
:active-value="1"
:inactive-value="0"
@change="pointDialogSwitchChange"
></el-switch>
</div>
<div class="pointDialogColTitleRightPart">
<el-radio-group v-model="pointDialogSearchData.type" @change="pointDialogRaidoChange">
<el-radio :value="138" label="模拟量"></el-radio>
@ -112,21 +121,33 @@
<el-table-column label="平均值" prop="average" width="70">
<template #default="scope">
<div class="showValueType">
<el-checkbox @change="autoSelectRow(scope, 'average')" v-model="scope.row.average"></el-checkbox>
<el-checkbox
:disabled="searchData.interval === 'NONE'"
@change="autoSelectRow(scope, 'average')"
v-model="scope.row.average"
></el-checkbox>
</div>
</template>
</el-table-column>
<el-table-column label="最大值" prop="max" width="70">
<template #default="scope">
<div class="showValueType">
<el-checkbox @change="autoSelectRow(scope, 'max')" v-model="scope.row.max"></el-checkbox>
<el-checkbox
:disabled="searchData.interval === 'NONE'"
@change="autoSelectRow(scope, 'max')"
v-model="scope.row.max"
></el-checkbox>
</div>
</template>
</el-table-column>
<el-table-column label="最小值" prop="min" width="70">
<template #default="scope">
<div class="showValueType">
<el-checkbox @change="autoSelectRow(scope, 'min')" v-model="scope.row.min"></el-checkbox>
<el-checkbox
:disabled="searchData.interval === 'NONE'"
@change="autoSelectRow(scope, 'min')"
v-model="scope.row.min"
></el-checkbox>
</div>
</template>
</el-table-column>
@ -328,13 +349,23 @@ const openMeasure = () => {
const attrList = item.prop.split('--')
const type = attrList[1] as 'interpolation' | 'average' | 'max' | 'min'
const rowIndex = pointDialogTableData.value.findIndex((r) => r.attributeCode === attrList[0])!
if (rowIndex > -1) {
pointDialogTableData.value[rowIndex][type] = true
}
})
pointDialogVisible.value = true
}
const searchLoading = ref(false)
const getData = () => {
if (!submitParams.column.length) {
ElMessage.warning('请选择测点')
return
}
if (!searchData.time) {
ElMessage.warning('请选择时间')
return
}
searchLoading.value = true
getRealValueRange()
}
@ -425,8 +456,8 @@ const getRealValueRange = () => {
calFunction: 'min',
})
}
const reqPromise = Promise.all(reqList)
reqPromise.then((res) => {
Promise.all(reqList)
.then((res) => {
const [interpolationRes, averageRes, maxRes, minRes] = res
const tableDataList: any = []
if (interpolationRes && interpolationRes.code === 200) {
@ -436,11 +467,18 @@ const getRealValueRange = () => {
device[attr].times.forEach((t: number, index: number) => {
const attrNameKey = attr + '--interpolation'
const val = getCutDecimalsValue(device[attr].values[index], 2)
const tableDataIndex = tableDataList.findIndex(
(data: any) => data.name == deviceNameData[deviceId] && data.time == dayjs(t).format(timeIntervalFormat.value)
)
if (tableDataIndex > -1) {
tableDataList[tableDataIndex][attrNameKey] = val
} else {
tableDataList.push({
name: deviceNameData[deviceId],
time: dayjs(t).format('YYYY-MM-DD HH:mm:ss'),
time: dayjs(t).format(timeIntervalFormat.value),
[attrNameKey]: val,
})
}
})
})
})
@ -453,9 +491,17 @@ const getRealValueRange = () => {
const attrNameKey = attr + '--average'
const val = getCutDecimalsValue(device[attr].values[index], 2)
const tableDataIndex = tableDataList.findIndex(
(data: any) => data.name == deviceNameData[deviceId] && data.time == dayjs(t).format('YYYY-MM-DD HH:mm:ss')
(data: any) => data.name == deviceNameData[deviceId] && data.time == dayjs(t).format(timeIntervalFormat.value)
)
if (tableDataIndex > -1) {
tableDataList[tableDataIndex][attrNameKey] = val
} else {
tableDataList.push({
name: deviceNameData[deviceId],
time: dayjs(t).format(timeIntervalFormat.value),
[attrNameKey]: val,
})
}
})
})
})
@ -468,9 +514,17 @@ const getRealValueRange = () => {
const attrNameKey = attr + '--max'
const val = getCutDecimalsValue(device[attr].values[index], 2)
const tableDataIndex = tableDataList.findIndex(
(data: any) => data.name == deviceNameData[deviceId] && data.time == dayjs(t).format('YYYY-MM-DD HH:mm:ss')
(data: any) => data.name == deviceNameData[deviceId] && data.time == dayjs(t).format(timeIntervalFormat.value)
)
if (tableDataIndex > -1) {
tableDataList[tableDataIndex][attrNameKey] = val
} else {
tableDataList.push({
name: deviceNameData[deviceId],
time: dayjs(t).format(timeIntervalFormat.value),
[attrNameKey]: val,
})
}
})
})
})
@ -483,9 +537,17 @@ const getRealValueRange = () => {
const attrNameKey = attr + '--min'
const val = getCutDecimalsValue(device[attr].values[index], 2)
const tableDataIndex = tableDataList.findIndex(
(data: any) => data.name == deviceNameData[deviceId] && data.time == dayjs(t).format('YYYY-MM-DD HH:mm:ss')
(data: any) => data.name == deviceNameData[deviceId] && data.time == dayjs(t).format(timeIntervalFormat.value)
)
if (tableDataIndex > -1) {
tableDataList[tableDataIndex][attrNameKey] = val
} else {
tableDataList.push({
name: deviceNameData[deviceId],
time: dayjs(t).format(timeIntervalFormat.value),
[attrNameKey]: val,
})
}
})
})
})
@ -496,6 +558,14 @@ const getRealValueRange = () => {
triggerTableRefresh.value = !triggerTableRefresh.value
searchLoading.value = false
})
.catch(function (error) {
if (error.code === 'ECONNABORTED') {
//
ElMessage.error('请求超时,请调整时间范围')
searchLoading.value = false
}
})
}
const addTemplate = () => {
@ -531,7 +601,9 @@ const searchData = reactive({
interval: '5m',
template: '',
})
const timeIntervalFormat = computed(() => {
return searchData.interval === 'NONE' ? 'YYYY-MM-DD HH:mm:ss.SSS' : 'YYYY-MM-DD HH:mm:ss'
})
const getTemplateList = () => {
getTemplateListReq({
category: '历史数据',
@ -609,10 +681,12 @@ const pointDialogSearchData = reactive<{
inputValue: string
type: 138 | 199
modelId: string
highSpeed: 0 | 1
}>({
inputValue: '',
type: 138,
modelId: '',
highSpeed: 0,
})
const pointDialogSearch = () => {
@ -624,14 +698,19 @@ const pointDialogRaidoChange = () => {
getModelAttributeList()
}
const pointDialogSwitchChange = () => {
if (!pointDialogVisible.value) return
getModelAttributeList()
}
const pointDialogTableRef = ref<TableInstance>()
const pointDialogTableData = ref<selectData[]>([])
const selectRowList = ref<selectData[]>([])
const autoSelectRow = (scope: any, type: 'interpolation' | 'average' | 'max' | 'min') => {
const state = scope.row[type]
if (state) {
const exist = selectRowList.value.find((item) => item.id === scope.row.id)
if (state) {
if (!exist) {
selectRowList.value.push(scope.row)
} else {
@ -639,6 +718,9 @@ const autoSelectRow = (scope: any, type: 'interpolation' | 'average' | 'max' | '
}
getAddColumn()
} else {
if (exist) {
exist[type] = state
}
const index = multipleSelection.value.findIndex((item) => {
const attrList = item.prop.split('--')
return attrList[0] === scope.row.attributeCode && attrList[1] === type
@ -667,6 +749,7 @@ const getModelAttributeList = () => {
iotModelId: pointDialogSearchData.modelId,
attributeName: pointDialogSearchData.inputValue,
attributeType: pointDialogSearchData.type,
highSpeed: pointDialogSearchData.highSpeed,
pageNum: pointDialogPageSetting.current,
pageSize: pointDialogPageSetting.pageSize,
}
@ -692,6 +775,7 @@ const getModelAttributeList = () => {
id: item.id!,
attributeName: item.attributeName,
attributeCode: item.attributeCode,
highSpeed: item.highSpeed as 0 | 1,
...compareData,
}
})
@ -707,13 +791,14 @@ const getcurrentPageForPointDialog = () => {
}
const getAddColumn = () => {
const dynamicColumn: { label: string; prop: string; id: string }[] = []
const dynamicColumn: { label: string; prop: string; id: string; highSpeed: 0 | 1 }[] = []
for (let item of selectRowList.value) {
if (item.interpolation) {
dynamicColumn.push({
label: item.attributeName,
prop: item.attributeCode + '--interpolation',
id: item.id,
highSpeed: item.highSpeed,
})
}
if (item.average) {
@ -721,6 +806,7 @@ const getAddColumn = () => {
label: item.attributeName + '-平均值',
prop: item.attributeCode + '--average',
id: item.id,
highSpeed: item.highSpeed,
})
}
if (item.max) {
@ -728,6 +814,7 @@ const getAddColumn = () => {
label: item.attributeName + '-最大值',
prop: item.attributeCode + '--max',
id: item.id,
highSpeed: item.highSpeed,
})
}
if (item.min) {
@ -735,6 +822,7 @@ const getAddColumn = () => {
label: item.attributeName + '-最小值',
prop: item.attributeCode + '--min',
id: item.id,
highSpeed: item.highSpeed,
})
}
}
@ -749,7 +837,7 @@ const submitParams: {
windBlowerList: [],
}
const multipleSelection = ref<{ label: string; prop: string; id: string }[]>([])
const multipleSelection = ref<{ label: string; prop: string; id: string; highSpeed: 0 | 1 }[]>([])
const moveUp = (index: number) => {
const temp = multipleSelection.value[index]
multipleSelection.value[index] = multipleSelection.value[index - 1]
@ -814,28 +902,63 @@ const cancelPointDialog = () => {
pointDialogVisible.value = false
}
const exportExcel = () => {
const title = tableColumn.value.map((item: any) => item.label).join('\t,') + '\n'
const titleKeyArr = tableColumn.value.map((item: any) => item.prop)
if (!allTableData.length) {
ElMessage.error('请查询后导出')
return
}
let highSpeedTitle = ''
let title = ''
const highSpeedColumnArr: string[] = []
const columnArr: string[] = []
tableColumn.value.forEach((item: any, index: number) => {
if (index > 1) {
if (item.highSpeed === 1) {
highSpeedTitle += item.label + '\t,'
highSpeedColumnArr.push(item.prop)
} else {
title += item.label + '\t,'
columnArr.push(item.prop)
}
} else {
highSpeedTitle += item.label + '\t,'
highSpeedColumnArr.push(item.prop)
title += item.label + '\t,'
columnArr.push(item.prop)
}
})
function downloadData(column: string[], title: string, highSpeed = '') {
let str = ''
allTableData.forEach((item: any) => {
titleKeyArr.forEach((prop: any) => {
const val = typeof item[prop] === 'string' ? item[prop] : item[prop] ? String(item[prop]) : ''
column.forEach((prop: any) => {
const val = typeof item[prop] === 'number' ? String(item[prop]) : item[prop] ? item[prop] : ''
str += val + '\t' + ','
})
str += '\n'
})
str = title + str
str = title + '\n' + str
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str)
let link = document.createElement('a')
link.href = uri
link.download = '历史数据' + searchData.time[0] + '-' + searchData.time[1] + '.csv'
link.download = highSpeed + '历史数据' + searchData.time[0] + '-' + searchData.time[1] + '.csv'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
downloadData(columnArr, title)
downloadData(highSpeedColumnArr, highSpeedTitle, '高频')
}
const selectToTable = () => {
selectRowList.value.forEach((item: selectData) => {
const row = pointDialogTableData.value.find((row) => row.id === item.id)
if (row) {
row.interpolation = item.interpolation
row.average = item.average
row.max = item.max
row.min = item.min
}
})
}
</script>
<style scoped lang="scss">
@ -951,6 +1074,14 @@ const exportExcel = () => {
margin-left: 10px;
}
}
.pointDialogColTitleSwitch {
display: flex;
align-items: center;
margin-left: 20px;
.el-switch {
margin-left: 5px;
}
}
.pointDialogColTitleRightPart {
margin-left: auto;
width: 170px;

View File

@ -3,6 +3,7 @@ export type selectData =
id: string
attributeName: string
attributeCode: string
highSpeed: 0 | 1
interpolation: boolean
average: boolean
max: boolean

View File

@ -41,11 +41,13 @@
</template>
</Container>
<el-dialog v-model="showCorrelationPoint" title="关联测点" @close="closecorrectionDevice">
<el-row>
<el-col :span="12">
<el-button @click="addCorrectionDevice" class="btnStyle">添加设备</el-button>
<el-row class="operateRow">
<el-col :span="12" class="colStyle">
<h3>设备选择</h3>
<!-- <el-button @click="addCorrectionDevice" class="btnStyle">添加设备</el-button> -->
</el-col>
<el-col :span="12">
<el-col :span="12" class="colStyle">
<h3>已选择列表</h3>
<el-popconfirm @confirm="clearCorrectionDevice" title="确认清空么?">
<template #reference>
<el-button class="btnStyle">清空</el-button>
@ -64,12 +66,20 @@
lazy
:load="loadDeviceTreeData"
show-checkbox
@check="checkDevice"
></el-tree>
</div>
</el-col>
<el-col :span="12">
<div class="treeMain">
<el-tree :data="correctionDevice" :props="repalceDeviceTreeKey" node-key="id" draggable :allow-drop="dropJudge">
<el-tree
:data="correctionDevice"
:props="repalceDeviceTreeKey"
node-key="id"
draggable
:allow-drop="dropJudge"
ref="correctionDeviceRef"
>
<template #default="{ node, data }">
<div class="correctionTreeItem">
<span>{{ correctionDevice.findIndex((item) => item === data) + 1 + '、' + data.name }}</span>
@ -310,28 +320,42 @@ const loadDeviceTreeData = (node: any, resolve: any) => {
})
}
const checkDevice = (data: any, node: any) => {
const { checkedKeys, checkedNodes } = node
const existKeys = correctionDevice.value.map((item) => item.id)
const addList: any = checkedNodes.filter((item: any) => !item.isType && !existKeys.includes(item.id))
for (let i = correctionDevice.value.length - 1; i >= 0; i--) {
if (!correctionDevice.value[i].isType && !checkedKeys.includes(correctionDevice.value[i].id)) {
correctionDevice.value.splice(i, 1)
}
}
correctionDevice.value = [...correctionDevice.value, ...addList]
}
const correctionDeviceRef = ref()
const correctionDevice = ref<any[]>([])
const addCorrectionDevice = () => {
const nodeList = deviceTreeRef.value!.getCheckedNodes()
// const addCorrectionDevice = () => {
// const nodeList = deviceTreeRef.value!.getCheckedNodes()
const data: any = []
nodeList.forEach((item) => {
if (!item.isType) {
const exist = correctionDevice.value.find((Correction) => Correction.id == item.id)
if (!exist) {
data.push(item)
}
}
})
correctionDevice.value = [...correctionDevice.value, ...data]
}
// const data: any = []
// nodeList.forEach((item) => {
// if (!item.isType) {
// const exist = correctionDevice.value.find((Correction) => Correction.id == item.id)
// if (!exist) {
// data.push(item)
// }
// }
// })
// correctionDevice.value = [...correctionDevice.value, ...data]
// }
const clearCorrectionDevice = () => {
correctionDevice.value = []
deviceTreeRef.value?.setCheckedKeys([],false)
}
const delCorrectionDevice = (node: any) => {
deviceTreeRef.value!.remove(node)
correctionDeviceRef.value!.remove(node)
deviceTreeRef.value?.setChecked(node.data.id, false, false)
}
const editAttr = (data: any) => {
@ -386,7 +410,9 @@ const saveExcelData = () => {
const getBindDeviceTree = () => {
getBindDeviceTreeReq({ linkId: route.query.id as any }).then((res) => {
if (res.data) {
correctionDevice.value = res.data.map((item: any) => {
const keys: string[] = []
const data = res.data.map((item: any) => {
keys.push(item.id)
return {
id: item.id,
name: item.name,
@ -394,6 +420,8 @@ const getBindDeviceTree = () => {
iotModelId: item.iotModelId,
}
})
deviceTreeRef.value?.setCheckedKeys(keys)
correctionDevice.value = data
}
})
}
@ -420,14 +448,16 @@ const getMappingList = () => {
const saveMappingList = (data: any[]) => {
hasLoading.value = true
saveMappingListReq(data).then((res) => {
saveMappingListReq(data)
.then((res) => {
if (res.success) {
ElMessage.success('保存成功!')
resetExcel()
} else {
ElMessage.warning(res.msg ?? '保存失败!')
}
}).catch(()=>{
})
.catch(() => {
ElMessage.error('保存失败!')
})
}
@ -541,9 +571,19 @@ onBeforeUnmount(() => {
}
}
}
.operateRow {
width: 100%;
height: 40px;
border-bottom: 1px solid #ccc;
.colStyle {
display: flex;
justify-content: space-between;
align-items: center;
}
.btnStyle {
margin-bottom: 10px;
}
}
.header {
display: flex;
justify-content: space-between;