jianghu-ui 1.0.1 → 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 +50 -20
- package/dist/jianghu-ui.css +92 -57
- package/dist/jianghu-ui.js +1 -1
- package/package.json +1 -1
- package/src/Introduction.stories.mdx +2 -2
- package/src/components/JhAddressSelect/JhAddressSelect.md +19 -2
- package/src/components/JhAddressSelect/JhAddressSelect.stories.js +38 -3
- package/src/components/JhAddressSelect/JhAddressSelect.vue +229 -81
- package/src/components/JhTable/JhTable.vue +38 -2
package/package.json
CHANGED
|
@@ -24,13 +24,13 @@ import { Meta } from '@storybook/blocks';
|
|
|
24
24
|
<!DOCTYPE html>
|
|
25
25
|
<html>
|
|
26
26
|
<head>
|
|
27
|
-
<link href="https://
|
|
27
|
+
<link href="https://cdn.jsdelivr.net/npm/jianghu-ui@1.0.1/dist/jianghu-ui.css" rel="stylesheet">
|
|
28
28
|
</head>
|
|
29
29
|
<body>
|
|
30
30
|
<div id="app">
|
|
31
31
|
<!-- 你的应用内容 -->
|
|
32
32
|
</div>
|
|
33
|
-
<script src="https://
|
|
33
|
+
<script src="https://cdn.jsdelivr.net/npm/jianghu-ui@1.0.1/dist/jianghu-ui.js"></script>
|
|
34
34
|
</body>
|
|
35
35
|
</html>
|
|
36
36
|
```
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
- ✅ **双向绑定**: 支持 v-model 双向数据绑定
|
|
11
11
|
- ✅ **事件触发**: change 事件在值变化时触发
|
|
12
12
|
- ✅ **清除功能**: 支持清除已选值
|
|
13
|
-
- ✅ **返回完整信息**:
|
|
13
|
+
- ✅ **返回完整信息**: 事件返回包�� code 和 name 的完整对象
|
|
14
|
+
- ✅ **多种模式**: 支持普通联动选择 (select) 和级联选择 (cascader) 两种模式
|
|
14
15
|
|
|
15
16
|
## 基本用法
|
|
16
17
|
|
|
@@ -54,6 +55,8 @@ export default {
|
|
|
54
55
|
| --- | --- | --- | --- |
|
|
55
56
|
| value / v-model | 绑定值,返回包含 code 和 name 的对象 | object | { province: null, city: null, district: null } |
|
|
56
57
|
| level | 显示层级:1-仅省份,2-省市,3-省市区,4-省市区镇 | number | 3 |
|
|
58
|
+
| type | 显示模式:'select' (默认) 或 'cascader' | string | 'select' |
|
|
59
|
+
| label | 级联模式下的输入框标签 | string | '请选择地区' |
|
|
57
60
|
| outlined | 是否使用 outlined 样式 | boolean | true |
|
|
58
61
|
| dense | 是否使用紧凑模式 | boolean | false |
|
|
59
62
|
| loading | 是否显示加载状态 | boolean | false |
|
|
@@ -118,6 +121,19 @@ data 属性需要符合以下格式:
|
|
|
118
121
|
></jh-address-select>
|
|
119
122
|
```
|
|
120
123
|
|
|
124
|
+
### 级联选择模式
|
|
125
|
+
|
|
126
|
+
使用 `type="cascader"` 开启级联选择模式。
|
|
127
|
+
|
|
128
|
+
```vue
|
|
129
|
+
<jh-address-select
|
|
130
|
+
v-model="address"
|
|
131
|
+
type="cascader"
|
|
132
|
+
label="收货地址"
|
|
133
|
+
:data="addressData"
|
|
134
|
+
></jh-address-select>
|
|
135
|
+
```
|
|
136
|
+
|
|
121
137
|
### 仅选择到城市
|
|
122
138
|
|
|
123
139
|
```vue
|
|
@@ -243,8 +259,9 @@ export default {
|
|
|
243
259
|
4. **禁用状态**: 未选择上级时,下级选择器会自动禁用
|
|
244
260
|
5. **响应式布局**: 组件会根据 level 自动调整栅格布局(level=1 时占 12 列,level=2 时占 6 列,level=3 时占 4 列,level=4 时占 3 列)
|
|
245
261
|
6. **返回值格式**: v-model 和事件返回的值包含 code 和 name 两个字段,方便获取编码和名称
|
|
262
|
+
7. **级联模式**: 在 cascader 模式下,点击省份/城市/区县会展示下一级列表,直到选择完指定 level 级数后自动收起菜单
|
|
246
263
|
|
|
247
264
|
## 相关链接
|
|
248
265
|
|
|
249
266
|
- [Vuetify Autocomplete](https://vuetifyjs.com/en/components/autocompletes/)
|
|
250
|
-
- [中国行政区划代码](http://www.mca.gov.cn/article/sj/xzqh/)
|
|
267
|
+
- [中国行政区划代码](http://www.mca.gov.cn/article/sj/xzqh/)
|
|
@@ -31,6 +31,23 @@ export default {
|
|
|
31
31
|
defaultValue: { summary: '3' },
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
|
+
type: {
|
|
35
|
+
control: { type: 'select' },
|
|
36
|
+
options: ['select', 'cascader'],
|
|
37
|
+
description: '显示模式:select-普通联动,cascader-级联选择',
|
|
38
|
+
table: {
|
|
39
|
+
type: { summary: 'string' },
|
|
40
|
+
defaultValue: { summary: 'select' },
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
label: {
|
|
44
|
+
control: 'text',
|
|
45
|
+
description: '级联模式下的输入框标签',
|
|
46
|
+
table: {
|
|
47
|
+
type: { summary: 'string' },
|
|
48
|
+
defaultValue: { summary: '请选择地区' },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
34
51
|
outlined: {
|
|
35
52
|
control: 'boolean',
|
|
36
53
|
description: '是否使用 `outlined` 样式',
|
|
@@ -105,6 +122,8 @@ const Template = (args) => ({
|
|
|
105
122
|
<jh-address-select
|
|
106
123
|
v-model="value"
|
|
107
124
|
:level="args.level"
|
|
125
|
+
:type="args.type"
|
|
126
|
+
:label="args.label"
|
|
108
127
|
:outlined="args.outlined"
|
|
109
128
|
:dense="args.dense"
|
|
110
129
|
:loading="args.loading"
|
|
@@ -123,6 +142,8 @@ const Template = (args) => ({
|
|
|
123
142
|
const baseArgs = {
|
|
124
143
|
value: { province: null, city: null, district: null, town: null },
|
|
125
144
|
level: 3,
|
|
145
|
+
type: 'select',
|
|
146
|
+
label: '请选择地区',
|
|
126
147
|
outlined: true,
|
|
127
148
|
dense: true,
|
|
128
149
|
loading: false,
|
|
@@ -144,6 +165,21 @@ Default.parameters = {
|
|
|
144
165
|
},
|
|
145
166
|
};
|
|
146
167
|
|
|
168
|
+
export const CascaderMode = Template.bind({});
|
|
169
|
+
CascaderMode.storyName = "级联选择模式";
|
|
170
|
+
CascaderMode.args = {
|
|
171
|
+
...baseArgs,
|
|
172
|
+
type: 'cascader',
|
|
173
|
+
label: '请选择收货地址',
|
|
174
|
+
};
|
|
175
|
+
CascaderMode.parameters = {
|
|
176
|
+
docs: {
|
|
177
|
+
description: {
|
|
178
|
+
story: '使用 `type="cascader"` 开启级联选择模式,在一个下拉菜单中完成多级选择。',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
|
|
147
183
|
export const WithInitialValue = Template.bind({});
|
|
148
184
|
WithInitialValue.storyName = "带初始值";
|
|
149
185
|
WithInitialValue.args = {
|
|
@@ -157,7 +193,7 @@ WithInitialValue.args = {
|
|
|
157
193
|
WithInitialValue.parameters = {
|
|
158
194
|
docs: {
|
|
159
195
|
description: {
|
|
160
|
-
story: '设置 `v-model` 的初始值可以使组件在加载时就显示已选定的地址。返回值包含 `code` 和 `name`
|
|
196
|
+
story: '设置 `v-model` 的初始值可以使组件在加载时就显示已选定的地址。返回值包含 `code` 和 `name` ���个字段。',
|
|
161
197
|
},
|
|
162
198
|
},
|
|
163
199
|
};
|
|
@@ -278,5 +314,4 @@ Level4WithInitialValue.parameters = {
|
|
|
278
314
|
story: '四级联动并设置初始值,展示完整的省市区镇选择功能。',
|
|
279
315
|
},
|
|
280
316
|
},
|
|
281
|
-
};
|
|
282
|
-
|
|
317
|
+
};
|
|
@@ -1,86 +1,158 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<v-
|
|
4
|
-
<v-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
2
|
+
<div class="jh-address-select">
|
|
3
|
+
<template v-if="type === 'select'">
|
|
4
|
+
<v-row dense>
|
|
5
|
+
<v-col cols="12" :md="gridCol">
|
|
6
|
+
<v-autocomplete
|
|
7
|
+
class="jh-v-input"
|
|
8
|
+
v-model="internalValue.province"
|
|
9
|
+
:items="provinces"
|
|
10
|
+
:label="labels.province"
|
|
11
|
+
:outlined="outlined"
|
|
12
|
+
:dense="dense"
|
|
13
|
+
:filled="filled"
|
|
14
|
+
:single-line="singleLine"
|
|
15
|
+
:loading="loading"
|
|
16
|
+
item-text="name"
|
|
17
|
+
item-value="code"
|
|
18
|
+
clearable
|
|
19
|
+
hide-details
|
|
20
|
+
hide-no-data
|
|
21
|
+
prepend-inner-icon="mdi-map-outline"
|
|
22
|
+
@change="handleProvinceChange"
|
|
23
|
+
></v-autocomplete>
|
|
24
|
+
</v-col>
|
|
25
|
+
|
|
26
|
+
<v-col v-if="level >= 2" cols="12" :md="gridCol">
|
|
27
|
+
<v-autocomplete
|
|
28
|
+
class="jh-v-input"
|
|
29
|
+
v-model="internalValue.city"
|
|
30
|
+
:items="cities"
|
|
31
|
+
:label="labels.city"
|
|
32
|
+
:disabled="!internalValue.province"
|
|
33
|
+
:outlined="outlined"
|
|
34
|
+
:dense="dense"
|
|
35
|
+
:filled="filled"
|
|
36
|
+
:single-line="singleLine"
|
|
37
|
+
:loading="loading"
|
|
38
|
+
item-text="name"
|
|
39
|
+
item-value="code"
|
|
40
|
+
clearable
|
|
41
|
+
prepend-inner-icon="mdi-city-variant-outline"
|
|
42
|
+
@change="handleCityChange"
|
|
43
|
+
></v-autocomplete>
|
|
44
|
+
</v-col>
|
|
45
|
+
|
|
46
|
+
<v-col v-if="level >= 3" cols="12" :md="gridCol">
|
|
47
|
+
<v-autocomplete
|
|
48
|
+
class="jh-v-input"
|
|
49
|
+
v-model="internalValue.district"
|
|
50
|
+
:items="districts"
|
|
51
|
+
:label="labels.district"
|
|
52
|
+
:disabled="!internalValue.city"
|
|
53
|
+
:outlined="outlined"
|
|
54
|
+
:dense="dense"
|
|
55
|
+
:filled="filled"
|
|
56
|
+
:single-line="singleLine"
|
|
57
|
+
:loading="loading"
|
|
58
|
+
item-text="name"
|
|
59
|
+
item-value="code"
|
|
60
|
+
clearable
|
|
61
|
+
prepend-inner-icon="mdi-home-city-outline"
|
|
62
|
+
@change="handleDistrictChange"
|
|
63
|
+
></v-autocomplete>
|
|
64
|
+
</v-col>
|
|
65
|
+
|
|
66
|
+
<v-col v-if="level >= 4" cols="12" :md="gridCol">
|
|
67
|
+
<v-autocomplete
|
|
68
|
+
class="jh-v-input"
|
|
69
|
+
v-model="internalValue.town"
|
|
70
|
+
:items="towns"
|
|
71
|
+
:label="labels.town"
|
|
72
|
+
:disabled="!internalValue.district"
|
|
73
|
+
:outlined="outlined"
|
|
74
|
+
:dense="dense"
|
|
75
|
+
:filled="filled"
|
|
76
|
+
:single-line="singleLine"
|
|
77
|
+
:loading="loading"
|
|
78
|
+
item-text="name"
|
|
79
|
+
item-value="code"
|
|
80
|
+
clearable
|
|
81
|
+
prepend-inner-icon="mdi-home-variant-outline"
|
|
82
|
+
@change="emitChange"
|
|
83
|
+
></v-autocomplete>
|
|
84
|
+
</v-col>
|
|
85
|
+
</v-row>
|
|
86
|
+
</template>
|
|
43
87
|
|
|
44
|
-
<
|
|
45
|
-
<v-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
88
|
+
<template v-else-if="type === 'cascader'">
|
|
89
|
+
<v-menu
|
|
90
|
+
v-model="menuVisible"
|
|
91
|
+
:close-on-content-click="false"
|
|
92
|
+
offset-y
|
|
93
|
+
max-width="100%"
|
|
94
|
+
transition="scale-transition"
|
|
95
|
+
>
|
|
96
|
+
<template v-slot:activator="{ on, attrs }">
|
|
97
|
+
<v-text-field
|
|
98
|
+
class="jh-v-input"
|
|
99
|
+
v-bind="attrs"
|
|
100
|
+
v-on="on"
|
|
101
|
+
:value="displayText"
|
|
102
|
+
:label="label"
|
|
103
|
+
:outlined="outlined"
|
|
104
|
+
:dense="dense"
|
|
105
|
+
:filled="filled"
|
|
106
|
+
:single-line="singleLine"
|
|
107
|
+
:loading="loading"
|
|
108
|
+
readonly
|
|
109
|
+
append-icon="mdi-menu-down"
|
|
110
|
+
clearable
|
|
111
|
+
hide-details
|
|
112
|
+
@click:clear="clearValue"
|
|
113
|
+
></v-text-field>
|
|
114
|
+
</template>
|
|
115
|
+
<v-card class="jh-cascader-card">
|
|
116
|
+
<div class="jh-cascader-container">
|
|
117
|
+
<div class="jh-cascader-column" v-if="provinces.length">
|
|
118
|
+
<v-list dense class="pa-0">
|
|
119
|
+
<v-list-item v-for="item in provinces" :key="item.code" @click="onProvinceClick(item)" :class="{'v-item--active v-list-item--active primary--text': internalValue.province === item.code}">
|
|
120
|
+
<v-list-item-content><v-list-item-title :title="item.name">{{ item.name }}</v-list-item-title></v-list-item-content>
|
|
121
|
+
<v-list-item-action v-if="level > 1"><v-icon small>mdi-chevron-right</v-icon></v-list-item-action>
|
|
122
|
+
</v-list-item>
|
|
123
|
+
</v-list>
|
|
124
|
+
</div>
|
|
63
125
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
126
|
+
<div v-if="level >= 2" class="jh-cascader-column">
|
|
127
|
+
<v-list dense class="pa-0" v-if="cities.length">
|
|
128
|
+
<v-list-item v-for="item in cities" :key="item.code" @click="onCityClick(item)" :class="{'v-item--active v-list-item--active primary--text': internalValue.city === item.code}">
|
|
129
|
+
<v-list-item-content><v-list-item-title :title="item.name">{{ item.name }}</v-list-item-title></v-list-item-content>
|
|
130
|
+
<v-list-item-action v-if="level > 2"><v-icon small>mdi-chevron-right</v-icon></v-list-item-action>
|
|
131
|
+
</v-list-item>
|
|
132
|
+
</v-list>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<div v-if="level >= 3" class="jh-cascader-column">
|
|
136
|
+
<v-list dense class="pa-0" v-if="districts.length">
|
|
137
|
+
<v-list-item v-for="item in districts" :key="item.code" @click="onDistrictClick(item)" :class="{'v-item--active v-list-item--active primary--text': internalValue.district === item.code}">
|
|
138
|
+
<v-list-item-content><v-list-item-title :title="item.name">{{ item.name }}</v-list-item-title></v-list-item-content>
|
|
139
|
+
<v-list-item-action v-if="level > 3"><v-icon small>mdi-chevron-right</v-icon></v-list-item-action>
|
|
140
|
+
</v-list-item>
|
|
141
|
+
</v-list>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<div v-if="level >= 4" class="jh-cascader-column">
|
|
145
|
+
<v-list dense class="pa-0" v-if="towns.length">
|
|
146
|
+
<v-list-item v-for="item in towns" :key="item.code" @click="onTownClick(item)" :class="{'v-item--active v-list-item--active primary--text': internalValue.town === item.code}">
|
|
147
|
+
<v-list-item-content><v-list-item-title :title="item.name">{{ item.name }}</v-list-item-title></v-list-item-content>
|
|
148
|
+
</v-list-item>
|
|
149
|
+
</v-list>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
</v-card>
|
|
153
|
+
</v-menu>
|
|
154
|
+
</template>
|
|
155
|
+
</div>
|
|
84
156
|
</template>
|
|
85
157
|
|
|
86
158
|
<script>
|
|
@@ -96,6 +168,8 @@ export default {
|
|
|
96
168
|
dense: { type: Boolean, default: true },
|
|
97
169
|
filled: { type: Boolean, default: true },
|
|
98
170
|
singleLine: { type: Boolean, default: true },
|
|
171
|
+
type: { type: String, default: 'select' }, // select | cascader
|
|
172
|
+
label: { type: String, default: '请选择地区' },
|
|
99
173
|
|
|
100
174
|
loading: { type: Boolean, default: false },
|
|
101
175
|
labels: {
|
|
@@ -121,7 +195,8 @@ export default {
|
|
|
121
195
|
internalValue: { ...this.value },
|
|
122
196
|
cities: [],
|
|
123
197
|
districts: [],
|
|
124
|
-
towns: []
|
|
198
|
+
towns: [],
|
|
199
|
+
menuVisible: false,
|
|
125
200
|
};
|
|
126
201
|
},
|
|
127
202
|
computed: {
|
|
@@ -134,6 +209,28 @@ export default {
|
|
|
134
209
|
if (this.level === 3) return 4;
|
|
135
210
|
return 3;
|
|
136
211
|
},
|
|
212
|
+
displayText() {
|
|
213
|
+
if (!this.internalValue.province) return '';
|
|
214
|
+
const p = this.provinces.find(x => x.code === this.internalValue.province);
|
|
215
|
+
let text = p ? p.name : '';
|
|
216
|
+
|
|
217
|
+
if (this.level >= 2 && this.internalValue.city) {
|
|
218
|
+
const c = this.cities.find(x => x.code === this.internalValue.city);
|
|
219
|
+
if (c) text += ` / ${c.name}`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (this.level >= 3 && this.internalValue.district) {
|
|
223
|
+
const d = this.districts.find(x => x.code === this.internalValue.district);
|
|
224
|
+
if (d) text += ` / ${d.name}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (this.level >= 4 && this.internalValue.town) {
|
|
228
|
+
const t = this.towns.find(x => x.code === this.internalValue.town);
|
|
229
|
+
if (t) text += ` / ${t.name}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return text;
|
|
233
|
+
},
|
|
137
234
|
fullValue() {
|
|
138
235
|
const result = {
|
|
139
236
|
province: null,
|
|
@@ -252,10 +349,61 @@ export default {
|
|
|
252
349
|
emitChange() {
|
|
253
350
|
this.$emit('input', { ...this.fullValue });
|
|
254
351
|
this.$emit('change', { ...this.fullValue });
|
|
352
|
+
},
|
|
353
|
+
onProvinceClick(item) {
|
|
354
|
+
this.internalValue.province = item.code;
|
|
355
|
+
this.handleProvinceChange(item.code);
|
|
356
|
+
if (this.level === 1) this.menuVisible = false;
|
|
357
|
+
},
|
|
358
|
+
onCityClick(item) {
|
|
359
|
+
this.internalValue.city = item.code;
|
|
360
|
+
this.handleCityChange(item.code);
|
|
361
|
+
if (this.level === 2) this.menuVisible = false;
|
|
362
|
+
},
|
|
363
|
+
onDistrictClick(item) {
|
|
364
|
+
this.internalValue.district = item.code;
|
|
365
|
+
this.handleDistrictChange(item.code);
|
|
366
|
+
if (this.level === 3) this.menuVisible = false;
|
|
367
|
+
},
|
|
368
|
+
onTownClick(item) {
|
|
369
|
+
this.internalValue.town = item.code;
|
|
370
|
+
this.emitChange();
|
|
371
|
+
if (this.level === 4) this.menuVisible = false;
|
|
372
|
+
},
|
|
373
|
+
clearValue() {
|
|
374
|
+
this.internalValue = { province: null, city: null, district: null, town: null };
|
|
375
|
+
this.cities = [];
|
|
376
|
+
this.districts = [];
|
|
377
|
+
this.towns = [];
|
|
378
|
+
this.emitChange();
|
|
255
379
|
}
|
|
256
380
|
}
|
|
257
381
|
};
|
|
258
382
|
</script>
|
|
259
383
|
|
|
260
384
|
<style scoped>
|
|
385
|
+
.jh-cascader-container {
|
|
386
|
+
display: flex;
|
|
387
|
+
overflow-x: auto;
|
|
388
|
+
white-space: nowrap;
|
|
389
|
+
}
|
|
390
|
+
.jh-cascader-column {
|
|
391
|
+
min-width: 180px;
|
|
392
|
+
max-width: 250px;
|
|
393
|
+
max-height: 400px;
|
|
394
|
+
overflow-y: auto;
|
|
395
|
+
border-right: 1px solid #eee;
|
|
396
|
+
}
|
|
397
|
+
.jh-cascader-column:last-child {
|
|
398
|
+
border-right: none;
|
|
399
|
+
}
|
|
400
|
+
/* 优化列表项内容防止过早截断 */
|
|
401
|
+
.jh-cascader-column .v-list-item__content {
|
|
402
|
+
overflow: visible;
|
|
403
|
+
}
|
|
404
|
+
.jh-cascader-column .v-list-item__title {
|
|
405
|
+
white-space: nowrap;
|
|
406
|
+
overflow: hidden;
|
|
407
|
+
text-overflow: ellipsis;
|
|
408
|
+
}
|
|
261
409
|
</style>
|
|
@@ -117,6 +117,17 @@
|
|
|
117
117
|
clearable
|
|
118
118
|
></v-text-field>
|
|
119
119
|
|
|
120
|
+
<!-- 导出按钮 -->
|
|
121
|
+
<v-btn
|
|
122
|
+
v-if="toolbarConfig.export"
|
|
123
|
+
icon
|
|
124
|
+
small
|
|
125
|
+
@click="handleExport"
|
|
126
|
+
title="导出"
|
|
127
|
+
>
|
|
128
|
+
<v-icon>mdi-export-variant</v-icon>
|
|
129
|
+
</v-btn>
|
|
130
|
+
|
|
120
131
|
<!-- 刷新按钮 -->
|
|
121
132
|
<v-btn
|
|
122
133
|
v-if="toolbarConfig.refresh"
|
|
@@ -244,7 +255,7 @@
|
|
|
244
255
|
:single-select="singleSelectComputed"
|
|
245
256
|
:value="selectedItems"
|
|
246
257
|
:item-key="rowKey"
|
|
247
|
-
:dense="
|
|
258
|
+
:dense="tableDense"
|
|
248
259
|
:multi-sort="multiSort"
|
|
249
260
|
:must-sort="mustSort"
|
|
250
261
|
:sort-by="internalSortBy"
|
|
@@ -964,6 +975,7 @@ export default {
|
|
|
964
975
|
setting: true,
|
|
965
976
|
density: true,
|
|
966
977
|
fullscreen: false,
|
|
978
|
+
export: false, // Default to false, can be enabled via prop
|
|
967
979
|
...this.toolbar
|
|
968
980
|
};
|
|
969
981
|
}
|
|
@@ -972,7 +984,8 @@ export default {
|
|
|
972
984
|
refresh: true,
|
|
973
985
|
setting: true,
|
|
974
986
|
density: true,
|
|
975
|
-
fullscreen: false
|
|
987
|
+
fullscreen: false,
|
|
988
|
+
export: false // Default to false
|
|
976
989
|
};
|
|
977
990
|
},
|
|
978
991
|
// 可见的表头
|
|
@@ -992,6 +1005,15 @@ export default {
|
|
|
992
1005
|
}
|
|
993
1006
|
];
|
|
994
1007
|
},
|
|
1008
|
+
tableDense() {
|
|
1009
|
+
if (this.currentDensity === 'compact') {
|
|
1010
|
+
return true;
|
|
1011
|
+
}
|
|
1012
|
+
// For 'medium' and 'default', we don't use the dense prop, but a custom class.
|
|
1013
|
+
// But we still respect the component's `dense` prop as a baseline.
|
|
1014
|
+
return this.dense;
|
|
1015
|
+
},
|
|
1016
|
+
|
|
995
1017
|
// 密度样式类
|
|
996
1018
|
densityClass() {
|
|
997
1019
|
return {
|
|
@@ -1463,6 +1485,10 @@ export default {
|
|
|
1463
1485
|
this.emitColumnStateChange();
|
|
1464
1486
|
this.$forceUpdate();
|
|
1465
1487
|
},
|
|
1488
|
+
// 导出表格
|
|
1489
|
+
handleExport() {
|
|
1490
|
+
this.$emit('export');
|
|
1491
|
+
},
|
|
1466
1492
|
// 刷新表格
|
|
1467
1493
|
async handleRefresh() {
|
|
1468
1494
|
this.$emit('refresh');
|
|
@@ -2000,6 +2026,16 @@ export default {
|
|
|
2000
2026
|
flex: 1;
|
|
2001
2027
|
}
|
|
2002
2028
|
|
|
2029
|
+
/* --- 密度调整 --- */
|
|
2030
|
+
/* 中等密度 */
|
|
2031
|
+
.jh-pro-table ::v-deep .jh-table-medium.v-data-table > .v-data-table__wrapper > table > thead > tr > th {
|
|
2032
|
+
height: 40px;
|
|
2033
|
+
}
|
|
2034
|
+
.jh-pro-table ::v-deep .jh-table-medium.v-data-table > .v-data-table__wrapper > table > tbody > tr > td {
|
|
2035
|
+
height: 40px;
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
|
|
2003
2039
|
.jh-pro-table-header-right {
|
|
2004
2040
|
display: flex;
|
|
2005
2041
|
align-items: center;
|