UNPKG

vxe-gantt

Version:
1,309 lines (1,308 loc) 73.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _vue = require("vue"); var _comp = require("../../ui/src/comp"); var _dom = require("../../ui/src/dom"); var _core = require("@vxe-ui/core"); var _util = require("./util"); var _xeUtils = _interopRequireDefault(require("xe-utils")); var _ganttHeader = _interopRequireDefault(require("./gantt-header")); var _ganttBody = _interopRequireDefault(require("./gantt-body")); var _ganttFooter = _interopRequireDefault(require("./gantt-footer")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const { globalEvents } = _core.VxeUI; const sourceType = 'gantt'; const minuteMs = 1000 * 60; const dayMs = minuteMs * 60 * 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 var _default = exports.default = (0, _comp.defineVxeComponent)({ name: 'VxeGanttView', setup(props, context) { const xID = _xeUtils.default.uniqueId(); const $xeGantt = (0, _vue.inject)('$xeGantt', {}); const { reactData: ganttReactData, internalData: ganttInternalData } = $xeGantt; const { computeTaskOpts, computeTaskViewOpts, computeStartField, computeEndField, computeTypeField, computeScrollbarOpts, computeScrollbarXToTop, computeScrollbarYToLeft, computeScaleUnit, computeWeekScale, computeMinScale, computeTaskNowLineOpts } = $xeGantt.getComputeMaps(); const refElem = (0, _vue.ref)(); const refScrollXVirtualElem = (0, _vue.ref)(); const refScrollYVirtualElem = (0, _vue.ref)(); const refScrollXHandleElem = (0, _vue.ref)(); const refScrollXLeftCornerElem = (0, _vue.ref)(); const refScrollXRightCornerElem = (0, _vue.ref)(); const refScrollYHandleElem = (0, _vue.ref)(); const refScrollYTopCornerElem = (0, _vue.ref)(); const refScrollXWrapperElem = (0, _vue.ref)(); const refScrollYWrapperElem = (0, _vue.ref)(); const refScrollYBottomCornerElem = (0, _vue.ref)(); const refScrollXSpaceElem = (0, _vue.ref)(); const refScrollYSpaceElem = (0, _vue.ref)(); const refColInfoElem = (0, _vue.ref)(); const reactData = (0, _vue.reactive)(createReactData()); const internalData = createInternalData(); const refMaps = { refElem, refScrollXHandleElem, refScrollYHandleElem }; const computeScaleDateList = (0, _vue.computed)(() => { const { minViewDate, maxViewDate } = reactData; const taskViewOpts = computeTaskViewOpts.value; const minScale = computeMinScale.value; const { gridding } = taskViewOpts; const dateList = []; if (!minScale || !minViewDate || !maxViewDate) { return dateList; } const { type, startDay } = minScale; const leftSize = -(ganttReactData.currLeftSpacing + _xeUtils.default.toNumber(gridding ? gridding.leftSpacing || 0 : 0)); const rightSize = ganttReactData.currRightSpacing + _xeUtils.default.toNumber(gridding ? gridding.rightSpacing || 0 : 0); const currStep = 1; // XEUtils.toNumber(step || 1) || 1 switch (type) { case 'year': { let currDate = _xeUtils.default.getWhatYear(minViewDate, leftSize, 'first'); const endDate = _xeUtils.default.getWhatYear(maxViewDate, rightSize, 'first'); while (currDate <= endDate) { const itemDate = currDate; dateList.push(itemDate); currDate = _xeUtils.default.getWhatYear(currDate, currStep); } break; } case 'quarter': { let currDate = _xeUtils.default.getWhatQuarter(minViewDate, leftSize, 'first'); const endDate = _xeUtils.default.getWhatQuarter(maxViewDate, rightSize, 'first'); while (currDate <= endDate) { const itemDate = currDate; dateList.push(itemDate); currDate = _xeUtils.default.getWhatQuarter(currDate, currStep); } break; } case 'month': { let currDate = _xeUtils.default.getWhatMonth(minViewDate, leftSize, 'first'); const endDate = _xeUtils.default.getWhatMonth(maxViewDate, rightSize, 'first'); while (currDate <= endDate) { const itemDate = currDate; dateList.push(itemDate); currDate = _xeUtils.default.getWhatMonth(currDate, currStep); } break; } case 'week': { let currDate = _xeUtils.default.getWhatWeek(minViewDate, leftSize, startDay, startDay); const endDate = _xeUtils.default.getWhatWeek(maxViewDate, rightSize, startDay, startDay); while (currDate <= endDate) { const itemDate = currDate; dateList.push(itemDate); currDate = _xeUtils.default.getWhatWeek(currDate, currStep); } break; } case 'day': case 'date': { let currDate = _xeUtils.default.getWhatDay(minViewDate, leftSize, 'first'); const endDate = _xeUtils.default.getWhatDay(maxViewDate, rightSize, 'first'); while (currDate <= endDate) { const itemDate = currDate; dateList.push(itemDate); currDate = _xeUtils.default.getWhatDay(currDate, currStep); } break; } case 'hour': case 'minute': case 'second': { const gapTime = (0, _util.getStandardGapTime)(minScale.type) * currStep; 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 = (0, _vue.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 taskOpts = computeTaskOpts.value; const { dateFormat } = taskOpts; return _xeUtils.default.toStringDate(dateValue, dateFormat || null); }; 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.default.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.default.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.default.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.default.getYearWeek(itemDate, weekScale ? weekScale.startDay : undefined)}`; const WW = _xeUtils.default.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.default.toStringDate(date); let yyyy = currDate.getFullYear(); const month = currDate.getMonth(); const weekNum = _xeUtils.default.getYearWeek(currDate, firstDay); if (checkWeekOfsetYear(weekNum, month + 1)) { yyyy++; } return { yyyy, W: weekNum }; }; const createChartRender = fullCols => { const { minViewDate } = reactData; const minScale = computeMinScale.value; const scaleUnit = computeScaleUnit.value; const weekScale = computeWeekScale.value; if (minScale) { switch (scaleUnit) { case 'year': { const indexMaps = {}; fullCols.forEach(({ dateObj }, i) => { const yyyyMM = _xeUtils.default.toDateString(dateObj.date, 'yyyy'); indexMaps[yyyyMM] = i; }); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); const startStr = _xeUtils.default.toDateString(startDate, 'yyyy'); const startFirstDate = _xeUtils.default.getWhatYear(startDate, 0, 'first'); const endStr = _xeUtils.default.toDateString(endDate, 'yyyy'); const endFirstDate = _xeUtils.default.getWhatYear(endDate, 0, 'first'); const dateSize = Math.floor((_xeUtils.default.getWhatYear(endDate, 1, 'first').getTime() - endFirstDate.getTime()) / dayMs); const subtract = (startDate.getTime() - startFirstDate.getTime()) / dayMs / dateSize; const addSize = Math.max(0, (endDate.getTime() - endFirstDate.getTime()) / dayMs + 1) / dateSize; const offsetLeftSize = (indexMaps[startStr] || 0) + subtract; return { offsetLeftSize, offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + addSize }; }; } case 'quarter': { const indexMaps = {}; fullCols.forEach(({ dateObj }, i) => { const q = _xeUtils.default.toDateString(dateObj.date, 'yyyy-q'); indexMaps[q] = i; }); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); const startStr = _xeUtils.default.toDateString(startDate, 'yyyy-q'); const startFirstDate = _xeUtils.default.getWhatQuarter(startDate, 0, 'first'); const endStr = _xeUtils.default.toDateString(endDate, 'yyyy-q'); const endFirstDate = _xeUtils.default.getWhatQuarter(endDate, 0, 'first'); const dateSize = Math.floor((_xeUtils.default.getWhatQuarter(endDate, 1, 'first').getTime() - endFirstDate.getTime()) / dayMs); const subtract = (startDate.getTime() - startFirstDate.getTime()) / dayMs / dateSize; const addSize = Math.max(0, (endDate.getTime() - endFirstDate.getTime()) / dayMs + 1) / dateSize; const offsetLeftSize = (indexMaps[startStr] || 0) + subtract; return { offsetLeftSize, offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + addSize }; }; } case 'month': { const indexMaps = {}; fullCols.forEach(({ dateObj }, i) => { const yyyyMM = _xeUtils.default.toDateString(dateObj.date, 'yyyy-MM'); indexMaps[yyyyMM] = i; }); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); const startStr = _xeUtils.default.toDateString(startDate, 'yyyy-MM'); const startFirstDate = _xeUtils.default.getWhatMonth(startDate, 0, 'first'); const endStr = _xeUtils.default.toDateString(endDate, 'yyyy-MM'); const endFirstDate = _xeUtils.default.getWhatMonth(endDate, 0, 'first'); const dateSize = Math.floor((_xeUtils.default.getWhatMonth(endDate, 1, 'first').getTime() - endFirstDate.getTime()) / dayMs); const subtract = (startDate.getTime() - startFirstDate.getTime()) / dayMs / dateSize; const addSize = Math.max(0, (endDate.getTime() - endFirstDate.getTime()) / dayMs + 1) / dateSize; const offsetLeftSize = (indexMaps[startStr] || 0) + subtract; return { offsetLeftSize, offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + addSize }; }; } case 'week': { const indexMaps = {}; fullCols.forEach(({ dateObj }, i) => { const yyyyW = `${dateObj.yyyy}-${dateObj.W}`; indexMaps[yyyyW] = i; }); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); const startWeekObj = parseWeekObj(startDate, weekScale ? weekScale.startDay : undefined); const startStr = `${startWeekObj.yyyy}-${startWeekObj.W}`; const startFirstDate = _xeUtils.default.getWhatWeek(startDate, 0, weekScale ? weekScale.startDay : undefined, weekScale ? weekScale.startDay : undefined); const endWeekObj = parseWeekObj(endDate, weekScale ? weekScale.startDay : undefined); const endStr = `${endWeekObj.yyyy}-${endWeekObj.W}`; const endFirstDate = _xeUtils.default.getWhatWeek(endDate, 0, weekScale ? weekScale.startDay : undefined, weekScale ? weekScale.startDay : undefined); const dateSize = Math.floor((_xeUtils.default.getWhatWeek(endDate, 1, weekScale ? weekScale.startDay : undefined, weekScale ? weekScale.startDay : undefined).getTime() - endFirstDate.getTime()) / dayMs); const subtract = (startDate.getTime() - startFirstDate.getTime()) / dayMs / dateSize; const addSize = Math.max(0, (endDate.getTime() - endFirstDate.getTime()) / dayMs + 1) / dateSize; const offsetLeftSize = (indexMaps[startStr] || 0) + subtract; return { offsetLeftSize, offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + addSize }; }; } case 'day': case 'date': { const indexMaps = {}; fullCols.forEach(({ dateObj }, i) => { const yyyyMM = _xeUtils.default.toDateString(dateObj.date, 'yyyy-MM-dd'); indexMaps[yyyyMM] = i; }); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); const startStr = _xeUtils.default.toDateString(startDate, 'yyyy-MM-dd'); const startFirstDate = _xeUtils.default.getWhatDay(startDate, 0, 'first'); const endStr = _xeUtils.default.toDateString(endDate, 'yyyy-MM-dd'); const endFirstDate = _xeUtils.default.getWhatDay(endDate, 0, 'first'); const minuteSize = Math.floor((_xeUtils.default.getWhatDay(endDate, 1, 'first').getTime() - endFirstDate.getTime()) / minuteMs); // 开始和结束时间是否存在偏移时 const startSubtract = (startDate.getTime() - startFirstDate.getTime()) / minuteMs / minuteSize; const endSubtract = (endDate.getTime() - endFirstDate.getTime()) / minuteMs / minuteSize; const addSize = Math.max(0, (endDate.getTime() - endFirstDate.getTime()) / minuteMs + 1) / minuteSize; const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtract; // 如果最小轴为天,当存在时分秒时,在当前单元格内渲染维度;如果不存在,则填充满单元格 return { offsetLeftSize, offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + addSize + (startSubtract || endSubtract ? 0 : 1) }; }; } case 'hour': { const indexMaps = {}; fullCols.forEach(({ dateObj }, i) => { const yyyyMM = _xeUtils.default.toDateString(dateObj.date, 'yyyy-MM-dd HH'); indexMaps[yyyyMM] = i; }); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); const startStr = _xeUtils.default.toDateString(startDate, 'yyyy-MM-dd HH'); const startFirstDate = _xeUtils.default.getWhatHours(startDate, 0, 'first'); const endStr = _xeUtils.default.toDateString(endDate, 'yyyy-MM-dd HH'); const endFirstDate = _xeUtils.default.getWhatHours(endDate, 0, 'first'); const minuteSize = Math.floor((_xeUtils.default.getWhatHours(endDate, 1, 'first').getTime() - endFirstDate.getTime()) / minuteMs); // 开始和结束时间是否存在偏移时 const startSubtract = (startDate.getTime() - startFirstDate.getTime()) / minuteMs / minuteSize; const endSubtract = (endDate.getTime() - endFirstDate.getTime()) / minuteMs / minuteSize; const addSize = Math.max(0, (endDate.getTime() - endFirstDate.getTime()) / minuteMs + 1) / minuteSize; const offsetLeftSize = (indexMaps[startStr] || 0) + startSubtract; return { offsetLeftSize, offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + addSize + (startSubtract || endSubtract ? 0 : 1) }; }; } case 'minute': { const indexMaps = {}; fullCols.forEach(({ dateObj }, i) => { const yyyyMM = _xeUtils.default.toDateString(dateObj.date, 'yyyy-MM-dd HH:mm'); indexMaps[yyyyMM] = i; }); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); const startStr = _xeUtils.default.toDateString(startDate, 'yyyy-MM-dd HH:mm'); const startFirstDate = _xeUtils.default.getWhatMinutes(startDate, 0, 'first'); const endStr = _xeUtils.default.toDateString(endDate, 'yyyy-MM-dd HH:mm'); const endFirstDate = _xeUtils.default.getWhatMinutes(endDate, 0, 'first'); const minuteSize = Math.floor((_xeUtils.default.getWhatMinutes(endDate, 1, 'first').getTime() - endFirstDate.getTime()) / minuteMs); const subtract = (startDate.getTime() - startFirstDate.getTime()) / minuteMs / minuteSize; const addSize = Math.max(0, (endDate.getTime() - endFirstDate.getTime()) / minuteMs + 1) / minuteSize; const offsetLeftSize = (indexMaps[startStr] || 0) + subtract; return { offsetLeftSize, offsetWidthSize: (indexMaps[endStr] || 0) - offsetLeftSize + addSize }; }; } case 'second': { const gapTime = (0, _util.getStandardGapTime)(minScale.type); return (startValue, endValue) => { const startDate = parseStringDate(startValue); const endDate = parseStringDate(endValue); let offsetLeftSize = 0; let offsetWidthSize = 0; if (minViewDate) { offsetLeftSize = (startDate.getTime() - minViewDate.getTime()) / gapTime; offsetWidthSize = (endDate.getTime() - startDate.getTime()) / gapTime; } return { offsetLeftSize, offsetWidthSize }; }; } } } 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.default.get(row, startField); let endValue = _xeUtils.default.get(row, endField); const renderTaskType = (0, _util.getTaskType)(_xeUtils.default.get(row, typeField)); const isMilestone = (0, _util.hasMilestoneTask)(renderTaskType); const isSubview = (0, _util.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.default.eachTree(afterGroupFullData, handleParseRender, { children: mapChildrenField }); } } else if (treeConfig) { // 树结构 _xeUtils.default.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.default.get(row, startField); let endValue = _xeUtils.default.get(row, endField); const typeValue = _xeUtils.default.get(row, typeField); const isMilestone = (0, _util.hasMilestoneTask)(typeValue); if (!startValue) { startValue = endValue; } if (isMilestone || !endValue) { endValue = startValue; } if (startValue) { const startDate = parseStringDate(startValue); if (!minDate || minDate.getTime() > startDate.getTime()) { minDate = startDate; } } if (endValue) { const endDate = parseStringDate(endValue); if (!maxDate || maxDate.getTime() < endDate.getTime()) { maxDate = endDate; } } }; if (isRowGroupStatus) { // 行分组 const mapChildrenField = aggregateOpts.mapChildrenField; if (mapChildrenField) { _xeUtils.default.eachTree(afterGroupFullData, handleMinMaxData, { children: mapChildrenField }); } } else if (treeConfig) { // 树结构 _xeUtils.default.eachTree(afterTreeFullData, handleMinMaxData, { children: transform ? treeOpts.mapChildrenField : childrenField }); } else { afterFullData.forEach(handleMinMaxData); } } scrollXStore.startIndex = 0; scrollXStore.endIndex = Math.max(1, scrollXStore.visibleSize); reactData.minViewDate = minDate; reactData.maxViewDate = maxDate; internalData.startMaps = sdMaps; internalData.endMaps = edMaps; handleParseColumn(); }; const calcScrollbar = () => { const { scrollXWidth, scrollYHeight } = reactData; const { elemStore } = internalData; const scrollbarOpts = computeScrollbarOpts.value; const bodyWrapperElem = (0, _util.getRefElem)(elemStore['main-body-wrapper']); const xHandleEl = refScrollXHandleElem.value; const yHandleEl = refScrollYHandleElem.value; let overflowY = false; let overflowX = false; if (bodyWrapperElem) { overflowY = scrollYHeight > bodyWrapperElem.clientHeight; if (yHandleEl) { reactData.scrollbarWidth = scrollbarOpts.width || yHandleEl.offsetWidth - yHandleEl.clientWidth || 14; } reactData.overflowY = overflowY; overflowX = scrollXWidth > bodyWrapperElem.clientWidth; if (xHandleEl) { reactData.scrollbarHeight = scrollbarOpts.height || xHandleEl.offsetHeight - xHandleEl.clientHeight || 14; } reactData.overflowX = overflowX; } }; const handleSubTaskMinMaxSize = ($xeTable, list) => { const { chartMaps } = internalData; const { computeTreeOpts } = $xeTable.getComputeMaps(); const treeOpts = computeTreeOpts.value; const childrenField = treeOpts.children || treeOpts.childrenField; const typeField = computeTypeField.value; let minChildLeftSize = 0; let maxChildLeftSize = 0; _xeUtils.default.eachTree(list, childRow => { const childRowid = $xeTable.getRowid(childRow); const renderTaskType = _xeUtils.default.get(childRow, typeField); if ((0, _util.hasSubviewTask)(renderTaskType)) { return; } const childChartRest = childRowid ? chartMaps[childRowid] : null; if (childChartRest) { maxChildLeftSize = Math.max(maxChildLeftSize, childChartRest.oLeftSize + childChartRest.oWidthSize); minChildLeftSize = minChildLeftSize ? Math.min(minChildLeftSize, childChartRest.oLeftSize) : childChartRest.oLeftSize; } }, { children: childrenField }); return { minSize: minChildLeftSize, maxSize: maxChildLeftSize }; }; const updateTaskChartStyle = () => { const { dragBarRow } = ganttInternalData; const { viewCellWidth } = reactData; const { elemStore, chartMaps } = internalData; const $xeTable = internalData.xeTable; const chartWrapper = (0, _util.getRefElem)(elemStore['main-chart-task-wrapper']); if (chartWrapper && $xeTable) { const { computeTreeOpts } = $xeTable.getComputeMaps(); const treeOpts = computeTreeOpts.value; const childrenField = treeOpts.children || treeOpts.childrenField; _xeUtils.default.arrayEach(chartWrapper.children, rowEl => { const barEl = rowEl.children[0]; if (!barEl) { return; } const rowid = rowEl.getAttribute('rowid'); if (dragBarRow && $xeTable.getRowid(dragBarRow) === rowid) { return; } const chartRest = rowid ? chartMaps[rowid] : null; const row = chartRest ? chartRest.row : null; // 子任务视图 if ((0, _dom.hasClass)(barEl, 'is--subview')) { const childWrapperEl = barEl.firstElementChild; if (childWrapperEl) { // 行内展示 if ((0, _dom.hasClass)(childWrapperEl, 'is--inline')) { _xeUtils.default.arrayEach(childWrapperEl.children, childRowEl => { const childBarEl = childRowEl.children[0]; const childRowid = childBarEl.getAttribute('rowid') || ''; const childChartRest = childRowid ? chartMaps[childRowid] : null; if (childChartRest) { const childRow = childChartRest.row; // 如果是子视图 if ((0, _dom.hasClass)(childBarEl, 'is--subview')) { const subChildren = childRow[childrenField]; const { minSize: minChildLeftSize, maxSize: maxChildLeftSize } = handleSubTaskMinMaxSize($xeTable, subChildren); childBarEl.style.left = `${viewCellWidth * minChildLeftSize}px`; childBarEl.style.width = `${viewCellWidth * (maxChildLeftSize - minChildLeftSize)}px`; } else { childBarEl.style.left = `${(0, _util.getTaskBarLeft)(childChartRest, viewCellWidth)}px`; if (!(0, _dom.hasClass)(childBarEl, 'is--milestone')) { // 里程碑不需要宽度 childBarEl.style.width = `${(0, _util.getTaskBarWidth)(childChartRest, viewCellWidth)}px`; } } } }); } else { // 如果展开子任务 const childRowEl = childWrapperEl.children[0]; const childBarEl = childRowEl ? childRowEl.children[0] : null; if (childBarEl) { const rowChildren = row ? row[childrenField] : []; const { minSize: minChildLeftSize, maxSize: maxChildLeftSize } = handleSubTaskMinMaxSize($xeTable, rowChildren); childBarEl.style.left = `${viewCellWidth * minChildLeftSize}px`; childBarEl.style.width = `${viewCellWidth * (maxChildLeftSize - minChildLeftSize)}px`; } } } } else { barEl.style.left = `${(0, _util.getTaskBarLeft)(chartRest, viewCellWidth)}px`; // 里程碑不需要宽度 if (!(0, _dom.hasClass)(barEl, 'is--milestone')) { barEl.style.width = `${(0, _util.getTaskBarWidth)(chartRest, viewCellWidth)}px`; } } }); } return (0, _vue.nextTick)(); }; const updateStyle = () => { const { scrollbarWidth, scrollbarHeight, headerGroups, tableColumn } = reactData; const { elemStore, visibleColumn } = internalData; const $xeTable = internalData.xeTable; const el = refElem.value; if (!el) { return; } if (!$xeGantt) { return; } const scrollbarOpts = computeScrollbarOpts.value; const scrollbarXToTop = computeScrollbarXToTop.value; const scrollbarYToLeft = computeScrollbarYToLeft.value; const xLeftCornerEl = refScrollXLeftCornerElem.value; const xRightCornerEl = refScrollXRightCornerElem.value; const scrollXVirtualEl = refScrollXVirtualElem.value; let osbWidth = scrollbarWidth; const osbHeight = scrollbarHeight; let tbHeight = 0; let tHeaderHeight = 0; let tFooterHeight = 0; if ($xeTable) { const tableInternalData = $xeTable.internalData; tbHeight = tableInternalData.tBodyHeight; tHeaderHeight = tableInternalData.tHeaderHeight; tFooterHeight = tableInternalData.tFooterHeight; } let yScrollbarVisible = 'visible'; if (scrollbarYToLeft || scrollbarOpts.y && scrollbarOpts.y.visible === false) { osbWidth = 0; yScrollbarVisible = 'hidden'; } const headerScrollElem = (0, _util.getRefElem)(elemStore['main-header-scroll']); if (headerScrollElem) { headerScrollElem.style.height = `${tHeaderHeight}px`; headerScrollElem.style.setProperty('--vxe-ui-gantt-view-cell-height', `${tHeaderHeight / headerGroups.length}px`); } const bodyScrollElem = (0, _util.getRefElem)(elemStore['main-body-scroll']); if (bodyScrollElem) { bodyScrollElem.style.height = `${tbHeight}px`; } const footerScrollElem = (0, _util.getRefElem)(elemStore['main-footer-scroll']); if (footerScrollElem) { footerScrollElem.style.height = `${tFooterHeight}px`; } if (scrollXVirtualEl) { scrollXVirtualEl.style.height = `${osbHeight}px`; scrollXVirtualEl.style.visibility = 'visible'; } const xWrapperEl = refScrollXWrapperElem.value; if (xWrapperEl) { xWrapperEl.style.left = scrollbarXToTop ? `${osbWidth}px` : ''; xWrapperEl.style.width = `${el.clientWidth - osbWidth}px`; } if (xLeftCornerEl) { xLeftCornerEl.style.width = scrollbarXToTop ? `${osbWidth}px` : ''; xLeftCornerEl.style.display = scrollbarXToTop ? osbHeight ? 'block' : '' : ''; } if (xRightCornerEl) { xRightCornerEl.style.width = scrollbarXToTop ? '' : `${osbWidth}px`; xRightCornerEl.style.display = scrollbarXToTop ? '' : osbHeight ? 'block' : ''; } const scrollYVirtualEl = refScrollYVirtualElem.value; if (scrollYVirtualEl) { scrollYVirtualEl.style.width = `${osbWidth}px`; scrollYVirtualEl.style.height = `${tbHeight + tHeaderHeight + tFooterHeight}px`; scrollYVirtualEl.style.visibility = yScrollbarVisible; } const yTopCornerEl = refScrollYTopCornerElem.value; if (yTopCornerEl) { yTopCornerEl.style.height = `${tHeaderHeight}px`; yTopCornerEl.style.display = tHeaderHeight ? 'block' : ''; } const yWrapperEl = refScrollYWrapperElem.value; if (yWrapperEl) { yWrapperEl.style.height = `${tbHeight}px`; yWrapperEl.style.top = `${tHeaderHeight}px`; } const yBottomCornerEl = refScrollYBottomCornerElem.value; if (yBottomCornerEl) { yBottomCornerEl.style.height = `${tFooterHeight}px`; yBottomCornerEl.style.top = `${tHeaderHeight + tbHeight}px`; yBottomCornerEl.style.display = tFooterHeight ? 'block' : ''; } const colInfoElem = refColInfoElem.value; let viewCellWidth = 40; if (colInfoElem) { viewCellWidth = colInfoElem.clientWidth || 40; } let viewTableWidth = viewCellWidth; if (visibleColumn.length) { viewTableWidth = Math.max(0, viewCellWidth * visibleColumn.length); if (bodyScrollElem) { const viewWidth = bodyScrollElem.clientWidth; const remainWidth = viewWidth - viewTableWidth; if (remainWidth > 0) { viewCellWidth += Math.max(0, remainWidth / visibleColumn.length); viewTableWidth = viewWidth; } } } reactData.viewCellWidth = viewCellWidth; const headerTableElem = (0, _util.getRefElem)(elemStore['main-header-table']); const bodyTableElem = (0, _util.getRefElem)(elemStore['main-body-table']); const vmTableWidth = viewCellWidth * tableColumn.length; if (headerTableElem) { headerTableElem.style.width = `${viewTableWidth}px`; } if (bodyTableElem) { bodyTableElem.style.width = `${vmTableWidth}px`; } reactData.scrollXWidth = viewTableWidth; return Promise.all([updateTaskChartStyle(), $xeGantt.handleUpdateTaskLinkStyle ? $xeGantt.handleUpdateTaskLinkStyle($xeGanttView) : null]); }; const handleRecalculateStyle = () => { const el = refElem.value; internalData.rceRunTime = Date.now(); if (!el || !el.clientWidth) { return (0, _vue.nextTick)(); } if (!$xeGantt) { return (0, _vue.nextTick)(); } calcScrollbar(); updateStyle(); return computeScrollLoad(); }; const handleLazyRecalculate = () => { return new Promise(resolve => { const { rceTimeout, rceRunTime } = internalData; const $xeTable = internalData.xeTable; let refreshDelay = 30; if ($xeTable) { const { computeResizeOpts } = $xeTable.getComputeMaps(); const resizeOpts = computeResizeOpts.value; refreshDelay = resizeOpts.refreshDelay || refreshDelay; } if (rceTimeout) { clearTimeout(rceTimeout); if (rceRunTime && rceRunTime + (refreshDelay - 5) < Date.now()) { resolve(handleRecalculateStyle()); } else { (0, _vue.nextTick)(() => { resolve(); }); } } else { resolve(handleRecalculateStyle()); } internalData.rceTimeout = setTimeout(() => { internalData.rceTimeout = undefined; handleRecalculateStyle(); }, refreshDelay); }); }; const computeScrollLoad = () => { return (0, _vue.nextTick)().then(() => { const { scrollXLoad } = reactData; const { scrollXStore } = internalData; // 计算 X 逻辑 if (scrollXLoad) { const { toVisibleIndex: toXVisibleIndex, visibleSize: visibleXSize } = handleVirtualXVisible(); const offsetXSize = 2; scrollXStore.preloadSize = 1; scrollXStore.offsetSize = offsetXSize; scrollXStore.visibleSize = visibleXSize; scrollXStore.endIndex = Math.max(scrollXStore.startIndex + scrollXStore.visibleSize + offsetXSize, scrollXStore.endIndex); scrollXStore.visibleStartIndex = Math.max(scrollXStore.startIndex, toXVisibleIndex); scrollXStore.visibleEndIndex = Math.min(scrollXStore.endIndex, toXVisibleIndex + visibleXSize); updateScrollXData().then(() => { loadScrollXData(); }); } else { updateScrollXSpace(); } }); }; const handleVirtualXVisible = () => { const { viewCellWidth } = reactData; const { elemStore } = internalData; const bodyScrollElem = (0, _util.getRefElem)(elemStore['main-body-scroll']); if (bodyScrollElem) { const clientWidth = bodyScrollElem.clientWidth; const scrollLeft = bodyScrollElem.scrollLeft; const toVisibleIndex = Math.floor(scrollLeft / viewCellWidth) - 1; const visibleSize = Math.ceil(clientWidth / viewCellWidth) + 1; return { toVisibleIndex: Math.max(0, toVisibleIndex), visibleSize: Ma