evui 3.3.10 → 3.3.13

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.
Files changed (30) hide show
  1. package/dist/evui.common.js +2439 -1032
  2. package/dist/evui.common.js.map +1 -1
  3. package/dist/evui.umd.js +2439 -1032
  4. package/dist/evui.umd.js.map +1 -1
  5. package/dist/evui.umd.min.js +1 -1
  6. package/dist/evui.umd.min.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/components/chart/chart.core.js +65 -24
  9. package/src/components/chart/element/element.heatmap.js +195 -51
  10. package/src/components/chart/element/element.line.js +22 -9
  11. package/src/components/chart/element/element.scatter.js +26 -9
  12. package/src/components/chart/element/element.tip.js +103 -83
  13. package/src/components/chart/helpers/helpers.constant.js +13 -11
  14. package/src/components/chart/model/model.series.js +1 -1
  15. package/src/components/chart/model/model.store.js +19 -74
  16. package/src/components/chart/plugins/plugins.interaction.js +15 -4
  17. package/src/components/chart/plugins/plugins.legend.js +6 -3
  18. package/src/components/chart/plugins/plugins.pie.js +17 -0
  19. package/src/components/chart/plugins/plugins.tooltip.js +205 -32
  20. package/src/components/chart/scale/scale.js +10 -11
  21. package/src/components/chart/scale/scale.step.js +38 -3
  22. package/src/components/chart/scale/scale.time.category.js +35 -3
  23. package/src/components/chart/uses.js +12 -0
  24. package/src/components/grid/Grid.vue +109 -36
  25. package/src/components/grid/grid.summary.vue +235 -0
  26. package/src/components/grid/style/grid.scss +0 -14
  27. package/src/components/grid/uses.js +55 -46
  28. package/src/components/treeGrid/TreeGrid.vue +269 -36
  29. package/src/components/treeGrid/TreeGridNode.vue +8 -9
  30. package/src/components/treeGrid/uses.js +152 -37
@@ -1,19 +1,18 @@
1
1
  <template>
2
2
  <div
3
- v-if="!!$slots.toolbar"
3
+ v-if="$slots.toolbar"
4
4
  class="toolbar-wrapper"
5
5
  :style="`width: ${gridWidth};`"
6
6
  >
7
7
  <!-- Toolbar -->
8
- <toolbar v-if="!!$slots.toolbar" >
8
+ <toolbar>
9
9
  <template #toolbarWrapper>
10
10
  <slot
11
11
  name="toolbar"
12
12
  :item="{
13
13
  onSearch,
14
14
  }"
15
- >
16
- </slot>
15
+ />
17
16
  </template>
18
17
  </toolbar>
19
18
  </div>
@@ -26,20 +25,20 @@
26
25
  }"
27
26
  :style="gridStyle"
28
27
  >
29
- <!--Table-->
28
+ <!-- Table -->
30
29
  <div
31
30
  v-cloak
32
31
  ref="grid"
33
32
  :class="gridClass"
34
33
  >
35
- <!--Header-->
34
+ <!-- Header -->
36
35
  <div
37
36
  v-show="showHeader"
38
37
  ref="header"
39
38
  :class="headerClass"
40
39
  >
41
40
  <ul class="column-list">
42
- <!--Header Checkbox-->
41
+ <!-- Header Checkbox -->
43
42
  <li
44
43
  v-if="useCheckbox.use"
45
44
  :class="headerCheckboxClass"
@@ -51,7 +50,7 @@
51
50
  @change="onCheckAll"
52
51
  />
53
52
  </li>
54
- <!--Column List-->
53
+ <!-- Column List -->
55
54
  <template
56
55
  v-for="(column, index) in orderedColumns"
57
56
  :key="index"
@@ -62,14 +61,14 @@
62
61
  :class="getColumnClass(column)"
63
62
  :style="getColumnStyle(column)"
64
63
  >
65
- <!--Column Name-->
64
+ <!-- Column Name -->
66
65
  <span
67
66
  :title="column.caption"
