|
|
@@ -1,11 +1,42 @@
|
|
|
+<template>
|
|
|
+ <!-- <div v-if="props.node.data.label!='模块化'"> -->
|
|
|
+ <div v-if="props.node.data != null">
|
|
|
+ <div class="custom-node icons" :id="`node-${node.id}`">
|
|
|
+ <img :src="props.node.data.image" />
|
|
|
+ <span v-show="props.showNumber">
|
|
|
+ {{ props.node.data.idCodeser }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <!-- 动态渲染 Handle -->
|
|
|
+ <Handle
|
|
|
+ v-for="pos in getHandlePositions()"
|
|
|
+ :key="`source-${pos}`"
|
|
|
+ :id="`source-${pos}`"
|
|
|
+ type="source"
|
|
|
+ :position="getHandlePosition(pos)"
|
|
|
+ :style="getHandleStyles(pos)"
|
|
|
+ class="custom-handle"
|
|
|
+ />
|
|
|
+ <!-- <Handle id="target-a" type="source" :position="Position.Right" class="custom-handle"/>
|
|
|
+ <Handle id="target-c" type="source" :position="Position.Top" class="custom-handle"/>
|
|
|
+ <Handle id="target-b" type="source" :position="Position.Left" class="custom-handle"/>
|
|
|
+ <Handle id="target-d" type="source" :position="Position.Bottom" class="custom-handle"/> -->
|
|
|
+ </div>
|
|
|
+ <!-- </div> -->
|
|
|
+</template>
|
|
|
+
|
|
|
<script setup>
|
|
|
-import { ref, onMounted, reactive, } from "vue";
|
|
|
-import { VueFlow,Handle, useVueFlow,Position } from '@vue-flow/core'
|
|
|
+import { ref, onMounted, reactive } from "vue"
|
|
|
+import { VueFlow, Handle, useVueFlow, Position } from "@vue-flow/core"
|
|
|
const props = defineProps({
|
|
|
node: {
|
|
|
type: Object,
|
|
|
- required: true,
|
|
|
+ required: true
|
|
|
},
|
|
|
+ showNumber: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ }
|
|
|
})
|
|
|
|
|
|
// 计算 Handle 的位置(基于时钟方位角度,调整为 0° 对应右边)
|
|
|
@@ -20,10 +51,10 @@ const getHandleStyles = (point) => {
|
|
|
const y = centerY + radius * Math.sin(angle) // y 轴向下为正
|
|
|
|
|
|
return {
|
|
|
- position: 'absolute',
|
|
|
+ position: "absolute",
|
|
|
left: `${x}px`,
|
|
|
top: `${y}px`,
|
|
|
- transform: 'translate(-50%, -50%)' // 居中 Handle
|
|
|
+ transform: "translate(-50%, -50%)" // 居中 Handle
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -31,80 +62,54 @@ const getHandleStyles = (point) => {
|
|
|
const getHandlePositions = () => {
|
|
|
const ptsite = props.node.data.ptsite || ""
|
|
|
if (!ptsite) return [] // 如果 ptsite 为空,返回空数组
|
|
|
- return ptsite.split("/").filter(pos => !isNaN(parseInt(pos))) // 过滤有效点位(数字)
|
|
|
+ return ptsite.split("/").filter((pos) => !isNaN(parseInt(pos))) // 过滤有效点位(数字)
|
|
|
}
|
|
|
|
|
|
const getHandlePosition = (point) => {
|
|
|
- const pos = parseInt(point);
|
|
|
+ const pos = parseInt(point)
|
|
|
switch (pos) {
|
|
|
case 0:
|
|
|
- return Position.Top;
|
|
|
+ return Position.Top
|
|
|
case 3:
|
|
|
- return Position.Right;
|
|
|
+ return Position.Right
|
|
|
case 6:
|
|
|
- return Position.Bottom;
|
|
|
+ return Position.Bottom
|
|
|
case 9:
|
|
|
- return Position.Left;
|
|
|
+ return Position.Left
|
|
|
default:
|
|
|
// 对于其他角度,可以近似选择最近的标准方位
|
|
|
- if (pos >= 1 && pos <= 2) return Position.Right;
|
|
|
- if (pos >= 4 && pos <= 5) return Position.Right;
|
|
|
- if (pos >= 7 && pos <= 8) return Position.Left;
|
|
|
- if (pos >= 10 && pos <= 11) return Position.Left;
|
|
|
- return Position.Right; // 默认值(防止无效值)
|
|
|
+ if (pos >= 1 && pos <= 2) return Position.Right
|
|
|
+ if (pos >= 4 && pos <= 5) return Position.Right
|
|
|
+ if (pos >= 7 && pos <= 8) return Position.Left
|
|
|
+ if (pos >= 10 && pos <= 11) return Position.Left
|
|
|
+ return Position.Right // 默认值(防止无效值)
|
|
|
}
|
|
|
-};
|
|
|
-onMounted(() => {
|
|
|
-});
|
|
|
+}
|
|
|
+onMounted(() => {})
|
|
|
</script>
|
|
|
-<template>
|
|
|
- <!-- <div v-if="props.node.data.label!='模块化'"> -->
|
|
|
- <div v-if="props.node.data!=null">
|
|
|
- <div class="custom-node icons " :id="`node-${node.id}`" >
|
|
|
- <img :src="props.node.data.image"/>
|
|
|
- <span>{{props.node.data.idCodeser }}</span>
|
|
|
- </div>
|
|
|
- <!-- 动态渲染 Handle -->
|
|
|
- <Handle
|
|
|
- v-for="pos in getHandlePositions()"
|
|
|
- :key="`source-${pos}`"
|
|
|
- :id="`source-${pos}`"
|
|
|
- type="source"
|
|
|
- :position="getHandlePosition(pos)"
|
|
|
- :style="getHandleStyles(pos)"
|
|
|
- class="custom-handle"
|
|
|
- />
|
|
|
- <!-- <Handle id="target-a" type="source" :position="Position.Right" class="custom-handle"/>
|
|
|
- <Handle id="target-c" type="source" :position="Position.Top" class="custom-handle"/>
|
|
|
- <Handle id="target-b" type="source" :position="Position.Left" class="custom-handle"/>
|
|
|
- <Handle id="target-d" type="source" :position="Position.Bottom" class="custom-handle"/> -->
|
|
|
- </div>
|
|
|
-<!-- </div> -->
|
|
|
-</template>
|
|
|
-<style scoped>
|
|
|
-
|
|
|
-.icons img{
|
|
|
- width: 20px;
|
|
|
|
|
|
+<style scoped>
|
|
|
+.icons img {
|
|
|
+ width: 20px;
|
|
|
}
|
|
|
-.icons span{
|
|
|
+.icons span {
|
|
|
display: block;
|
|
|
font-size: 8px;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
</style>
|
|
|
<style>
|
|
|
.custom-handle {
|
|
|
background: #c11f1f; /* 更浅的颜色 */
|
|
|
- width: 5px; /* 更小的尺寸 */
|
|
|
- height: 5px; /* 更小的尺寸 */
|
|
|
+ width: 5px; /* 更小的尺寸 */
|
|
|
+ height: 5px; /* 更小的尺寸 */
|
|
|
border-radius: 50%;
|
|
|
border: 1px solid #fff;
|
|
|
transition: all 0.2s ease;
|
|
|
}
|
|
|
|
|
|
-.vue-flow__node-default .vue-flow__handle, .vue-flow__node-input .vue-flow__handle, .vue-flow__node-output .vue-flow__handle {
|
|
|
+.vue-flow__node-default .vue-flow__handle,
|
|
|
+.vue-flow__node-input .vue-flow__handle,
|
|
|
+.vue-flow__node-output .vue-flow__handle {
|
|
|
background: #9d9c9c;
|
|
|
}
|
|
|
|
|
|
@@ -129,7 +134,7 @@ onMounted(() => {
|
|
|
.vue-flow__node-default.selected,
|
|
|
.vue-flow__node-input.selected,
|
|
|
.vue-flow__node-output.selected {
|
|
|
- border: 1px solid #2267B1; /* 选中时深蓝色边框 */
|
|
|
+ border: 1px solid #2267b1; /* 选中时深蓝色边框 */
|
|
|
box-shadow: none !important; /* 移除阴影 */
|
|
|
outline: none;
|
|
|
background-color: rgba(0, 0, 0, 0);
|
|
|
@@ -140,36 +145,35 @@ onMounted(() => {
|
|
|
}
|
|
|
|
|
|
.vue-flow__node.draggable {
|
|
|
- background-color: rgba(0,0,0,0);
|
|
|
+ background-color: rgba(0, 0, 0, 0);
|
|
|
}
|
|
|
|
|
|
.vue-flow__node-default.selected:hover,
|
|
|
.vue-flow__node-input.selected:hover,
|
|
|
.vue-flow__node-output.selected:hover {
|
|
|
- border: 1px solid #2267B1; /* 保持选中边框 */
|
|
|
+ border: 1px solid #2267b1; /* 保持选中边框 */
|
|
|
box-shadow: none !important;
|
|
|
outline: none;
|
|
|
}
|
|
|
|
|
|
.vue-flow__node {
|
|
|
- stroke: none; /* 移除节点边框 */
|
|
|
- }
|
|
|
+ stroke: none; /* 移除节点边框 */
|
|
|
+}
|
|
|
|
|
|
-.vue-flow__node:hover{
|
|
|
+.vue-flow__node:hover {
|
|
|
/* 移除 hover 时的阴影 */
|
|
|
box-shadow: none !important;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
.vue-flow__edge-text {
|
|
|
display: block;
|
|
|
}
|
|
|
.vue-flow__node-custom {
|
|
|
- background: purple;
|
|
|
- color: white;
|
|
|
- border: 1px solid purple;
|
|
|
- border-radius: 4px;
|
|
|
- box-shadow: 0 0 0 1px purple;
|
|
|
- padding: 8px;
|
|
|
+ background: purple;
|
|
|
+ color: white;
|
|
|
+ border: 1px solid purple;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 0 0 1px purple;
|
|
|
+ padding: 8px;
|
|
|
}
|
|
|
</style>
|