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

通用表单渲染

咱们把之前的表单模板的预览革新一下,提供一个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<PreviewProps> = ({ 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 (    <Modal      title="模板预览"      visible={visible}      onCancel={handleCancel}      footer={null}    >      <Form form={normalForm} onAutoSubmit={console.log} {...params.form}>        <SchemaField schema={params.schema} />        <Submit block>保留</Submit>      </Form>    </Modal>  );};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<NodeComponentProps> = (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 (    <div className={styles.nodeComponent}>      <Header title="节点编辑" />      <div className="formBox">        {schema && Object.keys(schema)?.length ? (          <Form {...formProps} form={form} onAutoSubmit={onFinish}>            <SchemaField schema={schema} />            {readOnly ? null : <Submit block>保留</Submit>}          </Form>        ) : (          <Empty            image={Empty.PRESENTED_IMAGE_SIMPLE}            description="无表单模板"          />        )}      </div>      {readOnly ? null : (        <div className="delBtn">          <Button size="large" block danger onClick={delBtn}>            删除节点          </Button>        </div>      )}    </div>  );};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<EdgeComponentProps> = (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 (    <div className={styles.edgeComponent}>      <Header title="连线编辑" />      <div className="formBox">        {schema && Object.keys(schema)?.length ? (          <Form {...formProps} form={form} onAutoSubmit={onFinish}>            <SchemaField schema={schema} />            {readOnly ? null : <Submit block>保留</Submit>}          </Form>        ) : (          <Empty            image={Empty.PRESENTED_IMAGE_SIMPLE}            description="无表单模板"          />        )}      </div>      {readOnly ? null : (        <div className="delBtn">          <Button size="large" block danger onClick={delBtn}>            删除连线          </Button>        </div>      )}    </div>  );};export default EdgeComponent;

去表单模板建设一个模板,并配置一下,回到流程图点击节点编辑一下,看是否与表单模板预览的展现一样,批改模板的表单配置,流程图的会同步批改:

好了,动静表单与自定义属性的增加相结合就实现了,一个次要性能较为齐全的流程可视化设计就曾经实现了,然而还有一些细节上的货色须要打磨一下,接下来几篇为细节的优化补充阐明,敬请期待。

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