vue3-smart-table 1.0.2 → 1.0.3

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 CHANGED
@@ -1,45 +1,292 @@
1
- # SmartTable 使用文档
1
+ # Vue3 Smart Table
2
2
 
3
- ## 概览
3
+ > 基于 Vue 3 + Element Plus 的高可复用表格组件库 - 插件化架构,支持自定义渲染器
4
4
 
5
- `SmartTable` 是一个 **基于 Vue 3 + Element Plus** 的高可复用表格组件,面向 **中后台系统** 场景设计,强调:
5
+ ## 特性
6
6
 
7
- - 配置驱动(columns schema)
8
- - 权限解耦(不依赖 store / 登录体系)
9
- - 操作列智能显示(无可见按钮 整列隐藏)
10
- - 列显隐持久化(方案 A:只缓存 visible)
11
- - 单元格渲染器体系(renderer 插件化)
7
+ - **插件化架构** - 支持自定义渲染器,灵活扩展
8
+ - **开箱即用** - 内置 12+ 种常用渲染器
9
+ - **类型安全** - 完整的 TypeScript 类型支持
10
+ - **主题定制** - 使用 CSS 变量,轻松定制主题
11
+ - **按需引入** - Tree-shaking 友好,减小打包体积
12
+ - **性能优化** - 列配置缓存、虚拟滚动支持
13
+ - **简单易用** - 专注于表格功能,不侵入数据管理
14
+
15
+ ## 安装
16
+
17
+ ```bash
18
+ npm install vue3-smart-table
19
+ # or
20
+ yarn add vue3-smart-table
21
+ # or
22
+ pnpm add vue3-smart-table
23
+ ```
24
+
25
+ ## 快速开始
26
+
27
+ ### 1️⃣ 安装依赖
28
+
29
+ SmartTable 依赖 Element Plus,需要先安装:
30
+
31
+ ```bash
32
+ # 安装 SmartTable
33
+ npm install vue3-smart-table
34
+
35
+ # 安装 Element Plus(如果还没安装)
36
+ npm install element-plus
37
+ ```
38
+
39
+ ### 2️⃣ 完整引入
40
+
41
+ ```typescript
42
+ // main.ts
43
+ import { createApp } from 'vue'
44
+ import App from './App.vue'
45
+
46
+ // 引入 Element Plus
47
+ import ElementPlus from 'element-plus'
48
+ import 'element-plus/dist/index.css'
49
+
50
+ // 引入 SmartTable
51
+ import SmartTable from 'vue3-smart-table'
52
+ import 'vue3-smart-table/dist/style.css'
53
+
54
+ const app = createApp(App)
55
+ app.use(ElementPlus)
56
+ app.use(SmartTable)
57
+ app.mount('#app')
58
+ ```
59
+
60
+ ### 3️⃣ 基础使用
61
+
62
+ ```vue
63
+ <template>
64
+ <SmartTable :columns="columns" :data="tableData" />
65
+ </template>
66
+
67
+ <script setup lang="ts">
68
+ import { ref } from 'vue'
69
+
70
+ // 表格列配置
71
+ const columns = [
72
+ { key: 'name', label: '姓名', width: 120 },
73
+ { key: 'age', label: '年龄', width: 80 },
74
+ { key: 'email', label: '邮箱' }
75
+ ]
76
+
77
+ // 表格数据
78
+ const tableData = ref([
79
+ { id: 1, name: '张三', age: 25, email: 'zhangsan@example.com' },
80
+ { id: 2, name: '李四', age: 30, email: 'lisi@example.com' },
81
+ { id: 3, name: '王五', age: 28, email: 'wangwu@example.com' }
82
+ ])
83
+ </script>
84
+ ```
85
+
86
+ ### 4️⃣ 按需引入(推荐)
87
+
88
+ 如果你只需要在特定页面使用:
89
+
90
+ ```vue
91
+ <template>
92
+ <SmartTable :columns="columns" :data="tableData" />
93
+ </template>
94
+
95
+ <script setup lang="ts">
96
+ import { ref } from 'vue'
97
+ import { SmartTable } from 'vue3-smart-table'
98
+ // 确保在 main.ts 中已经全局引入了样式
99
+ </script>
100
+ ```
101
+
102
+ ### 5️⃣ 完整示例(带加载状态和分页)
103
+
104
+ ```vue
105
+ <template>
106
+ <div>
107
+ <SmartTable
108
+ :columns="columns"
109
+ :data="tableData"
110
+ :loading="loading"
111
+ :pagination="{ page: 1, size: 10, total: total }"
112
+ />
113
+
114
+ <el-pagination
115
+ v-model:current-page="currentPage"
116
+ v-model:page-size="pageSize"
117
+ :total="total"
118
+ @current-change="handlePageChange"
119
+ @size-change="handleSizeChange"
120
+ />
121
+ </div>
122
+ </template>
123
+
124
+ <script setup lang="ts">
125
+ import { ref, onMounted } from 'vue'
126
+ import { SmartTable } from 'vue3-smart-table'
127
+
128
+ const columns = [
129
+ { key: 'name', label: '姓名' },
130
+ { key: 'age', label: '年龄' },
131
+ { key: 'email', label: '邮箱' }
132
+ ]
133
+
134
+ const tableData = ref([])
135
+ const loading = ref(false)
136
+ const currentPage = ref(1)
137
+ const pageSize = ref(10)
138
+ const total = ref(0)
139
+
140
+ // 模拟数据获取
141
+ const fetchData = async () => {
142
+ loading.value = true
143
+ try {
144
+ // 实际项目中替换为你的 API 调用
145
+ const response = await fetch(`/api/users?page=${currentPage.value}&size=${pageSize.value}`)
146
+ const result = await response.json()
147
+ tableData.value = result.data
148
+ total.value = result.total
149
+ } finally {
150
+ loading.value = false
151
+ }
152
+ }
153
+
154
+ const handlePageChange = (page: number) => {
155
+ currentPage.value = page
156
+ fetchData()
157
+ }
158
+
159
+ const handleSizeChange = (size: number) => {
160
+ pageSize.value = size
161
+ currentPage.value = 1
162
+ fetchData()
163
+ }
164
+
165
+ onMounted(() => {
166
+ fetchData()
167
+ })
168
+ </script>
169
+ ```
12
170
 
13
171
  ---
14
172
 
15
173
  ## 目录结构
16
174
 
