You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

410 lines
11 KiB

<template>
<div class="fault-rule-drawer">
<el-drawer
v-model="isShowDrawer"
:title="title"
direction="rtl"
size="90%"
modal-class="model-dev-opn"
:before-close="handleBeforeClose"
@opened="onDrawerOpened">
<main class="wh-full flex">
<EdfsWrap title="点位选择"
class="p-r-4 h-full w-340 border-r-1 border-solid border-r-#e4e7ed">
<el-select
v-if="currentGroup?.customNode"
v-model="selectValue"
placeholder="单体选择"
style="width:240px"
@change="onchangeSelect"
>
<el-option
v-for="item in currentGroup.brother"
:key="item.name"
:label="item.customCnName"
:value="item.name"
/>
</el-select>
<PointCheckbox
:pointList="pointList"
:loadingPoints="loadingPoints"
@onchange-points="onchangePoints"
ref="PointCheckboxRef"
>
</PointCheckbox>
</EdfsWrap>
<div class="flex-1 p-4 h-full overflow-hidden relative"
>
<div class="absolute w-full h-full bg-[#ffffffe5] z-99" v-if="loadingChart">
<div class="w-full h-full flex flex-col justify-center items-center">
<el-progress
style="width: 70%"
:text-inside="true"
:stroke-width="18"
:percentage="progress"
status="success"
/>
<div class="text-xl">
<div>当前加载数据量较大请稍等。。。</div>
</div>
</div>
</div>
<div class="flex w-full items-center gap-16">
<div class="w-400px">
<el-date-picker
v-model="time"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
range-separator="到"
:default-value="getBeforeMonth"
start-placeholder="开始时间"
end-placeholder="结束时间"
:disabled-date="disabledDate"
/>
</div>
<el-button type="primary" @click="loadChardData">查询数据</el-button>
</div>
<NewDataChart
v-if="isShowChart"
:chart-datas="chartData"
:legends="legends"
:axis-data="Array.from(axisData)"
ref="chartRef"/>
</div>
</main>
</el-drawer>
</div>
</template>
<script setup lang="ts">
import NewDataChart from '../../component/newDataChart.vue'
import type { IDevice, IMyPoint, IOfflineDevice, IOnlineDevice } from '../../type'
import {
getDeviceDetails,
getPoints,
type IGetDeviceDataParams,
type IPointGroupOV,
type IPointsParams,
} from '@/api/module/transfer'
import { useMessage } from '@/composables/useMessage'
import dayjs from 'dayjs'
import { nextTick } from "vue";
import EdfsWrap from "@/components/Edfs-wrap.vue";
import PointCheckbox from "@/views/stationData/component/pointCheckbox.vue";
const env = import.meta.env
const isShowDrawer = defineModel<boolean>()
const title = computed(() => (curDevice.value?.isonLine ? '数据详情' : `已迁移数据详情`))
const message = useMessage()
const PointCheckboxRef = ref<InstanceType<typeof PointCheckbox>>()
const emit = defineEmits(['on-save'])
const pointList = ref<IMyPoint[]>([])
const curDevice = ref<IDevice & { isonLine: boolean, siteName: string }>()
async function open(device: IDevice & {
isonLine: boolean,
siteName: string
}, group: IPointGroupOV) {
curDevice.value = device
currentGroup.value = group
if (
currentGroup.value.customNode &&
currentGroup.value.brother &&
currentGroup.value.brother.length
) {
selectValue.value = currentGroup.value.brother[0].name
}
PointCheckboxRef.value?.clearCheck()
await loadPoints()
.then(async () => {
await loadDeviceDetails()
})
.catch(() => {
message.error('获取点位数据失败')
fullscreenLoading.value?.close()
})
}
const selectValue = ref()
function onchangeSelect(value: string) {
PointCheckboxRef.value?.clearCheck()
}
const loadingPoints = ref(false)
const columParams = computed(() => ['ts', ...checkPointList.value.map(i => i.addr)])
const currentGroup = ref<IPointGroupOV & {
customNode?: boolean
brother?: Array<any>
}>()
async function loadPoints() {
if (!currentGroup.value) {
message.error('请先选择点位组')
return
}
const params: IPointsParams = {
type: currentGroup.value.type,
}
if (curDevice.value?.isonLine) {
const onlineDevice = curDevice.value as IOnlineDevice
params.isLocal = false
params.host = onlineDevice.clientIp
} else {
const offlineDevice = curDevice.value as IOfflineDevice
params.sn = offlineDevice.sn
params.site = curDevice.value!.siteName
params.isLocal = true
}
loadingPoints.value = true
const res = await getPoints(params)
if (res.code === 0) {
const data = Array.isArray(res?.data) ? res.data : []
pointList.value = data.map((i: any) => ({
label: i.cnName,
addr: i.addr,
unit: i.unit || '',
}))
}
loadingPoints.value = false
return res
}
async function loadDeviceDetails() {
if (!fullscreenLoading.value) {
openFullScreen()
}
chartData.clear()
axisData.clear()
legends.value = []
const pointsRes = await loadPoints()
if (!pointsRes || pointsRes.code !== 0) {
message.error('获取点位数据失败')
pointList.value = []
chartData.clear()
axisData.clear()
fullscreenLoading.value?.close()
return
}
isShowDrawer.value = true
fullscreenLoading.value?.close()
}
const chartData = reactive(new Map<string, any[]>())
const axisData = new Set<string>()
const legends = ref<{ addr: string; label: string, unit: string }[]>([])
const loadingChart = ref(false)
const chartAllTotal = ref(0)
const chartLimit = ref(1000)
const chartOffset = ref(0)
const progress = ref(0)
async function loadChardData() {
if (!time.value || time.value.length !== 2) {
message.error('请选择时间范围')
return
}
if (!currentGroup.value) return
if (!columParams.value.filter(i => i !== 'ts').length) {
message.error('请选择点位')
return
}
clearData()
const limit = chartLimit.value
const offset = chartOffset.value
const options: any = {
columns: columParams.value,
isLocal: !curDevice.value?.isonLine,
host: curDevice.value?.isonLine ? (curDevice.value as IOnlineDevice).clientIp : '',
name: currentGroup.value?.customNode ? selectValue.value : currentGroup.value?.name as string,
startTime: time.value[0],
endTime: time.value[1],
}
if (env.VITE_APP_ENV !== 'local' || !curDevice.value?.isonLine) {
options.site_id = curDevice.value!.siteName || ''
options.device_id = curDevice.value?.sn || ''
}
const params: IGetDeviceDataParams = {
...options,
limit,
offset
}
loadingChart.value = true
isShowChart.value = false
const res = await getDeviceDetails(params)
if (res.code !== 0) {
resetChartStatus()
message.error('获取设备数据失败')
return
}
chartAllTotal.value = res?.data?.total ?? 0
if (chartAllTotal.value === 0) {
resetChartStatus()
message.info('暂无数据')
return
}
const pointData = Array.isArray(res.data.results) ? res.data.results : []
setChartData(pointData)
const pageCount = Math.ceil(chartAllTotal.value / Number(limit))
if (pageCount <= 1) {
progress.value = 100
setTimeout(() => {
resetChartStatus()
})
return
}
for (let i = 1; i < pageCount; i++) {
const params: IGetDeviceDataParams = {
...options,
limit,
offset: i * Number(limit)
}
const res = await getDeviceDetails(params)
if (res.code !== 0) {
clearData()
resetChartStatus()
message.error('获取设备数据失败')
return
}
const pointData = Array.isArray(res.data.results) ? res.data.results : []
setChartData(pointData)
progress.value = Math.min(100, Math.floor(((i + 1) / pageCount) * 100))
}
resetChartStatus()
}
function setChartData(pointData: any[]) {
for (const addr of columParams.value.filter(i => i !== 'ts')) {
const label = pointList.value.find(i => i.addr === addr)?.label || addr
const find = legends.value.find(i => i.addr === addr)
const unit = pointList.value.find(i => i.addr === addr)?.unit || ''
if (!find) {
legends.value.push({ addr, label, unit })
}
}
pointData.forEach((data: any[]) => {
const [ts, val, addr] = data
if (checkPointList.value.some(i => i.addr === addr)) {
const time = dayjs(Number(ts)).format('YYYY-MM-DD HH:mm:ss')
if (addr) {
const colData = chartData.get(addr)
if (colData) {
colData.push([time, val])
} else {
chartData.set(addr, [[time, val]])
}
}
if (ts) {
axisData.add(time)
}
}
})
}
function handleBeforeClose(done: () => void) {
isShowDrawer.value = false
clearData()
fullscreenLoading.value = null
done()
}
function clearData() {
time.value = undefined
chartLimit.value = 1000
chartOffset.value = 0
chartAllTotal.value = 0
progress.value = 0
legends.value = []
chartData.clear()
axisData.clear()
}
function resetChartStatus() {
loadingChart.value = false
nextTick(() => {
isShowChart.value = true
})
}
const chartRef = ref<InstanceType<typeof NewDataChart>>()
const isShowChart = ref(false)
function onDrawerOpened() {
nextTick(() => {
isShowChart.value = true
})
}
const fullscreenLoading = ref<any>(null)
const openFullScreen = () => {
fullscreenLoading.value = ElLoading.service({
lock: true,
text: '数据加载中,请稍后...',
background: 'rgba(255, 255, 255, 0.8)',
})
}
const checkPointList = ref<IMyPoint[]>([])
function onchangePoints(checkPoints: IMyPoint[]) {
checkPointList.value = []
checkPointList.value = checkPoints
}
const time = ref<[string, string]>()
const disabledDate = (time: any) => {
const current = dayjs(time)
if (curDevice.value?.isonLine) {
return current.isAfter(dayjs(), 'day')
}
try {
const deviceOff = curDevice.value as IOfflineDevice
const start = dayjs(deviceOff.start_time).format('YYYY-MM-DD')
const end = dayjs(deviceOff.end_time).format('YYYY-MM-DD')
return current.isBefore(start, 'day') || current.isAfter(end, 'day')
} catch (e) {
console.log('disableDate error', e)
return current.isAfter(dayjs(), 'day')
}
}
const getBeforeMonth = dayjs().startOf('month').subtract(1, 'month').startOf('month').toDate()
defineExpose({
open,
openFullScreen,
})
</script>
<style scoped lang="scss">
.fault-rule-drawer {
font-size: 16px;
:deep(.edfs-wrap) {
width: auto;
}
:deep(.el-drawer__header) {
color: var(--text-color);
}
}
</style>