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