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
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>
|
|
|