68
67
  class="column-name"
69
68
  >
70
69
  {{ column.caption }}
71
70
  </span>
72
- <!--Column Resize-->
71
+ <!-- Column Resize -->
73
72
  <span
74
73
  class="column-resize"
75
74
  @mousedown.stop.left="onColumnResize(index, $event)"
@@ -78,7 +77,7 @@
78
77
  </template>
79
78
  </ul>
80
79
  </div>
81
- <!--Body-->
80
+ <!-- Body -->
82
81
  <div
83
82
  ref="body"
84
83
  :class="bodyStyle"
@@ -86,7 +85,7 @@
86
85
  @contextmenu="onContextMenu($event)"
87
86
  @contextmenu.prevent="menu.show"
88
87
  >
89
- <!--vScroll Top-->
88
+ <!-- vScroll Top -->
90
89
  <div
91
90
  :style="`height: ${vScrollTopHeight}px;`"
92
91
  class="vscroll-spacer"
@@ -114,7 +113,7 @@
114
113
  @click-tree-data="onRowClick"
115
114
  @dbl-click-tree-data="onRowDblClick"
116
115
  >
117
- <!-- cell renderer -->
116
+ <!-- Cell Renderer -->
118
117
  <template
119
118
  v-for="(column, cellIndex) in orderedColumns"
120
119
  :key="cellIndex"
@@ -131,7 +130,9 @@
131
130
  </slot>
132
131
  </template>
133
132
  <template v-else>
134
- <span :title="node[column.field]">{{node[column.field]}}</span>
133
+ <span :title="getConvertValue(column, node[column.field])">
134
+ {{ getConvertValue(column, node[column.field]) }}
135
+ </span>
135
136
  </template>
136
137
  </template>
137
138
  </tree-grid-node>
@@ -140,18 +141,18 @@
140
141
  </tr>
141
142
  </tbody>
142
143
  </table>
143
- <!--vScroll Bottom-->
144
+ <!-- vScroll Bottom -->
144
145
  <div
145
146
  :style="`height: ${vScrollBottomHeight}px;`"
146
147
  class="vscroll-spacer"
147
148
  />
148
- <!--Context Menu-->
149
+ <!-- Context Menu -->
149
150
  <ev-context-menu
150
151
  ref="menu"
151
152
  :items="contextMenuItems"
152
153
  />
153
154
  </div>
154
- <!--Resize Line-->
155
+ <!-- Resize Line -->
155
156
  <div
156
157
  v-show="showResizeLine"
157
158
  ref="resizeLine"
@@ -159,12 +160,37 @@
159
160
  />
160
161
  </div>
161
162
  </div>
163
+ <!-- Summary -->
164
+ <grid-summary
165
+ v-if="useSummary"
166
+ :is-tree="true"
167
+ :ordered-columns="orderedColumns"
168
+ :stores="stores"
169
+ :use-checkbox="useCheckbox.use"
170
+ :style-option="{
171
+ borderStyle,
172
+ minWidth,
173
+ rowHeight,
174
+ }"
175
+ />
176
+ <!-- Pagination -->
177
+ <grid-pagination
178
+ v-if="usePage && !isInfinite"
179
+ v-model="currentPage"
180
+ :total="showTreeStore.length"
181
+ :per-page="perPage"
182
+ :visible-page="visiblePage"
183
+ :show-page-info="showPageInfo"
184
+ :order="order"
185
+ />
162
186
  </template>
163
187
 
164
188
  <script>
165
189
  import { reactive, toRefs, computed, watch, onMounted, onActivated, nextTick } from 'vue';
166
190
  import treeGridNode from './TreeGridNode';
167
191
  import Toolbar from './treeGrid.toolbar';
