es-grid-template 1.8.28 → 1.8.29
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/CHANGELOG.md +6 -0
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/assets/index.scss +1170 -1170
- package/es/grid-component/hooks/constant.js +6 -6
- package/es/grid-component/hooks/useColumns.d.ts +1 -3
- package/es/grid-component/styles.scss +1437 -1437
- package/es/table-component/TableContainer.d.ts +7 -0
- package/es/table-component/TableContainer.js +7 -2
- package/es/table-component/TableContainerEdit.d.ts +7 -0
- package/es/table-component/TableContainerEdit.js +16 -6
- package/es/table-component/body/TableBodyCell.js +126 -24
- package/es/table-component/body/TableBodyCellEdit.js +29 -12
- package/es/table-component/body/TableBodyRow.js +4 -2
- package/es/table-component/components/number/index.d.ts +2 -1
- package/es/table-component/components/number/index.js +13 -5
- package/es/table-component/components/number-range/index.d.ts +2 -1
- package/es/table-component/components/number-range/index.js +22 -6
- package/es/table-component/header/TableHeadCell.js +2 -1
- package/es/table-component/header/TableHeadCell2.js +42 -16
- package/es/table-component/header/TableHeadGroupCell.js +2 -1
- package/es/table-component/header/renderFilter.d.ts +1 -1
- package/es/table-component/header/renderFilter.js +13 -5
- package/es/table-component/hook/constant.js +6 -6
- package/es/table-component/hook/useColumns.js +2 -2
- package/es/table-component/hook/utils.d.ts +7 -0
- package/es/table-component/hook/utils.js +133 -0
- package/es/table-component/style.scss +1220 -1220
- package/es/table-component/table/Grid.js +27 -23
- package/es/table-component/table/TableWrapper.js +2 -1
- package/es/table-component/type.d.ts +9 -5
- package/es/table-component/useContext.d.ts +11 -2
- package/lib/grid-component/hooks/constant.js +6 -6
- package/lib/grid-component/hooks/useColumns.d.ts +1 -3
- package/lib/grid-component/styles.scss +1437 -1437
- package/lib/table-component/TableContainer.d.ts +7 -0
- package/lib/table-component/TableContainer.js +7 -2
- package/lib/table-component/TableContainerEdit.d.ts +7 -0
- package/lib/table-component/TableContainerEdit.js +15 -5
- package/lib/table-component/body/TableBodyCell.js +126 -24
- package/lib/table-component/body/TableBodyCellEdit.js +29 -12
- package/lib/table-component/body/TableBodyRow.js +4 -2
- package/lib/table-component/components/number/index.d.ts +2 -1
- package/lib/table-component/components/number/index.js +13 -5
- package/lib/table-component/components/number-range/index.d.ts +2 -1
- package/lib/table-component/components/number-range/index.js +22 -6
- package/lib/table-component/header/TableHeadCell.js +2 -1
- package/lib/table-component/header/TableHeadCell2.js +41 -15
- package/lib/table-component/header/TableHeadGroupCell.js +2 -1
- package/lib/table-component/header/renderFilter.d.ts +1 -1
- package/lib/table-component/header/renderFilter.js +13 -5
- package/lib/table-component/hook/constant.js +6 -6
- package/lib/table-component/hook/useColumns.js +2 -2
- package/lib/table-component/hook/utils.d.ts +7 -0
- package/lib/table-component/hook/utils.js +144 -2
- package/lib/table-component/style.scss +1220 -1220
- package/lib/table-component/table/Grid.js +26 -22
- package/lib/table-component/table/TableWrapper.js +2 -1
- package/lib/table-component/type.d.ts +9 -5
- package/lib/table-component/useContext.d.ts +11 -2
- package/package.json +116 -116
|
@@ -9,7 +9,7 @@ import { ArrowDown, ArrowUp, FilterFill, SortCancel } from 'becoxy-icons';
|
|
|
9
9
|
import classNames from 'classnames';
|
|
10
10
|
import { Checkbox, Dropdown, Select } from 'rc-master-ui';
|
|
11
11
|
import { booleanOperator, nonActionColumn, numberOperator, stringOperator, translateOption } from "../hook/constant";
|
|
12
|
-
import { extendsObject, getCommonPinningStyles, getDefaultOperator, getTypeFilter } from "../hook/utils";
|
|
12
|
+
import { excludeItems, extendsObject, getCommonPinningStyles, getDefaultOperator, getTypeFilter } from "../hook/utils";
|
|
13
13
|
import { TableContext } from "../useContext";
|
|
14
14
|
import { renderFilter } from "./renderFilter";
|
|
15
15
|
import ReactDOMServer from 'react-dom/server';
|
|
@@ -38,9 +38,11 @@ const TableHeadCell2 = props => {
|
|
|
38
38
|
setFilterChange,
|
|
39
39
|
wrapSettings,
|
|
40
40
|
selectionSettings,
|
|
41
|
+
isSelectionChange,
|
|
41
42
|
setIsSelectionChange,
|
|
42
43
|
id,
|
|
43
|
-
locale
|
|
44
|
+
locale,
|
|
45
|
+
format
|
|
44
46
|
} = useContext(TableContext);
|
|
45
47
|
const isPinned = column.getIsPinned();
|
|
46
48
|
const isLastLeftPinnedColumn = isPinned === 'left' && column.getIsLastColumn('left');
|
|
@@ -110,9 +112,15 @@ const TableHeadCell2 = props => {
|
|
|
110
112
|
if (info.source === 'trigger') {
|
|
111
113
|
if (newVisible) {
|
|
112
114
|
const filterValue = column.getFilterValue() ?? [];
|
|
113
|
-
const operatorValue = column.getFilterOperator() ?? getDefaultOperator(column?.meta ?? {});
|
|
115
|
+
const operatorValue = column.getFilterOperator() ?? getDefaultOperator(column.columnDef?.meta ?? {});
|
|
114
116
|
setSelectedKeys(filterValue);
|
|
115
117
|
column.setFilterOperator?.(operatorValue);
|
|
118
|
+
setTimeout(() => {
|
|
119
|
+
const inputFilter = document.querySelector('.filter-input');
|
|
120
|
+
if (inputFilter) {
|
|
121
|
+
inputFilter.focus();
|
|
122
|
+
}
|
|
123
|
+
}, 200);
|
|
116
124
|
} else {}
|
|
117
125
|
triggerVisible(newVisible);
|
|
118
126
|
}
|
|
@@ -144,10 +152,7 @@ const TableHeadCell2 = props => {
|
|
|
144
152
|
destroyPopupOnHide: true,
|
|
145
153
|
dropdownRender: () => {
|
|
146
154
|
const type = getTypeFilter(originalColumn);
|
|
147
|
-
|
|
148
|
-
// const operatorValue = (column.getFilterOperator() ?? getDefaultOperator(originalColumn)) as string
|
|
149
|
-
|
|
150
|
-
const operatorValue = header.column.getFilterOperator() ?? getDefaultOperator(column.columnDef?.meta ?? {});
|
|
155
|
+
const operatorValue = column.getFilterOperator() ?? getDefaultOperator(originalColumn);
|
|
151
156
|
const operatorOptions = ['Checkbox', 'Dropdown', 'DropTree', 'CheckboxDropdown'].includes(type) ? booleanOperator : !type || type === 'Text' ? stringOperator : numberOperator;
|
|
152
157
|
return /*#__PURE__*/React.createElement("div", {
|
|
153
158
|
// className='ui-rc-table-filter-dropdown'
|
|
@@ -159,7 +164,7 @@ const TableHeadCell2 = props => {
|
|
|
159
164
|
minWidth: 275,
|
|
160
165
|
padding: '8px'
|
|
161
166
|
}
|
|
162
|
-
}, /*#__PURE__*/React.createElement("div", null), column.columnDef
|
|
167
|
+
}, /*#__PURE__*/React.createElement("div", null), column.columnDef?.meta?.showOperator !== false && column.columnDef?.meta?.typeFilter !== 'DateRange' && column.columnDef?.meta?.typeFilter !== 'NumberRange' && /*#__PURE__*/React.createElement("div", {
|
|
163
168
|
className: 'mb-1'
|
|
164
169
|
}, /*#__PURE__*/React.createElement(Select, {
|
|
165
170
|
options: translateOption(operatorOptions, t),
|
|
@@ -178,7 +183,10 @@ const TableHeadCell2 = props => {
|
|
|
178
183
|
}, renderFilter({
|
|
179
184
|
column: column.columnDef,
|
|
180
185
|
selectedKeys,
|
|
181
|
-
setSelectedKeys
|
|
186
|
+
setSelectedKeys,
|
|
187
|
+
doFilter,
|
|
188
|
+
format
|
|
189
|
+
|
|
182
190
|
// selectedKeys: (column.getFilterValue() ?? []) as string[],
|
|
183
191
|
// setSelectedKeys: column.setFilterValue,
|
|
184
192
|
})), /*#__PURE__*/React.createElement(Space, {
|
|
@@ -253,15 +261,33 @@ const TableHeadCell2 = props => {
|
|
|
253
261
|
[`${prefix}-grid-selection-column`]: column.id === 'selection_column'
|
|
254
262
|
})
|
|
255
263
|
}, column.id === 'selection_column' && selectionSettings && selectionSettings.hideSelectAll !== true && selectionSettings.type !== 'single' && selectionSettings.mode !== 'radio' && /*#__PURE__*/React.createElement(Checkbox, {
|
|
256
|
-
checked: table.getIsAllRowsSelected()
|
|
257
|
-
indeterminate
|
|
264
|
+
checked: table.getIsAllRowsSelected()
|
|
265
|
+
// indeterminate={table.getIsSomeRowsSelected()}
|
|
266
|
+
,
|
|
267
|
+
indeterminate: table.getIsSomePageRowsSelected(),
|
|
258
268
|
onChange: e => {
|
|
259
|
-
setIsSelectionChange({
|
|
260
|
-
isChange: true,
|
|
261
|
-
type: 'all',
|
|
262
|
-
rowData: {}
|
|
263
|
-
});
|
|
264
269
|
table.getToggleAllRowsSelectedHandler()(e);
|
|
270
|
+
const aa = isSelectionChange?.rowsData ?? [];
|
|
271
|
+
if (table.getIsAllRowsSelected()) {
|
|
272
|
+
const dd = table.getRowModel().flatRows;
|
|
273
|
+
const cc = excludeItems(aa, dd);
|
|
274
|
+
setIsSelectionChange({
|
|
275
|
+
isChange: true,
|
|
276
|
+
type: 'all',
|
|
277
|
+
rowData: {},
|
|
278
|
+
rowsData: cc
|
|
279
|
+
});
|
|
280
|
+
} else {
|
|
281
|
+
aa.concat(table.getRowModel().flatRows);
|
|
282
|
+
const bb = table.getRowModel().flatRows;
|
|
283
|
+
const abc = [...aa, ...bb];
|
|
284
|
+
setIsSelectionChange({
|
|
285
|
+
isChange: true,
|
|
286
|
+
type: 'all',
|
|
287
|
+
rowData: {},
|
|
288
|
+
rowsData: abc
|
|
289
|
+
});
|
|
290
|
+
}
|
|
265
291
|
}
|
|
266
292
|
}), column.id !== 'selection_column' && /*#__PURE__*/React.createElement("span", {
|
|
267
293
|
className: "ui-rc-table-column-title",
|
|
@@ -5,7 +5,6 @@ type RenderFilterProps<RecordType> = {
|
|
|
5
5
|
column: ColumnDef<RecordType, unknown>;
|
|
6
6
|
selectedKeys: any[];
|
|
7
7
|
setSelectedKeys: (keys: any[]) => void;
|
|
8
|
-
confirm?: () => void;
|
|
9
8
|
t?: any;
|
|
10
9
|
locale?: any;
|
|
11
10
|
dataSourceFilter?: {
|
|
@@ -15,6 +14,7 @@ type RenderFilterProps<RecordType> = {
|
|
|
15
14
|
format?: IFormat;
|
|
16
15
|
buddhistLocale?: any;
|
|
17
16
|
dateRangeLocale?: any;
|
|
17
|
+
doFilter?: (type: boolean) => void;
|
|
18
18
|
};
|
|
19
19
|
export declare const renderFilter: <RecordType>(args: RenderFilterProps<RecordType>) => React.JSX.Element;
|
|
20
20
|
export {};
|
|
@@ -15,13 +15,14 @@ export const renderFilter = args => {
|
|
|
15
15
|
column,
|
|
16
16
|
selectedKeys,
|
|
17
17
|
setSelectedKeys,
|
|
18
|
-
confirm,
|
|
18
|
+
// confirm,
|
|
19
19
|
t,
|
|
20
20
|
locale,
|
|
21
21
|
buddhistLocale,
|
|
22
22
|
dateRangeLocale,
|
|
23
23
|
dataSourceFilter,
|
|
24
|
-
format
|
|
24
|
+
format,
|
|
25
|
+
doFilter
|
|
25
26
|
} = args;
|
|
26
27
|
const {
|
|
27
28
|
format: columnFormat,
|
|
@@ -45,7 +46,8 @@ export const renderFilter = args => {
|
|
|
45
46
|
value: selectedKeys[0],
|
|
46
47
|
onChange: vals => {
|
|
47
48
|
setSelectedKeys(vals);
|
|
48
|
-
}
|
|
49
|
+
},
|
|
50
|
+
onPressEnter: () => doFilter?.(true)
|
|
49
51
|
}))));
|
|
50
52
|
case 'NumberRange':
|
|
51
53
|
return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(NumberRange, {
|
|
@@ -54,7 +56,8 @@ export const renderFilter = args => {
|
|
|
54
56
|
max: selectedKeys[1],
|
|
55
57
|
onChange: vals => {
|
|
56
58
|
setSelectedKeys(vals);
|
|
57
|
-
}
|
|
59
|
+
},
|
|
60
|
+
onPressEnter: () => doFilter?.(true)
|
|
58
61
|
})));
|
|
59
62
|
case 'Date':
|
|
60
63
|
const dateValue = selectedKeys[0] ? convertDateToDayjs(new Date(selectedKeys[0]), dateFormat) : null;
|
|
@@ -269,13 +272,18 @@ export const renderFilter = args => {
|
|
|
269
272
|
return /*#__PURE__*/React.createElement(Fragment, null, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
|
|
270
273
|
className: 'mb-1'
|
|
271
274
|
}, /*#__PURE__*/React.createElement(Input, {
|
|
275
|
+
className: "aaaa",
|
|
276
|
+
classNames: {
|
|
277
|
+
input: 'filter-input'
|
|
278
|
+
},
|
|
272
279
|
placeholder: t ? t('Search') : `Search`,
|
|
273
280
|
value: selectedKeys[0],
|
|
274
281
|
onChange: e => setSelectedKeys(e.target.value ? [e.target.value] : [])
|
|
275
282
|
// onPressEnter={() => handleSearch(selectedKeys as string[], confirm)}
|
|
276
283
|
,
|
|
277
|
-
onPressEnter: () =>
|
|
284
|
+
onPressEnter: () => doFilter?.(true),
|
|
278
285
|
allowClear: true
|
|
286
|
+
// autoFocus={true}
|
|
279
287
|
}))));
|
|
280
288
|
}
|
|
281
289
|
};
|
|
@@ -213,16 +213,16 @@ export const optionFontSize = [{
|
|
|
213
213
|
label: '48'
|
|
214
214
|
}];
|
|
215
215
|
|
|
216
|
-
/**
|
|
217
|
-
* Sort order for BaseTable
|
|
216
|
+
/**
|
|
217
|
+
* Sort order for BaseTable
|
|
218
218
|
*/
|
|
219
219
|
const SortOrder = {
|
|
220
|
-
/**
|
|
221
|
-
* Sort data in ascending order
|
|
220
|
+
/**
|
|
221
|
+
* Sort data in ascending order
|
|
222
222
|
*/
|
|
223
223
|
ascend: 'Ascending',
|
|
224
|
-
/**
|
|
225
|
-
* Sort data in descending order
|
|
224
|
+
/**
|
|
225
|
+
* Sort data in descending order
|
|
226
226
|
*/
|
|
227
227
|
descend: 'Descending'
|
|
228
228
|
};
|
|
@@ -96,7 +96,7 @@ export function convertToTanStackColumns({
|
|
|
96
96
|
allowResizing,
|
|
97
97
|
minWidth,
|
|
98
98
|
template,
|
|
99
|
-
|
|
99
|
+
allowSortering,
|
|
100
100
|
allowFiltering
|
|
101
101
|
} = col;
|
|
102
102
|
const {
|
|
@@ -149,7 +149,7 @@ export function convertToTanStackColumns({
|
|
|
149
149
|
sortDescFirst: false,
|
|
150
150
|
minSize: minWidth,
|
|
151
151
|
// maxSize: maxWidth,
|
|
152
|
-
enableSorting:
|
|
152
|
+
enableSorting: allowSortering !== false || col.sorter !== false,
|
|
153
153
|
// enableColumnFilter: allowFiltering !== false && !nonActionColumn.includes(field)
|
|
154
154
|
enableColumnFilter: allowFiltering !== false
|
|
155
155
|
};
|
|
@@ -141,3 +141,10 @@ export declare function isTreeArray(arr: any[], options?: any): boolean;
|
|
|
141
141
|
export declare function updateColumnWidthsRecursive(columns: any[], sizing: Record<string, number>): any[];
|
|
142
142
|
export declare function updateWidthsByOther(source: any[], target: any[]): any[];
|
|
143
143
|
export declare function findAllChildrenKeys2<RecordType>(data: readonly RecordType[], rowKey: any, childrenColumnName: string): Key[];
|
|
144
|
+
export declare function parseExcelText(text: string): string[][];
|
|
145
|
+
export declare function parseExcelClipboard(e: React.ClipboardEvent): string[][];
|
|
146
|
+
export declare function parseExcelClipboardText(text: string): string[][];
|
|
147
|
+
export declare function parseClipboardEvent(e: ClipboardEvent | React.ClipboardEvent): string[][];
|
|
148
|
+
export declare function arraysEqualIgnoreOrderFast(a: any[], b: any[]): boolean;
|
|
149
|
+
export declare function filterByIds(a: any[], b: any[]): any[];
|
|
150
|
+
export declare function excludeItems(arrayA: any[], arrayB: any[]): any[];
|
|
@@ -2038,4 +2038,137 @@ export function findAllChildrenKeys2(data, rowKey, childrenColumnName) {
|
|
|
2038
2038
|
}
|
|
2039
2039
|
dig(data);
|
|
2040
2040
|
return keys;
|
|
2041
|
+
}
|
|
2042
|
+
export function parseExcelText(text) {
|
|
2043
|
+
// const text = e.clipboardData?.getData('text/plain') ?? '';
|
|
2044
|
+
if (!text) return [];
|
|
2045
|
+
|
|
2046
|
+
// Excel thường dùng \r\n giữa dòng, \t giữa cột
|
|
2047
|
+
const rows = text.split(/\r?\n/) // tách theo dòng
|
|
2048
|
+
.filter(r => r.trim() !== '') // bỏ dòng trống
|
|
2049
|
+
.map(row => row.split('\t') // tách theo cột
|
|
2050
|
+
.map(cell => cell.replace(/\r/g, '').replace(/\n/g, '\n')) // giữ xuống dòng trong ô
|
|
2051
|
+
);
|
|
2052
|
+
return rows;
|
|
2053
|
+
}
|
|
2054
|
+
export function parseExcelClipboard(e) {
|
|
2055
|
+
const text = e.clipboardData?.getData('text/plain') ?? '';
|
|
2056
|
+
if (!text) return [];
|
|
2057
|
+
|
|
2058
|
+
// Excel thường dùng \r\n giữa dòng, \t giữa cột
|
|
2059
|
+
const rows = text.split(/\r?\n/) // tách theo dòng
|
|
2060
|
+
.filter(r => r.trim() !== '') // bỏ dòng trống
|
|
2061
|
+
.map(row => row.split('\t') // tách theo cột
|
|
2062
|
+
.map(cell => cell.replace(/\r/g, '').replace(/\n/g, '\n')) // giữ xuống dòng trong ô
|
|
2063
|
+
);
|
|
2064
|
+
return rows;
|
|
2065
|
+
}
|
|
2066
|
+
export function parseExcelClipboardText(text) {
|
|
2067
|
+
const rows = [];
|
|
2068
|
+
let curRow = [];
|
|
2069
|
+
let curCell = '';
|
|
2070
|
+
let inQuotes = false;
|
|
2071
|
+
for (let i = 0; i < text.length; i++) {
|
|
2072
|
+
const ch = text[i];
|
|
2073
|
+
if (ch === '"') {
|
|
2074
|
+
// "" -> an escaped quote inside quoted field
|
|
2075
|
+
if (inQuotes && text[i + 1] === '"') {
|
|
2076
|
+
curCell += '"';
|
|
2077
|
+
i++; // skip next
|
|
2078
|
+
} else {
|
|
2079
|
+
inQuotes = !inQuotes; // open/close quote
|
|
2080
|
+
}
|
|
2081
|
+
continue;
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
// tab as column separator (only if not inside quotes)
|
|
2085
|
+
if (ch === '\t' && !inQuotes) {
|
|
2086
|
+
curRow.push(curCell);
|
|
2087
|
+
curCell = '';
|
|
2088
|
+
continue;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// newline as row separator (handle \r\n and lone \r or \n), only outside quotes
|
|
2092
|
+
if ((ch === '\r' || ch === '\n') && !inQuotes) {
|
|
2093
|
+
// handle CRLF
|
|
2094
|
+
if (ch === '\r' && text[i + 1] === '\n') i++;
|
|
2095
|
+
curRow.push(curCell);
|
|
2096
|
+
curCell = '';
|
|
2097
|
+
rows.push(curRow);
|
|
2098
|
+
curRow = [];
|
|
2099
|
+
continue;
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
// normal character
|
|
2103
|
+
curCell += ch;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// push last cell/row (if any)
|
|
2107
|
+
// avoid adding one spurious empty row when text ends with newline (we already pushed that row)
|
|
2108
|
+
if (curCell !== '' || curRow.length > 0) {
|
|
2109
|
+
curRow.push(curCell);
|
|
2110
|
+
rows.push(curRow);
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// if the whole input was empty, return []
|
|
2114
|
+
if (rows.length === 1 && rows[0].length === 1 && rows[0][0] === '' && text.trim() === '') {
|
|
2115
|
+
return [];
|
|
2116
|
+
}
|
|
2117
|
+
return rows;
|
|
2118
|
+
}
|
|
2119
|
+
export function parseClipboardEvent(e) {
|
|
2120
|
+
const dataTransfer = e.clipboardData ?? e.nativeEvent?.clipboardData;
|
|
2121
|
+
if (!dataTransfer) return [];
|
|
2122
|
+
|
|
2123
|
+
// 1) try HTML (better fidelity for Excel)
|
|
2124
|
+
const html = dataTransfer.getData?.('text/html');
|
|
2125
|
+
if (html) {
|
|
2126
|
+
try {
|
|
2127
|
+
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
2128
|
+
const table = doc.querySelector('table');
|
|
2129
|
+
if (table) {
|
|
2130
|
+
const result = [];
|
|
2131
|
+
for (const tr of Array.from(table.rows)) {
|
|
2132
|
+
const row = [];
|
|
2133
|
+
for (const cell of Array.from(tr.cells)) {
|
|
2134
|
+
// innerText preserves newlines from <br>
|
|
2135
|
+
row.push(cell.innerText ?? '');
|
|
2136
|
+
}
|
|
2137
|
+
result.push(row);
|
|
2138
|
+
}
|
|
2139
|
+
if (result.length) return result;
|
|
2140
|
+
}
|
|
2141
|
+
} catch {
|
|
2142
|
+
// fallback to text parsing
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
// 2) fallback: parse plain text (TSV with quoted fields)
|
|
2147
|
+
const text = dataTransfer.getData?.('text/plain') ?? '';
|
|
2148
|
+
return parseExcelClipboardText(text);
|
|
2149
|
+
}
|
|
2150
|
+
export function arraysEqualIgnoreOrderFast(a, b) {
|
|
2151
|
+
if (a.length !== b.length) return false;
|
|
2152
|
+
const count = Object.create(null);
|
|
2153
|
+
for (let i = 0; i < a.length; i++) {
|
|
2154
|
+
const key = a[i];
|
|
2155
|
+
count[key] = (count[key] || 0) + 1;
|
|
2156
|
+
}
|
|
2157
|
+
for (let i = 0; i < b.length; i++) {
|
|
2158
|
+
const key = b[i];
|
|
2159
|
+
if (!count[key]) return false;
|
|
2160
|
+
count[key]--;
|
|
2161
|
+
if (count[key] === 0) delete count[key];
|
|
2162
|
+
}
|
|
2163
|
+
return Object.keys(count).length === 0;
|
|
2164
|
+
}
|
|
2165
|
+
export function filterByIds(a, b) {
|
|
2166
|
+
const idSet = new Set(a);
|
|
2167
|
+
return b.filter(item => idSet.has(item.id));
|
|
2168
|
+
}
|
|
2169
|
+
export function excludeItems(arrayA, arrayB) {
|
|
2170
|
+
const idsInB = new Set(arrayB.map(item => item.id));
|
|
2171
|
+
|
|
2172
|
+
// Lọc A, chỉ giữ lại phần tử không có trong B
|
|
2173
|
+
return arrayA.filter(item => !idsInB.has(item.id));
|
|
2041
2174
|
}
|