import { Graph } from '@antv/g6'; import type { CustomBehaviorOption, IPointerEvent } from '@antv/g6'; import type { Canvas } from '@antv/g6/lib/runtime/canvas'; import { useThemeStore } from '@/store/modules/theme'; import { getNodeIcon, nodeStatus } from './status'; import type { CustomEdgeData, CustomGraphData, CustomNodeData } from './types'; interface AntFlowConfig { container: string | HTMLElement | Canvas; data: CustomGraphData; behaviors?: CustomBehaviorOption[]; autoFit?: 'view' | 'center'; } export function useAntFlow(config: AntFlowConfig) { const themeStore = useThemeStore(); const baseColor = 'rgb(158 163 171)'; const { container, autoFit = 'center', data, behaviors = [] } = config; const graph = new Graph({ container, animation: false, padding: 16, theme: 'light', autoFit, data, node: { type: 'rect', style: (node: CustomNodeData) => { const iconS = getNodeIcon(node); let labelFill = '#000000'; if (node.taskState === 'NOT_STARTED') { labelFill = '#787878'; } return { labelText: node.name as string, size: [120, 26], radius: 99, fill: '#FFFFFF', stroke: node.isDeleted ? themeStore.otherColor.error : baseColor, lineDash: node.isDeleted ? 4 : 0, lineWidth: 1, labelFill, labelX: 2, labelY: 2, labelTextBaseline: 'middle', labelTextAlign: 'center', labelLineHeight: 13, labelWordWrap: true, labelMaxWidth: 72, iconSrc: iconS, iconWidth: 16, iconHeight: 16, iconX: -45, labelFontSize: 12, labelPlacement: 'center', badgeLineWidth: 6, badgeFontSize: 8, badges: [ { text: '延期', placement: 'top', offsetY: -11, visibility: node.isDelayed ? 'visible' : 'hidden' }, { text: '已删除', placement: 'bottom', offsetY: 11, visibility: node.isDeleted ? 'visible' : 'hidden' } ], badgePalette: [themeStore.otherColor.error, themeStore.otherColor.error], ports: [{ placement: 'left' }, { placement: 'right' }] }; }, state: { selected: { lineWidth: 2, stroke: themeStore.themeColor, labelFill: themeStore.themeColor, halo: true, haloStroke: themeStore.themeColor, haloLineWidth: 6 }, active: (node: CustomNodeData) => ({ halo: true, haloStroke: node.isDeleted ? themeStore.otherColor.error : themeStore.themeColor, haloLineWidth: 6, zIndex: 2 }) } }, edge: { type: 'cubic-horizontal', style: (node: CustomEdgeData) => ({ curveOffset: 10, curvePosition: 0.5, stroke: node.isDeleted ? themeStore.otherColor.error : baseColor, lineDash: node.isDeleted ? 4 : 0 }), state: { active: (node: CustomEdgeData) => ({ lineWidth: 2, stroke: node.isDeleted ? themeStore.otherColor.error : themeStore.themeColor, halo: true, haloStroke: node.isDeleted ? themeStore.otherColor.error : themeStore.themeColor, haloLineWidth: 6, zIndex: 2 }) } }, layout: { type: 'antv-dagre', rankdir: 'LR', ranksep: 20, nodesep: -20, controlPoints: true }, behaviors: [ { key: 'hover-activate', type: 'hover-activate', degree: 1, direction: 'both' }, 'drag-canvas', ...behaviors ], plugins: [ { type: 'tooltip', enable: (event: IPointerEvent) => event.targetType === 'node', getContent: (_event: IPointerEvent, items?: CustomNodeData[]) => { let result = '
'; // 弹出提示可以自定义各种内容,但是这里很奇怪,有的class不跟随unocss的样式 items?.forEach(item => { result += `

${item.name}

`; result += `
状态:
${nodeStatus[item.status as keyof typeof nodeStatus].type}
`; result += `
`; result += `
预计开始
${item.startDate || '-'}
`; result += `
预计结束
${item.endDate || '-'}
`; result += `
实际开始
${item.actualStartDate || '-'}
`; result += `
实际结束
${item.actualEndDate || '-'}
`; result += `
`; }); result += '
'; return result; } } ] }); graph.render(); return { graph }; }