index.tsx 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. import { IAppLoad, NsGraphCmd } from '@antv/xflow';
  2. import React, { useRef, useEffect, useImperativeHandle } from 'react';
  3. /** 交互组件 */
  4. import {
  5. /** XFlow核心组件 */
  6. XFlow,
  7. /** 流程图画布组件 */
  8. FlowchartCanvas,
  9. /** 流程图配置扩展 */
  10. FlowchartExtension,
  11. /** 流程图节点组件 */
  12. FlowchartNodePanel,
  13. /** 流程图表单组件 */
  14. FlowchartFormPanel,
  15. /** 通用组件:快捷键 */
  16. KeyBindings,
  17. /** 通用组件:画布缩放 */
  18. CanvasScaleToolbar,
  19. /** 通用组件:右键菜单 */
  20. CanvasContextMenu,
  21. /** 通用组件:工具栏 */
  22. CanvasToolbar,
  23. /** 通用组件:对齐线 */
  24. CanvasSnapline,
  25. /** 通用组件:节点连接桩 */
  26. CanvasNodePortTooltip,
  27. IApplication,
  28. XFlowNodeCommands,
  29. } from '@antv/xflow';
  30. import { Graph } from '@antv/x6';
  31. /** 配置Command*/
  32. import { useCmdConfig, initGraphCmds } from './config-cmd';
  33. /** 配置Menu */
  34. import { useMenuConfig } from './config-menu';
  35. /** 配置Toolbar */
  36. import { TOOLBAR_ITEMS, useToolbarConfig } from './config-toolbar';
  37. /** 配置快捷键 */
  38. import { useKeybindingConfig } from './config-keybinding';
  39. import { registerNode } from './node/registerNode';
  40. import CustomFlowchartFormPanel from './node/FlowFormPanel';
  41. /** 配置Dnd组件面板 */
  42. // import CustomCircle from './react-node/CustomCircle';
  43. // import CustomRect from './react-node/CustomRect';
  44. import '@antv/xflow/dist/index.css';
  45. import './index.less';
  46. import { TYPE } from './node/auditNode/mapServe';
  47. export interface IProps {
  48. meta: { flowId: string; type: 'edit' };
  49. flowDetail: any;
  50. onSelectNode?: Function;
  51. parentRef?: any;
  52. }
  53. export const Demo: React.FC<IProps> = props => {
  54. const { meta, flowDetail, parentRef } = props;
  55. const isEdit = meta.type == 'edit';
  56. const toolbarConfig = useToolbarConfig();
  57. const menuConfig = useMenuConfig();
  58. const keybindingConfig = useKeybindingConfig();
  59. const graphRef = useRef<Graph>();
  60. const appRef = useRef<IApplication>();
  61. const commandConfig: any = useCmdConfig(props);
  62. // 封装供外部主动调用的接口
  63. useImperativeHandle(parentRef, () => ({
  64. getGraphData: async cb => {
  65. appRef.current.commandService.executeCommand<NsGraphCmd.SaveGraphData.IArgs>(
  66. TOOLBAR_ITEMS.SAVE_GRAPH_DATA,
  67. {
  68. saveGraphDataService: (meta, graphData) => {
  69. let data = JSON.parse(JSON.stringify(graphData));
  70. let simpleNodes = data?.nodes?.map(curNode => {
  71. let childrenNodes = data.edges
  72. .map(edge => {
  73. if (edge.source?.cell == curNode.id) {
  74. return data.nodes.find(item => item.id == edge.target?.cell);
  75. }
  76. })
  77. .filter(item => item);
  78. //按优先级排序子节点
  79. const children = childrenNodes
  80. .sort((a, b) => a.priority - b.priority)
  81. .map(item => item.id);
  82. const node = {
  83. id: curNode.id,
  84. type: curNode.type,
  85. //条件节点
  86. formItems:
  87. curNode.type == TYPE.JUDGE && !curNode.formItems ? '[]' : curNode.formItems,
  88. priority: curNode.priority,
  89. //审批节点
  90. initiator: curNode.type == TYPE.INITIATOR ? curNode.initiator : null,
  91. audits: curNode.type == TYPE.AUDIT ? curNode.audits : null,
  92. children: children,
  93. };
  94. return node;
  95. });
  96. data.nodes = data.nodes.map(item => {
  97. let newItem = JSON.parse(JSON.stringify(item));
  98. delete newItem.incomingEdges;
  99. delete newItem.originData;
  100. delete newItem.outgoingEdges;
  101. delete newItem.ports.groups;
  102. // let ports = { ...item.ports };
  103. // delete ports.groups;
  104. // return {
  105. // id: item.id,
  106. // renderKey: item.renderKey,
  107. // name: item.name,
  108. // label: item.label,
  109. // width: item.width,
  110. // height: item.height,
  111. // ports: ports,
  112. // isCustom: item.isCustom,
  113. // parentKey: item.parentKey,
  114. // x: item.x,
  115. // y: item.y,
  116. // zIndex: item.zIndex,
  117. // count: item.count,
  118. // };
  119. return newItem;
  120. });
  121. // graphData.edges = []
  122. data.edges = data.edges.map(item => {
  123. // delete item.data;
  124. // delete item.attrs;
  125. // delete item.sourcePort;
  126. // delete item.sourcePortId;
  127. // delete item.targetPort;
  128. // delete item.targetPortId;
  129. // delete item.zIndex;
  130. return {
  131. id: item.id,
  132. source: item.source,
  133. target: item.target,
  134. // attr: JSON.stringify(item.attrs),
  135. };
  136. });
  137. console.log(simpleNodes);
  138. console.log(JSON.stringify(data));
  139. cb?.(JSON.stringify(data), JSON.stringify(simpleNodes));
  140. return data;
  141. },
  142. }
  143. );
  144. },
  145. }));
  146. /**
  147. * @param app 当前XFlow工作空间
  148. * @param extensionRegistry 当前XFlow配置项
  149. */
  150. const onLoad: IAppLoad = async app => {
  151. appRef.current = app;
  152. graphRef.current = await app.getGraphInstance();
  153. // graphRef.current.disableSnapline()
  154. renderGraph();
  155. };
  156. const renderGraph = () => {
  157. if (flowDetail.nodes.length == 0 || !appRef.current) return;
  158. initGraphCmds(appRef.current, flowDetail);
  159. // 设置选中状态
  160. const node = flowDetail.nodes.find(item => item.isCheck);
  161. if (node) {
  162. const args = {
  163. nodeIds: [node.id],
  164. resetSelection: true,
  165. };
  166. setTimeout(() => {
  167. appRef.current.commandService.executeCommand(XFlowNodeCommands.SELECT_NODE.id, args);
  168. }, 100);
  169. }
  170. };
  171. const getConfig = () => {
  172. const defaultOption = {
  173. grid: 1,
  174. mousewheel: {
  175. enabled: true,
  176. /** 将鼠标位置作为中心缩放 */
  177. zoomAtMousePosition: true,
  178. },
  179. resizing: {
  180. enabled: true,
  181. minWidth: 0,
  182. minHeight: 0,
  183. preserveAspectRatio: false,
  184. },
  185. snapline: false,
  186. };
  187. return isEdit
  188. ? defaultOption
  189. : {
  190. ...defaultOption,
  191. grid: false,
  192. resizing: false,
  193. panning: false,
  194. selecting: {
  195. enabled: true,
  196. showNodeSelectionBox: true,
  197. },
  198. interacting: false,
  199. mousewheel: false,
  200. connecting: {
  201. highlight: false,
  202. allowBlank: false,
  203. allowPort: false,
  204. dangling: false,
  205. },
  206. };
  207. };
  208. useEffect(() => {
  209. if (graphRef.current) {
  210. graphRef.current.on('node:click', (...arg) => {
  211. console.log(arg);
  212. });
  213. }
  214. }, [graphRef]);
  215. useEffect(() => {
  216. renderGraph();
  217. }, [flowDetail, appRef.current]);
  218. return (
  219. <XFlow
  220. className="flow-user-custom-clz"
  221. commandConfig={commandConfig}
  222. onLoad={onLoad}
  223. meta={meta}
  224. >
  225. <FlowchartNodePanel
  226. registerNode={{
  227. title: '节点',
  228. key: 'custom',
  229. nodes: registerNode,
  230. }}
  231. showOfficial={false}
  232. defaultActiveKey={['custom']}
  233. position={{ width: 162, top: 40, bottom: 0, left: isEdit ? 0 : -999 }}
  234. />
  235. {isEdit && (
  236. <CanvasToolbar
  237. className="xflow-workspace-toolbar-top"
  238. layout="horizontal"
  239. config={toolbarConfig}
  240. position={{ top: 0, left: 0, right: 0, bottom: 0 }}
  241. />
  242. )}
  243. <FlowchartCanvas
  244. config={getConfig()}
  245. position={{ top: isEdit ? 40 : 0, left: 0, right: 0, bottom: 0 }}
  246. >
  247. {isEdit && (
  248. <>
  249. <CanvasScaleToolbar
  250. layout="horizontal"
  251. position={{ top: -40, right: 0 }}
  252. style={{
  253. width: 150,
  254. left: 'auto',
  255. height: 39,
  256. }}
  257. />
  258. <CanvasContextMenu config={menuConfig} />
  259. <CanvasSnapline color="#faad14" />
  260. <CanvasNodePortTooltip />
  261. </>
  262. )}
  263. </FlowchartCanvas>
  264. {isEdit && (
  265. <>
  266. <FlowchartExtension />
  267. {/* <FlowchartFormPanel show={true} position={{ width: 200, top: 40, bottom: 0, right: 0 }} /> */}
  268. <CustomFlowchartFormPanel />
  269. <KeyBindings config={keybindingConfig} />
  270. </>
  271. )}
  272. </XFlow>
  273. );
  274. };
  275. // 高阶组件
  276. const DemoHoc = Demo => {
  277. const forwardRef = (props, ref) => {
  278. return <Demo parentRef={ref} {...props}></Demo>;
  279. };
  280. return React.forwardRef(forwardRef);
  281. };
  282. export default DemoHoc(Demo);