evui 3.3.36 → 3.3.39

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 (141) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +40 -40
  3. package/dist/evui.common.js +1907 -1832
  4. package/dist/evui.common.js.map +1 -1
  5. package/dist/evui.umd.js +1907 -1832
  6. package/dist/evui.umd.js.map +1 -1
  7. package/dist/evui.umd.min.js +1 -1
  8. package/dist/evui.umd.min.js.map +1 -1
  9. package/dist/img/{EVUI.7f3588fb.svg → EVUI.b82ee81a.svg} +292 -292
  10. package/dist/img/{icon_mysql.7ea26d5d.svg → icon_mysql.1085fdc9.svg} +78 -78
  11. package/dist/img/{icon_oracle.9009b108.svg → icon_oracle.0572d3ee.svg} +13 -13
  12. package/dist/img/{icon_postgresql.f8fffba9.svg → icon_postgresql.ee12bde8.svg} +58 -58
  13. package/package.json +61 -61
  14. package/src/common/emitter.js +20 -20
  15. package/src/common/utils.debounce.js +223 -223
  16. package/src/common/utils.js +134 -134
  17. package/src/common/utils.table.js +78 -78
  18. package/src/common/utils.throttle.js +83 -83
  19. package/src/common/utils.tree.js +18 -18
  20. package/src/components/button/Button.vue +198 -198
  21. package/src/components/button/index.js +7 -7
  22. package/src/components/buttonGroup/ButtonGroup.vue +11 -11
  23. package/src/components/buttonGroup/index.js +7 -7
  24. package/src/components/calendar/Calendar.vue +661 -661
  25. package/src/components/calendar/index.js +7 -7
  26. package/src/components/calendar/uses.js +1272 -1272
  27. package/src/components/chart/Chart.vue +189 -192
  28. package/src/components/chart/chart.core.js +870 -870
  29. package/src/components/chart/element/element.bar.js +524 -524
  30. package/src/components/chart/element/element.bar.time.js +156 -156
  31. package/src/components/chart/element/element.heatmap.js +533 -533
  32. package/src/components/chart/element/element.line.js +339 -339
  33. package/src/components/chart/element/element.pie.js +197 -197
  34. package/src/components/chart/element/element.scatter.js +184 -184
  35. package/src/components/chart/element/element.tip.js +550 -542
  36. package/src/components/chart/helpers/helpers.canvas.js +265 -265
  37. package/src/components/chart/helpers/helpers.constant.js +206 -206
  38. package/src/components/chart/helpers/helpers.util.js +346 -338
  39. package/src/components/chart/index.js +9 -9
  40. package/src/components/chart/model/index.js +4 -4
  41. package/src/components/chart/model/model.series.js +93 -93
  42. package/src/components/chart/model/model.store.js +977 -967
  43. package/src/components/chart/plugins/plugins.interaction.js +769 -769
  44. package/src/components/chart/plugins/plugins.legend.gradient.js +602 -602
  45. package/src/components/chart/plugins/plugins.legend.js +1155 -1151
  46. package/src/components/chart/plugins/plugins.pie.js +254 -254
  47. package/src/components/chart/plugins/plugins.title.js +56 -56
  48. package/src/components/chart/plugins/plugins.tooltip.js +692 -692
  49. package/src/components/chart/scale/scale.js +848 -848
  50. package/src/components/chart/scale/scale.linear.js +38 -38
  51. package/src/components/chart/scale/scale.logarithmic.js +128 -128
  52. package/src/components/chart/scale/scale.step.js +336 -336
  53. package/src/components/chart/scale/scale.time.category.js +277 -277
  54. package/src/components/chart/scale/scale.time.js +48 -48
  55. package/src/components/chart/style/chart.scss +312 -312
  56. package/src/components/chart/uses.js +264 -252
  57. package/src/components/checkbox/Checkbox.vue +200 -200
  58. package/src/components/checkbox/index.js +7 -7
  59. package/src/components/checkboxGroup/CheckboxGroup.vue +44 -44
  60. package/src/components/checkboxGroup/index.js +7 -7
  61. package/src/components/contextMenu/ContextMenu.vue +80 -80
  62. package/src/components/contextMenu/MenuList.vue +149 -149
  63. package/src/components/contextMenu/index.js +7 -7
  64. package/src/components/contextMenu/uses.js +203 -203
  65. package/src/components/datePicker/DatePicker.vue +437 -437
  66. package/src/components/datePicker/index.js +7 -7
  67. package/src/components/datePicker/uses.js +419 -419
  68. package/src/components/grid/Grid.vue +827 -827
  69. package/src/components/grid/grid.filter.window.vue +493 -493
  70. package/src/components/grid/grid.pagination.vue +75 -75
  71. package/src/components/grid/grid.summary.vue +265 -265
  72. package/src/components/grid/grid.toolbar.vue +26 -26
  73. package/src/components/grid/index.js +11 -11
  74. package/src/components/grid/style/grid.scss +263 -263
  75. package/src/components/grid/uses.js +1002 -1007
  76. package/src/components/icon/Icon.vue +49 -49
  77. package/src/components/icon/index.js +8 -8
  78. package/src/components/inputNumber/InputNumber.vue +212 -212
  79. package/src/components/inputNumber/index.js +7 -7
  80. package/src/components/inputNumber/uses.js +217 -217
  81. package/src/components/loading/Loading.vue +125 -125
  82. package/src/components/loading/index.js +7 -7
  83. package/src/components/menu/Menu.vue +68 -68
  84. package/src/components/menu/MenuItem.vue +187 -187
  85. package/src/components/menu/index.js +7 -7
  86. package/src/components/message/Message.vue +223 -223
  87. package/src/components/message/index.js +31 -31
  88. package/src/components/messageBox/MessageBox.vue +358 -358
  89. package/src/components/messageBox/index.js +22 -22
  90. package/src/components/notification/Notification.vue +316 -316
  91. package/src/components/notification/index.js +49 -49
  92. package/src/components/pagination/Pagination.vue +271 -271
  93. package/src/components/pagination/index.js +7 -7
  94. package/src/components/pagination/pageButton.vue +30 -30
  95. package/src/components/progress/Progress.vue +139 -139
  96. package/src/components/progress/index.js +7 -7
  97. package/src/components/radio/Radio.vue +159 -159
  98. package/src/components/radio/index.js +7 -7
  99. package/src/components/radioGroup/RadioGroup.vue +41 -41
  100. package/src/components/radioGroup/index.js +7 -7
  101. package/src/components/scheduler/Scheduler.vue +149 -149
  102. package/src/components/scheduler/index.js +7 -7
  103. package/src/components/scheduler/uses.js +183 -183
  104. package/src/components/select/Select.vue +440 -440
  105. package/src/components/select/index.js +7 -7
  106. package/src/components/select/uses.js +270 -270
  107. package/src/components/slider/Slider.vue +505 -505
  108. package/src/components/slider/index.js +7 -7
  109. package/src/components/slider/uses.js +390 -390
  110. package/src/components/tabPanel/TabPanel.vue +74 -74
  111. package/src/components/tabPanel/index.js +7 -7
  112. package/src/components/tabs/Tabs.vue +517 -517
  113. package/src/components/tabs/index.js +7 -7
  114. package/src/components/textField/TextField.vue +375 -375
  115. package/src/components/textField/index.js +7 -7
  116. package/src/components/timePicker/TimePicker.vue +352 -352
  117. package/src/components/timePicker/index.js +7 -7
  118. package/src/components/toggle/Toggle.vue +115 -115
  119. package/src/components/toggle/index.js +7 -7
  120. package/src/components/tree/Tree.vue +313 -313
  121. package/src/components/tree/TreeNode.vue +293 -293
  122. package/src/components/tree/index.js +7 -7
  123. package/src/components/treeGrid/TreeGrid.vue +758 -758
  124. package/src/components/treeGrid/TreeGridNode.vue +275 -275
  125. package/src/components/treeGrid/index.js +9 -9
  126. package/src/components/treeGrid/style/treeGrid.scss +261 -261
  127. package/src/components/treeGrid/treeGrid.toolbar.vue +26 -26
  128. package/src/components/treeGrid/uses.js +867 -867
  129. package/src/components/window/Window.vue +329 -329
  130. package/src/components/window/index.js +7 -7
  131. package/src/components/window/uses.js +899 -899
  132. package/src/directives/clickoutside.js +90 -90
  133. package/src/main.js +116 -116
  134. package/src/style/components/input.scss +108 -108
  135. package/src/style/functions.scss +3 -3
  136. package/src/style/index.scss +6 -6
  137. package/src/style/lib/fonts/EVUI.svg +292 -292
  138. package/src/style/lib/icon.css +888 -888
  139. package/src/style/mixins.scss +94 -94
  140. package/src/style/themes.scss +67 -67
  141. package/src/style/variables.scss +22 -22
