@xpyjs/gantt-core
Version:
A powerful and flexible Gantt chart component library for modern web applications with TypeScript support
1,583 lines • 298 kB
JavaScript
var Pt = Object.defineProperty;
var Yt = (f, t, e) => t in f ? Pt(f, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : f[t] = e;
var a = (f, t, e) => Yt(f, typeof t != "symbol" ? t + "" : t, e);
import G from "dayjs";
import { default as ai } from "dayjs";
import { merge as rt, isArray as X, isString as V, isFunction as j, cloneDeep as Z, isObject as Et, isNumber as Ut, omit as yt, throttle as wt, isBoolean as ht, debounce as Xt } from "lodash-es";
import S from "konva";
const Ct = "0.0.1-rc.2";
function Vt() {
const f = "#eca710", t = "#ffffff", e = "#e7209e", i = "#ffffff", s = "#1c42e8";
[
" __ __ _____ _____ _____ _____ _____ ",
"| | || __|| _ || | ||_ _||_ _|",
"|- -|| | || || | | | | | | | ",
"|__|__||_____||__|__||_|___| |_| |_| "
].forEach((o) => {
console.log(
`%c${o}`,
`color: ${f}; font-weight: bold; font-family: monospace;`
);
}), console.log(
`%c 🚀 欢迎使用 XGantt %c Version: ${Ct} `,
`background-color: ${e}; color: ${t}; padding: 2px 4px; border-radius: 6px 0 0 6px; font-weight: bold; margin: 4px 0;`,
`background-color: ${s}; color: ${i}; padding: 2px 4px; border-radius: 0 6px 6px 0; font-weight: normal; margin: 4px 0;`
);
}
const N = class N {
/**
* 设置日志配置
* @param options - 新的日志配置
*/
static setOptions(t) {
N.options = { ...N.options, ...t };
}
/**
* 获取当前日志级别
* @returns 当前设置的日志级别
*/
static getLevel() {
return N.options.level;
}
/**
* 输出 DEBUG 级别的日志
* 仅当当前日志级别 <= DEBUG 时输出
* @param args - 需要打印的参数
*/
static debug(...t) {
N.logWithLevel(1, console.debug, ...t);
}
/**
* 输出 INFO 级别的日志
* 仅当当前日志级别 <= INFO 时输出
* @param args - 需要打印的参数
*/
static info(...t) {
N.logWithLevel(2, console.info, ...t);
}
/**
* 输出 WARN 级别的日志
* 仅当当前日志级别 <= WARN 时输出
* @param args - 需要打印的参数
*/
static warn(...t) {
N.logWithLevel(3, console.warn, ...t);
}
/**
* 输出 ERROR 级别的日志
* 仅当当前日志级别 <= ERROR 时输出
* @param args - 需要打印的参数
*/
static error(...t) {
N.logWithLevel(4, console.error, ...t);
}
/**
* 断言方法
* 如果条件为 false,则输出 ERROR 级别的日志
* @param condition - 断言条件
* @param args - 断言失败时需要打印的参数
*/
static assert(t, ...e) {
if (!t && N.options.level <= 4) {
const i = N.formatArgs("Assertion failed:", ...e);
console.error(...i);
}
}
/**
* 返回日志信息
*/
static getMessage(...t) {
return N.formatArgs(...t).join("");
}
/**
* 抛出异常
*/
static exception(...t) {
return new Error(N.getMessage(...t));
}
/**
* 根据级别输出日志的核心方法
* @param level - 当前尝试输出的日志级别
* @param logFn - 使用的 console 方法 (console.log, console.warn, etc.)
* @param args - 需要打印的参数
*/
static logWithLevel(t, e, ...i) {
if (N.options.level <= t) {
const s = N.formatArgs(...i);
e(...s);
}
}
/**
* 格式化日志参数,添加前缀和可选的时间戳
* @param args - 原始日志参数
* @returns 格式化后的日志参数数组
*/
static formatArgs(...t) {
const e = [N.Prefix];
return N.options.showTimestamp && e.unshift(`[${G().format("YYYY-MM-DD HH:mm:ss.SSS")}]`), [e.join(""), ...t];
}
};
a(N, "Prefix", "[XGantt]"), a(N, "options", {
// 默认级别,INFO 及以上会被打印
level: 2,
// 默认不显示时间戳
showTimestamp: !1
});
let O = N;
const lt = () => ({
data: [],
links: {
show: !1,
key: "id",
data: [],
distance: 20,
dash: [0],
width: 1,
gap: 5,
arrow: {
width: 6,
height: 8
},
radius: 3,
create: {
enabled: !1,
mode: "hover",
radius: 3,
width: 2,
from: !0,
to: !0
},
move: {
enabled: !1
},
enableCycleDetection: !0
},
baselines: {
data: [],
taskKey: "taskId",
show: !1,
fields: {
startTime: "startTime",
endTime: "endTime",
name: "name",
id: "id",
target: "target",
highlight: "highlight"
},
mode: "line",
position: "bottom",
backgroundColor: "#999",
opacity: 0.6,
radius: 2,
label: {
show: !1,
forceDisplay: !1,
color: "#666",
fontSize: 10,
position: "right",
fontFamily: "Arial"
},
compare: {
enabled: !1,
tolerance: 0.5,
mode: "both",
target: "end",
delayed: {
backgroundColor: "#ff4444",
opacity: 0.8
},
ahead: {
backgroundColor: "#44ff44",
opacity: 0.8
},
indicator: {
show: !0,
position: "top",
fontFamily: "Arial",
fontSize: 10,
size: 6,
delayed: {
show: !0,
color: "#af1b1b",
opacity: 1
},
ahead: {
show: !0,
color: "#1baf1b",
opacity: 1
},
ontime: {
show: !1,
color: "#999",
opacity: 1
}
}
}
},
milestone: {
show: !1,
shape: "diamond",
border: {
width: 1
},
label: {
show: !0,
text: "",
fontSize: 10,
fontFamily: "Arial",
position: "top-right"
}
},
summary: {
show: !1,
mode: "expand",
move: {
enabled: !1
}
},
fields: {
id: "id",
startTime: "startTime",
endTime: "endTime",
name: "name",
progress: "progress",
children: "children",
type: "type"
},
selection: {
enabled: !1,
includeSelf: !0
},
expand: {
show: !0,
enabled: !0
},
dateFormat: "YYYY-MM-DD HH:mm:ss",
locale: "en",
unit: "day",
table: {
width: 100,
ellipsis: !0,
align: "center",
headerAlign: "center",
emptyText: "-"
},
chart: {
autoCellWidth: !1,
cellWidth: "normal"
},
primaryColor: "#eca710",
border: {
color: "#e5e5e5"
},
header: {
height: 80,
color: "#000",
fontSize: 14,
fontWeight: 600,
fontFamily: "Arial"
},
row: {
height: 30,
indent: 16,
hover: {
backgroundColor: "#000",
opacity: 0.05
},
select: {
backgroundColor: "#000",
opacity: 0.1
}
},
bar: {
height: 20,
show: !0,
move: {
byUnit: !1,
link: {
child: "none",
parent: "none"
}
}
},
today: {
show: !0,
type: "line",
backgroundColor: "lightblue",
opacity: 1,
width: 1
},
weekend: {
show: !0,
backgroundColor: "#c9c9c9",
opacity: 0.1
},
holiday: {
opacity: 0.1
}
});
class Kt {
constructor() {
a(this, "options", lt());
}
getOptions() {
return this.options;
}
setOptions(t, e = { merge: !0 }) {
var i;
if (this.options = e.merge ? rt(lt(), this.options, t) : rt(lt(), t), (i = t.holiday) != null && i.holidays && t.holiday.holidays.length > 0) {
const s = [];
t.holiday.holidays.forEach((n) => {
if (X(n.date)) {
const o = n.date.map((r) => G(r)).sort((r, h) => r.diff(h));
for (let r = 1; r < o.length; r++)
if (o[r].diff(o[r - 1], "day") > 1) {
s.push({
...n,
date: o.slice(0, r).map((h) => h.valueOf())
}), o.splice(0, r);
break;
}
o.length > 0 && s.push({
...n,
date: o.map((r) => r.valueOf())
});
} else
s.push(n);
}), this.options.holiday.holidays = s;
}
}
update(t) {
this.setOptions(t);
}
getRowBackgroundColor(t) {
var s;
let e = "";
const i = (s = this.options.row) == null ? void 0 : s.backgroundColor;
return V(i) ? e = i : X(i) && i.length > 0 ? e = i[t.level] : j(i) && (e = i(t.getEmitData())), e;
}
unpackFunc(t, e) {
return j(t) ? t(e.getEmitData()) : t;
}
}
class jt {
constructor() {
a(this, "events", /* @__PURE__ */ new Map());
}
/**
* 注册事件监听器
* @param event 事件名称
* @param callback 回调函数
*/
on(t, e) {
var i;
this.events.has(t) || this.events.set(t, []), (i = this.events.get(t)) == null || i.push(e);
}
/**
* 触发事件
* @param event 事件名称
* @param args 参数列表
*/
emit(t, ...e) {
var i;
this.events.has(t) && ((i = this.events.get(t)) == null || i.forEach((s) => s(...e)));
}
/**
* 移除特定事件的特定监听器
* @param event 事件名称
* @param callback 要移除的回调函数
*/
off(t, e) {
var i;
this.events.has(t) && this.events.set(
t,
((i = this.events.get(t)) == null ? void 0 : i.filter((s) => s !== e)) || []
);
}
/**
* 移除所有事件监听器
*/
offAll() {
this.events.clear();
}
}
var k = /* @__PURE__ */ ((f) => (f.LOADED = "loaded", f.COLUMN_WIDTH_CHANGE = "column-width-change", f.MOVE_GUIDELINE = "move-guideline", f.SHOW_GUIDELINE = "show-guideline", f.HIDE_GUIDELINE = "hide-guideline", f.TOGGLE_COLLAPSE = "toggle-collapse", f.SCROLL = "scroll", f.CHART_OFFSET_CHANGE = "chart_offset_change", f.DATA_UPDATE = "data-update", f.VIEW_UPDATE = "view-update", f.UPDATE_TABLE_HEADER = "update_table_header", f.UPDATE_TABLE_BODY = "update_table_body", f.UPDATE_CHART_HEADER = "update_chart_header", f.UPDATE_TASK = "update_task", f.UPDATE_LINK = "update_link", f.CREATE_LINK = "create_link", f.TASK_SELECTED = "task_selected", f.TASK_UNSELECTED = "task_unselected", f.SELECT_LINK = "select_link", f.CHECK_TASK = "check_task", f.CONTEXT_LINK = "context_link", f.ROW_CLICK = "row-click", f.ROW_DBL_CLICK = "row-dbl-click", f.ROW_CONTEXTMENU = "row-contextmenu", f.SLIDER_CLICK = "slider-click", f.SLIDER_DBL_CLICK = "slider-dbl-click", f.SLIDER_CONTEXTMENU = "slider-contextmenu", f.SLIDER_DRAGGING = "slider-dragging", f.SLIDER_ENTER = "slider-enter", f.SLIDER_HOVER = "slider-hover", f.SLIDER_LEAVE = "slider-leave", f.SLIDER_BLINK = "slider-blink", f.LINK_BLINK = "link-blink", f.ROW_HIGHLIGHT = "row-highlight", f.ROW_UNHIGHLIGHT = "row-unhighlight", f.TASK_DRAG_START = "task-drag-start", f.TASK_DRAG_MOVE = "task-drag-move", f.TASK_DRAG_END = "task-drag-end", f.BASELINE_CLICK = "baseline-click", f.BASELINE_CONTEXTMENU = "baseline-contextmenu", f.BASELINE_MOUSEENTER = "baseline-mouseenter", f.BASELINE_MOUSEMOVE = "baseline-mousemove", f.BASELINE_MOUSEOUT = "baseline-mouseout", f.ERROR = "error", f))(k || {}), Y = /* @__PURE__ */ ((f) => (f.INVALID_TYPE = "INVALID_TYPE", f.TASK_NOT_FOUND = "TASK_NOT_FOUND", f.LINK_NOT_ALLOWED = "LINK_NOT_ALLOWED", f.LINK_SAME = "LINK_SAME", f.LINK_EXIST = "LINK_EXIST", f.LINK_INVALID_ARG = "LINK_INVALID_ARG", f.LINK_CYCLE = "LINK_CYCLE", f))(Y || {});
function Q() {
return Math.random().toString(36).substring(2, 15);
}
function $(f, t, e) {
if (!Number.isFinite(f) || !Number.isFinite(t) || !Number.isFinite(e))
return Number.isFinite(t) ? t : 0;
const i = Math.min(t, e), s = Math.max(t, e);
return Math.min(Math.max(i, f), s);
}
function nt(f, t) {
let e = f;
return V(e) && (/%$/.test(e) ? e = t * parseFloat(e) / 100 : e = parseFloat(e)), isNaN(e) ? 0 : e;
}
function ct(f, t) {
if (t === 0)
throw new Error("基准值不能为0");
if (Math.abs(f) <= t / 2)
return 0;
const e = Math.floor(f / t), i = Math.ceil(f / t), s = e * t, n = i * t, o = Math.abs(f - s), r = Math.abs(f - n);
return o <= r ? s : n;
}
function ot(f, t = 4) {
return typeof f == "number" ? [f, f, f, f] : Array.isArray(f) ? [
f[0] ?? t,
f[1] ?? t,
f[2] ?? t,
f[3] ?? t
] : [t, t, t, t];
}
function qt(f, t = 100) {
if (!Number.isFinite(f) || !Number.isFinite(t) || t === 0 || f < 0)
return 0;
const e = f / Math.abs(t);
return Math.min(e, 1);
}
function gt(f, t = 2, e = !1) {
const i = f.toFixed(t);
return e ? i : i.replace(/\.?0+$/, "");
}
const dt = /* @__PURE__ */ new Map();
function bt(f, t = 16, e = 16) {
const i = dt.get(f);
if (i) return i;
const s = new Promise((n, o) => {
let r = f;
if (!/viewBox\s*=\s*["'][^"']*["']/.test(r)) {
const l = r.match(/width\s*=\s*["']([^"']*)["']/), m = r.match(/height\s*=\s*["']([^"']*)["']/), p = l ? parseFloat(l[1]) : t, u = m ? parseFloat(m[1]) : e;
r = r.replace(
/<svg([^>]*)>/,
`<svg$1 viewBox="0 0 ${p} ${u}">`
);
}
r = r.replace(/width\s*=\s*["'][^"']*["']/, `width="${t}"`), r = r.replace(/height\s*=\s*["'][^"']*["']/, `height="${e}"`), /width\s*=/.test(r) || (r = r.replace(/<svg/, `<svg width="${t}"`)), /height\s*=/.test(r) || (r = r.replace(/<svg/, `<svg height="${e}"`)), /preserveAspectRatio\s*=/.test(r) || (r = r.replace(
/<svg([^>]*)>/,
'<svg$1 preserveAspectRatio="xMidYMid meet">'
));
const c = new Image();
c.onload = () => {
URL.revokeObjectURL(c.src), n(c);
}, c.onerror = (l) => {
URL.revokeObjectURL(c.src), dt.delete(f), o(l);
};
const g = new Blob([r], { type: "image/svg+xml" }), d = URL.createObjectURL(g);
c.src = d;
});
return dt.set(f, s), s;
}
class mt {
constructor(t, e, i, s, n) {
a(this, "__key__", Q());
/**
* 任务ID
* 如果没有提供,则会自动生成一个唯一ID
*/
a(this, "id");
/**
* 任务名称
*/
a(this, "name");
/**
* 任务开始时间
* 如果没有提供,则默认为 undefined
*/
a(this, "startTime");
/**
* 任务结束时间
* 如果没有提供,则默认为 undefined
*/
a(this, "endTime");
/**
* 任务进度
*/
a(this, "progress");
/** 任务类型 */
a(this, "type");
/**
* 是否展开
* 如果没有提供,则默认为 true
*/
a(this, "expanded");
/**
* 子任务列表
* 如果没有子任务,则默认为空数组
*/
a(this, "children");
/**
* 父任务
* 如果没有父任务,则默认为 undefined
*/
a(this, "parent");
/**
* 任务层级,从0开始
*/
a(this, "level");
/**
* 在扁平化列表中的索引位置,从0开始
*/
a(this, "flatIndex");
/**
* 时间持续间隔
*/
a(this, "duration", 0);
/**
* 原始数据
*/
a(this, "data");
a(this, "fields");
this.store = t, this.event = e, this.fields = this.store.getOptionManager().getOptions().fields, this.id = n || i[this.fields.id] || Q(), this.data = i, this.name = i[this.fields.name] || "", this.type = i[this.fields.type] || "task", this.updateMode(), this.progress = i[this.fields.progress], this.expanded = this.store.getOptionManager().getOptions().expand.show ? this.store.getOptionManager().getOptions().expand.enabled : !0, this.children = [], this.level = s && s.level !== void 0 ? s.level + 1 : 0, this.parent = s, this.flatIndex = 0, this.store.updateTime(this.startTime, this.endTime);
}
getField(t) {
if (!t || V(t) && t.trim() === "")
return;
if (!t.includes("."))
return this.data[t];
const e = t.split(".");
let i = this.data;
for (let s = 0; s < e.length; s++) {
const n = e[s];
if (i == null || typeof i != "object" || !(n in i))
return;
i = i[n];
}
return Et(i) ? Z(i) : i;
}
/** 切换展示模式时,需要调整时间 */
updateMode() {
let t = !1;
return this.data[this.fields.startTime] && (!this.startTime || !this.startTime.isSame(G(this.data[this.fields.startTime]))) && (this.startTime = G(this.data[this.fields.startTime]), t = !0), this.data[this.fields.endTime] && (!this.endTime || !this.endTime.isSame(G(this.data[this.fields.endTime]))) && (this.endTime = G(this.data[this.fields.endTime]), t = !0), this.startTime && this.endTime && this.duration === 0 && (this.duration = this.endTime.diff(this.startTime)), this.isMilestone() && (!this.endTime || !this.endTime.isSame(this.startTime)) && (this.endTime = this.startTime, t = !0), t;
}
updateData(t) {
this.data = t;
let e = !1;
t[this.fields.name] && this.name !== t[this.fields.name] && (this.name = t[this.fields.name], e = !0), t[this.fields.type] && this.type !== t[this.fields.type] && (this.type = t[this.fields.type], e = !0), e = this.updateMode(), t[this.fields.progress] !== void 0 && (this.progress !== t[this.fields.progress] && (e = !0), this.progress = $(t[this.fields.progress], 0, 100)), e && this.event.emit(k.UPDATE_TASK, this);
}
updateTime(t, e) {
var s, n;
this.startTime = t, this.endTime = this.isMilestone() ? t : e;
const i = (n = (s = this.store) == null ? void 0 : s.getOptionManager().getOptions()) == null ? void 0 : n.dateFormat;
this.data[this.fields.startTime || "startTime"] = this.startTime.format(i), this.isMilestone() ? this.data[this.fields.endTime || "endTime"] = this.startTime.add(this.duration).format(i) : this.data[this.fields.endTime || "endTime"] = this.endTime.format(i), this.event.emit(k.UPDATE_TASK, this);
}
clone() {
return new mt(
this.store,
this.event,
Z(this.data),
this.parent,
this.id
);
}
getEmitData() {
return {
data: this.data,
$index: this.flatIndex,
level: this.level + 1
};
}
getAllChildren() {
const t = [], e = (i) => {
i.forEach((s) => {
t.push(s), X(s.children) && s.children.length > 0 && e(s.children);
});
};
return e(this.children), t;
}
isMilestone() {
return this.store.getOptionManager().getOptions().milestone.show ? this.type === "milestone" : !1;
}
isSummary() {
return this.store.getOptionManager().getOptions().summary.show ? this.type === "summary" : !1;
}
}
class Qt {
constructor(t, e, i) {
/** 基线ID */
a(this, "id");
/** 任务ID */
a(this, "taskId");
/** 开始时间 */
a(this, "startTime");
/** 结束时间 */
a(this, "endTime");
/** 基线名称 */
a(this, "name");
/** 原始数据 */
a(this, "data");
/** 是否高亮 */
a(this, "highlight", !0);
/** 是否为指示器对比基线 */
a(this, "target", !1);
this.store = t, this.event = e;
const s = this.store.getOptionManager().getOptions().fields, n = this.store.getOptionManager().getOptions().baselines.fields;
this.taskId = i[t.getOptionManager().getOptions().baselines.taskKey], this.id = i[s.id] || i[n.id] || Q(), this.name = i[s.name] || i[n.name] || "", this.highlight = i[n.highlight] !== !1, this.target = i[n.target] === !0;
const o = i[s.startTime] || i[n.startTime];
o && (this.startTime = G(o));
const r = i[s.endTime] || i[n.endTime];
r && (this.endTime = G(r)), this.data = i;
}
getField(t) {
return this.data[t];
}
/**
* 验证基线的有效性
*/
validate() {
return !this.taskId || !this.startTime || !this.endTime ? !1 : this.startTime.isBefore(this.endTime);
}
/**
* 获取基线与任务的时间差异分析
*/
getTimeDiff() {
if (!this.validate()) return null;
const t = this.store.getDataManager().getTaskById(this.taskId);
if (!t || !t.startTime || !t.endTime) return null;
const e = this.store.getTimeAxis().getCellUnit(), i = this.startTime.diff(t.startTime, e, !0), s = this.endTime.diff(t.endTime, e, !0), n = this.store.getOptionManager().getOptions().baselines.compare.tolerance, o = i < -n ? "delayed" : i > n ? "ahead" : "ontime", r = s < -n ? "delayed" : s > n ? "ahead" : "ontime", h = this.endTime.diff(this.startTime, e, !0), c = t.endTime.diff(t.startTime, e, !0), g = h > 0 ? (c - h) / h * 100 : 0;
return { startDiff: i, endDiff: s, startStatus: o, endStatus: r, progressDiff: g, unit: e };
}
}
class Jt {
constructor(t, e) {
/**
* 原始数据
*/
a(this, "rawData", []);
/**
* 任务列表。树形结构
*/
a(this, "tasks", []);
/**
* 任务映射,使用ID作为键,便于快速查找
*/
a(this, "taskMap", /* @__PURE__ */ new Map());
/**
* 缓存扁平化的可视任务列表
* 用于提高性能,避免每次都遍历树形结构
*/
a(this, "visibleTasksCache", []);
/** 标记缓存是否需要更新 */
a(this, "isDirty", !0);
/** 缓存被折叠的任务 ID */
a(this, "collapsedTaskIds", /* @__PURE__ */ new Set());
/** 存储当前选中的任务ID */
a(this, "selectedTaskId", null);
/** 选中列表 */
a(this, "checkedList", []);
/** 基线数据 */
a(this, "baselines", []);
/** 基线映射,使用ID作为键 */
a(this, "baselineMap", /* @__PURE__ */ new Map());
/** 任务与基线映射,使用任务ID作为键。 一个任务可以对应多条基线 */
a(this, "baselineTaskMap", /* @__PURE__ */ new Map());
/** 数据最大层级。 0 开始 */
a(this, "dataLevel", 0);
this.store = t, this.event = e;
}
/**
* 设置源数据并初始化任务
*/
setData(t, e = !1) {
this.rawData = t, this.initTasks(e), this.invalidateCache(), this.event.emit(k.DATA_UPDATE);
}
/**
* 初始化任务
*/
initTasks(t = !1) {
t ? (this.dataLevel = 0, this.tasks = [], this.taskMap.clear(), this.collapsedTaskIds.clear(), this.rawData.forEach((e) => {
this.tasks.push(this.createTask(e));
})) : this.rawData.length > 0 ? this.updateTask(this.rawData, this.tasks) : (this.tasks = [], this.taskMap.clear(), this.collapsedTaskIds.clear());
}
createTask(t, e) {
const i = this.store.getOptionManager().getOptions().fields, s = new mt(this.store, this.event, t, e);
return Array.isArray(t[i.children]) && (s.children = t[i.children].map(
(n) => this.createTask(n, s)
)), this.taskMap.set(s.id, s), this.dataLevel = Math.max(this.dataLevel, s.level), s;
}
updateTask(t, e, i) {
let s = 0;
for (; s < t.length; ) {
const n = t[s], o = e[s];
if (n && !o) {
const r = this.createTask(n, i);
e.push(r), this.taskMap.set(r.id, r), this.dataLevel = Math.max(this.dataLevel, r.level);
} else !n && o ? (this.taskMap.delete(o.id), e.splice(s, 1)) : n && o && (n[this.store.getOptionManager().getOptions().fields.id] === o.id ? (o.updateData(n), this.dataLevel = Math.max(this.dataLevel, o.level)) : (this.taskMap.delete(o.id), e[s] = this.createTask(n, o.parent), this.taskMap.set(e[s].id, e[s]), this.dataLevel = Math.max(this.dataLevel, e[s].level)));
if (n[this.store.getOptionManager().getOptions().fields.children]) {
const r = n[this.store.getOptionManager().getOptions().fields.children];
if (o && o.children)
this.updateTask(r, o.children, o);
else {
const h = r.map(
(c) => this.createTask(c, e[s])
);
e[s].children = h;
}
} else o && o.children && (o.children = []);
s++;
}
e.length >= s && e.splice(s).forEach((o) => {
this.taskMap.delete(o.id);
});
}
/**
* 获取源数据
*/
getData() {
return this.rawData;
}
/**
* 获取所有任务
*/
getTasks(t = !0) {
return t ? this.tasks : Array.from(this.taskMap.values());
}
/**
* 通过 ID 获取任务
*/
getTaskById(t) {
return this.taskMap.get(t);
}
/**
* 移动任务位置
*/
// moveTask(
// id: string,
// targetParentId?: string,
// index?: number
// ): Task | undefined {
// const task = this.getTaskById(id);
// if (!task) {
// return undefined;
// }
// // 从原位置移除
// if (task.parent && task.parent.children) {
// task.parent.children = task.parent.children.filter(
// child => child.id !== id
// );
// } else {
// this.tasks = this.tasks.filter(t => t.id !== id);
// }
// // 移动到新位置
// let targetTasks: Task[];
// let targetParent: Task | undefined;
// if (targetParentId) {
// targetParent = this.getTaskById(targetParentId);
// if (!targetParent) {
// return undefined;
// }
// targetTasks = targetParent.children || [];
// targetParent.children = targetTasks;
// } else {
// targetTasks = this.tasks;
// }
// // 更新任务的父任务和层级
// task.parent = targetParent;
// task.level = targetParent
// ? targetParent.level !== undefined
// ? targetParent.level + 1
// : 0
// : 0;
// // 更新子任务的层级
// if (task.children && task.children.length > 0) {
// this.updateChildrenLevel(task);
// }
// // 插入到目标位置
// if (index !== undefined && index >= 0 && index <= targetTasks.length) {
// targetTasks.splice(index, 0, task);
// } else {
// targetTasks.push(task);
// }
// this.invalidateCache(); // 移动任务后,缓存失效
// this.event.emit(EventName.VIEW_UPDATE);
// return task;
// }
/**
* 展开任务
*/
expandTask(t, e = !1) {
const i = this.getTaskById(t);
return i ? (i.expanded = !i.expanded, i.expanded ? this.collapsedTaskIds.delete(i.id) : this.collapsedTaskIds.add(i.id), e && i.children && i.children.length > 0 && i.children.forEach((s) => {
this.expandTask(s.id, e);
}), this.invalidateCache(), this.event.emit(k.VIEW_UPDATE), !0) : !1;
}
/**
* 按条件筛选任务
*/
// filterTasks(criteria: (task: Task) => boolean): Task[] {
// return Array.from(this.taskMap.values()).filter(criteria);
// }
/**
* 排序任务
*/
// sortTasks(
// compareFn: (a: Task, b: Task) => number,
// parentId?: string
// ): Task[] {
// let tasksToSort: Task[];
// if (parentId) {
// const parent = this.getTaskById(parentId);
// if (!parent || !parent.children) {
// return [];
// }
// tasksToSort = parent.children;
// } else {
// tasksToSort = this.tasks;
// }
// tasksToSort.sort(compareFn);
// this.invalidateCache(); // 排序后,缓存失效
// // this.emit("tasks:sorted", { parentId, tasks: tasksToSort });
// return tasksToSort;
// }
/**
* 获取扁平化的任务列表,包括已展开的子任务
* 使用缓存提高性能,只有在必要时才会重建列表
*/
getVisibleTasks() {
if (!this.isDirty && this.visibleTasksCache.length > 0)
return this.visibleTasksCache;
const t = [];
let e = 0;
const i = (s, n) => {
this.collapsedTaskIds.has(s.id) && s.expanded && (s.expanded = !1), s.flatIndex = e++, t.push(s), s.expanded && s.children && s.children.length > 0 && s.children.forEach((o) => i(o));
};
return this.tasks.forEach((s) => i(s)), this.visibleTasksCache = t, this.isDirty = !1, t;
}
/**
* 获取一个任务是否可展示
*/
isTaskVisible(t) {
let e = t.parent;
for (; e; ) {
if (this.collapsedTaskIds.has(e.id))
return !1;
e = e.parent;
}
return !0;
}
/**
* 获取可展示任务数量
*/
getVisibleSize() {
return this.getVisibleTasks().length;
}
/**
* 清空所有数据
*/
clear() {
this.rawData = [], this.tasks = [], this.taskMap.clear(), this.visibleTasksCache = [], this.isDirty = !0, this.collapsedTaskIds.clear(), this.event.emit(k.DATA_UPDATE);
}
/**
* 更新子任务的层级
*/
// private updateChildrenLevel(task: Task): void {
// if (!task.children || task.children.length === 0) {
// return;
// }
// const parentLevel = task.level !== undefined ? task.level : 0;
// task.children.forEach(child => {
// child.level = parentLevel + 1;
// this.updateChildrenLevel(child);
// });
// }
/**
* 使缓存失效,标记需要重新生成扁平化任务列表
*/
invalidateCache() {
this.isDirty = !0;
}
/**
* 选择任务
* @param taskId 任务ID
* @returns 是否选择成功
*/
selectTask(t) {
const e = this.getTaskById(t);
return e ? (this.selectedTaskId === t || (this.unselectTask(), this.selectedTaskId = t, this.event.emit(k.TASK_SELECTED, e)), !0) : !1;
}
/**
* 取消任务选择
*/
unselectTask() {
if (this.selectedTaskId) {
const t = this.selectedTaskId;
this.selectedTaskId = null, this.event.emit(k.TASK_UNSELECTED, t);
}
}
/**
* 检查任务是否被选中
* @param taskId 任务ID
* @returns 是否被选中
*/
isTaskSelected(t) {
return this.selectedTaskId === t;
}
/**
* 获取当前选中的任务
* @returns 选中的任务,如果没有则返回undefined
*/
getSelectedTask() {
return this.selectedTaskId ? this.getTaskById(this.selectedTaskId) : void 0;
}
getCheckedList() {
return this.checkedList;
}
updateCheckedList(t, e) {
const i = this.checkedList.findIndex((s) => s.id === e.id);
t ? i === -1 ? this.checkedList.push(e) : this.checkedList.splice(i, 1, e) : i !== -1 && this.checkedList.splice(i, 1);
}
toggleAllChecked(t) {
t ? this.checkedList = this.getVisibleTasks().slice() : this.checkedList = [];
}
isTaskChecked(t) {
return this.checkedList.findIndex((e) => e.id === t.id) !== -1;
}
updateTaskTime(t, e, i, s, n = []) {
let o = e, r = i;
const h = this.store.getOptionManager().getOptions().bar.move.link.child, c = this.store.getOptionManager().getOptions().bar.move.link.parent, g = this.store.getTimeAxis().getCellUnit();
let d = t.parent;
for (; c !== "none" && d; ) {
if (c === "expand") {
let m = d.startTime || o, p = d.endTime || r;
(!d.startTime || o.isBefore(d.startTime)) && (m = o), (!d.endTime || r.isAfter(d.endTime)) && (p = r), (d.startTime === void 0 || d.endTime === void 0 || !m.isSame(d.startTime) || !p.isSame(d.endTime)) && (n.findIndex((u) => u.id === d.id) === -1 && n.push(d.clone()), d.updateTime(m, p));
} else c === "strict" && (d.startTime && o.isBefore(d.startTime) && (o = d.startTime, r.isSameOrBefore(o) && (r = o.add(1, g))), d.endTime && r.isAfter(d.endTime) && (r = d.endTime, o.isAfter(r) && (o = r.subtract(1, g))));
d = d.parent;
}
let l = t.children || [];
for (; h !== "none" && l.length > 0; ) {
const m = [];
l.forEach((p) => {
let u = p.startTime || o, y = p.endTime || r, x = o.diff(t.startTime), T = r.diff(t.endTime);
h === "scale" ? s === "both" ? (n.findIndex((b) => b.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u.add(x), y.add(T))) : s === "left" ? (u = u.add(x), u.isSameOrAfter(y.subtract(1, g)) && (y.isBefore(t.endTime) ? y = u.add(1, g) : u = y.subtract(1, g), u.isSameOrBefore(o) && (o = u)), n.findIndex((b) => b.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, y)) : s === "right" && (y = y.add(T), y.isSameOrBefore(u.add(1, g)) && (u.isAfter(t.startTime) ? u = y.subtract(1, g) : y = u.add(1, g)), y.isSameOrAfter(r) && (r = y), n.findIndex((b) => b.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, y)) : h === "fixed" && (s === "both" ? (n.findIndex((b) => b.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u.add(x), y.add(T))) : s === "left" ? u.isSameOrBefore(o) && (u = o, u.isSameOrAfter(y.subtract(1, g)) && (y.isBefore(t.endTime) ? y = u.add(1, g) : u = y.subtract(1, g), u.isSameOrBefore(o) && (o = u)), n.findIndex((b) => b.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, y)) : s === "right" && y.isSameOrAfter(r) && (y = r, y.isSameOrBefore(u.add(1, g)) && (u.isAfter(t.startTime) ? u = y.subtract(1, g) : y = u.add(1, g)), y.isSameOrAfter(r) && (r = y), n.findIndex((b) => b.id === p.id) === -1 && n.push(p.clone()), p.updateTime(u, y))), p.children && p.children.length > 0 && m.push(...p.children);
}), l = m;
}
n.findIndex((m) => m.id === t.id) === -1 && n.push(t.clone()), t.updateTime(o, r);
}
//** 基线数据操作 */
setBaselines(t) {
this.baselines = [], this.baselineMap.clear(), this.baselineTaskMap.clear(), t.forEach((e) => {
var s, n;
const i = new Qt(this.store, this.event, e);
this.baselines.push(i), this.baselineMap.set(i.id, i), this.baselineTaskMap.has(i.taskId) || this.baselineTaskMap.set(i.taskId, []), i.target ? (s = this.baselineTaskMap.get(i.taskId)) == null || s.unshift(i) : (n = this.baselineTaskMap.get(i.taskId)) == null || n.push(i);
});
}
getBaselines() {
return this.baselines;
}
/** 根据ID获取基线 */
getBaselineById(t) {
return this.baselineMap.get(t);
}
/** 根据任务ID获取基线 */
getBaselinesByTaskId(t) {
return this.baselineTaskMap.get(t) || [];
}
}
function Zt(f) {
var s;
if (typeof f == "object" && f !== null)
return {
r: $(f.r ?? 0, 0, 255),
g: $(f.g ?? 0, 0, 255),
b: $(f.b ?? 0, 0, 255),
a: $(f.a ?? 1, 0, 1)
};
if (typeof f != "string")
return O.warn(`Invalid color value type: ${typeof f}`), null;
let t = f.trim();
const e = (s = document == null ? void 0 : document.createElement("canvas")) == null ? void 0 : s.getContext("2d");
if (e && (e.fillStyle = t, t = e.fillStyle), t.startsWith("#")) {
const n = t.slice(1);
let o, r, h, c, g = 1;
try {
o = parseInt(n, 16);
} catch {
return O.warn(`Invalid hex color: ${f}`), null;
}
if (n.length === 3)
r = (o >> 8 & 15) * 17, h = (o >> 4 & 15) * 17, c = (o & 15) * 17;
else if (n.length === 6)
r = o >> 16 & 255, h = o >> 8 & 255, c = o & 255;
else if (n.length === 8)
r = o >> 24 & 255, h = o >> 16 & 255, c = o >> 8 & 255, g = (o & 255) / 255;
else
return O.warn(`Invalid hex color length: ${f}`), null;
return { r, g: h, b: c, a: g };
}
let i = t.match(
/rgba?\(\s*(\d+%?)\s*,\s*(\d+%?)\s*,\s*(\d+%?)\s*(?:,\s*([\d.]+)\s*)?\)/i
);
if (i) {
const n = (o) => o.endsWith("%") ? $(parseFloat(o) / 100 * 255, 0, 255) : $(parseInt(o, 10), 0, 255);
return {
r: n(i[1]),
g: n(i[2]),
b: n(i[3]),
a: i[4] !== void 0 ? $(parseFloat(i[4]), 0, 1) : 1
};
}
return O.warn(`Could not parse color: ${f}`), null;
}
function te(f, t, e, i, s = !1, n = !1) {
const o = (l) => {
const m = Math.round($(l, 0, 255)).toString(16);
return m.length === 1 ? "0" + m : m;
}, r = o(f), h = o(t), c = o(e), g = o(i * 255);
if (s && r[0] === r[1] && h[0] === h[1] && c[0] === c[1] && i === 1 && // Alpha 必须为 1 才能缩写
!n)
return `#${r[0]}${h[0]}${c[0]}`;
const d = `#${r}${h}${c}`;
return n || i < 1 ? `${d}${g}` : d;
}
class et {
/**
* 创建一个新的 Colorjs 实例。
* 推荐使用 colorjs(value) 工厂函数来创建。
* @param value - 颜色值 (字符串, 如 '#rgb', '#rrggbb', 'rgb()', 'rgba()', 颜色名; 或对象 {r, g, b, a})
* @throws {Error} 如果颜色值无法解析
*/
constructor(t) {
// 使用 private 属性,强制通过方法访问和修改
a(this, "_r");
a(this, "_g");
a(this, "_b");
a(this, "_a");
const e = Zt(t);
e === null ? (O.error(`Failed to parse color: ${t}. Using default black.`), this._r = 0, this._g = 0, this._b = 0, this._a = 1) : (this._r = Math.round(e.r), this._g = Math.round(e.g), this._b = Math.round(e.b), this._a = e.a);
}
// --- Getters ---
/** 获取 Red 通道值 (0-255) */
get R() {
return this._r;
}
/** 获取 Green 通道值 (0-255) */
get G() {
return this._g;
}
/** 获取 Blue 通道值 (0-255) */
get B() {
return this._b;
}
/** 获取 Alpha 通道值 (0-1) */
get A() {
return this._a;
}
red(t) {
return t === void 0 ? this._r : (this._r = Math.round($(t, 0, 255)), this);
}
green(t) {
return t === void 0 ? this._g : (this._g = Math.round($(t, 0, 255)), this);
}
blue(t) {
return t === void 0 ? this._b : (this._b = Math.round($(t, 0, 255)), this);
}
alpha(t) {
return t === void 0 ? this._a : (this._a = $(t, 0, 1), this);
}
// --- 输出方法 ---
/**
* 输出为 Hex (#RRGGBB) 或 HexA (#RRGGBBAA) 格式字符串。
* @param allow3Char - 是否允许输出 #RGB 简写格式 (如果可能, 默认 false)。
* @param forceAlpha - 是否强制输出 Alpha 通道 (即使 a=1, 默认 false)。
* @returns Hex/HexA 字符串。
*/
toHex(t = !1, e = !1) {
return te(
this._r,
this._g,
this._b,
this._a,
t,
e
);
}
/**
* 输出为 rgb() 或 rgba() 格式字符串。
* @returns 'rgb(r, g, b)' 或 'rgba(r, g, b, a)' 格式字符串。
*/
toRgb() {
const t = Math.round(this._r), e = Math.round(this._g), i = Math.round(this._b);
if (this._a === 1)
return `rgb(${t}, ${e}, ${i})`;
{
const s = parseFloat(this._a.toFixed(2));
return `rgba(${t}, ${e}, ${i}, ${s})`;
}
}
/**
* 输出为包含 r, g, b, a 的对象。
* @returns RGBA 对象 { r, g, b, a }。
*/
toObject() {
return { r: this._r, g: this._g, b: this._b, a: this._a };
}
/**
* 默认字符串表示形式,输出为 rgba 格式。
* @returns rgba 格式字符串。
*/
toString() {
return this.toRgb();
}
// --- 操作方法 (返回 this 以支持链式调用) ---
/**
* 增加颜色亮度。
* @param amount - 增加的百分比 (0-100),默认为 10。
* @returns 当前 Colorjs 实例。
*/
brighten(t = 10) {
if (t < 0) return this.darken(-t);
const e = $(t, 0, 100) / 100;
return this._r = Math.round($(this._r + (255 - this._r) * e, 0, 255)), this._g = Math.round($(this._g + (255 - this._g) * e, 0, 255)), this._b = Math.round($(this._b + (255 - this._b) * e, 0, 255)), this;
}
/**
* 降低颜色亮度 (变暗)。
* @param amount - 降低的百分比 (0-100),默认为 10。
* @returns 当前 Colorjs 实例。
*/
darken(t = 10) {
if (t < 0) return this.brighten(-t);
const e = $(t, 0, 100) / 100;
return this._r = Math.round($(this._r * (1 - e), 0, 255)), this._g = Math.round($(this._g * (1 - e), 0, 255)), this._b = Math.round($(this._b * (1 - e), 0, 255)), this;
}
/**
* 判断颜色是否偏亮。
* 使用标准的亮度计算公式。
* @returns 如果颜色偏亮则返回 true,否则返回 false。
*/
isLight() {
return (this._r * 299 + this._g * 587 + this._b * 114) / 1e3 > 128;
}
/**
* 判断颜色是否偏暗。
* @returns 如果颜色偏暗则返回 true,否则返回 false。
*/
isDark() {
return !this.isLight();
}
/**
* 混合当前颜色与指定颜色。
* @param colorToMix - 要混合的颜色 (Colorjs 实例或可被 colorjs() 解析的颜色值)。
* @param amount - 混合的比例 (0-100),表示 `colorToMix` 所占的权重,默认为 50 (各占一半)。
* @returns 当前 Colorjs 实例。
*/
mix(t, e = 50) {
const i = $(e, 0, 100) / 100, s = B(t);
return this._r = Math.round(
$(this._r * (1 - i) + s.R * i, 0, 255)
), this._g = Math.round(
$(this._g * (1 - i) + s.G * i, 0, 255)
), this._b = Math.round(
$(this._b * (1 - i) + s.B * i, 0, 255)
), this._a = $(this._a * (1 - i) + s.A * i, 0, 1), this;
}
/**
* 创建当前颜色对象的副本。
* @returns 一个新的 Colorjs 实例,具有相同的颜色值。
*/
clone() {
return new et({
r: this._r,
g: this._g,
b: this._b,
a: this._a
});
}
// --- 静态方法 ---
/**
* 扩展 Colorjs 功能的插件机制。
* @param plugin - 插件函数。
* @param option - 传递给插件的选项 (可选)。
*/
static extend(t, e) {
typeof t == "function" ? t(e, et, B) : O.warn(
"Invalid plugin provided to Colorjs.extend. Expected a function."
);
}
}
const B = (f) => f instanceof et ? f : new et(f);
class Lt {
constructor(t, e, i) {
a(this, "element");
a(this, "iconElement");
a(this, "_state", 0);
a(this, "options");
var o;
this.context = t, this.container = e, this.task = i;
const n = (this.task ? this.context.store.getDataManager().isTaskChecked(this.task) : !1) ? 1 : 0;
this.options = {
initialState: n,
size: 14
}, this.element = document.createElement("div"), this.iconElement = document.createElement("div"), this._state = this.options.initialState, this.createElement(), this.updateIcon(), this.bindEvents(), this.registerEvents(), (o = this.container) == null || o.appendChild(this.element);
}
createElement() {
this.element.className = "x-gantt-checkbox", this.element.style.width = `${this.options.size}px`, this.element.style.height = `${this.options.size}px`, this.element.style.setProperty(
"border",
`1px solid ${this.context.store.getOptionManager().getOptions().border.color}`,
"important"
), this.iconElement.className = "x-gantt-checkbox__icon", this.iconElement.style.cssText = `
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
color: #ffffff;
font-size: ${Math.floor(this.options.size * 0.75)}px;
line-height: 1;
`, this.element.appendChild(this.iconElement), this.element.addEventListener("mouseenter", () => {
this._state === 0 && this.element.classList.add("hover");
}), this.element.addEventListener("mouseleave", () => {
this._state === 0 && this.element.classList.remove("hover");
});
}
updateIcon() {
const t = this.context.store.getOptionManager().getOptions().primaryColor;
this.iconElement.innerHTML = "";
let e = "#ffffff", i = B(t).alpha(0.5).toHex();
switch (this._state) {
case 0:
e = "#ffffff", i = i;
break;
case 1:
e = t, i = t, this.iconElement.innerHTML = `
<svg width="12" height="9" viewBox="0 0 12 9" fill="none">
<path d="M10.5 1.5L4.5 7.5L1.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
`;
break;
case 2:
e = t, i = t, this.iconElement.innerHTML = `
<svg width="8" height="2" viewBox="0 0 8 2" fill="none">
<rect width="8" height="2" fill="currentColor" rx="1"/>
</svg>
`;
break;
}
this.iconElement.style.setProperty(
"background-color",
e,
"important"
), this.iconElement.style.setProperty(
"border-color",
i,
"important"
);
}
bindEvents() {
this.element.addEventListener("click", (t) => {
if (t.preventDefault(), t.stopPropagation(), this.task) {
const e = this.context.store.getDataManager().isTaskChecked(this.task);
e ? (this.context.store.getDataManager().updateCheckedList(!1, this.task), this.setState(
0
/* UNCHECKED */
)) : (this.context.store.getDataManager().updateCheckedList(!0, this.task), this.setState(
1
/* CHECKED */
)), this.context.event.emit(k.CHECK_TASK, [this.task], !e);
} else {
const e = this.context.store.getDataManager().getCheckedList().length === this.context.store.getDataManager().getVisibleSize();
this.setState(
e ? 1 : 0
/* UNCHECKED */
), this.context.store.getDataManager().toggleAllChecked(!e), this.context.event.emit(
k.CHECK_TASK,
this.context.store.getDataManager().getVisibleTasks(),
!e
);
}
}), this.element.addEventListener("contextmenu", (t) => {
if (t.preventDefault(), t.stopPropagation(), this.task) {
const e = this.task.getAllChildren();
if (e.length === 0) return;
this.context.store.getOptionManager().getOptions().selection.includeSelf && e.unshift(this.task);
const i = e.every(
(s) => this.context.store.getDataManager().isTaskChecked(s)
);
i ? (e.forEach((s) => {
this.context.store.getDataManager().updateCheckedList(!1, s);
}), this.setState(
0
/* UNCHECKED */
)) : (e.forEach((s) => {
this.context.store.getDataManager().updateCheckedList(!0, s);
}), this.setState(
1
/* CHECKED */
)), this.context.event.emit(k.CHECK_TASK, e, !i);
} else {
const e = this.context.store.getDataManager().getCheckedList().length === this.context.store.getDataManager().getVisibleSize();
this.setState(
e ? 1 : 0
/* UNCHECKED */
), this.context.store.getDataManager().toggleAllChecked(!e), this.context.event.emit(
k.CHECK_TASK,
this.context.store.getDataManager().getVisibleTasks(),
!e
);
}
});
}
registerEvents() {
this.context.event.on(k.CHECK_TASK, this.updateState.bind(this));
}
/** 获取元素 */
getElement() {
return this.element;
}
/**
* 设置状态
*/
setState(t) {
this._state !== t && (this._state = t, this.updateIcon());
}
/**
* 更新状态
*/
updateState() {
if (this.task) {
const t = this.context.store.getDataManager().isTaskChecked(this.task);
this.setState(
t ? 1 : 0
/* UNCHECKED */
);
} else {
const t = this.context.store.getDataManager().getCheckedList().length === this.context.store.getDataManager().getVisibleSize();
this.setState(
t ? 1 : 0
/* UNCHECKED */
);
}
}
/**
* 销毁组件
*/
destroy() {
this.element && this.element.parentNode && this.element.parentNode.removeChild(this.element);
}
}
const Tt = "handler_column";
class ee {
constructor(t) {
/** 源列数据 */
a(this, "sourceColumns", []);
/** 处理后的所有列数据 */
a(this, "columns", []);
/** 叶子列数据,只包含最终显示的列 */
a(this, "leafColumns", []);
/** 临时叶子列数据,用于更新源数据,读取宽度等原信息 */
a(this, "temporaryLeafColumns", []);
/**
* 保存所有行列合并的信息
*
* Map<task_id, Map<col_index, object>>
*/
a(this, "mergeInfo", /* @__PURE__ */ new Map());
/**
* 收起表格
*/
a(this, "collapseTable", !1);
this.context = t;
}
/**
* 初始化列数据
*/
init(t) {
t != null && t.length && (this.sourceColumns = t), this.columns = [], this.leafColumns = [], this.processColumns(this.sourceColumns, this.columns);
}
/**
* 处理列数据,将源数据转换为内部数据结构
*/
processColumns(t, e = [], i, s = 1) {
t.forEach((n, o) => {
var p;
const r = "children" in n && Array.isArray(n.children) && n.children.length > 0, h = !r;
let c = "";
r ? c = `group-${o}` : c = `field-${n.field}`;
const g = [...(i == null ? void 0 : i.path) || [], c];
c = "column-" + o + "-" + g.join("-");
const d = n.label || (h ? n.field : ""), l = h ? ((p = this.temporaryLeafColumns.find((u) => u.key === c)) == null ? void 0 : p.width) || n.width || 100 : "auto", m = {
label: d,
level: s,
maxLevel: s,
column: n,
children: [],
path: g,
key: c,
isLeaf: h,
width: l
};
if (e.push(m), h)
this.leafColumns.push(m);
else if (r) {
const u = n.children;
this.processColumns(
u,
m.children,
m,
s + 1
), m.maxLevel = Math.max(
m.maxLevel,
m.children.reduce((y, x) => Math.max(y, x.maxLevel), 0)
);
}
}), this.temporaryLeafColumns = Z(this.leafColumns);
}
/**
* 根据 key 查找列
*/
findColumnByKey(t) {
return this.columns.find((e) => e.key === t);
}
update(t) {
this.init(t), this.clearMergeInfo();
}
getColumns() {
return this.columns;
}
getColumn(t) {
return this.leafColumns.find((e) => e.key === t);
}
getLeafColumns() {
return this.leafColumns;
}
getTotalWidth() {
return this.isCollapsed() ? 0 : this.leafColumns.reduce((t, e) => t + e.width, this.getHandlerColumn().width);
}
getColumnWidth(t) {
if (t === Tt) return this.getHandlerColumn().width;
const e = this.leafColumns.find((i) => i.key === t);
return typeof (e == null ? void 0 : e.width) == "number" ? e.width : 0;
}
setColumnWidth(t, e) {
const i = this.leafColumns.find((s) => s.key === t);
i && (i.width = e), this.context.event.emit(k.COLUMN_WIDTH_CHANGE, t, e);
}
isLastColumn(t) {
return this.leafColumns.findIndex((i) => i.key === t) === this.leafColumns.length - 1;
}
addMergeInfo(t, e, i) {
this.mergeInfo.has(t) || this.mergeInfo.set(t, /* @__PURE__ */ new Map()), this.mergeInfo.get(t).set(e, i);
}
getMergeInfo(t, e) {
var i;
return (i = this.mergeInfo.get(t)) == null ? void 0 : i.get(e);
}
clearMergeInfo() {
this.mergeInfo.clear();
}
getHandlerColumn() {
let t = 0;
return this.context.store.getOptionManager().getOptions().selection.enabled && (t += 40), this.context.store.getDataManager().dataLevel > 0 && this.context.store.getOptionManager().getOptions().expand.show && (t += 40), {
label: "",
level: 1,
maxLevel: 1,
column: {
field: "",
resizable: !1,
align: "left",
headerAlign: "left",
customStyle: {
paddingLeft: this.context.store.getOptionManager().getOptions().expand.show ? "8px" : 0
},
headerRender: () => this.context.store.getOptionManager().getOptions().selection.enabled ? new Lt(this.context).getElement() : null,
ellipsis: !1
},
children: [],
path: [],
key: Tt,
isLeaf: !0,
width: t
};
}
isMultiHeader() {
return this.columns.some((t) => t.maxLevel > 1);
}
collapse() {
this.collapseTable = !this.collapseTable, this.context.event.emit(k.TOGGLE_COLLAPSE);
}
isCollapsed() {
return this.collapseTable;
}
}
const tt = class tt {
// ==================== 构造函数和基础设置 ====================
constructor(t, e) {
// ==================== 核心数据结构 ====================
/** 原始连线数据集合 */
a(this, "links", []);
/** 以起点任务 id 为 key 的出边邻接表 */
a(this, "fromLinksMap", /* @__PURE__ */ new Map());
/** 以终点任务 id 为 key 的入边邻接表 */
a(this, "toLinksMap", /* @__PURE__ */ new Map());
// ==================== 缓存系统(简化版) ====================
/** 拓扑序(无环情况下才有效,懒计算) */
a(this, "topoOrder", null);
/** 节点 id -> 拓扑序索引 */
a(this, "topoIndex", /* @__PURE__ */ new Map());
/** 最近一次全量环检测报告 */
a(this, "lastCycleReport", null);
/** 直接连接关系缓存(轻量级) */
a(this, "directConnectionCache", /* @__PURE__ */ new Map());
/** 记忆化缓存(用于链路查询优化) */
a(this, "forwardMemo", /* @__PURE__ */ new Map());
a(this, "backwardMemo", /* @__PURE__ */ new Map());
// ==================== 增强缓存系统 ====================
/** 缓存依赖关系追踪 */
a(this, "cacheDependencies", /* @__PURE__ */ new Map());
/** 缓存访问频率统计 */
a(this, "cacheAccessStats", /* @__PURE__ */ new Map());
/** 缓存大小限制 */
a(this, "MAX_CACHE_SIZE", 1e3);
/** 缓存生存时间(毫秒) */
a(this, "CACHE_TTL", 5 * 60 * 1e3);
// 5分钟
// ==================== 配置选项 ====================
/** 是否启用环检测 */
a(this, "enableCycleDetection", !0);
this.store = t, this.event = e;
}
/** 开启/关闭环检测 */
setCycleDetection(t) {
this.enableCycleDetection = !!t;
}
// ==================== 核心数据管理 ====================
/** 获取所有连线 */
getLinks() {
return this.links;
}
/** 获取某个任务ID的连线 */
getLinksByTaskId(t) {
return this.links.filter((e) => e.from === t || e.to === t);
}
/** 批量设置连线(唯一的数据修改入口) */
setLinks(t, e = !1) {
const i = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set();
this.links.forEach((r) => {
i.add(r.from), i.add(r.to);
}), t.forEach((r) => {
s.add(r.from), s.add(r.to);
});
const n = Array.from(/* @__PURE__ */ new Set([...i, ...s]));
let o = "BATCH";
this.links.length === 0 ? o = "ADD" : t.length === 0 ? o = "REMOVE" : Math.abs(t.length - this.links.length) === 1 && (o = t.length > this.links.length ? "ADD" : "REMOVE"), this.links = t || [], this.rebuildAdjacency(), this.invalidateSmartCaches(n, o), e && this.enableCycleDetection ? this.detectAllCycles() : this.lastCycleReport = null;
}
/** 更新各种缓存配置 */
update() {
this.setLinks(this.links, !0);
}
/** 检查连线是否存在 */
isLinkExist(t, e, i) {
return this.links.some(
(s) => s.from === t && s.to === e && (s.type || "FS") === (i || "FS")
);
}
// ==================== 连线类型系统 ====================
/** 校验连线类型是否合法 */
validateLinkType(t) {
return Object.keys(tt.LINK_TYPE_MAP).includes(t);
}
/** 将起止点转换为连线类型 */
convertPointsToLinkType(t, e) {
return `${t}${e}`;
}
// =