ct-gantt-core 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +205 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +70 -8
- package/dist/index.d.ts +70 -8
- package/dist/index.js +197 -63
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -22,12 +22,15 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
DAY_MS: () => DAY_MS,
|
|
24
24
|
DEFAULT_HOUR_COLORS: () => DEFAULT_HOUR_COLORS,
|
|
25
|
+
DEFAULT_RESOURCE_COLORS: () => DEFAULT_RESOURCE_COLORS,
|
|
25
26
|
DEFAULT_TASK_COLORS: () => DEFAULT_TASK_COLORS,
|
|
27
|
+
DEFAULT_WORKLOAD_COLORS: () => DEFAULT_WORKLOAD_COLORS,
|
|
26
28
|
EDITOR_COLOR_OPTIONS: () => EDITOR_COLOR_OPTIONS,
|
|
27
29
|
GanttEngine: () => GanttEngine,
|
|
28
30
|
HOUR_MS: () => HOUR_MS,
|
|
29
31
|
OWNER_COLOR_PALETTE: () => OWNER_COLOR_PALETTE,
|
|
30
32
|
RESOURCE_COLOR_PALETTE: () => RESOURCE_COLOR_PALETTE,
|
|
33
|
+
RESOURCE_EDITOR_COLOR_OPTIONS: () => RESOURCE_EDITOR_COLOR_OPTIONS,
|
|
31
34
|
addDays: () => addDays,
|
|
32
35
|
addHours: () => addHours,
|
|
33
36
|
addPlannedDuration: () => addPlannedDuration,
|
|
@@ -38,8 +41,10 @@ __export(index_exports, {
|
|
|
38
41
|
computeLayout: () => computeLayout,
|
|
39
42
|
computeResourceLayout: () => computeResourceLayout,
|
|
40
43
|
computeTimeScale: () => computeTimeScale,
|
|
44
|
+
computeVisibleWindow: () => computeVisibleWindow,
|
|
41
45
|
computeWorkload: () => computeWorkload,
|
|
42
46
|
createGanttEngine: () => createGanttEngine,
|
|
47
|
+
dateExtent: () => dateExtent,
|
|
43
48
|
defaultConfig: () => defaultConfig,
|
|
44
49
|
diffDays: () => diffDays,
|
|
45
50
|
diffHours: () => diffHours,
|
|
@@ -49,15 +54,18 @@ __export(index_exports, {
|
|
|
49
54
|
hasTimeComponent: () => hasTimeComponent,
|
|
50
55
|
inclusiveDays: () => inclusiveDays,
|
|
51
56
|
isValidDate: () => isValidDate,
|
|
57
|
+
mergeGanttConfig: () => mergeGanttConfig,
|
|
52
58
|
mergeTaskPatch: () => mergeTaskPatch,
|
|
53
59
|
normalizeLinks: () => normalizeLinks,
|
|
54
60
|
plannedDurationBetween: () => plannedDurationBetween,
|
|
61
|
+
resolveGanttConfig: () => resolveGanttConfig,
|
|
55
62
|
resolveResourceColor: () => resolveResourceColor,
|
|
56
63
|
resolveUsageColor: () => resolveUsageColor,
|
|
57
64
|
resolveUsageTimes: () => resolveUsageTimes,
|
|
58
65
|
resultInvalidDate: () => resultInvalidDate,
|
|
59
66
|
scheduleByDependencies: () => scheduleByDependencies,
|
|
60
67
|
shiftTask: () => shiftTask,
|
|
68
|
+
sliceRangeItems: () => sliceRangeItems,
|
|
61
69
|
startOfDay: () => startOfDay,
|
|
62
70
|
subtractPlannedDuration: () => subtractPlannedDuration,
|
|
63
71
|
toDate: () => toDate,
|
|
@@ -67,41 +75,58 @@ module.exports = __toCommonJS(index_exports);
|
|
|
67
75
|
|
|
68
76
|
// src/styles/colors.ts
|
|
69
77
|
var DEFAULT_TASK_COLORS = {
|
|
70
|
-
task: "#
|
|
71
|
-
// 普通任务实际条
|
|
72
|
-
summary: "#
|
|
73
|
-
// 阶段条
|
|
74
|
-
milestone: "#
|
|
75
|
-
// 里程碑菱形 / 参考线默认
|
|
76
|
-
plan: "#
|
|
77
|
-
// 计划条外部底色
|
|
78
|
-
progress: "#
|
|
79
|
-
//
|
|
78
|
+
task: "#409EFF",
|
|
79
|
+
// 普通任务实际条 · Element 主色
|
|
80
|
+
summary: "#909399",
|
|
81
|
+
// 阶段条 · Element Info
|
|
82
|
+
milestone: "#E6A23C",
|
|
83
|
+
// 里程碑菱形 / 参考线默认 · Element Warning
|
|
84
|
+
plan: "#C6E2FF",
|
|
85
|
+
// 计划条外部底色 · 主色浅阶
|
|
86
|
+
progress: "#67C23A"
|
|
87
|
+
// 计划条内部进度色 · Element Success
|
|
80
88
|
};
|
|
81
89
|
var DEFAULT_HOUR_COLORS = {
|
|
82
|
-
plan: "#
|
|
83
|
-
//
|
|
84
|
-
progress: "#
|
|
85
|
-
//
|
|
86
|
-
milestone: "#
|
|
90
|
+
plan: "#409EFF",
|
|
91
|
+
// 小时视图只有计划条,用主色保证在白底网格上可见
|
|
92
|
+
progress: "#67C23A",
|
|
93
|
+
// 兼容保留,小时视图不再绘制进度填充
|
|
94
|
+
milestone: "#E6A23C"
|
|
87
95
|
// 里程碑菱形 / 参考线默认
|
|
88
96
|
};
|
|
89
|
-
var
|
|
97
|
+
var DEFAULT_RESOURCE_COLORS = {
|
|
98
|
+
booking: "#409EFF",
|
|
99
|
+
assignment: "#909399"
|
|
100
|
+
};
|
|
101
|
+
var DEFAULT_WORKLOAD_COLORS = {
|
|
102
|
+
used: "#67C23A",
|
|
103
|
+
// 已排工时徽章 · Element Success
|
|
104
|
+
over: "#F56C6C",
|
|
105
|
+
// 超负荷徽章 / 超载面积条 · Element Danger
|
|
106
|
+
area: "#409EFF"
|
|
107
|
+
// capacity 模式容量面积条 · Element 主色
|
|
108
|
+
};
|
|
109
|
+
var RESOURCE_COLOR_PALETTE = [DEFAULT_RESOURCE_COLORS.booking];
|
|
110
|
+
var RESOURCE_EDITOR_COLOR_OPTIONS = [
|
|
111
|
+
"#409eff",
|
|
112
|
+
"#79bbff",
|
|
113
|
+
"#909399"
|
|
114
|
+
];
|
|
90
115
|
var EDITOR_COLOR_OPTIONS = [
|
|
91
|
-
"#
|
|
92
|
-
"#
|
|
93
|
-
"#
|
|
94
|
-
"#
|
|
95
|
-
"#
|
|
96
|
-
"#
|
|
97
|
-
"#
|
|
98
|
-
"#
|
|
116
|
+
"#409eff",
|
|
117
|
+
"#66b1ff",
|
|
118
|
+
"#67c23a",
|
|
119
|
+
"#e6a23c",
|
|
120
|
+
"#f56c6c",
|
|
121
|
+
"#909399",
|
|
122
|
+
"#9b87c4",
|
|
123
|
+
"#36cfc9"
|
|
99
124
|
];
|
|
100
|
-
var OWNER_COLOR_PALETTE = ["#
|
|
125
|
+
var OWNER_COLOR_PALETTE = ["#409EFF", "#67C23A", "#E6A23C", "#F56C6C", "#909399"];
|
|
101
126
|
|
|
102
127
|
// src/types/index.ts
|
|
103
128
|
var defaultConfig = {
|
|
104
|
-
viewMode: "
|
|
129
|
+
viewMode: "day",
|
|
105
130
|
rowHeight: 44,
|
|
106
131
|
columnWidth: 30,
|
|
107
132
|
headerHeight: 50,
|
|
@@ -120,11 +145,16 @@ var defaultConfig = {
|
|
|
120
145
|
showLinkRejectionNotice: true,
|
|
121
146
|
virtualScroll: true,
|
|
122
147
|
taskColors: { ...DEFAULT_TASK_COLORS },
|
|
148
|
+
resourceUsageColors: { ...DEFAULT_RESOURCE_COLORS },
|
|
149
|
+
workloadColors: { ...DEFAULT_WORKLOAD_COLORS },
|
|
123
150
|
timeUnit: "day",
|
|
124
151
|
hourWidth: 12,
|
|
125
152
|
autoSchedule: true,
|
|
126
153
|
editable: true,
|
|
127
|
-
enableSelection: false
|
|
154
|
+
enableSelection: false,
|
|
155
|
+
showAddTaskColumn: true,
|
|
156
|
+
addTaskAs: "child",
|
|
157
|
+
showAddUsageColumn: true
|
|
128
158
|
};
|
|
129
159
|
|
|
130
160
|
// src/services/checkCyclicDependency.ts
|
|
@@ -234,12 +264,21 @@ function flattenTasks(tasks, collapsedIds = /* @__PURE__ */ new Set()) {
|
|
|
234
264
|
const children = /* @__PURE__ */ new Map();
|
|
235
265
|
for (const task of tasks) {
|
|
236
266
|
const parentId = task.parentId ?? null;
|
|
237
|
-
const bucket = children.get(parentId)
|
|
238
|
-
bucket
|
|
239
|
-
|
|
267
|
+
const bucket = children.get(parentId);
|
|
268
|
+
if (bucket) {
|
|
269
|
+
bucket.push(task);
|
|
270
|
+
} else {
|
|
271
|
+
children.set(parentId, [task]);
|
|
272
|
+
}
|
|
240
273
|
}
|
|
241
274
|
const flattened = [];
|
|
275
|
+
const visited = /* @__PURE__ */ new Set();
|
|
276
|
+
const taskIds = new Set(tasks.map((task) => task.id));
|
|
242
277
|
const visit = (task, depth) => {
|
|
278
|
+
if (visited.has(task.id)) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
visited.add(task.id);
|
|
243
282
|
const childTasks = children.get(task.id) ?? [];
|
|
244
283
|
const collapsed = collapsedIds.has(task.id);
|
|
245
284
|
flattened.push({
|
|
@@ -258,6 +297,12 @@ function flattenTasks(tasks, collapsedIds = /* @__PURE__ */ new Set()) {
|
|
|
258
297
|
for (const root of children.get(null) ?? []) {
|
|
259
298
|
visit(root, 0);
|
|
260
299
|
}
|
|
300
|
+
for (const task of tasks) {
|
|
301
|
+
if (visited.has(task.id)) continue;
|
|
302
|
+
const parentId = task.parentId ?? null;
|
|
303
|
+
if (parentId && taskIds.has(parentId)) continue;
|
|
304
|
+
visit(task, 0);
|
|
305
|
+
}
|
|
261
306
|
return flattened;
|
|
262
307
|
}
|
|
263
308
|
|
|
@@ -359,6 +404,18 @@ function isValidDate(value) {
|
|
|
359
404
|
const date = value instanceof Date ? value : new Date(value);
|
|
360
405
|
return !Number.isNaN(date.getTime());
|
|
361
406
|
}
|
|
407
|
+
function dateExtent(dates) {
|
|
408
|
+
let min = Number.POSITIVE_INFINITY;
|
|
409
|
+
let max = Number.NEGATIVE_INFINITY;
|
|
410
|
+
for (const value of dates) {
|
|
411
|
+
const time = typeof value === "number" ? value : value.getTime();
|
|
412
|
+
if (!Number.isFinite(time)) continue;
|
|
413
|
+
if (time < min) min = time;
|
|
414
|
+
if (time > max) max = time;
|
|
415
|
+
}
|
|
416
|
+
if (!Number.isFinite(min) || !Number.isFinite(max)) return void 0;
|
|
417
|
+
return { start: new Date(min), end: new Date(max) };
|
|
418
|
+
}
|
|
362
419
|
function formatDate(date) {
|
|
363
420
|
const value = toDate(date);
|
|
364
421
|
const year = value.getFullYear();
|
|
@@ -463,6 +520,51 @@ function computeHourScale(start, end, hourWidth) {
|
|
|
463
520
|
return { days, hours, start: rangeStart, end: rangeEnd };
|
|
464
521
|
}
|
|
465
522
|
|
|
523
|
+
// src/services/computeVisibleWindow.ts
|
|
524
|
+
function computeVisibleWindow(scroll, viewportSize, itemSize, itemCount, overscan = 8) {
|
|
525
|
+
if (itemCount <= 0 || itemSize <= 0) {
|
|
526
|
+
return { start: 0, end: -1, before: 0, after: 0 };
|
|
527
|
+
}
|
|
528
|
+
if (viewportSize <= 0) {
|
|
529
|
+
return { start: 0, end: itemCount - 1, before: 0, after: 0 };
|
|
530
|
+
}
|
|
531
|
+
const start = Math.max(0, Math.floor(scroll / itemSize) - overscan);
|
|
532
|
+
const end = Math.min(
|
|
533
|
+
itemCount - 1,
|
|
534
|
+
Math.ceil((scroll + viewportSize) / itemSize) + overscan
|
|
535
|
+
);
|
|
536
|
+
return {
|
|
537
|
+
start,
|
|
538
|
+
end,
|
|
539
|
+
before: start * itemSize,
|
|
540
|
+
after: Math.max(0, (itemCount - end - 1) * itemSize)
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
function sliceRangeItems(items, scrollLeft, viewportWidth, overscanPx = 320) {
|
|
544
|
+
if (viewportWidth <= 0 || items.length === 0) {
|
|
545
|
+
return items;
|
|
546
|
+
}
|
|
547
|
+
const min = scrollLeft - overscanPx;
|
|
548
|
+
const max = scrollLeft + viewportWidth + overscanPx;
|
|
549
|
+
return items.filter((item) => item.left + item.width >= min && item.left <= max);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// src/utils/mergeConfig.ts
|
|
553
|
+
function mergeGanttConfig(base, patch = {}) {
|
|
554
|
+
return {
|
|
555
|
+
...base,
|
|
556
|
+
...patch,
|
|
557
|
+
taskColors: { ...base.taskColors, ...patch.taskColors },
|
|
558
|
+
columnWidths: { ...base.columnWidths, ...patch.columnWidths },
|
|
559
|
+
resourceColors: { ...base.resourceColors, ...patch.resourceColors },
|
|
560
|
+
resourceUsageColors: { ...base.resourceUsageColors, ...patch.resourceUsageColors },
|
|
561
|
+
workloadColors: { ...base.workloadColors, ...patch.workloadColors }
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function resolveGanttConfig(patch = {}) {
|
|
565
|
+
return mergeGanttConfig(defaultConfig, patch);
|
|
566
|
+
}
|
|
567
|
+
|
|
466
568
|
// src/engines/scheduling.ts
|
|
467
569
|
function scheduleByDependencies(tasks, links) {
|
|
468
570
|
const cycle = checkCyclicDependency(links);
|
|
@@ -491,8 +593,18 @@ function scheduleByDependencies(tasks, links) {
|
|
|
491
593
|
}
|
|
492
594
|
};
|
|
493
595
|
}
|
|
494
|
-
|
|
495
|
-
|
|
596
|
+
const incomingList = incoming.get(link.targetId);
|
|
597
|
+
if (incomingList) {
|
|
598
|
+
incomingList.push(link);
|
|
599
|
+
} else {
|
|
600
|
+
incoming.set(link.targetId, [link]);
|
|
601
|
+
}
|
|
602
|
+
const outgoingList = outgoing.get(link.sourceId);
|
|
603
|
+
if (outgoingList) {
|
|
604
|
+
outgoingList.push(link);
|
|
605
|
+
} else {
|
|
606
|
+
outgoing.set(link.sourceId, [link]);
|
|
607
|
+
}
|
|
496
608
|
}
|
|
497
609
|
const ordered = topologicalOrder(tasks.map((task) => task.id), links);
|
|
498
610
|
for (const taskId of ordered) {
|
|
@@ -550,12 +662,20 @@ function topologicalOrder(ids, links) {
|
|
|
550
662
|
const outgoing = /* @__PURE__ */ new Map();
|
|
551
663
|
for (const link of links) {
|
|
552
664
|
indegree.set(link.targetId, (indegree.get(link.targetId) ?? 0) + 1);
|
|
553
|
-
|
|
665
|
+
const targets = outgoing.get(link.sourceId);
|
|
666
|
+
if (targets) {
|
|
667
|
+
targets.push(link.targetId);
|
|
668
|
+
} else {
|
|
669
|
+
outgoing.set(link.sourceId, [link.targetId]);
|
|
670
|
+
}
|
|
554
671
|
}
|
|
555
672
|
const queue = ids.filter((id) => (indegree.get(id) ?? 0) === 0);
|
|
556
673
|
const ordered = [];
|
|
557
|
-
|
|
558
|
-
|
|
674
|
+
let cursor = 0;
|
|
675
|
+
while (cursor < queue.length) {
|
|
676
|
+
const current = queue[cursor];
|
|
677
|
+
cursor += 1;
|
|
678
|
+
if (!current) continue;
|
|
559
679
|
ordered.push(current);
|
|
560
680
|
for (const target of outgoing.get(current) ?? []) {
|
|
561
681
|
indegree.set(target, (indegree.get(target) ?? 1) - 1);
|
|
@@ -590,7 +710,7 @@ function shiftTask(task, start) {
|
|
|
590
710
|
|
|
591
711
|
// src/engines/computeLayout.ts
|
|
592
712
|
function computeLayout(tasks, links, config, collapsedIds = /* @__PURE__ */ new Set(), viewport) {
|
|
593
|
-
const mergedConfig =
|
|
713
|
+
const mergedConfig = resolveGanttConfig(config);
|
|
594
714
|
for (const task of tasks) {
|
|
595
715
|
if (!isValidDate(task.actual.start) || !isValidDate(task.actual.end)) {
|
|
596
716
|
return {
|
|
@@ -608,7 +728,7 @@ function computeLayout(tasks, links, config, collapsedIds = /* @__PURE__ */ new
|
|
|
608
728
|
return scheduled;
|
|
609
729
|
}
|
|
610
730
|
const flatTasks = flattenTasks(scheduled.data, collapsedIds);
|
|
611
|
-
const firstDate = mergedConfig.visibleRange ? toDate(mergedConfig.visibleRange.start) :
|
|
731
|
+
const firstDate = mergedConfig.visibleRange ? toDate(mergedConfig.visibleRange.start) : dateExtent(scheduled.data.map((task) => toDate(task.actual.start)))?.start ?? toDate(/* @__PURE__ */ new Date());
|
|
612
732
|
const visibleStart = viewport ? Math.max(0, Math.floor(viewport.scrollTop / mergedConfig.rowHeight) - 8) : 0;
|
|
613
733
|
const visibleEnd = viewport ? Math.ceil((viewport.scrollTop + viewport.clientHeight) / mergedConfig.rowHeight) + 8 : Number.POSITIVE_INFINITY;
|
|
614
734
|
const layouts = flatTasks.filter((flat) => flat.rowIndex >= visibleStart && flat.rowIndex <= visibleEnd).map((flat) => {
|
|
@@ -627,9 +747,6 @@ function computeLayout(tasks, links, config, collapsedIds = /* @__PURE__ */ new
|
|
|
627
747
|
});
|
|
628
748
|
return { ok: true, data: layouts };
|
|
629
749
|
}
|
|
630
|
-
function minDate(dates) {
|
|
631
|
-
return new Date(Math.min(...dates.map((date) => date.getTime())));
|
|
632
|
-
}
|
|
633
750
|
|
|
634
751
|
// src/engines/computeImpact.ts
|
|
635
752
|
function computeImpact(taskId, patch, tasks, links, config) {
|
|
@@ -718,8 +835,14 @@ function resolveResourceColor(resource, resourceColors) {
|
|
|
718
835
|
const source = resource.name || resource.id;
|
|
719
836
|
return RESOURCE_COLOR_PALETTE[colorHash(source) % RESOURCE_COLOR_PALETTE.length];
|
|
720
837
|
}
|
|
721
|
-
function resolveUsageColor(usage, resource, resourceColors) {
|
|
722
|
-
|
|
838
|
+
function resolveUsageColor(usage, resource, resourceColors, resourceUsageColors) {
|
|
839
|
+
if (usage.color) {
|
|
840
|
+
return usage.color;
|
|
841
|
+
}
|
|
842
|
+
if (resource.color || resourceColors?.[resource.id]) {
|
|
843
|
+
return resolveResourceColor(resource, resourceColors);
|
|
844
|
+
}
|
|
845
|
+
return usage.type === "assignment" ? resourceUsageColors?.assignment ?? DEFAULT_RESOURCE_COLORS.assignment : resourceUsageColors?.booking ?? DEFAULT_RESOURCE_COLORS.booking;
|
|
723
846
|
}
|
|
724
847
|
function resolveUsageTimes(usage, timeUnit) {
|
|
725
848
|
if (timeUnit === "hour") {
|
|
@@ -730,7 +853,7 @@ function resolveUsageTimes(usage, timeUnit) {
|
|
|
730
853
|
return { start: toDate(usage.start), end: toDate(usage.end) };
|
|
731
854
|
}
|
|
732
855
|
function computeResourceLayout(resources, usages, config, viewport) {
|
|
733
|
-
const mergedConfig =
|
|
856
|
+
const mergedConfig = resolveGanttConfig(config);
|
|
734
857
|
const timeUnit = mergedConfig.timeUnit ?? "day";
|
|
735
858
|
const hourMode = timeUnit === "hour";
|
|
736
859
|
const hourW = mergedConfig.hourWidth ?? 12;
|
|
@@ -763,7 +886,12 @@ function computeResourceLayout(resources, usages, config, viewport) {
|
|
|
763
886
|
const resourceById = new Map(resources.map((resource) => [resource.id, resource]));
|
|
764
887
|
const usagesByResource = /* @__PURE__ */ new Map();
|
|
765
888
|
for (const usage of usages) {
|
|
766
|
-
|
|
889
|
+
const grouped = usagesByResource.get(usage.resourceId);
|
|
890
|
+
if (grouped) {
|
|
891
|
+
grouped.push(usage);
|
|
892
|
+
} else {
|
|
893
|
+
usagesByResource.set(usage.resourceId, [usage]);
|
|
894
|
+
}
|
|
767
895
|
}
|
|
768
896
|
const rows = [];
|
|
769
897
|
const usageLayouts = [];
|
|
@@ -808,8 +936,8 @@ function computeResourceLayout(resources, usages, config, viewport) {
|
|
|
808
936
|
const visibleStart = viewport ? Math.max(0, Math.floor(viewport.scrollTop / mergedConfig.rowHeight) - 8) : 0;
|
|
809
937
|
const visibleEnd = viewport ? Math.ceil((viewport.scrollTop + viewport.clientHeight) / mergedConfig.rowHeight) + 8 : Number.POSITIVE_INFINITY;
|
|
810
938
|
const firstDate = hourMode ? startOfDay(
|
|
811
|
-
mergedConfig.visibleRange ? toDateTime(mergedConfig.visibleRange.start) :
|
|
812
|
-
) : mergedConfig.visibleRange ? toDate(mergedConfig.visibleRange.start) :
|
|
939
|
+
mergedConfig.visibleRange ? toDateTime(mergedConfig.visibleRange.start) : dateExtent(usages.map((usage) => resolveUsageTimes(usage, "hour").start))?.start ?? toDateTime(/* @__PURE__ */ new Date())
|
|
940
|
+
) : mergedConfig.visibleRange ? toDate(mergedConfig.visibleRange.start) : dateExtent(usages.map((usage) => toDate(usage.start)))?.start ?? toDate(/* @__PURE__ */ new Date());
|
|
813
941
|
for (const row of rows) {
|
|
814
942
|
if (row.rowIndex < visibleStart || row.rowIndex > visibleEnd) {
|
|
815
943
|
continue;
|
|
@@ -846,16 +974,13 @@ function computeResourceLayout(resources, usages, config, viewport) {
|
|
|
846
974
|
function isLaneFree(laneEnd, start, hourMode) {
|
|
847
975
|
return hourMode ? diffHours(laneEnd, start) >= 0 : diffDays(laneEnd, start) > 0;
|
|
848
976
|
}
|
|
849
|
-
function minDate2(dates) {
|
|
850
|
-
return new Date(Math.min(...dates.map((date) => date.getTime())));
|
|
851
|
-
}
|
|
852
977
|
|
|
853
978
|
// src/engines/computeWorkload.ts
|
|
854
979
|
function computeWorkload(tasks, people, departments = [], range) {
|
|
855
980
|
const dated = range ?? inferRange(tasks);
|
|
856
981
|
if (!dated) return { dates: [], departments: [], ungrouped: [] };
|
|
857
982
|
const dates = datesBetween(dated.start, dated.end);
|
|
858
|
-
const
|
|
983
|
+
const dateIndex = new Map(dates.map((date, index) => [date, index]));
|
|
859
984
|
const rows = new Map(people.map((person) => [person.id, createPerson(person, dates)]));
|
|
860
985
|
for (const task of tasks) {
|
|
861
986
|
if (task.type === "summary" || task.type === "milestone") continue;
|
|
@@ -865,21 +990,32 @@ function computeWorkload(tasks, people, departments = [], range) {
|
|
|
865
990
|
for (const personId of ids) {
|
|
866
991
|
const row = rows.get(personId);
|
|
867
992
|
if (!row) continue;
|
|
868
|
-
for (const [date, hours] of Object.entries(values))
|
|
993
|
+
for (const [date, hours] of Object.entries(values)) {
|
|
994
|
+
const index = dateIndex.get(date);
|
|
995
|
+
if (index !== void 0) row.days[index].hours += hours;
|
|
996
|
+
}
|
|
869
997
|
}
|
|
870
998
|
}
|
|
871
999
|
for (const row of rows.values()) finalize(row);
|
|
872
1000
|
const grouped = /* @__PURE__ */ new Map();
|
|
873
1001
|
const ungrouped = [];
|
|
874
|
-
for (const row of rows.values())
|
|
1002
|
+
for (const row of rows.values()) {
|
|
1003
|
+
if (row.person.departmentId) {
|
|
1004
|
+
const members = grouped.get(row.person.departmentId);
|
|
1005
|
+
if (members) members.push(row);
|
|
1006
|
+
else grouped.set(row.person.departmentId, [row]);
|
|
1007
|
+
} else {
|
|
1008
|
+
ungrouped.push(row);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
875
1011
|
const departmentMap = new Map(departments.map((item) => [item.id, item]));
|
|
876
1012
|
const result = [...grouped].map(([id, members]) => aggregateDepartment(departmentMap.get(id) ?? { id, name: id }, members, dates));
|
|
877
1013
|
return { dates, departments: result, ungrouped };
|
|
878
1014
|
}
|
|
879
1015
|
function inferRange(tasks) {
|
|
880
1016
|
if (!tasks.length) return void 0;
|
|
881
|
-
const
|
|
882
|
-
return { start:
|
|
1017
|
+
const extent = dateExtent(tasks.flatMap((task) => [toDate(task.plan.start), toDate(task.plan.end)]));
|
|
1018
|
+
return extent ? { start: extent.start, end: extent.end } : void 0;
|
|
883
1019
|
}
|
|
884
1020
|
function datesBetween(start, end) {
|
|
885
1021
|
const values = [];
|
|
@@ -952,7 +1088,7 @@ var GanttEngine = class {
|
|
|
952
1088
|
constructor(options = {}) {
|
|
953
1089
|
this.tasks = options.tasks ? options.tasks.map((task) => ({ ...task })) : [];
|
|
954
1090
|
this.links = options.links ? options.links.map((link) => ({ ...link })) : [];
|
|
955
|
-
this.config = { ...defaultConfig, ...options.config };
|
|
1091
|
+
this.config = mergeGanttConfig({ ...defaultConfig }, { ...options.config });
|
|
956
1092
|
this.container = options.container ?? null;
|
|
957
1093
|
this.collapsedIds = new Set(options.collapsedIds ?? []);
|
|
958
1094
|
this.markers = options.markers ? options.markers.map((marker) => ({ ...marker })) : [];
|
|
@@ -986,22 +1122,22 @@ var GanttEngine = class {
|
|
|
986
1122
|
setTasks(tasks) {
|
|
987
1123
|
this.assertNotDestroyed();
|
|
988
1124
|
this.tasks = tasks.map((task) => ({ ...task }));
|
|
989
|
-
this.emit("taskschange", this.
|
|
1125
|
+
this.emit("taskschange", this.tasks);
|
|
990
1126
|
}
|
|
991
1127
|
setLinks(links) {
|
|
992
1128
|
this.assertNotDestroyed();
|
|
993
1129
|
this.links = links.map((link) => ({ ...link }));
|
|
994
|
-
this.emit("linkschange", this.
|
|
1130
|
+
this.emit("linkschange", this.links);
|
|
995
1131
|
}
|
|
996
1132
|
setMarkers(markers) {
|
|
997
1133
|
this.assertNotDestroyed();
|
|
998
1134
|
this.markers = markers.map((marker) => ({ ...marker }));
|
|
999
|
-
this.emit("markerschange", this.
|
|
1135
|
+
this.emit("markerschange", this.markers);
|
|
1000
1136
|
}
|
|
1001
1137
|
/** 合并配置 patch,等价于 setConfig(mergeConfig(patch)) */
|
|
1002
1138
|
mergeConfig(patch) {
|
|
1003
1139
|
this.assertNotDestroyed();
|
|
1004
|
-
this.config =
|
|
1140
|
+
this.config = mergeGanttConfig(this.config, patch);
|
|
1005
1141
|
this.emit("configchange", this.getConfig());
|
|
1006
1142
|
}
|
|
1007
1143
|
setConfig(config) {
|
|
@@ -1121,10 +1257,8 @@ var GanttEngine = class {
|
|
|
1121
1257
|
const today = toDate(/* @__PURE__ */ new Date());
|
|
1122
1258
|
return { start: today, end: addDays(today, 30) };
|
|
1123
1259
|
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
end: new Date(Math.max(...dates.map((d) => d.getTime())))
|
|
1127
|
-
};
|
|
1260
|
+
const extent = dateExtent(dates);
|
|
1261
|
+
return extent ?? { start: dates[0], end: dates[0] };
|
|
1128
1262
|
}
|
|
1129
1263
|
getTimeScale() {
|
|
1130
1264
|
const range = this.getDateRange();
|
|
@@ -1289,12 +1423,15 @@ function createGanttEngine(options = {}) {
|
|
|
1289
1423
|
0 && (module.exports = {
|
|
1290
1424
|
DAY_MS,
|
|
1291
1425
|
DEFAULT_HOUR_COLORS,
|
|
1426
|
+
DEFAULT_RESOURCE_COLORS,
|
|
1292
1427
|
DEFAULT_TASK_COLORS,
|
|
1428
|
+
DEFAULT_WORKLOAD_COLORS,
|
|
1293
1429
|
EDITOR_COLOR_OPTIONS,
|
|
1294
1430
|
GanttEngine,
|
|
1295
1431
|
HOUR_MS,
|
|
1296
1432
|
OWNER_COLOR_PALETTE,
|
|
1297
1433
|
RESOURCE_COLOR_PALETTE,
|
|
1434
|
+
RESOURCE_EDITOR_COLOR_OPTIONS,
|
|
1298
1435
|
addDays,
|
|
1299
1436
|
addHours,
|
|
1300
1437
|
addPlannedDuration,
|
|
@@ -1305,8 +1442,10 @@ function createGanttEngine(options = {}) {
|
|
|
1305
1442
|
computeLayout,
|
|
1306
1443
|
computeResourceLayout,
|
|
1307
1444
|
computeTimeScale,
|
|
1445
|
+
computeVisibleWindow,
|
|
1308
1446
|
computeWorkload,
|
|
1309
1447
|
createGanttEngine,
|
|
1448
|
+
dateExtent,
|
|
1310
1449
|
defaultConfig,
|
|
1311
1450
|
diffDays,
|
|
1312
1451
|
diffHours,
|
|
@@ -1316,15 +1455,18 @@ function createGanttEngine(options = {}) {
|
|
|
1316
1455
|
hasTimeComponent,
|
|
1317
1456
|
inclusiveDays,
|
|
1318
1457
|
isValidDate,
|
|
1458
|
+
mergeGanttConfig,
|
|
1319
1459
|
mergeTaskPatch,
|
|
1320
1460
|
normalizeLinks,
|
|
1321
1461
|
plannedDurationBetween,
|
|
1462
|
+
resolveGanttConfig,
|
|
1322
1463
|
resolveResourceColor,
|
|
1323
1464
|
resolveUsageColor,
|
|
1324
1465
|
resolveUsageTimes,
|
|
1325
1466
|
resultInvalidDate,
|
|
1326
1467
|
scheduleByDependencies,
|
|
1327
1468
|
shiftTask,
|
|
1469
|
+
sliceRangeItems,
|
|
1328
1470
|
startOfDay,
|
|
1329
1471
|
subtractPlannedDuration,
|
|
1330
1472
|
toDate,
|