UNPKG

es-grid-template

Version:

es-grid-template

1,530 lines (1,462 loc) 77.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.addRowIdArray = void 0; exports.addRowsDown = addRowsDown; exports.addRowsDownWithCtrl = addRowsDownWithCtrl; exports.addRowsUp = addRowsUp; exports.addRowsUpWithCtrl = addRowsUpWithCtrl; exports.appendIfNotExists = void 0; exports.areStringArraysEqual = areStringArraysEqual; exports.arraysEqualIgnoreOrderFast = arraysEqualIgnoreOrderFast; exports.checkThousandSeparator = exports.checkFieldKey = exports.checkDecimalSeparator = void 0; exports.compareDate = compareDate; exports.compareDates = compareDates; exports.convertArrayWithIndent = void 0; exports.convertColumnsToTreeData = convertColumnsToTreeData; exports.convertFlatColumn1 = exports.convertFilters = exports.convertDayjsToDate = exports.convertDateToDayjs = void 0; exports.convertFormat = convertFormat; exports.convertToObjTrue = exports.convertToObj = exports.convertLabelToTitle = void 0; exports.countUnselectedChildren = countUnselectedChildren; exports.detectSeparators = exports.customWeekStartEndFormat = void 0; exports.excludeItems = excludeItems; exports.extendsObject = void 0; exports.filterByIds = filterByIds; exports.filterDataByColumns = filterDataByColumns; exports.findAllChildrenKeys2 = findAllChildrenKeys2; exports.findFirst = findFirst; exports.genPresets = exports.flattenData = exports.flattenArray = exports.flatColumnsWithoutParent = exports.flatColumns2 = exports.findItemByKey = void 0; exports.getAllChildren = getAllChildren; exports.getAllVisibleKeys1 = exports.getAllVisibleKeys = exports.getAllRowKey = void 0; exports.getCellsByPosition = getCellsByPosition; exports.getColIdsBetween = getColIdsBetween; exports.getFormat = exports.getFixedFields = exports.getEditType = exports.getDiffent2Array = exports.getDefaultValue = exports.getDefaultOperator = exports.getDatepickerFormat = exports.getDateRangeFormat = exports.getCommonPinningStyles2 = exports.getCommonPinningStyles = void 0; exports.getHiddenParentKeys = getHiddenParentKeys; exports.getHiddenParentKeys1 = getHiddenParentKeys1; exports.getInvisibleColumns = getInvisibleColumns; exports.getNewItemsOnly = exports.getLastSelectCell = void 0; exports.getRowIdsBetween = getRowIdsBetween; exports.getVisibleColumnKeys1 = exports.getVisibleColumnKeys = exports.getTypeFilter = exports.getTableHeight = exports.getSelectedCellMatrix = void 0; exports.groupArrayByColumns = groupArrayByColumns; exports.isColor = void 0; exports.isDateString = isDateString; exports.isEmpty = exports.isEditable = exports.isDisable = void 0; exports.isEqualSet = isEqualSet; exports.isObjEmpty = exports.isNullOrUndefined = exports.isNameColor = exports.isFormattedNumber = void 0; exports.isObjEqual = isObjEqual; exports.isTreeArray = isTreeArray; exports.isTreeArray2 = isTreeArray2; exports.parseBooleanToValue = exports.onRemoveBgSelectedCell = exports.onAddBgSelectedCell = exports.newGuid = void 0; exports.parseExcelClipboard = parseExcelClipboard; exports.parseExcelClipboardText = parseExcelClipboardText; exports.removeColumns = void 0; exports.removeDuplicatesByKey = removeDuplicatesByKey; exports.sortByType = exports.shouldInclude = exports.removeVietnameseTones = void 0; exports.sortData = sortData; exports.sumSize = void 0; exports.toggleRowAndChildren = toggleRowAndChildren; exports.updateArrayByKey = exports.unFlattenData = void 0; exports.updateColumnWidthsRecursive = updateColumnWidthsRecursive; exports.updateColumnsByGroup = exports.updateColumns1 = void 0; exports.updateOrInsert = updateOrInsert; exports.updateWidthsByOther = updateWidthsByOther; var _uuid = require("uuid"); var _colors = require("@ant-design/colors"); var _dayjs = _interopRequireDefault(require("dayjs")); var _moment = _interopRequireDefault(require("moment")); const newGuid = () => { for (let i = 0; i < 20; i++) { // @ts-ignore // const id = crypto.randomUUID() return (0, _uuid.v4)(); } }; exports.newGuid = newGuid; const convertDayjsToDate = (dateString, format) => { const dayjsDate = (0, _dayjs.default)(dateString, format); // Parse using the provided format if (!dayjsDate.isValid()) { throw new Error('Invalid date or format'); } // return moment(dayjsDate.toDate()).format() // Convert to JavaScript Date return dayjsDate.toDate(); // Convert to JavaScript Date }; exports.convertDayjsToDate = convertDayjsToDate; const convertDateToDayjs = (date, format) => { const dateValue = date ? (0, _dayjs.default)(date).format(format) : null; return dateValue ? (0, _dayjs.default)(dateValue, format) : null; }; exports.convertDateToDayjs = convertDateToDayjs; const getCommonPinningStyles = column => { const isPinned = column.getIsPinned(); return { left: isPinned === "left" ? `${column.getStart("left")}px` : undefined, right: isPinned === "right" ? `${column.getAfter("right")}px` : undefined, opacity: 1, position: isPinned ? "sticky" : "relative", width: 'auto', zIndex: isPinned ? 2 : 0 }; }; exports.getCommonPinningStyles = getCommonPinningStyles; const getCommonPinningStyles2 = header => { const isPinned = header.column.getIsPinned(); // const isLastLeftPinnedColumn = isPinned === "left" && column.getIsLastColumn("left"); // const isFirstRightPinnedColumn =isPinned === "right" && column.getIsFirstColumn("right"); return { // boxShadow: isFirstRightPinnedColumn // ? "#e0e0e0 2px 0px 1px -1px inset" // : undefined, left: isPinned === "left" ? `${header.getStart("left")}px` : undefined, right: isPinned === "right" ? `${header.getAfter("right")}px` : undefined, opacity: 1, position: isPinned ? "sticky" : "relative", width: 'auto', zIndex: isPinned ? 2 : 0 }; }; exports.getCommonPinningStyles2 = getCommonPinningStyles2; const sumSize = items => { return items.reduce((total, item) => total + item.size, 0); }; exports.sumSize = sumSize; const appendIfNotExists = (a, b) => { const existingKeys = new Set(a.map(item => item.index)); b.forEach(item => { if (!existingKeys.has(item.index)) { a.push(item); } }); return a; }; exports.appendIfNotExists = appendIfNotExists; const getNewItemsOnly = (a, b) => { const existingKeys = new Set(a.map(item => item.key)); return b.filter(item => !existingKeys.has(item.key)); }; exports.getNewItemsOnly = getNewItemsOnly; const extendsObject = (...list) => { const result = { ...list[0] }; for (let i = 1; i < list.length; i++) { const obj = list[i]; if (obj) { Object.keys(obj).forEach(key => { const val = obj[key]; if (val !== undefined) { result[key] = val; } }); } } return result; }; exports.extendsObject = extendsObject; const isEmpty = d => { return d === null || d === undefined || d === ''; }; exports.isEmpty = isEmpty; const getFormat = (colFormat, format) => { return { thousandSeparator: colFormat?.thousandSeparator ?? format?.thousandSeparator, decimalSeparator: colFormat?.decimalSeparator ?? format?.decimalSeparator, decimalScale: colFormat?.decimalScale ?? format?.decimalScale ? Number(colFormat?.decimalScale ?? format?.decimalScale) : colFormat?.decimalScale ?? format?.decimalScale, allowNegative: colFormat?.allowNegative ?? format?.allowNegative, // check nhập số âm prefix: colFormat?.prefix ?? format?.prefix, suffix: colFormat?.suffix ?? format?.suffix, fixedDecimalScale: colFormat?.fixedDecimalScale ?? format?.fixedDecimalScale, // mặc định thêm số 0 sau số thập phân dateFormat: colFormat?.dateFormat ?? format?.dateFormat, datetimeFormat: colFormat?.datetimeFormat ?? format?.datetimeFormat, timeFormat: colFormat?.timeFormat ?? format?.timeFormat, weekFormat: colFormat?.weekFormat ?? format?.weekFormat, monthFormat: colFormat?.monthFormat ?? format?.monthFormat, yearFormat: colFormat?.yearFormat ?? format?.yearFormat }; }; exports.getFormat = getFormat; function convertFormat(formatStr) { // return formatStr.split('').map((char, i) => { // if (char === 'D' || char === 'd') { // return 'd'; // ngày: lowercase // } // if (char === 'Y' || char === 'y') { // return 'y'; // năm: lowercase // } // if (char === 'M' || char === 'm') { // return char; // tháng: giữ nguyên // } // return char; // separator // }).join(''); return formatStr.split('').map(char => { if (char === 'D' || char === 'd') return 'd'; if (char === 'Y' || char === 'y') return 'y'; if ('Hhmsa'.includes(char)) return char; // giờ, phút, giây, am/pm if (char === 'M' || char === 'm') return char; // tháng: giữ nguyên return char; // dấu phân cách }).join(''); } const getDatepickerFormat = (type, format) => { const typeFormat = type ? type.toLowerCase() : ''; switch (typeFormat) { case "date": case "daterange": return format?.dateFormat ?? 'DD/MM/YYYY'; case "datetime": return format?.datetimeFormat ?? 'DD/MM/YYYY HH:mm'; case "week": return format?.weekFormat ?? 'DD/MM'; case "month": return format?.monthFormat ?? 'MM/YYYY'; case "quarter": return format?.dateFormat ?? 'DD/MM/YYYY'; case "year": return format?.yearFormat ?? 'YYYY'; case "time": return format?.timeFormat ?? 'HH:mm'; default: return 'DD/MM/YYYY'; } }; exports.getDatepickerFormat = getDatepickerFormat; const getDateRangeFormat = (type, format) => { const typeFormat = type ? type.toLowerCase() : ''; switch (typeFormat) { case "date": case "daterange": return convertFormat(format?.dateFormat ?? 'dd/MM/yyyy'); case "datetime": return format?.datetimeFormat ?? 'dd/MM/yyyy HH:mm'; case "week": return format?.weekFormat ?? 'dd/MM'; case "month": return format?.monthFormat ?? 'MM/yyyy'; case "quarter": return format?.dateFormat ?? 'dd/MM/yyyy'; case "year": return format?.yearFormat ?? 'yyyy'; case "time": return format?.timeFormat ?? 'HH:mm'; default: return 'dd/MM/yyyy'; } }; exports.getDateRangeFormat = getDateRangeFormat; const getTypeFilter = col => { if (col?.typeFilter) { return col.typeFilter; } const type = col?.type ?? 'Text'; switch (type) { case "number": return 'Number'; case "date": return 'Date'; case "datetime": return 'Datetime'; case "boolean": return 'Checkbox'; case "checkbox": return 'Checkbox'; // case "week": return '' // case "month": return 'Month' // case "quarter": return col.format?.dateFormat ? col.format?.dateFormat : 'DD/MM/YYYY' // case "year": return col.format?.yearFormat ? col.format?.yearFormat : 'YYYY' // case "time": return col.format?.timeFormat ? col.format?.timeFormat : 'HH:mm' case "string": default: return 'Text'; } }; exports.getTypeFilter = getTypeFilter; const addRowIdArray = inputArray => { if (inputArray) { return inputArray.map(item => { if (typeof item.children !== "string" && item.children && item.children.length > 0) { item.children = addRowIdArray(item.children); } // return { ...item, rowId: item.rowId ?? item.id ?? newGuid() } return { ...item, rowId: item.id ?? item.rowId ?? newGuid() }; }); } else { return []; } }; exports.addRowIdArray = addRowIdArray; function groupArrayByColumns(arr, columns) { const result = []; const checkEmpty = d => { return d === null || d === undefined || d === ''; }; if (columns) { arr.forEach(item => { let currentLevel = result; columns.forEach((column, index) => { const value = item[column]; const existingItem = currentLevel.find(i => i[column] === value); if (existingItem) { currentLevel = existingItem.children; } else { // const newItem = {[column]: value, field: column, rowId: !isEmpty(value) ? (value) : newGuid(), parentId: !isEmpty(item[columns[index - 1]]) ? (item[columns[index - 1]]) : null, indent: index, children: [] } const newItem = { [column]: value, field: column, rowId: newGuid(), // rowId: item[column], parentId: !isEmpty(item[columns[index - 1]]) ? item[columns[index - 1]] : null, // parentId: item.rowId[index - 1], // indent: index, children: [] }; currentLevel.push(newItem); currentLevel = newItem.children; } }); currentLevel.push({ ...item, rowId: item.id ?? item.rowId, parentId: !checkEmpty(columns[columns.length - 1]) ? item[columns[columns.length - 1]] : null // parentId: item.rowId[columns.length - 1], // indent: columns.length }); }); return result; } else { return arr; } } const flatColumns2 = columns => { return columns.reduce((list, column) => { const subColumns = column.children; if (column.field === 'selection_column') { return [...list, { ...column }]; } if (subColumns && subColumns.length > 0) { return [...list, ...flatColumns2(subColumns).map(subColum => ({ ...subColum }))]; } return [...list, { ...column }]; }, []); }; exports.flatColumns2 = flatColumns2; const flatColumnsWithoutParent = columns => { return columns.reduce((list, column) => { const subColumns = column.children; if (column.field === 'selection_column') { return [...list, { ...column }]; } if (subColumns && subColumns.length > 0) { return [...list, ...flatColumns2(subColumns).map(subColum => ({ ...subColum }))]; } return [...list, { ...column }]; }, []); }; exports.flatColumnsWithoutParent = flatColumnsWithoutParent; const checkThousandSeparator = (thousandSeparator, decimalSeparator) => { if (thousandSeparator) { if (decimalSeparator) { if (thousandSeparator === decimalSeparator) { return ','; } else { return thousandSeparator; } } else { return thousandSeparator; } } else { return undefined; } }; exports.checkThousandSeparator = checkThousandSeparator; const checkDecimalSeparator = (thousandSeparator, decimalSeparator) => { if (decimalSeparator) { if (thousandSeparator) { if (thousandSeparator === decimalSeparator) { return '.'; } else { return decimalSeparator; } } else { return decimalSeparator; } } else { if (thousandSeparator && thousandSeparator === '.') { return ','; } return '.'; } }; exports.checkDecimalSeparator = checkDecimalSeparator; const getFixedFields = (columns, type) => { const result = []; function traverse(cols) { for (const col of cols) { if ((col.fixed ?? col.fixedType) === type && col.field && (col.visible !== false || col.hidden)) { result.push(col.field); } if (col.children && col.children.length > 0) { traverse(col.children); } } } traverse(columns); return result; }; exports.getFixedFields = getFixedFields; function areStringArraysEqual(a, b) { if (a.length !== b.length) return false; const sortedA = [...a].sort(); const sortedB = [...b].sort(); return sortedA.every((val, index) => val === sortedB[index]); } const getDefaultOperator = col => { if (col.operator) { return col.operator; } if (col.typeFilter) { switch (col.typeFilter) { case 'Number': case 'Date': case 'Datetime': case 'Time': case 'Month': case 'Quarter': case 'Year': case 'Week': case 'Dropdown': case 'Checkbox': case 'CheckboxDropdown': case 'CheckboxTree': case 'DropTree': return 'equal'; case 'Text': default: return 'contains'; } } switch (col.type) { case 'number': case 'date': case 'datetime': case 'week': case 'year': case 'quarter': return 'equal'; case 'string': default: return 'contains'; } }; exports.getDefaultOperator = getDefaultOperator; function isEqualSet(setA, setB) { if (setA.size !== setB.size) { return false; } for (const item of setA) { if (!setB.has(item)) { return false; } } return true; } const getLastSelectCell = selectCells => { if (selectCells.size === 0) { return { row: 0, col: 0 }; } const lastValue = [...selectCells].at(-1); const [row, col] = lastValue.split("-").map(Number); return { row, col }; }; exports.getLastSelectCell = getLastSelectCell; function getCellsByPosition(cellSet, position = "bottom") { const cells = Array.from(cellSet).map(key => { const [row, col] = key.split("-").map(Number); return { row, col, key }; }); switch (position) { case "top": { // const minRow = Math.min(...cells.map(c => c.row)); // return cells.filter(c => c.row === minRow).map(c => c.key); // const rows = cells.map(c => c.row).filter(r => r > 0); // if (rows.length === 0) return []; // const minRow = Math.min(...rows); // return cells.filter(c => c.row === minRow).map(c => c.key); const minRow = Math.min(...cells.map(c => c.row)); if (minRow === 0) { return []; } // Bỏ qua nếu rowIndex = 0 return cells.filter(c => c.row === minRow).map(c => `${c.row}-${c.col}`); } case "bottom": { const maxRow = Math.max(...cells.map(c => c.row)); return cells.filter(c => c.row === maxRow).map(c => c.key); } case "left": { // const minCol = Math.min(...cells.map(c => c.col)); // return cells.filter(c => c.col === minCol).map(c => c.key); // const cols = cells.map(c => c.col).filter(c => c > 0); // if (cols.length === 0) return []; // const minCol = Math.min(...cols); // return cells.filter(c => c.col === minCol).map(c => c.key); const minCol = Math.min(...cells.map(c => c.col)); if (minCol === 0) { return []; } // Bỏ qua nếu colIndex = 0 // Trả về các ô cùng row, nhưng ở cột bên trái return cells.filter(c => c.col === minCol).map(c => `${c.row}-${c.col}`); } case "right": { const maxCol = Math.max(...cells.map(c => c.col)); return cells.filter(c => c.col === maxCol).map(c => c.key); } default: return []; } } const onAddBgSelectedCell = (selectedCells, id, isFocusCellIndex) => { const selectors = Array.from(selectedCells).map(pos => { const [row1, col1] = pos.split('-'); return `[data-row-index="${row1}"][data-col-index="${col1}"]`; }); const table = document.querySelector(`#${id}`); //// xóa class các ô đã chọn trước đó const cellsSelected = table ? table?.querySelectorAll('.ui-rc-table-cell.selected-bg') : null; if (cellsSelected) { cellsSelected.forEach(cell => { cell.classList.remove('selected-bg'); }); } /// thêm class const cells = table && selectors.length > 0 ? table?.querySelectorAll(selectors.join(',')) : null; if (cells) { cells.forEach(cell => { cell.classList.add('selected-bg'); }); } const rowsArray = [...new Set([...selectedCells].map(item => item.split("-")[0]))]; const rowsSelectors = rowsArray.map(r => `.rc-ui-cell-index[data-row-index="${r}"]`).join(", "); const cellsIndex = table && rowsSelectors.length > 0 ? table?.querySelectorAll(rowsSelectors) : null; if (cellsIndex && isFocusCellIndex !== false) { cellsIndex.forEach(cell => { cell.classList.add('focus'); }); } // // tăng z-index để hiển thị round point paste // const row = getLastSelectCell(selectedCells).row // const col = getLastSelectCell(selectedCells).col // const cell: any = table?.querySelector(`.ui-rc-table-cell[data-row-index="${row}"][data-col-index="${col}"]`) // // if (cell) { // cell.style.zIndex = 1 // } // // if (cell && cell.classList.contains('ui-rc-table-cell-fix-left')) { // cell.style.zIndex = 3; // } // thêm class border selected // addBorderClass(selectedCells, 'bottom', 'cell-border-bottom', id) // addBorderClass(selectedCells, 'right', 'cell-border-right', id) // addBorderClass(selectedCells, 'top', 'cell-border-top', id) // addBorderClass(selectedCells, 'left', 'cell-border-left', id) }; exports.onAddBgSelectedCell = onAddBgSelectedCell; const onRemoveBgSelectedCell = (selectedCells, id, rowsSelected) => { const table = document.querySelector(`#${id}`); const cells = table ? table?.querySelectorAll('.ui-rc-table-cell.selected-bg') : null; if (cells) { cells.forEach(cell => { cell.classList.remove('selected-bg'); }); } const cellsIndex = table ? table?.querySelectorAll('.ui-rc-table-cell.focus') : null; if (cellsIndex) { cellsIndex.forEach(cell => { cell.classList.remove('focus'); }); } // xóa class selected ô STT if (rowsSelected && rowsSelected.size > 0) { const rowsSelectedArray = [...new Set([...rowsSelected].map(item => item.split("-")[0]))]; const rowsSelectedSelectors = rowsSelectedArray.map(r => `.rc-ui-cell-index[data-row-index="${r}"]`).join(", "); const cellsSelectedIndex = table && rowsSelectedSelectors.length > 0 ? table?.querySelectorAll(rowsSelectedSelectors) : null; if (cellsSelectedIndex) { cellsSelectedIndex.forEach(cell => { cell.classList.remove('selected'); }); } } }; exports.onRemoveBgSelectedCell = onRemoveBgSelectedCell; function getColIdsBetween(table, a, b) { const ids = table.getVisibleLeafColumns().map(c => c.id); const [start, end] = [ids.indexOf(a), ids.indexOf(b)].sort((x, y) => x - y); return ids.slice(start, end + 1); } function getRowIdsBetween(table, a, b) { // const ids = table.getRowModel().rows.map(r => r.id); const ids = table.getRowModel().flatRows.map(r => r.id); const [start, end] = [ids.indexOf(a), ids.indexOf(b)].sort((x, y) => x - y); return ids.slice(start, end + 1); } const updateArrayByKey = (arr, element, key) => { if (arr) { return arr.map(it => { const item = { ...it }; if (item[key] === element[key]) { return { ...item, ...element }; } else if (item.children && item.children.length > 0) { item.children = updateArrayByKey(item.children, element, key); } return item; }); } else { return []; } }; exports.updateArrayByKey = updateArrayByKey; const unFlattenData = data => { const idToNodeMap = {}; const tree = []; // Bước 1: Tạo map id -> node data.forEach(item => { // idToNodeMap[item.rowId] = { ...item, children: [] } idToNodeMap[item.rowId] = { ...item }; }); // Bước 2: Gắn vào parent hoặc đẩy lên root nếu không có parent data.forEach(item => { const currentNode = idToNodeMap[item.rowId]; if (!item.parentId) { tree.push(currentNode); } else { const parentNode = idToNodeMap[item.parentId]; if (parentNode) { parentNode.children = parentNode.children ?? []; parentNode.children.push(currentNode); } else { // Nếu parentId không tồn tại thì xem như root tree.push(currentNode); } } }); return tree; }; exports.unFlattenData = unFlattenData; const flattenArray = arr => { if (!arr) { return []; } return arr.reduce((r, { children, ...rest }) => { r.push(rest); if (children) { r.push(...flattenArray(children)); } return r; }, []); }; exports.flattenArray = flattenArray; function updateOrInsert(dataArray, dataFilter) { const updatedArray = [...dataArray]; dataFilter.forEach(filterItem => { const existingIndex = updatedArray.findIndex(item => item.rowId === filterItem.rowId); if (existingIndex !== -1) { // Cập nhật item đã tồn tại updatedArray[existingIndex] = { ...updatedArray[existingIndex], ...filterItem }; } else { // Tìm vị trí cuối cùng của item trước đó trong dataFilter const prevIndexInFilter = dataFilter.findIndex(f => f.rowId === filterItem.rowId) - 1; if (prevIndexInFilter >= 0) { const prevId = dataFilter[prevIndexInFilter].rowId; const prevIndexInArray = updatedArray.findIndex(item => item.rowId === prevId); if (prevIndexInArray !== -1) { // Thêm ngay sau phần tử trước đó updatedArray.splice(prevIndexInArray + 1, 0, filterItem); return; } } // Nếu không tìm thấy phần tử trước đó, hoặc là phần đầu tiên, thì push vào cuối updatedArray.push(filterItem); } }); return updatedArray; } const findItemByKey = (array, key, value) => { for (let i = 0; i < array.length; i++) { const item = array[i]; if (item[key] === value) { return item; } if (item.children && item.children.length > 0) { const foundInChildren = findItemByKey(item.children, key, value); if (foundInChildren) { return foundInChildren; } } } return null; }; exports.findItemByKey = findItemByKey; const isFormattedNumber = str => { if (!str) return false; if (typeof str !== 'string') return false; const regexUS = /^\d{1,3}(,\d{3})*(\.\d+)?$/; // 100,000.111 const regexEU = /^\d{1,3}(\.\d{3})*(,\d+)?$/; // 100.000,111 // Không có dấu hàng nghìn, chỉ dấu thập phân: 100000.1 hoặc 100000,01 const regexDecimalOnly = /^-?\d+([.,]\d{1,})$/; return regexUS.test(str) || regexEU.test(str) || regexDecimalOnly.test(str); }; exports.isFormattedNumber = isFormattedNumber; const detectSeparators = str => { if (typeof str !== 'string') return null; const hasComma = str.includes(','); const hasDot = str.includes('.'); // Trường hợp có cả dấu , và . if (hasComma && hasDot) { const lastComma = str.lastIndexOf(','); const lastDot = str.lastIndexOf('.'); return lastComma > lastDot ? { thousandSeparator: '.', decimalSeparator: ',' } : { thousandSeparator: ',', decimalSeparator: '.' }; } // Trường hợp chỉ có dấu phẩy if (hasComma && !hasDot) { const parts = str.split(','); if (parts.length === 2) { return parts[1].length === 3 ? { thousandSeparator: ',', decimalSeparator: undefined } : { thousandSeparator: undefined, decimalSeparator: ',' }; } } // Trường hợp chỉ có dấu chấm if (hasDot && !hasComma) { const parts = str.split('.'); if (parts.length === 2) { return parts[1].length === 3 ? { thousandSeparator: '.', decimalSeparator: undefined } : { thousandSeparator: undefined, decimalSeparator: '.' }; } } // Không có dấu hoặc không hợp lệ return null; }; exports.detectSeparators = detectSeparators; function isDate(value) { if (value instanceof Date) { return !isNaN(value.getTime()); } if (typeof value === "string") { // Chỉ chấp nhận định dạng yyyy-mm-dd hoặc mm/yyyy return /^\d{4}-\d{2}-\d{2}$/.test(value) || /^\d{2}\/\d{4}$/.test(value); } return false; } // Chuỗi MM/YYYY → Date function isDateString(str) { return typeof str === "string" && (/^\d{2}\/\d{4}$/.test(str) || /^\d{4}-\d{2}-\d{2}$/.test(str)); } function parseToDate(str) { if (/^\d{2}\/\d{4}$/.test(str)) { const [month, year] = str.split('/'); return new Date(parseInt(year), parseInt(month) - 1, 1); } return new Date(str); } // So sánh ngày (cùng ngày/tháng/năm) function compareDates(date1, date2) { return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear(); } // Helper: compare MM/YYYY date string with itemValue function compareDate(itemValue, value) { const [month, year] = value.split('/').map(Number); const date = new Date(itemValue); return date.getMonth() + 1 === month && date.getFullYear() === year; } const removeVietnameseTones = str => { if (!str) { return ''; } return str.normalize('NFD') // Tách các ký tự có dấu thành ký tự cơ bản + dấu .replace(/[\u0300-\u036f]/g, '') // Xóa dấu .replace(/đ/g, 'd') // Thay thế đ .replace(/Đ/g, 'D').replace(/[^a-zA-Z0-9\s]/g, '') // Loại bỏ ký tự đặc biệt .replace(/\s+/g, ' ') // Thay nhiều khoảng trắng thành 1 khoảng trắng .trim(); }; exports.removeVietnameseTones = removeVietnameseTones; const shouldInclude = (item, queries, ignoreAccents) => { if (item.isFilterState === true) { return true; } let result = null; for (const query of queries) { const { field, value, operator, predicate } = query; const itemValue = item[field]; let condition = false; const isDateComparison = isDate(itemValue) || isDateString(value); const itemDate = isDateComparison ? new Date(itemValue) : null; const queryDate = isDateComparison ? parseToDate(value) : null; const itemStr = removeVietnameseTones(itemValue?.toString().toLowerCase?.() ?? ''); const queryStr = removeVietnameseTones(value?.toString().toLowerCase?.() ?? ''); switch (operator.toLowerCase()) { case "equal": // mặc định so sánh không dấu + lowercase // ignoreAccents !== false => không khai báo hoặc ignoreAccents = true => so sánh không dấu // ignoreAccents = false => so sánh có dấu + uperrcase sensitive const abc = ignoreAccents === false ? itemValue === value : itemStr === queryStr; condition = isDateComparison ? compareDates(itemDate, queryDate) : abc; // condition = isDateComparison ? compareDates(itemDate, queryDate) : (itemValue === value) break; case "notequal": const abcN = ignoreAccents === false ? itemValue !== value : itemStr !== queryStr; condition = isDateComparison ? !compareDates(itemDate, queryDate) : abcN; break; case "greaterthan": // @ts-ignore condition = isDateComparison ? itemDate > queryDate : itemValue > value; // condition = isDateComparison ? invalidDate(itemDate) && invalidDate(queryDate) && itemDate > queryDate : itemValue > value; break; case "greaterthanorequal": // @ts-ignore condition = isDateComparison ? itemDate >= queryDate : itemValue >= value; break; case "lessthan": // @ts-ignore condition = isDateComparison ? itemDate < queryDate : itemValue < value; break; case "lessthanorequal": // @ts-ignore condition = isDateComparison ? itemDate <= queryDate : itemValue <= value; break; case "contains": condition = ignoreAccents === false ? itemValue?.includes(value) : itemStr?.includes(queryStr); break; case "startswith": condition = ignoreAccents === false ? itemValue?.startsWith(value) : itemStr?.startsWith(queryStr); break; case "endswith": condition = ignoreAccents === false ? itemValue?.endsWith(value) : itemStr?.endsWith(queryStr); break; default: console.warn(`Unknown operator: ${operator}`); break; } if (predicate === "and") { result = result === null ? condition : result && condition; } else if (predicate === "or") { result = result === null ? condition : result || condition; } } return result; }; // function compareValues(a: any, b: any, order: "ascend" | "descend") { // const desc = order === "descend"; // if (a == null && b == null) return 0; // if (a == null) return desc ? 1 : -1; // if (b == null) return desc ? -1 : 1; // // Nếu là số // if (typeof a === "number" && typeof b === "number") { // return desc ? b - a : a - b; // } // // Nếu là ngày hợp lệ // const dateA = new Date(a); // const dateB = new Date(b); // if (!isNaN(dateA.getTime()) && !isNaN(dateB.getTime())) { // return desc // ? dateB.getTime() - dateA.getTime() // : dateA.getTime() - dateB.getTime(); // } // // Mặc định coi như string // return desc // ? String(b).localeCompare(String(a)) // : String(a).localeCompare(String(b)); // } // export function sortData(data: any[], sorter: Sorter[]): any[] { // const sorted = [...data].sort((a, b) => { // for (const { field, order } of sorter) { // const result = compareValues(a[field], b[field], order); // if (result !== 0) return result; // } // return 0; // }); // return sorted.map(item => ({ // ...item, // children: item.children // ? sortData(item.children, sorter) // : undefined // })); // } // export function filterDataByColumns(data: any[], queries: any[], sorter: Sorter[], keysFilter: string[] | undefined) { // if (!queries || queries.length === 0) { // return sorter ? sortData(data, sorter) : data; // } // let filtered = data.map(item => { // const newItem = { ...item } // if (Array.isArray(item.children)) { // newItem.children = filterDataByColumns(item.children, queries, sorter, keysFilter) // } // const isSelfMatched = shouldInclude(item, queries) || keysFilter?.includes(newItem?.rowId) // // Nếu chính item thỏa hoặc có con thỏa → giữ lại // if (isSelfMatched || (newItem.children && newItem.children.length > 0)) { // return newItem // } // return null // loại bỏ node không phù hợp // }) // .filter(Boolean) // xóa các null // if (sorter && sorter.length > 0) { // filtered = sortData(filtered, sorter); // } // return filtered; // } exports.shouldInclude = shouldInclude; function getSortValue(item, field) { if (item[field] !== undefined) return item[field]; if (item.children && item.children.length > 0) { return getSortValue(item.children[0], field); } return undefined; } function compareValues(a, b, order) { const desc = order === "descend"; if (a === null && b === null) return 0; if (a === null) return desc ? 1 : -1; if (b === null) return desc ? -1 : 1; // Nếu là số if (typeof a === "number" && typeof b === "number") { return desc ? b - a : a - b; } // Nếu là ngày hợp lệ const dateA = new Date(a); const dateB = new Date(b); if (!isNaN(dateA.getTime()) && !isNaN(dateB.getTime())) { return desc ? dateB.getTime() - dateA.getTime() : dateA.getTime() - dateB.getTime(); } // Mặc định coi như string return desc ? String(b).localeCompare(String(a)) : String(a).localeCompare(String(b)); } function sortData(data, sorter) { const sorted = [...data].sort((a, b) => { for (const { field, order } of sorter) { const result = compareValues(getSortValue(a, field), getSortValue(b, field), order); if (result !== 0) return result; } return 0; }); return sorted.map(item => ({ ...item, children: item.children ? sortData(item.children, sorter) : undefined })); } function filterDataByColumns(data, queries, sorter, keysFilter, ignoreAccents) { if (!queries || queries.length === 0) { return sorter ? sortData(data, sorter) : data; } let filtered = data.map(item => { const newItem = { ...item }; if (Array.isArray(item.children)) { newItem.children = filterDataByColumns(item.children, queries, sorter, keysFilter, ignoreAccents); } // const isSelfMatched = shouldInclude(item, queries, ignoreAccents) || keysFilter?.includes(newItem?.rowId) const isSelfMatched = shouldInclude(item, queries, ignoreAccents); // Nếu chính item thỏa hoặc có con thỏa → giữ lại if (isSelfMatched || newItem.children && newItem.children.length > 0) { return newItem; } return null; // loại bỏ node không phù hợp }).filter(Boolean); // xóa các null if (sorter && sorter.length > 0) { filtered = sortData(filtered, sorter); } return filtered; } const getAllRowKey = data => { const a = flattenArray(data); return a.length ? a.map(it => it.rowId) : undefined; }; exports.getAllRowKey = getAllRowKey; const isEditable = (column, rowData) => { if (column && typeof column.editEnable === 'function') { return column.editEnable(rowData); } return column?.editEnable; }; exports.isEditable = isEditable; const checkFieldKey = key => { if (key) { return key; } else { return 'value'; } }; exports.checkFieldKey = checkFieldKey; const convertArrayWithIndent = (inputArray, parentIndent = 0) => { if (inputArray) { return inputArray.map(item => { const indent = parentIndent; if (item.children && item.children.length > 0) { item.children = convertArrayWithIndent(item.children, indent + 1); } return { ...item, indent, rowId: item.rowId ? item.rowId : item.id ? item.id : newGuid() }; }); } else { return []; } }; exports.convertArrayWithIndent = convertArrayWithIndent; const convertLabelToTitle = data => { return data.map(item => { const { label, title, value, key, ...rest } = item; const newItem = { ...rest, value, label, key: key ?? value, title: title ?? label }; if (item.children) { newItem.children = convertLabelToTitle(item.children); } return newItem; }); }; exports.convertLabelToTitle = convertLabelToTitle; const isNullOrUndefined = d => { return d === null || d === undefined; }; exports.isNullOrUndefined = isNullOrUndefined; const isObjEmpty = obj => { if (isNullOrUndefined(obj)) { return true; } else { return Object.keys(obj).length === 0; } }; exports.isObjEmpty = isObjEmpty; const isDisable = (column, rowData) => { if (column && typeof column?.disable === 'function') { return column.disable(rowData); } return !!column?.disable; }; exports.isDisable = isDisable; const customWeekStartEndFormat = (value, weekFormat) => { return `${(0, _dayjs.default)(value).startOf('week').format(weekFormat)} ~ ${(0, _dayjs.default)(value).endOf('week').format(weekFormat)}`; }; exports.customWeekStartEndFormat = customWeekStartEndFormat; const parseBooleanToValue = (value, type) => { return type === 'boolean' ? value : Number(value); }; exports.parseBooleanToValue = parseBooleanToValue; const isNameColor = strColor => { const s = new Option().style; s.color = strColor; return s.color === strColor; }; exports.isNameColor = isNameColor; const isColor = value => { const hexRegex = /^#([0-9A-F]{3}){1,2}$/i; const rgbRegex = /^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/; const rgbaRegex = /^rgba\((\d{1,3}), (\d{1,3}), (\d{1,3}), (0|1|0?\.\d+)\)$/; const hslRegex = /^hsl\(\d{1,3}, \d{1,3}%, \d{1,3}%\)$/; const hslaRegex = /^hsla\(\d{1,3}, \d{1,3}%, \d{1,3}%, (0|1|0?\.\d+)\)$/; const namedColors = /^(?:aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)$/i; return hexRegex.test(value) || rgbRegex.test(value) || rgbaRegex.test(value) || hslRegex.test(value) || hslaRegex.test(value) || namedColors.test(value) || isNameColor(value); }; exports.isColor = isColor; const genPresets = (presets = _colors.presetPalettes) => { return Object.entries(presets).map(([label, colors]) => ({ label, colors, key: label })); }; exports.genPresets = genPresets; const getEditType = (column, rowData) => { if (column && typeof column.editType === 'function') { return column.editType(rowData); } return column?.editType ?? 'text'; }; exports.getEditType = getEditType; const getDefaultValue = defaultValue => { if (defaultValue && typeof defaultValue === 'function') { return defaultValue(); } return defaultValue; }; exports.getDefaultValue = getDefaultValue; const flattenData = (childrenColumnName, data) => { let list = []; (data || []).forEach(record => { list.push(record); if (record && typeof record === 'object' && childrenColumnName in record) { list = [...list, ...flattenData(childrenColumnName, record[childrenColumnName])]; } }); return list; }; exports.flattenData = flattenData; const getSelectedCellMatrix = (table, startCell, endCell) => { if (!startCell || !endCell) return { rowIds: [], colIds: [], startRowIndex: undefined, endRowIndex: undefined, startColIndex: undefined, endColIndex: undefined, colRange: [], rowRange: [] }; // const rowIds = table.getRowModel().rows.map(r => r.id); const rowIds = table.getRowModel().flatRows.map(r => r.id); const colIds = table.getVisibleLeafColumns().map(c => c.id); // const colIds = table.getAllLeafColumns().map(c => c.id); const [startRowIndex, endRowIndex] = [rowIds.indexOf(startCell.rowId), rowIds.indexOf(endCell.rowId)].sort((a, b) => a - b); const [startColIndex, endColIndex] = [colIds.indexOf(startCell.colId), colIds.indexOf(endCell.colId)].sort((a, b) => a - b); return { rowRange: rowIds.slice(startRowIndex, endRowIndex + 1), colRange: colIds.slice(startColIndex, endColIndex + 1), startRowIndex, endRowIndex, startColIndex, endColIndex, rowIds, colIds }; }; exports.getSelectedCellMatrix = getSelectedCellMatrix; function addRowsDownWithCtrl(arr, n) { if (!Array.isArray(arr) || arr.length === 0) { return { combined: arr, addedRows: [] }; } const m = arr.length; const numCols = arr[0].length; const addedRows = []; // Hàm kiểm tra kiểu date hợp lệ const isValidDate = item => { // return !isNaN(Date.parse(d)) if (typeof item === 'number') { // return 'number' return false; } if (typeof item === 'string') { // Kiểm tra nếu là chuỗi ISO date hợp lệ const date = new Date(item); if (!isNaN(date.getTime()) && item.includes('T')) { // return 'date' return true; } // return 'string' return false; } return !isNaN(Date.parse(item)); }; // Lấy giá trị mẫu của cột j từ hàng đầu tiên const getSample = j => arr[0][j]; // Xác định chế độ xử lý cho mỗi cột: // mode = 'number-stepping' | 'date-stepping' | 'number-constant' | 'cycle' const modes = []; const steps = []; // bước tăng, nếu có (cho number hoặc date) for (let j = 0; j < numCols; j++) { const sample = getSample(j); if (m === 1) { // Nếu mảng chỉ có 1 hàng: nếu là số thì giữ nguyên; nếu là date thì tăng 1 ngày; còn lại giữ nguyên. if (typeof sample === "number") { modes[j] = "number-constant"; } else if (isValidDate(sample)) { modes[j] = "date-stepping"; steps[j] = 24 * 3600 * 1000; // 1 ngày = 86400000 ms } else { modes[j] = "cycle"; } } else if (m === 2) { // Nếu mảng có 2 hàng: nếu là số thì tính bước = row2 - row1, tương tự với date const first = arr[0][j], second = arr[1][j]; if (typeof first === "number" && typeof second === "number") { modes[j] = "number-stepping"; steps[j] = second - first; } else if (isValidDate(first) && isValidDate(second)) { modes[j] = "date-stepping"; steps[j] = Date.parse(second) - Date.parse(first); } else { modes[j] = "cycle"; } } else { // Nếu mảng có >2 hàng const first = arr[0][j], second = arr[1][j], third = arr[2][j]; if (typeof first === "number" && typeof second === "number" && typeof third === "number") { const step1 = second - first; const step2 = third - second; if (step1 === step2) { modes[j] = "number-stepping"; steps[j] = step1; } else { modes[j] = "cycle"; } } else if (isValidDate(first) && isValidDate(second) && isValidDate(third)) { const step1 = Date.parse(second) - Date.parse(first); const step2 = Date.parse(third) - Date.parse(second); if (step1 === step2) { modes[j] = "date-stepping"; steps[j] = step1; } else { modes[j] = "cycle"; } } else { modes[j] = "cycle"; } } } // Tạo các dòng mới (thêm n dòng) // Với mỗi cột, nếu chế độ là stepping thì lấy giá trị cuối của mảng ban đầu và cộng thêm (i+1)*step // Nếu chế độ là cycle thì dùng arr[i mod m][j] for (let i = 0; i < n; i++) { const newRow = []; for (let j = 0; j < numCols; j++) { let newValue; switch (modes[j]) { case "number-constant": // Mảng có 1 hàng, số giữ nguyên newValue = arr[0][j]; break; case "number-stepping": { // Lấy giá trị cuối của cột j trong mảng ban đầu const lastValue = arr[m - 1][j]; newValue = lastValue + (i + 1) * steps[j]; } break; case "date-stepping": { // Lấy giá trị cuối, chuyển về date, cộng thêm (i+1)*step, chuyển lại về định dạng ISO const lastDate = new Date(arr[m - 1][j]); const newTime = lastDate.getTime() + (i + 1) * steps[j]; newValue = (0, _moment.default)(new Date(newTime)).format(); } break; case "cycle": default: // Lặp lại nội dung theo vòng tròn: dùng hàng thứ (i mod m) newValue = arr[i % m][j]; break; } newRow.push(newValue); } addedRows.push(newRow); } const combined = arr.concat(addedRows); return { combined, addedRows }; } function addRowsDown(arr, n) { if (!Array.isArray(arr) || arr.length === 0) { return { combined: arr, addedRows: [] }; } const m = arr.length; const numCols = arr[0].length; const addedRows = []; // // Hàm kiểm tra kiểu date hợp lệ // const isValidDate = (item: any) => { // // // // return !isNaN(Date.parse(d)) // // if (typeof item === 'number') { // // return 'number' // return false // } // if (typeof item === 'string') { // // Kiểm tra nếu là chuỗi ISO date hợp lệ // const date = new Date(item) // if (!isNaN(date.getTime()) && item.includes('T')) { // // return 'date' // return true // } // // return 'string' // return false // } // // return !isNaN(Date.parse(item)) // // } // Lấy giá trị mẫu của cột j từ hàng đầu tiên const getSample = j => arr[0][j]; // Xác định chế độ xử lý cho mỗi cột: // mode = 'number-stepping' | 'date-stepping' | 'number-constant' | 'cycle' const modes = []; const steps = []; // bước tăng, nếu có (cho number hoặc date) for (let j = 0; j < numCols; j++) { const sample = getSample(j); if (m === 1) { // Nếu mảng chỉ có 1 hàng: nếu là số thì giữ nguyên; nếu là date thì tăng 1 ngày; còn lại giữ nguyên. if (typeof sample === "number") { modes[j] = "number-constant"; } // else if (isValidDate(sample)) { // modes[j] = "date-stepping" // steps[j] = 24 * 3600 * 1000 // 1 ngày = 86400000 ms // } else { modes[j] = "cycle"; } } else if (m === 2) { // Nếu mảng có 2 hàng: nếu là số thì tính bước = row2 - row1, tương tự với date const first = arr[0][j], second = arr[1][j]; if (typeof first === "number" && typeof second === "number") { modes[j] = "number-stepping"; steps[j] = second - first; } // else if (isValidDate(first) && isValidDate(second)) { // modes[j] = "date-stepping" // steps[j] = Date.parse(second) - Date.parse(first) // } else { modes[j] = "cycle"; } } else { // Nếu mảng có >2 hàng const first = arr[0][j], second = arr[1][j], third = arr[2][j]; if (typeof first === "number" && typeof second === "number" && typeof third === "number") { const step1 = second - first; const step2 = third - second; if (step1 === step2) { modes[j] = "number-stepping"; steps[j] = step1; } else { modes[j] = "cycle"; } } // else if (isValidDate(first) && isValidDate(second) && isValidDate(third)) { // const step1 = Date.parse(second) - Date.parse(first) // const step2 = Date.parse(third) - Date.parse(second) // if (step1 === step2) { // modes[j] = "date-stepping" // steps[j] = step1 // } else { // modes[j] = "cycle" // } // } else { modes[j] = "cycle"; } } } // Tạo các dòng mới (thêm n dòng) // Với mỗi cột, nếu chế độ là stepping thì lấy giá trị cuối của mảng ban đầu và cộng thêm (i+1)*step // Nếu chế độ là cycle thì dùng arr[i mod m][j] for (let i = 0; i < n; i++) { const newRow = []; for (let j = 0; j < numCols; j++) { let newValue; switch (modes[j]) { case "number-constant": // Mảng có 1 hàng, số giữ nguyên newValue = arr[0][j]; break; case "number-stepping": { // Lấy giá trị cuối của cột j trong mảng ban đầu const lastValue = arr[m - 1][j]; newValue = lastValue + (i + 1) * steps[j]; } break; // case "date-stepping": // { // // Lấy giá trị cuối, chuyển về date, cộng thêm (i+1)*step, chuyển lại về định dạng ISO // const lastDate = new Date(arr[m - 1][j]) // const newTime = lastDate.getTime() + (i + 1) * steps[j] // newValue = moment(new Date(newTime)).format() // } // break case "cycle": default: // Lặp lại nội dung theo vòng tròn: dùng hàng thứ (i mod m) newValue = arr[i % m][j];