map/ui/dasadmin/src/views/backend/equipment/airBlower/index.vue
高云鹏 14e00ae08f 历史数据:新增页面
实时数据:添加本地测点缓存
2025-01-13 17:45:55 +08:00

985 lines
36 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="airBlower">
<el-container class="containerPart">
<el-header class="headerPart">
<div class="headerLeft">
<div class="selectPart">
<span>{{ t('airBlower.status') }}</span>
<el-select
v-model="airBlowerSelect.processedoperationmode"
@change="selectAirBlower('processedoperationmode')"
:placeholder="'请选择' + t('airBlower.status')"
class="airBlowerSelect"
>
<el-option
v-for="v in airBlowerSelectOptions.processedoperationmode"
:key="v.value"
:label="v.label"
:value="v.value"
></el-option>
</el-select>
</div>
<div class="selectPart">
<span>{{ t('airBlower.feeder') }}</span>
<el-select
v-model="airBlowerSelect.belongLine"
@change="selectAirBlower('belongLine')"
:placeholder="'请选择' + t('airBlower.feeder')"
class="airBlowerSelect"
>
<el-option v-for="v in airBlowerSelectOptions.belongLine" :key="v.value" :label="v.value" :value="v.value"></el-option>
</el-select>
</div>
<div class="selectPart">
<span>自动更新:</span>
<el-switch
v-model="autoUpdate"
class="ml-2"
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
></el-switch>
</div>
</div>
<div class="headerCenter">
<el-button type="primary" :icon="Crop" class="defaultBtn" @click="openMeasure">测点选择</el-button>
<el-button style="color: rgb(0, 100, 170)" :icon="Download" class="defaultBtn" @click="downFun">数据导出</el-button>
</div>
<div class="headerRight" v-permission="[104]">
<el-popconfirm title="确认启动么?" @confirm="airBlowerOperate('setTurbineFastStart')">
<template #reference>
<el-button type="primary">{{ t('airBlower.start') }}</el-button>
</template>
</el-popconfirm>
<el-popconfirm title="确认停机么?" @confirm="airBlowerOperate('setTurbineStop')">
<template #reference>
<el-button style="color: #0064aa">{{ t('airBlower.stop') }}</el-button>
</template>
</el-popconfirm>
<el-popconfirm title="确认复位么?" @confirm="airBlowerOperate('setTurbineResetStatusCode')">
<template #reference>
<el-button style="color: #0064aa">{{ t('airBlower.reset') }}</el-button>
</template>
</el-popconfirm>
<!-- <el-popconfirm title="确认风机对时么?">
<template #reference>
<el-button style="color: #0064aa">{{ t('airBlower.verify') }}</el-button>
</template>
</el-popconfirm> -->
</div>
</el-header>
<el-main class="mainPart">
<el-table
ref="tableRef"
:column="tableColumn"
:data="tableData"
:header-row-style="tableHaderStyle"
@selectionChange="selectTable"
class="tableClass"
>
<el-table-column type="selection" width="55"></el-table-column>
<template v-for="item in tableColumn" :key="item.prop">
<el-table-column
v-if="!item.custom"
:prop="item.prop"
:label="item.label"
:align="item.align"
:width="item.width"
:type="item.type"
/>
<el-table-column v-else :label="item.label" :align="item.align" :width="item.width">
<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
>
</div>
<div v-if="item.prop === 'chart'" @click="openLineChart(scope.row)" class="operate">
<div class="chartIcon">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon"
width="100%"
height="100%"
viewBox="0 0 1024 1024"
version="1.1"
>
{{ scope.row }}
<path
d="M896 896H96a32 32 0 0 1-32-32V224a32 32 0 0 1 64 0v608h768a32 32 0 1 1 0 64zM247.008 640a32 32 0 0 1-20.992-56.192l200.992-174.24a32 32 0 0 1 42.272 0.288l172.128 153.44 229.088-246.304a32 32 0 0 1 46.88 43.616l-250.432 269.216a31.936 31.936 0 0 1-44.704 2.08l-174.56-155.52-179.744 155.84a31.872 31.872 0 0 1-20.928 7.776z"
fill="#00a4ff"
/>
</svg>
</div>
</div>
</template>
<template v-if="item.custom === 'header'" #header="scope">
<div>{{ scope.column.label.split(' ')[0] }}</div>
<div>{{ scope.column.label.split(' ')[1] }}</div>
</template>
<template v-if="item.custom === 'header'" #default="scope">
<div>{{ scope.row[item.prop] }}</div>
</template>
<template v-if="item.prop === 'name'" #default="scope">
<div class="tableColumnClick" @click="openWindTurbine(scope.row)">{{ scope.row[item.prop] }}</div>
</template>
</el-table-column>
</template>
</el-table>
</el-main>
</el-container>
<el-dialog v-model="multiTaskVisible" :title="mutiTaskTitle" width="400" :close-on-click-modal="false">
<el-row v-for="item in mutiTaskList" :key="item.sendData.deviceId">
<el-col :span="18">
<div class="mutiTaskName">
{{ item.deviceName }}
</div>
</el-col>
<el-col :span="6">
<div class="mutiTaskStatus">
<el-icon style="color: #f56c6c" size="30" v-if="item.loading === 3">
<CircleClose />
</el-icon>
<el-icon style="color: #06b429" size="30" v-if="item.loading === 2">
<CircleCheck />
</el-icon>
<el-icon style="color: #4fa5ff" size="30" class="mutiTaskLoading" v-if="item.loading === 1">
<Loading />
</el-icon>
<div v-if="item.loading === 0">等待发送</div>
</div>
</el-col>
</el-row>
</el-dialog>
<el-dialog v-model="selectPointVisible" title="选择测点" width="1000">
<SelectPoint
ref="selectPointDialogRef"
:defaultAttr="defaultAttr"
:visible="selectPointVisible"
:iot-model-id="selectPointModelId"
></SelectPoint>
<template #footer>
<div class="selectPointDialogFooter">
<el-button type="primary" @click="saveSelectPoint">保存</el-button>
<el-button @click="selectPointVisible = false">取消</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="realDataLineChartVisible" title="实时曲线" @close="closeLineChart" width="1200">
<!-- <RealDataChart
ref="realDataChartRef"
:visible="realDataLineChartVisible"
:id="clickRow!.irn"
:iot-model-id="selectPointModelId"
@clearChart="() => (linePause = false)"
></RealDataChart> -->
<RealDataChart
ref="realDataChartRef"
:visible="realDataLineChartVisible"
:id="clickRow!.irn"
:iot-model-id="selectPointModelId"
></RealDataChart>
<template #header>
<div>
<span style="font-size: 18px">实时曲线</span>
<el-button class="saveBtn" @click="saveLineChart" type="primary" plain>保存</el-button>
<!-- <el-button v-if="linePause" class="continueBtn" @click="continueLineChart" type="primary" plain>继续</el-button> -->
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { SelectTypeObjType, SelectTypeKeyUnionType, TableDataObjType, TableColumnType } from './type'
import { onUnmounted, reactive, ref, watch, computed, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import { getAirBlowerListReq, getBelongLineListReq } from '/@/api/backend/airBlower/request'
import { CircleCheck, CircleClose, Loading, Crop, Download } from '@element-plus/icons-vue'
import { ElMessage, TableInstance, ElPopconfirm } from 'element-plus'
import { useRouter, useRoute } from 'vue-router'
import { getRealTimeState, getCutDecimalsValue, getEnumToValue } from './utils'
import { sendCommandReq } from '/@/api/backend/control/request'
import { adminBaseRoutePath } from '/@/router/static/adminBase'
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'
const vPermission = permission()
const router = useRouter()
const { t } = useI18n()
const airBlowerSelect = reactive<SelectTypeObjType>({
processedoperationmode: 987654321,
belongLine: '全部',
})
const airBlowerSelectOptions = reactive<{ [K in SelectTypeKeyUnionType]: { label: string; value: string | number }[] }>({
processedoperationmode: [
{
label: '全部',
value: 987654321,
},
{
label: '并网',
value: 20,
},
{
label: '待机',
value: 11,
},
{
label: '启动',
value: 16,
},
{
label: '维护',
value: 10,
},
{
label: '离线',
value: 0,
},
{
label: '限功率运行',
value: 8,
},
{
label: '正常停机',
value: 6,
},
{
label: '外部因素导致停机',
value: 1,
},
{
label: '停机',
value: 2,
},
{
label: '通讯中断',
value: 33,
},
{
label: '解缆状态',
value: 1110,
},
{
label: '电网故障停机',
value: 1111,
},
{
label: '安全链停机',
value: 1112,
},
],
belongLine: [],
})
const selectAirBlower = (type: SelectTypeKeyUnionType) => {
if (airBlowerSelect.belongLine === '全部' && airBlowerSelect.processedoperationmode === 987654321) {
tableData.value = originTableData.value
return
} else if (airBlowerSelect.belongLine !== '全部' && airBlowerSelect.processedoperationmode !== 987654321) {
if (type === 'processedoperationmode' && airBlowerSelect.processedoperationmode === 2) {
const type1 = originTableData.value.filter((item) => item.processedoperationmode === 1)
const type6 = originTableData.value.filter((item) => item.processedoperationmode === 6)
const type2 = originTableData.value.filter((item) => item.processedoperationmode === 2)
const typeAll = [...type1, ...type6, ...type2]
tableData.value = typeAll.filter((item) => item.belongLine === airBlowerSelect.belongLine)
return
}
const resData = originTableData.value.filter((item) => item.processedoperationmode === airBlowerSelect.processedoperationmode)
tableData.value = resData.filter((item) => item.belongLine === airBlowerSelect.belongLine)
return
} else {
if (type === 'belongLine' && airBlowerSelect.belongLine === '全部') {
tableData.value = originTableData.value.filter((item) => item.processedoperationmode === airBlowerSelect.processedoperationmode)
return
} else if (type === 'processedoperationmode' && airBlowerSelect.processedoperationmode === 987654321) {
tableData.value = originTableData.value.filter((item) => item.belongLine === airBlowerSelect.belongLine)
return
}
if (type === 'processedoperationmode' && airBlowerSelect.processedoperationmode === 2) {
const type1 = originTableData.value.filter((item) => item.processedoperationmode === 1)
const type6 = originTableData.value.filter((item) => item.processedoperationmode === 6)
const type2 = originTableData.value.filter((item) => item.processedoperationmode === 2)
tableData.value = [...type1, ...type6, ...type2]
return
}
tableData.value = originTableData.value.filter((item) => item[type] === airBlowerSelect[type])
return
}
}
const airBlowerOperate = async (type: 'setTurbineFastStart' | 'setTurbineStop' | 'setTurbineResetStatusCode') => {
const sendTypeEnum = {
setTurbineFastStart: '风机快速启动指令',
setTurbineStop: '风机停机指令',
setTurbineResetStatusCode: '风机复位故障代码指令',
}
if (!selectList.value.length) {
ElMessage.warning('请先选择风机')
return
}
const data = selectList.value.map((item) => {
return {
sendData: {
deviceId: item,
serviceName: sendTypeEnum[type],
serviceCode: type,
optDesc: sendTypeEnum[type] + ',设定值为:' + 1,
opValue: 1 as const,
},
deviceName: tableData.value.find((listItem) => listItem.irn === item)!.name,
loading: 0 as const,
}
})
mutiTaskList.value = data
mutiTaskTitle.value = sendTypeEnum[type]
multiTaskVisible.value = true
for (let i = 0; i < mutiTaskList.value.length; i++) {
mutiTaskList.value[i].loading = 1
runTask(mutiTaskList.value[i].sendData, i)
}
}
const runTask = async (data: any, index: number) => {
try {
let resp = await sendCommandReq(data)
if (resp.success) {
mutiTaskList.value[index].loading = 2
}
} catch (error) {
mutiTaskList.value[index].loading = 3
}
}
const tableHaderStyle = {
color: '#333',
}
const defaultColumn: TableColumnType[] = [
{
label: '风机列表',
prop: 'name',
align: 'center',
custom: 'default',
width: 120,
},
{
label: '实时曲线',
prop: 'chart',
align: 'center',
custom: 'default',
width: 55,
},
{
label: '风机型号',
prop: 'model',
align: 'center',
width: 120,
},
{
label: '风机状态',
prop: 'processedoperationmode',
align: 'center',
custom: 'default',
width: 100,
},
]
let dynamicColumn: TableColumnType[] = [
{
label: '风速 (m/s)',
prop: 'iwindspeed',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '风向 (°)',
prop: 'iwinddirection',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '发电机转速 (rmp)',
prop: 'igenspeed',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '有功功率 (kW)',
prop: 'igenpower',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '有功给定 (kW)',
prop: 'iactivepowersetpointvalue',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '无功功率 (kVar)',
prop: 'ireactivepower',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '无功给定 (kVar)',
prop: 'ireactivepowersetpointvalue',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '桨叶1角度 (°)',
prop: 'ipitchangle1',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '桨叶2角度 (°)',
prop: 'ipitchangle2',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '桨叶3角度 (°)',
prop: 'ipitchangle3',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '限电原因',
prop: 'powerlimitsource',
align: 'center',
width: 100,
},
{
label: '机舱位置 (°)',
prop: 'ivanedirection',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '日发电量 (kWh)',
prop: 'ikwhthisday',
align: 'center',
custom: 'header',
width: 100,
},
{
label: '总发电量 (kWh)',
prop: 'ikwhoverall',
align: 'center',
custom: 'header',
width: 100,
},
]
const tableColumn = ref<TableColumnType[]>([...defaultColumn, ...dynamicColumn])
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)
}
}
getSaveColumn()
const tableRef = ref<TableInstance>()
const tableData = ref<TableDataObjType[]>([])
const originTableData = ref<TableDataObjType[]>([])
const createTableReqParams = (airblowerList: { irn: string; name: string }[]) => {
const curTableKey = tableColumn.value.map((item) => item.prop)
const airBlowerIds: any = []
const airBlowerInfo: any = {}
const params = airblowerList.map((item: any) => {
airBlowerInfo[item.irn] = {
name: item.name,
model: item.model,
belongLine: item.belongLine,
modelId: item.modelId,
deviceCode: item.deviceCode,
}
airBlowerIds.push(item.irn)
return {
deviceId: item.irn,
attributes: [...curTableKey, 'processedoperationmode', 'iyplevel', 'gridlostdetected', 'ibplevel'],
}
})
return { params, airBlowerInfo, airBlowerIds }
}
const getTableData = () => {
let airBlowerInfoObj: any = {}
let airBlowerIdList: any[] = []
getAirBlowerListReq()
.then((res) => {
if (res.success) {
return createTableReqParams(res.data)
} else {
throw '获取风机列表失败'
}
})
.then((data) => {
airBlowerInfoObj = data.airBlowerInfo
airBlowerIdList = data.airBlowerIds
return getRealValueListReq(data!.params)
})
.then((res) => {
if (res.success) {
const data = airBlowerIdList.map((id) => {
const realData: any = {}
Object.keys(res.data[id]).forEach((key) => {
const cutVal = getCutDecimalsValue(res.data[id][key])
realData[key] = getEnumToValue(key, cutVal)
})
const state = getRealTimeState(res.data[id])
return {
irn: id,
name: airBlowerInfoObj[id].name,
model: airBlowerInfoObj[id].model,
iotModelId: airBlowerInfoObj[id].modelId,
belongLine: airBlowerInfoObj[id].belongLine,
deviceCode: airBlowerInfoObj[id].deviceCode,
...realData,
processedoperationmode: state,
}
})
originTableData.value = data
if (airBlowerSelect.belongLine === '全部' && airBlowerSelect.processedoperationmode === 987654321) {
tableData.value = data
} else {
const irn = tableData.value.map((item) => item.irn)
const result: TableDataObjType[] = []
data.forEach((item: TableDataObjType) => {
if (irn.includes(item.irn)) {
result.push(item)
}
})
tableData.value = result
}
if (selectList.value.length) {
const selected = tableData.value.filter((item) => selectList.value.includes(item.irn))
selected.forEach((item) => {
nextTick(() => {
tableRef.value?.toggleRowSelection(item, true)
})
})
}
} else {
throw '获取风机列表失败'
}
})
.catch((err) => {
// ElMessage.error(err)
})
}
const getBlongLineList = () => {
getBelongLineListReq()
.then((res) => {
const data = res.data.map((item: any) => {
return {
value: item,
}
})
airBlowerSelectOptions.belongLine = [{ value: '全部', label: '全部' }, ...data]
})
.catch((err) => {
console.log(err)
})
}
const selectList = ref<string[]>([])
const selectTable = (selected: TableDataObjType[]) => {
selectList.value = selected.map((item) => item.irn)
}
const autoUpdate = ref(true)
const autoUpdateInterval = ref<any>(null)
watch(
() => autoUpdate.value,
(newVal: boolean) => {
if (newVal) {
if (autoUpdateInterval.value) return
autoUpdateInterval.value = setInterval(() => {
getTableData()
}, 2000)
} else {
clearInterval(autoUpdateInterval.value)
autoUpdateInterval.value = null
}
},
{
immediate: true,
}
)
const openWindTurbine = (row: TableDataObjType) => {
if (!router.hasRoute('windTurbine')) {
router.addRoute('admin', {
path: adminBaseRoutePath + '/windTurbine',
name: 'windTurbine',
component: () => import('/@/views/backend/WindBlower/index.vue'),
meta: {
title: 'WindBlower',
menuDesc: '单风机详情',
addtab: true,
},
})
}
router.push({
name: 'windTurbine',
query: {
irn: row.irn,
iotModelId: row.iotModelId,
deviceCode: row.deviceCode,
model: row.model,
name: row.name,
},
})
}
const multiTaskVisible = ref(false)
const mutiTaskTitle = ref('')
const mutiTaskList = ref<
{
loading: 0 | 1 | 2 | 3
deviceName: string
sendData: {
deviceId: string
serviceName: string
serviceCode: string
optDesc: string
opValue: 1
}
}[]
>([])
const selectPointDialogRef = ref()
const selectPointVisible = ref(false)
const defaultAttr = computed(() => {
return dynamicColumn.map((item) => {
tableColumn.value.length
return {
attributeName: item.label.split(' ')[0],
unit:item.label.split(' ')[1] ?? '',
attributeCode: item.prop as string,
}
})
})
const selectPointModelId = computed(() => {
return tableData.value[0]?.iotModelId ?? ''
})
const openMeasure = () => {
selectPointVisible.value = true
}
const saveSelectPoint = () => {
const list = selectPointDialogRef.value?.getSelectList()
if (list) {
const addCoulmn = list.map((item: any) => {
return {
label: item.unit ? item.attributeName + item.unit : item.attributeName,
prop: item.attributeCode.toLowerCase(),
align: 'center',
custom: item.unit ? 'header' : undefined,
width: 100,
}
})
tableColumn.value = [...defaultColumn, ...addCoulmn]
localStorage.setItem('airBlowerTableColumnList', JSON.stringify(tableColumn.value))
getTableData()
selectPointVisible.value = false
ElMessage.success('选择成功')
}
}
const downFun = () => {
// const itemsWithoutAge = tableData.value.map((item) => {
// const { irn, ...rest } = item
// return rest
// })
// if (!tableColumn.value.length || !itemsWithoutAge.length) {
// return []
// }
// const columnSet = new Set(tableColumn.value.map((item) => item.prop))
// const result: any = []
// itemsWithoutAge.forEach((item) => {
// const newItem: any = {}
// for (const itemKey in item) {
// if (columnSet.has(itemKey)) {
// newItem[itemKey] = item[itemKey]
// }
// }
// if (Object.keys(newItem).length > 0) {
// result.push(newItem)
// }
// })
// let addobj: any = {}
// tableColumn.value.map((v, i) => {
// addobj['rowData' + i] = v.label
// })
// let tableDatadown = JSON.parse(JSON.stringify(result))
// tableDatadown.unshift(addobj)
// console.log(tableDatadown)
// debugger
// let str = ``
// for (let i = 0; i < tableDatadown.length; i++) {
// for (let item in tableDatadown[i]) {
// if (typeof tableDatadown[i][item] === 'string') {
// tableDatadown[i][item] = tableDatadown[i][item].replace(/[\n,]/g, (match: any) => (match === '\n' ? ' ' : ''))
// } else {
// console.warn(`tableDatadown[${i}][${item}] is not a string`)
// }
// str += `${tableDatadown[i][item] + '\t'},`
// }
// str += '\n'
// }
const title = tableColumn.value.map((item: any) => item.label).join('\t,') + '\n'
const titleKeyArr = tableColumn.value.map((item: any) => item.prop)
let str = ''
tableData.value.forEach((item) => {
titleKeyArr.forEach((prop: any) => {
const val = typeof item[prop] === 'string' ? item[prop] : item[prop] ? String(item[prop]) : ''
str += val + '\t' + ','
})
str += '\n'
})
str = title + str
let uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str)
let link = document.createElement('a')
link.href = uri
link.download = '实时数据' + Date.now() + '.csv'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
const realDataChartRef = ref()
const clickRow = ref<TableDataObjType>()
const realDataLineChartVisible = ref(false)
const openLineChart = (row: TableDataObjType) => {
clickRow.value = row
realDataLineChartVisible.value = true
autoUpdate.value = false
// linePause.value = false
}
const closeLineChart = () => {
autoUpdate.value = true
}
// const linePause = ref(false)
const saveLineChart = () => {
const data = realDataChartRef.value?.saveChart()
// linePause.value = true
const info = 'deviceCode:' + clickRow.value?.deviceCode + '\n' + 'deviceName:' + clickRow.value?.name + '\n'
let title = 'TimeStamp;'
let columns = ''
data.time.forEach((item: any, index: number) => {
columns += item
data.chartData.forEach((item: any) => {
if (index === 0) {
title += `${item.id};`
}
const val = item.data[index]
columns += `;${val}`
})
columns += '\n'
})
let str = info + title + '\n' + columns
let uri = 'data:text/plain;charset=utf-8,' + encodeURIComponent(str)
let link = document.createElement('a')
link.href = uri
const titleTime = data.time[0] + '-' + data.time[data.time.length - 1]
link.download = 'deviceCode' + clickRow.value?.deviceCode + ';' + titleTime + '.txt'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
// const continueLineChart = () => {
// realDataChartRef.value?.continueChart()
// linePause.value = false
// }
onUnmounted(() => {
autoUpdateInterval.value && clearInterval(autoUpdateInterval.value)
autoUpdateInterval.value = null
})
getTableData()
getBlongLineList()
</script>
<style scoped lang="scss">
.airBlower {
width: 100%;
height: 100%;
.containerPart {
width: 100%;
height: 100%;
.headerPart {
padding: 20px;
width: 100%;
height: 60px;
display: flex;
// justify-content: space-between;
align-items: center;
.headerLeft {
display: flex;
flex-shrink: 0;
.selectPart {
display: flex;
justify-content: space-between;
align-items: center;
height: 40px;
margin-right: 20px;
span {
margin-right: 10px;
}
.airBlowerSelect {
width: 200px;
:deep(.el-select__wrapper) {
height: 40px;
}
}
}
}
.headerCenter {
width: 212px;
margin-left: 30px;
flex-shrink: 0;
.el-button {
width: 100px;
height: 40px;
}
}
.headerRight {
margin-left: auto;
width: 336px;
display: flex;
justify-content: space-between;
.el-button {
width: 100px;
height: 40px;
}
}
}
.mainPart {
width: 100%;
height: calc(100% - 60px);
.tableClass {
width: 100%;
height: 100%;
}
.tableColumnClick {
text-decoration: underline;
color: #00a4ff;
cursor: pointer;
}
.operate {
display: flex;
justify-content: center;
align-items: center;
.chartIcon {
width: 16px;
height: 16px;
}
&:hover {
cursor: pointer;
}
}
}
}
}
.mutiTaskName {
width: 100%;
height: 40px;
line-height: 40px;
font-size: 16px;
}
.mutiTaskStatus {
display: flex;
align-items: center;
justify-content: right;
width: 100%;
height: 40px;
}
.mutiTaskLoading {
animation: rotate 1s linear infinite;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.selectPointDialogFooter {
text-align: center;
.el-button {
width: 120px;
height: 40px;
}
}
.saveBtn {
margin-left: 164px;
}
</style>