xflow流程可视化-节点编辑关联表单模板

前面两篇我们介绍了阿里的表单设计器及应用,本篇我们将回归我们的流程设计,将表单模板和流程可视化的编辑功能关联起来,修改表单模板就能修改节点或连线的属性编辑,达到真正的动态属性编辑效果。

通用表单渲染

我们把之前的表单模板的预览改造一下,提供一个formily渲染模板生成的函数。新建playground/temp-schemaField.tsx:

import React from 'react';
import { createSchemaField } from '@formily/react';
import {
  Form,
  FormItem,
  DatePicker,
  Checkbox,
  Cascader,
  Editable,
  Input,
  NumberPicker,
  Switch,
  Password,
  PreviewText,
  Radio,
  Reset,
  Select,
  Space,
  Submit,
  TimePicker,
  Transfer,
  TreeSelect,
  Upload,
  FormGrid,
  FormLayout,
  FormTab,
  FormCollapse,
  ArrayTable,
  ArrayCards,
} from '@formily/antd';
import { Card, Slider, Rate } from 'antd';

const Text: React.FC<{
  value?: string;
  content?: string;
  mode?: 'normal' | 'h1' | 'h2' | 'h3' | 'p';
}> = ({ value, mode, content, ...props }) => {
  const tagName = mode === 'normal' || !mode ? 'div' : mode;
  return React.createElement(tagName, props, value || content);
};

const TempSchemaField = (scope?: any) => {
  const SchemaField = createSchemaField({
    components: {
      Space,
      FormGrid,
      FormLayout,
      FormTab,
      FormCollapse,
      ArrayTable,
      ArrayCards,
      FormItem,
      DatePicker,
      Checkbox,
      Cascader,
      Editable,
      Input,
      Text,
      NumberPicker,
      Switch,
      Password,
      PreviewText,
      Radio,
      Reset,
      Select,
      Submit,
      TimePicker,
      Transfer,
      TreeSelect,
      Upload,
      Card,
      Slider,
      Rate,
    },
    scope,
  });
  return SchemaField;
};

export default TempSchemaField;

原来的预览playground/Preview.tsx修改为:

import { FC, Ref, useEffect, useImperativeHandle, useState } from 'react';
import { Modal } from 'antd';
import { request } from 'umi';
import { Form, Submit } from '@formily/antd';
import tempSchemaField from '@/pages/playground/temp-schemaField';
import { LgetItem } from '@/utils/storage';
import { createForm } from '@formily/core';

interface PreviewProps {
  previewRef: Ref<{ setVisible: (flag: boolean) => void }>;
  modalConfig: { [key: string]: any };
}

const Preview: FC = ({ previewRef, modalConfig }) => {
  const [visible, setVisible] = useState(false);
  const [params, setParams] = useState<{ [key: string]: any }>({});
  const normalForm = createForm({});
  const SchemaField = tempSchemaField({
    $fetch: request,
  });

  useImperativeHandle(previewRef, () => ({
    setVisible,
  }));
  useEffect(() => {
    if (modalConfig && visible) {
      const playgroundList = LgetItem('playgroundList') || [];
      const data = playgroundList.find(
        (s: { id: string }) => s.id === modalConfig.id,
      );
      setParams(data?.params || {});
    }
    request('/api/users', {
      params: {
        id: 1,
      },
    }).then((res) => {
      console.log(res);
    });
  }, [modalConfig, visible]);

  const handleCancel = () => {
    setVisible(false);
  };
  return (
    
      
保存
); }; export default Preview;

节点编辑改造

import { FC, useEffect, useState } from 'react';
import { Button, Empty, message } from 'antd';
import { NsJsonSchemaForm, useXFlowApp } from '@antv/xflow';
import { Form, Submit } from '@formily/antd';
import { createForm } from '@formily/core';
import { set } from 'lodash';
import { request } from 'umi';
import tempSchemaField from '@/pages/playground/temp-schemaField';
import Header from '../Header';
import styles from './index.less';
import { LgetItem } from '@/utils/storage';

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

