@ebiz/designer-components 0.0.18-beta.27 → 0.0.18-beta.29
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/dist/designer-components.css +1 -0
- package/dist/favicon.ico +0 -0
- package/dist/index.mjs +123236 -0
- package/package.json +1 -1
- package/src/apiService/simpleDataService.js +0 -1
- package/src/components/EbizTree.vue +22 -0
- package/src/components/EbizTreeSelector.vue +513 -0
- package/src/index.js +3 -1
- package/src/router/index.js +14 -0
- package/src/views/Home.vue +25 -1
- package/src/views/TreeDemo.vue +37 -25
- package/src/views/TreeSelectorDemo.vue +246 -0
package/package.json
CHANGED
@@ -5,6 +5,9 @@
|
|
5
5
|
:value="modelValue"
|
6
6
|
:expanded="expandedModel"
|
7
7
|
:actived="activedModel"
|
8
|
+
:transition="transition"
|
9
|
+
:disable-check="disableCheck"
|
10
|
+
:keys="keys"
|
8
11
|
@change="handleChange"
|
9
12
|
@expand="handleExpand"
|
10
13
|
@active="handleActive"
|
@@ -63,6 +66,25 @@ const props = defineProps({
|
|
63
66
|
items: {
|
64
67
|
type: Array,
|
65
68
|
default: () => []
|
69
|
+
},
|
70
|
+
// 是否启用过渡动画
|
71
|
+
transition: {
|
72
|
+
type: Boolean,
|
73
|
+
default: false
|
74
|
+
},
|
75
|
+
// 自定义节点禁用状态,返回true表示禁用
|
76
|
+
disableCheck: {
|
77
|
+
type: Function,
|
78
|
+
default: null
|
79
|
+
},
|
80
|
+
// 自定义节点数据中的字段名称
|
81
|
+
keys: {
|
82
|
+
type: Object,
|
83
|
+
default: () => ({
|
84
|
+
label: 'label',
|
85
|
+
value: 'value',
|
86
|
+
children: 'children'
|
87
|
+
})
|
66
88
|
}
|
67
89
|
});
|
68
90
|
|
@@ -0,0 +1,513 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="ebiz-tree-selector">
|
3
|
+
<div class="selected-items" v-if="modelValue && modelValue.length">
|
4
|
+
<div v-for="(item, index) in modelValue" :key="index" class="selected-item">
|
5
|
+
<span class="item-text">{{ item.label }}</span>
|
6
|
+
<span class="item-remove" @click.stop="removeItem(index)">×</span>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
<t-button @click="showDialog" icon="add">
|
10
|
+
<t-icon name="add"></t-icon>添加
|
11
|
+
</t-button>
|
12
|
+
|
13
|
+
<EbizDialog
|
14
|
+
v-model:visible="dialogVisible"
|
15
|
+
:header="{
|
16
|
+
text: '选择人员/部门',
|
17
|
+
icon: 'folder-open'
|
18
|
+
}"
|
19
|
+
width="800px"
|
20
|
+
placement="center"
|
21
|
+
confirmBtn="确定"
|
22
|
+
cancelBtn="取消"
|
23
|
+
@confirm="handleConfirm"
|
24
|
+
@cancel="handleCancel"
|
25
|
+
>
|
26
|
+
<div class="selector-container">
|
27
|
+
<!-- 左侧选择区域 -->
|
28
|
+
<div class="left-panel">
|
29
|
+
<!-- 顶部搜索区域 -->
|
30
|
+
<div class="search-box">
|
31
|
+
<t-input v-model="searchText" placeholder="搜索成员、部门或标签" clearable>
|
32
|
+
<template #suffix-icon>
|
33
|
+
<t-icon name="search"></t-icon>
|
34
|
+
</template>
|
35
|
+
</t-input>
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<!-- 选项卡 -->
|
39
|
+
<t-tabs v-model="activeTab" class="selector-tabs">
|
40
|
+
<t-tab-panel value="organization" label="组织架构"></t-tab-panel>
|
41
|
+
<t-tab-panel value="department" label="部门"></t-tab-panel>
|
42
|
+
<t-tab-panel value="position" label="岗位"></t-tab-panel>
|
43
|
+
<t-tab-panel value="employee" label="员工"></t-tab-panel>
|
44
|
+
</t-tabs>
|
45
|
+
|
46
|
+
<!-- 树形结构区域 -->
|
47
|
+
<div class="tree-content">
|
48
|
+
<div v-if="loading" class="loading-container">
|
49
|
+
<t-loading />
|
50
|
+
</div>
|
51
|
+
<EbizTree
|
52
|
+
v-else-if="activeTab === 'organization'"
|
53
|
+
checkable
|
54
|
+
:items="filteredData.organization"
|
55
|
+
v-model="checkedNodes"
|
56
|
+
:disable-check="disableCheck"
|
57
|
+
/>
|
58
|
+
<EbizTree
|
59
|
+
v-else-if="activeTab === 'department'"
|
60
|
+
checkable
|
61
|
+
:items="filteredData.department"
|
62
|
+
v-model="checkedNodes"
|
63
|
+
:disable-check="disableCheck"
|
64
|
+
/>
|
65
|
+
<EbizTree
|
66
|
+
v-else-if="activeTab === 'position'"
|
67
|
+
checkable
|
68
|
+
:items="filteredData.position"
|
69
|
+
v-model="checkedNodes"
|
70
|
+
:disable-check="disableCheck"
|
71
|
+
/>
|
72
|
+
<EbizTree
|
73
|
+
v-else-if="activeTab === 'employee'"
|
74
|
+
checkable
|
75
|
+
:items="filteredData.employee"
|
76
|
+
v-model="checkedNodes"
|
77
|
+
:disable-check="disableCheck"
|
78
|
+
/>
|
79
|
+
</div>
|
80
|
+
</div>
|
81
|
+
|
82
|
+
<!-- 右侧已选区域 -->
|
83
|
+
<div class="right-panel">
|
84
|
+
<div class="selected-title">已选择的部门、成员</div>
|
85
|
+
<div class="selected-count">共 {{ selectPreview.length }} 项</div>
|
86
|
+
<div class="selected-list">
|
87
|
+
<div v-for="(item, index) in selectPreview" :key="index" class="selected-list-item">
|
88
|
+
<t-icon :name="getIconForType(item.type)" class="item-icon" />
|
89
|
+
<span class="selected-label">{{ item.label }}</span>
|
90
|
+
<t-icon name="close-circle" class="remove-icon" @click="removePreviewItem(index)" />
|
91
|
+
</div>
|
92
|
+
<div v-if="selectPreview.length === 0" class="no-selection">
|
93
|
+
<t-icon name="info-circle" />
|
94
|
+
<span>请在左侧选择部门或成员</span>
|
95
|
+
</div>
|
96
|
+
</div>
|
97
|
+
</div>
|
98
|
+
</div>
|
99
|
+
</EbizDialog>
|
100
|
+
</div>
|
101
|
+
</template>
|
102
|
+
|
103
|
+
<script setup>
|
104
|
+
import { ref, computed, watch, onMounted } from 'vue';
|
105
|
+
import { Button as TButton, Icon as TIcon, Input as TInput, Tabs as TTabs, TabPanel as TTabPanel, Loading as TLoading, MessagePlugin } from 'tdesign-vue-next';
|
106
|
+
import request from '../apiService/simpleDataService';
|
107
|
+
import EbizDialog from './TdesignDialog.vue';
|
108
|
+
import EbizTree from './EbizTree.vue';
|
109
|
+
|
110
|
+
const props = defineProps({
|
111
|
+
// 选中的数据,支持v-model
|
112
|
+
modelValue: {
|
113
|
+
type: Array,
|
114
|
+
default: () => []
|
115
|
+
},
|
116
|
+
// 树形数据,可以是单个数组或分类对象
|
117
|
+
data: {
|
118
|
+
type: [Array, Object],
|
119
|
+
default: () => ([])
|
120
|
+
},
|
121
|
+
// 禁用选择的节点
|
122
|
+
disableCheck: {
|
123
|
+
type: Function,
|
124
|
+
default: null
|
125
|
+
},
|
126
|
+
// 标题
|
127
|
+
title: {
|
128
|
+
type: String,
|
129
|
+
default: '选择人员/部门'
|
130
|
+
}
|
131
|
+
});
|
132
|
+
|
133
|
+
const emit = defineEmits(['update:modelValue', 'change']);
|
134
|
+
|
135
|
+
// 弹窗显示状态
|
136
|
+
const dialogVisible = ref(false);
|
137
|
+
// 搜索文本
|
138
|
+
const searchText = ref('');
|
139
|
+
// 选中的节点
|
140
|
+
const checkedNodes = ref([]);
|
141
|
+
// 当前活动的选项卡
|
142
|
+
const activeTab = ref('organization');
|
143
|
+
// 弹窗内预览的选中项
|
144
|
+
const selectPreview = ref([]);
|
145
|
+
// 加载状态
|
146
|
+
const loading = ref(false);
|
147
|
+
// API返回的数据
|
148
|
+
const apiData = ref(null);
|
149
|
+
|
150
|
+
// 固定的API请求URL和参数
|
151
|
+
const API_URL = '/permissions/tree';
|
152
|
+
|
153
|
+
// 根据数据结构处理树形数据
|
154
|
+
const treeData = computed(() => {
|
155
|
+
// 如果已有API数据,则优先使用API数据
|
156
|
+
if (apiData.value) {
|
157
|
+
return apiData.value;
|
158
|
+
}
|
159
|
+
|
160
|
+
// 否则使用props传入的数据
|
161
|
+
if (Array.isArray(props.data)) {
|
162
|
+
return {
|
163
|
+
organization: props.data,
|
164
|
+
department: [],
|
165
|
+
position: [],
|
166
|
+
employee: []
|
167
|
+
};
|
168
|
+
} else {
|
169
|
+
return {
|
170
|
+
organization: props.data.organization || [],
|
171
|
+
department: props.data.department || [],
|
172
|
+
position: props.data.position || [],
|
173
|
+
employee: props.data.employee || []
|
174
|
+
};
|
175
|
+
}
|
176
|
+
});
|
177
|
+
|
178
|
+
// 过滤后的树形数据
|
179
|
+
const filteredData = computed(() => {
|
180
|
+
if (!searchText.value) {
|
181
|
+
return treeData.value;
|
182
|
+
}
|
183
|
+
|
184
|
+
return {
|
185
|
+
organization: filterTreeData(treeData.value.organization, searchText.value),
|
186
|
+
department: filterTreeData(treeData.value.department, searchText.value),
|
187
|
+
position: filterTreeData(treeData.value.position, searchText.value),
|
188
|
+
employee: filterTreeData(treeData.value.employee, searchText.value)
|
189
|
+
};
|
190
|
+
});
|
191
|
+
|
192
|
+
// 获取API数据
|
193
|
+
const fetchApiData = async () => {
|
194
|
+
loading.value = true;
|
195
|
+
try {
|
196
|
+
const response = await request.fetch({}, {}, API_URL);
|
197
|
+
console.log(response, 201);
|
198
|
+
// 处理返回数据转换
|
199
|
+
if (response && response.code === 0) {
|
200
|
+
const responseData = response.data || {};
|
201
|
+
|
202
|
+
// 转换API返回数据为组件需要的格式
|
203
|
+
apiData.value = {
|
204
|
+
organization: responseData.items || [],
|
205
|
+
department: responseData.items || [], // 可根据实际需求自定义
|
206
|
+
position: responseData.positions || [],
|
207
|
+
employee: responseData.users || []
|
208
|
+
};
|
209
|
+
} else {
|
210
|
+
throw new Error('API返回数据格式不正确');
|
211
|
+
}
|
212
|
+
} catch (error) {
|
213
|
+
console.error('获取树数据失败:', error);
|
214
|
+
MessagePlugin.error('获取数据失败,请稍后重试');
|
215
|
+
|
216
|
+
// 如果API请求失败,使用props.data作为备选数据
|
217
|
+
apiData.value = null;
|
218
|
+
} finally {
|
219
|
+
loading.value = false;
|
220
|
+
}
|
221
|
+
};
|
222
|
+
|
223
|
+
// 过滤树形数据
|
224
|
+
function filterTreeData(data, keyword) {
|
225
|
+
if (!data || !data.length) {
|
226
|
+
return [];
|
227
|
+
}
|
228
|
+
|
229
|
+
return data.filter(node => {
|
230
|
+
// 如果节点名称包含关键字,则保留该节点
|
231
|
+
if (node.label.toLowerCase().includes(keyword.toLowerCase())) {
|
232
|
+
return true;
|
233
|
+
}
|
234
|
+
|
235
|
+
// 递归过滤子节点
|
236
|
+
if (node.children && node.children.length) {
|
237
|
+
const filteredChildren = filterTreeData(node.children, keyword);
|
238
|
+
if (filteredChildren.length) {
|
239
|
+
// 复制节点并替换children
|
240
|
+
const clonedNode = { ...node, children: filteredChildren };
|
241
|
+
return true;
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
245
|
+
return false;
|
246
|
+
});
|
247
|
+
}
|
248
|
+
|
249
|
+
// 根据类型获取对应图标
|
250
|
+
const getIconForType = (type) => {
|
251
|
+
const iconMap = {
|
252
|
+
organization: 'internet',
|
253
|
+
department: 'folder',
|
254
|
+
position: 'user-talk',
|
255
|
+
employee: 'user'
|
256
|
+
};
|
257
|
+
return iconMap[type] || 'user';
|
258
|
+
};
|
259
|
+
|
260
|
+
// 显示对话框
|
261
|
+
function showDialog() {
|
262
|
+
// 获取API数据
|
263
|
+
fetchApiData();
|
264
|
+
|
265
|
+
// 重置弹窗内的预览数据
|
266
|
+
selectPreview.value = props.modelValue.map(item => ({
|
267
|
+
...item,
|
268
|
+
type: item.type || 'employee' // 默认为员工类型
|
269
|
+
}));
|
270
|
+
|
271
|
+
// 重置选中的节点
|
272
|
+
checkedNodes.value = props.modelValue.map(item => item.value);
|
273
|
+
dialogVisible.value = true;
|
274
|
+
}
|
275
|
+
|
276
|
+
// 确认选择
|
277
|
+
function handleConfirm() {
|
278
|
+
emit('update:modelValue', selectPreview.value.map(item => ({
|
279
|
+
label: item.label,
|
280
|
+
value: item.value,
|
281
|
+
type: item.type
|
282
|
+
})));
|
283
|
+
emit('change', selectPreview.value);
|
284
|
+
dialogVisible.value = false;
|
285
|
+
}
|
286
|
+
|
287
|
+
// 取消选择
|
288
|
+
function handleCancel() {
|
289
|
+
dialogVisible.value = false;
|
290
|
+
}
|
291
|
+
|
292
|
+
// 移除已选择预览中的项目
|
293
|
+
function removePreviewItem(index) {
|
294
|
+
const removedItem = selectPreview.value[index];
|
295
|
+
selectPreview.value.splice(index, 1);
|
296
|
+
checkedNodes.value = checkedNodes.value.filter(value => value !== removedItem.value);
|
297
|
+
}
|
298
|
+
|
299
|
+
// 移除选中项
|
300
|
+
function removeItem(index) {
|
301
|
+
const newValue = [...props.modelValue];
|
302
|
+
newValue.splice(index, 1);
|
303
|
+
emit('update:modelValue', newValue);
|
304
|
+
emit('change', newValue);
|
305
|
+
}
|
306
|
+
|
307
|
+
// 获取所有树数据的扁平结构
|
308
|
+
const flattenAllTrees = computed(() => {
|
309
|
+
let result = [];
|
310
|
+
const flattenTree = (nodes, type) => {
|
311
|
+
if (!nodes) return;
|
312
|
+
nodes.forEach(node => {
|
313
|
+
result.push({
|
314
|
+
...node,
|
315
|
+
type: node.type || type
|
316
|
+
});
|
317
|
+
if (node.children && node.children.length) {
|
318
|
+
flattenTree(node.children, type);
|
319
|
+
}
|
320
|
+
});
|
321
|
+
};
|
322
|
+
|
323
|
+
flattenTree(treeData.value.organization, 'organization');
|
324
|
+
flattenTree(treeData.value.department, 'department');
|
325
|
+
flattenTree(treeData.value.position, 'position');
|
326
|
+
flattenTree(treeData.value.employee, 'employee');
|
327
|
+
|
328
|
+
return result;
|
329
|
+
});
|
330
|
+
|
331
|
+
// 监听选中节点变化,同步到预览
|
332
|
+
watch(checkedNodes, (newValues) => {
|
333
|
+
// 提取所有树中的节点
|
334
|
+
const flatNodes = flattenAllTrees.value;
|
335
|
+
|
336
|
+
// 找到所有选中的节点
|
337
|
+
const selectedItems = newValues
|
338
|
+
.map(value => flatNodes.find(node => node.value === value))
|
339
|
+
.filter(Boolean);
|
340
|
+
|
341
|
+
// 更新预览
|
342
|
+
selectPreview.value = selectedItems;
|
343
|
+
}, { deep: true });
|
344
|
+
|
345
|
+
// 监听modelValue变化,同步到选中节点
|
346
|
+
watch(() => props.modelValue, (newValue) => {
|
347
|
+
if (!dialogVisible.value) return;
|
348
|
+
|
349
|
+
checkedNodes.value = newValue.map(item => item.value);
|
350
|
+
selectPreview.value = newValue.map(item => ({
|
351
|
+
...item,
|
352
|
+
type: item.type || 'employee'
|
353
|
+
}));
|
354
|
+
}, { deep: true });
|
355
|
+
|
356
|
+
// 组件挂载时,预加载数据
|
357
|
+
onMounted(() => {
|
358
|
+
// 预加载不再需要,点击添加按钮时才加载
|
359
|
+
showDialog()
|
360
|
+
console.log(dialogVisible.value);
|
361
|
+
});
|
362
|
+
</script>
|
363
|
+
|
364
|
+
<style scoped>
|
365
|
+
.ebiz-tree-selector {
|
366
|
+
display: flex;
|
367
|
+
flex-wrap: wrap;
|
368
|
+
align-items: center;
|
369
|
+
gap: 8px;
|
370
|
+
min-height: 32px;
|
371
|
+
}
|
372
|
+
|
373
|
+
.selected-items {
|
374
|
+
display: flex;
|
375
|
+
flex-wrap: wrap;
|
376
|
+
gap: 4px;
|
377
|
+
}
|
378
|
+
|
379
|
+
.selected-item {
|
380
|
+
display: flex;
|
381
|
+
align-items: center;
|
382
|
+
padding: 4px 8px;
|
383
|
+
background-color: #f0f0f0;
|
384
|
+
border-radius: 4px;
|
385
|
+
font-size: 14px;
|
386
|
+
}
|
387
|
+
|
388
|
+
.item-text {
|
389
|
+
margin-right: 4px;
|
390
|
+
}
|
391
|
+
|
392
|
+
.item-remove {
|
393
|
+
cursor: pointer;
|
394
|
+
color: #999;
|
395
|
+
font-size: 16px;
|
396
|
+
}
|
397
|
+
|
398
|
+
.item-remove:hover {
|
399
|
+
color: #ff4d4f;
|
400
|
+
}
|
401
|
+
|
402
|
+
.add-button {
|
403
|
+
display: flex;
|
404
|
+
align-items: center;
|
405
|
+
}
|
406
|
+
|
407
|
+
.selector-container {
|
408
|
+
display: flex;
|
409
|
+
height: 500px;
|
410
|
+
}
|
411
|
+
|
412
|
+
.left-panel {
|
413
|
+
flex: 1;
|
414
|
+
display: flex;
|
415
|
+
flex-direction: column;
|
416
|
+
border-right: 1px solid #e0e0e0;
|
417
|
+
padding-right: 16px;
|
418
|
+
}
|
419
|
+
|
420
|
+
.right-panel {
|
421
|
+
width: 280px;
|
422
|
+
display: flex;
|
423
|
+
flex-direction: column;
|
424
|
+
padding-left: 16px;
|
425
|
+
}
|
426
|
+
|
427
|
+
.search-box {
|
428
|
+
margin-bottom: 12px;
|
429
|
+
}
|
430
|
+
|
431
|
+
.selector-tabs {
|
432
|
+
margin-bottom: 12px;
|
433
|
+
}
|
434
|
+
|
435
|
+
.tree-content {
|
436
|
+
flex: 1;
|
437
|
+
overflow: auto;
|
438
|
+
border: 1px solid #e0e0e0;
|
439
|
+
border-radius: 4px;
|
440
|
+
padding: 12px;
|
441
|
+
position: relative;
|
442
|
+
}
|
443
|
+
|
444
|
+
.loading-container {
|
445
|
+
position: absolute;
|
446
|
+
top: 0;
|
447
|
+
left: 0;
|
448
|
+
right: 0;
|
449
|
+
bottom: 0;
|
450
|
+
display: flex;
|
451
|
+
align-items: center;
|
452
|
+
justify-content: center;
|
453
|
+
background-color: rgba(255, 255, 255, 0.7);
|
454
|
+
}
|
455
|
+
|
456
|
+
.selected-title {
|
457
|
+
font-weight: bold;
|
458
|
+
margin-bottom: 8px;
|
459
|
+
}
|
460
|
+
|
461
|
+
.selected-count {
|
462
|
+
color: #999;
|
463
|
+
font-size: 12px;
|
464
|
+
margin-bottom: 12px;
|
465
|
+
}
|
466
|
+
|
467
|
+
.selected-list {
|
468
|
+
flex: 1;
|
469
|
+
overflow: auto;
|
470
|
+
border: 1px solid #e0e0e0;
|
471
|
+
border-radius: 4px;
|
472
|
+
padding: 8px;
|
473
|
+
}
|
474
|
+
|
475
|
+
.selected-list-item {
|
476
|
+
display: flex;
|
477
|
+
align-items: center;
|
478
|
+
padding: 8px;
|
479
|
+
border-bottom: 1px solid #f0f0f0;
|
480
|
+
}
|
481
|
+
|
482
|
+
.selected-list-item:last-child {
|
483
|
+
border-bottom: none;
|
484
|
+
}
|
485
|
+
|
486
|
+
.item-icon {
|
487
|
+
color: #0052d9;
|
488
|
+
margin-right: 8px;
|
489
|
+
}
|
490
|
+
|
491
|
+
.selected-label {
|
492
|
+
flex: 1;
|
493
|
+
}
|
494
|
+
|
495
|
+
.remove-icon {
|
496
|
+
color: #999;
|
497
|
+
cursor: pointer;
|
498
|
+
}
|
499
|
+
|
500
|
+
.remove-icon:hover {
|
501
|
+
color: #ff4d4f;
|
502
|
+
}
|
503
|
+
|
504
|
+
.no-selection {
|
505
|
+
display: flex;
|
506
|
+
flex-direction: column;
|
507
|
+
align-items: center;
|
508
|
+
justify-content: center;
|
509
|
+
height: 100%;
|
510
|
+
color: #999;
|
511
|
+
gap: 8px;
|
512
|
+
}
|
513
|
+
</style>
|
package/src/index.js
CHANGED
@@ -52,6 +52,7 @@ import EbizTableColumn from './components/EbizTableColumn.vue';
|
|
52
52
|
import EbizTableSort from './components/EbizTableSort.vue';
|
53
53
|
import EbizDetailBlock from './components/EbizDetailBlock.vue';
|
54
54
|
import EbizTree from './components/EbizTree.vue';
|
55
|
+
import EbizTreeSelector from './components/EbizTreeSelector.vue';
|
55
56
|
import { MessagePlugin as EbizMessage } from 'tdesign-vue-next';
|
56
57
|
|
57
58
|
// 导入简洁数据服务
|
@@ -157,5 +158,6 @@ export {
|
|
157
158
|
// 详情块组件
|
158
159
|
EbizDetailBlock,
|
159
160
|
// 树组件
|
160
|
-
EbizTree
|
161
|
+
EbizTree,
|
162
|
+
EbizTreeSelector
|
161
163
|
};
|
package/src/router/index.js
CHANGED
@@ -267,6 +267,20 @@ const routes = [
|
|
267
267
|
name: 'Tree',
|
268
268
|
component: () => import('../views/TreeDemo.vue'),
|
269
269
|
meta: { title: 'Ebiz树组件示例' }
|
270
|
+
},
|
271
|
+
{
|
272
|
+
path: '/tree-demo',
|
273
|
+
name: 'TreeDemo',
|
274
|
+
component: () => import('../views/TreeDemo.vue'),
|
275
|
+
meta: { title: 'Ebiz树组件示例' }
|
276
|
+
},
|
277
|
+
{
|
278
|
+
path: '/tree-selector-demo',
|
279
|
+
name: 'TreeSelectorDemo',
|
280
|
+
component: () => import('../views/TreeSelectorDemo.vue'),
|
281
|
+
meta: {
|
282
|
+
title: '树形选择器'
|
283
|
+
}
|
270
284
|
}
|
271
285
|
]
|
272
286
|
|
package/src/views/Home.vue
CHANGED
@@ -1,12 +1,22 @@
|
|
1
1
|
<template>
|
2
2
|
<div class="home">
|
3
|
-
<h1
|
3
|
+
<h1>Ebiz 组件库</h1>
|
4
4
|
<div class="component-list">
|
5
5
|
<div v-for="(item, index) in components" :key="index" class="component-item">
|
6
6
|
<router-link :to="item.path" class="component-link">
|
7
7
|
{{ item.title }}
|
8
8
|
</router-link>
|
9
9
|
</div>
|
10
|
+
|
11
|
+
<router-link to="/tree-demo" class="component-item">
|
12
|
+
<div class="component-title">树组件</div>
|
13
|
+
<div class="component-desc">用于展示层级结构和操作的组件</div>
|
14
|
+
</router-link>
|
15
|
+
|
16
|
+
<router-link to="/tree-selector-demo" class="component-item">
|
17
|
+
<div class="component-title">树形选择器</div>
|
18
|
+
<div class="component-desc">基于树组件的选择器,支持搜索和多选</div>
|
19
|
+
</router-link>
|
10
20
|
</div>
|
11
21
|
</div>
|
12
22
|
</template>
|
@@ -96,4 +106,18 @@ export default {
|
|
96
106
|
.component-link:hover {
|
97
107
|
color: #1890ff;
|
98
108
|
}
|
109
|
+
|
110
|
+
.component-title {
|
111
|
+
font-size: 16px;
|
112
|
+
font-weight: bold;
|
113
|
+
margin-bottom: 10px;
|
114
|
+
}
|
115
|
+
|
116
|
+
.component-desc {
|
117
|
+
font-size: 14px;
|
118
|
+
}
|
119
|
+
|
120
|
+
.component-item:hover {
|
121
|
+
background-color: #e6e6e6;
|
122
|
+
}
|
99
123
|
</style>
|