实现可视化task连接线操作

This commit is contained in:
qiuchengw
2025-12-02 19:44:05 +08:00
parent 734c1cf4cb
commit dc6ab95709
4 changed files with 1031 additions and 7 deletions
+90 -1
View File
@@ -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"