diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f64cb0..662b811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,32 @@ 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.9.2] - 2026-02-26 + +### Added +- 🎉 新增:Singleton Tooltip 架构重构,TaskBar 不再独立维护 Teleport DOM,改由 Timeline 统一管理单一 Tooltip 节点,大幅降低大数据量下的 DOM 开销 +- 🎉 新增:GanttChart 支持 `#taskbar-tooltip` 自定义 Scoped Slot,可完全替换内置 Tooltip 内容,获得 `task`、`taskStatus`、`resourcePercent` 三个作用域参数 +- 🎉 新增:GanttChart 新增 Props `enableTaskListCollapsible`(默认 `true`),设为 `false` 时强制隐藏 TaskList 并让 Timeline 独占全宽 +- 🎉 新增:GanttChart 新增 Props `taskListVisible`(默认 `true`),支持响应式外部控制 TaskList 显隐 +- 🎉 新增:GanttChart Expose API 新增 `getTaskListVisible()`、`setTaskListVisible(visible)`、`toggleTaskList()` 三个方法,支持命令式控制 TaskList +- 🎉 新增:ToolbarConfig 新增 `showViewMode` 字段,用于控制视图切换按钮组的可见性 +- 🎉 新增:Demo 新增 `data-100.json` 中等规模数据集(100 条任务),默认数据源切换至此 +- 🎉 Added: Singleton Tooltip architecture refactored — TaskBar no longer maintains independent Teleport DOM, Timeline now manages a single shared Tooltip node, significantly reducing DOM overhead for large datasets +- 🎉 Added: GanttChart supports `#taskbar-tooltip` custom Scoped Slot to fully replace built-in Tooltip content, exposing `task`, `taskStatus`, `resourcePercent` scope parameters +- 🎉 Added: GanttChart new prop `enableTaskListCollapsible` (default `true`); set to `false` to force-hide TaskList and let Timeline occupy full width +- 🎉 Added: GanttChart new prop `taskListVisible` (default `true`) for reactive external control of TaskList visibility +- 🎉 Added: GanttChart Expose API adds `getTaskListVisible()`, `setTaskListVisible(visible)`, `toggleTaskList()` for imperative TaskList control +- 🎉 Added: ToolbarConfig adds `showViewMode` field to control visibility of the view-mode toggle button group +- 🎉 Added: Demo adds `data-100.json` medium-scale dataset (100 tasks) as the new default data source + +### Fixed +- 🔧 修复:异步加载数据时首次滚动以空任务列表计算范围,真实数据到来后今日定位失效 +- 🔧 修复:从资源视图切换回任务视图后,`updateTimelineRange` 重算偏移导致今日标记偏离视口 +- 🔧 修复:GanttToolbar 中视图切换按钮组缺少 `v-if` 守卫,导致 `showViewMode: false` 设置不生效 +- 🔧 Fixed: When data is loaded asynchronously, initial scroll used empty task list; today marker lost after real data arrived +- 🔧 Fixed: After switching from resource view back to task view, `updateTimelineRange` recalculation caused today marker to move out of viewport +- 🔧 Fixed: View-mode toggle button group in GanttToolbar was missing `v-if` guard, causing `showViewMode: false` to have no effect + ## [1.9.1] - 2026-02-07 ### Fixed diff --git a/README-EN.md b/README-EN.md index 131a5a1..6d593df 100644 --- a/README-EN.md +++ b/README-EN.md @@ -223,7 +223,9 @@ npm run dev | `showActualTaskbar`  | `boolean` | `false` | Whether to display actual TaskBar (shows actual execution progress below planned TaskBar) | | `enableTaskbarTooltip`  | `boolean` | `true` | Whether to enable TaskBar hover tooltip (shows task details on mouse hover) | | `showConflicts`  | `boolean` | `true` | Whether to display resource conflict visualization layer (shows diagonal stripe background for overload zones in resource view) | -| `showTaskbarTab`  | `boolean` | `true` | Whether to display resource tab on TaskBar (shows resource allocation label on TaskBar in resource view) | +| `showTaskbarTab`  | `boolean` | `true` | Whether to display resource tab on TaskBar (shows resource allocation label on TaskBar in resource view) | +| `enableTaskListCollapsible`  | `boolean` | `true` | Whether to allow collapsing/expanding the TaskList panel. When `false`: forcibly hides TaskList, SplitterBar and collapse button; Timeline takes full width | +| `taskListVisible`  | `boolean` | `true` | Controls TaskList visibility (reactive). Only effective when `enableTaskListCollapsible=true` | #### TaskListColumn Component Props @@ -1798,6 +1800,7 @@ Customize the toolbar functional buttons and time scale options. | `timeScaleDimensions` | `TimelineScale[]` | `['hour', 'day', 'week', 'month', 'quarter', 'year']` | Set time scale dimensions to display, options: `'hour'`, `'day'`, `'week'`, `'month'`, `'quarter'`, `'year'` | | `defaultTimeScale` | `TimelineScale` | `'week'` | Default selected time scale | | `showExpandCollapse` | `boolean` | `true` | Show "Expand All/Collapse All" button (for parent-child task tree structure) | +| `showViewMode`  | `boolean` | `true` | Show Task / Resource view mode toggle button group | **TimelineScale Type Description:** @@ -2349,6 +2352,9 @@ The GanttChart component exposes a series of methods through `defineExpose`, all | `scrollToToday`  | - | `void` | Scroll to today's position | | `scrollToTask`  | `taskId: number \| string` | `void` | Scroll to specified task (task will auto-expand to visible state) | | `scrollToDate`  | `date: string \| Date` | `void` | Scroll to specified date position (format: `'YYYY-MM-DD'` or Date object) | +| `getTaskListVisible`  | - | `boolean` | Get the current visibility state of TaskList | +| `setTaskListVisible`  | `visible: boolean` | `void` | Imperatively set TaskList visibility (only effective when `enableTaskListCollapsible=true`) | +| `toggleTaskList`  | - | `void` | Toggle TaskList expand/collapse state with animation | #### Usage Example @@ -2780,6 +2786,71 @@ const month = formatMonth(3) // '3月' (zh-CN) or '03' (en-US) Component provides slots support, allowing custom task content rendering。 +##### `taskbar-tooltip` Slot  + +Fully replaces the built-in TaskBar hover tooltip content. When used, the built-in tooltip is no longer rendered — the consumer has complete control. + +> **Prerequisite**: Requires `:enable-taskbar-tooltip="true"` (enabled by default) + +**Slot scope parameters (`TaskbarTooltipSlotScope`):** + +> The component provides data via ``. The consumer can receive the whole `scope` object or destructure only what's needed — all parameters are **optional**. `task` is the raw task object from your `:tasks` / `:resources` data, including any custom fields. + +| Param | Type | Description | +| --- | --- | --- | +| `task` | `Task` | The currently hovered task object with complete task data | +| `taskStatus` | `{ color: string; label: string }` | Pre-computed task status (color + label) for quick display | +| `resourcePercent` | `number \| null` | Resource usage percentage (valid in resource view; `null` in task view) | + +**All three patterns are equivalent:** + +```vue + + + {{ scope.task.name }} + + + + + {{ task.name }} + + + + + ... + +``` + +**Example — minimal usage (task name only):** + +```vue + + + {{ task.name }} + + +``` + +**Example — using full scope:** + +```vue + + + + + {{ task.name }} + + Status: {{ taskStatus.label }} + Start: {{ task.startDate }} + End: {{ task.endDate }} + Resource: {{ resourcePercent }}% + + + +``` + +--- + ##### `custom-task-content` Slots Used to customize task display content in task list (TaskRow) and timeline (TaskBar). diff --git a/README.md b/README.md index 4138831..e2060aa 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,9 @@ npm run dev | `showActualTaskbar`  | `boolean` | `false` | 是否显示实际TaskBar(在计划TaskBar下方显示实际执行进度) | | `enableTaskbarTooltip`  | `boolean` | `true` | 是否启用TaskBar悬停提示框(鼠标悬停显示任务详情) | | `showConflicts`  | `boolean` | `true` | 是否显示资源冲突可视化层(资源视图下显示斜纹背景标识超载区域) | -| `showTaskbarTab`  | `boolean` | `true` | 是否显示TaskBar上的资源Tab标签(资源视图下TaskBar的资源分配标签) | +| `showTaskbarTab`  | `boolean` | `true` | 是否显示TaskBar上的资源Tab标签(资源视图下TaskBar的资源分配标签) | +| `enableTaskListCollapsible`  | `boolean` | `true` | 是否允许折叠/展开 TaskList 面板。`false` 时强制隐藏 TaskList、SplitterBar 及折叠按钮,Timeline 独占全宽 | +| `taskListVisible`  | `boolean` | `true` | 控制 TaskList 的显隐状态(响应式)。仅在 `enableTaskListCollapsible=true` 时有效 | #### TaskListColumn 属性 @@ -1791,6 +1793,7 @@ const tasks = ref([ | `timeScaleDimensions` | `TimelineScale[]` | `['hour', 'day', 'week', 'month', 'quarter', 'year']` | 设置时间刻度按钮组要显示的维度,可选值:`'hour'`、`'day'`、`'week'`、`'month'`、`'quarter'`、`'year'` | | `defaultTimeScale` | `TimelineScale` | `'week'` | 默认选中的时间刻度 | | `showExpandCollapse` | `boolean` | `true` | 显示"全部展开/折叠"按钮(用于父子任务树形结构) | +| `showViewMode`  | `boolean` | `true` | 显示 Task / Resource 视图切换按钮组 | **TimelineScale 类型说明:** @@ -2342,6 +2345,9 @@ GanttChart 组件通过 `defineExpose` 暴露了一系列方法,允许父组 | `scrollToToday`  | - | `void` | 滚动到今天的位置 | | `scrollToTask`  | `taskId: number \| string` | `void` | 滚动到指定任务(任务会自动展开到可见状态) | | `scrollToDate`  | `date: string \| Date` | `void` | 滚动到指定日期位置(格式:`'YYYY-MM-DD'` 或 Date 对象) | +| `getTaskListVisible`  | - | `boolean` | 获取 TaskList 当前可见状态 | +| `setTaskListVisible`  | `visible: boolean` | `void` | 命令式设置 TaskList 显隐(仅 `enableTaskListCollapsible=true` 时生效) | +| `toggleTaskList`  | - | `void` | 带动画切换 TaskList 展开/收起状态 | #### 使用示例 @@ -2773,6 +2779,71 @@ const month = formatMonth(3) // '3月' (zh-CN) 或 '03' (en-US) 组件提供了插槽支持,允许自定义任务内容的渲染。 +##### `taskbar-tooltip` 插槽  + +用于完全替换 TaskBar 的内置悬停 Tooltip 内容。启用后内置样式不再渲染,由消费方完全控制。 + +> **前提条件**:需设置 `:enable-taskbar-tooltip="true"`(默认已开启) + +**插槽作用域参数(`TaskbarTooltipSlotScope`):** + +> 组件通过 `` 提供数据,消费者可用整体对象 `scope` 接收,也可按需解构——所有参数均为**可选**。`task` 是完整的任务对象,自定义字段(如 `task.myField`)均可直接访问。 + +| 参数名 | 类型 | 说明 | +| --- | --- | --- | +| `task` | `Task` | 当前悬停的任务对象,包含完整的任务数据 | +| `taskStatus` | `{ color: string; label: string }` | 由组件计算好的任务状态(颜色 + 文本),辅助快速显示状态 | +| `resourcePercent` | `number \| null` | 资源占比百分比(资源视图有效,任务视图为 `null`) | + +**三种写法完全等价:** + +```vue + + + {{ scope.task.name }} + + + + + {{ task.name }} + + + + + ... + +``` + +**示例——仅展示任务名称(最简用法):** + +```vue + + + {{ task.name }} + + +``` + +**示例——利用全部作用域参数:** + +```vue + + + + + {{ task.name }} + + 状态:{{ taskStatus.label }} + 开始:{{ task.startDate }} + 结束:{{ task.endDate }} + 资源占比:{{ resourcePercent }}% + + + +``` + +--- + ##### `custom-task-content` 插槽 用于自定义任务在任务列表(TaskRow)和时间轴(TaskBar)中的显示内容。 diff --git a/demo/version-history.json b/demo/version-history.json index d4d7146..17638d0 100644 --- a/demo/version-history.json +++ b/demo/version-history.json @@ -552,5 +552,29 @@ "🔧 修复: GanttChart管理ThemeChange的问题", "🔧 Fixed: Issue with ThemeChange management in GanttChart" ] + }, + { + "version": "1.9.2", + "date": "2026-02-26", + "notes": [ + "🎉 新增:Singleton Tooltip 架构重构,整个 Timeline 共享单一 Tooltip 节点,大幅降低大数据量下的 DOM 开销", + "🎉 新增:GanttChart 支持 #taskbar-tooltip 自定义插槽,可完全替换内置 Tooltip 内容", + "🎉 新增:GanttChart 新增 enableTaskListCollapsible / taskListVisible Props,支持响应式外部控制 TaskList 显隐", + "🎉 新增:GanttChart Expose API 新增 getTaskListVisible()、setTaskListVisible()、toggleTaskList() 方法", + "🎉 新增:ToolbarConfig 新增 showViewMode 字段,控制视图切换按钮组可见性", + "🔧 修复:异步数据加载后今日定位失效", + "🔧 修复:资源视图切换回任务视图后今日定位偏移", + "🔧 修复:GanttToolbar 视图切换按钮组 showViewMode:false 设置不生效", + "特别感谢来自德国柏林的 Andrés Jorge 使用与反馈", + "🎉 Added: Singleton Tooltip architecture refactored — Timeline shares a single Tooltip node, greatly reducing DOM overhead for large datasets", + "🎉 Added: GanttChart supports #taskbar-tooltip custom scoped slot to fully replace built-in Tooltip content", + "🎉 Added: GanttChart new props enableTaskListCollapsible / taskListVisible for reactive external TaskList visibility control", + "🎉 Added: GanttChart Expose API adds getTaskListVisible(), setTaskListVisible(), toggleTaskList() methods", + "🎉 Added: ToolbarConfig adds showViewMode field to control view-mode toggle button group visibility", + "🔧 Fixed: Today marker lost after async data load", + "🔧 Fixed: Today marker offset after switching from resource view back to task view", + "🔧 Fixed: GanttToolbar showViewMode:false had no effect due to missing v-if guard", + "Special thanks to Andrés Jorge from Berlin, Germany for their use and feedback" + ] } ] diff --git a/package.json b/package.json index 75e9e5a..3cc6b2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jordium-gantt-vue3", - "version": "1.9.2-rc.1", + "version": "1.9.2", "type": "module", "main": "npm-package/dist/jordium-gantt-vue3.cjs.js", "module": "npm-package/dist/jordium-gantt-vue3.es.js", diff --git a/src/components/Timeline.vue b/src/components/Timeline.vue index 8235679..b3595da 100644 --- a/src/components/Timeline.vue +++ b/src/components/Timeline.vue @@ -4661,15 +4661,25 @@ watch([timelineData, timelineContainerWidth], () => { // 监听viewMode和dataSource变化,刷新缓存和时间线 watch( [viewMode, dataSource], - ([newViewMode]) => { + ([newViewMode], [oldViewMode]) => { invalidateTaskDateRangeCache() - // bugfix: 切换回任务视图时重置 hasInitialAutoScroll,确保 updateTimelineRange 完成后能重新定位今日 - // 场景:资源视图切换回任务视图时,updateTimelineRange 重新计算任务范围导致像素偏移, - // 若不重置则 scrollToTodayCenter 不会被触发,今日标记将出现在视口之外 + const viewModeChanged = newViewMode !== oldViewMode if (newViewMode === 'task') { + // bugfix: 切换回任务视图时重置 hasInitialAutoScroll,确保 updateTimelineRange 完成后能重新定位今日 + // 场景:资源视图切换回任务视图时,updateTimelineRange 重新计算任务范围导致像素偏移, + // 若不重置则 scrollToTodayCenter 不会被触发,今日标记将出现在视口之外 hasInitialAutoScroll = false + debouncedUpdateTimelineRange() + } else if (newViewMode === 'resource') { + if (viewModeChanged) { + // bugfix: 切换到资源视图时直接调用 scrollToTodayCenter + // 原因:updateTimelineRange() 在 resource 视图下直接返回(不更新 timelineData/timelineConfig), + // 导致内层 watch 无法触发,timeline 保留任务视图中拖拽后的偏移位置 + // 注意:切换视图不重新挂载 DOM,timelineContainerElement 始终可用, + // nextTick 后直接调用即可,scrollToTodayCenter 内部有重试机制无需额外 setTimeout + nextTick(() => scrollToTodayCenter()) + } } - debouncedUpdateTimelineRange() }, )