乐趣区

关于前端:xflow流程可视化自定义属性编辑

上一篇文章次要对可视化的自定义节点的增加及生成进行阐明,本篇次要介绍自定义节点的编辑性能,实现自定义节点上的各种属性的编辑。

流程图编辑面板

页面右侧的流程节点组件为 FlowchartFormPanel,和自定义节点列表的组件一样,所以咱们这里去除掉FlowchartFormPanel,应用原始的JsonSchemaForm 进行替换,实现节点属性的更新。

增加自定义属性

咱们先在创立节点时增加一些自定义属性,前面通过点击节点让属性反显在编辑框上,对其进行编辑,attribute便是咱们增加的自定义属性。

// config-dnd-panel.tsx(见上一篇阐明)export const nodeDataService: NsNodeCollapsePanel.INodeDataService =
  async () => {
    // 这里能够通过接口获取节点列表
    const resData = [
      {
        id: 1,
        renderKey: 'CustomNode',
        label: '开始',
        attrs: {
          attribute: {
            type: 'aaa',
            tag: [1, 2],
          },
          style: {
            width: 280,
            height: 40,
          },
          canvansStyle: {
            width: 120,
            height: 40,
          },
        },
      },
      {
        id: 2,
        renderKey: 'CustomConnecto',
        label: '审核节点',
        attrs: {
          attribute: {
            type: 'bbb',
            tag: [2],
          },
          style: {
            width: 80,
            height: 80,
          },
          canvansStyle: {
            width: 80,
            height: 80,
          },
        },
      },
    ];
    return [
      {
        id: 'NODE',
        header: '节点',
        children: nodeList(resData),
      },
    ];
  };

自定义编辑

首先咱们把上一章的组件 FlowchartFormPanel 删除,新建一个文件夹 CustomFlowchartFormPanel,新建index.tsxNodeComponent/index.tsxEdgeComponent/index.tsxCanvasService,这几个别离为咱们的主视图,Node 节点编辑表单,Edge连线编辑表单,Canvas主视图编辑表单。

// index.tsx
import type {
  NsNodeCmd,
  NsGraph,
  NsEdgeCmd,
  NsJsonSchemaForm,
} from '@antv/xflow';
import {
  JsonSchemaForm,
  XFlowNodeCommands,
  XFlowEdgeCommands,
} from '@antv/xflow';
import {FC} from 'react';
import {CanvasService, canvasSchema} from './CanvasService';
import NodeComponent from './NodeComponent';
import EdgeComponent from './EdgeComponent';

namespace NsJsonForm {
  export const getCustomRenderComponent: NsJsonSchemaForm.ICustomRender = (
    targetType,
    targetData,
    _modelService,
    commandService,
  ) => {const updateNode = (node: NsGraph.INodeConfig) => {
      return commandService.executeCommand<NsNodeCmd.UpdateNode.IArgs>(
        XFlowNodeCommands.UPDATE_NODE.id,
        {nodeConfig: node},
      );
    };
    const updateEdge = (edge: NsGraph.IEdgeConfig) => {
      return commandService.executeCommand<NsEdgeCmd.UpdateEdge.IArgs>(
        XFlowEdgeCommands.UPDATE_EDGE.id,
        {edgeConfig: edge, options: {} },
      );
    };
    if (targetType === 'node') {return () => (<NodeComponent updateNode={updateNode} targetData={targetData} />
      );
    }
    if (targetType === 'edge') {return () => (<EdgeComponent updateEdge={updateEdge} targetData={targetData} />
      );
    }
    if (targetType === 'canvas') {return () => <CanvasService />;
    }

    return null;
  };
  export const formSchemaService: NsJsonSchemaForm.IFormSchemaService = async (args,) => {return canvasSchema();
  };
}

const CustomFlowchartFormPanel: FC = () => {
  return (
    <JsonSchemaForm
      targetType={['canvas', 'node', 'edge']}
      formSchemaService={NsJsonForm.formSchemaService}
      getCustomRenderComponent={NsJsonForm.getCustomRenderComponent}
      position={{top: 40, bottom: 0, right: 0, width: 400}}
    />
  );
};

export default CustomFlowchartFormPanel;

咱们在 getCustomRenderComponent 判断选中的是节点、连线或者主视图返回对应的自定义编辑控件,须要留神的是本来 xflow 提供了 json 配置表单的形式,然而咱们这里是齐全自定义编辑框,故不应用内置的 controlMapService,有趣味应用内置自定义的表单渲染的同学能够查考官网文档尝试一下,留神formSchemaService 还是得返回一下,否则会处于 loading 状态。

节点编辑

节点编辑组件接管两个值,updateNode为更新节点的函数,targetData为点击节点的节点属性,咱们点击保留按钮时遍历表单为 attribute 更新对应值,Header为简略的公共 header 头,没啥可说的。

