devextreme-planit-treegrid-react 0.2.2 → 0.2.3

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.
@@ -0,0 +1,610 @@
1
+ "use strict";
2
+
3
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = void 0;
8
+ var _react = require("react");
9
+ var _loadPanel = require("devextreme-react/load-panel");
10
+ var _pivotGrid = _interopRequireWildcard(require("devextreme-react/pivot-grid"));
11
+ var _dataGrid = require("devextreme-react/data-grid");
12
+ var _excel_exporter = require("devextreme/excel_exporter");
13
+ var _exceljs = require("exceljs");
14
+ var _fileSaver = _interopRequireDefault(require("file-saver"));
15
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
17
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
18
+ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
19
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
20
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
21
+ function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
22
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
23
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
24
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
25
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
26
+ function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0) { ; } } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
27
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
28
+ /**
29
+ * devextreme pivotgrid Configrations 중 사용 불가 항목 : id, width, height, showColumnGrandTotals, showColumnTotals, showRowGrandTotals, FieldChooser
30
+ * devextreme pivotgrid Configrations 중 사용 방법 변경 항목 : stateStoring, Export
31
+ * onExported, onFileSaving 이벤트 사용하지 않음.
32
+ */
33
+ /**
34
+ * todoList:
35
+ * 2) columIndex 초기화 기능이 있어야 함(column 개수 변할 때)
36
+ * 3) 헤더에 테이블 삽입되면서 그리드 크기가 늘어남. height에 그리드 크기 늘어난 만큼 반영되어야 함.
37
+ */
38
+
39
+ var grandTotalCssNm = 'data-grand-total';
40
+ var DxPlanitTreeGrid = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) {
41
+ var _props$id = props.id,
42
+ id = _props$id === void 0 ? 'dx-planit-vera-pivotgrid-id' : _props$id,
43
+ groupField = props.groupField,
44
+ dataColor = props.dataColor,
45
+ _props$convertNullToH = props.convertNullToHipen,
46
+ convertNullToHipen = _props$convertNullToH === void 0 ? true : _props$convertNullToH,
47
+ _props$convertZeroToH = props.convertZeroToHipen,
48
+ convertZeroToHipen = _props$convertZeroToH === void 0 ? true : _props$convertZeroToH,
49
+ _props$stateStoringKe = props.stateStoringKey,
50
+ stateStoringKey = _props$stateStoringKe === void 0 ? '' : _props$stateStoringKe,
51
+ _props$allowExpandAll = props.allowExpandAll,
52
+ allowExpandAll = _props$allowExpandAll === void 0 ? false : _props$allowExpandAll,
53
+ _props$allowFiltering = props.allowFiltering,
54
+ allowFiltering = _props$allowFiltering === void 0 ? false : _props$allowFiltering,
55
+ _props$allowSorting = props.allowSorting,
56
+ allowSorting = _props$allowSorting === void 0 ? false : _props$allowSorting,
57
+ _props$allowSortingBy = props.allowSortingBySummary,
58
+ allowSortingBySummary = _props$allowSortingBy === void 0 ? false : _props$allowSortingBy,
59
+ _props$dataFieldArea = props.dataFieldArea,
60
+ dataFieldArea = _props$dataFieldArea === void 0 ? 'column' : _props$dataFieldArea,
61
+ dataSource = props.dataSource,
62
+ _props$disabled = props.disabled,
63
+ disabled = _props$disabled === void 0 ? false : _props$disabled,
64
+ elementAttr = props.elementAttr,
65
+ encodeHtml = props.encodeHtml,
66
+ _props$hideEmptySumma = props.hideEmptySummaryCells,
67
+ hideEmptySummaryCells = _props$hideEmptySumma === void 0 ? false : _props$hideEmptySumma,
68
+ hint = props.hint,
69
+ _props$rowHeaderLayou = props.rowHeaderLayout,
70
+ rowHeaderLayout = _props$rowHeaderLayou === void 0 ? 'standard' : _props$rowHeaderLayou,
71
+ _props$rtlEnabled = props.rtlEnabled,
72
+ rtlEnabled = _props$rtlEnabled === void 0 ? false : _props$rtlEnabled,
73
+ _props$showBorders = props.showBorders,
74
+ showBorders = _props$showBorders === void 0 ? true : _props$showBorders,
75
+ _props$showRowTotals = props.showRowTotals,
76
+ showRowTotals = _props$showRowTotals === void 0 ? true : _props$showRowTotals,
77
+ _props$showTotalsPrio = props.showTotalsPrior,
78
+ showTotalsPrior = _props$showTotalsPrio === void 0 ? 'none' : _props$showTotalsPrio,
79
+ _props$tabIndex = props.tabIndex,
80
+ tabIndex = _props$tabIndex === void 0 ? 0 : _props$tabIndex,
81
+ _props$visible = props.visible,
82
+ visible = _props$visible === void 0 ? true : _props$visible,
83
+ _props$wordWrapEnable = props.wordWrapEnabled,
84
+ wordWrapEnabled = _props$wordWrapEnable === void 0 ? false : _props$wordWrapEnable,
85
+ _props$customExcelBut = props.customExcelButton,
86
+ customExcelButton = _props$customExcelBut === void 0 ? false : _props$customExcelBut,
87
+ onCellClick = props.onCellClick,
88
+ onCellPrepared = props.onCellPrepared,
89
+ onContentReady = props.onContentReady,
90
+ onContextMenuPreparing = props.onContextMenuPreparing,
91
+ onDisposing = props.onDisposing,
92
+ onExporting = props.onExporting,
93
+ onInitialized = props.onInitialized,
94
+ onOptionChanged = props.onOptionChanged;
95
+ var _useState = (0, _react.useState)(0),
96
+ _useState2 = _slicedToArray(_useState, 2),
97
+ width = _useState2[0],
98
+ setWidth = _useState2[1];
99
+ var _useState3 = (0, _react.useState)(0),
100
+ _useState4 = _slicedToArray(_useState3, 2),
101
+ height = _useState4[0],
102
+ setHeight = _useState4[1];
103
+ var _useState5 = (0, _react.useState)(0),
104
+ _useState6 = _slicedToArray(_useState5, 2),
105
+ columnIndex = _useState6[0],
106
+ setColumnIndex = _useState6[1];
107
+ var _useState7 = (0, _react.useState)(dataSource),
108
+ _useState8 = _slicedToArray(_useState7, 2),
109
+ gridDataSource = _useState8[0],
110
+ setGridDataSource = _useState8[1];
111
+ var $tableRef = (0, _react.useRef)(null);
112
+ var excelBorder = {
113
+ style: 'thin',
114
+ color: {
115
+ argb: 'FF7E7E7E'
116
+ }
117
+ };
118
+ (0, _react.useImperativeHandle)(ref, function () {
119
+ return {
120
+ exportToExcel: exportToExcel
121
+ };
122
+ });
123
+
124
+ /**
125
+ * 그리드 사이즈 재조정
126
+ * @returns 그리드 사이즈
127
+ */
128
+ var getGridSize = function getGridSize() {
129
+ var _wrapper$clientWidth;
130
+ var wrapper = document.querySelector('.diag-table-wrapper');
131
+ var gap = 10;
132
+ setWidth((_wrapper$clientWidth = wrapper === null || wrapper === void 0 ? void 0 : wrapper.clientWidth) !== null && _wrapper$clientWidth !== void 0 ? _wrapper$clientWidth : 0);
133
+ setHeight(wrapper ? wrapper.clientHeight - gap : 0);
134
+ window.addEventListener('resize', function () {
135
+ var _wrapper$clientWidth2;
136
+ setWidth((_wrapper$clientWidth2 = wrapper === null || wrapper === void 0 ? void 0 : wrapper.clientWidth) !== null && _wrapper$clientWidth2 !== void 0 ? _wrapper$clientWidth2 : 0);
137
+ setHeight(wrapper ? wrapper.clientHeight - gap : 0);
138
+ });
139
+ return {
140
+ width: width,
141
+ height: height
142
+ };
143
+ };
144
+
145
+ /**
146
+ * 'Total' 을 한글로 변경
147
+ * @param e devextreme CellPreparedEvent
148
+ */
149
+ var changeTotalText = function changeTotalText(e) {
150
+ var _e$cell;
151
+ if (!e.cellElement) {
152
+ return;
153
+ }
154
+ if (((_e$cell = e.cell) === null || _e$cell === void 0 ? void 0 : _e$cell.type) === 'T') {
155
+ var _e$cell$text;
156
+ var text = (_e$cell$text = e.cell.text) === null || _e$cell$text === void 0 ? void 0 : _e$cell$text.replace('Total', '합계');
157
+ e.cellElement.innerHTML = "<span>".concat(text, "</span>");
158
+ }
159
+ };
160
+
161
+ /**
162
+ * null값을 하이픈으로 모두 변경
163
+ * @param e devextreme CellPreparedEvent
164
+ */
165
+ var changeNullToHipen = function changeNullToHipen(e) {
166
+ var _e$cell2;
167
+ if (!convertNullToHipen) {
168
+ return;
169
+ }
170
+ if (e.area === 'data' && ((_e$cell2 = e.cell) === null || _e$cell2 === void 0 ? void 0 : _e$cell2.text) === null && e.cellElement) {
171
+ e.cellElement.innerHTML = '<span class="text-color">-</span>';
172
+ }
173
+ };
174
+
175
+ /**
176
+ * '0', '0.0%' 를 하이픈으로 모두 변경
177
+ * @param e devextreme CellPreparedEvent
178
+ */
179
+ var changeZeroToHipen = function changeZeroToHipen(e) {
180
+ var _e$cell3, _e$cell4, _e$cell5;
181
+ if (!convertZeroToHipen) {
182
+ return;
183
+ }
184
+ if (e.area === 'data' && (((_e$cell3 = e.cell) === null || _e$cell3 === void 0 ? void 0 : _e$cell3.text) === '0' || ((_e$cell4 = e.cell) === null || _e$cell4 === void 0 ? void 0 : _e$cell4.text) === '0.0%' || ((_e$cell5 = e.cell) === null || _e$cell5 === void 0 ? void 0 : _e$cell5.text) === '') && e.cellElement) {
185
+ e.cellElement.innerHTML = '<span class="text-color">-</span>';
186
+ }
187
+ };
188
+
189
+ /**
190
+ * 테이블 헤더에 colspan, rowspan 한 HTMLElement 정보 반환
191
+ * @param groupField 사용자가 작성한 그룹 정보
192
+ * @return
193
+ */
194
+ var makeColspan = function makeColspan(group, index, isLast) {
195
+ var td = document.createElement('td');
196
+ var text = group.groupCaption;
197
+ if (group.depth === 1) {
198
+ text = "".concat(group.groupCaption);
199
+ }
200
+ td.setAttribute('colspan', group.colspan.toString());
201
+ td.setAttribute('class', 'dx-row-total dx-grand-total dx-planit-colspan');
202
+ if (isLast && index === 0) {
203
+ td.setAttribute('style', 'border-bottom: 0; border-right: 0');
204
+ } else if (isLast && index !== 0) {
205
+ td.setAttribute('style', 'border-right: 0');
206
+ } else if (!isLast && index === 0) {
207
+ td.setAttribute('style', 'border-bottom: 0');
208
+ }
209
+ td.innerHTML = "<div>".concat(text, "</div>");
210
+ return td;
211
+ };
212
+
213
+ /**
214
+ * 그룹 필드 데이터 유효성 검증용 데이터 생성
215
+ * @param groupField
216
+ * @returns
217
+ */
218
+ var makeCheckGroupData = function makeCheckGroupData(groupField) {
219
+ var data = {};
220
+ groupField === null || groupField === void 0 ? void 0 : groupField.forEach(function (group) {
221
+ if (data[group.depth]) {
222
+ data[group.depth] += group.colspan;
223
+ } else {
224
+ data[group.depth] = group.colspan;
225
+ }
226
+ });
227
+ return data;
228
+ };
229
+
230
+ /**
231
+ * GroupField 데이터 검증
232
+ * @param 사용자가 설정한 그룹 필드 정보
233
+ * @returns 데이터 검증 결과
234
+ */
235
+ var isCheckGroupField = function isCheckGroupField(groupField) {
236
+ var map = makeCheckGroupData(groupField);
237
+ for (var _i2 = 0, _Object$keys = Object.keys(map); _i2 < _Object$keys.length; _i2++) {
238
+ var depth = _Object$keys[_i2];
239
+ if (map[depth] !== columnIndex + 1) {
240
+ console.error('그룹 데이터의 children 숫자가 columnIndex와 맞지 않습니다. 다시 한 번 확인 바랍니다.');
241
+ }
242
+ }
243
+ return true;
244
+ };
245
+
246
+ /**
247
+ * Grand Total 셀 정보 저장
248
+ * @param e
249
+ */
250
+ var setTotalElementInfo = function setTotalElementInfo(e) {
251
+ var _e$cell6, _e$cell7, _e$cellElement;
252
+ if (!(groupField !== null && groupField !== void 0 && groupField.length) || ((_e$cell6 = e.cell) === null || _e$cell6 === void 0 ? void 0 : _e$cell6.type) !== 'GT' || ((_e$cell7 = e.cell) === null || _e$cell7 === void 0 ? void 0 : _e$cell7.text) !== 'Grand Total') {
253
+ return;
254
+ }
255
+ (_e$cellElement = e.cellElement) === null || _e$cellElement === void 0 ? void 0 : _e$cellElement.classList.add(grandTotalCssNm);
256
+ };
257
+
258
+ /**
259
+ * cell의 columnIndex 최대값 저장
260
+ * @param e
261
+ */
262
+ var setMaxColumIndex = function setMaxColumIndex(e) {
263
+ if (!e.columnIndex) {
264
+ return;
265
+ }
266
+ if (e.columnIndex > columnIndex) {
267
+ setColumnIndex(e.columnIndex);
268
+ }
269
+ };
270
+
271
+ /**
272
+ * groupField depth의 유니크한 배열 구하기
273
+ * @param group
274
+ * @param arr
275
+ * @returns
276
+ */
277
+ var getGroupDepth = function getGroupDepth(group, arr) {
278
+ var groupData = group.slice();
279
+ var set = new Set(groupData.map(function (group) {
280
+ return group.depth;
281
+ }));
282
+ return Array.from(set).sort(function compare(a, b) {
283
+ if (a > b) {
284
+ return arr === 'asc' ? -1 : 1;
285
+ }
286
+ if (a < b) {
287
+ return arr === 'asc' ? 1 : -1;
288
+ }
289
+ return 0;
290
+ });
291
+ };
292
+
293
+ /**
294
+ * 현재 depth에 맞는 그룹 필드 정보 반환
295
+ * @param group
296
+ * @param depth
297
+ * @returns
298
+ */
299
+ var getCurrentGroup = function getCurrentGroup(group, depth) {
300
+ return group.filter(function (gr) {
301
+ return gr.depth === depth;
302
+ });
303
+ };
304
+
305
+ /**
306
+ * 테이블 헤더(DOM)에 colspan 적용된 테이블 삽입
307
+ */
308
+ var insertRowHeaderGroup = function insertRowHeaderGroup() {
309
+ var _thead$previousSiblin;
310
+ if (!(groupField !== null && groupField !== void 0 && groupField.length)) {
311
+ return;
312
+ }
313
+ isCheckGroupField(groupField);
314
+ var totalElement = document.querySelector('.' + grandTotalCssNm);
315
+ var targetElement = totalElement === null || totalElement === void 0 ? void 0 : totalElement.parentNode;
316
+ var thead = targetElement === null || targetElement === void 0 ? void 0 : targetElement.parentNode;
317
+ if (!targetElement || !thead) {
318
+ return;
319
+ }
320
+ var firstChild = thead === null || thead === void 0 ? void 0 : thead.firstChild;
321
+ if (!firstChild) {
322
+ return;
323
+ }
324
+ totalElement.innerHTML = '';
325
+ totalElement.setAttribute('style', 'padding: 0; border: 0');
326
+ var colgroup = (_thead$previousSiblin = thead.previousSibling) === null || _thead$previousSiblin === void 0 ? void 0 : _thead$previousSiblin.cloneNode(true);
327
+ var groupData = groupField.slice();
328
+ var depth = getGroupDepth(groupData, 'asc');
329
+ var table = document.createElement('table');
330
+ depth.forEach(function (dep, index) {
331
+ var groupInfo = getCurrentGroup(groupData, dep);
332
+ var tr = document.createElement('tr');
333
+ groupInfo.forEach(function (group, cellIndex) {
334
+ var isLast = cellIndex === groupInfo.length - 1 ? true : false;
335
+ tr.appendChild(makeColspan(group, index, isLast));
336
+ });
337
+ table.prepend(tr);
338
+ });
339
+ table.prepend(colgroup);
340
+ totalElement.appendChild(table);
341
+ };
342
+
343
+ /**
344
+ * Devextreme의 dateController columnInfo에 그룹 정보 삽입
345
+ * @param group
346
+ * @returns
347
+ */
348
+ var makeDataControllerColumnGroup = function makeDataControllerColumnGroup(group) {
349
+ var groupData = group.slice();
350
+ var depth = getGroupDepth(groupData, 'desc');
351
+ return depth.map(function (dep) {
352
+ var groupInfo = getCurrentGroup(groupData, dep);
353
+ return groupInfo.map(function (group) {
354
+ return {
355
+ colspan: group.colspan,
356
+ text: group.groupCaption,
357
+ type: 'GT'
358
+ };
359
+ });
360
+ });
361
+ };
362
+
363
+ /**
364
+ * 사용자가 입력한 컬러 조건을 { standard: string; condition: string } 형식으로 변경 반환
365
+ * @param condition 사용자 입력 컬러 조건식 ex) '>= 100'
366
+ * @returns
367
+ */
368
+ var makeSplitCondtion = function makeSplitCondtion(condition) {
369
+ var newCondition = {
370
+ standard: '',
371
+ condition: ''
372
+ };
373
+ _toConsumableArray(condition).forEach(function (cond) {
374
+ if (Number.isNaN(parseFloat(cond))) {
375
+ newCondition.condition += cond;
376
+ } else {
377
+ newCondition.standard += cond;
378
+ }
379
+ });
380
+ return newCondition;
381
+ };
382
+
383
+ /**
384
+ * 데이터에 색상 적용
385
+ * @param e onCellPrepared 이벤트
386
+ * @returns
387
+ */
388
+ var makeColorAtPercent = function makeColorAtPercent(e) {
389
+ if (!dataColor || !e.cellElement) {
390
+ return;
391
+ }
392
+ dataColor.forEach(function (color) {
393
+ var _e$cell8, _e$cell8$format;
394
+ if (e.cell.value === null) {
395
+ return;
396
+ }
397
+ if (((_e$cell8 = e.cell) === null || _e$cell8 === void 0 ? void 0 : (_e$cell8$format = _e$cell8.format) === null || _e$cell8$format === void 0 ? void 0 : _e$cell8$format.type) === color.format && !Number.isNaN(e.cell.value)) {
398
+ var standardData = makeSplitCondtion(color.condition.replace(/(\s*)/g, ''));
399
+ var rate = color.format === 'percent' ? 0.01 : 1;
400
+ var condition = false;
401
+ switch (standardData.condition) {
402
+ case '>':
403
+ condition = e.cell.value > parseFloat(standardData.standard) * rate;
404
+ break;
405
+ case '>=':
406
+ condition = e.cell.value >= parseFloat(standardData.standard) * rate;
407
+ break;
408
+ case '<':
409
+ condition = e.cell.value < parseFloat(standardData.standard) * rate;
410
+ break;
411
+ case '<=':
412
+ condition = e.cell.value <= parseFloat(standardData.standard) * rate;
413
+ break;
414
+ }
415
+ if (condition && !(e.cell.value === 0 && convertZeroToHipen)) {
416
+ e.cellElement.style.color = color.color;
417
+ }
418
+ }
419
+ });
420
+ };
421
+
422
+ /**
423
+ * 그리드 데이터 정합성 체크. 데이터 잘못되어 있으면 에러 발생
424
+ * @param dataSource
425
+ */
426
+ var checkDataSource = function checkDataSource(dataSource) {
427
+ var isColumns = dataSource._fields.findIndex(function (field) {
428
+ return field.area === 'column';
429
+ });
430
+ var isRows = dataSource._fields.findIndex(function (field) {
431
+ return field.area === 'row';
432
+ });
433
+ var isDatas = dataSource._fields.findIndex(function (field) {
434
+ return field.area === 'data';
435
+ });
436
+ if (isColumns > -1) {
437
+ throw Error('DxPlanitTreeGrid는 column이 존재하는 형식의 pivot grid에는 사용할 수 없습니다.');
438
+ }
439
+ if (isRows === -1 || isDatas === -1) {
440
+ throw Error('DxPlanitTreeGrid 데이터는 row와 data가 반드시 존재해야 합니다.');
441
+ }
442
+ };
443
+
444
+ /**
445
+ * 그리드 펼침 정보 세션스토리지 리셋
446
+ */
447
+ var resetSession = function resetSession() {
448
+ sessionStorage.removeItem('dx-vera-pivotgrid-storing');
449
+ };
450
+
451
+ /**
452
+ * 엑셀 export 명령
453
+ * @param fileName 저장하고자 하는 엑셀파일명
454
+ */
455
+ var exportToExcel = function exportToExcel(fileName) {
456
+ setTimeout(function () {
457
+ var _$tableRef$current;
458
+ return exportToExcelAction((_$tableRef$current = $tableRef.current) === null || _$tableRef$current === void 0 ? void 0 : _$tableRef$current.instance, fileName);
459
+ });
460
+ };
461
+
462
+ /**
463
+ * devextreme component 정보의 dataController의 columnInfo에 사용자가 설정한 groupFIled 정보 병합
464
+ * @param component devextreme component
465
+ * @returns devextreme component
466
+ */
467
+ var convertDataControllerColumnsInfo = function convertDataControllerColumnsInfo(component) {
468
+ var arr = [];
469
+ var columnInfo = component._dataController._columnsInfo.forEach(function (column) {
470
+ var newColumn = column.slice();
471
+ if (groupField && newColumn.length === 1 && newColumn[0].type === 'GT' && newColumn[0].text === 'Grand Total') {
472
+ arr.push.apply(arr, _toConsumableArray(makeDataControllerColumnGroup(groupField)));
473
+ } else {
474
+ arr.push(newColumn);
475
+ }
476
+ });
477
+ component._dataController._columnsInfo = arr;
478
+ return component;
479
+ };
480
+
481
+ /**
482
+ * 엑셀 export
483
+ * @param e
484
+ */
485
+ var exportToExcelAction = function exportToExcelAction(e, fileName) {
486
+ var newComponent = convertDataControllerColumnsInfo(e);
487
+ var workbook = new _exceljs.Workbook();
488
+ var worksheet = workbook.addWorksheet(fileName);
489
+ (0, _excel_exporter.exportPivotGrid)({
490
+ component: newComponent,
491
+ worksheet: worksheet,
492
+ customizeCell: function customizeCell(_ref) {
493
+ var excelCell = _ref.excelCell;
494
+ var borderStyle = excelBorder;
495
+ excelCell.border = {
496
+ bottom: borderStyle,
497
+ left: borderStyle,
498
+ right: borderStyle,
499
+ top: borderStyle
500
+ };
501
+ }
502
+ }).then(function () {
503
+ workbook.xlsx.writeBuffer().then(function (buffer) {
504
+ (0, _fileSaver.default)(new Blob([buffer], {
505
+ type: 'application/octet-stream'
506
+ }), fileName + '.xlsx');
507
+ });
508
+ });
509
+ e.cancel = true;
510
+ };
511
+
512
+ /**
513
+ * devextreme CellPreparedEvent 이벤트 실행
514
+ * @param e
515
+ */
516
+ var onCellPreparedChild = function onCellPreparedChild(e) {
517
+ makeColorAtPercent(e);
518
+ setTotalElementInfo(e);
519
+ setMaxColumIndex(e);
520
+ changeTotalText(e);
521
+ changeNullToHipen(e);
522
+ changeZeroToHipen(e);
523
+ return onCellPrepared ? onCellPrepared(e) : undefined;
524
+ };
525
+
526
+ /**
527
+ * devextreme Raise Event
528
+ */
529
+ var onContentReadyChild = function onContentReadyChild(e) {
530
+ setTimeout(function () {
531
+ return insertRowHeaderGroup();
532
+ }, 0);
533
+ getGridSize();
534
+ return onContentReady ? onContentReady(e) : undefined;
535
+ };
536
+ var onCellClickChild = function onCellClickChild(e) {
537
+ return onCellClick ? onCellClick(e) : undefined;
538
+ };
539
+ var onContextMenuPreparingChild = function onContextMenuPreparingChild(e) {
540
+ return onContextMenuPreparing ? onContextMenuPreparing(e) : undefined;
541
+ };
542
+ var onDisposingChild = function onDisposingChild(e) {
543
+ return onDisposing ? onDisposing(e) : undefined;
544
+ };
545
+ var onExportingChild = function onExportingChild(e) {
546
+ return onExporting ? onExporting(e) : undefined;
547
+ };
548
+ var onInitializedChild = function onInitializedChild(e) {
549
+ return onInitialized ? onInitialized(e) : undefined;
550
+ };
551
+ var onOptionChangedChild = function onOptionChangedChild(e) {
552
+ return onOptionChanged ? onOptionChanged(e) : undefined;
553
+ };
554
+ (0, _react.useEffect)(function () {
555
+ if (customExcelButton) {}
556
+ }, [customExcelButton]);
557
+ (0, _react.useEffect)(function () {
558
+ setGridDataSource(dataSource);
559
+ checkDataSource(dataSource);
560
+ resetSession();
561
+ }, [dataSource]);
562
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(_loadPanel.LoadPanel, {
563
+ position: {
564
+ of: id
565
+ }
566
+ }), /*#__PURE__*/React.createElement(_pivotGrid.default, {
567
+ id: id,
568
+ ref: $tableRef,
569
+ dataSource: gridDataSource,
570
+ showColumnTotals: false,
571
+ showColumnGrandTotals: true,
572
+ showRowGrandTotals: false,
573
+ width: width,
574
+ height: height,
575
+ allowExpandAll: allowExpandAll,
576
+ allowFiltering: allowFiltering,
577
+ allowSorting: allowSorting,
578
+ allowSortingBySummary: allowSortingBySummary,
579
+ dataFieldArea: dataFieldArea,
580
+ disabled: disabled,
581
+ elementAttr: elementAttr,
582
+ encodeHtml: encodeHtml,
583
+ hideEmptySummaryCells: hideEmptySummaryCells,
584
+ hint: hint,
585
+ rowHeaderLayout: rowHeaderLayout,
586
+ rtlEnabled: rtlEnabled,
587
+ showBorders: showBorders,
588
+ showRowTotals: showRowTotals,
589
+ showTotalsPrior: showTotalsPrior,
590
+ tabIndex: tabIndex,
591
+ visible: visible,
592
+ wordWrapEnabled: wordWrapEnabled,
593
+ onCellClick: onCellClickChild,
594
+ onContentReady: onContentReadyChild,
595
+ onCellPrepared: onCellPreparedChild,
596
+ onContextMenuPreparing: onContextMenuPreparingChild,
597
+ onDisposing: onDisposingChild,
598
+ onExporting: onExportingChild,
599
+ onInitialized: onInitializedChild,
600
+ onOptionChanged: onOptionChangedChild
601
+ }, /*#__PURE__*/React.createElement(_dataGrid.StateStoring, {
602
+ enabled: stateStoringKey === null || stateStoringKey === void 0 ? void 0 : stateStoringKey.length,
603
+ type: "sessionStorage",
604
+ storageKey: stateStoringKey
605
+ }), /*#__PURE__*/React.createElement(_pivotGrid.FieldChooser, {
606
+ enabled: false
607
+ })));
608
+ });
609
+ var _default = DxPlanitTreeGrid;
610
+ exports.default = _default;
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _DxPlanitTreeGrid = _interopRequireDefault(require("./DxPlanitTreeGrid"));
8
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
+ var _default = _DxPlanitTreeGrid.default;
10
+ exports.default = _default;
package/dist/type.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devextreme-planit-treegrid-react",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Devextreme의 DxPivotGrid를 Tree Grid처럼 보여주는 Wrapper입니다.",
5
5
  "main": "dist/index.tsx",
