import Components from '@/components' import ElementPlus from 'element-plus' import * as ElementPlusIcons from '@element-plus/icons-vue' import zhCn from 'element-plus/dist/locale/zh-cn.mjs' import { HtmlResize } from '@logicflow/extension' import { h as lh } from '@logicflow/core' import { createApp, h } from 'vue' import directives from '@/directives' import i18n from '@/locales' import { WorkflowType } from '@/enums/workflow' import { nodeDict } from '@/workflow/common/data' class AppNode extends HtmlResize.view { isMounted r app constructor(props: any, VueNode: any) { super(props) this.isMounted = false this.r = h(VueNode, { properties: props.model.properties, nodeModel: props.model }) this.app = createApp({ render: () => this.r }) this.app.use(ElementPlus, { locale: zhCn }) this.app.use(Components) this.app.use(directives) this.app.use(i18n) for (const [key, component] of Object.entries(ElementPlusIcons)) { this.app.component(key, component) } if (props.model.properties.noRender) { delete props.model.properties.noRender } else { const filterNodes = props.graphModel.nodes.filter((v: any) => v.type === props.model.type) if (filterNodes.length - 1 > 0) { props.model.properties.stepName = props.model.properties.stepName + (filterNodes.length - 1) } } props.model.properties.config = nodeDict[props.model.type].properties.config if (props.model.properties.height) { props.model.height = props.model.properties.height } } getAnchorShape(anchorData: any) { const { x, y, type } = anchorData let isConnect = false if (type == 'left') { isConnect = this.props.graphModel.edges.some((edge) => edge.targetAnchorId == anchorData.id) } else { isConnect = this.props.graphModel.edges.some((edge) => edge.sourceAnchorId == anchorData.id) } return lh( 'foreignObject', { ...anchorData, x: x - 10, y: y - 12, width: 30, height: 30 }, [ lh('div', { style: { zindex: 0 }, onClick: () => { if (type == 'right') { this.props.model.openNodeMenu(anchorData) } }, dangerouslySetInnerHTML: { __html: isConnect ? ` ` : ` ` } }) ] ) } setHtml(rootEl: HTMLElement) { if (!this.isMounted) { this.isMounted = true const node = document.createElement('div') rootEl.appendChild(node) this.app?.mount(node) } else { if (this.r && this.r.component) { this.r.component.props.properties = this.props.model.getProperties() } } } } class AppNodeModel extends HtmlResize.model { getResizeOutlineStyle() { const style = super.getResizeOutlineStyle() style.stroke = 'none' return style } getControlPointStyle() { const style = super.getControlPointStyle() style.stroke = 'none' style.fill = 'none' return style } getNodeStyle() { return { overflow: 'visible' } } getOutlineStyle() { const style = super.getOutlineStyle() style.stroke = 'none' if (style.hover) { style.hover.stroke = 'none' } return style } // 如果不用修改锚地形状,可以重写颜色相关样式 getAnchorStyle(anchorInfo: any) { const style = super.getAnchorStyle(anchorInfo) if (anchorInfo.type === 'left') { style.fill = 'red' style.hover.fill = 'transparent' style.hover.stroke = 'transpanrent' style.className = 'lf-hide-default' } else { style.fill = 'green' } return style } setHeight(height: number) { const sourceHeight = this.height const targetHeight = height + 100 this.height = targetHeight this.properties['height'] = targetHeight this.move(0, (targetHeight - sourceHeight) / 2) this.outgoing.edges.forEach((edge: any) => { // 调用自定义的更新方案 edge.updatePathByAnchor() }) this.incoming.edges.forEach((edge: any) => { // 调用自定义的更新方案 edge.updatePathByAnchor() }) } get_width() { return this.properties?.width || 340 } setAttributes() { this.width = this.get_width() const isLoop=(node_id:string,target_node_id:string)=>{ const up_node_list=this.graphModel.getNodeIncomingNode(node_id) for (const index in up_node_list) { const item=up_node_list[index] if(item.id===target_node_id){ return true }else{ const result= isLoop(item.id,target_node_id) if(result){ return true } } } return false } const circleOnlyAsTarget = { message: '只允许从右边的锚点连出', validate: (sourceNode: any, targetNode: any, sourceAnchor: any) => { return sourceAnchor.type === 'right' } } this.sourceRules.push({ message: '不可循环连线', validate: (sourceNode: any, targetNode: any, sourceAnchor: any, targetAnchor: any) => { return !isLoop(sourceNode.id,targetNode.id) } }) this.sourceRules.push(circleOnlyAsTarget) this.targetRules.push({ message: '只允许连接左边的锚点', validate: (sourceNode: any, targetNode: any, sourceAnchor: any, targetAnchor: any) => { return targetAnchor.type === 'left' } }) } getDefaultAnchor() { const { id, x, y, width } = this const anchors: any = [] if (this.type !== WorkflowType.Base) { if (this.type !== WorkflowType.Start) { anchors.push({ x: x - width / 2 + 10, y: y, id: `${id}_left`, edgeAddable: false, type: 'left' }) } anchors.push({ x: x + width / 2 - 10, y: y, id: `${id}_right`, type: 'right' }) } return anchors } } export { AppNodeModel, AppNode }