UNPKG

es-grid-template

Version:

es-grid-template

529 lines (515 loc) 17.2 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import React, { Fragment } from 'react'; import { createStyles } from 'antd-style'; import { numericFormatter } from "react-numeric-component"; import { Empty, Table, Toolbar } from "rc-master-ui"; // import Table from "../../core/table" import 'dayjs/locale/es'; import 'dayjs/locale/vi'; import ContextMenu from "./ContextMenu"; import classNames from "classnames"; import { checkDecimalSeparator, checkThousandSeparator, // filterDataByColumns2, // filterDataByColumns3, filterDataByColumns4, getFormat, // convertFlatColumn, isEmpty, // newGuid, // removeColumns, sumDataByField // updateArrayByKey } from "./hooks"; // import {ConfigProvider} from "antd"; import { flatColumns } from "./hooks/columns"; import Pagination from "rc-master-ui/es/pagination"; import ComponentSpinner from "./LoadingSpinner"; import { ColumnsChoose } from "./ColumnsChoose"; import useMergedState from "rc-util/es/hooks/useMergedState"; import AdvanceFilter from "./AdvanceFilter"; import { Tooltip } from "react-tooltip"; const convertFilters = filters => { const result = []; filters.forEach(({ key, column, filteredKeys, operator }) => { if (!filteredKeys || filteredKeys.length === 0) { return; } if (column?.typeFilter === "DateRange" && filteredKeys.length === 2) { result.push({ key, field: column?.dataIndex, value: filteredKeys[0], predicate: "and", operator: "greaterthanorequal" }, { key, field: column?.dataIndex, value: filteredKeys[1], predicate: "and", operator: "lessthanorequal" }); } else if (column?.typeFilter === "NumberRange") { if ((filteredKeys[0] || filteredKeys[0] === 0) && !filteredKeys[1]) { result.push({ key, field: column?.dataIndex, value: filteredKeys[0], predicate: "and", operator: "greaterthanorequal" }); } if ((filteredKeys[1] || filteredKeys[1] === 0) && !filteredKeys[0]) { result.push({ key, field: column?.dataIndex, value: filteredKeys[1], predicate: "and", operator: "lessthanorequal" }); } if ((filteredKeys[0] || filteredKeys[0] === 0) && (filteredKeys[1] || filteredKeys[1] === 0)) { result.push({ key, field: column?.dataIndex, value: filteredKeys[0], predicate: "and", operator: "greaterthanorequal" }, { key, field: column?.dataIndex, value: filteredKeys[1], predicate: "and", operator: "lessthanorequal" }); } } else if (column?.typeFilter === 'Checkbox') { filteredKeys.forEach(value => { result.push({ key, field: column?.dataIndex, value, predicate: "or", operator }); }); } else { result.push({ key, field: column?.dataIndex, value: filteredKeys[0], predicate: 'and', operator }); } }); return result; }; const useStyle = createStyles(({ css }) => { const antCls = 'ui-rc'; return { customTable: css` ${antCls}-table { ${antCls}-table-container { ${antCls}-table-body, ${antCls}-table-content { scrollbar-width: thin; scrollbar-color: #eaeaea transparent; scrollbar-gutter: stable; } } } ` }; }); // type OnChange = NonNullable<TableProps<any>['onChange']>; const EMPTY_LIST = []; const TableGrid = props => { const { id, columns, tableRef, dataSource, locale, expandable, rowHoverable, title, format, virtual = true, t, lang, contextMenuOpen, className, contextMenuItems: propContextMenuItems, contextMenuHidden, contextMenuClick, recordDoubleClick, toolbarItems, showColumnChoose, showAdvanceFilter, onFilter, triggerFilter, selectionSettings, rowSelection, rowSelected, rowKey = 'id', pagination, scroll, onFilterClick, dataSourceFilter: propDataSourceFilter, loading, triggerChangeColumns, triggerGroupColumns, summary, showToolbar, onSorter, bottomToolbar, groupSetting, groupAble, getRowKey, groupColumns, groupToolbar, showEmptyText, setIsFilter, ...rest } = props; const { styles } = useStyle(); const { mode, type, checkboxOnly, hideSelectAll, columnWidth, selectedRowKeys, defaultSelectedRowKeys } = selectionSettings || {}; const clickRef = React.useRef(null); const menuRef = React.useRef(null); const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const [menuVisible, setMenuVisible] = React.useState(false); const [selectedRowData, setSelectedRowData] = React.useState(null); const [position, setPosition] = React.useState({ x: 0, y: 0, viewportWidth, viewportHeight }); const [filterStates, setFilterState] = React.useState(null); // const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>(defaultSelected); // ========================= Keys ========================= const [mergedSelectedKeys, setMergedSelectedKeys] = useMergedState(selectedRowKeys || defaultSelectedRowKeys || EMPTY_LIST, { value: selectedRowKeys }); // Reset if rowSelection reset React.useEffect(() => { if (!selectionSettings) { setMergedSelectedKeys(EMPTY_LIST); } }, [!!selectionSettings]); const contextMenuItems = React.useMemo(() => { if (typeof contextMenuHidden === "function" && propContextMenuItems && selectedRowData) { const hiddenItems = contextMenuHidden({ rowInfo: { rowData: selectedRowData } }); return propContextMenuItems.filter(item => !hiddenItems.includes(item?.key)); } if (contextMenuHidden && typeof contextMenuHidden !== 'function' && propContextMenuItems) { return propContextMenuItems.filter(item => !contextMenuHidden.includes(item?.key)); } return propContextMenuItems; }, [propContextMenuItems, contextMenuHidden, selectedRowData]); React.useLayoutEffect(() => { setMenuVisible(false); }, []); const onContextMenu = data => event => { event.preventDefault(); // Ngăn chặn menu mặc định của trình duyệt setSelectedRowData(data); contextMenuOpen?.({ rowInfo: { rowData: data }, event }); setMenuVisible(true); // Đợi DOM cập nhật và lấy kích thước menu setTimeout(() => { const menuElement = menuRef.current; // Lấy menu từ DOM const menuWidth = menuElement?.offsetWidth || 200; // Mặc định 200px nếu chưa render const menuHeight = menuElement?.offsetHeight; // Mặc định 450px nếu chưa render // Điều chỉnh vị trí menu let x = event.clientX; let y = event.clientY; if (x + menuWidth > viewportWidth) { x = x - menuWidth - 10; // Cách cạnh phải 10px } if (y + menuHeight > viewportHeight) { if (y < menuHeight) { y = 10; } else { y = y - 10 - menuHeight; // Cách cạnh dưới 10px } } setPosition(prevState => ({ ...prevState, x, y })); }, 100); if (!menuVisible) { document.addEventListener(`click`, function onClickOutside(e) { const element = e.target; const menuContainer = document.querySelector(".popup-context-menu"); const isInsideContainer = element.closest(".popup-context-menu") && menuContainer; if (isInsideContainer) { return; } setMenuVisible(false); document.removeEventListener(`click`, onClickOutside); }); } }; const handleRowClick = () => () => { // const key = getRowKey(record, index); if (checkboxOnly !== true) { if (type === 'single') {} } }; const handleRowDoubleClick = (record, index) => e => { if (clickRef.current) { clearTimeout(clickRef.current); clickRef.current = null; } recordDoubleClick?.({ e, rowIndex: index, rowData: record }); }; const onSelectChange = (keys, selectedRows, info, selectedRow) => { if (info.type === 'all') { setMergedSelectedKeys(keys); rowSelected?.({ selected: selectedRows, type: 'rowSelected', rowData: {} }); } else { if (selectionSettings?.type === 'multiple') { setMergedSelectedKeys(keys); rowSelected?.({ selected: selectedRows, type: 'rowSelected', rowData: selectedRow }); } else { // @ts-ignore setMergedSelectedKeys(keys); rowSelected?.({ selected: selectedRows, type: 'rowSelected', rowData: selectedRow }); } } }; const handleChange = sorter => { onSorter?.(sorter); }; const handleOnFilter = queries => { if (onFilter) { onFilter?.(convertFilters(queries)); } else { setFilterState(convertFilters(queries)); if (queries && queries.length > 0) { setIsFilter?.(true); } else { setIsFilter?.(false); } } }; return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(ContextMenu, { open: menuVisible, pos: position, setOpen: setMenuVisible, menuRef: menuRef, contextMenuItems: contextMenuItems, contextMenuClick: contextMenuClick, rowData: selectedRowData }), /*#__PURE__*/React.createElement(Table, _extends({ ref: tableRef }, rest, { tableLayout: 'fixed', locale: { ...locale, emptyText: showEmptyText !== false ? /*#__PURE__*/React.createElement(Empty, { image: Empty.PRESENTED_IMAGE_SIMPLE, description: locale?.emptyText }) : /*#__PURE__*/React.createElement(React.Fragment, null) }, loading: { spinning: columns && columns.length === 0 || loading === true, indicator: /*#__PURE__*/React.createElement(ComponentSpinner, null) } // dataSource={columns && columns.length > 0 ? filterDataByColumns3(dataSource, filterStates) : []} , dataSource: columns && columns.length > 0 ? filterDataByColumns4(dataSource, filterStates) : [], className: classNames(className, { 'table-none-column-select': selectionSettings?.mode === undefined && selectionSettings?.type !== 'multiple' }, styles.customTable), bordered: true, virtual: virtual, columns: columns, rowKey: rowKey, rowHoverable: rowHoverable, size: "small", scroll: scroll ? scroll : { y: 500 }, onRow: (data, index) => { return { onDoubleClick: handleRowDoubleClick(data, index), onClick: handleRowClick(), onContextMenu: onContextMenu(data) }; }, rowSelection: columns && columns.length === 0 ? undefined : { ...selectionSettings, // type: selectionSettings?.mode, type: mode, columnWidth: columnWidth ?? 50, onChange: onSelectChange, // selectedRowKeys: mode === 'checkbox' && type === 'single' ? selectedRowKeys : undefined, selectedRowKeys: mergedSelectedKeys, // defaultSelectedRowKeys: selectionSettings?.defaultSelectedRowKeys, defaultSelectedRowKeys, preserveSelectedRowKeys: true, hideSelectAll: !type || type === 'single' || mode === 'radio' ? true : hideSelectAll ?? type !== 'multiple' } // onScroll={(event) => { // console.log('event', event) // }} , onFilter: val => { handleOnFilter(val); // triggerFilter?.(convertFilters(val)) // onFilter?.(convertFilters(val)) }, onChange: (paging, filters, sorter) => handleChange(sorter), title: showToolbar === false ? undefined : () => { return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, title?.(dataSource)), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '.75rem' } }, groupAble && groupToolbar?.(), toolbarItems && toolbarItems?.length > 0 && /*#__PURE__*/React.createElement("div", { style: { flex: 1, overflow: 'hidden' } }, /*#__PURE__*/React.createElement(Toolbar // @ts-ignore // style={{width: pagination && pagination.onChange && pagination?.position && pagination?.position[0] === 'topRight' ? `calc(100% - 650px - ${groupAble ? 50 : 0}px` : `calc(100% - 25px - ${groupAble ? 50 : 0}px`}} , { items: (toolbarItems ?? []).filter(it => it.position !== 'Bottom'), mode: 'scroll' })), /*#__PURE__*/React.createElement("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '.75rem' } }, pagination && pagination.onChange && pagination?.position && pagination?.position[0] === 'topRight' && /*#__PURE__*/React.createElement(Pagination, _extends({ showSizeChanger: true, responsive: true, size: 'small', rootClassName: 'top-pagination' // @ts-ignore , showTotal: (total, range) => `${range[0]}-${range[1]} / ${total} ${t ? t(pagination?.locale?.items ?? 'items') : 'items'}` }, pagination)), showColumnChoose && /*#__PURE__*/React.createElement(ColumnsChoose, { columns: columns, t: t, columnsGroup: groupColumns, triggerChangeColumns: triggerChangeColumns }), showAdvanceFilter && /*#__PURE__*/React.createElement(AdvanceFilter, { columns: columns, t: t // columnsGroup={groupColumns} // triggerChangeColumns={triggerChangeColumns} })))); }, expandable: { ...expandable }, summary: () => { if (typeof summary === 'function') { return summary(dataSource); } if (!summary) { return undefined; } return /*#__PURE__*/React.createElement(Table.Summary, { fixed: true }, /*#__PURE__*/React.createElement(Table.Summary.Row, null, flatColumns(!!mode ? [Table.SELECTION_COLUMN, ...columns] : [...columns]).filter(col => col.hidden !== true).map((col, index) => { // const cellFormat: IFormat | undefined = col.format ? typeof col.format === 'function' ? col.format({}) : col.format : format const colFormat = typeof col.format === 'function' ? col.format({}) : col.format; const cellFormat = getFormat(colFormat, format); const thousandSeparator = cellFormat?.thousandSeparator; const decimalSeparator = cellFormat?.decimalSeparator; // const dec = (col.format?.decimalScale || col.format?.decimalScale === 0) ? col.format?.decimalScale : format?.decimalScale const dec = cellFormat?.decimalScale; const sumValue = col.type === 'number' ? sumDataByField(filterDataByColumns4(dataSource, filterStates), col?.key) : 0; const value = !isEmpty(sumValue) ? dec || dec === 0 ? parseFloat(Number(sumValue).toFixed(dec)).toString() : sumValue.toString() : '0'; const cellValue = col.type === 'number' && col.isSummary !== false ? value : ''; const numericFormatProps = { thousandSeparator: checkThousandSeparator(thousandSeparator, decimalSeparator), decimalSeparator: checkDecimalSeparator(thousandSeparator, decimalSeparator), allowNegative: cellFormat?.allowNegative ?? false, prefix: cellFormat?.prefix, suffix: cellFormat?.suffix, decimalScale: dec, fixedDecimalScale: cellFormat?.fixedDecimalScale ?? false }; return /*#__PURE__*/React.createElement(Table.Summary.Cell, { key: col.key, index: index, align: col.align ?? 'right', className: 'ui-rc-table-cell-ellipsis' }, col.summaryTemplate ? col.summaryTemplate(cellValue, col.key) : numericFormatter(cellValue, numericFormatProps)); }))); }, pagination: !pagination || pagination && pagination?.onChange ? false : { showTotal: (total, range) => `${range[0]}-${range[1]} / ${total} items`, ...pagination } })), /*#__PURE__*/React.createElement("div", null), pagination && pagination.onChange && !pagination.position && /*#__PURE__*/React.createElement(Pagination // style={{padding: '0.75rem 1rem'}} , _extends({ rootClassName: 'pagination-template', showSizeChanger: true, responsive: true, size: 'small' // @ts-ignore , showTotal: (total, range) => `${range[0]}-${range[1]} / ${total} ${t ? t(pagination?.locale?.items ?? 'items') : 'items'}` }, pagination)), bottomToolbar?.(), /*#__PURE__*/React.createElement(Tooltip, { id: `${id}-tooltip-header`, style: { zIndex: 1999 } })); }; export default TableGrid;