ct-gantt-core 1.0.13 → 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 +19 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -5
- package/dist/index.d.ts +28 -5
- package/dist/index.js +18 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
DEFAULT_HOUR_COLORS: () => DEFAULT_HOUR_COLORS,
|
|
25
25
|
DEFAULT_RESOURCE_COLORS: () => DEFAULT_RESOURCE_COLORS,
|
|
26
26
|
DEFAULT_TASK_COLORS: () => DEFAULT_TASK_COLORS,
|
|
27
|
+
DEFAULT_WORKLOAD_COLORS: () => DEFAULT_WORKLOAD_COLORS,
|
|
27
28
|
EDITOR_COLOR_OPTIONS: () => EDITOR_COLOR_OPTIONS,
|
|
28
29
|
GanttEngine: () => GanttEngine,
|
|
29
30
|
HOUR_MS: () => HOUR_MS,
|
|
@@ -97,6 +98,14 @@ var DEFAULT_RESOURCE_COLORS = {
|
|
|
97
98
|
booking: "#409EFF",
|
|
98
99
|
assignment: "#909399"
|
|
99
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
|
+
};
|
|
100
109
|
var RESOURCE_COLOR_PALETTE = [DEFAULT_RESOURCE_COLORS.booking];
|
|
101
110
|
var RESOURCE_EDITOR_COLOR_OPTIONS = [
|
|
102
111
|
"#409eff",
|
|
@@ -136,13 +145,16 @@ var defaultConfig = {
|
|
|
136
145
|
showLinkRejectionNotice: true,
|
|
137
146
|
virtualScroll: true,
|
|
138
147
|
taskColors: { ...DEFAULT_TASK_COLORS },
|
|
148
|
+
resourceUsageColors: { ...DEFAULT_RESOURCE_COLORS },
|
|
149
|
+
workloadColors: { ...DEFAULT_WORKLOAD_COLORS },
|
|
139
150
|
timeUnit: "day",
|
|
140
151
|
hourWidth: 12,
|
|
141
152
|
autoSchedule: true,
|
|
142
153
|
editable: true,
|
|
143
154
|
enableSelection: false,
|
|
144
155
|
showAddTaskColumn: true,
|
|
145
|
-
addTaskAs: "child"
|
|
156
|
+
addTaskAs: "child",
|
|
157
|
+
showAddUsageColumn: true
|
|
146
158
|
};
|
|
147
159
|
|
|
148
160
|
// src/services/checkCyclicDependency.ts
|
|
@@ -544,7 +556,9 @@ function mergeGanttConfig(base, patch = {}) {
|
|
|
544
556
|
...patch,
|
|
545
557
|
taskColors: { ...base.taskColors, ...patch.taskColors },
|
|
546
558
|
columnWidths: { ...base.columnWidths, ...patch.columnWidths },
|
|
547
|
-
resourceColors: { ...base.resourceColors, ...patch.resourceColors }
|
|
559
|
+
resourceColors: { ...base.resourceColors, ...patch.resourceColors },
|
|
560
|
+
resourceUsageColors: { ...base.resourceUsageColors, ...patch.resourceUsageColors },
|
|
561
|
+
workloadColors: { ...base.workloadColors, ...patch.workloadColors }
|
|
548
562
|
};
|
|
549
563
|
}
|
|
550
564
|
function resolveGanttConfig(patch = {}) {
|
|
@@ -821,14 +835,14 @@ function resolveResourceColor(resource, resourceColors) {
|
|
|
821
835
|
const source = resource.name || resource.id;
|
|
822
836
|
return RESOURCE_COLOR_PALETTE[colorHash(source) % RESOURCE_COLOR_PALETTE.length];
|
|
823
837
|
}
|
|
824
|
-
function resolveUsageColor(usage, resource, resourceColors) {
|
|
838
|
+
function resolveUsageColor(usage, resource, resourceColors, resourceUsageColors) {
|
|
825
839
|
if (usage.color) {
|
|
826
840
|
return usage.color;
|
|
827
841
|
}
|
|
828
842
|
if (resource.color || resourceColors?.[resource.id]) {
|
|
829
843
|
return resolveResourceColor(resource, resourceColors);
|
|
830
844
|
}
|
|
831
|
-
return usage.type === "assignment" ? DEFAULT_RESOURCE_COLORS.assignment : DEFAULT_RESOURCE_COLORS.booking;
|
|
845
|
+
return usage.type === "assignment" ? resourceUsageColors?.assignment ?? DEFAULT_RESOURCE_COLORS.assignment : resourceUsageColors?.booking ?? DEFAULT_RESOURCE_COLORS.booking;
|
|
832
846
|
}
|
|
833
847
|
function resolveUsageTimes(usage, timeUnit) {
|
|
834
848
|
if (timeUnit === "hour") {
|
|
@@ -1411,6 +1425,7 @@ function createGanttEngine(options = {}) {
|
|
|
1411
1425
|
DEFAULT_HOUR_COLORS,
|
|
1412
1426
|
DEFAULT_RESOURCE_COLORS,
|
|
1413
1427
|
DEFAULT_TASK_COLORS,
|
|
1428
|
+
DEFAULT_WORKLOAD_COLORS,
|
|
1414
1429
|
EDITOR_COLOR_OPTIONS,
|
|
1415
1430
|
GanttEngine,
|
|
1416
1431
|
HOUR_MS,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/styles/colors.ts","../src/types/index.ts","../src/services/checkCyclicDependency.ts","../src/services/normalizeLinks.ts","../src/services/flattenTasks.ts","../src/utils/date.ts","../src/services/computeTimeScale.ts","../src/services/computeHourScale.ts","../src/services/computeVisibleWindow.ts","../src/utils/mergeConfig.ts","../src/engines/scheduling.ts","../src/engines/computeLayout.ts","../src/engines/computeImpact.ts","../src/engines/computeResourceLayout.ts","../src/engines/computeWorkload.ts","../src/engine/GanttEngine.ts"],"sourcesContent":["export * from \"./types\"\nexport * from \"./styles/colors\"\nexport * from \"./services/checkCyclicDependency\"\nexport * from \"./services/normalizeLinks\"\nexport * from \"./services/flattenTasks\"\nexport * from \"./services/computeTimeScale\"\nexport * from \"./services/computeHourScale\"\nexport * from \"./services/computeVisibleWindow\"\nexport * from \"./utils/mergeConfig\"\nexport * from \"./engines/computeLayout\"\nexport * from \"./engines/computeImpact\"\nexport * from \"./engines/computeResourceLayout\"\nexport * from \"./engines/computeWorkload\"\nexport * from \"./engines/scheduling\"\nexport * from \"./utils/date\"\nexport * from \"./engine/GanttEngine\"\n","/**\n * 默认颜色统一配置 —— 甘特图 / 资源视图 / 小时视图的默认条色与调色板都从这里读取。\n *\n * 默认语义色对齐饿了么 / Element Plus:主色蓝、成功绿、警告橙、信息灰。\n * 单个实例仍可通过 config.taskColors / config.hourColors / config.resourceColors /\n * 任务 color、planColor 字段按需覆盖。\n *\n * 默认色按视图拆分:\n * - DEFAULT_TASK_COLORS:甘特图(实际条 / 计划条 / 阶段 / 里程碑),也是小时视图的共享回退。\n * - DEFAULT_HOUR_COLORS:小时视图计划条与里程碑的独立默认,互不影响甘特图。\n * - DEFAULT_RESOURCE_COLORS:资源视图占用条只保留蓝 / 灰两档(预订 / 承接)。\n */\n\n/** 甘特图默认语义色(对应 GanttConfig.taskColors) */\nexport const DEFAULT_TASK_COLORS: {\n task: string\n summary: string\n milestone: string\n plan: string\n progress: string\n} = {\n task: \"#409EFF\", // 普通任务实际条 · Element 主色\n summary: \"#909399\", // 阶段条 · Element Info\n milestone: \"#E6A23C\", // 里程碑菱形 / 参考线默认 · Element Warning\n plan: \"#C6E2FF\", // 计划条外部底色 · 主色浅阶\n progress: \"#67C23A\" // 计划条内部进度色 · Element Success\n}\n\n/** 小时视图计划条与里程碑默认色(对应 GanttConfig.hourColors);独立于甘特图,可单独修改 */\nexport const DEFAULT_HOUR_COLORS: {\n plan: string\n progress: string\n milestone: string\n} = {\n plan: \"#409EFF\", // 小时视图只有计划条,用主色保证在白底网格上可见\n progress: \"#67C23A\", // 兼容保留,小时视图不再绘制进度填充\n milestone: \"#E6A23C\" // 里程碑菱形 / 参考线默认\n}\n\n/** 资源视图占用条默认色:预订主色蓝、承接信息灰 */\nexport const DEFAULT_RESOURCE_COLORS: {\n booking: string\n assignment: string\n} = {\n booking: \"#409EFF\",\n assignment: \"#909399\"\n}\n\n/** 资源未指定颜色时的哈希回退;只含主色蓝,避免同一画面出现多种高饱和色 */\nexport const RESOURCE_COLOR_PALETTE: string[] = [DEFAULT_RESOURCE_COLORS.booking]\n\n/** 资源占用编辑器可选色:主色、浅主色、信息灰 */\nexport const RESOURCE_EDITOR_COLOR_OPTIONS: string[] = [\n \"#409eff\",\n \"#79bbff\",\n \"#909399\"\n]\n\n/** 内置任务编辑器 / 里程碑编辑器的可选颜色板 */\nexport const EDITOR_COLOR_OPTIONS: string[] = [\n \"#409eff\",\n \"#66b1ff\",\n \"#67c23a\",\n \"#e6a23c\",\n \"#f56c6c\",\n \"#909399\",\n \"#9b87c4\",\n \"#36cfc9\"\n]\n\n/** 左侧列表负责人头像兜底色板 */\nexport const OWNER_COLOR_PALETTE: string[] = [\"#409EFF\", \"#67C23A\", \"#E6A23C\", \"#F56C6C\", \"#909399\"]\n","import { DEFAULT_TASK_COLORS } from \"../styles/colors\"\r\n\r\nexport type ViewMode = \"day\" | \"week\" | \"month\" | \"quarter\" | \"year\"\r\n\r\nexport type LinkType = \"FS\" | \"SS\" | \"FF\" | \"SF\"\r\nexport type LagUnit = \"calendar\" | \"working\"\r\n\r\nexport type Result<T> =\r\n | { ok: true; data: T }\r\n | { ok: false; error: GanttError }\r\n\r\nexport interface GanttError {\r\n code:\r\n | \"CYCLE_DEPENDENCY\"\r\n | \"INVALID_DATE\"\r\n | \"MISSING_TASK\"\r\n | \"ORPHAN_DEPENDENCY\"\r\n | \"INVALID_DEPENDENCY\"\r\n message: string\r\n details?: unknown\r\n}\r\n\r\nexport interface DateRange {\r\n start: string | Date\r\n end: string | Date\r\n progress?: number\r\n}\r\n\r\nexport interface Dependency {\r\n id?: string\r\n predecessorId: string\r\n type: LinkType\r\n lag: number\r\n lagUnit: LagUnit\r\n}\r\n\r\nexport interface GanttTask {\r\n id: string\r\n name: string\r\n type: \"task\" | \"milestone\" | \"summary\"\r\n plan: DateRange\r\n actual: Required<DateRange>\r\n dependencies?: Dependency[]\r\n parentId?: string | null\r\n color?: string\r\n planColor?: string\r\n calendarId?: string\r\n resources?: string[]\r\n segments?: Array<{ start: string | Date; end: string | Date }>\r\n constraint?: {\r\n type: \"SNET\" | \"SNLT\" | \"MSO\" | \"MFO\" | \"ASAP\" | \"ALAP\"\r\n date?: string | Date\r\n }\r\n schedulingMode?: \"auto\" | \"manual\"\r\n duration?: number\r\n /** 用于资源负荷计算的计划总工时;未提供时按 duration*8 估算。 */\r\n workload?: number\r\n /** 覆盖平均分摊的逐日计划工时。 */\r\n dailyWorkloads?: Record<string, number>\r\n custom?: Record<string, unknown>\r\n}\r\n\r\nexport interface GanttMarker {\r\n id: string\r\n name: string\r\n date: string | Date\r\n color?: string\r\n}\r\n\r\nexport interface GanttEditorField {\r\n key: string\r\n label: string\r\n visible?: boolean\r\n editable?: boolean\r\n type?: \"text\" | \"number\" | \"date\" | \"select\" | \"checkbox\"\r\n options?: Array<{ label: string; value: string | number }>\r\n placeholder?: string\r\n}\r\n\r\n/** 内置任务字段键。列可通过 CustomColumn.field 绑定到这些内置字段。\r\n * 除 status / owner 外都对应任务对象上的真实字段;status 与 owner 是派生展示字段。 */\r\nexport type BuiltinFieldKey =\r\n | \"name\"\r\n | \"status\"\r\n | \"owner\"\r\n | \"resources\"\r\n | \"type\"\r\n | \"parentId\"\r\n | \"planStart\"\r\n | \"planEnd\"\r\n | \"actualStart\"\r\n | \"actualEnd\"\r\n | \"progress\"\r\n | \"duration\"\r\n | \"calendarId\"\r\n | \"schedulingMode\"\r\n | \"color\"\r\n | \"planColor\"\r\n\r\nexport interface CustomColumn {\r\n key: string\r\n /** 绑定到的内置任务字段键。缺省时列按自定义列处理,从 task.custom[key] 读取/编辑;设置后列读取/编辑该内置字段,key 仍作为列标识。 */\r\n field?: BuiltinFieldKey\r\n label: string\r\n width?: number\r\n visible?: boolean\r\n align?: \"left\" | \"center\" | \"right\"\r\n editable?: boolean\r\n /**\r\n * 是否在左侧表格横向滚动时固定(sticky)。\r\n * 默认不固定,需显式 `frozen: true`。所有固定列在左侧连续排列,\r\n * `left` 仅累计其前面的其他固定列宽度(中间未固定列不参与、可随滚动离开)。\r\n */\r\n frozen?: boolean\r\n /** checkbox 类型:布尔数据列,值存 task.custom[key](布尔),单元格点击即切换并触发 taskChange。 */\r\n type?: \"text\" | \"number\" | \"date\" | \"select\" | \"checkbox\"\r\n options?: Array<{ label: string; value: string | number }>\r\n placeholder?: string\r\n editor?: Omit<GanttEditorField, \"key\" | \"label\">\r\n formatter?: (value: unknown, task: GanttTask) => string\r\n cellClass?: string | ((task: GanttTask) => string)\r\n cellStyle?: Record<string, string | number> | ((task: GanttTask) => Record<string, string | number>)\r\n render?: (task: GanttTask) => { text: string; className?: string }\r\n}\r\n\r\nexport interface GanttConfig {\r\n viewMode: ViewMode\r\n rowHeight: number\r\n columnWidth: number\r\n headerHeight: number\r\n taskListWidth: number\r\n width?: string | number\r\n height?: string | number\r\n locale: string\r\n firstDayOfWeek: 0 | 1\r\n dateFormat: string\r\n customColumns?: CustomColumn[]\r\n columns?: CustomColumn[]\r\n editorFields?: GanttEditorField[]\r\n columnWidths?: Partial<Record<ViewMode, number>>\r\n theme?: \"light\" | \"dark\" | string\r\n visibleRange?: {\r\n start: string | Date\r\n end: string | Date\r\n }\r\n showPlanBar?: boolean\r\n showActualBar?: boolean\r\n showTimelineWhenEmpty?: boolean\r\n builtInTaskEditor?: boolean\r\n builtInMarkerEditor?: boolean\r\n editablePlan?: boolean\r\n editableActual?: boolean\r\n enableLinkCreation?: boolean\r\n showLinkRejectionNotice?: boolean\r\n virtualScroll?: boolean\r\n taskColors?: {\r\n task?: string\r\n summary?: string\r\n milestone?: string\r\n plan?: string\r\n progress?: string\r\n }\r\n /** 小时视图独立配色:plan/progress/milestone 缺省时回退到 taskColors 与 DEFAULT_HOUR_COLORS */\r\n hourColors?: {\r\n plan?: string\r\n progress?: string\r\n milestone?: string\r\n }\r\n resourceColors?: Record<string, string>\r\n /** 资源视图时间粒度;day 按整天渲染,hour 按占用携带的小时渲染(仅 ResourceTimeline 使用) */\r\n timeUnit?: \"day\" | \"hour\"\r\n /** 资源视图 hour 粒度下每小时像素宽 */\r\n hourWidth?: number\r\n /** 小时视图计划条高度;缺省时随 rowHeight 自动推导(与资源视图单车道条高公式一致) */\r\n barHeight?: number\r\n autoSchedule?: boolean\r\n editable?: boolean\r\n /** 在任务表格最左侧内置一列复选框(批量选择),值为组件内部状态,不写入任务数据。\r\n * 也可通过 columns 中 key 为 \"selection\" 的列显式启用并自定义位置/宽度。 */\r\n enableSelection?: boolean\r\n /** 是否显示左侧表格最右侧的快捷「+ / -」列;默认 true,横向滚动时固定在右侧。 */\r\n showAddTaskColumn?: boolean\r\n /** 「+」列新增任务的层级:child 为当前行的子任务(叶子会先变成阶段),bro 为同级任务。默认 child。 */\r\n addTaskAs?: \"child\" | \"bro\"\r\n}\r\n\r\nexport interface GanttLink {\r\n id: string\r\n sourceId: string\r\n targetId: string\r\n type: LinkType\r\n lag?: number\r\n lagUnit?: LagUnit\r\n}\r\n\r\nexport interface TaskLayout {\r\n taskId: string\r\n rowIndex: number\r\n left: number\r\n width: number\r\n top: number\r\n depth: number\r\n isCritical: boolean\r\n}\r\n\r\n/** 资源(会议室、负责人等),资源视图的 Y 轴主体 */\r\nexport interface Resource {\r\n id: string\r\n name: string\r\n color?: string\r\n custom?: Record<string, unknown>\r\n}\r\n\r\nexport type ResourceUsageType = \"booking\" | \"assignment\"\r\n\r\n/** 资源在某时间段的占用(会议室预订、负责人承接的项目等) */\r\nexport interface ResourceUsage {\r\n id: string\r\n resourceId: string\r\n /** 日历日粒度,与 GanttTask 一致;同一天内的时段(如 9:00-11:00)按当天整格渲染,时刻体现在 label/tooltip */\r\n start: string | Date\r\n end: string | Date\r\n label?: string\r\n color?: string\r\n type?: ResourceUsageType\r\n custom?: Record<string, unknown>\r\n}\r\n\r\nexport interface ResourceRowLayout {\r\n resourceId: string\r\n rowIndex: number\r\n /** 行内占用车道数(同时段重叠数),>1 时条需要堆叠变薄 */\r\n laneCount: number\r\n color: string\r\n usageIds: string[]\r\n}\r\n\r\nexport interface ResourceUsageLayout {\r\n usageId: string\r\n resourceId: string\r\n rowIndex: number\r\n laneIndex: number\r\n laneCount: number\r\n left: number\r\n width: number\r\n /** 绝对 top(含 headerHeight + rowIndex*rowHeight + 行内 lane 偏移) */\r\n top: number\r\n /** 条高度,由 laneCount 与 rowHeight 决定 */\r\n height: number\r\n}\r\n\r\nexport interface ResourceLayout {\r\n rows: ResourceRowLayout[]\r\n usages: ResourceUsageLayout[]\r\n}\r\n\r\nexport interface FlatTask {\r\n task: GanttTask\r\n depth: number\r\n rowIndex: number\r\n hasChildren: boolean\r\n collapsed: boolean\r\n}\r\n\r\nexport interface Calendar {\r\n id: string\r\n workingDays: number[]\r\n holidays: string[]\r\n hours: [number, number][]\r\n}\r\n\r\nexport interface TimeScale {\r\n start: Date\r\n end: Date\r\n left: number\r\n width: number\r\n}\r\n\r\nexport interface Viewport {\r\n scrollTop: number\r\n scrollLeft: number\r\n clientWidth: number\r\n clientHeight: number\r\n dpr: number\r\n}\r\n\r\nexport interface AffectedTasks {\r\n changed: Array<{\r\n taskId: string\r\n actualStart: string | Date\r\n actualEnd: string | Date\r\n rowIndex: number\r\n }>\r\n conflicts: Array<{\r\n taskId: string\r\n constraintType: string\r\n message: string\r\n }>\r\n}\r\n\r\nexport interface PatchTask {\r\n planStart?: string | Date\r\n planEnd?: string | Date\r\n actualStart?: string | Date\r\n actualEnd?: string | Date\r\n progress?: number\r\n name?: string\r\n type?: GanttTask[\"type\"]\r\n parentId?: string | null\r\n color?: string\r\n planColor?: string\r\n duration?: number\r\n workload?: number\r\n dailyWorkloads?: Record<string, number>\r\n schedulingMode?: \"auto\" | \"manual\"\r\n resources?: string[]\r\n calendarId?: string\r\n custom?: Record<string, unknown>\r\n}\r\n\r\nexport interface WorkloadPerson {\r\n id: string\r\n name: string\r\n departmentId?: string\r\n capacityPerDay?: number\r\n custom?: Record<string, unknown>\r\n}\r\n\r\nexport interface WorkloadDepartment { id: string; name: string }\r\nexport type WorkloadMode = \"badge\" | \"capacity\"\r\nexport interface DailyWorkload { date: string; hours: number; capacity: number }\r\nexport interface PersonWorkload {\r\n person: WorkloadPerson\r\n days: DailyWorkload[]\r\n workload: number\r\n capacity: number\r\n /** 已排工时占可用容量的百分比,可以超过 100。 */\r\n utilization?: number\r\n /** @deprecated 请使用 utilization;该字段仅为兼容旧版本保留。 */\r\n progress: number\r\n}\r\nexport interface DepartmentWorkload {\r\n department: WorkloadDepartment\r\n people: PersonWorkload[]\r\n days: DailyWorkload[]\r\n workload: number\r\n capacity: number\r\n /** 部门已排工时占总可用容量的百分比,可以超过 100。 */\r\n utilization?: number\r\n /** @deprecated 请使用 utilization;该字段仅为兼容旧版本保留。 */\r\n progress: number\r\n}\r\nexport interface WorkloadResult { dates: string[]; departments: DepartmentWorkload[]; ungrouped: PersonWorkload[] }\r\n\r\nexport const defaultConfig: GanttConfig = {\r\n viewMode: \"day\",\r\n rowHeight: 44,\r\n columnWidth: 30,\r\n headerHeight: 50,\r\n taskListWidth: 280,\r\n locale: \"zh-CN\",\r\n firstDayOfWeek: 0,\r\n dateFormat: \"YYYY-MM-DD\",\r\n showPlanBar: true,\r\n showActualBar: true,\r\n showTimelineWhenEmpty: false,\r\n builtInTaskEditor: false,\r\n builtInMarkerEditor: true,\r\n editablePlan: false,\r\n editableActual: true,\r\n enableLinkCreation: true,\r\n showLinkRejectionNotice: true,\r\n virtualScroll: true,\r\n taskColors: { ...DEFAULT_TASK_COLORS },\r\n timeUnit: \"day\",\r\n hourWidth: 12,\r\n autoSchedule: true,\r\n editable: true,\r\n enableSelection: false,\r\n showAddTaskColumn: true,\r\n addTaskAs: \"child\"\r\n}\r\n","import type { GanttLink } from \"../types\"\n\nexport function checkCyclicDependency(\n links: GanttLink[]\n): { hasCycle: boolean; cyclePath?: string[] } {\n const graph = new Map<string, string[]>()\n\n for (const link of links) {\n const targets = graph.get(link.sourceId) ?? []\n targets.push(link.targetId)\n graph.set(link.sourceId, targets)\n if (!graph.has(link.targetId)) {\n graph.set(link.targetId, [])\n }\n }\n\n const visiting = new Set<string>()\n const visited = new Set<string>()\n const path: string[] = []\n\n const dfs = (node: string): string[] | undefined => {\n if (visiting.has(node)) {\n const start = path.indexOf(node)\n return [...path.slice(start), node]\n }\n if (visited.has(node)) {\n return undefined\n }\n\n visiting.add(node)\n path.push(node)\n\n for (const next of graph.get(node) ?? []) {\n const cycle = dfs(next)\n if (cycle) {\n return cycle\n }\n }\n\n path.pop()\n visiting.delete(node)\n visited.add(node)\n return undefined\n }\n\n for (const node of graph.keys()) {\n const cyclePath = dfs(node)\n if (cyclePath) {\n return { hasCycle: true, cyclePath }\n }\n }\n\n return { hasCycle: false }\n}\n","import type { GanttLink, GanttTask } from \"../types\"\n\nexport function normalizeLinks(tasks: GanttTask[], standaloneLinks: GanttLink[] = []): GanttLink[] {\n const taskIds = new Set(tasks.map((task) => task.id))\n const byTaskPair = new Map<string, GanttLink>()\n const outgoing = new Map<string, Set<string>>()\n\n const createsCycle = (sourceId: string, targetId: string): boolean => {\n const pending = [targetId]\n const visited = new Set<string>()\n while (pending.length > 0) {\n const current = pending.pop()!\n if (current === sourceId) {\n return true\n }\n if (visited.has(current)) {\n continue\n }\n visited.add(current)\n pending.push(...(outgoing.get(current) ?? []))\n }\n return false\n }\n\n const append = (link: GanttLink) => {\n if (\n !taskIds.has(link.sourceId)\n || !taskIds.has(link.targetId)\n || link.sourceId === link.targetId\n ) {\n return\n }\n\n const normalized: GanttLink = {\n ...link,\n id: link.id || `link-${link.sourceId}-${link.targetId}`,\n lag: link.lag ?? 0,\n lagUnit: link.lagUnit ?? \"calendar\"\n }\n const pairKey = `${normalized.sourceId}|${normalized.targetId}`\n if (byTaskPair.has(pairKey) || createsCycle(normalized.sourceId, normalized.targetId)) {\n return\n }\n\n byTaskPair.set(pairKey, normalized)\n const targets = outgoing.get(normalized.sourceId) ?? new Set<string>()\n targets.add(normalized.targetId)\n outgoing.set(normalized.sourceId, targets)\n }\n\n for (const task of tasks) {\n for (const dependency of task.dependencies ?? []) {\n append({\n id: dependency.id || `link-${dependency.predecessorId}-${task.id}`,\n sourceId: dependency.predecessorId,\n targetId: task.id,\n type: dependency.type,\n lag: dependency.lag,\n lagUnit: dependency.lagUnit\n })\n }\n }\n\n for (const link of standaloneLinks) {\n append(link)\n }\n\n return [...byTaskPair.values()]\n}\n","import type { FlatTask, GanttTask } from \"../types\"\n\nexport function flattenTasks(tasks: GanttTask[], collapsedIds: Set<string> = new Set()): FlatTask[] {\n const children = new Map<string | null, GanttTask[]>()\n\n for (const task of tasks) {\n const parentId = task.parentId ?? null\n const bucket = children.get(parentId)\n if (bucket) {\n bucket.push(task)\n } else {\n children.set(parentId, [task])\n }\n }\n\n const flattened: FlatTask[] = []\n const visited = new Set<string>()\n const taskIds = new Set(tasks.map((task) => task.id))\n const visit = (task: GanttTask, depth: number) => {\n if (visited.has(task.id)) {\n return\n }\n visited.add(task.id)\n const childTasks = children.get(task.id) ?? []\n const collapsed = collapsedIds.has(task.id)\n\n flattened.push({\n task,\n depth,\n rowIndex: flattened.length,\n hasChildren: childTasks.length > 0,\n collapsed\n })\n\n if (!collapsed) {\n for (const child of childTasks) {\n visit(child, depth + 1)\n }\n }\n }\n\n for (const root of children.get(null) ?? []) {\n visit(root, 0)\n }\n for (const task of tasks) {\n if (visited.has(task.id)) continue\n const parentId = task.parentId ?? null\n if (parentId && taskIds.has(parentId)) continue\n visit(task, 0)\n }\n\n return flattened\n}\n","import type { Result } from \"../types\"\n\nexport const DAY_MS = 24 * 60 * 60 * 1000\nexport const HOUR_MS = 60 * 60 * 1000\n\nexport function toDate(value: string | Date): Date {\n if (value instanceof Date) {\n return startOfDay(value)\n }\n\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value)\n if (match) {\n return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]))\n }\n\n return startOfDay(new Date(value))\n}\n\n/** 字符串是否携带时间(\"T09:00\" 或 \" 09:00\")。Date 实例一律视为已带时间 */\nexport function hasTimeComponent(value: string | Date): boolean {\n return typeof value === \"string\" && /T\\d|:\\d/.test(value)\n}\n\n/**\n * 解析为保留时间部分的 Date。\n * 时间字符串(如 \"2026-07-02T09:00\" / \"2026-07-02 09:00\")按本地时间解析;\n * 纯日期字符串(如 \"2026-07-02\")回退到 toDate 的本地零点语义。\n */\nexport function toDateTime(value: string | Date): Date {\n if (value instanceof Date) {\n return new Date(value.getTime())\n }\n if (hasTimeComponent(value)) {\n const date = new Date(value.replace(\" \", \"T\"))\n if (!Number.isNaN(date.getTime())) {\n return date\n }\n }\n return toDate(value)\n}\n\nexport function startOfDay(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate())\n}\n\nexport function addDays(date: string | Date, days: number): Date {\n const next = toDate(date)\n next.setDate(next.getDate() + days)\n return startOfDay(next)\n}\n\nexport function diffDays(start: string | Date, end: string | Date): number {\n return Math.round((toDate(end).getTime() - toDate(start).getTime()) / DAY_MS)\n}\n\nexport function addHours(date: string | Date, hours: number): Date {\n return new Date(toDateTime(date).getTime() + hours * HOUR_MS)\n}\n\n/** 小时差(可含分钟的小数,如 09:00-11:30 = 2.5) */\nexport function diffHours(start: string | Date, end: string | Date): number {\n return (toDateTime(end).getTime() - toDateTime(start).getTime()) / HOUR_MS\n}\n\nexport function inclusiveDays(start: string | Date, end: string | Date): number {\n return Math.max(0, diffDays(start, end) + 1)\n}\n\n/**\n * Calculate the inclusive finish date for a planned duration.\n * The delivery calendar includes weekends; every other calendar currently\n * follows the standard Monday-Friday work week.\n */\nexport function addPlannedDuration(\n start: string | Date,\n duration: number,\n calendarId = \"standard\"\n): Date {\n const days = Math.max(0, Math.trunc(Number.isFinite(duration) ? duration : 0))\n if (days === 0) return toDate(start)\n if (calendarId === \"delivery\") return addDays(start, days - 1)\n\n let current = toDate(start)\n let remaining = days\n while (remaining > 0) {\n const day = current.getDay()\n if (day !== 0 && day !== 6) remaining -= 1\n if (remaining > 0) current = addDays(current, 1)\n }\n return current\n}\n\n/** Calculate the inclusive start date when a finish and duration are known. */\nexport function subtractPlannedDuration(\n end: string | Date,\n duration: number,\n calendarId = \"standard\"\n): Date {\n const days = Math.max(0, Math.trunc(Number.isFinite(duration) ? duration : 0))\n if (days === 0) return toDate(end)\n if (calendarId === \"delivery\") return addDays(end, -(days - 1))\n\n let current = toDate(end)\n let remaining = days\n while (remaining > 0) {\n const day = current.getDay()\n if (day !== 0 && day !== 6) remaining -= 1\n if (remaining > 0) current = addDays(current, -1)\n }\n return current\n}\n\n/** Move a planned date off a weekend for the standard calendar. */\nexport function alignPlannedDate(\n date: string | Date,\n calendarId = \"standard\",\n direction: 1 | -1 = 1\n): Date {\n let current = toDate(date)\n if (calendarId === \"delivery\") return current\n while (current.getDay() === 0 || current.getDay() === 6) {\n current = addDays(current, direction)\n }\n return current\n}\n\n/** Count inclusive planned working days between two dates. */\nexport function plannedDurationBetween(\n start: string | Date,\n end: string | Date,\n calendarId = \"standard\"\n): number {\n const first = toDate(start)\n const last = toDate(end)\n if (last.getTime() < first.getTime()) return 0\n if (calendarId === \"delivery\") return inclusiveDays(first, last)\n\n let duration = 0\n for (let current = first; current <= last; current = addDays(current, 1)) {\n const day = current.getDay()\n if (day !== 0 && day !== 6) duration += 1\n }\n return duration\n}\n\nexport function isValidDate(value: string | Date): boolean {\n const date = value instanceof Date ? value : new Date(value)\n return !Number.isNaN(date.getTime())\n}\n\n/** Min/max of dates without Math.min(...array), which throws on large lists. */\nexport function dateExtent(dates: Iterable<Date | number>): { start: Date; end: Date } | undefined {\n let min = Number.POSITIVE_INFINITY\n let max = Number.NEGATIVE_INFINITY\n for (const value of dates) {\n const time = typeof value === \"number\" ? value : value.getTime()\n if (!Number.isFinite(time)) continue\n if (time < min) min = time\n if (time > max) max = time\n }\n if (!Number.isFinite(min) || !Number.isFinite(max)) return undefined\n return { start: new Date(min), end: new Date(max) }\n}\n\nexport function formatDate(date: string | Date): string {\n const value = toDate(date)\n const year = value.getFullYear()\n const month = String(value.getMonth() + 1).padStart(2, \"0\")\n const day = String(value.getDate()).padStart(2, \"0\")\n return `${year}-${month}-${day}`\n}\n\nexport function formatDateTime(date: string | Date): string {\n const value = toDateTime(date)\n const hours = String(value.getHours()).padStart(2, \"0\")\n const minutes = String(value.getMinutes()).padStart(2, \"0\")\n return `${formatDate(value)} ${hours}:${minutes}`\n}\n\nexport function resultInvalidDate<T>(message: string, details?: unknown): Result<T> {\n return {\n ok: false,\n error: { code: \"INVALID_DATE\", message, details }\n }\n}\n","import type { TimeScale, ViewMode } from \"../types\"\nimport { addDays, diffDays, startOfDay } from \"../utils/date\"\n\nexport function computeTimeScale(\n start: Date,\n end: Date,\n viewMode: ViewMode,\n columnWidth: number,\n firstDayOfWeek: 0 | 1\n): TimeScale[] {\n const rangeStart = alignStart(start, viewMode, firstDayOfWeek)\n const endDate = startOfDay(end)\n const rangeEnd = viewMode === \"day\"\n ? addDays(endDate, (firstDayOfWeek + 6 - endDate.getDay() + 7) % 7)\n : endDate\n const scale: TimeScale[] = []\n let cursor = rangeStart\n let left = 0\n\n while (cursor.getTime() <= rangeEnd.getTime()) {\n const next = nextUnit(cursor, viewMode)\n const unitEnd = addDays(next, -1)\n const width = Math.max(1, diffDays(cursor, next)) * columnWidth\n\n scale.push({\n start: cursor,\n end: unitEnd,\n left,\n width\n })\n\n left += width\n cursor = next\n }\n\n return scale\n}\n\nfunction alignStart(date: Date, viewMode: ViewMode, firstDayOfWeek: 0 | 1): Date {\n const start = startOfDay(date)\n if (viewMode === \"day\" || viewMode === \"week\") {\n const delta = (start.getDay() - firstDayOfWeek + 7) % 7\n return addDays(start, -delta)\n }\n if (viewMode === \"month\") {\n return new Date(start.getFullYear(), start.getMonth(), 1)\n }\n if (viewMode === \"quarter\") {\n return new Date(start.getFullYear(), Math.floor(start.getMonth() / 3) * 3, 1)\n }\n if (viewMode === \"year\") {\n return new Date(start.getFullYear(), 0, 1)\n }\n return start\n}\n\nfunction nextUnit(date: Date, viewMode: ViewMode): Date {\n if (viewMode === \"week\") {\n return addDays(date, 7)\n }\n if (viewMode === \"month\") {\n return new Date(date.getFullYear(), date.getMonth() + 1, 1)\n }\n if (viewMode === \"quarter\") {\n return new Date(date.getFullYear(), date.getMonth() + 3, 1)\n }\n if (viewMode === \"year\") {\n return new Date(date.getFullYear() + 1, 0, 1)\n }\n return addDays(date, 1)\n}\n","import type { TimeScale } from \"../types\"\nimport { addDays, addHours, inclusiveDays, startOfDay } from \"../utils/date\"\n\nexport interface HourScale {\n /** 每日一格(顶行表头用) */\n days: TimeScale[]\n /** 每小时一格(底部刻度用) */\n hours: TimeScale[]\n start: Date\n end: Date\n}\n\n/** 小时级时间刻度:范围对齐到整天,每天拆成 24 个整点小时,width = hourWidth */\nexport function computeHourScale(start: Date, end: Date, hourWidth: number): HourScale {\n const rangeStart = startOfDay(start)\n const rangeEnd = startOfDay(end)\n const totalDays = Math.max(1, inclusiveDays(rangeStart, rangeEnd))\n const days: TimeScale[] = []\n const hours: TimeScale[] = []\n\n for (let d = 0; d < totalDays; d += 1) {\n const dayStart = addDays(rangeStart, d)\n days.push({\n start: dayStart,\n end: addHours(dayStart, 24),\n left: d * 24 * hourWidth,\n width: 24 * hourWidth\n })\n for (let h = 0; h < 24; h += 1) {\n const hourStart = addHours(dayStart, h)\n hours.push({\n start: hourStart,\n end: addHours(hourStart, 1),\n left: (d * 24 + h) * hourWidth,\n width: hourWidth\n })\n }\n }\n\n return { days, hours, start: rangeStart, end: rangeEnd }\n}\n","export interface VisibleWindow {\n start: number\n end: number\n before: number\n after: number\n}\n\n/**\n * Slice a uniform list (rows, equal-width columns) to the viewport plus overscan.\n * When the viewport has not been measured yet (size <= 0), return the full range\n * so jsdom tests and first paint still render.\n */\nexport function computeVisibleWindow(\n scroll: number,\n viewportSize: number,\n itemSize: number,\n itemCount: number,\n overscan = 8\n): VisibleWindow {\n if (itemCount <= 0 || itemSize <= 0) {\n return { start: 0, end: -1, before: 0, after: 0 }\n }\n if (viewportSize <= 0) {\n return { start: 0, end: itemCount - 1, before: 0, after: 0 }\n }\n const start = Math.max(0, Math.floor(scroll / itemSize) - overscan)\n const end = Math.min(\n itemCount - 1,\n Math.ceil((scroll + viewportSize) / itemSize) + overscan\n )\n return {\n start,\n end,\n before: start * itemSize,\n after: Math.max(0, (itemCount - end - 1) * itemSize)\n }\n}\n\n/** Keep variable-width timeline ticks whose span overlaps the horizontal viewport. */\nexport function sliceRangeItems<T extends { left: number; width: number }>(\n items: T[],\n scrollLeft: number,\n viewportWidth: number,\n overscanPx = 320\n): T[] {\n if (viewportWidth <= 0 || items.length === 0) {\n return items\n }\n const min = scrollLeft - overscanPx\n const max = scrollLeft + viewportWidth + overscanPx\n return items.filter((item) => item.left + item.width >= min && item.left <= max)\n}\n","import type { GanttConfig } from \"../types\"\nimport { defaultConfig } from \"../types\"\n\nexport function mergeGanttConfig(\n base: GanttConfig,\n patch: Partial<GanttConfig> = {}\n): GanttConfig {\n return {\n ...base,\n ...patch,\n taskColors: { ...base.taskColors, ...patch.taskColors },\n columnWidths: { ...base.columnWidths, ...patch.columnWidths },\n resourceColors: { ...base.resourceColors, ...patch.resourceColors }\n }\n}\n\nexport function resolveGanttConfig(patch: Partial<GanttConfig> = {}): GanttConfig {\n return mergeGanttConfig(defaultConfig, patch)\n}\n","import type { GanttLink, GanttTask, LinkType, Result } from \"../types\"\nimport { addDays, diffDays, inclusiveDays, toDate } from \"../utils/date\"\nimport { checkCyclicDependency } from \"../services/checkCyclicDependency\"\n\nexport function scheduleByDependencies(tasks: GanttTask[], links: GanttLink[]): Result<GanttTask[]> {\n const cycle = checkCyclicDependency(links)\n if (cycle.hasCycle) {\n return {\n ok: false,\n error: {\n code: \"CYCLE_DEPENDENCY\",\n message: \"Dependency graph contains a cycle.\",\n details: cycle.cyclePath\n }\n }\n }\n\n const taskMap = new Map(tasks.map((task) => [task.id, cloneTask(task)]))\n const incoming = new Map<string, GanttLink[]>()\n const outgoing = new Map<string, GanttLink[]>()\n\n for (const link of links) {\n const source = taskMap.get(link.sourceId)\n const target = taskMap.get(link.targetId)\n if (!source || !target) {\n return {\n ok: false,\n error: {\n code: \"ORPHAN_DEPENDENCY\",\n message: `Dependency ${link.id} references a missing task.`\n }\n }\n }\n const incomingList = incoming.get(link.targetId)\n if (incomingList) {\n incomingList.push(link)\n } else {\n incoming.set(link.targetId, [link])\n }\n const outgoingList = outgoing.get(link.sourceId)\n if (outgoingList) {\n outgoingList.push(link)\n } else {\n outgoing.set(link.sourceId, [link])\n }\n }\n\n const ordered = topologicalOrder(tasks.map((task) => task.id), links)\n\n for (const taskId of ordered) {\n const task = taskMap.get(taskId)\n if (!task || task.schedulingMode === \"manual\") {\n continue\n }\n\n const linksToTask = incoming.get(taskId) ?? []\n let start = toDate(task.actual.start)\n let end = toDate(task.actual.end)\n const duration = Math.max(0, task.duration ?? inclusiveDays(start, end))\n\n for (const link of linksToTask) {\n const source = taskMap.get(link.sourceId)\n if (!source) {\n continue\n }\n\n const candidate = applyDependency(source, start, end, duration, link.type, link.lag ?? 0)\n if (candidate.start.getTime() > start.getTime()) {\n start = candidate.start\n }\n if (candidate.end.getTime() > end.getTime()) {\n end = candidate.end\n }\n }\n\n const normalizedEnd = task.type === \"milestone\" ? start : addDays(start, Math.max(0, duration - 1))\n task.actual = {\n ...task.actual,\n start,\n end: normalizedEnd\n }\n }\n\n return { ok: true, data: tasks.map((task) => taskMap.get(task.id) ?? task) }\n}\n\nfunction applyDependency(\n source: GanttTask,\n currentStart: Date,\n currentEnd: Date,\n duration: number,\n type: LinkType,\n lag: number\n): { start: Date; end: Date } {\n const sourceStart = toDate(source.actual.start)\n const sourceEnd = toDate(source.actual.end)\n const span = Math.max(0, duration - 1)\n\n if (type === \"FS\") {\n const start = addDays(sourceEnd, lag + 1)\n return { start, end: addDays(start, span) }\n }\n\n if (type === \"SS\") {\n const start = addDays(sourceStart, lag)\n return { start, end: addDays(start, span) }\n }\n\n if (type === \"FF\") {\n const end = addDays(sourceEnd, lag)\n return { start: addDays(end, -span), end }\n }\n\n const end = addDays(sourceStart, lag)\n return { start: addDays(end, -span), end: end.getTime() > currentEnd.getTime() ? end : currentEnd }\n}\n\nfunction topologicalOrder(ids: string[], links: GanttLink[]): string[] {\n const indegree = new Map(ids.map((id) => [id, 0]))\n const outgoing = new Map<string, string[]>()\n\n for (const link of links) {\n indegree.set(link.targetId, (indegree.get(link.targetId) ?? 0) + 1)\n const targets = outgoing.get(link.sourceId)\n if (targets) {\n targets.push(link.targetId)\n } else {\n outgoing.set(link.sourceId, [link.targetId])\n }\n }\n\n const queue = ids.filter((id) => (indegree.get(id) ?? 0) === 0)\n const ordered: string[] = []\n let cursor = 0\n\n while (cursor < queue.length) {\n const current = queue[cursor]\n cursor += 1\n if (!current) continue\n ordered.push(current)\n for (const target of outgoing.get(current) ?? []) {\n indegree.set(target, (indegree.get(target) ?? 1) - 1)\n if (indegree.get(target) === 0) {\n queue.push(target)\n }\n }\n }\n\n return ordered.length === ids.length ? ordered : ids\n}\n\nfunction cloneTask(task: GanttTask): GanttTask {\n return {\n ...task,\n plan: { ...task.plan },\n actual: { ...task.actual },\n dependencies: task.dependencies?.map((dependency) => ({ ...dependency }))\n }\n}\n\nexport function shiftTask(task: GanttTask, start: string | Date): GanttTask {\n const currentStart = toDate(task.actual.start)\n const nextStart = toDate(start)\n const delta = diffDays(currentStart, nextStart)\n return {\n ...task,\n actual: {\n ...task.actual,\n start: nextStart,\n end: addDays(toDate(task.actual.end), delta)\n }\n }\n}\n","import type { GanttConfig, GanttLink, GanttTask, Result, TaskLayout, Viewport } from \"../types\"\nimport { flattenTasks } from \"../services/flattenTasks\"\nimport { normalizeLinks } from \"../services/normalizeLinks\"\nimport { scheduleByDependencies } from \"./scheduling\"\nimport { dateExtent, diffDays, inclusiveDays, isValidDate, toDate } from \"../utils/date\"\nimport { resolveGanttConfig } from \"../utils/mergeConfig\"\n\nexport function computeLayout(\n tasks: GanttTask[],\n links: GanttLink[],\n config: Partial<GanttConfig>,\n collapsedIds: Set<string> = new Set(),\n viewport?: Viewport\n): Result<TaskLayout[]> {\n const mergedConfig = resolveGanttConfig(config)\n\n for (const task of tasks) {\n if (!isValidDate(task.actual.start) || !isValidDate(task.actual.end)) {\n return {\n ok: false,\n error: {\n code: \"INVALID_DATE\",\n message: `Task ${task.id} has invalid actual dates.`\n }\n }\n }\n }\n\n const normalizedLinks = normalizeLinks(tasks, links)\n const scheduled = mergedConfig.autoSchedule === false\n ? { ok: true as const, data: tasks }\n : scheduleByDependencies(tasks, normalizedLinks)\n\n if (!scheduled.ok) {\n return scheduled\n }\n\n const flatTasks = flattenTasks(scheduled.data, collapsedIds)\n const firstDate = mergedConfig.visibleRange\n ? toDate(mergedConfig.visibleRange.start)\n : dateExtent(scheduled.data.map((task) => toDate(task.actual.start)))?.start ?? toDate(new Date())\n\n const visibleStart = viewport\n ? Math.max(0, Math.floor(viewport.scrollTop / mergedConfig.rowHeight) - 8)\n : 0\n const visibleEnd = viewport\n ? Math.ceil((viewport.scrollTop + viewport.clientHeight) / mergedConfig.rowHeight) + 8\n : Number.POSITIVE_INFINITY\n\n const layouts = flatTasks\n .filter((flat) => flat.rowIndex >= visibleStart && flat.rowIndex <= visibleEnd)\n .map<TaskLayout>((flat) => {\n const start = toDate(flat.task.actual.start)\n const end = toDate(flat.task.actual.end)\n const duration = flat.task.type === \"milestone\" ? 0 : inclusiveDays(start, end)\n\n return {\n taskId: flat.task.id,\n rowIndex: flat.rowIndex,\n left: diffDays(firstDate, start) * mergedConfig.columnWidth,\n width: Math.max(flat.task.type === \"milestone\" ? mergedConfig.columnWidth / 2 : mergedConfig.columnWidth, duration * mergedConfig.columnWidth),\n top: mergedConfig.headerHeight + flat.rowIndex * mergedConfig.rowHeight,\n depth: flat.depth,\n isCritical: false\n }\n })\n\n return { ok: true, data: layouts }\n}\n","import type { AffectedTasks, GanttConfig, GanttLink, GanttTask, PatchTask, Result } from \"../types\"\nimport { flattenTasks } from \"../services/flattenTasks\"\nimport { scheduleByDependencies, shiftTask } from \"./scheduling\"\nimport { addDays, inclusiveDays, toDate } from \"../utils/date\"\n\nexport function computeImpact(\n taskId: string,\n patch: PatchTask,\n tasks: GanttTask[],\n links: GanttLink[],\n config: Partial<GanttConfig>\n): Result<AffectedTasks> {\n const target = tasks.find((task) => task.id === taskId)\n if (!target) {\n return {\n ok: false,\n error: {\n code: \"MISSING_TASK\",\n message: `Task ${taskId} does not exist.`\n }\n }\n }\n\n const patchedTasks = tasks.map((task) => {\n if (task.id !== taskId) {\n return task\n }\n\n let next = { ...task, actual: { ...task.actual } }\n if (patch.actualStart) {\n next = shiftTask(next, patch.actualStart)\n }\n if (patch.actualEnd) {\n next.actual.end = patch.actualEnd\n }\n if (typeof patch.progress === \"number\") {\n next.actual.progress = patch.progress\n }\n if (patch.duration) {\n next.duration = patch.duration\n next.actual.end = addDays(toDate(next.actual.start), Math.max(0, patch.duration - 1))\n }\n if (patch.name) {\n next.name = patch.name\n }\n if (patch.type) {\n next.type = patch.type\n }\n if (\"parentId\" in patch) {\n next.parentId = patch.parentId\n }\n if (patch.color) {\n next.color = patch.color\n }\n if (\"planColor\" in patch) {\n next.planColor = patch.planColor\n }\n if (patch.schedulingMode) {\n next.schedulingMode = patch.schedulingMode\n }\n return next\n })\n\n const scheduled = config.autoSchedule === false\n ? { ok: true as const, data: patchedTasks }\n : scheduleByDependencies(patchedTasks, links)\n\n if (!scheduled.ok) {\n return scheduled\n }\n\n const rows = new Map(flattenTasks(scheduled.data).map((flat) => [flat.task.id, flat.rowIndex]))\n const originalById = new Map(tasks.map((task) => [task.id, task]))\n const changed = scheduled.data\n .filter((task) => {\n const original = originalById.get(task.id)\n return original && (\n String(original.actual.start) !== String(task.actual.start) ||\n String(original.actual.end) !== String(task.actual.end)\n )\n })\n .map((task) => ({\n taskId: task.id,\n actualStart: task.actual.start,\n actualEnd: task.actual.end,\n rowIndex: rows.get(task.id) ?? 0\n }))\n\n const conflicts = scheduled.data\n .filter((task) => task.constraint?.date && inclusiveDays(task.actual.start, task.constraint.date) < 0)\n .map((task) => ({\n taskId: task.id,\n constraintType: task.constraint!.type,\n message: \"Task violates its configured constraint date.\"\n }))\n\n return { ok: true, data: { changed, conflicts } }\n}\n","import type {\n GanttConfig,\n Resource,\n ResourceLayout,\n ResourceRowLayout,\n ResourceUsage,\n ResourceUsageLayout,\n Result,\n Viewport\n} from \"../types\"\nimport {\n addHours,\n dateExtent,\n diffDays,\n diffHours,\n hasTimeComponent,\n inclusiveDays,\n isValidDate,\n startOfDay,\n toDate,\n toDateTime\n} from \"../utils/date\"\nimport { resolveGanttConfig } from \"../utils/mergeConfig\"\nimport { DEFAULT_RESOURCE_COLORS, RESOURCE_COLOR_PALETTE } from \"../styles/colors\"\n\n// 向后兼容:RESOURCE_COLOR_PALETTE 原在本文件导出,继续从这里再导出一次\nexport { RESOURCE_COLOR_PALETTE }\n\nfunction colorHash(source: string): number {\n return [...source].reduce((sum, char) => sum + (char.codePointAt(0) ?? 0), 0)\n}\n\n/** 解析资源主色:resource.color → config.resourceColors[id] → 名称 hash 调色板(确定性) */\nexport function resolveResourceColor(\n resource: Resource,\n resourceColors?: Record<string, string>\n): string {\n if (resource.color) {\n return resource.color\n }\n if (resourceColors?.[resource.id]) {\n return resourceColors[resource.id]\n }\n const source = resource.name || resource.id\n return RESOURCE_COLOR_PALETTE[colorHash(source) % RESOURCE_COLOR_PALETTE.length]\n}\n\n/** 解析占用条颜色:usage.color → 所属资源色 → 预订蓝 / 承接灰 */\nexport function resolveUsageColor(\n usage: ResourceUsage,\n resource: Resource,\n resourceColors?: Record<string, string>\n): string {\n if (usage.color) {\n return usage.color\n }\n if (resource.color || resourceColors?.[resource.id]) {\n return resolveResourceColor(resource, resourceColors)\n }\n return usage.type === \"assignment\"\n ? DEFAULT_RESOURCE_COLORS.assignment\n : DEFAULT_RESOURCE_COLORS.booking\n}\n\n/**\n * 将占用解析为布局用的起止 Date。\n * - day:与 GanttTask 一致,截断到天。\n * - hour:保留时间;纯日期(未携带时间)按\"含结束日整天\"处理,与 day 模式的含末语义一致。\n */\nexport function resolveUsageTimes(\n usage: ResourceUsage,\n timeUnit: \"day\" | \"hour\"\n): { start: Date; end: Date } {\n if (timeUnit === \"hour\") {\n const start = toDateTime(usage.start)\n const endRaw = toDateTime(usage.end)\n return { start, end: hasTimeComponent(usage.end) ? endRaw : addHours(endRaw, 24) }\n }\n return { start: toDate(usage.start), end: toDate(usage.end) }\n}\n\n/**\n * 资源视图布局:每个资源一行(Y 轴),占用时间段以横向色条展示。\n * 同一资源同时段多个占用按贪心 first-fit 车道分配,行内堆叠子条。\n * day 粒度像素数学与 computeLayout 一致(diffDays × columnWidth);\n * hour 粒度按 diffHours × hourWidth 渲染,纯日期占用含结束日整天。\n * 传入 viewport 时仅产出可见行窗口内的占用几何(±8 overscan),rows 始终全量返回。\n */\nexport function computeResourceLayout(\n resources: Resource[],\n usages: ResourceUsage[],\n config: Partial<GanttConfig>,\n viewport?: Viewport\n): Result<ResourceLayout> {\n const mergedConfig = resolveGanttConfig(config)\n const timeUnit = mergedConfig.timeUnit ?? \"day\"\n const hourMode = timeUnit === \"hour\"\n const hourW = mergedConfig.hourWidth ?? 12\n\n for (const usage of usages) {\n const { start, end } = resolveUsageTimes(usage, timeUnit)\n if (!isValidDate(start) || !isValidDate(end)) {\n return {\n ok: false,\n error: {\n code: \"INVALID_DATE\",\n message: `Resource usage ${usage.id} has invalid dates.`\n }\n }\n }\n }\n\n // 行序:resources 顺序在前,usage 引用但未声明的 resourceId 追加在后(容错)\n const orderedIds: string[] = []\n const seen = new Set<string>()\n for (const resource of resources) {\n if (!seen.has(resource.id)) {\n seen.add(resource.id)\n orderedIds.push(resource.id)\n }\n }\n for (const usage of usages) {\n if (!seen.has(usage.resourceId)) {\n seen.add(usage.resourceId)\n orderedIds.push(usage.resourceId)\n }\n }\n\n const resourceById = new Map(resources.map((resource) => [resource.id, resource]))\n const usagesByResource = new Map<string, ResourceUsage[]>()\n for (const usage of usages) {\n const grouped = usagesByResource.get(usage.resourceId)\n if (grouped) {\n grouped.push(usage)\n } else {\n usagesByResource.set(usage.resourceId, [usage])\n }\n }\n\n const rows: ResourceRowLayout[] = []\n const usageLayouts: ResourceUsageLayout[] = []\n const laneIndexByUsage = new Map<string, number>()\n\n orderedIds.forEach((resourceId, rowIndex) => {\n const resource = resourceById.get(resourceId) ?? {\n id: resourceId,\n name: resourceId\n } satisfies Resource\n const grouped = [...(usagesByResource.get(resourceId) ?? [])].sort((a, b) => {\n const as = resolveUsageTimes(a, timeUnit)\n const bs = resolveUsageTimes(b, timeUnit)\n return as.start.getTime() - bs.start.getTime() || as.end.getTime() - bs.end.getTime()\n })\n\n // 贪心 first-fit 车道分配:占用放入第一个\"前一个占用结束不晚于其开始\"的车道。\n // day:diffDays(end, start) > 0(相邻日复用);hour:diffHours(end, start) >= 0(首尾相接复用)\n const laneEnds: Array<Date | null> = []\n for (const usage of grouped) {\n const { start, end } = resolveUsageTimes(usage, timeUnit)\n let laneIndex = -1\n for (let k = 0; k < laneEnds.length; k += 1) {\n const laneEnd = laneEnds[k]\n if (laneEnd === null || isLaneFree(laneEnd, start, hourMode)) {\n laneIndex = k\n break\n }\n }\n if (laneIndex === -1) {\n laneIndex = laneEnds.length\n laneEnds.push(null)\n }\n laneEnds[laneIndex] = end\n laneIndexByUsage.set(usage.id, laneIndex)\n }\n\n rows.push({\n resourceId,\n rowIndex,\n laneCount: laneEnds.length,\n color: resolveResourceColor(resource, mergedConfig.resourceColors),\n usageIds: grouped.map((usage) => usage.id)\n })\n })\n\n const usageById = new Map(usages.map((usage) => [usage.id, usage]))\n const visibleStart = viewport\n ? Math.max(0, Math.floor(viewport.scrollTop / mergedConfig.rowHeight) - 8)\n : 0\n const visibleEnd = viewport\n ? Math.ceil((viewport.scrollTop + viewport.clientHeight) / mergedConfig.rowHeight) + 8\n : Number.POSITIVE_INFINITY\n\n const firstDate = hourMode\n ? startOfDay(\n mergedConfig.visibleRange\n ? toDateTime(mergedConfig.visibleRange.start)\n : dateExtent(usages.map((usage) => resolveUsageTimes(usage, \"hour\").start))?.start\n ?? toDateTime(new Date())\n )\n : mergedConfig.visibleRange\n ? toDate(mergedConfig.visibleRange.start)\n : dateExtent(usages.map((usage) => toDate(usage.start)))?.start ?? toDate(new Date())\n\n for (const row of rows) {\n if (row.rowIndex < visibleStart || row.rowIndex > visibleEnd) {\n continue\n }\n const resource = resourceById.get(row.resourceId) ?? { id: row.resourceId, name: row.resourceId }\n const laneCount = Math.max(1, row.laneCount)\n const slot = mergedConfig.rowHeight / laneCount\n const barHeight = Math.max(6, Math.min(14, slot - 4))\n\n for (const usageId of row.usageIds) {\n const usage = usageById.get(usageId)\n if (!usage) {\n continue\n }\n const { start, end } = resolveUsageTimes(usage, timeUnit)\n const laneIndex = laneIndexByUsage.get(usageId) ?? 0\n const laneTop = laneIndex * slot + (slot - barHeight) / 2\n const left = hourMode\n ? diffHours(firstDate, start) * hourW\n : diffDays(firstDate, start) * mergedConfig.columnWidth\n const width = hourMode\n ? Math.max(hourW, diffHours(start, end) * hourW)\n : Math.max(mergedConfig.columnWidth, inclusiveDays(start, end) * mergedConfig.columnWidth)\n\n usageLayouts.push({\n usageId,\n resourceId: row.resourceId,\n rowIndex: row.rowIndex,\n laneIndex,\n laneCount,\n left,\n width,\n top: mergedConfig.headerHeight + row.rowIndex * mergedConfig.rowHeight + laneTop,\n height: barHeight\n })\n }\n }\n\n return { ok: true, data: { rows, usages: usageLayouts } }\n}\n\nfunction isLaneFree(laneEnd: Date, start: Date, hourMode: boolean): boolean {\n return hourMode ? diffHours(laneEnd, start) >= 0 : diffDays(laneEnd, start) > 0\n}\n","import type { DepartmentWorkload, GanttTask, PersonWorkload, WorkloadDepartment, WorkloadPerson, WorkloadResult } from \"../types\"\nimport { addDays, dateExtent, formatDate, inclusiveDays, toDate } from \"../utils/date\"\n\nexport function computeWorkload(tasks: GanttTask[], people: WorkloadPerson[], departments: WorkloadDepartment[] = [], range?: { start: string | Date; end: string | Date }): WorkloadResult {\n const dated = range ?? inferRange(tasks)\n if (!dated) return { dates: [], departments: [], ungrouped: [] }\n const dates = datesBetween(dated.start, dated.end)\n const dateIndex = new Map(dates.map((date, index) => [date, index]))\n const rows = new Map(people.map(person => [person.id, createPerson(person, dates)]))\n for (const task of tasks) {\n if (task.type === \"summary\" || task.type === \"milestone\") continue\n const ids = task.resources ?? []\n if (!ids.length) continue\n const values = task.dailyWorkloads ?? averageTaskWorkload(task)\n for (const personId of ids) {\n const row = rows.get(personId)\n if (!row) continue\n for (const [date, hours] of Object.entries(values)) {\n const index = dateIndex.get(date)\n if (index !== undefined) row.days[index].hours += hours\n }\n }\n }\n for (const row of rows.values()) finalize(row)\n const grouped = new Map<string, PersonWorkload[]>()\n const ungrouped: PersonWorkload[] = []\n for (const row of rows.values()) {\n if (row.person.departmentId) {\n const members = grouped.get(row.person.departmentId)\n if (members) members.push(row)\n else grouped.set(row.person.departmentId, [row])\n } else {\n ungrouped.push(row)\n }\n }\n const departmentMap = new Map(departments.map(item => [item.id, item]))\n const result: DepartmentWorkload[] = [...grouped].map(([id, members]) => aggregateDepartment(departmentMap.get(id) ?? { id, name: id }, members, dates))\n return { dates, departments: result, ungrouped }\n}\n\nfunction inferRange(tasks: GanttTask[]) {\n if (!tasks.length) return undefined\n const extent = dateExtent(tasks.flatMap(task => [toDate(task.plan.start), toDate(task.plan.end)]))\n return extent ? { start: extent.start, end: extent.end } : undefined\n}\nfunction datesBetween(start: string | Date, end: string | Date) { const values: string[] = []; for (let date = toDate(start); date <= toDate(end); date = addDays(date, 1)) values.push(formatDate(date)); return values }\nfunction averageTaskWorkload(task: GanttTask) { const total = task.workload ?? (task.duration ?? inclusiveDays(task.plan.start, task.plan.end)) * 8; const allDates = datesBetween(task.plan.start, task.plan.end); const dates = task.calendarId === \"delivery\" ? allDates : allDates.filter(date => { const day = toDate(date).getDay(); return day !== 0 && day !== 6 }); const hours = dates.length ? total / dates.length : 0; return Object.fromEntries(dates.map(date => [date, hours])) }\nfunction createPerson(person: WorkloadPerson, dates: string[]): PersonWorkload { return { person, days: dates.map(date => ({ date, hours: 0, capacity: person.capacityPerDay ?? 8 })), workload: 0, capacity: 0, utilization: 0, progress: 0 } }\nfunction finalize(row: PersonWorkload) { row.workload = row.days.reduce((sum, day) => sum + day.hours, 0); row.capacity = row.days.reduce((sum, day) => sum + day.capacity, 0); row.utilization = row.capacity ? Math.round(row.workload / row.capacity * 100) : 0; row.progress = row.utilization }\nfunction aggregateDepartment(department: WorkloadDepartment, people: PersonWorkload[], dates: string[]): DepartmentWorkload { 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) })); const workload = days.reduce((sum, day) => sum + day.hours, 0); const capacity = days.reduce((sum, day) => sum + day.capacity, 0); const utilization = capacity ? Math.round(workload / capacity * 100) : 0; return { department, people, days, workload, capacity, utilization, progress: utilization } }\n","import type {\n GanttConfig,\n GanttTask,\n GanttLink,\n GanttMarker,\n PatchTask,\n TaskLayout,\n TimeScale,\n FlatTask,\n Result\n} from \"../types\"\nimport { defaultConfig } from \"../types\"\nimport { computeLayout } from \"../engines/computeLayout\"\nimport { computeTimeScale } from \"../services/computeTimeScale\"\nimport { flattenTasks } from \"../services/flattenTasks\"\nimport { addDays, dateExtent, diffDays, plannedDurationBetween, toDate } from \"../utils/date\"\nimport { mergeGanttConfig } from \"../utils/mergeConfig\"\n\n/**\n * 把扁平的 PatchTask 合并回嵌套的 GanttTask。\n * PatchTask 用 planStart/planEnd/actualStart/actualEnd 表示日期,\n * GanttTask 用 plan.start/end、actual.start/end 嵌套表示——这是组件层\n * 和数据层之间的桥,本该在引擎层而不是散落在各 demo 里。\n */\nexport function mergeTaskPatch(task: GanttTask, patch: PatchTask): GanttTask {\n const type = patch.type ?? task.type\n const calendarId = patch.calendarId ?? task.calendarId ?? \"standard\"\n const planStart = patch.planStart ?? task.plan.start\n const planEnd = type === \"milestone\"\n ? planStart\n : patch.planEnd ?? task.plan.end\n const duration = type === \"milestone\"\n ? 1\n : plannedDurationBetween(planStart, planEnd, calendarId)\n return {\n ...task,\n ...patch,\n duration,\n plan: {\n ...task.plan,\n start: planStart,\n end: planEnd,\n progress: patch.progress ?? task.plan.progress\n },\n actual: {\n ...task.actual,\n start: patch.actualStart ?? task.actual.start,\n end: patch.actualEnd ?? task.actual.end,\n progress: patch.progress ?? task.actual.progress\n },\n custom: patch.custom ? { ...task.custom, ...patch.custom } : task.custom\n }\n}\n\nexport interface GanttEngineOptions {\n tasks?: GanttTask[]\n links?: GanttLink[]\n config?: Partial<GanttConfig>\n /** 滚动容器元素;命令式视口 API(scrollToDate / zoomToFit)需要它。纯计算场景可不传。 */\n container?: HTMLElement | null\n /** 初始折叠的任务 id */\n collapsedIds?: Iterable<string>\n /** 里程碑标记 */\n markers?: GanttMarker[]\n}\n\nexport type GanttEngineEvent =\n | \"ready\"\n | \"taskschange\"\n | \"taskchange\"\n | \"taskcreate\"\n | \"taskdelete\"\n | \"linkschange\"\n | \"configchange\"\n | \"collapsechange\"\n | \"previewchange\"\n | \"markerschange\"\n | \"destroy\"\n\ntype Listener = (...args: unknown[]) => void\n\n/** 命令式甘特图引擎。框架无关,可被 Vue/React/原生 各自的薄壳组件驱动。 */\nexport class GanttEngine {\n private tasks: GanttTask[]\n private links: GanttLink[]\n private config: GanttConfig\n private readonly container: HTMLElement | null\n private collapsedIds: Set<string>\n private dragPreview: { taskId: string; patch: PatchTask; affected?: Record<string, PatchTask> } | null = null\n private markers: GanttMarker[]\n private readonly listeners: Map<GanttEngineEvent, Set<Listener>>\n private destroyed = false\n\n constructor(options: GanttEngineOptions = {}) {\n this.tasks = options.tasks ? options.tasks.map((task) => ({ ...task })) : []\n this.links = options.links ? options.links.map((link) => ({ ...link })) : []\n this.config = mergeGanttConfig({ ...defaultConfig }, { ...options.config })\n this.container = options.container ?? null\n this.collapsedIds = new Set(options.collapsedIds ?? [])\n this.markers = options.markers ? options.markers.map((marker) => ({ ...marker })) : []\n this.listeners = new Map()\n // 异步发 ready,确保订阅者能在构造后、首次 emit 前注册\n queueMicrotask(() => this.emit(\"ready\"))\n }\n\n // ── 状态查询 ──\n getTasks(): GanttTask[] {\n return this.tasks.map((task) => ({ ...task }))\n }\n getLinks(): GanttLink[] {\n return this.links.map((link) => ({ ...link }))\n }\n getMarkers(): GanttMarker[] {\n return this.markers.map((marker) => ({ ...marker }))\n }\n getConfig(): GanttConfig {\n return { ...this.config }\n }\n getTask(id: string): GanttTask | undefined {\n const task = this.tasks.find((item) => item.id === id)\n return task ? { ...task } : undefined\n }\n getCollapsedIds(): string[] {\n return Array.from(this.collapsedIds)\n }\n isDestroyed(): boolean {\n return this.destroyed\n }\n\n // ── 命令式变更(均触发对应事件) ──\n setTasks(tasks: GanttTask[]): void {\n this.assertNotDestroyed()\n this.tasks = tasks.map((task) => ({ ...task }))\n this.emit(\"taskschange\", this.tasks)\n }\n setLinks(links: GanttLink[]): void {\n this.assertNotDestroyed()\n this.links = links.map((link) => ({ ...link }))\n this.emit(\"linkschange\", this.links)\n }\n setMarkers(markers: GanttMarker[]): void {\n this.assertNotDestroyed()\n this.markers = markers.map((marker) => ({ ...marker }))\n this.emit(\"markerschange\", this.markers)\n }\n /** 合并配置 patch,等价于 setConfig(mergeConfig(patch)) */\n mergeConfig(patch: Partial<GanttConfig>): void {\n this.assertNotDestroyed()\n this.config = mergeGanttConfig(this.config, patch)\n this.emit(\"configchange\", this.getConfig())\n }\n setConfig(config: Partial<GanttConfig>): void {\n this.mergeConfig(config)\n }\n /** 用 mergeTaskPatch 把扁平 patch 合并回嵌套结构后更新单个任务 */\n setTask(id: string, patch: PatchTask): void {\n this.assertNotDestroyed()\n const target = this.tasks.find((task) => task.id === id)\n if (!target) {\n return\n }\n const updated = mergeTaskPatch(target, patch)\n this.tasks = this.tasks.map((task) => (task.id === id ? updated : task))\n this.emit(\"taskchange\", id, patch, { ...updated })\n }\n addTask(task: GanttTask): void {\n this.assertNotDestroyed()\n this.tasks = [...this.tasks, { ...task }]\n this.emit(\"taskcreate\", { ...task })\n }\n removeTask(id: string): void {\n this.assertNotDestroyed()\n const removed = this.tasks.find((task) => task.id === id)\n if (!removed) return\n this.tasks = this.tasks.filter((task) => task.id !== id)\n this.collapsedIds.delete(id)\n this.emit(\"taskdelete\", id)\n }\n collapse(id: string, collapsed = true): void {\n this.assertNotDestroyed()\n if (collapsed) this.collapsedIds.add(id)\n else this.collapsedIds.delete(id)\n this.emit(\"collapsechange\", this.getCollapsedIds())\n }\n toggleCollapse(id: string): void {\n this.collapse(id, !this.collapsedIds.has(id))\n }\n /** 批量折叠/展开多个任务(如\"折叠全部分组\") */\n setCollapsed(ids: string[], collapsed = true): void {\n this.assertNotDestroyed()\n const next = new Set(this.collapsedIds)\n for (const id of ids) {\n if (collapsed) {\n next.add(id)\n } else {\n next.delete(id)\n }\n }\n this.collapsedIds = next\n this.emit(\"collapsechange\", this.getCollapsedIds())\n }\n\n // ── 拖拽预览(交互态源;组件写入迁移到 engine,dateRange 可据此扩展) ──\n setPreview(preview: { taskId: string; patch: PatchTask; affected?: Record<string, PatchTask> }): void {\n this.assertNotDestroyed()\n this.dragPreview = {\n taskId: preview.taskId,\n patch: { ...preview.patch },\n affected: preview.affected ? { ...preview.affected } : undefined\n }\n this.emit(\"previewchange\", this.getPreview())\n }\n clearPreview(): void {\n if (!this.dragPreview) {\n return\n }\n this.dragPreview = null\n this.emit(\"previewchange\", null)\n }\n getPreview(): { taskId: string; patch: PatchTask; affected?: Record<string, PatchTask> } | null {\n if (!this.dragPreview) {\n return null\n }\n return {\n taskId: this.dragPreview.taskId,\n patch: { ...this.dragPreview.patch },\n affected: this.dragPreview.affected ? { ...this.dragPreview.affected } : undefined\n }\n }\n\n // ── 计算(delegate 到 core 纯函数) ──\n /** 数据真实日期范围(未含 viewport pad) */\n getDateRange(): { start: Date; end: Date } {\n const dates: Date[] = []\n for (const task of this.tasks) {\n dates.push(\n toDate(task.plan.start),\n toDate(task.plan.end),\n toDate(task.actual.start),\n toDate(task.actual.end)\n )\n }\n for (const marker of this.markers) {\n dates.push(toDate(marker.date))\n }\n // 合并拖拽预览:用 mergeTaskPatch 算 patch 后日期扩范围(只扩不缩)\n const preview = this.dragPreview\n if (preview) {\n const ids = [preview.taskId, ...Object.keys(preview.affected ?? {})]\n for (const id of ids) {\n const task = this.tasks.find((item) => item.id === id)\n if (!task) {\n continue\n }\n const patch = preview.taskId === id ? preview.patch : preview.affected?.[id]\n if (!patch) {\n continue\n }\n const merged = mergeTaskPatch(task, patch)\n dates.push(\n toDate(merged.plan.start),\n toDate(merged.plan.end),\n toDate(merged.actual.start),\n toDate(merged.actual.end)\n )\n }\n }\n if (!dates.length) {\n const today = toDate(new Date())\n return { start: today, end: addDays(today, 30) }\n }\n const extent = dateExtent(dates)\n return extent ?? { start: dates[0], end: dates[0] }\n }\n getTimeScale(): TimeScale[] {\n const range = this.getDateRange()\n return computeTimeScale(\n range.start,\n range.end,\n this.config.viewMode,\n this.config.columnWidth,\n this.config.firstDayOfWeek\n )\n }\n getLayout(): Result<TaskLayout[]> {\n return computeLayout(\n this.tasks,\n this.links,\n this.config,\n this.collapsedIds\n )\n }\n getFlatTasks(): FlatTask[] {\n return flattenTasks(this.tasks, this.collapsedIds)\n }\n getTotalWidth(): number {\n return this.getTimeScale().reduce((sum, tick) => sum + tick.width, 0)\n }\n getTotalHeight(): number {\n const rows = this.getFlatTasks().length\n return this.config.headerHeight + rows * this.config.rowHeight\n }\n\n // ── 视口命令(需要 container) ──\n getScrollLeft(): number {\n return this.container?.scrollLeft ?? 0\n }\n setScrollLeft(px: number): void {\n if (!this.container) return\n const max = Math.max(0, this.container.scrollWidth - this.container.clientWidth)\n this.container.scrollLeft = Math.max(0, Math.min(max, px))\n }\n /** 把当前 scrollLeft 限制到 [0, maxScrollLeft]。\n * 拖拽预览收缩(松手/取消)后 timeline 总宽度变小,scrollLeft 可能超出新边界,\n * 导致 canvas translate 超出内容区、右侧网格未覆盖。此时调用本方法防超界。 */\n clampScrollLeft(): void {\n if (!this.container) return\n const max = Math.max(0, this.container.scrollWidth - this.container.clientWidth)\n if (this.container.scrollLeft > max) {\n this.container.scrollLeft = max\n }\n }\n getScrollTop(): number {\n return this.container?.scrollTop ?? 0\n }\n setScrollTop(px: number): void {\n if (!this.container) return\n const max = Math.max(0, this.container.scrollHeight - this.container.clientHeight)\n this.container.scrollTop = Math.max(0, Math.min(max, px))\n }\n /** 滚动到包含目标日期的 tick 列(跨 viewMode 精确) */\n scrollToDate(date: string | Date): void {\n if (!this.container) return\n const target = toDate(date)\n const scale = this.getTimeScale()\n const tick = scale.find((t) => target >= t.start && target <= t.end)\n const left = tick ? tick.left : diffDays(this.getDateRange().start, target) * this.config.columnWidth\n this.setScrollLeft(left)\n }\n scrollToTask(id: string): void {\n const layout = this.getLayout()\n if (!layout.ok) return\n const item = layout.data.find((row) => row.taskId === id)\n if (item) this.setScrollLeft(item.left)\n }\n scrollToStart(): void {\n this.setScrollLeft(0)\n }\n scrollToEnd(): void {\n if (!this.container) return\n this.setScrollLeft(this.getTotalWidth())\n }\n /** 让整个 timeline 总宽度≈视口宽度(调 columnWidth) */\n zoomToFit(padding = 1): void {\n if (!this.container) return\n const spanDays = Math.max(1, diffDays(this.getDateRange().start, this.getDateRange().end) + 1)\n const target = (this.container.clientWidth * padding) / spanDays\n this.mergeConfig({ columnWidth: this.clampColumnWidth(target) })\n }\n /** 让指定日期范围占满视口宽度(调 columnWidth) */\n zoomToRange(start: string | Date, end: string | Date): void {\n if (!this.container) return\n const span = Math.max(1, diffDays(start, end) + 1)\n const target = this.container.clientWidth / span\n this.mergeConfig({ columnWidth: this.clampColumnWidth(target) })\n }\n private clampColumnWidth(value: number): number {\n return Math.max(4, Math.min(400, Math.round(value)))\n }\n\n // ── 事件订阅 ──\n on(event: GanttEngineEvent, fn: Listener): () => void {\n this.assertNotDestroyed()\n let set = this.listeners.get(event)\n if (!set) {\n set = new Set()\n this.listeners.set(event, set)\n }\n set.add(fn)\n return () => {\n const current = this.listeners.get(event)\n if (current) {\n current.delete(fn)\n if (!current.size) this.listeners.delete(event)\n }\n }\n }\n once(event: GanttEngineEvent, fn: Listener): () => void {\n const off = this.on(event, (...args: unknown[]) => {\n off()\n fn(...args)\n })\n return off\n }\n off(event: GanttEngineEvent, fn?: Listener): void {\n const set = this.listeners.get(event)\n if (!set) return\n if (fn) {\n set.delete(fn)\n if (!set.size) this.listeners.delete(event)\n } else {\n this.listeners.delete(event)\n }\n }\n emit(event: GanttEngineEvent, ...args: unknown[]): void {\n const set = this.listeners.get(event)\n if (!set) return\n // 复制遍历,避免回调中增删导致迭代错乱\n for (const fn of Array.from(set)) {\n try {\n fn(...args)\n } catch (error) {\n // 单个监听器抛错不应打断其他监听器\n if (typeof console !== \"undefined\") {\n console.error(`[GanttEngine] listener for \"${event}\" threw`, error)\n }\n }\n }\n }\n\n // ── 生命周期 ──\n destroy(): void {\n if (this.destroyed) return\n this.destroyed = true\n this.emit(\"destroy\")\n this.listeners.clear()\n this.tasks = []\n this.links = []\n }\n\n private assertNotDestroyed(): void {\n if (this.destroyed) {\n throw new Error(\"GanttEngine: operation on destroyed instance\")\n }\n }\n}\n\n/** 工厂函数,对应成熟做法的 new GanttEngine(container, config) 入口 */\nexport function createGanttEngine(options: GanttEngineOptions = {}): GanttEngine {\n return new GanttEngine(options)\n}\n"],"mappings":"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","names":["end"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/styles/colors.ts","../src/types/index.ts","../src/services/checkCyclicDependency.ts","../src/services/normalizeLinks.ts","../src/services/flattenTasks.ts","../src/utils/date.ts","../src/services/computeTimeScale.ts","../src/services/computeHourScale.ts","../src/services/computeVisibleWindow.ts","../src/utils/mergeConfig.ts","../src/engines/scheduling.ts","../src/engines/computeLayout.ts","../src/engines/computeImpact.ts","../src/engines/computeResourceLayout.ts","../src/engines/computeWorkload.ts","../src/engine/GanttEngine.ts"],"sourcesContent":["export * from \"./types\"\nexport * from \"./styles/colors\"\nexport * from \"./services/checkCyclicDependency\"\nexport * from \"./services/normalizeLinks\"\nexport * from \"./services/flattenTasks\"\nexport * from \"./services/computeTimeScale\"\nexport * from \"./services/computeHourScale\"\nexport * from \"./services/computeVisibleWindow\"\nexport * from \"./utils/mergeConfig\"\nexport * from \"./engines/computeLayout\"\nexport * from \"./engines/computeImpact\"\nexport * from \"./engines/computeResourceLayout\"\nexport * from \"./engines/computeWorkload\"\nexport * from \"./engines/scheduling\"\nexport * from \"./utils/date\"\nexport * from \"./engine/GanttEngine\"\n","/**\n * 默认颜色统一配置 —— 甘特图 / 资源视图 / 小时视图 / 负荷视图的默认条色与调色板都从这里读取。\n *\n * 默认语义色对齐饿了么 / Element Plus:主色蓝、成功绿、警告橙、信息灰。\n * 单个实例仍可通过 config.taskColors / config.hourColors / config.resourceColors /\n * config.resourceUsageColors / config.workloadColors 及任务 color、planColor 字段按需覆盖。\n *\n * 默认色按视图拆分:\n * - DEFAULT_TASK_COLORS:甘特图(实际条 / 计划条 / 阶段 / 里程碑),也是小时视图的共享回退。\n * - DEFAULT_HOUR_COLORS:小时视图计划条与里程碑的独立默认,互不影响甘特图。\n * - DEFAULT_RESOURCE_COLORS:资源视图占用条只保留蓝 / 灰两档(预订 / 承接)。\n * - DEFAULT_WORKLOAD_COLORS:负荷视图已排 / 超负荷徽章与容量面积条。\n */\n\n/** 甘特图默认语义色(对应 GanttConfig.taskColors) */\nexport const DEFAULT_TASK_COLORS: {\n task: string\n summary: string\n milestone: string\n plan: string\n progress: string\n} = {\n task: \"#409EFF\", // 普通任务实际条 · Element 主色\n summary: \"#909399\", // 阶段条 · Element Info\n milestone: \"#E6A23C\", // 里程碑菱形 / 参考线默认 · Element Warning\n plan: \"#C6E2FF\", // 计划条外部底色 · 主色浅阶\n progress: \"#67C23A\" // 计划条内部进度色 · Element Success\n}\n\n/** 小时视图计划条与里程碑默认色(对应 GanttConfig.hourColors);独立于甘特图,可单独修改 */\nexport const DEFAULT_HOUR_COLORS: {\n plan: string\n progress: string\n milestone: string\n} = {\n plan: \"#409EFF\", // 小时视图只有计划条,用主色保证在白底网格上可见\n progress: \"#67C23A\", // 兼容保留,小时视图不再绘制进度填充\n milestone: \"#E6A23C\" // 里程碑菱形 / 参考线默认\n}\n\n/** 资源视图占用条默认色:预订主色蓝、承接信息灰 */\nexport const DEFAULT_RESOURCE_COLORS: {\n booking: string\n assignment: string\n} = {\n booking: \"#409EFF\",\n assignment: \"#909399\"\n}\n\n/** 负荷视图(Workload Timeline)默认色:已排徽章成功绿、超负荷徽章危险红、容量面积条主色蓝 */\nexport const DEFAULT_WORKLOAD_COLORS: {\n used: string\n over: string\n area: string\n} = {\n used: \"#67C23A\", // 已排工时徽章 · Element Success\n over: \"#F56C6C\", // 超负荷徽章 / 超载面积条 · Element Danger\n area: \"#409EFF\" // capacity 模式容量面积条 · Element 主色\n}\n\n/** 资源未指定颜色时的哈希回退;只含主色蓝,避免同一画面出现多种高饱和色 */\nexport const RESOURCE_COLOR_PALETTE: string[] = [DEFAULT_RESOURCE_COLORS.booking]\n\n/** 资源占用编辑器可选色:主色、浅主色、信息灰 */\nexport const RESOURCE_EDITOR_COLOR_OPTIONS: string[] = [\n \"#409eff\",\n \"#79bbff\",\n \"#909399\"\n]\n\n/** 内置任务编辑器 / 里程碑编辑器的可选颜色板 */\nexport const EDITOR_COLOR_OPTIONS: string[] = [\n \"#409eff\",\n \"#66b1ff\",\n \"#67c23a\",\n \"#e6a23c\",\n \"#f56c6c\",\n \"#909399\",\n \"#9b87c4\",\n \"#36cfc9\"\n]\n\n/** 左侧列表负责人头像兜底色板 */\nexport const OWNER_COLOR_PALETTE: string[] = [\"#409EFF\", \"#67C23A\", \"#E6A23C\", \"#F56C6C\", \"#909399\"]\n","import { DEFAULT_RESOURCE_COLORS, DEFAULT_TASK_COLORS, DEFAULT_WORKLOAD_COLORS } from \"../styles/colors\"\n\nexport type ViewMode = \"day\" | \"week\" | \"month\" | \"quarter\" | \"year\"\n\nexport type LinkType = \"FS\" | \"SS\" | \"FF\" | \"SF\"\nexport type LagUnit = \"calendar\" | \"working\"\n\nexport type Result<T> =\n | { ok: true; data: T }\n | { ok: false; error: GanttError }\n\nexport interface GanttError {\n code:\n | \"CYCLE_DEPENDENCY\"\n | \"INVALID_DATE\"\n | \"MISSING_TASK\"\n | \"ORPHAN_DEPENDENCY\"\n | \"INVALID_DEPENDENCY\"\n message: string\n details?: unknown\n}\n\nexport interface DateRange {\n start: string | Date\n end: string | Date\n progress?: number\n}\n\nexport interface Dependency {\n id?: string\n predecessorId: string\n type: LinkType\n lag: number\n lagUnit: LagUnit\n}\n\nexport interface GanttTask {\n id: string\n name: string\n type: \"task\" | \"milestone\" | \"summary\"\n plan: DateRange\n actual: Required<DateRange>\n dependencies?: Dependency[]\n parentId?: string | null\n color?: string\n planColor?: string\n calendarId?: string\n resources?: string[]\n segments?: Array<{ start: string | Date; end: string | Date }>\n constraint?: {\n type: \"SNET\" | \"SNLT\" | \"MSO\" | \"MFO\" | \"ASAP\" | \"ALAP\"\n date?: string | Date\n }\n schedulingMode?: \"auto\" | \"manual\"\n duration?: number\n /** 用于资源负荷计算的计划总工时;未提供时按 duration*8 估算。 */\n workload?: number\n /** 覆盖平均分摊的逐日计划工时。 */\n dailyWorkloads?: Record<string, number>\n custom?: Record<string, unknown>\n}\n\nexport interface GanttMarker {\n id: string\n name: string\n date: string | Date\n color?: string\n}\n\nexport interface GanttEditorField {\n key: string\n label: string\n visible?: boolean\n editable?: boolean\n type?: \"text\" | \"number\" | \"date\" | \"select\" | \"checkbox\"\n options?: Array<{ label: string; value: string | number }>\n placeholder?: string\n}\n\n/** 内置任务字段键。列可通过 CustomColumn.field 绑定到这些内置字段。\n * 除 status / owner 外都对应任务对象上的真实字段;status 与 owner 是派生展示字段。 */\nexport type BuiltinFieldKey =\n | \"name\"\n | \"status\"\n | \"owner\"\n | \"resources\"\n | \"type\"\n | \"parentId\"\n | \"planStart\"\n | \"planEnd\"\n | \"actualStart\"\n | \"actualEnd\"\n | \"progress\"\n | \"duration\"\n | \"calendarId\"\n | \"schedulingMode\"\n | \"color\"\n | \"planColor\"\n\nexport interface CustomColumn {\n key: string\n /** 绑定到的内置任务字段键。缺省时列按自定义列处理,从 task.custom[key] 读取/编辑;设置后列读取/编辑该内置字段,key 仍作为列标识。 */\n field?: BuiltinFieldKey\n label: string\n width?: number\n visible?: boolean\n align?: \"left\" | \"center\" | \"right\"\n editable?: boolean\n /**\n * 是否在左侧表格横向滚动时固定(sticky)。\n * 默认不固定,需显式 `frozen: true`。所有固定列在左侧连续排列,\n * `left` 仅累计其前面的其他固定列宽度(中间未固定列不参与、可随滚动离开)。\n */\n frozen?: boolean\n /** checkbox 类型:布尔数据列,值存 task.custom[key](布尔),单元格点击即切换并触发 taskChange。 */\n type?: \"text\" | \"number\" | \"date\" | \"select\" | \"checkbox\"\n options?: Array<{ label: string; value: string | number }>\n placeholder?: string\n editor?: Omit<GanttEditorField, \"key\" | \"label\">\n formatter?: (value: unknown, task: GanttTask) => string\n cellClass?: string | ((task: GanttTask) => string)\n cellStyle?: Record<string, string | number> | ((task: GanttTask) => Record<string, string | number>)\n render?: (task: GanttTask) => { text: string; className?: string }\n}\n\nexport interface GanttConfig {\n viewMode: ViewMode\n rowHeight: number\n columnWidth: number\n headerHeight: number\n taskListWidth: number\n width?: string | number\n height?: string | number\n locale: string\n firstDayOfWeek: 0 | 1\n dateFormat: string\n customColumns?: CustomColumn[]\n columns?: CustomColumn[]\n editorFields?: GanttEditorField[]\n columnWidths?: Partial<Record<ViewMode, number>>\n theme?: \"light\" | \"dark\" | string\n visibleRange?: {\n start: string | Date\n end: string | Date\n }\n showPlanBar?: boolean\n showActualBar?: boolean\n showTimelineWhenEmpty?: boolean\n builtInTaskEditor?: boolean\n builtInMarkerEditor?: boolean\n editablePlan?: boolean\n editableActual?: boolean\n enableLinkCreation?: boolean\n showLinkRejectionNotice?: boolean\n virtualScroll?: boolean\n taskColors?: {\n task?: string\n summary?: string\n milestone?: string\n plan?: string\n progress?: string\n }\n /** 小时视图独立配色:plan/progress/milestone 缺省时回退到 taskColors 与 DEFAULT_HOUR_COLORS */\n hourColors?: {\n plan?: string\n progress?: string\n milestone?: string\n }\n resourceColors?: Record<string, string>\n /** 资源视图占用类型默认色:booking(预订)/ assignment(承接);缺省时回退到 DEFAULT_RESOURCE_COLORS */\n resourceUsageColors?: {\n booking?: string\n assignment?: string\n }\n /** 负荷视图默认色:used(已排徽章)/ over(超负荷徽章与超载面积条)/ area(容量面积条);缺省时回退到 DEFAULT_WORKLOAD_COLORS */\n workloadColors?: {\n used?: string\n over?: string\n area?: string\n }\n /** 资源视图时间粒度;day 按整天渲染,hour 按占用携带的小时渲染(仅 ResourceTimeline 使用) */\n timeUnit?: \"day\" | \"hour\"\n /** 资源视图 hour 粒度下每小时像素宽 */\n hourWidth?: number\n /** 小时视图计划条高度;缺省时随 rowHeight 自动推导(与资源视图单车道条高公式一致) */\n barHeight?: number\n autoSchedule?: boolean\n editable?: boolean\n /** 在任务表格最左侧内置一列复选框(批量选择),值为组件内部状态,不写入任务数据。\n * 也可通过 columns 中 key 为 \"selection\" 的列显式启用并自定义位置/宽度。 */\n enableSelection?: boolean\n /** 是否显示左侧表格最右侧的快捷「+ / -」列;默认 true,横向滚动时固定在右侧。 */\n showAddTaskColumn?: boolean\n /** 「+」列新增任务的层级:child 为当前行的子任务(叶子会先变成阶段),bro 为同级任务。默认 child。 */\n addTaskAs?: \"child\" | \"bro\"\n /** 资源视图是否在左侧表格最右侧显示快捷「+ / -」列(新增/删除占用)。默认 true。 */\n showAddUsageColumn?: boolean\n}\n\nexport interface GanttLink {\n id: string\n sourceId: string\n targetId: string\n type: LinkType\n lag?: number\n lagUnit?: LagUnit\n}\n\nexport interface TaskLayout {\n taskId: string\n rowIndex: number\n left: number\n width: number\n top: number\n depth: number\n isCritical: boolean\n}\n\n/** 资源(会议室、负责人等),资源视图的 Y 轴主体 */\nexport interface Resource {\n id: string\n name: string\n color?: string\n custom?: Record<string, unknown>\n}\n\nexport type ResourceUsageType = \"booking\" | \"assignment\"\n\n/** 资源在某时间段的占用(会议室预订、负责人承接的项目等) */\nexport interface ResourceUsage {\n id: string\n resourceId: string\n /** 日历日粒度,与 GanttTask 一致;同一天内的时段(如 9:00-11:00)按当天整格渲染,时刻体现在 label/tooltip */\n start: string | Date\n end: string | Date\n label?: string\n color?: string\n type?: ResourceUsageType\n custom?: Record<string, unknown>\n}\n\nexport interface ResourceRowLayout {\n resourceId: string\n rowIndex: number\n /** 行内占用车道数(同时段重叠数),>1 时条需要堆叠变薄 */\n laneCount: number\n color: string\n usageIds: string[]\n}\n\nexport interface ResourceUsageLayout {\n usageId: string\n resourceId: string\n rowIndex: number\n laneIndex: number\n laneCount: number\n left: number\n width: number\n /** 绝对 top(含 headerHeight + rowIndex*rowHeight + 行内 lane 偏移) */\n top: number\n /** 条高度,由 laneCount 与 rowHeight 决定 */\n height: number\n}\n\nexport interface ResourceLayout {\n rows: ResourceRowLayout[]\n usages: ResourceUsageLayout[]\n}\n\nexport interface FlatTask {\n task: GanttTask\n depth: number\n rowIndex: number\n hasChildren: boolean\n collapsed: boolean\n}\n\nexport interface Calendar {\n id: string\n workingDays: number[]\n holidays: string[]\n hours: [number, number][]\n}\n\nexport interface TimeScale {\n start: Date\n end: Date\n left: number\n width: number\n}\n\nexport interface Viewport {\n scrollTop: number\n scrollLeft: number\n clientWidth: number\n clientHeight: number\n dpr: number\n}\n\nexport interface AffectedTasks {\n changed: Array<{\n taskId: string\n actualStart: string | Date\n actualEnd: string | Date\n rowIndex: number\n }>\n conflicts: Array<{\n taskId: string\n constraintType: string\n message: string\n }>\n}\n\nexport interface PatchTask {\n planStart?: string | Date\n planEnd?: string | Date\n actualStart?: string | Date\n actualEnd?: string | Date\n progress?: number\n name?: string\n type?: GanttTask[\"type\"]\n parentId?: string | null\n color?: string\n planColor?: string\n duration?: number\n workload?: number\n dailyWorkloads?: Record<string, number>\n schedulingMode?: \"auto\" | \"manual\"\n resources?: string[]\n calendarId?: string\n custom?: Record<string, unknown>\n}\n\nexport interface WorkloadPerson {\n id: string\n name: string\n departmentId?: string\n capacityPerDay?: number\n custom?: Record<string, unknown>\n}\n\nexport interface WorkloadDepartment { id: string; name: string }\nexport type WorkloadMode = \"badge\" | \"capacity\"\nexport interface DailyWorkload { date: string; hours: number; capacity: number }\nexport interface PersonWorkload {\n person: WorkloadPerson\n days: DailyWorkload[]\n workload: number\n capacity: number\n /** 已排工时占可用容量的百分比,可以超过 100。 */\n utilization?: number\n /** @deprecated 请使用 utilization;该字段仅为兼容旧版本保留。 */\n progress: number\n}\nexport interface DepartmentWorkload {\n department: WorkloadDepartment\n people: PersonWorkload[]\n days: DailyWorkload[]\n workload: number\n capacity: number\n /** 部门已排工时占总可用容量的百分比,可以超过 100。 */\n utilization?: number\n /** @deprecated 请使用 utilization;该字段仅为兼容旧版本保留。 */\n progress: number\n}\nexport interface WorkloadResult { dates: string[]; departments: DepartmentWorkload[]; ungrouped: PersonWorkload[] }\n\nexport const defaultConfig: GanttConfig = {\n viewMode: \"day\",\n rowHeight: 44,\n columnWidth: 30,\n headerHeight: 50,\n taskListWidth: 280,\n locale: \"zh-CN\",\n firstDayOfWeek: 0,\n dateFormat: \"YYYY-MM-DD\",\n showPlanBar: true,\n showActualBar: true,\n showTimelineWhenEmpty: false,\n builtInTaskEditor: false,\n builtInMarkerEditor: true,\n editablePlan: false,\n editableActual: true,\n enableLinkCreation: true,\n showLinkRejectionNotice: true,\n virtualScroll: true,\n taskColors: { ...DEFAULT_TASK_COLORS },\n resourceUsageColors: { ...DEFAULT_RESOURCE_COLORS },\n workloadColors: { ...DEFAULT_WORKLOAD_COLORS },\n timeUnit: \"day\",\n hourWidth: 12,\n autoSchedule: true,\n editable: true,\n enableSelection: false,\n showAddTaskColumn: true,\n addTaskAs: \"child\",\n showAddUsageColumn: true\n}\n","import type { GanttLink } from \"../types\"\n\nexport function checkCyclicDependency(\n links: GanttLink[]\n): { hasCycle: boolean; cyclePath?: string[] } {\n const graph = new Map<string, string[]>()\n\n for (const link of links) {\n const targets = graph.get(link.sourceId) ?? []\n targets.push(link.targetId)\n graph.set(link.sourceId, targets)\n if (!graph.has(link.targetId)) {\n graph.set(link.targetId, [])\n }\n }\n\n const visiting = new Set<string>()\n const visited = new Set<string>()\n const path: string[] = []\n\n const dfs = (node: string): string[] | undefined => {\n if (visiting.has(node)) {\n const start = path.indexOf(node)\n return [...path.slice(start), node]\n }\n if (visited.has(node)) {\n return undefined\n }\n\n visiting.add(node)\n path.push(node)\n\n for (const next of graph.get(node) ?? []) {\n const cycle = dfs(next)\n if (cycle) {\n return cycle\n }\n }\n\n path.pop()\n visiting.delete(node)\n visited.add(node)\n return undefined\n }\n\n for (const node of graph.keys()) {\n const cyclePath = dfs(node)\n if (cyclePath) {\n return { hasCycle: true, cyclePath }\n }\n }\n\n return { hasCycle: false }\n}\n","import type { GanttLink, GanttTask } from \"../types\"\n\nexport function normalizeLinks(tasks: GanttTask[], standaloneLinks: GanttLink[] = []): GanttLink[] {\n const taskIds = new Set(tasks.map((task) => task.id))\n const byTaskPair = new Map<string, GanttLink>()\n const outgoing = new Map<string, Set<string>>()\n\n const createsCycle = (sourceId: string, targetId: string): boolean => {\n const pending = [targetId]\n const visited = new Set<string>()\n while (pending.length > 0) {\n const current = pending.pop()!\n if (current === sourceId) {\n return true\n }\n if (visited.has(current)) {\n continue\n }\n visited.add(current)\n pending.push(...(outgoing.get(current) ?? []))\n }\n return false\n }\n\n const append = (link: GanttLink) => {\n if (\n !taskIds.has(link.sourceId)\n || !taskIds.has(link.targetId)\n || link.sourceId === link.targetId\n ) {\n return\n }\n\n const normalized: GanttLink = {\n ...link,\n id: link.id || `link-${link.sourceId}-${link.targetId}`,\n lag: link.lag ?? 0,\n lagUnit: link.lagUnit ?? \"calendar\"\n }\n const pairKey = `${normalized.sourceId}|${normalized.targetId}`\n if (byTaskPair.has(pairKey) || createsCycle(normalized.sourceId, normalized.targetId)) {\n return\n }\n\n byTaskPair.set(pairKey, normalized)\n const targets = outgoing.get(normalized.sourceId) ?? new Set<string>()\n targets.add(normalized.targetId)\n outgoing.set(normalized.sourceId, targets)\n }\n\n for (const task of tasks) {\n for (const dependency of task.dependencies ?? []) {\n append({\n id: dependency.id || `link-${dependency.predecessorId}-${task.id}`,\n sourceId: dependency.predecessorId,\n targetId: task.id,\n type: dependency.type,\n lag: dependency.lag,\n lagUnit: dependency.lagUnit\n })\n }\n }\n\n for (const link of standaloneLinks) {\n append(link)\n }\n\n return [...byTaskPair.values()]\n}\n","import type { FlatTask, GanttTask } from \"../types\"\n\nexport function flattenTasks(tasks: GanttTask[], collapsedIds: Set<string> = new Set()): FlatTask[] {\n const children = new Map<string | null, GanttTask[]>()\n\n for (const task of tasks) {\n const parentId = task.parentId ?? null\n const bucket = children.get(parentId)\n if (bucket) {\n bucket.push(task)\n } else {\n children.set(parentId, [task])\n }\n }\n\n const flattened: FlatTask[] = []\n const visited = new Set<string>()\n const taskIds = new Set(tasks.map((task) => task.id))\n const visit = (task: GanttTask, depth: number) => {\n if (visited.has(task.id)) {\n return\n }\n visited.add(task.id)\n const childTasks = children.get(task.id) ?? []\n const collapsed = collapsedIds.has(task.id)\n\n flattened.push({\n task,\n depth,\n rowIndex: flattened.length,\n hasChildren: childTasks.length > 0,\n collapsed\n })\n\n if (!collapsed) {\n for (const child of childTasks) {\n visit(child, depth + 1)\n }\n }\n }\n\n for (const root of children.get(null) ?? []) {\n visit(root, 0)\n }\n for (const task of tasks) {\n if (visited.has(task.id)) continue\n const parentId = task.parentId ?? null\n if (parentId && taskIds.has(parentId)) continue\n visit(task, 0)\n }\n\n return flattened\n}\n","import type { Result } from \"../types\"\n\nexport const DAY_MS = 24 * 60 * 60 * 1000\nexport const HOUR_MS = 60 * 60 * 1000\n\nexport function toDate(value: string | Date): Date {\n if (value instanceof Date) {\n return startOfDay(value)\n }\n\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value)\n if (match) {\n return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3]))\n }\n\n return startOfDay(new Date(value))\n}\n\n/** 字符串是否携带时间(\"T09:00\" 或 \" 09:00\")。Date 实例一律视为已带时间 */\nexport function hasTimeComponent(value: string | Date): boolean {\n return typeof value === \"string\" && /T\\d|:\\d/.test(value)\n}\n\n/**\n * 解析为保留时间部分的 Date。\n * 时间字符串(如 \"2026-07-02T09:00\" / \"2026-07-02 09:00\")按本地时间解析;\n * 纯日期字符串(如 \"2026-07-02\")回退到 toDate 的本地零点语义。\n */\nexport function toDateTime(value: string | Date): Date {\n if (value instanceof Date) {\n return new Date(value.getTime())\n }\n if (hasTimeComponent(value)) {\n const date = new Date(value.replace(\" \", \"T\"))\n if (!Number.isNaN(date.getTime())) {\n return date\n }\n }\n return toDate(value)\n}\n\nexport function startOfDay(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate())\n}\n\nexport function addDays(date: string | Date, days: number): Date {\n const next = toDate(date)\n next.setDate(next.getDate() + days)\n return startOfDay(next)\n}\n\nexport function diffDays(start: string | Date, end: string | Date): number {\n return Math.round((toDate(end).getTime() - toDate(start).getTime()) / DAY_MS)\n}\n\nexport function addHours(date: string | Date, hours: number): Date {\n return new Date(toDateTime(date).getTime() + hours * HOUR_MS)\n}\n\n/** 小时差(可含分钟的小数,如 09:00-11:30 = 2.5) */\nexport function diffHours(start: string | Date, end: string | Date): number {\n return (toDateTime(end).getTime() - toDateTime(start).getTime()) / HOUR_MS\n}\n\nexport function inclusiveDays(start: string | Date, end: string | Date): number {\n return Math.max(0, diffDays(start, end) + 1)\n}\n\n/**\n * Calculate the inclusive finish date for a planned duration.\n * The delivery calendar includes weekends; every other calendar currently\n * follows the standard Monday-Friday work week.\n */\nexport function addPlannedDuration(\n start: string | Date,\n duration: number,\n calendarId = \"standard\"\n): Date {\n const days = Math.max(0, Math.trunc(Number.isFinite(duration) ? duration : 0))\n if (days === 0) return toDate(start)\n if (calendarId === \"delivery\") return addDays(start, days - 1)\n\n let current = toDate(start)\n let remaining = days\n while (remaining > 0) {\n const day = current.getDay()\n if (day !== 0 && day !== 6) remaining -= 1\n if (remaining > 0) current = addDays(current, 1)\n }\n return current\n}\n\n/** Calculate the inclusive start date when a finish and duration are known. */\nexport function subtractPlannedDuration(\n end: string | Date,\n duration: number,\n calendarId = \"standard\"\n): Date {\n const days = Math.max(0, Math.trunc(Number.isFinite(duration) ? duration : 0))\n if (days === 0) return toDate(end)\n if (calendarId === \"delivery\") return addDays(end, -(days - 1))\n\n let current = toDate(end)\n let remaining = days\n while (remaining > 0) {\n const day = current.getDay()\n if (day !== 0 && day !== 6) remaining -= 1\n if (remaining > 0) current = addDays(current, -1)\n }\n return current\n}\n\n/** Move a planned date off a weekend for the standard calendar. */\nexport function alignPlannedDate(\n date: string | Date,\n calendarId = \"standard\",\n direction: 1 | -1 = 1\n): Date {\n let current = toDate(date)\n if (calendarId === \"delivery\") return current\n while (current.getDay() === 0 || current.getDay() === 6) {\n current = addDays(current, direction)\n }\n return current\n}\n\n/** Count inclusive planned working days between two dates. */\nexport function plannedDurationBetween(\n start: string | Date,\n end: string | Date,\n calendarId = \"standard\"\n): number {\n const first = toDate(start)\n const last = toDate(end)\n if (last.getTime() < first.getTime()) return 0\n if (calendarId === \"delivery\") return inclusiveDays(first, last)\n\n let duration = 0\n for (let current = first; current <= last; current = addDays(current, 1)) {\n const day = current.getDay()\n if (day !== 0 && day !== 6) duration += 1\n }\n return duration\n}\n\nexport function isValidDate(value: string | Date): boolean {\n const date = value instanceof Date ? value : new Date(value)\n return !Number.isNaN(date.getTime())\n}\n\n/** Min/max of dates without Math.min(...array), which throws on large lists. */\nexport function dateExtent(dates: Iterable<Date | number>): { start: Date; end: Date } | undefined {\n let min = Number.POSITIVE_INFINITY\n let max = Number.NEGATIVE_INFINITY\n for (const value of dates) {\n const time = typeof value === \"number\" ? value : value.getTime()\n if (!Number.isFinite(time)) continue\n if (time < min) min = time\n if (time > max) max = time\n }\n if (!Number.isFinite(min) || !Number.isFinite(max)) return undefined\n return { start: new Date(min), end: new Date(max) }\n}\n\nexport function formatDate(date: string | Date): string {\n const value = toDate(date)\n const year = value.getFullYear()\n const month = String(value.getMonth() + 1).padStart(2, \"0\")\n const day = String(value.getDate()).padStart(2, \"0\")\n return `${year}-${month}-${day}`\n}\n\nexport function formatDateTime(date: string | Date): string {\n const value = toDateTime(date)\n const hours = String(value.getHours()).padStart(2, \"0\")\n const minutes = String(value.getMinutes()).padStart(2, \"0\")\n return `${formatDate(value)} ${hours}:${minutes}`\n}\n\nexport function resultInvalidDate<T>(message: string, details?: unknown): Result<T> {\n return {\n ok: false,\n error: { code: \"INVALID_DATE\", message, details }\n }\n}\n","import type { TimeScale, ViewMode } from \"../types\"\nimport { addDays, diffDays, startOfDay } from \"../utils/date\"\n\nexport function computeTimeScale(\n start: Date,\n end: Date,\n viewMode: ViewMode,\n columnWidth: number,\n firstDayOfWeek: 0 | 1\n): TimeScale[] {\n const rangeStart = alignStart(start, viewMode, firstDayOfWeek)\n const endDate = startOfDay(end)\n const rangeEnd = viewMode === \"day\"\n ? addDays(endDate, (firstDayOfWeek + 6 - endDate.getDay() + 7) % 7)\n : endDate\n const scale: TimeScale[] = []\n let cursor = rangeStart\n let left = 0\n\n while (cursor.getTime() <= rangeEnd.getTime()) {\n const next = nextUnit(cursor, viewMode)\n const unitEnd = addDays(next, -1)\n const width = Math.max(1, diffDays(cursor, next)) * columnWidth\n\n scale.push({\n start: cursor,\n end: unitEnd,\n left,\n width\n })\n\n left += width\n cursor = next\n }\n\n return scale\n}\n\nfunction alignStart(date: Date, viewMode: ViewMode, firstDayOfWeek: 0 | 1): Date {\n const start = startOfDay(date)\n if (viewMode === \"day\" || viewMode === \"week\") {\n const delta = (start.getDay() - firstDayOfWeek + 7) % 7\n return addDays(start, -delta)\n }\n if (viewMode === \"month\") {\n return new Date(start.getFullYear(), start.getMonth(), 1)\n }\n if (viewMode === \"quarter\") {\n return new Date(start.getFullYear(), Math.floor(start.getMonth() / 3) * 3, 1)\n }\n if (viewMode === \"year\") {\n return new Date(start.getFullYear(), 0, 1)\n }\n return start\n}\n\nfunction nextUnit(date: Date, viewMode: ViewMode): Date {\n if (viewMode === \"week\") {\n return addDays(date, 7)\n }\n if (viewMode === \"month\") {\n return new Date(date.getFullYear(), date.getMonth() + 1, 1)\n }\n if (viewMode === \"quarter\") {\n return new Date(date.getFullYear(), date.getMonth() + 3, 1)\n }\n if (viewMode === \"year\") {\n return new Date(date.getFullYear() + 1, 0, 1)\n }\n return addDays(date, 1)\n}\n","import type { TimeScale } from \"../types\"\nimport { addDays, addHours, inclusiveDays, startOfDay } from \"../utils/date\"\n\nexport interface HourScale {\n /** 每日一格(顶行表头用) */\n days: TimeScale[]\n /** 每小时一格(底部刻度用) */\n hours: TimeScale[]\n start: Date\n end: Date\n}\n\n/** 小时级时间刻度:范围对齐到整天,每天拆成 24 个整点小时,width = hourWidth */\nexport function computeHourScale(start: Date, end: Date, hourWidth: number): HourScale {\n const rangeStart = startOfDay(start)\n const rangeEnd = startOfDay(end)\n const totalDays = Math.max(1, inclusiveDays(rangeStart, rangeEnd))\n const days: TimeScale[] = []\n const hours: TimeScale[] = []\n\n for (let d = 0; d < totalDays; d += 1) {\n const dayStart = addDays(rangeStart, d)\n days.push({\n start: dayStart,\n end: addHours(dayStart, 24),\n left: d * 24 * hourWidth,\n width: 24 * hourWidth\n })\n for (let h = 0; h < 24; h += 1) {\n const hourStart = addHours(dayStart, h)\n hours.push({\n start: hourStart,\n end: addHours(hourStart, 1),\n left: (d * 24 + h) * hourWidth,\n width: hourWidth\n })\n }\n }\n\n return { days, hours, start: rangeStart, end: rangeEnd }\n}\n","export interface VisibleWindow {\n start: number\n end: number\n before: number\n after: number\n}\n\n/**\n * Slice a uniform list (rows, equal-width columns) to the viewport plus overscan.\n * When the viewport has not been measured yet (size <= 0), return the full range\n * so jsdom tests and first paint still render.\n */\nexport function computeVisibleWindow(\n scroll: number,\n viewportSize: number,\n itemSize: number,\n itemCount: number,\n overscan = 8\n): VisibleWindow {\n if (itemCount <= 0 || itemSize <= 0) {\n return { start: 0, end: -1, before: 0, after: 0 }\n }\n if (viewportSize <= 0) {\n return { start: 0, end: itemCount - 1, before: 0, after: 0 }\n }\n const start = Math.max(0, Math.floor(scroll / itemSize) - overscan)\n const end = Math.min(\n itemCount - 1,\n Math.ceil((scroll + viewportSize) / itemSize) + overscan\n )\n return {\n start,\n end,\n before: start * itemSize,\n after: Math.max(0, (itemCount - end - 1) * itemSize)\n }\n}\n\n/** Keep variable-width timeline ticks whose span overlaps the horizontal viewport. */\nexport function sliceRangeItems<T extends { left: number; width: number }>(\n items: T[],\n scrollLeft: number,\n viewportWidth: number,\n overscanPx = 320\n): T[] {\n if (viewportWidth <= 0 || items.length === 0) {\n return items\n }\n const min = scrollLeft - overscanPx\n const max = scrollLeft + viewportWidth + overscanPx\n return items.filter((item) => item.left + item.width >= min && item.left <= max)\n}\n","import type { GanttConfig } from \"../types\"\nimport { defaultConfig } from \"../types\"\n\nexport function mergeGanttConfig(\n base: GanttConfig,\n patch: Partial<GanttConfig> = {}\n): GanttConfig {\n return {\n ...base,\n ...patch,\n taskColors: { ...base.taskColors, ...patch.taskColors },\n columnWidths: { ...base.columnWidths, ...patch.columnWidths },\n resourceColors: { ...base.resourceColors, ...patch.resourceColors },\n resourceUsageColors: { ...base.resourceUsageColors, ...patch.resourceUsageColors },\n workloadColors: { ...base.workloadColors, ...patch.workloadColors }\n }\n}\n\nexport function resolveGanttConfig(patch: Partial<GanttConfig> = {}): GanttConfig {\n return mergeGanttConfig(defaultConfig, patch)\n}\n","import type { GanttLink, GanttTask, LinkType, Result } from \"../types\"\nimport { addDays, diffDays, inclusiveDays, toDate } from \"../utils/date\"\nimport { checkCyclicDependency } from \"../services/checkCyclicDependency\"\n\nexport function scheduleByDependencies(tasks: GanttTask[], links: GanttLink[]): Result<GanttTask[]> {\n const cycle = checkCyclicDependency(links)\n if (cycle.hasCycle) {\n return {\n ok: false,\n error: {\n code: \"CYCLE_DEPENDENCY\",\n message: \"Dependency graph contains a cycle.\",\n details: cycle.cyclePath\n }\n }\n }\n\n const taskMap = new Map(tasks.map((task) => [task.id, cloneTask(task)]))\n const incoming = new Map<string, GanttLink[]>()\n const outgoing = new Map<string, GanttLink[]>()\n\n for (const link of links) {\n const source = taskMap.get(link.sourceId)\n const target = taskMap.get(link.targetId)\n if (!source || !target) {\n return {\n ok: false,\n error: {\n code: \"ORPHAN_DEPENDENCY\",\n message: `Dependency ${link.id} references a missing task.`\n }\n }\n }\n const incomingList = incoming.get(link.targetId)\n if (incomingList) {\n incomingList.push(link)\n } else {\n incoming.set(link.targetId, [link])\n }\n const outgoingList = outgoing.get(link.sourceId)\n if (outgoingList) {\n outgoingList.push(link)\n } else {\n outgoing.set(link.sourceId, [link])\n }\n }\n\n const ordered = topologicalOrder(tasks.map((task) => task.id), links)\n\n for (const taskId of ordered) {\n const task = taskMap.get(taskId)\n if (!task || task.schedulingMode === \"manual\") {\n continue\n }\n\n const linksToTask = incoming.get(taskId) ?? []\n let start = toDate(task.actual.start)\n let end = toDate(task.actual.end)\n const duration = Math.max(0, task.duration ?? inclusiveDays(start, end))\n\n for (const link of linksToTask) {\n const source = taskMap.get(link.sourceId)\n if (!source) {\n continue\n }\n\n const candidate = applyDependency(source, start, end, duration, link.type, link.lag ?? 0)\n if (candidate.start.getTime() > start.getTime()) {\n start = candidate.start\n }\n if (candidate.end.getTime() > end.getTime()) {\n end = candidate.end\n }\n }\n\n const normalizedEnd = task.type === \"milestone\" ? start : addDays(start, Math.max(0, duration - 1))\n task.actual = {\n ...task.actual,\n start,\n end: normalizedEnd\n }\n }\n\n return { ok: true, data: tasks.map((task) => taskMap.get(task.id) ?? task) }\n}\n\nfunction applyDependency(\n source: GanttTask,\n currentStart: Date,\n currentEnd: Date,\n duration: number,\n type: LinkType,\n lag: number\n): { start: Date; end: Date } {\n const sourceStart = toDate(source.actual.start)\n const sourceEnd = toDate(source.actual.end)\n const span = Math.max(0, duration - 1)\n\n if (type === \"FS\") {\n const start = addDays(sourceEnd, lag + 1)\n return { start, end: addDays(start, span) }\n }\n\n if (type === \"SS\") {\n const start = addDays(sourceStart, lag)\n return { start, end: addDays(start, span) }\n }\n\n if (type === \"FF\") {\n const end = addDays(sourceEnd, lag)\n return { start: addDays(end, -span), end }\n }\n\n const end = addDays(sourceStart, lag)\n return { start: addDays(end, -span), end: end.getTime() > currentEnd.getTime() ? end : currentEnd }\n}\n\nfunction topologicalOrder(ids: string[], links: GanttLink[]): string[] {\n const indegree = new Map(ids.map((id) => [id, 0]))\n const outgoing = new Map<string, string[]>()\n\n for (const link of links) {\n indegree.set(link.targetId, (indegree.get(link.targetId) ?? 0) + 1)\n const targets = outgoing.get(link.sourceId)\n if (targets) {\n targets.push(link.targetId)\n } else {\n outgoing.set(link.sourceId, [link.targetId])\n }\n }\n\n const queue = ids.filter((id) => (indegree.get(id) ?? 0) === 0)\n const ordered: string[] = []\n let cursor = 0\n\n while (cursor < queue.length) {\n const current = queue[cursor]\n cursor += 1\n if (!current) continue\n ordered.push(current)\n for (const target of outgoing.get(current) ?? []) {\n indegree.set(target, (indegree.get(target) ?? 1) - 1)\n if (indegree.get(target) === 0) {\n queue.push(target)\n }\n }\n }\n\n return ordered.length === ids.length ? ordered : ids\n}\n\nfunction cloneTask(task: GanttTask): GanttTask {\n return {\n ...task,\n plan: { ...task.plan },\n actual: { ...task.actual },\n dependencies: task.dependencies?.map((dependency) => ({ ...dependency }))\n }\n}\n\nexport function shiftTask(task: GanttTask, start: string | Date): GanttTask {\n const currentStart = toDate(task.actual.start)\n const nextStart = toDate(start)\n const delta = diffDays(currentStart, nextStart)\n return {\n ...task,\n actual: {\n ...task.actual,\n start: nextStart,\n end: addDays(toDate(task.actual.end), delta)\n }\n }\n}\n","import type { GanttConfig, GanttLink, GanttTask, Result, TaskLayout, Viewport } from \"../types\"\nimport { flattenTasks } from \"../services/flattenTasks\"\nimport { normalizeLinks } from \"../services/normalizeLinks\"\nimport { scheduleByDependencies } from \"./scheduling\"\nimport { dateExtent, diffDays, inclusiveDays, isValidDate, toDate } from \"../utils/date\"\nimport { resolveGanttConfig } from \"../utils/mergeConfig\"\n\nexport function computeLayout(\n tasks: GanttTask[],\n links: GanttLink[],\n config: Partial<GanttConfig>,\n collapsedIds: Set<string> = new Set(),\n viewport?: Viewport\n): Result<TaskLayout[]> {\n const mergedConfig = resolveGanttConfig(config)\n\n for (const task of tasks) {\n if (!isValidDate(task.actual.start) || !isValidDate(task.actual.end)) {\n return {\n ok: false,\n error: {\n code: \"INVALID_DATE\",\n message: `Task ${task.id} has invalid actual dates.`\n }\n }\n }\n }\n\n const normalizedLinks = normalizeLinks(tasks, links)\n const scheduled = mergedConfig.autoSchedule === false\n ? { ok: true as const, data: tasks }\n : scheduleByDependencies(tasks, normalizedLinks)\n\n if (!scheduled.ok) {\n return scheduled\n }\n\n const flatTasks = flattenTasks(scheduled.data, collapsedIds)\n const firstDate = mergedConfig.visibleRange\n ? toDate(mergedConfig.visibleRange.start)\n : dateExtent(scheduled.data.map((task) => toDate(task.actual.start)))?.start ?? toDate(new Date())\n\n const visibleStart = viewport\n ? Math.max(0, Math.floor(viewport.scrollTop / mergedConfig.rowHeight) - 8)\n : 0\n const visibleEnd = viewport\n ? Math.ceil((viewport.scrollTop + viewport.clientHeight) / mergedConfig.rowHeight) + 8\n : Number.POSITIVE_INFINITY\n\n const layouts = flatTasks\n .filter((flat) => flat.rowIndex >= visibleStart && flat.rowIndex <= visibleEnd)\n .map<TaskLayout>((flat) => {\n const start = toDate(flat.task.actual.start)\n const end = toDate(flat.task.actual.end)\n const duration = flat.task.type === \"milestone\" ? 0 : inclusiveDays(start, end)\n\n return {\n taskId: flat.task.id,\n rowIndex: flat.rowIndex,\n left: diffDays(firstDate, start) * mergedConfig.columnWidth,\n width: Math.max(flat.task.type === \"milestone\" ? mergedConfig.columnWidth / 2 : mergedConfig.columnWidth, duration * mergedConfig.columnWidth),\n top: mergedConfig.headerHeight + flat.rowIndex * mergedConfig.rowHeight,\n depth: flat.depth,\n isCritical: false\n }\n })\n\n return { ok: true, data: layouts }\n}\n","import type { AffectedTasks, GanttConfig, GanttLink, GanttTask, PatchTask, Result } from \"../types\"\nimport { flattenTasks } from \"../services/flattenTasks\"\nimport { scheduleByDependencies, shiftTask } from \"./scheduling\"\nimport { addDays, inclusiveDays, toDate } from \"../utils/date\"\n\nexport function computeImpact(\n taskId: string,\n patch: PatchTask,\n tasks: GanttTask[],\n links: GanttLink[],\n config: Partial<GanttConfig>\n): Result<AffectedTasks> {\n const target = tasks.find((task) => task.id === taskId)\n if (!target) {\n return {\n ok: false,\n error: {\n code: \"MISSING_TASK\",\n message: `Task ${taskId} does not exist.`\n }\n }\n }\n\n const patchedTasks = tasks.map((task) => {\n if (task.id !== taskId) {\n return task\n }\n\n let next = { ...task, actual: { ...task.actual } }\n if (patch.actualStart) {\n next = shiftTask(next, patch.actualStart)\n }\n if (patch.actualEnd) {\n next.actual.end = patch.actualEnd\n }\n if (typeof patch.progress === \"number\") {\n next.actual.progress = patch.progress\n }\n if (patch.duration) {\n next.duration = patch.duration\n next.actual.end = addDays(toDate(next.actual.start), Math.max(0, patch.duration - 1))\n }\n if (patch.name) {\n next.name = patch.name\n }\n if (patch.type) {\n next.type = patch.type\n }\n if (\"parentId\" in patch) {\n next.parentId = patch.parentId\n }\n if (patch.color) {\n next.color = patch.color\n }\n if (\"planColor\" in patch) {\n next.planColor = patch.planColor\n }\n if (patch.schedulingMode) {\n next.schedulingMode = patch.schedulingMode\n }\n return next\n })\n\n const scheduled = config.autoSchedule === false\n ? { ok: true as const, data: patchedTasks }\n : scheduleByDependencies(patchedTasks, links)\n\n if (!scheduled.ok) {\n return scheduled\n }\n\n const rows = new Map(flattenTasks(scheduled.data).map((flat) => [flat.task.id, flat.rowIndex]))\n const originalById = new Map(tasks.map((task) => [task.id, task]))\n const changed = scheduled.data\n .filter((task) => {\n const original = originalById.get(task.id)\n return original && (\n String(original.actual.start) !== String(task.actual.start) ||\n String(original.actual.end) !== String(task.actual.end)\n )\n })\n .map((task) => ({\n taskId: task.id,\n actualStart: task.actual.start,\n actualEnd: task.actual.end,\n rowIndex: rows.get(task.id) ?? 0\n }))\n\n const conflicts = scheduled.data\n .filter((task) => task.constraint?.date && inclusiveDays(task.actual.start, task.constraint.date) < 0)\n .map((task) => ({\n taskId: task.id,\n constraintType: task.constraint!.type,\n message: \"Task violates its configured constraint date.\"\n }))\n\n return { ok: true, data: { changed, conflicts } }\n}\n","import type {\n GanttConfig,\n Resource,\n ResourceLayout,\n ResourceRowLayout,\n ResourceUsage,\n ResourceUsageLayout,\n Result,\n Viewport\n} from \"../types\"\nimport {\n addHours,\n dateExtent,\n diffDays,\n diffHours,\n hasTimeComponent,\n inclusiveDays,\n isValidDate,\n startOfDay,\n toDate,\n toDateTime\n} from \"../utils/date\"\nimport { resolveGanttConfig } from \"../utils/mergeConfig\"\nimport { DEFAULT_RESOURCE_COLORS, RESOURCE_COLOR_PALETTE } from \"../styles/colors\"\n\n// 向后兼容:RESOURCE_COLOR_PALETTE 原在本文件导出,继续从这里再导出一次\nexport { RESOURCE_COLOR_PALETTE }\n\nfunction colorHash(source: string): number {\n return [...source].reduce((sum, char) => sum + (char.codePointAt(0) ?? 0), 0)\n}\n\n/** 解析资源主色:resource.color → config.resourceColors[id] → 名称 hash 调色板(确定性) */\nexport function resolveResourceColor(\n resource: Resource,\n resourceColors?: Record<string, string>\n): string {\n if (resource.color) {\n return resource.color\n }\n if (resourceColors?.[resource.id]) {\n return resourceColors[resource.id]\n }\n const source = resource.name || resource.id\n return RESOURCE_COLOR_PALETTE[colorHash(source) % RESOURCE_COLOR_PALETTE.length]\n}\n\n/** 解析占用条颜色:usage.color → 所属资源色 → config.resourceUsageColors → DEFAULT_RESOURCE_COLORS */\nexport function resolveUsageColor(\n usage: ResourceUsage,\n resource: Resource,\n resourceColors?: Record<string, string>,\n resourceUsageColors?: { booking?: string; assignment?: string }\n): string {\n if (usage.color) {\n return usage.color\n }\n if (resource.color || resourceColors?.[resource.id]) {\n return resolveResourceColor(resource, resourceColors)\n }\n return usage.type === \"assignment\"\n ? resourceUsageColors?.assignment ?? DEFAULT_RESOURCE_COLORS.assignment\n : resourceUsageColors?.booking ?? DEFAULT_RESOURCE_COLORS.booking\n}\n\n/**\n * 将占用解析为布局用的起止 Date。\n * - day:与 GanttTask 一致,截断到天。\n * - hour:保留时间;纯日期(未携带时间)按\"含结束日整天\"处理,与 day 模式的含末语义一致。\n */\nexport function resolveUsageTimes(\n usage: ResourceUsage,\n timeUnit: \"day\" | \"hour\"\n): { start: Date; end: Date } {\n if (timeUnit === \"hour\") {\n const start = toDateTime(usage.start)\n const endRaw = toDateTime(usage.end)\n return { start, end: hasTimeComponent(usage.end) ? endRaw : addHours(endRaw, 24) }\n }\n return { start: toDate(usage.start), end: toDate(usage.end) }\n}\n\n/**\n * 资源视图布局:每个资源一行(Y 轴),占用时间段以横向色条展示。\n * 同一资源同时段多个占用按贪心 first-fit 车道分配,行内堆叠子条。\n * day 粒度像素数学与 computeLayout 一致(diffDays × columnWidth);\n * hour 粒度按 diffHours × hourWidth 渲染,纯日期占用含结束日整天。\n * 传入 viewport 时仅产出可见行窗口内的占用几何(±8 overscan),rows 始终全量返回。\n */\nexport function computeResourceLayout(\n resources: Resource[],\n usages: ResourceUsage[],\n config: Partial<GanttConfig>,\n viewport?: Viewport\n): Result<ResourceLayout> {\n const mergedConfig = resolveGanttConfig(config)\n const timeUnit = mergedConfig.timeUnit ?? \"day\"\n const hourMode = timeUnit === \"hour\"\n const hourW = mergedConfig.hourWidth ?? 12\n\n for (const usage of usages) {\n const { start, end } = resolveUsageTimes(usage, timeUnit)\n if (!isValidDate(start) || !isValidDate(end)) {\n return {\n ok: false,\n error: {\n code: \"INVALID_DATE\",\n message: `Resource usage ${usage.id} has invalid dates.`\n }\n }\n }\n }\n\n // 行序:resources 顺序在前,usage 引用但未声明的 resourceId 追加在后(容错)\n const orderedIds: string[] = []\n const seen = new Set<string>()\n for (const resource of resources) {\n if (!seen.has(resource.id)) {\n seen.add(resource.id)\n orderedIds.push(resource.id)\n }\n }\n for (const usage of usages) {\n if (!seen.has(usage.resourceId)) {\n seen.add(usage.resourceId)\n orderedIds.push(usage.resourceId)\n }\n }\n\n const resourceById = new Map(resources.map((resource) => [resource.id, resource]))\n const usagesByResource = new Map<string, ResourceUsage[]>()\n for (const usage of usages) {\n const grouped = usagesByResource.get(usage.resourceId)\n if (grouped) {\n grouped.push(usage)\n } else {\n usagesByResource.set(usage.resourceId, [usage])\n }\n }\n\n const rows: ResourceRowLayout[] = []\n const usageLayouts: ResourceUsageLayout[] = []\n const laneIndexByUsage = new Map<string, number>()\n\n orderedIds.forEach((resourceId, rowIndex) => {\n const resource = resourceById.get(resourceId) ?? {\n id: resourceId,\n name: resourceId\n } satisfies Resource\n const grouped = [...(usagesByResource.get(resourceId) ?? [])].sort((a, b) => {\n const as = resolveUsageTimes(a, timeUnit)\n const bs = resolveUsageTimes(b, timeUnit)\n return as.start.getTime() - bs.start.getTime() || as.end.getTime() - bs.end.getTime()\n })\n\n // 贪心 first-fit 车道分配:占用放入第一个\"前一个占用结束不晚于其开始\"的车道。\n // day:diffDays(end, start) > 0(相邻日复用);hour:diffHours(end, start) >= 0(首尾相接复用)\n const laneEnds: Array<Date | null> = []\n for (const usage of grouped) {\n const { start, end } = resolveUsageTimes(usage, timeUnit)\n let laneIndex = -1\n for (let k = 0; k < laneEnds.length; k += 1) {\n const laneEnd = laneEnds[k]\n if (laneEnd === null || isLaneFree(laneEnd, start, hourMode)) {\n laneIndex = k\n break\n }\n }\n if (laneIndex === -1) {\n laneIndex = laneEnds.length\n laneEnds.push(null)\n }\n laneEnds[laneIndex] = end\n laneIndexByUsage.set(usage.id, laneIndex)\n }\n\n rows.push({\n resourceId,\n rowIndex,\n laneCount: laneEnds.length,\n color: resolveResourceColor(resource, mergedConfig.resourceColors),\n usageIds: grouped.map((usage) => usage.id)\n })\n })\n\n const usageById = new Map(usages.map((usage) => [usage.id, usage]))\n const visibleStart = viewport\n ? Math.max(0, Math.floor(viewport.scrollTop / mergedConfig.rowHeight) - 8)\n : 0\n const visibleEnd = viewport\n ? Math.ceil((viewport.scrollTop + viewport.clientHeight) / mergedConfig.rowHeight) + 8\n : Number.POSITIVE_INFINITY\n\n const firstDate = hourMode\n ? startOfDay(\n mergedConfig.visibleRange\n ? toDateTime(mergedConfig.visibleRange.start)\n : dateExtent(usages.map((usage) => resolveUsageTimes(usage, \"hour\").start))?.start\n ?? toDateTime(new Date())\n )\n : mergedConfig.visibleRange\n ? toDate(mergedConfig.visibleRange.start)\n : dateExtent(usages.map((usage) => toDate(usage.start)))?.start ?? toDate(new Date())\n\n for (const row of rows) {\n if (row.rowIndex < visibleStart || row.rowIndex > visibleEnd) {\n continue\n }\n const resource = resourceById.get(row.resourceId) ?? { id: row.resourceId, name: row.resourceId }\n const laneCount = Math.max(1, row.laneCount)\n const slot = mergedConfig.rowHeight / laneCount\n const barHeight = Math.max(6, Math.min(14, slot - 4))\n\n for (const usageId of row.usageIds) {\n const usage = usageById.get(usageId)\n if (!usage) {\n continue\n }\n const { start, end } = resolveUsageTimes(usage, timeUnit)\n const laneIndex = laneIndexByUsage.get(usageId) ?? 0\n const laneTop = laneIndex * slot + (slot - barHeight) / 2\n const left = hourMode\n ? diffHours(firstDate, start) * hourW\n : diffDays(firstDate, start) * mergedConfig.columnWidth\n const width = hourMode\n ? Math.max(hourW, diffHours(start, end) * hourW)\n : Math.max(mergedConfig.columnWidth, inclusiveDays(start, end) * mergedConfig.columnWidth)\n\n usageLayouts.push({\n usageId,\n resourceId: row.resourceId,\n rowIndex: row.rowIndex,\n laneIndex,\n laneCount,\n left,\n width,\n top: mergedConfig.headerHeight + row.rowIndex * mergedConfig.rowHeight + laneTop,\n height: barHeight\n })\n }\n }\n\n return { ok: true, data: { rows, usages: usageLayouts } }\n}\n\nfunction isLaneFree(laneEnd: Date, start: Date, hourMode: boolean): boolean {\n return hourMode ? diffHours(laneEnd, start) >= 0 : diffDays(laneEnd, start) > 0\n}\n","import type { DepartmentWorkload, GanttTask, PersonWorkload, WorkloadDepartment, WorkloadPerson, WorkloadResult } from \"../types\"\nimport { addDays, dateExtent, formatDate, inclusiveDays, toDate } from \"../utils/date\"\n\nexport function computeWorkload(tasks: GanttTask[], people: WorkloadPerson[], departments: WorkloadDepartment[] = [], range?: { start: string | Date; end: string | Date }): WorkloadResult {\n const dated = range ?? inferRange(tasks)\n if (!dated) return { dates: [], departments: [], ungrouped: [] }\n const dates = datesBetween(dated.start, dated.end)\n const dateIndex = new Map(dates.map((date, index) => [date, index]))\n const rows = new Map(people.map(person => [person.id, createPerson(person, dates)]))\n for (const task of tasks) {\n if (task.type === \"summary\" || task.type === \"milestone\") continue\n const ids = task.resources ?? []\n if (!ids.length) continue\n const values = task.dailyWorkloads ?? averageTaskWorkload(task)\n for (const personId of ids) {\n const row = rows.get(personId)\n if (!row) continue\n for (const [date, hours] of Object.entries(values)) {\n const index = dateIndex.get(date)\n if (index !== undefined) row.days[index].hours += hours\n }\n }\n }\n for (const row of rows.values()) finalize(row)\n const grouped = new Map<string, PersonWorkload[]>()\n const ungrouped: PersonWorkload[] = []\n for (const row of rows.values()) {\n if (row.person.departmentId) {\n const members = grouped.get(row.person.departmentId)\n if (members) members.push(row)\n else grouped.set(row.person.departmentId, [row])\n } else {\n ungrouped.push(row)\n }\n }\n const departmentMap = new Map(departments.map(item => [item.id, item]))\n const result: DepartmentWorkload[] = [...grouped].map(([id, members]) => aggregateDepartment(departmentMap.get(id) ?? { id, name: id }, members, dates))\n return { dates, departments: result, ungrouped }\n}\n\nfunction inferRange(tasks: GanttTask[]) {\n if (!tasks.length) return undefined\n const extent = dateExtent(tasks.flatMap(task => [toDate(task.plan.start), toDate(task.plan.end)]))\n return extent ? { start: extent.start, end: extent.end } : undefined\n}\nfunction datesBetween(start: string | Date, end: string | Date) { const values: string[] = []; for (let date = toDate(start); date <= toDate(end); date = addDays(date, 1)) values.push(formatDate(date)); return values }\nfunction averageTaskWorkload(task: GanttTask) { const total = task.workload ?? (task.duration ?? inclusiveDays(task.plan.start, task.plan.end)) * 8; const allDates = datesBetween(task.plan.start, task.plan.end); const dates = task.calendarId === \"delivery\" ? allDates : allDates.filter(date => { const day = toDate(date).getDay(); return day !== 0 && day !== 6 }); const hours = dates.length ? total / dates.length : 0; return Object.fromEntries(dates.map(date => [date, hours])) }\nfunction createPerson(person: WorkloadPerson, dates: string[]): PersonWorkload { return { person, days: dates.map(date => ({ date, hours: 0, capacity: person.capacityPerDay ?? 8 })), workload: 0, capacity: 0, utilization: 0, progress: 0 } }\nfunction finalize(row: PersonWorkload) { row.workload = row.days.reduce((sum, day) => sum + day.hours, 0); row.capacity = row.days.reduce((sum, day) => sum + day.capacity, 0); row.utilization = row.capacity ? Math.round(row.workload / row.capacity * 100) : 0; row.progress = row.utilization }\nfunction aggregateDepartment(department: WorkloadDepartment, people: PersonWorkload[], dates: string[]): DepartmentWorkload { 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) })); const workload = days.reduce((sum, day) => sum + day.hours, 0); const capacity = days.reduce((sum, day) => sum + day.capacity, 0); const utilization = capacity ? Math.round(workload / capacity * 100) : 0; return { department, people, days, workload, capacity, utilization, progress: utilization } }\n","import type {\n GanttConfig,\n GanttTask,\n GanttLink,\n GanttMarker,\n PatchTask,\n TaskLayout,\n TimeScale,\n FlatTask,\n Result\n} from \"../types\"\nimport { defaultConfig } from \"../types\"\nimport { computeLayout } from \"../engines/computeLayout\"\nimport { computeTimeScale } from \"../services/computeTimeScale\"\nimport { flattenTasks } from \"../services/flattenTasks\"\nimport { addDays, dateExtent, diffDays, plannedDurationBetween, toDate } from \"../utils/date\"\nimport { mergeGanttConfig } from \"../utils/mergeConfig\"\n\n/**\n * 把扁平的 PatchTask 合并回嵌套的 GanttTask。\n * PatchTask 用 planStart/planEnd/actualStart/actualEnd 表示日期,\n * GanttTask 用 plan.start/end、actual.start/end 嵌套表示——这是组件层\n * 和数据层之间的桥,本该在引擎层而不是散落在各 demo 里。\n */\nexport function mergeTaskPatch(task: GanttTask, patch: PatchTask): GanttTask {\n const type = patch.type ?? task.type\n const calendarId = patch.calendarId ?? task.calendarId ?? \"standard\"\n const planStart = patch.planStart ?? task.plan.start\n const planEnd = type === \"milestone\"\n ? planStart\n : patch.planEnd ?? task.plan.end\n const duration = type === \"milestone\"\n ? 1\n : plannedDurationBetween(planStart, planEnd, calendarId)\n return {\n ...task,\n ...patch,\n duration,\n plan: {\n ...task.plan,\n start: planStart,\n end: planEnd,\n progress: patch.progress ?? task.plan.progress\n },\n actual: {\n ...task.actual,\n start: patch.actualStart ?? task.actual.start,\n end: patch.actualEnd ?? task.actual.end,\n progress: patch.progress ?? task.actual.progress\n },\n custom: patch.custom ? { ...task.custom, ...patch.custom } : task.custom\n }\n}\n\nexport interface GanttEngineOptions {\n tasks?: GanttTask[]\n links?: GanttLink[]\n config?: Partial<GanttConfig>\n /** 滚动容器元素;命令式视口 API(scrollToDate / zoomToFit)需要它。纯计算场景可不传。 */\n container?: HTMLElement | null\n /** 初始折叠的任务 id */\n collapsedIds?: Iterable<string>\n /** 里程碑标记 */\n markers?: GanttMarker[]\n}\n\nexport type GanttEngineEvent =\n | \"ready\"\n | \"taskschange\"\n | \"taskchange\"\n | \"taskcreate\"\n | \"taskdelete\"\n | \"linkschange\"\n | \"configchange\"\n | \"collapsechange\"\n | \"previewchange\"\n | \"markerschange\"\n | \"destroy\"\n\ntype Listener = (...args: unknown[]) => void\n\n/** 命令式甘特图引擎。框架无关,可被 Vue/React/原生 各自的薄壳组件驱动。 */\nexport class GanttEngine {\n private tasks: GanttTask[]\n private links: GanttLink[]\n private config: GanttConfig\n private readonly container: HTMLElement | null\n private collapsedIds: Set<string>\n private dragPreview: { taskId: string; patch: PatchTask; affected?: Record<string, PatchTask> } | null = null\n private markers: GanttMarker[]\n private readonly listeners: Map<GanttEngineEvent, Set<Listener>>\n private destroyed = false\n\n constructor(options: GanttEngineOptions = {}) {\n this.tasks = options.tasks ? options.tasks.map((task) => ({ ...task })) : []\n this.links = options.links ? options.links.map((link) => ({ ...link })) : []\n this.config = mergeGanttConfig({ ...defaultConfig }, { ...options.config })\n this.container = options.container ?? null\n this.collapsedIds = new Set(options.collapsedIds ?? [])\n this.markers = options.markers ? options.markers.map((marker) => ({ ...marker })) : []\n this.listeners = new Map()\n // 异步发 ready,确保订阅者能在构造后、首次 emit 前注册\n queueMicrotask(() => this.emit(\"ready\"))\n }\n\n // ── 状态查询 ──\n getTasks(): GanttTask[] {\n return this.tasks.map((task) => ({ ...task }))\n }\n getLinks(): GanttLink[] {\n return this.links.map((link) => ({ ...link }))\n }\n getMarkers(): GanttMarker[] {\n return this.markers.map((marker) => ({ ...marker }))\n }\n getConfig(): GanttConfig {\n return { ...this.config }\n }\n getTask(id: string): GanttTask | undefined {\n const task = this.tasks.find((item) => item.id === id)\n return task ? { ...task } : undefined\n }\n getCollapsedIds(): string[] {\n return Array.from(this.collapsedIds)\n }\n isDestroyed(): boolean {\n return this.destroyed\n }\n\n // ── 命令式变更(均触发对应事件) ──\n setTasks(tasks: GanttTask[]): void {\n this.assertNotDestroyed()\n this.tasks = tasks.map((task) => ({ ...task }))\n this.emit(\"taskschange\", this.tasks)\n }\n setLinks(links: GanttLink[]): void {\n this.assertNotDestroyed()\n this.links = links.map((link) => ({ ...link }))\n this.emit(\"linkschange\", this.links)\n }\n setMarkers(markers: GanttMarker[]): void {\n this.assertNotDestroyed()\n this.markers = markers.map((marker) => ({ ...marker }))\n this.emit(\"markerschange\", this.markers)\n }\n /** 合并配置 patch,等价于 setConfig(mergeConfig(patch)) */\n mergeConfig(patch: Partial<GanttConfig>): void {\n this.assertNotDestroyed()\n this.config = mergeGanttConfig(this.config, patch)\n this.emit(\"configchange\", this.getConfig())\n }\n setConfig(config: Partial<GanttConfig>): void {\n this.mergeConfig(config)\n }\n /** 用 mergeTaskPatch 把扁平 patch 合并回嵌套结构后更新单个任务 */\n setTask(id: string, patch: PatchTask): void {\n this.assertNotDestroyed()\n const target = this.tasks.find((task) => task.id === id)\n if (!target) {\n return\n }\n const updated = mergeTaskPatch(target, patch)\n this.tasks = this.tasks.map((task) => (task.id === id ? updated : task))\n this.emit(\"taskchange\", id, patch, { ...updated })\n }\n addTask(task: GanttTask): void {\n this.assertNotDestroyed()\n this.tasks = [...this.tasks, { ...task }]\n this.emit(\"taskcreate\", { ...task })\n }\n removeTask(id: string): void {\n this.assertNotDestroyed()\n const removed = this.tasks.find((task) => task.id === id)\n if (!removed) return\n this.tasks = this.tasks.filter((task) => task.id !== id)\n this.collapsedIds.delete(id)\n this.emit(\"taskdelete\", id)\n }\n collapse(id: string, collapsed = true): void {\n this.assertNotDestroyed()\n if (collapsed) this.collapsedIds.add(id)\n else this.collapsedIds.delete(id)\n this.emit(\"collapsechange\", this.getCollapsedIds())\n }\n toggleCollapse(id: string): void {\n this.collapse(id, !this.collapsedIds.has(id))\n }\n /** 批量折叠/展开多个任务(如\"折叠全部分组\") */\n setCollapsed(ids: string[], collapsed = true): void {\n this.assertNotDestroyed()\n const next = new Set(this.collapsedIds)\n for (const id of ids) {\n if (collapsed) {\n next.add(id)\n } else {\n next.delete(id)\n }\n }\n this.collapsedIds = next\n this.emit(\"collapsechange\", this.getCollapsedIds())\n }\n\n // ── 拖拽预览(交互态源;组件写入迁移到 engine,dateRange 可据此扩展) ──\n setPreview(preview: { taskId: string; patch: PatchTask; affected?: Record<string, PatchTask> }): void {\n this.assertNotDestroyed()\n this.dragPreview = {\n taskId: preview.taskId,\n patch: { ...preview.patch },\n affected: preview.affected ? { ...preview.affected } : undefined\n }\n this.emit(\"previewchange\", this.getPreview())\n }\n clearPreview(): void {\n if (!this.dragPreview) {\n return\n }\n this.dragPreview = null\n this.emit(\"previewchange\", null)\n }\n getPreview(): { taskId: string; patch: PatchTask; affected?: Record<string, PatchTask> } | null {\n if (!this.dragPreview) {\n return null\n }\n return {\n taskId: this.dragPreview.taskId,\n patch: { ...this.dragPreview.patch },\n affected: this.dragPreview.affected ? { ...this.dragPreview.affected } : undefined\n }\n }\n\n // ── 计算(delegate 到 core 纯函数) ──\n /** 数据真实日期范围(未含 viewport pad) */\n getDateRange(): { start: Date; end: Date } {\n const dates: Date[] = []\n for (const task of this.tasks) {\n dates.push(\n toDate(task.plan.start),\n toDate(task.plan.end),\n toDate(task.actual.start),\n toDate(task.actual.end)\n )\n }\n for (const marker of this.markers) {\n dates.push(toDate(marker.date))\n }\n // 合并拖拽预览:用 mergeTaskPatch 算 patch 后日期扩范围(只扩不缩)\n const preview = this.dragPreview\n if (preview) {\n const ids = [preview.taskId, ...Object.keys(preview.affected ?? {})]\n for (const id of ids) {\n const task = this.tasks.find((item) => item.id === id)\n if (!task) {\n continue\n }\n const patch = preview.taskId === id ? preview.patch : preview.affected?.[id]\n if (!patch) {\n continue\n }\n const merged = mergeTaskPatch(task, patch)\n dates.push(\n toDate(merged.plan.start),\n toDate(merged.plan.end),\n toDate(merged.actual.start),\n toDate(merged.actual.end)\n )\n }\n }\n if (!dates.length) {\n const today = toDate(new Date())\n return { start: today, end: addDays(today, 30) }\n }\n const extent = dateExtent(dates)\n return extent ?? { start: dates[0], end: dates[0] }\n }\n getTimeScale(): TimeScale[] {\n const range = this.getDateRange()\n return computeTimeScale(\n range.start,\n range.end,\n this.config.viewMode,\n this.config.columnWidth,\n this.config.firstDayOfWeek\n )\n }\n getLayout(): Result<TaskLayout[]> {\n return computeLayout(\n this.tasks,\n this.links,\n this.config,\n this.collapsedIds\n )\n }\n getFlatTasks(): FlatTask[] {\n return flattenTasks(this.tasks, this.collapsedIds)\n }\n getTotalWidth(): number {\n return this.getTimeScale().reduce((sum, tick) => sum + tick.width, 0)\n }\n getTotalHeight(): number {\n const rows = this.getFlatTasks().length\n return this.config.headerHeight + rows * this.config.rowHeight\n }\n\n // ── 视口命令(需要 container) ──\n getScrollLeft(): number {\n return this.container?.scrollLeft ?? 0\n }\n setScrollLeft(px: number): void {\n if (!this.container) return\n const max = Math.max(0, this.container.scrollWidth - this.container.clientWidth)\n this.container.scrollLeft = Math.max(0, Math.min(max, px))\n }\n /** 把当前 scrollLeft 限制到 [0, maxScrollLeft]。\n * 拖拽预览收缩(松手/取消)后 timeline 总宽度变小,scrollLeft 可能超出新边界,\n * 导致 canvas translate 超出内容区、右侧网格未覆盖。此时调用本方法防超界。 */\n clampScrollLeft(): void {\n if (!this.container) return\n const max = Math.max(0, this.container.scrollWidth - this.container.clientWidth)\n if (this.container.scrollLeft > max) {\n this.container.scrollLeft = max\n }\n }\n getScrollTop(): number {\n return this.container?.scrollTop ?? 0\n }\n setScrollTop(px: number): void {\n if (!this.container) return\n const max = Math.max(0, this.container.scrollHeight - this.container.clientHeight)\n this.container.scrollTop = Math.max(0, Math.min(max, px))\n }\n /** 滚动到包含目标日期的 tick 列(跨 viewMode 精确) */\n scrollToDate(date: string | Date): void {\n if (!this.container) return\n const target = toDate(date)\n const scale = this.getTimeScale()\n const tick = scale.find((t) => target >= t.start && target <= t.end)\n const left = tick ? tick.left : diffDays(this.getDateRange().start, target) * this.config.columnWidth\n this.setScrollLeft(left)\n }\n scrollToTask(id: string): void {\n const layout = this.getLayout()\n if (!layout.ok) return\n const item = layout.data.find((row) => row.taskId === id)\n if (item) this.setScrollLeft(item.left)\n }\n scrollToStart(): void {\n this.setScrollLeft(0)\n }\n scrollToEnd(): void {\n if (!this.container) return\n this.setScrollLeft(this.getTotalWidth())\n }\n /** 让整个 timeline 总宽度≈视口宽度(调 columnWidth) */\n zoomToFit(padding = 1): void {\n if (!this.container) return\n const spanDays = Math.max(1, diffDays(this.getDateRange().start, this.getDateRange().end) + 1)\n const target = (this.container.clientWidth * padding) / spanDays\n this.mergeConfig({ columnWidth: this.clampColumnWidth(target) })\n }\n /** 让指定日期范围占满视口宽度(调 columnWidth) */\n zoomToRange(start: string | Date, end: string | Date): void {\n if (!this.container) return\n const span = Math.max(1, diffDays(start, end) + 1)\n const target = this.container.clientWidth / span\n this.mergeConfig({ columnWidth: this.clampColumnWidth(target) })\n }\n private clampColumnWidth(value: number): number {\n return Math.max(4, Math.min(400, Math.round(value)))\n }\n\n // ── 事件订阅 ──\n on(event: GanttEngineEvent, fn: Listener): () => void {\n this.assertNotDestroyed()\n let set = this.listeners.get(event)\n if (!set) {\n set = new Set()\n this.listeners.set(event, set)\n }\n set.add(fn)\n return () => {\n const current = this.listeners.get(event)\n if (current) {\n current.delete(fn)\n if (!current.size) this.listeners.delete(event)\n }\n }\n }\n once(event: GanttEngineEvent, fn: Listener): () => void {\n const off = this.on(event, (...args: unknown[]) => {\n off()\n fn(...args)\n })\n return off\n }\n off(event: GanttEngineEvent, fn?: Listener): void {\n const set = this.listeners.get(event)\n if (!set) return\n if (fn) {\n set.delete(fn)\n if (!set.size) this.listeners.delete(event)\n } else {\n this.listeners.delete(event)\n }\n }\n emit(event: GanttEngineEvent, ...args: unknown[]): void {\n const set = this.listeners.get(event)\n if (!set) return\n // 复制遍历,避免回调中增删导致迭代错乱\n for (const fn of Array.from(set)) {\n try {\n fn(...args)\n } catch (error) {\n // 单个监听器抛错不应打断其他监听器\n if (typeof console !== \"undefined\") {\n console.error(`[GanttEngine] listener for \"${event}\" threw`, error)\n }\n }\n }\n }\n\n // ── 生命周期 ──\n destroy(): void {\n if (this.destroyed) return\n this.destroyed = true\n this.emit(\"destroy\")\n this.listeners.clear()\n this.tasks = []\n this.links = []\n }\n\n private assertNotDestroyed(): void {\n if (this.destroyed) {\n throw new Error(\"GanttEngine: operation on destroyed instance\")\n }\n }\n}\n\n/** 工厂函数,对应成熟做法的 new GanttEngine(container, config) 入口 */\nexport function createGanttEngine(options: GanttEngineOptions = {}): GanttEngine {\n return new GanttEngine(options)\n}\n"],"mappings":"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","names":["end"]}
|