es-grid-template 1.9.63 → 1.9.64

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 (46) hide show
  1. package/es/ali-table/Grid.js +5 -2
  2. package/es/ali-table/InternalTable.js +499 -49
  3. package/es/ali-table/base-table/calculations.js +1 -1
  4. package/es/ali-table/base-table/cell/EditCell.js +14 -6
  5. package/es/ali-table/base-table/renderFilter.js +1 -1
  6. package/es/ali-table/interfaces.d.ts +2 -2
  7. package/es/ali-table/pipeline/features/columnCustom.d.ts +4 -2
  8. package/es/ali-table/pipeline/features/columnCustom.js +112 -48
  9. package/es/ali-table/utils/constants.d.ts +1 -0
  10. package/es/ali-table/utils/constants.js +1 -0
  11. package/es/ali-table/utils/convertColumnsChoose.d.ts +2 -2
  12. package/es/ali-table/utils/convertColumnsChoose.js +1 -2
  13. package/es/ali-table/utils/utility.d.ts +15 -1
  14. package/es/ali-table/utils/utility.js +399 -1
  15. package/es/grid-component/type.d.ts +2 -2
  16. package/es/group-component/hook/utils.d.ts +3 -3
  17. package/es/table-component/TableContainerEdit.js +148 -98
  18. package/es/table-component/body/EditableCell.js +9 -5
  19. package/es/table-component/body/TableBodyCellEdit.js +14 -8
  20. package/es/table-component/header/renderFilter.js +1 -1
  21. package/es/table-component/hook/utils.d.ts +1 -1
  22. package/es/table-component/hook/utils.js +2 -6
  23. package/es/table-component/useContext.d.ts +1 -1
  24. package/lib/ali-table/Grid.js +5 -2
  25. package/lib/ali-table/InternalTable.js +490 -45
  26. package/lib/ali-table/base-table/calculations.js +1 -1
  27. package/lib/ali-table/base-table/cell/EditCell.js +14 -6
  28. package/lib/ali-table/base-table/renderFilter.js +1 -1
  29. package/lib/ali-table/interfaces.d.ts +2 -2
  30. package/lib/ali-table/pipeline/features/columnCustom.d.ts +4 -2
  31. package/lib/ali-table/pipeline/features/columnCustom.js +106 -46
  32. package/lib/ali-table/utils/constants.d.ts +1 -0
  33. package/lib/ali-table/utils/constants.js +2 -1
  34. package/lib/ali-table/utils/convertColumnsChoose.d.ts +2 -2
  35. package/lib/ali-table/utils/convertColumnsChoose.js +1 -2
  36. package/lib/ali-table/utils/utility.d.ts +15 -1
  37. package/lib/ali-table/utils/utility.js +410 -2
  38. package/lib/grid-component/type.d.ts +2 -2
  39. package/lib/table-component/TableContainerEdit.js +148 -98
  40. package/lib/table-component/body/EditableCell.js +9 -5
  41. package/lib/table-component/body/TableBodyCellEdit.js +11 -7
  42. package/lib/table-component/header/renderFilter.js +1 -1
  43. package/lib/table-component/hook/utils.d.ts +1 -1
  44. package/lib/table-component/hook/utils.js +2 -6
  45. package/lib/table-component/useContext.d.ts +1 -1
  46. package/package.json +1 -1
@@ -4,13 +4,19 @@ import * as fusion from '@alifd/next';
4
4
  import { useLocale } from "rc-master-ui/es/locale";
5
5
  import { faker } from "@faker-js/faker";
6
6
  import React, { Fragment, useRef } from "react";
7
+ import { useCopyToClipboard } from 'usehooks-ts';
7
8
  import "./base-table/styles.scss";
8
- import { addRowIdArray, findItemByKey, flatColumns2, flattenArray, flattenData,
9
+ import { addRowIdArray, checkDecimalSeparator, checkThousandSeparator, detectSeparators, findItemByKey, flatColumns2, flattenArray, flattenData, getColIdsBetween1,
9
10
  // getAllRowKey,
10
- getDefaultValue, getRowIdsBetween3, getRowIndexMap,
11
+ getDefaultValue, getRowIdsBetween3, getRowIndexMap, getSelectedCellMatrix1, getVisibleFields,
11
12
  // getInvisibleColumns,
12
- getVisibleFields, groupArrayByColumns, isTreeArray, newGuid, revertConvertFilters, sortByType, sumFields, unFlattenData, updateArrayByKey, updateOrInsert } from "../table-component/hook/utils";
13
- import { CustomProvider, ConfigProvider, Modal, Button, Dropdown } from 'rc-master-ui';
13
+ // getVisibleFields,
14
+ groupArrayByColumns, isDateValue, isEditable, isEmpty, isFormattedNumber, isTreeArray, newGuid, parseExcelClipboard, revertConvertFilters,
15
+ // sortByType,
16
+ sumFields, unFlattenData, updateArrayByKey
17
+ // updateOrInsert
18
+ } from "../table-component/hook/utils";
19
+ import { CustomProvider, ConfigProvider, Modal, Button, Dropdown, Typography } from 'rc-master-ui';
14
20
  import { getLocale, getLocales } from "../locale/useLocale";
