es-grid-template
Version:
es-grid-template
493 lines (470 loc) • 16.7 kB
JavaScript
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, sumByField
// 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";
import { Maximize, Minimize } from 'becoxy-icons';
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,
actionTemplate,
handleFullScreen,
fullScreen,
isFullScreen,
...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<any>(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 {
const keySet = new Set(keys);
// @ts-ignore
if (!keySet.has(selectedRow[rowKey])) {
setMergedSelectedKeys([]);
rowSelected?.({
selected: [],
type: 'rowSelected',
rowData: selectedRow
});
} else {
// @ts-ignore
setMergedSelectedKeys([selectedRow[rowKey]]);
rowSelected?.({
// @ts-ignore
selected: [selectedRow],
type: 'rowSelected',
rowData: selectedRow
});
}
}
}
};
// const handleChange = (sorter: any) => {
// onSorter?.(sorter)
// }
// const handleOnFilter = (queries: any) => {
//
// 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) : []}
,
dataSource: dataSource,
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: any) => {
// handleOnFilter(val)
// // triggerFilter?.(convertFilters(val))
// // onFilter?.(convertFilters(val))
//
// }}
// onChange={(paging, filters, sorter) => handleChange(sorter)}
,
title: showToolbar !== false || fullScreen !== false ? () => {
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'
})), fullScreen !== false && (isFullScreen ? /*#__PURE__*/React.createElement(Minimize, {
fontSize: 16,
onClick: () => handleFullScreen?.(),
"data-tooltip-id": "tooltip-icon",
"data-tooltip-content": t ? t('Minimized') : 'Minimized'
}) : /*#__PURE__*/React.createElement(Maximize, {
fontSize: 16,
onClick: () => handleFullScreen?.(),
"data-tooltip-id": "tooltip-icon",
"data-tooltip-content": t ? t('Full screen') : 'Full screen'
})), /*#__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)), typeof actionTemplate === 'function' ? actionTemplate() : actionTemplate, 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}
}))));
} : undefined,
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) as any[], col?.key as string) : 0
const sumValue = col.type === 'number' ? sumByField(filterDataByColumns4(dataSource, [], []), col?.field) : 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 numberValue = Number(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(numberValue, 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,
maxWidth: 350
}
}), /*#__PURE__*/React.createElement(Tooltip, {
id: "tooltip-icon"
}));
};
export default TableGrid;