画布添加功能和选择节点变为选中后就可以添加,添加逻辑和生成多张逻辑一致,

This commit is contained in:
X1627315083@163.com
2026-03-23 14:23:30 +08:00
parent 21a0acfff9
commit c7b62fdf88
7 changed files with 85 additions and 75 deletions

View File

@@ -11,15 +11,12 @@
<div class="item" @mousedown="(e) => stateManager.setActiveNodeID(node.id)"> <div class="item" @mousedown="(e) => stateManager.setActiveNodeID(node.id)">
<slot></slot> <slot></slot>
</div> </div>
<div class="add" @mousedown.stop v-if="isAdd" @click="onAdd">
<svg-icon name="add" size="14" size-unit="px" />
</div>
<div class="mask" v-show="mask"></div> <div class="mask" v-show="mask"></div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { Handle, Position } from '@vue-flow/core' import { Handle, Position } from '@vue-flow/core'
import { NODE_DATATYPE, NODE_DATATIER, NODE_TYPE } from '../tools/index.d' import { NODE_DATATYPE, NODE_TYPE } from '../tools/index.d'
import { computed, ref, inject } from 'vue' import { computed, ref, inject } from 'vue'
const handles = ref({ const handles = ref({
[NODE_TYPE.INPUT]: [{ id: 'Right', type: 'source', position: Position.Right }], [NODE_TYPE.INPUT]: [{ id: 'Right', type: 'source', position: Position.Right }],
@@ -48,39 +45,6 @@
default: false default: false
} }
}) })
const stateManager = inject('stateManager') as any
const nodes = computed(() => props.stateManager.nodes.value)
const isSubord = computed(() => nodes.value.some((v) => v.data.superiorID === props.node.id))
const tier = computed(() => Number(props.node?.data?.tier || 0))
//只有3d模型才有三级菜单,目前三级菜单内容少直接禁用按钮
const isAdd3d = computed(() => (tier.value === 2 && props.node?.data?.superiorNodeType === NODE_DATATYPE.TO_3D_MODEL) || props.node?.data?.superiorNodeType !== NODE_DATATYPE.TO_3D_MODEL)
const isReturned = computed(() => {
return (
props.node.data.type == NODE_DATATYPE.RESULT_IMAGE &&
props.node.data.data.imageProcessTasks[0].status == 'RETURNED'
)
})
const isAdd = computed(
() =>
!isSubord.value &&
NODE_DATATYPE.RESULT_IMAGE === props.node.data.type &&
!(tier.value === NODE_DATATIER.TO_3VIEW) &&
isReturned.value &&
isAdd3d.value
)
const onAdd = () => {
const tier_ = tier.value + 1
// 从data中获取originalImage
let nodeData = props.node?.data?.data.imageProcessTasks.filter(
(v) => v.taskId === props.node?.data?.data.selectTaskId
)
const originalImage = nodeData[0]?.url
if (!originalImage) console.log('originalImage 找不到原始图片')
props.stateManager.nodeManager.createCardsSelect({
data: { tier: tier_, superiorID: props.node.id, originalImage }
})
stateManager.setActiveNodeID('')
}
const posCenter = computed(() => { const posCenter = computed(() => {
const arr = [NODE_DATATYPE.RESULT_IMAGE] const arr = [NODE_DATATYPE.RESULT_IMAGE]
return arr.includes(props.node?.data?.type) return arr.includes(props.node?.data?.type)
@@ -106,25 +70,6 @@
> .item { > .item {
position: relative; position: relative;
} }
> .add {
position: absolute;
width: 32px;
height: 32px;
border: 2px solid #fff;
top: var(--top);
right: -16px;
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;
}
&.center { &.center {
--top: 50%; --top: 50%;
} }

View File

@@ -69,28 +69,31 @@
const onClickItem = (v) => { const onClickItem = (v) => {
const id = props.node.id const id = props.node.id
if (!id) return if (!id) return
stateManager.deleteNode(id) const superiorID = props.node.data.superiorID
console.log(props.node)
if(v.secondaryMenu){ if(v.secondaryMenu){
nodeManager.createCardsSelect({ nodeManager.createCardsSelect({
data: { data: {
tier: props.node.data?.tier, tier: props.node.data?.tier,
superiorID: props.node.data?.superiorID, superiorID,
isActive: props.node.data?.isActive,
originalImage: props.node.data?.originalImage, originalImage: props.node.data?.originalImage,
secondaryMenu: v.secondaryMenu secondaryMenu: v.secondaryMenu,
createIndexPosition: props.node.data.createIndexPosition,
} }
}) })
}else{ }else{
const superiorID = props.node.data.superiorID
nodeManager.createCardNode({ nodeManager.createCardNode({
data: { data: {
tier: v.tier, tier: v.tier,
type: v.type, type: v.type,
superiorID, superiorID,
isActive: props.node.data?.isActive,
createIndexPosition: props.node.data.createIndexPosition,
originalImage: props.node.data?.originalImage, originalImage: props.node.data?.originalImage,
} }
}) })
} }
stateManager.deleteNode(id)
} }
defineExpose({}) defineExpose({})

View File

@@ -143,7 +143,6 @@
const onGenerateClick = async () => { const onGenerateClick = async () => {
const data = componentRef.value?.getApiData?.() || {} const data = componentRef.value?.getApiData?.() || {}
const subordNode = stateManager.getSubordNodeById(attrs.node.id)
const subordNodes = stateManager.getSubordNodes(attrs.node.id) const subordNodes = stateManager.getSubordNodes(attrs.node.id)
emit('update-data', componentRef.value?.data) emit('update-data', componentRef.value?.data)
if(!attrs.node?.data?.originalImage)console.log('originalImage 找不到原始图片') if(!attrs.node?.data?.originalImage)console.log('originalImage 找不到原始图片')

View File

@@ -53,6 +53,9 @@
</div> </div>
</div> </div>
</div> </div>
<div class="add" @mousedown.stop v-if="isAdd" @click="onAdd">
<svg-icon name="add" size="14" size-unit="px" />
</div>
</div> </div>
</template> </template>
@@ -61,7 +64,7 @@
import { downloadImage } from '../../../tools/tools' import { downloadImage } from '../../../tools/tools'
import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, computed, onMounted } from 'vue' import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, computed, onMounted } from 'vue'
import HighlightAdmin from '@/components/highlightAdmin.vue' import HighlightAdmin from '@/components/highlightAdmin.vue'
import { NODE_DATATYPE } from '../../tools/index.d' import { NODE_DATATIER, NODE_DATATYPE } from '../../tools/index.d'
const openImagePreview = inject('openImagePreview') as (url: string) => void const openImagePreview = inject('openImagePreview') as (url: string) => void
const openThreeModelPreview = inject('openThreeModelPreview') as (url: string) => void const openThreeModelPreview = inject('openThreeModelPreview') as (url: string) => void
const props = defineProps({ const props = defineProps({
@@ -229,6 +232,45 @@
eventManager.removeEvents() eventManager.removeEvents()
myEvent.emit('openDepthCanvas', data) myEvent.emit('openDepthCanvas', data)
} }
const isSubord = computed(() => props.node.id == stateManager.activeNodeID.value)
const tier = computed(() => Number(props.node?.data?.tier || 0))
//只有3d模型才有三级菜单,目前三级菜单内容少直接禁用按钮
const isAdd3d = computed(() => (tier.value === 2 && props.node?.data?.superiorNodeType === NODE_DATATYPE.TO_3D_MODEL) || props.node?.data?.superiorNodeType !== NODE_DATATYPE.TO_3D_MODEL)
const isReturned = computed(() => {
return (
props.node.data.type == NODE_DATATYPE.RESULT_IMAGE &&
props.node.data.data.imageProcessTasks[0].status == 'RETURNED'
)
})
const isAdd = computed(
() =>
NODE_DATATYPE.RESULT_IMAGE === props.node.data.type &&
!(tier.value === NODE_DATATIER.TO_3VIEW) &&
isReturned.value &&
isAdd3d.value &&
isSubord.value
)
const onAdd = () => {
const tier_ = tier.value + 1
// 从data中获取originalImage
let nodeData = props.node?.data?.data.imageProcessTasks.filter(
(v) => v.taskId === props.node?.data?.data.selectTaskId
)
const subordNodes = stateManager.getSubordNodes(props.node.id)
const originalImage = nodeData[0]?.url
if (!originalImage) console.log('originalImage 找不到原始图片')
stateManager.nodeManager.createCardsSelect({
data: {
tier: tier_,
superiorID: props.node.id,
originalImage,
createIndexPosition: subordNodes.length + 1,
isActive: subordNodes.length == 0
}
})
stateManager.setActiveNodeID('')
}
document.addEventListener('mousedown', hideMenu) document.addEventListener('mousedown', hideMenu)
onBeforeUnmount(() => { onBeforeUnmount(() => {
document.removeEventListener('mousedown', hideMenu) document.removeEventListener('mousedown', hideMenu)
@@ -250,6 +292,25 @@
gap: 8px; gap: 8px;
} }
} }
.add {
position: absolute;
width: 32px;
height: 32px;
border: 2px solid #fff;
top: var(--top);
right: -16px;
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;
}
.result-image { .result-image {
width: 244px; width: 244px;
border-radius: 16px; border-radius: 16px;

View File

@@ -45,24 +45,27 @@ export class NodeManager {
/** 创建节点 */ /** 创建节点 */
createNode(options: NodeOptions) { createNode(options: NodeOptions) {
const superiorID = options?.data?.superiorID const superiorID = options?.data?.superiorID
const snode = superiorID ? this.stateManager.flowManager.getNodeById(superiorID) : this.stateManager.flowManager.getLastNode();
//获取上级节点所生成的最后一个node设置位置为最后一个节点的xy 加上 节点间距 //获取上级节点所生成的最后一个node设置位置为最后一个节点的xy 加上 节点间距
const superiorGenerateNodes = this.stateManager.getSubordNodes(superiorID) const superiorGenerateNodes = this.stateManager.getSubordNodes(superiorID)
const currentNode = superiorGenerateNodes.find((node) => {
return node.data.createIndexPosition === options?.data?.createIndexPosition
})
const endGenerateNode = superiorGenerateNodes.reduce((max, current) => { const endGenerateNode = superiorGenerateNodes.reduce((max, current) => {
return current.data.createIndexPosition > max.data.createIndexPosition ? current : max return current.data.createIndexPosition > max.data.createIndexPosition ? current : max
}, superiorGenerateNodes[0]) }, superiorGenerateNodes[0])
const snode = superiorID ? this.stateManager.flowManager.getNodeById(superiorID) : this.stateManager.flowManager.getLastNode();
const id = options.id || createId() const id = options.id || createId()
const positionX = options.positionX || 0 const positionX = options.positionX || 0
const positionY = options.positionY || 0 const positionY = options.positionY || 0
const position = options.position || const position = options.position ||
( (
endGenerateNode? currentNode ?
currentNode.position :
endGenerateNode ?
{ {
x: endGenerateNode.position.x + positionX, x: endGenerateNode.position.x + positionX,
y: endGenerateNode.position.y + positionY + this.ranksep + 200 y: endGenerateNode.position.y + positionY + this.ranksep + 200
} : } :
!snode ?
{ x: positionX, y: positionY } :
{ {
x: snode.position.x + snode.dimensions.width + this.nodesep + positionX, x: snode.position.x + snode.dimensions.width + this.nodesep + positionX,
y: snode.position.y + positionY y: snode.position.y + positionY
@@ -103,6 +106,7 @@ export class NodeManager {
data: { data: {
tier: NODE_DATATIER.CARDS_SELECT, tier: NODE_DATATIER.CARDS_SELECT,
type: NODE_DATATYPE.CARDS_SELECT, type: NODE_DATATYPE.CARDS_SELECT,
createIndexPosition: options?.data?.createIndexPosition || 1,
...(options?.data || {}), ...(options?.data || {}),
}, },
} }
@@ -113,7 +117,7 @@ export class NodeManager {
const options_ = { const options_ = {
...(options ? options : {}), ...(options ? options : {}),
component: NODE_COMPONENT.CARD, component: NODE_COMPONENT.CARD,
data: { data: {
...(options?.data || {}), ...(options?.data || {}),
} }
} }

View File

@@ -101,7 +101,7 @@ export class StateManager {
source: source, source: source,
target: target, target: target,
selectable: false, selectable: false,
visible: (node.data.type !== NODE_DATATYPE.RESULT_IMAGE || node.data.isActive), visible: (node.data.isActive),
type: 'default' type: 'default'
}) })
} }
@@ -223,8 +223,7 @@ export class StateManager {
/** 显示指定子节点和父节点连接线,隐藏父节点和其他子节点链接线, */ /** 显示指定子节点和父节点连接线,隐藏父节点和其他子节点链接线, */
showNodeConnections(id: string) { showNodeConnections(id: string) {
const node = this.getNodeById(id) const node = this.getNodeById(id)
if(node.data.component != NODE_DATATYPE.RESULT_IMAGE && node.data.superiorID) return if(!node.data.superiorID) return
let edges_ = JSON.parse(JSON.stringify(this.edges.value))
this.nodes.value.forEach((nodeItem) => { this.nodes.value.forEach((nodeItem) => {
if(node.data.superiorID === nodeItem.data.superiorID && nodeItem.id == id) { if(node.data.superiorID === nodeItem.data.superiorID && nodeItem.id == id) {
nodeItem.data.isActive = true nodeItem.data.isActive = true

View File

@@ -58,6 +58,9 @@ const setVersionsList = (res)=>{
} }
traverseArray(res,'',(item,i,father)=>{ traverseArray(res,'',(item,i,father)=>{
item.versionId = father?`${father.versionId}-${i+1}`:'1' item.versionId = father?`${father.versionId}-${i+1}`:'1'
if(item.id == projectStore.state.nodeId){
selectItem.value = {...item}
}
}) })
versionsList.value = res versionsList.value = res
} }
@@ -110,10 +113,6 @@ const versionDelete = (versionDetail)=>{
treeKey.value++ treeKey.value++
} }
watch(()=>projectStore.state.nodeId,(newVal,oldVal)=>{
if(!newVal || newVal === selectItem?.value?.id)return
selectItem.value = {id:newVal}
})
let data = reactive({}) let data = reactive({})
// onMounted(() => {setVersionsList('')}) // onMounted(() => {setVersionsList('')})