vue3-smart-table 0.0.2 → 0.0.4
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 +404 -42
- package/dist/vue3-smart-table.cjs.js +12 -2
- package/dist/vue3-smart-table.css +1 -1
- package/dist/vue3-smart-table.es.js +292 -224
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SmartTable 使用文档
|
|
2
2
|
|
|
3
3
|
## 概览
|
|
4
4
|
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
- 配置驱动(columns 即 schema)
|
|
8
8
|
- 权限解耦(不依赖 store / 登录体系)
|
|
9
9
|
- 操作列智能显示(无可见按钮 → 整列隐藏)
|
|
10
|
-
-
|
|
11
|
-
- 单元格渲染器体系(renderer
|
|
10
|
+
- 列显隐持久化(只缓存 visible)
|
|
11
|
+
- 单元格渲染器体系(renderer 插件化 + 插槽可自定义复杂列)
|
|
12
|
+
- 保留 SFC 模板渲染 input / input-number / select
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
@@ -17,8 +18,12 @@
|
|
|
17
18
|
```txt
|
|
18
19
|
SmartTable/
|
|
19
20
|
├─ column/
|
|
20
|
-
│ ├─
|
|
21
|
-
│
|
|
21
|
+
│ ├─ renderer
|
|
22
|
+
│ ├─ index.ts # createRenderer 工厂
|
|
23
|
+
│ ├─ input.vue # 可编辑 input
|
|
24
|
+
│ ├─ inputNumber.vue # 可编辑 input-number
|
|
25
|
+
│ └─ select.vue # 可编辑 select
|
|
26
|
+
│ └─ index.vue # TableColumn 子组件
|
|
22
27
|
├─ hooks/
|
|
23
28
|
│ ├─ useOperationColumn.ts # 操作列按钮可见性 / 宽度逻辑
|
|
24
29
|
│ └─ useTableColumns.ts # 列显隐缓存(只缓存 visible)
|
|
@@ -40,6 +45,7 @@ SmartTable/
|
|
|
40
45
|
| permissions | `string[]` | `[]` | 当前用户权限列表 |
|
|
41
46
|
| pageKey | `string` | - | 列缓存 pageKey(可选) |
|
|
42
47
|
| userId | `string \| number` | - | 列缓存 userId(可选) |
|
|
48
|
+
| pagination | `{page: number, size: number}` | - | 序号列计算序号(可选),page:当前页,size:当前页显示条数,不填则默认序号 |
|
|
43
49
|
|
|
44
50
|
> 其余属性将 **透传给 el-table**。
|
|
45
51
|
|
|
@@ -55,10 +61,8 @@ export interface ColumnConfig<R = any> {
|
|
|
55
61
|
|
|
56
62
|
visible?: boolean
|
|
57
63
|
inControl?: boolean
|
|
58
|
-
|
|
59
64
|
render?: string
|
|
60
|
-
|
|
61
|
-
editType?: 'input' | 'number' | 'select'
|
|
65
|
+
slot?: string // render为slot时可自定slot否则使用key
|
|
62
66
|
|
|
63
67
|
renderProps?: Record<string, any>
|
|
64
68
|
columnProps?: Record<string, any>
|
|
@@ -78,6 +82,7 @@ export interface ColumnConfig<R = any> {
|
|
|
78
82
|
- `selection / index / operation` 为 **核心列**
|
|
79
83
|
- 核心列必须:`inControl = false`
|
|
80
84
|
- 普通列通过 `visible` 控制显示 / 隐藏
|
|
85
|
+
- 可通过 render 使用内置 renderer 或自定义插槽
|
|
81
86
|
|
|
82
87
|
---
|
|
83
88
|
|
|
@@ -119,9 +124,74 @@ export interface ButtonConfig<R = any> {
|
|
|
119
124
|
| `dict` | 字典映射 |
|
|
120
125
|
| `map` | key-value 映射 |
|
|
121
126
|
| `formatter` | 自定义格式化 |
|
|
122
|
-
| `editable` | 可编辑单元格(input / number / select) |
|
|
123
127
|
| `icon` | iconfont / svg / url |
|
|
128
|
+
| `input` | 可编辑单元格 |
|
|
129
|
+
| `input-number` | 可编辑单元格 |
|
|
130
|
+
| `select` | 可编辑单元格 |
|
|
131
|
+
| `button` | 单行按钮 |
|
|
132
|
+
| `link` | 单行链接 |
|
|
133
|
+
| `slot` | 自定义插槽,插槽名称默认用 key |
|
|
134
|
+
|
|
135
|
+
### 插槽自定义复杂列
|
|
136
|
+
- 如果某一列过于复杂,可通过 #key 插槽完全自定义:
|
|
137
|
+
- 自定义插槽 render="slot",插槽名称默认用 key,配置slot="xx"可自定义slot名称
|
|
138
|
+
```vue
|
|
139
|
+
<script>
|
|
140
|
+
const columns = [{
|
|
141
|
+
key: "attachments",
|
|
142
|
+
label: "自定义复杂列",
|
|
143
|
+
visible: true,
|
|
144
|
+
render: 'slot',
|
|
145
|
+
slot: 'attachments',
|
|
146
|
+
columnProps: { minWidth: 100, align: 'right'},
|
|
147
|
+
}]
|
|
148
|
+
</script>
|
|
149
|
+
|
|
150
|
+
<template>
|
|
151
|
+
<SmartTable :columns="columns" :data="tableData">
|
|
152
|
+
<template #attachments="{ row }">
|
|
153
|
+
<div v-for="(item, index) in row.attachments" :key="index">
|
|
154
|
+
<el-image v-if="item.fileType === 1" :src="item.thumbnailUrl" :preview-src-list="row.imgPaths"/>
|
|
155
|
+
<el-button v-if="item.fileType === 0" type="text" @click="download(item.fileUrl)">下载日志</el-button>
|
|
156
|
+
<div v-if="item.fileType === 2" @click="handleVideo(item.fileUrl)">
|
|
157
|
+
<img :src="item.thumbnailUrl" alt="video"/>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
</template>
|
|
161
|
+
</SmartTable>
|
|
162
|
+
</template>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 编辑型 渲染器
|
|
166
|
+
- 支持类型:input / number / select
|
|
167
|
+
- 支持事件:
|
|
168
|
+
- cellChange(row, col) 值变化
|
|
169
|
+
- cellBlur(row, col) 失去焦点
|
|
170
|
+
- cellEnter(row, col) 回车事件(input)
|
|
171
|
+
```vue
|
|
172
|
+
<script>
|
|
173
|
+
const columns = [
|
|
174
|
+
{
|
|
175
|
+
key: "selectId",
|
|
176
|
+
label: "可选单元格",
|
|
177
|
+
render: "select",
|
|
178
|
+
renderProps: { options: [{label:'选中-1', value:1}, {label:'选中-2', value:2}] }
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
key: "orderNum",
|
|
182
|
+
label: "输入单元格",
|
|
183
|
+
render: "input-number",
|
|
184
|
+
renderProps: { min: 0, max: 150 }
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
key: "username",
|
|
188
|
+
label: "姓名",
|
|
189
|
+
render: "input"
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
</script>
|
|
124
193
|
|
|
194
|
+
```
|
|
125
195
|
### copy 示例
|
|
126
196
|
|
|
127
197
|
```ts
|
|
@@ -143,12 +213,39 @@ export interface ButtonConfig<R = any> {
|
|
|
143
213
|
key: 'avatar',
|
|
144
214
|
label: '头像',
|
|
145
215
|
render: 'img',
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
216
|
+
columnProps: { minWidth: 150},
|
|
217
|
+
renderProps: {
|
|
218
|
+
width: '60px',
|
|
219
|
+
height: '60px',
|
|
220
|
+
fit: 'cover',
|
|
221
|
+
placeholder: '--'
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
key: 'gallery',
|
|
226
|
+
label: '相册',
|
|
227
|
+
render: 'img',
|
|
228
|
+
columnProps: { minWidth: 150},
|
|
229
|
+
renderProps: {
|
|
230
|
+
width: '100px',
|
|
231
|
+
height: '100px'
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
const tableData = reactive([
|
|
235
|
+
{ id: 3, name: 'Charlie', code: '9525', status: 0, map: 1, regionCode:'海外', orderNum: 1, selectId: 2,
|
|
236
|
+
avatar: 'https://iconfont.alicdn.com/p/illus_3d/file/UMAqlm6KX5gw/8e357f00-9a4e-44c4-b0c5-bbed255cff24.png' ,
|
|
237
|
+
gallery: [
|
|
238
|
+
'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
|
|
239
|
+
'https://iconfont.alicdn.com/p/illus_3d/file/UMAqlm6KX5gw/8e357f00-9a4e-44c4-b0c5-bbed255cff24.png',
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
])
|
|
149
243
|
```
|
|
150
|
-
-
|
|
151
|
-
-
|
|
244
|
+
- 单张图片:正常显示并支持预览
|
|
245
|
+
- 多张图片:显示第一张,右侧显示剩余数量(如:+2)
|
|
246
|
+
- 支持 previewSrcList 自定义预览列表
|
|
247
|
+
- 支持图片大小(width/height)、填充模式(fit)配置
|
|
248
|
+
- 无图片时显示占位符或空内容
|
|
152
249
|
|
|
153
250
|
### map 示例
|
|
154
251
|
|
|
@@ -208,23 +305,7 @@ const Enables = [
|
|
|
208
305
|
```
|
|
209
306
|
- 使用自定义函数格式化显示内容
|
|
210
307
|
|
|
211
|
-
### editable 渲染器
|
|
212
308
|
|
|
213
|
-
```ts
|
|
214
|
-
{
|
|
215
|
-
key: 'age',
|
|
216
|
-
label: '年龄',
|
|
217
|
-
render: 'editable',
|
|
218
|
-
editable: true,
|
|
219
|
-
editType: 'number',
|
|
220
|
-
renderProps: { min: 0, max: 120 }
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
- 支持类型:input / number / select
|
|
224
|
-
- 支持事件:
|
|
225
|
-
- cellChange(row, key) 值变化
|
|
226
|
-
- cellBlur(row, key) 失去焦点
|
|
227
|
-
- cellEnter(row, key) 回车事件(input)
|
|
228
309
|
### icon 示例
|
|
229
310
|
```ts
|
|
230
311
|
{
|
|
@@ -237,7 +318,21 @@ const Enables = [
|
|
|
237
318
|
- 支持网络图片 URL
|
|
238
319
|
- 支持 svg 字符串
|
|
239
320
|
- 支持 iconfont class
|
|
321
|
+
|
|
322
|
+
### button / link
|
|
323
|
+
```ts
|
|
324
|
+
{ key: 'action', label: '操作', render: 'button', renderProps: { label: '编辑', type: 'text' } }
|
|
325
|
+
{ key: 'url', label: '查看', render: 'link', renderProps: { label: '详情', href: 'https://example.com', blank: true } }
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
- 支持事件:
|
|
329
|
+
- cellClick(row, col) 点击事件
|
|
330
|
+
|
|
331
|
+
|
|
240
332
|
## 5. useTableColumns(列显隐缓存)
|
|
333
|
+
```ts
|
|
334
|
+
const { columns } = useTableColumns(defaultColumns, { pageKey: 'user-list', userId: currentUserId })
|
|
335
|
+
```
|
|
241
336
|
|
|
242
337
|
### 设计原则
|
|
243
338
|
|
|
@@ -257,26 +352,293 @@ const { columns } = useTableColumns(defaultColumns, {
|
|
|
257
352
|
- 不传则不启用缓存
|
|
258
353
|
|
|
259
354
|
---
|
|
355
|
+
## 6. 事件
|
|
356
|
+
- 支持类型:input / number / select
|
|
357
|
+
- 支持事件:
|
|
358
|
+
- cellChange(row, col) 值变化
|
|
359
|
+
- cellBlur(row, col) 失去焦点
|
|
360
|
+
- cellEnter(row, col) 回车事件(input)
|
|
361
|
+
- cellClick(row, col) 点击事件
|
|
260
362
|
|
|
261
|
-
|
|
363
|
+
|
|
364
|
+
## 7. 使用示例
|
|
262
365
|
|
|
263
366
|
```vue
|
|
367
|
+
<!-- 全局注册 -->
|
|
368
|
+
import { createApp } from 'vue'
|
|
369
|
+
import App from './App.vue'
|
|
370
|
+
import { SmartTable } from 'vue3-smart-table'
|
|
371
|
+
|
|
372
|
+
const app = createApp(App)
|
|
373
|
+
app.component('SmartTable', SmartTable)
|
|
374
|
+
app.mount('#app')
|
|
375
|
+
|
|
376
|
+
<!-- 或者局部注册 -->
|
|
377
|
+
<script setup>
|
|
378
|
+
import { SmartTable } from 'vue3-smart-table'
|
|
379
|
+
</script>
|
|
380
|
+
|
|
264
381
|
<SmartTable
|
|
265
|
-
:data="tableData"
|
|
266
382
|
v-model:columns="columns"
|
|
267
|
-
:
|
|
268
|
-
:
|
|
269
|
-
|
|
383
|
+
:border="true"
|
|
384
|
+
:loading="loading"
|
|
385
|
+
:pageKey="route.name"
|
|
386
|
+
:rowKey="'appId'"
|
|
387
|
+
:data="tabList"
|
|
388
|
+
:userId="userInfo?.userId"
|
|
389
|
+
:permissions="userStore.permissions"
|
|
270
390
|
@cellChange="onCellChange"
|
|
271
|
-
|
|
391
|
+
@cellBlur="onCellBlur"
|
|
392
|
+
@cellEnter="onCellEnter"
|
|
393
|
+
@cellClick="onCellClick" >
|
|
394
|
+
<!-- 自定义复杂列 -->
|
|
395
|
+
<template #attachments="{ row }">
|
|
396
|
+
<div v-for="(item, index) in row.attachments" :key="index">
|
|
397
|
+
<el-image v-if="item.fileType === 1" :src="item.thumbnailUrl" :preview-src-list="row.imgPaths"/>
|
|
398
|
+
<el-button v-if="item.fileType === 0" type="text" @click="download(item.fileUrl)">下载日志</el-button>
|
|
399
|
+
<div v-if="item.fileType === 2" @click="handleVideo(item.fileUrl)">
|
|
400
|
+
<img :src="item.thumbnailUrl" alt="video"/>
|
|
401
|
+
</div>
|
|
402
|
+
</div>
|
|
403
|
+
</template>
|
|
404
|
+
</SmartTable>
|
|
405
|
+
```
|
|
406
|
+
## 完整示例代码
|
|
407
|
+

|
|
408
|
+
```vue
|
|
409
|
+
<template>
|
|
410
|
+
<div class="demo-container" style="padding: 20px;">
|
|
411
|
+
<h2>Demo</h2>
|
|
412
|
+
<SmartTable
|
|
413
|
+
class="h-400px"
|
|
414
|
+
class-name="table-flex"
|
|
415
|
+
:border="true"
|
|
416
|
+
:loading="loading"
|
|
417
|
+
:pageKey="'route.name'"
|
|
418
|
+
:rowKey="'id'"
|
|
419
|
+
:data="tableData"
|
|
420
|
+
v-model:columns="columns"
|
|
421
|
+
:userId="'userId'"
|
|
422
|
+
:permissions="permissions"
|
|
423
|
+
@cell-blur="onCellBlur"
|
|
424
|
+
@cell-enter="onCellEnter"
|
|
425
|
+
@cell-change="onCellChange"
|
|
426
|
+
@cell-click="onCellClick"
|
|
427
|
+
/>
|
|
428
|
+
</div>
|
|
429
|
+
</template>
|
|
430
|
+
|
|
431
|
+
<script setup lang="ts" name="APP">
|
|
432
|
+
import { reactive, ref } from 'vue'
|
|
433
|
+
import { SmartTable } from 'vue3-smart-table'
|
|
434
|
+
const loading = ref(false)
|
|
435
|
+
const Enables = [
|
|
436
|
+
{ label: '启用', value: 1, listClass: 'primary' },
|
|
437
|
+
{ label: '禁用', value: 0, listClass: 'warning' }
|
|
438
|
+
]
|
|
439
|
+
const buttonConfigs = [
|
|
440
|
+
{ permission: 'edit', label: '编辑', type: 'primary', action: (row: any) => console.log(row)},
|
|
441
|
+
{ permission: 'view', label:'删除', type: 'danger', action: (row: any) => console.log(row)},
|
|
442
|
+
{ permission: 'copy', label: '复制', type: 'success', action: (row: any) => console.log(row)},
|
|
443
|
+
]
|
|
444
|
+
const permissions = ['edit', 'view']
|
|
445
|
+
const columns = ref([
|
|
446
|
+
{
|
|
447
|
+
type: 'selection',
|
|
448
|
+
key: 'index',
|
|
449
|
+
inControl: false,
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
type: 'index',
|
|
453
|
+
key: 'index',
|
|
454
|
+
label: '序号',
|
|
455
|
+
inControl: false,
|
|
456
|
+
columnProps: { width: 60}
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
type: 'operation',
|
|
460
|
+
key: 'opt',
|
|
461
|
+
label: '操作',
|
|
462
|
+
inControl: false,
|
|
463
|
+
buttons: buttonConfigs,
|
|
464
|
+
columnProps: {
|
|
465
|
+
fixed: "right",
|
|
466
|
+
align: "left"
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
key: 'action',
|
|
471
|
+
label: '按钮',
|
|
472
|
+
render: 'button',
|
|
473
|
+
renderProps: {
|
|
474
|
+
label: '编辑',
|
|
475
|
+
type: 'text'
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
key: 'url',
|
|
480
|
+
label: 'li单元格',
|
|
481
|
+
render: 'link',
|
|
482
|
+
renderProps: {
|
|
483
|
+
label: '查看详情',
|
|
484
|
+
href: 'https://example.com',
|
|
485
|
+
blank: true
|
|
486
|
+
}
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
key: "selectId",
|
|
490
|
+
label: "可选单元格",
|
|
491
|
+
visible: true,
|
|
492
|
+
render: 'select',
|
|
493
|
+
columnProps: { minWidth: 150},
|
|
494
|
+
renderProps:{
|
|
495
|
+
options: [
|
|
496
|
+
{label: '选中-1', value: 1},
|
|
497
|
+
{label: '选中-2', value: 2},
|
|
498
|
+
]
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
key: "orderNum",
|
|
503
|
+
label: "输入单元格",
|
|
504
|
+
visible: true,
|
|
505
|
+
render: 'input-number',
|
|
506
|
+
columnProps: { minWidth: 150, sortable: true}
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
key: 'avatar',
|
|
510
|
+
label: '头像',
|
|
511
|
+
render: 'img',
|
|
512
|
+
columnProps: { minWidth: 150, sortable: true},
|
|
513
|
+
renderProps: {
|
|
514
|
+
width: '60px',
|
|
515
|
+
height: '60px',
|
|
516
|
+
fit: 'cover',
|
|
517
|
+
placeholder: '--'
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
key: 'gallery',
|
|
522
|
+
label: '相册',
|
|
523
|
+
render: 'img',
|
|
524
|
+
columnProps: { minWidth: 150, sortable: true},
|
|
525
|
+
renderProps: {
|
|
526
|
+
width: '100px',
|
|
527
|
+
height: '100px'
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
key: 'name',
|
|
532
|
+
label: 'Name',
|
|
533
|
+
visible: true,
|
|
534
|
+
render: 'html'
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
key: "code",
|
|
538
|
+
label: "系统标识",
|
|
539
|
+
visible: true,
|
|
540
|
+
render: "copy",
|
|
541
|
+
columnProps: { minWidth: 160, sortable: true}
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
key: "status",
|
|
545
|
+
label: "状态",
|
|
546
|
+
visible: true,
|
|
547
|
+
render: "dict",
|
|
548
|
+
renderProps: {
|
|
549
|
+
options: Enables,
|
|
550
|
+
},
|
|
551
|
+
columnProps: { minWidth: 80, sortable: true}
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
key: 'map',
|
|
555
|
+
label: 'Map',
|
|
556
|
+
visible: true,
|
|
557
|
+
render: 'map',
|
|
558
|
+
renderProps: { options: { 1: 'Active', 0: 'Inactive' } }
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
key: "regionCode",
|
|
562
|
+
label: "区域",
|
|
563
|
+
visible: true,
|
|
564
|
+
render: "formatter",
|
|
565
|
+
columnProps: { minWidth: 100, sortable: true, align: 'left'},
|
|
566
|
+
formatter: (val: string) => `${val}-123`,
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
key: "regionCode",
|
|
570
|
+
label: "自定义复杂列",
|
|
571
|
+
visible: true,
|
|
572
|
+
columnProps: { minWidth: 100, align: 'right'},
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
key: "handling.feedbackId",
|
|
576
|
+
label: "key.key取值",
|
|
577
|
+
visible: true,
|
|
578
|
+
columnProps: { minWidth: 100, align: 'right'},
|
|
579
|
+
},
|
|
580
|
+
])
|
|
581
|
+
|
|
582
|
+
const tableData = reactive([
|
|
583
|
+
{ id: 1, name: 'Alice', code: '9527', status: 1, map: 1, regionCode:'海外', orderNum: 1, selectId: 1 },
|
|
584
|
+
{ id: 2, name: 'Bob', code: '9526', status: 1, map: 1, regionCode:'海外', orderNum: 1, selectId: 1 },
|
|
585
|
+
{ id: 3, name: 'Charlie', code: '9525', status: 0, map: 1, regionCode:'海外', orderNum: 1, selectId: 2 },
|
|
586
|
+
{ id: 3, name: 'Charlie', code: '9525', status: 0, map: 1, regionCode:'海外', orderNum: 1, selectId: 2,
|
|
587
|
+
avatar: 'https://iconfont.alicdn.com/p/illus_3d/file/UMAqlm6KX5gw/8e357f00-9a4e-44c4-b0c5-bbed255cff24.png' ,
|
|
588
|
+
gallery: [
|
|
589
|
+
'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
|
|
590
|
+
'https://iconfont.alicdn.com/p/illus_3d/file/UMAqlm6KX5gw/8e357f00-9a4e-44c4-b0c5-bbed255cff24.png',
|
|
591
|
+
],
|
|
592
|
+
attachments: [
|
|
593
|
+
{
|
|
594
|
+
"id": 1337611,
|
|
595
|
+
"feedbackId": 1334127,
|
|
596
|
+
"fileType": 1,
|
|
597
|
+
"fileUrl": "http://xxxxxxxxxxxxxxxx/attachment/cn.com.blackview.dashcam/2025/12/17/193000-1334127-1.jpg",
|
|
598
|
+
"fileSize": 298696,
|
|
599
|
+
"thumbnailUrl": "http://xxxxxxxxxxxxxxxxxx/attachment/cn.com.blackview.dashcam/2025/12/17/193000-1334127-1-thumbnail.jpg"
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"id": 1337612,
|
|
603
|
+
"feedbackId": 1334127,
|
|
604
|
+
"fileType": 0,
|
|
605
|
+
"fileUrl": "http://xxxxxxxxxxxxxxxxx/attachment/cn.com.blackview.dashcam/2025/12/17/193000-1334127-2.txt",
|
|
606
|
+
"fileSize": 1619,
|
|
607
|
+
"thumbnailUrl": null
|
|
608
|
+
}
|
|
609
|
+
],
|
|
610
|
+
handling: {
|
|
611
|
+
"id": 1334076,
|
|
612
|
+
"feedbackId": 1334160,
|
|
613
|
+
"problemCategory": null,
|
|
614
|
+
"handlePerson": null,
|
|
615
|
+
"handleTime": "2025-12-19 09:51:05",
|
|
616
|
+
"handleRemark": null,
|
|
617
|
+
"handleStatus": 1,
|
|
618
|
+
"callbackStatus": 1,
|
|
619
|
+
"solveStatus": 1
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
])
|
|
623
|
+
|
|
624
|
+
// 编辑单元格回调
|
|
625
|
+
const onCellBlur = (row: any, col: any) => {
|
|
626
|
+
console.log('cell blur:', row, col)
|
|
627
|
+
}
|
|
628
|
+
const onCellEnter = (row: any, col: any) => {
|
|
629
|
+
console.log('cell enter:', row, col)
|
|
630
|
+
}
|
|
631
|
+
const onCellChange = (row: any, col: any) => {
|
|
632
|
+
console.log('cell Change:', row, col)
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
const onCellClick = (row: any, col: any) => {
|
|
636
|
+
console.log('cell button click:', row, col)
|
|
637
|
+
}
|
|
638
|
+
</script>
|
|
639
|
+
|
|
272
640
|
```
|
|
273
641
|
|
|
274
|
-
## 7. 设计边界说明
|
|
275
|
-
|
|
276
|
-
- SmartTable **不关心权限系统如何实现**
|
|
277
|
-
- permission 只是 string 比对
|
|
278
|
-
- renderer 只负责 UI,不处理权限
|
|
279
|
-
- 操作列是否显示由 SmartTable 统一决策
|
|
280
642
|
|
|
281
643
|
|
|
282
644
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),w=require("element-plus");function h(n,t){if(!(!n||!t))return t.split(".").reduce((l,o)=>l==null?void 0:l[o],n)}function V(n,t,l){if(!n||!t)return;const o=t.split("."),s=o.pop(),r=o.reduce((i,a)=>(i[a]||(i[a]={}),i[a]),n);r[s]=l}const A=e.defineComponent({__name:"input",props:{row:{},col:{},onCellBlur:{type:Function},onCellEnter:{type:Function}},setup(n){const t=n,l=e.ref(h(t.row,t.col.key));e.watch(l,r=>{V(t.row,t.col.key,r)});const o=()=>{var r;return(r=t.onCellBlur)==null?void 0:r.call(t,t.row,t.col)},s=()=>{var r;return(r=t.onCellEnter)==null?void 0:r.call(t,t.row,t.col)};return(r,i)=>{const a=e.resolveComponent("el-input");return e.openBlock(),e.createBlock(a,e.mergeProps({modelValue:l.value,"onUpdate:modelValue":i[0]||(i[0]=d=>l.value=d)},{placeholder:"",size:"small",clearable:!0,...n.col.renderProps},{onBlur:o,onKeyup:e.withKeys(s,["enter"])}),null,16,["modelValue"])}}}),I=e.defineComponent({__name:"inputNumber",props:{row:{},col:{},onCellChange:{type:Function},onCellBlur:{type:Function},onCellEnter:{type:Function}},setup(n){const t=n,l=e.ref(h(t.row,t.col.key));e.watch(l,r=>{var i;V(t.row,t.col.key,r),(i=t.onCellChange)==null||i.call(t,t.row,t.col)});const o=()=>{var r;return(r=t.onCellBlur)==null?void 0:r.call(t,t.row,t.col)},s=()=>{var r;return(r=t.onCellEnter)==null?void 0:r.call(t,t.row,t.col)};return(r,i)=>{const a=e.resolveComponent("el-input-number");return e.openBlock(),e.createBlock(a,e.mergeProps({modelValue:l.value,"onUpdate:modelValue":i[0]||(i[0]=d=>l.value=d)},{min:0,max:99999,controls:!1,size:"small",...n.col.renderProps},{onBlur:o,onKeyup:e.withKeys(s,["enter"])}),null,16,["modelValue"])}}}),L=e.defineComponent({__name:"select",props:{row:{},col:{},onCellChange:{type:Function},onCellBlur:{type:Function},onCellEnter:{type:Function}},setup(n){const t=n,l=e.ref(h(t.row,t.col.key));e.watch(l,i=>{V(t.row,t.col.key,i)});const o=()=>{var i;return(i=t.onCellChange)==null?void 0:i.call(t,t.row,t.col)},s=()=>{var i;return(i=t.onCellBlur)==null?void 0:i.call(t,t.row,t.col)},r=()=>{var i;return(i=t.onCellEnter)==null?void 0:i.call(t,t.row,t.col)};return(i,a)=>{const d=e.resolveComponent("el-option"),p=e.resolveComponent("el-select");return e.openBlock(),e.createBlock(p,e.mergeProps({modelValue:l.value,"onUpdate:modelValue":a[0]||(a[0]=g=>l.value=g)},{placeholder:"请选择",size:"small",clearable:!0,...n.col.renderProps},{onChange:o,onBlur:s,onKeyup:e.withKeys(r,["enter"])}),{default:e.withCtx(()=>{var g;return[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(((g=n.col.renderProps)==null?void 0:g.options)||[],u=>(e.openBlock(),e.createBlock(d,{key:u.value,label:u.label,value:u.value},null,8,["label","value"]))),128))]}),_:1},16,["modelValue"])}}}),S=n=>e.defineComponent({props:["row","col","onCellChange","onCellBlur","onCellEnter","onClick"],setup(t){return()=>e.h(n,t)}});function M(n){return typeof n.formatter=="function"}function z(){return{input:S(A),"input-number":S(I),select:S(L),button:n=>{const t=n.col.renderProps||{},l=h(n.row,n.col.key);return e.h(w.ElButton,{type:t.type||"primary",...t,onClick:()=>{var o;return(o=n.onClick)==null?void 0:o.call(n,n.row,n.col)}},()=>t.label||l)},link:n=>{const t=n.col.renderProps||{},l=h(n.row,n.col.key);return e.h("a",{href:t.href||"#",target:t.blank?"_blank":"_self",style:t.style||"color:#409EFF;cursor:pointer;",onClick:o=>{var s;o.preventDefault(),(s=n.onClick)==null||s.call(n,n.row,n.col)}},t.label||l)},html:n=>{var l;const t=h(n.row,n.col.key);return e.h("div",{class:"line-clamp-2",innerHTML:t??"",...((l=n.col)==null?void 0:l.renderProps)||{}})},copy:n=>{const t=h(n.row,n.col.key)??"";return e.h("div",{class:"copy-wrapper",style:"position: relative; display: inline-block;"},[e.h("span",{class:"copy-text line-clamp-1",style:"padding-right: 20px;"},t),e.h("span",{class:"copy-btn",style:`
|
|
2
2
|
position: absolute;
|
|
3
3
|
right: 0;
|
|
4
4
|
top: 50%;
|
|
@@ -8,4 +8,14 @@
|
|
|
8
8
|
font-size: 12px;
|
|
9
9
|
color: #409EFF;
|
|
10
10
|
user-select: none;
|
|
11
|
-
`,onClick:()=>{if(t)try{if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(t).then(()=>{
|
|
11
|
+
`,onClick:()=>{if(t)try{if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(t).then(()=>{w.ElMessage.success("复制成功")}).catch(()=>{w.ElMessage.error("复制失败")});else{const l=document.createElement("textarea");l.value=t,l.style.position="fixed",l.style.opacity="0",document.body.appendChild(l),l.select();const o=document.execCommand("copy");document.body.removeChild(l),o?w.ElMessage.success("复制成功"):w.ElMessage.error("复制失败")}}catch{w.ElMessage.error("复制失败")}}},"📋")])},img:n=>{var i;const t=h(n.row,n.col.key)??"",l=((i=n.col)==null?void 0:i.renderProps)||{},s=t?Array.isArray(t)?t.filter(a=>a&&typeof a=="string"):[t]:[];if(s.length===0)return l.placeholder||"";const r={width:l.width||"80px",height:l.height||"80px",marginRight:s.length>1?"4px":"0",...l.style||{}};return s.length===1?e.h(w.ElImage,{src:s[0],previewSrcList:l.previewSrcList||s,fit:l.fit||"contain",style:r,...l}):(console.log(l.previewSrcList),e.h("div",{style:"display: flex; align-items: center; position: relative"},[e.h(w.ElImage,{src:s[0],previewSrcList:l.previewSrcList||s,fit:l.fit||"contain",style:r,...l}),s.length>1&&e.h("span",{style:`
|
|
12
|
+
margin-left: 8px;
|
|
13
|
+
font-size: 12px;
|
|
14
|
+
color: #666;
|
|
15
|
+
background: #f0f0f0;
|
|
16
|
+
padding: 2px 6px;
|
|
17
|
+
border-radius: 2px;
|
|
18
|
+
position: absolute;
|
|
19
|
+
top: 0;
|
|
20
|
+
right: 0;
|
|
21
|
+
`,title:`共 ${s.length} 张图片`},`+${s.length-1}`)]))},dict:n=>{const t=h(n.row,n.col.key)??"",l=n.col.renderProps||{},o=l.options??[],s=l.showValue??!1;if(t==null||t==="")return"";const r=Array.isArray(t)?t.map(String):[String(t)],i=o.filter(p=>r.includes(String(p.value))),a=r.filter(p=>!o.some(g=>String(g.value)===p)),d=i.map((p,g)=>e.h(w.ElTag,{key:p.value,type:p.listClass,class:p.cssClass,disableTransitions:!0},{default:()=>p.label+" "}));return s&&a.length>0&&d.push(e.h("span",{},a.join(" "))),e.h("div",{},d)},map:n=>{var o;const t=h(n.row,n.col.key)??"",l=((o=n.col.renderProps)==null?void 0:o.options)??{};return t!=null?l[t]??"":""},formatter:n=>{var s;const{col:t,row:l}=n,o=h(n.row,n.col.key)??"";return M(t)?(s=t.formatter)==null?void 0:s.call(t,o,l):o??""},icon:n=>{const t=h(n.row,n.col.key)??"",l=n.col.renderProps||{};return t?/^https?:\/\//.test(t)?e.h(w.ElImage,{src:t,previewSrcList:[t],fit:"contain",style:"width:40px;height:40px",...l}):/^\s*<svg[\s\S]*<\/svg>\s*$/.test(t)?e.h("div",{innerHTML:t,style:`width:40px;height:40px;display:inline-block;${l.style||""}`,...l}):e.h("i",{class:t,style:`font-size:20px;${l.style||""}`,...l}):""}}}function T(n,t=10,l=[]){const s="*:*:*",r=c=>{if(!c)return!0;const f=Array.isArray(c)?c:[c];return l.some(y=>y===s||f.includes(y))},i=e.computed(()=>n.some(c=>r(c.permission))),a=e.computed(()=>n.filter(f=>r(f.permission)).slice(0,t).reduce((f,y)=>f+(y.width??60),0)),d=(c,f)=>r(c.permission)&&(c.visible?c.visible(f):!0),p=c=>n.filter(y=>d(y,c)).slice(0,t).reduce((y,b)=>y+(b.width??60),0);return{hasAnyButton:i,optWidth:a,hasAnyVisibleButton:c=>c!=null&&c.length?c.some(f=>n.some(y=>d(y,f))):!1,getMaxOptWidth:c=>c!=null&&c.length?c.reduce((f,y)=>Math.max(f,p(y)),0):a.value,getVisibleButtons:c=>n.filter(f=>d(f,c)).slice(0,t)}}const W=["title"],D=e.defineComponent({__name:"index",props:{col:{type:Object,required:!0},permissions:{type:Array,default:()=>[]},pagination:{type:Object,default:()=>({})}},emits:["cellBlur","cellEnter","cellChange","cellClick"],setup(n,{emit:t}){const l=n,o=t,s=m=>{var x,C;const v=(x=l.pagination)==null?void 0:x.page,B=(C=l.pagination)==null?void 0:C.size;return v&&B?(v-1)*B+m+1:m+1},{col:r}=e.toRefs(l),i=(m,v)=>o("cellChange",m,v),a=(m,v)=>o("cellBlur",m,v),d=(m,v)=>o("cellEnter",m,v),p=(m,v)=>o("cellClick",m,v),g=z(),{hasAnyButton:u,hasAnyVisibleButton:k,optWidth:c,getMaxOptWidth:f,getVisibleButtons:y}=T(r.value.buttons||[],r.value.maxbtn??10,l.permissions||[]),b=e.computed(()=>(r.value.buttons||[]).length?(r.value.__rows||[]).length?k(r.value.__rows||[]):u.value:!1),E=e.computed(()=>r.value.__rows?f(r.value.__rows):c.value);function $(m){return!(m.type==="selection"||m.type==="index"||m.type==="operation"&&!b.value||m.visible===!1)}return(m,v)=>{const B=e.resolveComponent("el-table-column"),x=e.resolveComponent("el-button");return e.unref(r).type==="selection"?(e.openBlock(),e.createBlock(B,e.mergeProps({key:0,type:"selection"},e.unref(r).columnProps),null,16)):e.unref(r).type==="index"?(e.openBlock(),e.createBlock(B,e.mergeProps({key:1,type:"index",label:e.unref(r).label||"#",align:"center"},e.unref(r).columnProps),{default:e.withCtx(({$index:C})=>[e.createTextVNode(e.toDisplayString(s(C)),1)]),_:1},16,["label"])):e.unref(r).type==="operation"&&b.value?(e.openBlock(),e.createBlock(B,e.mergeProps({key:2,label:e.unref(r).label||"操作",align:"center"},{...e.unref(r).columnProps,width:E.value}),{default:e.withCtx(({row:C})=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(y)(C),_=>(e.openBlock(),e.createBlock(x,{key:_.label,type:_.type||"primary",link:"",onClick:P=>_.action(C)},{default:e.withCtx(()=>[e.createTextVNode(e.toDisplayString(_.label),1)]),_:2},1032,["type","onClick"]))),128))]),_:1},16,["label"])):$(e.unref(r))?(e.openBlock(),e.createBlock(B,e.mergeProps({key:3,label:e.unref(r).label,align:"center"},e.unref(r).columnProps||{}),{default:e.withCtx(C=>{var _,P,O,F;return[e.unref(r).render==="slot"&&m.$slots[((_=e.unref(r))==null?void 0:_.slot)||e.unref(r).key]?e.renderSlot(m.$slots,((P=e.unref(r))==null?void 0:P.slot)||e.unref(r).key,e.normalizeProps(e.mergeProps({key:0},C))):e.unref(r).render&&e.unref(g)[e.unref(r).render]?(e.openBlock(),e.createBlock(e.resolveDynamicComponent(e.unref(g)[e.unref(r).render]),{key:1,row:C.row,col:e.unref(r),onCellChange:i,onCellBlur:a,onCellEnter:d,onClick:p},null,40,["row","col"])):(e.openBlock(),e.createElementBlock("span",{key:2,style:e.normalizeStyle(((O=e.unref(r).renderProps)==null?void 0:O.style)||""),class:e.normalizeClass(((F=e.unref(r).renderProps)==null?void 0:F.class)||""),title:e.unref(h)(C.row,e.unref(r).key)},e.toDisplayString(e.unref(h)(C.row,e.unref(r).key)),15,W))]}),_:3},16,["label"])):e.createCommentVNode("",!0)}}}),N="table_columns_";function R(n,t){return`${N}${n}_${t}`}function K(n,t){if(!(t!=null&&t.length))return n;const l=new Map(t.map(o=>[o.key,o]));return n.map(o=>{const s=l.get(o.key);return s?{...o,visible:typeof s.visible=="boolean"?s.visible:o.visible}:o})}function j(n,t){const{pageKey:l,userId:o,storage:s=localStorage}=t||{},i=o?R(o,l||""):null,a=i?s.getItem(i):null,d=e.ref(K(n,a?JSON.parse(a):[]));return e.watch(d,p=>{if(!i)return;const g=p.map(u=>({key:u.key,visible:u.visible,columnOpts:u.columnOpts}));s.setItem(i,JSON.stringify(g))},{deep:!0}),{columns:d,setColumns(p){d.value=K(n,p),i&&s.setItem(i,JSON.stringify(p))},resetColumns(){d.value=n,i&&s.removeItem(i)}}}const q=e.defineComponent({__name:"index",props:{data:{type:Array,default:()=>[]},columns:{type:Array,default:()=>[]},pageKey:String,rowKey:{type:String,default:"id"},loading:{type:Boolean,default:!1},permissions:{type:Array,default:()=>[]},userId:{type:[String,Number],default:""},pagination:{type:Object,default:()=>({})}},emits:["update:columns","cellChange","cellBlur","cellEnter","cell-click"],setup(n,{expose:t,emit:l}){const o=n,s=l,{columns:r}=j(o.columns,{pageKey:o.pageKey??"",userId:o.userId??""});e.watch(r,u=>s("update:columns",u),{deep:!0,immediate:!0});const i=(u,k)=>s("cellChange",u,k),a=(u,k)=>{s("cellBlur",u,k)},d=(u,k)=>{console.log("enter"),s("cellEnter",u,k)},p=(u,k)=>{k&&s("cell-click",u,k)},g=e.ref();return t({tableRef:g}),(u,k)=>{const c=e.resolveComponent("el-table"),f=e.resolveDirective("loading");return e.withDirectives((e.openBlock(),e.createBlock(c,e.mergeProps({ref_key:"tableRef",ref:g},u.$attrs,{data:n.data,"row-key":n.rowKey,class:"smart-table"}),{default:e.withCtx(()=>[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(e.unref(r),y=>(e.openBlock(),e.createBlock(D,{key:y.key,col:y,permissions:n.permissions,pagination:n.pagination,onCellChange:i,onCellBlur:a,onCellEnter:d,onCellClick:p},e.createSlots({_:2},[e.renderList(e.unref(r),b=>({name:b.key,fn:e.withCtx(E=>[e.renderSlot(u.$slots,b.key,e.mergeProps({ref_for:!0},E),void 0,!0)])}))]),1032,["col","permissions","pagination"]))),128))]),_:3},16,["data","row-key"])),[[f,n.loading]])}}}),J=(n,t)=>{const l=n.__vccOpts||n;for(const[o,s]of t)l[o]=s;return l},U=J(q,[["__scopeId","data-v-7c94ec39"]]);exports.SmartTable=U;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.copy-wrapper:hover .copy-btn{display:inline-block!important}.smart-table[data-v-
|
|
1
|
+
.copy-wrapper:hover .copy-btn{display:inline-block!important}.smart-table[data-v-7c94ec39]{width:100%}
|