UNPKG

es-grid-template

Version:

es-grid-template

1,563 lines (1,483 loc) 94.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.addRowIdArray = exports.addClassCellIndexSelected = exports.addClassBorderPasteCell = exports.addBorderPasteClass = exports.addBorderClass = void 0; exports.addRowsDown = addRowsDown; exports.addRowsDownWithCtrl = addRowsDownWithCtrl; exports.addRowsUp = addRowsUp; exports.addRowsUpWithCtrl = addRowsUpWithCtrl; exports.checkThousandSeparator = exports.checkFieldKey = exports.checkDecimalSeparator = exports.checkChild = exports.buildConnectedRegions = void 0; exports.compareDate = compareDate; exports.compareDates = compareDates; exports.convertFlatColumn = exports.convertFilters = exports.convertDayjsToDate = exports.convertDateToDayjs = exports.convertArrayWithIndent = void 0; exports.convertFormat = convertFormat; exports.filterDataByColumns3 = exports.filterDataByColumns2 = exports.filterDataByColumns = exports.editAbleColumns = exports.detectSeparators = exports.customWeekStartEndFormat = exports.customFilterOption = exports.countItemsBeforeIndex = exports.convertLabelToTitle = void 0; exports.filterDataByColumns4 = filterDataByColumns4; exports.findAllChildrenKeys = findAllChildrenKeys; exports.findAllChildrenKeys2 = findAllChildrenKeys2; exports.getAllVisibleKeys = exports.getAllRowKey = exports.genPresets = exports.flattenData = exports.flattenArray = exports.findItemPath = exports.findItemByKey = void 0; exports.getBottomRowCells = getBottomRowCells; exports.getCellsByPosition = getCellsByPosition; exports.getCellsByPosition2 = getCellsByPosition2; exports.getFormat = exports.getFirstSelectCell = exports.getEditType = exports.getDefaultValue = exports.getDatepickerFormat = exports.getDateString = exports.getDateRangeFormat = exports.getColumnsVisible = void 0; exports.getHiddenParentKeys = getHiddenParentKeys; exports.getVisibleColumnKeys = exports.getTypeFilter = exports.getTemplate = exports.getRowsPasteIndex = exports.getRowNumber = exports.getLastSelectCell = void 0; exports.groupAndSum = groupAndSum; exports.groupArrayByColumns = groupArrayByColumns; exports.hideDraggingPoint = void 0; exports.invalidDate = invalidDate; exports.isArraysEqual = void 0; exports.isBottomMostInRanges = isBottomMostInRanges; exports.isContinuous = exports.isColor = exports.isBottomMostInRegion = void 0; exports.isDateString = isDateString; exports.isEmpty = exports.isEditable = exports.isDisable = void 0; exports.isEqualSet = isEqualSet; exports.isRangeCell = exports.isObjEmpty = exports.isNullOrUndefined = exports.isNameColor = exports.isFormattedNumber = void 0; exports.isRightMostInRegion = isRightMostInRegion; exports.isTopMostInRegion = exports.isSelectedCell = void 0; exports.mergeWithFilter = mergeWithFilter; exports.mergeWithFilter2 = mergeWithFilter2; exports.removeInvisibleColumns = exports.removeFieldRecursive = exports.removeClassCellIndexSelected = exports.removeClassBorderPasteCell = exports.removeBorderPasteClass = exports.removeBorderClass2 = exports.removeBorderClass = exports.parseCells = exports.parseBooleanToValue = exports.onRemoveBorderSelectedCell = exports.onRemoveBgSelectedCell = exports.onRemoveBgCellIndex = exports.onAddBorderSelectedCell = exports.onAddBgSelectedCell = exports.onAddBgCellIndex = exports.newGuid = exports.mergedSets = void 0; exports.updateData = exports.updateColumnsByGroup = exports.updateColumns = exports.updateArrayByKey = exports.unFlattenData = exports.sumDataByField = exports.sumByField = exports.sortedSetDSC = exports.sortedSetASC = exports.showDraggingPoint = exports.shouldInclude = exports.removeVietnameseTones = void 0; exports.updateDataByFilter = updateDataByFilter; exports.updateOrInsert = updateOrInsert; var _dayjs = _interopRequireDefault(require("dayjs")); var _moment = _interopRequireDefault(require("moment/moment")); var _uuid = require("uuid"); var _colors = require("@ant-design/colors"); // import type {ColumnTable, GetRowKey, IFormat, Presets} from "./../ type" // import type {SelectionSettings} from "../type" // import type {AnyObject} from "../type" // import {Table} from "rc-master-ui" // import {flatColumns2} from "./columns" // import {SELECTION_COLUMN} from "./useColumns" const newGuid = () => { for (let i = 0; i < 20; i++) { // @ts-ignore // const id = crypto.randomUUID() return (0, _uuid.v4)(); } }; exports.newGuid = newGuid; const sumDataByField = (data, field) => { if (data && data.length > 0) { return data.reduce((accumulator, currentValue) => { const val = typeof currentValue[field] === 'number' || !isNaN(currentValue[field]) ? Number(currentValue[field]) : 0; return accumulator + val; }, 0); } else { return 0; } }; exports.sumDataByField = sumDataByField; 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 isEmpty = d => { return d === null || d === undefined || d === ''; }; exports.isEmpty = isEmpty; 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 isNullOrUndefined = d => { return d === null || d === undefined; }; exports.isNullOrUndefined = isNullOrUndefined; 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 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 getAllVisibleKeys = columns => { const keys = []; const traverse = (cols, parentHidden = false) => { for (const col of cols) { if (col.hidden || parentHidden) { continue; } if (col.key) { keys.push(col.key); } if (col.children) { traverse(col.children, col.hidden); } } }; traverse(columns); return keys; }; exports.getAllVisibleKeys = getAllVisibleKeys; const getVisibleColumnKeys = columns => { const allKeys = getAllVisibleKeys(columns); const allParentKeys = getHiddenParentKeys(columns); return allKeys.filter(item => !allParentKeys.includes(item)); }; exports.getVisibleColumnKeys = getVisibleColumnKeys; function getHiddenParentKeys(columns, parentKeys = []) { const hiddenParents = new Set(); for (const column of columns) { if (column.children) { const currentPath = column.key ? [...parentKeys, column.key] : [...parentKeys]; const childHiddenParents = getHiddenParentKeys(column.children, currentPath); if (childHiddenParents.length > 0) { childHiddenParents.forEach(key => hiddenParents.add(key)); currentPath.forEach(key => hiddenParents.add(key)); } } else if (column.hidden) { parentKeys.forEach(key => hiddenParents.add(key)); } } return Array.from(hiddenParents); } const updateColumns = (columns, includes) => { return columns.map(column => { const newColumn = { ...column }; let hasVisibleChild = false; if (!column.key && !column.dataIndex) { return column; } if (newColumn.children) { newColumn.children = updateColumns(newColumn.children, includes); hasVisibleChild = newColumn.children.some(child => !child.hidden); } // newColumn.hidden = newColumn.key && !includes.includes(newColumn.key) newColumn.hidden = newColumn.field && !includes.includes(newColumn.field); // newColumn.fixed = newColumn.field && !includes.includes(newColumn.field) ? undefined : newColumn.fixed if (newColumn.children && newColumn.children.length > 0) { newColumn.hidden = !hasVisibleChild; // newColumn.fixed = !hasVisibleChild ? undefined : newColumn.fixed } return newColumn; }); }; exports.updateColumns = updateColumns; const updateColumnsByGroup = (columns, columnsGroup) => { return columns.map(column => { const newColumn = { ...column }; let hasVisibleChild = false; if (!column.key && !column.dataIndex) { return column; } if (newColumn.children) { newColumn.children = updateColumnsByGroup(newColumn.children, columnsGroup); hasVisibleChild = newColumn.children.some(child => !child.hidden); } newColumn.hidden = newColumn.key && columnsGroup.includes(newColumn.key); if (newColumn.children && newColumn.children.length > 0) { newColumn.hidden = !hasVisibleChild; } return newColumn; }); }; exports.updateColumnsByGroup = updateColumnsByGroup; 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 customWeekStartEndFormat = (value, weekFormat) => { return `${(0, _dayjs.default)(value).startOf('week').format(weekFormat)} ~ ${(0, _dayjs.default)(value).endOf('week').format(weekFormat)}`; }; exports.customWeekStartEndFormat = customWeekStartEndFormat; 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 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 getDateString = (column, value) => { if (value instanceof Date) { return (0, _moment.default)(value).format(); } return value; }; exports.getDateString = getDateString; const getEditType = (column, rowData) => { if (column && typeof column.editType === 'function') { return column.editType(rowData); } return column?.editType ?? 'text'; }; exports.getEditType = getEditType; const isDisable = (column, rowData) => { if (column && typeof column?.disable === 'function') { return column.disable(rowData); } return !!column?.disable; }; exports.isDisable = isDisable; const checkFieldKey = key => { if (key) { return key; } else { return 'value'; } }; exports.checkFieldKey = checkFieldKey; 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 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 getTemplate = (template, column) => { if (template && typeof template === 'function') { return template(column); } return template; }; // export const totalFixedWidth = <T, >(columns: ColumnsTable<T>, type: 'left' | 'right', selectionSettings?: SelectionSettings) => { // const totalFixedLeftWidth: number = columns // .filter(column => column.fixed === type) // Lọc các cột có fixed // .reduce((sum, column) => { // const width = typeof column.width === 'number' ? column.width : parseInt(column.width as string, 10) || 0 // Chuyển từ chuỗi sang số, nếu không hợp lệ thì lấy 0 // return sum + width // }, 0) // const selectColumnWidth: number = !selectionSettings?.mode ? 0 : ( // typeof selectionSettings?.columnWidth === 'number' ? selectionSettings?.columnWidth : parseInt(selectionSettings?.columnWidth as string, 10) || 50) // return totalFixedLeftWidth + selectColumnWidth // } exports.getTemplate = getTemplate; const isObjEmpty = obj => { if (isNullOrUndefined(obj)) { return true; } else { return Object.keys(obj).length === 0; } }; exports.isObjEmpty = isObjEmpty; const getColumnsVisible = (columns, index) => { const itemsBeforeIndex = columns.slice(0, index); const itemsAfterIndex = columns.slice(index); itemsAfterIndex.map(it => { if (it.hidden !== false) { itemsBeforeIndex.push(it); } }); return itemsBeforeIndex; }; exports.getColumnsVisible = getColumnsVisible; const updateData = (initData, rows, key) => { const updatedData = initData.map(item => { const newData = rows.find(row => row[key] === item[key]); return newData ? { ...item, ...newData } : item; }); // Thêm các phần tử mới chưa có trong initialData const newRows = rows.filter(row => !initData.some(item => item[key] === row[key])); return [...updatedData, ...newRows]; }; exports.updateData = updateData; const parseBooleanToValue = (value, type) => { return type === 'boolean' ? value : Number(value); }; exports.parseBooleanToValue = parseBooleanToValue; const genPresets = (presets = _colors.presetPalettes) => { return Object.entries(presets).map(([label, colors]) => ({ label, colors, key: label })); }; exports.genPresets = genPresets; function findAllChildrenKeys(data, getRowKey, childrenColumnName) { const keys = []; function dig(list) { (list || []).forEach((item, index) => { keys.push(getRowKey(item, index)); dig(item[childrenColumnName]); }); } dig(data); return keys; } function findAllChildrenKeys2(data, rowKey, childrenColumnName) { const keys = []; function dig(list) { (list || []).forEach(item => { keys.push(item[rowKey]); dig(item[childrenColumnName]); }); } dig(data); return keys; } 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; 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 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 === null) { tree.push(currentNode); } else { const parentNode = idToNodeMap[item.parentId]; if (parentNode) { 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 countItemsBeforeIndex = (array, index) => { let count = 0; for (let i = 0; i < index; i++) { if (array[i].children && array[i].children.length > 0) { const rs = flattenData('children', [array[i]]); count += rs.length; } else { count++; } } return count; }; exports.countItemsBeforeIndex = countItemsBeforeIndex; const getRowNumber = (array, rowKey, key) => { // const flattArray = flattenArray(array) const flattArray = flattenData('children', array); return flattArray.findIndex(it => it[key] === rowKey); }; exports.getRowNumber = getRowNumber; const getDefaultValue = defaultValue => { if (defaultValue && typeof defaultValue === 'function') { return defaultValue(); } return defaultValue; }; exports.getDefaultValue = getDefaultValue; 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() }; }); } else { return []; } }; exports.addRowIdArray = addRowIdArray; 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 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; const getFirstSelectCell = selectCells => { if (selectCells.size === 0) { return { row: 0, col: 0 }; } const firstValue = selectCells.values().next().value; const [row, col] = firstValue.split("-").map(Number); return { row, col }; }; exports.getFirstSelectCell = getFirstSelectCell; const getRowsPasteIndex = pasteRows => { if (!pasteRows) { return []; } const result = Array.from(pasteRows).map(item => parseInt(item.split("-")[0])); return [...new Set(result)]; }; exports.getRowsPasteIndex = getRowsPasteIndex; 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]; break; } newRow.push(newValue); } addedRows.push(newRow); } const combined = arr.concat(addedRows); return { combined, addedRows }; } function addRowsUpWithCtrl(array, n) { const arr = array.reverse(); 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 = n - 1; i >= 0; 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] * -1; } 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 = m === 1 ? lastDate.getTime() - (i + 1) * steps[j] : lastDate.getTime() - (i + 1) * steps[j] * -1; 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 addRowsUp(array, n) { const arr = array.reverse(); 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 { 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 { 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 { 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 = n - 1; i >= 0; 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] * -1; } 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 }; } // export const transformColumns = <RecordType, >(cols: ColumnsTable<RecordType>, convertColumns: any[], t?: any): ColumnsTable<RecordType> => { // // @ts-ignore // return cols.map((column) => { // const find = convertColumns.find((it) => it.key === column.field) // if (!column?.field && !column?.key) { // return Table.SELECTION_COLUMN // } // if (find) { // return {...find} // } // // Xử lý đệ quy cho children // if (column.children?.length) { // return { // ...column, // key: column.field ?? column.dataIndex ?? column.key, // title: t ? t(column.headerText) : column.headerText, // ellipsis: column.ellipsis !== false, // align: column.textAlign ?? column.align, // children: transformColumns(column.children, convertColumns) // } // } // }) // } // export const transformColumns1 = <RecordType, >(cols: ColumnsTable<RecordType>, sortMultiple?: boolean): ColumnsTable<RecordType> => { // const convertColumns = flatColumns2(cols).map((column: any, colIndex) => { // if (!column?.field && !column?.key) { // return Table.SELECTION_COLUMN // } // if (column.dataIndex === '#' || column.dataIndex === '#') { // return { // ...column // } // } // if ((column.key || column.field) === 'command') { // return { // ...column // } // } // return { // ...column, // key: column.field ?? column.dataIndex ?? column.key, // sorter: (column.sorter === false ? undefined : { // compare: (a: any) => a, // multiple: sortMultiple ? colIndex : undefined // }) // } // }) // // @ts-ignore // return cols.map((column) => { // const find = convertColumns.find((it) => it.key === column.field) // if (!column?.field && !column?.key) { // return Table.SELECTION_COLUMN // } // if (find) { // return {...find} // } // // Xử lý đệ quy cho children // if (column.children?.length) { // return { // ...column, // key: column.field ?? column.dataIndex ?? column.key, // ellipsis: column.ellipsis !== false, // align: column.textAlign ?? column.align, // children: transformColumns(column.children, convertColumns) // } // } // }) // } // export const removeColumns = <RecordType, >(columns: ColumnTable<RecordType>[], groupColumns: string[]): ColumnsTable<RecordType> => { // const ttt: ColumnTable<RecordType>[] = [...columns] // return ttt.filter(column => !groupColumns.includes(column.field as string)).map((column) => { // const newCol = {...column} // if (newCol?.children && newCol?.children.length > 0) { // newCol.children = removeColumns(newCol.children, groupColumns) as any[] // } // return newCol // }) // } const convertFlatColumn = array => { const tmp = [...array]; let result = []; tmp.forEach(item => { if (item.children) { result = result.concat(convertFlatColumn(item.children)); } else { result.push(item); } }); return result; }; // export const convertColumns = <RecordType, >(cols: ColumnsTable<RecordType>): ColumnsTable<RecordType> => { // return cols.map((col) => { // if (col === SELECTION_COLUMN) { // return SELECTION_COLUMN // } // const transformedColumn = { // ...col, // dataIndex: col.field ?? col.dataIndex, // key: col.field ?? col.dataIndex ?? col.key, // // title: t ? t(col.columnGroupText ?? col.headerText ?? col.title) : col.columnGroupText ?? col.headerText ?? col.title, // // title: () => (<span>aaa</span>), // // title: () => (<HeaderContent column={{...col} as any} t={t}/>), // // title: () => (<span>{t ? t(col.columnGroupText ?? col.headerText ?? col.title) : col.columnGroupText ?? col.headerText ?? col.title}</span>), // ellipsis: col.ellipsis !== false, // align: col.textAlign ?? col.align, // fixed: col.fixedType ?? col.fixed // } // if (transformedColumn.children && transformedColumn.children?.length) { // return { // ...transformedColumn, // children: convertColumns(transformedColumn.children) // } // } // if (["index", "#"].includes(col.field as string)) { // return { // ...transformedColumn, // onCell: () => ({className: 'cell-number'}), // render: (_: any, __: any, rowIndex: number) => rowIndex + 1 // } // } // if (col.key === 'command') { // return { // ...transformedColumn, // onCell: () => ({className: 'cell-number', style: {padding: '2px 8px'}}) // } // } // return { // ...transformedColumn // } // }) // } exports.convertFlatColumn = convertFlatColumn; const checkChild = inputArray => { return inputArray.some(item => item.children && item.children.length > 0); }; exports.checkChild = checkChild; const isEditable = (column, rowData) => { if (column && typeof column.editEnable === 'function') { return column.editEnable(rowData); } return column?.editEnable; }; exports.isEditable = isEditable; const isArraysEqual = (arr1, arr2) => { if (arr1.length !== arr2.length) { return false; } return arr1.every((element, index) => element === arr2[index]); }; exports.isArraysEqual = isArraysEqual; const editAbleColumns = columns => { return columns.filter(col => col.field !== '#' && col.field !== 'index' && col.field !== 'command' && col.visible !== false); }; exports.editAbleColumns = editAbleColumns; const findItemPath = (tree, targetItem, rowKey, currentPage, pageSize) => { let result = null; function dfs(nodes, path = []) { for (let i = 0; i < nodes.length; i++) { const currentPath = currentPage && pageSize ? [...path, i + 1 + (currentPage - 1) * pageSize] : [...path, i + 1]; const node = nodes[i]; if (node?.[rowKey] === targetItem?.[rowKey]) { result = currentPath.join('.'); return true; } if (node?.children) { if (dfs(node.children, currentPath)) { return true; } } } return false; } dfs(tree); return result; }; exports.findItemPath = findItemPath; const filterDataByColumns = (data, queries) => { if (!queries || queries.length === 0) { return data; } return data.filter(item => { let result = null; for (const query of queries) { const { field, value, operator, predicate } = query; const itemValue = item[field]; let condition = false; // Normalize string values for comparison const itemStr = itemValue?.toString().toLowerCase?.(); const queryStr = value?.toString().toLowerCase?.(); switch (operator.toLowerCase()) { case "equal": if (isDateString(value)) { condition = compareDate(itemValue, value); } else { condition = itemValue == value; } break; case "notequal": if (isDateString(value)) { condition = !compareDate(itemValue, value); } else { condition = itemValue != value; } break; case "greaterthan": condition = itemValue > value; break; case "greaterthanorequal": condition = itemValue >= value; break; case "lessthan": condition = itemValue < value; break; case "lessthanorequal": condition = itemValue <= value; break; case "contains": condition = itemStr?.includes(queryStr); break; case "startswith": condition = itemStr?.startsWith(queryStr); break; case "endswith": condition = 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; }); }; exports.filterDataByColumns = filterDataByColumns; const filterDataByColumns2 = (data, queries) => { if (!queries || queries.length === 0) { return data; } return data.filter(item => { // Nếu isFilterState = true thì giữ lại dòng này, không cần kiểm tra filter if (item.isFilterState) { return true; } let result = null; for (const query of queries) { const { field, value, operator, predicate } = query; const itemValue = item[field]; let condition = false; // Normalize string values for comparison const itemStr = itemValue?.toString().toLowerCase?.(); const queryStr = value?.toString().toLowerCase?.(); switch (operator.toLowerCase()) { case "equal": condition = isDateString(value) ? compareDate(itemValue, value) : itemValue == value; break; case "notequal": condition = isDateString(value) ? !compareDate(itemValue, value) : itemValue != value; break; case "greaterthan": c