es-grid-template 1.3.3 → 1.3.4
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.
- package/assets/index.css +10 -0
- package/assets/index.scss +15 -0
- package/es/grid-component/ContextMenu.js +4 -1
- package/es/grid-component/EditableCell.js +60 -18
- package/es/grid-component/TableGrid.js +1 -7
- package/es/grid-component/hooks/columns/index.js +13 -16
- package/es/grid-component/hooks/useColumns.js +2 -1
- package/es/grid-component/hooks/utils.d.ts +13 -0
- package/es/grid-component/hooks/utils.js +136 -4
- package/es/grid-component/number/index.d.ts +10 -0
- package/es/grid-component/number/index.js +39 -0
- package/es/grid-component/styles.scss +15 -0
- package/es/grid-component/table/GridEdit.js +575 -204
- package/es/grid-component/type.d.ts +3 -0
- package/es/grid-component/useContext.d.ts +2 -0
- package/lib/grid-component/ContextMenu.js +4 -1
- package/lib/grid-component/EditableCell.js +61 -18
- package/lib/grid-component/TableGrid.js +1 -7
- package/lib/grid-component/hooks/columns/index.js +12 -15
- package/lib/grid-component/hooks/useColumns.js +2 -1
- package/lib/grid-component/hooks/utils.d.ts +13 -0
- package/lib/grid-component/hooks/utils.js +150 -7
- package/lib/grid-component/number/index.d.ts +10 -0
- package/lib/grid-component/number/index.js +47 -0
- package/lib/grid-component/styles.scss +15 -0
- package/lib/grid-component/table/GridEdit.js +563 -200
- package/lib/grid-component/type.d.ts +3 -0
- package/lib/grid-component/useContext.d.ts +2 -0
- package/package.json +1 -1
package/assets/index.css
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
min-width: 200px;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
.ant-dropdown-menu.popup-context-menu .ant-dropdown-menu-submenu .ant-dropdown-menu-submenu-title {
|
|
14
|
+
align-items: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
.ui-rc-table-wrapper p {
|
|
14
18
|
margin: 0;
|
|
15
19
|
}
|
|
@@ -111,6 +115,12 @@
|
|
|
111
115
|
.ui-rc-table-wrapper .ui-rc-table-thead .ui-rc-table-cell .ui-rc-table-cell-content {
|
|
112
116
|
line-height: 22px;
|
|
113
117
|
}
|
|
118
|
+
.ui-rc-table-wrapper .ui-rc-table-thead .ui-rc-table-cell.head-align-center {
|
|
119
|
+
text-align: center;
|
|
120
|
+
}
|
|
121
|
+
.ui-rc-table-wrapper .ui-rc-table-thead .ui-rc-table-cell.head-align-right {
|
|
122
|
+
text-align: right;
|
|
123
|
+
}
|
|
114
124
|
.ui-rc-table-wrapper .ui-rc-table-summary .ui-rc-table-cell {
|
|
115
125
|
background-color: #fafafa;
|
|
116
126
|
height: 39px;
|
package/assets/index.scss
CHANGED
|
@@ -26,6 +26,14 @@ $fontFamily: "Montserrat",Helvetica,Arial,serif !default;
|
|
|
26
26
|
|
|
27
27
|
.popup-context-menu {
|
|
28
28
|
min-width: 200px;
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
.ant-dropdown-menu.popup-context-menu {
|
|
32
|
+
.ant-dropdown-menu-submenu {
|
|
33
|
+
.ant-dropdown-menu-submenu-title {
|
|
34
|
+
align-items: center;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
// -------------- Table -------------
|
|
@@ -239,6 +247,13 @@ $fontFamily: "Montserrat",Helvetica,Arial,serif !default;
|
|
|
239
247
|
.#{$prefix}-table-column-title {
|
|
240
248
|
//display: flex;
|
|
241
249
|
}
|
|
250
|
+
|
|
251
|
+
&.head-align-center {
|
|
252
|
+
text-align: center;
|
|
253
|
+
}
|
|
254
|
+
&.head-align-right {
|
|
255
|
+
text-align: right;
|
|
256
|
+
}
|
|
242
257
|
}
|
|
243
258
|
}
|
|
244
259
|
|
|
@@ -98,7 +98,10 @@ const ContextMenu = props => {
|
|
|
98
98
|
maxHeight: pos.viewportHeight - 20,
|
|
99
99
|
width: 'fit-content'
|
|
100
100
|
},
|
|
101
|
-
rootClassName: 'popup-context-menu'
|
|
101
|
+
rootClassName: 'popup-context-menu'
|
|
102
|
+
// rootClassName={'be-popup-container'}
|
|
103
|
+
,
|
|
104
|
+
|
|
102
105
|
onClick: e => {
|
|
103
106
|
setOpen(false);
|
|
104
107
|
contextMenuClick?.({
|
|
@@ -11,14 +11,14 @@ getDatepickerFormat, getTemplate, isDisable, isEmpty, isNullOrUndefined, customW
|
|
|
11
11
|
} from "./hooks";
|
|
12
12
|
// import moment from "moment";
|
|
13
13
|
// import dayjs from "dayjs";
|
|
14
|
-
import {
|
|
14
|
+
// import {TreeSelect} from "antd";
|
|
15
15
|
import classNames from "classnames";
|
|
16
16
|
import { NumericFormat } from "react-numeric-component";
|
|
17
17
|
import { TableContext } from "./useContext";
|
|
18
18
|
import dayjs from "dayjs";
|
|
19
19
|
import moment from "moment";
|
|
20
20
|
import { Controller } from "react-hook-form";
|
|
21
|
-
import { Checkbox, Select } from "rc-master-ui";
|
|
21
|
+
import { Checkbox, Select, TreeSelect } from "rc-master-ui";
|
|
22
22
|
import { AsyncSelect } from "./async-select";
|
|
23
23
|
import { AsyncTableSelect } from "./async-table-select";
|
|
24
24
|
import { cyan, green, red, blue } from '@ant-design/colors';
|
|
@@ -52,7 +52,6 @@ const EditableCell = props => {
|
|
|
52
52
|
...restProps
|
|
53
53
|
} = props;
|
|
54
54
|
const {
|
|
55
|
-
rowKey,
|
|
56
55
|
format,
|
|
57
56
|
control,
|
|
58
57
|
getValues,
|
|
@@ -121,6 +120,8 @@ const EditableCell = props => {
|
|
|
121
120
|
prevState,
|
|
122
121
|
newState,
|
|
123
122
|
option: newState,
|
|
123
|
+
indexCol,
|
|
124
|
+
indexRow,
|
|
124
125
|
type: 'blur'
|
|
125
126
|
});
|
|
126
127
|
}
|
|
@@ -193,6 +194,8 @@ const EditableCell = props => {
|
|
|
193
194
|
prevState,
|
|
194
195
|
newState,
|
|
195
196
|
option: newState,
|
|
197
|
+
indexCol,
|
|
198
|
+
indexRow,
|
|
196
199
|
type: 'blur'
|
|
197
200
|
});
|
|
198
201
|
}
|
|
@@ -313,6 +316,8 @@ const EditableCell = props => {
|
|
|
313
316
|
prevState,
|
|
314
317
|
newState,
|
|
315
318
|
option: option,
|
|
319
|
+
indexCol,
|
|
320
|
+
indexRow,
|
|
316
321
|
type: 'blur'
|
|
317
322
|
});
|
|
318
323
|
},
|
|
@@ -393,6 +398,8 @@ const EditableCell = props => {
|
|
|
393
398
|
prevState,
|
|
394
399
|
newState,
|
|
395
400
|
option: option,
|
|
401
|
+
indexCol,
|
|
402
|
+
indexRow,
|
|
396
403
|
type: 'blur'
|
|
397
404
|
});
|
|
398
405
|
},
|
|
@@ -448,6 +455,8 @@ const EditableCell = props => {
|
|
|
448
455
|
prevState,
|
|
449
456
|
newState,
|
|
450
457
|
option: option,
|
|
458
|
+
indexCol,
|
|
459
|
+
indexRow,
|
|
451
460
|
type: 'blur'
|
|
452
461
|
});
|
|
453
462
|
},
|
|
@@ -518,12 +527,23 @@ const EditableCell = props => {
|
|
|
518
527
|
|
|
519
528
|
const newTreeData = convertLabelToTitle(optionsTree);
|
|
520
529
|
// @ts-ignore
|
|
521
|
-
const valueTreeSelect = column?.editSelectSettings?.isMulti ? Array.isArray(record[column.dataIndex]) ? record[column.dataIndex] : [] : record[column.dataIndex]
|
|
530
|
+
// const valueTreeSelect = column?.editSelectSettings?.isMulti ? (Array.isArray(record[column.dataIndex]) ? record[column.dataIndex] : []) : record[column.dataIndex]
|
|
531
|
+
|
|
532
|
+
let valueTreeSelect = value;
|
|
533
|
+
if (fieldValue) {
|
|
534
|
+
// @ts-ignore
|
|
535
|
+
valueTreeSelect = record[fieldValue] ?? value;
|
|
536
|
+
}
|
|
537
|
+
if (isMulti || selectMode === 'checkbox') {
|
|
538
|
+
// @ts-ignore
|
|
539
|
+
valueTreeSelect = !isNullOrUndefined(record[column.dataIndex]) && Array.isArray(record[column.dataIndex]) && record[column.dataIndex]?.length > 0 ? options.filter(val => record[column.dataIndex]?.includes(val[keySelect])) : undefined;
|
|
540
|
+
}
|
|
522
541
|
return /*#__PURE__*/React.createElement(TreeSelect, {
|
|
523
542
|
id: `col${indexCol}-record${indexRow}`,
|
|
524
543
|
className: 'be-tree-select',
|
|
525
544
|
style: {
|
|
526
|
-
width: '100%'
|
|
545
|
+
width: '100%',
|
|
546
|
+
height: '100%'
|
|
527
547
|
},
|
|
528
548
|
value: valueTreeSelect,
|
|
529
549
|
dropdownStyle: {
|
|
@@ -550,17 +570,28 @@ const EditableCell = props => {
|
|
|
550
570
|
value: keySelect,
|
|
551
571
|
children: 'children'
|
|
552
572
|
},
|
|
553
|
-
treeCheckable: column?.editSelectSettings?.selectMode === 'checkbox'
|
|
554
|
-
|
|
555
|
-
,
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
573
|
+
treeCheckable: column?.editSelectSettings?.selectMode === 'checkbox',
|
|
574
|
+
filterTreeNode: filterTreeNode,
|
|
575
|
+
onSelect: (val, option) => {
|
|
576
|
+
onChange(val ?? '');
|
|
577
|
+
const formState = getValues();
|
|
578
|
+
// const itemState = getValues(dataIndex)
|
|
579
|
+
// @ts-ignore
|
|
580
|
+
const prevState = record[dataIndex];
|
|
581
|
+
const newState = val;
|
|
582
|
+
handleCellChange?.({
|
|
583
|
+
key: getRowKey?.(record, index),
|
|
584
|
+
field: column.field ?? column.dataIndex,
|
|
585
|
+
record: formState,
|
|
586
|
+
prevState,
|
|
587
|
+
newState,
|
|
588
|
+
option: option,
|
|
589
|
+
indexCol,
|
|
590
|
+
indexRow,
|
|
591
|
+
type: 'blur'
|
|
592
|
+
});
|
|
593
|
+
},
|
|
594
|
+
popupClassName: 'be-popup-container',
|
|
564
595
|
status: isInvalid ? 'error' : undefined
|
|
565
596
|
});
|
|
566
597
|
case 'checkbox':
|
|
@@ -589,6 +620,8 @@ const EditableCell = props => {
|
|
|
589
620
|
prevState: value,
|
|
590
621
|
newState: newVal,
|
|
591
622
|
field: column.field ?? column.dataIndex,
|
|
623
|
+
indexCol,
|
|
624
|
+
indexRow,
|
|
592
625
|
type: 'blur'
|
|
593
626
|
});
|
|
594
627
|
},
|
|
@@ -674,6 +707,8 @@ const EditableCell = props => {
|
|
|
674
707
|
record: formState,
|
|
675
708
|
prevState: value,
|
|
676
709
|
newState: `#${valueColor.toHex()}`,
|
|
710
|
+
indexCol,
|
|
711
|
+
indexRow,
|
|
677
712
|
type: 'blur'
|
|
678
713
|
});
|
|
679
714
|
},
|
|
@@ -773,6 +808,8 @@ const EditableCell = props => {
|
|
|
773
808
|
record: formState,
|
|
774
809
|
prevState,
|
|
775
810
|
newState,
|
|
811
|
+
indexCol,
|
|
812
|
+
indexRow,
|
|
776
813
|
type: 'blur'
|
|
777
814
|
});
|
|
778
815
|
}
|
|
@@ -810,23 +847,28 @@ const EditableCell = props => {
|
|
|
810
847
|
prevState,
|
|
811
848
|
newState,
|
|
812
849
|
field: column.field ?? column.dataIndex,
|
|
850
|
+
indexCol,
|
|
851
|
+
indexRow,
|
|
813
852
|
type: 'blur'
|
|
814
853
|
});
|
|
815
854
|
}
|
|
816
855
|
},
|
|
817
856
|
onPressEnter: () => {
|
|
857
|
+
const key = getRowKey?.(record, index);
|
|
818
858
|
const formState = getValues();
|
|
819
859
|
const newState = getValues(dataIndex);
|
|
820
860
|
// @ts-ignore
|
|
821
861
|
const prevState = record[dataIndex];
|
|
822
862
|
// @ts-ignore
|
|
823
863
|
// if (itemState !== record[dataIndex]) {
|
|
824
|
-
|
|
864
|
+
|
|
825
865
|
handleCellChange?.({
|
|
826
|
-
key:
|
|
866
|
+
key: key,
|
|
827
867
|
newState,
|
|
828
868
|
prevState,
|
|
829
869
|
record: formState,
|
|
870
|
+
indexCol,
|
|
871
|
+
indexRow,
|
|
830
872
|
type: 'enter'
|
|
831
873
|
});
|
|
832
874
|
// }
|
|
@@ -287,12 +287,6 @@ const TableGrid = props => {
|
|
|
287
287
|
if (checkboxOnly !== true) {
|
|
288
288
|
if (type === 'single') {}
|
|
289
289
|
}
|
|
290
|
-
if (clickRef.current) return;
|
|
291
|
-
|
|
292
|
-
// @ts-ignore
|
|
293
|
-
clickRef.current = setTimeout(() => {
|
|
294
|
-
clickRef.current = null;
|
|
295
|
-
}, 250);
|
|
296
290
|
};
|
|
297
291
|
const handleRowDoubleClick = (record, index) => e => {
|
|
298
292
|
if (clickRef.current) {
|
|
@@ -372,7 +366,7 @@ const TableGrid = props => {
|
|
|
372
366
|
spinning: columns && columns.length === 0 || loading === true,
|
|
373
367
|
indicator: /*#__PURE__*/React.createElement(ComponentSpinner, null)
|
|
374
368
|
},
|
|
375
|
-
dataSource: columns && columns.length > 0
|
|
369
|
+
dataSource: columns && columns.length > 0 ? filterDataByColumns3(dataSource, filterStates) : []
|
|
376
370
|
// dataSource={columns && columns.length > 0 && loading !== true ? dataSource : []}
|
|
377
371
|
// className={styles.customTable}
|
|
378
372
|
,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { checkDecimalSeparator, checkThousandSeparator, convertDateToDayjs, convertDayjsToDate, getDatepickerFormat, getDateString, getTypeFilter, isColor, isEmpty } from "../utils";
|
|
2
|
-
import {
|
|
2
|
+
import { numericFormatter } from "react-numeric-component";
|
|
3
3
|
import dayjs from "dayjs";
|
|
4
4
|
import moment from "moment/moment";
|
|
5
5
|
import React, { Fragment } from "react";
|
|
@@ -7,6 +7,7 @@ import { DatePicker, Empty, Input, Select } from "rc-master-ui";
|
|
|
7
7
|
import CheckboxFilter from "../../CheckboxFilter";
|
|
8
8
|
import { SELECTION_COLUMN } from "rc-master-ui/es/table/hooks/useSelection";
|
|
9
9
|
import NumberRange from "../../number-range";
|
|
10
|
+
import Number from "../../number";
|
|
10
11
|
const {
|
|
11
12
|
RangePicker
|
|
12
13
|
} = DatePicker;
|
|
@@ -68,7 +69,10 @@ export const getValueCell = (column, value, format) => {
|
|
|
68
69
|
const thousandSeparator = column?.format?.thousandSeparator ? column?.format?.thousandSeparator : format?.thousandSeparator;
|
|
69
70
|
const decimalSeparator = column?.format?.decimalSeparator ? column?.format?.decimalSeparator : format?.decimalSeparator;
|
|
70
71
|
const dec = column?.format?.decimalScale || column?.format?.decimalScale === 0 ? column?.format?.decimalScale : format?.decimalScale;
|
|
71
|
-
|
|
72
|
+
|
|
73
|
+
// const contentNumber = !isEmpty(value) ? ((dec || dec === 0) ? parseFloat(Number(value).toFixed(dec)).toString() : value.toString()) : '0'
|
|
74
|
+
|
|
75
|
+
const contentNumber = !isEmpty(value) ? dec || dec === 0 ? parseFloat(value.toFixed(dec)).toString() : value.toString() : '0';
|
|
72
76
|
const numericFormatProps = {
|
|
73
77
|
thousandSeparator: checkThousandSeparator(thousandSeparator, decimalSeparator),
|
|
74
78
|
decimalSeparator: checkDecimalSeparator(thousandSeparator, decimalSeparator),
|
|
@@ -78,7 +82,7 @@ export const getValueCell = (column, value, format) => {
|
|
|
78
82
|
decimalScale: column?.format?.decimalScale || column?.format?.decimalScale === 0 ? column?.format?.decimalScale : format?.decimalScale,
|
|
79
83
|
fixedDecimalScale: (column?.format?.fixedDecimalScale ? column?.format?.fixedDecimalScale : format?.fixedDecimalScale) ?? false
|
|
80
84
|
};
|
|
81
|
-
return !isEmpty(
|
|
85
|
+
return !isEmpty(contentNumber) ? numericFormatter(contentNumber, numericFormatProps) : '';
|
|
82
86
|
case 'date':
|
|
83
87
|
return value ? dayjs(value).format(column?.format?.dateFormat ?? format?.dateFormat ?? 'DD/MM/YYYY') : '';
|
|
84
88
|
case 'time':
|
|
@@ -102,7 +106,7 @@ export const getValueCell = (column, value, format) => {
|
|
|
102
106
|
}));
|
|
103
107
|
case 'checkbox':
|
|
104
108
|
return /*#__PURE__*/React.createElement(Input, {
|
|
105
|
-
checked: !!
|
|
109
|
+
checked: !!value,
|
|
106
110
|
readOnly: true,
|
|
107
111
|
type: "checkbox"
|
|
108
112
|
});
|
|
@@ -136,18 +140,11 @@ export const renderFilter = (column, selectedKeys, setSelectedKeys, confirm, vis
|
|
|
136
140
|
case 'Number':
|
|
137
141
|
return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
138
142
|
className: 'mb-1'
|
|
139
|
-
}, /*#__PURE__*/React.createElement(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
,
|
|
145
|
-
allowNegative: true,
|
|
146
|
-
customInput: Input,
|
|
147
|
-
className: ' rounded-0 input-element form-control',
|
|
148
|
-
onValueChange: values => {
|
|
149
|
-
// onChangeValueFilter(type, values.floatValue)
|
|
150
|
-
setSelectedKeys(values.floatValue || values.floatValue === 0 ? [values.floatValue] : []);
|
|
143
|
+
}, /*#__PURE__*/React.createElement(Number, {
|
|
144
|
+
t: t,
|
|
145
|
+
value: selectedKeys[0],
|
|
146
|
+
onChange: vals => {
|
|
147
|
+
setSelectedKeys(vals);
|
|
151
148
|
}
|
|
152
149
|
}))));
|
|
153
150
|
case 'NumberRange':
|
|
@@ -263,7 +263,8 @@ const useColumns = config => {
|
|
|
263
263
|
},
|
|
264
264
|
onHeaderCell: () => ({
|
|
265
265
|
width: col.width,
|
|
266
|
-
onResize: handleResize?.(col)
|
|
266
|
+
onResize: handleResize?.(col),
|
|
267
|
+
className: col.headerTextAlign === 'center' ? 'head-align-center' : col.headerTextAlign === 'right' ? 'head-align-right' : ''
|
|
267
268
|
}),
|
|
268
269
|
onCell: (data, index) => {
|
|
269
270
|
return {
|
|
@@ -80,3 +80,16 @@ export declare function isDateString(str: any): boolean;
|
|
|
80
80
|
export declare function compareDates(date1: any, date2: any): boolean;
|
|
81
81
|
export declare function compareDate(itemValue: any, value: any): boolean;
|
|
82
82
|
export declare function invalidDate(date: any): boolean;
|
|
83
|
+
export declare const isContinuous: (set: any) => boolean;
|
|
84
|
+
export declare const parseCells: (cellSet: any) => {
|
|
85
|
+
row: any;
|
|
86
|
+
col: any;
|
|
87
|
+
key: any;
|
|
88
|
+
}[];
|
|
89
|
+
export declare const buildConnectedRegions: (cells: any) => any[];
|
|
90
|
+
export declare const isBottomMostInRegion: (rowIndex: number, colIndex: number, listSelectCell: any) => boolean;
|
|
91
|
+
export declare const isTopMostInRegion: (rowIndex: number, colIndex: number, listSelectCell: any) => boolean;
|
|
92
|
+
export declare function isRightMostInRegion(rowIndex: number, colIndex: number, listSelectCell: any): boolean;
|
|
93
|
+
export declare function isEqualSet(setA: any, setB: any): boolean;
|
|
94
|
+
export declare function isBottomMostInRanges(rowIndex: number, colIndex: number, regions: any[]): boolean;
|
|
95
|
+
export declare const mergedSets: (arr: any[]) => Set<unknown>;
|
|
@@ -980,10 +980,10 @@ export const filterDataByColumns3 = (data, queries) => {
|
|
|
980
980
|
const queryStr = value?.toString().toLowerCase?.();
|
|
981
981
|
switch (operator.toLowerCase()) {
|
|
982
982
|
case "equal":
|
|
983
|
-
condition = isDateComparison ? compareDates(itemDate, queryDate) : itemValue
|
|
983
|
+
condition = isDateComparison ? compareDates(itemDate, queryDate) : itemValue === value;
|
|
984
984
|
break;
|
|
985
985
|
case "notequal":
|
|
986
|
-
condition = isDateComparison ? !compareDates(itemDate, queryDate) : itemValue
|
|
986
|
+
condition = isDateComparison ? !compareDates(itemDate, queryDate) : itemValue !== value;
|
|
987
987
|
break;
|
|
988
988
|
case "greaterthan":
|
|
989
989
|
// @ts-ignore
|
|
@@ -1029,8 +1029,19 @@ export const filterDataByColumns3 = (data, queries) => {
|
|
|
1029
1029
|
// ======= Helper functions ========
|
|
1030
1030
|
|
|
1031
1031
|
// Kiểm tra có phải Date object không
|
|
1032
|
+
// function isDate(value: any) {
|
|
1033
|
+
// return value instanceof Date || !isNaN(Date.parse(value));
|
|
1034
|
+
// }
|
|
1035
|
+
|
|
1032
1036
|
function isDate(value) {
|
|
1033
|
-
|
|
1037
|
+
if (value instanceof Date) {
|
|
1038
|
+
return !isNaN(value.getTime());
|
|
1039
|
+
}
|
|
1040
|
+
if (typeof value === "string") {
|
|
1041
|
+
// Chỉ chấp nhận định dạng yyyy-mm-dd hoặc mm/yyyy
|
|
1042
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(value) || /^\d{2}\/\d{4}$/.test(value);
|
|
1043
|
+
}
|
|
1044
|
+
return false;
|
|
1034
1045
|
}
|
|
1035
1046
|
|
|
1036
1047
|
// Chuỗi MM/YYYY → Date
|
|
@@ -1064,4 +1075,125 @@ export function compareDate(itemValue, value) {
|
|
|
1064
1075
|
}
|
|
1065
1076
|
export function invalidDate(date) {
|
|
1066
1077
|
return date instanceof Date && !isNaN(date.getTime());
|
|
1067
|
-
}
|
|
1078
|
+
}
|
|
1079
|
+
export const isContinuous = set => {
|
|
1080
|
+
const rows = [];
|
|
1081
|
+
const cols = [];
|
|
1082
|
+
for (const item of set) {
|
|
1083
|
+
const [row, col] = item.split('-').map(Number);
|
|
1084
|
+
rows.push(row);
|
|
1085
|
+
cols.push(col);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// Lấy danh sách duy nhất và sắp xếp
|
|
1089
|
+
const uniqueSorted = arr => [...new Set(arr)].sort((a, b) => a - b);
|
|
1090
|
+
const isSequential = arr => {
|
|
1091
|
+
for (let i = 1; i < arr.length; i++) {
|
|
1092
|
+
if (arr[i] !== arr[i - 1] + 1) {
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
return true;
|
|
1097
|
+
};
|
|
1098
|
+
const sortedRows = uniqueSorted(rows);
|
|
1099
|
+
const sortedCols = uniqueSorted(cols);
|
|
1100
|
+
return isSequential(sortedRows) && isSequential(sortedCols);
|
|
1101
|
+
};
|
|
1102
|
+
export const parseCells = cellSet => {
|
|
1103
|
+
return Array.from(cellSet).map(cell => {
|
|
1104
|
+
const [row, col] = cell.split('-').map(Number);
|
|
1105
|
+
return {
|
|
1106
|
+
row,
|
|
1107
|
+
col,
|
|
1108
|
+
key: cell
|
|
1109
|
+
};
|
|
1110
|
+
});
|
|
1111
|
+
};
|
|
1112
|
+
export const buildConnectedRegions = cells => {
|
|
1113
|
+
const cellMap = new Map();
|
|
1114
|
+
const visited = new Set();
|
|
1115
|
+
for (const cell of cells) {
|
|
1116
|
+
cellMap.set(cell.key, cell);
|
|
1117
|
+
}
|
|
1118
|
+
const directions = [[1, 0],
|
|
1119
|
+
// down
|
|
1120
|
+
[-1, 0],
|
|
1121
|
+
// up
|
|
1122
|
+
[0, 1],
|
|
1123
|
+
// right
|
|
1124
|
+
[0, -1] // left
|
|
1125
|
+
];
|
|
1126
|
+
const regions = [];
|
|
1127
|
+
for (const cell of cells) {
|
|
1128
|
+
if (visited.has(cell.key)) continue;
|
|
1129
|
+
const stack = [cell];
|
|
1130
|
+
const region = [];
|
|
1131
|
+
while (stack.length) {
|
|
1132
|
+
const current = stack.pop();
|
|
1133
|
+
if (visited.has(current.key)) continue;
|
|
1134
|
+
visited.add(current.key);
|
|
1135
|
+
region.push(current);
|
|
1136
|
+
for (const [dr, dc] of directions) {
|
|
1137
|
+
const neighborKey = `${current.row + dr}-${current.col + dc}`;
|
|
1138
|
+
if (cellMap.has(neighborKey) && !visited.has(neighborKey)) {
|
|
1139
|
+
stack.push(cellMap.get(neighborKey));
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
regions.push(region);
|
|
1144
|
+
}
|
|
1145
|
+
return regions;
|
|
1146
|
+
};
|
|
1147
|
+
export const isBottomMostInRegion = (rowIndex, colIndex, listSelectCell) => {
|
|
1148
|
+
const cells = parseCells(listSelectCell);
|
|
1149
|
+
const regions = buildConnectedRegions(cells);
|
|
1150
|
+
for (const region of regions) {
|
|
1151
|
+
if (region.some(cell => cell.row === rowIndex && cell.col === colIndex)) {
|
|
1152
|
+
const maxRow = Math.max(...region.map(cell => cell.row));
|
|
1153
|
+
return rowIndex === maxRow;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
return false;
|
|
1157
|
+
};
|
|
1158
|
+
export const isTopMostInRegion = (rowIndex, colIndex, listSelectCell) => {
|
|
1159
|
+
const cells = parseCells(listSelectCell);
|
|
1160
|
+
const regions = buildConnectedRegions(cells);
|
|
1161
|
+
for (const region of regions) {
|
|
1162
|
+
if (region.some(cell => cell.row === rowIndex && cell.col === colIndex)) {
|
|
1163
|
+
const minRow = Math.min(...region.map(cell => cell.row));
|
|
1164
|
+
return rowIndex === minRow;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return false;
|
|
1168
|
+
};
|
|
1169
|
+
export function isRightMostInRegion(rowIndex, colIndex, listSelectCell) {
|
|
1170
|
+
const cells = parseCells(listSelectCell);
|
|
1171
|
+
const regions = buildConnectedRegions(cells);
|
|
1172
|
+
for (const region of regions) {
|
|
1173
|
+
if (region.some(cell => cell.row === rowIndex && cell.col === colIndex)) {
|
|
1174
|
+
const maxCol = Math.max(...region.map(cell => cell.col));
|
|
1175
|
+
return colIndex === maxCol;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return false;
|
|
1179
|
+
}
|
|
1180
|
+
export function isEqualSet(setA, setB) {
|
|
1181
|
+
if (setA.size !== setB.size) return false;
|
|
1182
|
+
for (const item of setA) {
|
|
1183
|
+
if (!setB.has(item)) return false;
|
|
1184
|
+
}
|
|
1185
|
+
return true;
|
|
1186
|
+
}
|
|
1187
|
+
export function isBottomMostInRanges(rowIndex, colIndex, regions) {
|
|
1188
|
+
const ranges = regions.map(it => parseCells(it));
|
|
1189
|
+
for (const region of ranges) {
|
|
1190
|
+
if (region.some(cell => cell.row === rowIndex && cell.col === colIndex)) {
|
|
1191
|
+
const maxRow = Math.max(...region.map(cell => cell.row));
|
|
1192
|
+
return rowIndex === maxRow;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
return false;
|
|
1196
|
+
}
|
|
1197
|
+
export const mergedSets = arr => {
|
|
1198
|
+
return new Set(arr.flatMap(set => Array.from(set)));
|
|
1199
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { IFormat } from "../type";
|
|
3
|
+
type Props = {
|
|
4
|
+
t?: any;
|
|
5
|
+
format?: IFormat;
|
|
6
|
+
value: number | string | undefined;
|
|
7
|
+
onChange?: (values: any[]) => void;
|
|
8
|
+
};
|
|
9
|
+
declare const Number: (props: Props) => React.JSX.Element;
|
|
10
|
+
export default Number;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { Fragment } from "react";
|
|
2
|
+
import { NumericFormat } from "react-numeric-component";
|
|
3
|
+
import { Input } from "rc-master-ui";
|
|
4
|
+
import { checkDecimalSeparator, checkThousandSeparator } from "../hooks";
|
|
5
|
+
const Number = props => {
|
|
6
|
+
const {
|
|
7
|
+
t,
|
|
8
|
+
value,
|
|
9
|
+
format,
|
|
10
|
+
onChange
|
|
11
|
+
} = props;
|
|
12
|
+
const values = React.useMemo(() => [value], [value]);
|
|
13
|
+
|
|
14
|
+
// const [values, setValues] = React.useState<any[]>(() =>
|
|
15
|
+
// mergedValues,
|
|
16
|
+
// );
|
|
17
|
+
|
|
18
|
+
return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement(NumericFormat, {
|
|
19
|
+
value: values[0] ?? ''
|
|
20
|
+
// value={min}
|
|
21
|
+
,
|
|
22
|
+
thousandSeparator: checkThousandSeparator(format?.thousandSeparator, format?.decimalSeparator),
|
|
23
|
+
decimalSeparator: checkDecimalSeparator(format?.thousandSeparator, format?.decimalSeparator),
|
|
24
|
+
allowNegative: true,
|
|
25
|
+
customInput: Input,
|
|
26
|
+
className: 'rounded-0 input-element',
|
|
27
|
+
onValueChange: vals => {
|
|
28
|
+
// onChangeValueFilter(type, values.floatValue, 'min')
|
|
29
|
+
|
|
30
|
+
// setValues([vals.floatValue, values[1]])
|
|
31
|
+
onChange?.([vals.floatValue]);
|
|
32
|
+
}
|
|
33
|
+
// placeholder={t ? t('Min') : 'Min'}
|
|
34
|
+
,
|
|
35
|
+
placeholder: t ? t('Enter') : 'Enter',
|
|
36
|
+
autoFocus: true
|
|
37
|
+
}));
|
|
38
|
+
};
|
|
39
|
+
export default Number;
|
|
@@ -26,6 +26,14 @@ $fontFamily: "Montserrat",Helvetica,Arial,serif !default;
|
|
|
26
26
|
|
|
27
27
|
.popup-context-menu {
|
|
28
28
|
min-width: 200px;
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
.ant-dropdown-menu.popup-context-menu {
|
|
32
|
+
.ant-dropdown-menu-submenu {
|
|
33
|
+
.ant-dropdown-menu-submenu-title {
|
|
34
|
+
align-items: center;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
// -------------- Table -------------
|
|
@@ -239,6 +247,13 @@ $fontFamily: "Montserrat",Helvetica,Arial,serif !default;
|
|
|
239
247
|
.#{$prefix}-table-column-title {
|
|
240
248
|
//display: flex;
|
|
241
249
|
}
|
|
250
|
+
|
|
251
|
+
&.head-align-center {
|
|
252
|
+
text-align: center;
|
|
253
|
+
}
|
|
254
|
+
&.head-align-right {
|
|
255
|
+
text-align: right;
|
|
256
|
+
}
|
|
242
257
|
}
|
|
243
258
|
}
|
|
244
259
|
|