后面两篇咱们介绍了阿里的表单设计器及利用,本篇咱们将回归咱们的流程设计,将表单模板和流程可视化的编辑性能关联起来,批改表单模板就能批改节点或连线的属性编辑,达到真正的动静属性编辑成果。
通用表单渲染
咱们把之前的表单模板的预览革新一下,提供一个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地址:链接