UNPKG

vxe-table-select-area

Version:

一个基于 vxe-table 的可区域选中复制、粘贴的组件

1,590 lines (1,443 loc) 43.3 kB
/* eslint-disable brace-style */ import { PREFIX_CLS, CONTEXTMENU_NODE_TYPES, COLUMN_FIXED_TYPE, AUTOFILLING_DIRECTION } from './constant' import { MOUSE_EVENT_CLICK_TYPE } from '../utils/constant' import { isEmptyValue, isEmptyArray, isFunction } from '../utils/index' // import { getRandomId } from "../../../src/utils/random"; /** * @clsName * @desc get class name * @param {string} cls - class */ export function clsName (cls) { return PREFIX_CLS + cls } /** * @getRowKey * @desc get row key * @param {Object} rowData - rowData * @param {string} rowKeyFieldName - row key field name */ export function getRowKey (rowData, rowKeyFieldName) { let result = null if (rowData && rowKeyFieldName) { result = rowData[rowKeyFieldName] } return result } /** * @getColumnByColkey * @desc get column by col key * @param {string} colKey - column key */ export function getColumnByColkey (colKey, colgroups) { if (colKey) { return colgroups.find((x) => x.key === colKey) } return null } /** * @isLastColumnByColKey * @desc is last column by column key * @param {string} colKey - column key */ export function isLastColumnByColKey (colKey, colgroups) { if (!isEmptyValue(colKey) && !isEmptyArray(colgroups)) { return colgroups[colgroups.length - 1].key === colKey } return false } /** * @isOperationColumn * @desc is operation column * @param {string} colKey - column key * @param {arrat<object>} colgroups - column key */ export function isOperationColumn (colKey, colgroups) { if (!isEmptyValue(colKey) && !isEmptyArray(colgroups)) { const firstCol = colgroups[0] // console.log(72,firstCol) if (firstCol.key === colKey && firstCol.operationColumn) { return true } } return false } /** * @isLastRowByRowKey * @desc is last row by row key * @param {string} rowKey - row key */ export function isLastRowByRowKey (rowKey, allRowKeys) { if (!isEmptyValue(rowKey) && !isEmptyArray(allRowKeys)) { return allRowKeys[allRowKeys.length - 1] === rowKey } return false } /** * @getDomResizeObserverCompKey * @desc get dom resize observer comp key * @param {Any} originalKey - original key * @param {Number} columnsOptionResetTime - columns option change time */ export function getDomResizeObserverCompKey ( originalKey, columnsOptionResetTime ) { let result = originalKey if (result || result === 0) { result = originalKey + '@' + columnsOptionResetTime } return result } /** * @recursiveRemoveColumnByKey * @desc recursive remove column key * @param {object} columns - deep clone column * @param {any} key - column key */ export function recursiveRemoveColumnByKey (columns, key) { return columns.filter((item) => { if ('children' in item) { item.children = recursiveRemoveColumnByKey(item.children, key) } return item.key !== key }) } /** * @getFixedTotalWidthByColumnKey * @desc get fixed total width by column key * @param {object} colgroups - columns info * @param {any} colKey - column key * @param {string} fixed - left|right */ export function getFixedTotalWidthByColumnKey ({ colgroups, colKey, fixed }) { const currentIndex = colgroups.findIndex((x) => x.key === colKey) let result = 0 if (fixed === COLUMN_FIXED_TYPE.LEFT) { // 只计算左列固定的 result = colgroups.reduce((total, currentVal, index) => { return index < currentIndex && // eslint-disable-next-line eqeqeq currentVal.fixed == COLUMN_FIXED_TYPE.LEFT ? currentVal._realTimeWidth + total : total }, 0) } else if (fixed === COLUMN_FIXED_TYPE.RIGHT) { // 只计算右列固定的 result = colgroups.reduce((total, currentVal, index) => { return index > currentIndex && currentVal.fixed === COLUMN_FIXED_TYPE.RIGHT ? currentVal._realTimeWidth + total : total }, 0) } return result } /** * @getNotFixedTotalWidthByColumnKey * @desc get not fixed total width by column key * @param {object} colgroups - 列信息 * @param {any} colKey - column key * @param {string} direction - left|right */ export function getNotFixedTotalWidthByColumnKey ({ colgroups, colKey, fixed }) { const currentIndex = colgroups.findIndex((x) => x.key === colKey) let result = 0 if (fixed === COLUMN_FIXED_TYPE.LEFT) { // 只计算左侧非固定列 result = colgroups.reduce((total, currentVal, index) => { return index < currentIndex && !currentVal.fixed ? currentVal._realTimeWidth + total : total }, 0) } else if (fixed === COLUMN_FIXED_TYPE.RIGHT) { // 只计算右侧非固定列 result = colgroups.reduce((total, currentVal, index) => { return index > currentIndex && !currentVal.fixed ? currentVal._realTimeWidth + total : total }, 0) } return result } /** * @getTotalWidthByColKeys * @desc get total width by collumn keys * @param {array<T>} colKeys * @param {array<object>} colgroups * @return {number} width */ export function getTotalWidthByColKeys ({ colKeys, colgroups }) { const result = colgroups.reduce((total, currentVal, index) => { return colKeys.indexOf(currentVal.key) > -1 ? currentVal._realTimeWidth + total : total }, 0) return result } /** * @initGroupColumns * @desc int group columns * @param {array} cloneColumns - clone columns * @return { isGroupHeader, colgroups, groupColumns } */ export function initGroupColumns (cloneColumns) { const colgroups = [] const groupColumns = [] // set column level let maxLevel = 1 const setColumnLevel = (column, parent) => { if (parent) { column._level = parent._level + 1 if (maxLevel < column._level) { maxLevel = column._level } } if (column.children) { column.children.forEach((item) => { item.fixed = column.fixed setColumnLevel(item, column) }) } } cloneColumns.forEach((column) => { column._level = 1 setColumnLevel(column) }) // set colspan and rowspan and keys const setColspanAndRowspanAndKeys = (column) => { if (column.children) { let keys = '' let colspan = 0 column.children.forEach((item) => { setColspanAndRowspanAndKeys(item) colspan += item._colspan keys += item._keys.endsWith('|') ? item._keys : item._keys + '|' }) column._keys = keys column._colspan = colspan column._rowspan = 1 } else { column._keys = column.key column._colspan = 1 column._rowspan = maxLevel - column._level + 1 } } cloneColumns.forEach((column) => { setColspanAndRowspanAndKeys(column) }) // init groupColumns for (let i = 0; i < maxLevel; i++) { groupColumns.push([]) } // set colgroups and groupColumns const setColgroupsAndGroupColumns = (column) => { // column has children || column key is not empty if (!isEmptyArray(column.children) || !isEmptyValue(column.key)) { // set groupColumns const { ...groupColumn } = column groupColumns[column._level - 1].push(groupColumn) if (column.children) { column.children.forEach((item) => { setColgroupsAndGroupColumns(item) }) } else { // set colgroups const { ...colgroup } = column colgroup._realTimeWidth = colgroup.width colgroups.push(colgroup) } } } cloneColumns.forEach((column) => { setColgroupsAndGroupColumns(column) }) return { // set is group header isGroupHeader: maxLevel > 1, // set colgroups colgroups, // set groupColumns groupColumns } } // get header contextmenu option collection export function getHeaderContextmenuOptionCollection (t) { return [ { type: CONTEXTMENU_NODE_TYPES.SEPARATOR }, { label: t('cut'), type: CONTEXTMENU_NODE_TYPES.CUT }, { label: t('copy'), type: CONTEXTMENU_NODE_TYPES.COPY }, // { // label: t("paste"), // type: CONTEXTMENU_NODE_TYPES.PASTE, // }, { label: t('removeColumn'), type: CONTEXTMENU_NODE_TYPES.REMOVE_COLUMN }, { label: t('emptyColumn'), type: CONTEXTMENU_NODE_TYPES.EMPTY_COLUMN }, { label: t('hideColumn'), type: CONTEXTMENU_NODE_TYPES.HIDE_COLUMN }, { label: t('leftFixedColumnTo'), type: CONTEXTMENU_NODE_TYPES.LEFT_FIXED_COLUMN_TO }, { label: t('cancelLeftFixedColumnTo'), type: CONTEXTMENU_NODE_TYPES.CANCEL_LEFT_FIXED_COLUMN_TO }, { label: t('rightFixedColumnTo'), type: CONTEXTMENU_NODE_TYPES.RIGHT_FIXED_COLUMN_TO }, { label: t('cancelRightFixedColumnTo'), type: CONTEXTMENU_NODE_TYPES.CANCEL_RIGHT_FIXED_COLUMN_TO } ] } // get body contextmenu option collection export function getBodyContextmenuOptionCollection (t) { return [ { type: CONTEXTMENU_NODE_TYPES.SEPARATOR }, { label: t('cut'), type: CONTEXTMENU_NODE_TYPES.CUT }, { label: t('copy'), type: CONTEXTMENU_NODE_TYPES.COPY }, // { // label: t("paste"), // type: CONTEXTMENU_NODE_TYPES.PASTE, // }, { label: t('insertRowAbove'), type: CONTEXTMENU_NODE_TYPES.INSERT_ROW_ABOVE }, { label: t('insertRowBelow'), type: CONTEXTMENU_NODE_TYPES.INSERT_ROW_BELOW }, { label: t('removeRow'), type: CONTEXTMENU_NODE_TYPES.REMOVE_ROW }, { label: t('emptyRow'), type: CONTEXTMENU_NODE_TYPES.EMPTY_ROW }, { label: t('removeColumn'), type: CONTEXTMENU_NODE_TYPES.REMOVE_COLUMN }, { label: t('emptyCell'), type: CONTEXTMENU_NODE_TYPES.EMPTY_CELL } ] } /*** * @setHeaderContextmenuOptions * @desc set header contextmenu options * @param {array<object>} column * @param {array<object>} contextmenuHeaderOption * @param {object} cellSelectionRangeData * @param {array<object>} colgroups * @param {object} headerIndicatorColKeys * @param {boolean} enableHeaderContextmenu * @param {boolean} t locale * @return headerContextmenuOptions */ export function setHeaderContextmenuOptions ({ column, contextmenuHeaderOption, cellSelectionRangeData, colgroups, allRowKeys, headerIndicatorColKeys, enableHeaderContextmenu, t }) { const result = [] if (enableHeaderContextmenu) { const selectionRangeKeys = getSelectionRangeKeys({ cellSelectionRangeData }) const selectionRangeIndexes = getSelectionRangeIndexes({ cellSelectionRangeData, colgroups, allRowKeys }) const isOperationCol = isOperationColumn(column.key, colgroups) const colCount = selectionRangeIndexes.endColIndex - selectionRangeIndexes.startColIndex + 1 const { contextmenus, beforeShow } = contextmenuHeaderOption const isWholeColSelection = !isEmptyValue( headerIndicatorColKeys.startColKey ) const leftFixedColKeys = getColKeysByFixedType({ fixedType: COLUMN_FIXED_TYPE.LEFT, colgroups, isExcludeOperationColumn: true }) const rightFixedColKeys = getColKeysByFixedType({ fixedType: COLUMN_FIXED_TYPE.RIGHT, colgroups, isExcludeOperationColumn: true }) if (isFunction(beforeShow)) { beforeShow({ isWholeColSelection, selectionRangeKeys, selectionRangeIndexes }) } const headerContextmenuOptionCollection = getHeaderContextmenuOptionCollection(t) contextmenus.forEach((contextmenu) => { const contentmenuCollectionItem = headerContextmenuOptionCollection.find( (x) => x.type === contextmenu.type ) if (contentmenuCollectionItem) { let isContinue = true // empty column. 选中整列时支持 if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.EMPTY_COLUMN ) { if (isWholeColSelection) { contentmenuCollectionItem.label = contentmenuCollectionItem.label.replace( '$1', colCount ) } else { isContinue = false } // eslint-disable-next-line brace-style } // left fixed column to else if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.LEFT_FIXED_COLUMN_TO ) { // if (isOperationCol) { contentmenuCollectionItem.disabled = true } } // calcel left fixed column to else if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.CANCEL_LEFT_FIXED_COLUMN_TO ) { if (leftFixedColKeys.length < 1) { contentmenuCollectionItem.disabled = true } } // right fixed column to else if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.RIGHT_FIXED_COLUMN_TO ) { // if (isOperationCol) { contentmenuCollectionItem.disabled = true } } // calcel right fixed column to else if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.CANCEL_RIGHT_FIXED_COLUMN_TO ) { if (rightFixedColKeys.length < 1) { contentmenuCollectionItem.disabled = true } } if (isContinue) { result.push(contentmenuCollectionItem) } } else { result.push(contextmenu) } }) } return result } /*** * @setHeaderContextmenuOptions * @desc set header contextmenu options * @param {array<object>} column * @param {array<object>} contextmenuBodyOption * @param {object} cellSelectionRangeData * @param {array<object>} colgroups * @param {object} bodyIndicatorRowKeys * @param {boolean} enableHeaderContextmenu * @param {boolean} t locale * @return headerContextmenuOptions */ export function setBodyContextmenuOptions ({ enableBodyContextmenu, contextmenuBodyOption, cellSelectionRangeData, colgroups, allRowKeys, bodyIndicatorRowKeys, t }) { const result = [] if (enableBodyContextmenu) { const selectionRangeKeys = getSelectionRangeKeys({ cellSelectionRangeData }) const selectionRangeIndexes = getSelectionRangeIndexes({ cellSelectionRangeData, colgroups, allRowKeys }) const rowCount = selectionRangeIndexes.endRowIndex - selectionRangeIndexes.startRowIndex + 1 const colCount = selectionRangeIndexes.endColIndex - selectionRangeIndexes.startColIndex + 1 const { contextmenus, beforeShow } = contextmenuBodyOption const isWholeRowSelection = !isEmptyValue( bodyIndicatorRowKeys.startRowKey ) if (isFunction(beforeShow)) { beforeShow({ isWholeRowSelection, selectionRangeKeys, selectionRangeIndexes }) } const bodyContextmenuOptionCollection = getBodyContextmenuOptionCollection(t) contextmenus.forEach((contextmenu) => { const contentmenuCollectionItem = bodyContextmenuOptionCollection.find( (x) => x.type === contextmenu.type ) if (contentmenuCollectionItem) { let isContinue = true // remove row if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.REMOVE_ROW ) { contentmenuCollectionItem.label = contentmenuCollectionItem.label.replace('$1', rowCount) } // empty row. 选中整行时支持 else if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.EMPTY_ROW ) { if (isWholeRowSelection) { contentmenuCollectionItem.label = contentmenuCollectionItem.label.replace( '$1', rowCount ) } else { isContinue = false } } // empty cell.没选中整行时支持 else if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.EMPTY_CELL ) { isContinue = !isWholeRowSelection } // remove column.没选中整行时支持 else if ( contentmenuCollectionItem.type === CONTEXTMENU_NODE_TYPES.REMOVE_COLUMN ) { if (isWholeRowSelection) { isContinue = false } else { contentmenuCollectionItem.label = contentmenuCollectionItem.label.replace( '$1', colCount ) } } if (isContinue) { result.push(contentmenuCollectionItem) } } else { result.push(contextmenu) } }) } return result } // create empty row data // export function createEmptyRowData({ colgroups, rowKeyFieldName }) { // let rowData = { // [rowKeyFieldName]: getRandomId(), // }; // colgroups.forEach((column) => { // if (column.field) { // rowData[column.field] = ""; // } // }); // return rowData; // } // empty row data // export function emptyRowData({ rowData, rowKeyFieldName }) { // Object.keys(rowData).forEach((key) => { // if (key !== rowKeyFieldName) { // rowData[key] = ""; // } // }); // return rowData; // } // is contextmenu panel clicked export function isContextmenuPanelClicked (event) { let result = false const contextmenuPanelEls = document.querySelectorAll( '.ve-contextmenu-popper' ); [].forEach.call(contextmenuPanelEls, function (el) { if (el.contains(event.target)) { result = true } }) return result } /** * @getColKeysByHeaderColumn * @desc * @param {object} headerColumnItem * @param {any} colKey2 * @return Array<colKeys> */ export function getColKeysByHeaderColumn ({ headerColumnItem }) { let result = null const { _keys } = headerColumnItem result = _keys.split('|') if (result.length > 1) { result = result.slice(0, result.length - 1) } return result } /** * @getColKeysByRangeColKeys * @desc get col keys by range col keys * @param {any} colKey1 * @param {any} colKey2 * @return Array<colKeys> */ export function getColKeysByRangeColKeys ({ colKey1, colKey2, colgroups }) { let result = null const index1 = colgroups.findIndex((x) => x.key === colKey1) const index2 = colgroups.findIndex((x) => x.key === colKey2) if (index1 !== -1 && index1 !== -1) { const beginIndex = index1 < index2 ? index1 : index2 const endIndex = index1 < index2 ? index2 : index1 result = colgroups.slice(beginIndex, endIndex + 1).map((x) => x.key) } return result } /** * @getColKeysByFixedTypeWithinColKeys * @desc get col keys by fixed type * @param {array<T>} colKeys * @param {string} fixedType - fixed type * @param {array<object>} colgroups * @return {array} colKeys */ export function getColKeysByFixedTypeWithinColKeys ({ colKeys, fixedType, colgroups }) { let result = null if (Array.isArray(colKeys)) { result = colgroups .filter((x) => colKeys.indexOf(x.key) > -1 && x.fixed === fixedType) .map((x) => x.key) } return result } /** * @getColKeysByFixedType * @desc get col keys by fixed type * @param {string} fixedType - fixed type * @param {array<object>} colgroups * * @param {boolean} isExcludeOperationColumn * @return colKey */ export function getColKeysByFixedType ({ fixedType, colgroups, isExcludeOperationColumn }) { let result = null result = colgroups .filter((x) => { const condition = x.fixed === fixedType // 排除操作列 if (isExcludeOperationColumn) { return condition && !x.operationColumn } return condition }) .map((x) => x.key) return result } /** * @getRowKeysByRangeRowKeys * @desc get row keys by range row keys * @param {any} topRowKey - top row key * @param {any} bottomRowKey - bottom row key * @return Array<colKeys> */ export function getRowKeysByRangeRowKeys ({ topRowKey, bottomRowKey, allRowKeys }) { let result = null const beginIndex = allRowKeys.findIndex((x) => x === topRowKey) const endIndex = allRowKeys.findIndex((x) => x === bottomRowKey) if (beginIndex !== -1 && endIndex !== -1) { result = allRowKeys.slice(beginIndex, endIndex + 1) } return result } /** * @isCellInSelectionRange * @desc is cell in selection range * @param {object} cellData - cell data * @param {object} cellSelectionRangeData * @param {array<object>} colgroups * @param {array<object>} allRowKeys * @return {Array<colKeys>} */ export function isCellInSelectionRange ({ cellData, cellSelectionRangeData, colgroups, allRowKeys }) { const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData const colKeys = getColKeysByRangeColKeys({ colKey1: leftColKey, colKey2: rightColKey, colgroups }) const rowKeys = getRowKeysByRangeRowKeys({ topRowKey, bottomRowKey, allRowKeys }) if ( colKeys.indexOf(cellData.colKey) > -1 && rowKeys.indexOf(cellData.rowKey) > -1 ) { return true } return false } /** * @isClearSelectionByBodyCellRightClick * @desc is clear selection by body cell click * @param {number} mouseEventClickType * @param {object} cellData - cell data * @param {object} cellSelectionRangeData * @param {array<object>} colgroups * @param {array<object>} allRowKeys * @return {bool} */ export function isClearSelectionByBodyCellRightClick ({ mouseEventClickType, cellData, cellSelectionData, cellSelectionRangeData, colgroups, allRowKeys }) { let result = true if (mouseEventClickType === MOUSE_EVENT_CLICK_TYPE.RIGHT_MOUSE) { const { normalEndCell } = cellSelectionData if (normalEndCell.rowIndex > -1) { result = !isCellInSelectionRange({ cellData, cellSelectionRangeData, colgroups, allRowKeys }) } } return result } /** * @getSelectionRangeKeys * @desc get selection range keys * @param {object} cellSelectionRangeData * @return Array<colKeys> */ export function getSelectionRangeKeys ({ cellSelectionRangeData }) { const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData return { startColKey: leftColKey, endColKey: rightColKey, startRowKey: topRowKey, endRowKey: bottomRowKey } } /** * @getSelectionRangeIndexes * @desc get selection range indexes * @param {object} cellSelectionRangeData * @param {array<object>} colgroups * @param {array<object>} allRowKeys * @return Array<colKeys> */ export function getSelectionRangeIndexes ({ cellSelectionRangeData, colgroups, allRowKeys }) { const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData return { startColIndex: colgroups.findIndex((x) => x.key === leftColKey), endColIndex: colgroups.findIndex((x) => x.key === rightColKey), startRowIndex: allRowKeys.indexOf(topRowKey), endRowIndex: allRowKeys.indexOf(bottomRowKey) } } /** * @getSelectionRangeData * @desc get selection range data * @param {object} cellSelectionRangeData * @param {string} resultType "normal": contains key/value ; "flat":only contains value * @param {array<object>} tableData * @param {array<object>} colgroups * @param {array<object>} allRowKeys * @return Array<colKeys> */ export function getSelectionRangeData ({ cellSelectionRangeData, resultType = 'normal', tableData, colgroups, allRowKeys }) { let result = null const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData const startColIndex = colgroups.findIndex((x) => x.key === leftColKey) const endColIndex = colgroups.findIndex((x) => x.key === rightColKey) const startRowIndex = allRowKeys.indexOf(topRowKey) const endRowIndex = allRowKeys.indexOf(bottomRowKey) const fieldNames = colgroups .slice(startColIndex, endColIndex + 1) .map((x) => x.field) if (resultType === 'normal') { result = tableData .slice(startRowIndex, endRowIndex + 1) .map((rowData) => { const newRow = {} fieldNames.forEach((fieldName) => { newRow[fieldName] = rowData[fieldName] || '' }) return newRow }) } else { result = tableData .slice(startRowIndex, endRowIndex + 1) .map((rowData) => { const newRow = [] fieldNames.forEach((fieldName) => { newRow.push(rowData[fieldName] || '') }) return newRow }) } return result } /** * @isExistFixedColKey * @desc is exist given fixed col key * @param {string} fixedType - fixed type * @param {array<T>} colKeys * @param {array<object>} colgroups * @return bool */ export function isExistGivenFixedColKey ({ fixedType, colKeys, colgroups }) { let result = false if (Array.isArray(colKeys)) { result = colgroups.some((x) => { return colKeys.indexOf(x.key) > -1 && x.fixed === fixedType }) } return result } /** * @isExistNotFixedColKey * @desc is exist not fixed col key * @param {array<T>} colKeys * @param {array<object>} colgroups * @return bool */ export function isExistNotFixedColKey ({ colKeys, colgroups }) { let result = false if (Array.isArray(colKeys)) { result = colgroups.filter( (x) => !x.fixed && colKeys.indexOf(x.key) > -1 ).length } return result } /** * @getLeftmostOrRightmostColKey * @desc get leftmost or rightmost column key * @param {string} type * @param {array<object>} colgroups * @param {array<any>} colKeys * @return colKey */ function getLeftmostOrRightmostColKey ({ type, colgroups, colKeys }) { let result = null if (Array.isArray(colKeys) && colKeys.length) { let mostObj = { colKey: null, colIndex: null } colKeys.forEach((colKey) => { const colIndex = colgroups.findIndex((x) => x.key === colKey) if (colIndex === -1) { console.warn( `getLeftmostOrRightmostColKey error:: can't find colKey:${colKey}` ) return false } if (isEmptyValue(mostObj.colKey)) { mostObj = { colKey, colIndex: colIndex } } else { if (type === 'leftmost') { if (colIndex < mostObj.colIndex) { mostObj = { colKey, colIndex: colIndex } } } else if (type === 'rightmost') { if (colIndex > mostObj.colIndex) { mostObj = { colKey, colIndex: colIndex } } } } }) result = mostObj.colKey } return result } /** * @getLeftmostColKey * @desc get leftmost column key * @param {array<object>} colgroups * @param {array<any>} colKeys * @return colKey */ export function getLeftmostColKey ({ colgroups, colKeys }) { return getLeftmostOrRightmostColKey({ type: 'leftmost', colgroups, colKeys }) } /** * @getRightmostColKey * @desc get rightmost column key * @param {array<object>} colgroups * @param {array<any>} colKeys * @return colKey */ export function getRightmostColKey ({ colgroups, colKeys }) { return getLeftmostOrRightmostColKey({ type: 'rightmost', colgroups, colKeys }) } /** * @getPreviewColKey * @desc get preview column key * @param {array<object>} colgroups * @param {any} currentColKey * @return colKey */ export function getPreviewColKey ({ colgroups, currentColKey }) { let result = null if (!isEmptyValue(currentColKey)) { const index = colgroups.findIndex((x) => x.key === currentColKey) if (index === 0) { result = currentColKey } else if (index > 0) { result = colgroups[index - 1].key } } return result } /** * @getNextColKey * @desc get next column key * @param {array<object>} colgroups * @param {any} currentColKey * @return colKey */ export function getNextColKey ({ colgroups, currentColKey }) { let result = null if (!isEmptyValue(currentColKey)) { const index = colgroups.findIndex((x) => x.key === currentColKey) if (index === colgroups.length - 1) { result = currentColKey } else if (index < colgroups.length - 1) { result = colgroups[index + 1].key } } return result } /*** * @cellAutofill * @desc cell auto fill * @param {bool} isReplaceData * @param {array<object>} tableData * @param {array<any>} allRowKeys * @param {array<object>} colgroups * @param {string} direction * @param {string} rowKeyFieldName * @param {object} nextCurrentCell next current cell * @param {object} nextNormalEndCell next normal end cell * @return autofillChangeDatas */ export function cellAutofill ({ isReplaceData, tableData, allRowKeys, colgroups, direction, rowKeyFieldName, cellSelectionRangeData, nextCurrentCell, nextNormalEndCell }) { let cellSelectionTableData = [] const { leftColKey, rightColKey, topRowKey, bottomRowKey } = cellSelectionRangeData // source selection range const sourceSelectionRangeIndexes = { startRowIndex: -1, endRowIndex: -1, startColIndex: -1, endColIndex: -1 } // target selection range const targetSelectionRangeIndexes = { startRowIndex: -1, endRowIndex: -1, startColIndex: -1, endColIndex: -1 } sourceSelectionRangeIndexes.startRowIndex = allRowKeys.indexOf(topRowKey) sourceSelectionRangeIndexes.endRowIndex = allRowKeys.indexOf(bottomRowKey) sourceSelectionRangeIndexes.startColIndex = colgroups.findIndex( (x) => x.key === leftColKey ) sourceSelectionRangeIndexes.endColIndex = colgroups.findIndex( (x) => x.key === rightColKey ) cellSelectionTableData = tableData.slice( sourceSelectionRangeIndexes.startRowIndex, sourceSelectionRangeIndexes.endRowIndex + 1 ) if (direction === AUTOFILLING_DIRECTION.UP) { // targetSelectionRangeIndexes.startRowIndex = allRowKeys.indexOf( nextCurrentCell.rowKey ) targetSelectionRangeIndexes.endRowIndex = sourceSelectionRangeIndexes.startRowIndex - 1 targetSelectionRangeIndexes.startColIndex = sourceSelectionRangeIndexes.startColIndex targetSelectionRangeIndexes.endColIndex = sourceSelectionRangeIndexes.endColIndex if (isReplaceData) { let cellSelectionTableDataRowIndex = cellSelectionTableData.length - 1 for ( let rowIndex = targetSelectionRangeIndexes.endRowIndex; rowIndex >= targetSelectionRangeIndexes.startRowIndex; rowIndex-- ) { for ( let colIndex = targetSelectionRangeIndexes.startColIndex; colIndex <= targetSelectionRangeIndexes.endColIndex; colIndex++ ) { const fieldName = colgroups[colIndex].field // repeat autofill cell selection data if (cellSelectionTableDataRowIndex < 0) { cellSelectionTableDataRowIndex = cellSelectionTableData.length - 1 } tableData[rowIndex][fieldName] = cellSelectionTableData[cellSelectionTableDataRowIndex][ fieldName ] } --cellSelectionTableDataRowIndex } } } else if (direction === AUTOFILLING_DIRECTION.DOWN) { // targetSelectionRangeIndexes.startRowIndex = sourceSelectionRangeIndexes.endRowIndex + 1 targetSelectionRangeIndexes.endRowIndex = allRowKeys.indexOf( nextNormalEndCell.rowKey ) targetSelectionRangeIndexes.startColIndex = sourceSelectionRangeIndexes.startColIndex targetSelectionRangeIndexes.endColIndex = sourceSelectionRangeIndexes.endColIndex if (isReplaceData) { let cellSelectionTableDataRowIndex = 0 for ( let rowIndex = targetSelectionRangeIndexes.startRowIndex; rowIndex <= targetSelectionRangeIndexes.endRowIndex; rowIndex++ ) { for ( let colIndex = targetSelectionRangeIndexes.startColIndex; colIndex <= targetSelectionRangeIndexes.endColIndex; colIndex++ ) { const fieldName = colgroups[colIndex].field // repeat autofill cell selection data if ( cellSelectionTableDataRowIndex > cellSelectionTableData.length - 1 ) { cellSelectionTableDataRowIndex = 0 } tableData[rowIndex][fieldName] = cellSelectionTableData[cellSelectionTableDataRowIndex][ fieldName ] } ++cellSelectionTableDataRowIndex } } } else if (direction === AUTOFILLING_DIRECTION.LEFT) { // targetSelectionRangeIndexes.startRowIndex = sourceSelectionRangeIndexes.startRowIndex targetSelectionRangeIndexes.endRowIndex = sourceSelectionRangeIndexes.endRowIndex targetSelectionRangeIndexes.startColIndex = colgroups.findIndex( (x) => x.key === nextCurrentCell.colKey ) targetSelectionRangeIndexes.endColIndex = sourceSelectionRangeIndexes.startColIndex - 1 if (isReplaceData) { let cellSelectionTableDataRowIndex = 0 for ( let rowIndex = targetSelectionRangeIndexes.startRowIndex; rowIndex <= targetSelectionRangeIndexes.endRowIndex; rowIndex++ ) { let cellSelectionTableDataColIndex = sourceSelectionRangeIndexes.endColIndex for ( let colIndex = targetSelectionRangeIndexes.endColIndex; colIndex >= targetSelectionRangeIndexes.startColIndex; colIndex-- ) { const fieldName = colgroups[colIndex].field // repeat autofill cell selection data if ( cellSelectionTableDataColIndex < sourceSelectionRangeIndexes.startColIndex ) { cellSelectionTableDataColIndex = sourceSelectionRangeIndexes.endColIndex } tableData[rowIndex][fieldName] = cellSelectionTableData[cellSelectionTableDataRowIndex][ colgroups[cellSelectionTableDataColIndex].field ] --cellSelectionTableDataColIndex } ++cellSelectionTableDataRowIndex } } } else if (direction === AUTOFILLING_DIRECTION.RIGHT) { // targetSelectionRangeIndexes.startRowIndex = sourceSelectionRangeIndexes.startRowIndex targetSelectionRangeIndexes.endRowIndex = sourceSelectionRangeIndexes.endRowIndex targetSelectionRangeIndexes.startColIndex = sourceSelectionRangeIndexes.endColIndex + 1 targetSelectionRangeIndexes.endColIndex = colgroups.findIndex( (x) => x.key === nextNormalEndCell.colKey ) if (isReplaceData) { let cellSelectionTableDataRowIndex = 0 for ( let rowIndex = targetSelectionRangeIndexes.startRowIndex; rowIndex <= targetSelectionRangeIndexes.endRowIndex; rowIndex++ ) { let cellSelectionTableDataColIndex = sourceSelectionRangeIndexes.startColIndex for ( let colIndex = targetSelectionRangeIndexes.startColIndex; colIndex <= targetSelectionRangeIndexes.endColIndex; colIndex++ ) { const fieldName = colgroups[colIndex].field // repeat autofill cell selection data if ( cellSelectionTableDataColIndex > sourceSelectionRangeIndexes.startColIndex + (sourceSelectionRangeIndexes.endColIndex - sourceSelectionRangeIndexes.startColIndex) ) { cellSelectionTableDataColIndex = sourceSelectionRangeIndexes.startColIndex } tableData[rowIndex][fieldName] = cellSelectionTableData[cellSelectionTableDataRowIndex][ colgroups[cellSelectionTableDataColIndex].field ] ++cellSelectionTableDataColIndex } ++cellSelectionTableDataRowIndex } } } const response = { direction, sourceSelectionRangeIndexes, targetSelectionRangeIndexes, sourceSelectionData: [], targetSelectionData: [] } const sourceFieldNames = colgroups .slice( sourceSelectionRangeIndexes.startColIndex, sourceSelectionRangeIndexes.endColIndex + 1 ) .map((x) => x.field) response.sourceSelectionData = tableData .slice( sourceSelectionRangeIndexes.startRowIndex, sourceSelectionRangeIndexes.endRowIndex + 1 ) .map((rowData) => { const newData = { [rowKeyFieldName]: rowData[rowKeyFieldName] } sourceFieldNames.forEach((fieldName) => { newData[fieldName] = rowData[fieldName] }) return newData }) const targetFieldNames = colgroups .slice( targetSelectionRangeIndexes.startColIndex, targetSelectionRangeIndexes.endColIndex + 1 ) .map((x) => x.field) response.targetSelectionData = tableData .slice( targetSelectionRangeIndexes.startRowIndex, targetSelectionRangeIndexes.endRowIndex + 1 ) .map((rowData) => { const newData = { [rowKeyFieldName]: rowData[rowKeyFieldName] } targetFieldNames.forEach((fieldName) => { newData[fieldName] = rowData[fieldName] }) return newData }) return response } /*** * @setColumnFixed * @desc set column fixed * @param {array<object>} cloneColumns * @param {object} cellSelectionRangeData * @param {string} fixedType COLUMN_FIXED_TYPE * @param {array<object>} colgroups * @param {bool} enableColumnResize * @return cloneColumns */ export function setColumnFixed ({ cloneColumns, cellSelectionRangeData, fixedType, colgroups, enableColumnResize }) { let result = cloneColumns const { leftColKey, rightColKey } = cellSelectionRangeData let colKey if (COLUMN_FIXED_TYPE.LEFT === fixedType) { colKey = rightColKey } else if (COLUMN_FIXED_TYPE.RIGHT === fixedType) { colKey = leftColKey } // find col index from cloneColumns // eslint-disable-next-line array-callback-return const fixedColIndex = cloneColumns.findIndex((colItem) => { if (colItem._level === 1 && colItem.key === colKey) { return true } else { const colKeys = getColKeysByHeaderColumn({ headerColumnItem: colItem }) if (colKeys.indexOf(colKey) > -1) { return true } } }) if (fixedColIndex > -1) { // 不允许改变原有固定列方向 const oldFixedType = cloneColumns[fixedColIndex].fixed if (!isEmptyValue(oldFixedType) && oldFixedType !== fixedType) { return false } result = cloneColumns.map((colItem, index) => { // 清除所有固定 if (colItem.fixed === fixedType) { colItem.fixed = '' } // 允许列自适应 && 不是多列表头 if ( enableColumnResize && !(Array.isArray(colItem.children) && colItem.children.length) ) { const _colItem = colgroups.find( (x) => x.key === colItem.key && !isEmptyValue(x.key) ) if (_colItem) { colItem.width = _colItem._columnResizeWidth } } if (COLUMN_FIXED_TYPE.LEFT === fixedType) { // 不允许左冻结最后一列 if (index <= fixedColIndex && index < cloneColumns.length) { colItem.fixed = fixedType } } else { // 不允许右冻结第一列 if (index >= fixedColIndex && index > 0) { colItem.fixed = fixedType } } return colItem }) } return result } /*** * @cancelColumnFixed * @desc cancel column fixed * @param {array<object>} cloneColumns * @param {array<object>} colgroups * @param {string} fixedType COLUMN_FIXED_TYPE * @param {bool} enableColumnResize * @return cloneColumns */ export function cancelColumnFixed ({ cloneColumns, colgroups, fixedType, enableColumnResize }) { return cloneColumns.map((colItem) => { // 允许列自适应 && 不是多列表头 if ( enableColumnResize && !(Array.isArray(colItem.children) && colItem.children.length) ) { const _colItem = colgroups.find( (x) => x.key === colItem.key && !isEmptyValue(x.key) ) if (_colItem) { colItem.width = _colItem._columnResizeWidth } } if (COLUMN_FIXED_TYPE.LEFT === fixedType) { if ( colItem.fixed === fixedType && !isOperationColumn(colItem.key, colgroups) ) { colItem.fixed = '' } } else { if (colItem.fixed === fixedType) { colItem.fixed = '' } } return colItem }) }