实现可视化task连接线操作
This commit is contained in:
@@ -4,6 +4,7 @@ import { ref, computed, onUnmounted, onMounted, nextTick, watch, useSlots } from
|
||||
import type { Task } from '../models/classes/Task'
|
||||
import { TimelineScale } from '../models/types/TimelineScale'
|
||||
import TaskContextMenu from './TaskContextMenu.vue'
|
||||
import LinkAnchor from './LinkAnchor.vue'
|
||||
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import type { TaskBarConfig } from '../models/configs/TaskBarConfig'
|
||||
@@ -35,6 +36,14 @@ interface Props {
|
||||
isPrimaryHighlight?: boolean
|
||||
// 是否处于高亮模式(有任务被高亮)
|
||||
isInHighlightMode?: boolean
|
||||
// 连接线拖拽模式:'predecessor' | 'successor' | null
|
||||
dragLinkMode?: 'predecessor' | 'successor' | null
|
||||
// 是否是连接线拖拽的起始任务
|
||||
isLinkDragSource?: boolean
|
||||
// 是否是有效的连接目标
|
||||
isValidLinkTarget?: boolean
|
||||
// 是否是无效的连接目标
|
||||
isInvalidLinkTarget?: boolean
|
||||
}
|
||||
|
||||
interface TaskStatus {
|
||||
@@ -73,6 +82,9 @@ const emit = defineEmits([
|
||||
'delete',
|
||||
'context-menu',
|
||||
'long-press',
|
||||
'link-drag-start',
|
||||
'link-drag-move',
|
||||
'link-drag-end',
|
||||
])
|
||||
|
||||
defineSlots<{
|
||||
@@ -198,6 +210,9 @@ const longPressTimer = ref<number | null>(null)
|
||||
const longPressTriggered = ref(false)
|
||||
const LONG_PRESS_DURATION = 1000 // 1秒(缩短了)
|
||||
|
||||
// TaskBar 悬停状态(用于显示 LinkAnchor)
|
||||
const isTaskBarHovered = ref(false)
|
||||
|
||||
// 防误触配置 - 使用配置项或默认值
|
||||
const dragThreshold = computed(() => barConfig.value.dragThreshold ?? 5)
|
||||
const isDragThresholdMet = ref(false) // 是否达到拖拽阈值
|
||||
@@ -2227,7 +2242,48 @@ const handleTaskDelete = (task: Task, deleteChildren?: boolean) => {
|
||||
closeContextMenu()
|
||||
}
|
||||
|
||||
// 监听全局关闭菜单事件
|
||||
// 连接线触点事件处理
|
||||
const handleLinkDragStart = (event: { task: Task; type: 'predecessor' | 'successor'; mouseEvent: MouseEvent }) => {
|
||||
emit('link-drag-start', event)
|
||||
}
|
||||
|
||||
const handleLinkDragMove = (event: { mouseX: number; mouseY: number }) => {
|
||||
emit('link-drag-move', event)
|
||||
}
|
||||
|
||||
const handleLinkDragEnd = (event: { task: Task; type: 'predecessor' | 'successor' }) => {
|
||||
emit('link-drag-end', event)
|
||||
}
|
||||
|
||||
// 处理 LinkAnchor 的 drag-start 事件(转换为统一格式)
|
||||
const handleAnchorDragStart = (anchorEvent: { taskId: number; type: 'predecessor' | 'successor'; x: number; y: number }) => {
|
||||
const mouseEvent = {
|
||||
clientX: anchorEvent.x,
|
||||
clientY: anchorEvent.y,
|
||||
} as MouseEvent
|
||||
|
||||
handleLinkDragStart({
|
||||
task: props.task,
|
||||
type: anchorEvent.type,
|
||||
mouseEvent,
|
||||
})
|
||||
}
|
||||
|
||||
// 处理 LinkAnchor 的 drag-move 事件
|
||||
const handleAnchorDragMove = (anchorEvent: { x: number; y: number }) => {
|
||||
handleLinkDragMove({
|
||||
mouseX: anchorEvent.x,
|
||||
mouseY: anchorEvent.y,
|
||||
})
|
||||
}
|
||||
|
||||
// 处理 LinkAnchor 的 drag-end 事件
|
||||
const handleAnchorDragEnd = (anchorEvent: { taskId: number; type: 'predecessor' | 'successor' }) => {
|
||||
handleLinkDragEnd({
|
||||
task: props.task,
|
||||
type: anchorEvent.type,
|
||||
})
|
||||
}// 监听全局关闭菜单事件
|
||||
onMounted(() => {
|
||||
window.addEventListener('close-all-taskbar-menus', closeContextMenu)
|
||||
})
|
||||
@@ -2246,6 +2302,7 @@ onUnmounted(() => {
|
||||
<div
|
||||
ref="barRef"
|
||||
class="task-bar"
|
||||
:data-task-id="task.id"
|
||||
:style="{
|
||||
...taskBarStyle,
|
||||
backgroundColor: taskStatus.bgColor,
|
||||
@@ -2270,6 +2327,8 @@ onUnmounted(() => {
|
||||
@click="handleTaskBarClick"
|
||||
@contextmenu="handleContextMenu"
|
||||
@dblclick="handleTaskBarDoubleClick"
|
||||
@mouseenter="isTaskBarHovered = true"
|
||||
@mouseleave="isTaskBarHovered = false"
|
||||
>
|
||||
<!-- 父级任务的标签 -->
|
||||
<div v-if="isParent" class="parent-label">
|
||||
@@ -2382,6 +2441,36 @@ onUnmounted(() => {
|
||||
@mousedown="e => handleMouseDown(e, 'resize-right')"
|
||||
></div>
|
||||
|
||||
<!-- 连接线触点 - 只在非高亮模式且非父级任务时显示 -->
|
||||
<!-- 前置任务触点(左侧) -->
|
||||
<LinkAnchor
|
||||
v-if="!isParent && !isInHighlightMode"
|
||||
type="predecessor"
|
||||
:task-id="task.id"
|
||||
:visible="isTaskBarHovered"
|
||||
:is-drag-source="isLinkDragSource && dragLinkMode === 'predecessor'"
|
||||
:is-drag-target="isValidLinkTarget || isInvalidLinkTarget"
|
||||
:is-valid-target="isValidLinkTarget"
|
||||
:global-dragging="!!dragLinkMode"
|
||||
@drag-start="handleAnchorDragStart"
|
||||
@drag-move="handleAnchorDragMove"
|
||||
@drag-end="handleAnchorDragEnd"
|
||||
/>
|
||||
<!-- 后置任务触点(右侧) -->
|
||||
<LinkAnchor
|
||||
v-if="!isParent && !isInHighlightMode"
|
||||
type="successor"
|
||||
:task-id="task.id"
|
||||
:visible="isTaskBarHovered"
|
||||
:is-drag-source="isLinkDragSource && dragLinkMode === 'successor'"
|
||||
:is-drag-target="isValidLinkTarget || isInvalidLinkTarget"
|
||||
:is-valid-target="isValidLinkTarget"
|
||||
:global-dragging="!!dragLinkMode"
|
||||
@drag-start="handleAnchorDragStart"
|
||||
@drag-move="handleAnchorDragMove"
|
||||
@drag-end="handleAnchorDragEnd"
|
||||
/>
|
||||
|
||||
<!-- 半圆气泡指示器 - 只在 TaskBar 完全消失时显示 -->
|
||||
<div
|
||||
v-if="bubbleIndicator.show && !isParent"
|
||||
|
||||
Reference in New Issue
Block a user