index.tsx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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 { Collapse } from 'antd';
  46. import './index.less';
  47. import { TYPE } from './node/auditNode/mapServe';
  48. const { Panel } = Collapse;
  49. export interface IProps {
  50. meta: {
  51. flowId: string;
  52. type: 'edit';
  53. editMode?: number; // 1. 管理员编辑 2. 普通编辑
  54. };
  55. flowDetail: any;
  56. onSelectNode?: Function;
  57. parentRef?: any;
  58. }
  59. export const Demo: React.FC<IProps> = props => {
  60. const { meta, flowDetail, parentRef } = props;
  61. const isEdit = meta.type == 'edit';
  62. const toolbarConfig = useToolbarConfig();
  63. const menuConfig = useMenuConfig();
  64. const keybindingConfig = useKeybindingConfig();
  65. const graphRef = useRef<Graph>();
  66. const appRef = useRef<IApplication>();
  67. const commandConfig: any = useCmdConfig(props);
  68. // 封装供外部主动调用的接口
  69. useImperativeHandle(parentRef, () => ({
  70. getGraphData: async cb => {
  71. appRef.current.commandService.executeCommand<NsGraphCmd.SaveGraphData.IArgs>(
  72. TOOLBAR_ITEMS.SAVE_GRAPH_DATA,
  73. {
  74. saveGraphDataService: (meta, graphData) => {
  75. let data = JSON.parse(JSON.stringify(graphData));
  76. let simpleNodes = data?.nodes?.map(curNode => {
  77. let childrenNodes = data.edges
  78. .map(edge => {
  79. if (edge.source?.cell == curNode.id) {
  80. return data.nodes.find(item => item.id == edge.target?.cell);
  81. }
  82. })
  83. .filter(item => item);
  84. //按优先级排序子节点
  85. const children = childrenNodes
  86. .sort((a, b) => a.priority - b.priority)
  87. .map(item => item.id);
  88. const node = {
  89. id: curNode.id,
  90. type: curNode.type,
  91. //条件节点
  92. formItems:
  93. curNode.type == TYPE.JUDGE && !curNode.formItems ? '[]' : curNode.formItems,
  94. priority: curNode.priority,
  95. //审批节点
  96. initiator: curNode.type == TYPE.INITIATOR ? curNode.initiator : null,
  97. audits: curNode.audits,
  98. children: children,
  99. };
  100. return node;
  101. });
  102. data.nodes = data.nodes.map(item => {
  103. let newItem = JSON.parse(JSON.stringify(item));
  104. delete newItem.incomingEdges;
  105. delete newItem.originData;
  106. delete newItem.outgoingEdges;
  107. delete newItem.ports.groups;
  108. // let ports = { ...item.ports };
  109. // delete ports.groups;
  110. // return {
  111. // id: item.id,
  112. // renderKey: item.renderKey,
  113. // name: item.name,
  114. // label: item.label,
  115. // width: item.width,
  116. // height: item.height,
  117. // ports: ports,
  118. // isCustom: item.isCustom,
  119. // parentKey: item.parentKey,
  120. // x: item.x,
  121. // y: item.y,
  122. // zIndex: item.zIndex,
  123. // count: item.count,
  124. // };
  125. return newItem;
  126. });
  127. // graphData.edges = []
  128. data.edges = data.edges.map(item => {
  129. // delete item.data;
  130. // delete item.attrs;
  131. // delete item.sourcePort;
  132. // delete item.sourcePortId;
  133. // delete item.targetPort;
  134. // delete item.targetPortId;
  135. // delete item.zIndex;
  136. return {
  137. id: item.id,
  138. source: item.source,
  139. target: item.target,
  140. // attr: JSON.stringify(item.attrs),
  141. };
  142. });
  143. console.log(simpleNodes);
  144. console.log(JSON.stringify(data));
  145. cb?.(JSON.stringify(data), JSON.stringify(simpleNodes));
  146. return data;
  147. },
  148. }
  149. );
  150. },
  151. }));
  152. /**
  153. * @param app 当前XFlow工作空间
  154. * @param extensionRegistry 当前XFlow配置项
  155. */
  156. const onLoad: IAppLoad = async app => {
  157. appRef.current = app;
  158. graphRef.current = await app.getGraphInstance();
  159. // graphRef.current.disableSnapline()
  160. renderGraph();
  161. };
  162. const renderGraph = () => {
  163. if (flowDetail.nodes.length == 0 || !appRef.current) return;
  164. initGraphCmds(appRef.current, flowDetail);
  165. // 设置选中状态
  166. const node = flowDetail.nodes.find(item => item.isCheck);
  167. if (node) {
  168. const args = {
  169. nodeIds: [node.id],
  170. resetSelection: true,
  171. };
  172. setTimeout(() => {
  173. appRef.current.commandService.executeCommand(XFlowNodeCommands.SELECT_NODE.id, args);
  174. }, 100);
  175. }
  176. };
  177. const getConfig = () => {
  178. const defaultOption = {
  179. grid: 1,
  180. mousewheel: {
  181. enabled: true,
  182. /** 将鼠标位置作为中心缩放 */
  183. zoomAtMousePosition: true,
  184. },
  185. resizing: {
  186. enabled: true,
  187. minWidth: 0,
  188. minHeight: 0,
  189. preserveAspectRatio: false,
  190. },
  191. snapline: false,
  192. };
  193. if (isEdit) {
  194. // 非管理员编辑
  195. if (meta.editMode == 2) {
  196. return {
  197. ...defaultOption,
  198. grid: false,
  199. selecting: {
  200. enabled: true,
  201. showNodeSelectionBox: true,
  202. },
  203. interacting: false,
  204. mousewheel: false,
  205. connecting: {
  206. highlight: false,
  207. allowBlank: false,
  208. allowPort: false,
  209. dangling: false,
  210. },
  211. };
  212. } else {
  213. // 管理员编辑
  214. return defaultOption;
  215. }
  216. } else {
  217. return {
  218. ...defaultOption,
  219. grid: false,
  220. resizing: false,
  221. panning: false,
  222. selecting: {
  223. enabled: true,
  224. showNodeSelectionBox: true,
  225. movable: false,
  226. },
  227. interacting: false,
  228. mousewheel: false,
  229. connecting: {
  230. highlight: false,
  231. allowBlank: false,
  232. allowPort: false,
  233. dangling: false,
  234. },
  235. };
  236. }
  237. };
  238. useEffect(() => {
  239. if (graphRef.current) {
  240. graphRef.current.on('node:click', (...arg) => {
  241. console.log(arg);
  242. });
  243. }
  244. }, [graphRef]);
  245. useEffect(() => {
  246. renderGraph();
  247. }, [flowDetail, appRef.current]);
  248. return (
  249. <XFlow
  250. className="flow-user-custom-clz"
  251. commandConfig={commandConfig}
  252. onLoad={onLoad}
  253. meta={meta}
  254. >
  255. <FlowchartNodePanel
  256. registerNode={{
  257. title: '节点',
  258. key: 'custom',
  259. nodes: registerNode,
  260. }}
  261. showOfficial={false}
  262. defaultActiveKey={['custom']}
  263. position={{ width: 162, top: 40, bottom: 0, left: isEdit && meta.editMode == 1 ? 0 : -999 }}
  264. />
  265. {isEdit && (
  266. <CanvasToolbar
  267. className="xflow-workspace-toolbar-top"
  268. layout="horizontal"
  269. config={toolbarConfig}
  270. position={{ top: 0, left: 0, right: 0, bottom: 0 }}
  271. />
  272. )}
  273. <FlowchartCanvas
  274. config={getConfig()}
  275. position={{ top: isEdit ? 40 : 0, left: 0, right: 0, bottom: 0 }}
  276. >
  277. {isEdit && (
  278. <>
  279. <CanvasScaleToolbar
  280. layout="horizontal"
  281. position={{ top: -40, right: 0 }}
  282. style={{
  283. width: 150,
  284. left: 'auto',
  285. height: 39,
  286. }}
  287. />
  288. <CanvasContextMenu config={menuConfig} />
  289. <CanvasSnapline color="#faad14" />
  290. <CanvasNodePortTooltip />
  291. </>
  292. )}
  293. </FlowchartCanvas>
  294. {isEdit && (
  295. <>
  296. <FlowchartExtension />
  297. {/* <FlowchartFormPanel show={true} position={{ width: 200, top: 40, bottom: 0, right: 0 }} /> */}
  298. <CustomFlowchartFormPanel />
  299. <KeyBindings config={keybindingConfig} />
  300. </>
  301. )}
  302. </XFlow>
  303. );
  304. };
  305. // 高阶组件
  306. const DemoHoc = Demo => {
  307. const forwardRef = (props, ref) => {
  308. return <Demo parentRef={ref} {...props}></Demo>;
  309. };
  310. return React.forwardRef(forwardRef);
  311. };
  312. export default DemoHoc(Demo);