- 更新纵坐标刻度算法,优化小数趋势图范围显示 - 添加稳态趋势图全屏模式和共享工具组件 - 实现多图联动的鼠标悬停竖线同步功能 - 调整主线线宽分档策略,降低最大线宽限制 - 重构稳态趋势工具栏,优化谐波次数选择逻辑 - 添加周时间周期搜索支持和自定义时间范围选择 - 完善稳态数据表格和指示器浮动面板功能 - 优化稳态趋势图性能,添加LTB采样和动画控制 - 修复数据表格打开前的趋势数据验证问题 - 统一时间轴标签格式化和网格对齐处理
172 lines
5.8 KiB
TypeScript
172 lines
5.8 KiB
TypeScript
import type { SteadyDataView } from '@/api/steady/steadyDataView/interface'
|
|
|
|
export const MAX_TREND_SERIES_COUNT = 24
|
|
export const MAX_SELECTED_LINE_COUNT = 6
|
|
export const MAX_SELECTED_INDICATOR_COUNT = 6
|
|
export const MAX_HARMONIC_ORDER_COUNT = 3
|
|
const STEADY_INDICATOR_GROUP_ORDER = ['电压趋势', '电流趋势']
|
|
|
|
const isSelectableLineNode = (node: SteadyDataView.SteadyLedgerNode) => {
|
|
return node.level === 3 && node.selectable !== false
|
|
}
|
|
|
|
export const collectSelectedLineIds = (nodes: SteadyDataView.SteadyLedgerNode[]) => {
|
|
const lineIds = new Set<string>()
|
|
|
|
const collect = (node: SteadyDataView.SteadyLedgerNode) => {
|
|
if (isSelectableLineNode(node)) {
|
|
lineIds.add(node.id)
|
|
}
|
|
|
|
node.children?.forEach(collect)
|
|
}
|
|
|
|
nodes.forEach(collect)
|
|
|
|
return Array.from(lineIds)
|
|
}
|
|
|
|
export const collectLeafIndicators = (nodes: SteadyDataView.SteadyIndicatorNode[]) => {
|
|
const indicators: SteadyDataView.SteadyIndicatorNode[] = []
|
|
const seenIndicatorKeys = new Set<string>()
|
|
|
|
const collect = (node: SteadyDataView.SteadyIndicatorNode) => {
|
|
if (node.children?.length) {
|
|
node.children.forEach(collect)
|
|
return
|
|
}
|
|
|
|
const indicatorKey = node.indicatorCode || node.treeKey || node.id
|
|
if (!indicatorKey || seenIndicatorKeys.has(indicatorKey)) return
|
|
|
|
seenIndicatorKeys.add(indicatorKey)
|
|
indicators.push(node)
|
|
}
|
|
|
|
nodes.forEach(collect)
|
|
|
|
return indicators
|
|
}
|
|
|
|
const resolveSteadyIndicatorGroupOrder = (node: SteadyDataView.SteadyIndicatorNode) => {
|
|
const orderName = String(node.name || '').trim()
|
|
const orderIndex = STEADY_INDICATOR_GROUP_ORDER.findIndex(name => orderName === name)
|
|
|
|
return orderIndex === -1 ? STEADY_INDICATOR_GROUP_ORDER.length : orderIndex
|
|
}
|
|
|
|
export const sortSteadyIndicatorTree = (
|
|
nodes: SteadyDataView.SteadyIndicatorNode[]
|
|
): SteadyDataView.SteadyIndicatorNode[] => {
|
|
return nodes
|
|
.map((node, index) => ({ node, index }))
|
|
.sort((left, right) => {
|
|
const leftOrder = resolveSteadyIndicatorGroupOrder(left.node)
|
|
const rightOrder = resolveSteadyIndicatorGroupOrder(right.node)
|
|
|
|
return leftOrder === rightOrder ? left.index - right.index : leftOrder - rightOrder
|
|
})
|
|
.map(({ node }) => ({
|
|
...node,
|
|
children: node.children?.length ? sortSteadyIndicatorTree(node.children) : node.children
|
|
}))
|
|
}
|
|
|
|
export const findFirstSelectableLedgerNode = (
|
|
nodes: SteadyDataView.SteadyLedgerNode[]
|
|
): SteadyDataView.SteadyLedgerNode | null => {
|
|
for (const node of nodes) {
|
|
if (isSelectableLineNode(node)) {
|
|
return node
|
|
}
|
|
|
|
const childNode = findFirstSelectableLedgerNode(node.children || [])
|
|
if (childNode) return childNode
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export const findFirstLeafIndicator = (
|
|
nodes: SteadyDataView.SteadyIndicatorNode[]
|
|
): SteadyDataView.SteadyIndicatorNode | null => {
|
|
for (const node of nodes) {
|
|
if (node.children?.length) {
|
|
const childNode = findFirstLeafIndicator(node.children)
|
|
if (childNode) return childNode
|
|
continue
|
|
}
|
|
|
|
if (node.indicatorCode) {
|
|
return node
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export const hasHarmonicIndicator = (indicators: SteadyDataView.SteadyIndicatorNode[]) => {
|
|
return indicators.some(item => item.harmonic || Boolean(item.harmonicOrderStart || item.harmonicOrderEnd))
|
|
}
|
|
|
|
export const resolveAvailableStats = (indicators: SteadyDataView.SteadyIndicatorNode[]) => {
|
|
const statSet = new Set<SteadyDataView.SteadyTrendStatType>()
|
|
|
|
indicators.forEach(indicator => {
|
|
indicator.supportStats?.forEach(stat => statSet.add(stat))
|
|
})
|
|
|
|
return Array.from(statSet)
|
|
}
|
|
|
|
export const estimateTrendSeriesCount = (
|
|
lineIds: string[],
|
|
indicators: SteadyDataView.SteadyIndicatorNode[],
|
|
statType: SteadyDataView.SteadyTrendStatType,
|
|
harmonicOrders: number[]
|
|
) => {
|
|
void harmonicOrders
|
|
const harmonicMultiplier = 1
|
|
|
|
return indicators.reduce((count, indicator) => {
|
|
const phaseCount = indicator.phaseCodes?.length || 1
|
|
const fieldCount = Math.max(indicator.seriesFields?.length || indicator.baseFields?.length || 1, 1)
|
|
|
|
return count + lineIds.length * phaseCount * (statType ? 1 : 0) * fieldCount * harmonicMultiplier
|
|
}, 0)
|
|
}
|
|
|
|
export const validateHarmonicOrders = (indicators: SteadyDataView.SteadyIndicatorNode[], harmonicOrders: number[]) => {
|
|
if (!hasHarmonicIndicator(indicators)) return ''
|
|
if (!harmonicOrders.length) return '谐波指标必须选择谐波次数'
|
|
if (harmonicOrders.length > MAX_HARMONIC_ORDER_COUNT) return `谐波次数最多选择 ${MAX_HARMONIC_ORDER_COUNT} 个`
|
|
|
|
return ''
|
|
}
|
|
|
|
export const validateTrendSelection = (params: {
|
|
lineIds: string[]
|
|
indicators: SteadyDataView.SteadyIndicatorNode[]
|
|
statType: SteadyDataView.SteadyTrendStatType
|
|
harmonicOrders: number[]
|
|
}) => {
|
|
const { lineIds, indicators, statType, harmonicOrders } = params
|
|
|
|
if (!lineIds.length) return '请选择监测点'
|
|
if (!indicators.length) return '请选择趋势指标'
|
|
if (lineIds.length > 1 && indicators.length > 1) return '多监测点查询时只能选择 1 个指标'
|
|
if (lineIds.length > MAX_SELECTED_LINE_COUNT) return '监测点最多选择 6 个'
|
|
if (indicators.length > MAX_SELECTED_INDICATOR_COUNT) return '趋势指标最多选择 6 个'
|
|
if (!statType) return '请选择统计类型'
|
|
|
|
const harmonicError = validateHarmonicOrders(indicators, harmonicOrders)
|
|
if (harmonicError) return harmonicError
|
|
|
|
const seriesCount = estimateTrendSeriesCount(lineIds, indicators, statType, harmonicOrders)
|
|
if (seriesCount > MAX_TREND_SERIES_COUNT) {
|
|
return '趋势曲线数量不能超过 24 条,请缩小监测点、指标或统计类型范围'
|
|
}
|
|
|
|
return ''
|
|
}
|