devextreme-planit-treegrid-react 0.1.5 → 0.1.6
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/dist/DxPlanitTreeGrid.tsx +580 -0
- package/dist/index.tsx +3 -0
- package/dist/type.ts +32 -0
- package/package.json +2 -2
@@ -0,0 +1,580 @@
|
|
1
|
+
import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
2
|
+
|
3
|
+
import { LoadPanel } from 'devextreme-react/load-panel';
|
4
|
+
|
5
|
+
import PivotGrid, { FieldChooser } from 'devextreme-react/pivot-grid';
|
6
|
+
import { StateStoring } from 'devextreme-react/data-grid';
|
7
|
+
import DevExpress from 'devextreme';
|
8
|
+
import { ColumnField, IColorInfo, IGroupField, Props } from './type';
|
9
|
+
import { exportPivotGrid } from 'devextreme/excel_exporter';
|
10
|
+
import { Workbook } from 'exceljs';
|
11
|
+
import saveAs from 'file-saver';
|
12
|
+
import PivotGridDataSource from 'devextreme/ui/pivot_grid/data_source';
|
13
|
+
|
14
|
+
/**
|
15
|
+
* devextreme pivotgrid Configrations 중 사용 불가 항목 : id, width, height, showColumnGrandTotals, showColumnTotals, showRowGrandTotals, FieldChooser
|
16
|
+
* devextreme pivotgrid Configrations 중 사용 방법 변경 항목 : stateStoring, Export
|
17
|
+
* onExported, onFileSaving 이벤트 사용하지 않음.
|
18
|
+
*/
|
19
|
+
/**
|
20
|
+
* todoList:
|
21
|
+
* 2) columIndex 초기화 기능이 있어야 함(column 개수 변할 때)
|
22
|
+
* 3) 헤더에 테이블 삽입되면서 그리드 크기가 늘어남. height에 그리드 크기 늘어난 만큼 반영되어야 함.
|
23
|
+
*/
|
24
|
+
|
25
|
+
const grandTotalCssNm = 'data-grand-total';
|
26
|
+
|
27
|
+
const DxPlanitTreeGrid = forwardRef(
|
28
|
+
(props: Props, ref: any): JSX.Element => {
|
29
|
+
const {
|
30
|
+
id = 'dx-planit-vera-pivotgrid-id',
|
31
|
+
groupField,
|
32
|
+
dataColor,
|
33
|
+
convertNullToHipen = true,
|
34
|
+
convertZeroToHipen = true,
|
35
|
+
stateStoringKey = '',
|
36
|
+
allowExpandAll = false,
|
37
|
+
allowFiltering = false,
|
38
|
+
allowSorting = false,
|
39
|
+
allowSortingBySummary = false,
|
40
|
+
dataFieldArea = 'column',
|
41
|
+
dataSource,
|
42
|
+
disabled = false,
|
43
|
+
elementAttr,
|
44
|
+
encodeHtml,
|
45
|
+
hideEmptySummaryCells = false,
|
46
|
+
hint,
|
47
|
+
rowHeaderLayout = 'standard',
|
48
|
+
rtlEnabled = false,
|
49
|
+
showBorders = true,
|
50
|
+
showRowTotals = true,
|
51
|
+
showTotalsPrior = 'none',
|
52
|
+
tabIndex = 0,
|
53
|
+
visible = true,
|
54
|
+
wordWrapEnabled = false,
|
55
|
+
customExcelButton = false,
|
56
|
+
onCellClick,
|
57
|
+
onCellPrepared,
|
58
|
+
onContentReady,
|
59
|
+
onContextMenuPreparing,
|
60
|
+
onDisposing,
|
61
|
+
onExporting,
|
62
|
+
onInitialized,
|
63
|
+
onOptionChanged,
|
64
|
+
} = props;
|
65
|
+
|
66
|
+
const [width, setWidth] = useState(0);
|
67
|
+
const [height, setHeight] = useState(0);
|
68
|
+
const [columnIndex, setColumnIndex] = useState(0);
|
69
|
+
const [gridDataSource, setGridDataSource] = useState<PivotGridDataSource>(dataSource);
|
70
|
+
|
71
|
+
const $tableRef = useRef<PivotGrid>(null);
|
72
|
+
const excelBorder = { style: 'thin', color: { argb: 'FF7E7E7E' } };
|
73
|
+
|
74
|
+
useImperativeHandle(ref, () => ({
|
75
|
+
exportToExcel,
|
76
|
+
}));
|
77
|
+
|
78
|
+
/**
|
79
|
+
* 그리드 사이즈 재조정
|
80
|
+
* @returns 그리드 사이즈
|
81
|
+
*/
|
82
|
+
const getGridSize = (): { width: number; height: number } => {
|
83
|
+
const wrapper = document.querySelector('.diag-table-wrapper');
|
84
|
+
const gap = 10;
|
85
|
+
setWidth(wrapper?.clientWidth ?? 0);
|
86
|
+
setHeight(wrapper ? wrapper.clientHeight - gap : 0);
|
87
|
+
|
88
|
+
window.addEventListener('resize', () => {
|
89
|
+
setWidth(wrapper?.clientWidth ?? 0);
|
90
|
+
setHeight(wrapper ? wrapper.clientHeight - gap : 0);
|
91
|
+
});
|
92
|
+
return { width, height };
|
93
|
+
};
|
94
|
+
|
95
|
+
/**
|
96
|
+
* 'Total' 을 한글로 변경
|
97
|
+
* @param e devextreme CellPreparedEvent
|
98
|
+
*/
|
99
|
+
const changeTotalText = (e: DevExpress.ui.dxPivotGrid.CellPreparedEvent): void => {
|
100
|
+
if (!e.cellElement) {
|
101
|
+
return;
|
102
|
+
}
|
103
|
+
if (e.cell?.type === 'T') {
|
104
|
+
const text = e.cell.text?.replace('Total', '합계');
|
105
|
+
e.cellElement.innerHTML = `<span>${text}</span>`;
|
106
|
+
}
|
107
|
+
};
|
108
|
+
|
109
|
+
/**
|
110
|
+
* null값을 하이픈으로 모두 변경
|
111
|
+
* @param e devextreme CellPreparedEvent
|
112
|
+
*/
|
113
|
+
const changeNullToHipen = (e: DevExpress.ui.dxPivotGrid.CellPreparedEvent): void => {
|
114
|
+
if (!convertNullToHipen) {
|
115
|
+
return;
|
116
|
+
}
|
117
|
+
if (e.area === 'data' && e.cell?.text === null && e.cellElement) {
|
118
|
+
e.cellElement.innerHTML = '<span class="text-color">-</span>';
|
119
|
+
}
|
120
|
+
};
|
121
|
+
|
122
|
+
/**
|
123
|
+
* '0', '0.0%' 를 하이픈으로 모두 변경
|
124
|
+
* @param e devextreme CellPreparedEvent
|
125
|
+
*/
|
126
|
+
const changeZeroToHipen = (e: DevExpress.ui.dxPivotGrid.CellPreparedEvent): void => {
|
127
|
+
if (!convertZeroToHipen) {
|
128
|
+
return;
|
129
|
+
}
|
130
|
+
if (e.area === 'data' && (e.cell?.text === '0' || e.cell?.text === '0.0%' || e.cell?.text === '') && e.cellElement) {
|
131
|
+
e.cellElement.innerHTML = '<span class="text-color">-</span>';
|
132
|
+
}
|
133
|
+
};
|
134
|
+
|
135
|
+
/**
|
136
|
+
* 테이블 헤더에 colspan, rowspan 한 HTMLElement 정보 반환
|
137
|
+
* @param groupField 사용자가 작성한 그룹 정보
|
138
|
+
* @return
|
139
|
+
*/
|
140
|
+
const makeColspan = (group: IGroupField, index: number, isLast: boolean): HTMLElement => {
|
141
|
+
const td = document.createElement('td');
|
142
|
+
let text = group.groupCaption;
|
143
|
+
|
144
|
+
if (group.depth === 1) {
|
145
|
+
text = `${group.groupCaption}`;
|
146
|
+
}
|
147
|
+
|
148
|
+
td.setAttribute('colspan', group.colspan.toString());
|
149
|
+
td.setAttribute('class', 'dx-row-total dx-grand-total dx-planit-colspan');
|
150
|
+
|
151
|
+
if (isLast && index === 0) {
|
152
|
+
td.setAttribute('style', 'border-bottom: 0; border-right: 0');
|
153
|
+
} else if (isLast && index !== 0) {
|
154
|
+
td.setAttribute('style', 'border-right: 0');
|
155
|
+
} else if (!isLast && index === 0) {
|
156
|
+
td.setAttribute('style', 'border-bottom: 0');
|
157
|
+
}
|
158
|
+
td.innerHTML = `<div>${text}</div>`;
|
159
|
+
|
160
|
+
return td;
|
161
|
+
};
|
162
|
+
|
163
|
+
/**
|
164
|
+
* 그룹 필드 데이터 유효성 검증용 데이터 생성
|
165
|
+
* @param groupField
|
166
|
+
* @returns
|
167
|
+
*/
|
168
|
+
const makeCheckGroupData = (groupField: IGroupField[]): any => {
|
169
|
+
const data: any = {};
|
170
|
+
|
171
|
+
groupField?.forEach((group: IGroupField) => {
|
172
|
+
if (data[group.depth]) {
|
173
|
+
data[group.depth] += group.colspan;
|
174
|
+
} else {
|
175
|
+
data[group.depth] = group.colspan;
|
176
|
+
}
|
177
|
+
});
|
178
|
+
|
179
|
+
return data;
|
180
|
+
};
|
181
|
+
|
182
|
+
/**
|
183
|
+
* GroupField 데이터 검증
|
184
|
+
* @param 사용자가 설정한 그룹 필드 정보
|
185
|
+
* @returns 데이터 검증 결과
|
186
|
+
*/
|
187
|
+
const isCheckGroupField = (groupField: IGroupField[]): boolean => {
|
188
|
+
const map = makeCheckGroupData(groupField);
|
189
|
+
|
190
|
+
for (const depth of Object.keys(map)) {
|
191
|
+
if (map[depth] !== columnIndex + 1) {
|
192
|
+
console.error('그룹 데이터의 children 숫자가 columnIndex와 맞지 않습니다. 다시 한 번 확인 바랍니다.');
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
return true;
|
197
|
+
};
|
198
|
+
|
199
|
+
/**
|
200
|
+
* Grand Total 셀 정보 저장
|
201
|
+
* @param e
|
202
|
+
*/
|
203
|
+
const setTotalElementInfo = (e: DevExpress.ui.dxPivotGrid.CellPreparedEvent): void => {
|
204
|
+
if (!groupField?.length || e.cell?.type !== 'GT' || e.cell?.text !== 'Grand Total') {
|
205
|
+
return;
|
206
|
+
}
|
207
|
+
|
208
|
+
e.cellElement?.classList.add(grandTotalCssNm);
|
209
|
+
};
|
210
|
+
|
211
|
+
/**
|
212
|
+
* cell의 columnIndex 최대값 저장
|
213
|
+
* @param e
|
214
|
+
*/
|
215
|
+
const setMaxColumIndex = (e: DevExpress.ui.dxPivotGrid.CellPreparedEvent): void => {
|
216
|
+
if (!e.columnIndex) {
|
217
|
+
return;
|
218
|
+
}
|
219
|
+
if (e.columnIndex > columnIndex) {
|
220
|
+
setColumnIndex(e.columnIndex);
|
221
|
+
}
|
222
|
+
};
|
223
|
+
|
224
|
+
/**
|
225
|
+
* groupField depth의 유니크한 배열 구하기
|
226
|
+
* @param group
|
227
|
+
* @param arr
|
228
|
+
* @returns
|
229
|
+
*/
|
230
|
+
const getGroupDepth = (group: IGroupField[], arr: 'asc' | 'desc'): number[] => {
|
231
|
+
const groupData = group.slice();
|
232
|
+
const set = new Set(groupData.map((group: IGroupField) => group.depth));
|
233
|
+
return Array.from(set).sort(function compare(a: number, b: number) {
|
234
|
+
if (a > b) {
|
235
|
+
return arr === 'asc' ? -1 : 1;
|
236
|
+
}
|
237
|
+
if (a < b) {
|
238
|
+
return arr === 'asc' ? 1 : -1;
|
239
|
+
}
|
240
|
+
return 0;
|
241
|
+
});
|
242
|
+
};
|
243
|
+
|
244
|
+
/**
|
245
|
+
* 현재 depth에 맞는 그룹 필드 정보 반환
|
246
|
+
* @param group
|
247
|
+
* @param depth
|
248
|
+
* @returns
|
249
|
+
*/
|
250
|
+
const getCurrentGroup = (group: IGroupField[], depth: number): IGroupField[] => {
|
251
|
+
return group.filter((gr: IGroupField) => gr.depth === depth);
|
252
|
+
};
|
253
|
+
|
254
|
+
/**
|
255
|
+
* 테이블 헤더(DOM)에 colspan 적용된 테이블 삽입
|
256
|
+
*/
|
257
|
+
const insertRowHeaderGroup = (): void => {
|
258
|
+
if (!groupField?.length) {
|
259
|
+
return;
|
260
|
+
}
|
261
|
+
|
262
|
+
isCheckGroupField(groupField);
|
263
|
+
|
264
|
+
const totalElement = document.querySelector('.' + grandTotalCssNm);
|
265
|
+
const targetElement = totalElement?.parentNode;
|
266
|
+
const thead = targetElement?.parentNode;
|
267
|
+
|
268
|
+
if (!targetElement || !thead) {
|
269
|
+
return;
|
270
|
+
}
|
271
|
+
|
272
|
+
const firstChild = thead?.firstChild;
|
273
|
+
if (!firstChild) {
|
274
|
+
return;
|
275
|
+
}
|
276
|
+
totalElement.innerHTML = '';
|
277
|
+
totalElement.setAttribute('style', 'padding: 0; border: 0');
|
278
|
+
const colgroup = thead.previousSibling?.cloneNode(true);
|
279
|
+
|
280
|
+
const groupData = groupField.slice();
|
281
|
+
const depth = getGroupDepth(groupData, 'asc');
|
282
|
+
|
283
|
+
const table = document.createElement('table');
|
284
|
+
|
285
|
+
depth.forEach((dep: number, index: number) => {
|
286
|
+
const groupInfo = getCurrentGroup(groupData, dep);
|
287
|
+
|
288
|
+
const tr = document.createElement('tr');
|
289
|
+
|
290
|
+
groupInfo.forEach((group: IGroupField, cellIndex: number) => {
|
291
|
+
const isLast = cellIndex === groupInfo.length - 1 ? true : false;
|
292
|
+
tr.appendChild(makeColspan(group, index, isLast));
|
293
|
+
});
|
294
|
+
(table as HTMLElement).prepend(tr);
|
295
|
+
});
|
296
|
+
|
297
|
+
table.prepend(colgroup as Node);
|
298
|
+
totalElement.appendChild(table);
|
299
|
+
};
|
300
|
+
|
301
|
+
/**
|
302
|
+
* Devextreme의 dateController columnInfo에 그룹 정보 삽입
|
303
|
+
* @param group
|
304
|
+
* @returns
|
305
|
+
*/
|
306
|
+
const makeDataControllerColumnGroup = (group: IGroupField[]): ColumnField[][] => {
|
307
|
+
const groupData = group.slice();
|
308
|
+
const depth = getGroupDepth(groupData, 'desc');
|
309
|
+
|
310
|
+
return depth.map((dep: number) => {
|
311
|
+
const groupInfo = getCurrentGroup(groupData, dep);
|
312
|
+
return groupInfo.map((group: IGroupField) => ({ colspan: group.colspan, text: group.groupCaption, type: 'GT' }));
|
313
|
+
});
|
314
|
+
};
|
315
|
+
|
316
|
+
/**
|
317
|
+
* 사용자가 입력한 컬러 조건을 { standard: string; condition: string } 형식으로 변경 반환
|
318
|
+
* @param condition 사용자 입력 컬러 조건식 ex) '>= 100'
|
319
|
+
* @returns
|
320
|
+
*/
|
321
|
+
const makeSplitCondtion = (condition: string): { standard: string; condition: string } => {
|
322
|
+
const newCondition = { standard: '', condition: '' };
|
323
|
+
[...condition].forEach((cond: string) => {
|
324
|
+
if (Number.isNaN(parseFloat(cond))) {
|
325
|
+
newCondition.condition += cond;
|
326
|
+
} else {
|
327
|
+
newCondition.standard += cond;
|
328
|
+
}
|
329
|
+
});
|
330
|
+
|
331
|
+
return newCondition;
|
332
|
+
};
|
333
|
+
|
334
|
+
/**
|
335
|
+
* 데이터에 색상 적용
|
336
|
+
* @param e onCellPrepared 이벤트
|
337
|
+
* @returns
|
338
|
+
*/
|
339
|
+
const makeColorAtPercent = (e: any): void => {
|
340
|
+
if (!dataColor || !e.cellElement) {
|
341
|
+
return;
|
342
|
+
}
|
343
|
+
|
344
|
+
dataColor.forEach((color: IColorInfo) => {
|
345
|
+
if (e.cell.value === null) {
|
346
|
+
return;
|
347
|
+
}
|
348
|
+
if (e.cell?.format?.type === color.format && !Number.isNaN(e.cell.value)) {
|
349
|
+
const standardData = makeSplitCondtion(color.condition.replace(/(\s*)/g, ''));
|
350
|
+
const rate = color.format === 'percent' ? 0.01 : 1;
|
351
|
+
let condition = false;
|
352
|
+
|
353
|
+
switch (standardData.condition) {
|
354
|
+
case '>':
|
355
|
+
condition = e.cell.value > parseFloat(standardData.standard) * rate;
|
356
|
+
break;
|
357
|
+
case '>=':
|
358
|
+
condition = e.cell.value >= parseFloat(standardData.standard) * rate;
|
359
|
+
break;
|
360
|
+
case '<':
|
361
|
+
condition = e.cell.value < parseFloat(standardData.standard) * rate;
|
362
|
+
break;
|
363
|
+
case '<=':
|
364
|
+
condition = e.cell.value <= parseFloat(standardData.standard) * rate;
|
365
|
+
break;
|
366
|
+
}
|
367
|
+
|
368
|
+
if (condition && !(e.cell.value === 0 && convertZeroToHipen)) {
|
369
|
+
e.cellElement.style.color = color.color;
|
370
|
+
}
|
371
|
+
}
|
372
|
+
});
|
373
|
+
};
|
374
|
+
|
375
|
+
/**
|
376
|
+
* 그리드 데이터 정합성 체크. 데이터 잘못되어 있으면 에러 발생
|
377
|
+
* @param dataSource
|
378
|
+
*/
|
379
|
+
const checkDataSource = (dataSource: any): void => {
|
380
|
+
const isColumns = dataSource._fields.findIndex((field: any) => field.area === 'column');
|
381
|
+
const isRows = dataSource._fields.findIndex((field: any) => field.area === 'row');
|
382
|
+
const isDatas = dataSource._fields.findIndex((field: any) => field.area === 'data');
|
383
|
+
|
384
|
+
if (isColumns > -1) {
|
385
|
+
throw Error('DxPlanitTreeGrid는 column이 존재하는 형식의 pivot grid에는 사용할 수 없습니다.');
|
386
|
+
}
|
387
|
+
|
388
|
+
if (isRows === -1 || isDatas === -1) {
|
389
|
+
throw Error('DxPlanitTreeGrid 데이터는 row와 data가 반드시 존재해야 합니다.');
|
390
|
+
}
|
391
|
+
};
|
392
|
+
|
393
|
+
/**
|
394
|
+
* 그리드 펼침 정보 세션스토리지 리셋
|
395
|
+
*/
|
396
|
+
const resetSession = (): void => {
|
397
|
+
sessionStorage.removeItem('dx-vera-pivotgrid-storing');
|
398
|
+
};
|
399
|
+
|
400
|
+
/**
|
401
|
+
* 엑셀 export 명령
|
402
|
+
* @param fileName 저장하고자 하는 엑셀파일명
|
403
|
+
*/
|
404
|
+
const exportToExcel = (fileName: string): void => {
|
405
|
+
setTimeout(() => exportToExcelAction($tableRef.current?.instance, fileName));
|
406
|
+
};
|
407
|
+
|
408
|
+
/**
|
409
|
+
* devextreme component 정보의 dataController의 columnInfo에 사용자가 설정한 groupFIled 정보 병합
|
410
|
+
* @param component devextreme component
|
411
|
+
* @returns devextreme component
|
412
|
+
*/
|
413
|
+
const convertDataControllerColumnsInfo = (component: any): any => {
|
414
|
+
let arr: ColumnField[][] = [];
|
415
|
+
const columnInfo = component._dataController._columnsInfo.forEach((column: ColumnField[]) => {
|
416
|
+
let newColumn = column.slice();
|
417
|
+
if (groupField && newColumn.length === 1 && newColumn[0].type === 'GT' && newColumn[0].text === 'Grand Total') {
|
418
|
+
arr.push(...makeDataControllerColumnGroup(groupField));
|
419
|
+
} else {
|
420
|
+
arr.push(newColumn);
|
421
|
+
}
|
422
|
+
});
|
423
|
+
component._dataController._columnsInfo = arr;
|
424
|
+
return component;
|
425
|
+
};
|
426
|
+
|
427
|
+
/**
|
428
|
+
* 엑셀 export
|
429
|
+
* @param e
|
430
|
+
*/
|
431
|
+
const exportToExcelAction = (e: any, fileName: string): void => {
|
432
|
+
const newComponent = convertDataControllerColumnsInfo(e);
|
433
|
+
|
434
|
+
const workbook = new Workbook();
|
435
|
+
const worksheet = workbook.addWorksheet(fileName);
|
436
|
+
|
437
|
+
exportPivotGrid({
|
438
|
+
component: newComponent,
|
439
|
+
worksheet,
|
440
|
+
customizeCell: ({ excelCell }) => {
|
441
|
+
const borderStyle = excelBorder;
|
442
|
+
excelCell.border = {
|
443
|
+
bottom: borderStyle,
|
444
|
+
left: borderStyle,
|
445
|
+
right: borderStyle,
|
446
|
+
top: borderStyle,
|
447
|
+
};
|
448
|
+
},
|
449
|
+
}).then(() => {
|
450
|
+
workbook.xlsx.writeBuffer().then(buffer => {
|
451
|
+
saveAs(new Blob([buffer], { type: 'application/octet-stream' }), fileName + '.xlsx');
|
452
|
+
});
|
453
|
+
});
|
454
|
+
e.cancel = true;
|
455
|
+
};
|
456
|
+
|
457
|
+
/**
|
458
|
+
* devextreme CellPreparedEvent 이벤트 실행
|
459
|
+
* @param e
|
460
|
+
*/
|
461
|
+
const onCellPreparedChild = (
|
462
|
+
e: DevExpress.ui.dxPivotGrid.CellPreparedEvent
|
463
|
+
): ((e: DevExpress.ui.dxPivotGrid.CellPreparedEvent) => void) | void => {
|
464
|
+
makeColorAtPercent(e);
|
465
|
+
setTotalElementInfo(e);
|
466
|
+
setMaxColumIndex(e);
|
467
|
+
changeTotalText(e);
|
468
|
+
changeNullToHipen(e);
|
469
|
+
changeZeroToHipen(e);
|
470
|
+
|
471
|
+
return onCellPrepared ? onCellPrepared(e) : undefined;
|
472
|
+
};
|
473
|
+
|
474
|
+
/**
|
475
|
+
* devextreme Raise Event
|
476
|
+
*/
|
477
|
+
const onContentReadyChild = (
|
478
|
+
e: DevExpress.ui.dxPivotGrid.ContentReadyEvent
|
479
|
+
): ((e: DevExpress.ui.dxPivotGrid.ContentReadyEvent) => void) | void => {
|
480
|
+
setTimeout(() => insertRowHeaderGroup(), 0);
|
481
|
+
getGridSize();
|
482
|
+
|
483
|
+
return onContentReady ? onContentReady(e) : undefined;
|
484
|
+
};
|
485
|
+
|
486
|
+
const onCellClickChild = (
|
487
|
+
e: DevExpress.ui.dxPivotGrid.CellClickEvent
|
488
|
+
): ((e: DevExpress.ui.dxPivotGrid.CellClickEvent) => void) | void => {
|
489
|
+
return onCellClick ? onCellClick(e) : undefined;
|
490
|
+
};
|
491
|
+
|
492
|
+
const onContextMenuPreparingChild = (
|
493
|
+
e: DevExpress.ui.dxPivotGrid.ContextMenuPreparingEvent
|
494
|
+
): ((e: DevExpress.ui.dxPivotGrid.ContextMenuPreparingEvent) => void) | void => {
|
495
|
+
return onContextMenuPreparing ? onContextMenuPreparing(e) : undefined;
|
496
|
+
};
|
497
|
+
|
498
|
+
const onDisposingChild = (
|
499
|
+
e: DevExpress.ui.dxPivotGrid.DisposingEvent
|
500
|
+
): ((e: DevExpress.ui.dxPivotGrid.DisposingEvent) => void) | void => {
|
501
|
+
return onDisposing ? onDisposing(e) : undefined;
|
502
|
+
};
|
503
|
+
|
504
|
+
const onExportingChild = (
|
505
|
+
e: DevExpress.ui.dxPivotGrid.ExportingEvent
|
506
|
+
): ((e: DevExpress.ui.dxPivotGrid.ExportingEvent) => void) | void => {
|
507
|
+
return onExporting ? onExporting(e) : undefined;
|
508
|
+
};
|
509
|
+
|
510
|
+
const onInitializedChild = (
|
511
|
+
e: DevExpress.ui.dxPivotGrid.InitializedEvent
|
512
|
+
): ((e: DevExpress.ui.dxPivotGrid.InitializedEvent) => void) | void => {
|
513
|
+
return onInitialized ? onInitialized(e) : undefined;
|
514
|
+
};
|
515
|
+
|
516
|
+
const onOptionChangedChild = (
|
517
|
+
e: DevExpress.ui.dxPivotGrid.OptionChangedEvent
|
518
|
+
): ((e: DevExpress.ui.dxPivotGrid.OptionChangedEvent) => void) | void => {
|
519
|
+
return onOptionChanged ? onOptionChanged(e) : undefined;
|
520
|
+
};
|
521
|
+
|
522
|
+
useEffect(() => {
|
523
|
+
if (customExcelButton) {
|
524
|
+
}
|
525
|
+
}, [customExcelButton]);
|
526
|
+
|
527
|
+
useEffect(() => {
|
528
|
+
setGridDataSource(dataSource);
|
529
|
+
checkDataSource(dataSource);
|
530
|
+
resetSession();
|
531
|
+
}, [dataSource]);
|
532
|
+
|
533
|
+
return (
|
534
|
+
<div>
|
535
|
+
<LoadPanel position={{ of: id }} />
|
536
|
+
<PivotGrid
|
537
|
+
id={id}
|
538
|
+
ref={$tableRef}
|
539
|
+
dataSource={gridDataSource}
|
540
|
+
showColumnTotals={false}
|
541
|
+
showColumnGrandTotals={true}
|
542
|
+
showRowGrandTotals={false}
|
543
|
+
width={width}
|
544
|
+
height={height}
|
545
|
+
allowExpandAll={allowExpandAll}
|
546
|
+
allowFiltering={allowFiltering}
|
547
|
+
allowSorting={allowSorting}
|
548
|
+
allowSortingBySummary={allowSortingBySummary}
|
549
|
+
dataFieldArea={dataFieldArea}
|
550
|
+
disabled={disabled}
|
551
|
+
elementAttr={elementAttr}
|
552
|
+
encodeHtml={encodeHtml}
|
553
|
+
hideEmptySummaryCells={hideEmptySummaryCells}
|
554
|
+
hint={hint}
|
555
|
+
rowHeaderLayout={rowHeaderLayout}
|
556
|
+
rtlEnabled={rtlEnabled}
|
557
|
+
showBorders={showBorders}
|
558
|
+
showRowTotals={showRowTotals}
|
559
|
+
showTotalsPrior={showTotalsPrior}
|
560
|
+
tabIndex={tabIndex}
|
561
|
+
visible={visible}
|
562
|
+
wordWrapEnabled={wordWrapEnabled}
|
563
|
+
onCellClick={onCellClickChild}
|
564
|
+
onContentReady={onContentReadyChild}
|
565
|
+
onCellPrepared={onCellPreparedChild}
|
566
|
+
onContextMenuPreparing={onContextMenuPreparingChild}
|
567
|
+
onDisposing={onDisposingChild}
|
568
|
+
onExporting={onExportingChild}
|
569
|
+
onInitialized={onInitializedChild}
|
570
|
+
onOptionChanged={onOptionChangedChild}
|
571
|
+
>
|
572
|
+
<StateStoring enabled={stateStoringKey?.length} type="sessionStorage" storageKey={stateStoringKey} />
|
573
|
+
<FieldChooser enabled={false} />
|
574
|
+
</PivotGrid>
|
575
|
+
</div>
|
576
|
+
);
|
577
|
+
}
|
578
|
+
);
|
579
|
+
|
580
|
+
export default DxPlanitTreeGrid;
|
package/dist/index.tsx
ADDED
package/dist/type.ts
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
import DevExpress from 'devextreme';
|
2
|
+
import { Format } from 'devextreme/localization';
|
3
|
+
|
4
|
+
export interface IGroupField {
|
5
|
+
groupCaption: string;
|
6
|
+
groupName?: string;
|
7
|
+
depth: number;
|
8
|
+
colspan: number;
|
9
|
+
}
|
10
|
+
|
11
|
+
export interface IColorInfo {
|
12
|
+
format: Format;
|
13
|
+
color: string;
|
14
|
+
condition: string;
|
15
|
+
}
|
16
|
+
|
17
|
+
export interface ColumnField {
|
18
|
+
colspan: number;
|
19
|
+
text: string;
|
20
|
+
type: string;
|
21
|
+
}
|
22
|
+
|
23
|
+
export interface Props extends DevExpress.ui.dxPivotGrid.Properties {
|
24
|
+
id?: string;
|
25
|
+
dataSource?: any;
|
26
|
+
groupField?: IGroupField[];
|
27
|
+
dataColor?: IColorInfo[];
|
28
|
+
convertNullToHipen?: boolean;
|
29
|
+
convertZeroToHipen?: boolean;
|
30
|
+
stateStoringKey?: string;
|
31
|
+
customExcelButton?: boolean;
|
32
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "devextreme-planit-treegrid-react",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.6",
|
4
4
|
"description": "Devextreme의 DxPivotGrid를 Tree Grid처럼 보여주는 Wrapper입니다.",
|
5
5
|
"main": "dist/index.tsx",
|
6
6
|
"module": "dist/index.tsx",
|
@@ -47,7 +47,7 @@
|
|
47
47
|
},
|
48
48
|
"dependencies": {
|
49
49
|
"devextreme": "^22.1.6",
|
50
|
-
"devextreme-planit-treegrid-react": "^0.1.
|
50
|
+
"devextreme-planit-treegrid-react": "^0.1.5",
|
51
51
|
"devextreme-react": "^22.1.6",
|
52
52
|
"exceljs": "^4.3.0",
|
53
53
|
"file-saver": "^2.0.5",
|