优化项目

This commit is contained in:
guanj
2026-06-04 19:06:36 +08:00
parent 4f32f84132
commit 4f907a80c4
53 changed files with 987 additions and 3499 deletions

View File

@@ -154,7 +154,7 @@ const tableStore: any = new TableStore({
series: [
{
type: 'bar',
name: '越限占比',
name: '指标越限严重度',
data: tableStore.table.data.map((item: any) => Math.floor(item.extent * 100) / 100),
barMaxWidth: 30
}

View File

@@ -52,9 +52,10 @@
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h, computed, nextTick } from 'vue'
import { ref, onMounted, onUnmounted, provide, reactive, watch, h, computed, nextTick } from 'vue'
import TableStore from '@/utils/tableStore'
import { exportExcel } from '@/views/govern/reportForms/export.js'
import { destroyLuckysheet, renderLuckysheetReport } from '@/utils/luckysheetHelper'
import TableHeader from '@/components/table/header/index.vue'
import { querySysExcel } from '@/api/harmonic-boot/luckyexcel'
import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit'
@@ -119,6 +120,9 @@ const downloadExcel = () => {
onMounted(() => {
initListByIds()
})
onUnmounted(() => {
destroyLuckysheet()
})
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
if (datePickerValue && datePickerValue.timeValue) {
@@ -159,16 +163,7 @@ const tableStore: any = new TableStore({
// }
},
loadCallback: () => {
luckysheet.create({
container: 'luckysheet',
title: '', // 表 头名
lang: 'zh', // 中文
showtoolbar: false, // 是否显示工具栏
showinfobar: false, // 是否显示顶部信息栏
showsheetbar: true, // 是否显示底部sheet按钮
allowEdit: false, // 禁止所有编辑操作(必填)
data: tableStore.table.data
})
renderLuckysheetReport('luckysheet', tableStore.table.data, { allowEdit: false })
}
})

View File

@@ -220,7 +220,7 @@ const tableStore: any = new TableStore({
icon: 'el-icon-DataLine',
render: 'basicButton',
disabled: row => {
return !!row.wavePath
return row.wavePath
}
}
]

View File

@@ -214,7 +214,7 @@ const tableStore: any = new TableStore({
icon: 'el-icon-DataLine',
render: 'basicButton',
disabled: row => {
return !!row.wavePath
return row.wavePath
}
}
]

View File

@@ -236,7 +236,7 @@ const fliteWaveData = (wp, step, iphasicValue, isOpen) => {
// 监听消息
self.onmessage = function (e) {
const { wp, isOpen, value, boxoList } = JSON.parse(e.data)
const { wp, isOpen, value, boxoList, requestId } = e.data
try {
const iphasicValue = wp.iphasic || 1
@@ -303,6 +303,7 @@ self.onmessage = function (e) {
}
// 发送处理结果回主线程
self.postMessage({
requestId,
titles: titles,
success: true,
waveDatas,
@@ -313,6 +314,7 @@ self.onmessage = function (e) {
})
} catch (error) {
self.postMessage({
requestId,
success: false,
error: error.message
})

View File

@@ -14,9 +14,15 @@ import html2canvas from 'html2canvas'
import $ from 'jquery'
import * as echarts from 'echarts'
import { mainHeight } from '@/utils/layout'
import { calcRmsYAxisRange, formatAxisLabel } from '@/utils/chartAxisHelper'
import url from '@/assets/img/point.png'
import url2 from '@/assets/img/dw.png'
const worker = ref<Worker | null>(null)
import { buildWaveCacheKey, getWaveCache, setWaveCache } from '@/utils/waveCache'
import { getRmsWorker, buildWorkerPayload } from '@/utils/waveWorkerPool'
let waveRequestId = 0
const pendingCacheKeys = new Map<number, string>()
let rmsWorker: Worker | null = null
interface WaveData {
instantF: { max: number; min: number }
instantS: { max: number; min: number }
@@ -125,52 +131,61 @@ const vw = computed(() => '100%')
watch(
() => props.value,
newVal => {
if (newVal == 2) {
initWaves()
} else {
$('#wave1').remove()
initWaves()
}
() => {
query()
}
)
watch(
() => props.wp,
() => {
query()
}
)
const applyWorkerResult = (data: any) => {
titles.value = data.titles
waveDatas.value = data.waveDatas
time.value = data.time
type.value = data.type
severity.value = data.severity
iphasic.value = data.iphasic
if (Number(severity.value) < 0) {
severity.value = '/'
type.value = '/'
}
initWave(waveDatas.value, time.value, type.value, severity.value, isOpen.value)
loading.value = false
}
onMounted(() => {
const zoomValue = document.body.style.getPropertyValue('zoom')
zoom.value = 1 / (zoomValue ? parseFloat(zoomValue) : 1)
window.addEventListener('resize', handleResize)
// 初始化 Web Worker
worker.value = new Worker(new URL('./rmsWorker.js', import.meta.url))
worker.value.onmessage = e => {
if (e.data.success) {
const data = e.data
titles.value = data.titles
waveDatas.value = data.waveDatas
time.value = data.time
type.value = data.type
severity.value = data.severity
iphasic.value = data.iphasic
// 初始化波形图
initWave(waveDatas.value, time.value, type.value, severity.value, isOpen.value)
} else {
console.error('Worker error:', e.data.error)
rmsWorker = getRmsWorker(data => {
if (data.requestId !== waveRequestId) return
if (!data.success) {
console.error('Worker error:', data.error)
loading.value = false
return
}
}
const cacheKey = pendingCacheKeys.get(data.requestId)
if (cacheKey) {
setWaveCache(cacheKey, data)
pendingCacheKeys.delete(data.requestId)
}
applyWorkerResult(data)
})
nextTick(() => {
setTimeout(() => {
query()
}, 500)
query()
})
})
onBeforeUnmount(() => {
if (worker.value) {
worker.value.terminate()
}
backbxlb()
window.removeEventListener('resize', handleResize)
})
@@ -195,23 +210,15 @@ const download = () => {
}
}
const EXTRA_PANEL_CLASS = 'wave-extra-panel'
const resetWaveDom = () => {
backbxlb()
$('#rmsp').nextAll(`.${EXTRA_PANEL_CLASS}`).remove()
}
const query = () => {
loading.value = true
if (props.wp) {
// 使用 Worker 处理数据
if (worker.value) {
worker.value.postMessage(
JSON.stringify({
wp: props.wp,
isOpen: isOpen.value,
value: props.value,
boxoList: props.boxoList
})
)
}
} else {
initWave(null, null, null, null, null)
}
initWaves()
}
const waveData = (
@@ -245,29 +252,31 @@ const waveData = (
}
const initWaves = () => {
if (props.wp) {
iphasic.value = props.wp.iphasic || 1
const picCounts = (props.wp.waveTitle.length - 1) / iphasic.value
waveDatas.value = []
for (let i = 0; i < picCounts; i++) {
const data = fliteWaveData(props.wp, i)
waveDatas.value.push(data)
}
time.value = props.wp.time
type.value = props.wp.waveType
severity.value = props.wp.yzd
if (Number(severity.value) < 0) {
severity.value = '/'
type.value = '/'
}
initWave(waveDatas.value, time.value, type.value, severity.value, isOpen.value)
} else {
if (!props.wp?.listRmsData?.length) {
initWave(null, null, null, null, null)
loading.value = false
return
}
const cacheKey = buildWaveCacheKey('rms', props.wp, props.value, isOpen.value, props.boxoList)
const cached = getWaveCache<any>(cacheKey)
if (cached) {
applyWorkerResult(cached)
return
}
loading.value = true
iphasic.value = props.wp.iphasic || 1
const currentRequestId = ++waveRequestId
pendingCacheKeys.set(currentRequestId, cacheKey)
rmsWorker?.postMessage(
buildWorkerPayload('rms', props.wp, props.boxoList, {
requestId: currentRequestId,
value: props.value,
isOpen: isOpen.value
})
)
}
const fliteWaveData = (wp: any, step: number): WaveData => {
@@ -482,7 +491,7 @@ const initWave = (
severity: string | null,
isOpen: boolean | null
) => {
$('div.bx').remove()
resetWaveDom()
let picHeight = vh.value
const show = !isOpen
@@ -594,7 +603,7 @@ const initWave = (
for (let step = waveDatas.length - 1; step > 0 && step < waveDatas.length; step--) {
const rmsId = 'rms' + step
const newDivRms = $(
`<div style="height:${vh.value};overflow: hidden;min-height: 200px;"><div class='bx' id='${rmsId}'></div></div>`
`<div class="${EXTRA_PANEL_CLASS}" style="height:${vh.value};overflow: hidden;min-height: 200px;"><div class='bx' id='${rmsId}'></div></div>`
)
newDivRms.insertAfter($('#rmsp'))
$(`#${rmsId}`).css('height', picHeight).css('width', vw.value).css('min-height', '200px')
@@ -607,6 +616,12 @@ const initWave = (
const rms = document.getElementById('rmsp')
if (!rms) return
const yRange = calcRmsYAxisRange(rmscu[0]?.[1] ?? 0, rmscm[0]?.[1] ?? 0)
const existingChart = echarts.getInstanceByDom(rms)
if (existingChart) existingChart.dispose()
const myChartes = echarts.init(rms)
const echartsColor = {
WordColor: '#000',
@@ -750,8 +765,8 @@ const initWave = (
},
// max: rmscm[0]?.[1] * 1.06 || 0,
// min: rmscu[0]?.[1] - rmscu[0]?.[1] * 0.2 || 0,
max: Math.floor((rmscm[0]?.[1] * 1.06 || 0) * 1.1 * 10) / 10,
min: Math.floor((rmscu[0]?.[1] - rmscu[0]?.[1] * 0.2 || 0) * 10) / 10,
max: yRange.max,
min: yRange.min,
boundaryGap: [0, '100%'],
showLastLabel: true,
opposite: false,
@@ -770,7 +785,7 @@ const initWave = (
fontSize: '12px',
color: props.DColor ? '#000' : echartsColor.WordColor,
formatter: function (value: number) {
return Math.floor(value * 1000) / 1000
return formatAxisLabel(value)
}
},
splitLine: {
@@ -955,6 +970,10 @@ const drawPics = (
const rmsIds = document.getElementById(rmsId)
if (!rmsIds) return
const subMin = props.value === 1 ? waveDataTemp.RMSF.min : waveDataTemp.RMSS.min
const subMax = props.value === 1 ? waveDataTemp.RMSF.max : waveDataTemp.RMSS.max
const yRange = calcRmsYAxisRange(subMin, subMax)
const myChartes = echarts.init(rmsIds)
const echartsColor = {
WordColor: '#000',
@@ -1078,6 +1097,8 @@ const drawPics = (
},
boundaryGap: [0, '100%'],
showLastLabel: true,
max: yRange.max,
min: yRange.min,
opposite: false,
// max: Math.floor((rmscm[0]?.[1] * 1.06 || 0) * 1.1 * 10) / 10,
// min: Math.floor((rmscu[0]?.[1] - rmscu[0]?.[1] * 0.2 || 0) * 10) / 10,
@@ -1096,8 +1117,7 @@ const drawPics = (
fontSize: '12px',
color: props.DColor ? '#000' : echartsColor.WordColor,
formatter: function (value: number) {
// return (value - 0).toFixed(2)
return Math.floor(value * 1000) / 1000
return formatAxisLabel(value)
}
},
splitLine: {
@@ -1213,12 +1233,7 @@ const backbxlb = () => {
myChartess4.value = null
myChartess5.value = null
// echarts.disconnect(charts.filter(Boolean) as echarts.ECharts[])
charts.filter(Boolean).forEach(chart => {
if (chart && typeof chart.dispose === 'function') {
chart.dispose()
}
})
$('#rmsp').nextAll(`.${EXTRA_PANEL_CLASS}`).remove()
}
const getMax = (temp: number, tempA: number, tempB: number, tempC: number): number => {

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
// waveData.worker.js
self.addEventListener('message', function (e) {
const { wp, value, iphasic, isOpen, boxoList } = JSON.parse(e.data)
const { wp, value, iphasic, isOpen, boxoList, requestId } = e.data
// 处理波形数据的函数
const fliteWaveData = (wp, step) => {
@@ -195,6 +195,8 @@ self.addEventListener('message', function (e) {
// 将处理结果发送回主线程
self.postMessage({
requestId,
success: true,
waveDatas,
time,
type,

View File

@@ -1,8 +1,8 @@
<template>
<div v-loading="loading" class="boxbx" style="position: relative; height: 100%">
<div id="boxsj">
<div id="shushi" :style="`height:${vh};overflow: hidden;min-height: 200px;`">
<div class="bx" id="wave" style="min-height: 200px"></div>
<div id="shushi" :style="containerStyle">
<div class="bx" id="wave" :style="waveStyle"></div>
</div>
</div>
</div>
@@ -14,9 +14,14 @@ import html2canvas from 'html2canvas'
import $ from 'jquery'
import * as echarts from 'echarts'
import { mainHeight } from '@/utils/layout'
import { calcShuYAxisRange, formatAxisLabel } from '@/utils/chartAxisHelper'
import url from '@/assets/img/point.png'
// 创建Worker
let waveDataWorker: Worker | null = null
import { buildWaveCacheKey, getWaveCache, setWaveCache } from '@/utils/waveCache'
import { getShuWorker, buildWorkerPayload } from '@/utils/waveWorkerPool'
let waveRequestId = 0
const pendingCacheKeys = new Map<number, string>()
let shuWorker: Worker | null = null
interface WaveData {
instantF: { max: number; min: number }
instantS: { max: number; min: number }
@@ -110,38 +115,82 @@ const vh = computed(() => {
const vw = computed(() => '100%')
const containerStyle = computed(() => ({
height: vh.value,
overflow: 'hidden',
minHeight: '200px'
}))
const waveStyle = computed(() => ({
width: '100%',
height: '100%',
minHeight: '200px'
}))
const applyChartSize = (el: HTMLElement) => {
el.style.width = '100%'
el.style.height = vh.value
}
const finishChartRender = (chart: echarts.ECharts, endLoading = false) => {
nextTick(() => {
chart.resize()
if (endLoading) {
loading.value = false
}
})
}
watch(
() => props.value,
newVal => {
if (newVal == 2) {
initWaves()
} else {
$('#wave1').remove()
initWaves()
}
() => {
query()
}
)
watch(
() => props.wp,
() => {
query()
}
)
const applyWorkerResult = (data: any) => {
titles.value = data.titles
iphasic.value = data.iphasic
time.value = data.time
type.value = data.type
severity.value = data.severity
initWave(data.waveDatas, data.time, data.type, data.severity, isOpen.value)
loading.value = false
}
onMounted(() => {
const zoomValue = document.body.style.getPropertyValue('zoom')
zoom.value = 1 / (zoomValue ? parseFloat(zoomValue) : 1)
window.addEventListener('resize', handleResize)
shuWorker = getShuWorker(data => {
if (data.requestId !== waveRequestId) return
if (!data.success) {
console.error('Worker error:', data.error)
loading.value = false
return
}
const cacheKey = pendingCacheKeys.get(data.requestId)
if (cacheKey) {
setWaveCache(cacheKey, data)
pendingCacheKeys.delete(data.requestId)
}
applyWorkerResult(data)
})
nextTick(() => {
setTimeout(() => {
query()
}, 500)
query()
})
})
onBeforeUnmount(() => {
console.log('组件卸载')
if (waveDataWorker) {
waveDataWorker.terminate()
waveDataWorker = null
}
backbxlb()
window.removeEventListener('resize', handleResize)
})
@@ -166,6 +215,13 @@ const download = () => {
}
}
const EXTRA_PANEL_CLASS = 'wave-extra-panel'
const resetWaveDom = () => {
backbxlb()
$('#shushi').nextAll(`.${EXTRA_PANEL_CLASS}`).remove()
}
const query = () => {
loading.value = true
initWaves()
@@ -184,48 +240,32 @@ const waveData = (instantF: any, instantS: any, shunshiF: any, shunshiS: any, ti
// 在组件中修改initWaves函数
const initWaves = () => {
if (props.wp) {
loading.value = true
iphasic.value = props.wp.iphasic || 1
// 使用Web Worker处理数据
if (!waveDataWorker) {
waveDataWorker = new Worker(new URL('./shuWorker.js', import.meta.url))
waveDataWorker.onmessage = function (e) {
const data = e.data
titles.value = data.titles
iphasic.value = data.iphasic
time.value = data.time
type.value = data.type
severity.value = data.severity
initWave(data.waveDatas, data.time, data.type, data.severity, isOpen.value)
loading.value = false
}
waveDataWorker.onerror = function (error) {
console.error('Worker error:', error)
loading.value = false
// 备用方案:在主线程处理数据
// processDataInMainThread();
}
}
// 发送数据到Worker
waveDataWorker.postMessage(
JSON.stringify({
wp: props.wp,
value: props.value,
iphasic: iphasic.value,
isOpen: isOpen.value,
boxoList: props.boxoList
})
)
} else {
if (!props.wp?.listWaveData?.length) {
initWave(null, null, null, null, null)
loading.value = false
return
}
const cacheKey = buildWaveCacheKey('shu', props.wp, props.value, isOpen.value, props.boxoList)
const cached = getWaveCache<any>(cacheKey)
if (cached) {
applyWorkerResult(cached)
return
}
loading.value = true
iphasic.value = props.wp.iphasic || 1
const currentRequestId = ++waveRequestId
pendingCacheKeys.set(currentRequestId, cacheKey)
shuWorker?.postMessage(
buildWorkerPayload('shu', props.wp, props.boxoList, {
requestId: currentRequestId,
value: props.value,
isOpen: isOpen.value,
iphasic: iphasic.value
})
)
}
const initWave = (
@@ -235,6 +275,7 @@ const initWave = (
severity: string | null,
isOpen: boolean | null
) => {
resetWaveDom()
$('div.bx1').remove()
let picHeight = vh.value
@@ -327,7 +368,7 @@ const initWave = (
for (let step = waveDatas.length - 1; step > 0 && step < waveDatas.length; step--) {
const waveId = 'wave' + step
const newDivShunshi = $(`<div style="height:${vh.value};overflow: hidden;min-height: 200px;">
const newDivShunshi = $(`<div class="${EXTRA_PANEL_CLASS}" style="height:${vh.value};overflow: hidden;min-height: 200px;">
<div class='bx1' id='${waveId}'></div>
</div>`)
newDivShunshi.insertAfter($('#shushi'))
@@ -342,6 +383,13 @@ const initWave = (
const wave = document.getElementById('wave')
if (!wave) return
applyChartSize(wave)
const yRange = calcShuYAxisRange(Number(min), Number(max))
const existingChart = echarts.getInstanceByDom(wave)
if (existingChart) existingChart.dispose()
const myChartes = echarts.init(wave)
const echartsColor = {
WordColor: '#000',
@@ -363,11 +411,6 @@ const initWave = (
]
}
setTimeout(() => {
wave.style.width = '100%'
wave.style.height = vh.value
}, 0)
const option = {
tooltip: {
top: '10px',
@@ -481,10 +524,8 @@ const initWave = (
},
boundaryGap: [0, '100%'],
showLastLabel: true,
// max: max.toFixed(2) * 1.1,
// min: min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1,
max: Math.floor(max.toFixed(2) * 1.1 * 10) / 10,
min: Math.floor(min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1 * 10) / 10 ,
max: yRange.max,
min: yRange.min,
opposite: false,
nameTextStyle: {
fontSize: '12px',
@@ -501,8 +542,7 @@ const initWave = (
fontSize: '12px',
color: props.DColor ? '#000' : echartsColor.WordColor,
formatter: function (value: number) {
// return (value - 0).toFixed(2)
return Math.floor(value * 1000) / 1000
return formatAxisLabel(value)
}
},
splitLine: {
@@ -518,7 +558,6 @@ const initWave = (
right: '45px',
bottom: '40px',
top: '60px'
// containLabel: true
},
dataZoom: [
{
@@ -578,11 +617,7 @@ const initWave = (
myChartes.setOption(option)
myChartess.value = myChartes
setTimeout(() => {
myChartes.resize()
loading.value = false
}, 400)
finishChartRender(myChartes, true)
if (waveDatas && waveDatas.length > 1) {
const waveDatasTemp = waveDatas.slice(1)
@@ -679,6 +714,13 @@ const drawPics = (
const waveIds = document.getElementById(waveId)
if (!waveIds) return
applyChartSize(waveIds)
const yRange = calcShuYAxisRange(Number(min), Number(max))
const existingChart = echarts.getInstanceByDom(waveIds)
if (existingChart) existingChart.dispose()
const myChartes = echarts.init(waveIds)
const echartsColor = {
WordColor: '#000',
@@ -791,8 +833,8 @@ const drawPics = (
},
boundaryGap: [0, '100%'],
showLastLabel: true,
max: Math.floor(max.toFixed(2) * 1.1 * 10) / 10,
min: Math.floor(min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1 * 10) / 10 ,
max: yRange.max,
min: yRange.min,
opposite: false,
nameTextStyle: {
fontSize: '12px',
@@ -809,8 +851,7 @@ const drawPics = (
fontSize: '12px',
color: props.DColor ? '#000' : echartsColor.WordColor,
formatter: function (value: number) {
// return (value - 0).toFixed(2)
return Math.floor(value * 1000) / 1000
return formatAxisLabel(value)
}
},
splitLine: {
@@ -897,10 +938,7 @@ const drawPics = (
break
}
setTimeout(() => {
myChartes.resize()
loading.value = false
}, 400)
finishChartRender(myChartes)
echarts.connect([myChartes1, myChartes])
}
@@ -929,12 +967,8 @@ const backbxlb = () => {
myChartess4.value = null
myChartess5.value = null
// echarts.disconnect(charts.filter(Boolean) as echarts.ECharts[])
charts.filter(Boolean).forEach(chart => {
if (chart && typeof chart.dispose === 'function') {
chart.dispose()
}
})
$('#shushi').nextAll(`.${EXTRA_PANEL_CLASS}`).remove()
$('div.bx1').remove()
}
const getMax = (temp: number, tempA: number, tempB: number, tempC: number): number => {

File diff suppressed because it is too large Load Diff

View File

@@ -10,10 +10,11 @@
@checkbox-all="selectChangeEvent"
@checkbox-change="selectChangeEvent"
:showOverflow="showOverflow"
:sort-config="{ remote: true }"
@sort-change="handleSortChange"
>
<!-- :sort-config="{ remote: true }" -->
<!-- @sort-change="handleSortChange" -->
<!-- Column 组件内部是 el-table-column -->
<template v-if="isGroup">
<GroupColumn :column="tableStore.table.column" />

View File

@@ -152,7 +152,7 @@ async function selectInitialNode(
treeInstance?.setCurrentKey(node.id)
emit('init', { level, ...node })
emit('init', { ...node })
return

View File

@@ -64,7 +64,7 @@ async function loadTree() {
await selectTreeNode(treRef.value, node, {
level: 3,
onSelect: selected => {
emit('init', { level: 3, ...selected })
emit('init', { ...selected, level: 3 })
changePointType('4', selected)
}
})

View File

@@ -48,7 +48,7 @@ async function initTree(list: any[]) {
}
await selectTreeNode(treRef.value, node, {
onSelect: selected => emit('init', { level: 2, ...selected })
onSelect: selected => emit('init', { ...selected, level: 2 })
})
}

View File

@@ -1,16 +1,7 @@
<template>
<Tree
ref="treRef"
@check-change="handleCheckChange"
:default-checked-keys="defaultCheckedKeys"
:show-checkbox="props.showCheckbox"
:data="tree"
:height="props.height"
@changeDeviceType="changeDeviceType"
@changeTreeType="loadTree"
:engineering="props.engineering"
leaf-mode="device"
/>
<Tree ref="treRef" @check-change="handleCheckChange" :default-checked-keys="defaultCheckedKeys"
:show-checkbox="props.showCheckbox" :data="tree" :height="props.height" @changeDeviceType="changeDeviceType"
@changeTreeType="loadTree" :engineering="props.engineering" leaf-mode="device" />
</template>
<script lang="ts" setup>
@@ -55,17 +46,17 @@ async function selectInitialNode(type: string | undefined, leaves: LineTreeLeave
type === '2'
? [{ refKey: 'treeRef4', list: leaves.engineering, level: 2 }]
: [
{ refKey: 'treeRef1', list: leaves.govern, level: 2 },
{ refKey: 'treeRef2', list: leaves.portable, level: 2 },
{ refKey: 'treeRef3', list: leaves.monitor, level: 2 }
]
{ refKey: 'treeRef1', list: leaves.govern, level: 2 },
{ refKey: 'treeRef2', list: leaves.portable, level: 2 },
{ refKey: 'treeRef3', list: leaves.monitor, level: 2 }
]
for (const { refKey, list, level } of candidates) {
const node = list[0]
if (!node) continue
const treeInstance = await waitForTreeRef(treRef.value, refKey)
treeInstance?.setCurrentKey(node.id)
emit('init', { level, ...node })
emit('init', { ...node })
return
}
emit('init')
@@ -81,13 +72,10 @@ const loadTree = (type?: string) => {
onMounted(() => loadTree(props.engineering ? '2' : '1'))
const handleCheckChange = throttle(
const handleCheckChange =
(data: any, checked: any, indeterminate: any) => {
emit('checkChange', { data, checked, indeterminate })
},
300,
{ leading: true, trailing: false }
)
}
defineExpose({ treRef })
</script>

View File

@@ -17,7 +17,8 @@ export function decorateDeviceTree(
child.children?.forEach((grand: any) => {
applyMeta(grand, {
icon: 'el-icon-Platform',
color: statusColor(grand.comFlag)
color: statusColor(grand.comFlag),
level: 3
})
leaves.engineering.push(grand)
})
@@ -68,6 +69,7 @@ export function decorateDeviceTree(
l3.pName = '监测设备'
applyMeta(l3, {
icon: 'el-icon-Platform',
level: 3,
color: l3.comFlag === 1 ? '#e26257 !important' : primary()
})
leaves.monitor.push(l3)

View File

@@ -39,6 +39,21 @@ export function createLineTreeDecorators(getPrimaryColor: () => string): LineTre
export type TreeRefKey = 'treeRef1' | 'treeRef2' | 'treeRef3' | 'treeRef4'
/** 线路树可选叶子节点元数据 */
export const LINE_LEAF_META = { level: 3, type: 'line' as const }
/** 是否为线路树可选叶子(监测点/线路) */
export function isLineTreeLeaf(node: any): boolean {
if (!node?.id) return false
return node.type === 'line' || node.level === 3
}
/** 是否为报告/导出可选监测点 */
export function isReportMonitorPoint(node: any): boolean {
if (!node?.id) return false
return isLineTreeLeaf(node) || node.level === 3 || (!node.children?.length && !!node.pid)
}
export interface DecorateLineTreeOptions {
/** 是否禁用父级节点(分析树隐藏父节点,测点树不禁用) */
disableParents?: boolean
@@ -69,7 +84,11 @@ export function decorateLineTree(
...parentDisabled
})
grand.children?.forEach((leaf: any) => {
applyMeta(leaf, { icon: 'el-icon-Platform', color: statusColor(leaf.comFlag) })
applyMeta(leaf, {
icon: 'el-icon-Platform',
color: statusColor(leaf.comFlag),
...LINE_LEAF_META
})
leaves.engineering.push(leaf)
})
})
@@ -90,7 +109,11 @@ export function decorateLineTree(
...parentDisabled
})
l3.children?.forEach((l4: any) => {
applyMeta(l4, { icon: 'el-icon-Platform', color: statusColor(l4.comFlag) })
applyMeta(l4, {
icon: 'el-icon-Platform',
color: statusColor(l4.comFlag),
...LINE_LEAF_META
})
leaves.govern.push(l4)
})
})
@@ -100,7 +123,11 @@ export function decorateLineTree(
item.children?.forEach((l1: any) => {
applyMeta(l1, { icon: 'el-icon-Platform', color: statusColor(l1.comFlag) })
l1.children?.forEach((l2: any) => {
applyMeta(l2, { icon: 'el-icon-Platform', color: statusColor(l2.comFlag) })
applyMeta(l2, {
icon: 'el-icon-Platform',
color: statusColor(l2.comFlag),
...LINE_LEAF_META
})
leaves.portable.push(l2)
})
})
@@ -117,7 +144,11 @@ export function decorateLineTree(
...parentDisabled
})
l3.children?.forEach((l4: any) => {
applyMeta(l4, { icon: 'el-icon-Platform', color: statusColor(l4.comFlag) })
applyMeta(l4, {
icon: 'el-icon-Platform',
color: statusColor(l4.comFlag),
...LINE_LEAF_META
})
leaves.monitor.push(l4)
})
})

View File

@@ -64,7 +64,7 @@ async function selectInitialNode(type: string | undefined, leaves: LineTreeLeave
const treeInstance = await waitForTreeRef(treRef.value, refKey)
treeInstance?.setCurrentKey(node.id)
emit('init', { level, ...node })
emit('init', { ...node })
if (type === '2') {
changePointType('4', node)

View File

@@ -59,7 +59,7 @@ interface Props {
const props = withDefaults(defineProps<Props>(), { template: false })
const emit = defineEmits(['init', 'checkChange', 'nodeChange', 'editNode', 'getChart', 'Policy'])
const emit = defineEmits(['init', 'checkChange', 'nodeChange', 'node-click', 'editNode', 'getChart', 'Policy'])
const config = useConfig()
const tree = ref<any[]>([])
@@ -109,6 +109,7 @@ const clickNode = (e: any) => {
planId.value = e?.children ? e.id : e.pid
id.value = e.id
emit('nodeChange', e)
emit('node-click', e)
}
bootstrapWithTemplate(

View File

@@ -52,6 +52,7 @@ import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElMessage, ElTree } from 'element-plus'
import { ref, watch } from 'vue'
import { createTreeFilterNode } from './govern/treeFilterUtils'
import { isLineTreeLeaf } from './govern/lineTreeUtils'
defineOptions({ name: 'govern/select', inheritAttrs: false })
@@ -75,7 +76,8 @@ const filterNode = createTreeFilterNode()
const checkedNodes = ref<any[]>([])
const defaultCheckedKeys = ref<string[]>([])
const MAX_CHECK = 5
const MONITOR_LEVEL = 3
const isMonitorLeaf = (node: any) => isLineTreeLeaf(node)
watch(filterText, val => treeRef.value?.filter(val))
@@ -85,7 +87,7 @@ const onMenuCollapse = () => {
}
const handleCheckChange = (_data: any, checkInfo: any) => {
const monitoringPointNodes = (checkInfo.checkedNodes as any[]).filter(node => node.level === MONITOR_LEVEL)
const monitoringPointNodes = (checkInfo.checkedNodes as any[]).filter(isMonitorLeaf)
if (monitoringPointNodes.length > MAX_CHECK) {
const previousCheckedNodes = checkedNodes.value
@@ -122,7 +124,7 @@ const updateNodeCheckStatus = (currentCount: number) => {
if (!treeRef.value) return
const isMaxSelected = currentCount >= MAX_CHECK
treeRef.value.store._getAllNodes().forEach((node: any) => {
if (node.level === MONITOR_LEVEL) {
if (isMonitorLeaf(node.data)) {
node.data.disabled = isMaxSelected && !node.checked
}
})