es-grid-template
Version:
es-grid-template
1,545 lines (1,506 loc) • 74.9 kB
JavaScript
"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.addRows8 = addRows8;
exports.addRowsUp = addRowsUp;
exports.checkThousandSeparator = exports.checkFieldKey = exports.checkDecimalSeparator = exports.checkChild = exports.buildConnectedRegions = void 0;
exports.compareDate = compareDate;
exports.compareDates = compareDates;
exports.convertFlatColumn = exports.convertDayjsToDate = exports.convertDateToDayjs = exports.convertColumns = exports.convertArrayWithIndent = void 0;
exports.convertFormat = convertFormat;
exports.filterDataByColumns3 = exports.filterDataByColumns2 = exports.filterDataByColumns = exports.editAbleColumns = exports.customWeekStartEndFormat = exports.countItemsBeforeIndex = exports.convertLabelToTitle = void 0;
exports.filterDataByColumns4 = filterDataByColumns4;
exports.findAllChildrenKeys = findAllChildrenKeys;
exports.getAllVisibleKeys = 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.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 = void 0;
exports.isRightMostInRegion = isRightMostInRegion;
exports.updateColumns = exports.updateArrayByKey = exports.transformColumns1 = exports.transformColumns = exports.totalFixedWidth = exports.sumDataByField = exports.sortedSetDSC = exports.sortedSetASC = exports.showDraggingPoint = exports.shouldInclude = exports.removeFieldRecursive = exports.removeColumns = 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 = exports.isTopMostInRegion = exports.isSelectedCell = void 0;
exports.updateData = exports.updateColumnsByGroup = void 0;
var _dayjs = _interopRequireDefault(require("dayjs"));
var _moment = _interopRequireDefault(require("moment/moment"));
var _uuid = require("uuid");
var _colors = require("@ant-design/colors");
var _rcMasterUi = require("rc-master-ui");
var _columns = require("./columns");
var _useColumns = require("./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 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,
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 => {
if (template && typeof template === 'function') {
return template();
}
return template;
};
exports.getTemplate = getTemplate;
const totalFixedWidth = (columns, type, selectionSettings) => {
const totalFixedLeftWidth = 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, 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 = !selectionSettings?.mode ? 0 : typeof selectionSettings?.columnWidth === 'number' ? selectionSettings?.columnWidth : parseInt(selectionSettings?.columnWidth, 10) || 50;
return totalFixedLeftWidth + selectColumnWidth;
};
exports.totalFixedWidth = totalFixedWidth;
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;
}
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 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 addRows8(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 => {
// console.log('!isNaN(Date.parse(d))', !isNaN(Date.parse(d)))
// 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 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 => {
// console.log('!isNaN(Date.parse(d))', !isNaN(Date.parse(d)))
// 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
};
}
const transformColumns = (cols, convertColumns, t) => {
// @ts-ignore
return cols.map(column => {
const find = convertColumns.find(it => it.key === column.field);
if (!column?.field && !column?.key) {
return _rcMasterUi.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)
};
}
});
};
exports.transformColumns = transformColumns;
const transformColumns1 = (cols, sortMultiple) => {
const convertColumns = (0, _columns.flatColumns2)(cols).map((column, colIndex) => {
if (!column?.field && !column?.key) {
return _rcMasterUi.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 => 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 _rcMasterUi.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)
};
}
});
};
exports.transformColumns1 = transformColumns1;
const removeColumns = (columns, groupColumns) => {
const ttt = [...columns];
return ttt.filter(column => !groupColumns.includes(column.field)).map(column => {
const newCol = {
...column
};
if (newCol?.children && newCol?.children.length > 0) {
newCol.children = removeColumns(newCol.children, groupColumns);
}
return newCol;
});
};
exports.removeColumns = removeColumns;
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;
};
exports.convertFlatColumn = convertFlatColumn;
const convertColumns = cols => {
return cols.map(col => {
if (col === _useColumns.SELECTION_COLUMN) {
return _useColumns.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)) {
return {
...transformedColumn,
onCell: () => ({
className: 'cell-number'
}),
render: (_, __, rowIndex) => rowIndex + 1
};
}
if (col.key === 'command') {
return {
...transformedColumn,
onCell: () => ({
className: 'cell-number',
style: {
padding: '2px 8px'
}
})
};
}
return {
...transformedColumn
};
});
};
exports.convertColumns = convertColumns;
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":
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;
}
// Áp dụng toán tử logic (and/or)
if (predicate === "and") {
result = result === null ? condition : result && condition;
} else if (predicate === "or") {
result = result === null ? condition : result || condition;
}
}
return result;
});
};
exports.filterDataByColumns2 = filterDataByColumns2;
const removeFieldRecursive = (data, field) => {
return data.map(item => {
const {
[field]: _,
...rest
} = item;
if (rest.children && Array.isArray(rest.children)) {
rest.children = removeFieldRecursive(rest.children, field);
}
return rest;
});
};
exports.removeFieldRecursive = removeFieldRecursive;
const filterDataByColumns3 = (data, queries) => {
if (!queries || queries.length === 0) {
return data;
}
return data.filter(item => {
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 = itemValue?.toString().toLowerCase?.();
const queryStr = value?.toString().toLowerCase?.();
switch (operator.toLowerCase()) {
case "equal":
condition = isDateComparison ? compareDates(itemDate, queryDate) : itemValue === value;
break;
case "notequal":
condition = isDateComparison ? !compareDates(itemDate, queryDate) : itemValue !== value;
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 = 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.filterDataByColumns3 = filterDataByColumns3;
const shouldInclude = (item, queries) => {
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 = itemValue?.toString().toLowerCase?.();
const queryStr = value?.toString().toLowerCase?.();
switch (operator.toLowerCase()) {
case "equal":
condition = isDateComparison ? compareDates(itemDate, queryDate) : itemValue === value;
break;
case "notequal":
condition = isDateComparison ? !compareDates(itemDate, queryDate) : itemValue !== value;
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 = 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.shouldInclude = shouldInclude;
function filterDataByColumns4(data, queries) {
if (!queries || queries.length === 0) {
return data;
}
return data.map(item => {
const newItem = {
...item
};
if (Array.isArray(item.children)) {
newItem.children = filterDataByColumns4(item.children, queries);
}
const isSelfMatched = shouldInclude(item, queries);
// 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
}
// ======= Helper functions ========
// Kiểm tra có phải Date object không
// function isDate(value: any) {
// return value instanceof Date || !isNaN(Date.parse(value));
// }
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));
}
// // Helper: check if a string is in MM/YYYY format
// export function isDateString(str: any) {
// return typeof str === "string" && /^\d{2}\/\d{4}$/.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;
}
function invalidDate(date) {
return date instanceof Date && !isNaN(date.getTime());
}
const isContinuous = set => {
const rows = [];
const cols = [];
for (const item of set) {
const [row, col] = item.split('-').map(Number);
rows.push(row);
cols.push(col);
}
// Lấy danh sách duy nhất và sắp xếp
const uniqueSorted = arr => [...new Set(arr)].sort((a, b) => a - b);
const isSequential = arr => {
for (let i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i - 1] + 1) {
return false;
}
}
return true;
};
const sortedRows = uniqueSorted(rows);
const sortedCols = uniqueSorted(cols);
return isSequential(sortedRows) && isSequential(sortedCols);
};
exports.isContinuous = isContinuous;
const parseCells = cellSet => {
return Array.from(cellSet).map(cell => {
const [row, col] = cell.split('-').map(Number);
return {
row,
col,
key: cell
};
});
};
exports.parseCells = parseCells;
const buildConnectedRegions = cells => {
const cellMap = new Map();
const visited = new Set();
for (const cell of cells) {
cellMap.set(cell.key, cell);
}
const directions = [[1, 0],
// down
[-1, 0],
// up
[0, 1],
// right
[0, -1] // left
];
const regions = [];
for (const cell of cells) {
if (visited.has(cell.key)) {
continue;
}
const stack = [cell];
const region = [];
while (stack.length) {
const current = stack.pop();
if (visited.has(current.key)) {
continue;
}
visited.add(current.key);
region.push(current);
for (const [dr, dc] of directions) {
const neighborKey = `${current.row + dr}-${current.col + dc}`;
if (cellMap.has(neighborKey) && !visited.has(neighborKey)) {
stack.push(cellMap.get(neighborKey));
}
}
}
regions.push(region);
}
return regions;
};
exports.buildConnectedRegions = buildConnectedRegions;
const isBottomMostInRegion = (rowIndex, colIndex, listSelectCell) => {
const cells = parseCells(listSelectCell);
const regions = buildConnectedRegions(cells);
for (const region of regions) {
if (region.some(cell => cell.row === rowIndex && cell.col === colIndex)) {
const maxRow = Math.max(...re