index.tsx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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. zIndex: 0,
  141. // attr: JSON.stringify(item.attrs),
  142. };
  143. });
  144. console.log(simpleNodes);
  145. console.log(JSON.stringify(data));
  146. cb?.(JSON.stringify(data), JSON.stringify(simpleNodes));
  147. return data;
  148. },
  149. }
  150. );
  151. },
  152. }));
  153. /**
  154. * @param app 当前XFlow工作空间
  155. * @param extensionRegistry 当前XFlow配置项
  156. */
  157. const onLoad: IAppLoad = async app => {
  158. appRef.current = app;
  159. graphRef.current = await app.getGraphInstance();
  160. // graphRef.current.disableSnapline()
  161. renderGraph();
  162. };
  163. const renderGraph = () => {
  164. if (flowDetail.nodes.length == 0 || !appRef.current) return;
  165. initGraphCmds(appRef.current, flowDetail);
  166. // 设置选中状态
  167. const node = flowDetail.nodes.find(item => item.isCheck);
  168. if (node) {
  169. const args = {
  170. nodeIds: [node.id],
  171. resetSelection: true,
  172. };
  173. setTimeout(() => {
  174. appRef.current.commandService.executeCommand(XFlowNodeCommands.SELECT_NODE.id, args);
  175. }, 100);
  176. }
  177. };
  178. const getConfig = () => {
  179. const defaultOption = {
  180. grid: 1,
  181. mousewheel: {
  182. enabled: true,
  183. /** 将鼠标位置作为中心缩放 */
  184. zoomAtMousePosition: true,
  185. },
  186. resizing: {
  187. enabled: true,
  188. minWidth: 0,
  189. minHeight: 0,
  190. preserveAspectRatio: false,
  191. },
  192. snapline: false,
  193. };
  194. if (isEdit) {
  195. // 非管理员编辑
  196. if (meta.editMode == 2) {
  197. return {
  198. ...defaultOption,
  199. grid: false,
  200. selecting: {
  201. enabled: true,
  202. showNodeSelectionBox: true,
  203. },
  204. interacting: false,
  205. mousewheel: false,
  206. connecting: {
  207. highlight: false,
  208. allowBlank: false,
  209. allowPort: false,
  210. dangling: false,
  211. },
  212. };
  213. } else {
  214. // 管理员编辑
  215. return defaultOption;
  216. }
  217. } else {
  218. return {
  219. ...defaultOption,
  220. grid: false,
  221. resizing: false,
  222. panning: false,
  223. selecting: {
  224. enabled: true,
  225. showNodeSelectionBox: true,
  226. movable: false,
  227. },
  228. interacting: false,
  229. mousewheel: false,
  230. connecting: {
  231. highlight: false,
  232. allowBlank: false,
  233. allowPort: false,
  234. dangling: false,
  235. },
  236. };
  237. }
  238. };
  239. useEffect(() => {
  240. if (graphRef.current) {
  241. graphRef.current.on('node:click', (...arg) => {
  242. console.log(arg);
  243. });
  244. }
  245. }, [graphRef]);
  246. useEffect(() => {
  247. renderGraph();
  248. }, [flowDetail, appRef.current]);
  249. return (
  250. <XFlow
  251. className="flow-user-custom-clz"
  252. commandConfig={commandConfig}
  253. onLoad={onLoad}
  254. meta={meta}
  255. >
  256. <FlowchartNodePanel
  257. registerNode={{
  258. title: '节点',
  259. key: 'custom',
  260. nodes: registerNode,
  261. }}
  262. showOfficial={false}
  263. defaultActiveKey={['custom']}
  264. position={{ width: 162, top: 40, bottom: 0, left: isEdit && meta.editMode == 1 ? 0 : -999 }}
  265. />
  266. {isEdit && (
  267. <CanvasToolbar
  268. className="xflow-workspace-toolbar-top"
  269. layout="horizontal"
  270. config={toolbarConfig}
  271. position={{ top: 0, left: 0, right: 0, bottom: 0 }}
  272. />
  273. )}
  274. <FlowchartCanvas
  275. config={getConfig()}
  276. position={{ top: isEdit ? 40 : 0, left: 0, right: 0, bottom: 0 }}
  277. >
  278. {isEdit && (
  279. <>
  280. <CanvasScaleToolbar
  281. layout="horizontal"
  282. position={{ top: -40, right: 0 }}
  283. style={{
  284. width: 150,
  285. left: 'auto',
  286. height: 39,
  287. }}
  288. />
  289. <CanvasContextMenu config={menuConfig} />
  290. <CanvasSnapline color="#faad14" />
  291. <CanvasNodePortTooltip />
  292. </>
  293. )}
  294. </FlowchartCanvas>
  295. {isEdit && (
  296. <>
  297. <FlowchartExtension />
  298. {/* <FlowchartFormPanel show={true} position={{ width: 200, top: 40, bottom: 0, right: 0 }} /> */}
  299. <CustomFlowchartFormPanel />
  300. <KeyBindings config={keybindingConfig} />
  301. </>
  302. )}
  303. </XFlow>
  304. );
  305. };
  306. // 高阶组件
  307. const DemoHoc = Demo => {
  308. const forwardRef = (props, ref) => {
  309. return <Demo parentRef={ref} {...props}></Demo>;
  310. };
  311. return React.forwardRef(forwardRef);
  312. };
  313. export default DemoHoc(Demo);