网站目标人群企业网站推广技巧
最近接到一个需求是需要在前端进行工作流流程图的设计,上网找了一圈轮子,最终还是选择了GG-editor,原因是这个界面看起来相对比较简洁,我也没什么专业编辑的需求。GG-editor是用蚂蚁金服的g6可视化引擎做的,而19年g6升级到了3.x版本,于是GG-editor的作者高力也把GG-editor重构升级到了3.x版本,但是由于3.x在本文写作时仍在重构阶段,文档残缺,所以我在使用了一段时间的新版本后仍然选择了2.0.4版本,之后若是升级我会再更一篇。
在使用3.x版本的时候我遇到了两个坑,一是undo命令会有bug,在2.0.4版本中,undo命令可以撤销位置移动操作,而在3.x版本中就不行了,在github上有issue但是作者并没有响应。二是如何保存流程图,在2.0.4版本中通过调用propsAPI.save()函数来实现(下面会贴代码),但是3.x版本中没有给出示例,我尝试在源码中全局搜索save函数结果没有搜到哈哈,不过我看最近作者在github的issue中回应说新版本需要用withEditorContext,和withPropsAPI用法一样
,我没有具体尝试,之后若是升级会试一下。下面是在2.0.4版本中的保存示例,我自己加了一个弹窗确认:
import React from 'react';
import { connect } from 'dva';
import { Button, Modal, Form, Input, Icon } from 'antd';
import { withPropsAPI } from 'gg-editor';
import styles from './index.less'const CollectionCreateForm = Form.create({ name: 'save_template' })(// eslint-disable-next-lineclass extends React.Component {render() {const { visible, onCancel, onSubmit, form, isSubmitting } = this.props;const { getFieldDecorator } = form;return (<Modalvisible={visible}title="模板保存"okText="提交"onCancel={onCancel}confirmLoading={isSubmitting}onOk={onSubmit}><Form layout="vertical"><Form.Item label="模板名称">{getFieldDecorator('name', {rules: [{ required: true, message: '请输入模板名称!' }],})(<Input />)}</Form.Item><Form.Item label="描述">{getFieldDecorator('description')(<Input type="textarea" />)}</Form.Item></Form></Modal>);}},
);@connect(({ workflow, loading }) => ({workflow,isSubmitting: loading.effects['workflow/submitWorkflowTemplate'],
}))
class Save extends React.Component {constructor(props) {super(props);this.state = {modalVisible: false,};}showModal = () => {this.setState({ modalVisible: true });};handleCancel = () => {this.setState({ modalVisible: false });};saveFormRef = formRef => {this.formRef = formRef;};handleSubmit = e => {const { form } = this.formRef.props;const { dispatch } = this.props;form.validateFields((err, values) => {if (err) {return;}const { propsAPI } = this.props;const data = propsAPI.save();//将数据传换为接口所需参数let taskList = [];if (data.hasOwnProperty('edges')) {const edges = data.edges;for (let i in edges) {taskList.push({'task_id': edges[i].id,'upstream': edges[i].source,});}}const params = {name: values.name,description: values.description,task: taskList,};//上传成功后清空表单关闭弹窗dispatch({type: 'workflow/submitWorkflowTemplate',payload: params,}).then(res => {if (res && res.success) {form.resetFields();this.setState({ modalVisible: false });}});});};render() {const { isSubmitting = false } = this.props;return (<div className={styles.actionGroup}><div style={{ padding: 8 }}><Button onClick={this.showModal}><Icon type="save" />保存</Button></div><CollectionCreateFormwrappedComponentRef={this.saveFormRef}visible={this.state.modalVisible}onCancel={this.handleCancel}onSubmit={this.handleSubmit}isSubmitting={isSubmitting}/></div>);}
}export default withPropsAPI(Save);
关键代码其实就两处,一是组件要外包withPropsAPI(3.x版本要换成withEditorContext),二是从props中获取propsAPI,然后调用propsAPI.save()函数;
还有一个非常常见的需求就是将左侧拖拽区改造成树状结构,我看网上有不少人问,这里我贴一下我的解决方案。我去翻了一下antd的文档,发现树节点的标题是接受组件传入的:

所以我就进行了如下尝试,一试居然成功了:
import React from 'react';
import { Tree, Icon } from 'antd';
import { ItemPanel, Item } from 'gg-editor';
import styles from './index.less';const { TreeNode } = Tree;const FlowItemPanel = () => {const onSelect = (keys, event) => {console.log('Trigger Select', keys, event);};const onExpand = () => {console.log('Trigger Expand');};return (<ItemPanel className={styles.itemPanel}><div style={{ padding: '0 12px' }}><TreedefaultExpandAllonSelect={onSelect}onExpand={onExpand}showIcon><TreeNode title="模型节点" key="0-0"><TreeNode title={<Itemtype="node"size="184*40"shape="customModelNode"model={{label: '船舶检测模型',color_type: '#1890FF',type_icon_url: 'https://gw.alipayobjects.com/zos/rmsportal/czNEJAmyDpclFaSucYWB.svg',status: 'running',}}// src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iNTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxyZWN0IGlkPSJiIiB4PSIwIiB5PSIwIiB3aWR0aD0iODAiIGhlaWdodD0iNDgiIHJ4PSIyNCIvPjxmaWx0ZXIgeD0iLTguOCUiIHk9Ii0xMC40JSIgd2lkdGg9IjExNy41JSIgaGVpZ2h0PSIxMjkuMiUiIGZpbHRlclVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgaWQ9ImEiPjxmZU9mZnNldCBkeT0iMiIgaW49IlNvdXJjZUFscGhhIiByZXN1bHQ9InNoYWRvd09mZnNldE91dGVyMSIvPjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIvPjxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjA0IDAiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIi8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNCAyKSI+PHVzZSBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiIHhsaW5rOmhyZWY9IiNiIi8+PHVzZSBmaWxsLW9wYWNpdHk9Ii45MiIgZmlsbD0iI0Y5RjBGRiIgeGxpbms6aHJlZj0iI2IiLz48cmVjdCBzdHJva2U9IiNCMzdGRUIiIHg9Ii41IiB5PSIuNSIgd2lkdGg9Ijc5IiBoZWlnaHQ9IjQ3IiByeD0iMjMuNSIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgMikiPjx0c3BhbiB4PSIyNCIgeT0iMjkiPk1vZGVsPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg=="><span className="panel-type-icon" />船舶检测模型</Item>} key="0-0-1" isLeaf /><TreeNode title={<Itemtype="node"size="184*40"shape="customModelNode"model={{label: '场景识别模型',color_type: '#1890FF',type_icon_url: 'https://gw.alipayobjects.com/zos/rmsportal/czNEJAmyDpclFaSucYWB.svg',status: 'running',}}// src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODgiIGhlaWdodD0iNTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxyZWN0IGlkPSJiIiB4PSIwIiB5PSIwIiB3aWR0aD0iODAiIGhlaWdodD0iNDgiIHJ4PSIyNCIvPjxmaWx0ZXIgeD0iLTguOCUiIHk9Ii0xMC40JSIgd2lkdGg9IjExNy41JSIgaGVpZ2h0PSIxMjkuMiUiIGZpbHRlclVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgaWQ9ImEiPjxmZU9mZnNldCBkeT0iMiIgaW49IlNvdXJjZUFscGhhIiByZXN1bHQ9InNoYWRvd09mZnNldE91dGVyMSIvPjxmZUdhdXNzaWFuQmx1ciBzdGREZXZpYXRpb249IjIiIGluPSJzaGFkb3dPZmZzZXRPdXRlcjEiIHJlc3VsdD0ic2hhZG93Qmx1ck91dGVyMSIvPjxmZUNvbXBvc2l0ZSBpbj0ic2hhZG93Qmx1ck91dGVyMSIgaW4yPSJTb3VyY2VBbHBoYSIgb3BlcmF0b3I9Im91dCIgcmVzdWx0PSJzaGFkb3dCbHVyT3V0ZXIxIi8+PGZlQ29sb3JNYXRyaXggdmFsdWVzPSIwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwLjA0IDAiIGluPSJzaGFkb3dCbHVyT3V0ZXIxIi8+PC9maWx0ZXI+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNCAyKSI+PHVzZSBmaWxsPSIjMDAwIiBmaWx0ZXI9InVybCgjYSkiIHhsaW5rOmhyZWY9IiNiIi8+PHVzZSBmaWxsLW9wYWNpdHk9Ii45MiIgZmlsbD0iI0Y5RjBGRiIgeGxpbms6aHJlZj0iI2IiLz48cmVjdCBzdHJva2U9IiNCMzdGRUIiIHg9Ii41IiB5PSIuNSIgd2lkdGg9Ijc5IiBoZWlnaHQ9IjQ3IiByeD0iMjMuNSIvPjwvZz48dGV4dCBmb250LWZhbWlseT0iUGluZ0ZhbmdTQy1SZWd1bGFyLCBQaW5nRmFuZyBTQyIgZm9udC1zaXplPSIxMiIgZmlsbD0iIzAwMCIgZmlsbC1vcGFjaXR5PSIuNjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQgMikiPjx0c3BhbiB4PSIyNCIgeT0iMjkiPk1vZGVsPC90c3Bhbj48L3RleHQ+PC9nPjwvc3ZnPg=="><span className="panel-type-icon" />场景识别模型</Item>} key="0-0-2" isLeaf /></TreeNode></Tree></div></ItemPanel>);
};export default FlowItemPanel;
当然这里的Item是我自己自定义的,直接复制粘贴怕是用不了。
待续