192
+ import GridPagination from '../grid/grid.pagination';
193
+ import GridSummary from '../grid/grid.summary';
168
194
  import {
169
195
  commonFunctions,
170
196
  scrollEvent,
@@ -174,6 +200,7 @@ import {
174
200
  contextMenuEvent,
175
201
  treeEvent,
176
202
  filterEvent,
203
+ pagingEvent,
177
204
  } from './uses';
178
205
 
179
206
  export default {
@@ -181,6 +208,8 @@ export default {
181
208
  components: {
182
209
  treeGridNode,
183
210
  Toolbar,
211
+ GridPagination,
212
+ GridSummary,
184
213
  },
185
214
  props: {
186
215
  columns: {
@@ -200,8 +229,8 @@ export default {
200
229
  default: '100%',
201
230
  },
202
231
  selected: {
203
- type: [Array, Object],
204
- default: null,
232
+ type: [Array],
233
+ default: () => [],
205
234
  },
206
235
  checked: {
207
236
  type: [Array],
@@ -227,8 +256,10 @@ export default {
227
256
  'update:checked': null,
228
257
  'check-row': null,
229
258
  'check-all': null,
259
+ 'page-change': null,
230
260
  },
231
261
  setup(props) {
262
+ const useSummary = computed(() => (props.option?.useSummary || false));
232
263
  const elementInfo = reactive({
233
264
  body: null,
234
265
  header: null,
@@ -243,6 +274,7 @@ export default {
243
274
  treeStore: [],
244
275
  viewStore: [],
245
276
  filterStore: [],
277
+ pagingStore: [],
246
278
  treeRows: props.rows,
247
279
  searchStore: computed(() => stores.treeStore.filter(item => item.isFilter)),
248
280
  showTreeStore: computed(() => stores.treeStore.filter(item => item.show)),
@@ -250,6 +282,23 @@ export default {
250
282
  props.columns.map((column, index) => ({ index, ...column }))),
251
283
  store: computed(() => (filterInfo.isSearch ? stores.searchStore : stores.treeStore)),
252
284
  });
285
+ const pageInfo = reactive({
286
+ usePage: computed(() => (props.option.page?.use || false)),
287
+ useClient: props.option.page?.useClient || false,
288
+ isInfinite: computed(() => (props.option.page?.isInfinite || false)),
289
+ startIndex: 0,
290
+ prevPage: 0,
291
+ currentPage: 0,
292
+ total: computed(() => (props.option.page?.total || 0)),
293
+ perPage: computed(() => (props.option.page?.perPage || 20)),
294
+ visiblePage: computed(() => (props.option.page?.visiblePage || 8)),
295
+ order: computed(() => (props.option.page?.order || 'center')),
296
+ showPageInfo: computed(() => (props.option.page?.showPageInfo || false)),
297
+ isClientPaging: computed(() =>
298
+ pageInfo.useClient && pageInfo.usePage && !pageInfo.isInfinite),
299
+ isHighlight: false,
300
+ highlightPage: 0,
301
+ });
253
302
  const checkInfo = reactive({
254
303
  prevCheckedRow: [],
255
304
  isHeaderChecked: false,
@@ -274,8 +323,14 @@ export default {
274
323
  hasVerticalScrollBar: false,
275
324
  });
276
325
  const selectInfo = reactive({
277
- useSelect: props.option.useSelect === undefined ? true : props.option.useSelect,
278
326
  selectedRow: props.selected,
327
+ useSelect: computed(() => props.option?.useSelection?.use ?? true),
328
+ limitCount: computed(() => {
329
+ let limit = props.option?.useSelection?.limitCount;
330
+ limit = !!limit && limit >= 2 ? limit : 0;
331
+ return limit;
332
+ }),
333
+ multiple: computed(() => props.option?.useSelection?.multiple ?? false),
279
334
  });
280
335
  const contextInfo = reactive({
281
336
  menu: null,
@@ -299,13 +354,45 @@ export default {
299
354
  (props.option.showHeader === undefined ? true : props.option.showHeader)),
300
355
  stripeStyle: computed(() => props.option.style?.stripe || false),
301
356
  borderStyle: computed(() => props.option.style?.border || ''),
302
- highlightIdx: computed(() => props.option.style?.highlight),
357
+ highlightIdx: computed(() => props.option.style?.highlight ?? -1),
358
+ });
359
+ const clearSelectInfo = () => {
360
+ selectInfo.selectedRow.length = 0;
361
+ stores.store.forEach((row) => {
362
+ row.selected = false;
363
+ });
364
+ };
365
+ const clearCheckInfo = () => {
366
+ checkInfo.isHeaderChecked = false;
367
+ checkInfo.checkedRows.length = 0;
368
+ stores.store.forEach((row) => {
369
+ row.checked = false;
370
+ });
371
+ };
372
+ const {
373
+ getPagingData,
374
+ updatePagingInfo,
375
+ changePage,
376
+ } = pagingEvent({
377
+ stores,
378
+ pageInfo,
379
+ filterInfo,
380
+ elementInfo,
381
+ clearCheckInfo,
303
382
  });
304
383
  const {
305
384
  updateVScroll,
306
385
  updateHScroll,
307
386
  onScroll,
308
- } = scrollEvent({ scrollInfo, stores, elementInfo, resizeInfo });
387
+ } = scrollEvent({
388
+ scrollInfo,
389
+ stores,
390
+ elementInfo,
391
+ resizeInfo,
392
+ pageInfo,
393
+ getPagingData,
394
+ updatePagingInfo,
395
+ });
309
396
 
310
397
  const {
311
398
  onRowClick,
@@ -315,14 +402,28 @@ export default {
315
402
  const {
316
403
  onCheck,
317
404
  onCheckAll,
318
- } = checkEvent({ checkInfo, stores, checkHeader });
405
+ } = checkEvent({
406
+ checkInfo,
407
+ stores,
408
+ checkHeader,
409
+ pageInfo,
410
+ getPagingData,
411
+ updatePagingInfo,
412
+ });
319
413
 
320
414
  const {
321
415
  calculatedColumn,
322
416
  onResize,
323
417
  onShow,
324
418
  onColumnResize,
325
- } = resizeEvent({ resizeInfo, elementInfo, checkInfo, stores, isRenderer, updateVScroll });
419
+ } = resizeEvent({
420
+ resizeInfo,
421
+ elementInfo,
422
+ checkInfo,
423
+ stores,
424
+ isRenderer,
425
+ updateVScroll,
426
+ });
326
427
 
327
428
  const {
328
429
  setContextMenu,
@@ -336,7 +437,16 @@ export default {
336
437
 
337
438
  const {
338
439
  onSearch,
339
- } = filterEvent({ stores, filterInfo, getConvertValue, onResize, checkHeader });
440
+ } = filterEvent({
441
+ stores,
442
+ filterInfo,
443
+ pageInfo,
444
+ getConvertValue,
445
+ onResize,
446
+ checkHeader,
447
+ getPagingData,
448
+ updatePagingInfo,
449
+ });
340
450
 
341
451
  onMounted(() => {
342
452
  stores.treeStore = setTreeNodeStore();
@@ -344,15 +454,24 @@ export default {
344
454
  onActivated(() => {
345
455
  onResize();
346
456
  });
457
+
347
458
  watch(
348
459
  () => props.checked,
349
- (checkedList) => {
350
- const store = stores.store;
351
- checkInfo.checkedRows = checkedList;
460
+ (value) => {
461
+ checkInfo.checkedRows = value;
462
+ },
463
+ );
464
+ watch(
465
+ () => checkInfo.checkedRows,
466
+ (value) => {
352
467
  checkInfo.isHeaderChecked = false;
468
+ let store = stores.store;
469
+ if (pageInfo.isClientPaging) {
470
+ store = getPagingData();
471
+ }
353
472
  if (store.length) {
354
473
  store.forEach((row) => {
355
- row.checked = !!checkedList.find(c => c.index === row.index);
474
+ row.checked = !!value.find(checkedRow => checkedRow.index === row.index);
356
475
  });
357
476
  checkHeader(store);
358
477
  }
@@ -362,7 +481,78 @@ export default {
362
481
  watch(
363
482
  () => props.selected,
364
483
  (value) => {
365
- selectInfo.selectedRow = value;
484
+ if (selectInfo.useSelect) {
485
+ selectInfo.selectedRow = value;
486
+ }
487
+ },
488
+ );
489
+ watch(
490
+ () => selectInfo.selectedRow,
491
+ (value) => {
492
+ if (selectInfo.useSelect) {
493
+ stores.store.forEach((row) => {
494
+ row.selected = !!value.find(selectedRow => selectedRow.index === row.index);
495
+ });
496
+ updateVScroll();
497
+ }
498
+ }, { deep: true },
499
+ );
500
+ watch(
501
+ () => styleInfo.highlightIdx,
502
+ async (index) => {
503
+ await nextTick();
504
+ const setChildShow = (data) => {
505
+ if (!data?.children) {
506
+ return;
507
+ }
508
+ const { children } = data;
509
+ children.forEach((node) => {
510
+ const childNode = node;
511
+ if (childNode.parent.show && childNode.parent.expand) {
512
+ childNode.show = true;
513
+ } else {
514
+ childNode.show = false;
515
+ }
516
+ childNode.isFilter = true;
517
+ if (childNode.hasChild) {
518
+ setChildShow(childNode);
519
+ }
520
+ });
521
+ };
522
+ const setParentShow = (data) => {
523
+ if (!data?.parent) {
524
+ return;
525
+ }
526
+ const { parent } = data;
527
+ parent.show = true;
528
+ parent.isFilter = true;
529
+ parent.expand = true;
530
+ setChildShow(parent);
531
+ setParentShow(parent);
532
+ };
533
+ if (index >= 0) {
534
+ const highlightNode = stores.store.find(node => node.index === index);
535
+ if (!highlightNode) {
536
+ return;
537
+ }
538
+ // highlightNode parents 자동 펼치기
539
+ highlightNode.show = true;
540
+ highlightNode.isFilter = true;
541
+ setParentShow(highlightNode);
542
+ if (pageInfo.usePage && !pageInfo.isInfinite) {
543
+ const highlightNodeIndex = (stores.showTreeStore
544
+ .map(node => node.index)
545
+ .indexOf(highlightNode.index)
546
+ ) + 1; // tree 에 보여지는 데이터 기준으로 index 다시 구하기
547
+ pageInfo.highlightPage = Math.ceil(highlightNodeIndex / pageInfo.perPage) || 1;
548
+ if (pageInfo.highlightPage !== pageInfo.currentPage) {
549
+ pageInfo.currentPage = pageInfo.highlightPage;
550
+ pageInfo.isHighlight = true;
551
+ return;
552
+ }
553
+ }
554
+ elementInfo.body.scrollTop = resizeInfo.rowHeight * styleInfo.highlightIdx;
555
+ }
366
556
  },
367
557
  );
368
558
  watch(
@@ -372,6 +562,18 @@ export default {
372
562
  checkInfo.isHeaderChecked = false;
373
563
  },
374
564
  );
565
+ watch(
566
+ () => selectInfo.useSelect,
567
+ () => {
568
+ clearSelectInfo();
569
+ },
570
+ );
571
+ watch(
572
+ () => selectInfo.multiple,
573
+ () => {
574
+ clearSelectInfo();
575
+ },
576
+ );
375
577
  watch(
376
578
  () => props.rows,
377
579
  (newData) => {
@@ -408,10 +610,38 @@ export default {
408
610
  nextTick(() => {
409
611
  if (value !== undefined) {
410
612
  onSearch(value?.value ?? value);
613
+ if (pageInfo.isClientPaging) {
614
+ clearCheckInfo();
615
+ clearSelectInfo();
616
+ }
411
617
  }
412
618
  });
413
619
  }, { immediate: true },
414
620
  );
621
+ watch(
622
+ () => props.option.page?.currentPage,
623
+ (value) => {
624
+ const current = !value ? 1 : value;
625
+ pageInfo.currentPage = !props.option.page?.isInfinite ? current : 1;
626
+ }, { immediate: true },
627
+ );
628
+ watch(
629
+ () => pageInfo.currentPage,
630
+ (current, before) => {
631
+ nextTick(() => {
632
+ changePage(before);
633
+ if (pageInfo.isClientPaging && current !== before) {
634
+ clearCheckInfo();
635
+ clearSelectInfo();
636
+ }
637
+ updateVScroll();
638
+ if (current === pageInfo.highlightPage && pageInfo.isHighlight) {
639
+ elementInfo.body.scrollTop = resizeInfo.rowHeight * styleInfo.highlightIdx;
640
+ pageInfo.isHighlight = !pageInfo.isHighlight;
641
+ }
642
+ });
643
+ },
644
+ );
415
645
  const gridStyle = computed(() => ({
416
646
  width: resizeInfo.gridWidth,
417
647
  height: resizeInfo.gridHeight,
@@ -459,6 +689,14 @@ export default {
459
689
  const getSlotName = column => `${column}Node`;
460
690
 
461
691
  return {
692
+ gridStyle,
693
+ gridClass,
694
+ headerClass,
695
+ headerCheckboxClass,
696
+ isHeaderCheckbox,
697
+ bodyStyle,
698
+ useSummary,
699
+ stores,
462
700
  ...toRefs(styleInfo),
463
701
  ...toRefs(elementInfo),
464
702
  ...toRefs(stores),
@@ -468,6 +706,7 @@ export default {
468
706
  ...toRefs(selectInfo),
469
707
  ...toRefs(checkInfo),
470
708
  ...toRefs(contextInfo),
709
+ ...toRefs(pageInfo),
471
710
  isRenderer,
472
711
  getComponentName,
473
712
  getConvertValue,
@@ -488,15 +727,9 @@ export default {
488
727
  onContextMenu,
489
728
  onSearch,
490
729
  handleExpand,
491
- gridStyle,
492
- gridClass,
493
- headerClass,
494
- headerCheckboxClass,
495
- isHeaderCheckbox,
496
730
  getColumnClass,
497
731
  getColumnStyle,
498
732
  getSlotName,
499
- bodyStyle,
500
733
  };
501
734
  },
502
735
  };
@@ -26,7 +26,7 @@
26
26
  <td
27
27
  v-if="!column.hide"
28
28
  :data-name="column.field"
29
- :data-index="column.index"
29
+ :data-index="node.index"
30
30
  :class="getColumnClass(column, cellIndex)"
31
31
  :style="getColumnStyle(column)"
32
32
  >
@@ -83,8 +83,7 @@
83
83
  :item="{
84
84
  data: node.data,
85
85
  }"
86
- >
87
- </slot>
86
+ />
88
87
  </template>
89
88
  </div>
90
89
  </td>
@@ -185,7 +184,7 @@ export default {
185
184
  'tree-row': true,
186
185
  [`tree-row--level-${nodeInfo?.level}`]: true,
187
186
  highlight: nodeInfo?.index === props.highlightIndex,
188
- selected: nodeInfo?.index === props.selectedData?.index,
187
+ selected: nodeInfo.selected,
189
188
  'non-border': !!props.borderStyle && props.borderStyle !== 'rows',
190
189
  });
191
190
  const checkboxClass = computed(() => ({
@@ -213,17 +212,17 @@ export default {
213
212
  };
214
213
  };
215
214
  return {
215
+ parentIconMV,
216
+ childIconMV,
217
+ node,
218
+ isDataIcon,
219
+ checkboxClass,
216
220
  onCheck,
217
221
  onExpand,
218
222
  onClick,
219
223
  onDblClick,
220
224
  expandIconClasses,
221
- parentIconMV,
222
- childIconMV,
223
- node,
224
- isDataIcon,
225
225
  getRowClass,
226
- checkboxClass,
227
226
  getColumnClass,
228
227
  getColumnStyle,
229
228
  getDepthStyle,