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