import { nextTick } from 'vue' export interface LineTreeLeaves { govern: any[] portable: any[] monitor: any[] engineering: any[] } export interface LineTreeDecorators { primary: () => string statusColor: (comFlag: number) => string applyMeta: ( node: any, meta: { icon: string; color?: string; level?: number; disabled?: boolean } ) => void } export function createLineTreeDecorators(getPrimaryColor: () => string): LineTreeDecorators { const offlineColor = '#e26257 !important' const statusColor = (comFlag: number) => (comFlag === 2 ? getPrimaryColor() : offlineColor) const applyMeta = ( node: any, meta: { icon: string; color?: string; level?: number; disabled?: boolean } ) => { node.icon = meta.icon if (meta.color !== undefined) node.color = meta.color if (meta.level !== undefined) node.level = meta.level if (meta.disabled) node.disabled = true } return { primary: getPrimaryColor, statusColor, applyMeta } } 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 } /** 装饰线路树节点并收集可选叶子节点 */ export function decorateLineTree( data: any[], type: string | undefined, decorators: LineTreeDecorators, options: DecorateLineTreeOptions = {} ): LineTreeLeaves { const leaves: LineTreeLeaves = { govern: [], portable: [], monitor: [], engineering: [] } const { primary, statusColor, applyMeta } = decorators const disableParents = options.disableParents ?? true const parentDisabled = disableParents ? ({ disabled: true } as const) : {} data.forEach(item => { if (type === '2') { applyMeta(item, { icon: 'el-icon-HomeFilled', color: primary(), ...parentDisabled }) item.children?.forEach((child: any) => { applyMeta(child, { icon: 'el-icon-List', color: primary(), ...parentDisabled }) child.children?.forEach((grand: any) => { applyMeta(grand, { icon: 'el-icon-Platform', color: statusColor(grand.comFlag), level: 2, ...parentDisabled }) grand.children?.forEach((leaf: any) => { applyMeta(leaf, { icon: 'el-icon-Platform', color: statusColor(leaf.comFlag), ...LINE_LEAF_META }) leaves.engineering.push(leaf) }) }) }) return } if (item.name === '治理设备') { item.children?.forEach((l1: any) => { applyMeta(l1, { icon: 'el-icon-HomeFilled', color: primary(), level: 1, ...parentDisabled }) l1.children?.forEach((l2: any) => { applyMeta(l2, { icon: 'el-icon-List', color: primary(), level: 1, ...parentDisabled }) l2.children?.forEach((l3: any) => { applyMeta(l3, { icon: 'el-icon-Platform', color: statusColor(l3.comFlag), level: 2, ...parentDisabled }) l3.children?.forEach((l4: any) => { applyMeta(l4, { icon: 'el-icon-Platform', color: statusColor(l4.comFlag), ...LINE_LEAF_META }) leaves.govern.push(l4) }) }) }) }) } else if (item.name === '便携式设备') { 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), ...LINE_LEAF_META }) leaves.portable.push(l2) }) }) } else if (item.name === '监测设备') { item.children?.forEach((l1: any) => { applyMeta(l1, { icon: 'el-icon-HomeFilled', color: primary(), level: 1, ...parentDisabled }) l1.children?.forEach((l2: any) => { applyMeta(l2, { icon: 'el-icon-List', color: primary(), level: 1, ...parentDisabled }) l2.children?.forEach((l3: any) => { applyMeta(l3, { icon: 'el-icon-Platform', color: statusColor(l3.comFlag), level: 1, ...parentDisabled }) l3.children?.forEach((l4: any) => { applyMeta(l4, { icon: 'el-icon-Platform', color: statusColor(l4.comFlag), ...LINE_LEAF_META }) leaves.monitor.push(l4) }) }) }) }) } }) return leaves } /** 从折叠面板树数据中收集叶子节点(与 decorateLineTree 层级一致) */ export function collectDeviceLeaves( governNodes: any[], portableNodes: any[], monitorNodes: any[] ): Pick { const govern: any[] = [] const portable: any[] = [] const monitor: any[] = [] governNodes.forEach(l1 => { l1.children?.forEach((l2: any) => { l2.children?.forEach((l3: any) => { l3.children?.forEach((l4: any) => govern.push(l4)) }) }) }) portableNodes.forEach(l1 => { l1.children?.forEach((l2: any) => portable.push(l2)) }) monitorNodes.forEach(l1 => { l1.children?.forEach((l2: any) => { l2.children?.forEach((l3: any) => { l3.children?.forEach((l4: any) => monitor.push(l4)) }) }) }) return { govern, portable, monitor } } export async function waitForTreeRef(treRef: any, refKey: TreeRefKey, maxRetries = 20) { for (let i = 0; i < maxRetries; i++) { await nextTick() if (treRef?.[refKey]) return treRef[refKey] await new Promise(resolve => setTimeout(resolve, 50)) } return null }