es-grid-template 1.7.23 → 1.7.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/es/index.d.ts +1 -0
  2. package/es/index.js +3 -1
  3. package/es/table-component/ColumnsChoose.d.ts +13 -0
  4. package/es/table-component/ColumnsChoose.js +206 -0
  5. package/es/table-component/ContextMenu.d.ts +20 -0
  6. package/es/table-component/ContextMenu.js +75 -0
  7. package/es/table-component/InternalTable.d.ts +9 -0
  8. package/es/table-component/InternalTable.js +308 -0
  9. package/es/table-component/TableContainer.d.ts +31 -0
  10. package/es/table-component/TableContainer.js +249 -0
  11. package/es/table-component/TableContainerEdit.d.ts +31 -0
  12. package/es/table-component/TableContainerEdit.js +1301 -0
  13. package/es/table-component/body/EditableCell.d.ts +16 -0
  14. package/es/table-component/body/EditableCell.js +1039 -0
  15. package/es/table-component/body/TableBody.d.ts +19 -0
  16. package/es/table-component/body/TableBody.js +64 -0
  17. package/es/table-component/body/TableBodyCell.d.ts +12 -0
  18. package/es/table-component/body/TableBodyCell.js +149 -0
  19. package/es/table-component/body/TableBodyCellEdit.d.ts +16 -0
  20. package/es/table-component/body/TableBodyCellEdit.js +931 -0
  21. package/es/table-component/body/TableBodyRow.d.ts +21 -0
  22. package/es/table-component/body/TableBodyRow.js +151 -0
  23. package/es/table-component/components/ControlCheckbox.d.ts +13 -0
  24. package/es/table-component/components/ControlCheckbox.js +84 -0
  25. package/es/table-component/components/EditForm/EditForm.d.ts +27 -0
  26. package/es/table-component/components/EditForm/EditForm.js +395 -0
  27. package/es/table-component/components/EditForm/index.d.ts +1 -0
  28. package/es/table-component/components/EditForm/index.js +1 -0
  29. package/es/table-component/components/InputControl/InputControl.d.ts +27 -0
  30. package/es/table-component/components/InputControl/InputControl.js +121 -0
  31. package/es/table-component/components/InputControl/index.d.ts +1 -0
  32. package/es/table-component/components/InputControl/index.js +1 -0
  33. package/es/table-component/components/async-select/index.d.ts +11 -0
  34. package/es/table-component/components/async-select/index.js +41 -0
  35. package/es/table-component/components/async-table-select/index.d.ts +11 -0
  36. package/es/table-component/components/async-table-select/index.js +44 -0
  37. package/es/table-component/components/checkbox-control/index.d.ts +13 -0
  38. package/es/table-component/components/checkbox-control/index.js +40 -0
  39. package/es/table-component/components/checkbox-filter/CheckboxFilter.d.ts +18 -0
  40. package/es/table-component/components/checkbox-filter/CheckboxFilter.js +240 -0
  41. package/es/table-component/components/checkbox-filter/FilterSearch.d.ts +12 -0
  42. package/es/table-component/components/checkbox-filter/FilterSearch.js +36 -0
  43. package/es/table-component/components/command/Command.d.ts +10 -0
  44. package/es/table-component/components/command/Command.js +33 -0
  45. package/es/table-component/components/number/index.d.ts +10 -0
  46. package/es/table-component/components/number/index.js +42 -0
  47. package/es/table-component/components/number-range/index.d.ts +11 -0
  48. package/es/table-component/components/number-range/index.js +66 -0
  49. package/es/table-component/features/operator.d.ts +24 -0
  50. package/es/table-component/features/operator.js +62 -0
  51. package/es/table-component/footer/TableFooter.d.ts +13 -0
  52. package/es/table-component/footer/TableFooter.js +33 -0
  53. package/es/table-component/footer/TableFooterCell.d.ts +10 -0
  54. package/es/table-component/footer/TableFooterCell.js +66 -0
  55. package/es/table-component/footer/TableFooterRow.d.ts +14 -0
  56. package/es/table-component/footer/TableFooterRow.js +73 -0
  57. package/es/table-component/header/TableHead.d.ts +14 -0
  58. package/es/table-component/header/TableHead.js +60 -0
  59. package/es/table-component/header/TableHeadCell.d.ts +14 -0
  60. package/es/table-component/header/TableHeadCell.js +343 -0
  61. package/es/table-component/header/TableHeadRow.d.ts +16 -0
  62. package/es/table-component/header/TableHeadRow.js +76 -0
  63. package/es/table-component/header/renderFilter.d.ts +20 -0
  64. package/es/table-component/header/renderFilter.js +281 -0
  65. package/es/table-component/hook/constant.d.ts +73 -0
  66. package/es/table-component/hook/constant.js +240 -0
  67. package/es/table-component/hook/useColumns.d.ts +9 -0
  68. package/es/table-component/hook/useColumns.js +169 -0
  69. package/es/table-component/hook/useFilterOperator.d.ts +7 -0
  70. package/es/table-component/hook/useFilterOperator.js +33 -0
  71. package/es/table-component/hook/utils.d.ts +133 -0
  72. package/es/table-component/hook/utils.js +1870 -0
  73. package/es/table-component/index.d.ts +5 -0
  74. package/es/table-component/index.js +2 -0
  75. package/es/table-component/style.scss +1129 -0
  76. package/es/table-component/table/Grid.d.ts +24 -0
  77. package/es/table-component/table/Grid.js +234 -0
  78. package/es/table-component/type.d.ts +513 -0
  79. package/es/table-component/type.js +1 -0
  80. package/es/table-component/useContext.d.ts +74 -0
  81. package/es/table-component/useContext.js +15 -0
  82. package/lib/index.d.ts +1 -0
  83. package/lib/index.js +8 -1
  84. package/lib/table-component/ColumnsChoose.d.ts +13 -0
  85. package/lib/table-component/ColumnsChoose.js +216 -0
  86. package/lib/table-component/ContextMenu.d.ts +20 -0
  87. package/lib/table-component/ContextMenu.js +85 -0
  88. package/lib/table-component/InternalTable.d.ts +9 -0
  89. package/lib/table-component/InternalTable.js +313 -0
  90. package/lib/table-component/TableContainer.d.ts +31 -0
  91. package/lib/table-component/TableContainer.js +257 -0
  92. package/lib/table-component/TableContainerEdit.d.ts +31 -0
  93. package/lib/table-component/TableContainerEdit.js +1310 -0
  94. package/lib/table-component/body/EditableCell.d.ts +16 -0
  95. package/lib/table-component/body/EditableCell.js +1041 -0
  96. package/lib/table-component/body/TableBody.d.ts +19 -0
  97. package/lib/table-component/body/TableBody.js +72 -0
  98. package/lib/table-component/body/TableBodyCell.d.ts +12 -0
  99. package/lib/table-component/body/TableBodyCell.js +158 -0
  100. package/lib/table-component/body/TableBodyCellEdit.d.ts +16 -0
  101. package/lib/table-component/body/TableBodyCellEdit.js +938 -0
  102. package/lib/table-component/body/TableBodyRow.d.ts +21 -0
  103. package/lib/table-component/body/TableBodyRow.js +158 -0
  104. package/lib/table-component/components/ControlCheckbox.d.ts +13 -0
  105. package/lib/table-component/components/ControlCheckbox.js +92 -0
  106. package/lib/table-component/components/EditForm/EditForm.d.ts +27 -0
  107. package/lib/table-component/components/EditForm/EditForm.js +406 -0
  108. package/lib/table-component/components/EditForm/index.d.ts +1 -0
  109. package/lib/table-component/components/EditForm/index.js +16 -0
  110. package/lib/table-component/components/InputControl/InputControl.d.ts +27 -0
  111. package/lib/table-component/components/InputControl/InputControl.js +131 -0
  112. package/lib/table-component/components/InputControl/index.d.ts +1 -0
  113. package/lib/table-component/components/InputControl/index.js +16 -0
  114. package/lib/table-component/components/async-select/index.d.ts +11 -0
  115. package/lib/table-component/components/async-select/index.js +49 -0
  116. package/lib/table-component/components/async-table-select/index.d.ts +11 -0
  117. package/lib/table-component/components/async-table-select/index.js +53 -0
  118. package/lib/table-component/components/checkbox-control/index.d.ts +13 -0
  119. package/lib/table-component/components/checkbox-control/index.js +48 -0
  120. package/lib/table-component/components/checkbox-filter/CheckboxFilter.d.ts +18 -0
  121. package/lib/table-component/components/checkbox-filter/CheckboxFilter.js +249 -0
  122. package/lib/table-component/components/checkbox-filter/FilterSearch.d.ts +12 -0
  123. package/lib/table-component/components/checkbox-filter/FilterSearch.js +44 -0
  124. package/lib/table-component/components/command/Command.d.ts +10 -0
  125. package/lib/table-component/components/command/Command.js +42 -0
  126. package/lib/table-component/components/number/index.d.ts +10 -0
  127. package/lib/table-component/components/number/index.js +50 -0
  128. package/lib/table-component/components/number-range/index.d.ts +11 -0
  129. package/lib/table-component/components/number-range/index.js +74 -0
  130. package/lib/table-component/features/operator.d.ts +24 -0
  131. package/lib/table-component/features/operator.js +67 -0
  132. package/lib/table-component/footer/TableFooter.d.ts +13 -0
  133. package/lib/table-component/footer/TableFooter.js +42 -0
  134. package/lib/table-component/footer/TableFooterCell.d.ts +10 -0
  135. package/lib/table-component/footer/TableFooterCell.js +76 -0
  136. package/lib/table-component/footer/TableFooterRow.d.ts +14 -0
  137. package/lib/table-component/footer/TableFooterRow.js +81 -0
  138. package/lib/table-component/header/TableHead.d.ts +14 -0
  139. package/lib/table-component/header/TableHead.js +69 -0
  140. package/lib/table-component/header/TableHeadCell.d.ts +14 -0
  141. package/lib/table-component/header/TableHeadCell.js +352 -0
  142. package/lib/table-component/header/TableHeadRow.d.ts +16 -0
  143. package/lib/table-component/header/TableHeadRow.js +84 -0
  144. package/lib/table-component/header/renderFilter.d.ts +20 -0
  145. package/lib/table-component/header/renderFilter.js +291 -0
  146. package/lib/table-component/hook/constant.d.ts +73 -0
  147. package/lib/table-component/hook/constant.js +247 -0
  148. package/lib/table-component/hook/useColumns.d.ts +9 -0
  149. package/lib/table-component/hook/useColumns.js +180 -0
  150. package/lib/table-component/hook/useFilterOperator.d.ts +7 -0
  151. package/lib/table-component/hook/useFilterOperator.js +40 -0
  152. package/lib/table-component/hook/utils.d.ts +133 -0
  153. package/lib/table-component/hook/utils.js +1969 -0
  154. package/lib/table-component/index.d.ts +5 -0
  155. package/lib/table-component/index.js +9 -0
  156. package/lib/table-component/style.scss +1129 -0
  157. package/lib/table-component/table/Grid.d.ts +24 -0
  158. package/lib/table-component/table/Grid.js +236 -0
  159. package/lib/table-component/type.d.ts +513 -0
  160. package/lib/table-component/type.js +5 -0
  161. package/lib/table-component/useContext.d.ts +74 -0
  162. package/lib/table-component/useContext.js +21 -0
  163. package/package.json +4 -2
