diff --git a/common/changes/@visactor/vtable-gantt/fix-issue-4631-set-records-project-times_2026-09-20-16-00.json b/common/changes/@visactor/vtable-gantt/fix-issue-4631-set-records-project-times_2026-09-20-16-00.json new file mode 100644 index 0000000000..db207f1fba --- /dev/null +++ b/common/changes/@visactor/vtable-gantt/fix-issue-4631-set-records-project-times_2026-09-20-16-00.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "fix(gantt): recalculate project task dates when setting records", + "type": "patch", + "packageName": "@visactor/vtable-gantt" + } + ], + "packageName": "@visactor/vtable-gantt", + "email": "892739385@qq.com" +} diff --git a/packages/vtable-gantt/__tests__/gantt-set-records.test.ts b/packages/vtable-gantt/__tests__/gantt-set-records.test.ts new file mode 100644 index 0000000000..17560defa9 --- /dev/null +++ b/packages/vtable-gantt/__tests__/gantt-set-records.test.ts @@ -0,0 +1,65 @@ +// @ts-nocheck + +global.__VERSION__ = 'none'; + +import { Gantt } from '../src'; + +describe('gantt setRecords', () => { + test('recalculates project task dates from new child records', () => { + const gantt = { + records: [], + options: {}, + parsedOptions: { + startDateField: 'start', + endDateField: 'end', + dateFormat: 'yyyy-mm-dd', + reverseSortedTimelineScales: [{ unit: 'day', step: 1 }], + sortedTimelineScales: [{ unit: 'day', step: 1 }] + }, + data: { + setRecords: jest.fn() + }, + taskListTableInstance: { + records: [], + setRecords(records) { + this.records = records; + } + }, + _syncPropsFromTable: jest.fn(), + _generateTimeLineDateMap: jest.fn(), + _updateSize: jest.fn(), + scenegraph: { + refreshAll: jest.fn(), + setX: jest.fn(), + setY: jest.fn() + }, + verticalSplitResizeLine: { style: {} }, + drawHeight: 400, + stateManager: { + scroll: { + horizontalBarPos: 0, + verticalBarPos: 0 + } + } + }; + + const nextRecords = [ + { + id: 2, + name: 'Planning', + type: 'project', + children: [ + { id: 3, name: 'Design', start: '2024-11-15', end: '2024-11-18' }, + { id: 4, name: 'Review', start: '2024-11-12', end: '2024-11-20' } + ] + } + ]; + + Gantt.prototype.setRecords.call(gantt, nextRecords); + + expect(gantt.records[0].start).toBe('2024-11-12'); + expect(gantt.records[0].end).toBe('2024-11-20'); + expect(gantt.taskListTableInstance.records[0].start).toBe('2024-11-12'); + expect(gantt.taskListTableInstance.records[0].end).toBe('2024-11-20'); + }); +}); diff --git a/packages/vtable-gantt/examples/gantt/issue-4631-set-records-project.ts b/packages/vtable-gantt/examples/gantt/issue-4631-set-records-project.ts new file mode 100644 index 0000000000..61fe2b8281 --- /dev/null +++ b/packages/vtable-gantt/examples/gantt/issue-4631-set-records-project.ts @@ -0,0 +1,70 @@ +import type { GanttConstructorOptions } from '../../src'; +import { Gantt, TYPES } from '../../src'; + +const CONTAINER_ID = 'vTable'; + +const projectRecords = [ + { + id: 2, + name: 'Planning', + type: 'project', + children: [ + { id: 3, name: 'Design', start: '2024-11-15', end: '2024-11-18' }, + { id: 4, name: 'Review', start: '2024-11-12', end: '2024-11-20' } + ] + } +]; + +export function createTable() { + const container = document.getElementById(CONTAINER_ID); + if (!container) { + return; + } + const status = document.createElement('div'); + const updateButton = document.createElement('button'); + + status.style.cssText = 'height: 32px; line-height: 32px; font: 14px sans-serif;'; + updateButton.textContent = 'Set project records'; + updateButton.style.cssText = 'margin-bottom: 8px; padding: 6px 12px; cursor: pointer;'; + container.parentElement?.insertBefore(status, container); + container.parentElement?.insertBefore(updateButton, container); + + const options: GanttConstructorOptions = { + records: [{ id: 1, name: 'Initial task', start: '2024-11-01', end: '2024-11-02' }], + taskListTable: { + columns: [ + { field: 'name', title: 'Task', width: 160, tree: true }, + { field: 'start', title: 'Start', width: 110 }, + { field: 'end', title: 'End', width: 110 } + ], + tableWidth: 380 + }, + tasksShowMode: TYPES.TasksShowMode.Tasks_Separate, + taskBar: { + startDateField: 'start', + endDateField: 'end', + labelText: '{name}' + }, + timelineHeader: { + colWidth: 50, + scales: [ + { unit: 'week', step: 1, startOfWeek: 'monday' }, + { unit: 'day', step: 1 } + ] + }, + minDate: '2024-11-01', + maxDate: '2024-11-30' + }; + + const ganttInstance = new Gantt(container, options); + window.ganttInstance = ganttInstance; + + const updateRecords = () => { + ganttInstance.setRecords(projectRecords); + const project = ganttInstance.records[0]; + status.textContent = `Project range: ${project.start ?? 'missing'} - ${project.end ?? 'missing'}`; + }; + + updateButton.addEventListener('click', updateRecords); + updateRecords(); +} diff --git a/packages/vtable-gantt/examples/menu.ts b/packages/vtable-gantt/examples/menu.ts index 1bcfe17a99..560d06f343 100644 --- a/packages/vtable-gantt/examples/menu.ts +++ b/packages/vtable-gantt/examples/menu.ts @@ -182,6 +182,10 @@ export const menus = [ { path: 'gantt', name: 'issue-4778-taskbar-relative-rect' + }, + { + path: 'gantt', + name: 'issue-4631-set-records-project' } // ] // } diff --git a/packages/vtable-gantt/src/Gantt.ts b/packages/vtable-gantt/src/Gantt.ts index 0cfcca00c1..9fe3966529 100644 --- a/packages/vtable-gantt/src/Gantt.ts +++ b/packages/vtable-gantt/src/Gantt.ts @@ -1510,6 +1510,7 @@ export class Gantt extends EventTarget { } setRecords(records: any[]) { this.records = records; + initProjectTaskTimes(this); this.data.setRecords(records); updateOptionsWhenRecordChanged(this); this.taskListTableInstance.setRecords(records);