diff --git a/src/views/iot/deviceParamAnalysis/index.vue b/src/views/iot/deviceParamAnalysis/index.vue index cb36eed0..e34fa0a5 100644 --- a/src/views/iot/deviceParamAnalysis/index.vue +++ b/src/views/iot/deviceParamAnalysis/index.vue @@ -190,8 +190,12 @@ type SelectedGroup = { } const selectedGroups = ref([]) +const lastCheckedSignature = ref('') let keywordTimer: number | undefined +let treeCheckTimer: number | undefined +let pendingCheckedNodes: DeviceTreeNode[] = [] +let pendingCheckedKeys: Array = [] const handleKeywordChange = () => { if (keywordTimer) window.clearTimeout(keywordTimer) keywordTimer = window.setTimeout(() => { @@ -334,6 +338,7 @@ const loadTree = async () => { treeRef.value?.setCurrentKey?.(undefined) treeRef.value?.setCheckedKeys?.([]) selectedGroups.value = [] + lastCheckedSignature.value = '' } } catch { message.error(t('DataCollection.DeviceParamAnalysis.messageLoadTreeFailed')) @@ -401,6 +406,7 @@ const fetchGroupChart = async (group: SelectedGroup, notify: boolean) => { if (typeof group.modelId === 'number' && Number.isFinite(group.modelId)) { req.modelId = group.modelId } + const data = await DeviceModelAttributeApi.operationAnalysisDetails(req as any) if (requestSeq !== group.requestSeq) return const rows: Record[] = extractChartRows(data) @@ -416,46 +422,78 @@ const fetchGroupChart = async (group: SelectedGroup, notify: boolean) => { const firstRow = rows[0] || {} const keys = Object.keys(firstRow) - const xKey = keys.find((k) => /time|date|时间|日期/i.test(k)) - if (xKey) { + + if (keys.includes('collectTime') && keys.includes('attributeName') && keys.includes('addressValue')) { const sortedRows = [...rows].sort((a, b) => - String(a?.[xKey] ?? '').localeCompare(String(b?.[xKey] ?? '')) + String(a?.collectTime ?? '').localeCompare(String(b?.collectTime ?? '')) ) if (requestSeq !== group.requestSeq) return - group.chartXAxis = sortedRows.map((r) => String(r?.[xKey] ?? '')) - const seriesKeys = keys.filter((k) => k !== xKey) + const xAxis = Array.from(new Set(sortedRows.map((r) => String(r?.collectTime ?? '')))) + const xIndexMap = new Map() + xAxis.forEach((x, idx) => xIndexMap.set(x, idx)) + group.chartXAxis = xAxis + const seriesMap = new Map>() const ensureSeries = (name: string) => { if (!seriesMap.has(name)) { - seriesMap.set(name, Array(sortedRows.length).fill(null)) + seriesMap.set(name, Array(xAxis.length).fill(null)) } return seriesMap.get(name)! } - sortedRows.forEach((row, rowIndex) => { - seriesKeys.forEach((k) => { - const v = row?.[k] - if (Array.isArray(v)) { - v.forEach((item) => { - const name = String(item?.attributeName ?? k) - const series = ensureSeries(name) - series[rowIndex] = toNumber(item?.addressValue ?? item?.value ?? item?.val) - }) - return - } - const series = ensureSeries(k) - series[rowIndex] = toNumber(v) - }) + sortedRows.forEach((row) => { + const time = String(row?.collectTime ?? '') + const idx = xIndexMap.get(time) + if (typeof idx !== 'number') return + const name = String(row?.attributeName ?? group.param?.label ?? '') + const series = ensureSeries(name) + series[idx] = toNumber(row?.addressValue) }) group.chartSeries = Array.from(seriesMap.entries()).map(([name, data]) => ({ name, data })) } else { - group.chartXAxis = keys - const values = keys.map((k) => toNumber(firstRow[k])) - group.chartSeries = [ - { name: group.param?.label || t('DataCollection.DeviceParamAnalysis.defaultSeriesName'), data: values } - ] + const xKey = keys.find((k) => /time|date|时间|日期/i.test(k)) + if (xKey) { + const sortedRows = [...rows].sort((a, b) => + String(a?.[xKey] ?? '').localeCompare(String(b?.[xKey] ?? '')) + ) + if (requestSeq !== group.requestSeq) return + group.chartXAxis = sortedRows.map((r) => String(r?.[xKey] ?? '')) + + const seriesKeys = keys.filter((k) => k !== xKey) + const seriesMap = new Map>() + const ensureSeries = (name: string) => { + if (!seriesMap.has(name)) { + seriesMap.set(name, Array(sortedRows.length).fill(null)) + } + return seriesMap.get(name)! + } + + sortedRows.forEach((row, rowIndex) => { + seriesKeys.forEach((k) => { + const v = row?.[k] + if (Array.isArray(v)) { + v.forEach((item) => { + const name = String(item?.attributeName ?? k) + const series = ensureSeries(name) + series[rowIndex] = toNumber(item?.addressValue ?? item?.value ?? item?.val) + }) + return + } + const series = ensureSeries(k) + series[rowIndex] = toNumber(v) + }) + }) + + group.chartSeries = Array.from(seriesMap.entries()).map(([name, data]) => ({ name, data })) + } else { + group.chartXAxis = keys + const values = keys.map((k) => toNumber(firstRow[k])) + group.chartSeries = [ + { name: group.param?.label || t('DataCollection.DeviceParamAnalysis.defaultSeriesName'), data: values } + ] + } } group.chartState = group.chartXAxis.length && group.chartSeries.length ? 'ready' : 'empty' @@ -504,12 +542,31 @@ const syncGroupsByCheckedNodes = (checkedNodes: DeviceTreeNode[]) => { return addedGroups } -const handleTreeCheck = async () => { - const checkedNodes = (treeRef.value?.getCheckedNodes?.(true) ?? []) as DeviceTreeNode[] - const addedGroups = syncGroupsByCheckedNodes(checkedNodes) - const needFetchGroups = selectedGroups.value.filter((g) => g.chartState === 'idle' && !g.chartLoading) - const groups = [...new Set([...addedGroups, ...needFetchGroups])] - await Promise.allSettled(groups.map((g) => fetchGroupChart(g, false))) +const handleTreeCheck = async (_node?: DeviceTreeNode, info?: any) => { + const checkedNodes = (info?.checkedNodes ?? []) as DeviceTreeNode[] + const checkedKeys = (info?.checkedKeys ?? []) as Array + pendingCheckedNodes = Array.isArray(checkedNodes) ? checkedNodes : [] + pendingCheckedKeys = Array.isArray(checkedKeys) ? checkedKeys : [] + if (treeCheckTimer) { + window.clearTimeout(treeCheckTimer) + } + treeCheckTimer = window.setTimeout(async () => { + treeCheckTimer = undefined + const effectiveNodes = pendingCheckedNodes.filter((n) => n?.type === 'param') + const signature = pendingCheckedKeys + .map((k) => String(k ?? '')) + .filter(Boolean) + .sort() + .join(',') + if (signature === lastCheckedSignature.value) return + lastCheckedSignature.value = signature + + const addedGroups = syncGroupsByCheckedNodes(effectiveNodes) + const needFetchGroups = selectedGroups.value.filter((g) => g.chartState === 'idle' && !g.chartLoading) + const ids = new Set([...addedGroups.map((g) => g.id), ...needFetchGroups.map((g) => g.id)]) + const groups = selectedGroups.value.filter((g) => ids.has(g.id)) + await Promise.allSettled(groups.map((g) => fetchGroupChart(g, false))) + }, 0) } const handleQuery = async (group: SelectedGroup) => {