@@ -1,758 +1,758 @@
1
- <template>
2
- <div
3
- v-if="$slots.toolbar"
4
- class="toolbar-wrapper"
5
- :style="`width: ${gridWidth};`"
6
- >
7
- <!-- Toolbar -->
8
- <toolbar>
9
- <template #toolbarWrapper>
10
- <slot
11
- name="toolbar"
12
- :item="{
13
- onSearch,
14
- }"
15
- />
16
- </template>
17
- </toolbar>
18
- </div>
19
- <div
20
- ref="grid-wrapper"
21
- v-resize="onResize"
22
- v-observe-visibility="{
23
- callback: onShow,
24
- once: true,
25
- }"
26
- :style="gridStyle"
27
- >
28
- <!-- Table -->
29
- <div
30
- v-cloak
31
- ref="grid"
32
- :class="gridClass"
33
- >
34
- <!-- Header -->
35
- <div
36
- v-show="showHeader"
37
- ref="header"
38
- :class="headerClass"
39
- >
40
- <ul class="column-list">
41
- <!-- Header Checkbox -->
42
- <li
43
- v-if="useCheckbox.use"
44
- :class="headerCheckboxClass"
45
- :style="`width: ${minWidth}px;`"
46
- >
47
- <ev-checkbox
48
- v-if="isHeaderCheckbox"
49
- v-model="isHeaderChecked"
50
- @change="onCheckAll"
51
- />
52
- </li>
53
- <!-- Column List -->
54
- <template
55
- v-for="(column, index) in orderedColumns"
56
- :key="index"
57
- >
58
- <li
59
- v-if="!column.hide"
60
- :data-index="index"
61
- :class="getColumnClass(column)"
62
- :style="getColumnStyle(column, index)"
63
- >
64
- <!-- Column Name -->
65
- <span
66
- :title="column.caption"
67
- class="column-name"
68
- >
69
- {{ column.caption }}
70
- </span>
71
- <!-- Column Resize -->
72
- <span
73
- class="column-resize"
74
- @mousedown.stop.left="onColumnResize(index, $event)"
75
- />
76
- </li>
77
- </template>
78
- </ul>
79
- </div>
80
- <!-- Body -->
81
- <div
82
- ref="body"
83
- :class="bodyStyle"
84
- @scroll="onScroll"
85
- @contextmenu="onContextMenu($event)"
86
- @contextmenu.prevent="menu.show"
87
- >
88
- <!-- vScroll Top -->
89
- <div
90
- :style="`height: ${vScrollTopHeight}px;`"
91
- class="vscroll-spacer"
92
- />
93
- <table ref="table">
94
- <tbody>
95
- <tree-grid-node
96
- v-for="(node, idx) in viewStore"
97
- :key="idx"
98
- :selected-data="selectedRow"
99
- :node-data="node"
100
- :use-checkbox="useCheckbox"
101
- :ordered-columns="orderedColumns"
102
- :expand-icon="option.expandIcon"
103
- :collapse-icon="option.collapseIcon"
104
- :parent-icon="option.parentIcon"
105
- :child-icon="option.childIcon"
106
- :is-resize="isResize"
107
- :row-height="rowHeight"
108
- :min-width="minWidth"
109
- :highlight-index="highlightIdx"
110
- :border-style="borderStyle"
111
- @check-tree-data="onCheck"
112
- @expand-tree-data="handleExpand"
113
- @click-tree-data="onRowClick"
114
- @dbl-click-tree-data="onRowDblClick"
115
- >
116
- <!-- Cell Renderer -->
117
- <template
118
- v-for="(column, cellIndex) in orderedColumns"
119
- :key="cellIndex"
120
- v-slot:[getSlotName(column.field)] = "{ item }"
121
- >
122
- <template v-if="!!$slots[column.field]">
123
- <slot
124
- :name="column.field"
125
- :item="{
126
- data: item.data,
127
- fieldName: column.field
128
- }"
129
- >
130
- </slot>
131
- </template>
132
- <template v-else>
133
- <span :title="getConvertValue(column, node[column.field])">
134
- {{ getConvertValue(column, node[column.field]) }}
135
- </span>
136
- </template>
137
- </template>
138
- </tree-grid-node>
139
- <tr v-if="!viewStore.length">
140
- <td class="is-empty">No records</td>
141
- </tr>
142
- </tbody>
143
- </table>
144
- <!-- vScroll Bottom -->
145
- <div
146
- :style="`height: ${vScrollBottomHeight}px;`"
147
- class="vscroll-spacer"
148
- />
149
- <!-- Context Menu -->
150
- <ev-context-menu
151
- ref="menu"
152
- :items="contextMenuItems"
153
- />
154
- </div>
155
- <!-- Resize Line -->
156
- <div
157
- v-show="showResizeLine"
158
- ref="resizeLine"
159
- class="table-resize-line"
160
- />
161
- </div>
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
- :scroll-left="summaryScroll"
176
- />
177
- <!-- Pagination -->
178
- <grid-pagination
179
- v-if="usePage && !isInfinite"
180
- v-model="currentPage"
181
- :total="showTreeStore.length"
182
- :per-page="perPage"
183
- :visible-page="visiblePage"
184
- :show-page-info="showPageInfo"
185
- :order="order"
186
- />
187
- </template>
188
-
189
- <script>
190
- import { reactive, toRefs, computed, watch, onMounted, onActivated, nextTick, ref } from 'vue';
191
- import treeGridNode from './TreeGridNode';
192
- import Toolbar from './treeGrid.toolbar';
193
- import GridPagination from '../grid/grid.pagination';
194
- import GridSummary from '../grid/grid.summary';
195
- import {
196
- commonFunctions,
197
- scrollEvent,
198
- resizeEvent,
199
- clickEvent,
200
- checkEvent,
201
- contextMenuEvent,
202
- treeEvent,
203
- filterEvent,
204
- pagingEvent,
205
- } from './uses';
206
-
207
- export default {
208
- name: 'EvTreeGrid',
209
- components: {
210
- treeGridNode,
211
- Toolbar,
212
- GridPagination,
213
- GridSummary,
214
- },
215
- props: {
216
- columns: {
217
- type: [Array],
218
- default: () => [],
219
- },
220
- rows: {
221
- type: [Array, Object],
222
- default: () => null,
223
- },
224
- width: {
225
- type: [String, Number],
226
- default: '100%',
227
- },
228
- height: {
229
- type: [String, Number],
230
- default: '100%',
231
- },
232
- selected: {
233
- type: [Array],
234
- default: () => [],
235
- },
236
- checked: {
237
- type: [Array],
238
- default: () => [],
239
- },
240
- option: {
241
- type: Object,
242
- default: () => ({}),
243
- },
244
- expandIcon: {
245
- type: String,
246
- default: '',
247
- },
248
- collapseIcon: {
249
- type: String,
250
- default: '',
251
- },
252
- },
253
- emits: {
254
- 'update:selected': null,
255
- 'click-row': null,
256
- 'dblclick-row': null,
257
- 'update:checked': null,
258
- 'check-row': null,
259
- 'check-all': null,
260
- 'page-change': null,
261
- },
262
- setup(props) {
263
- const useSummary = computed(() => (props.option?.useSummary || false));
264
- const elementInfo = reactive({
265
- body: null,
266
- header: null,
267
- table: null,
268
- resizeLine: null,
269
- 'grid-wrapper': null,
270
- });
271
- const filterInfo = reactive({
272
- isSearch: false,
273
- searchWord: '',
274
- });
275
- const stores = reactive({
276
- treeStore: [],
277
- viewStore: [],
278
- filterStore: [],
279
- pagingStore: [],
280
- treeRows: props.rows,
281
- searchStore: computed(() => stores.treeStore.filter(item => item.isFilter)),
282
- showTreeStore: computed(() => stores.treeStore.filter(item => item.show)),
283
- orderedColumns: computed(() =>
284
- props.columns.map((column, index) => ({ index, ...column }))),
285
- store: computed(() => (filterInfo.isSearch ? stores.searchStore : stores.treeStore)),
286
- });
287
- const pageInfo = reactive({
288
- usePage: computed(() => (props.option.page?.use || false)),
289
- useClient: props.option.page?.useClient || false,
290
- isInfinite: computed(() => (props.option.page?.isInfinite || false)),
291
- startIndex: 0,
292
- prevPage: 0,
293
- currentPage: 0,
294
- pageTotal: computed(() => (props.option.page?.total || 0)),
295
- perPage: computed(() => (props.option.page?.perPage || 20)),
296
- visiblePage: computed(() => (props.option.page?.visiblePage || 8)),
297
- order: computed(() => (props.option.page?.order || 'center')),
298
- showPageInfo: computed(() => (props.option.page?.showPageInfo || false)),
299
- isClientPaging: computed(() =>
300
- pageInfo.useClient && pageInfo.usePage && !pageInfo.isInfinite),
301
- isHighlight: false,
302
- highlightPage: 0,
303
- });
304
- const checkInfo = reactive({
305
- prevCheckedRow: [],
306
- isHeaderChecked: false,
307
- checkedRows: props.checked,
308
- useCheckbox: computed(() => props.option.useCheckbox || {}),
309
- });
310
- const {
311
- isRenderer,
312
- getComponentName,
313
- getConvertValue,
314
- getColumnIndex,
315
- setPixelUnit,
316
- checkHeader,
317
- } = commonFunctions({ checkInfo });
318
- const scrollInfo = reactive({
319
- lastScroll: {
320
- top: 0,
321
- left: 0,
322
- },
323
- vScrollTopHeight: 0,
324
- vScrollBottomHeight: 0,
325
- hasVerticalScrollBar: false,
326
- hasHorizontalScrollBar: false,
327
- });
328
- const selectInfo = reactive({
329
- selectedRow: props.selected,
330
- useSelect: computed(() => props.option?.useSelection?.use ?? true),
331
- limitCount: computed(() => {
332
- let limit = props.option?.useSelection?.limitCount;
333
- limit = !!limit && limit >= 2 ? limit : 0;
334
- return limit;
335
- }),
336
- multiple: computed(() => props.option?.useSelection?.multiple ?? false),
337
- });
338
- const contextInfo = reactive({
339
- menu: null,
340
- contextMenuItems: [],
341
- customContextMenu: props.option.customContextMenu || [],
342
- });
343
- const resizeInfo = reactive({
344
- minWidth: 40,
345
- rendererMinWidth: 80,
346
- showResizeLine: false,
347
- adjust: props.option.adjust || false,
348
- columnWidth: props.option.columnWidth || 80,
349
- scrollWidth: props.option.scrollWidth || 17,
350
- rowHeight: computed(() => props.option.rowHeight || 35),
351
- gridWidth: computed(() => (props.width ? setPixelUnit(props.width) : '100%')),
352
- gridHeight: computed(() => (props.height ? setPixelUnit(props.height) : '100%')),
353
- isResize: false,
354
- });
355
- const styleInfo = reactive({
356
- showHeader: computed(() =>
357
- (props.option.showHeader === undefined ? true : props.option.showHeader)),
358
- stripeStyle: computed(() => props.option.style?.stripe || false),
359
- borderStyle: computed(() => props.option.style?.border || ''),
360
- highlightIdx: computed(() => props.option.style?.highlight ?? -1),
361
- });
362
- const clearSelectInfo = () => {
363
- selectInfo.selectedRow.length = 0;
364
- stores.store.forEach((row) => {
365
- row.selected = false;
366
- });
367
- };
368
- const clearCheckInfo = () => {
369
- checkInfo.isHeaderChecked = false;
370
- checkInfo.checkedRows.length = 0;
371
- stores.store.forEach((row) => {
372
- row.checked = false;
373
- });
374
- };
375
- const {
376
- getPagingData,
377
- updatePagingInfo,
378
- changePage,
379
- } = pagingEvent({
380
- stores,
381
- pageInfo,
382
- filterInfo,
383
- elementInfo,
384
- clearCheckInfo,
385
- });
386
- const summaryScroll = ref(0);
387
- const {
388
- updateVScroll,
389
- updateHScroll,
390
- onScroll,
391
- } = scrollEvent({
392
- scrollInfo,
393
- stores,
394
- elementInfo,
395
- resizeInfo,
396
- pageInfo,
397
- summaryScroll,
398
- getPagingData,
399
- updatePagingInfo,
400
- });
401
-
402
- const {
403
- onRowClick,
404
- onRowDblClick,
405
- } = clickEvent(selectInfo);
406
-
407
- const {
408
- onCheck,
409
- onCheckAll,
410
- } = checkEvent({
411
- checkInfo,
412
- stores,
413
- checkHeader,
414
- pageInfo,
415
- getPagingData,
416
- updatePagingInfo,
417
- });
418
-
419
- const {
420
- calculatedColumn,
421
- onResize,
422
- onShow,
423
- onColumnResize,
424
- } = resizeEvent({
425
- resizeInfo,
426
- elementInfo,
427
- checkInfo,
428
- stores,
429
- isRenderer,
430
- updateVScroll,
431
- updateHScroll,
432
- });
433
-
434
- const {
435
- setContextMenu,
436
- onContextMenu,
437
- } = contextMenuEvent({ contextInfo, stores, selectInfo });
438
-
439
- const {
440
- setTreeNodeStore,
441
- handleExpand,
442
- } = treeEvent({ stores, onResize });
443
-
444
- const {
445
- onSearch,
446
- } = filterEvent({
447
- stores,
448
- filterInfo,
449
- pageInfo,
450
- getConvertValue,
451
- onResize,
452
- checkHeader,
453
- getPagingData,
454
- updatePagingInfo,
455
- });
456
-
457
- onMounted(() => {
458
- stores.treeStore = setTreeNodeStore();
459
- });
460
- onActivated(() => {
461
- onResize();
462
- });
463
-
464
- watch(
465
- () => props.checked,
466
- (value) => {
467
- checkInfo.checkedRows = value;
468
- },
469
- );
470
- watch(
471
- () => checkInfo.checkedRows,
472
- (value) => {
473
- checkInfo.isHeaderChecked = false;
474
- let store = stores.store;
475
- if (pageInfo.isClientPaging) {
476
- store = getPagingData();
477
- }
478
- if (store.length) {
479
- store.forEach((row) => {
480
- row.checked = !!value.find(checkedRow => checkedRow.index === row.index);
481
- });
482
- checkHeader(store);
483
- }
484
- updateVScroll();
485
- },
486
- );
487
- watch(
488
- () => props.selected,
489
- (value) => {
490
- if (selectInfo.useSelect) {
491
- selectInfo.selectedRow = value;
492
- }
493
- },
494
- );
495
- watch(
496
- () => selectInfo.selectedRow,
497
- (value) => {
498
- if (selectInfo.useSelect) {
499
- stores.store.forEach((row) => {
500
- row.selected = !!value.find(selectedRow => selectedRow.index === row.index);
501
- });
502
- updateVScroll();
503
- }
504
- }, { deep: true },
505
- );
506
- watch(
507
- () => styleInfo.highlightIdx,
508
- async (index) => {
509
- await nextTick();
510
- const setChildShow = (data) => {
511
- if (!data?.children) {
512
- return;
513
- }
514
- const { children } = data;
515
- children.forEach((node) => {
516
- const childNode = node;
517
- if (childNode.parent.show && childNode.parent.expand) {
518
- childNode.show = true;
519
- } else {
520
- childNode.show = false;
521
- }
522
- childNode.isFilter = true;
523
- if (childNode.hasChild) {
524
- setChildShow(childNode);
525
- }
526
- });
527
- };
528
- const setParentShow = (data) => {
529
- if (!data?.parent) {
530
- setChildShow(data);
531
- return;
532
- }
533
- const { parent } = data;
534
- parent.show = true;
535
- parent.isFilter = true;
536
- parent.expand = true;
537
- setChildShow(parent);
538
- setParentShow(parent);
539
- };
540
- if (index >= 0) {
541
- const highlightNode = stores.store.find(node => node.index === index);
542
- if (!highlightNode) {
543
- return;
544
- }
545
- // highlightNode parents 자동 펼치기
546
- highlightNode.show = true;
547
- highlightNode.isFilter = true;
548
- setParentShow(highlightNode);
549
- // tree 에 보여지는 데이터 기준으로 index 다시 구하기
550
- const highlightIndex = stores.showTreeStore
551
- .map(node => node.index)
552
- .indexOf(highlightNode.index);
553
- if (pageInfo.usePage && !pageInfo.isInfinite) {
554
- const page = Math.ceil(highlightIndex / pageInfo.perPage);
555
- pageInfo.highlightPage = highlightIndex === pageInfo.perPage ? page + 1 : page || 1;
556
- // 페이지 이동
557
- if (pageInfo.highlightPage !== pageInfo.currentPage) {
558
- pageInfo.currentPage = pageInfo.highlightPage;
559
- pageInfo.isHighlight = true;
560
- return;
561
- }
562
- }
563
- elementInfo.body.scrollTop = resizeInfo.rowHeight * highlightIndex;
564
- }
565
- },
566
- );
567
- watch(
568
- () => checkInfo.useCheckbox.mode,
569
- () => {
570
- checkInfo.checkedRows = [];
571
- checkInfo.isHeaderChecked = false;
572
- },
573
- );
574
- watch(
575
- () => selectInfo.useSelect,
576
- () => {
577
- clearSelectInfo();
578
- },
579
- );
580
- watch(
581
- () => selectInfo.multiple,
582
- () => {
583
- clearSelectInfo();
584
- },
585
- );
586
- watch(
587
- () => props.rows,
588
- (newData) => {
589
- stores.treeRows = newData;
590
- stores.treeStore = setTreeNodeStore();
591
- onResize();
592
- }, { deep: true },
593
- );
594
- watch(
595
- () => stores.treeStore.length,
596
- () => {
597
- checkHeader(stores.store);
598
- },
599
- );
600
- watch(
601
- () => [props.width, props.height, props.option.columnWidth],
602
- (value) => {
603
- resizeInfo.columnWidth = value[3];
604
- stores.orderedColumns.map((column) => {
605
- const item = column;
606
-
607
- if (!props.columns[column.index].width && !item.resized) {
608
- item.width = 0;
609
- }
610
-
611
- return item;
612
- });
613
- onResize();
614
- },
615
- );
616
- watch(
617
- () => props.option.searchValue,
618
- (value) => {
619
- nextTick(() => {
620
- if (value !== undefined) {
621
- onSearch(value?.value ?? value);
622
- if (pageInfo.isClientPaging) {
623
- clearCheckInfo();
624
- clearSelectInfo();
625
- }
626
- }
627
- });
628
- }, { immediate: true },
629
- );
630
- watch(
631
- () => props.option.page?.currentPage,
632
- (value) => {
633
- const current = !value ? 1 : value;
634
- pageInfo.currentPage = !props.option.page?.isInfinite ? current : 1;
635
- }, { immediate: true },
636
- );
637
- watch(
638
- () => pageInfo.currentPage,
639
- (current, before) => {
640
- nextTick(() => {
641
- changePage(before);
642
- if (pageInfo.isClientPaging && current !== before) {
643
- clearCheckInfo();
644
- clearSelectInfo();
645
- }
646
- updateVScroll();
647
- if (current === pageInfo.highlightPage && pageInfo.isHighlight) {
648
- const highlightIndex = stores.pagingStore
649
- .map(node => node.index)
650
- .indexOf(styleInfo.highlightIdx);
651
- elementInfo.body.scrollTop = resizeInfo.rowHeight * highlightIndex;
652
- pageInfo.isHighlight = !pageInfo.isHighlight;
653
- }
654
- });
655
- },
656
- );
657
- const gridStyle = computed(() => ({
658
- width: resizeInfo.gridWidth,
659
- height: resizeInfo.gridHeight,
660
- }));
661
- const bodyStyle = computed(() => ({
662
- 'table-body': true,
663
- stripe: styleInfo.stripeStyle,
664
- 'bottom-border': !!stores.viewStore.length,
665
- 'non-border': !!styleInfo.borderStyle,
666
- }));
667
- const gridClass = computed(() => ({
668
- table: true,
669
- 'ev-grid': true,
670
- 'ev-tree-grid': true,
671
- adjust: resizeInfo.adjust,
672
- 'non-header': !styleInfo.showHeader,
673
- 'ev-tree-grid--empty': !stores.viewStore.length,
674
- }));
675
- const headerClass = computed(() => ({
676
- 'table-header': true,
677
- 'non-border': !!styleInfo.borderStyle,
678
- }));
679
- const headerCheckboxClass = computed(() => ({
680
- column: true,
681
- 'non-border': !!styleInfo.borderStyle,
682
- }));
683
- const isHeaderCheckbox = computed(() => (
684
- checkInfo.useCheckbox.use
685
- && checkInfo.useCheckbox.headerCheck
686
- && checkInfo.useCheckbox.mode !== 'single'
687
- ));
688
- const getColumnClass = (column) => {
689
- const render = isRenderer(column);
690
- return {
691
- column: true,
692
- render,
693
- 'non-border': !!styleInfo.borderStyle,
694
- };
695
- };
696
- const getColumnStyle = (column, index) => {
697
- const render = isRenderer(column);
698
- return {
699
- width: `${column.width}px`,
700
- 'min-width': render ? `${resizeInfo.rendererMinWidth}px;` : `${resizeInfo.minWidth}px`,
701
- 'margin-right': (stores.orderedColumns.length - 1 === index
702
- && scrollInfo.hasVerticalScrollBar
703
- && scrollInfo.hasHorizontalScrollBar) ? `${resizeInfo.scrollWidth}px` : '0px',
704
- };
705
- };
706
- const getSlotName = column => `${column}Node`;
707
-
708
- return {
709
- summaryScroll,
710
- gridStyle,
711
- gridClass,
712
- headerClass,
713
- headerCheckboxClass,
714
- isHeaderCheckbox,
715
- bodyStyle,
716
- useSummary,
717
- stores,
718
- ...toRefs(styleInfo),
719
- ...toRefs(elementInfo),
720
- ...toRefs(stores),
721
- ...toRefs(filterInfo),
722
- ...toRefs(scrollInfo),
723
- ...toRefs(resizeInfo),
724
- ...toRefs(selectInfo),
725
- ...toRefs(checkInfo),
726
- ...toRefs(contextInfo),
727
- ...toRefs(pageInfo),
728
- isRenderer,
729
- getComponentName,
730
- getConvertValue,
731
- getColumnIndex,
732
- setPixelUnit,
733
- updateVScroll,
734
- updateHScroll,
735
- onScroll,
736
- calculatedColumn,
737
- onResize,
738
- onShow,
739
- onColumnResize,
740
- onRowClick,
741
- onRowDblClick,
742
- onCheck,
743
- onCheckAll,
744
- setContextMenu,
745
- onContextMenu,
746
- onSearch,
747
- handleExpand,
748
- getColumnClass,
749
- getColumnStyle,
750
- getSlotName,
751
- };
752
- },
753
- };
754
- </script>
755
-
756
- <style lang="scss" scoped>
757
- @import './style/treeGrid.scss';
758
- </style>
1
+ <template>
2
+ <div
3
+ v-if="$slots.toolbar"
4
+ class="toolbar-wrapper"
5
+ :style="`width: ${gridWidth};`"
6
+ >
7
+ <!-- Toolbar -->
8
+ <toolbar>
9
+ <template #toolbarWrapper>
10
+ <slot
11
+ name="toolbar"
12
+ :item="{
13
+ onSearch,
14
+ }"
15
+ />
16
+ </template>
17
+ </toolbar>
18
+ </div>
19
+ <div
20
+ ref="grid-wrapper"
21
+ v-resize="onResize"
22
+ v-observe-visibility="{
23
+ callback: onShow,
24
+ once: true,
25
+ }"
26
+ :style="gridStyle"
27
+ >
28
+ <!-- Table -->
29
+ <div
30
+ v-cloak
31
+ ref="grid"
32
+ :class="gridClass"
33
+ >
34
+ <!-- Header -->
35
+ <div
36
+ v-show="showHeader"
37
+ ref="header"
38
+ :class="headerClass"
39
+ >
40
+ <ul class="column-list">
41
+ <!-- Header Checkbox -->
42
+ <li
43
+ v-if="useCheckbox.use"
44
+ :class="headerCheckboxClass"
45
+ :style="`width: ${minWidth}px;`"
46
+ >
47
+ <ev-checkbox
48
+ v-if="isHeaderCheckbox"
49
+ v-model="isHeaderChecked"
50
+ @change="onCheckAll"
51
+ />
52
+ </li>
53
+ <!-- Column List -->
54
+ <template
55
+ v-for="(column, index) in orderedColumns"
56
+ :key="index"
57
+ >
58
+ <li
59
+ v-if="!column.hide"
60
+ :data-index="index"
61
+ :class="getColumnClass(column)"
62
+ :style="getColumnStyle(column, index)"
63
+ >
64
+ <!-- Column Name -->
65
+ <span
66
+ :title="column.caption"
67
+ class="column-name"
68
+ >
69
+ {{ column.caption }}
70
+ </span>
71
+ <!-- Column Resize -->
72
+ <span
73
+ class="column-resize"
74
+ @mousedown.stop.left="onColumnResize(index, $event)"
75
+ />
76
+ </li>
77
+ </template>
78
+ </ul>
79
+ </div>
80
+ <!-- Body -->
81
+ <div
82
+ ref="body"
83
+ :class="bodyStyle"
84
+ @scroll="onScroll"
85
+ @contextmenu="onContextMenu($event)"
86
+ @contextmenu.prevent="menu.show"
87
+ >
88
+ <!-- vScroll Top -->
89
+ <div
90
+ :style="`height: ${vScrollTopHeight}px;`"
91
+ class="vscroll-spacer"
92
+ />
93
+ <table ref="table">
94
+ <tbody>
95
+ <tree-grid-node
96
+ v-for="(node, idx) in viewStore"
97
+ :key="idx"
98
+ :selected-data="selectedRow"
99
+ :node-data="node"
100
+ :use-checkbox="useCheckbox"
101
+ :ordered-columns="orderedColumns"
102
+ :expand-icon="option.expandIcon"
103
+ :collapse-icon="option.collapseIcon"
104
+ :parent-icon="option.parentIcon"
105
+ :child-icon="option.childIcon"
106
+ :is-resize="isResize"
107
+ :row-height="rowHeight"
108
+ :min-width="minWidth"
109
+ :highlight-index="highlightIdx"
110
+ :border-style="borderStyle"
111
+ @check-tree-data="onCheck"
112
+ @expand-tree-data="handleExpand"
113
+ @click-tree-data="onRowClick"
114
+ @dbl-click-tree-data="onRowDblClick"
115
+ >
116
+ <!-- Cell Renderer -->
117
+ <template
118
+ v-for="(column, cellIndex) in orderedColumns"
119
+ :key="cellIndex"
120
+ v-slot:[getSlotName(column.field)] = "{ item }"
121
+ >
122
+ <template v-if="!!$slots[column.field]">
123
+ <slot
124
+ :name="column.field"
125
+ :item="{
126
+ data: item.data,
127
+ fieldName: column.field
128
+ }"
129
+ >
130
+ </slot>
131
+ </template>
132
+ <template v-else>
133
+ <span :title="getConvertValue(column, node[column.field])">
134
+ {{ getConvertValue(column, node[column.field]) }}
135
+ </span>
136
+ </template>
137
+ </template>
138
+ </tree-grid-node>
139
+ <tr v-if="!viewStore.length">
140
+ <td class="is-empty">No records</td>
141
+ </tr>
142
+ </tbody>
143
+ </table>
144
+ <!-- vScroll Bottom -->
145
+ <div
146
+ :style="`height: ${vScrollBottomHeight}px;`"
147
+ class="vscroll-spacer"
148
+ />
149
+ <!-- Context Menu -->
150
+ <ev-context-menu
151
+ ref="menu"
152
+ :items="contextMenuItems"
153
+ />
154
+ </div>
155
+ <!-- Resize Line -->
156
+ <div
157
+ v-show="showResizeLine"
158
+ ref="resizeLine"
159
+ class="table-resize-line"
160
+ />
161
+ </div>
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
+ :scroll-left="summaryScroll"
176
+ />
177
+ <!-- Pagination -->
178
+ <grid-pagination
179
+ v-if="usePage && !isInfinite"
180
+ v-model="currentPage"
181
+ :total="showTreeStore.length"
182
+ :per-page="perPage"
183
+ :visible-page="visiblePage"
184
+ :show-page-info="showPageInfo"
185
+ :order="order"
186
+ />
187
+ </template>
188
+
189
+ <script>
190
+ import { reactive, toRefs, computed, watch, onMounted, onActivated, nextTick, ref } from 'vue';
191
+ import treeGridNode from './TreeGridNode';
192
+ import Toolbar from './treeGrid.toolbar';
193
+ import GridPagination from '../grid/grid.pagination';
194
+ import GridSummary from '../grid/grid.summary';
195
+ import {
196
+ commonFunctions,
197
+ scrollEvent,
198
+ resizeEvent,
199
+ clickEvent,
200
+ checkEvent,
201
+ contextMenuEvent,
202
+ treeEvent,
203
+ filterEvent,
204
+ pagingEvent,
205
+ } from './uses';
206
+
207
+ export default {
208
+ name: 'EvTreeGrid',
209
+ components: {
210
+ treeGridNode,
211
+ Toolbar,
212
+ GridPagination,
213
+ GridSummary,
214
+ },
215
+ props: {
216
+ columns: {
217
+ type: [Array],
218
+ default: () => [],
219
+ },
220
+ rows: {
221
+ type: [Array, Object],
222
+ default: () => null,
223
+ },
224
+ width: {
225
+ type: [String, Number],
226
+ default: '100%',
227
+ },
228
+ height: {
229
+ type: [String, Number],
230
+ default: '100%',
231
+ },
232
+ selected: {
233
+ type: [Array],
234
+ default: () => [],
235
+ },
236
+ checked: {
237
+ type: [Array],
238
+ default: () => [],
239
+ },
240
+ option: {
241
+ type: Object,
242
+ default: () => ({}),
243
+ },
244
+ expandIcon: {
245
+ type: String,
246
+ default: '',
247
+ },
248
+ collapseIcon: {
249
+ type: String,
250
+ default: '',
251
+ },
252
+ },
253
+ emits: {
254
+ 'update:selected': null,
255
+ 'click-row': null,
256
+ 'dblclick-row': null,
257
+ 'update:checked': null,
258
+ 'check-row': null,
259
+ 'check-all': null,
260
+ 'page-change': null,
261
+ },
262
+ setup(props) {
263
+ const useSummary = computed(() => (props.option?.useSummary || false));
264
+ const elementInfo = reactive({
265
+ body: null,
266
+ header: null,
267
+ table: null,
268
+ resizeLine: null,
269
+ 'grid-wrapper': null,
270
+ });
271
+ const filterInfo = reactive({
272
+ isSearch: false,
273
+ searchWord: '',
274
+ });
275
+ const stores = reactive({
276
+ treeStore: [],
277
+ viewStore: [],
278
+ filterStore: [],
279
+ pagingStore: [],
280
+ treeRows: props.rows,
281
+ searchStore: computed(() => stores.treeStore.filter(item => item.isFilter)),
282
+ showTreeStore: computed(() => stores.treeStore.filter(item => item.show)),
283
+ orderedColumns: computed(() =>
284
+ props.columns.map((column, index) => ({ index, ...column }))),
285
+ store: computed(() => (filterInfo.isSearch ? stores.searchStore : stores.treeStore)),
286
+ });
287
+ const pageInfo = reactive({
288
+ usePage: computed(() => (props.option.page?.use || false)),
289
+ useClient: props.option.page?.useClient || false,
290
+ isInfinite: computed(() => (props.option.page?.isInfinite || false)),
291
+ startIndex: 0,
292
+ prevPage: 0,
293
+ currentPage: 0,
294
+ pageTotal: computed(() => (props.option.page?.total || 0)),
295
+ perPage: computed(() => (props.option.page?.perPage || 20)),
296
+ visiblePage: computed(() => (props.option.page?.visiblePage || 8)),
297
+ order: computed(() => (props.option.page?.order || 'center')),
298
+ showPageInfo: computed(() => (props.option.page?.showPageInfo || false)),
299
+ isClientPaging: computed(() =>
300
+ pageInfo.useClient && pageInfo.usePage && !pageInfo.isInfinite),
301
+ isHighlight: false,
302
+ highlightPage: 0,
303
+ });
304
+ const checkInfo = reactive({
305
+ prevCheckedRow: [],
306
+ isHeaderChecked: false,
307
+ checkedRows: props.checked,
308
+ useCheckbox: computed(() => props.option.useCheckbox || {}),
309
+ });
310
+ const {
311
+ isRenderer,
312
+ getComponentName,
313
+ getConvertValue,
314
+ getColumnIndex,
315
+ setPixelUnit,
316
+ checkHeader,
317
+ } = commonFunctions({ checkInfo });
318
+ const scrollInfo = reactive({
319
+ lastScroll: {
320
+ top: 0,
321
+ left: 0,
322
+ },
323
+ vScrollTopHeight: 0,
324
+ vScrollBottomHeight: 0,
325
+ hasVerticalScrollBar: false,
326
+ hasHorizontalScrollBar: false,
327
+ });
328
+ const selectInfo = reactive({
329
+ selectedRow: props.selected,
330
+ useSelect: computed(() => props.option?.useSelection?.use ?? true),
331
+ limitCount: computed(() => {
332
+ let limit = props.option?.useSelection?.limitCount;
333
+ limit = !!limit && limit >= 2 ? limit : 0;
334
+ return limit;
335
+ }),
336
+ multiple: computed(() => props.option?.useSelection?.multiple ?? false),
337
+ });
338
+ const contextInfo = reactive({
339
+ menu: null,
340
+ contextMenuItems: [],
341
+ customContextMenu: props.option.customContextMenu || [],
342
+ });
343
+ const resizeInfo = reactive({
344
+ minWidth: 40,
345
+ rendererMinWidth: 80,
346
+ showResizeLine: false,
347
+ adjust: props.option.adjust || false,
348
+ columnWidth: props.option.columnWidth || 80,
349
+ scrollWidth: props.option.scrollWidth || 17,
350
+ rowHeight: computed(() => props.option.rowHeight || 35),
351
+ gridWidth: computed(() => (props.width ? setPixelUnit(props.width) : '100%')),
352
+ gridHeight: computed(() => (props.height ? setPixelUnit(props.height) : '100%')),
353
+ isResize: false,
354
+ });
355
+ const styleInfo = reactive({
356
+ showHeader: computed(() =>
357
+ (props.option.showHeader === undefined ? true : props.option.showHeader)),
358
+ stripeStyle: computed(() => props.option.style?.stripe || false),
359
+ borderStyle: computed(() => props.option.style?.border || ''),
360
+ highlightIdx: computed(() => props.option.style?.highlight ?? -1),
361
+ });
362
+ const clearSelectInfo = () => {
363
+ selectInfo.selectedRow.length = 0;
364
+ stores.store.forEach((row) => {
365
+ row.selected = false;
366
+ });
367
+ };
368
+ const clearCheckInfo = () => {
369
+ checkInfo.isHeaderChecked = false;
370
+ checkInfo.checkedRows.length = 0;
371
+ stores.store.forEach((row) => {
372
+ row.checked = false;
373
+ });
374
+ };
375
+ const {
376
+ getPagingData,
377
+ updatePagingInfo,
378
+ changePage,
379
+ } = pagingEvent({
380
+ stores,
381
+ pageInfo,
382
+ filterInfo,
383
+ elementInfo,
384
+ clearCheckInfo,
385
+ });
386
+ const summaryScroll = ref(0);
387
+ const {
388
+ updateVScroll,
389
+ updateHScroll,
390
+ onScroll,
391
+ } = scrollEvent({
392
+ scrollInfo,
393
+ stores,
394
+ elementInfo,
395
+ resizeInfo,
396
+ pageInfo,
397
+ summaryScroll,
398
+ getPagingData,
399
+ updatePagingInfo,
400
+ });
401
+
402
+ const {
403
+ onRowClick,
404
+ onRowDblClick,
405
+ } = clickEvent(selectInfo);
406
+
407
+ const {
408
+ onCheck,
409
+ onCheckAll,
410
+ } = checkEvent({
411
+ checkInfo,
412
+ stores,
413
+ checkHeader,
414
+ pageInfo,
415
+ getPagingData,
416
+ updatePagingInfo,
417
+ });
418
+
419
+ const {
420
+ calculatedColumn,
421
+ onResize,
422
+ onShow,
423
+ onColumnResize,
424
+ } = resizeEvent({
425
+ resizeInfo,
426
+ elementInfo,
427
+ checkInfo,
428
+ stores,
429
+ isRenderer,
430
+ updateVScroll,
431
+ updateHScroll,
432
+ });
433
+
434
+ const {
435
+ setContextMenu,
436
+ onContextMenu,
437
+ } = contextMenuEvent({ contextInfo, stores, selectInfo });
438
+
439
+ const {
440
+ setTreeNodeStore,
441
+ handleExpand,
442
+ } = treeEvent({ stores, onResize });
443
+
444
+ const {
445
+ onSearch,
446
+ } = filterEvent({
447
+ stores,
448
+ filterInfo,
449
+ pageInfo,
450
+ getConvertValue,
451
+ onResize,
452
+ checkHeader,
453
+ getPagingData,
454
+ updatePagingInfo,
455
+ });
456
+
457
+ onMounted(() => {
458
+ stores.treeStore = setTreeNodeStore();
459
+ });
460
+ onActivated(() => {
461
+ onResize();
462
+ });
463
+
464
+ watch(
465
+ () => props.checked,
466
+ (value) => {
467
+ checkInfo.checkedRows = value;
468
+ },
469
+ );
470
+ watch(
471
+ () => checkInfo.checkedRows,
472
+ (value) => {
473
+ checkInfo.isHeaderChecked = false;
474
+ let store = stores.store;
475
+ if (pageInfo.isClientPaging) {
476
+ store = getPagingData();
477
+ }
478
+ if (store.length) {
479
+ store.forEach((row) => {
480
+ row.checked = !!value.find(checkedRow => checkedRow.index === row.index);
481
+ });
482
+ checkHeader(store);
483
+ }
484
+ updateVScroll();
485
+ },
486
+ );
487
+ watch(
488
+ () => props.selected,
489
+ (value) => {
490
+ if (selectInfo.useSelect) {
491
+ selectInfo.selectedRow = value;
492
+ }
493
+ },
494
+ );
495
+ watch(
496
+ () => selectInfo.selectedRow,
497
+ (value) => {
498
+ if (selectInfo.useSelect) {
499
+ stores.store.forEach((row) => {
500
+ row.selected = !!value.find(selectedRow => selectedRow.index === row.index);
501
+ });
502
+ updateVScroll();
503
+ }
504
+ }, { deep: true },
505
+ );
506
+ watch(
507
+ () => styleInfo.highlightIdx,
508
+ async (index) => {
509
+ await nextTick();
510
+ const setChildShow = (data) => {
511
+ if (!data?.children) {
512
+ return;
513
+ }
514
+ const { children } = data;
515
+ children.forEach((node) => {
516
+ const childNode = node;
517
+ if (childNode.parent.show && childNode.parent.expand) {
518
+ childNode.show = true;
519
+ } else {
520
+ childNode.show = false;
521
+ }
522
+ childNode.isFilter = true;
523
+ if (childNode.hasChild) {
524
+ setChildShow(childNode);
525
+ }
526
+ });
527
+ };
528
+ const setParentShow = (data) => {
529
+ if (!data?.parent) {
530
+ setChildShow(data);
531
+ return;
532
+ }
533
+ const { parent } = data;
534
+ parent.show = true;
535
+ parent.isFilter = true;
536
+ parent.expand = true;
537
+ setChildShow(parent);
538
+ setParentShow(parent);
539
+ };
540
+ if (index >= 0) {
541
+ const highlightNode = stores.store.find(node => node.index === index);
542
+ if (!highlightNode) {
543
+ return;
544
+ }
545
+ // highlightNode parents 자동 펼치기
546
+ highlightNode.show = true;
547
+ highlightNode.isFilter = true;
548
+ setParentShow(highlightNode);
549
+ // tree 에 보여지는 데이터 기준으로 index 다시 구하기
550
+ const highlightIndex = stores.showTreeStore
551
+ .map(node => node.index)
552
+ .indexOf(highlightNode.index);
553
+ if (pageInfo.usePage && !pageInfo.isInfinite) {
554
+ const page = Math.ceil(highlightIndex / pageInfo.perPage);
555
+ pageInfo.highlightPage = highlightIndex === pageInfo.perPage ? page + 1 : page || 1;
556
+ // 페이지 이동
557
+ if (pageInfo.highlightPage !== pageInfo.currentPage) {
558
+ pageInfo.currentPage = pageInfo.highlightPage;
559
+ pageInfo.isHighlight = true;
560
+ return;
561
+ }
562
+ }
563
+ elementInfo.body.scrollTop = resizeInfo.rowHeight * highlightIndex;
564
+ }
565
+ },
566
+ );
567
+ watch(
568
+ () => checkInfo.useCheckbox.mode,
569
+ () => {
570
+ checkInfo.checkedRows = [];
571
+ checkInfo.isHeaderChecked = false;
572
+ },
573
+ );
574
+ watch(
575
+ () => selectInfo.useSelect,
576
+ () => {
577
+ clearSelectInfo();
578
+ },
579
+ );
580
+ watch(
581
+ () => selectInfo.multiple,
582
+ () => {
583
+ clearSelectInfo();
584
+ },
585
+ );
586
+ watch(
587
+ () => props.rows,
588
+ (newData) => {
589
+ stores.treeRows = newData;
590
+ stores.treeStore = setTreeNodeStore();
591
+ onResize();
592
+ }, { deep: true },
593
+ );
594
+ watch(
595
+ () => stores.treeStore.length,
596
+ () => {
597
+ checkHeader(stores.store);
598
+ },
599
+ );
600
+ watch(
601
+ () => [props.width, props.height, props.option.columnWidth],
602
+ (value) => {
603
+ resizeInfo.columnWidth = value[3];
604
+ stores.orderedColumns.map((column) => {
605
+ const item = column;
606
+
607
+ if (!props.columns[column.index].width && !item.resized) {
608
+ item.width = 0;
609
+ }
610
+
611
+ return item;
612
+ });
613
+ onResize();
614
+ },
615
+ );
616
+ watch(
617
+ () => props.option.searchValue,
618
+ (value) => {
619
+ nextTick(() => {
620
+ if (value !== undefined) {
621
+ onSearch(value?.value ?? value);
622
+ if (pageInfo.isClientPaging) {
623
+ clearCheckInfo();
624
+ clearSelectInfo();
625
+ }
626
+ }
627
+ });
628
+ }, { immediate: true },
629
+ );
630
+ watch(
631
+ () => props.option.page?.currentPage,
632
+ (value) => {
633
+ const current = !value ? 1 : value;
634
+ pageInfo.currentPage = !props.option.page?.isInfinite ? current : 1;
635
+ }, { immediate: true },
636
+ );
637
+ watch(
638
+ () => pageInfo.currentPage,
639
+ (current, before) => {
640
+ nextTick(() => {
641
+ changePage(before);
642
+ if (pageInfo.isClientPaging && current !== before) {
643
+ clearCheckInfo();
644
+ clearSelectInfo();
645
+ }
646
+ updateVScroll();
647
+ if (current === pageInfo.highlightPage && pageInfo.isHighlight) {
648
+ const highlightIndex = stores.pagingStore
649
+ .map(node => node.index)
650
+ .indexOf(styleInfo.highlightIdx);
651
+ elementInfo.body.scrollTop = resizeInfo.rowHeight * highlightIndex;
652
+ pageInfo.isHighlight = !pageInfo.isHighlight;
653
+ }
654
+ });
655
+ },
656
+ );
657
+ const gridStyle = computed(() => ({
658
+ width: resizeInfo.gridWidth,
659
+ height: resizeInfo.gridHeight,
660
+ }));
661
+ const bodyStyle = computed(() => ({
662
+ 'table-body': true,
663
+ stripe: styleInfo.stripeStyle,
664
+ 'bottom-border': !!stores.viewStore.length,
665
+ 'non-border': !!styleInfo.borderStyle,
666
+ }));
667
+ const gridClass = computed(() => ({
668
+ table: true,
669
+ 'ev-grid': true,
670
+ 'ev-tree-grid': true,
671
+ adjust: resizeInfo.adjust,
672
+ 'non-header': !styleInfo.showHeader,
673
+ 'ev-tree-grid--empty': !stores.viewStore.length,
674
+ }));
675
+ const headerClass = computed(() => ({
676
+ 'table-header': true,
677
+ 'non-border': !!styleInfo.borderStyle,
678
+ }));
679
+ const headerCheckboxClass = computed(() => ({
680
+ column: true,
681
+ 'non-border': !!styleInfo.borderStyle,
682
+ }));
683
+ const isHeaderCheckbox = computed(() => (
684
+ checkInfo.useCheckbox.use
685
+ && checkInfo.useCheckbox.headerCheck
686
+ && checkInfo.useCheckbox.mode !== 'single'
687
+ ));
688
+ const getColumnClass = (column) => {
689
+ const render = isRenderer(column);
690
+ return {
691
+ column: true,
692
+ render,
693
+ 'non-border': !!styleInfo.borderStyle,
694
+ };
695
+ };
696
+ const getColumnStyle = (column, index) => {
697
+ const render = isRenderer(column);
698
+ return {
699
+ width: `${column.width}px`,
700
+ 'min-width': render ? `${resizeInfo.rendererMinWidth}px;` : `${resizeInfo.minWidth}px`,
701
+ 'margin-right': (stores.orderedColumns.length - 1 === index
702
+ && scrollInfo.hasVerticalScrollBar
703
+ && scrollInfo.hasHorizontalScrollBar) ? `${resizeInfo.scrollWidth}px` : '0px',
704
+ };
705
+ };
706
+ const getSlotName = column => `${column}Node`;
707
+
708
+ return {
709
+ summaryScroll,
710
+ gridStyle,
711
+ gridClass,
712
+ headerClass,
713
+ headerCheckboxClass,
714
+ isHeaderCheckbox,
715
+ bodyStyle,
716
+ useSummary,
717
+ stores,
718
+ ...toRefs(styleInfo),
719
+ ...toRefs(elementInfo),
720
+ ...toRefs(stores),
721
+ ...toRefs(filterInfo),
722
+ ...toRefs(scrollInfo),
723
+ ...toRefs(resizeInfo),
724
+ ...toRefs(selectInfo),
725
+ ...toRefs(checkInfo),
726
+ ...toRefs(contextInfo),
727
+ ...toRefs(pageInfo),
728
+ isRenderer,
729
+ getComponentName,
730
+ getConvertValue,
731
+ getColumnIndex,
732
+ setPixelUnit,
733
+ updateVScroll,
734
+ updateHScroll,
735
+ onScroll,
736
+ calculatedColumn,
737
+ onResize,
738
+ onShow,
739
+ onColumnResize,
740
+ onRowClick,
741
+ onRowDblClick,
742
+ onCheck,
743
+ onCheckAll,
744
+ setContextMenu,
745
+ onContextMenu,
746
+ onSearch,
747
+ handleExpand,
748
+ getColumnClass,
749
+ getColumnStyle,
750
+ getSlotName,
751
+ };
752
+ },
753
+ };
754
+ </script>
755
+
756
+ <style lang="scss" scoped>
757
+ @import './style/treeGrid.scss';
758
+ </style>