UNPKG

es-grid-template

Version:

es-grid-template

1,404 lines (1,319 loc) 95.6 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import React, { Fragment, useMemo, useRef, useState } from 'react'; import customParseFormat from 'dayjs/plugin/customParseFormat'; import classNames from "classnames"; // import {Button, Dropdown, Form, Modal, Typography} from "antd" import { Button, Dropdown, Modal, Typography } from "antd"; import { useForm } from 'react-hook-form'; import { Toaster } from "react-hot-toast"; import { yupResolver } from "@hookform/resolvers/yup"; import { flatColumns2, getValueCell, renderContent } from "../hooks/columns"; import EditableCell from "../EditableCell"; import { GridStyle } from "../GridStyle"; import { TableContext } from "../useContext"; import dayjs from "dayjs"; import 'dayjs/locale/es'; import 'dayjs/locale/vi'; import TableGrid from "../TableGrid"; import { addClassBorderPasteCell, addClassCellIndexSelected, // addRowsDownWithCtrl, addRowsUp, checkChild, editAbleColumns, findAllChildrenKeys, findItemByKey, findItemPath, flattenArray, flattenData, getDefaultValue, getEditType, getFirstSelectCell, getLastSelectCell, getRowNumber, getRowsPasteIndex, hideDraggingPoint, isEditable, isEqualSet, isObjEmpty, newGuid, onAddBgSelectedCell, // onRemoveBorderSelectedCell, onRemoveBgSelectedCell, removeClassBorderPasteCell, removeClassCellIndexSelected, showDraggingPoint, sortedSetASC, totalFixedWidth, updateArrayByKey, getFormat, // isRangeCell, // isSelectedCell, onRemoveBgCellIndex, onAddBgCellIndex, onAddBorderSelectedCell, onRemoveBorderSelectedCell, isFormattedNumber, checkThousandSeparator, checkDecimalSeparator, detectSeparators, unFlattenData, getAllRowKey, // updateDataByFilter, addRowsDown, // mergeWithFilter, // mergeWithFilter2, // updateDataByFilter, updateOrInsert, addRowsDownWithCtrl, addRowsUpWithCtrl } from "../hooks"; import Message from "../../Message/Message"; import { Toolbar, ConfigProvider, InputNumber } from "rc-master-ui"; import classnames from "classnames"; import { Plus, Trash2 } from "becoxy-icons"; // import {faker} from "@faker-js/faker"; import { SELECTION_COLUMN } from "../InternalTable"; import { removeNumericFormat } from "react-numeric-component"; import HeaderContent from "../hooks/content/HeaderContent"; import { useSortable } from "@dnd-kit/sortable"; const { Paragraph, Title } = Typography; dayjs.extend(customParseFormat); const toast = 'top-right'; // const defaultContext = [ // { // key: 'INSERT_BEFORE', // label: 'Thêm dòng bên trên', // icon: <Plus fontSize={14} />, // children: [ // { // parentKey: 'INSERT_BEFORE', // key: 'INSERT_BEFORE_1', // label: 'Thêm 1 dòng', // row: 1 // }, // { // parentKey: 'INSERT_BEFORE', // key: 'INSERT_BEFORE_10', // label: 'Thêm 10 dòng', // row: 10 // }, // { // parentKey: 'INSERT_BEFORE', // key: 'INSERT_BEFORE_50', // label: 'Thêm 50 dòng', // row: 50 // }, // { // parentKey: 'INSERT_BEFORE', // key: 'INSERT_BEFORE_100', // label: 'Thêm 100 dòng', // row: 100 // }, // { // parentKey: 'INSERT_BEFORE', // key: 'INSERT_BEFORE_ADV', // label: 'Tùy chỉnh' // } // ] // }, // { // key: 'INSERT_AFTER', // label: 'Thêm dòng bên dưới', // icon: <Plus fontSize={14} />, // children: [ // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_1', // label: 'Thêm 1 dòng', // row: 1 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_10', // label: 'Thêm 10 dòng', // row: 10 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_50', // label: 'Thêm 50 dòng', // row: 50 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_100', // label: 'Thêm 100 dòng', // row: 100 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_ADV', // label: 'Tùy chỉnh' // } // ] // }, // { // key: 'INSERT_CHILDREN', // // label: 'Insert item children', // label: 'Thêm cấp con', // icon: <Plus fontSize={14} /> // // children: [ // // { // // parentKey: 'INSERT_AFTER', // // key: 'INSERT_AFTER_1', // // label: 'Thêm 1 dòng', // // row: 1 // // }, // // { // // parentKey: 'INSERT_AFTER', // // key: 'INSERT_AFTER_10', // // label: 'Thêm 10 dòng', // // row: 10 // // }, // // { // // parentKey: 'INSERT_AFTER', // // key: 'INSERT_AFTER_50', // // label: 'Thêm 50 dòng', // // row: 50 // // }, // // { // // parentKey: 'INSERT_AFTER', // // key: 'INSERT_AFTER_100', // // label: 'Thêm 100 dòng', // // row: 100 // // }, // // { // // parentKey: 'INSERT_AFTER', // // key: 'INSERT_AFTER_ADV', // // label: 'Tùy chỉnh' // // } // // ] // }, // { key: 'DELETE_CONTENT', label: 'Xóa nội dung', icon: <Trash2 fontSize={14} /> }, // { key: 'DELETE_ROWS', label: 'Xóa dòng', icon: <Trash2 fontSize={14} /> } // ] const validateData = async (data, formSchema) => { if (!formSchema) { return []; } else { const errors = []; for (let i = 0; i < data.length; i++) { try { await formSchema.validate(data[i], { abortEarly: false }); } catch (error) { errors.push(error.inner.reduce((acc, err) => { acc[err.path] = { field: err.path, index: i, message: err.message, type: err.type, ref: { name: err.path } }; return { ...acc, index: i }; }, {})); } } return errors; } }; const SortableHeaderCell = ({ children, columnKey }) => { const { attributes, listeners, setNodeRef, isDragging } = useSortable({ id: columnKey }); const style = { // ...props.style, cursor: 'move', // position: 'absolute', // left: 3, // top: -2, ...(isDragging ? { zIndex: 9999, userSelect: 'none' } : {}) // ...dragActiveStyle(dragState, props.id), }; return /*#__PURE__*/React.createElement("div", _extends({ ref: setNodeRef, style: style }, attributes, listeners), children); }; const GridEdit = props => { const { id, tableRef, t, columns, dataSource, originData, components, allowResizing, rowKey = 'id', selectionSettings, height, scrollHeight, format, triggerChangeData, triggerChangeColumns, onCellPaste, onCellChange, triggerPaste, style, getRowKey, className, toolbarItems, defaultValue, expandable, onCellClick, rowEditable, contextMenuItems: propsContext, showDefaultContext, validate, setTooltipContent, onBlur, locale, mergedFilterKeys, setMergedFilterKeys, wrapSettings, isFullScreen, ...rest } = props; const ref = useRef(null); const isSelecting = useRef(false); const startCell = useRef(null); const childrenColumnName = 'children'; // const hoveredRow: any = useRef(null) const isSelectingRow = useRef(false); const rowStart = useRef(null); const rowsSelected = useRef(new Set()); const selectedCells = useRef(new Set()); const pasteCells = useRef(new Set()); const startSelectedCells = useRef(null); // quét vùng chọn const isDragMouse = useRef(false); const isMouseDown = useRef(false); const editingKey = useRef(''); const cellEditing = useRef({}); // quét vùng được paste - tiếp tục hiển thị con trỏ crosshair // const isPasteDragging = useRef(false); const visibleCols = React.useMemo(() => { return flatColumns2(columns.filter(it => it.visible !== false)); }, [columns]); // const id = React.useMemo(() => { // // return tableId ?? faker.string.alpha(20) // // return tableId ?? newGuid() // // }, [tableId]) const itemsAdd = React.useMemo(() => { return [{ key: '10', label: `10 ${t ? t('rows') : 'rows'}` }, { key: '50', label: `50 ${t ? t('rows') : 'rows'}` }, { key: '100', label: `100 ${t ? t('rows') : 'rows'}` }]; }, [t]); const defaultContext = React.useMemo(() => { return [{ key: 'INSERT_BEFORE', // label: 'Thêm dòng bên trên', label: `${t ? t(locale?.add_rows_before ?? 'Add rows before') : 'Add rows before'}`, icon: /*#__PURE__*/React.createElement(Plus, { fontSize: 14 }), children: [{ parentKey: 'INSERT_BEFORE', key: 'INSERT_BEFORE_1', label: `${t ? t(locale?.add_1 ?? 'Add 1 rows') : 'Add 1 rows'}`, row: 1 }, { parentKey: 'INSERT_BEFORE', key: 'INSERT_BEFORE_10', label: `${t ? t(locale?.add_10 ?? 'Add 10 rows') : 'Add 10 rows'}`, row: 10 }, { parentKey: 'INSERT_BEFORE', key: 'INSERT_BEFORE_50', label: `${t ? t(locale?.add_50 ?? 'Add 50 rows') : 'Add 50 rows'}`, row: 50 }, { parentKey: 'INSERT_BEFORE', key: 'INSERT_BEFORE_100', label: `${t ? t(locale?.add_100 ?? 'Add 100 rows') : 'Add 100 rows'}`, row: 100 }, { parentKey: 'INSERT_BEFORE', key: 'INSERT_BEFORE_ADV', label: `${t ? t(locale?.custom ?? 'Custom') : 'Custom'}` }] }, { key: 'INSERT_AFTER', label: `${t ? t(locale?.add_rows_after ?? 'Add rows after') : 'Add rows before'}`, icon: /*#__PURE__*/React.createElement(Plus, { fontSize: 14 }), children: [{ parentKey: 'INSERT_AFTER', key: 'INSERT_AFTER_1', label: `${t ? t(locale?.add_1 ?? 'Add 1 rows') : 'Add 1 rows'}`, row: 1 }, { parentKey: 'INSERT_AFTER', key: 'INSERT_AFTER_10', label: `${t ? t(locale?.add_10 ?? 'Add 10 rows') : 'Add 10 rows'}`, row: 10 }, { parentKey: 'INSERT_AFTER', key: 'INSERT_AFTER_50', label: `${t ? t(locale?.add_50 ?? 'Add 50 rows') : 'Add 50 rows'}`, row: 50 }, { parentKey: 'INSERT_AFTER', key: 'INSERT_AFTER_100', label: `${t ? t(locale?.add_100 ?? 'Add 100 rows') : 'Add 100 rows'}`, row: 100 }, { parentKey: 'INSERT_AFTER', key: 'INSERT_AFTER_ADV', label: `${t ? t(locale?.custom ?? 'Custom') : 'Custom'}` }] }, { key: 'INSERT_CHILDREN', // label: 'Insert item children', label: `${t ? t(locale?.add_children ?? 'Add children') : 'Add children'}`, icon: /*#__PURE__*/React.createElement(Plus, { fontSize: 14 }) // children: [ // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_1', // label: 'Thêm 1 dòng', // row: 1 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_10', // label: 'Thêm 10 dòng', // row: 10 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_50', // label: 'Thêm 50 dòng', // row: 50 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_100', // label: 'Thêm 100 dòng', // row: 100 // }, // { // parentKey: 'INSERT_AFTER', // key: 'INSERT_AFTER_ADV', // label: 'Tùy chỉnh' // } // ] }, { key: 'DELETE_CONTENT', label: `${t ? t(locale?.delete_content ?? 'Delete content') : 'Delete content'}`, icon: /*#__PURE__*/React.createElement(Trash2, { fontSize: 14 }) }, { key: 'DELETE_ROWS', label: `${t ? t(locale?.delete_rows ?? 'Delete rows') : 'Delete rows'}`, icon: /*#__PURE__*/React.createElement(Trash2, { fontSize: 14 }) }]; }, [t, locale]); // const [form] = Form.useForm() // const [editingKey, setEditingKey] = useState<string | number>('') const [dataErrors, setDataErrors] = useState([]); // const abc = useMemo(() => { // // return selectedCells // // return [...new Set(Array.from(selectedCells.current).map((item: any) => parseInt(item.split('-')[0])))] // // }, [selectedCells]) const [rangeCells, setRangeCells] = useState(new Set()); const [openModalAddRow, setOpenModalAddRow] = useState({ open: false, type: '' }); const [rowsAdd, setRowsAdd] = useState(1); // const [cellEditing, setCellEditing] = useState<any>(null) const [isPasteDragging, setIsPasteDragging] = useState(false); // isPasteDragging == tiếp tục hiển thị con trỏ crosshair const [innerExpandedKeys, setInnerExpandedKeys] = React.useState(() => { // if (defaultExpandedRowKeys) { // return defaultExpandedRowKeys; // } // if (defaultExpandAllRows) { return findAllChildrenKeys(dataSource, getRowKey, childrenColumnName) ?? []; // } // return []; }); const mergedExpandedKeys = React.useMemo(() => new Set(innerExpandedKeys || []), [innerExpandedKeys]); React.useEffect(() => { if (validate && dataSource && dataSource.length) { validateData(dataSource, validate).then(error => { setDataErrors([...error]); // if (getErrors) { // getErrors([...error]) // } }); } }, [validate, dataSource]); const rowsFocus = React.useMemo(() => { const leng = flattenArray(dataSource).length; const arr = [...new Set(Array.from(rangeCells).map(item => parseInt(item.split('-')[0])))]; // return [...new Set(Array.from(rangeCells).map((item: any) => parseInt(item.split('-')[0])))] ?? [] return arr.filter(it => it < leng); }, [dataSource.length, rangeCells]); const contextMenuItems = React.useMemo(() => { const a = showDefaultContext !== false ? [...defaultContext] : []; const b = propsContext && propsContext.length > 0 ? [...propsContext, { type: 'divider' }] : []; return [...b, ...a]; }, [propsContext, showDefaultContext]); const onTriggerExpand = React.useCallback(record => { const key = getRowKey(record, dataSource.indexOf(record)); let newExpandedKeys; const hasKey = mergedExpandedKeys.has(key); if (hasKey) { mergedExpandedKeys.delete(key); newExpandedKeys = [...mergedExpandedKeys]; } else { newExpandedKeys = [...mergedExpandedKeys, key]; } setInnerExpandedKeys(newExpandedKeys); // // onAddBgSelectedCell(rangeCells, id) // onAddBorderSelectedCell(rangeCells, id) }, [getRowKey, dataSource, mergedExpandedKeys]); const handleAddSingle = React.useCallback(item => { const defaultRowValue = getDefaultValue(defaultValue); const rowId = defaultRowValue && defaultRowValue.id ? defaultRowValue.id : newGuid(); if (item && item.onClick) { item.onClick({ toolbar: item }); } else { const newData = [...dataSource, defaultValue ? { ...defaultRowValue, id: undefined, rowId } : { id: undefined, rowId }]; triggerChangeData?.(newData, 'Add'); } }, [dataSource, defaultValue, triggerChangeData]); const handleAddMulti = React.useCallback((item, n) => { if (item.onClick) { item.onClick({ toolbar: item }); } else { const defaultRowValue = getDefaultValue(defaultValue); const newRows = Array.from({ length: n }).map(() => defaultRowValue ? { ...defaultRowValue, id: undefined, rowId: newGuid() } : { id: undefined, rowId: newGuid() }); const kkk = getAllRowKey(newRows) ?? []; const rs = mergedFilterKeys ? [...mergedFilterKeys, ...kkk] : [...kkk]; setMergedFilterKeys?.(rs); const newData = dataSource.concat(newRows); triggerChangeData?.(newData, 'Add'); } }, [dataSource, defaultValue, mergedFilterKeys, setMergedFilterKeys, triggerChangeData]); const handleDuplicate = React.useCallback(() => { // không tính tree // Cập nhật data mới const newData = [...dataSource]; const duplicatedItems = rowsFocus.map(index => ({ ...newData[index], rowId: newGuid(), id: undefined, isDuplicate: true })); // Vị trí chèn là ngay sau phần tử lớn nhất trong rowsFocus const insertAfter = Math.max(...rowsFocus); const rsFilter = [...newData.slice(0, insertAfter + 1), ...duplicatedItems, ...newData.slice(insertAfter + 1)]; // const rs = updateOrInsertInOrder(originData, rsFilter) const rs = updateOrInsert(originData, rsFilter); // const rs2 = mergeWithFilter(originData, rsFilter) triggerChangeData?.(rs, 'DUPLICATE'); }, [dataSource, originData, rowsFocus, triggerChangeData]); // thêm n dòng bên trên const handleInsertBefore = React.useCallback((item, n) => { const defaultRowValue = getDefaultValue(defaultValue); // const rowId = defaultRowValue && defaultRowValue.id ? defaultRowValue.id : newGuid() const record = flattenData(childrenColumnName, dataSource)[rowsFocus[rowsFocus.length - 1]]; if (item.onClick) { item.onClick({ toolbar: item }); } else { if (!record?.parentId) { // Cập nhật data mới // const newData = [...dataSource] const newData = [...originData]; const newRows = Array.from({ length: n }).map(() => defaultRowValue ? { ...defaultRowValue, id: undefined, rowId: newGuid() } : { id: undefined, rowId: newGuid() }); const kkk = getAllRowKey(newRows) ?? []; const rs = mergedFilterKeys ? [...mergedFilterKeys, ...kkk] : [...kkk]; setMergedFilterKeys?.(rs); const index = newData.findIndex(obj => obj[rowKey] === record[rowKey]); newData.splice(index, 0, ...newRows); triggerChangeData?.(newData, 'INSERT_BEFORE'); } else { // const newData = [...dataSource] const newData = [...originData]; const parent = findItemByKey(newData, rowKey, record.parentId); const newRows = Array.from({ length: n }).map(() => defaultRowValue ? { ...defaultRowValue, id: undefined, rowId: newGuid(), parentId: parent.rowId } : { id: undefined, rowId: newGuid(), parentId: parent.rowId }); // Cập nhật childData mới const childData = parent?.children ? [...parent.children] : []; const index = childData.findIndex(obj => obj[rowKey] === record[rowKey]); childData.splice(index, 0, ...newRows); const newRowData = { ...parent, children: childData }; const newDataSource = updateArrayByKey(newData, newRowData, rowKey); triggerChangeData?.(newDataSource, 'INSERT_BEFORE'); } } }, [dataSource, defaultValue, mergedFilterKeys, originData, rowKey, rowsFocus, setMergedFilterKeys, triggerChangeData]); //thêm 1 dòng bên dưới const handleInsertAfter = React.useCallback((item, n) => { const defaultRowValue = getDefaultValue(defaultValue); const insertAfter = Math.max(...rowsFocus); const record = flattenData(childrenColumnName, dataSource)[insertAfter]; // const record: RecordType = flattenData(childrenColumnName, originData)[rowsFocus[rowsFocus.length - 1]] // const record = getRecordByKey() if (item.onClick) { item.onClick({ toolbar: item }); } else { if (!record?.parentId) { // Cập nhật data mới const newData = [...originData]; const newRows = Array.from({ length: n }).map(() => defaultRowValue ? { ...defaultRowValue, id: undefined, rowId: newGuid() } : { id: undefined, rowId: newGuid() }); const kkk = getAllRowKey(newRows) ?? []; const rs = mergedFilterKeys ? [...mergedFilterKeys, ...kkk] : [...kkk]; setMergedFilterKeys?.(rs); const index = newData.findIndex(obj => obj[rowKey] === record[rowKey]); newData.splice(index + 1, 0, ...newRows); triggerChangeData?.(newData, 'INSERT_AFTER'); } else { const newData = [...originData]; const parent = findItemByKey(newData, rowKey, record.parentId); const newRows = Array.from({ length: n }).map(() => defaultRowValue ? { ...defaultRowValue, id: undefined, rowId: newGuid(), parentId: parent.rowId } : { id: undefined, rowId: newGuid(), parentId: parent.rowId }); const kkk = getAllRowKey(newRows) ?? []; const rs = mergedFilterKeys ? [...mergedFilterKeys, ...kkk] : [...kkk]; setMergedFilterKeys?.(rs); // Cập nhật childData mới const childData = parent?.children ? [...parent.children] : []; const index = childData.findIndex(obj => obj[rowKey] === record[rowKey]); childData.splice(index + 1, 0, ...newRows); const newRowData = { ...parent, children: childData }; const newDataSource = updateArrayByKey(newData, newRowData, rowKey); triggerChangeData?.(newDataSource, 'INSERT_BEFORE'); } } }, [defaultValue, dataSource, rowsFocus, originData, mergedFilterKeys, setMergedFilterKeys, triggerChangeData, rowKey]); const handleInsertChild = React.useCallback(item => { const defaultRowValue = getDefaultValue(defaultValue); const rowId = newGuid(); const record = flattenData(childrenColumnName, dataSource)[rowsFocus[rowsFocus.length - 1]]; if (item.onClick) { item.onClick({ toolbar: item }); } else { // const newData = [...dataSource] const newData = [...originData]; let newElement; if (!record.children || record.children.length === 0) { newElement = { ...record, children: [{ ...defaultRowValue, parentId: record.rowId, rowId }] }; } else { newElement = { ...record, children: [...record.children, { ...defaultRowValue, parentId: record.rowId, rowId }] }; } const rs = mergedFilterKeys ? [...mergedFilterKeys, rowId] : [rowId]; setMergedFilterKeys?.(rs); const newDataSource = updateArrayByKey(newData, newElement, rowKey); triggerChangeData?.(newDataSource, 'INSERT_CHILDREN'); } const key = getRowKey(record, dataSource.indexOf(record)); // let newExpandedKeys: Key[]; const hasKey = mergedExpandedKeys.has(key); if (!hasKey) { const newExpandedKeys = [...mergedExpandedKeys, key]; setInnerExpandedKeys(newExpandedKeys); } }, [dataSource, defaultValue, getRowKey, mergedExpandedKeys, rowKey, rowsFocus, triggerChangeData]); const handleDeleteRows = React.useCallback(item => { // setTimeout(() => { // onAddBgSelectedCell(selectedCells.current, id) // onAddBorderSelectedCell(selectedCells.current, id) // }) if (item.onClick) { item.onClick({ toolbar: item }); } else { // const filterData = flattenArray([...dataSource]) const filterData = flattenArray([...originData]); const indexesToDelete = [...rowsFocus]; // Sắp xếp giảm dần để xóa từ cuối lên đầu indexesToDelete.sort((a, b) => b - a).forEach(index => { filterData.splice(index, 1); }); // const newData = updateOrInsert(flattenArray([...originData]), filterData) // const rs = unFlattenData(filterData); triggerChangeData?.([...rs], 'DELETE_ROWS'); } setTimeout(() => { onAddBorderSelectedCell(selectedCells.current, id); showDraggingPoint(selectedCells.current, id); }, 0); }, [id, originData, rowsFocus, triggerChangeData]); const handleDeleteAll = React.useCallback(() => { triggerChangeData?.([], 'INSERT_BEFORE'); }, [triggerChangeData]); const handleDeleteContent = React.useCallback(() => { if (selectedCells.current.size > 0) { const newData = [...dataSource]; // colIndex => field const colIndexToField = flatColumns2(visibleCols).map(col => col.field); // Duyệt qua mỗi ô cần xóa for (const cell of selectedCells.current) { const [rowIndexStr, colIndexStr] = cell.split("-"); const rowIndex = Number(rowIndexStr); const colIndex = Number(colIndexStr); const field = colIndexToField[colIndex]; const column = flatColumns2(visibleCols)[colIndex]; const rowData = flattenData(childrenColumnName, dataSource)[rowIndex]; if (newData[rowIndex] && field && field in newData[rowIndex] && isEditable(column, rowData)) { // @ts-ignore newData[rowIndex][field] = ''; } } const rsFilterData = updateOrInsert(flattenArray([...originData]), newData); // triggerChangeData?.([...newData], 'DELETE_CONTENT') triggerChangeData?.([...rsFilterData], 'DELETE_CONTENT'); } }, [dataSource, originData, triggerChangeData, visibleCols]); const toolbarItemsBottom = useMemo(() => { if (!rowsFocus || rowsFocus.length === 0) { return toolbarItems?.filter(it => it.position === 'Bottom' && it.visible !== false && it.key !== 'DUPLICATE' && it.key !== 'INSERT_BEFORE' && it.key !== 'INSERT_AFTER' && it.key !== 'DELETE_ROWS' && it.key !== 'INSERT_CHILDREN').map(item => { if (item.key === 'ADD') { return { ...item, template: () => { return /*#__PURE__*/React.createElement(Fragment, null, item.key === 'ADD' && /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Dropdown.Button, { overlayClassName: 'be-popup-container', trigger: ['click'], style: { color: '#28c76f', borderColor: '#28c76f' }, className: 'toolbar-button toolbar-dropdown-button', menu: { items: itemsAdd, onClick: e => handleAddMulti(item, Number(e.key)) } }, /*#__PURE__*/React.createElement("span", { style: { color: '#28c76f' }, onClick: () => handleAddMulti(item, 1) }, item.label ? t ? t(item.label) : item.label : t ? t('Add item') : 'Add item')))); } }; } if (item.key === 'DELETE') { return { ...item, template: () => { return /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Button, { style: { color: '#eb4619', borderColor: '#eb4619' }, variant: 'outlined', onClick: handleDeleteAll, className: "d-flex toolbar-button" }, item.label ? t ? t(item.label) : item.label : t ? t('Delete all item') : 'Delete all item')); } }; } return { ...item }; }); } return toolbarItems?.filter(it => it.position === 'Bottom' && it.visible !== false).map(item => { if (item.key === 'ADD') { return { ...item, template: () => { return /*#__PURE__*/React.createElement(Fragment, null, item.key === 'ADD' && /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Dropdown.Button, { overlayClassName: 'be-popup-container', style: { color: '#28c76f', borderColor: '#28c76f' }, className: 'toolbar-button toolbar-dropdown-button', menu: { items: itemsAdd, onClick: e => handleAddMulti(item, Number(e.key)) } }, /*#__PURE__*/React.createElement("span", { style: { color: '#28c76f' }, onClick: () => handleAddMulti(item, 1) }, item.label ? t ? t(item.label) : item.label : t ? t('Add item') : 'Add item')))); } }; } if (item.key === 'DUPLICATE') { return { ...item, template: () => { return /*#__PURE__*/React.createElement(Fragment, null, item.key === 'DUPLICATE' && item.visible !== false && rowsFocus.length > 0 && /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Button, { style: { color: '#28c76f', borderColor: '#28c76f' }, variant: 'outlined', onClick: handleDuplicate, className: "d-flex toolbar-button" }, item.label ? t ? t(item.label) : item.label : t ? t('Duplicate') : 'Duplicate'))); } }; } if (item.key === 'INSERT_BEFORE') { return { ...item, template: () => { return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Dropdown.Button, { overlayClassName: 'be-popup-container', style: { color: '#28c76f', borderColor: '#28c76f' }, className: 'toolbar-button toolbar-dropdown-button', menu: { items: itemsAdd, onClick: e => handleInsertBefore(item, Number(e.key)) } }, /*#__PURE__*/React.createElement("span", { style: { color: '#28c76f' }, onClick: () => handleInsertBefore(item, 1) }, item.label ? t ? t(item.label) : item.label : t ? t('Insert item before') : 'Insert item before')))); } }; } if (item.key === 'INSERT_AFTER') { return { ...item, template: () => { return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Dropdown.Button, { overlayClassName: 'be-popup-container', style: { color: '#28c76f', borderColor: '#28c76f' }, className: 'toolbar-button toolbar-dropdown-button', menu: { items: itemsAdd, onClick: e => handleInsertAfter(item, Number(e.key)) } }, /*#__PURE__*/React.createElement("span", { style: { color: '#28c76f' }, onClick: () => handleInsertAfter(item, 1) }, item.label ? t ? t(item.label) : item.label : t ? t('Insert item after') : 'Insert item after')))); } }; } if (item.key === 'INSERT_CHILDREN') { return { ...item, template: () => { return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Button, { style: { color: '#28c76f', borderColor: '#28c76f' }, variant: 'outlined', onClick: () => handleInsertChild(item), className: "d-flex toolbar-button" }, item.label ? t ? t(item.label) : item.label : t ? t('Insert item children') : 'Insert item children'))); } }; } if (item.key === 'DELETE') { return { ...item, template: () => { return /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Button, { style: { color: '#eb4619', borderColor: '#eb4619' }, variant: 'outlined', onClick: handleDeleteAll, className: "d-flex toolbar-button" }, item.label ? t ? t(item.label) : item.label : t ? t('Delete all item') : 'Delete all item')); } }; } if (item.key === 'DELETE_ROWS') { return { ...item, template: () => { return /*#__PURE__*/React.createElement("div", { className: classnames(`be-toolbar-item`, item?.className) }, /*#__PURE__*/React.createElement(Button, { style: { color: '#eb4619', borderColor: '#eb4619' }, variant: 'outlined', onClick: () => handleDeleteRows(item), className: "d-flex toolbar-button" }, t ? `${t('Delete')} ${rowsFocus.length} ${t('row')}` : `Delete ${rowsFocus.length} item`)); } }; } return { ...item }; }); }, [handleAddMulti, handleDeleteAll, handleDeleteRows, handleDuplicate, handleInsertAfter, handleInsertBefore, handleInsertChild, itemsAdd, rowsFocus, t, toolbarItems]); const { control, handleSubmit, setValue, trigger, getValues, reset, formState: { errors } } = useForm({ mode: 'onChange', resolver: validate ? yupResolver(validate) : undefined }); // const isEditing = React.useCallback((record: RecordType) => { // return record[rowKey as any] === editingKey.current // }, [editingKey, rowKey]) React.useEffect(() => { const handleClickOutside = event => { const element = event.target; // const tableId = id ? document.getElementById(id) : undefined // const tableBodies = document.getElementsByClassName("ui-rc-table-tbody"); const container = document.querySelector(".be-popup-container"); const containerContextMenu = document.querySelector(".popup-context-menu"); const tableBody = document.querySelector(`#${id} .ui-rc-table-tbody .ui-rc-table-tbody-virtual-holder`); // const containerHidden = document.querySelector(".be-popup-container.ant-picker-dropdown-hidden") // const toolbarContainer = document.getElementsByClassName("ui-rc-toolbar"); const itemContainer = document.querySelector(`#${id} .ui-rc-toolbar-selection-overflow-item`); const itemHeader = document.querySelector(`#${id} .ui-rc-table-thead`); const isInsideContainer = element.closest(".be-popup-container") && container; const isInsideContainerContext = containerContextMenu && element.closest(".popup-context-menu"); const isInsideToolbar = element.closest(`.ui-rc-toolbar-selection-overflow-item`) && itemContainer; const isInsideHeader = itemHeader && itemHeader.contains(event.target); if (isInsideContainer || isInsideToolbar || isInsideHeader || isInsideContainerContext) { return; } // if (ref.current && !ref.current.contains(event.target)) { // if (ref.current && tableId && !tableId.contains(event.target as Node)) { if (ref.current && tableBody && !tableBody.contains(event.target)) { if (editingKey.current) { onBlur?.(dataSource); } setTimeout(() => { // setEditingKey('') editingKey.current = ''; }); isSelecting.current = false; startCell.current = null; // setSelectedCells(new Set()) // setRowsSelected(new Set()) onRemoveBgSelectedCell(selectedCells.current, id); onRemoveBorderSelectedCell(selectedCells.current, id); hideDraggingPoint(selectedCells.current, id); rowsSelected.current = new Set(); selectedCells.current = new Set(); setRangeCells(new Set()); } }; // document.addEventListener('click', handleClickOutside) document.addEventListener('mousedown', handleClickOutside); // document.addEventListener('touchstart', handleClickOutside) return () => { // document.removeEventListener('click', handleClickOutside) document.removeEventListener('mousedown', handleClickOutside); // document.removeEventListener('touchstart', handleClickOutside) }; }, [dataSource, id, onBlur]); const triggerDragPaste = (pastesArray, ctrlKey) => { const mergedSet = new Set([...selectedCells.current, ...pastesArray]); const tmpCols = { ...visibleCols }; const rowSelectedFirst = getFirstSelectCell(selectedCells.current).row; const rowPasteLast = getLastSelectCell(pasteCells.current).row; const selectedArray = Array.from(selectedCells.current).map(key => { const [row, col] = key.split("-").map(Number); const columnKey = tmpCols[col].field; // @ts-ignore return { row, col, value: flattenData(childrenColumnName, dataSource)[row][columnKey] }; // return { row, col, value: '' }; }); const copyRows = selectedArray.map(it => ({ ...flattenData(childrenColumnName, dataSource)[it.row] })); // Xác định min/max row và col để sắp xếp dữ liệu const minRow = Math.min(...selectedArray.map(cell => cell.row)); const maxRow = Math.max(...selectedArray.map(cell => cell.row)); const minCol = Math.min(...selectedArray.map(cell => cell.col)); const maxCol = Math.max(...selectedArray.map(cell => cell.col)); // Tạo dữ liệu dạng bảng (mảng 2D) const table = Array.from({ length: maxRow - minRow + 1 }, () => Array(maxCol - minCol + 1).fill("")); // Gán giá trị vào bảng selectedArray.forEach(({ row, col, value }) => { table[row - minRow][col - minCol] = value; }); let newRange; if (rowPasteLast > rowSelectedFirst) { // kéo xuóng newRange = ctrlKey ? addRowsDownWithCtrl(table, getRowsPasteIndex(pastesArray).length) : addRowsDown(table, getRowsPasteIndex(pastesArray).length); } else { // kéo lên newRange = ctrlKey ? addRowsUpWithCtrl(table, getRowsPasteIndex(pastesArray).length) : addRowsUp(table, getRowsPasteIndex(pastesArray).length); } // const record = flattenData(childrenColumnName, dataSource)[getFirstSelectCell(pastesArray).row] // if (!record?.parentId) { // Cập nhật data mới const newData = flattenArray([...dataSource]); // const newData = flattenArray([...originData]) // Lấy vị trí bắt đầu // const { row: startRow, col: startCol } = selectedCell; const startRow = getFirstSelectCell(pastesArray).row; const startCol = getFirstSelectCell(selectedCells.current).col; const pastedRows = []; const pastedColumns = new Set(); newRange.addedRows.forEach((rowValues, rowIndex) => { const targetRow = startRow + rowIndex; // Nếu vượt quá số dòng hiện có, thêm dòng mới if (targetRow >= newData.length) { // @ts-ignore newData.push({ id: undefined, rowId: newGuid() }); } rowValues.forEach((cellValue, colIndex) => { const targetCol = startCol + colIndex; if (targetCol >= tmpCols.length) { // Không vượt quá số cột return; } // @ts-ignore const columnKey = tmpCols[targetCol].field; // @ts-ignore newData[targetRow] = { ...newData[targetRow], [columnKey]: typeof cellValue === 'string' ? cellValue.trim() : cellValue }; pastedColumns.add(columnKey); }); // Lưu dòng được paste pastedRows.push(newData[targetRow]); }); const pastedColumnsArray = Array.from(pastedColumns) ?? []; // const rsFilterData = updateDataByFilter(flattenArray([...originData]), newData) const rsFilterData = updateOrInsert(flattenArray([...originData]), newData); // const rsFilterData = mergeWithFilter(flattenArray([...originData]), newData) // const rsFilterData = mergeWithFilter2(flattenArray([...originData]), newData) const rs = unFlattenData(rsFilterData); triggerPaste?.(pastedRows, pastedColumnsArray, rs, copyRows); // } /// cập nhật cell class if (selectedCells.current && selectedCells.current.size > 0) { // onRemoveBgSelectedCell(rangeCells, id) // onRemoveBorderSelectedCell(rangeCells, id) } // selectedCells.current = sortedSetASC(mergedSet) hideDraggingPoint(selectedCells.current, id); const newCells = sortedSetASC(mergedSet); selectedCells.current = newCells; onAddBgCellIndex(newCells, id); setRangeCells(newCells); onAddBgSelectedCell(newCells, id); onAddBorderSelectedCell(newCells, id); setTimeout(() => { showDraggingPoint(newCells, id); }, 50); // setPasteCells(new Set()) if (pasteCells.current && pasteCells.current.size > 0) { removeClassBorderPasteCell(pasteCells.current, 'up', id); } pasteCells.current = new Set(); }; const handlePasted = (record, indexCol, rowNumber, pasteData) => { const rows = pasteData.slice(0, onCellPaste?.maxRowsPaste ?? 200); if (!record?.parentId) { // Cập nhật data mới const newData = flattenArray([...dataSource]); // const indexRows = newData.findIndex((it) => it[rowKey as any] === record[rowKey]) // Lấy vị trí bắt đầu // const { row: startRow, col: startCol } = selectedCell; const startRow = newData.findIndex(it => it[rowKey] === record[rowKey]); const startCol = indexCol; // const flattData = flattenArray(newData); const pastedRows = []; const pastedColumns = new Set(); rows.forEach((rowValues, rowIndex) => { const targetRow = startRow + rowIndex; // Nếu vượt quá số dòng hiện có, thêm dòng mới if (targetRow >= newData.length) { // @ts-ignore // newData.push({ id: newGuid()}); newData.push({ id: undefined, rowId: newGuid() }); } rowValues.forEach((cellValue, colIndex) => { const targetCol = startCol + colIndex; if (targetCol >= visibleCols.length) { // Không vượt quá số cột return; } const columnTarget = visibleCols[targetCol]; const isEdit = typeof columnTarget.editEnable === 'function' ? columnTarget.editEnable(newData[targetRow]) : columnTarget.editEnable; if (isEdit) { const columnKey = visibleCols[targetCol].field; // const isEdit = typeof columnTarget.editEnable === 'function' ? columnTarget.editEnable(newData[targetRow]) : columnTarget.editEnable if (columnTarget.type === 'number' && isFormattedNumber(cellValue.trim())) { const colFormat = typeof columnTarget.format === 'function' ? columnTarget.format(record) : columnTarget.format; const valuePasteFormat = detectSeparators(cellValue.trim()); const cellFormat = getFormat(colFormat, format); const thousandSeparator = valuePasteFormat?.thousandSeparator ?? cellFormat?.thousandSeparator; const decimalSeparator = valuePasteFormat?.decimalSeparator ?? cellFormat?.decimalSeparator; const dec = cellFormat?.decimalScale; const numericFormatProps = { thousandSeparator: checkThousandSeparator(thousandSeparator, decimalSeparator), decimalSeparator: checkDecimalSeparator(thousandSeparator, decimalSeparator), allowNegative: cellFormat?.allowNegative ?? true, prefix: cellFormat?.prefix, suffix: cellFormat?.suffix, decimalScale: dec, fixedDecimalScale: cellFormat?.fixedDecimalScale ?? false }; const val = removeNumericFormat(cellValue.trim(), undefined, numericFormatProps); // @ts-ignore newData[targetRow] = { ...newData[targetRow], [columnKey]: Number(val) }; } else { // @ts-ignore newData[targetRow] = { ...newData[targetRow], [columnKey]: cellValue.trim() }; } pastedColumns.add(columnKey); } }); // Lưu dòng được paste pastedRows.push(newData[targetRow]); }); const pastedColumnsArray = Array.from(pastedColumns) ?? []; // const rsFilterData = updateDataByFilter(flattenArray([...originData]), newData) // const rsFilterData = mergeWithFilter(flattenArray([...originData]), newData) const rsFilterData = updateOrInsert(flattenArray([...originData]), newData); const rs = unFlattenData(rsFilterData); triggerPaste?.(pastedRows, pastedColumnsArray, rs, []); } else { // Cập nhật data mới // const newData = flattenArray([...dataSource]) const parent = findItemByKey(dataSource, rowKey, record.parentId); // Cập nhật childData mới const childData = parent?.children ? [...parent.children] : []; // Lấy vị trí bắt đầu // const { row: startRow, col: startCol } = selectedCell; const startRow = childData.findIndex(it => it[rowKey] === record[rowKey]); const startCol = indexCol; const pastedRows = []; const pastedColumns = new Set(); rows.forEach((rowValues, rowIndex) => { const targetRow = startRow + rowIndex; // Nếu vượt quá số dòng hiện có, thêm dòng mới if (targetRow >= childData.length) { childData.push({ id: undefined, rowId: newGuid(), parentId: parent[rowKey ?? 'id'] }); } rowValues.forEach((cellValue, colIndex) => { const targetCol = startCol + colIndex; if (targetCol >= visibleCols.length) { // Không vượt quá số cột return; } const columnTarget = visibleCols[targetCol]; const isEdit = typeof columnTarget.editEnable === 'function' ? columnTarget.editEnable(childData[targetRow]) : columnTarget.editEnable; if (isEdit) { // @ts-ignore const columnKey = visibleCols[targetCol].field; // @ts-ignore childData[targetRow] = { ...childData[targetRow], [columnKey]: cellValue.trim() }; pastedColumns.add(columnKey); } }); // Lưu dòng được paste pastedRows.push(childData[targetRow]); }); const pastedColumnsArray = Array.from(pastedColumns) ?? []; const newRowData = { ...parent, children: childData }; // item đã được filter // const newDataSource = updateArrayByKey(newData, newRowData, rowKey as string) const newDataSource = updateArrayByKey(originData, newRowData, rowKey); // // // const rsFilterData = updateDataByFilter(flattenArray([...originData]), flattenArray(newDataSource)) // // const rsFilterData = mergeWithFilter(flattenArray([...originData]), flattenArray(newDataSource)) // const rsFilterData1 = updateOrInsert(flattenArray([...originData]), flattenArray([...newDataSource])) // // // // const rs = unFlattenData(rsFilterData) // const rs1 = unFlattenData(rsFilterData1) triggerPaste?.(pastedRows, pastedColumnsArray, newDataSource, []); } }; const handlePaste = (record, indexCol, rowNumber, e) => { // const clipboard: any = (e.clipboardData || (window && window?.Clipboard)).getData("text") const pasteData = e.clipboardData.getData("text/plain"); // Chuyển đổi dữ liệu từ clipboard thành mảng const rowsPasted = pasteData.split("\n").filter(row => row !== '').map(row => // const rows = pasteData.split("\n").map((row: any) => row.replace(/\r/g, "").split("\t") // { // console.log('row', row) // return row.replace(/\r/g, "").split("\t") // } ); if (rowsPasted.length > (onCellPaste?.maxRowsPaste ?? 200)) { // bật popup thông báo Modal.confirm({ content: /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Paragraph, { style: { marginBottom: '.25rem', fontSize: 14 } }, "D\u1EEF li\u1EC7u sao ch\xE9p v\u01B0\u1EE3t qu\xE1 s\u1ED1 d\xF2ng cho ph\xE9p (500 d\xF2ng).Ph\u1EA7n m\u1EC1n s\u1EBD ch\u1EC9 l\u1EA5y 500 d\xF2ng \u0111\u1EA7u ti\xEAn."), /*#__PURE__*/React.createElement(Title, { level: 5, style: { marginTop: '.75rem' } }, "B\u1EA1n c\xF3 mu\u1ED1n ti\u1EBFp t\u1EE5c sao ch\xE9p kh\xF4ng?")), centered: true, className: 'be-popup-container', onOk: () => { handlePasted(record, indexCol, rowNumber, rowsPasted); } // footer: (_, { OkBtn, CancelBtn