17
175
  ```txt
18
- SmartTable/
19
- ├─ column/
20
- │ ├─ index.vue # TableColumn 子组件
21
- └─ renderer.ts # renderer 注册中心
22
- ├─ hooks/
23
- │ ├─ useOperationColumn.ts # 操作列按钮可见性 / 宽度逻辑
24
- └─ useTableColumns.ts # 列显隐缓存(只缓存 visible)
25
- ├─ index.vue # SmartTable 主组件
26
- ├─ types.ts # ColumnConfig / ButtonConfig 类型
27
- └─ README.md
176
+ src/
177
+ ├─ components/SmartTable/ # 主组件(完全自包含)
178
+ │ ├─ column/ # TableColumn 子组件
179
+ ├─ hooks/ # 组件内部 Hooks(不对外暴露)
180
+ ├─ renderers/ # 内置渲染器
181
+ │ ├─ renderer.ts # 渲染器管理器
182
+ ├─ config.ts # 全局配置管理
183
+ ├─ utils/ # 内部工具函数
184
+ ├─ types.ts # 类型定义
185
+ └─ index.vue # SmartTable 主组件
186
+ ├─ types/ # 类型工具(对外提供)
187
+ └─ index.ts # 入口文件
28
188
  ```
29
189
 
190
+ **架构优势**:
191
+ - ✅ SmartTable 组件完全自包含
192
+ - ✅ utils 和 styles 在组件内部
193
+ - ✅ 无外部依赖,易于移植和维护
194
+ - ✅ 清晰的内部和外部边界
195
+
30
196
  ---
31
197
 
32
- ## 1. SmartTable Props
198
+ ## 核心概念
199
+
200
+ ### 📦 SmartTable 是什么?
201
+
202
+ SmartTable 是一个**完全自包含的表格组件**,专注于表格渲染和交互功能。它:
203
+
204
+ - ✅ **不侵入你的数据管理** - 你可以用任何方式管理数据(ref、computed、VueUse 等)
205
+ - ✅ **专注于表格功能** - 渲染、编辑、排序、筛选等表格特有的功能
206
+ - ✅ **高度可定制** - 通过渲染器系统扩展任何自定义单元格
207
+
208
+ ### 🎯 设计理念
209
+
210
+ 与传统表格库不同,SmartTable 遵循以下理念:
211
+
212
+ ```typescript
213
+ // ❌ 传统方式:强制使用组件的数据管理
214
+ import { useTable } from 'some-table-lib' // 被迫使用特定的数据管理方案
215
+ const { data, loading, refresh } = useTable(...)
216
+
217
+ // ✅ SmartTable:你自己管理数据
218
+ import { ref } from 'vue' // 使用你熟悉的方式
219
+ const data = ref([])
220
+ const loading = ref(false)
221
+ // 完全的控制权!
222
+ ```
223
+
224
+ **为什么这样做?**
225
+
226
+ 1. **灵活性** - 不同项目有不同的数据管理需求
227
+ 2. **简单性** - 不需要学习特定的数据管理 API
228
+ 3. **兼容性** - 可以与任何状态管理方案配合使用
229
+ 4. **标准性** - 符合 Vue 生态的最佳实践
230
+
231
+ ---
232
+
233
+
234
+
235
+ ### 1. 插件化架构
236
+
237
+ 支持动态注册自定义渲染器:
238
+
239
+ ```typescript
240
+ import { getRendererManager, createFunctionalRenderer } from 'vue3-smart-table'
241
+ import { h } from 'vue'
242
+
243
+ // 创建自定义渲染器
244
+ const myRenderer = createFunctionalRenderer((props) => {
245
+ const val = props.row[props.col.key]
246
+ return h('span', { class: 'custom-renderer' }, `前缀: ${val}`)
247
+ })
248
+
249
+ // 注册渲染器
250
+ getRendererManager().register('my-renderer', myRenderer)
251
+
252
+ // 使用
253
+ const columns = [
254
+ { key: 'name', render: 'my-renderer' }
255
+ ]
256
+ ```
257
+
258
+ ### 2. 全局配置
259
+
260
+ ```typescript
261
+ import { setSmartTableConfig } from 'vue3-smart-table'
262
+
263
+ setSmartTableConfig({
264
+ defaultPagination: {
265
+ page: 1,
266
+ size: 20
267
+ },
268
+ renderers: {
269
+ // 全局注册自定义渲染器
270
+ 'custom-renderer': MyRendererComponent
271
+ }
272
+ })
273
+ ```
274
+
275
+ ---
276
+
277
+ ## API 文档
278
+
279
+ ### SmartTable Props
33
280
 
34
281
  | 属性 | 类型 | 默认值 | 说明 |
35
282
  | --- | --- | --- | --- |
