evui 3.4.64 → 3.4.66
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.
- package/dist/evui.common.js +389 -271
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +389 -271
- package/dist/evui.umd.js.map +1 -1
- package/dist/evui.umd.min.js +1 -1
- package/dist/evui.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chart/element/element.tip.js +5 -3
- package/src/components/grid/Grid.vue +85 -64
- package/src/components/grid/uses.js +45 -8
- package/src/components/pagination/Pagination.vue +49 -3
- package/src/components/treeGrid/TreeGrid.vue +20 -13
- package/src/components/treeGrid/TreeGridNode.vue +1 -0
package/package.json
CHANGED
|
@@ -92,9 +92,11 @@ const modules = {
|
|
|
92
92
|
|
|
93
93
|
if (maxTipOpt.use && maxArgs) {
|
|
94
94
|
if (tooltipValueFormatter) {
|
|
95
|
-
maxArgs.text =
|
|
96
|
-
|
|
97
|
-
:
|
|
95
|
+
maxArgs.text = tooltipValueFormatter({
|
|
96
|
+
seriesId: seriesInfo.sId,
|
|
97
|
+
x: isHorizontal ? maxArgs.value : undefined,
|
|
98
|
+
y: !isHorizontal ? maxArgs.value : undefined,
|
|
99
|
+
});
|
|
98
100
|
} else {
|
|
99
101
|
maxArgs.text = numberWithComma(maxArgs.value);
|
|
100
102
|
}
|
|
@@ -248,69 +248,75 @@
|
|
|
248
248
|
@dragover="onDragOver"
|
|
249
249
|
@drop="onDrop"
|
|
250
250
|
>
|
|
251
|
-
<!--
|
|
252
|
-
<
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
251
|
+
<!-- Custom Header -->
|
|
252
|
+
<template v-if="column.customHeader && !!$slots.customHeader">
|
|
253
|
+
<slot name="customHeader" />
|
|
254
|
+
</template>
|
|
255
|
+
<template v-else>
|
|
256
|
+
<!-- Column Name -->
|
|
257
|
+
<span
|
|
258
|
+
:title="column.caption"
|
|
259
|
+
class="column-name"
|
|
260
|
+
@click="onColumnContextMenu($event, column)"
|
|
261
|
+
@click.prevent="columnMenu.show"
|
|
262
|
+
>
|
|
263
|
+
{{ column.caption }}
|
|
264
|
+
<!-- Sort Icon -->
|
|
265
|
+
<span @click.stop="onSort(column)">
|
|
266
|
+
<template v-if="!!$slots.sortIcon">
|
|
267
|
+
<span
|
|
268
|
+
v-if="column.sortable === undefined ? true : column.sortable"
|
|
269
|
+
class="column-sort__icon column-sort__icon--basic"
|
|
270
|
+
:style="{
|
|
271
|
+
height: `${rowHeight}px`,
|
|
272
|
+
'line-height': `${rowHeight}px`,
|
|
273
|
+
}"
|
|
274
|
+
>
|
|
275
|
+
<slot name="sortIcon" />
|
|
276
|
+
</span>
|
|
277
|
+
<span
|
|
278
|
+
v-if="sortField === column.field"
|
|
279
|
+
:class="[{
|
|
280
|
+
'column-sort__icon': true,
|
|
281
|
+
'column-sort__icon--asc': sortOrder === 'asc',
|
|
282
|
+
'column-sort__icon--desc': sortOrder === 'desc',
|
|
283
|
+
}]"
|
|
284
|
+
:style="{
|
|
285
|
+
height: `${rowHeight}px`,
|
|
286
|
+
'line-height': `${rowHeight}px`,
|
|
287
|
+
}"
|
|
288
|
+
>
|
|
289
|
+
<slot :name="`sortIcon_${sortOrder}`" />
|
|
290
|
+
</span>
|
|
291
|
+
</template>
|
|
292
|
+
<template v-else>
|
|
293
|
+
<grid-sort-button
|
|
294
|
+
v-if="column.sortable === undefined ? true : column.sortable"
|
|
295
|
+
class="column-sort__icon column-sort__icon--basic"
|
|
296
|
+
:icon="'basic'"
|
|
297
|
+
:style="{
|
|
298
|
+
height: `${rowHeight}px`,
|
|
299
|
+
'line-height': `${rowHeight}px`,
|
|
300
|
+
}"
|
|
301
|
+
/>
|
|
302
|
+
<grid-sort-button
|
|
303
|
+
v-if="sortField === column.field"
|
|
304
|
+
:class="[{
|
|
305
|
+
'column-sort__icon': true,
|
|
306
|
+
'column-sort__icon--asc': sortOrder === 'asc',
|
|
307
|
+
'column-sort__icon--desc': sortOrder === 'desc',
|
|
308
|
+
}]"
|
|
309
|
+
:icon="sortOrder"
|
|
310
|
+
:style="{
|
|
311
|
+
height: `${rowHeight}px`,
|
|
312
|
+
'line-height': `${rowHeight}px`,
|
|
313
|
+
visibility: !!sortOrder ? column.hidden : true,
|
|
314
|
+
}"
|
|
315
|
+
/>
|
|
316
|
+
</template>
|
|
317
|
+
</span>
|
|
312
318
|
</span>
|
|
313
|
-
</
|
|
319
|
+
</template>
|
|
314
320
|
<!-- Column Resize -->
|
|
315
321
|
<span
|
|
316
322
|
class="column-resize"
|
|
@@ -352,12 +358,13 @@
|
|
|
352
358
|
:style="`height: ${vScrollTopHeight}px;`"
|
|
353
359
|
class="vscroll-spacer"
|
|
354
360
|
/>
|
|
361
|
+
|
|
355
362
|
<table ref="table">
|
|
356
363
|
<tbody>
|
|
357
364
|
<!-- Row List -->
|
|
358
365
|
<template
|
|
359
366
|
v-for="(row, rowIndex) in viewStore"
|
|
360
|
-
:key="rowIndex"
|
|
367
|
+
:key="idColIndex !== -1 ? row[2][idColIndex] : rowIndex"
|
|
361
368
|
>
|
|
362
369
|
<tr
|
|
363
370
|
:data-index="row[0]"
|
|
@@ -418,7 +425,7 @@
|
|
|
418
425
|
<!-- Cell -->
|
|
419
426
|
<template
|
|
420
427
|
v-for="(column, cellIndex) in orderedColumns"
|
|
421
|
-
:key="cellIndex"
|
|
428
|
+
:key="`${idColIndex !== -1 ? row[2][idColIndex] : rowIndex}-${cellIndex}`"
|
|
422
429
|
>
|
|
423
430
|
<td
|
|
424
431
|
v-if="!column.hide && !column.hiddenDisplay"
|
|
@@ -497,10 +504,18 @@
|
|
|
497
504
|
<tr
|
|
498
505
|
v-if="useRowDetail && $slots?.rowDetail && row[4]"
|
|
499
506
|
>
|
|
507
|
+
<div
|
|
508
|
+
:style="{
|
|
509
|
+
height: `${detailRowHeight}px`,
|
|
510
|
+
'min-height': `${detailRowHeight}px`,
|
|
511
|
+
'max-height': `${detailRowHeight}px`
|
|
512
|
+
}">
|
|
513
|
+
|
|
500
514
|
<slot
|
|
501
515
|
name="rowDetail"
|
|
502
516
|
:item="{ row }"
|
|
503
517
|
/>
|
|
518
|
+
</div>
|
|
504
519
|
</tr>
|
|
505
520
|
</template>
|
|
506
521
|
<tr v-if="!viewStore.length">
|
|
@@ -513,6 +528,7 @@
|
|
|
513
528
|
:style="`height: ${vScrollBottomHeight}px;`"
|
|
514
529
|
class="vscroll-spacer"
|
|
515
530
|
/>
|
|
531
|
+
|
|
516
532
|
<!-- Context Menu -->
|
|
517
533
|
<ev-context-menu
|
|
518
534
|
ref="menu"
|
|
@@ -811,6 +827,7 @@ export default {
|
|
|
811
827
|
const expandedInfo = reactive({
|
|
812
828
|
expandedRows: props.expanded,
|
|
813
829
|
useRowDetail: computed(() => props.option?.rowDetail?.use ?? false),
|
|
830
|
+
detailRowHeight: computed(() => (props.option?.rowDetail?.detailRowHeight)),
|
|
814
831
|
});
|
|
815
832
|
const scrollInfo = reactive({
|
|
816
833
|
lastScroll: {
|
|
@@ -1221,6 +1238,7 @@ export default {
|
|
|
1221
1238
|
if (!expendedSize) {
|
|
1222
1239
|
clearExpandedInfo();
|
|
1223
1240
|
}
|
|
1241
|
+
updateVScroll();
|
|
1224
1242
|
},
|
|
1225
1243
|
);
|
|
1226
1244
|
watch(
|
|
@@ -1411,7 +1429,10 @@ export default {
|
|
|
1411
1429
|
|
|
1412
1430
|
onBeforeMount(() => initWrapperDiv());
|
|
1413
1431
|
|
|
1432
|
+
const idColIndex = computed(() => stores.orderedColumns.findIndex(c => c.field === 'id'));
|
|
1433
|
+
|
|
1414
1434
|
return {
|
|
1435
|
+
idColIndex,
|
|
1415
1436
|
summaryScroll,
|
|
1416
1437
|
showHeader,
|
|
1417
1438
|
stripeStyle,
|
|
@@ -114,19 +114,56 @@ export const scrollEvent = (params) => {
|
|
|
114
114
|
const updateVScrollBase = (isScroll) => {
|
|
115
115
|
const bodyEl = elementInfo.body;
|
|
116
116
|
const rowHeight = resizeInfo.rowHeight;
|
|
117
|
+
const expandedRowHeight = expandedInfo.detailRowHeight ?? 0;
|
|
118
|
+
|
|
117
119
|
if (bodyEl) {
|
|
118
120
|
let store = stores.store;
|
|
119
121
|
if (pageInfo.isClientPaging) {
|
|
120
122
|
store = getPagingData();
|
|
121
123
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
124
|
+
|
|
125
|
+
const expandedRowCount = expandedInfo.expandedRows?.length ?? 0;
|
|
126
|
+
const expandedRowIndexes = expandedInfo.expandedRows?.map(
|
|
127
|
+
row => store.findIndex(data => data[ROW_DATA_INDEX] === row),
|
|
128
|
+
) ?? [];
|
|
129
|
+
const totalScrollHeight = store.length * rowHeight + expandedRowCount * expandedRowHeight;
|
|
130
|
+
|
|
131
|
+
let firstVisibleIndex = 0;
|
|
132
|
+
let scrollTop = 0;
|
|
133
|
+
|
|
134
|
+
if (expandedRowCount) {
|
|
135
|
+
for (firstVisibleIndex = 0; scrollTop + rowHeight < bodyEl.scrollTop; firstVisibleIndex++) {
|
|
136
|
+
if (expandedRowIndexes.includes(firstVisibleIndex)) {
|
|
137
|
+
scrollTop += expandedRowHeight;
|
|
138
|
+
}
|
|
139
|
+
scrollTop += rowHeight;
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
firstVisibleIndex = Math.floor(bodyEl.scrollTop / rowHeight);
|
|
143
|
+
scrollTop = Math.max(firstVisibleIndex, 0) * rowHeight;
|
|
144
|
+
}
|
|
145
|
+
|
|
126
146
|
if (firstVisibleIndex > store.length - 1) {
|
|
127
147
|
firstVisibleIndex = 0;
|
|
128
148
|
}
|
|
129
149
|
|
|
150
|
+
let rowCount = 0;
|
|
151
|
+
let renderRowHeight = 0;
|
|
152
|
+
|
|
153
|
+
if (expandedRowCount) {
|
|
154
|
+
for (let i = firstVisibleIndex; renderRowHeight <= bodyEl.clientHeight; i++) {
|
|
155
|
+
if (expandedRowIndexes.includes(i)) {
|
|
156
|
+
renderRowHeight += expandedRowHeight;
|
|
157
|
+
}
|
|
158
|
+
renderRowHeight += rowHeight;
|
|
159
|
+
rowCount += 1;
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
rowCount = bodyEl.clientHeight > rowHeight
|
|
163
|
+
? Math.ceil(bodyEl.clientHeight / rowHeight) : store.length;
|
|
164
|
+
renderRowHeight = rowCount * rowHeight;
|
|
165
|
+
}
|
|
166
|
+
|
|
130
167
|
const lastVisibleIndex = firstVisibleIndex + rowCount + 1;
|
|
131
168
|
const firstIndex = Math.max(firstVisibleIndex, 0);
|
|
132
169
|
const lastIndex = lastVisibleIndex;
|
|
@@ -135,8 +172,8 @@ export const scrollEvent = (params) => {
|
|
|
135
172
|
stores.viewStore = store.slice(firstIndex, lastIndex);
|
|
136
173
|
scrollInfo.hasVerticalScrollBar = rowCount < store.length
|
|
137
174
|
|| bodyEl.clientHeight < tableEl.clientHeight;
|
|
138
|
-
scrollInfo.vScrollTopHeight =
|
|
139
|
-
scrollInfo.vScrollBottomHeight = totalScrollHeight -
|
|
175
|
+
scrollInfo.vScrollTopHeight = scrollTop;
|
|
176
|
+
scrollInfo.vScrollBottomHeight = totalScrollHeight - renderRowHeight
|
|
140
177
|
- scrollInfo.vScrollTopHeight;
|
|
141
178
|
if (isScroll && pageInfo.isInfinite && scrollInfo.vScrollBottomHeight === 0) {
|
|
142
179
|
pageInfo.prevPage = pageInfo.currentPage;
|
|
@@ -148,10 +185,10 @@ export const scrollEvent = (params) => {
|
|
|
148
185
|
};
|
|
149
186
|
|
|
150
187
|
/**
|
|
151
|
-
* rowDetail slot 시에는 가상 스크롤을 적용하지 않는다.
|
|
188
|
+
* 고정 높이를 지정하지 않은 rowDetail slot 시에는 가상 스크롤을 적용하지 않는다.
|
|
152
189
|
*/
|
|
153
190
|
const updateVScroll = (isScroll) => {
|
|
154
|
-
if (expandedInfo.useRowDetail) {
|
|
191
|
+
if (expandedInfo.useRowDetail && !expandedInfo.detailRowHeight) {
|
|
155
192
|
let store = stores.store;
|
|
156
193
|
if (pageInfo.isClientPaging) {
|
|
157
194
|
store = getPagingData();
|
|
@@ -10,9 +10,25 @@
|
|
|
10
10
|
/ {{ total }}
|
|
11
11
|
</template>
|
|
12
12
|
</small>
|
|
13
|
+
|
|
13
14
|
<ul class="pagination-list" :style="listClasses">
|
|
15
|
+
<!-- Jump -->
|
|
16
|
+
<li v-if="$props.pagePerJump"
|
|
17
|
+
class="step-button"
|
|
18
|
+
:class="{'is-disabled': !hasPrev}">
|
|
19
|
+
<page-button
|
|
20
|
+
class="pagination-previous"
|
|
21
|
+
:disabled="!hasPrev"
|
|
22
|
+
:page="getPage(prevJumpPage, {isCurrent: false})"
|
|
23
|
+
>
|
|
24
|
+
<ev-icon icon="ev-icon-s-double-left"/>
|
|
25
|
+
</page-button>
|
|
26
|
+
</li>
|
|
27
|
+
|
|
14
28
|
<!-- Previous -->
|
|
15
|
-
<li
|
|
29
|
+
<li
|
|
30
|
+
class="step-button"
|
|
31
|
+
:class="{'is-disabled': !hasPrev}">
|
|
16
32
|
<page-button
|
|
17
33
|
class="pagination-previous"
|
|
18
34
|
:disabled="!hasPrev"
|
|
@@ -33,7 +49,9 @@
|
|
|
33
49
|
</template>
|
|
34
50
|
|
|
35
51
|
<!-- Next -->
|
|
36
|
-
<li
|
|
52
|
+
<li
|
|
53
|
+
class="step-button"
|
|
54
|
+
:class="{'is-disabled': !hasNext}">
|
|
37
55
|
<page-button
|
|
38
56
|
class="pagination-next"
|
|
39
57
|
:disabled="!hasNext"
|
|
@@ -42,6 +60,20 @@
|
|
|
42
60
|
<ev-icon icon="ev-icon-s-arrow-right"/>
|
|
43
61
|
</page-button>
|
|
44
62
|
</li>
|
|
63
|
+
|
|
64
|
+
<!-- Jump -->
|
|
65
|
+
<li v-if="$props.pagePerJump"
|
|
66
|
+
class="step-button"
|
|
67
|
+
:class="{'is-disabled': !hasNext}">
|
|
68
|
+
<page-button
|
|
69
|
+
class="pagination-previous"
|
|
70
|
+
:disabled="!hasNext"
|
|
71
|
+
:page="getPage(nextJumpPage, {isCurrent: false})"
|
|
72
|
+
>
|
|
73
|
+
<ev-icon icon="ev-icon-s-double-right"/>
|
|
74
|
+
</page-button>
|
|
75
|
+
</li>
|
|
76
|
+
|
|
45
77
|
</ul>
|
|
46
78
|
</nav>
|
|
47
79
|
</template>
|
|
@@ -83,6 +115,10 @@ export default {
|
|
|
83
115
|
default: 'left',
|
|
84
116
|
validator: val => ['left', 'right', 'center'].includes(val),
|
|
85
117
|
},
|
|
118
|
+
pagePerJump: {
|
|
119
|
+
type: [Number, undefined],
|
|
120
|
+
default: undefined,
|
|
121
|
+
},
|
|
86
122
|
},
|
|
87
123
|
emits: {
|
|
88
124
|
'update:modelValue': null,
|
|
@@ -95,6 +131,14 @@ export default {
|
|
|
95
131
|
? 1 : Math.ceil(props.total / props.perPage)));
|
|
96
132
|
const hasPrev = computed(() => current.value > 1);
|
|
97
133
|
const hasNext = computed(() => current.value < pageCount.value);
|
|
134
|
+
|
|
135
|
+
const prevJumpPage = computed(
|
|
136
|
+
() => Math.max(current.value - props.pagePerJump, 1),
|
|
137
|
+
);
|
|
138
|
+
const nextJumpPage = computed(
|
|
139
|
+
() => Math.min(current.value + props.pagePerJump, pageCount.value),
|
|
140
|
+
);
|
|
141
|
+
|
|
98
142
|
const firstData = computed(() => {
|
|
99
143
|
const item = current.value * props.perPage - props.perPage + 1;
|
|
100
144
|
return item >= 0 ? item : 0;
|
|
@@ -109,7 +153,7 @@ export default {
|
|
|
109
153
|
};
|
|
110
154
|
const getPage = (num, options = {}) => ({
|
|
111
155
|
number: num,
|
|
112
|
-
isCurrent: current.value === num,
|
|
156
|
+
isCurrent: options.isCurrent ?? current.value === num,
|
|
113
157
|
click: event => changePage(num, event),
|
|
114
158
|
input: (event, inputNum) => changePage(+inputNum, event),
|
|
115
159
|
disabled: options.disabled || false,
|
|
@@ -198,6 +242,8 @@ export default {
|
|
|
198
242
|
current,
|
|
199
243
|
changePage,
|
|
200
244
|
getPage,
|
|
245
|
+
prevJumpPage,
|
|
246
|
+
nextJumpPage,
|
|
201
247
|
};
|
|
202
248
|
},
|
|
203
249
|
};
|
|
@@ -72,18 +72,24 @@
|
|
|
72
72
|
:class="getColumnClass(column)"
|
|
73
73
|
:style="getColumnStyle(column, index)"
|
|
74
74
|
>
|
|
75
|
-
<!--
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
75
|
+
<!-- Custom Header -->
|
|
76
|
+
<template v-if="column.customHeader && !!$slots.customHeader">
|
|
77
|
+
<slot name="customHeader" />
|
|
78
|
+
</template>
|
|
79
|
+
<template v-else>
|
|
80
|
+
<!-- Column Name -->
|
|
81
|
+
<span
|
|
82
|
+
:title="column.caption"
|
|
83
|
+
:class="[
|
|
84
|
+
'column-name',
|
|
85
|
+
{ 'column-name--click' : useGridSetting }
|
|
86
|
+
]"
|
|
87
|
+
@click="onColumnContextMenu($event, column)"
|
|
88
|
+
@click.prevent="columnMenu.show"
|
|
89
|
+
>
|
|
90
|
+
{{ column.caption }}
|
|
91
|
+
</span>
|
|
92
|
+
</template>
|
|
87
93
|
<!-- Column Resize -->
|
|
88
94
|
<span
|
|
89
95
|
class="column-resize"
|
|
@@ -125,7 +131,7 @@
|
|
|
125
131
|
<tbody>
|
|
126
132
|
<tree-grid-node
|
|
127
133
|
v-for="(node, idx) in viewStore"
|
|
128
|
-
:key="idx"
|
|
134
|
+
:key="node['id'] || idx"
|
|
129
135
|
:selected-data="selectedRow"
|
|
130
136
|
:node-data="node"
|
|
131
137
|
:use-checkbox="useCheckbox"
|
|
@@ -886,6 +892,7 @@ export default {
|
|
|
886
892
|
column: true,
|
|
887
893
|
render,
|
|
888
894
|
'non-border': !!styleInfo.borderStyle,
|
|
895
|
+
[column.field]: column.field,
|
|
889
896
|
};
|
|
890
897
|
};
|
|
891
898
|
const getColumnStyle = (column, index) => {
|