UNPKG

linkmore-design

Version:

🌈 🚀lm组件库。🚀

1,569 lines (1,537 loc) 51.6 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.Summary = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _sortable = require("@dnd-kit/sortable"); var _ahooks = require("ahooks"); var _classnames = _interopRequireDefault(require("classnames")); var _immer = require("immer"); var _lodash = require("lodash"); var _react = _interopRequireWildcard(require("react")); var _reactResizable = require("react-resizable"); var _toFixed = require("./toFixed"); var _configProvider = _interopRequireDefault(require("../config-provider")); var _empty = _interopRequireDefault(require("../empty")); var _table = _interopRequireDefault(require("../table")); var _useRowSelectControllableValue = _interopRequireDefault(require("./hooks/useRowSelectControllableValue")); var _CalcExpression = _interopRequireDefault(require("./components/CalcExpression")); var _sheelTableCell = _interopRequireDefault(require("./components/sheelTableCell")); var _DndContainer = _interopRequireDefault(require("./components/DndContainer")); var _DraggableContainer = _interopRequireDefault(require("./components/rowSort/DraggableContainer")); var _Dragger = _interopRequireDefault(require("./components/rowSort/Dragger")); var _sortableItem = _interopRequireDefault(require("./components/rowSort/sortableItem")); var _util = require("./util"); var _resetConfig = _interopRequireDefault(require("./resetConfig")); var _HeaderCol = _interopRequireDefault(require("./components/HeaderCol")); var _HeaderRow = _interopRequireDefault(require("./components/HeaderRow")); var _headRowSortWarp = _interopRequireDefault(require("./components/headRowSortWarp")); var _useDndItems = _interopRequireDefault(require("./hooks/useDndItems")); var _useGroupDataSource = _interopRequireDefault(require("./hooks/useGroupDataSource")); var _virTual = require("./virTual"); var _index = require("./common/index"); /** 表表列排序组件 */ /** 表格行排序组件 */ const { Summary } = _table.default; exports.Summary = Summary; const { ConfigContext } = _configProvider.default; const isEmpty = obj => Object.keys(obj || {})?.length === 0; const defaultParsePaste = str => { return str.split(/\r\n|\n|\r/).map(row => row.split('\t')); }; const decimalLists = ['amount', 'price', 'number']; const ResetTable = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => { const { changeSize, columns: customizeColumns, dataSource: customizeDataSource, autoSize, rowClick, onDoubleClick, checkConfig, summary, pagination, hiddenPage, loading, virtual = false, colSortOpen = false, resizeable = false, customCheck, components, rowSelection, columnsState, onChange, filterChange, /** 默认类型一定要手动选择一个之后,点击整行才会选中,select模式则是点击整行就选中 */ tableRowType = 'default', size = 'default', /** 打开excel模式 */ openSheet = false, /** 打开sheet的编辑模式 */ editSheet = false, dataChange, // 分组 openColGroup, colGroupTitle, openRowGroup, rowGroupTitle, groupWidth, groupRowKeys: customizeGroupRowKeys, groupColKeys: customizeGroupColKeys, onGroupChange = () => {}, onExpressionChange, rowStyle, /** 开启表头拖动排序 */ headerColSort, /** 表头排序后返回事件,返回最新的columns的 */ colChange, /** 开启行排序 */ sortOpen = false, /** 行排序返回事件,返回最新的 */ rowSortEnd, emptyProps, /** 是否点击时出现边框 */ showClickBorder = false, /** 点击选择行发生变化时触发 */ selectRowChange, /** 敏感列keys */ roleFiledKeys = [], columnsValueDecimal = { amount: 2 }, columnsMinWidth = 56, rowClassName, ...resetProps } = props; if (!Array.isArray(customizeColumns) || !customizeColumns.length) { return null; } const { rowKey = 'id' } = resetProps; const { locale } = _react.default.useContext(ConfigContext); const transformRowClick = data => rowClick?.(data.selectedRows || data); // const [useSelectedRows, setSelectedRows] = useState({ selectedRows: [] }) // 复选中的值 const [useSelectedRows, setSelectedRows] = (0, _useRowSelectControllableValue.default)({ value: { selectedRows: rowSelection?.selectedRows || rowSelection?.selectedRowKeys || [] }, onChange: rowClick ? transformRowClick : undefined }); const [useActiveKey, setActiveKey] = (0, _react.useState)(''); // 行选中 const tableWarpRef = (0, _react.useRef)(null); const tableRef = (0, _react.useRef)(null); /** 记录最原始数据 */ const dataSourceRef = (0, _react.useRef)(null); dataSourceRef.current = customizeDataSource; const columnsRef = (0, _react.useRef)(null); columnsRef.current = customizeColumns; /** 右键的ref */ const contentMenuRef = (0, _react.useRef)(null); /** 当前展开的列 */ const [expandedRowKeys, setExpandedRowKeys] = (0, _react.useState)([]); const deepDataSourceRef = (0, _react.useRef)([]); const deepColumnsRef = (0, _react.useRef)([]); // const copyAllData = (0, _react.useRef)(null); // const update = (0, _ahooks.useUpdate)(); /** 最后一个点击的行 */ const [lastClickRow, setLastClickRow] = (0, _react.useState)(null); (0, _react.useEffect)(() => { if (showClickBorder && selectRowChange) { const item = dataSourceRef.current?.find(item => item[rowKey] === lastClickRow); selectRowChange?.(item || lastClickRow); } }, [lastClickRow]); const { dndColumns, items, groupRowKeys, groupColKeys, updateItems } = (0, _useDndItems.default)({ columns: customizeColumns, openColGroup, openRowGroup, colSortOpen, filterChange, customizeGroupRowKeys, customizeGroupColKeys }); onGroupChange && onGroupChange(groupRowKeys, groupColKeys); /** 行分组 */ const [groupDataSource] = (0, _useGroupDataSource.default)({ groupRowKeys, customizeDataSource, columnsRef }); /** 列分组 */ const { columns, dataSource } = (0, _react.useMemo)(() => { if (!groupColKeys?.length) { return { dataSource: groupDataSource, columns: dndColumns }; } return (0, _util.transformWithColGroup)(dndColumns, groupDataSource, groupColKeys, groupRowKeys); }, [dndColumns, groupDataSource, groupColKeys, groupRowKeys]); (0, _react.useEffect)(() => { setExpandedRowKeys([]); deepDataSourceRef.current = []; deepColumnsRef.current = []; }, [groupRowKeys, groupColKeys]); /** sheel数据的表格 */ const [sheelStataus, setSheelStatus] = (0, _react.useState)({ // 记录框选的行列坐标信息 start: {}, end: {}, // 是否在框选 selecting: false, forceEdit: false, // 是否在编辑中 editing: {}, clear: {}, // 记录右下角小方块的拖动信息 commiting: {} }); const shellStatusRef = (0, _react.useRef)({ start: {}, end: {}, selecting: false, forceEdit: false, editing: {}, clear: {}, commiting: {} }); const [selectIng, setSelectIng] = (0, _react.useState)(false); const [editIng, setEditIng] = (0, _react.useState)(false); const [commitIng, setCommitIng] = (0, _react.useState)(false); /** 右键菜单是否显示 */ const [contextMenuStatus, setContextMenuStatus] = (0, _react.useState)(false); /** 右键按钮的位置 */ const [style, setStyle] = (0, _react.useState)({ position: 'fixed', left: 300, top: 200 }); // 列设置 const [columnsStateMap, setColumnsStateMap] = (0, _react.useState)(false); // 行分组数据铺平, 在框选时获取数据使用 (0, _react.useEffect)(() => { const source = []; const deepChildren = arr => { arr?.forEach(item => { source.push((0, _lodash.omit)(item, 'children')); // 展开 if (item?.children && expandedRowKeys.includes(item.key)) { deepChildren(item?.children); } }); }; deepChildren(dataSource); deepDataSourceRef.current = source; }, [dataSource, expandedRowKeys]); // 列分组数据铺平,在框选时获取数据使用 (0, _react.useEffect)(() => { const source = []; const deepChildren = arr => { arr?.forEach(item => { if (item.children && item.children.length) { deepChildren(item.children); } else { source.push(item); } }); }; deepChildren(columns); deepColumnsRef.current = source; }, [columns, groupColKeys]); const [useColumns, setColumns] = (0, _react.useState)(columns); (0, _react.useEffect)(() => { setColumns(columns); }, [columns]); const onSortEnd = (active, over) => { const cloneArr = [...dataSourceRef.current]; const oldIndex = cloneArr.findIndex(v => v[rowKey] === active); const newIndex = cloneArr.findIndex(v => v[rowKey] === over); rowSortEnd?.((0, _sortable.arrayMove)(cloneArr, oldIndex, newIndex)); }; const DraggableContainer = props => /*#__PURE__*/_react.default.createElement(_DraggableContainer.default, (0, _extends2.default)({}, props, { virtual: true, options: dataSourceRef.current, rowKey: rowKey, onSortEnd: onSortEnd, tableWidth: tableWarpRef?.current?.getBoundingClientRect()?.width, columns: columnsRef.current || resultColumns, keys: dataSourceRef.current?.map(item => item[rowKey]) })); const DraggableBodyRow = props => { return /*#__PURE__*/_react.default.createElement(_sortableItem.default, (0, _extends2.default)({ virtual: true }, props)); }; const sortDefaultColumnItem = { title: '排序', dataIndex: 'sort', width: 54, maxWidth: 54, fixed: 'left', order: -2, className: 'drag-visible', render: (_, record) => /*#__PURE__*/_react.default.createElement(_Dragger.default, { id: record?.[rowKey] || record?.id }) }; /** 列宽拖动时速度 */ const handleResize = index => (e, { size }) => { let i = index; const nextColumns = [...useColumns]; nextColumns.forEach((item, index) => { if (index <= i && item.show === false) { i += 1; } }); nextColumns[i] = { ...nextColumns[i], width: size.width }; setColumns(nextColumns); }; /** 列宽拖动结束事件 */ const endResize = () => { setTimeout(() => { filterChange?.(useColumns); }); }; /** 表格sheet化事件中心START */ const isSelected = (i, j) => { const { start, end, editing, commiting } = shellStatusRef.current; const maxi = Math.max(start?.i, end.i); const mini = Math.min(start?.i, end.i); const maxj = Math.max(start?.j, end.j); const minj = Math.min(start?.j, end.j); const isSelected = (0, _util.checkIsSelectd)(i, j, start, end); return { /** 是否选中 */ isSelected, /** 是否尾行 */ isEnd: i === maxi && j >= minj && j <= maxj, /** 是否尾列 */ isRightEnd: j === maxj && i >= mini && i <= maxi, /** 是否在编辑中 */ isEditing: editing?.i === i && editing?.j === j, /** 是否有效拉伸 */ isVaildCommit: isEmpty(commiting) ? false : isSelected && !(0, _util.checkIsSelectd)(i, j, commiting?.start, commiting?.end), /** 是否选中只读框 */ // TODO selectedReadonly: true }; }; /** 获取框选的数据 */ const getSelectDatas = (start, end) => { return (0, _util.range)(start.i, end.i).map(i => (0, _util.range)(start.j, end.j).map(j => { const columnKey = groupColKeys?.length ? deepColumnsRef.current[j].dataIndex : columns[j]?.dataIndex; const dataItem = groupRowKeys?.length ? deepDataSourceRef.current[i] : dataSource[i]; const cell = dataItem?.[columnKey]; if (columns[j]?.render) { return columns[j]?.render?.(cell, dataItem, i); } return cell; }).join('\t')).join('\n'); }; /** 复制选中内容 */ const handleCopy = e => { e?.preventDefault(); const { start, end } = shellStatusRef.current; const text = copyAllData.current || getSelectDatas(start, end); if (window.clipboardData && window.clipboardData.setData) { window.clipboardData.setData('Text', text); document.removeEventListener('copy', handleCopy); } else if (e.clipboardData?.setData) { e.clipboardData.setData('text/plain', text); document.removeEventListener('copy', handleCopy); } else if (!copyAllData.current) { document?.execCommand('copy'); if (contextMenuStatus) { setContextMenuStatus(false); } } copyAllData.current = null; }; /** 复制所有数据 */ const handleCopyAll = e => { e?.preventDefault(); const source = dataSourceRef.current; const columns = columnsRef.current; const text = source.map((rItem, i) => columns.map((cItem, j) => { const columnKey = columns[j]?.dataIndex; const dataItem = dataSource[i]; const cell = dataItem?.[columnKey]; if (columns[j]?.render) { return columns[j]?.render?.(cell, dataItem, i); } return cell; }).join('\t')).join('\n'); copyAllData.current = text; document?.execCommand('copy'); setContextMenuStatus(false); }; const onMouseOver = (i, j) => { if (isEmpty(shellStatusRef?.current?.commiting)) { if (shellStatusRef?.current?.selecting && isEmpty(shellStatusRef?.current?.editing)) { shellStatusRef.current = { ...shellStatusRef.current, end: { i, j } }; setSheelStatus({ ...sheelStataus, end: { i, j } }); } } else if (!isEmpty(shellStatusRef?.current?.commiting || {}) && (0, _util.checkStatus)(i, j, shellStatusRef?.current?.commiting)?.isVaildCommit) { if ((0, _util.isSelectCrossRowGroup)(i, shellStatusRef, deepDataSourceRef)) { return; } if ((0, _util.isSelectCrossInvalidCol)(i, j, shellStatusRef, deepDataSourceRef, deepColumnsRef)) { return; } shellStatusRef.current = { ...shellStatusRef.current, end: { i, j } }; setSheelStatus({ ...sheelStataus, end: { i, j } }); } }; // 通过表格的行列索引,获取对应的原始数据的item信息 const getSourceItemInfo = (trIndex, tdIndex) => { const innerColumns = groupColKeys?.length ? deepColumnsRef.current : columns; const columnsKeysList = innerColumns.map(item => item.dataIndex); let key = columnsKeysList[tdIndex]; let index; const nil = { index: -1, key: undefined }; if (key === undefined) { return nil; } // 列分组的情况下 if (groupColKeys?.length) { if (groupRowKeys?.length && deepDataSourceRef?.current?.[trIndex]._group) { return nil; } index = (0, _util.getDataSourceIndex)({ key, dataSource }); const arr = key.split('_'); key = arr[arr.length - 2]; } else if (groupRowKeys.length) { index = deepDataSourceRef.current[trIndex].__index; } else { index = trIndex; } return { index, key }; }; /** sheel 表格 鼠标松开 */ /** TODO: 在分组的情况,需要排除_group行的数据转换,以及要进行对子级的覆盖 */ const sheelOnMouseUp = () => { if (!isEmpty(shellStatusRef.current?.commiting)) { const { start, end, commiting } = shellStatusRef.current; // const innerColumns = groupColKeys?.length ? deepColumnsRef.current : columns; const innerDataSource = groupRowKeys?.length ? deepDataSourceRef.current : dataSource; // const columnsKeysList = innerColumns.map(item => item.dataIndex); // 行文本 const rowtext = (0, _util.getSelectionRowText)({ selection: commiting, columnsKeysList, dataSource: innerDataSource }); // 列文本 const coltext = (0, _util.getSelectionColText)({ selection: commiting, columns: innerColumns, dataSource: innerDataSource }); /** 选择范围 例如:i:[0,1], j:[1,2] */ const selectedRange = { i: (0, _util.range)(start.i, end.i), j: (0, _util.range)(start.j, end.j) }; /** 提交范围 */ const commitRange = { i: (0, _util.range)(commiting?.start?.i, commiting?.end?.i), j: (0, _util.range)(commiting?.start?.j, commiting?.end?.j) }; // obj 为新增的范围 let obj = { i: [], j: [] }; let type = ''; if ((0, _lodash.difference)(selectedRange.i, commitRange.i)?.length) { obj = { i: (0, _lodash.difference)(selectedRange.i, commitRange.i), j: selectedRange.j }; type = 'row'; } else if ((0, _lodash.difference)(selectedRange.j, commitRange.j)?.length) { obj = { i: selectedRange.i, j: (0, _lodash.difference)(selectedRange.j, commitRange.j) }; type = 'col'; } const data = (0, _lodash.cloneDeep)(dataSourceRef.current); obj.i?.forEach((tri, index) => { obj.j?.forEach(tdj => { if (isSelected(tri, tdj)?.isSelected) { // 只读列无法修改其内容 if (deepColumnsRef?.current?.[tdj]?.readOnly) { return; } const { index: sourceIndex, key } = getSourceItemInfo(tri, tdj); if (sourceIndex < 0 || sourceIndex >= data.length) { return; } // 行替换 if (type === 'row') { data[sourceIndex][key] = rowtext[index % rowtext.length]?.[tdj]; } else { // 列替换 data[sourceIndex][key] = coltext[index % coltext.length]?.[tdj % coltext[index % coltext.length].length]; } } }); }); if (editSheet) { dataChange?.(data); } setSheelStatus({ ...sheelStataus, selecting: false, commiting: {} }); shellStatusRef.current = { ...shellStatusRef.current, selecting: false, commiting: {} }; setCommitIng(false); } else { setSheelStatus({ ...sheelStataus, selecting: false }); shellStatusRef.current = { ...shellStatusRef.current, selecting: false }; } document.removeEventListener('mouseup', sheelOnMouseUp); }; /** 剪切内容 */ const handleCut = e => { if (isEmpty(shellStatusRef.current?.editing)) { e.preventDefault(); handleCopy(e); /** 暂时先不隐藏 */ // const { start, end } = shellStatusRef.current // clearSelectedCells(start, end) } }; /** 内容粘贴 */ /** TODO: 在分组的情况,需要排除_group行的数据转换 */ const handlePaste = e => { if (isEmpty(shellStatusRef.current?.editing)) { let { start, end } = shellStatusRef.current; start = { i: Math.min(start.i, end.i), j: Math.min(start.j, end.j) }; end = { i: Math.max(start.i, end.i), j: Math.max(start.j, end.j) }; const parse = defaultParsePaste; let pasteData = []; if (window.clipboardData && window.clipboardData.getData) { // IE pasteData = parse(window.clipboardData.getData('Text')); } else if (e.clipboardData && e.clipboardData.getData) { pasteData = parse(e.clipboardData.getData('text/plain')); } // in order of preference const resultEnd = []; pasteData?.forEach((row, i) => { row?.forEach((value, j) => { resultEnd.push({ i: start.i + i, j: start.j + j, value }); }); }); const res = (0, _immer.produce)(dataSourceRef.current, draft => { resultEnd?.forEach(item => { if (isSelected(item.i, item.j)?.isSelected) { const { index, key } = getSourceItemInfo(item.i, item.j); if (index < 0 || index >= draft.length) { return; } draft[index][key] = item.value; } }); }); /** 只有开通了编辑权限之后才可以 */ if (editSheet) { dataChange?.(res); } } // 修复重复问题 document.removeEventListener('paste', handlePaste); document.removeEventListener('copy', handleCopy); document.removeEventListener('cut', handleCut); }; const pageClick = e => { // if (this.props.disablePageClick) return; const element = tableWarpRef.current; if (!element?.contains(e.target)) { shellStatusRef.current = { start: {}, end: {}, selecting: false, forceEdit: false, editing: {}, clear: {}, commiting: {} }; setSelectIng(false); document.removeEventListener('mousedown', pageClick); document.removeEventListener('mouseup', sheelOnMouseUp); document.removeEventListener('cut', handleCut); document.removeEventListener('copy', handleCopy); document.removeEventListener('paste', handlePaste); } /** 关闭右键 */ const contentElement = contentMenuRef.current; if (!contentElement?.contains(e.target)) { setContextMenuStatus(false); } }; /** sheel 表格 鼠标点击 */ /** * i 行 * j 列 * e 点击元素 * commitStatus boolena 是否点击了快速选择 */ const sheelMouseDown = (i, j, e, commitStatus) => { const isNowEditingSameCell = !isEmpty(shellStatusRef.current?.editing) && shellStatusRef.current?.editing.i === i && shellStatusRef.current?.editing.j === j; const editing = isEmpty(shellStatusRef.current?.editing) || shellStatusRef.current?.editing.i !== i || shellStatusRef.current?.editing.j !== j ? {} : shellStatusRef.current?.editing; shellStatusRef.current = { selecting: !isNowEditingSameCell, start: e?.shiftKey || commitStatus ? shellStatusRef.current?.start : { i, j }, end: { i, j }, editing, forceEdit: !!isNowEditingSameCell, commiting: commitStatus ? { start: shellStatusRef.current?.start, end: { i, j } } : {} }; setSelectIng(!isNowEditingSameCell); if (commitStatus) { setCommitIng(true); } if (isEmpty(shellStatusRef.current?.editing)) { setEditIng(false); } document.addEventListener('mouseup', sheelOnMouseUp); document.addEventListener('mousedown', pageClick); document.addEventListener('cut', handleCut); document.addEventListener('copy', handleCopy); document.addEventListener('paste', handlePaste); }; /** 鼠标右键点击事件 */ const onContextMenu = (evt, i, j) => { evt.preventDefault(); const { start, end } = shellStatusRef.current; /** 如果表格当前没有选择,则把当前的右击的td块默认选中 */ if (isEmpty(start) && isEmpty(end)) { sheelMouseDown(i, j, evt); } if (!(0, _util.checkIsSelectd)(i, j, start, end)) { sheelMouseDown(i, j, evt); } setContextMenuStatus(true); // 获得点击的位置 let { clientX, clientY } = evt; // 文档显示区的宽度 const screenW = window.innerWidth; const screenH = window.innerHeight; // 右键菜单的宽度 // const rightClickRefW = rightClickRef.current.offsetWidth; // const rightClickRefH = rightClickRef.current.offsetHeight; const rightClickRefW = 200; const rightClickRefH = 200; // right为true,说明鼠标点击的位置到浏览器的右边界的宽度可以放下contextmenu。 // 否则,菜单放到左边。 const right = screenW - clientX > rightClickRefW; const top = screenH - clientY > rightClickRefH; // 赋值右键菜单离鼠标一些距离 clientX = right ? clientX + 6 : clientX - rightClickRefW - 6; clientY = top ? clientY + 6 : clientY - rightClickRefH - 6; setStyle({ ...style, left: clientX, top: clientY }); }; const onSheelDoubleClick = (i, j, col) => { if (editSheet) { if (!col.readOnly) { shellStatusRef.current = { ...shellStatusRef.current, editing: { i, j }, forceEdit: true, clear: {} }; setEditIng(true); } } }; const dataSourceChange = (i, j, value) => { const { index, key } = getSourceItemInfo(i, j); if (index < 0 || index >= dataSourceRef.current.length) { return; } // 表格中的行数 转化为 对应的数据源索引 const res = (0, _immer.produce)(dataSourceRef.current, draft => { draft[index][key] = value; }); dataChange?.(res); shellStatusRef.current = { ...shellStatusRef.current, editing: {}, forceEdit: false, clear: {} }; }; (0, _react.useEffect)(() => { return () => { document.removeEventListener('mousedown', pageClick); document.removeEventListener('mouseup', sheelOnMouseUp); document.removeEventListener('cut', handleCut); document.removeEventListener('copy', handleCopy); document.removeEventListener('paste', handlePaste); }; }, []); /** 表格sheet化事件中心END */ const resetColumns = (0, _react.useCallback)(() => { const roleHideKeys = roleFiledKeys?.filter(item => item.type === 0)?.map(item => item.key) || []; let colIndex = 0; const traverseColumns = columns => { for (let i = 0; i < columns.length; i += 1) { const col = columns[i]; const mergeColDecimal = { number: null, price: null, amount: 2, ...(columnsValueDecimal || {}) }; const { decimalType } = col; const hasDecimal = decimalLists?.includes(decimalType); const align = col.align || (hasDecimal ? 'right' : 'left'); col.align = align; col.render = col.render ? col.render : hasDecimal && !!mergeColDecimal[decimalType] ? text => /*#__PURE__*/_react.default.createElement("span", { style: { textAlign: 'right' } }, (0, _toFixed.toFixedNumber)(text, mergeColDecimal[decimalType])) : null; if (col.show === false || roleHideKeys.includes(col.roleKey || col.dataIndex)) { columns.splice(i, 1); i -= 1; } else if (col.children && col.children.length) { traverseColumns(col.children); } else { // $_ 开头表示私有属性 col.$_colIndex = colIndex; // eslint-disable-next-line no-loop-func col.onHeaderCell = column => { return resizeable ? { width: column.width, dataIndex: column.dataIndex, onResize: handleResize(i), onResizeStop: endResize, minWidth: column.minWidth } : { width: column.width, dataIndex: column.dataIndex }; }; if (openSheet) { col.onCell = (record, rowIndex) => { return { record, rowKey, col, colIndex: col.$_colIndex, selectIng, editIng, commitIng, rowIndex, onMouseDown: sheelMouseDown, onMouseOver, onContextMenu, isSelected, onDoubleClick: onSheelDoubleClick, dataSourceChange }; }; } else if (openRowGroup) { col.onCell = record => { return { record, col, onChangeRecord: (dfs, dataIndex, value, isUpdate) => { dfs(dataSource, dataIndex, value); isUpdate && update(); }, onExpressionChange }; }; } colIndex += 1; } } }; let innerColumns = (0, _lodash.cloneDeep)(useColumns.filter(item => item.show !== false)); if (groupRowKeys?.length) { /** 如果是进行了行分组,则会生成一列dataIndex为Group的Col, 如果需要修改此处,请备注原因 */ innerColumns = [{ type: 'name', title: '分组', dataIndex: '_group', key: '_group', width: groupWidth || 100, fixed: 'left' }, ...innerColumns]; } traverseColumns(innerColumns, null); return sortOpen ? [sortDefaultColumnItem, ...innerColumns] : innerColumns; }, [useColumns, sortOpen, selectIng, dataSource, groupRowKeys, commitIng, roleFiledKeys]); // 行点击事件 const onRecord = record => { const { trigger, highlight } = Object.assign(_resetConfig.default.checkConfig, checkConfig); if (highlight) { setActiveKey(record[rowKey]); } setLastClickRow(record[rowKey]); if (trigger === 'row') { const { selectedRows } = useSelectedRows; if (showClickBorder) { /** 如果是点击出现框的,则不变 */ setSelectedRows({ selectedRows }); } else if (tableRowType === 'default' && selectedRows.length < 2) { /** TODO: 点击行时默认开启单选模式 */ setSelectedRows({ selectedRows: [(0, _lodash.isObject)(selectedRows[0]) || !selectedRows.length ? record : record[rowKey]] }); } else if (tableRowType === 'select' || tableRowType === 'default' && selectedRows.length) { if (rowSelection?.type === 'radio') { setSelectedRows({ selectedRows: [(0, _lodash.isObject)(selectedRows[0]) || !selectedRows.length ? record : record[rowKey]] }); } else { const selectIndex = selectedRows?.findIndex(v => (0, _lodash.isObject)(v) ? v[rowKey] === record[rowKey] : v === record[rowKey]); selectIndex >= 0 ? selectedRows.splice(selectIndex, 1) : selectedRows.push((0, _lodash.isObject)(selectedRows[0]) || !selectedRows.length ? record : record[rowKey]); setSelectedRows({ selectedRows: (0, _lodash.cloneDeep)(selectedRows) }); } } } else { rowClick?.(record); } }; const restRowClassName = (0, _react.useCallback)((record, index) => { const customRowClassName = rowClassName?.(record, index) || ''; return (0, _classnames.default)(customRowClassName, record[rowKey] === useActiveKey && 'row-active', record[rowKey] === lastClickRow && !!showClickBorder && 'row-clicking'); }, [rowClassName, rowKey, useActiveKey, lastClickRow, showClickBorder]); // 复选框配置 const config = (0, _react.useMemo)(() => { let autoSizeHeight = autoSize.height; if (autoSizeHeight === '100%' && (openRowGroup || openColGroup)) { autoSizeHeight = 'calc(100% - 100px)'; } return { defaultSize: 'small', tableLayout: 'fixed', rowKey, debounceTime: 300, revalidateOnFocus: false, options: { setting: false, density: false, fullScreen: false, reload: false }, columnsState: { value: columnsStateMap, onChange: k => { setColumnsStateMap(k); } }, search: false, tableAlertRender: false, checkConfig, // components: vComponents, scroll: resetProps.autoSizer || resetProps.scroll ? { y: autoSizeHeight, ...resetProps.scroll, ...(resizeable ? { x: '100%' } : {}) } : resizeable ? { x: '100%' } : null, pagination: !hiddenPage && { showSizeChanger: true, showQuickJumper: true, showTotal: total => locale?.locale === 'en' ? `total ${total} Page` : `共 ${total} 条`, locale: locale?.locale === 'en' ? locale?.Pagination || {} : { items_per_page: '条/页', jump_to: '前往', page: '页' }, size: 'small', ...pagination }, rowSelection: rowSelection === false ? undefined : { fixed: true, type: 'checkbox', columnWidth: 36, selectedRowKeys: useSelectedRows.selectedRows.map(v => (0, _lodash.isObject)(v) ? v[rowKey] : v), /** 如果开启了行分组,则需要把checkStrictly关闭,变成受控模式 */ checkStrictly: !groupRowKeys?.length, onChange: !rowSelection?.selectedRows ? (selectedRowKeys, selectedRows) => { setSelectedRows({ selectedRows }); // rowClick?.(selectedRows) } : undefined, onSelectAll: rowSelection?.selectedRows ? (selected, selectedRows, changeRows) => { const changeRowKeys = changeRows?.map(item => item[rowKey]); const reulstSelect = selected ? (0, _lodash.uniqBy)([...rowSelection.selectedRows, ...changeRows], rowKey) : rowSelection.selectedRows.filter(item => !changeRowKeys.includes(item[rowKey])); setSelectedRows({ selectedRows: reulstSelect }); // rowClick?.(reulstSelect) } : undefined, onSelect: rowSelection?.selectedRows ? (record, selected) => { const reulstSelect = rowSelection.type === 'radio' ? [record] : selected ? (0, _lodash.uniqBy)([...rowSelection.selectedRows, record], rowKey) : rowSelection.selectedRows.filter(item => item[rowKey] !== record[rowKey]); setSelectedRows({ selectedRows: reulstSelect }); // rowClick?.(reulstSelect) } : undefined, ...rowSelection }, onRow: record => ({ onClick: () => { onRecord(record); }, onDoubleClick: () => { onDoubleClick?.(record); }, ...(resetProps.onRow || {}) }), rowClassName: restRowClassName, columns: resetColumns(), size, ...resetProps }; }, [useColumns, useSelectedRows, columnsStateMap, restRowClassName, resetProps, autoSize.height, resizeable]); const resultColumns = (0, _react.useMemo)(() => { const result = useColumns.map((item, index) => { return { ...item, colSort: columnsStateMap?.[item.dataIndex]?.order === undefined ? index : columnsStateMap?.[item.dataIndex]?.order || index, fixed: columnsStateMap?.[item.dataIndex]?.fixed || item.fixed || undefined, show: columnsStateMap?.[item.dataIndex]?.show !== false }; }).filter(item => !!item.show); result.sort((a, b) => { return (a.fixed === 'left' ? a.colSort : a.fixed === 'right' ? 500 + a.colSort : a.colSort + 50) - (b.fixed === 'left' ? b.colSort : b.fixed === 'right' ? 500 + b.colSort : b.colSort + 50); }); return result; }, [columnsStateMap, useColumns]); (0, _react.useEffect)(() => { const obj = { ...columnsState }; columns?.forEach(item => { /** 目前支持三种 */ const { order, show, fixed } = obj[item.dataIndex || item.key] || {}; obj[item.dataIndex || item.key] = { fixed: fixed || item.fixed, show: show === false ? false : item.show || true, order: order || item.order }; }); setColumnsStateMap(obj); }, [columnsState]); // 将节点方法给外部使用 _react.default.useImperativeHandle(ref, () => ({ changeSize, getCheckboxRecords: () => useSelectedRows.selectedRows, // 用于按钮触发事件 clearSelect: () => { setSelectedRows({ selectedRows: [] }); // rowClick?.([]) }, customSetCheckboxRecords: value => { setSelectedRows({ selectedRows: value }); // rowClick?.(value) }, checkboxRecords: useSelectedRows.selectedRows, columns: useColumns.map(item => { return (0, _lodash.omit)(item, ['render', 'sorter', 'onFilter', 'filters']); }) })); const onTableChange = (pagination, filters, sorter, extra) => { const resultColumns = useColumns.map(item => { const obj = { ...item, sortOrder: false }; obj.filteredValue = filters[obj.dataIndex] || []; if (Array.isArray(sorter)) { const checkSort = sorter.find(s => s.field === obj.dataIndex); if (checkSort) { obj.sortOrder = checkSort.order; } } else if (sorter?.field === obj.dataIndex) { obj.sortOrder = sorter.order; } return obj; }); setColumns(resultColumns); filterChange?.(resultColumns); onChange?.(pagination, filters, sorter, extra); }; /** 排序的表头 */ const ResizableTitle = props => { const { onResize = () => {}, width, dataIndex, onResizeStop, ...restProps } = props; const style = customizeDataSource.length === 0 ? { width: `${width}px`, position: 'relative', left: 'auto', right: 'auto' } : {}; if (!width) { return headerColSort ? /*#__PURE__*/_react.default.createElement(_HeaderRow.default, (0, _extends2.default)({ column: column }, props, restProps, { style: { ...restProps.style, ...style }, rowSort: headerColSort, openRowGroup: openRowGroup, openColGroup: openColGroup })) : /*#__PURE__*/_react.default.createElement("th", restProps); } const column = (0, _index.treeFind)(columns, node => { return node.dataIndex === dataIndex; }); if (!column || groupRowKeys.includes(dataIndex)) { return /*#__PURE__*/_react.default.createElement("th", (0, _extends2.default)({}, restProps, { style: { ...restProps.style, ...style } })); } return /*#__PURE__*/_react.default.createElement(_reactResizable.Resizable, { width: width, height: 0, handle: /*#__PURE__*/_react.default.createElement("span", { className: "react-resizable-handle", onClick: e => { e.stopPropagation(); } }), axis: "x", minConstraints: [props?.minWidth || columnsMinWidth || 56, 10], onResize: onResize, onResizeStop: onResizeStop, draggableOpts: { enableUserSelectHack: false } }, headerColSort ? /*#__PURE__*/_react.default.createElement(_HeaderRow.default, (0, _extends2.default)({ column: column }, props, restProps, { style: { ...restProps.style, ...style }, rowSort: headerColSort, openRowGroup: openRowGroup, openColGroup: openColGroup })) : /*#__PURE__*/_react.default.createElement("th", (0, _extends2.default)({}, restProps, { style: { ...restProps.style, ...style } }), /*#__PURE__*/_react.default.createElement(_HeaderCol.default, (0, _extends2.default)({ column: column }, props, { rowSort: headerColSort, openRowGroup: openRowGroup, openColGroup: openColGroup })))); }; const colDraggableContainer = (0, _react.useCallback)(({ ...props }) => { const { children } = props; return /*#__PURE__*/_react.default.createElement("tr", null, children); }, [columns]); // 重写表格 const tableComponents = (0, _react.useMemo)(() => { const { body = {}, header = {} } = components || {}; let table = null; if (virtual) { table = function InnerVirtualTable(props) { return /*#__PURE__*/_react.default.createElement(_virTual.VirtualTable, (0, _extends2.default)({}, props, { isEmpty: !customizeDataSource.length, emptyProps: emptyProps })); }; } let headerRow = null; if (openRowGroup || openColGroup) { headerRow = colDraggableContainer; } let headerCell = null; if (openRowGroup || openColGroup || resizeable || headerColSort) { headerCell = ResizableTitle; } let bodyCell = null; if (openSheet) { bodyCell = _sheelTableCell.default; } else if (openRowGroup) { bodyCell = _CalcExpression.default; } return { table, header: { row: headerRow, cell: headerCell, ...header }, body: { wrapper: sortOpen ? DraggableContainer : virtual ? _virTual.VirtualWrapper : null, row: sortOpen ? DraggableBodyRow : virtual ? _virTual.VirtualRow : null, cell: bodyCell, ...body } }; }, [sortOpen, resizeable, components, colSortOpen, customizeDataSource, columns, openRowGroup, headerColSort]); (0, _react.useEffect)(() => { if (autoSize && autoSize.height !== '100%') { const dom = document.querySelector('.lm_protable .ant-table-body'); if (dom) { dom.style.height = `${autoSize.height}px`; } } }, [autoSize]); return /*#__PURE__*/_react.default.createElement("div", { style: { height: '100%', width: '100%' }, ref: tableWarpRef }, /*#__PURE__*/_react.default.createElement(_configProvider.default // locale={locale} , { renderEmpty: loading ? () => null : emptyProps ? () => /*#__PURE__*/_react.default.createElement(_empty.default, emptyProps, emptyProps?.footer || null) : () => /*#__PURE__*/_react.default.createElement(_empty.default, { title: null, image: "nodata", description: null }, emptyProps?.footer || null) }, headerColSort ? /*#__PURE__*/_react.default.createElement(_headRowSortWarp.default, { items: resultColumns, updateItems: data => colChange?.(data) }, /*#__PURE__*/_react.default.createElement(_table.default, (0, _extends2.default)({ ref: tableRef }, config, { loading: loading, dataSource: dataSource, components: tableComponents, onChange: onTableChange, expandable: resetProps?.expandable || { onExpand: () => { shellStatusRef.current = { start: {}, end: {}, selecting: false, forceEdit: false, editing: {}, clear: {}, commiting: {} }; }, expandedRowKeys, onExpandedRowsChange: expandedRows => setExpandedRowKeys(expandedRows) }, className: (0, _classnames.default)('lm_protable', resizeable && 'lm_resizeable', resetProps?.autoSizer && 'lm_autosize_table', (!hiddenPage || !!customCheck) && resetProps?.autoSizer && 'lm_page_info_table'), summary: pageData => summary && summary(pageData, resultColumns, resetColumns()), onRow: () => { return { style: rowStyle || {} }; } }))) : openRowGroup || openColGroup || colSortOpen ? /*#__PURE__*/_react.default.createElement(_DndContainer.default, { items: items, updateItems: updateItems, rowGroupTitle: rowGroupTitle, colGroupTitle: colGroupTitle, filterColumns: (columnsRef.current || []).filter(item => item.rowGroup || item.colGroup) }, /*#__PURE__*/_react.default.createElement(_table.default, (0, _extends2.default)({ ref: tableRef }, config, { loading: loading, dataSource: dataSource, components: tableComponents, onChange: onTableChange, expandable: resetProps?.expandable || { onExpand: () => { shellStatusRef.current = { start: {}, end: {}, selecting: false, forceEdit: false, editing: {}, clear: {}, commiting: {} }; }, expandedRowKeys, onExpandedRowsChange: expandedRows => setExpandedRowKeys(expandedRows) }, className: (0, _classnames.default)('lm_protable', resizeable && 'lm_resizeable', resetProps?.autoSizer && 'lm_autosize_table', (!hiddenPage || !!customCheck) && resetProps?.autoSizer && 'lm_page_info_table'), summary: pageData => summary && summary(pageData, resultColumns, resetColumns()), onRow: () => { return { style: rowStyle || {} }; } }))) : /*#__PURE__*/_react.default.createElement(_table.default, (0, _extends2.default)({}, config, { ref: tableRef, loading: loading, dataSource: dataSource, components: tableComponents, onChange: onTableChange, expandable: resetProps?.expandable || { onExpand: () => { shellStatusRef.current = { start: {}, end: {}, selecting: false, forceEdit: false, editing: {}, clear: {}, commiting: {} }; }, expandedRowKeys, onExpandedRowsChange: expandedRows => setExpandedRowKeys(expandedRows) }, className: (0, _classnames.default)('lm_protable', resizeable && 'lm_resizeable', resetProps?.autoSizer && 'lm_autosize_table', (!hiddenPage || !!customCheck) && resetProps?.autoSizer && 'lm_page_info_table'), summary: pageData => summary && summary(pageData, resultColumns, resetColumns()) }))), !!customCheck && useSelectedRows?.selectedRows?.length > 1 && /*#__PURE__*/_react.default.createElement("div", { className: "lm_customCheck" }, customCheck), contextMenuStatus && /*#__PURE__*/_react.default.createElement("div", { ref: contentMenuRef, className: "WeChatContactsAvatarTools", style: style }, /*#__PURE__*/_react.default.createElement("div", { className: "rightClickItems", onClick: handleCopy }, "\u590D\u5236"), /*#__PURE__*/_react.default.createElement("div", { className: "rightClickItems", onClick: handleCopyAll }, "\u590D\u5236\u5168\u90E8"))); }); // 监听大小: 这里的高度是整个表格的高度,表体需要减去列头和分页的高度 /** 1: 使用scroll.x y 来控制宽高 默认都是100% */ const ResizeSize = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => { const { autoSizer = false, openRowGroup, openColGroup, groupHeight, footer, footerHeight, summary, summaryCustomFormrt } = props; const [tableSize, setTableSize] = (0, _react.useState)({ width: '100%', height: '100%' }); const defaultRef = ref || (0, _react.useRef)(null); const tableWarpRef = (0, _react.useRef)(null); const resizeRef = (0, _react.useRef)(null); const clsName = (0, _classnames.default)(footer && 'lm_protable_with_footer'); const columnsSummer = (0, _react.useMemo)(() => { if ((0, _lodash.isFunction)(summary)) { return summary; } else if ((0, _lodash.isObject)(summary)) { return (pageData, columns, newColumns = []) => { const { expandable, rowSelection } = props; const summaryColumns = (0, _lodash.compact)([expandable ? { dataIndex: '_expandable' } : null, rowSelection ? { dataIndex: '_rowSelection' } : null, ...newColumns]); const resultCol = (0, _util.getLeafNodes)(summaryColumns); return /*#__PURE__*/_react.default.createElement(_table.default.Summary, { fixed: true }, /*#__PURE__*/_react.default.createElement(_table.default.Summary.Row, null, resultCol.map(item => { return /*#__PURE__*/_react.default.createElement(_table.default.Summary.Cell, { align: item.align || 'left', key: item?.dataIndex }, (0, _lodash.isFunction)(summary[item.dataIndex]) ? summary[item.dataIndex]?.(pageData, item.dataIndex) : (0, _lodash.isBoolean)(summary[item.dataIndex]) ? summaryCustomFormrt ? summaryCustomFormrt(pageData, item.dataIndex) : (pageData || [])?.reduce((a, b) => { return a + Number(b[item.dataIndex] || 0); }, 0) : // : sumBy(pageData, item?.dataIndex) summary[item.dataIndex] ? summary[item.dataIndex] : ''); }))); }; } return summary; }, [summary]); if (!autoSizer) { return /*#__PURE__*/_react.default.createElement("div", { ref: tableWarpRef, className: clsName, id: "lm_protable_warp no_auto_sizer", style: { width: '100%', height: '100%' } }, /*#__PURE__*/_react.default.createElement(ResetTable, (0, _extends2.default)({ ref: defaultRef }, props, { summary: columnsSummer, autoSize: { height: '100%', width: '100%' } }))); } const resetHeight = (0, _react.useMemo)(() => { const { height } = tableSize; if (typeof height === 'string') { return height; } // 头部高度 let h = height - (props.size === 'middle' ? 48 : 40); if (!props.hiddenPage || props.customCheck) { h -= 64; } if (props.columns.some(v => v.children)) { h -= 32; } // 行列分组的高度 if (openRowGroup || openColGroup) { h -= groupHeight || 102; } if (footer) { h -= footerHeight || 54; } // safe area if (h < 0) { h = 0; } return h; }, [props.hiddenPage, props.customCheck, props.columns, tableSize, footer, footerHeight, groupHeight]); const changeSize = () => { if (!tableWarpRef.current) { return; } const value = props.summary ? 48 : 0; const { width = '100%', height = '100%' } = tableWarpRef.current.getBoundingClientRect() || {}; setTableSize({ width, height: typeof height === 'string' ? `calc(${height} - ${value}px)` : height - value }); }; const throttleSize = (0, _react.useCallback)(() => { const { width } = tableSize; return /*#__PURE__*/_react.default.createElement(ResetTable, (0, _extends2.default)({ ref: defaultRef }, props, { summary: columnsSummer, changeSize: changeSize, autoSize: { height: resetHeight, width } })); }, [tableSize, props]); const handResize = (0, _lodash.throttle)(changeSize, 600); (0, _react.useEffect)(() => { const { summary } = props; setTimeout(() => { if (!tableWarpRef.current) { return; } const { width = '100%', height = '100%' } = tableWarpRef.current.getBoundingClientRect(); const value = summary ? 48 : 0; setTableSize({ width, height: typeof height === 'string' ? `calc(${height} - ${value}px)` : height - value }); }, 100); resizeRef.current = window.addEventListener('resize', handResize); return () => { window.removeEventListener('resize', handResize); }; }, []); return /*#__PURE__*/_react.default.createElement("div", { className: clsName, ref: tableWarpRef, id: "lm_protable_warp", style: { width: '100%', height: '100%' } }, throttleSize()); }); var _default = /*#__PURE__*/(0, _react.memo)(ResizeSize); exports.default = _default;