webcake-ui-kit 1.2.0 → 1.2.1
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/package.json +8 -2
- package/src/components/checkbox/Checkbox.vue +1 -1
- package/src/components/drawer/Drawer.vue +261 -0
- package/src/components/drawer/drawer.css +162 -0
- package/src/components/dropdown/Dropdown.vue +15 -9
- package/src/components/hover-card/HoverCard.vue +159 -0
- package/src/components/hover-card/hover-card.css +10 -0
- package/src/components/input-counter/InputCounter.vue +250 -0
- package/src/components/input-counter/input-counter.css +209 -0
- package/src/components/menu/Menu.vue +4 -2
- package/src/components/popover/Popover.vue +144 -0
- package/src/components/popover/popover.css +3 -0
- package/src/components/table-v2/ColumnDragHandle.vue +103 -0
- package/src/components/table-v2/Table.vue +299 -0
- package/src/components/table-v2/TableColGroup.vue +55 -0
- package/src/components/table-v2/TableEmpty.vue +10 -0
- package/src/components/table-v2/TableLoading.vue +25 -0
- package/src/components/table-v2/TableResizeObserver.vue +93 -0
- package/src/components/table-v2/TableWrapper.vue +193 -0
- package/src/components/table-v2/body/DragPreview.vue +65 -0
- package/src/components/table-v2/body/MeasureCell.vue +42 -0
- package/src/components/table-v2/body/TableBody.vue +126 -0
- package/src/components/table-v2/body/TableCell.vue +108 -0
- package/src/components/table-v2/body/TableRow.vue +73 -0
- package/src/components/table-v2/composables/useColumns.js +19 -0
- package/src/components/table-v2/composables/useSorter.js +12 -0
- package/src/components/table-v2/composables/useSticky.js +31 -0
- package/src/components/table-v2/constants.js +2 -0
- package/src/components/table-v2/context/createTableContext.js +79 -0
- package/src/components/table-v2/header/TableHeader.vue +15 -0
- package/src/components/table-v2/header/TableHeaderCell.vue +89 -0
- package/src/components/table-v2/header/TableHeaderRow.vue +107 -0
- package/src/components/table-v2/style/table-body.css +0 -0
- package/src/components/table-v2/style/table-header.css +0 -0
- package/src/components/table-v2/style/table-loading.css +19 -0
- package/src/components/table-v2/style/table-wrapper.css +287 -0
- package/src/components/table-v2/style/table.css +5 -0
- package/src/icons/BoxShadow.vue +35 -0
- package/src/icons/Carousel.vue +34 -0
- package/src/icons/CloudSync2.vue +42 -0
- package/src/icons/CornerBottomLeft.vue +26 -0
- package/src/icons/CornerBottomRight.vue +26 -0
- package/src/icons/CornerTopLeft.vue +26 -0
- package/src/icons/CornerTopRight.vue +26 -0
- package/src/icons/DistanceRight.vue +30 -0
- package/src/icons/DistanceTop.vue +30 -0
- package/src/icons/DropShadow.vue +35 -0
- package/src/icons/Fire.vue +26 -0
- package/src/icons/GlobeAccess.vue +32 -0
- package/src/icons/InnerShadow.vue +33 -0
- package/src/icons/Livestream.vue +54 -0
- package/src/icons/PaddingBottom.vue +30 -0
- package/src/icons/PaddingLeft.vue +30 -0
- package/src/icons/PaddingRight.vue +30 -0
- package/src/icons/PaddingTop.vue +30 -0
- package/src/icons/SkewHeight.vue +32 -0
- package/src/icons/SkewWidth.vue +32 -0
- package/src/icons/SquareDashedBottomSolid.vue +26 -0
- package/src/icons/SquareDashedLeftSolid.vue +26 -0
- package/src/icons/SquareDashedRightSolid.vue +26 -0
- package/src/icons/StrokeLine.vue +23 -0
- package/src/icons/Topline.vue +26 -0
- package/src/icons/index.js +25 -0
- package/src/index.js +5 -0
- package/src/styles/.omc/state/agent-replay-645326b7-372b-463d-ab45-0adaafe31a51.jsonl +2 -0
- package/src/styles/.omc/state/subagent-tracking.json +7 -0
- package/src/utils/common.js +34 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
class="ui-table-v2__wrapper"
|
|
4
|
+
:class="{
|
|
5
|
+
'ui-table-v2__wrapper--ping-left': isPingedLeft,
|
|
6
|
+
'ui-table-v2__wrapper--ping-right': isPingedRight
|
|
7
|
+
}"
|
|
8
|
+
>
|
|
9
|
+
<DragPreview v-if="hasDraggable" ref="dragPreview">
|
|
10
|
+
<template #bodyCell="slotData">
|
|
11
|
+
<slot name="bodyCell" v-bind="slotData"></slot>
|
|
12
|
+
</template>
|
|
13
|
+
</DragPreview>
|
|
14
|
+
|
|
15
|
+
<!-- Case 3: scroll.y — header và body là 2 table riêng để sticky header -->
|
|
16
|
+
<template v-if="hasScrollY && !isEmpty">
|
|
17
|
+
<div ref="headerRef" class="ui-table-v2__header-hold" style="overflow: hidden">
|
|
18
|
+
<table :class="tableClass" :style="fixedTableStyle">
|
|
19
|
+
<TableColGroup :is-header="true" />
|
|
20
|
+
<TableHeader />
|
|
21
|
+
</table>
|
|
22
|
+
</div>
|
|
23
|
+
<div ref="bodyRef" class="ui-table-v2__body-hold" :style="bodyHoldStyle" @scroll="handleBodyScroll">
|
|
24
|
+
<table :class="tableClass" :style="fixedTableStyle">
|
|
25
|
+
<TableColGroup />
|
|
26
|
+
<TableBody :measureColumnWidth="hasScrollY || hasScrollX || hasSticky">
|
|
27
|
+
<template #bodyCell="slotData">
|
|
28
|
+
<slot name="bodyCell" v-bind="slotData"></slot>
|
|
29
|
+
</template>
|
|
30
|
+
</TableBody>
|
|
31
|
+
</table>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<!-- Case 1 & 2: một table duy nhất -->
|
|
36
|
+
<div v-else class="ui-table-v2__content" ref="bodyRef" :style="contentStyle" @scroll="handleBodyScroll">
|
|
37
|
+
<table :class="tableClass" :style="tableStyle">
|
|
38
|
+
<TableColGroup />
|
|
39
|
+
<TableHeader />
|
|
40
|
+
<TableBody :measureColumnWidth="hasScrollY || hasScrollX || hasSticky" :is-empty="isEmpty">
|
|
41
|
+
<template #bodyCell="slotData">
|
|
42
|
+
<slot name="bodyCell" v-bind="slotData"></slot>
|
|
43
|
+
</template>
|
|
44
|
+
</TableBody>
|
|
45
|
+
</table>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
import TableColGroup from './TableColGroup.vue'
|
|
52
|
+
import TableHeader from './header/TableHeader.vue'
|
|
53
|
+
import TableBody from './body/TableBody.vue'
|
|
54
|
+
import DragPreview from './body/DragPreview.vue'
|
|
55
|
+
import { toCssSize, getTargetScrollBarSize } from '../../utils/common'
|
|
56
|
+
|
|
57
|
+
export default {
|
|
58
|
+
name: 'TableV2Wrapper',
|
|
59
|
+
|
|
60
|
+
data: () => {
|
|
61
|
+
return {
|
|
62
|
+
toCssSize,
|
|
63
|
+
getTargetScrollBarSize,
|
|
64
|
+
isPingedLeft: false,
|
|
65
|
+
isPingedRight: false
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
components: { TableColGroup, TableHeader, TableBody, DragPreview },
|
|
70
|
+
|
|
71
|
+
inject: ['tableContext'],
|
|
72
|
+
|
|
73
|
+
computed: {
|
|
74
|
+
scroll: function () {
|
|
75
|
+
return this.tableContext.layout.scroll
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
isEmpty() {
|
|
79
|
+
return this.tableContext.data.display.length === 0
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
hasScrollY: function () {
|
|
83
|
+
// has fix header
|
|
84
|
+
return !!(this.scroll && this.scroll.y)
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
hasScrollX: function () {
|
|
88
|
+
// has horizontal scroll
|
|
89
|
+
return !!(this.scroll && this.scroll.x)
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
hasSticky: function () {
|
|
93
|
+
// has sticky column
|
|
94
|
+
const leftOffsets = this.tableContext.sticky.leftOffsets
|
|
95
|
+
const rightOffsets = this.tableContext.sticky.rightOffsets
|
|
96
|
+
return Object.keys(leftOffsets).length > 0 || Object.keys(rightOffsets).length > 0
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
hasDraggable() {
|
|
100
|
+
return !!(this.tableContext.draggable && this.tableContext.draggable.enabled)
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
tableClass: function () {
|
|
104
|
+
return {
|
|
105
|
+
'ui-table-v2__table': true,
|
|
106
|
+
'ui-table-v2__table--bordered': this.tableContext.layout.bordered
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
// Case 1 & 2 — wrapper có overflow-x khi scroll.x
|
|
111
|
+
contentStyle: function () {
|
|
112
|
+
return this.hasScrollX ? { overflow: 'auto hidden' } : {}
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// Case 1 & 2 — table style
|
|
116
|
+
tableStyle: function () {
|
|
117
|
+
if (this.hasScrollX && !this.isEmpty) {
|
|
118
|
+
return {
|
|
119
|
+
tableLayout: 'fixed',
|
|
120
|
+
width: this.toCssSize(this.scroll.x),
|
|
121
|
+
minWidth: '100%'
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { tableLayout: 'auto' }
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// Case 3 — cả header table và body table dùng chung style này
|
|
128
|
+
fixedTableStyle: function () {
|
|
129
|
+
return {
|
|
130
|
+
tableLayout: 'fixed',
|
|
131
|
+
width: this.scroll && this.scroll.x ? this.toCssSize(this.scroll.x) : undefined,
|
|
132
|
+
minWidth: '100%'
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
// Case 3 — body scroll container
|
|
137
|
+
bodyHoldStyle: function () {
|
|
138
|
+
var style = {
|
|
139
|
+
overflowY: 'auto',
|
|
140
|
+
maxHeight: this.toCssSize(this.scroll.y)
|
|
141
|
+
}
|
|
142
|
+
if (this.hasScrollX) {
|
|
143
|
+
style.overflowX = 'auto'
|
|
144
|
+
}
|
|
145
|
+
return style
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
methods: {
|
|
149
|
+
handleBodyScroll(e) {
|
|
150
|
+
const { scrollLeft, scrollWidth, clientWidth } = e.currentTarget
|
|
151
|
+
if (this.$refs.headerRef) {
|
|
152
|
+
this.$refs.headerRef.scrollLeft = scrollLeft
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
this.isPingedLeft = scrollLeft > 0
|
|
156
|
+
this.isPingedRight = scrollLeft < scrollWidth - clientWidth
|
|
157
|
+
},
|
|
158
|
+
updateScrollState() {
|
|
159
|
+
console.log('update')
|
|
160
|
+
if (this.$refs.bodyRef) {
|
|
161
|
+
const { width } = getTargetScrollBarSize(this.$refs.bodyRef)
|
|
162
|
+
this.tableContext.layout.scrollBarWidth = width == 'auto' ? '0px' : width
|
|
163
|
+
|
|
164
|
+
const { scrollWidth, clientWidth, scrollLeft } = this.$refs.bodyRef
|
|
165
|
+
this.isPingedLeft = scrollLeft > 0
|
|
166
|
+
this.isPingedRight = scrollLeft < scrollWidth - clientWidth
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
watch: {
|
|
172
|
+
'tableContext.data.display.length': function () {
|
|
173
|
+
this.$nextTick(() => {
|
|
174
|
+
this.updateScrollState()
|
|
175
|
+
})
|
|
176
|
+
},
|
|
177
|
+
hasScrollY(val) {
|
|
178
|
+
console.log('hasScrollY', val)
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
mounted: function () {
|
|
183
|
+
const self = this
|
|
184
|
+
this.tableContext.draggable.getPreviewEl = function () {
|
|
185
|
+
return self.$refs.dragPreview && self.$refs.dragPreview.$el
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
this.updateScrollState()
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
</script>
|
|
192
|
+
|
|
193
|
+
<style src="./style/table-wrapper.css" scoped></style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<table
|
|
3
|
+
class="ui-table-v2__drag-preview"
|
|
4
|
+
aria-hidden="true"
|
|
5
|
+
:style="{ width: containerWidth ? containerWidth + 'px' : '100%' }"
|
|
6
|
+
>
|
|
7
|
+
<tbody class="ui-table-v2__body">
|
|
8
|
+
<tr class="ui-table-v2__row">
|
|
9
|
+
<td v-for="col in columns" :key="col.key">
|
|
10
|
+
<div v-if="col.type === DRAGGABLE_COLUMN" class="wrapper-option">
|
|
11
|
+
<span class="drag-handle">
|
|
12
|
+
<WkiGripVertical :size="16" />
|
|
13
|
+
</span>
|
|
14
|
+
</div>
|
|
15
|
+
<div v-else-if="col.type === SELECTION_COLUMN" class="wrapper-option" />
|
|
16
|
+
<slot v-else name="bodyCell" :column="col" :text="record && record[col.dataIndex]" :record="record">
|
|
17
|
+
<span>{{ record && record[col.dataIndex] }}</span>
|
|
18
|
+
</slot>
|
|
19
|
+
</td>
|
|
20
|
+
</tr>
|
|
21
|
+
</tbody>
|
|
22
|
+
</table>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script>
|
|
26
|
+
import { WkiGripVertical } from '../../../icons'
|
|
27
|
+
import { SELECTION_COLUMN, DRAGGABLE_COLUMN } from '../constants.js'
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
name: 'TableV2DragPreview',
|
|
31
|
+
components: { WkiGripVertical },
|
|
32
|
+
inject: ['tableContext'],
|
|
33
|
+
data: function () {
|
|
34
|
+
return {
|
|
35
|
+
SELECTION_COLUMN: SELECTION_COLUMN,
|
|
36
|
+
DRAGGABLE_COLUMN: DRAGGABLE_COLUMN
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
computed: {
|
|
40
|
+
record: function () {
|
|
41
|
+
return this.tableContext.draggable.draggingRecord
|
|
42
|
+
},
|
|
43
|
+
columns: function () {
|
|
44
|
+
return this.tableContext.columns.flat
|
|
45
|
+
},
|
|
46
|
+
containerWidth: function () {
|
|
47
|
+
return this.tableContext.layout.containerWidth
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<style scoped>
|
|
54
|
+
.ui-table-v2__drag-preview {
|
|
55
|
+
position: fixed;
|
|
56
|
+
top: -10000px;
|
|
57
|
+
left: -10000px;
|
|
58
|
+
pointer-events: none;
|
|
59
|
+
border-collapse: separate;
|
|
60
|
+
border-spacing: 0;
|
|
61
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
|
|
62
|
+
border-radius: 4px;
|
|
63
|
+
overflow: hidden;
|
|
64
|
+
}
|
|
65
|
+
</style>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<TableResizeObserver @resize="handleCellResize">
|
|
3
|
+
<td ref="cellRef" :style="{ padding: '0', border: '0', height: '0' }">
|
|
4
|
+
<div :style="{ height: 0, overflow: 'hidden' }"> </div>
|
|
5
|
+
</td>
|
|
6
|
+
</TableResizeObserver>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import TableResizeObserver from '../TableResizeObserver.vue'
|
|
11
|
+
import { DRAGGABLE_COLUMN, SELECTION_COLUMN } from '../constants.js'
|
|
12
|
+
export default {
|
|
13
|
+
name: 'MeasureCell',
|
|
14
|
+
components: { TableResizeObserver },
|
|
15
|
+
props: {
|
|
16
|
+
measureColumnWidth: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: false
|
|
19
|
+
},
|
|
20
|
+
colKey: {
|
|
21
|
+
type: String,
|
|
22
|
+
required: true
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
inject: ['tableContext'],
|
|
26
|
+
|
|
27
|
+
methods: {
|
|
28
|
+
handleCellResize({ offsetWidth }) {
|
|
29
|
+
if (this.colKey === DRAGGABLE_COLUMN || this.colKey === SELECTION_COLUMN) {
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
this.tableContext.actions.resize(this.colKey, offsetWidth)
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
mounted() {
|
|
37
|
+
if (this.$refs.cellRef) {
|
|
38
|
+
this.handleCellResize({ offsetWidth: this.$refs.cellRef.offsetWidth })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
</script>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<tbody class="ui-table-v2__body">
|
|
3
|
+
<template v-if="measureColumnWidth">
|
|
4
|
+
<tr aria-hidden="true" class="ui-table-v2__measure-row" :style="{ height: '0', fontSize: '0' }">
|
|
5
|
+
<MeasureCell v-for="(column, colIndex) in tableContext.columns.flat" :key="colIndex" :colKey="column.key" />
|
|
6
|
+
</tr>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<template v-if="isEmpty">
|
|
10
|
+
<tr class="ui-table-v2__row">
|
|
11
|
+
<td colspan="100">
|
|
12
|
+
<div class="ui-table-v2__row-empty ui-table-v2__empty">
|
|
13
|
+
<div class="wrapper-img">
|
|
14
|
+
<img
|
|
15
|
+
src="https://content.pancake.vn/web-media-262/2e/2a/0c/96/c2b58ae9f06c4dc2a3b83016e56d5b4132ff40637862ba23435e43a0-w:224-h:224-l:3927-t:image/png.png"
|
|
16
|
+
/>
|
|
17
|
+
</div>
|
|
18
|
+
<span class="wk-paragraph-small">{{ emptyText }}</span>
|
|
19
|
+
</div>
|
|
20
|
+
</td>
|
|
21
|
+
</tr>
|
|
22
|
+
</template>
|
|
23
|
+
|
|
24
|
+
<TableRow
|
|
25
|
+
v-for="(record, rowIndex) in tableContext.data.display"
|
|
26
|
+
:key="record[tableContext.layout.rowKey]"
|
|
27
|
+
:record="record"
|
|
28
|
+
:row-index="rowIndex"
|
|
29
|
+
:is-last-item="rowIndex == tableContext.data.display.length - 1"
|
|
30
|
+
>
|
|
31
|
+
<template #bodyCell="slotData">
|
|
32
|
+
<slot name="bodyCell" v-bind="slotData"></slot>
|
|
33
|
+
</template>
|
|
34
|
+
</TableRow>
|
|
35
|
+
</tbody>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script>
|
|
39
|
+
import Sortable from 'sortablejs'
|
|
40
|
+
import TableRow from './TableRow.vue'
|
|
41
|
+
import MeasureCell from './MeasureCell.vue'
|
|
42
|
+
|
|
43
|
+
export default {
|
|
44
|
+
name: 'TableV2Body',
|
|
45
|
+
components: { TableRow, MeasureCell },
|
|
46
|
+
props: {
|
|
47
|
+
measureColumnWidth: {
|
|
48
|
+
type: Boolean,
|
|
49
|
+
default: false
|
|
50
|
+
},
|
|
51
|
+
isEmpty: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: false
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
inject: ['tableContext'],
|
|
57
|
+
watch: {
|
|
58
|
+
'tableContext.draggable.enabled': function (val) {
|
|
59
|
+
val ? this._initSortable() : this._destroySortable()
|
|
60
|
+
},
|
|
61
|
+
'tableContext.draggable.enableAnimationFlip': function () {
|
|
62
|
+
if (this.tableContext.draggable.enabled) this._initSortable()
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
mounted: function () {
|
|
66
|
+
if (this.tableContext.draggable.enabled) {
|
|
67
|
+
this._initSortable()
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
computed: {
|
|
71
|
+
emptyText() {
|
|
72
|
+
return this.tableContext.data.emptyText || 'Không có dữ liệu'
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
beforeUnmount: function () {
|
|
76
|
+
this._destroySortable()
|
|
77
|
+
},
|
|
78
|
+
// eslint-disable-next-line vue/no-deprecated-destroyed-lifecycle, vue/no-dupe-keys
|
|
79
|
+
beforeDestroy: function () {
|
|
80
|
+
this._destroySortable()
|
|
81
|
+
},
|
|
82
|
+
methods: {
|
|
83
|
+
_initSortable: function () {
|
|
84
|
+
this._destroySortable()
|
|
85
|
+
const self = this
|
|
86
|
+
const offset = this.measureColumnWidth ? 1 : 0
|
|
87
|
+
this._sortable = Sortable.create(this.$el, {
|
|
88
|
+
handle: '.drag-handle',
|
|
89
|
+
draggable: '.ui-table-v2__row',
|
|
90
|
+
animation: this.tableContext.draggable.enableAnimationFlip ? 150 : 0,
|
|
91
|
+
onChoose: function (evt) {
|
|
92
|
+
const rowIndex = evt.oldIndex - offset
|
|
93
|
+
self.tableContext.draggable.draggingRecord = self.tableContext.data.display[rowIndex] || null
|
|
94
|
+
},
|
|
95
|
+
setData: function (dataTransfer, dragEl) {
|
|
96
|
+
let previewEl =
|
|
97
|
+
typeof self.tableContext.draggable.getPreviewEl === 'function'
|
|
98
|
+
? self.tableContext.draggable.getPreviewEl()
|
|
99
|
+
: null
|
|
100
|
+
if (!previewEl) return
|
|
101
|
+
dataTransfer.setDragImage(previewEl, 0, previewEl.offsetHeight / 2)
|
|
102
|
+
},
|
|
103
|
+
onEnd: function (evt) {
|
|
104
|
+
self.tableContext.draggable.draggingRecord = null
|
|
105
|
+
// Revert SortableJS DOM move — Vue owns the DOM
|
|
106
|
+
evt.from.insertBefore(evt.item, evt.from.children[evt.oldIndex] || null)
|
|
107
|
+
const oldIndex = evt.oldIndex - offset
|
|
108
|
+
const newIndex = evt.newIndex - offset
|
|
109
|
+
if (oldIndex === newIndex) return
|
|
110
|
+
if (typeof self.tableContext.actions.reorder === 'function') {
|
|
111
|
+
self.tableContext.actions.reorder(oldIndex, newIndex)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
},
|
|
116
|
+
_destroySortable: function () {
|
|
117
|
+
if (this._sortable) {
|
|
118
|
+
this._sortable.destroy()
|
|
119
|
+
this._sortable = null
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
</script>
|
|
125
|
+
|
|
126
|
+
<style src="../style/table-body.css" scoped></style>
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<td
|
|
3
|
+
:class="[
|
|
4
|
+
'ui-table-v2__cell',
|
|
5
|
+
isSelectionCol && 'ui-table-v2__cell--selection',
|
|
6
|
+
isSelectionCol && 'ui-table-v2__header-cell--selection',
|
|
7
|
+
column.fixed && `ui-table-v2__cell--fixed-${column.fixed}`,
|
|
8
|
+
isLastFixedLeft && 'ui-table-v2__cell--fixed-left__last',
|
|
9
|
+
isFirstFixedRight && 'ui-table-v2__cell--fixed-right__first'
|
|
10
|
+
]"
|
|
11
|
+
:style="cellStyle"
|
|
12
|
+
>
|
|
13
|
+
<div v-if="isSelectionCol" class="wrapper-option">
|
|
14
|
+
<Checkbox :checked="isSelected" :model-value="isSelected" @change="onToggle" />
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<div v-else-if="isDraggableCol" class="wrapper-option">
|
|
18
|
+
<span class="drag-handle">
|
|
19
|
+
<WkiGripVertical :size="16" />
|
|
20
|
+
</span>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<slot name="bodyCell" :column="column" :text="record[column.dataIndex]" :record="record">
|
|
24
|
+
<span :class="[column.ellipsis && 'ui-table-v2__cell--ellipsis']">
|
|
25
|
+
{{ record[column.dataIndex] }}
|
|
26
|
+
</span>
|
|
27
|
+
</slot>
|
|
28
|
+
</td>
|
|
29
|
+
</template>
|
|
30
|
+
|
|
31
|
+
<script>
|
|
32
|
+
import Checkbox from '../../checkbox/Checkbox.vue'
|
|
33
|
+
import { SELECTION_COLUMN, DRAGGABLE_COLUMN } from '../constants.js'
|
|
34
|
+
import { toCssSize } from '../../../utils/common.js'
|
|
35
|
+
import { WkiGripVertical } from '../../../icons'
|
|
36
|
+
|
|
37
|
+
export default {
|
|
38
|
+
name: 'TableV2Cell',
|
|
39
|
+
components: { Checkbox, WkiGripVertical },
|
|
40
|
+
inject: ['tableContext'],
|
|
41
|
+
props: {
|
|
42
|
+
column: { type: Object, required: true },
|
|
43
|
+
record: { type: Object, required: true },
|
|
44
|
+
offset: { type: [Number, String], default: 0 }
|
|
45
|
+
},
|
|
46
|
+
computed: {
|
|
47
|
+
isSelectionCol: function () {
|
|
48
|
+
return this.column.type === SELECTION_COLUMN
|
|
49
|
+
},
|
|
50
|
+
isDraggableCol: function () {
|
|
51
|
+
return this.column.type === DRAGGABLE_COLUMN
|
|
52
|
+
},
|
|
53
|
+
isLastFixedLeft: function () {
|
|
54
|
+
if (this.column.fixed !== 'left') return false
|
|
55
|
+
const cols = this.tableContext.columns.flat
|
|
56
|
+
let lastKey = null
|
|
57
|
+
for (let i = 0; i < cols.length; i++) {
|
|
58
|
+
if (cols[i].fixed === 'left') lastKey = cols[i].key
|
|
59
|
+
}
|
|
60
|
+
return lastKey === this.column.key
|
|
61
|
+
},
|
|
62
|
+
isFirstFixedRight: function () {
|
|
63
|
+
if (this.column.fixed !== 'right') return false
|
|
64
|
+
const cols = this.tableContext.columns.flat
|
|
65
|
+
for (let i = 0; i < cols.length; i++) {
|
|
66
|
+
if (cols[i].fixed === 'right') return cols[i].key === this.column.key
|
|
67
|
+
}
|
|
68
|
+
return false
|
|
69
|
+
},
|
|
70
|
+
isSelected: function () {
|
|
71
|
+
var key = this.record[this.tableContext.layout.rowKey]
|
|
72
|
+
return this.tableContext.selection.selectedRowKeys.indexOf(key) !== -1
|
|
73
|
+
},
|
|
74
|
+
cellStyle: function () {
|
|
75
|
+
const res = { textAlign: this.column.align }
|
|
76
|
+
if (this.column.fixed) {
|
|
77
|
+
res.position = 'sticky'
|
|
78
|
+
if (this.column.fixed === 'left') {
|
|
79
|
+
res.left = toCssSize(this.offset)
|
|
80
|
+
} else if (this.column.fixed === 'right') {
|
|
81
|
+
res.right = toCssSize(this.offset)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return res
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
methods: {
|
|
88
|
+
onToggle: function (checked, nativeEvent) {
|
|
89
|
+
const key = this.record[this.tableContext.layout.rowKey]
|
|
90
|
+
const keys = [...this.tableContext.selection.selectedRowKeys]
|
|
91
|
+
const idx = keys.indexOf(key)
|
|
92
|
+
|
|
93
|
+
if (checked && idx === -1) {
|
|
94
|
+
keys.push(key)
|
|
95
|
+
} else if (!checked && idx !== -1) {
|
|
96
|
+
keys.splice(idx, 1)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.tableContext.actions.select(keys, {
|
|
100
|
+
type: 'row',
|
|
101
|
+
record: this.record,
|
|
102
|
+
selected: checked,
|
|
103
|
+
nativeEvent: nativeEvent
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
</script>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<tr
|
|
3
|
+
v-bind="customAttrs"
|
|
4
|
+
v-on="customListeners"
|
|
5
|
+
:class="[
|
|
6
|
+
'ui-table-v2__row',
|
|
7
|
+
isLastItem && 'ui-table-v2__row--last',
|
|
8
|
+
isSelected && 'ui-table-v2__row--selected',
|
|
9
|
+
customAttrs.class
|
|
10
|
+
]"
|
|
11
|
+
:style="rowStyle"
|
|
12
|
+
>
|
|
13
|
+
<TableCell
|
|
14
|
+
v-for="column in tableContext.columns.flat"
|
|
15
|
+
:key="column.key"
|
|
16
|
+
:column="column"
|
|
17
|
+
:record="record"
|
|
18
|
+
:offset="column.fixed === 'left' ? leftStickyOffsets[column.key] : rightStickyOffsets[column.key]"
|
|
19
|
+
>
|
|
20
|
+
<template #bodyCell="slotData">
|
|
21
|
+
<slot name="bodyCell" v-bind="slotData"></slot>
|
|
22
|
+
</template>
|
|
23
|
+
</TableCell>
|
|
24
|
+
</tr>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script>
|
|
28
|
+
import TableCell from './TableCell.vue'
|
|
29
|
+
import { splitProps } from '../../../utils/common.js'
|
|
30
|
+
|
|
31
|
+
export default {
|
|
32
|
+
name: 'TableV2Row',
|
|
33
|
+
components: { TableCell },
|
|
34
|
+
inject: ['tableContext'],
|
|
35
|
+
props: {
|
|
36
|
+
record: { type: Object, required: true },
|
|
37
|
+
rowIndex: { type: Number, required: true },
|
|
38
|
+
isLastItem: { type: Boolean, default: false }
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
computed: {
|
|
42
|
+
rowStyle() {
|
|
43
|
+
return { height: this.tableContext.layout.rowHeight + 'px' }
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
isSelected: function () {
|
|
47
|
+
var key = this.record[this.tableContext.layout.rowKey]
|
|
48
|
+
return this.tableContext.selection.selectedRowKeys.indexOf(key) !== -1
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
leftStickyOffsets() {
|
|
52
|
+
return this.tableContext.sticky.leftOffsets
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
rightStickyOffsets() {
|
|
56
|
+
return this.tableContext.sticky.rightOffsets
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
customProps: function () {
|
|
60
|
+
var fn = this.tableContext.rows.customRow
|
|
61
|
+
return typeof fn === 'function' ? fn(this.record, this.rowIndex) || {} : {}
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
customAttrs: function () {
|
|
65
|
+
return splitProps(this.customProps).attrs
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
customListeners: function () {
|
|
69
|
+
return splitProps(this.customProps).listeners
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function flattenColumns(columns) {
|
|
2
|
+
return (columns || []).map(function (col, i) {
|
|
3
|
+
return {
|
|
4
|
+
key: col.key || col.dataIndex || String(i),
|
|
5
|
+
type: col.type || null,
|
|
6
|
+
dataIndex: col.dataIndex || '',
|
|
7
|
+
title: col.title || '',
|
|
8
|
+
width: col.width || null,
|
|
9
|
+
align: col.align == 'left' ? null : col.align,
|
|
10
|
+
fixed: col.fixed || null,
|
|
11
|
+
ellipsis: col.ellipsis || false,
|
|
12
|
+
customCell: col.customCell || null,
|
|
13
|
+
customHeaderCell: col.customHeaderCell || null,
|
|
14
|
+
minWidth: col.minWidth || 50,
|
|
15
|
+
maxWidth: col.maxWidth || Infinity,
|
|
16
|
+
resizable: col.resizable || false
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function sortData(source, columnKey, order) {
|
|
2
|
+
if (!columnKey || !order) return source
|
|
3
|
+
var arr = source.slice()
|
|
4
|
+
arr.sort(function (a, b) {
|
|
5
|
+
var av = a[columnKey]
|
|
6
|
+
var bv = b[columnKey]
|
|
7
|
+
if (av === bv) return 0
|
|
8
|
+
var asc = av < bv ? -1 : 1
|
|
9
|
+
return order === 'ascend' ? asc : -asc
|
|
10
|
+
})
|
|
11
|
+
return arr
|
|
12
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function computeOffsets(columns, columnWidths) {
|
|
2
|
+
var left = {}
|
|
3
|
+
var right = {}
|
|
4
|
+
var leftAcc = 0
|
|
5
|
+
var rightAcc = 0
|
|
6
|
+
|
|
7
|
+
for (var i = 0; i < columns.length; i++) {
|
|
8
|
+
var col = columns[i]
|
|
9
|
+
if (col.fixed === 'left') {
|
|
10
|
+
left[col.key] = leftAcc
|
|
11
|
+
leftAcc += columnWidths.get(col.key) || parseWidth(col.width) || 0
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
for (var j = columns.length - 1; j >= 0; j--) {
|
|
16
|
+
var colR = columns[j]
|
|
17
|
+
if (colR.fixed === 'right') {
|
|
18
|
+
right[colR.key] = rightAcc
|
|
19
|
+
rightAcc += columnWidths.get(colR.key) || parseWidth(colR.width) || 0
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return { left: left, right: right }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseWidth(width) {
|
|
27
|
+
if (!width) return 0
|
|
28
|
+
if (typeof width === 'number') return width
|
|
29
|
+
var n = parseInt(width, 10)
|
|
30
|
+
return isNaN(n) ? 0 : n
|
|
31
|
+
}
|