vue3-smart-table 1.0.4 → 1.0.6
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/README.md +1 -1
- package/dist/vue3-smart-table.cjs.js +1 -1
- package/dist/vue3-smart-table.cjs.js.map +1 -1
- package/dist/vue3-smart-table.es.js +430 -418
- package/dist/vue3-smart-table.es.js.map +1 -1
- package/dist/vue3-smart-table.umd.js +2 -2
- package/dist/vue3-smart-table.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/components/SmartTable/hooks/useOperationColumn.ts +5 -1
- package/src/components/SmartTable/index.vue +219 -21
- package/src/components/SmartTable/renderer.ts +3 -2
- package/src/components/SmartTable/renderers/index.ts +6 -2
- package/src/components/SmartTable/renderers/input.vue +1 -0
- package/src/components/SmartTable/renderers/inputNumber.vue +1 -0
- package/src/components/SmartTable/renderers/select.vue +1 -0
- package/src/components/SmartTable/types.ts +11 -1
- package/src/components/SmartTable/column/index.vue +0 -170
|
@@ -164,6 +164,7 @@ const img = createFunctionalRenderer((props) => {
|
|
|
164
164
|
return h(ElImage, {
|
|
165
165
|
src: imageList[0],
|
|
166
166
|
previewSrcList: rp.previewSrcList || imageList,
|
|
167
|
+
previewTeleported: true,
|
|
167
168
|
fit: rp.fit || 'contain',
|
|
168
169
|
style: defaultStyle,
|
|
169
170
|
...rp
|
|
@@ -179,6 +180,7 @@ const img = createFunctionalRenderer((props) => {
|
|
|
179
180
|
h(ElImage, {
|
|
180
181
|
src: imageList[0],
|
|
181
182
|
previewSrcList: rp.previewSrcList || imageList,
|
|
183
|
+
previewTeleported: true,
|
|
182
184
|
fit: rp.fit || 'contain',
|
|
183
185
|
style: defaultStyle,
|
|
184
186
|
...rp
|
|
@@ -241,10 +243,11 @@ export function isDataColumn(
|
|
|
241
243
|
}
|
|
242
244
|
|
|
243
245
|
const formatter = createFunctionalRenderer((props) => {
|
|
244
|
-
const { col, row } = props
|
|
246
|
+
const { col, row, index } = props
|
|
245
247
|
const val = getValueByPath(props.row, props.col.key) ?? ''
|
|
246
248
|
if (isDataColumn(col)) {
|
|
247
|
-
|
|
249
|
+
// formatter 函数签名: (value, row, index) => string
|
|
250
|
+
return col.formatter?.(val, row, index)
|
|
248
251
|
}
|
|
249
252
|
return val ?? ''
|
|
250
253
|
})
|
|
@@ -261,6 +264,7 @@ const icon = createFunctionalRenderer((props) => {
|
|
|
261
264
|
return h(ElImage, {
|
|
262
265
|
src: val,
|
|
263
266
|
previewSrcList: [val],
|
|
267
|
+
previewTeleported: true,
|
|
264
268
|
fit: 'contain',
|
|
265
269
|
style: 'width:40px;height:40px',
|
|
266
270
|
...rp
|
|
@@ -15,6 +15,7 @@ import { getValueByPath, setValueByPath } from '../utils/path'
|
|
|
15
15
|
interface Props {
|
|
16
16
|
readonly row: any
|
|
17
17
|
readonly col: ColumnConfig
|
|
18
|
+
readonly index: number
|
|
18
19
|
onCellBlur?: (row: any, col: ColumnConfig) => void
|
|
19
20
|
onCellEnter?: (row: any, col: ColumnConfig) => void
|
|
20
21
|
}
|
|
@@ -15,6 +15,7 @@ import { getValueByPath, setValueByPath } from '../utils/path'
|
|
|
15
15
|
interface Props {
|
|
16
16
|
readonly row: any
|
|
17
17
|
readonly col: ColumnConfig
|
|
18
|
+
readonly index: number
|
|
18
19
|
onCellChange?: (row: any, col: ColumnConfig) => void
|
|
19
20
|
onCellBlur?: (row: any, col: ColumnConfig) => void
|
|
20
21
|
onCellEnter?: (row: any, col: ColumnConfig) => void
|
|
@@ -23,6 +23,7 @@ import { getValueByPath, setValueByPath } from '../utils/path'
|
|
|
23
23
|
interface Props {
|
|
24
24
|
readonly row: any
|
|
25
25
|
readonly col: ColumnConfig
|
|
26
|
+
readonly index: number
|
|
26
27
|
onCellChange?: (row: any, col: ColumnConfig) => void
|
|
27
28
|
onCellBlur?: (row: any, col: ColumnConfig) => void
|
|
28
29
|
onCellEnter?: (row: any, col: ColumnConfig) => void
|
|
@@ -223,7 +223,17 @@ export interface BaseColumn<R extends DefaultRow> {
|
|
|
223
223
|
export interface SelectionColumn<R extends DefaultRow> extends BaseColumn<R> { type: 'selection' }
|
|
224
224
|
export interface IndexColumn<R extends DefaultRow> extends BaseColumn<R> { type: 'index' }
|
|
225
225
|
export interface OperationColumn<R extends DefaultRow> extends BaseColumn<R> { type: 'operation'; buttons: ButtonConfig<R>[] }
|
|
226
|
-
export interface DataColumn<R extends DefaultRow> extends BaseColumn<R> {
|
|
226
|
+
export interface DataColumn<R extends DefaultRow> extends BaseColumn<R> {
|
|
227
|
+
type?: 'default'
|
|
228
|
+
/**
|
|
229
|
+
* 格式化函数
|
|
230
|
+
* @param value 单元格值
|
|
231
|
+
* @param row 当前行数据
|
|
232
|
+
* @param index 当前行索引(从0开始)
|
|
233
|
+
* @returns 格式化后的显示内容
|
|
234
|
+
*/
|
|
235
|
+
formatter?: (value: any, row: R, index: number) => any
|
|
236
|
+
}
|
|
227
237
|
|
|
228
238
|
export type ColumnConfig<R extends DefaultRow = any> =
|
|
229
239
|
| SelectionColumn<R>
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<!-- ========== selection 列 ========== -->
|
|
3
|
-
<el-table-column
|
|
4
|
-
v-if="col.type === 'selection'"
|
|
5
|
-
type="selection"
|
|
6
|
-
v-bind="col.columnProps"
|
|
7
|
-
/>
|
|
8
|
-
|
|
9
|
-
<!-- ========== index 列 ========== -->
|
|
10
|
-
<el-table-column
|
|
11
|
-
v-else-if="col.type === 'index'"
|
|
12
|
-
type="index"
|
|
13
|
-
:label="col.label || '#'"
|
|
14
|
-
align="center"
|
|
15
|
-
v-bind="col.columnProps"
|
|
16
|
-
>
|
|
17
|
-
<template #default="{ $index }">
|
|
18
|
-
{{ computeIndex($index) }}
|
|
19
|
-
</template>
|
|
20
|
-
</el-table-column>
|
|
21
|
-
|
|
22
|
-
<!-- ========== operation 列 ========== -->
|
|
23
|
-
<el-table-column
|
|
24
|
-
v-else-if="col.type === 'operation' && showOperationColumn"
|
|
25
|
-
:label="col.label || '操作'"
|
|
26
|
-
align="center"
|
|
27
|
-
v-bind="{
|
|
28
|
-
...col.columnProps,
|
|
29
|
-
width: operationWidth
|
|
30
|
-
}"
|
|
31
|
-
>
|
|
32
|
-
<template #default="{ row }">
|
|
33
|
-
<el-button
|
|
34
|
-
v-for="btn in getVisibleButtons(row)"
|
|
35
|
-
:key="btn.label"
|
|
36
|
-
:type="btn.type || 'primary'"
|
|
37
|
-
link
|
|
38
|
-
@click="btn.action(row)"
|
|
39
|
-
>
|
|
40
|
-
{{ btn.label }}
|
|
41
|
-
</el-button>
|
|
42
|
-
</template>
|
|
43
|
-
</el-table-column>
|
|
44
|
-
|
|
45
|
-
<!-- ========== 普通列 / renderer / editable ========== -->
|
|
46
|
-
<el-table-column
|
|
47
|
-
v-else-if="isDataOrOperationColumn(col)"
|
|
48
|
-
:label="col.label"
|
|
49
|
-
align="center"
|
|
50
|
-
v-bind="col.columnProps || {}"
|
|
51
|
-
>
|
|
52
|
-
|
|
53
|
-
<template #default="scope">
|
|
54
|
-
<!-- 父组件插槽优先 -->
|
|
55
|
-
<template v-if="col.render === 'slot' && $slots[col?.slot || col.key]">
|
|
56
|
-
<slot :name="col?.slot || col.key" v-bind="scope" />
|
|
57
|
-
</template>
|
|
58
|
-
|
|
59
|
-
<!-- renderer -->
|
|
60
|
-
<component
|
|
61
|
-
v-else-if="col.render && renderer[col.render]"
|
|
62
|
-
:is="renderer[col.render]"
|
|
63
|
-
:row="scope.row"
|
|
64
|
-
:col="col"
|
|
65
|
-
:onCellChange="handleCellChange"
|
|
66
|
-
:onCellBlur="handleCellBlur"
|
|
67
|
-
:onCellEnter="handleCellEnter"
|
|
68
|
-
:onClick="handleCellClick"
|
|
69
|
-
/>
|
|
70
|
-
<!-- 默认文本 -->
|
|
71
|
-
<span v-else
|
|
72
|
-
:style="col.renderProps?.style || ''"
|
|
73
|
-
:class="col.renderProps?.class || ''"
|
|
74
|
-
:title="getValueByPath(scope.row, col.key)">
|
|
75
|
-
{{ getValueByPath(scope.row, col.key) }}
|
|
76
|
-
</span>
|
|
77
|
-
</template>
|
|
78
|
-
</el-table-column>
|
|
79
|
-
|
|
80
|
-
</template>
|
|
81
|
-
|
|
82
|
-
<script setup lang="ts">
|
|
83
|
-
import { computed, toRefs } from 'vue'
|
|
84
|
-
import type { PropType } from 'vue'
|
|
85
|
-
import type { ColumnConfig } from '../types'
|
|
86
|
-
import { getRendererManager } from '../renderer'
|
|
87
|
-
import { registerBuiltInRenderers } from '../renderers'
|
|
88
|
-
import { useOperationColumn } from '../hooks/useOperationColumn'
|
|
89
|
-
import { getValueByPath } from '../utils/path'
|
|
90
|
-
|
|
91
|
-
const props = defineProps({
|
|
92
|
-
col: { type: Object as PropType<ColumnConfig>, required: true },
|
|
93
|
-
permissions: { type: Array as PropType<string[]>, default: () => [] },
|
|
94
|
-
pagination: { type: Object, default: () => ({}) },
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
const emit = defineEmits(['cellBlur', 'cellEnter', 'cellChange', 'cellClick'])
|
|
98
|
-
|
|
99
|
-
const computeIndex = (index: number) => {
|
|
100
|
-
const page = props.pagination?.page
|
|
101
|
-
const size = props.pagination?.size
|
|
102
|
-
return page && size ? (page - 1) * size + index + 1 : index + 1
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** 解构 col 响应式引用 */
|
|
106
|
-
const { col } = toRefs(props)
|
|
107
|
-
|
|
108
|
-
/** ========== 事件统一上抛 ========== */
|
|
109
|
-
const handleCellChange = (row: any, key: string) => emit('cellChange', row, key)
|
|
110
|
-
const handleCellBlur = (row: any, key: string) => emit('cellBlur', row, key)
|
|
111
|
-
const handleCellEnter = (row: any, key: string) => emit('cellEnter', row, key)
|
|
112
|
-
const handleCellClick = (row: any, col: any) => emit('cellClick', row, col)
|
|
113
|
-
|
|
114
|
-
/** ========== renderer 注册 ========== */
|
|
115
|
-
// 注册内置渲染器(重复调用会自动跳过已存在的)
|
|
116
|
-
registerBuiltInRenderers(getRendererManager())
|
|
117
|
-
|
|
118
|
-
// 获取所有渲染器(内置 + 自定义)
|
|
119
|
-
const renderer = computed(() => {
|
|
120
|
-
const manager = getRendererManager()
|
|
121
|
-
const allRenderers: Record<string, any> = {}
|
|
122
|
-
|
|
123
|
-
// 合并内置渲染器和自定义渲染器
|
|
124
|
-
manager.names().forEach((name: string) => {
|
|
125
|
-
const r = manager.get(name)
|
|
126
|
-
if (r) allRenderers[name] = r
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
return allRenderers
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
/** ========== operation 列逻辑 ========== */
|
|
133
|
-
const {
|
|
134
|
-
hasAnyButton,
|
|
135
|
-
hasAnyVisibleButton,
|
|
136
|
-
optWidth,
|
|
137
|
-
getMaxOptWidth,
|
|
138
|
-
getVisibleButtons
|
|
139
|
-
} = useOperationColumn(
|
|
140
|
-
col.value.buttons || [],
|
|
141
|
-
col.value.maxbtn ?? 10,
|
|
142
|
-
props.permissions || []
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
/** 是否显示操作列 */
|
|
146
|
-
const showOperationColumn = computed(() => {
|
|
147
|
-
const buttons = col.value.buttons || []
|
|
148
|
-
if (!buttons.length) return false // 没有配置按钮直接隐藏
|
|
149
|
-
const rows = col.value.__rows || []
|
|
150
|
-
// 无行数据时,至少有一个按钮有权限就显示
|
|
151
|
-
if (!rows.length) return hasAnyButton.value
|
|
152
|
-
// 有行数据时,至少一行有可见按钮才显示
|
|
153
|
-
return hasAnyVisibleButton(col.value.__rows || [])
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
/** 操作列宽度 */
|
|
157
|
-
const operationWidth = computed(() => {
|
|
158
|
-
// 无行数据,用静态宽度
|
|
159
|
-
if (!col.value.__rows) return optWidth.value
|
|
160
|
-
// 有行数据,取最大宽度
|
|
161
|
-
return getMaxOptWidth(col.value.__rows)
|
|
162
|
-
})
|
|
163
|
-
|
|
164
|
-
function isDataOrOperationColumn(c: ColumnConfig) {
|
|
165
|
-
if (c.type === 'selection' || c.type === 'index') return false
|
|
166
|
-
if (c.type === 'operation' && !showOperationColumn.value) return false
|
|
167
|
-
if (c.visible === false) return false
|
|
168
|
-
return true
|
|
169
|
-
}
|
|
170
|
-
</script>
|