mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-06-23 00:23:51 +08:00
123 lines
2.8 KiB
TypeScript
123 lines
2.8 KiB
TypeScript
import { useVueFlow } from '@vue-flow/core'
|
|
import { ref, watch } from 'vue'
|
|
import { cloneDeep } from 'lodash-es'
|
|
|
|
/**
|
|
* @returns {string} - A unique id.
|
|
*/
|
|
function getId() {
|
|
// 生成以act_开头的唯一id
|
|
return 'act_' + Math.random().toString(36).substr(2, 9)
|
|
}
|
|
|
|
/**
|
|
* In a real world scenario you'd want to avoid creating refs in a global scope like this as they might not be cleaned up properly.
|
|
* @type {{draggedData: Ref<any>, isDragOver: Ref<boolean>, isDragging: Ref<boolean>}}
|
|
*/
|
|
const state = {
|
|
/**
|
|
* The type of the node being dragged.
|
|
*/
|
|
draggedData: ref<any | null>({}),
|
|
isDragOver: ref(false),
|
|
isDragging: ref(false),
|
|
}
|
|
|
|
export default function useDragAndDrop() {
|
|
const { draggedData, isDragOver, isDragging } = state
|
|
|
|
const { addNodes, screenToFlowCoordinate, onNodesInitialized, updateNode } = useVueFlow()
|
|
|
|
watch(isDragging, dragging => {
|
|
document.body.style.userSelect = dragging ? 'none' : ''
|
|
})
|
|
|
|
function onDragStart(event: any, data: any) {
|
|
if (event.dataTransfer) {
|
|
event.dataTransfer.setData('application/vueflow', data)
|
|
event.dataTransfer.effectAllowed = 'move'
|
|
}
|
|
|
|
draggedData.value = data
|
|
isDragging.value = true
|
|
|
|
document.addEventListener('drop', onDragEnd)
|
|
}
|
|
|
|
/**
|
|
* Handles the drag over event.
|
|
*
|
|
* @param {DragEvent} event
|
|
*/
|
|
function onDragOver(event: any) {
|
|
event.preventDefault()
|
|
|
|
if (draggedData.value) {
|
|
isDragOver.value = true
|
|
|
|
if (event.dataTransfer) {
|
|
event.dataTransfer.dropEffect = 'move'
|
|
}
|
|
}
|
|
}
|
|
|
|
function onDragLeave() {
|
|
isDragOver.value = false
|
|
}
|
|
|
|
function onDragEnd() {
|
|
isDragging.value = false
|
|
isDragOver.value = false
|
|
draggedData.value = null
|
|
document.removeEventListener('drop', onDragEnd)
|
|
}
|
|
|
|
/**
|
|
* Handles the drop event.
|
|
*
|
|
* @param {DragEvent} event
|
|
*/
|
|
function onDrop(event: any) {
|
|
const position = screenToFlowCoordinate({
|
|
x: event.clientX,
|
|
y: event.clientY,
|
|
})
|
|
|
|
const nodeId = getId()
|
|
|
|
const newNode = {
|
|
id: nodeId,
|
|
type: draggedData.value?.type,
|
|
name: draggedData.value?.name,
|
|
description: draggedData.value?.description,
|
|
position,
|
|
data: draggedData.value?.data ? cloneDeep(draggedData.value.data) : {},
|
|
}
|
|
|
|
/**
|
|
* Align node position after drop, so it's centered to the mouse
|
|
*
|
|
* We can hook into events even in a callback, and we can remove the event listener after it's been called.
|
|
*/
|
|
const { off } = onNodesInitialized(() => {
|
|
updateNode(nodeId, node => ({
|
|
position: { x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2 },
|
|
}))
|
|
|
|
off()
|
|
})
|
|
|
|
addNodes(newNode)
|
|
}
|
|
|
|
return {
|
|
draggedData,
|
|
isDragOver,
|
|
isDragging,
|
|
onDragStart,
|
|
onDragLeave,
|
|
onDragOver,
|
|
onDrop,
|
|
}
|
|
}
|