// NodeComponent/index.tsx
import {FC, useEffect, useState} from 'react';
import {Input, Form, Spin, Button, Select} from 'antd';
import {NsJsonSchemaForm} from '@antv/xflow';
import {set} from 'lodash';
import Header from '../Header';
import styles from './index.less';

const {Option} = Select;

interface NodeComponentProps {
  updateNode: any;
  targetData: NsJsonSchemaForm.TargetData;
}

const NodeComponent: FC<NodeComponentProps> = (props) => {const { updateNode, targetData} = props;
  const [loading, setLoading] = useState(true);
  const [form] = Form.useForm();

  useEffect(() => {
    form.setFieldsValue({
      label: targetData?.label,
      ...targetData?.attrs?.attribute,
    });
    setLoading(false);
  }, [targetData]);

  const onFinish = (values: any) => {
    const data: any = {...targetData,};
    Object.keys(values).forEach((key: any) => {if (key === 'label') {set(data, key, values[key]);
      } else {set(data.attrs.attribute, key, values[key]);
      }
    });
    updateNode(data);
  };

  return (<div className={styles.nodeComponent}>
      <Header title="节点编辑" />
      <Spin spinning={loading}>
        <Form form={form} onFinish={onFinish}>
          <Form.Item name="label" label="节点名">
            <Input />
          </Form.Item>
          <Form.Item name="type" label="类型">
            <Input />
          </Form.Item>
          <Form.Item name="tag" label="类型">
            <Select mode="multiple">
              <Option key={1}>1</Option>
              <Option key={2}>2</Option>
            </Select>
          </Form.Item>
          <Button type="primary" htmlType="submit">
            保留
          </Button>
        </Form>
      </Spin>
    </div>
  );
};

export default NodeComponent;

连线编辑

连线编辑和节点编辑相似,就不做过多阐明,须要留神的是连线 attrs 中初始并没有 attribute,所以咱们做了一个判断为其增加一个空attribute 属性。

// EdgeComponent/index.tsx
import {NsJsonSchemaForm} from '@antv/xflow';
import {Input, Button, Form, Spin} from 'antd';
import {set} from 'lodash';
import {FC, useEffect, useState} from 'react';
import Header from '../Header';
import styles from './index.less';
interface EdgeComponentProps {
  updateEdge: any;
  targetData: NsJsonSchemaForm.TargetData;
}

const EdgeComponent: FC<EdgeComponentProps> = (props) => {const { updateEdge, targetData} = props;
  const [loading, setLoading] = useState(true);
  const [form] = Form.useForm();

  useEffect(() => {
    form.setFieldsValue({...targetData?.attrs?.attribute,});
    setLoading(false);
  }, [targetData]);

  const onFinish = (values: any) => {
    const data: any = {...targetData,};
    Object.keys(values).forEach((key: any) => {if (!data.attrs?.attribute) {set(data.attrs, 'attribute', {});
      }
      set(data.attrs.attribute, key, values[key]);
    });
    updateEdge(data);
  };

  return (<div className={styles.edgeComponent}>
      <Header title="连线编辑" />
      <Spin spinning={loading}>
        <Form form={form} onFinish={onFinish}>
          <Form.Item name="key" label="key">
            <Input />
          </Form.Item>
          <Form.Item name="value" label="value">
            <Input />
          </Form.Item>
          <Button type="primary" htmlType="submit">
            保留
          </Button>
        </Form>
      </Spin>
    </div>
  );
};

export default EdgeComponent;

画布展现

画布这里就不作编辑了,咱们间接写点文字

// CanvasService.tsx
import Header from './Header';

const CanvasService = () => {
  return (<div style={{ padding: '15px'}}>
      <Header title="主画布" />
    </div>
  );
};

const canvasSchema = () => {
  return {
    tabs: [
      {
        /** Tab 的 title */
        name: '画布配置',
        groups: [],},
    ],
  };
};

export {CanvasService, canvasSchema};

尝试批改节点以及连线上的属性,保留后再保留整个流程(上一期咱们把数据存储在 localStorage 中)并刷新页面,再次点击节点与连线,看批改后的是否能胜利反显进去。

好了,这样咱们的自定义节点编辑就根本实现了,实现了节点以及连线上的自定义属性编辑及反显,一个根本的流程可视化性能基本上就实现了,然而呢当初的编辑性能有一些毛病,比方自定义属性须要确定其类型,咱们的编辑须要用什么控件来渲染编辑,增加属性都须要编辑控件代码增加对应的表单,不能增加任意属性,那么有什么方法能够解决这个问题,让咱们能够随便增加属性,不改变代码就能渲染成咱们想要的表单呢,这就是咱们下一篇优化的内容:应用 formliy 生成自定义表单对节点属性进行编辑,纵情期待。

本文地址:链接
本文 github 地址:链接

退出移动版