vxe-gantt
Version:
A vue based gantt component
950 lines • 96.2 kB
JavaScript
import { h, ref, reactive, nextTick, inject, onBeforeUnmount, provide, computed, onMounted, onUnmounted } from 'vue';
import { defineVxeComponent } from '../../ui/src/comp';
import { setScrollTop, setScrollLeft, removeClass, addClass, hasClass } from '../../ui/src/dom';
import { VxeUI } from '@vxe-ui/core';
import { getRefElem, getStandardGapTime, getTaskBarLeft, getTaskBarWidth, hasMilestoneTask, getTaskType, hasSubviewTask } from './util';
import XEUtils from 'xe-utils';
import GanttViewHeaderComponent from './gantt-header';
import GanttViewBodyComponent from './gantt-body';
import GanttViewFooterComponent from './gantt-footer';
const { globalEvents } = VxeUI;
const sourceType = 'gantt';
const secondMs = 1000;
const minuteMs = 1000 * 60;
const hourMs = 1000 * 60 * 60;
const dayMs = hourMs * 24;
function createInternalData() {
return {
xeTable: null,
visibleColumn: [],
startMaps: {},
endMaps: {},
chartMaps: {},
todayDateMaps: {},
elemStore: {},
// 存放横向 X 虚拟滚动相关的信息
scrollXStore: {
preloadSize: 0,
offsetSize: 0,
visibleSize: 0,
visibleStartIndex: 0,
visibleEndIndex: 0,
startIndex: 0,
endIndex: 0
},
// 最后滚动位置
lastScrollTop: 0,
lastScrollLeft: 0
};
}
function createReactData() {
return {
// 是否启用了横向 X 可视渲染方式加载
scrollXLoad: false,
// 是否启用了纵向 Y 可视渲染方式加载
scrollYLoad: false,
// 是否存在纵向滚动条
overflowY: true,
// 是否存在横向滚动条
overflowX: true,
// 纵向滚动条的宽度
scrollbarWidth: 0,
// 横向滚动条的高度
scrollbarHeight: 0,
// 最后滚动时间戳
lastScrollTime: 0,
lazScrollLoading: false,
scrollVMLoading: false,
scrollYHeight: 0,
scrollYTop: 0,
isScrollYBig: false,
scrollXLeft: 0,
scrollXWidth: 0,
isScrollXBig: false,
minViewDate: null,
maxViewDate: null,
tableData: [],
tableColumn: [],
headerGroups: [],
viewCellWidth: 40
};
}
const maxYHeight = 5e6;
// const maxXWidth = 5e6
export default defineVxeComponent({
name: 'VxeGanttView',
setup(props, context) {
const xID = XEUtils.uniqueId();
const $xeGantt = inject('$xeGantt', {});
const { reactData: ganttReactData, internalData: ganttInternalData } = $xeGantt;
const { computeDateFormat, computeTaskViewOpts, computeStartField, computeEndField, computeTypeField, computeScrollbarOpts, computeScrollbarXToTop, computeScrollbarYToLeft, computeScaleUnit, computeWeekScale, computeMinScale, computeTaskNowLineOpts, computeScaleStep } = $xeGantt.getComputeMaps();
const refElem = ref();
const refScrollXVirtualElem = ref();
const refScrollYVirtualElem = ref();
const refScrollXHandleElem = ref();
const refScrollXLeftCornerElem = ref();
const refScrollXRightCornerElem = ref();
const refScrollYHandleElem = ref();
const refScrollYTopCornerElem = ref();
const refScrollXWrapperElem = ref();
const refScrollYWrapperElem = ref();
const refScrollYBottomCornerElem = ref();
const refScrollXSpaceElem = ref();
const refScrollYSpaceElem = ref();
const refColInfoElem = ref();
const reactData = reactive(createReactData());
const internalData = createInternalData();
const refMaps = {
refElem,
refScrollXHandleElem,
refScrollYHandleElem
};
const computeScaleDateList = computed(() => {
const { minViewDate, maxViewDate } = reactData;
const taskViewOpts = computeTaskViewOpts.value;
const minScale = computeMinScale.value;
const scaleStep = computeScaleStep.value;
const { gridding } = taskViewOpts;
const dateList = [];
if (!minScale || !minViewDate || !maxViewDate) {
return dateList;
}
const { type, startDay } = minScale;
const leftSize = -(ganttReactData.currLeftSpacing + XEUtils.toNumber(gridding ? gridding.leftSpacing || 0 : 0));
const rightSize = ganttReactData.currRightSpacing + XEUtils.toNumber(gridding ? gridding.rightSpacing || 0 : 0);
switch (type) {
case 'year': {
let currDate = XEUtils.getWhatYear(minViewDate, leftSize, 'first');
const endDate = XEUtils.getWhatYear(maxViewDate, rightSize, 'first');
while (currDate <= endDate) {
const itemDate = currDate;
dateList.push(itemDate);
currDate = XEUtils.getWhatYear(currDate, scaleStep);
}
break;
}
case 'quarter': {
let currDate = XEUtils.getWhatQuarter(minViewDate, leftSize, 'first');
const endDate = XEUtils.getWhatQuarter(maxViewDate, rightSize, 'first');
while (currDate <= endDate) {
const itemDate = currDate;
dateList.push(itemDate);
currDate = XEUtils.getWhatQuarter(currDate, scaleStep);
}
break;
}
case 'month': {
let currDate = XEUtils.getWhatMonth(minViewDate, leftSize, 'first');
const endDate = XEUtils.getWhatMonth(maxViewDate, rightSize, 'first');
while (currDate <= endDate) {
const itemDate = currDate;
dateList.push(itemDate);
currDate = XEUtils.getWhatMonth(currDate, scaleStep);
}
break;
}
case 'week': {
let currDate = XEUtils.getWhatWeek(minViewDate, leftSize, startDay, startDay);
const endDate = XEUtils.getWhatWeek(maxViewDate, rightSize, startDay, startDay);
while (currDate <= endDate) {
const itemDate = currDate;
dateList.push(itemDate);
currDate = XEUtils.getWhatWeek(currDate, scaleStep);
}
break;
}
case 'day':
case 'date': {
let currDate = XEUtils.getWhatDay(minViewDate, leftSize, 'first');
const endDate = XEUtils.getWhatDay(maxViewDate, rightSize, 'first');
while (currDate <= endDate) {
const itemDate = currDate;
dateList.push(itemDate);
currDate = XEUtils.getWhatDay(currDate, scaleStep);
}
break;
}
case 'hour':
case 'minute':
case 'second': {
const gapTime = getStandardGapTime(minScale.type) * scaleStep;
let currTime = minViewDate.getTime() + (leftSize * gapTime);
const endTime = maxViewDate.getTime() + (rightSize * gapTime);
while (currTime <= endTime) {
const itemDate = new Date(currTime);
dateList.push(itemDate);
currTime += gapTime;
}
break;
}
}
return dateList;
});
const computeNowLineLeft = computed(() => {
const ganttReactData = $xeGantt.reactData;
const { minViewDate, maxViewDate, viewCellWidth } = reactData;
const { visibleColumn, todayDateMaps } = internalData;
const minScale = computeMinScale.value;
const taskViewOpts = computeTaskViewOpts.value;
const taskNowLineOpts = computeTaskNowLineOpts.value;
const { showNowLine } = taskViewOpts;
const { mode } = taskNowLineOpts;
const { nowTime } = ganttReactData;
// 此刻线
let nlLeft = 0;
if (showNowLine && minScale && minViewDate && maxViewDate && nowTime >= minViewDate.getTime() && nowTime <= maxViewDate.getTime()) {
const todayValue = todayDateMaps[minScale.type];
let currCol = null;
let nextCol = null;
for (let i = 0; i < visibleColumn.length; i++) {
const column = visibleColumn[i];
if (column.field === todayValue) {
currCol = column;
nlLeft = i * viewCellWidth;
nextCol = visibleColumn[i + 1];
break;
}
}
if (mode === 'progress') {
if (currCol && nextCol) {
const currTime = currCol.dateObj.date.getTime();
const offsetTime = nowTime - currTime;
const nowProgress = Math.max(0, Math.min(1, offsetTime / (nextCol.dateObj.date.getTime() - currTime)));
nlLeft += nowProgress * viewCellWidth;
}
}
else if (mode === 'center') {
nlLeft += viewCellWidth / 2;
}
else if (mode === 'end') {
nlLeft += viewCellWidth - 1;
}
}
return nlLeft;
});
const computeMaps = {
computeScaleDateList,
computeNowLineLeft
};
const $xeGanttView = {
xID,
props,
context,
reactData,
internalData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps
};
const parseStringDate = (dateValue) => {
const dateFormat = computeDateFormat.value;
return XEUtils.toStringDate(dateValue, dateFormat);
};
const updateTodayData = () => {
const ganttReactData = $xeGantt.reactData;
const { taskScaleList } = ganttReactData;
const minScale = computeMinScale.value;
if (minScale) {
const weekScale = taskScaleList.find(item => item.type === 'week');
const isMinWeek = minScale.type === 'week';
const itemDate = new Date();
let [yyyy, M, MM, dd, HH, mm, ss] = XEUtils.toDateString(itemDate, 'yyyy-M-MM-dd-HH-mm-ss').split('-');
const e = itemDate.getDay();
const E = e + 1;
const q = Math.ceil((itemDate.getMonth() + 1) / 3);
const W = `${XEUtils.getYearWeek(itemDate, weekScale ? weekScale.startDay : undefined)}`;
if (isMinWeek && checkWeekOfsetYear(W, M)) {
yyyy = `${Number(yyyy) + 1}`;
M = '1';
MM = '0' + M;
}
ganttReactData.nowTime = itemDate.getTime();
internalData.todayDateMaps = {
year: yyyy,
quarter: `${yyyy}_q${q}`,
month: `${yyyy}_${MM}`,
week: `${yyyy}_W${W}`,
day: `${yyyy}_${MM}_${dd}_E${E}`,
date: `${yyyy}_${MM}_${dd}`,
hour: `${yyyy}_${MM}_${dd}_${HH}`,
minute: `${yyyy}_${MM}_${dd}_${HH}_${mm}`,
second: `${yyyy}_${MM}_${dd}_${HH}_${mm}_${ss}`
};
}
};
const handleColumnHeader = () => {
const ganttReactData = $xeGantt.reactData;
const { taskScaleList } = ganttReactData;
const scaleUnit = computeScaleUnit.value;
const minScale = computeMinScale.value;
const weekScale = computeWeekScale.value;
const scaleDateList = computeScaleDateList.value;
const fullCols = [];
const groupCols = [];
if (minScale && scaleUnit && scaleDateList.length) {
const renderListMaps = {
year: [],
quarter: [],
month: [],
week: [],
day: [],
date: [],
hour: [],
minute: [],
second: []
};
const tempTypeMaps = {
year: {},
quarter: {},
month: {},
week: {},
day: {},
date: {},
hour: {},
minute: {},
second: {}
};
const isMinWeek = minScale.type === 'week';
const handleData = (type, colMaps, minCol) => {
if (minScale.type === type) {
return;
}
const currCol = colMaps[type];
const currKey = `${currCol.field}`;
let currGpCol = tempTypeMaps[type][currKey];
if (!currGpCol) {
currGpCol = currCol;
tempTypeMaps[type][currKey] = currGpCol;
renderListMaps[type].push(currGpCol);
}
if (currGpCol) {
if (!currGpCol.children) {
currGpCol.children = [];
}
currGpCol.children.push(minCol);
}
};
for (let i = 0; i < scaleDateList.length; i++) {
const itemDate = scaleDateList[i];
let [yy, yyyy, M, MM, d, dd, H, HH, m, mm, s, ss] = XEUtils.toDateString(itemDate, 'yy-yyyy-M-MM-d-dd-H-HH-m-mm-s-ss').split('-');
const e = itemDate.getDay();
const E = e + 1;
const q = Math.ceil((itemDate.getMonth() + 1) / 3);
const W = `${XEUtils.getYearWeek(itemDate, weekScale ? weekScale.startDay : undefined)}`;
const WW = XEUtils.padStart(W, 2, '0');
if (isMinWeek && checkWeekOfsetYear(W, M)) {
yyyy = `${Number(yyyy) + 1}`;
M = '1';
MM = '0' + M;
}
const dateObj = { date: itemDate, yy, yyyy, M, MM, d, dd, H, HH, m, mm, s, ss, q, W, WW, E, e };
const colMaps = {
year: {
field: yyyy,
title: yyyy,
dateObj
},
quarter: {
field: `${yyyy}_q${q}`,
title: `${q}`,
dateObj
},
month: {
field: `${yyyy}_${MM}`,
title: MM,
dateObj
},
week: {
field: `${yyyy}_W${W}`,
title: `${W}`,
dateObj
},
day: {
field: `${yyyy}_${MM}_${dd}_E${E}`,
title: `${E}`,
dateObj
},
date: {
field: `${yyyy}_${MM}_${dd}`,
title: dd,
dateObj
},
hour: {
field: `${yyyy}_${MM}_${dd}_${HH}`,
title: HH,
dateObj
},
minute: {
field: `${yyyy}_${MM}_${dd}_${HH}_${mm}`,
title: mm,
dateObj
},
second: {
field: `${yyyy}_${MM}_${dd}_${HH}_${mm}_${ss}`,
title: ss,
dateObj
}
};
const minCol = colMaps[minScale.type];
if (minScale.level < 19) {
handleData('year', colMaps, minCol);
}
if (minScale.level < 17) {
handleData('quarter', colMaps, minCol);
}
if (minScale.level < 15) {
handleData('month', colMaps, minCol);
}
if (minScale.level < 13) {
handleData('week', colMaps, minCol);
}
if (minScale.level < 11) {
handleData('day', colMaps, minCol);
}
if (minScale.level < 9) {
handleData('date', colMaps, minCol);
}
if (minScale.level < 7) {
handleData('hour', colMaps, minCol);
}
if (minScale.level < 5) {
handleData('minute', colMaps, minCol);
}
if (minScale.level < 3) {
handleData('second', colMaps, minCol);
}
fullCols.push(minCol);
}
taskScaleList.forEach(scaleItem => {
if (scaleItem.type === minScale.type) {
groupCols.push({
scaleItem,
columns: fullCols
});
return;
}
const list = renderListMaps[scaleItem.type] || [];
if (list) {
list.forEach(item => {
item.childCount = item.children ? item.children.length : 0;
item.children = undefined;
});
}
groupCols.push({
scaleItem,
columns: list
});
});
}
return {
fullCols,
groupCols
};
};
/**
* 判断周的年份是否跨年
*/
const checkWeekOfsetYear = (W, M) => {
return `${W}` === '1' && `${M}` === '12';
};
/**
* 周维度,由于年份和第几周是冲突的行为,所以需要特殊处理,判断是否跨年,例如
* '2024-12-31' 'yyyy-MM-dd W' >> '2024-12-31 1'
* '2025-01-01' 'yyyy-MM-dd W' >> '2025-01-01 1'
*/
const parseWeekObj = (date, firstDay) => {
const currDate = XEUtils.toStringDate(date);
let yyyy = currDate.getFullYear();
const month = currDate.getMonth();
const weekNum = XEUtils.getYearWeek(currDate, firstDay);
if (checkWeekOfsetYear(weekNum, month + 1)) {
yyyy++;
}
return {
yyyy,
W: weekNum
};
};
const createChartRender = (fullCols) => {
const minScale = computeMinScale.value;
const scaleStep = computeScaleStep.value;
const scaleUnit = computeScaleUnit.value;
const weekScale = computeWeekScale.value;
const dateFormat = computeDateFormat.value;
if (minScale) {
const currRatio = scaleStep > 1 ? 1 / scaleStep : 0;
switch (scaleUnit) {
case 'year': {
const showActualProgress = /M|d|H|m|s|S/.test(dateFormat);
const renderFormat = 'yyyy';
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = XEUtils.toDateString(dateObj.date, 'yyyy');
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const currStr = XEUtils.toDateString(XEUtils.getWhatYear(dateObj.date, scaleStep - currStep), renderFormat);
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startStr = XEUtils.toDateString(startValDate, renderFormat);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatYear(startValDate, 0, 'first');
const startFirstDate = XEUtils.getWhatYear(startValDate, 0, 'first');
const endStr = XEUtils.toDateString(endValDate, renderFormat);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatYear(endValDate, 0, 'last');
const endFirstDate = XEUtils.getWhatYear(endDate, 0, 'first');
// 当前是年维度,当指定解析格式精确到天时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
// 按年的天数比计算
const syDaySize = XEUtils.getDayOfYear(startDate, 0);
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / dayMs / syDaySize;
const eyDaySize = XEUtils.getDayOfYear(endDate, 0);
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / dayMs / eyDaySize;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
case 'quarter': {
const showActualProgress = /M|d|H|m|ss|S/.test(dateFormat);
const renderFormat = 'yyyy-q';
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = XEUtils.toDateString(dateObj.date, renderFormat);
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const currStr = XEUtils.toDateString(XEUtils.getWhatQuarter(dateObj.date, scaleStep - currStep), renderFormat);
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startStr = XEUtils.toDateString(startValDate, renderFormat);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatQuarter(startValDate, 0, 'first');
const startFirstDate = XEUtils.getWhatQuarter(startValDate, 0, 'first');
const endStr = XEUtils.toDateString(endValDate, renderFormat);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatQuarter(endValDate, 0, 'last');
const endFirstDate = XEUtils.getWhatQuarter(endDate, 0, 'first');
// 当前是季度维度,当指定解析格式精确到天时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
// 按季度天数比计算
const sqDaySize = XEUtils.getDayOfQuarter(startDate, 0);
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / dayMs / sqDaySize;
const eqDaySize = XEUtils.getDayOfQuarter(endDate, 0);
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / dayMs / eqDaySize;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
case 'month': {
const renderFormat = 'yyyy-MM';
const showActualProgress = /d|H|m|ss|S/.test(dateFormat);
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = XEUtils.toDateString(dateObj.date, renderFormat);
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const currStr = XEUtils.toDateString(XEUtils.getWhatMonth(dateObj.date, scaleStep - currStep), renderFormat);
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startStr = XEUtils.toDateString(startValDate, renderFormat);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatMonth(startValDate, 0, 'first');
const startFirstDate = XEUtils.getWhatMonth(startValDate, 0, 'first');
const endStr = XEUtils.toDateString(endValDate, renderFormat);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatMonth(endValDate, 0, 'last');
const endFirstDate = XEUtils.getWhatMonth(endDate, 0, 'first');
// 当前是月维度,当指定解析格式精确到天时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
// 按月天数比计算
const smDaySize = XEUtils.getDayOfMonth(startDate, 0);
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / dayMs / smDaySize;
const emDaySize = XEUtils.getDayOfMonth(endDate, 0);
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / dayMs / emDaySize;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
case 'week': {
const weekStartDay = weekScale ? weekScale.startDay : undefined;
const showActualProgress = /d|H|m|s|S/.test(dateFormat);
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = `${dateObj.yyyy}-${dateObj.W}`;
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const offsetDate = XEUtils.getWhatWeek(dateObj.date, scaleStep - currStep, weekStartDay, weekStartDay);
let [yyyy, M] = XEUtils.toDateString(offsetDate, 'yyyy-M-MM-dd-HH-mm-ss').split('-');
const W = `${XEUtils.getYearWeek(offsetDate, weekScale ? weekScale.startDay : undefined)}`;
if (checkWeekOfsetYear(W, M)) {
yyyy = `${Number(yyyy) + 1}`;
}
const currStr = `${yyyy}-${W}`;
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatWeek(startValDate, 0, 'first', weekStartDay);
const startWeekObj = parseWeekObj(startDate, weekStartDay);
const startStr = `${startWeekObj.yyyy}-${startWeekObj.W}`;
const startFirstDate = XEUtils.getWhatWeek(startDate, 0, 'first', weekStartDay);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatWeek(endValDate, 0, 'first', weekStartDay);
const endWeekObj = parseWeekObj(endDate, weekStartDay);
const endStr = `${endWeekObj.yyyy}-${endWeekObj.W}`;
const endFirstDate = XEUtils.getWhatWeek(endDate, 0, 'first', weekStartDay);
// 当前是周维度,当指定解析格式精确到天时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
// 按周天数比计算
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / dayMs / 7;
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / dayMs / 7;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
case 'day':
case 'date': {
const renderFormat = 'yyyy-MM-dd';
const showActualProgress = /H|m|s|S/.test(dateFormat);
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = XEUtils.toDateString(dateObj.date, renderFormat);
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const currStr = XEUtils.toDateString(XEUtils.getWhatDay(dateObj.date, scaleStep - currStep), renderFormat);
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startStr = XEUtils.toDateString(startValDate, renderFormat);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatDay(startValDate, 0, 'first');
const startFirstDate = XEUtils.getWhatDay(startDate, 0, 'first');
const endStr = XEUtils.toDateString(endValDate, renderFormat);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatDay(endValDate, 0, 'last');
const endFirstDate = XEUtils.getWhatDay(endDate, 0, 'first');
// 当前是天维度,当指定解析格式精确到时分秒豪秒时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / dayMs;
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / dayMs;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
case 'hour': {
const renderFormat = 'yyyy-MM-dd HH';
const showActualProgress = /m|s|S/.test(dateFormat);
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = XEUtils.toDateString(dateObj.date, renderFormat);
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const currStr = XEUtils.toDateString(XEUtils.getWhatHours(dateObj.date, scaleStep - currStep), renderFormat);
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startStr = XEUtils.toDateString(startValDate, renderFormat);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatHours(startValDate, 0, 'first');
const startFirstDate = XEUtils.getWhatHours(startDate, 0, 'first');
const endStr = XEUtils.toDateString(endValDate, renderFormat);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatHours(endValDate, 0, 'last');
const endFirstDate = XEUtils.getWhatHours(endDate, 0, 'first');
// 当前是小时维度,当指定解析格式精确到分秒豪秒时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / hourMs;
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / hourMs;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
case 'minute': {
const renderFormat = 'yyyy-MM-dd HH:mm';
const showActualProgress = /s|S/.test(dateFormat);
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = XEUtils.toDateString(dateObj.date, renderFormat);
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const currStr = XEUtils.toDateString(XEUtils.getWhatMinutes(dateObj.date, scaleStep - currStep), renderFormat);
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startStr = XEUtils.toDateString(startValDate, renderFormat);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatMinutes(startValDate, 0, 'first');
const startFirstDate = XEUtils.getWhatMinutes(startDate, 0, 'first');
const endStr = XEUtils.toDateString(endValDate, renderFormat);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatMinutes(endValDate, 0, 'last');
const endFirstDate = XEUtils.getWhatMinutes(endDate, 0, 'first');
// 当前是分钟维度,当指定解析格式精确到秒豪秒时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / minuteMs;
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / minuteMs;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
case 'second': {
const renderFormat = 'yyyy-MM-dd HH:mm:ss';
const showActualProgress = /S/.test(dateFormat);
const indexMaps = {};
fullCols.forEach(({ dateObj }, i) => {
const currStr = XEUtils.toDateString(dateObj.date, renderFormat);
indexMaps[currStr] = i;
if (currRatio) {
let currStep = scaleStep - 1;
while (currStep) {
const currStr = XEUtils.toDateString(XEUtils.getWhatSeconds(dateObj.date, scaleStep - currStep), renderFormat);
indexMaps[currStr] = i + currRatio;
currStep--;
}
}
});
return (startValue, endValue) => {
const startValDate = parseStringDate(startValue);
const endValDate = parseStringDate(endValue);
const startStr = XEUtils.toDateString(startValDate, renderFormat);
const startDate = showActualProgress ? startValDate : XEUtils.getWhatSeconds(startValDate, 0, 'first');
const startFirstDate = XEUtils.getWhatSeconds(startDate, 0, 'first');
const endStr = XEUtils.toDateString(endValDate, renderFormat);
const endDate = showActualProgress ? endValDate : XEUtils.getWhatSeconds(endValDate, 0, 'last');
const endFirstDate = XEUtils.getWhatSeconds(endDate, 0, 'first');
// 当前是秒维度,当指定解析格式精确到豪秒时,显示实际进度
let startSubtractSize = 0;
let endSubtractSize = 1;
if (showActualProgress) {
startSubtractSize = (startDate.getTime() - startFirstDate.getTime()) / secondMs;
endSubtractSize = (endDate.getTime() - endFirstDate.getTime()) / secondMs;
if (currRatio) {
startSubtractSize *= currRatio;
endSubtractSize *= currRatio;
}
}
const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtractSize;
return {
offsetLeftSize,
offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + endSubtractSize
};
};
}
}
}
return () => {
return {
offsetLeftSize: 0,
offsetWidthSize: 0
};
};
};
const handleParseColumn = () => {
const ganttProps = $xeGantt.props;
const { treeConfig } = ganttProps;
const { minViewDate, maxViewDate } = reactData;
const { fullCols, groupCols } = handleColumnHeader();
if (minViewDate && maxViewDate && fullCols.length) {
const $xeTable = internalData.xeTable;
if ($xeTable) {
const startField = computeStartField.value;
const endField = computeEndField.value;
const typeField = computeTypeField.value;
const { computeAggregateOpts, computeTreeOpts } = $xeTable.getComputeMaps();
const tableReactData = $xeTable.reactData;
const { isRowGroupStatus } = tableReactData;
const tableInternalData = $xeTable.internalData;
const { afterFullData, afterTreeFullData, afterGroupFullData } = tableInternalData;
const aggregateOpts = computeAggregateOpts.value;
const treeOpts = computeTreeOpts.value;
const { transform } = treeOpts;
const childrenField = treeOpts.children || treeOpts.childrenField;
const ctMaps = {};
const renderFn = createChartRender(fullCols);
const handleParseRender = (row) => {
const rowid = $xeTable.getRowid(row);
let startValue = XEUtils.get(row, startField);
let endValue = XEUtils.get(row, endField);
const renderTaskType = getTaskType(XEUtils.get(row, typeField));
const isMilestone = hasMilestoneTask(renderTaskType);
const isSubview = hasSubviewTask(renderTaskType);
if (isMilestone) {
if (!startValue) {
startValue = endValue;
}
endValue = startValue;
}
if (isSubview) {
ctMaps[rowid] = {
row,
rowid,
oLeftSize: 0,
oWidthSize: 0
};
}
else if (startValue && endValue) {
const { offsetLeftSize, offsetWidthSize } = renderFn(startValue, endValue);
ctMaps[rowid] = {
row,
rowid,
oLeftSize: offsetLeftSize,
oWidthSize: offsetWidthSize
};
}
};
if (isRowGroupStatus) {
// 行分组
const mapChildrenField = aggregateOpts.mapChildrenField;
if (mapChildrenField) {
XEUtils.eachTree(afterGroupFullData, handleParseRender, { children: mapChildrenField });
}
}
else if (treeConfig) {
// 树结构
XEUtils.eachTree(afterTreeFullData, handleParseRender, { children: transform ? treeOpts.mapChildrenField : childrenField });
}
else {
afterFullData.forEach(handleParseRender);
}
internalData.chartMaps = ctMaps;
}
}
internalData.visibleColumn = fullCols;
reactData.headerGroups = groupCols;
updateTodayData();
updateScrollXStatus();
handleTableColumn();
};
const handleUpdateData = () => {
const ganttProps = $xeGantt.props;
const { treeConfig } = ganttProps;
const { scrollXStore } = internalData;
const $xeTable = internalData.xeTable;
const sdMaps = {};
const edMaps = {};
let minDate = null;
let maxDate = null;
if ($xeTable) {
const startField = computeStartField.value;
const endField = computeEndField.value;
const typeField = computeTypeField.value;
const { computeAggregateOpts, computeTreeOpts } = $xeTable.getComputeMaps();
const tableReactData = $xeTable.reactData;
const { isRowGroupStatus } = tableReactData;
const tableInternalData = $xeTable.internalData;
const { afterFullData, afterTreeFullData, afterGroupFullData } = tableInternalData;
const aggregateOpts = computeAggregateOpts.value;
const treeOpts = computeTreeOpts.value;
const { transform } = treeOpts;
const childrenField = treeOpts.children || treeOpts.childrenField;
const handleMinMaxData = (row) => {
let startValue = XEUtils.get(row, startField);
let endValue = XEUtils.get(row, endField);
const typeValue = XEUtils.get(row, typeField);
const isMilestone = hasMilestoneTask(typeVal