ct-gantt-core 1.0.7 → 1.0.9
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 +126 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -1
- package/dist/index.d.ts +66 -1
- package/dist/index.js +121 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,12 +30,15 @@ __export(index_exports, {
|
|
|
30
30
|
RESOURCE_COLOR_PALETTE: () => RESOURCE_COLOR_PALETTE,
|
|
31
31
|
addDays: () => addDays,
|
|
32
32
|
addHours: () => addHours,
|
|
33
|
+
addPlannedDuration: () => addPlannedDuration,
|
|
34
|
+
alignPlannedDate: () => alignPlannedDate,
|
|
33
35
|
checkCyclicDependency: () => checkCyclicDependency,
|
|
34
36
|
computeHourScale: () => computeHourScale,
|
|
35
37
|
computeImpact: () => computeImpact,
|
|
36
38
|
computeLayout: () => computeLayout,
|
|
37
39
|
computeResourceLayout: () => computeResourceLayout,
|
|
38
40
|
computeTimeScale: () => computeTimeScale,
|
|
41
|
+
computeWorkload: () => computeWorkload,
|
|
39
42
|
createGanttEngine: () => createGanttEngine,
|
|
40
43
|
defaultConfig: () => defaultConfig,
|
|
41
44
|
diffDays: () => diffDays,
|
|
@@ -48,6 +51,7 @@ __export(index_exports, {
|
|
|
48
51
|
isValidDate: () => isValidDate,
|
|
49
52
|
mergeTaskPatch: () => mergeTaskPatch,
|
|
50
53
|
normalizeLinks: () => normalizeLinks,
|
|
54
|
+
plannedDurationBetween: () => plannedDurationBetween,
|
|
51
55
|
resolveResourceColor: () => resolveResourceColor,
|
|
52
56
|
resolveUsageColor: () => resolveUsageColor,
|
|
53
57
|
resolveUsageTimes: () => resolveUsageTimes,
|
|
@@ -55,6 +59,7 @@ __export(index_exports, {
|
|
|
55
59
|
scheduleByDependencies: () => scheduleByDependencies,
|
|
56
60
|
shiftTask: () => shiftTask,
|
|
57
61
|
startOfDay: () => startOfDay,
|
|
62
|
+
subtractPlannedDuration: () => subtractPlannedDuration,
|
|
58
63
|
toDate: () => toDate,
|
|
59
64
|
toDateTime: () => toDateTime
|
|
60
65
|
});
|
|
@@ -107,7 +112,7 @@ var defaultConfig = {
|
|
|
107
112
|
showPlanBar: true,
|
|
108
113
|
showActualBar: true,
|
|
109
114
|
showTimelineWhenEmpty: false,
|
|
110
|
-
builtInTaskEditor:
|
|
115
|
+
builtInTaskEditor: false,
|
|
111
116
|
builtInMarkerEditor: true,
|
|
112
117
|
editablePlan: false,
|
|
113
118
|
editableActual: true,
|
|
@@ -303,6 +308,52 @@ function diffHours(start, end) {
|
|
|
303
308
|
function inclusiveDays(start, end) {
|
|
304
309
|
return Math.max(0, diffDays(start, end) + 1);
|
|
305
310
|
}
|
|
311
|
+
function addPlannedDuration(start, duration, calendarId = "standard") {
|
|
312
|
+
const days = Math.max(0, Math.trunc(Number.isFinite(duration) ? duration : 0));
|
|
313
|
+
if (days === 0) return toDate(start);
|
|
314
|
+
if (calendarId === "delivery") return addDays(start, days - 1);
|
|
315
|
+
let current = toDate(start);
|
|
316
|
+
let remaining = days;
|
|
317
|
+
while (remaining > 0) {
|
|
318
|
+
const day = current.getDay();
|
|
319
|
+
if (day !== 0 && day !== 6) remaining -= 1;
|
|
320
|
+
if (remaining > 0) current = addDays(current, 1);
|
|
321
|
+
}
|
|
322
|
+
return current;
|
|
323
|
+
}
|
|
324
|
+
function subtractPlannedDuration(end, duration, calendarId = "standard") {
|
|
325
|
+
const days = Math.max(0, Math.trunc(Number.isFinite(duration) ? duration : 0));
|
|
326
|
+
if (days === 0) return toDate(end);
|
|
327
|
+
if (calendarId === "delivery") return addDays(end, -(days - 1));
|
|
328
|
+
let current = toDate(end);
|
|
329
|
+
let remaining = days;
|
|
330
|
+
while (remaining > 0) {
|
|
331
|
+
const day = current.getDay();
|
|
332
|
+
if (day !== 0 && day !== 6) remaining -= 1;
|
|
333
|
+
if (remaining > 0) current = addDays(current, -1);
|
|
334
|
+
}
|
|
335
|
+
return current;
|
|
336
|
+
}
|
|
337
|
+
function alignPlannedDate(date, calendarId = "standard", direction = 1) {
|
|
338
|
+
let current = toDate(date);
|
|
339
|
+
if (calendarId === "delivery") return current;
|
|
340
|
+
while (current.getDay() === 0 || current.getDay() === 6) {
|
|
341
|
+
current = addDays(current, direction);
|
|
342
|
+
}
|
|
343
|
+
return current;
|
|
344
|
+
}
|
|
345
|
+
function plannedDurationBetween(start, end, calendarId = "standard") {
|
|
346
|
+
const first = toDate(start);
|
|
347
|
+
const last = toDate(end);
|
|
348
|
+
if (last.getTime() < first.getTime()) return 0;
|
|
349
|
+
if (calendarId === "delivery") return inclusiveDays(first, last);
|
|
350
|
+
let duration = 0;
|
|
351
|
+
for (let current = first; current <= last; current = addDays(current, 1)) {
|
|
352
|
+
const day = current.getDay();
|
|
353
|
+
if (day !== 0 && day !== 6) duration += 1;
|
|
354
|
+
}
|
|
355
|
+
return duration;
|
|
356
|
+
}
|
|
306
357
|
function isValidDate(value) {
|
|
307
358
|
const date = value instanceof Date ? value : new Date(value);
|
|
308
359
|
return !Number.isNaN(date.getTime());
|
|
@@ -798,15 +849,82 @@ function minDate2(dates) {
|
|
|
798
849
|
return new Date(Math.min(...dates.map((date) => date.getTime())));
|
|
799
850
|
}
|
|
800
851
|
|
|
852
|
+
// src/engines/computeWorkload.ts
|
|
853
|
+
function computeWorkload(tasks, people, departments = [], range) {
|
|
854
|
+
const dated = range ?? inferRange(tasks);
|
|
855
|
+
if (!dated) return { dates: [], departments: [], ungrouped: [] };
|
|
856
|
+
const dates = datesBetween(dated.start, dated.end);
|
|
857
|
+
const dateSet = new Set(dates);
|
|
858
|
+
const rows = new Map(people.map((person) => [person.id, createPerson(person, dates)]));
|
|
859
|
+
for (const task of tasks) {
|
|
860
|
+
if (task.type === "summary" || task.type === "milestone") continue;
|
|
861
|
+
const ids = task.resources ?? [];
|
|
862
|
+
if (!ids.length) continue;
|
|
863
|
+
const values = task.dailyWorkloads ?? averageTaskWorkload(task);
|
|
864
|
+
for (const personId of ids) {
|
|
865
|
+
const row = rows.get(personId);
|
|
866
|
+
if (!row) continue;
|
|
867
|
+
for (const [date, hours] of Object.entries(values)) if (dateSet.has(date)) row.days.find((day) => day.date === date).hours += hours;
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
for (const row of rows.values()) finalize(row);
|
|
871
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
872
|
+
const ungrouped = [];
|
|
873
|
+
for (const row of rows.values()) (row.person.departmentId ? grouped.get(row.person.departmentId) ?? (grouped.set(row.person.departmentId, []), grouped.get(row.person.departmentId)) : ungrouped).push(row);
|
|
874
|
+
const departmentMap = new Map(departments.map((item) => [item.id, item]));
|
|
875
|
+
const result = [...grouped].map(([id, members]) => aggregateDepartment(departmentMap.get(id) ?? { id, name: id }, members, dates));
|
|
876
|
+
return { dates, departments: result, ungrouped };
|
|
877
|
+
}
|
|
878
|
+
function inferRange(tasks) {
|
|
879
|
+
if (!tasks.length) return void 0;
|
|
880
|
+
const dates = tasks.flatMap((t) => [toDate(t.plan.start), toDate(t.plan.end)]);
|
|
881
|
+
return { start: new Date(Math.min(...dates.map((d) => d.getTime()))), end: new Date(Math.max(...dates.map((d) => d.getTime()))) };
|
|
882
|
+
}
|
|
883
|
+
function datesBetween(start, end) {
|
|
884
|
+
const values = [];
|
|
885
|
+
for (let date = toDate(start); date <= toDate(end); date = addDays(date, 1)) values.push(formatDate(date));
|
|
886
|
+
return values;
|
|
887
|
+
}
|
|
888
|
+
function averageTaskWorkload(task) {
|
|
889
|
+
const total = task.workload ?? (task.duration ?? inclusiveDays(task.plan.start, task.plan.end)) * 8;
|
|
890
|
+
const allDates = datesBetween(task.plan.start, task.plan.end);
|
|
891
|
+
const dates = task.calendarId === "delivery" ? allDates : allDates.filter((date) => {
|
|
892
|
+
const day = toDate(date).getDay();
|
|
893
|
+
return day !== 0 && day !== 6;
|
|
894
|
+
});
|
|
895
|
+
const hours = dates.length ? total / dates.length : 0;
|
|
896
|
+
return Object.fromEntries(dates.map((date) => [date, hours]));
|
|
897
|
+
}
|
|
898
|
+
function createPerson(person, dates) {
|
|
899
|
+
return { person, days: dates.map((date) => ({ date, hours: 0, capacity: person.capacityPerDay ?? 8 })), workload: 0, capacity: 0, progress: 0 };
|
|
900
|
+
}
|
|
901
|
+
function finalize(row) {
|
|
902
|
+
row.workload = row.days.reduce((sum, day) => sum + day.hours, 0);
|
|
903
|
+
row.capacity = row.days.reduce((sum, day) => sum + day.capacity, 0);
|
|
904
|
+
row.progress = row.capacity ? Math.round(row.workload / row.capacity * 100) : 0;
|
|
905
|
+
}
|
|
906
|
+
function aggregateDepartment(department, people, dates) {
|
|
907
|
+
const days = dates.map((date, index) => ({ date, hours: people.reduce((sum, person) => sum + person.days[index].hours, 0), capacity: people.reduce((sum, person) => sum + person.days[index].capacity, 0) }));
|
|
908
|
+
const workload = days.reduce((sum, day) => sum + day.hours, 0);
|
|
909
|
+
const capacity = days.reduce((sum, day) => sum + day.capacity, 0);
|
|
910
|
+
return { department, people, days, workload, capacity, progress: capacity ? Math.round(workload / capacity * 100) : 0 };
|
|
911
|
+
}
|
|
912
|
+
|
|
801
913
|
// src/engine/GanttEngine.ts
|
|
802
914
|
function mergeTaskPatch(task, patch) {
|
|
915
|
+
const type = patch.type ?? task.type;
|
|
916
|
+
const calendarId = patch.calendarId ?? task.calendarId ?? "standard";
|
|
917
|
+
const planStart = patch.planStart ?? task.plan.start;
|
|
918
|
+
const planEnd = type === "milestone" ? planStart : patch.planEnd ?? task.plan.end;
|
|
919
|
+
const duration = type === "milestone" ? 1 : plannedDurationBetween(planStart, planEnd, calendarId);
|
|
803
920
|
return {
|
|
804
921
|
...task,
|
|
805
922
|
...patch,
|
|
923
|
+
duration,
|
|
806
924
|
plan: {
|
|
807
925
|
...task.plan,
|
|
808
|
-
start:
|
|
809
|
-
end:
|
|
926
|
+
start: planStart,
|
|
927
|
+
end: planEnd,
|
|
810
928
|
progress: patch.progress ?? task.plan.progress
|
|
811
929
|
},
|
|
812
930
|
actual: {
|
|
@@ -1176,12 +1294,15 @@ function createGanttEngine(options = {}) {
|
|
|
1176
1294
|
RESOURCE_COLOR_PALETTE,
|
|
1177
1295
|
addDays,
|
|
1178
1296
|
addHours,
|
|
1297
|
+
addPlannedDuration,
|
|
1298
|
+
alignPlannedDate,
|
|
1179
1299
|
checkCyclicDependency,
|
|
1180
1300
|
computeHourScale,
|
|
1181
1301
|
computeImpact,
|
|
1182
1302
|
computeLayout,
|
|
1183
1303
|
computeResourceLayout,
|
|
1184
1304
|
computeTimeScale,
|
|
1305
|
+
computeWorkload,
|
|
1185
1306
|
createGanttEngine,
|
|
1186
1307
|
defaultConfig,
|
|
1187
1308
|
diffDays,
|
|
@@ -1194,6 +1315,7 @@ function createGanttEngine(options = {}) {
|
|
|
1194
1315
|
isValidDate,
|
|
1195
1316
|
mergeTaskPatch,
|
|
1196
1317
|
normalizeLinks,
|
|
1318
|
+
plannedDurationBetween,
|
|
1197
1319
|
resolveResourceColor,
|
|
1198
1320
|
resolveUsageColor,
|
|
1199
1321
|
resolveUsageTimes,
|
|
@@ -1201,6 +1323,7 @@ function createGanttEngine(options = {}) {
|
|
|
1201
1323
|
scheduleByDependencies,
|
|
1202
1324
|
shiftTask,
|
|
1203
1325
|
startOfDay,
|
|
1326
|
+
subtractPlannedDuration,
|
|
1204
1327
|
toDate,
|
|
1205
1328
|
toDateTime
|
|
1206
1329
|
});
|