const NodeComponent: FC = (props) => {
  const [formilySchema, setFormilySchema] = useState<{ [key: string]: any }>(
    {},
  );
  const { updateNode, targetData, readOnly = false } = props;
  const SchemaField = tempSchemaField({
    $fetch: request,
  });

  const xflowApp = useXFlowApp();
  const form = createForm({
    values: {
      label: targetData?.label,
      ...targetData?.attrs?.attribute,
    },
    readOnly,
  });

  const onFinish = async (values: any) => {
    const grap = await xflowApp.getGraphInstance();
    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);
    message.success('暂存成功');
    // 失去焦点
    grap.resetSelection();
  };

  const delBtn = async () => {
    const grap = await xflowApp.getGraphInstance();
    grap.removeNode(targetData!.id);
  };

  useEffect(() => {
    // 这里用接口获取节点id关联的表单模板,我简写了
    if (targetData?.renderKey) {
      const playgroundList = LgetItem('playgroundList') || [];
      setFormilySchema(playgroundList[0]?.params ?? {});
    }
  }, [targetData]);

  const { form: formProps, schema } = formilySchema;
  return (
    
{schema && Object.keys(schema)?.length ? (
{readOnly ? null : 保存} ) : ( )}
{readOnly ? null : (
)}
); }; export default NodeComponent; // index.less .nodeComponent { height: 100%; padding: 0 16px; display: flex; flex-direction: column; justify-content: space-between; :global { .formBox { flex: 1; overflow: auto; padding-bottom: 16px; box-sizing: border-box; } .delBtn { flex: 0 0 40px; height: 40px; margin-bottom: 16px; } } }

连线编辑改造

import { FC, useEffect, useState } from 'react';
import { Empty, Button } from 'antd';
import { useXFlowApp, NsJsonSchemaForm } from '@antv/xflow';
import { Form, Submit } from '@formily/antd';
import { createForm } from '@formily/core';
import { set } from 'lodash';
import { request } from 'umi';
import tempSchemaField from '@/pages/playground/temp-schemaField';
import Header from '../Header';
import styles from './index.less';
import { LgetItem } from '@/utils/storage';

interface EdgeComponentProps {
  updateEdge: any;
  targetData: NsJsonSchemaForm.TargetData;
  readOnly?: boolean;
}

const EdgeComponent: FC = (props) => {
  const [formilySchema, setFormilySchema] = useState<{ [key: string]: any }>(
    {},
  );
  const { updateEdge, targetData, readOnly = false } = props;
  const SchemaField = tempSchemaField({
    $fetch: request,
  });

  const xflowApp = useXFlowApp();

  const form = createForm({
    values: targetData!.attrs ?? {},
    readOnly,
  });

  const onFinish = async (values: any) => {
    const grap = await xflowApp.getGraphInstance();
    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);
    grap.resetSelection();
  };

  const delBtn = async () => {
    const grap = await xflowApp.getGraphInstance();
    grap.removeEdge(targetData!.id);
  };

  useEffect(() => {
    // 这里用接口获取节点id关联的表单模板,我简写了
    const playgroundList = LgetItem('playgroundList') || [];
    setFormilySchema(playgroundList[0]?.params ?? {});
  }, []);

  const { form: formProps, schema } = formilySchema;

  return (
    
{schema && Object.keys(schema)?.length ? (
{readOnly ? null : 保存} ) : ( )}
{readOnly ? null : (
)}
); }; export default EdgeComponent;

去表单模板建立一个模板,并配置一下,回到流程图点击节点编辑一下,看是否与表单模板预览的展示一样,修改模板的表单配置,流程图的会同步修改:
xflow流程可视化-节点编辑关联表单模板_第1张图片

xflow流程可视化-节点编辑关联表单模板_第2张图片

好了,动态表单与自定义属性的添加相结合就完成了,一个主要功能较为齐全的流程可视化设计就已经完成了,但是还有一些细节上的东西需要打磨一下,接下来几篇为细节的优化补充说明,敬请期待。

本文地址:https://xuxin123.com/web/xflow-contact-formily
本文github地址:链接
github demo地址:链接

你可能感兴趣的:(xflow流程可视化-节点编辑关联表单模板)