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
@@ -108,7 +108,7 @@
108
108
  </template>
109
109
  <!-- Filter Button -->
110
110
  <span
111
- v-if="isFilterButton(column.field)"
111
+ v-if="isFiltering"
112
112
  class="column-filter"
113
113
  @click.capture="onClickFilter(column)"
114
114
  >
@@ -150,7 +150,7 @@
150
150
  :data-index="row[0]"
151
151
  :class="{
152
152
  row: true,
153
- selected: row[2] === selectedRow,
153
+ selected: row[3],
154
154
  'non-border': !!borderStyle && borderStyle !== 'rows',
155
155
  highlight: row[0] === highlightIdx,
156
156
  }"
@@ -206,8 +206,8 @@
206
206
  </template>
207
207
  <!-- Cell Value -->
208
208
  <template v-else>
209
- <div :title="getConvertValue(column.type, row[2][column.index])">
210
- {{ getConvertValue(column.type, row[2][column.index]) }}
209
+ <div :title="getConvertValue(column, row[2][column.index])">
210
+ {{ getConvertValue(column, row[2][column.index]) }}
211
211
  </div>
212
212
  </template>
213
213
  </td>
@@ -246,7 +246,20 @@
246
246
  />
247
247
  </div>
248
248
  </div>
249
- <pagination
249
+ <!-- Summary -->
250
+ <grid-summary
251
+ v-if="useSummary"
252
+ :ordered-columns="orderedColumns"
253
+ :stores="stores"
254
+ :use-checkbox="useCheckbox.use"
255
+ :style-option="{
256
+ borderStyle,
257
+ minWidth,
258
+ rowHeight,
259
+ }"
260
+ />
261
+ <!-- Pagination -->
262
+ <grid-pagination
250
263
  v-if="usePage && !isInfinite"
251
264
  v-model="currentPage"
252
265
  :total="store.length"
@@ -254,15 +267,15 @@
254
267
  :visible-page="visiblePage"
255
268
  :show-page-info="showPageInfo"
256
269
  :order="order"
257
- >
258
- </pagination>
270
+ />
259
271
  </template>
260
272
 
261
273
  <script>
262
274
  import { reactive, toRefs, computed, watch, onMounted, onActivated, nextTick } from 'vue';
263
275
  import Toolbar from './grid.toolbar';
264
- import Pagination from './grid.pagination';
265
276
  import FilterWindow from './grid.filter.window';
