jianghu-ui 1.0.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/README.md +376 -0
- package/dist/jianghu-ui.css +2318 -0
- package/dist/jianghu-ui.js +2 -0
- package/dist/jianghu-ui.js.LICENSE.txt +1 -0
- package/package.json +56 -0
- package/src/Design.stories.mdx +195 -0
- package/src/Introduction.stories.mdx +148 -0
- package/src/components/JhAddressSelect/JhAddressSelect.md +250 -0
- package/src/components/JhAddressSelect/JhAddressSelect.stories.js +282 -0
- package/src/components/JhAddressSelect/JhAddressSelect.vue +261 -0
- package/src/components/JhCard/JhCard.md +246 -0
- package/src/components/JhCard/JhCard.stories.js +688 -0
- package/src/components/JhCard/JhCard.vue +604 -0
- package/src/components/JhCheckCard/JhCheckCard.md +245 -0
- package/src/components/JhCheckCard/JhCheckCard.stories.js +750 -0
- package/src/components/JhCheckCard/JhCheckCard.vue +476 -0
- package/src/components/JhConfirmDialog/JhConfirmDialog.md +70 -0
- package/src/components/JhConfirmDialog/JhConfirmDialog.stories.js +550 -0
- package/src/components/JhConfirmDialog/JhConfirmDialog.vue +181 -0
- package/src/components/JhDateRangePicker/JhDateRangePicker.md +56 -0
- package/src/components/JhDateRangePicker/JhDateRangePicker.stories.js +320 -0
- package/src/components/JhDateRangePicker/JhDateRangePicker.vue +307 -0
- package/src/components/JhDescriptions/JhDescriptions.md +724 -0
- package/src/components/JhDescriptions/JhDescriptions.stories.js +858 -0
- package/src/components/JhDescriptions/JhDescriptions.vue +933 -0
- package/src/components/JhDraggable/JhDraggable.md +66 -0
- package/src/components/JhDraggable/JhDraggable.stories.js +161 -0
- package/src/components/JhDraggable/JhDraggable.vue +254 -0
- package/src/components/JhDrawer/JhDrawer.md +68 -0
- package/src/components/JhDrawer/JhDrawer.stories.js +478 -0
- package/src/components/JhDrawer/JhDrawer.vue +281 -0
- package/src/components/JhDrawerForm/JhDrawerForm.md +69 -0
- package/src/components/JhDrawerForm/JhDrawerForm.stories.js +492 -0
- package/src/components/JhDrawerForm/JhDrawerForm.vue +297 -0
- package/src/components/JhEditableTable/JhEditableTable.md +507 -0
- package/src/components/JhEditableTable/JhEditableTable.stories.js +615 -0
- package/src/components/JhEditableTable/JhEditableTable.vue +685 -0
- package/src/components/JhFileInput/JhFileInput.md +56 -0
- package/src/components/JhFileInput/JhFileInput.stories.js +103 -0
- package/src/components/JhFileInput/JhFileInput.vue +253 -0
- package/src/components/JhForm/JhForm.md +676 -0
- package/src/components/JhForm/JhForm.stories.js +1375 -0
- package/src/components/JhForm/JhForm.vue +657 -0
- package/src/components/JhFormField/JhFormField.stories.js +217 -0
- package/src/components/JhFormField/JhFormField.vue +439 -0
- package/src/components/JhFormFields/JhFormFields.md +647 -0
- package/src/components/JhFormFields/JhFormFields.stories.js +922 -0
- package/src/components/JhFormFields/JhFormFields.vue +998 -0
- package/src/components/JhFormList/JhFormList.md +303 -0
- package/src/components/JhFormList/JhFormList.stories.js +661 -0
- package/src/components/JhFormList/JhFormList.vue +1127 -0
- package/src/components/JhJsonEditor/JhJsonEditor.md +54 -0
- package/src/components/JhJsonEditor/JhJsonEditor.stories.js +157 -0
- package/src/components/JhJsonEditor/JhJsonEditor.vue +178 -0
- package/src/components/JhLayout/JhLayout.md +580 -0
- package/src/components/JhLayout/JhLayout.stories.js +414 -0
- package/src/components/JhLayout/JhLayout.vue +387 -0
- package/src/components/JhList/JhList.md +441 -0
- package/src/components/JhList/JhList.stories.js +524 -0
- package/src/components/JhList/JhList.vue +571 -0
- package/src/components/JhMarkdownEditor/JhMarkdownEditor.md +56 -0
- package/src/components/JhMarkdownEditor/JhMarkdownEditor.stories.js +191 -0
- package/src/components/JhMarkdownEditor/JhMarkdownEditor.vue +188 -0
- package/src/components/JhMask/JhMask.md +62 -0
- package/src/components/JhMask/JhMask.stories.js +270 -0
- package/src/components/JhMask/JhMask.vue +123 -0
- package/src/components/JhMenu/JhMenu.md +85 -0
- package/src/components/JhMenu/JhMenu.stories.js +384 -0
- package/src/components/JhMenu/JhMenu.vue +545 -0
- package/src/components/JhModal/JhModal.md +68 -0
- package/src/components/JhModal/JhModal.stories.js +562 -0
- package/src/components/JhModal/JhModal.vue +235 -0
- package/src/components/JhModalForm/JhModalForm.md +69 -0
- package/src/components/JhModalForm/JhModalForm.stories.js +592 -0
- package/src/components/JhModalForm/JhModalForm.vue +298 -0
- package/src/components/JhPageContainer/JhPageContainer.md +409 -0
- package/src/components/JhPageContainer/JhPageContainer.stories.js +209 -0
- package/src/components/JhPageContainer/JhPageContainer.vue +72 -0
- package/src/components/JhQueryFilter/JhQueryFilter.md +77 -0
- package/src/components/JhQueryFilter/JhQueryFilter.stories.js +684 -0
- package/src/components/JhQueryFilter/JhQueryFilter.vue +429 -0
- package/src/components/JhScene/JhScene.md +64 -0
- package/src/components/JhScene/JhScene.stories.js +317 -0
- package/src/components/JhScene/JhScene.vue +376 -0
- package/src/components/JhStatisticCard/JhStatisticCard.md +363 -0
- package/src/components/JhStatisticCard/JhStatisticCard.stories.js +847 -0
- package/src/components/JhStatisticCard/JhStatisticCard.vue +459 -0
- package/src/components/JhStepsForm/JhStepsForm.md +666 -0
- package/src/components/JhStepsForm/JhStepsForm.stories.js +1224 -0
- package/src/components/JhStepsForm/JhStepsForm.vue +749 -0
- package/src/components/JhTable/JhTable.md +730 -0
- package/src/components/JhTable/JhTable.stories.js +1444 -0
- package/src/components/JhTable/JhTable.vue +2298 -0
- package/src/components/JhTableAttachment/JhTableAttachment.md +70 -0
- package/src/components/JhTableAttachment/JhTableAttachment.stories.js +198 -0
- package/src/components/JhTableAttachment/JhTableAttachment.vue +264 -0
- package/src/components/JhToast/JhToast.md +67 -0
- package/src/components/JhToast/JhToast.stories.js +386 -0
- package/src/components/JhToast/JhToast.vue +239 -0
- package/src/components/JhTreeSelect/JhTreeSelect.md +82 -0
- package/src/components/JhTreeSelect/JhTreeSelect.stories.js +391 -0
- package/src/components/JhTreeSelect/JhTreeSelect.vue +727 -0
- package/src/components/JhWaterMark/JhWaterMark.md +190 -0
- package/src/components/JhWaterMark/JhWaterMark.stories.js +675 -0
- package/src/components/JhWaterMark/JhWaterMark.vue +351 -0
- package/src/components/README.md +52 -0
- package/src/index.js +135 -0
- package/src/style/globalCSSJHV4.css +348 -0
- package/src/style/globalCSSVuetifyV4.css +637 -0
- package/src/style/storybook.css +4 -0
- package/src/tailwind.css +3 -0
- package/src/utils/vuetify.js +31 -0
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
# JhTable - 高级表格组件
|
|
2
|
+
|
|
3
|
+
参考 Ant Design Pro 的 ProTable 设计的增强版数据表格组件,提供丰富的企业级功能。
|
|
4
|
+
|
|
5
|
+
## ✨ 核心特性
|
|
6
|
+
|
|
7
|
+
### 1. ProTable 样式系统
|
|
8
|
+
|
|
9
|
+
#### 表格标题区
|
|
10
|
+
- **headerTitle**: 表格标题显示
|
|
11
|
+
- **tooltip**: 标题提示信息
|
|
12
|
+
- **header-title 插槽**: 自定义标题内容
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<jh-table
|
|
16
|
+
header-title="用户列表"
|
|
17
|
+
tooltip="这是用户管理列表"
|
|
18
|
+
>
|
|
19
|
+
<template v-slot:header-title>
|
|
20
|
+
<div class="custom-title">
|
|
21
|
+
<v-icon>mdi-account-group</v-icon>
|
|
22
|
+
<span>用户管理</span>
|
|
23
|
+
</div>
|
|
24
|
+
</template>
|
|
25
|
+
</jh-table>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
#### 卡片样式
|
|
29
|
+
- **cardBordered**: 显示卡片边框和阴影(默认 true)
|
|
30
|
+
- **ghost**: 幽灵模式,无边框无背景(默认 false)
|
|
31
|
+
|
|
32
|
+
```vue
|
|
33
|
+
<!-- 卡片样式 -->
|
|
34
|
+
<jh-table :card-bordered="true" />
|
|
35
|
+
|
|
36
|
+
<!-- 幽灵模式 -->
|
|
37
|
+
<jh-table :ghost="true" />
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. 批量操作提示栏
|
|
41
|
+
|
|
42
|
+
当启用行选择时,选中数据后会自动显示批量操作提示栏。
|
|
43
|
+
|
|
44
|
+
```vue
|
|
45
|
+
<jh-table
|
|
46
|
+
:show-select="true"
|
|
47
|
+
@selection-change="handleSelectionChange"
|
|
48
|
+
>
|
|
49
|
+
<!-- 自定义批量操作提示内容 -->
|
|
50
|
+
<template v-slot:alert="{ selectedRowKeys, selectedRows }">
|
|
51
|
+
<span>已选择 {{ selectedRows.length }} 项</span>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<!-- 自定义批量操作按钮 -->
|
|
55
|
+
<template v-slot:alert-actions="{ selectedRowKeys, selectedRows }">
|
|
56
|
+
<v-btn small text color="primary" @click="handleBatchExport">
|
|
57
|
+
<v-icon small left>mdi-download</v-icon>
|
|
58
|
+
导出
|
|
59
|
+
</v-btn>
|
|
60
|
+
<v-btn small text color="error" @click="handleBatchDelete">
|
|
61
|
+
<v-icon small left>mdi-delete</v-icon>
|
|
62
|
+
批量删除
|
|
63
|
+
</v-btn>
|
|
64
|
+
</template>
|
|
65
|
+
</jh-table>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. 轮询和防抖
|
|
69
|
+
|
|
70
|
+
#### 轮询刷新
|
|
71
|
+
自动定时刷新表格数据,适用于实时监控场景。
|
|
72
|
+
|
|
73
|
+
```vue
|
|
74
|
+
<jh-table
|
|
75
|
+
:request="fetchData"
|
|
76
|
+
:polling="5000"
|
|
77
|
+
/>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### 搜索防抖
|
|
81
|
+
减少搜索时的请求频率,提升性能。
|
|
82
|
+
|
|
83
|
+
```vue
|
|
84
|
+
<jh-table
|
|
85
|
+
:request="fetchData"
|
|
86
|
+
:debounce-time="500"
|
|
87
|
+
/>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 4. 增强的工具栏
|
|
91
|
+
|
|
92
|
+
#### 工具栏配置
|
|
93
|
+
```vue
|
|
94
|
+
<jh-table
|
|
95
|
+
:toolbar="{
|
|
96
|
+
search: true, // 搜索框
|
|
97
|
+
refresh: true, // 刷新按钮
|
|
98
|
+
setting: true, // 列设置
|
|
99
|
+
density: true, // 密度切换
|
|
100
|
+
fullscreen: true // 全屏
|
|
101
|
+
}"
|
|
102
|
+
/>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### 工具栏插槽
|
|
106
|
+
```vue
|
|
107
|
+
<jh-table>
|
|
108
|
+
<!-- 左侧操作按钮(在标题区显示) -->
|
|
109
|
+
<template v-slot:toolbar-actions>
|
|
110
|
+
<v-btn color="success" @click="handleCreate">
|
|
111
|
+
<v-icon left>mdi-plus</v-icon>
|
|
112
|
+
新增
|
|
113
|
+
</v-btn>
|
|
114
|
+
</template>
|
|
115
|
+
|
|
116
|
+
<!-- 右侧额外按钮 -->
|
|
117
|
+
<template v-slot:toolbar-extra>
|
|
118
|
+
<v-btn outlined>
|
|
119
|
+
<v-icon left>mdi-download</v-icon>
|
|
120
|
+
导出
|
|
121
|
+
</v-btn>
|
|
122
|
+
</template>
|
|
123
|
+
</jh-table>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 5. 表格额外内容区
|
|
127
|
+
|
|
128
|
+
在表格下方添加额外内容,如统计信息、图表等。
|
|
129
|
+
|
|
130
|
+
```vue
|
|
131
|
+
<jh-table>
|
|
132
|
+
<template v-slot:table-extra>
|
|
133
|
+
<div class="pa-4">
|
|
134
|
+
<v-row>
|
|
135
|
+
<v-col cols="3">
|
|
136
|
+
<v-card>
|
|
137
|
+
<v-card-text>
|
|
138
|
+
<div class="text-h4">1,234</div>
|
|
139
|
+
<div class="text-caption">总用户数</div>
|
|
140
|
+
</v-card-text>
|
|
141
|
+
</v-card>
|
|
142
|
+
</v-col>
|
|
143
|
+
</v-row>
|
|
144
|
+
</div>
|
|
145
|
+
</template>
|
|
146
|
+
</jh-table>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 6. 高级筛选栏
|
|
150
|
+
|
|
151
|
+
集成 JhQueryFilter 组件,提供强大的筛选功能。
|
|
152
|
+
|
|
153
|
+
```vue
|
|
154
|
+
<jh-table
|
|
155
|
+
:show-filter="true"
|
|
156
|
+
:filter-fields="[
|
|
157
|
+
{ key: 'username', label: '用户名', type: 'text' },
|
|
158
|
+
{ key: 'status', label: '状态', type: 'select', options: [...] },
|
|
159
|
+
{ key: 'dateRange', label: '日期', type: 'daterange' }
|
|
160
|
+
]"
|
|
161
|
+
:filter-collapsible="true"
|
|
162
|
+
:filter-default-collapsed="true"
|
|
163
|
+
@filter-search="handleFilterSearch"
|
|
164
|
+
@filter-reset="handleFilterReset"
|
|
165
|
+
/>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 7. 列增强功能
|
|
169
|
+
|
|
170
|
+
#### copyable - 可复制
|
|
171
|
+
```javascript
|
|
172
|
+
{
|
|
173
|
+
text: '邮箱',
|
|
174
|
+
value: 'email',
|
|
175
|
+
copyable: true // 显示复制按钮
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
#### ellipsis - 省略号
|
|
180
|
+
```javascript
|
|
181
|
+
{
|
|
182
|
+
text: '描述',
|
|
183
|
+
value: 'description',
|
|
184
|
+
ellipsis: true // 超长文本省略,hover 显示完整内容
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### 8. 操作列配置化
|
|
189
|
+
|
|
190
|
+
```vue
|
|
191
|
+
<jh-table
|
|
192
|
+
:action-column="{
|
|
193
|
+
title: '操作',
|
|
194
|
+
width: 180,
|
|
195
|
+
fixed: 'right',
|
|
196
|
+
buttons: [
|
|
197
|
+
{
|
|
198
|
+
text: '编辑',
|
|
199
|
+
type: 'link', // link / icon / button
|
|
200
|
+
icon: 'mdi-pencil',
|
|
201
|
+
color: 'primary',
|
|
202
|
+
tooltip: '编辑记录',
|
|
203
|
+
onClick: (row) => { console.log('编辑', row) },
|
|
204
|
+
visible: (row) => row.status !== '禁用',
|
|
205
|
+
confirm: '确认编辑?'
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
text: '删除',
|
|
209
|
+
type: 'link',
|
|
210
|
+
icon: 'mdi-delete',
|
|
211
|
+
color: 'error',
|
|
212
|
+
onClick: (row) => { console.log('删除', row) },
|
|
213
|
+
confirm: '确认删除?'
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
}"
|
|
217
|
+
/>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 9. 服务端分页
|
|
221
|
+
|
|
222
|
+
```vue
|
|
223
|
+
<jh-table
|
|
224
|
+
:request="fetchData"
|
|
225
|
+
:pagination="{
|
|
226
|
+
current: 1,
|
|
227
|
+
pageSize: 20,
|
|
228
|
+
pageSizeOptions: [10, 20, 50, 100]
|
|
229
|
+
}"
|
|
230
|
+
/>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
async fetchData(params) {
|
|
235
|
+
// params: { page, pageSize, search, sorter, filters }
|
|
236
|
+
const response = await fetch('/api/users', {
|
|
237
|
+
method: 'POST',
|
|
238
|
+
body: JSON.stringify(params),
|
|
239
|
+
});
|
|
240
|
+
return {
|
|
241
|
+
data: response.list,
|
|
242
|
+
total: response.total,
|
|
243
|
+
success: true,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### 10. 行选择
|
|
249
|
+
|
|
250
|
+
```vue
|
|
251
|
+
<jh-table
|
|
252
|
+
:show-select="true"
|
|
253
|
+
:single-select="false"
|
|
254
|
+
@selection-change="handleSelectionChange"
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
```javascript
|
|
259
|
+
handleSelectionChange({ selectedRowKeys, selectedRows }) {
|
|
260
|
+
console.log('选中的 keys:', selectedRowKeys);
|
|
261
|
+
console.log('选中的行:', selectedRows);
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 11. 密度切换
|
|
266
|
+
|
|
267
|
+
三种密度自动适配:
|
|
268
|
+
- **default**: 48px 行高
|
|
269
|
+
- **medium**: 40px 行高
|
|
270
|
+
- **compact**: 32px 行高
|
|
271
|
+
|
|
272
|
+
```vue
|
|
273
|
+
<jh-table size="medium" />
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 12. 列 Schema 渲染(ProTable 对齐)
|
|
277
|
+
|
|
278
|
+
- 列可声明 `valueType`、`valueEnum`、`valueEnumStatusMap`、`valueFormatter`、`valueProps`,JhTable 会按类型自动格式化并保持 Tooltip / 复制 / hover 等体验。
|
|
279
|
+
- 典型类型:`status`、`money`、`percent`、`progress`、`digit`、`date`/`dateTime`/`dateRange`、`avatar`、`json`、`code`、`index` 等。
|
|
280
|
+
|
|
281
|
+
| 字段 | 说明 |
|
|
282
|
+
| ---- | ---- |
|
|
283
|
+
| `valueType` | 控制默认渲染器,例如 `status` 显示 chip、`progress` 显示进度条 |
|
|
284
|
+
| `valueEnum` | 枚举映射 `{ value: { text, status, color, icon } }` |
|
|
285
|
+
| `valueEnumStatusMap` | 按状态调整颜色/样式,覆盖内置的 success/warning/error/processing/default |
|
|
286
|
+
| `valueFormatter(value, row, column)` | 最终展示前的格式化函数(返回值将直接显示) |
|
|
287
|
+
| `valueProps` | 透传给默认渲染器的配置(进度条高度、金额精度、头像尺寸等) |
|
|
288
|
+
|
|
289
|
+
```vue
|
|
290
|
+
<jh-table
|
|
291
|
+
:headers="[
|
|
292
|
+
{
|
|
293
|
+
text: '状态',
|
|
294
|
+
value: 'status',
|
|
295
|
+
valueType: 'status',
|
|
296
|
+
valueEnumStatusMap: { warning: { color: 'orange darken-2' } },
|
|
297
|
+
valueEnum: {
|
|
298
|
+
pending: { text: '待审核', status: 'warning', icon: 'mdi-clock' },
|
|
299
|
+
online: { text: '可用', status: 'success' },
|
|
300
|
+
offline: { text: '禁用', status: 'error' },
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
text: '账单金额',
|
|
305
|
+
value: 'amount',
|
|
306
|
+
valueType: 'money',
|
|
307
|
+
valueFormatter: (value) => `${(value / 10000).toFixed(2)} 万`,
|
|
308
|
+
valueProps: { currencySymbol: '¥', precision: 2 },
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
text: '完成进度',
|
|
312
|
+
value: 'progress',
|
|
313
|
+
valueType: 'progress',
|
|
314
|
+
valueProps: { color: 'success', height: 8, showValue: true },
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
text: '任务 JSON',
|
|
318
|
+
value: 'payload',
|
|
319
|
+
valueType: 'json',
|
|
320
|
+
ellipsis: true,
|
|
321
|
+
},
|
|
322
|
+
]"
|
|
323
|
+
:items="taskList"
|
|
324
|
+
/>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 13. 列驱动筛选(search schema → JhQueryFilter)
|
|
328
|
+
|
|
329
|
+
- `show-filter` + `auto-filter-from-headers(默认 true)` 开启后,只有在 `headers` 中显式声明了 `search`(`true` 或配置对象)的列才会自动生成 JhQueryFilter 字段,默认不会把所有列都展示出来。
|
|
330
|
+
- `search: true` 代表采用默认的文本输入筛选;设置为对象时可进一步控制输入类型、占位、初始值等;`search: false` 仍可用于兼容旧配置的“强制关闭”场景。
|
|
331
|
+
- `search` 支持对象写法:`{ valueType, formItemProps, transform, initialValue, key, placeholder }`,可直接控制控件类型、初始值和后端映射。
|
|
332
|
+
- `transform(value)` 用于把表单值拆分成后端期望的结构,例如日期区间拆成 `startDate/endDate`;也可通过 `valueEnumKey` 让 select 选项使用枚举中的其他字段。
|
|
333
|
+
- 手动传入 `filter-fields` 且 key 重复时,组件会优先使用手动配置,保证可完全自定义。
|
|
334
|
+
|
|
335
|
+
```vue
|
|
336
|
+
const headers = [
|
|
337
|
+
{
|
|
338
|
+
text: '状态',
|
|
339
|
+
value: 'status',
|
|
340
|
+
valueType: 'status',
|
|
341
|
+
valueEnum: {
|
|
342
|
+
pending: { text: '待审核', status: 'warning', value: 'PENDING' },
|
|
343
|
+
approved: { text: '已通过', status: 'success', value: 'APPROVED' },
|
|
344
|
+
},
|
|
345
|
+
search: {
|
|
346
|
+
valueType: 'select',
|
|
347
|
+
valueEnumKey: 'value',
|
|
348
|
+
initialValue: 'PENDING',
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
text: '创建时间',
|
|
353
|
+
value: 'createdAt',
|
|
354
|
+
valueType: 'dateTime',
|
|
355
|
+
search: {
|
|
356
|
+
valueType: 'dateRange',
|
|
357
|
+
initialValue: ['2024-01-01', '2024-01-31'],
|
|
358
|
+
transform: (value) => ({
|
|
359
|
+
startDate: value?.[0],
|
|
360
|
+
endDate: value?.[1],
|
|
361
|
+
}),
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
];
|
|
365
|
+
|
|
366
|
+
<jh-table
|
|
367
|
+
:headers="headers"
|
|
368
|
+
:request="fetchData"
|
|
369
|
+
show-filter
|
|
370
|
+
@filter-search="filters => console.log(filters)"
|
|
371
|
+
/>;
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
如需关闭自动注入,可设置 `:auto-filter-from-headers="false"`,或直接移除列的 `search` 配置(保留 `search: false` 写法也兼容)。
|
|
375
|
+
|
|
376
|
+
## 📋 完整 Props
|
|
377
|
+
|
|
378
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
379
|
+
|------|------|------|--------|
|
|
380
|
+
| headers | 表格表头配置 | Array | [] |
|
|
381
|
+
| items | 表格数据(客户端分页) | Array | [] |
|
|
382
|
+
| request | 数据请求函数(服务端分页) | Function | null |
|
|
383
|
+
| headerTitle | 表格标题 | String | '' |
|
|
384
|
+
| tooltip | 标题提示信息 | String | '' |
|
|
385
|
+
| cardBordered | 是否显示卡片边框 | Boolean | true |
|
|
386
|
+
| ghost | 幽灵模式(无边框无背景) | Boolean | false |
|
|
387
|
+
| toolbar | 工具栏配置 | Object/Boolean | {...} |
|
|
388
|
+
| showFilter | 是否显示筛选栏 | Boolean | false |
|
|
389
|
+
| filterFields | 筛选字段配置 | Array | [] |
|
|
390
|
+
| filterInitialValues | 筛选初始值 | Object | {} |
|
|
391
|
+
| autoFilterFromHeaders | 是否根据列 schema 自动注入筛选字段 | Boolean | true |
|
|
392
|
+
| filterCollapsible | 筛选栏是否可折叠 | Boolean | true |
|
|
393
|
+
| filterDefaultCollapsed | 筛选栏默认是否折叠 | Boolean | true |
|
|
394
|
+
| actionColumn | 操作列配置 | Object/Boolean | null |
|
|
395
|
+
| pagination | 分页配置 | Object/Boolean | {...} |
|
|
396
|
+
| showSelect | 是否显示选择框 | Boolean | false |
|
|
397
|
+
| singleSelect | 是否单选 | Boolean | false |
|
|
398
|
+
| polling | 轮询间隔(毫秒),0 表示不轮询 | Number | 0 |
|
|
399
|
+
| debounceTime | 搜索防抖时间(毫秒) | Number | 300 |
|
|
400
|
+
| loading | 加载状态 | Boolean | false |
|
|
401
|
+
| size | 表格密度 | String | 'default' |
|
|
402
|
+
| rowKey | 行数据的 Key | String | 'id' |
|
|
403
|
+
|
|
404
|
+
## 🎯 插槽
|
|
405
|
+
|
|
406
|
+
| 插槽名 | 说明 | 参数 |
|
|
407
|
+
|--------|------|------|
|
|
408
|
+
| header-title | 自定义标题内容 | - |
|
|
409
|
+
| toolbar-actions | 工具栏左侧操作按钮 | - |
|
|
410
|
+
| toolbar-extra | 工具栏右侧额外内容 | - |
|
|
411
|
+
| alert | 自定义批量操作提示内容 | { selectedRowKeys, selectedRows } |
|
|
412
|
+
| alert-actions | 批量操作按钮区 | { selectedRowKeys, selectedRows } |
|
|
413
|
+
| table-extra | 表格额外内容区 | - |
|
|
414
|
+
| item.{column} | 自定义列内容 | { item, value, index } |
|
|
415
|
+
| header.{column} | 自定义表头 | { header } |
|
|
416
|
+
|
|
417
|
+
## 🔧 方法
|
|
418
|
+
|
|
419
|
+
| 方法名 | 说明 | 参数 |
|
|
420
|
+
|--------|------|------|
|
|
421
|
+
| reload() | 重新加载数据(服务端分页) | - |
|
|
422
|
+
| reset() | 重置到第一页 | - |
|
|
423
|
+
| clearSelection() | 清空选择 | - |
|
|
424
|
+
| getSelectedRows() | 获取选中的行 | - |
|
|
425
|
+
|
|
426
|
+
## 📡 事件
|
|
427
|
+
|
|
428
|
+
| 事件名 | 说明 | 回调参数 |
|
|
429
|
+
|--------|------|----------|
|
|
430
|
+
| create-click | 点击新增按钮 | - |
|
|
431
|
+
| update-click | 点击详情按钮 | (item) |
|
|
432
|
+
| delete-click | 点击删除按钮 | (item) |
|
|
433
|
+
| row-click | 点击行 | (item, event) |
|
|
434
|
+
| selection-change | 选择改变 | { selectedRowKeys, selectedRows } |
|
|
435
|
+
| refresh | 点击刷新按钮 | - |
|
|
436
|
+
| copy-success | 复制成功 | (text) |
|
|
437
|
+
| request-error | 请求失败 | (error) |
|
|
438
|
+
| filter-search | 筛选查询 | (queryData) |
|
|
439
|
+
| filter-reset | 筛选重置 | - |
|
|
440
|
+
|
|
441
|
+
## 🎨 完整示例
|
|
442
|
+
|
|
443
|
+
```vue
|
|
444
|
+
<template>
|
|
445
|
+
<jh-table
|
|
446
|
+
ref="tableRef"
|
|
447
|
+
header-title="用户管理"
|
|
448
|
+
tooltip="管理系统用户信息"
|
|
449
|
+
:card-bordered="true"
|
|
450
|
+
:headers="headers"
|
|
451
|
+
:request="fetchData"
|
|
452
|
+
:show-select="true"
|
|
453
|
+
:show-filter="true"
|
|
454
|
+
:filter-fields="filterFields"
|
|
455
|
+
:action-column="actionColumn"
|
|
456
|
+
:polling="10000"
|
|
457
|
+
:debounce-time="500"
|
|
458
|
+
@selection-change="handleSelectionChange"
|
|
459
|
+
@filter-search="handleFilterSearch"
|
|
460
|
+
>
|
|
461
|
+
<!-- 工具栏按钮 -->
|
|
462
|
+
<template v-slot:toolbar-actions>
|
|
463
|
+
<v-btn color="success" @click="handleCreate">
|
|
464
|
+
<v-icon left>mdi-plus</v-icon>
|
|
465
|
+
新增用户
|
|
466
|
+
</v-btn>
|
|
467
|
+
</template>
|
|
468
|
+
|
|
469
|
+
<!-- 额外工具 -->
|
|
470
|
+
<template v-slot:toolbar-extra>
|
|
471
|
+
<v-btn outlined @click="handleExport">
|
|
472
|
+
<v-icon left>mdi-download</v-icon>
|
|
473
|
+
导出
|
|
474
|
+
</v-btn>
|
|
475
|
+
</template>
|
|
476
|
+
|
|
477
|
+
<!-- 批量操作 -->
|
|
478
|
+
<template v-slot:alert-actions="{ selectedRows }">
|
|
479
|
+
<v-btn small text color="error" @click="handleBatchDelete">
|
|
480
|
+
批量删除
|
|
481
|
+
</v-btn>
|
|
482
|
+
</template>
|
|
483
|
+
|
|
484
|
+
<!-- 自定义状态列 -->
|
|
485
|
+
<template v-slot:item.status="{ item }">
|
|
486
|
+
<v-chip
|
|
487
|
+
:color="item.status === '启用' ? 'success' : 'error'"
|
|
488
|
+
small
|
|
489
|
+
>
|
|
490
|
+
{{ item.status }}
|
|
491
|
+
</v-chip>
|
|
492
|
+
</template>
|
|
493
|
+
</jh-table>
|
|
494
|
+
</template>
|
|
495
|
+
|
|
496
|
+
<script>
|
|
497
|
+
export default {
|
|
498
|
+
data() {
|
|
499
|
+
return {
|
|
500
|
+
headers: [
|
|
501
|
+
{ text: 'ID', value: 'id', width: 80 },
|
|
502
|
+
{ text: '用户名', value: 'username', copyable: true },
|
|
503
|
+
{ text: '邮箱', value: 'email', ellipsis: true, copyable: true },
|
|
504
|
+
{ text: '状态', value: 'status' },
|
|
505
|
+
{ text: '创建时间', value: 'createdAt' },
|
|
506
|
+
{ text: '操作', value: 'action', width: 180 },
|
|
507
|
+
],
|
|
508
|
+
filterFields: [
|
|
509
|
+
{ key: 'username', label: '用户名', type: 'text' },
|
|
510
|
+
{ key: 'status', label: '状态', type: 'select', options: [...] },
|
|
511
|
+
],
|
|
512
|
+
actionColumn: {
|
|
513
|
+
title: '操作',
|
|
514
|
+
width: 180,
|
|
515
|
+
buttons: [
|
|
516
|
+
{
|
|
517
|
+
text: '编辑',
|
|
518
|
+
type: 'link',
|
|
519
|
+
icon: 'mdi-pencil',
|
|
520
|
+
color: 'primary',
|
|
521
|
+
onClick: this.handleEdit,
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
text: '删除',
|
|
525
|
+
type: 'link',
|
|
526
|
+
icon: 'mdi-delete',
|
|
527
|
+
color: 'error',
|
|
528
|
+
confirm: '确认删除?',
|
|
529
|
+
onClick: this.handleDelete,
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
},
|
|
533
|
+
};
|
|
534
|
+
},
|
|
535
|
+
methods: {
|
|
536
|
+
async fetchData(params) {
|
|
537
|
+
const response = await this.$api.getUsers(params);
|
|
538
|
+
return {
|
|
539
|
+
data: response.list,
|
|
540
|
+
total: response.total,
|
|
541
|
+
success: true,
|
|
542
|
+
};
|
|
543
|
+
},
|
|
544
|
+
handleCreate() {
|
|
545
|
+
// 新增逻辑
|
|
546
|
+
},
|
|
547
|
+
handleEdit(row) {
|
|
548
|
+
// 编辑逻辑
|
|
549
|
+
},
|
|
550
|
+
handleDelete(row) {
|
|
551
|
+
// 删除逻辑
|
|
552
|
+
},
|
|
553
|
+
handleBatchDelete() {
|
|
554
|
+
const rows = this.$refs.tableRef.getSelectedRows();
|
|
555
|
+
// 批量删除逻辑
|
|
556
|
+
},
|
|
557
|
+
handleSelectionChange({ selectedRows }) {
|
|
558
|
+
console.log('选中:', selectedRows);
|
|
559
|
+
},
|
|
560
|
+
handleFilterSearch(queryData) {
|
|
561
|
+
console.log('筛选:', queryData);
|
|
562
|
+
},
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
</script>
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
## 🆚 对比 Ant Design ProTable
|
|
569
|
+
|
|
570
|
+
### ✅ 已实现的 ProTable 功能
|
|
571
|
+
|
|
572
|
+
- ✅ headerTitle - 表格标题
|
|
573
|
+
- ✅ tooltip - 标题提示
|
|
574
|
+
- ✅ cardBordered - 卡片边框
|
|
575
|
+
- ✅ ghost - 幽灵模式
|
|
576
|
+
- ✅ toolbar - 工具栏配置
|
|
577
|
+
- ✅ search - 搜索功能
|
|
578
|
+
- ✅ options - 列设置、密度、刷新、全屏
|
|
579
|
+
- ✅ request - 服务端分页
|
|
580
|
+
- ✅ polling - 轮询刷新
|
|
581
|
+
- ✅ debounceTime - 搜索防抖
|
|
582
|
+
- ✅ rowSelection - 行选择
|
|
583
|
+
- ✅ tableAlertRender - 批量操作提示栏
|
|
584
|
+
- ✅ tableAlertOptionRender - 批量操作按钮
|
|
585
|
+
- ✅ columns.copyable - 可复制列
|
|
586
|
+
- ✅ columns.ellipsis - 省略号
|
|
587
|
+
- ✅ actionColumn - 操作列配置
|
|
588
|
+
|
|
589
|
+
### 🎯 Jianghu UI 特色功能
|
|
590
|
+
|
|
591
|
+
- ✅ JhQueryFilter 集成 - 强大的高级筛选
|
|
592
|
+
- ✅ Vuetify 深度集成 - 完美的 Material Design
|
|
593
|
+
- ✅ 移动端优化 - 响应式设计
|
|
594
|
+
- ✅ 丰富的插槽系统 - 高度可定制
|
|
595
|
+
|
|
596
|
+
## 🚀 最新增强能力(v2.1)
|
|
597
|
+
|
|
598
|
+
### 1. 原生 v-data-table 属性透传
|
|
599
|
+
通过 `dataTableProps` 或直接在 `<jh-table>` 上声明属性,即可传递 Vuetify `v-data-table` 的原生能力(如 `hide-default-footer`、`show-expand`、`item-class` 等),迁移老项目时几乎零成本。
|
|
600
|
+
|
|
601
|
+
```vue
|
|
602
|
+
<jh-table
|
|
603
|
+
:headers="headers"
|
|
604
|
+
:items="items"
|
|
605
|
+
hide-default-footer
|
|
606
|
+
:data-table-props="{ showExpand: true, disablePagination: true }"
|
|
607
|
+
/>
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### 2. 多列排序 & 受控排序
|
|
611
|
+
- 新增 `sortBy`、`sortDesc`、`multiSort`、`mustSort` 属性
|
|
612
|
+
- 新增 `sort-change`、`update:sortBy`、`update:sortDesc` 事件
|
|
613
|
+
- 服务端模式自动携带 `sorter` 信息,便于后端直接解析
|
|
614
|
+
|
|
615
|
+
```vue
|
|
616
|
+
<jh-table
|
|
617
|
+
:headers="headers"
|
|
618
|
+
:request="fetchData"
|
|
619
|
+
multi-sort
|
|
620
|
+
:sort-by="['createdAt']"
|
|
621
|
+
:sort-desc="[true]"
|
|
622
|
+
@sort-change="({ sorter }) => console.log(sorter)"
|
|
623
|
+
/>
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
### 3. 列状态持久化(columnsState)
|
|
627
|
+
|
|
628
|
+
```vue
|
|
629
|
+
<jh-table
|
|
630
|
+
:headers="headers"
|
|
631
|
+
:columns-state="{
|
|
632
|
+
persistenceKey: 'user-table-columns',
|
|
633
|
+
defaultVisible: { email: false },
|
|
634
|
+
value: customState
|
|
635
|
+
}"
|
|
636
|
+
@columns-state-change="val => customState = val"
|
|
637
|
+
/>
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
> 会自动使用 `localStorage` 缓存列显示状态,刷新或重新登录依旧生效。
|
|
641
|
+
|
|
642
|
+
### 4. 对齐 ProTable 的 rowSelection API
|
|
643
|
+
- `rowSelection.type = 'radio' | 'checkbox'`
|
|
644
|
+
- `rowSelection.defaultSelectedRowKeys`
|
|
645
|
+
- `rowSelection.selectedRowKeys`(受控模式)
|
|
646
|
+
- `rowSelection.onChange(selectedKeys, selectedRows)`
|
|
647
|
+
|
|
648
|
+
```vue
|
|
649
|
+
<jh-table
|
|
650
|
+
:headers="headers"
|
|
651
|
+
:items="items"
|
|
652
|
+
:row-selection="{
|
|
653
|
+
type: 'radio',
|
|
654
|
+
defaultSelectedRowKeys: [1],
|
|
655
|
+
onChange: (keys, rows) => console.log(keys, rows)
|
|
656
|
+
}"
|
|
657
|
+
/>
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
### 5. 自定义批量操作提示(tableAlertRender)
|
|
661
|
+
|
|
662
|
+
- `tableAlertRender`:函数或 `false`。函数签名为 `(h, { selectedRows, selectedRowKeys, onCleanSelected }) => VNode`,返回的内容会替换默认 “已选择 X 项” 提示;配置为 `false` 时隐藏默认提示。
|
|
663
|
+
- `tableAlertOptionRender`:函数或 `false`。同样接受 `{ selectedRows, selectedRowKeys, onCleanSelected }`,可输出批量操作按钮;也可以直接使用 `#alert-actions` slot。
|
|
664
|
+
- 插槽优先级高于 props,方便在单文件组件内直接书写模板;若同时设置 `tableAlertRender === false` 且无插槽,则整块提示区域不会出现。
|
|
665
|
+
|
|
666
|
+
```vue
|
|
667
|
+
<jh-table
|
|
668
|
+
:headers="headers"
|
|
669
|
+
:items="apps"
|
|
670
|
+
show-select
|
|
671
|
+
:table-alert-render="(h, { selectedRows, onCleanSelected }) => {
|
|
672
|
+
const totalPods = selectedRows.reduce((sum, row) => sum + row.podCount, 0);
|
|
673
|
+
const totalCalls = selectedRows.reduce((sum, row) => sum + row.callCount, 0);
|
|
674
|
+
return h('div', { class: 'd-flex align-center flex-wrap gap-4' }, [
|
|
675
|
+
h('span', { class: 'font-weight-medium' }, `已选 ${selectedRows.length} 项`),
|
|
676
|
+
h('v-btn', {
|
|
677
|
+
props: { text: true, xSmall: true, color: 'primary' },
|
|
678
|
+
on: { click: onCleanSelected }
|
|
679
|
+
}, '取消选择'),
|
|
680
|
+
h('span', `容器数量:${totalPods} 个`),
|
|
681
|
+
h('span', `调用量:${totalCalls} 次`)
|
|
682
|
+
]);
|
|
683
|
+
}"
|
|
684
|
+
:table-alert-option-render="(h, { selectedRows }) => h('div', [
|
|
685
|
+
h('v-btn', { props: { small: true, color: 'error' } }, '批量删除'),
|
|
686
|
+
h('v-btn', { props: { small: true, outlined: true, color: 'primary' } }, '导出数据')
|
|
687
|
+
])"
|
|
688
|
+
/>
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
## 📱 响应式设计
|
|
692
|
+
|
|
693
|
+
组件针对移动端进行了全面优化:
|
|
694
|
+
- 自动调整工具栏布局
|
|
695
|
+
- 操作列在移动端显示为下拉菜单
|
|
696
|
+
- 批量操作栏自适应布局
|
|
697
|
+
- 表格密度自动调整
|
|
698
|
+
|
|
699
|
+
## 🎨 主题定制
|
|
700
|
+
|
|
701
|
+
组件完全遵循 Vuetify 主题系统,支持:
|
|
702
|
+
- 颜色主题定制
|
|
703
|
+
- 暗黑模式
|
|
704
|
+
- 自定义样式覆盖
|
|
705
|
+
|
|
706
|
+
## 📝 更新日志
|
|
707
|
+
|
|
708
|
+
### v2.1.0 (2024-04)
|
|
709
|
+
- ♻️ `dataTableProps` + `$attrs` 透传原生 `v-data-table` 能力,迁移更顺滑
|
|
710
|
+
- ✨ 新增列状态持久化 `columnsState`,支持 `localStorage` 和受控模式
|
|
711
|
+
- ✨ 新增 `sortBy`/`sortDesc`/`multiSort`/`mustSort` 以及 `sort-change` 事件
|
|
712
|
+
- ✨ rowSelection 对齐 ProTable(`type`、`defaultSelectedRowKeys`、`selectedRowKeys`、`onChange`)
|
|
713
|
+
- 🧼 selection 事件、`page`、`items-per-page`、`click:row` 等事件与 Vuetify 行为保持一致
|
|
714
|
+
|
|
715
|
+
### v2.0.0 (2024-01)
|
|
716
|
+
- ✨ 新增 ProTable 样式系统(headerTitle, tooltip, cardBordered, ghost)
|
|
717
|
+
- ✨ 新增批量操作提示栏(alert, alert-actions 插槽)
|
|
718
|
+
- ✨ 新增轮询刷新功能(polling)
|
|
719
|
+
- ✨ 新增搜索防抖功能(debounceTime)
|
|
720
|
+
- 🎨 优化工具栏布局和样式
|
|
721
|
+
- 🎨 优化移动端适配
|
|
722
|
+
- 📝 完善文档和示例
|
|
723
|
+
|
|
724
|
+
## 🤝 贡献
|
|
725
|
+
|
|
726
|
+
欢迎提交 Issue 和 Pull Request!
|
|
727
|
+
|
|
728
|
+
## 📄 License
|
|
729
|
+
|
|
730
|
+
MIT
|