36
- | data | `any[]` | `[]` | 表格数据 |
37
- | columns | `ColumnConfig[]` | `[]` | 列配置(支持 v-model:columns |
38
- | rowKey | `string` | `'id'` | 行唯一 key |
39
- | loading | `boolean` | `false` | loading 状态 |
40
- | permissions | `string[]` | `[]` | 当前用户权限列表 |
41
- | pageKey | `string` | - | 列缓存 pageKey(可选) |
42
- | userId | `string \| number` | - | 列缓存 userId(可选) |
283
+ | data | `any[]` | `[]` | 必需 - 表格数据 |
284
+ | columns | `ColumnConfig[]` | `[]` |必需 - 列配置数组,支持 v-model:columns 双向绑定|
285
+ | rowKey | `string` | `'id'` | 行数据的唯一标识字段 |
286
+ | loading | `boolean` | `false` | 加载状态,显示加载动画 |
287
+ | permissions | `string[]` | `[]` | 当前用户权限列表,用于操作列权限控制 |
288
+ | cacheKey | `string` | - | **列缓存键(推荐)**,如果提供则直接使用,格式:`table_columns_{userId}_{pageKey}` 或自定义 |
289
+ | pagination | `{page: number, size: number}` | - | 序号列计算序号(可选),page:当前页,size:当前页显示条数,不填则默认序号 |
43
290
 
44
291
  > 其余属性将 **透传给 el-table**。
45
292
 
@@ -56,6 +303,7 @@ export interface ColumnConfig<R = any> {
56
303
  visible?: boolean
57
304
  inControl?: boolean
58
305
  render?: string
306
+ slot?: string // render为slot时可自定slot否则使用key
59
307
 
60
308
  renderProps?: Record<string, any>
61
309
  columnProps?: Record<string, any>
@@ -75,6 +323,7 @@ export interface ColumnConfig<R = any> {
75
323
  - `selection / index / operation` 为 **核心列**
76
324
  - 核心列必须:`inControl = false`
77
325
  - 普通列通过 `visible` 控制显示 / 隐藏
326
+ - 可通过 render 使用内置 renderer 或自定义插槽
78
327
 
79
328
  ---
80
329
 
@@ -106,207 +355,949 @@ export interface ButtonConfig<R = any> {
106
355
 
107
356
  ---
108
357
 
109
- ## 4. 内置 Renderer
110
-
111
- | renderer | 说明 |
112
- | --- | --- |
113
- | `html` | 原生 HTML(ellipsis) |
114
- | `copy` | 可复制文本(hover 显示按钮 + ElMessage) |
115
- | `img` | 图片预览 |
116
- | `dict` | 字典映射 |
117
- | `map` | key-value 映射 |
118
- | `formatter` | 自定义格式化 |
119
- | `icon` | iconfont / svg / url |
120
- | `input` | 可编辑单元格 |
121
- | `input-number` | 可编辑单元格 |
122
- | `select` | 可编辑单元格 |
123
- | `button` | 单行按钮 |
124
- | `link` | 单行链接 |
125
-
126
- ### copy 示例
358
+ ## 4. 内置渲染器完整指南
359
+
360
+ SmartTable 提供 13 种内置渲染器,按功能分为 4 类:
361
+
362
+ - **📝 展示型** (7种):html、copy、img、dict、map、formatter、icon
363
+ - **✏️ 编辑型** (3种):input、input-number、select
364
+ - **🔘 操作型** (2种):button、link
365
+ - **🔧 扩展型** (1种):slot
366
+
367
+ ### 快速查找表
368
+
369
+ | 渲染器 | 类型 | 配置复杂度 | 支持事件 |
370
+ |--------|------|-----------|---------|
371
+ | `html` | 展示 | ⭐ | ❌ |
372
+ | `copy` | 展示 | ⭐⭐ | ❌ |
373
+ | `img` | 展示 | ⭐⭐ | ❌ |
374
+ | `dict` | 展示 | ⭐⭐⭐ | ❌ |
375
+ | `map` | 展示 | ⭐⭐ | ❌ |
376
+ | `formatter` | 展示 | ⭐⭐ | ❌ |
377
+ | `icon` | 展示 | ⭐⭐ | ❌ |
378
+ | `input` | 编辑 | ⭐⭐ | ✅ |
379
+ | `input-number` | 编辑 | ⭐⭐ | ✅ |
380
+ | `select` | 编辑 | ⭐⭐ | ✅ |
381
+ | `button` | 操作 | ⭐ | ✅ |
382
+ | `link` | 操作 | ⭐ | ✅ |
383
+ | `slot` | 扩展 | ⭐⭐⭐⭐ | ❌ |
127
384
 
128
- ```ts
385
+ ---
386
+
387
+ ### 📝 展示型渲染器
388
+
389
+ 用于数据展示,不涉及用户交互。
390
+
391
+ #### 1. `html` - HTML 内容渲染
392
+
393
+ **功能**:渲染 HTML 内容,支持多行文本截断(最多 2 行)。
394
+
395
+ **配置**:
396
+ ```typescript
129
397
  {
130
- key: 'username',
131
- label: '用户名',
132
- render: 'copy'
398
+ key: 'description',
399
+ label: '描述',
400
+ render: 'html',
401
+ renderProps: {
402
+ style?: string // 自定义样式
403
+ class?: string // 自定义类名
404
+ }
133
405
  }
134
406
  ```
135
407
 
136
- 特性:
137
- - hover 显示复制按钮
138
- - 复制成功 / 失败统一使用 `ElMessage`
408
+ **示例**:
409
+ ```typescript
410
+ const columns = [
411
+ {
412
+ key: 'content',
413
+ label: '商品描述',
414
+ render: 'html'
415
+ }
416
+ ]
417
+
418
+ const tableData = [
419
+ {
420
+ content: '<p>这是一段<strong>加粗</strong>的文本</p>'
421
+ }
422
+ ]
423
+ ```
424
+
425
+ **效果**:
426
+ - 自动截断为 2 行
427
+ - 支持富文本 HTML
428
+ - 超出部分显示省略号
139
429
 
140
430
  ---
141
- ### img 示例
142
- ```ts
431
+
432
+ #### 2. `copy` - 可复制文本
433
+
434
+ **功能**:hover 显示复制按钮,点击复制文本到剪贴板。
435
+
436
+ **配置**:
437
+ ```typescript
143
438
  {
144
- key: 'avatar',
145
- label: '头像',
146
- render: 'img',
147
- columnProps: { minWidth: 150},
439
+ key: 'code',
440
+ label: '编号',
441
+ render: 'copy',
148
442
  renderProps: {
149
- width: '60px',
150
- height: '60px',
151
- fit: 'cover',
152
- placeholder: '--'
443
+ iconColor?: string // 图标颜色,默认 '#409EFF'
444
+ copyTitle?: string // 复制提示文本,默认 '复制'
445
+ successText?: string // 成功提示,默认 '复制成功'
446
+ errorText?: string // 失败提示,默认 '复制失败'
153
447
  }
154
- },
448
+ }
449
+ ```
450
+
451
+ **示例**:
452
+ ```typescript
453
+ const columns = [
454
+ {
455
+ key: 'orderNo',
456
+ label: '订单号',
457
+ render: 'copy',
458
+ renderProps: {
459
+ iconColor: '#67C23A',
460
+ successText: '订单号已复制',
461
+ errorText: '复制失败,请重试'
462
+ }
463
+ }
464
+ ]
465
+ ```
466
+
467
+ **效果**:
468
+ - hover 显示复制按钮图标
469
+ - 点击自动复制到剪贴板
470
+ - 使用 ElMessage 提示结果
471
+ - 支持单行文本截断
472
+
473
+ ---
474
+
475
+ #### 3. `img` - 图片预览
476
+
477
+ **功能**:图片展示,支持单图/多图预览。
478
+
479
+ **配置**:
480
+ ```typescript
155
481
  {
156
- key: 'gallery',
157
- label: '相册',
482
+ key: 'avatar',
483
+ label: '头像',
158
484
  render: 'img',
159
- columnProps: { minWidth: 150},
160
485
  renderProps: {
161
- width: '100px',
162
- height: '100px'
486
+ width?: string | number // 图片宽度,默认 '80px'
487
+ height?: string | number // 图片高度,默认 '80px'
488
+ fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down' // 适应方式
489
+ previewSrcList?: string[] // 预览图片列表(可选)
490
+ placeholder?: string // 无图片时的占位文本
491
+ style?: string // 自定义样式
163
492
  }
164
- },
165
- const tableData = reactive([
166
- { id: 3, name: 'Charlie', code: '9525', status: 0, map: 1, regionCode:'海外', orderNum: 1, selectId: 2,
167
- avatar: 'https://iconfont.alicdn.com/p/illus_3d/file/UMAqlm6KX5gw/8e357f00-9a4e-44c4-b0c5-bbed255cff24.png' ,
493
+ }
494
+ ```
495
+
496
+ **示例 - 单图**:
497
+ ```typescript
498
+ const columns = [
499
+ {
500
+ key: 'avatar',
501
+ label: '头像',
502
+ render: 'img',
503
+ renderProps: {
504
+ width: '60px',
505
+ height: '60px',
506
+ fit: 'cover'
507
+ }
508
+ }
509
+ ]
510
+
511
+ const tableData = [
512
+ { avatar: 'https://example.com/avatar.jpg' }
513
+ ]
514
+ ```
515
+
516
+ **示例 - 多图**:
517
+ ```typescript
518
+ const columns = [
519
+ {
520
+ key: 'gallery',
521
+ label: '相册',
522
+ render: 'img',
523
+ renderProps: {
524
+ width: '80px',
525
+ height: '80px'
526
+ }
527
+ }
528
+ ]
529
+
530
+ const tableData = [
531
+ {
168
532
  gallery: [
169
- 'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
170
- 'https://iconfont.alicdn.com/p/illus_3d/file/UMAqlm6KX5gw/8e357f00-9a4e-44c4-b0c5-bbed255cff24.png',
171
- ],
172
- },
173
- ])
533
+ 'https://example.com/img1.jpg',
534
+ 'https://example.com/img2.jpg',
535
+ 'https://example.com/img3.jpg'
536
+ ]
537
+ }
538
+ ]
174
539
  ```
175
- - 单张图片:正常显示并支持预览
176
- - 多张图片:显示第一张,右侧显示剩余数量(如:+2)
177
- - 支持 previewSrcList 自定义预览列表
178
- - 支持图片大小(width/height)、填充模式(fit)配置
540
+
541
+ **效果**:
542
+ - **单图**:直接显示,点击预览
543
+ - **多图**:显示第一张 + 数量标记(如:+2),点击预览全部
544
+ - 支持 Element Plus Image 的所有预览功能
179
545
  - 无图片时显示占位符或空内容
180
546
 
181
- ### map 示例
547
+ ---
182
548
 
183
- ```ts
184
- const providerMap = {
185
- aa: 'xxx',
186
- bb: 'xxxx',
187
- cc: 'xxxxxx'
188
- }
189
- {
190
- visible: true,
191
- key: "status",
192
- label: "状态",
193
- render: "map",
549
+ #### 4. `dict` - 字典标签映射
550
+
551
+ **功能**:将值映射为标签显示(使用 ElTag)。
552
+
553
+ **配置**:
554
+ ```typescript
555
+ {
556
+ key: 'status',
557
+ label: '状态',
558
+ render: 'dict',
194
559
  renderProps: {
195
- options: providerMap,
196
- },
197
- columnProps: { width: 80, sortable: true}
198
- },
560
+ options: Array<{ // 字典配置(必需)
561
+ label: string // 显示文本
562
+ value: any //
563
+ listClass?: string // ElTag 类型:'primary' | 'success' | 'warning' | 'danger' | 'info'
564
+ cssClass?: string // 自定义类名
565
+ }>
566
+ showValue?: boolean // 是否显示未匹配的值,默认 false
567
+ }
568
+ }
569
+ ```
199
570
 
571
+ **示例 - 单值**:
572
+ ```typescript
573
+ const columns = [
574
+ {
575
+ key: 'status',
576
+ label: '状态',
577
+ render: 'dict',
578
+ renderProps: {
579
+ options: [
580
+ { label: '启用', value: 1, listClass: 'success' },
581
+ { label: '禁用', value: 0, listClass: 'danger' },
582
+ { label: '审核中', value: 2, listClass: 'warning' }
583
+ ]
584
+ }
585
+ }
586
+ ]
587
+
588
+ const tableData = [
589
+ { status: 1 } // 显示:[启用]
590
+ ]
200
591
  ```
201
- - 根据值映射显示文本
202
- - 不匹配则显示空字符串
203
592
 
204
- ### dict 示例
593
+ **示例 - 多值**:
594
+ ```typescript
595
+ const columns = [
596
+ {
597
+ key: 'tags',
598
+ label: '标签',
599
+ render: 'dict',
600
+ renderProps: {
601
+ options: [
602
+ { label: '重要', value: 'important', listClass: 'danger' },
603
+ { label: '紧急', value: 'urgent', listClass: 'warning' }
604
+ ],
605
+ showValue: true // 显示未匹配的值
606
+ }
607
+ }
608
+ ]
205
609
 
206
- ```ts
207
- const Enables = [
208
- { label: '启用', value: 1, listClass: 'primary' },
209
- { label: '禁用', value: 0, listClass: 'warning' }
610
+ const tableData = [
611
+ { tags: ['important', 'urgent'] } // 显示:[重要] [紧急]
210
612
  ]
613
+ ```
614
+
615
+ **效果**:
616
+ - 单值映射为单个标签
617
+ - 多值映射为多个标签
618
+ - 未匹配的值根据 `showValue` 决定是否显示
619
+ - 支持自定义标签颜色和样式
620
+
621
+ ---
622
+
623
+ #### 5. `map` - 键值映射
624
+
625
+ **功能**:简单的 key-value 映射。
211
626
 
212
- {
213
- key: "status",
214
- label: "状态",
215
- visible: true,
216
- render: "dict",
627
+ **配置**:
628
+ ```typescript
629
+ {
630
+ key: 'gender',
631
+ label: '性别',
632
+ render: 'map',
217
633
  renderProps: {
218
- options: Enables,
219
- },
220
- columnProps: { width: 80, sortable: true}
221
- },
634
+ options: Record<string | number, any> // 映射配置(必需)
635
+ }
636
+ }
222
637
  ```
638
+
639
+ **示例**:
640
+ ```typescript
641
+ const columns = [
642
+ {
643
+ key: 'gender',
644
+ label: '性别',
645
+ render: 'map',
646
+ renderProps: {
647
+ options: {
648
+ 1: '男',
649
+ 2: '女',
650
+ 0: '未知'
651
+ }
652
+ }
653
+ }
654
+ ]
655
+
656
+ const tableData = [
657
+ { gender: 1 }, // 显示:男
658
+ { gender: 2 }, // 显示:女
659
+ { gender: 99 } // 显示:(空)
660
+ ]
661
+ ```
662
+
663
+ **效果**:
664
+ - 根据值映射显示对应文本
665
+ - 未匹配的值显示空字符串
666
+ - 比 `dict` 更简单,适合不需要标签样式的场景
667
+
223
668
  ---
224
- - 支持多选值
225
- - 可通过 showValue 显示未匹配的值
226
- - 可自定义 tag 类型(listClass)
227
669
 
228
- ### formatter 示例
229
- ```ts
670
+ #### 6. `formatter` - 自定义格式化
671
+
672
+ **功能**:使用自定义函数格式化显示。
673
+
674
+ **配置**:
675
+ ```typescript
230
676
  {
231
677
  key: 'price',
232
678
  label: '价格',
233
679
  render: 'formatter',
234
- formatter: (val) => `$${val}`
680
+ formatter: (value: any, row: any) => string // 格式化函数
235
681
  }
236
682
  ```
237
- - 使用自定义函数格式化显示内容
238
683
 
239
- ### 编辑型 渲染器
684
+ **示例**:
685
+ ```typescript
686
+ const columns = [
687
+ {
688
+ key: 'price',
689
+ label: '价格',
690
+ render: 'formatter',
691
+ formatter: (value, row) => {
692
+ return `¥${Number(value).toFixed(2)}`
693
+ }
694
+ },
695
+ {
696
+ key: 'date',
697
+ label: '日期',
698
+ render: 'formatter',
699
+ formatter: (value) => {
700
+ return new Date(value).toLocaleDateString('zh-CN')
701
+ }
702
+ }
703
+ ]
240
704
 
241
- ```ts
705
+ const tableData = [
706
+ { price: 99.9, date: '2024-01-01' }
707
+ ]
708
+ ```
709
+
710
+ **效果**:
711
+ - 完全自定义格式化逻辑
712
+ - 可以访问当前行数据
713
+ - 适合复杂的格式化需求
714
+
715
+ ---
716
+
717
+ #### 7. `icon` - 图标渲染
718
+
719
+ **功能**:支持多种图标格式。
720
+
721
+ **配置**:
722
+ ```typescript
723
+ {
724
+ key: 'icon',
725
+ label: '图标',
726
+ render: 'icon',
727
+ renderProps: {
728
+ style?: string // 自定义样式
729
+ size?: number // 图标大小(像素)
730
+ class?: string // 自定义类名
731
+ }
732
+ }
733
+ ```
734
+
735
+ **示例**:
736
+ ```typescript
737
+ const columns = [
738
+ {
739
+ key: 'avatarIcon',
740
+ label: '头像',
741
+ render: 'icon',
742
+ renderProps: {
743
+ style: 'font-size: 32px; color: #409EFF'
744
+ }
745
+ }
746
+ ]
747
+
748
+ const tableData = [
749
+ // 1. 网络图片
750
+ { icon: 'https://example.com/icon.png' },
751
+
752
+ // 2. SVG 源码
753
+ { icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">...</svg>' },
754
+
755
+ // 3. iconfont 类名
756
+ { icon: 'iconfont icon-user' }
757
+ ]
758
+ ```
759
+
760
+ **效果**:
761
+ - 自动识别图标类型
762
+ - 网络图片:显示为 ElImage
763
+ - SVG:直接渲染
764
+ - iconfont:应用类名样式
765
+
766
+ ---
767
+
768
+ ### ✏️ 编辑型渲染器
769
+
770
+ 支持单元格编辑,触发 `cellChange`、`cellBlur`、`cellEnter` 事件。
771
+
772
+ #### 8. `input` - 可编辑输入框
773
+
774
+ **配置**:
775
+ ```typescript
776
+ {
777
+ key: 'username',
778
+ label: '用户名',
779
+ render: 'input',
780
+ renderProps: {
781
+ placeholder?: string // 占位文本,默认 ''
782
+ size?: 'large' | 'default' | 'small' // 尺寸,默认 'small'
783
+ clearable?: boolean // 是否可清空,默认 true
784
+ // ... 其他 ElInput 属性
785
+ }
786
+ }
787
+ ```
788
+
789
+ **示例**:
790
+ ```typescript
791
+ const columns = [
792
+ {
793
+ key: 'username',
794
+ label: '用户名',
795
+ render: 'input',
796
+ renderProps: {
797
+ placeholder: '请输入用户名',
798
+ clearable: true
799
+ }
800
+ }
801
+ ]
802
+ ```
803
+
804
+ **事件处理**:
805
+ ```vue
806
+ <script setup>
807
+ const handleCellChange = (row, col) => {
808
+ console.log('值已修改:', row[col.key])
809
+ }
810
+
811
+ const handleCellBlur = (row, col) => {
812
+ console.log('失去焦点')
813
+ }
814
+
815
+ const handleCellEnter = (row, col) => {
816
+ console.log('回车确认')
817
+ }
818
+ </script>
819
+
820
+ <template>
821
+ <SmartTable
822
+ :columns="columns"
823
+ :data="tableData"
824
+ @cellChange="handleCellChange"
825
+ @cellBlur="handleCellBlur"
826
+ @cellEnter="handleCellEnter"
827
+ />
828
+ </template>
829
+ ```
830
+
831
+ ---
832
+
833
+ #### 9. `input-number` - 可编辑数字输入框
834
+
835
+ **配置**:
836
+ ```typescript
242
837
  {
243
838
  key: 'age',
244
839
  label: '年龄',
245
840
  render: 'input-number',
246
- renderProps: { min: 0, max: 120 }
841
+ renderProps: {
842
+ min?: number // 最小值
843
+ max?: number // 最大值
844
+ step?: number // 步长
845
+ precision?: number // 精度
846
+ size?: 'large' | 'default' | 'small'
847
+ controls?: boolean // 是否显示增减按钮
848
+ // ... 其他 ElInputNumber 属性
849
+ }
247
850
  }
248
851
  ```
249
- - 支持类型:input / number / select
250
- - 支持事件:
251
- - cellChange(row, col) 值变化
252
- - cellBlur(row, col) 失去焦点
253
- - cellEnter(row, col) 回车事件(input)
254
- ### icon 示例
255
- ```ts
852
+
853
+ **示例**:
854
+ ```typescript
855
+ const columns = [
856
+ {
857
+ key: 'orderNum',
858
+ label: '序号',
859
+ render: 'input-number',
860
+ renderProps: {
861
+ min: 0,
862
+ max: 100,
863
+ step: 1,
864
+ controls: false // 隐藏增减按钮
865
+ }
866
+ }
867
+ ]
868
+ ```
869
+
870
+ ---
871
+
872
+ #### 10. `select` - 可编辑下拉选择
873
+
874
+ **配置**:
875
+ ```typescript
256
876
  {
257
- key: 'icon',
258
- label: '图标',
259
- render: 'icon',
260
- renderProps: { style: 'color:red;font-size:24px' }
877
+ key: 'status',
878
+ label: '状态',
879
+ render: 'select',
880
+ renderProps: {
881
+ options: Array<{ // 选项配置(必需)
882
+ label: string
883
+ value: any
884
+ }>
885
+ placeholder?: string // 占位文本,默认 '请选择'
886
+ size?: 'large' | 'default' | 'small'
887
+ clearable?: boolean // 是否可清空
888
+ // ... 其他 ElSelect 属性
889
+ }
261
890
  }
262
891
  ```
263
- - 支持网络图片 URL
264
- - 支持 svg 字符串
265
- - 支持 iconfont class
266
892
 
267
- ### button / link
268
- ```ts
269
- { key: 'action', label: '操作', render: 'button', renderProps: { label: '编辑', type: 'text' } }
270
- { key: 'url', label: '查看', render: 'link', renderProps: { label: '详情', href: 'https://example.com', blank: true } }
893
+ **示例**:
894
+ ```typescript
895
+ const columns = [
896
+ {
897
+ key: 'role',
898
+ label: '角色',
899
+ render: 'select',
900
+ renderProps: {
901
+ placeholder: '请选择角色',
902
+ clearable: true,
903
+ options: [
904
+ { label: '管理员', value: 'admin' },
905
+ { label: '普通用户', value: 'user' },
906
+ { label: '访客', value: 'guest' }
907
+ ]
908
+ }
909
+ }
910
+ ]
911
+ ```
912
+
913
+ ---
914
+
915
+ ### 🔘 操作型渲染器
916
+
917
+ 用于触发操作或跳转。
918
+
919
+ #### 11. `button` - 操作按钮
920
+
921
+ **配置**:
922
+ ```typescript
923
+ {
924
+ key: 'action',
925
+ label: '操作',
926
+ render: 'button',
927
+ renderProps: {
928
+ label?: string // 按钮文本
929
+ type?: 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text'
930
+ size?: 'large' | 'default' | 'small'
931
+ disabled?: boolean
932
+ // ... 其他 ElButton 属性
933
+ }
934
+ }
935
+ ```
271
936
 
937
+ **示例**:
938
+ ```typescript
939
+ const columns = [
940
+ {
941
+ key: 'edit',
942
+ label: '编辑',
943
+ render: 'button',
944
+ renderProps: {
945
+ label: '编辑',
946
+ type: 'primary',
947
+ size: 'small'
948
+ }
949
+ }
950
+ ]
272
951
  ```
273
- - 支持事件:
274
- - cellClick(row, col) 点击事件
275
952
 
953
+ **事件处理**:
954
+ ```vue
955
+ <script setup>
956
+ const handleCellClick = (row, col) => {
957
+ if (col.key === 'edit') {
958
+ console.log('编辑行:', row)
959
+ }
960
+ }
961
+ </script>
276
962
 
277
- ## 5. useTableColumns(列显隐缓存)
278
- ```ts
279
- const { columns } = useTableColumns(defaultColumns, { pageKey: 'user-list', userId: currentUserId })
963
+ <template>
964
+ <SmartTable
965
+ :columns="columns"
966
+ :data="tableData"
967
+ @cellClick="handleCellClick"
968
+ />
969
+ </template>
280
970
  ```
281
971
 
282
- ### 设计原则
972
+ ---
283
973
 
284
- - **顺序永远以 defaultColumns 为准**
285
- - ✅ **只缓存 visible**
286
- - ❌ 不缓存 render / action / 函数
287
- - ❌ 不侵入 store / 登录体系
974
+ #### 12. `link` - 链接
288
975
 
289
- ```ts
290
- const { columns } = useTableColumns(defaultColumns, {
291
- pageKey: 'user-list',
292
- userId: currentUserId
293
- })
976
+ **配置**:
977
+ ```typescript
978
+ {
979
+ key: 'detail',
980
+ label: '详情',
981
+ render: 'link',
982
+ renderProps: {
983
+ label?: string // 链接文本
984
+ href: string // 链接地址(必需)
985
+ blank?: boolean // 是否新窗口打开,默认 false
986
+ style?: string // 自定义样式
987
+ }
988
+ }
989
+ ```
990
+
991
+ **示例**:
992
+ ```typescript
993
+ const columns = [
994
+ {
995
+ key: 'url',
996
+ label: '查看',
997
+ render: 'link',
998
+ renderProps: {
999
+ label: '查看详情',
1000
+ href: 'https://example.com',
1001
+ blank: true,
1002
+ style: 'color: #409EFF'
1003
+ }
1004
+ }
1005
+ ]
1006
+ ```
1007
+
1008
+ ---
1009
+
1010
+ ### 🔧 扩展型渲染器
1011
+
1012
+ 用于自定义复杂场景。
1013
+
1014
+ #### 13. `slot` - 自定义插槽
1015
+
1016
+ **功能**:使用 Vue 插槽完全自定义列内容。
1017
+
1018
+ **配置**:
1019
+ ```typescript
1020
+ {
1021
+ key: 'attachments',
1022
+ label: '附件',
1023
+ render: 'slot',
1024
+ slot?: string // 插槽名称,默认使用 key
1025
+ }
1026
+ ```
1027
+
1028
+ **示例**:
1029
+ ```vue
1030
+ <script setup>
1031
+ const columns = [
1032
+ {
1033
+ key: 'attachments',
1034
+ label: '附件列表',
1035
+ render: 'slot',
1036
+ slot: 'attachments'
1037
+ }
1038
+ ]
1039
+
1040
+ const tableData = ref([
1041
+ {
1042
+ id: 1,
1043
+ attachments: [
1044
+ { name: 'file1.pdf', url: '/files/file1.pdf' },
1045
+ { name: 'file2.jpg', url: '/files/file2.jpg' }
1046
+ ]
1047
+ }
1048
+ ])
1049
+
1050
+ const download = (url) => {
1051
+ console.log('下载:', url)
1052
+ }
1053
+ </script>
1054
+
1055
+ <template>
1056
+ <SmartTable :columns="columns" :data="tableData">
1057
+ <template #attachments="{ row }">
1058
+ <div v-for="(file, index) in row.attachments" :key="index">
1059
+ <el-button type="text" @click="download(file.url)">
1060
+ {{ file.name }}
1061
+ </el-button>
1062
+ </div>
1063
+ </template>
1064
+ </SmartTable>
1065
+ </template>
294
1066
  ```
295
1067
 
296
- - `userId` / `pageKey` **由调用方决定**
297
- - 不传则不启用缓存
1068
+ **效果**:
1069
+ - 完全自定义列内容
1070
+ - 访问完整的行数据
1071
+ - 可以包含复杂的交互逻辑
1072
+
1073
+ ---
1074
+
1075
+ ### TypeScript 类型支持
1076
+
1077
+ 所有渲染器的 `renderProps` 都有完整的 TypeScript 类型定义:
1078
+
1079
+ ```typescript
1080
+ import type { ColumnConfig, RendererPropsMap } from 'vue3-smart-table'
1081
+
1082
+ // 类型安全
1083
+ const column: ColumnConfig = {
1084
+ key: 'status',
1085
+ label: '状态',
1086
+ render: 'dict',
1087
+ renderProps: {
1088
+ options: [ // ✅ 类型提示和检查
1089
+ { label: '启用', value: 1 }
1090
+ ]
1091
+ }
1092
+ }
1093
+
1094
+ // 提取特定渲染器的 props 类型
1095
+ type DictProps = RendererPropsMap['dict']
1096
+ const dictConfig: DictProps = {
1097
+ options: [],
1098
+ showValue: true
1099
+ }
1100
+ ```
1101
+
1102
+ ---
1103
+
1104
+ ### 最佳实践
1105
+
1106
+ 1. **选择合适的渲染器**
1107
+ - 简单映射 → `map`
1108
+ - 需要标签样式 → `dict`
1109
+ - 复杂逻辑 → `formatter`
1110
+ - 自定义内容 → `slot`
1111
+
1112
+ 2. **性能优化**
1113
+ - 大量数据时避免 `formatter`,使用 `map` 或 `dict`
1114
+ - 复杂自定义内容优先使用 `slot`
1115
+
1116
+ 3. **用户体验**
1117
+ - 图片显示添加 `placeholder`
1118
+ - 复制功能添加友好的提示文本
1119
+ - 编辑单元格添加合适的 `placeholder`
298
1120
 
299
1121
  ---
300
- ## 6. 事件
301
- - 支持类型:input / number / select
302
- - 支持事件:
303
- - cellChange(row, col) 值变化
304
- - cellBlur(row, col) 失去焦点
305
- - cellEnter(row, col) 回车事件(input)
306
- - cellClick(row, col) 点击事件
307
1122
 
1123
+ ## 5. 事件
308
1124
 
309
- ## 7. 使用示例
1125
+ ### 单元格编辑事件
1126
+ 支持类型:input / number / select
1127
+
1128
+ - `cellChange(row, col)` - 值变化
1129
+ - `cellBlur(row, col)` - 失去焦点
1130
+ - `cellEnter(row, col)` - 回车事件(input)
1131
+ - `cellClick(row, col)` - 点击事件(button/link)
1132
+
1133
+ ### 完整事件列表
1134
+
1135
+ ```typescript
1136
+ interface SmartTableEmits {
1137
+ (e: 'cellChange', row: any, col: any): void
1138
+ (e: 'cellBlur', row: any, col: any): void
1139
+ (e: 'cellEnter', row: any, col: any): void
1140
+ (e: 'cellClick', row: any, col: any): void
1141
+ (e: 'selectionChange', selection: any[]): void
1142
+ (e: 'sortChange', sort: any): void
1143
+ // ... Element Plus Table 事件透传
1144
+ }
1145
+ ```
1146
+
1147
+ ---
1148
+
1149
+ ## 6. 按需引入
1150
+
1151
+ ### 只引入需要的部分
1152
+
1153
+ ```typescript
1154
+ // 只引入类型
1155
+ import type { ColumnConfig, ButtonConfig } from 'vue3-smart-table'
1156
+
1157
+ // 只引入渲染器工具
1158
+ import {
1159
+ getRendererManager,
1160
+ createFunctionalRenderer,
1161
+ wrapSFCComponent
1162
+ } from 'vue3-smart-table'
1163
+
1164
+ // 只引入类型工具
1165
+ import { defineColumn } from 'vue3-smart-table'
1166
+ ```
1167
+
1168
+ ### Tree-shaking 支持
1169
+
1170
+ 库已优化为支持 Tree-shaking,只会打包你实际使用的代码:
1171
+
1172
+ ```typescript
1173
+ // ✅ 只会打包 SmartTable 组件
1174
+ import { SmartTable } from 'vue3-smart-table'
1175
+
1176
+ // ✅ 只会打包渲染器管理器
1177
+ import { getRendererManager, createFunctionalRenderer } from 'vue3-smart-table'
1178
+ ```
1179
+
1180
+ ---
1181
+
1182
+ ## 7. 高级用法
1183
+
1184
+ ### 自定义渲染器(3种方式)
1185
+
1186
+ #### 方式一:函数式渲染器
1187
+
1188
+ ```typescript
1189
+ import { createFunctionalRenderer } from 'vue3-smart-table'
1190
+ import { h } from 'vue'
1191
+
1192
+ const statusRenderer = createFunctionalRenderer((props) => {
1193
+ const val = props.row[props.col.key]
1194
+ const color = val === 1 ? 'green' : 'red'
1195
+ return h('span', { style: { color } }, val === 1 ? '启用' : '禁用')
1196
+ })
1197
+
1198
+ getRendererManager().register('status', statusRenderer)
1199
+ ```
1200
+
1201
+ #### 方式二:SFC 组件
1202
+
1203
+ ```vue
1204
+ <!-- StatusRenderer.vue -->
1205
+ <template>
1206
+ <el-tag :type="statusType">{{ statusText }}</el-tag>
1207
+ </template>
1208
+
1209
+ <script setup lang="ts">
1210
+ import { computed } from 'vue'
1211
+
1212
+ const props = defineProps<{
1213
+ row: any
1214
+ col: any
1215
+ }>()
1216
+
1217
+ const statusType = computed(() =>
1218
+ props.row[props.col.key] === 1 ? 'success' : 'danger'
1219
+ )
1220
+
1221
+ const statusText = computed(() =>
1222
+ props.row[props.col.key] === 1 ? '启用' : '禁用'
1223
+ )
1224
+ </script>
1225
+ ```
1226
+
1227
+ ```typescript
1228
+ import { wrapSFCComponent } from 'vue3-smart-table'
1229
+ import StatusRenderer from './StatusRenderer.vue'
1230
+
1231
+ getRendererManager().register('status', wrapSFCComponent(StatusRenderer))
1232
+ ```
1233
+
1234
+ #### 方式三:全局配置
1235
+
1236
+ ```typescript
1237
+ import { setSmartTableConfig } from 'vue3-smart-table'
1238
+ import StatusRenderer from './StatusRenderer.vue'
1239
+
1240
+ setSmartTableConfig({
1241
+ renderers: {
1242
+ 'status': StatusRenderer
1243
+ }
1244
+ })
1245
+ ```
1246
+
1247
+ ### 类型安全的列配置
1248
+
1249
+ ```typescript
1250
+ import { defineColumn } from 'vue3-smart-table'
1251
+
1252
+ interface User {
1253
+ id: number
1254
+ name: string
1255
+ email: string
1256
+ }
1257
+
1258
+ const columns = [
1259
+ defineColumn<User>('id', { label: 'ID' }),
1260
+ defineColumn<User>('name', { label: '姓名' }),
1261
+ defineColumn<User>('email', {
1262
+ label: '邮箱',
1263
+ render: 'copy'
1264
+ })
1265
+ ]
1266
+ ```
1267
+
1268
+ ### 操作列权限控制
1269
+
1270
+ ```typescript
1271
+ const columns = [
1272
+ {
1273
+ type: 'operation',
1274
+ key: 'operation',
1275
+ label: '操作',
1276
+ buttons: [
1277
+ {
1278
+ label: '编辑',
1279
+ type: 'primary',
1280
+ permission: 'user:edit', // 需要权限
1281
+ action: (row) => handleEdit(row)
1282
+ },
1283
+ {
1284
+ label: '删除',
1285
+ type: 'danger',
1286
+ permission: ['user:delete', 'admin'], // 多个权限之一
1287
+ action: (row) => handleDelete(row),
1288
+ visible: (row) => row.status === 1 // 行级可见性
1289
+ }
1290
+ ]
1291
+ }
1292
+ ]
1293
+
1294
+ // 传入用户权限
1295
+ const permissions = ['user:edit', 'user:view']
1296
+ ```
1297
+
1298
+ ---
1299
+
1300
+ ## 8. 完整示例
310
1301
 
311
1302
  ```vue
312
1303
  <!-- 全局注册 -->
@@ -327,15 +1318,24 @@ import { SmartTable } from 'vue3-smart-table'
327
1318
  v-model:columns="columns"
328
1319
  :border="true"
329
1320
  :loading="loading"
330
- :pageKey="route.name"
331
1321
  :rowKey="'appId'"
332
1322
  :data="tabList"
333
- :userId="userInfo?.userId"
334
1323
  :permissions="userStore.permissions"
1324
+ :cacheKey="`table_columns_${userInfo?.userId}_APPFeedback`"
335
1325
  @cellChange="onCellChange"
336
1326
  @cellBlur="onCellBlur"
337
1327
  @cellEnter="onCellEnter"
338
1328
  @cellClick="onCellClick" >
1329
+ <!-- 自定义复杂列 -->
1330
+ <template #attachments="{ row }">
1331
+ <div v-for="(item, index) in row.attachments" :key="index">
1332
+ <el-image v-if="item.fileType === 1" :src="item.thumbnailUrl" :preview-src-list="row.imgPaths"/>
1333
+ <el-button v-if="item.fileType === 0" type="text" @click="download(item.fileUrl)">下载日志</el-button>
1334
+ <div v-if="item.fileType === 2" @click="handleVideo(item.fileUrl)">
1335
+ <img :src="item.thumbnailUrl" alt="video"/>
1336
+ </div>
1337
+ </div>
1338
+ </template>
339
1339
  </SmartTable>
340
1340
  ```
341
1341
  ## 完整示例代码
@@ -349,12 +1349,11 @@ import { SmartTable } from 'vue3-smart-table'
349
1349
  class-name="table-flex"
350
1350
  :border="true"
351
1351
  :loading="loading"
352
- :pageKey="'route.name'"
353
1352
  :rowKey="'id'"
354
1353
  :data="tableData"
355
1354
  v-model:columns="columns"
356
- :userId="'userId'"
357
1355
  :permissions="permissions"
1356
+ :cacheKey="`table_columns_${userInfo?.userId}_APPFeedback`"
358
1357
  @cell-blur="onCellBlur"
359
1358
  @cell-enter="onCellEnter"
360
1359
  @cell-change="onCellChange"
@@ -500,6 +1499,18 @@ import { SmartTable } from 'vue3-smart-table'
500
1499
  columnProps: { minWidth: 100, sortable: true, align: 'left'},
501
1500
  formatter: (val: string) => `${val}-123`,
502
1501
  },
1502
+ {
1503
+ key: "regionCode",
1504
+ label: "自定义复杂列",
1505
+ visible: true,
1506
+ columnProps: { minWidth: 100, align: 'right'},
1507
+ },
1508
+ {
1509
+ key: "handling.feedbackId",
1510
+ label: "key.key取值",
1511
+ visible: true,
1512
+ columnProps: { minWidth: 100, align: 'right'},
1513
+ },
503
1514
  ])
