|
|
@@ -1,11 +1,76 @@
|
|
|
<script setup lang="ts">
|
|
|
+import { computed } from 'vue'
|
|
|
import { Position } from '@vue-flow/core'
|
|
|
import type { NodeProps } from '@vue-flow/core'
|
|
|
+import type {
|
|
|
+ IWorkflowNode,
|
|
|
+ CanvasConnectionPort,
|
|
|
+ CanvasElementPortWithRenderData
|
|
|
+} from '../../Interface'
|
|
|
|
|
|
import { Icon } from '@repo/ui'
|
|
|
import CanvasHandle from './handles/CanvasHandle.vue'
|
|
|
|
|
|
-const props = defineProps<NodeProps>()
|
|
|
+type Props = NodeProps<IWorkflowNode['data']> & {
|
|
|
+ readOnly?: boolean
|
|
|
+ hovered?: boolean
|
|
|
+}
|
|
|
+
|
|
|
+const props = defineProps<Props>()
|
|
|
+
|
|
|
+/**
|
|
|
+ * 处理节点
|
|
|
+ */
|
|
|
+const createEndpoint = (data: {
|
|
|
+ port: CanvasConnectionPort
|
|
|
+ index: number
|
|
|
+ count: number
|
|
|
+ offsetAxis: 'top' | 'left'
|
|
|
+ position: Position
|
|
|
+}): CanvasElementPortWithRenderData => {
|
|
|
+ const { port, index, count, offsetAxis, position } = data
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...port,
|
|
|
+ handleId: `${port.type}-${index}`,
|
|
|
+ position,
|
|
|
+ connectionsCount: count,
|
|
|
+ isConnecting: false,
|
|
|
+ offset: {
|
|
|
+ [offsetAxis]: `${(100 / (count + 1)) * (index + 1)}%`
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Inputs
|
|
|
+ */
|
|
|
+const inputs = computed(() =>
|
|
|
+ (props.data.inputs || []).map((target, index) =>
|
|
|
+ createEndpoint({
|
|
|
+ port: target,
|
|
|
+ index,
|
|
|
+ count: props.data.inputs.length,
|
|
|
+ offsetAxis: 'top',
|
|
|
+ position: Position.Left
|
|
|
+ })
|
|
|
+ )
|
|
|
+)
|
|
|
+
|
|
|
+/**
|
|
|
+ * Outputs
|
|
|
+ */
|
|
|
+const outputs = computed(() =>
|
|
|
+ (props.data.outputs || []).map((source, index) =>
|
|
|
+ createEndpoint({
|
|
|
+ port: source,
|
|
|
+ index,
|
|
|
+ count: props.data.outputs.length,
|
|
|
+ offsetAxis: 'top',
|
|
|
+ position: Position.Right
|
|
|
+ })
|
|
|
+ )
|
|
|
+)
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
@@ -13,17 +78,22 @@ const props = defineProps<NodeProps>()
|
|
|
class="w-full h-full bg-#fff box-border border-2 border-solid border-#dcdcdc rounded-4px relative"
|
|
|
>
|
|
|
<div className="w-full h-full relative flex items-center justify-center">
|
|
|
- <Icon icon="lucide:zoom-out" height="40" width="40" color="#00bb88" />
|
|
|
+ <Icon :icon="data?.icon" height="40" width="40" :color="data?.iconColor" />
|
|
|
</div>
|
|
|
|
|
|
<div className="absolute w-full bottom--22px text-12px text-center text-#222">
|
|
|
- {{ data.label }}
|
|
|
+ {{ data?.displayName }}
|
|
|
</div>
|
|
|
<div className="absolute w-full bottom--38px text-12px text-center text-#999 truncate">
|
|
|
{{ data.subtitle }}
|
|
|
</div>
|
|
|
|
|
|
- <CanvasHandle handle-id="1" handle-type="source" :position="Position.Right" />
|
|
|
- <CanvasHandle handle-id="2" handle-type="target" :position="Position.Left" />
|
|
|
+ <template v-for="target in inputs" :key="'handle-inputs-port' + target.index">
|
|
|
+ <CanvasHandle v-bind="target" type="target" />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-for="source in outputs" :key="'handle-outputs-port' + source.index">
|
|
|
+ <CanvasHandle v-bind="source" type="source" />
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</template>
|