devextreme-planit-treegrid-react 0.2.2 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,9 +1,9 @@
1
1
  {
2
2
  "name": "devextreme-planit-treegrid-react",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Devextreme의 DxPivotGrid를 Tree Grid처럼 보여주는 Wrapper입니다.",
5
- "main": "dist/index.tsx",
6
- "module": "dist/index.tsx",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
7
  "files": [
8
8
  "dist",
9
9
  "README.md"
@@ -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
- "devextreme-planit-treegrid-react": "^0.2.1",
43
+ "devextreme-planit-treegrid-react": "^0.2.3",
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
- }