504
1515
 
505
1516
  const tableData = reactive([
@@ -512,6 +1523,35 @@ import { SmartTable } from 'vue3-smart-table'
512
1523
  'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png',
513
1524
  'https://iconfont.alicdn.com/p/illus_3d/file/UMAqlm6KX5gw/8e357f00-9a4e-44c4-b0c5-bbed255cff24.png',
514
1525
  ],
1526
+ attachments: [
1527
+ {
1528
+ "id": 1337611,
1529
+ "feedbackId": 1334127,
1530
+ "fileType": 1,
1531
+ "fileUrl": "http://xxxxxxxxxxxxxxxx/attachment/cn.com.blackview.dashcam/2025/12/17/193000-1334127-1.jpg",
1532
+ "fileSize": 298696,
1533
+ "thumbnailUrl": "http://xxxxxxxxxxxxxxxxxx/attachment/cn.com.blackview.dashcam/2025/12/17/193000-1334127-1-thumbnail.jpg"
1534
+ },
1535
+ {
1536
+ "id": 1337612,
1537
+ "feedbackId": 1334127,
1538
+ "fileType": 0,
1539
+ "fileUrl": "http://xxxxxxxxxxxxxxxxx/attachment/cn.com.blackview.dashcam/2025/12/17/193000-1334127-2.txt",
1540
+ "fileSize": 1619,
1541
+ "thumbnailUrl": null
1542
+ }
1543
+ ],
1544
+ handling: {
1545
+ "id": 1334076,
1546
+ "feedbackId": 1334160,
1547
+ "problemCategory": null,
1548
+ "handlePerson": null,
1549
+ "handleTime": "2025-12-19 09:51:05",
1550
+ "handleRemark": null,
1551
+ "handleStatus": 1,
1552
+ "callbackStatus": 1,
1553
+ "solveStatus": 1
1554
+ }
515
1555
  },
516
1556
  ])
517
1557