15
21
  import { TableContext } from "./useContext";
16
22
  import Grid from "./Grid";
@@ -20,13 +26,20 @@ import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
20
26
  import { arrayMove } from "@dnd-kit/sortable";
21
27
  import { useForm } from "react-hook-form";
22
28
  import { yupResolver } from "@hookform/resolvers/yup";
23
- import { filterDataByColumns1 } from "./utils/utility";
29
+ import { filterDataByColumns1, sortByType, updateOrInsert } from "./utils/utility";
24
30
  import { stateKeyEndCell, stateKeyFocusedCell, stateKeyIsEditing, stateKeyStartCell } from "./utils/constants";
25
31
  import classNames from "classnames";
26
- import { getToolbarTemplate } from "../grid-component/hooks";
32
+ import { getEditType, getFormat, getToolbarTemplate } from "../grid-component/hooks";
27
33
  import withReactContent from "sweetalert2-react-content";
28
34
  import Swal from "sweetalert2";
35
+ import { collectNodes } from "./utils";
36
+ import { removeNumericFormat } from "react-numeric-component";
37
+ import moment from "moment";
29
38
  const MySwal = withReactContent(Swal);
39
+ const {
40
+ Paragraph,
41
+ Title
42
+ } = Typography;
30
43
  const InternalTable = props => {
31
44
  const {
32
45
  t,
@@ -69,6 +82,8 @@ const InternalTable = props => {
69
82
  defaultValue,
70
83
  commandSettings,
71
84
  headerData,
85
+ format,
86
+ onCellClick,
72
87
  ...rest
73
88
  } = props;
74
89
  const tableRef = useRef(null);
@@ -77,6 +92,7 @@ const InternalTable = props => {
77
92
  const childrenColumnName = 'children';
78
93
  const childrenKey = 'children';
79
94
  const [tableLocal] = useLocale('Table');
95
+ const [copiedText, copy] = useCopyToClipboard();
80
96
  const tableId = React.useMemo(() => {
81
97
  return faker.string.alpha(20);
82
98
  }, []);
@@ -86,6 +102,9 @@ const InternalTable = props => {
86
102
  const languages = React.useMemo(() => {
87
103
  return getLocales(lang);
88
104
  }, [lang]);
105
+
106
+ // const isCut = React.useRef<any>(false);
107
+
89
108
  const getWindowSize = () => {
90
109
  const {
91
110
  innerWidth,
@@ -119,18 +138,19 @@ const InternalTable = props => {
119
138
  return addRowIdArray(dataSource);
120
139
  }, [dataSource, groupAble, groupColumns, groupSetting]);
121
140
  const isDataTree = React.useMemo(() => {
122
- return isTreeArray(convertData);
123
- }, [convertData]);
141
+ return isTreeArray(dataSource);
142
+ }, [dataSource]);
124
143
  const mergedData = React.useMemo(() => {
125
144
  const shouldSkip = onFilter && onSorter;
126
145
  if (shouldSkip) {
127
146
  return convertData;
128
147
  }
129
-
130
- // const rs = filterDataByColumns(convertData, onFilter ? undefined : (filterState ?? defaultFilter), onSorter ? undefined : (sortState ?? defaultSorter), [], ignoreAccents)
131
148
  const rss = filterDataByColumns1(convertData, onFilter ? undefined : filterState ?? defaultFilter, onSorter ? undefined : sortState ?? defaultSorter, [], ignoreAccents);
132
149
  return rss;
133
150
  }, [convertData, filterState, ignoreAccents, sortState, onFilter, onSorter, defaultFilter, defaultSorter]);
151
+ const rowIndexMap = React.useMemo(() => {
152
+ return getRowIndexMap(convertData);
153
+ }, [convertData]);
134
154
  const footerData = React.useMemo(() => {
135
155
  if (!summary) {
136
156
  return undefined;
@@ -155,15 +175,15 @@ const InternalTable = props => {
155
175
  }
156
176
  return undefined;
157
177
  }, [defaultFilter]);
158
-
159
- // const columnInVisibility = React.useMemo(() => {
160
- // return getInvisibleColumns(columns)
161
- // }, [columns])
162
-
163
- const dataIds = React.useMemo(() => mergedData.map(it => it.rowId), [mergedData]);
164
178
  const columnVisibility = React.useMemo(() => {
165
179
  return getVisibleFields(columns);
166
180
  }, [columns]);
181
+ const dataIds = React.useMemo(() => convertData.map(it => it.rowId), [convertData]);
182
+
183
+ // const columnVisibility = React.useMemo(() => {
184
+ // return getVisibleFields(columns)
185
+ // }, [columns])
186
+
167
187
  const {
168
188
  control,
169
189
  handleSubmit,
@@ -194,7 +214,7 @@ const InternalTable = props => {
194
214
  }, [onDataChange]);
195
215
  const triggerPaste = React.useCallback((pastedRows, pastedColumnsArray, newData, copyRows) => {
196
216
  const handlePasteCallback = callbackData => {
197
- const rsFilterData = updateOrInsert(flattenArray([...convertData]), flattenArray([...callbackData]));
217
+ const rsFilterData = updateOrInsert(convertData, flattenArray(callbackData));
198
218
  const rs = unFlattenData(rsFilterData);
199
219
  triggerChangeData(rs, {
200
220
  type: 'OnPaste'
@@ -231,13 +251,10 @@ const InternalTable = props => {
231
251
  }, [onCellPaste, convertData, triggerChangeData]);
232
252
  const onSubmit = formData => {
233
253
  try {
234
- // const record = (await form.validateFields()) as RecordType;
235
254
  const row = {
236
255
  ...formData
237
256
  };
238
-
239
- // const newData = [...dataSource]
240
- const newData = [...convertData];
257
+ const newData = convertData;
241
258
  const index = flattenData(childrenColumnName, newData).findIndex(item => formData[rowKey] === item[rowKey]);
242
259
  const rs = updateArrayByKey(newData, row, rowKey);
243
260
  if (index > -1) {
@@ -280,8 +297,7 @@ const InternalTable = props => {
280
297
  indexRow,
281
298
  rowData: record,
282
299
  rowId: key,
283
- // rowsData: [...dataSource],
284
- rowsData: [...convertData],
300
+ rowsData: convertData,
285
301
  sumValue: []
286
302
  }, handleChangeCallback);
287
303
  } else {
@@ -294,8 +310,7 @@ const InternalTable = props => {
294
310
  indexRow,
295
311
  rowData: record,
296
312
  rowId: key,
297
- // rowsData: [...dataSource],
298
- rowsData: [...convertData],
313
+ rowsData: dataSource,
299
314
  sumValue: []
300
315
  }, handleChangeCallback);
301
316
  onSubmit(record);
@@ -401,6 +416,7 @@ const InternalTable = props => {
401
416
  columns,
402
417
  mode: sortMultiple !== false ? 'multiple' : 'single',
403
418
  dataSource: convertData,
419
+ rowIndexMap,
404
420
  columnResizeMode: 'onChange',
405
421
  disableUserSelectWhenResizing: true,
406
422
  allowFiltering,
@@ -446,7 +462,9 @@ const InternalTable = props => {
446
462
  headerEditAble,
447
463
  handleCellChange,
448
464
  handleHeaderCellChange,
449
- headerData
465
+ headerData,
466
+ triggerChangeData,
467
+ onCellClick
450
468
  })).use(features.paginationFeature({
451
469
  pagination
452
470
  }));
@@ -457,14 +475,42 @@ const InternalTable = props => {
457
475
 
458
476
  // reorder rows after drag & drop
459
477
 
478
+ const isEditing = React.useMemo(() => {
479
+ return pipeline.getStateAtKey(stateKeyIsEditing);
480
+ }, [pipeline]);
481
+ const startCell = React.useMemo(() => {
482
+ return pipeline.getStateAtKey(stateKeyStartCell);
483
+ }, [pipeline]);
484
+ const endCell = React.useMemo(() => {
485
+ return pipeline.getStateAtKey(stateKeyEndCell);
486
+ }, [pipeline]);
487
+ const leafColumns = React.useMemo(() => {
488
+ return collectNodes(pipeline.getColumns(), 'leaf-only');
489
+ }, [pipeline]);
490
+ const rangeState = React.useMemo(() => {
491
+ return startCell && endCell ? getSelectedCellMatrix1(convertData, leafColumns, startCell, endCell) : undefined;
492
+ }, [convertData, endCell, leafColumns, startCell]);
493
+
494
+ // const rowIds = React.useMemo(() => {
495
+
496
+ // return getKeys(convertData, 'rowId')
497
+
498
+ // }, [convertData])
499
+
500
+ // const colIds = React.useMemo(() => {
501
+
502
+ // const leafColumns = collectNodes(pipeline.getColumns(), 'leaf-only')
503
+
504
+ // return getKeys(leafColumns, 'field')
505
+
506
+ // }, [pipeline])
507
+
460
508
  React.useEffect(() => {
461
509
  const handleClickOutside = event => {
462
510
  if (!editAble) {
463
511
  return;
464
512
  }
465
513
  const isEditting = pipeline.getStateAtKey(stateKeyIsEditing);
466
- const startCell = pipeline.getStateAtKey(stateKeyStartCell);
467
- const endCell = pipeline.getStateAtKey(stateKeyEndCell);
468
514
  const focusedCell = pipeline.getStateAtKey(stateKeyFocusedCell);
469
515
  const element = event.target;
470
516
  const container = document.querySelector(".be-popup-container");
@@ -529,15 +575,11 @@ const InternalTable = props => {
529
575
  return () => {
530
576
  document.removeEventListener('mousedown', handleClickOutside);
531
577
  };
532
- }, [tableId, pipeline, editAble, headerEditAble]);
578
+ }, [tableId, pipeline, editAble, headerEditAble, endCell, startCell]);
533
579
  const rowsFocus = React.useMemo(() => {
534
- const startCell = pipeline.getStateAtKey(stateKeyStartCell);
535
- const endCell = pipeline.getStateAtKey(stateKeyEndCell);
536
- const allRows = pipeline.getDataSource(); // flat data
537
- const rowIndexMap = getRowIndexMap(allRows);
538
580
  const selectRowIds = startCell && endCell ? getRowIdsBetween3(convertData, rowIndexMap, startCell.rowId, endCell.rowId) : [];
539
581
  return selectRowIds;
540
- }, [convertData, pipeline]);
582
+ }, [convertData, endCell, rowIndexMap, startCell]);
541
583
  function handleDragEnd(event) {
542
584
  const {
543
585
  active,
@@ -548,7 +590,7 @@ const InternalTable = props => {
548
590
 
549
591
  const oldIndex = dataIds.indexOf(active.id);
550
592
  const newIndex = dataIds.indexOf(over.id);
551
- const rs = arrayMove(mergedData, oldIndex, newIndex); // this is just a splice util
593
+ const rs = arrayMove(dataSource, oldIndex, newIndex); // this is just a splice util
552
594
 
553
595
  if (rowDnd?.onChange) {
554
596
  rowDnd?.onChange({
@@ -564,7 +606,7 @@ const InternalTable = props => {
564
606
  toolbar: item
565
607
  });
566
608
  } else {
567
- const filterData = flattenArray([...convertData]);
609
+ const filterData = flattenArray(convertData);
568
610
  const rs = filterData.filter(it => !rowsFocus.includes(it[rowKey]));
569
611
  const newDaa = unFlattenData(rs);
570
612
  if (commandSettings && commandSettings.confirmDialog) {
@@ -583,7 +625,7 @@ const InternalTable = props => {
583
625
  buttonsStyling: false
584
626
  }).then(async result => {
585
627
  if (result.value) {
586
- triggerChangeData?.([...newDaa], {
628
+ triggerChangeData?.(newDaa, {
587
629
  type: 'DELETE_ROWS',
588
630
  row: rowsFocus.length
589
631
  });
@@ -591,7 +633,7 @@ const InternalTable = props => {
591
633
  });
592
634
  } else {
593
635
  // không hiện dialog
594
- triggerChangeData?.([...newDaa], {
636
+ triggerChangeData?.(newDaa, {
595
637
  type: 'DELETE_ROWS',
596
638
  row: rowsFocus.length
597
639
  });
@@ -664,7 +706,7 @@ const InternalTable = props => {
664
706
  // không tính tree
665
707
 
666
708
  // Cập nhật data mới
667
- const newData = flattenArray([...convertData]);
709
+ const newData = flattenArray(convertData);
668
710
  const focusedCell = pipeline.getStateAtKey(stateKeyFocusedCell);
669
711
  const duplicatedItem = newData.find(it => it.rowId === focusedCell?.rowId);
670
712
  const duplicatedItems = [{
@@ -701,7 +743,7 @@ const InternalTable = props => {
701
743
  if (!record?.parentId) {
702
744
  // Cập nhật data mới
703
745
 
704
- const newData = [...convertData];
746
+ const newData = convertData;
705
747
  const newRows = Array.from({
706
748
  length: n
707
749
  }).map(() => defaultRowValue ? {
@@ -726,7 +768,7 @@ const InternalTable = props => {
726
768
  row: n
727
769
  });
728
770
  } else {
729
- const newData = [...convertData];
771
+ const newData = convertData;
730
772
  const parent = findItemByKey(newData, rowKey, record.parentId);
731
773
  const newRows = Array.from({
732
774
  length: n
@@ -742,7 +784,7 @@ const InternalTable = props => {
742
784
  });
743
785
 
744
786
  // Cập nhật childData mới
745
- const childData = parent?.children ? [...parent.children] : [];
787
+ const childData = parent?.children ? parent.children : [];
746
788
  const index = childData.findIndex(obj => obj[rowKey] === record[rowKey]);
747
789
  childData.splice(index, 0, ...newRows);
748
790
  const newRowData = {
@@ -765,7 +807,7 @@ const InternalTable = props => {
765
807
 
766
808
  // const insertAfter = Math.max(...rowsFocus)
767
809
 
768
- // const record: RecordType = flattenData(childrenColumnName, dataSource)[insertAfter]
810
+ // const record: RecordType = flattenData(childrenColumnName, convertData)[insertAfter]
769
811
 
770
812
  // const record: any = table.getRowModel().rows.find((it) => it.id === focusedCell?.rowId)?.original
771
813
  const record = convertData.find(it => it.rowId === focusedCell?.rowId);
@@ -776,7 +818,7 @@ const InternalTable = props => {
776
818
  } else {
777
819
  if (!record?.parentId) {
778
820
  // Cập nhật data mới
779
- const newData = [...convertData];
821
+ const newData = convertData;
780
822
  const newRows = Array.from({
781
823
  length: n
782
824
  }).map(() => defaultRowValue ? {
@@ -801,7 +843,7 @@ const InternalTable = props => {
801
843
  row: n
802
844
  });
803
845
  } else {
804
- const newData = [...convertData];
846
+ const newData = convertData;
805
847
  const parent = findItemByKey(newData, rowKey, record.parentId);
806
848
  const newRows = Array.from({
807
849
  length: n
@@ -823,7 +865,7 @@ const InternalTable = props => {
823
865
  // setMergedFilterKeys?.(rs)
824
866
 
825
867
  // Cập nhật childData mới
826
- const childData = parent?.children ? [...parent.children] : [];
868
+ const childData = parent?.children ? parent.children : [];
827
869
  const index = childData.findIndex(obj => obj[rowKey] === record[rowKey]);
828
870
  childData.splice(index + 1, 0, ...newRows);
829
871
  const newRowData = {
@@ -848,8 +890,7 @@ const InternalTable = props => {
848
890
  toolbar: item
849
891
  });
850
892
  } else {
851
- // const newData = [...dataSource]
852
- const newData = [...convertData];
893
+ const newData = convertData;
853
894
  let newElement;
854
895
  if (!record?.children || record?.children && record.children.length === 0) {
855
896
  newElement = {
@@ -901,6 +942,415 @@ const InternalTable = props => {
901
942
  // setInnerExpandedKeys(newExpandedKeys)
902
943
  // }
903
944
  }, [convertData, defaultValue, pipeline, triggerChangeData]);
945
+
946
+ // Copy
947
+
948
+ const copySelectionToClipboard = React.useCallback(() => {
949
+ if (!startCell || !endCell) {
950
+ return;
951
+ }
952
+ const allRows = dataSource;
953
+ const rowIds = getRowIdsBetween3(convertData, rowIndexMap, startCell?.rowId ?? '', endCell?.rowId ?? '');
954
+ const colIds = getColIdsBetween1(leafColumns, startCell?.colId ?? '', endCell?.colId ?? '');
955
+ const dataToCopy = [];
956
+ rowIds.forEach(rowId => {
957
+ const row = allRows.find(r => r.rowId === rowId);
958
+ if (!row) return;
959
+ const rowData = [];
960
+ colIds.forEach(colId => {
961
+ const value = row[colId];
962
+ rowData.push(value !== undefined ? String(value) : '');
963
+ });
964
+ dataToCopy.push(rowData);
965
+ });
966
+
967
+ // Convert to TSV string
968
+ const tsv = dataToCopy.map(row => row.join('\t')).join('\n');
969
+ copy(tsv).then(() => {}).catch(() => {});
970
+ }, [startCell, endCell, dataSource, convertData, rowIndexMap, leafColumns, copy]);
971
+ React.useEffect(() => {
972
+ const handleKeyDown = e => {
973
+ if (e.ctrlKey && e.key === 'c' && startCell && endCell && !isEditing) {
974
+ e.preventDefault();
975
+ copySelectionToClipboard();
976
+ }
977
+ if (e.ctrlKey && e.key === 'x' && startCell && endCell && !isEditing) {
978
+ e.preventDefault();
979
+ if (startCell && endCell) {
980
+ const tmpData = flattenArray(convertData);
981
+ const rs = tmpData.map((row, index) => {
982
+ if (!rangeState?.rowRange.includes(row.rowId)) {
983
+ return row;
984
+ }
985
+ const updatedRow = {
986
+ ...row
987
+ };
988
+ for (const field of rangeState.colRange) {
989
+ const col = leafColumns.find(it => it.field === field);
990
+ const columnIndex = leafColumns.findIndex(it => it.field === field);
991
+ if (isEditable(col, row)) {
992
+ let newValue = '';
993
+ if (col.type === 'number') {
994
+ newValue = 0;
995
+ }
996
+ if (col.type === 'boolean' || col.type === 'checkbox') {
997
+ newValue = false;
998
+ }
999
+ const cellEditType = getEditType(col, row);
1000
+ if (col.type === 'date' || col.type === 'datetime' || col.type === 'time' || col.type === 'month' || col.type === 'week' || col.type === 'year' || col.type === 'quarter' || cellEditType === 'asyncSelect' || cellEditType === 'select' || cellEditType === 'treeSelect' || cellEditType === 'selectTable') {
1001
+ newValue = undefined;
1002
+ }
1003
+ updatedRow[col.field] = newValue;
1004
+ handleCellChange({
1005
+ key: row[rowKey],
1006
+ field: col.field,
1007
+ record: updatedRow,
1008
+ prevState: row[col.field],
1009
+ newState: newValue,
1010
+ option: '',
1011
+ indexCol: columnIndex,
1012
+ indexRow: index,
1013
+ type: e.key
1014
+ });
1015
+ }
1016
+ }
1017
+ return updatedRow;
1018
+ });
1019
+ const newData = unFlattenData(rs);
1020
+ triggerChangeData?.(newData, {
1021
+ type: 'DELETE_CONTENT'
1022
+ });
1023
+ }
1024
+ copySelectionToClipboard();
1025
+ }
1026
+ };
1027
+ document.addEventListener('keydown', handleKeyDown);
1028
+ return () => document.removeEventListener('keydown', handleKeyDown);
1029
+ }, [startCell, endCell, copySelectionToClipboard, isEditing, convertData, triggerChangeData, leafColumns, handleCellChange, rangeState?.rowRange, rangeState?.colRange]);
1030
+
1031
+ // Copy
1032
+
1033
+ // paste
1034
+
1035
+ const handlePasted = React.useCallback(pasteData => {
1036
+ if (!startCell) {
1037
+ return;
1038
+ }
1039
+ const rows = pasteData.slice(0, onCellPaste?.maxRowsPaste ?? 200);
1040
+ const allRows = convertData;
1041
+ const allCols = collectNodes(pipeline.getColumns(), 'leaf-only');
1042
+ const startRowIdx = rowIndexMap.get(startCell.rowId);
1043
+ const startColIdx = allCols.findIndex(c => c.field === startCell.colId);
1044
+
1045
+ // const record: any = allRows[startRowIdx].original
1046
+
1047
+ // const record: any = table.getRow(startCell.rowId).original
1048
+ const recordIndex = rowIndexMap.get(startCell.rowId);
1049
+ const row = recordIndex ? allRows[recordIndex] : {};
1050
+ if (!row.parentId) {
1051
+ // Cập nhật data mới
1052
+ const newData = flattenArray(convertData);
1053
+
1054
+ // Lấy vị trí bắt đầu
1055
+
1056
+ // const startRow = newData.findIndex((it) => it[rowKey as any] === record[rowKey])
1057
+ const startRow = startRowIdx;
1058
+ const startCol = startColIdx;
1059
+ const pastedRows = [];
1060
+ const pastedColumns = new Set();
1061
+ rows.forEach((rowValues, rowIndex) => {
1062
+ const targetRow = startRow + rowIndex;
1063
+
1064
+ // Nếu vượt quá số dòng hiện có, thêm dòng mới
1065
+ if (targetRow >= newData.length) {
1066
+ const newID = newGuid();
1067
+ const defaultRowValue = getDefaultValue(defaultValue);
1068
+ newData.push(defaultValue ? {
1069
+ ...defaultRowValue,
1070
+ id: undefined,
1071
+ rowId: newID
1072
+ } : {
1073
+ id: undefined,
1074
+ rowId: newID
1075
+ });
1076
+ }
1077
+ rowValues.forEach((cellValue, colIndex) => {
1078
+ const targetCol = startCol + colIndex;
1079
+ if (targetCol >= allCols.length) {
1080
+ // Không vượt quá số cột
1081
+ return;
1082
+ }
1083
+ const columnOri = allCols[targetCol];
1084
+ const isEdit = typeof columnOri?.editEnable === 'function' ? columnOri.editEnable(newData[targetRow]) : columnOri.editEnable;
1085
+ if (isEdit) {
1086
+ const columnKey = allCols[targetCol].field;
1087
+ if (columnOri.type === 'number') {
1088
+ if (cellValue.trim() === '') {
1089
+ newData[targetRow] = {
1090
+ ...newData[targetRow],
1091
+ [columnKey]: null
1092
+ };
1093
+ }
1094
+ if (isFormattedNumber(cellValue.trim()) || !isNaN(Number(cellValue.trim()))) {
1095
+ const colFormat = typeof columnOri.format === 'function' ? columnOri.format(row) : columnOri.format;
1096
+ const valuePasteFormat = detectSeparators(cellValue.trim());
1097
+ const cellFormat = getFormat(colFormat, format);
1098
+ const thousandSeparator = valuePasteFormat?.thousandSeparator;
1099
+ const decimalSeparator = valuePasteFormat?.decimalSeparator;
1100
+ const dec = cellFormat?.decimalScale;
1101
+ const numericFormatProps = {
1102
+ thousandSeparator: checkThousandSeparator(thousandSeparator, decimalSeparator),
1103
+ decimalSeparator: checkDecimalSeparator(thousandSeparator, decimalSeparator),
1104
+ allowNegative: cellFormat?.allowNegative ?? true,
1105
+ prefix: cellFormat?.prefix,
1106
+ suffix: cellFormat?.suffix,
1107
+ decimalScale: dec,
1108
+ fixedDecimalScale: cellFormat?.fixedDecimalScale ?? false
1109
+ };
1110
+ const val = removeNumericFormat(cellValue.trim(), undefined, numericFormatProps);
1111
+ newData[targetRow] = {
1112
+ ...newData[targetRow],
1113
+ [columnKey]: Number(val)
1114
+ };
1115
+ }
1116
+ } else if (columnOri.type === 'data' || columnOri.type === 'datatime' || columnOri.editType === 'date' || columnOri.editType === 'datetime') {
1117
+ const isDate = isDateValue(cellValue.trim());
1118
+ const date = isDate && !isEmpty(cellValue.trim()) ? moment(cellValue.trim()).format() : null;
1119
+ newData[targetRow] = {
1120
+ ...newData[targetRow],
1121
+ [columnKey]: date
1122
+ };
1123
+ } else {
1124
+ newData[targetRow] = {
1125
+ ...newData[targetRow],
1126
+ [columnKey]: cellValue.trim()
1127
+ };
1128
+ }
1129
+ pastedColumns.add(columnKey);
1130
+ }
1131
+ });
1132
+
1133
+ // Lưu dòng được paste
1134
+ pastedRows.push(newData[targetRow]);
1135
+ });
1136
+ const pastedColumnsArray = Array.from(pastedColumns) ?? [];
1137
+ const rsFilterData = updateOrInsert(convertData, newData);
1138
+ const rs = unFlattenData(rsFilterData);
1139
+ triggerPaste?.(pastedRows, pastedColumnsArray, rs, []);
1140
+ } else {
1141
+ // const parent = findItemByKey(convertData, rowKey as any, record.parentId)
1142
+ const parent = row.getParentRow()?.original;
1143
+
1144
+ // Cập nhật childData mới
1145
+ const childData = parent?.children ? [...parent.children] : [];
1146
+
1147
+ // Lấy vị trí bắt đầu
1148
+ // const { row: startRow, col: startCol } = selectedCell;
1149
+ const startRow = childData.findIndex(it => it[rowKey] === row[rowKey]);
1150
+ const startCol = startColIdx;
1151
+ const pastedRows = [];
1152
+ const pastedColumns = new Set();
1153
+ rows.forEach((rowValues, rowIndex) => {
1154
+ const targetRow = startRow + rowIndex;
1155
+
1156
+ // Nếu vượt quá số dòng hiện có, thêm dòng mới
1157
+ if (targetRow >= childData.length) {
1158
+ childData.push({
1159
+ id: undefined,
1160
+ rowId: newGuid(),
1161
+ parentId: parent[rowKey ?? 'id']
1162
+ });
1163
+ }
1164
+ rowValues.forEach((cellValue, colIndex) => {
1165
+ const targetCol = startCol + colIndex;
1166
+ if (targetCol >= allCols.length) {
1167
+ // Không vượt quá số cột
1168
+ return;
1169
+ }
1170
+ const columnTarget = allCols[targetCol];
1171
+ const columnOri = columnTarget.columnDef.meta ?? {};
1172
+ const isEdit = typeof columnOri?.editEnable === 'function' ? columnOri.editEnable(childData[targetRow]) : columnOri.editEnable;
1173
+ if (isEdit) {
1174
+ const columnKey = allCols[targetCol].id;
1175
+ if (columnOri.type === 'number') {
1176
+ if (cellValue.trim() === '') {
1177
+ childData[targetRow] = {
1178
+ ...childData[targetRow],
1179
+ [columnKey]: null
1180
+ };
1181
+ }
1182
+ if (isFormattedNumber(cellValue.trim()) || !isNaN(Number(cellValue.trim()))) {
1183
+ const colFormat = typeof columnOri.format === 'function' ? columnOri.format(row) : columnOri.format;
1184
+ const valuePasteFormat = detectSeparators(cellValue.trim());
1185
+ const cellFormat = getFormat(colFormat, format);
1186
+ const thousandSeparator = valuePasteFormat?.thousandSeparator;
1187
+ const decimalSeparator = valuePasteFormat?.decimalSeparator;
1188
+ const dec = cellFormat?.decimalScale;
1189
+ const numericFormatProps = {
1190
+ thousandSeparator: checkThousandSeparator(thousandSeparator, decimalSeparator),
1191
+ decimalSeparator: checkDecimalSeparator(thousandSeparator, decimalSeparator),
1192
+ allowNegative: cellFormat?.allowNegative ?? true,
1193
+ prefix: cellFormat?.prefix,
1194
+ suffix: cellFormat?.suffix,
1195
+ decimalScale: dec,
1196
+ fixedDecimalScale: cellFormat?.fixedDecimalScale ?? false
1197
+ };
1198
+ const val = removeNumericFormat(cellValue.trim(), undefined, numericFormatProps);
1199
+ childData[targetRow] = {
1200
+ ...childData[targetRow],
1201
+ [columnKey]: Number(val)
1202
+ };
1203
+ }
1204
+ } else if (columnOri.type === 'data' || columnOri.type === 'datatime' || columnOri.editType === 'date' || columnOri.editType === 'datetime') {
1205
+ const isDate = isDateValue(cellValue.trim());
1206
+ const date = isDate && !isEmpty(cellValue.trim()) ? moment(cellValue.trim()).format() : null;
1207
+ childData[targetRow] = {
1208
+ ...childData[targetRow],
1209
+ [columnKey]: date
1210
+ };
1211
+ } else {
1212
+ childData[targetRow] = {
1213
+ ...childData[targetRow],
1214
+ [columnKey]: cellValue.trim()
1215
+ };
1216
+ }
1217
+ pastedColumns.add(columnKey);
1218
+ }
1219
+ });
1220
+
1221
+ // Lưu dòng được paste
1222
+ pastedRows.push(childData[targetRow]);
1223
+ });
1224
+ const pastedColumnsArray = Array.from(pastedColumns) ?? [];
1225
+ const newRowData = {
1226
+ ...parent,
1227
+ children: childData
1228
+ }; // item đã được filter
1229
+
1230
+ const newDataSource = updateArrayByKey(convertData, newRowData, rowKey);
1231
+ triggerPaste?.(pastedRows, pastedColumnsArray, newDataSource, []);
1232
+ }
1233
+ }, [convertData, defaultValue, format, onCellPaste?.maxRowsPaste, pipeline, rowIndexMap, startCell, triggerPaste]);
1234
+ const handlePasteToTable = React.useCallback((pasteData, e) => {
1235
+ if (!startCell) return;
1236
+ const rowsPasted = parseExcelClipboard(e);
1237
+ if (rowsPasted.length > (onCellPaste?.maxRowsPaste ?? 200)) {
1238
+ // bật popup thông báo
1239
+
1240
+ Modal.confirm({
1241
+ content: /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Paragraph, {
1242
+ style: {
1243
+ marginBottom: '.25rem',
1244
+ fontSize: 14
1245
+ }
1246
+ }, "D\u1EEF li\u1EC7u sao ch\xE9p v\u01B0\u1EE3t qu\xE1 s\u1ED1 d\xF2ng cho ph\xE9p (", onCellPaste?.maxRowsPaste ?? 200, " d\xF2ng).Ph\u1EA7n m\u1EC1n s\u1EBD ch\u1EC9 l\u1EA5y (", onCellPaste?.maxRowsPaste ?? 200, " d\xF2ng \u0111\u1EA7u ti\xEAn."), /*#__PURE__*/React.createElement(Title, {
1247
+ level: 5,
1248
+ style: {
1249
+ marginTop: '.75rem'
1250
+ }
1251
+ }, "B\u1EA1n c\xF3 mu\u1ED1n ti\u1EBFp t\u1EE5c sao ch\xE9p kh\xF4ng?")),
1252
+ centered: true,
1253
+ className: 'be-popup-container',
1254
+ onOk: () => {
1255
+ handlePasted(rowsPasted);
1256
+ }
1257
+ });
1258
+ } else {
1259
+ handlePasted(rowsPasted);
1260
+ }
1261
+ }, [handlePasted, onCellPaste?.maxRowsPaste, startCell]);
1262
+
1263
+ // const handleDeleteContent = () => {
1264
+
1265
+ // if (startCell && endCell) {
1266
+
1267
+ // const tmpData = flattenArray([...convertData])
1268
+
1269
+ // const rs = tmpData.map((row, index: number) => {
1270
+
1271
+ // if (!rangeState?.rowRange.includes(row.rowId)) {
1272
+ // return row
1273
+ // }
1274
+
1275
+ // const updatedRow = { ...row }
1276
+
1277
+ // for (const colId of rangeState.colRange) {
1278
+
1279
+ // const column = leafColumns.find((it) => it.field === colId)
1280
+ // const columnIndex = leafColumns.findIndex((it) => it.field === colId)
1281
+
1282
+ // if (isEditable(column as any, row)) {
1283
+
1284
+ // let newValue: any = ''
1285
+
1286
+ // if (column.type === 'number') {
1287
+ // newValue = 0
1288
+ // }
1289
+
1290
+ // if (column.type === 'boolean' || column.type === 'checkbox') {
1291
+ // newValue = false
1292
+ // }
1293
+
1294
+ // const editType = getEditType(column as any, row)
1295
+
1296
+ // if (column.type === 'date' ||
1297
+ // column.type === 'datetime' ||
1298
+ // column.type === 'time' ||
1299
+ // column.type === 'month' ||
1300
+ // column.type === 'week' ||
1301
+ // column.type === 'year' ||
1302
+ // column.type === 'quarter' ||
1303
+ // editType === 'asyncSelect' ||
1304
+ // editType === 'select' ||
1305
+ // editType === 'treeSelect' ||
1306
+ // editType === 'selectTable'
1307
+ // ) {
1308
+ // newValue = undefined
1309
+ // }
1310
+
1311
+ // updatedRow[colId] = newValue
1312
+
1313
+ // handleCellChange({
1314
+ // key: row[rowKey] as any,
1315
+ // field: column.field ?? column.dataIndex as any,
1316
+ // record: updatedRow,
1317
+ // prevState: row[column.field],
1318
+ // newState: newValue,
1319
+ // option: '',
1320
+ // indexCol: columnIndex,
1321
+ // indexRow: index,
1322
+ // type: 'blur'
1323
+ // }
1324
+ // )
1325
+
1326
+ // }
1327
+ // }
1328
+
1329
+ // return updatedRow;
1330
+ // })
1331
+
1332
+ // const newData = unFlattenData(rs)
1333
+
1334
+ // triggerChangeData?.([...newData], { type: 'DELETE_CONTENT' })
1335
+
1336
+ // }
1337
+
1338
+ // }
1339
+
1340
+ React.useEffect(() => {
1341
+ const handlePaste = e => {
1342
+ if (startCell && !isEditing) {
1343
+ e.preventDefault(); // Chặn hành vi mặc định
1344
+ const clipboardText = e.clipboardData?.getData('text/plain') ?? '';
1345
+ handlePasteToTable(clipboardText, e);
1346
+ }
1347
+ };
1348
+ document.addEventListener('paste', handlePaste);
1349
+ return () => document.removeEventListener('paste', handlePaste);
1350
+ }, [startCell, endCell, handlePasteToTable, isEditing, copiedText]);
1351
+
1352
+ // Paste
1353
+
904
1354
  const toolbarItemsBottom = React.useMemo(() => {
905
1355
  // Chưa có dòng| ô được chọn
906
1356
  if (!rowsFocus || rowsFocus.length === 0) {
@@ -1489,7 +1939,7 @@ const InternalTable = props => {
1489
1939
  // {...pipeline.getProps()}
1490
1940
  ,
1491
1941
  originData: convertData,
1492
- dataSource: dataSource,
1942
+ dataSource: mergedData,
1493
1943
  originColumns: columns,
1494
1944
  groupColumns: groupColumns,
1495
1945
  setVisibleKeys: setVisibleKeys,