6
6
  "module": "dist/index.tsx",
@@ -20,7 +20,7 @@
20
20
  "test": "react-scripts test",
21
21
  "eject": "react-scripts eject",
22
22
  "clean": "rimraf dist",
23
- "compile": "rimraf -rf dist && mkdir dist && babel src/lib --out-dir dist --copy-files"
23
+ "compile": "npm run clean && cross-env NODE_ENV=production babel src/lib --out-dir dist --copy-files --extensions .ts,.tsx"
24
24
  },
25
25
  "babel": {
26
26
  "presets": [
@@ -39,25 +39,30 @@
39
39
  "not op_mini all"
40
40
  ],
41
41
  "dependencies": {
42
- "@babel/polyfill": "^7.12.1",
43
42
  "devextreme": "^22.1.6",
44
43
  "devextreme-planit-treegrid-react": "^0.2.1",
45
44
  "devextreme-react": "^22.1.6",
46
45
  "exceljs": "^4.3.0",
47
46
  "file-saver": "^2.0.5",
48
- "react": "^18.2.0",
49
- "react-dom": "^18.2.0",
50
- "react-router-dom": "^6.4.3",
51
- "react-scripts": "^5.0.1",
52
47
  "typescript": "^4.9.3",
53
48
  "uuid": "^9.0.0",
54
49
  "web-vitals": "^2.1.4"
55
50
  },
51
+ "peerDependencies": {
52
+ "react": "^18.2.0",
53
+ "react-dom": "^18.2.0",
54
+ "react-router-dom": "^6.4.3",
55
+ "react-scripts": "^5.0.1"
56
+ },
56
57
  "devDependencies": {
57
- "@babel/cli": "^7.19.3",
58
+ "@babel/cli": "^7.0.0",
58
59
  "@babel/core": "^7.20.5",
60
+ "@babel/node": "^7.20.5",
61
+ "@babel/polyfill": "^7.12.1",
59
62
  "@babel/preset-env": "^7.20.2",
60
63
  "@babel/preset-react": "^7.18.6",
64
+ "@babel/preset-typescript": "^7.18.6",
65
+ "@babel/register": "^7.18.9",
61
66
  "@testing-library/jest-dom": "^5.16.5",
62
67
  "@testing-library/react": "^13.4.0",
63
68
  "@testing-library/user-event": "^13.5.0",
@@ -65,7 +70,9 @@
65
70
  "@types/react": "^18.0.25",
66
71
  "@types/react-dom": "^18.0.9",
67
72
  "@types/uuid": "^8.3.4",
68
- "babel-loader": "^9.1.0",
73
+ "babel-core": "^7.0.0-bridge.0",
74
+ "babel-loader": "^8.0.0-beta.6",
75
+ "babel-plugin-transform-object-rest-spread": "^6.26.0",
69
76
  "cross-env": "^7.0.3",
70
77
  "css-loader": "^6.7.2",
71
78
  "eslint": "^8.27.0",
@@ -1,580 +0,0 @@
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 DELETED
@@ -1,3 +0,0 @@
1
- import DxPlanitTreeGrid from './DxPlanitTreeGrid';
2
-
3
- export default DxPlanitTreeGrid;
package/dist/type.ts DELETED
@@ -1,32 +0,0 @@
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
- }