UNPKG

vxe-gantt

Version:
950 lines 96.2 kB
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