processNode.vue 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <script setup lang="ts">
  2. import { toRef } from "vue";
  3. import { Handle, useNodeConnections } from "@vue-flow/core";
  4. const props = defineProps({
  5. data: {
  6. type: Object,
  7. required: true
  8. },
  9. sourcePosition: {
  10. type: String
  11. },
  12. targetPosition: {
  13. type: String
  14. }
  15. });
  16. const sourceConnections = useNodeConnections({
  17. handleType: "target"
  18. });
  19. const targetConnections = useNodeConnections({
  20. handleType: "source"
  21. });
  22. const isSender = toRef(() => sourceConnections.value.length <= 0);
  23. const isReceiver = toRef(() => targetConnections.value.length <= 0);
  24. const bgColor = toRef(() => {
  25. if (isSender.value) {
  26. return "#2563eb";
  27. }
  28. if (props.data.hasError) {
  29. return "#f87171";
  30. }
  31. if (props.data.isFinished) {
  32. return "#42B983";
  33. }
  34. if (props.data.isCancelled) {
  35. return "#fbbf24";
  36. }
  37. return "#4b5563";
  38. });
  39. const processLabel = toRef(() => {
  40. if (props.data.hasError) {
  41. return "❌";
  42. }
  43. if (props.data.isSkipped) {
  44. return "🚧";
  45. }
  46. if (props.data.isCancelled) {
  47. return "🚫";
  48. }
  49. if (isSender.value) {
  50. return "📦";
  51. }
  52. if (props.data.isFinished) {
  53. return "😎";
  54. }
  55. return "🏠";
  56. });
  57. </script>
  58. <template>
  59. <div
  60. class="process-node"
  61. :style="{
  62. backgroundColor: bgColor,
  63. boxShadow: data.isRunning ? '0 0 10px rgba(0, 0, 0, 0.5)' : ''
  64. }"
  65. >
  66. <Handle v-if="!isSender" type="target" :position="targetPosition as any">
  67. <span
  68. v-if="
  69. !data.isRunning &&
  70. !data.isFinished &&
  71. !data.isCancelled &&
  72. !data.isSkipped &&
  73. !data.hasError
  74. "
  75. >📥
  76. </span>
  77. </Handle>
  78. <Handle
  79. v-if="!isReceiver"
  80. type="source"
  81. :position="sourcePosition as any"
  82. />
  83. <div v-if="!isSender && data.isRunning" class="spinner" />
  84. <span v-else>
  85. {{ processLabel }}
  86. </span>
  87. </div>
  88. </template>
  89. <style scoped>
  90. @keyframes spin {
  91. 0% {
  92. transform: rotate(0deg);
  93. }
  94. 100% {
  95. transform: rotate(360deg);
  96. }
  97. }
  98. .process-node {
  99. display: flex;
  100. align-items: center;
  101. justify-content: center;
  102. width: 24px;
  103. height: 24px;
  104. padding: 10px;
  105. border-radius: 99px;
  106. }
  107. .process-node .vue-flow__handle {
  108. width: unset;
  109. height: unset;
  110. font-size: 12px;
  111. background: transparent;
  112. border: none;
  113. }
  114. .spinner {
  115. width: 20px;
  116. height: 20px;
  117. border: 1px solid #f3f3f3;
  118. border-top: 1px solid #2563eb;
  119. border-radius: 50%;
  120. animation: spin 1s linear infinite;
  121. }
  122. </style>