@@ -0,0 +1,1870 @@
1
+ import { SELECTION_COLUMN } from "rc-master-ui/es/table/hooks/useSelection";
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { presetPalettes } from "@ant-design/colors";
4
+
5
+ // import type { AnyObject } from './type';
6
+
7
+ // import moment from "moment/moment"
8
+
9
+ import dayjs from "dayjs";
10
+ import moment from "moment";
11
+ export const newGuid = () => {
12
+ for (let i = 0; i < 20; i++) {
13
+ // @ts-ignore
14
+ // const id = crypto.randomUUID()
15
+ return uuidv4();
16
+ }
17
+ };
18
+ export const convertDayjsToDate = (dateString, format) => {
19
+ const dayjsDate = dayjs(dateString, format); // Parse using the provided format
20
+ if (!dayjsDate.isValid()) {
21
+ throw new Error('Invalid date or format');
22
+ }
23
+ // return moment(dayjsDate.toDate()).format() // Convert to JavaScript Date
24
+ return dayjsDate.toDate(); // Convert to JavaScript Date
25
+ };
26
+ export const convertDateToDayjs = (date, format) => {
27
+ const dateValue = date ? dayjs(date).format(format) : null;
28
+ return dateValue ? dayjs(dateValue, format) : null;
29
+ };
30
+ export const getCommonPinningStyles = column => {
31
+ const isPinned = column.getIsPinned();
32
+ // const isLastLeftPinnedColumn = isPinned === "left" && column.getIsLastColumn("left");
33
+ // const isFirstRightPinnedColumn =isPinned === "right" && column.getIsFirstColumn("right");
34
+
35
+ return {
36
+ // boxShadow: isFirstRightPinnedColumn
37
+ // ? "#e0e0e0 2px 0px 1px -1px inset"
38
+ // : undefined,
39
+
40
+ left: isPinned === "left" ? `${column.getStart("left")}px` : undefined,
41
+ right: isPinned === "right" ? `${column.getAfter("right")}px` : undefined,
42
+ // opacity: isPinned ? 0.5 : 1,
43
+ opacity: 1,
44
+ position: isPinned ? "sticky" : "relative",
45
+ width: column.getSize(),
46
+ zIndex: isPinned ? 2 : 0
47
+ };
48
+ };
49
+ export const sumSize = items => {
50
+ return items.reduce((total, item) => total + item.size, 0);
51
+ };
52
+ export const appendIfNotExists = (a, b) => {
53
+ const existingKeys = new Set(a.map(item => item.index));
54
+ b.forEach(item => {
55
+ if (!existingKeys.has(item.index)) {
56
+ a.push(item);
57
+ }
58
+ });
59
+ return a;
60
+ };
61
+ export const getNewItemsOnly = (a, b) => {
62
+ const existingKeys = new Set(a.map(item => item.key));
63
+ return b.filter(item => !existingKeys.has(item.key));
64
+ };
65
+ export const extendsObject = (...list) => {
66
+ const result = {
67
+ ...list[0]
68
+ };
69
+ for (let i = 1; i < list.length; i++) {
70
+ const obj = list[i];
71
+ if (obj) {
72
+ Object.keys(obj).forEach(key => {
73
+ const val = obj[key];
74
+ if (val !== undefined) {
75
+ result[key] = val;
76
+ }
77
+ });
78
+ }
79
+ }
80
+ return result;
81
+ };
82
+ export const isEmpty = d => {
83
+ return d === null || d === undefined || d === '';
84
+ };
85
+ export const getFormat = (colFormat, format) => {
86
+ return {
87
+ thousandSeparator: colFormat?.thousandSeparator ?? format?.thousandSeparator,
88
+ decimalSeparator: colFormat?.decimalSeparator ?? format?.decimalSeparator,
89
+ decimalScale: colFormat?.decimalScale ?? format?.decimalScale ? Number(colFormat?.decimalScale ?? format?.decimalScale) : colFormat?.decimalScale ?? format?.decimalScale,
90
+ allowNegative: colFormat?.allowNegative ?? format?.allowNegative,
91
+ // check nhập số âm
92
+ prefix: colFormat?.prefix ?? format?.prefix,
93
+ suffix: colFormat?.suffix ?? format?.suffix,
94
+ fixedDecimalScale: colFormat?.fixedDecimalScale ?? format?.fixedDecimalScale,
95
+ // mặc định thêm số 0 sau số thập phân
96
+ dateFormat: colFormat?.dateFormat ?? format?.dateFormat,
97
+ datetimeFormat: colFormat?.datetimeFormat ?? format?.datetimeFormat,
98
+ timeFormat: colFormat?.timeFormat ?? format?.timeFormat,
99
+ weekFormat: colFormat?.weekFormat ?? format?.weekFormat,
100
+ monthFormat: colFormat?.monthFormat ?? format?.monthFormat,
101
+ yearFormat: colFormat?.yearFormat ?? format?.yearFormat
102
+ };
103
+ };
104
+ export function convertFormat(formatStr) {
105
+ // return formatStr.split('').map((char, i) => {
106
+ // if (char === 'D' || char === 'd') {
107
+ // return 'd'; // ngày: lowercase
108
+ // }
109
+ // if (char === 'Y' || char === 'y') {
110
+ // return 'y'; // năm: lowercase
111
+ // }
112
+ // if (char === 'M' || char === 'm') {
113
+ // return char; // tháng: giữ nguyên
114
+ // }
115
+ // return char; // separator
116
+ // }).join('');
117
+
118
+ return formatStr.split('').map(char => {
119
+ if (char === 'D' || char === 'd') return 'd';
120
+ if (char === 'Y' || char === 'y') return 'y';
121
+ if ('Hhmsa'.includes(char)) return char; // giờ, phút, giây, am/pm
122
+ if (char === 'M' || char === 'm') return char; // tháng: giữ nguyên
123
+ return char; // dấu phân cách
124
+ }).join('');
125
+ }
126
+ export const getDatepickerFormat = (type, format) => {
127
+ const typeFormat = type ? type.toLowerCase() : '';
128
+ switch (typeFormat) {
129
+ case "date":
130
+ case "daterange":
131
+ return format?.dateFormat ?? 'DD/MM/YYYY';
132
+ case "datetime":
133
+ return format?.datetimeFormat ?? 'DD/MM/YYYY HH:mm';
134
+ case "week":
135
+ return format?.weekFormat ?? 'DD/MM';
136
+ case "month":
137
+ return format?.monthFormat ?? 'MM/YYYY';
138
+ case "quarter":
139
+ return format?.dateFormat ?? 'DD/MM/YYYY';
140
+ case "year":
141
+ return format?.yearFormat ?? 'YYYY';
142
+ case "time":
143
+ return format?.timeFormat ?? 'HH:mm';
144
+ default:
145
+ return 'DD/MM/YYYY';
146
+ }
147
+ };
148
+ export const getDateRangeFormat = (type, format) => {
149
+ const typeFormat = type ? type.toLowerCase() : '';
150
+ switch (typeFormat) {
151
+ case "date":
152
+ case "daterange":
153
+ return convertFormat(format?.dateFormat ?? 'dd/MM/yyyy');
154
+ case "datetime":
155
+ return format?.datetimeFormat ?? 'dd/MM/yyyy HH:mm';
156
+ case "week":
157
+ return format?.weekFormat ?? 'dd/MM';
158
+ case "month":
159
+ return format?.monthFormat ?? 'MM/yyyy';
160
+ case "quarter":
161
+ return format?.dateFormat ?? 'dd/MM/yyyy';
162
+ case "year":
163
+ return format?.yearFormat ?? 'yyyy';
164
+ case "time":
165
+ return format?.timeFormat ?? 'HH:mm';
166
+ default:
167
+ return 'dd/MM/yyyy';
168
+ }
169
+ };
170
+ export const getTypeFilter = col => {
171
+ if (col?.typeFilter) {
172
+ return col.typeFilter;
173
+ }
174
+ const type = col?.type ?? 'Text';
175
+ switch (type) {
176
+ case "number":
177
+ return 'Number';
178
+ case "date":
179
+ return 'Date';
180
+ case "datetime":
181
+ return 'Datetime';
182
+ case "boolean":
183
+ return 'Checkbox';
184
+ case "checkbox":
185
+ return 'Checkbox';
186
+
187
+ // case "week": return ''
188
+ // case "month": return 'Month'
189
+ // case "quarter": return col.format?.dateFormat ? col.format?.dateFormat : 'DD/MM/YYYY'
190
+ // case "year": return col.format?.yearFormat ? col.format?.yearFormat : 'YYYY'
191
+ // case "time": return col.format?.timeFormat ? col.format?.timeFormat : 'HH:mm'
192
+ case "string":
193
+ default:
194
+ return 'Text';
195
+ }
196
+ };
197
+ export const addRowIdArray = inputArray => {
198
+ if (inputArray) {
199
+ return inputArray.map(item => {
200
+ if (typeof item.children !== "string" && item.children && item.children.length > 0) {
201
+ item.children = addRowIdArray(item.children);
202
+ }
203
+ return {
204
+ ...item,
205
+ rowId: item.rowId ?? item.id ?? newGuid()
206
+ };
207
+ });
208
+ } else {
209
+ return [];
210
+ }
211
+ };
212
+ export function groupArrayByColumns(arr, columns) {
213
+ const result = [];
214
+ const checkEmpty = d => {
215
+ return d === null || d === undefined || d === '';
216
+ };
217
+ if (columns) {
218
+ arr.forEach(item => {
219
+ let currentLevel = result;
220
+ columns.forEach((column, index) => {
221
+ const value = item[column];
222
+ const existingItem = currentLevel.find(i => i[column] === value);
223
+ if (existingItem) {
224
+ currentLevel = existingItem.children;
225
+ } else {
226
+ // 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: [] }
227
+ const newItem = {
228
+ [column]: value,
229
+ field: column,
230
+ rowId: newGuid(),
231
+ // rowId: item[column],
232
+ parentId: !isEmpty(item[columns[index - 1]]) ? item[columns[index - 1]] : null,
233
+ // parentId: item.rowId[index - 1],
234
+ // indent: index,
235
+ children: []
236
+ };
237
+ currentLevel.push(newItem);
238
+ currentLevel = newItem.children;
239
+ }
240
+ });
241
+ currentLevel.push({
242
+ ...item,
243
+ rowId: item.id ?? item.rowId,
244
+ parentId: !checkEmpty(columns[columns.length - 1]) ? item[columns[columns.length - 1]] : null
245
+ // parentId: item.rowId[columns.length - 1],
246
+ // indent: columns.length
247
+ });
248
+ });
249
+ return result;
250
+ } else {
251
+ return arr;
252
+ }
253
+ }
254
+ export const flatColumns2 = columns => {
255
+ return columns.reduce((list, column) => {
256
+ const subColumns = column.children;
257
+ if (column === SELECTION_COLUMN) {
258
+ return [...list, {
259
+ ...column
260
+ }];
261
+ }
262
+ if (subColumns && subColumns.length > 0) {
263
+ return [...list, ...flatColumns2(subColumns).map(subColum => ({
264
+ ...subColum
265
+ }))];
266
+ }
267
+ return [...list, {
268
+ ...column
269
+ }];
270
+ }, []);
271
+ };
272
+ export const checkThousandSeparator = (thousandSeparator, decimalSeparator) => {
273
+ if (thousandSeparator) {
274
+ if (decimalSeparator) {
275
+ if (thousandSeparator === decimalSeparator) {
276
+ return ',';
277
+ } else {
278
+ return thousandSeparator;
279
+ }
280
+ } else {
281
+ return thousandSeparator;
282
+ }
283
+ } else {
284
+ return undefined;
285
+ }
286
+ };
287
+ export const checkDecimalSeparator = (thousandSeparator, decimalSeparator) => {
288
+ if (decimalSeparator) {
289
+ if (thousandSeparator) {
290
+ if (thousandSeparator === decimalSeparator) {
291
+ return '.';
292
+ } else {
293
+ return decimalSeparator;
294
+ }
295
+ } else {
296
+ return decimalSeparator;
297
+ }
298
+ } else {
299
+ if (thousandSeparator && thousandSeparator === '.') {
300
+ return ',';
301
+ }
302
+ return '.';
303
+ }
304
+ };
305
+ export function getFixedFields(columns, type) {
306
+ const result = [];
307
+ function traverse(cols) {
308
+ for (const col of cols) {
309
+ if (col.fixed === type && col.field) {
310
+ result.push(col.field);
311
+ }
312
+ if (col.children && col.children.length > 0) {
313
+ traverse(col.children);
314
+ }
315
+ }
316
+ }
317
+ traverse(columns);
318
+ return result;
319
+ }
320
+ export function areStringArraysEqual(a, b) {
321
+ if (a.length !== b.length) return false;
322
+ const sortedA = [...a].sort();
323
+ const sortedB = [...b].sort();
324
+ return sortedA.every((val, index) => val === sortedB[index]);
325
+ }
326
+ export const getDefaultOperator = col => {
327
+ if (col.operator) {
328
+ return col.operator;
329
+ }
330
+ if (col.typeFilter) {
331
+ switch (col.typeFilter) {
332
+ case 'Number':
333
+ case 'Date':
334
+ case 'Datetime':
335
+ case 'Time':
336
+ case 'Month':
337
+ case 'Quarter':
338
+ case 'Year':
339
+ case 'Week':
340
+ case 'Dropdown':
341
+ case 'Checkbox':
342
+ case 'CheckboxDropdown':
343
+ case 'CheckboxTree':
344
+ case 'DropTree':
345
+ return 'equal';
346
+ case 'Text':
347
+ default:
348
+ return 'contains';
349
+ }
350
+ }
351
+ switch (col.type) {
352
+ case 'number':
353
+ case 'date':
354
+ case 'datetime':
355
+ case 'week':
356
+ case 'year':
357
+ case 'quarter':
358
+ return 'equal';
359
+ case 'string':
360
+ default:
361
+ return 'contains';
362
+ }
363
+ };
364
+ export function isEqualSet(setA, setB) {
365
+ if (setA.size !== setB.size) {
366
+ return false;
367
+ }
368
+ for (const item of setA) {
369
+ if (!setB.has(item)) {
370
+ return false;
371
+ }
372
+ }
373
+ return true;
374
+ }
375
+ export const getLastSelectCell = selectCells => {
376
+ if (selectCells.size === 0) {
377
+ return {
378
+ row: 0,
379
+ col: 0
380
+ };
381
+ }
382
+ const lastValue = [...selectCells].at(-1);
383
+ const [row, col] = lastValue.split("-").map(Number);
384
+ return {
385
+ row,
386
+ col
387
+ };
388
+ };
389
+ export function getCellsByPosition(cellSet, position = "bottom") {
390
+ const cells = Array.from(cellSet).map(key => {
391
+ const [row, col] = key.split("-").map(Number);
392
+ return {
393
+ row,
394
+ col,
395
+ key
396
+ };
397
+ });
398
+ switch (position) {
399
+ case "top":
400
+ {
401
+ // const minRow = Math.min(...cells.map(c => c.row));
402
+ // return cells.filter(c => c.row === minRow).map(c => c.key);
403
+
404
+ // const rows = cells.map(c => c.row).filter(r => r > 0);
405
+ // if (rows.length === 0) return [];
406
+ // const minRow = Math.min(...rows);
407
+ // return cells.filter(c => c.row === minRow).map(c => c.key);
408
+
409
+ const minRow = Math.min(...cells.map(c => c.row));
410
+ if (minRow === 0) {
411
+ return [];
412
+ } // Bỏ qua nếu rowIndex = 0
413
+
414
+ return cells.filter(c => c.row === minRow).map(c => `${c.row}-${c.col}`);
415
+ }
416
+ case "bottom":
417
+ {
418
+ const maxRow = Math.max(...cells.map(c => c.row));
419
+ return cells.filter(c => c.row === maxRow).map(c => c.key);
420
+ }
421
+ case "left":
422
+ {
423
+ // const minCol = Math.min(...cells.map(c => c.col));
424
+ // return cells.filter(c => c.col === minCol).map(c => c.key);
425
+
426
+ // const cols = cells.map(c => c.col).filter(c => c > 0);
427
+ // if (cols.length === 0) return [];
428
+ // const minCol = Math.min(...cols);
429
+ // return cells.filter(c => c.col === minCol).map(c => c.key);
430
+
431
+ const minCol = Math.min(...cells.map(c => c.col));
432
+ if (minCol === 0) {
433
+ return [];
434
+ } // Bỏ qua nếu colIndex = 0
435
+
436
+ // Trả về các ô cùng row, nhưng ở cột bên trái
437
+ return cells.filter(c => c.col === minCol).map(c => `${c.row}-${c.col}`);
438
+ }
439
+ case "right":
440
+ {
441
+ const maxCol = Math.max(...cells.map(c => c.col));
442
+ return cells.filter(c => c.col === maxCol).map(c => c.key);
443
+ }
444
+ default:
445
+ return [];
446
+ }
447
+ }
448
+ export const onAddBgSelectedCell = (selectedCells, id, isFocusCellIndex) => {
449
+ const selectors = Array.from(selectedCells).map(pos => {
450
+ const [row1, col1] = pos.split('-');
451
+ return `[data-row-index="${row1}"][data-col-index="${col1}"]`;
452
+ });
453
+ const table = document.querySelector(`#${id}`);
454
+
455
+ //// xóa class các ô đã chọn trước đó
456
+ const cellsSelected = table ? table?.querySelectorAll('.ui-rc-table-cell.selected-bg') : null;
457
+ if (cellsSelected) {
458
+ cellsSelected.forEach(cell => {
459
+ cell.classList.remove('selected-bg');
460
+ });
461
+ }
462
+
463
+ /// thêm class
464
+ const cells = table && selectors.length > 0 ? table?.querySelectorAll(selectors.join(',')) : null;
465
+ if (cells) {
466
+ cells.forEach(cell => {
467
+ cell.classList.add('selected-bg');
468
+ });
469
+ }
470
+ const rowsArray = [...new Set([...selectedCells].map(item => item.split("-")[0]))];
471
+ const rowsSelectors = rowsArray.map(r => `.rc-ui-cell-index[data-row-index="${r}"]`).join(", ");
472
+ const cellsIndex = table && rowsSelectors.length > 0 ? table?.querySelectorAll(rowsSelectors) : null;
473
+ if (cellsIndex && isFocusCellIndex !== false) {
474
+ cellsIndex.forEach(cell => {
475
+ cell.classList.add('focus');
476
+ });
477
+ }
478
+
479
+ // // tăng z-index để hiển thị round point paste
480
+ // const row = getLastSelectCell(selectedCells).row
481
+ // const col = getLastSelectCell(selectedCells).col
482
+ // const cell: any = table?.querySelector(`.ui-rc-table-cell[data-row-index="${row}"][data-col-index="${col}"]`)
483
+ //
484
+ // if (cell) {
485
+ // cell.style.zIndex = 1
486
+ // }
487
+ //
488
+ // if (cell && cell.classList.contains('ui-rc-table-cell-fix-left')) {
489
+ // cell.style.zIndex = 3;
490
+ // }
491
+
492
+ // thêm class border selected
493
+
494
+ // addBorderClass(selectedCells, 'bottom', 'cell-border-bottom', id)
495
+ // addBorderClass(selectedCells, 'right', 'cell-border-right', id)
496
+ // addBorderClass(selectedCells, 'top', 'cell-border-top', id)
497
+ // addBorderClass(selectedCells, 'left', 'cell-border-left', id)
498
+ };
499
+ export const onRemoveBgSelectedCell = (selectedCells, id, rowsSelected) => {
500
+ const table = document.querySelector(`#${id}`);
501
+ const cells = table ? table?.querySelectorAll('.ui-rc-table-cell.selected-bg') : null;
502
+ if (cells) {
503
+ cells.forEach(cell => {
504
+ cell.classList.remove('selected-bg');
505
+ });
506
+ }
507
+ const cellsIndex = table ? table?.querySelectorAll('.ui-rc-table-cell.focus') : null;
508
+ if (cellsIndex) {
509
+ cellsIndex.forEach(cell => {
510
+ cell.classList.remove('focus');
511
+ });
512
+ }
513
+
514
+ // xóa class selected ô STT
515
+
516
+ if (rowsSelected && rowsSelected.size > 0) {
517
+ const rowsSelectedArray = [...new Set([...rowsSelected].map(item => item.split("-")[0]))];
518
+ const rowsSelectedSelectors = rowsSelectedArray.map(r => `.rc-ui-cell-index[data-row-index="${r}"]`).join(", ");
519
+ const cellsSelectedIndex = table && rowsSelectedSelectors.length > 0 ? table?.querySelectorAll(rowsSelectedSelectors) : null;
520
+ if (cellsSelectedIndex) {
521
+ cellsSelectedIndex.forEach(cell => {
522
+ cell.classList.remove('selected');
523
+ });
524
+ }
525
+ }
526
+ };
527
+ export function getColIdsBetween(table, a, b) {
528
+ const ids = table.getVisibleLeafColumns().map(c => c.id);
529
+ const [start, end] = [ids.indexOf(a), ids.indexOf(b)].sort((x, y) => x - y);
530
+ return ids.slice(start, end + 1);
531
+ }
532
+ export function getRowIdsBetween(table, a, b) {
533
+ // const ids = table.getRowModel().rows.map(r => r.id);
534
+ const ids = table.getRowModel().flatRows.map(r => r.id);
535
+ const [start, end] = [ids.indexOf(a), ids.indexOf(b)].sort((x, y) => x - y);
536
+ return ids.slice(start, end + 1);
537
+ }
538
+ export const updateArrayByKey = (arr, element, key) => {
539
+ if (arr) {
540
+ return arr.map(it => {
541
+ const item = {
542
+ ...it
543
+ };
544
+ if (item[key] === element[key]) {
545
+ return {
546
+ ...item,
547
+ ...element
548
+ };
549
+ } else if (item.children && item.children.length > 0) {
550
+ item.children = updateArrayByKey(item.children, element, key);
551
+ }
552
+ return item;
553
+ });
554
+ } else {
555
+ return [];
556
+ }
557
+ };
558
+ export const unFlattenData = data => {
559
+ const idToNodeMap = {};
560
+ const tree = [];
561
+
562
+ // Bước 1: Tạo map id -> node
563
+ data.forEach(item => {
564
+ // idToNodeMap[item.rowId] = { ...item, children: [] }
565
+ idToNodeMap[item.rowId] = {
566
+ ...item
567
+ };
568
+ });
569
+
570
+ // Bước 2: Gắn vào parent hoặc đẩy lên root nếu không có parent
571
+ data.forEach(item => {
572
+ const currentNode = idToNodeMap[item.rowId];
573
+ if (!item.parentId) {
574
+ tree.push(currentNode);
575
+ } else {
576
+ const parentNode = idToNodeMap[item.parentId];
577
+ if (parentNode) {
578
+ parentNode.children = parentNode.children ?? [];
579
+ parentNode.children.push(currentNode);
580
+ } else {
581
+ // Nếu parentId không tồn tại thì xem như root
582
+ tree.push(currentNode);
583
+ }
584
+ }
585
+ });
586
+ return tree;
587
+ };
588
+ export const flattenArray = arr => {
589
+ if (!arr) {
590
+ return [];
591
+ }
592
+ return arr.reduce((r, {
593
+ children,
594
+ ...rest
595
+ }) => {
596
+ r.push(rest);
597
+ if (children) {
598
+ r.push(...flattenArray(children));
599
+ }
600
+ return r;
601
+ }, []);
602
+ };
603
+ export function updateOrInsert(dataArray, dataFilter) {
604
+ const updatedArray = [...dataArray];
605
+ dataFilter.forEach(filterItem => {
606
+ const existingIndex = updatedArray.findIndex(item => item.rowId === filterItem.rowId);
607
+ if (existingIndex !== -1) {
608
+ // Cập nhật item đã tồn tại
609
+ updatedArray[existingIndex] = {
610
+ ...updatedArray[existingIndex],
611
+ ...filterItem
612
+ };
613
+ } else {
614
+ // Tìm vị trí cuối cùng của item trước đó trong dataFilter
615
+ const prevIndexInFilter = dataFilter.findIndex(f => f.rowId === filterItem.rowId) - 1;
616
+ if (prevIndexInFilter >= 0) {
617
+ const prevId = dataFilter[prevIndexInFilter].rowId;
618
+ const prevIndexInArray = updatedArray.findIndex(item => item.rowId === prevId);
619
+ if (prevIndexInArray !== -1) {
620
+ // Thêm ngay sau phần tử trước đó
621
+ updatedArray.splice(prevIndexInArray + 1, 0, filterItem);
622
+ return;
623
+ }
624
+ }
625
+
626
+ // 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
627
+ updatedArray.push(filterItem);
628
+ }
629
+ });
630
+ return updatedArray;
631
+ }
632
+ export const findItemByKey = (array, key, value) => {
633
+ for (let i = 0; i < array.length; i++) {
634
+ const item = array[i];
635
+ if (item[key] === value) {
636
+ return item;
637
+ }
638
+ if (item.children && item.children.length > 0) {
639
+ const foundInChildren = findItemByKey(item.children, key, value);
640
+ if (foundInChildren) {
641
+ return foundInChildren;
642
+ }
643
+ }
644
+ }
645
+ return null;
646
+ };
647
+ export const isFormattedNumber = str => {
648
+ if (!str) return false;
649
+ if (typeof str !== 'string') return false;
650
+ const regexUS = /^\d{1,3}(,\d{3})*(\.\d+)?$/; // 100,000.111
651
+ const regexEU = /^\d{1,3}(\.\d{3})*(,\d+)?$/; // 100.000,111
652
+
653
+ // Không có dấu hàng nghìn, chỉ dấu thập phân: 100000.1 hoặc 100000,01
654
+ const regexDecimalOnly = /^\d+([.,]\d{1,})$/;
655
+ return regexUS.test(str) || regexEU.test(str) || regexDecimalOnly.test(str);
656
+ };
657
+ export const detectSeparators = str => {
658
+ if (typeof str !== 'string') return null;
659
+ const hasComma = str.includes(',');
660
+ const hasDot = str.includes('.');
661
+
662
+ // Trường hợp có cả dấu , và .
663
+ if (hasComma && hasDot) {
664
+ const lastComma = str.lastIndexOf(',');
665
+ const lastDot = str.lastIndexOf('.');
666
+ return lastComma > lastDot ? {
667
+ thousandSeparator: '.',
668
+ decimalSeparator: ','
669
+ } : {
670
+ thousandSeparator: ',',
671
+ decimalSeparator: '.'
672
+ };
673
+ }
674
+
675
+ // Trường hợp chỉ có dấu phẩy
676
+ if (hasComma && !hasDot) {
677
+ const parts = str.split(',');
678
+ if (parts.length === 2) {
679
+ return parts[1].length === 3 ? {
680
+ thousandSeparator: ',',
681
+ decimalSeparator: null
682
+ } : {
683
+ thousandSeparator: null,
684
+ decimalSeparator: ','
685
+ };
686
+ }
687
+ }
688
+
689
+ // Trường hợp chỉ có dấu chấm
690
+ if (hasDot && !hasComma) {
691
+ const parts = str.split('.');
692
+ if (parts.length === 2) {
693
+ return parts[1].length === 3 ? {
694
+ thousandSeparator: '.',
695
+ decimalSeparator: null
696
+ } : {
697
+ thousandSeparator: null,
698
+ decimalSeparator: '.'
699
+ };
700
+ }
701
+ }
702
+
703
+ // Không có dấu hoặc không hợp lệ
704
+ return null;
705
+ };
706
+ function isDate(value) {
707
+ if (value instanceof Date) {
708
+ return !isNaN(value.getTime());
709
+ }
710
+ if (typeof value === "string") {
711
+ // Chỉ chấp nhận định dạng yyyy-mm-dd hoặc mm/yyyy
712
+ return /^\d{4}-\d{2}-\d{2}$/.test(value) || /^\d{2}\/\d{4}$/.test(value);
713
+ }
714
+ return false;
715
+ }
716
+
717
+ // Chuỗi MM/YYYY → Date
718
+ export function isDateString(str) {
719
+ return typeof str === "string" && (/^\d{2}\/\d{4}$/.test(str) || /^\d{4}-\d{2}-\d{2}$/.test(str));
720
+ }
721
+ function parseToDate(str) {
722
+ if (/^\d{2}\/\d{4}$/.test(str)) {
723
+ const [month, year] = str.split('/');
724
+ return new Date(parseInt(year), parseInt(month) - 1, 1);
725
+ }
726
+ return new Date(str);
727
+ }
728
+
729
+ // So sánh ngày (cùng ngày/tháng/năm)
730
+ export function compareDates(date1, date2) {
731
+ return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
732
+ }
733
+
734
+ // Helper: compare MM/YYYY date string with itemValue
735
+ export function compareDate(itemValue, value) {
736
+ const [month, year] = value.split('/').map(Number);
737
+ const date = new Date(itemValue);
738
+ return date.getMonth() + 1 === month && date.getFullYear() === year;
739
+ }
740
+ export const removeVietnameseTones = str => {
741
+ if (!str) {
742
+ return '';
743
+ }
744
+ return str.normalize('NFD') // Tách các ký tự có dấu thành ký tự cơ bản + dấu
745
+ .replace(/[\u0300-\u036f]/g, '') // Xóa dấu
746
+ .replace(/đ/g, 'd') // Thay thế đ
747
+ .replace(/Đ/g, 'D').replace(/[^a-zA-Z0-9\s]/g, '') // Loại bỏ ký tự đặc biệt
748
+ .replace(/\s+/g, ' ') // Thay nhiều khoảng trắng thành 1 khoảng trắng
749
+ .trim();
750
+ };
751
+ export const shouldInclude = (item, queries) => {
752
+ if (item.isFilterState === true) {
753
+ return true;
754
+ }
755
+ let result = null;
756
+ for (const query of queries) {
757
+ const {
758
+ field,
759
+ value,
760
+ operator,
761
+ predicate
762
+ } = query;
763
+ const itemValue = item[field];
764
+ let condition = false;
765
+ const isDateComparison = isDate(itemValue) || isDateString(value);
766
+ const itemDate = isDateComparison ? new Date(itemValue) : null;
767
+ const queryDate = isDateComparison ? parseToDate(value) : null;
768
+ const itemStr = removeVietnameseTones(itemValue?.toString().toLowerCase?.() ?? '');
769
+ const queryStr = removeVietnameseTones(value?.toString().toLowerCase?.() ?? '');
770
+ switch (operator.toLowerCase()) {
771
+ case "equal":
772
+ condition = isDateComparison ? compareDates(itemDate, queryDate) : itemValue === value;
773
+ break;
774
+ case "notequal":
775
+ condition = isDateComparison ? !compareDates(itemDate, queryDate) : itemValue !== value;
776
+ break;
777
+ case "greaterthan":
778
+ // @ts-ignore
779
+ condition = isDateComparison ? itemDate > queryDate : itemValue > value;
780
+
781
+ // condition = isDateComparison ? invalidDate(itemDate) && invalidDate(queryDate) && itemDate > queryDate : itemValue > value;
782
+ break;
783
+ case "greaterthanorequal":
784
+ // @ts-ignore
785
+ condition = isDateComparison ? itemDate >= queryDate : itemValue >= value;
786
+ break;
787
+ case "lessthan":
788
+ // @ts-ignore
789
+ condition = isDateComparison ? itemDate < queryDate : itemValue < value;
790
+ break;
791
+ case "lessthanorequal":
792
+ // @ts-ignore
793
+ condition = isDateComparison ? itemDate <= queryDate : itemValue <= value;
794
+ break;
795
+ case "contains":
796
+ condition = itemStr?.includes(queryStr);
797
+ break;
798
+ case "startswith":
799
+ condition = itemStr?.startsWith(queryStr);
800
+ break;
801
+ case "endswith":
802
+ condition = itemStr?.endsWith(queryStr);
803
+ break;
804
+ default:
805
+ console.warn(`Unknown operator: ${operator}`);
806
+ break;
807
+ }
808
+ if (predicate === "and") {
809
+ result = result === null ? condition : result && condition;
810
+ } else if (predicate === "or") {
811
+ result = result === null ? condition : result || condition;
812
+ }
813
+ }
814
+ return result;
815
+ };
816
+ function compareValues(a, b, order) {
817
+ const desc = order === "descend";
818
+ if (a == null && b == null) return 0;
819
+ if (a == null) return desc ? 1 : -1;
820
+ if (b == null) return desc ? -1 : 1;
821
+
822
+ // Nếu là số
823
+ if (typeof a === "number" && typeof b === "number") {
824
+ return desc ? b - a : a - b;
825
+ }
826
+
827
+ // Nếu là ngày hợp lệ
828
+ const dateA = new Date(a);
829
+ const dateB = new Date(b);
830
+ if (!isNaN(dateA.getTime()) && !isNaN(dateB.getTime())) {
831
+ return desc ? dateB.getTime() - dateA.getTime() : dateA.getTime() - dateB.getTime();
832
+ }
833
+
834
+ // Mặc định coi như string
835
+ return desc ? String(b).localeCompare(String(a)) : String(a).localeCompare(String(b));
836
+ }
837
+ export function sortData(data, sorter) {
838
+ const sorted = [...data].sort((a, b) => {
839
+ for (const {
840
+ field,
841
+ order
842
+ } of sorter) {
843
+ const result = compareValues(a[field], b[field], order);
844
+ if (result !== 0) return result;
845
+ }
846
+ return 0;
847
+ });
848
+ return sorted.map(item => ({
849
+ ...item,
850
+ children: item.children ? sortData(item.children, sorter) : undefined
851
+ }));
852
+ }
853
+ export function filterDataByColumns(data, queries, sorter, keysFilter) {
854
+ if (!queries || queries.length === 0) {
855
+ return sorter ? sortData(data, sorter) : data;
856
+ }
857
+ let filtered = data.map(item => {
858
+ const newItem = {
859
+ ...item
860
+ };
861
+ if (Array.isArray(item.children)) {
862
+ newItem.children = filterDataByColumns(item.children, queries, sorter, keysFilter);
863
+ }
864
+ const isSelfMatched = shouldInclude(item, queries) || keysFilter?.includes(newItem?.rowId);
865
+
866
+ // Nếu chính item thỏa hoặc có con thỏa → giữ lại
867
+ if (isSelfMatched || newItem.children && newItem.children.length > 0) {
868
+ return newItem;
869
+ }
870
+ return null; // loại bỏ node không phù hợp
871
+ }).filter(Boolean); // xóa các null
872
+
873
+ if (sorter && sorter.length > 0) {
874
+ filtered = sortData(filtered, sorter);
875
+ }
876
+ return filtered;
877
+ }
878
+ export const getAllRowKey = data => {
879
+ const a = flattenArray(data);
880
+ return a.length ? a.map(it => it.rowId) : undefined;
881
+ };
882
+ export const isEditable = (column, rowData) => {
883
+ if (column && typeof column.editEnable === 'function') {
884
+ return column.editEnable(rowData);
885
+ }
886
+ return column?.editEnable;
887
+ };
888
+ export const checkFieldKey = key => {
889
+ if (key) {
890
+ return key;
891
+ } else {
892
+ return 'value';
893
+ }
894
+ };
895
+ export const convertArrayWithIndent = (inputArray, parentIndent = 0) => {
896
+ if (inputArray) {
897
+ return inputArray.map(item => {
898
+ const indent = parentIndent;
899
+ if (item.children && item.children.length > 0) {
900
+ item.children = convertArrayWithIndent(item.children, indent + 1);
901
+ }
902
+ return {
903
+ ...item,
904
+ indent,
905
+ rowId: item.rowId ? item.rowId : item.id ? item.id : newGuid()
906
+ };
907
+ });
908
+ } else {
909
+ return [];
910
+ }
911
+ };
912
+ export const convertLabelToTitle = data => {
913
+ return data.map(item => {
914
+ const {
915
+ label,
916
+ title,
917
+ value,
918
+ key,
919
+ ...rest
920
+ } = item;
921
+ const newItem = {
922
+ ...rest,
923
+ value,
924
+ label,
925
+ key: key ?? value,
926
+ title: title ?? label
927
+ };
928
+ if (item.children) {
929
+ newItem.children = convertLabelToTitle(item.children);
930
+ }
931
+ return newItem;
932
+ });
933
+ };
934
+ export const isNullOrUndefined = d => {
935
+ return d === null || d === undefined;
936
+ };
937
+ export const isObjEmpty = obj => {
938
+ if (isNullOrUndefined(obj)) {
939
+ return true;
940
+ } else {
941
+ return Object.keys(obj).length === 0;
942
+ }
943
+ };
944
+ export const isDisable = (column, rowData) => {
945
+ if (column && typeof column?.disable === 'function') {
946
+ return column.disable(rowData);
947
+ }
948
+ return !!column?.disable;
949
+ };
950
+ export const customWeekStartEndFormat = (value, weekFormat) => {
951
+ return `${dayjs(value).startOf('week').format(weekFormat)} ~ ${dayjs(value).endOf('week').format(weekFormat)}`;
952
+ };
953
+ export const parseBooleanToValue = (value, type) => {
954
+ return type === 'boolean' ? value : Number(value);
955
+ };
956
+ export const isNameColor = strColor => {
957
+ const s = new Option().style;
958
+ s.color = strColor;
959
+ return s.color === strColor;
960
+ };
961
+ export const isColor = value => {
962
+ const hexRegex = /^#([0-9A-F]{3}){1,2}$/i;
963
+ const rgbRegex = /^rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)$/;
964
+ const rgbaRegex = /^rgba\((\d{1,3}), (\d{1,3}), (\d{1,3}), (0|1|0?\.\d+)\)$/;
965
+ const hslRegex = /^hsl\(\d{1,3}, \d{1,3}%, \d{1,3}%\)$/;
966
+ const hslaRegex = /^hsla\(\d{1,3}, \d{1,3}%, \d{1,3}%, (0|1|0?\.\d+)\)$/;
967
+ const namedColors = /^(?:aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)$/i;
968
+ return hexRegex.test(value) || rgbRegex.test(value) || rgbaRegex.test(value) || hslRegex.test(value) || hslaRegex.test(value) || namedColors.test(value) || isNameColor(value);
969
+ };
970
+ export const genPresets = (presets = presetPalettes) => {
971
+ return Object.entries(presets).map(([label, colors]) => ({
972
+ label,
973
+ colors,
974
+ key: label
975
+ }));
976
+ };
977
+ export const getEditType = (column, rowData) => {
978
+ if (column && typeof column.editType === 'function') {
979
+ return column.editType(rowData);
980
+ }
981
+ return column?.editType ?? 'text';
982
+ };
983
+ export const getDefaultValue = defaultValue => {
984
+ if (defaultValue && typeof defaultValue === 'function') {
985
+ return defaultValue();
986
+ }
987
+ return defaultValue;
988
+ };
989
+ export const flattenData = (childrenColumnName, data) => {
990
+ let list = [];
991
+ (data || []).forEach(record => {
992
+ list.push(record);
993
+ if (record && typeof record === 'object' && childrenColumnName in record) {
994
+ list = [...list, ...flattenData(childrenColumnName, record[childrenColumnName])];
995
+ }
996
+ });
997
+ return list;
998
+ };
999
+ export const getSelectedCellMatrix = (table, startCell, endCell) => {
1000
+ if (!startCell || !endCell) return {
1001
+ rowIds: [],
1002
+ colIds: [],
1003
+ startRowIndex: undefined,
1004
+ endRowIndex: undefined,
1005
+ startColIndex: undefined,
1006
+ endColIndex: undefined,
1007
+ colRange: [],
1008
+ rowRange: []
1009
+ };
1010
+
1011
+ // const rowIds = table.getRowModel().rows.map(r => r.id);
1012
+ const rowIds = table.getRowModel().flatRows.map(r => r.id);
1013
+ const colIds = table.getVisibleLeafColumns().map(c => c.id);
1014
+
1015
+ // const colIds = table.getAllLeafColumns().map(c => c.id);
1016
+
1017
+ const [startRowIndex, endRowIndex] = [rowIds.indexOf(startCell.rowId), rowIds.indexOf(endCell.rowId)].sort((a, b) => a - b);
1018
+ const [startColIndex, endColIndex] = [colIds.indexOf(startCell.colId), colIds.indexOf(endCell.colId)].sort((a, b) => a - b);
1019
+ return {
1020
+ rowRange: rowIds.slice(startRowIndex, endRowIndex + 1),
1021
+ colRange: colIds.slice(startColIndex, endColIndex + 1),
1022
+ startRowIndex,
1023
+ endRowIndex,
1024
+ startColIndex,
1025
+ endColIndex,
1026
+ rowIds,
1027
+ colIds
1028
+ };
1029
+ };
1030
+ export function addRowsDownWithCtrl(arr, n) {
1031
+ if (!Array.isArray(arr) || arr.length === 0) {
1032
+ return {
1033
+ combined: arr,
1034
+ addedRows: []
1035
+ };
1036
+ }
1037
+ const m = arr.length;
1038
+ const numCols = arr[0].length;
1039
+ const addedRows = [];
1040
+
1041
+ // Hàm kiểm tra kiểu date hợp lệ
1042
+ const isValidDate = item => {
1043
+ // return !isNaN(Date.parse(d))
1044
+
1045
+ if (typeof item === 'number') {
1046
+ // return 'number'
1047
+ return false;
1048
+ }
1049
+ if (typeof item === 'string') {
1050
+ // Kiểm tra nếu là chuỗi ISO date hợp lệ
1051
+ const date = new Date(item);
1052
+ if (!isNaN(date.getTime()) && item.includes('T')) {
1053
+ // return 'date'
1054
+ return true;
1055
+ }
1056
+ // return 'string'
1057
+ return false;
1058
+ }
1059
+ return !isNaN(Date.parse(item));
1060
+ };
1061
+
1062
+ // Lấy giá trị mẫu của cột j từ hàng đầu tiên
1063
+ const getSample = j => arr[0][j];
1064
+
1065
+ // Xác định chế độ xử lý cho mỗi cột:
1066
+ // mode = 'number-stepping' | 'date-stepping' | 'number-constant' | 'cycle'
1067
+ const modes = [];
1068
+ const steps = []; // bước tăng, nếu có (cho number hoặc date)
1069
+
1070
+ for (let j = 0; j < numCols; j++) {
1071
+ const sample = getSample(j);
1072
+ if (m === 1) {
1073
+ // 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.
1074
+ if (typeof sample === "number") {
1075
+ modes[j] = "number-constant";
1076
+ } else if (isValidDate(sample)) {
1077
+ modes[j] = "date-stepping";
1078
+ steps[j] = 24 * 3600 * 1000; // 1 ngày = 86400000 ms
1079
+ } else {
1080
+ modes[j] = "cycle";
1081
+ }
1082
+ } else if (m === 2) {
1083
+ // 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
1084
+ const first = arr[0][j],
1085
+ second = arr[1][j];
1086
+ if (typeof first === "number" && typeof second === "number") {
1087
+ modes[j] = "number-stepping";
1088
+ steps[j] = second - first;
1089
+ } else if (isValidDate(first) && isValidDate(second)) {
1090
+ modes[j] = "date-stepping";
1091
+ steps[j] = Date.parse(second) - Date.parse(first);
1092
+ } else {
1093
+ modes[j] = "cycle";
1094
+ }
1095
+ } else {
1096
+ // Nếu mảng có >2 hàng
1097
+ const first = arr[0][j],
1098
+ second = arr[1][j],
1099
+ third = arr[2][j];
1100
+ if (typeof first === "number" && typeof second === "number" && typeof third === "number") {
1101
+ const step1 = second - first;
1102
+ const step2 = third - second;
1103
+ if (step1 === step2) {
1104
+ modes[j] = "number-stepping";
1105
+ steps[j] = step1;
1106
+ } else {
1107
+ modes[j] = "cycle";
1108
+ }
1109
+ } else if (isValidDate(first) && isValidDate(second) && isValidDate(third)) {
1110
+ const step1 = Date.parse(second) - Date.parse(first);
1111
+ const step2 = Date.parse(third) - Date.parse(second);
1112
+ if (step1 === step2) {
1113
+ modes[j] = "date-stepping";
1114
+ steps[j] = step1;
1115
+ } else {
1116
+ modes[j] = "cycle";
1117
+ }
1118
+ } else {
1119
+ modes[j] = "cycle";
1120
+ }
1121
+ }
1122
+ }
1123
+
1124
+ // Tạo các dòng mới (thêm n dòng)
1125
+ // 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
1126
+ // Nếu chế độ là cycle thì dùng arr[i mod m][j]
1127
+ for (let i = 0; i < n; i++) {
1128
+ const newRow = [];
1129
+ for (let j = 0; j < numCols; j++) {
1130
+ let newValue;
1131
+ switch (modes[j]) {
1132
+ case "number-constant":
1133
+ // Mảng có 1 hàng, số giữ nguyên
1134
+ newValue = arr[0][j];
1135
+ break;
1136
+ case "number-stepping":
1137
+ {
1138
+ // Lấy giá trị cuối của cột j trong mảng ban đầu
1139
+ const lastValue = arr[m - 1][j];
1140
+ newValue = lastValue + (i + 1) * steps[j];
1141
+ }
1142
+ break;
1143
+ case "date-stepping":
1144
+ {
1145
+ // 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
1146
+ const lastDate = new Date(arr[m - 1][j]);
1147
+ const newTime = lastDate.getTime() + (i + 1) * steps[j];
1148
+ newValue = moment(new Date(newTime)).format();
1149
+ }
1150
+ break;
1151
+ case "cycle":
1152
+ default:
1153
+ // Lặp lại nội dung theo vòng tròn: dùng hàng thứ (i mod m)
1154
+ newValue = arr[i % m][j];
1155
+ break;
1156
+ }
1157
+ newRow.push(newValue);
1158
+ }
1159
+ addedRows.push(newRow);
1160
+ }
1161
+ const combined = arr.concat(addedRows);
1162
+ return {
1163
+ combined,
1164
+ addedRows
1165
+ };
1166
+ }
1167
+ export function addRowsDown(arr, n) {
1168
+ if (!Array.isArray(arr) || arr.length === 0) {
1169
+ return {
1170
+ combined: arr,
1171
+ addedRows: []
1172
+ };
1173
+ }
1174
+ const m = arr.length;
1175
+ const numCols = arr[0].length;
1176
+ const addedRows = [];
1177
+
1178
+ // // Hàm kiểm tra kiểu date hợp lệ
1179
+ // const isValidDate = (item: any) => {
1180
+ //
1181
+ //
1182
+ // // return !isNaN(Date.parse(d))
1183
+ //
1184
+ // if (typeof item === 'number') {
1185
+ // // return 'number'
1186
+ // return false
1187
+ // }
1188
+ // if (typeof item === 'string') {
1189
+ // // Kiểm tra nếu là chuỗi ISO date hợp lệ
1190
+ // const date = new Date(item)
1191
+ // if (!isNaN(date.getTime()) && item.includes('T')) {
1192
+ // // return 'date'
1193
+ // return true
1194
+ // }
1195
+ // // return 'string'
1196
+ // return false
1197
+ // }
1198
+ //
1199
+ // return !isNaN(Date.parse(item))
1200
+ //
1201
+ // }
1202
+
1203
+ // Lấy giá trị mẫu của cột j từ hàng đầu tiên
1204
+ const getSample = j => arr[0][j];
1205
+
1206
+ // Xác định chế độ xử lý cho mỗi cột:
1207
+ // mode = 'number-stepping' | 'date-stepping' | 'number-constant' | 'cycle'
1208
+ const modes = [];
1209
+ const steps = []; // bước tăng, nếu có (cho number hoặc date)
1210
+
1211
+ for (let j = 0; j < numCols; j++) {
1212
+ const sample = getSample(j);
1213
+ if (m === 1) {
1214
+ // 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.
1215
+ if (typeof sample === "number") {
1216
+ modes[j] = "number-constant";
1217
+ }
1218
+ // else if (isValidDate(sample)) {
1219
+ // modes[j] = "date-stepping"
1220
+ // steps[j] = 24 * 3600 * 1000 // 1 ngày = 86400000 ms
1221
+ // }
1222
+ else {
1223
+ modes[j] = "cycle";
1224
+ }
1225
+ } else if (m === 2) {
1226
+ // 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
1227
+ const first = arr[0][j],
1228
+ second = arr[1][j];
1229
+ if (typeof first === "number" && typeof second === "number") {
1230
+ modes[j] = "number-stepping";
1231
+ steps[j] = second - first;
1232
+ }
1233
+ // else if (isValidDate(first) && isValidDate(second)) {
1234
+ // modes[j] = "date-stepping"
1235
+ // steps[j] = Date.parse(second) - Date.parse(first)
1236
+ // }
1237
+ else {
1238
+ modes[j] = "cycle";
1239
+ }
1240
+ } else {
1241
+ // Nếu mảng có >2 hàng
1242
+ const first = arr[0][j],
1243
+ second = arr[1][j],
1244
+ third = arr[2][j];
1245
+ if (typeof first === "number" && typeof second === "number" && typeof third === "number") {
1246
+ const step1 = second - first;
1247
+ const step2 = third - second;
1248
+ if (step1 === step2) {
1249
+ modes[j] = "number-stepping";
1250
+ steps[j] = step1;
1251
+ } else {
1252
+ modes[j] = "cycle";
1253
+ }
1254
+ }
1255
+ // else if (isValidDate(first) && isValidDate(second) && isValidDate(third)) {
1256
+ // const step1 = Date.parse(second) - Date.parse(first)
1257
+ // const step2 = Date.parse(third) - Date.parse(second)
1258
+ // if (step1 === step2) {
1259
+ // modes[j] = "date-stepping"
1260
+ // steps[j] = step1
1261
+ // } else {
1262
+ // modes[j] = "cycle"
1263
+ // }
1264
+ // }
1265
+ else {
1266
+ modes[j] = "cycle";
1267
+ }
1268
+ }
1269
+ }
1270
+
1271
+ // Tạo các dòng mới (thêm n dòng)
1272
+ // 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
1273
+ // Nếu chế độ là cycle thì dùng arr[i mod m][j]
1274
+ for (let i = 0; i < n; i++) {
1275
+ const newRow = [];
1276
+ for (let j = 0; j < numCols; j++) {
1277
+ let newValue;
1278
+ switch (modes[j]) {
1279
+ case "number-constant":
1280
+ // Mảng có 1 hàng, số giữ nguyên
1281
+ newValue = arr[0][j];
1282
+ break;
1283
+ case "number-stepping":
1284
+ {
1285
+ // Lấy giá trị cuối của cột j trong mảng ban đầu
1286
+ const lastValue = arr[m - 1][j];
1287
+ newValue = lastValue + (i + 1) * steps[j];
1288
+ }
1289
+ break;
1290
+ // case "date-stepping":
1291
+ // {
1292
+ // // 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
1293
+ // const lastDate = new Date(arr[m - 1][j])
1294
+ // const newTime = lastDate.getTime() + (i + 1) * steps[j]
1295
+ // newValue = moment(new Date(newTime)).format()
1296
+ // }
1297
+ // break
1298
+ case "cycle":
1299
+ default:
1300
+ // Lặp lại nội dung theo vòng tròn: dùng hàng thứ (i mod m)
1301
+ newValue = arr[i % m][j];
1302
+ break;
1303
+ }
1304
+ newRow.push(newValue);
1305
+ }
1306
+ addedRows.push(newRow);
1307
+ }
1308
+ const combined = arr.concat(addedRows);
1309
+ return {
1310
+ combined,
1311
+ addedRows
1312
+ };
1313
+ }
1314
+ export function addRowsUpWithCtrl(array, n) {
1315
+ const arr = array.reverse();
1316
+ if (!Array.isArray(arr) || arr.length === 0) {
1317
+ return {
1318
+ combined: arr,
1319
+ addedRows: []
1320
+ };
1321
+ }
1322
+ const m = arr.length;
1323
+ const numCols = arr[0].length;
1324
+ const addedRows = [];
1325
+
1326
+ // Hàm kiểm tra kiểu date hợp lệ
1327
+ const isValidDate = item => {
1328
+ // return !isNaN(Date.parse(d))
1329
+
1330
+ if (typeof item === 'number') {
1331
+ // return 'number'
1332
+ return false;
1333
+ }
1334
+ if (typeof item === 'string') {
1335
+ // Kiểm tra nếu là chuỗi ISO date hợp lệ
1336
+ const date = new Date(item);
1337
+ if (!isNaN(date.getTime()) && item.includes('T')) {
1338
+ // return 'date'
1339
+ return true;
1340
+ }
1341
+ // return 'string'
1342
+ return false;
1343
+ }
1344
+ return !isNaN(Date.parse(item));
1345
+ };
1346
+
1347
+ // Lấy giá trị mẫu của cột j từ hàng đầu tiên
1348
+ const getSample = j => arr[0][j];
1349
+
1350
+ // Xác định chế độ xử lý cho mỗi cột:
1351
+ // mode = 'number-stepping' | 'date-stepping' | 'number-constant' | 'cycle'
1352
+ const modes = [];
1353
+ const steps = []; // bước tăng, nếu có (cho number hoặc date)
1354
+
1355
+ for (let j = 0; j < numCols; j++) {
1356
+ const sample = getSample(j);
1357
+ if (m === 1) {
1358
+ // 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.
1359
+ if (typeof sample === "number") {
1360
+ modes[j] = "number-constant";
1361
+ } else if (isValidDate(sample)) {
1362
+ modes[j] = "date-stepping";
1363
+ steps[j] = 24 * 3600 * 1000; // 1 ngày = 86400000 ms
1364
+ } else {
1365
+ modes[j] = "cycle";
1366
+ }
1367
+ } else if (m === 2) {
1368
+ // 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
1369
+ const first = arr[0][j],
1370
+ second = arr[1][j];
1371
+ if (typeof first === "number" && typeof second === "number") {
1372
+ modes[j] = "number-stepping";
1373
+ steps[j] = second - first;
1374
+ } else if (isValidDate(first) && isValidDate(second)) {
1375
+ modes[j] = "date-stepping";
1376
+ steps[j] = Date.parse(second) - Date.parse(first);
1377
+ } else {
1378
+ modes[j] = "cycle";
1379
+ }
1380
+ } else {
1381
+ // Nếu mảng có >2 hàng
1382
+ const first = arr[0][j],
1383
+ second = arr[1][j],
1384
+ third = arr[2][j];
1385
+ if (typeof first === "number" && typeof second === "number" && typeof third === "number") {
1386
+ const step1 = second - first;
1387
+ const step2 = third - second;
1388
+ if (step1 === step2) {
1389
+ modes[j] = "number-stepping";
1390
+ steps[j] = step1;
1391
+ } else {
1392
+ modes[j] = "cycle";
1393
+ }
1394
+ } else if (isValidDate(first) && isValidDate(second) && isValidDate(third)) {
1395
+ const step1 = Date.parse(second) - Date.parse(first);
1396
+ const step2 = Date.parse(third) - Date.parse(second);
1397
+ if (step1 === step2) {
1398
+ modes[j] = "date-stepping";
1399
+ steps[j] = step1;
1400
+ } else {
1401
+ modes[j] = "cycle";
1402
+ }
1403
+ } else {
1404
+ modes[j] = "cycle";
1405
+ }
1406
+ }
1407
+ }
1408
+
1409
+ // Tạo các dòng mới (thêm n dòng)
1410
+ // 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
1411
+ // Nếu chế độ là cycle thì dùng arr[i mod m][j]
1412
+ for (let i = n - 1; i >= 0; i--) {
1413
+ const newRow = [];
1414
+ for (let j = 0; j < numCols; j++) {
1415
+ let newValue;
1416
+ switch (modes[j]) {
1417
+ case "number-constant":
1418
+ // Mảng có 1 hàng, số giữ nguyên
1419
+ newValue = arr[0][j];
1420
+ break;
1421
+ case "number-stepping":
1422
+ {
1423
+ // Lấy giá trị cuối của cột j trong mảng ban đầu
1424
+
1425
+ const lastValue = arr[m - 1][j];
1426
+ newValue = lastValue - (i + 1) * steps[j] * -1;
1427
+ }
1428
+ break;
1429
+ case "date-stepping":
1430
+ {
1431
+ // 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
1432
+
1433
+ const lastDate = new Date(arr[m - 1][j]);
1434
+ const newTime = m === 1 ? lastDate.getTime() - (i + 1) * steps[j] : lastDate.getTime() - (i + 1) * steps[j] * -1;
1435
+ newValue = moment(new Date(newTime)).format();
1436
+ }
1437
+ break;
1438
+ case "cycle":
1439
+ default:
1440
+ // Lặp lại nội dung theo vòng tròn: dùng hàng thứ (i mod m)
1441
+
1442
+ newValue = arr[i % m][j];
1443
+ break;
1444
+ }
1445
+ newRow.push(newValue);
1446
+ }
1447
+ addedRows.push(newRow);
1448
+ }
1449
+ const combined = arr.concat(addedRows);
1450
+ return {
1451
+ combined,
1452
+ addedRows
1453
+ };
1454
+ }
1455
+ export function addRowsUp(array, n) {
1456
+ const arr = array.reverse();
1457
+ if (!Array.isArray(arr) || arr.length === 0) {
1458
+ return {
1459
+ combined: arr,
1460
+ addedRows: []
1461
+ };
1462
+ }
1463
+ const m = arr.length;
1464
+ const numCols = arr[0].length;
1465
+ const addedRows = [];
1466
+
1467
+ // Hàm kiểm tra kiểu date hợp lệ
1468
+ // const isValidDate = (item: any) => {
1469
+ //
1470
+ //
1471
+ // // return !isNaN(Date.parse(d))
1472
+ //
1473
+ // if (typeof item === 'number') {
1474
+ // // return 'number'
1475
+ // return false
1476
+ // }
1477
+ // if (typeof item === 'string') {
1478
+ // // Kiểm tra nếu là chuỗi ISO date hợp lệ
1479
+ // const date = new Date(item)
1480
+ // if (!isNaN(date.getTime()) && item.includes('T')) {
1481
+ // // return 'date'
1482
+ // return true
1483
+ // }
1484
+ // // return 'string'
1485
+ // return false
1486
+ // }
1487
+ //
1488
+ // return !isNaN(Date.parse(item))
1489
+ //
1490
+ // }
1491
+
1492
+ // Lấy giá trị mẫu của cột j từ hàng đầu tiên
1493
+ const getSample = j => arr[0][j];
1494
+
1495
+ // Xác định chế độ xử lý cho mỗi cột:
1496
+ // mode = 'number-stepping' | 'date-stepping' | 'number-constant' | 'cycle'
1497
+ const modes = [];
1498
+ const steps = []; // bước tăng, nếu có (cho number hoặc date)
1499
+
1500
+ for (let j = 0; j < numCols; j++) {
1501
+ const sample = getSample(j);
1502
+ if (m === 1) {
1503
+ // 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.
1504
+ if (typeof sample === "number") {
1505
+ modes[j] = "number-constant";
1506
+ } else {
1507
+ modes[j] = "cycle";
1508
+ }
1509
+ } else if (m === 2) {
1510
+ // 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
1511
+ const first = arr[0][j],
1512
+ second = arr[1][j];
1513
+ if (typeof first === "number" && typeof second === "number") {
1514
+ modes[j] = "number-stepping";
1515
+ steps[j] = second - first;
1516
+ } else {
1517
+ modes[j] = "cycle";
1518
+ }
1519
+ } else {
1520
+ // Nếu mảng có >2 hàng
1521
+ const first = arr[0][j],
1522
+ second = arr[1][j],
1523
+ third = arr[2][j];
1524
+ if (typeof first === "number" && typeof second === "number" && typeof third === "number") {
1525
+ const step1 = second - first;
1526
+ const step2 = third - second;
1527
+ if (step1 === step2) {
1528
+ modes[j] = "number-stepping";
1529
+ steps[j] = step1;
1530
+ } else {
1531
+ modes[j] = "cycle";
1532
+ }
1533
+ } else {
1534
+ modes[j] = "cycle";
1535
+ }
1536
+ }
1537
+ }
1538
+
1539
+ // Tạo các dòng mới (thêm n dòng)
1540
+ // 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
1541
+ // Nếu chế độ là cycle thì dùng arr[i mod m][j]
1542
+ for (let i = n - 1; i >= 0; i--) {
1543
+ const newRow = [];
1544
+ for (let j = 0; j < numCols; j++) {
1545
+ let newValue;
1546
+ switch (modes[j]) {
1547
+ case "number-constant":
1548
+ // Mảng có 1 hàng, số giữ nguyên
1549
+ newValue = arr[0][j];
1550
+ break;
1551
+ case "number-stepping":
1552
+ {
1553
+ // Lấy giá trị cuối của cột j trong mảng ban đầu
1554
+
1555
+ const lastValue = arr[m - 1][j];
1556
+ newValue = lastValue - (i + 1) * steps[j] * -1;
1557
+ }
1558
+ break;
1559
+ case "cycle":
1560
+ default:
1561
+ // Lặp lại nội dung theo vòng tròn: dùng hàng thứ (i mod m)
1562
+
1563
+ newValue = arr[i % m][j];
1564
+ break;
1565
+ }
1566
+ newRow.push(newValue);
1567
+ }
1568
+ addedRows.push(newRow);
1569
+ }
1570
+ const combined = arr.concat(addedRows);
1571
+ return {
1572
+ combined,
1573
+ addedRows
1574
+ };
1575
+ }
1576
+ export const convertFilters = filters => {
1577
+ const result = [];
1578
+ filters.forEach(({
1579
+ key,
1580
+ column,
1581
+ filteredKeys,
1582
+ operator
1583
+ }) => {
1584
+ if (!filteredKeys || filteredKeys.length === 0) {
1585
+ return;
1586
+ }
1587
+ if (column?.typeFilter === "DateRange" && filteredKeys.length === 2) {
1588
+ result.push({
1589
+ key,
1590
+ field: column?.field,
1591
+ value: filteredKeys[0],
1592
+ predicate: "and",
1593
+ operator: "greaterthanorequal"
1594
+ }, {
1595
+ key,
1596
+ field: column?.field,
1597
+ value: filteredKeys[1],
1598
+ predicate: "and",
1599
+ operator: "lessthanorequal"
1600
+ });
1601
+ } else if (column?.typeFilter === "NumberRange") {
1602
+ if ((filteredKeys[0] || filteredKeys[0] === 0) && !filteredKeys[1]) {
1603
+ result.push({
1604
+ key,
1605
+ field: column?.field,
1606
+ value: filteredKeys[0],
1607
+ predicate: "and",
1608
+ operator: "greaterthanorequal"
1609
+ });
1610
+ }
1611
+ if ((filteredKeys[1] || filteredKeys[1] === 0) && !filteredKeys[0]) {
1612
+ result.push({
1613
+ key,
1614
+ field: column?.field,
1615
+ value: filteredKeys[1],
1616
+ predicate: "and",
1617
+ operator: "lessthanorequal"
1618
+ });
1619
+ }
1620
+ if ((filteredKeys[0] || filteredKeys[0] === 0) && (filteredKeys[1] || filteredKeys[1] === 0)) {
1621
+ result.push({
1622
+ key,
1623
+ field: column?.field,
1624
+ value: filteredKeys[0],
1625
+ predicate: "and",
1626
+ operator: "greaterthanorequal"
1627
+ }, {
1628
+ key,
1629
+ field: column?.field,
1630
+ value: filteredKeys[1],
1631
+ predicate: "and",
1632
+ operator: "lessthanorequal"
1633
+ });
1634
+ }
1635
+ } else if (column?.typeFilter === 'Checkbox') {
1636
+ filteredKeys.forEach(value => {
1637
+ result.push({
1638
+ key,
1639
+ field: column?.field,
1640
+ value,
1641
+ predicate: "or",
1642
+ operator
1643
+ });
1644
+ });
1645
+ } else {
1646
+ result.push({
1647
+ key,
1648
+ field: column?.field,
1649
+ value: filteredKeys[0],
1650
+ predicate: 'and',
1651
+ operator
1652
+ });
1653
+ }
1654
+ });
1655
+ return result;
1656
+ };
1657
+ export function getInvisibleColumns(columns) {
1658
+ const result = {};
1659
+ for (const col of columns) {
1660
+ if (col.visible === false) {
1661
+ result[col.field ?? ''] = false;
1662
+ }
1663
+ }
1664
+ return result;
1665
+ }
1666
+ export const getAllVisibleKeys = columns => {
1667
+ const keys = [];
1668
+ const traverse = (cols, parentHidden = false) => {
1669
+ for (const col of cols) {
1670
+ if (col.hidden || parentHidden) {
1671
+ continue;
1672
+ }
1673
+ if (col.key) {
1674
+ keys.push(col.key);
1675
+ }
1676
+ if (col.children) {
1677
+ traverse(col.children, col.hidden);
1678
+ }
1679
+ }
1680
+ };
1681
+ traverse(columns);
1682
+ return keys;
1683
+ };
1684
+ export const getAllVisibleKeys1 = columns => {
1685
+ const keys = [];
1686
+ const traverse = (cols, parentHidden = false) => {
1687
+ for (const col of cols) {
1688
+ if (col.visible === false || parentHidden) {
1689
+ continue;
1690
+ }
1691
+ if (col.field) {
1692
+ keys.push(col.field);
1693
+ }
1694
+ if (col.children) {
1695
+ traverse(col.children, col.visible);
1696
+ }
1697
+ }
1698
+ };
1699
+ traverse(columns);
1700
+ return keys;
1701
+ };
1702
+ export function getHiddenParentKeys(columns, parentKeys = []) {
1703
+ const hiddenParents = new Set();
1704
+ for (const column of columns) {
1705
+ if (column.children) {
1706
+ const currentPath = column.key ? [...parentKeys, column.key] : [...parentKeys];
1707
+ const childHiddenParents = getHiddenParentKeys(column.children, currentPath);
1708
+ if (childHiddenParents.length > 0) {
1709
+ childHiddenParents.forEach(key => hiddenParents.add(key));
1710
+ currentPath.forEach(key => hiddenParents.add(key));
1711
+ }
1712
+ } else if (column.hidden) {
1713
+ parentKeys.forEach(key => hiddenParents.add(key));
1714
+ }
1715
+ }
1716
+ return Array.from(hiddenParents);
1717
+ }
1718
+ export function getHiddenParentKeys1(columns, parentKeys = []) {
1719
+ const hiddenParents = new Set();
1720
+ for (const column of columns) {
1721
+ if (column.children) {
1722
+ const currentPath = column.field ? [...parentKeys, column.field] : [...parentKeys];
1723
+ const childHiddenParents = getHiddenParentKeys(column.children, currentPath);
1724
+ if (childHiddenParents.length > 0) {
1725
+ childHiddenParents.forEach(key => hiddenParents.add(key));
1726
+ currentPath.forEach(key => hiddenParents.add(key));
1727
+ }
1728
+ } else if (column.visible !== false) {
1729
+ parentKeys.forEach(key => hiddenParents.add(key));
1730
+ }
1731
+ }
1732
+ return Array.from(hiddenParents);
1733
+ }
1734
+ export const getVisibleColumnKeys = columns => {
1735
+ const allKeys = getAllVisibleKeys(columns);
1736
+ const allParentKeys = getHiddenParentKeys(columns);
1737
+ return allKeys.filter(item => !allParentKeys.includes(item));
1738
+ };
1739
+ export const getVisibleColumnKeys1 = columns => {
1740
+ const allKeys = getAllVisibleKeys1(columns);
1741
+ const allParentKeys = getHiddenParentKeys1(columns);
1742
+ return allKeys.filter(item => !allParentKeys.includes(item));
1743
+ };
1744
+ export function isObjEqual(obj1, obj2) {
1745
+ // Trường hợp tham chiếu bằng nhau
1746
+ if (obj1 === obj2) return true;
1747
+
1748
+ // Nếu 1 trong 2 không phải object hoặc null thì so sánh trực tiếp
1749
+ if (typeof obj1 !== 'object' || obj1 === null || typeof obj2 !== 'object' || obj2 === null) {
1750
+ return obj1 === obj2;
1751
+ }
1752
+
1753
+ // Lấy danh sách key
1754
+ const keys1 = Object.keys(obj1);
1755
+ const keys2 = Object.keys(obj2);
1756
+
1757
+ // Nếu số key khác nhau thì khác nhau
1758
+ if (keys1.length !== keys2.length) return false;
1759
+
1760
+ // Duyệt và so sánh từng key
1761
+ for (const key of keys1) {
1762
+ if (!keys2.includes(key)) return false;
1763
+ if (!isObjEqual(obj1[key], obj2[key])) return false;
1764
+ }
1765
+ return true;
1766
+ }
1767
+
1768
+ // Sorting function
1769
+ export const sortByType = arr => {
1770
+ if (arr) {
1771
+ return arr.sort((a, b) => {
1772
+ if (a.fixed === 'left' && b.fixed !== 'left') {
1773
+ return -1;
1774
+ } else if (a.fixed !== 'left' && b.fixed === 'left') {
1775
+ return 1;
1776
+ } else if (a.fixed === 'right' && b.fixed !== 'right') {
1777
+ return 1;
1778
+ } else if (a.fixed !== 'right' && b.fixed === 'right') {
1779
+ return -1;
1780
+ }
1781
+ return 0;
1782
+ });
1783
+ } else {
1784
+ return [];
1785
+ }
1786
+ };
1787
+ export function convertColumnsToTreeData(columns, groupColumns) {
1788
+ // return columns.map((col) => {
1789
+ // const node: TreeDataNode = {
1790
+ // key: String(col.id ?? col.id ?? col.header), // key duy nhất
1791
+ // title: String(col.header ?? col.id ?? ''), // tiêu đề
1792
+ // }
1793
+
1794
+ // // Nếu có children (nested columns)
1795
+ // if ('columns' in col && Array.isArray((col as any).columns)) {
1796
+ // node.children = convertColumnsToTreeData(
1797
+ // (col as any).columns as ColumnDef<T, any>[]
1798
+ // )
1799
+ // }
1800
+
1801
+ // return node
1802
+ // })
1803
+
1804
+ return columns.filter(col => {
1805
+ const meta = col.meta ?? {};
1806
+ const inGroup = groupColumns ? groupColumns.includes(String(col.id ?? col.id)) : false;
1807
+
1808
+ // Điều kiện filter:
1809
+ // - Nếu meta.showInColumnChoose = false => loại bỏ
1810
+ // - Nếu không nằm trong groupColumns và không phải column group => loại bỏ
1811
+ if (meta.showInColumnChoose === false) return false;
1812
+ if (inGroup && !('columns' in col && Array.isArray(col.columns))) {
1813
+ return false;
1814
+ }
1815
+ return true;
1816
+ }).map(col => {
1817
+ const node = {
1818
+ key: String(col.id ?? col.id ?? col.header),
1819
+ // title: () => col.header as any
1820
+ title: col.header
1821
+
1822
+ // title: String(col.header ?? col.id ?? ''),
1823
+ };
1824
+ if ('columns' in col && Array.isArray(col.columns)) {
1825
+ const children = convertColumnsToTreeData(col.columns, groupColumns);
1826
+ if (children.length > 0) {
1827
+ node.children = children;
1828
+ }
1829
+ }
1830
+ return node;
1831
+ });
1832
+ }
1833
+ export const updateColumns1 = (columns, includes) => {
1834
+ return columns.map(column => {
1835
+ const newColumn = {
1836
+ ...column
1837
+ };
1838
+ let hasVisibleChild = false;
1839
+ if (!column.field) {
1840
+ return column;
1841
+ }
1842
+ if (newColumn.children) {
1843
+ newColumn.children = updateColumns1(newColumn.children, includes);
1844
+ hasVisibleChild = newColumn.children.some(child => !child.hidden);
1845
+ }
1846
+
1847
+ // newColumn.hidden = newColumn.key && !includes.includes(newColumn.key)
1848
+ newColumn.visible = !!(newColumn.field && includes.includes(newColumn.field));
1849
+ // newColumn.fixed = newColumn.field && !includes.includes(newColumn.field) ? undefined : newColumn.fixed
1850
+
1851
+ if (newColumn.children && newColumn.children.length > 0) {
1852
+ newColumn.visible = !hasVisibleChild;
1853
+ // newColumn.fixed = !hasVisibleChild ? undefined : newColumn.fixed
1854
+ }
1855
+ return newColumn;
1856
+ });
1857
+ };
1858
+ export const convertToObj = arr => {
1859
+ // const result = Object.keys(obj).reduce((acc: any, key) => {
1860
+ // acc[key] = false;
1861
+ // return acc;
1862
+ // }, {});
1863
+
1864
+ // return result
1865
+
1866
+ return Object.fromEntries(arr.map(key => [key, false]));
1867
+ };
1868
+ export const getDiffent2Array = (a, b) => {
1869
+ return [...a.filter(x => !b.includes(x)), ...b.filter(x => !a.includes(x))];
1870
+ };