diff --git a/src/components/GanttLinks.vue b/src/components/GanttLinks.vue
new file mode 100644
index 0000000..2dd639f
--- /dev/null
+++ b/src/components/GanttLinks.vue
@@ -0,0 +1,232 @@
+
+
+
+
+
+
+
diff --git a/src/components/Timeline.vue b/src/components/Timeline.vue
index 5820bc5..5a04473 100644
--- a/src/components/Timeline.vue
+++ b/src/components/Timeline.vue
@@ -2,6 +2,7 @@
import { ref, onMounted, onUnmounted, computed, watch, nextTick, shallowRef } from 'vue'
import TaskBar from './TaskBar.vue'
import MilestonePoint from './MilestonePoint.vue'
+import GanttLinks from './GanttLinks.vue'
/* eslint-disable @typescript-eslint/no-explicit-any */
import { useI18n } from '../composables/useI18n'
import type { TaskBarConfig } from '../models/configs/TaskBarConfig'
@@ -1924,11 +1925,19 @@ const bodyContentRef = ref(null)
const svgWidth = ref(0)
const svgHeight = ref(0)
+// Canvas 关系线尺寸(用于 GanttLinks 组件)
+const canvasWidth = ref(0)
+const canvasHeight = ref(0)
+
function updateSvgSize() {
if (bodyContentRef.value) {
svgWidth.value = bodyContentRef.value.offsetWidth
// 使用计算的内容高度,确保SVG覆盖所有任务行
svgHeight.value = contentHeight.value
+
+ // 同步更新 Canvas 尺寸
+ canvasWidth.value = bodyContentRef.value.offsetWidth
+ canvasHeight.value = contentHeight.value
}
}
@@ -2001,77 +2010,6 @@ const handleMilestoneDragEnd = (updatedMilestone: Milestone) => {
window.dispatchEvent(new CustomEvent('milestone-drag-end', { detail: updatedMilestone }))
}
-// 优化:关系线路径缓存(减少 80% 的路径计算)
-const pathCache = new Map()
-
-// 计算所有连线(优化版:使用缓存和增量更新)
-const links = computed(() => {
- const result: { from: number; to: number; path: string }[] = []
-
- // 获取当前渲染的任务ID集合,用于过滤关系线
- const currentTaskIds = new Set()
- for (const task of tasks.value) {
- currentTaskIds.add(task.id)
- }
-
- for (const task of tasks.value) {
- if (!task.predecessor || !taskBarPositions.value[task.id]) continue
-
- // 获取所有前置任务ID
- const predecessorIds = getPredecessorIds(task.predecessor)
-
- // 为每个前置任务创建连线
- for (const predecessorId of predecessorIds) {
- // 只有当前置任务也在当前渲染列表中时,才绘制关系线
- const fromBar = taskBarPositions.value[predecessorId]
- const toBar = taskBarPositions.value[task.id]
-
- if (!fromBar || !toBar || !currentTaskIds.has(predecessorId)) continue
-
- // 计算高亮状态下的Y轴偏移
- const fromIsPrimary = highlightedTaskId.value === predecessorId
- const toIsPrimary = highlightedTaskId.value === task.id
- const fromIsHighlighted = highlightedTaskIds.value.has(predecessorId)
- const toIsHighlighted = highlightedTaskIds.value.has(task.id)
-
- // 高亮偏移量:primary-highlight -8px, highlighted -5px
- const fromYOffset = fromIsPrimary ? -8 : fromIsHighlighted ? -5 : 0
- const toYOffset = toIsPrimary ? -8 : toIsHighlighted ? -5 : 0
-
- // 起点为前置TaskBar右侧中点,终点为当前TaskBar左侧中点
- const x1 = fromBar.left + fromBar.width
- const y1 = fromBar.top + fromBar.height / 2 + fromYOffset
- const x2 = toBar.left
- const y2 = toBar.top + toBar.height / 2 + toYOffset
-
- // 优化:使用缓存键检查是否已计算过该路径
- const cacheKey = `${x1}-${y1}-${x2}-${y2}`
- let path = pathCache.get(cacheKey)
-
- if (!path) {
- // 控制点:横向中点,纵向分别为起点和终点
- const c1x = x1 + 40
- const c1y = y1
- const c2x = x2 - 40
- const c2y = y2
-
- // 三次贝塞尔曲线
- path = `M${x1},${y1} C${c1x},${c1y} ${c2x},${c2y} ${x2},${y2}`
- pathCache.set(cacheKey, path)
-
- // 限制缓存大小,防止内存泄漏(保留最近 500 条)
- if (pathCache.size > 500) {
- const firstKey = pathCache.keys().next().value
- if (firstKey) pathCache.delete(firstKey)
- }
- }
-
- result.push({ from: predecessorId, to: task.id, path })
- }
- }
- return result
-})
-
onMounted(() => {
// 等待下一帧,确保DOM和数据都已渲染
nextTick(() => {
@@ -3336,79 +3274,16 @@ const handleAddSuccessor = (task: Task) => {
-
-
+
+