This commit is contained in:
2026-02-27 09:56:49 +08:00
parent b6af9d5044
commit a8a898d2df
9 changed files with 98 additions and 56 deletions

View File

@@ -9,9 +9,6 @@
size-unit="px"
/>
<span>{{ currentComponent?.title }}</span>
<!-- <div class="add" @click="emit('add')" @mousedown.stop>
<svg-icon name="add" size="14" size-unit="px" />
</div> -->
</div>
<div class="body" @mousedown.stop>
<component :is="currentComponent?.component" ref="componentRef" />
@@ -146,24 +143,6 @@
font-size: 16px;
color: #fff;
}
> .add {
position: absolute;
width: 32px;
height: 32px;
border: 2px solid #fff;
bottom: -16px;
right: -16px;
background-color: #ed8936;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 25px;
box-shadow: 0 8px 20px 0 #71809633;
cursor: pointer;
z-index: 20;
}
}
> .body {
cursor: initial;

View File

@@ -21,16 +21,43 @@
<div class="item">
<slot></slot>
</div>
<div class="add" @mousedown.stop>
<svg-icon name="add" size="14" size-unit="px" />
</div>
</div>
</template>
<style lang="less" scoped>
.node {
position: relative;
.vue-flow__handle {
width: 5px;
height: 5px;
top: 50px;
z-index: 10;
}
> .item {
position: relative;
}
> .add {
position: absolute;
width: 32px;
height: 32px;
border: 2px solid #fff;
// bottom: -16px;
right: -16px;
top: 50%;
transform: translateY(-50%);
background-color: #ed8936;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 25px;
box-shadow: 0 8px 20px 0 #71809633;
cursor: pointer;
z-index: 20;
}
}
</style>

View File

@@ -20,9 +20,6 @@
class="image"
src="https://s3-alpha-sig.figma.com/img/ea2f/590e/9638f62a2fc91e31f33db0022db1642c?Expires=1773014400&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=M0B8oJJOk~dGG0aZAqOIocAp7T0LFdJ9FYmCrEZVTCRzYxM6SJRNtYMTX-rTO3Z~s14QINh~o-S41XiZnBv-0zcKjuWot~VVaNHfd0~1LesfNe2KwvCinT~72btFut1pheLnKE-wWCX5ewtonxU77bnw386YPMTqv7DBZzksf2udsJA7NmOYD6~TUG3Q2dWSt~zPH~lkaidscPqpCnCbqzljCEi4RiHY4U3A45l5XypcX2umqn1UaYUFCTqV9471J4qdB6Dg2pcKocdp-7-3s1De6Q~2SmBOrSgDQ~KEADCB2lhKfhxgWmy0lwMvhTd4l90ygVZDWZRABgjHNrGUvg__"
/>
<div class="add" @mousedown.stop>
<svg-icon name="add" size="14" size-unit="px" />
</div>
<div class="more" @click="showMenu = !showMenu" @mousedown.stop>
<svg-icon name="more" size="24" size-unit="px" color="#C9C9C9" />
</div>
@@ -81,6 +78,7 @@
box-shadow: 0px 15px 21px 0px #0000000d;
padding: 25px 6px;
user-select: none;
background-color: #fff;
> .header {
position: absolute;
top: -20px;
@@ -97,6 +95,7 @@
user-select: none;
padding: 0 19px;
gap: 12px;
background-color: #fff;
> .icon {
cursor: pointer;
display: flex;
@@ -133,26 +132,7 @@
height: auto;
}
position: relative;
> .add {
position: absolute;
width: 32px;
height: 32px;
border: 2px solid #fff;
// bottom: -16px;
right: -16px;
top: 50%;
transform: translateY(-50%);
background-color: #ed8936;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 25px;
box-shadow: 0 8px 20px 0 #71809633;
cursor: pointer;
z-index: 20;
}
> .more {
position: absolute;
top: 5px;

View File

@@ -12,12 +12,12 @@
@viewport-change="(e) => eventManager.handleViewportChange(e)"
>
<template #node-InputNode="nodeProps">
<node type="InputNode">
<node type="InputNode" :isAdd="lastNode.id === nodeProps.id">
<component :is="nodeProps.data.component" v-bind="nodeProps.data" />
</node>
</template>
<template #node-SecondaryNode="nodeProps">
<node type="SecondaryNode">
<node type="SecondaryNode" :isAdd="lastNode.id === nodeProps.id">
<component :is="nodeProps.data.component" v-bind="nodeProps.data" />
</node>
</template>
@@ -40,25 +40,39 @@
import zoom from '../components/zoom.vue'
import node from './components/node.vue'
import card from './components/cards/index.vue'
import resultImage from './components/result/result-image.vue'
import { computed, ref, markRaw, onMounted, reactive, nextTick } from 'vue'
// 管理器
import { StateManager } from './manager/StateManager'
import { EventManager } from './manager/EventManager'
import { FlowManager } from './manager/FlowManager'
import { NodeManager } from './manager/NodeManager'
const vueFlow = ref<any>()
// 状态管理器
const stateManager = new StateManager({ vueFlow })
const nodes = computed(() => stateManager.nodes.value)
const edges = computed(() => stateManager.edges.value)
const eventManager = new EventManager({
stateManager,
vueFlow
const lastNode = computed(() => nodes.value[nodes.value.length - 1])
// 事件管理器
const eventManager = new EventManager({ stateManager, vueFlow })
// 流程管理器
const flowManager = new FlowManager({ stateManager, vueFlow })
// 节点管理器
const nodeManager = new NodeManager({ stateManager, vueFlow })
stateManager.setManager({
eventManager,
flowManager,
nodeManager
})
const flowManager = new FlowManager({
stateManager,
vueFlow
nodeManager.createNode({
type: 'InputNode',
class: 'custom-node start',
component: resultImage,
data: {}
})
const { fitView } = useVueFlow()

View File

@@ -1,3 +1,12 @@
import { createId } from '../../tools/tools'
interface NodeOptions {
id?: string
type: "InputNode" | "SecondaryNode"
class?: string
position?: { x: number, y: number }
component: any
data?: object
}
export class NodeManager {
stateManager: any
vueFlow: any
@@ -6,6 +15,22 @@ export class NodeManager {
this.vueFlow = options.vueFlow
}
nodes: [
]
createNode(options: NodeOptions) {
const id = options.id || createId()
const type = options.type || 'InputNode'
const class_ = options.class || 'custom-node'
const position = options.position || { x: 0, y: 0 }
const data = options.data || {}
data['component'] = options.component
this.stateManager.nodes.value.push({
id,
type,
class: class_,
position,
data
})
console.log(this.stateManager.nodes.value)
}
}

View File

@@ -6,6 +6,16 @@ export class StateManager {
nodes: any
edges: any
zoom: any
// 管理器
eventManager: any
flowManager: any
nodeManager: any
// 设置管理器
setManager(options) {
options.eventManager && (this.eventManager = options.eventManager)
options.flowManager && (this.flowManager = options.flowManager)
options.nodeManager && (this.nodeManager = options.nodeManager)
}
constructor(options) {
this.vueFlow = options.vueFlow
this.nodes = ref<any[]>([
@@ -87,4 +97,5 @@ export class StateManager {
this.zoom = ref(1)
}
}

View File

@@ -0,0 +1,5 @@
export const createId = (before: string = 'node') => {
const time = Date.now().toString(36)
const random = Math.random().toString(36).substring(2, 20)
return `${before}_${time}${random}`
}

View File

@@ -39,7 +39,7 @@
import { useRoute, useRouter } from 'vue-router'
import { useUserInfoStore } from '@/stores'
const userInfoStore = useUserInfoStore()
const email = computed(() => userInfoStore.state.userInfo.email || '------')
const email = computed(() => userInfoStore.state.userInfo?.email || '------')
const router = useRouter()
const loading = ref(false)
const onShop = () => {