277
+ import GridPagination from './grid.pagination';
278
+ import GridSummary from './grid.summary';
266
279
  import {
267
280
  commonFunctions,
268
281
  scrollEvent,
@@ -280,8 +293,9 @@ export default {
280
293
  name: 'EvGrid',
281
294
  components: {
282
295
  Toolbar,
283
- Pagination,
284
296
  FilterWindow,
297
+ GridPagination,
298
+ GridSummary,
285
299
  },
286
300
  props: {
287
301
  columns: {
@@ -323,9 +337,10 @@ export default {
323
337
  'page-change': null,
324
338
  },
325
339
  setup(props) {
326
- const ROW_INDEX = 0;
340
+ // const ROW_INDEX = 0;
327
341
  const ROW_CHECK_INDEX = 1;
328
342
  const ROW_DATA_INDEX = 2;
343
+ const ROW_SELECT_INDEX = 3;
329
344
  const {
330
345
  isRenderer,
331
346
  getComponentName,
@@ -333,11 +348,11 @@ export default {
333
348
  getColumnIndex,
334
349
  setPixelUnit,
335
350
  } = commonFunctions();
336
- const showHeader = computed(() =>
337
- (props.option.showHeader === undefined ? true : props.option.showHeader));
351
+ const showHeader = computed(() => (props.option.showHeader ?? true));
352
+ const useSummary = computed(() => (props.option?.useSummary || false));
338
353
  const stripeStyle = computed(() => (props.option.style?.stripe || false));
339
354
  const borderStyle = computed(() => (props.option.style?.border || ''));
340
- const highlightIdx = computed(() => (props.option.style?.highlight || -1));
355
+ const highlightIdx = computed(() => (props.option.style?.highlight ?? -1));
341
356
  const rowMinHeight = props.option.rowMinHeight || 35;
342
357
  const elementInfo = reactive({
343
358
  body: null,
@@ -347,8 +362,7 @@ export default {
347
362
  });
348
363
  const filterInfo = reactive({
349
364
  filterList: {},
350
- isFiltering: computed(() =>
351
- (props.option.useFilter === undefined ? true : props.option.useFilter)),
365
+ isFiltering: computed(() => (props.option.useFilter ?? false)),
352
366
  setFiltering: false,
353
367
  showFilterWindow: false,
354
368
  currentFilter: {
@@ -384,12 +398,13 @@ export default {
384
398
  showPageInfo: computed(() => (props.option.page?.showPageInfo || false)),
385
399
  isClientPaging: computed(() =>
386
400
  pageInfo.useClient && pageInfo.usePage && !pageInfo.isInfinite),
401
+ isHighlight: false,
402
+ highlightPage: 0,
387
403
  });
388
404
  const checkInfo = reactive({
389
405
  prevCheckedRow: [],
390
406
  isHeaderChecked: false,
391
407
  checkedRows: props.checked,
392
- checkedIndex: new Set(),
393
408
  useCheckbox: computed(() => (props.option.useCheckbox || {})),
394
409
  });
395
410
  const scrollInfo = reactive({
@@ -402,8 +417,14 @@ export default {
402
417
  hasVerticalScrollBar: false,
403
418
  });
404
419
  const selectInfo = reactive({
405
- useSelect: props.option.useSelect === undefined ? true : props.option.useSelect,
406
420
  selectedRow: props.selected,
421
+ useSelect: computed(() => props.option?.useSelection?.use ?? true),
422
+ limitCount: computed(() => {
423
+ let limit = props.option?.useSelection?.limitCount;
424
+ limit = !!limit && limit >= 2 ? limit : 0;
425
+ return limit;
426
+ }),
427
+ multiple: computed(() => props.option?.useSelection?.multiple ?? false),
407
428
  });
408
429
  const sortInfo = reactive({
409
430
  isSorting: false,
@@ -430,12 +451,17 @@ export default {
430
451
  });
431
452
  const clearCheckInfo = () => {
432
453
  checkInfo.checkedRows = [];
433
- checkInfo.checkedIndex.clear();
434
454
  checkInfo.isHeaderChecked = false;
435
455
  stores.store.forEach((row) => {
436
456
  row[ROW_CHECK_INDEX] = false;
437
457
  });
438
458
  };
459
+ const clearSelectInfo = () => {
460
+ selectInfo.selectedRow = [];
461
+ stores.store.forEach((row) => {
462
+ row[ROW_SELECT_INDEX] = false;
463
+ });
464
+ };
439
465
  const {
440
466
  getPagingData,
441
467
  updatePagingInfo,
@@ -466,7 +492,7 @@ export default {
466
492
  const {
467
493
  onRowClick,
468
494
  onRowDblClick,
469
- } = clickEvent(selectInfo);
495
+ } = clickEvent({ selectInfo });
470
496
 
471
497
  const {
472
498
  onCheck,
@@ -579,22 +605,23 @@ export default {
579
605
  );
580
606
  watch(
581
607
  () => props.checked,
582
- (checkedList) => {
583
- checkInfo.checkedRows = checkedList;
608
+ (value) => {
609
+ checkInfo.checkedRows = value;
610
+ },
611
+ );
612
+ watch(
613
+ () => checkInfo.checkedRows,
614
+ (value) => {
584
615
  checkInfo.isHeaderChecked = false;
585
- checkInfo.checkedIndex.clear();
586
616
  let store = stores.store;
587
617
  if (pageInfo.isClientPaging) {
588
618
  store = getPagingData();
589
619
  }
590
620
  if (store.length) {
591
621
  store.forEach((row) => {
592
- row[ROW_CHECK_INDEX] = checkedList.includes(row[ROW_DATA_INDEX]);
593
- if (row[ROW_CHECK_INDEX]) {
594
- checkInfo.checkedIndex.add(row[ROW_INDEX]);
595
- }
622
+ row[ROW_CHECK_INDEX] = value.includes(row[ROW_DATA_INDEX]);
596
623
  });
597
- checkInfo.isHeaderChecked = checkedList.length === store.length;
624
+ checkInfo.isHeaderChecked = value.length === store.length;
598
625
  }
599
626
  updateVScroll();
600
627
  },
@@ -602,7 +629,37 @@ export default {
602
629
  watch(
603
630
  () => props.selected,
604
631
  (value) => {
605
- selectInfo.selectedRow = value;
632
+ if (selectInfo.useSelect) {
633
+ selectInfo.selectedRow = value;
634
+ }
635
+ },
636
+ );
637
+ watch(
638
+ () => selectInfo.selectedRow,
639
+ (value) => {
640
+ if (selectInfo.useSelect) {
641
+ stores.store.forEach((row) => {
642
+ row[ROW_SELECT_INDEX] = value.includes(row[ROW_DATA_INDEX]);
643
+ });
644
+ updateVScroll();
645
+ }
646
+ },
647
+ );
648
+ watch(
649
+ () => highlightIdx.value,
650
+ async (index) => {
651
+ await nextTick();
652
+ if (index >= 0) {
653
+ if (pageInfo.usePage && !pageInfo.isInfinite) {
654
+ pageInfo.highlightPage = Math.ceil(index / pageInfo.perPage) || 1;
655
+ if (pageInfo.highlightPage !== pageInfo.currentPage) {
656
+ pageInfo.currentPage = pageInfo.highlightPage;
657
+ pageInfo.isHighlight = true;
658
+ return;
659
+ }
660
+ }
661
+ elementInfo.body.scrollTop = resizeInfo.rowHeight * highlightIdx.value;
662
+ }
606
663
  },
607
664
  );
608
665
  watch(
@@ -611,6 +668,18 @@ export default {
611
668
  clearCheckInfo();
612
669
  },
613
670
  );
671
+ watch(
672
+ () => selectInfo.useSelect,
673
+ () => {
674
+ clearSelectInfo();
675
+ },
676
+ );
677
+ watch(
678
+ () => selectInfo.multiple,
679
+ () => {
680
+ clearSelectInfo();
681
+ },
682
+ );
614
683
  watch(
615
684
  () => props.checked.length,
616
685
  (checkedSize) => {
@@ -652,13 +721,11 @@ export default {
652
721
  onSearch(value?.value ?? value);
653
722
  if (pageInfo.isClientPaging) {
654
723
  clearCheckInfo();
724
+ clearSelectInfo();
655
725
  }
656
726
  }
657
727
  }, { immediate: true },
658
728
  );
659
- const isFilterButton = field => filterInfo.isFiltering
660
- && field !== 'db-icon'
661
- && field !== 'user-icon';
662
729
  watch(
663
730
  () => props.option.page?.currentPage,
664
731
  (value) => {
@@ -667,14 +734,19 @@ export default {
667
734
  }, { immediate: true },
668
735
  );
669
736
  watch(
670
- () => [pageInfo.currentPage, pageInfo.perPage],
671
- (currentVal, beforeVal) => {
737
+ () => pageInfo.currentPage,
738
+ (current, before) => {
672
739
  nextTick(() => {
673
- changePage(beforeVal[0]);
674
- if (pageInfo.isClientPaging && currentVal[0] !== beforeVal[0]) {
740
+ changePage(before);
741
+ if (pageInfo.isClientPaging && current !== before) {
675
742
  clearCheckInfo();
743
+ clearSelectInfo();
676
744
  }
677
745
  updateVScroll();
746
+ if (current === pageInfo.highlightPage && pageInfo.isHighlight) {
747
+ elementInfo.body.scrollTop = resizeInfo.rowHeight * highlightIdx.value;
748
+ pageInfo.isHighlight = !pageInfo.isHighlight;
749
+ }
678
750
  });
679
751
  },
680
752
  );
@@ -683,6 +755,8 @@ export default {
683
755
  stripeStyle,
684
756
  borderStyle,
685
757
  highlightIdx,
758
+ useSummary,
759
+ stores,
686
760
  ...toRefs(elementInfo),
687
761
  ...toRefs(stores),
688
762
  ...toRefs(filterInfo),
@@ -719,7 +793,6 @@ export default {
719
793
  setContextMenu,
720
794
  onContextMenu,
721
795
  onSearch,
722
- isFilterButton,
723
796
  };
724
797
  },
725
798
  };
@@ -0,0 +1,235 @@
1
+ <template>
2
+ <div
3
+ :class="{
4
+ 'grid-summary': true,
5
+ 'non-border': styleInfo.borderStyle === 'none',
6
+ }"
7
+ >
8
+ <ul class="column-list">
9
+ <li
10
+ v-if="showCheckbox"
11
+ :class="{
12
+ 'column': true,
13
+ 'non-border': !!styleInfo.borderStyle,
14
+ }"
15
+ :style="{
16
+ 'width': `${styleInfo.minWidth}px`,
17
+ 'line-height': `${styleInfo.rowHeight}px`
18
+ }"
19
+ >
20
+ <span :style="{'height': `${styleInfo.rowHeight}px`}" />
21
+ </li>
22
+ <template
23
+ v-for="(column, index) in columns"
24
+ :key="`summary_${index}`"
25
+ >
26
+ <li
27
+ v-if="!column.hide"
28
+ :class="{
29
+ column: true,
30
+ 'non-border': !!styleInfo.borderStyle,
31
+ [column.type]: column.type,
32
+ [column.align]: column.align,
33
+ }"
34
+ :style="{
35
+ width: `${column.width}px`,
36
+ 'min-width': `${styleInfo.minWidth}px`,
37
+ 'line-height': `${styleInfo.rowHeight}px`,
38
+ }"
39
+ >
40
+ <span
41
+ v-if="column.summaryType || column.summaryRenderer"
42
+ :style="{
43
+ width: '100%',
44
+ height: `${styleInfo.rowHeight}px`,
45
+ }"
46
+ >
47
+ <template v-if="column.summaryRenderer">
48
+ {{ getSummaryRenderer(column) }}
49
+ </template>
50
+ <template v-else>
51
+ {{ getSummaryValue(column, column.summaryType)}}
52
+ </template>
53
+ </span>
54
+ <span
55
+ v-else
56
+ :style="{'height': `${styleInfo.rowHeight}px`}"
57
+ />
58
+ </li>
59
+ </template>
60
+ </ul>
61
+ </div>
62
+ </template>
63
+
64
+ <script>
65
+ import { computed } from 'vue';
66
+ import { numberWithComma } from '@/common/utils';
67
+
68
+ export default {
69
+ name: 'EvGridSummary',
70
+ props: {
71
+ stores: {
72
+ type: Object,
73
+ default: () => ({}),
74
+ },
75
+ orderedColumns: {
76
+ type: Object,
77
+ default: () => ({}),
78
+ },
79
+ useCheckbox: {
80
+ type: Boolean,
81
+ default: false,
82
+ },
83
+ styleOption: {
84
+ type: Object,
85
+ default: () => ({}),
86
+ },
87
+ isTree: {
88
+ type: Boolean,
89
+ default: false,
90
+ },
91
+ },
92
+ setup(props) {
93
+ const ROW_DATA_INDEX = 2;
94
+ const stores = computed(() => props.stores);
95
+ const columns = computed(() => props.orderedColumns);
96
+ const showCheckbox = computed(() => props.useCheckbox);
97
+ const styleInfo = computed(() => props.styleOption);
98
+ const getConvertValue = (column, value) => {
99
+ let convertValue = value;
100
+
101
+ if (column.type === 'number') {
102
+ convertValue = numberWithComma(value);
103
+ convertValue = convertValue === false ? value : convertValue;
104
+ } else if (column.type === 'float') {
105
+ convertValue = convertValue.toFixed(column.decimal ?? 3);
106
+ }
107
+
108
+ return convertValue;
109
+ };
110
+ const getColumnIndex = field => columns.value.findIndex(column => column.field === field);
111
+ const getSummaryValue = (column, summaryType) => {
112
+ let result = '';
113
+ const columnIndex = getColumnIndex(column.field);
114
+ if (columnIndex >= 0) {
115
+ if (summaryType === 'count') {
116
+ return stores.value.store.length;
117
+ }
118
+ if (column.type === 'number' || column.type === 'float') {
119
+ let columnValues = [];
120
+ if (props.isTree) {
121
+ columnValues = stores.value.store.map(node => node.data?.[column.field]);
122
+ } else {
123
+ columnValues = stores.value.store.map(row => row[ROW_DATA_INDEX][columnIndex]);
124
+ }
125
+ switch (summaryType) {
126
+ case 'sum':
127
+ result = columnValues.reduce((prev, curr) => {
128
+ const value = Number(curr);
129
+ if (!Number.isNaN(value)) {
130
+ return prev + value;
131
+ }
132
+ return prev;
133
+ }, 0);
134
+ break;
135
+ case 'average':
136
+ result = columnValues.reduce((prev, curr) => {
137
+ const value = Number(curr);
138
+ if (!Number.isNaN(value)) {
139
+ return prev + value;
140
+ }
141
+ return prev;
142
+ }, 0) / columnValues.length;
143
+ if (result % 1 !== 0) {
144
+ result = result.toFixed(1);
145
+ }
146
+ break;
147
+ case 'max':
148
+ result = Math.max(...columnValues);
149
+ break;
150
+ case 'min':
151
+ result = Math.min(...columnValues);
152
+ break;
153
+ default:
154
+ break;
155
+ }
156
+ result = getConvertValue(column, result);
157
+ }
158
+ }
159
+ return result;
160
+ };
161
+ const getSummaryRenderer = (column) => {
162
+ const str = column.summaryRenderer;
163
+ const summaryData = column.summaryData ? column.summaryData : [];
164
+ const fields = [column.field, ...summaryData];
165
+ let result = str;
166
+ fields.forEach((name, idx) => {
167
+ const columnIndex = getColumnIndex(name);
168
+ if (columnIndex >= 0) {
169
+ const value = getSummaryValue(
170
+ stores.value.orderedColumns[columnIndex],
171
+ column.summaryType,
172
+ );
173
+ result = result.replace(`{${idx}}`, value);
174
+ }
175
+ });
176
+ return result;
177
+ };
178
+ return {
179
+ columns,
180
+ styleInfo,
181
+ showCheckbox,
182
+ getSummaryValue,
183
+ getSummaryRenderer,
184
+ };
185
+ },
186
+ };
187
+ </script>
188
+
189
+ <style lang="scss" scoped>
190
+ @import 'style/grid.scss';
191
+ .grid-summary {
192
+ @include evThemify() {
193
+ border-bottom: 1px solid evThemed('disabled');
194
+ background-color: evThemed('background-lighten');
195
+ }
196
+ .non-border {
197
+ border-bottom: none !important;
198
+ }
199
+ span {
200
+ display: inline-block;
201
+ overflow: hidden;
202
+ text-overflow: ellipsis;
203
+ font-size: 14px;
204
+
205
+ @include evThemify() {
206
+ color: evThemed('font-color-base');
207
+ }
208
+ }
209
+ .column {
210
+ &.number,
211
+ &.float {
212
+ text-align: right;
213
+ }
214
+ &.string,
215
+ &.stringNumber {
216
+ text-align: left;
217
+ }
218
+ &.center {
219
+ text-align: center;
220
+ }
221
+ &.left {
222
+ text-align: left;
223
+ .wrap {
224
+ justify-content: flex-start;
225
+ }
226
+ }
227
+ &.right {
228
+ text-align: right;
229
+ .wrap {
230
+ justify-content: flex-end;
231
+ }
232
+ }
233
+ }
234
+ }
235
+ </style>
@@ -71,11 +71,6 @@
71
71
  font-size: 13px;
72
72
  color: #005CC8;
73
73
  }
74
- &.db-icon, &.user-icon {
75
- width: 42px !important;
76
- min-width: 42px !important;
77
- border-right: 0;
78
- }
79
74
  }
80
75
 
81
76
  .column-name {
@@ -229,14 +224,6 @@
229
224
  &:last-child {
230
225
  border-right: 0;
231
226
  }
232
- &.user-icon {
233
- height: auto !important;
234
- }
235
- &.db-icon, &.user-icon {
236
- width: 42px !important;
237
- min-width: 42px !important;
238
- border-right: 0;
239
- }
240
227
  }
241
228
  }
242
229
 
@@ -271,4 +258,3 @@
271
258
  height: 30px;
272
259
  text-align: center;
273
260
  }
274
-