WorkflowBuilder.vue 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <template>
  2. <div
  3. id="drawflow"
  4. class="parent-drawflow relative"
  5. @drop="dropHandler"
  6. @dragover.prevent
  7. >
  8. <div class="absolute z-10 p-4 bottom-0 left-0">
  9. <button class="p-2 rounded-lg bg-white mr-2" @click="editor.zoom_reset()">
  10. <v-remixicon name="riFullscreenLine" />
  11. </button>
  12. <div class="rounded-lg bg-white inline-block">
  13. <button class="p-2 rounded-lg relative z-10" @click="editor.zoom_out()">
  14. <v-remixicon name="riSubtractLine" />
  15. </button>
  16. <hr class="h-6 border-r inline-block" />
  17. <button class="p-2 rounded-lg" @click="editor.zoom_in()">
  18. <v-remixicon name="riAddLine" />
  19. </button>
  20. </div>
  21. </div>
  22. </div>
  23. </template>
  24. <script>
  25. /* eslint-disable camelcase */
  26. import { onMounted, shallowRef, getCurrentInstance } from 'vue';
  27. import { tasks } from '@/utils/shared';
  28. import drawflow from '@/lib/drawflow';
  29. export default {
  30. props: {
  31. data: {
  32. type: [Object, String],
  33. default: null,
  34. },
  35. },
  36. emits: ['addBlock', 'export', 'load', 'deleteBlock'],
  37. setup(props, { emit }) {
  38. const editor = shallowRef(null);
  39. function dropHandler({ dataTransfer, clientX, clientY }) {
  40. const block = JSON.parse(dataTransfer.getData('block') || null);
  41. const isTriggerExists =
  42. block.id === 'trigger' &&
  43. editor.value.getNodesFromName('trigger').length !== 0;
  44. if (!block || isTriggerExists) return;
  45. const xPosition =
  46. clientX *
  47. (editor.value.precanvas.clientWidth /
  48. (editor.value.precanvas.clientWidth * editor.value.zoom)) -
  49. editor.value.precanvas.getBoundingClientRect().x *
  50. (editor.value.precanvas.clientWidth /
  51. (editor.value.precanvas.clientWidth * editor.value.zoom));
  52. const yPosition =
  53. clientY *
  54. (editor.value.precanvas.clientHeight /
  55. (editor.value.precanvas.clientHeight * editor.value.zoom)) -
  56. editor.value.precanvas.getBoundingClientRect().y *
  57. (editor.value.precanvas.clientHeight /
  58. (editor.value.precanvas.clientHeight * editor.value.zoom));
  59. editor.value.addNode(
  60. block.id,
  61. block.inputs,
  62. block.outputs,
  63. xPosition,
  64. yPosition,
  65. block.id,
  66. block.data,
  67. block.component,
  68. 'vue'
  69. );
  70. }
  71. function isInputAllowed(allowedInputs, input) {
  72. if (typeof allowedInputs === 'boolean') return allowedInputs;
  73. return allowedInputs.some((item) => {
  74. if (item.startsWith('#')) {
  75. return tasks[input].category === item.substr(1);
  76. }
  77. return item === input;
  78. });
  79. }
  80. onMounted(() => {
  81. const element = document.querySelector('#drawflow', getCurrentInstance());
  82. editor.value = drawflow(element);
  83. editor.value.start();
  84. emit('load', editor.value);
  85. if (props.data) {
  86. const data =
  87. typeof props.data === 'string' ? JSON.parse(props.data) : props.data;
  88. editor.value.import(data);
  89. } else {
  90. editor.value.addNode(
  91. 'trigger',
  92. 0,
  93. 1,
  94. 50,
  95. 300,
  96. 'trigger',
  97. { type: 'manual' },
  98. 'BlockBasic',
  99. 'vue'
  100. );
  101. }
  102. editor.value.on('nodeRemoved', (id) => {
  103. emit('deleteBlock', id);
  104. });
  105. editor.value.on(
  106. 'connectionCreated',
  107. ({ output_id, input_id, output_class, input_class }) => {
  108. const { name: outputs } = editor.value.getNodeFromId(output_id);
  109. const { name: inputName } = editor.value.getNodeFromId(input_id);
  110. const { allowedInputs, maxConnection } = tasks[inputName];
  111. const isAllowed = isInputAllowed(allowedInputs, inputName);
  112. const isMaxConnections =
  113. outputs[output_class].connections.length > maxConnection;
  114. if (!isAllowed || isMaxConnections) {
  115. editor.value.removeSingleConnection(
  116. output_id,
  117. input_id,
  118. output_class,
  119. input_class
  120. );
  121. }
  122. }
  123. );
  124. });
  125. return {
  126. editor,
  127. dropHandler,
  128. };
  129. },
  130. };
  131. </script>
  132. <style>
  133. #drawflow {
  134. background-image: url('@/assets/images/tile.png');
  135. background-size: 35px;
  136. }
  137. </style>