diff --git a/CHANGELOG.md b/CHANGELOG.md index 23efe3c..f0695d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.4.2-patch2] - 2025-11-11 + +### Fixed +- 缺陷修复:TaskList配置列宽无效的问题修复 +- Defect fix: Fixed the issue of invalid column width configuration in TaskList + ## [1.4.2-patch1] - 2025-11-03 ### Fixed diff --git a/demo/App.vue b/demo/App.vue index 0a4bfed..981972a 100644 --- a/demo/App.vue +++ b/demo/App.vue @@ -48,13 +48,13 @@ const toolbarConfig = { // TaskList列配置 const availableColumns = ref([ { key: 'predecessor', label: '前置任务', visible: true }, - { key: 'assignee', label: '负责人', visible: true }, + { key: 'assignee', label: '负责人', visible: true, width: 250 }, { key: 'startDate', label: '开始日期', visible: true }, { key: 'endDate', label: '结束日期', visible: true }, { key: 'estimatedHours', label: '预估工时', visible: true }, { key: 'actualHours', label: '实际工时', visible: true }, { key: 'progress', label: '进度', visible: true }, - { key: 'custom', label: '自定义列', visible: true, width: 120 }, // 添加默认宽度120px + { key: 'custom', label: '自定义列', visible: true, width: '30%' }, // 添加默认宽度120px ]) // TaskList宽度配置 diff --git a/demo/version-history.json b/demo/version-history.json index 8e04d8d..07ad78f 100644 --- a/demo/version-history.json +++ b/demo/version-history.json @@ -276,5 +276,15 @@ "Defect fix: Fixed the issue of infinite loop calls when updating child tasks after updating the parent task", "Special thanks to Ky1in666@github for their valuable use and feedback" ] + }, + { + "version": "1.4.2-patch2", + "date": "2025-11-11", + "notes": [ + "缺陷修复:TaskList配置列宽无效的问题修复", + "特别感谢 @SHENGLONG749的使用及反馈的宝贵意见", + "Defect fix: Fixed the issue of invalid column width configuration in TaskList", + "Special thanks to @SHENGLONG749 for their valuable use and feedback" + ] } ] diff --git a/package.json b/package.json index 05bbe8e..3b7cee2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jordium-gantt-vue3", - "version": "1.4.2-pacth.1", + "version": "1.4.2-patch.2", "type": "module", "main": "dist/jordium-gantt-vue3.cjs.js", "module": "dist/jordium-gantt-vue3.es.js", diff --git a/src/components/GanttChart.vue b/src/components/GanttChart.vue index 8ed75d8..e82a0d6 100644 --- a/src/components/GanttChart.vue +++ b/src/components/GanttChart.vue @@ -299,22 +299,45 @@ function onMouseDown(e: MouseEvent) { taskListBodyProposedWidth.value = window.innerWidth * 0.8 - 6 // 减去splitter宽度 // 获取左侧面板的最小宽度 - taskListBodyWidthLimit.value = Math.min(taskListBodyProposedWidth.value, taskListBodyWidth.value) + taskListBodyWidthLimit.value = Math.min(taskListBodyProposedWidth.value, + taskListBodyWidthLimit.value) // 广播拖拽开始事件,通知其他组件暂停悬停效果 window.dispatchEvent(new CustomEvent('splitter-drag-start')) - // 在拖拽期间禁用页面选择 + // 在拖拽期间禁用页面选择和所有指针事件 document.body.style.userSelect = 'none' document.body.style.webkitUserSelect = 'none' document.body.style.cursor = 'col-resize' + document.body.style.pointerEvents = 'none' // 禁止所有指针事件 + + // 全局事件拦截器:在捕获阶段拦截所有事件(除了 mousemove 和 mouseup) + const blockAllEvents = (ev: Event) => { + if (ev.type !== 'mousemove' && ev.type !== 'mouseup') { + ev.preventDefault() + ev.stopPropagation() + ev.stopImmediatePropagation() + } + } + + // 在捕获阶段添加事件监听,确保最先拦截 + document.addEventListener('mousedown', blockAllEvents, { capture: true }) + document.addEventListener('click', blockAllEvents, { capture: true }) + document.addEventListener('dblclick', blockAllEvents, { capture: true }) + document.addEventListener('mouseover', blockAllEvents, { capture: true }) + document.addEventListener('mouseout', blockAllEvents, { capture: true }) + document.addEventListener('mouseenter', blockAllEvents, { capture: true }) + document.addEventListener('mouseleave', blockAllEvents, { capture: true }) + document.addEventListener('wheel', blockAllEvents, { capture: true, passive: false }) + document.addEventListener('contextmenu', blockAllEvents, { capture: true }) function onMouseMove(ev: MouseEvent) { if (!dragging.value) return - // 阻止默认行为,防止滚动等 + // 强制阻止所有默认行为和事件传播 ev.preventDefault() ev.stopPropagation() + ev.stopImmediatePropagation() const delta = ev.clientX - startX const proposedWidth = startWidth + delta @@ -327,13 +350,25 @@ function onMouseDown(e: MouseEvent) { function onMouseUp() { dragging.value = false + // 移除全局事件拦截器 + document.removeEventListener('mousedown', blockAllEvents, { capture: true }) + document.removeEventListener('click', blockAllEvents, { capture: true }) + document.removeEventListener('dblclick', blockAllEvents, { capture: true }) + document.removeEventListener('mouseover', blockAllEvents, { capture: true }) + document.removeEventListener('mouseout', blockAllEvents, { capture: true }) + document.removeEventListener('mouseenter', blockAllEvents, { capture: true }) + document.removeEventListener('mouseleave', blockAllEvents, { capture: true }) + document.removeEventListener('wheel', blockAllEvents, { capture: true }) + document.removeEventListener('contextmenu', blockAllEvents, { capture: true }) + // 广播拖拽结束事件,通知其他组件恢复悬停效果 window.dispatchEvent(new CustomEvent('splitter-drag-end')) - // 恢复页面选择和光标 + // 恢复页面选择、光标和指针事件 document.body.style.userSelect = '' document.body.style.webkitUserSelect = '' document.body.style.cursor = '' + document.body.style.pointerEvents = '' taskListBodyWidth.value = getTaskListMaxWidth() // TaskList默认宽度 ganttPanelLeftMinWidth.value = getTaskListMinWidth() // 左侧面板最小宽度 diff --git a/src/components/TaskBar.vue b/src/components/TaskBar.vue index 39e44ab..d704af0 100644 --- a/src/components/TaskBar.vue +++ b/src/components/TaskBar.vue @@ -1572,7 +1572,6 @@ watch( const safeNewContainerWidth = newContainerWidth || 0 const safeOldScrollLeft = oldScrollLeft || 0 const safeOldContainerWidth = oldContainerWidth || 0 - // 如果容器宽度发生变化(包括Splitter拖拽、TaskList展开收起、窗口resize等) if (Math.abs(safeNewContainerWidth - safeOldContainerWidth) > 1 && safeOldContainerWidth > 0) { hasManualResize.value = true @@ -1583,6 +1582,13 @@ watch( // computed会自动重新计算 }) + // 🔥 容器宽度变化时,标记初始化完成(修复 splitter 拖拽后半圆不显示的问题) + if (isInitializing.value) { + setTimeout(() => { + isInitializing.value = false + }, 300) + } + // 延长禁用动画的时间,确保各种resize操作稳定 setTimeout(() => { hasManualResize.value = false @@ -1622,6 +1628,7 @@ watch( }, 200) } }, + { immediate: true }, ) // 监听外部hideBubbles属性变化,确保Timeline的容器变化能及时反应 diff --git a/src/components/TaskList.vue b/src/components/TaskList.vue index e1aabec..555f8bb 100644 --- a/src/components/TaskList.vue +++ b/src/components/TaskList.vue @@ -33,6 +33,37 @@ const hasRowSlot = computed(() => Boolean(slots['custom-task-content'])) // 多语言支持 const { t } = useI18n() +// TaskList 容器引用 +const taskListRef = ref(null) + +// 获取列宽度样式(百分比转像素) +const getColumnWidthStyle = (column: { width?: number | string }) => { + if (!column.width) return {} + + let widthPx: string + + // 如果是百分比,转换为像素 + if (typeof column.width === 'string' && column.width.includes('%')) { + const containerWidth = taskListRef.value?.offsetWidth || 0 + if (containerWidth > 0) { + const percentage = parseFloat(column.width) / 100 + const pixels = Math.floor(containerWidth * percentage) + widthPx = `${pixels}px` + } else { + return {} // 容器宽度未知时返回空 + } + } else { + // 像素值 + widthPx = `${column.width}px` + } + + return { + flex: `0 0 ${widthPx}`, + minWidth: widthPx, + maxWidth: widthPx, + } +} + // 计算可见的列配置 const visibleColumns = computed(() => { const columns = props.taskListConfig?.columns || DEFAULT_TASK_LIST_COLUMNS @@ -385,7 +416,7 @@ onUnmounted(() => {