@ebiz/designer-components 0.0.18-beta.1 → 0.0.18-beta.10
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/package.json +1 -1
- package/src/apiService/mockDataService.js +116 -0
- package/src/apiService/simpleDataService.js +133 -131
- package/src/components/Button.vue +3 -2
- package/src/components/EbizAvatar.vue +116 -0
- package/src/components/EbizEmployeeInfo.vue +139 -0
- package/src/components/EbizRemoteSelect.vue +99 -41
- package/src/components/EbizStatistic.vue +150 -0
- package/src/components/EbizTabHeader.vue +6 -10
- package/src/components/EbizTabPanel.vue +23 -0
- package/src/components/EbizTabs.vue +143 -0
- package/src/components/TdesignAlert.vue +116 -0
- package/src/components/TdesignCalendar/index.vue +6 -3
- package/src/components/TdesignDialog.vue +221 -0
- package/src/components/TdesignInput.vue +23 -23
- package/src/components/TdesignTimeline.vue +58 -0
- package/src/components/TdesignTimelineItem.vue +72 -0
- package/src/components/TdesignUpload.vue +67 -98
- package/src/components/TdesignWatermark.vue +108 -0
- package/src/index.js +79 -45
- package/src/main.js +2 -2
- package/src/router/index.js +48 -0
- package/src/views/DialogDemo.vue +126 -0
- package/src/views/EbizAvatar.vue +224 -0
- package/src/views/EbizEmployeeInfo.vue +250 -0
- package/src/views/Home.vue +9 -1
- package/src/views/RemoteSelect.vue +336 -5
- package/src/views/StatisticDemo.vue +191 -0
- package/src/views/TabsDemo.vue +283 -0
- package/src/views/TdesignAlert.vue +99 -0
- package/src/views/TimelineDemo.vue +161 -0
- package/src/views/WatermarkDemo.vue +86 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
<template>
|
2
|
+
<div class="ebiz-employee-info" :style="customStyle">
|
3
|
+
<div class="employee-avatar">
|
4
|
+
<ebiz-avatar
|
5
|
+
:image="employeeInfo.avatar"
|
6
|
+
:content="avatarContent"
|
7
|
+
:size="avatarSize"
|
8
|
+
:shape="avatarShape"
|
9
|
+
:alt="employeeInfo.name"
|
10
|
+
@error="handleAvatarError"
|
11
|
+
/>
|
12
|
+
</div>
|
13
|
+
<div class="employee-details">
|
14
|
+
<div class="employee-name">{{ employeeInfo.name }}</div>
|
15
|
+
<div class="employee-id" v-if="employeeInfo.id">ID: {{ employeeInfo.id }}</div>
|
16
|
+
<div class="employee-department" v-if="employeeInfo.department">{{ employeeInfo.department }}</div>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
</template>
|
20
|
+
|
21
|
+
<script>
|
22
|
+
export default {
|
23
|
+
name: "EbizEmployeeInfo"
|
24
|
+
}
|
25
|
+
</script>
|
26
|
+
|
27
|
+
<script setup>
|
28
|
+
import { computed, defineProps, defineEmits } from 'vue';
|
29
|
+
import EbizAvatar from './EbizAvatar.vue';
|
30
|
+
|
31
|
+
const props = defineProps({
|
32
|
+
// 员工信息对象,包含头像、名称、工号、部门
|
33
|
+
info: {
|
34
|
+
type: Object,
|
35
|
+
required: true,
|
36
|
+
default: () => ({
|
37
|
+
avatar: '',
|
38
|
+
name: '',
|
39
|
+
id: '',
|
40
|
+
department: ''
|
41
|
+
})
|
42
|
+
},
|
43
|
+
// 头像尺寸
|
44
|
+
avatarSize: {
|
45
|
+
type: String,
|
46
|
+
default: 'medium',
|
47
|
+
validator: (val) => ['small', 'medium', 'large'].includes(val) || /^(\d+px|\d+em|\d+rem|\d+%)$/.test(val)
|
48
|
+
},
|
49
|
+
// 头像形状
|
50
|
+
avatarShape: {
|
51
|
+
type: String,
|
52
|
+
default: 'circle',
|
53
|
+
validator: (val) => ['circle', 'round'].includes(val)
|
54
|
+
},
|
55
|
+
// 自定义宽度
|
56
|
+
width: {
|
57
|
+
type: [String, Number],
|
58
|
+
default: ''
|
59
|
+
},
|
60
|
+
// 自定义高度
|
61
|
+
height: {
|
62
|
+
type: [String, Number],
|
63
|
+
default: ''
|
64
|
+
}
|
65
|
+
});
|
66
|
+
|
67
|
+
const emit = defineEmits(['avatar-error']);
|
68
|
+
|
69
|
+
// 从props获取员工信息,提供默认值
|
70
|
+
const employeeInfo = computed(() => {
|
71
|
+
return {
|
72
|
+
avatar: props.info.avatar || '',
|
73
|
+
name: props.info.name || '未知',
|
74
|
+
id: props.info.id || '',
|
75
|
+
department: props.info.department || ''
|
76
|
+
};
|
77
|
+
});
|
78
|
+
|
79
|
+
// 生成头像内容(当没有提供头像图片时使用员工姓名首字母)
|
80
|
+
const avatarContent = computed(() => {
|
81
|
+
if (employeeInfo.value.name) {
|
82
|
+
return employeeInfo.value.name.charAt(0);
|
83
|
+
}
|
84
|
+
return '';
|
85
|
+
});
|
86
|
+
|
87
|
+
// 处理头像加载错误
|
88
|
+
const handleAvatarError = (context) => {
|
89
|
+
emit('avatar-error', context);
|
90
|
+
};
|
91
|
+
|
92
|
+
// 计算自定义样式
|
93
|
+
const customStyle = computed(() => {
|
94
|
+
const style = {};
|
95
|
+
if (props.width) {
|
96
|
+
style.width = typeof props.width === 'number' ? `${props.width}px` : props.width;
|
97
|
+
}
|
98
|
+
if (props.height) {
|
99
|
+
style.height = typeof props.height === 'number' ? `${props.height}px` : props.height;
|
100
|
+
}
|
101
|
+
return style;
|
102
|
+
});
|
103
|
+
</script>
|
104
|
+
|
105
|
+
<style lang="less" scoped>
|
106
|
+
.ebiz-employee-info {
|
107
|
+
display: flex;
|
108
|
+
align-items: center;
|
109
|
+
|
110
|
+
.employee-avatar {
|
111
|
+
margin-right: 16px;
|
112
|
+
}
|
113
|
+
|
114
|
+
.employee-details {
|
115
|
+
flex: 1;
|
116
|
+
display: flex;
|
117
|
+
flex-direction: column;
|
118
|
+
justify-content: center;
|
119
|
+
}
|
120
|
+
|
121
|
+
.employee-name {
|
122
|
+
font-size: 16px;
|
123
|
+
font-weight: 600;
|
124
|
+
color: #333;
|
125
|
+
margin-bottom: 4px;
|
126
|
+
}
|
127
|
+
|
128
|
+
.employee-id {
|
129
|
+
font-size: 13px;
|
130
|
+
color: #666;
|
131
|
+
margin-bottom: 2px;
|
132
|
+
}
|
133
|
+
|
134
|
+
.employee-department {
|
135
|
+
font-size: 13px;
|
136
|
+
color: #666;
|
137
|
+
}
|
138
|
+
}
|
139
|
+
</style>
|
@@ -1,14 +1,15 @@
|
|
1
1
|
<template>
|
2
|
-
<
|
3
|
-
|
4
|
-
:disabled="disabled"
|
5
|
-
|
2
|
+
<t-select ref="selectRef" v-model="selectedValue" :options="options" :loading="loading" :filterable="true"
|
3
|
+
@search="handleRemoteSearch" :multiple="multiple" :placeholder="placeholder" :clearable="clearable"
|
4
|
+
:disabled="disabled" :size="size" :empty="emptyText" :popupProps="popupProps" @change="handleChange"
|
5
|
+
@focus="handleFocus" @blur="handleBlur">
|
6
|
+
<template #prefixIcon v-if="$slots.prefix">
|
6
7
|
<slot name="prefix"></slot>
|
7
8
|
</template>
|
8
|
-
<template #suffix>
|
9
|
+
<template #suffixIcon v-if="$slots.suffix">
|
9
10
|
<slot name="suffix"></slot>
|
10
11
|
</template>
|
11
|
-
</
|
12
|
+
</t-select>
|
12
13
|
</template>
|
13
14
|
|
14
15
|
<script>
|
@@ -19,8 +20,8 @@ export default {
|
|
19
20
|
|
20
21
|
<script setup>
|
21
22
|
import { ref, onMounted, toRefs, computed } from 'vue';
|
22
|
-
import { Select as
|
23
|
-
import dataService from
|
23
|
+
import { Select as TSelect } from 'tdesign-vue-next';
|
24
|
+
import dataService from '../apiService/simpleDataServiceAppData';
|
24
25
|
|
25
26
|
const props = defineProps({
|
26
27
|
/**
|
@@ -30,6 +31,7 @@ const props = defineProps({
|
|
30
31
|
type: Object,
|
31
32
|
required: true,
|
32
33
|
default: () => ({
|
34
|
+
key: null,
|
33
35
|
apiId: null,
|
34
36
|
apiType: ''
|
35
37
|
})
|
@@ -39,7 +41,7 @@ const props = defineProps({
|
|
39
41
|
*/
|
40
42
|
queryParams: {
|
41
43
|
type: Object,
|
42
|
-
default: {}
|
44
|
+
default: () => ({})
|
43
45
|
},
|
44
46
|
/**
|
45
47
|
* 是否多选
|
@@ -73,21 +75,54 @@ const props = defineProps({
|
|
73
75
|
* 默认值
|
74
76
|
*/
|
75
77
|
modelValue: {
|
76
|
-
type: [String, Number],
|
78
|
+
type: [String, Number, Array],
|
77
79
|
default: ''
|
78
80
|
},
|
81
|
+
/**
|
82
|
+
* 选项配置
|
83
|
+
*/
|
79
84
|
optionsConfig: {
|
80
|
-
|
81
|
-
|
85
|
+
type: Object,
|
86
|
+
default: () => ({
|
87
|
+
labelField: '',
|
88
|
+
valueField: ''
|
89
|
+
})
|
90
|
+
},
|
91
|
+
/**
|
92
|
+
* 组件尺寸
|
93
|
+
*/
|
94
|
+
size: {
|
95
|
+
type: String,
|
96
|
+
default: 'medium',
|
97
|
+
validator: (val) => ['small', 'medium', 'large'].includes(val)
|
98
|
+
},
|
99
|
+
/**
|
100
|
+
* 空数据文本
|
101
|
+
*/
|
102
|
+
emptyText: {
|
103
|
+
type: String,
|
104
|
+
default: '暂无数据'
|
105
|
+
},
|
106
|
+
/**
|
107
|
+
* 弹出层配置
|
108
|
+
*/
|
109
|
+
popupProps: {
|
110
|
+
type: Object,
|
111
|
+
default: () => ({})
|
82
112
|
}
|
83
113
|
});
|
84
114
|
|
85
115
|
const { modelValue, apiConfig, queryParams } = toRefs(props)
|
86
116
|
|
87
|
-
const emit = defineEmits(['update:modelValue', 'change']);
|
117
|
+
const emit = defineEmits(['update:modelValue', 'change', 'focus', 'blur']);
|
88
118
|
|
89
119
|
// 选中的值
|
90
|
-
const selectedValue = computed(
|
120
|
+
const selectedValue = computed({
|
121
|
+
get: () => modelValue.value,
|
122
|
+
set: (val) => {
|
123
|
+
emit('update:modelValue', val);
|
124
|
+
}
|
125
|
+
});
|
91
126
|
|
92
127
|
// 选项列表
|
93
128
|
const options = ref([]);
|
@@ -104,37 +139,55 @@ const focus = () => {
|
|
104
139
|
};
|
105
140
|
|
106
141
|
defineExpose({
|
107
|
-
focus
|
142
|
+
focus,
|
143
|
+
selectRef
|
108
144
|
});
|
109
145
|
|
110
146
|
// 远程搜索处理函数
|
111
|
-
const handleRemoteSearch = async () => {
|
112
|
-
//if (options.value?.length > 0) return
|
113
|
-
|
147
|
+
const handleRemoteSearch = async (keyword) => {
|
114
148
|
loading.value = true;
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
149
|
+
console.log('handleRemoteSearch', keyword);
|
150
|
+
try {
|
151
|
+
const params = {
|
152
|
+
queryParams: {
|
153
|
+
...queryParams.value,
|
154
|
+
keyword
|
155
|
+
}
|
156
|
+
};
|
157
|
+
const res = await dataService.fetch(params, props.apiConfig);
|
158
|
+
const { labelField, valueField } = props.optionsConfig;
|
159
|
+
|
160
|
+
options.value = res.data.map(item => ({
|
161
|
+
label: labelField ? item[labelField] : (item.label || item.name),
|
162
|
+
value: valueField ? item[valueField] : (item.value || item.id)
|
163
|
+
}));
|
164
|
+
} catch (error) {
|
165
|
+
console.error('远程搜索失败:', error);
|
166
|
+
options.value = [];
|
167
|
+
} finally {
|
168
|
+
loading.value = false;
|
169
|
+
}
|
170
|
+
|
171
|
+
};
|
172
|
+
|
173
|
+
// 处理获取焦点事件
|
174
|
+
const handleFocus = (value, context) => {
|
175
|
+
emit('focus', value, context);
|
176
|
+
// 当选项为空时,初始加载数据
|
177
|
+
if (options.value.length === 0) {
|
178
|
+
handleRemoteSearch('');
|
131
179
|
}
|
132
180
|
};
|
133
181
|
|
182
|
+
// 处理失去焦点事件
|
183
|
+
const handleBlur = (value, context) => {
|
184
|
+
emit('blur', value, context);
|
185
|
+
};
|
186
|
+
|
134
187
|
// 值变化处理函数
|
135
|
-
const handleChange = (value) => {
|
188
|
+
const handleChange = (value, context) => {
|
136
189
|
emit('update:modelValue', value);
|
137
|
-
emit('change', value);
|
190
|
+
emit('change', value, context);
|
138
191
|
};
|
139
192
|
|
140
193
|
// 组件挂载时,如果有默认值则加载对应的选项
|
@@ -145,10 +198,16 @@ onMounted(async () => {
|
|
145
198
|
const params = {
|
146
199
|
queryParams: queryParams.value
|
147
200
|
};
|
148
|
-
const res = await dataService.fetch(params, {
|
201
|
+
const res = await dataService.fetch(params, {
|
202
|
+
key: props.apiConfig.key,
|
203
|
+
apiId: props.apiConfig.apiId,
|
204
|
+
apiType: 'MULTIPLE_DATA_SEARCH'
|
205
|
+
});
|
206
|
+
const { labelField, valueField } = props.optionsConfig;
|
207
|
+
|
149
208
|
options.value = res.data.map(item => ({
|
150
|
-
label: item.label || item.name,
|
151
|
-
value: item.value || item.id
|
209
|
+
label: labelField ? item[labelField] : (item.label || item.name),
|
210
|
+
value: valueField ? item[valueField] : (item.value || item.id)
|
152
211
|
}));
|
153
212
|
} catch (error) {
|
154
213
|
console.error('加载默认选项失败:', error);
|
@@ -156,12 +215,11 @@ onMounted(async () => {
|
|
156
215
|
loading.value = false;
|
157
216
|
}
|
158
217
|
}
|
159
|
-
|
160
218
|
});
|
161
219
|
</script>
|
162
220
|
|
163
221
|
<style scoped>
|
164
|
-
.
|
222
|
+
.t-select {
|
165
223
|
width: 100%;
|
166
224
|
}
|
167
225
|
</style>
|
@@ -0,0 +1,150 @@
|
|
1
|
+
<template>
|
2
|
+
<t-statistic
|
3
|
+
ref="statisticRef"
|
4
|
+
:animation="animation"
|
5
|
+
:animation-start="animationStart"
|
6
|
+
:color="color"
|
7
|
+
:decimalPlaces="decimalPlaces"
|
8
|
+
:loading="loading"
|
9
|
+
:prefix="prefix"
|
10
|
+
:suffix="suffix"
|
11
|
+
:title="title"
|
12
|
+
:trend="trend"
|
13
|
+
:trend-placement="trendPlacement"
|
14
|
+
:unit="unit"
|
15
|
+
:value="value"
|
16
|
+
@click="handleClick"
|
17
|
+
>
|
18
|
+
<!-- 加载中状态插槽 -->
|
19
|
+
<template v-if="$slots.loading" #loading>
|
20
|
+
<slot name="loading"></slot>
|
21
|
+
</template>
|
22
|
+
|
23
|
+
<!-- 前缀插槽 -->
|
24
|
+
<template v-if="$slots.prefix" #prefix>
|
25
|
+
<slot name="prefix"></slot>
|
26
|
+
</template>
|
27
|
+
|
28
|
+
<!-- 后缀插槽 -->
|
29
|
+
<template v-if="$slots.suffix" #suffix>
|
30
|
+
<slot name="suffix"></slot>
|
31
|
+
</template>
|
32
|
+
|
33
|
+
<!-- 标题插槽 -->
|
34
|
+
<template v-if="$slots.title" #title>
|
35
|
+
<slot name="title"></slot>
|
36
|
+
</template>
|
37
|
+
|
38
|
+
<!-- 趋势插槽 -->
|
39
|
+
<template v-if="$slots.trend" #trend>
|
40
|
+
<slot name="trend"></slot>
|
41
|
+
</template>
|
42
|
+
|
43
|
+
<!-- 单位插槽 -->
|
44
|
+
<template v-if="$slots.unit" #unit>
|
45
|
+
<slot name="unit"></slot>
|
46
|
+
</template>
|
47
|
+
|
48
|
+
<!-- 默认插槽 -->
|
49
|
+
<slot></slot>
|
50
|
+
</t-statistic>
|
51
|
+
</template>
|
52
|
+
|
53
|
+
<script>
|
54
|
+
export default {
|
55
|
+
name: "EbizStatistic"
|
56
|
+
}
|
57
|
+
</script>
|
58
|
+
|
59
|
+
<script setup>
|
60
|
+
import { defineProps, defineEmits, ref, onMounted } from 'vue';
|
61
|
+
import { Statistic as TStatistic } from 'tdesign-vue-next';
|
62
|
+
|
63
|
+
const props = defineProps({
|
64
|
+
// 数值动画配置
|
65
|
+
animation: {
|
66
|
+
type: Object,
|
67
|
+
default: () => ({}),
|
68
|
+
},
|
69
|
+
// 数值动画开始时间,单位:毫秒
|
70
|
+
animationStart: {
|
71
|
+
type: Boolean,
|
72
|
+
default: false,
|
73
|
+
},
|
74
|
+
// 颜色
|
75
|
+
color: {
|
76
|
+
type: String,
|
77
|
+
default: '',
|
78
|
+
},
|
79
|
+
// 小数位数
|
80
|
+
decimalPlaces: {
|
81
|
+
type: Number,
|
82
|
+
default: 0,
|
83
|
+
},
|
84
|
+
// 加载中状态
|
85
|
+
loading: {
|
86
|
+
type: Boolean,
|
87
|
+
default: false,
|
88
|
+
},
|
89
|
+
// 前缀内容
|
90
|
+
prefix: {
|
91
|
+
type: [String, Function],
|
92
|
+
default: '',
|
93
|
+
},
|
94
|
+
// 后缀内容
|
95
|
+
suffix: {
|
96
|
+
type: [String, Function],
|
97
|
+
default: '',
|
98
|
+
},
|
99
|
+
// 数值显示的标题
|
100
|
+
title: {
|
101
|
+
type: [String, Function],
|
102
|
+
default: '',
|
103
|
+
},
|
104
|
+
// 趋势
|
105
|
+
trend: {
|
106
|
+
type: String,
|
107
|
+
default: '',
|
108
|
+
validator: (val) => ['', 'increase', 'decrease'].includes(val)
|
109
|
+
},
|
110
|
+
// 趋势展示位置
|
111
|
+
trendPlacement: {
|
112
|
+
type: String,
|
113
|
+
default: 'left',
|
114
|
+
validator: (val) => ['left', 'right'].includes(val)
|
115
|
+
},
|
116
|
+
// 单位内容
|
117
|
+
unit: {
|
118
|
+
type: [String, Function],
|
119
|
+
default: '',
|
120
|
+
},
|
121
|
+
// 数值
|
122
|
+
value: {
|
123
|
+
type: Number,
|
124
|
+
default: 0,
|
125
|
+
},
|
126
|
+
});
|
127
|
+
|
128
|
+
const emit = defineEmits(['click']);
|
129
|
+
|
130
|
+
// 引用实例,用于调用组件的start方法
|
131
|
+
const statisticRef = ref(null);
|
132
|
+
|
133
|
+
// 点击事件
|
134
|
+
const handleClick = (e) => {
|
135
|
+
emit('click', e);
|
136
|
+
};
|
137
|
+
|
138
|
+
// 暴露start方法,用于手动开始动画
|
139
|
+
defineExpose({
|
140
|
+
start: () => {
|
141
|
+
if (statisticRef.value) {
|
142
|
+
statisticRef.value.start();
|
143
|
+
}
|
144
|
+
}
|
145
|
+
});
|
146
|
+
</script>
|
147
|
+
|
148
|
+
<style lang="less" scoped>
|
149
|
+
/* 自定义样式 */
|
150
|
+
</style>
|
@@ -1,12 +1,7 @@
|
|
1
1
|
<template>
|
2
2
|
<tiny-tabs v-model="showTab" :tab-style="props.tabStyle" activeColor="#5e7ce0" @click="tabChange">
|
3
|
-
<tiny-tab-item
|
4
|
-
|
5
|
-
v-for="i in showTabs"
|
6
|
-
:key="i.value"
|
7
|
-
:title="i.label"
|
8
|
-
:name="i.value.toString()"
|
9
|
-
/>
|
3
|
+
<tiny-tab-item activeColor="#5e7ce0" v-for="i in showTabs" :key="i.value" :title="i.label"
|
4
|
+
:name="i.value.toString()" />
|
10
5
|
</tiny-tabs>
|
11
6
|
</template>
|
12
7
|
|
@@ -22,6 +17,7 @@ const props = defineProps({
|
|
22
17
|
apiConfig: {
|
23
18
|
type: Object,
|
24
19
|
default: () => ({
|
20
|
+
key: null,
|
25
21
|
apiId: null,
|
26
22
|
apiType: 'MULTIPLE_DATA_SEARCH',
|
27
23
|
}),
|
@@ -63,7 +59,7 @@ const remoteTabs = ref([])
|
|
63
59
|
|
64
60
|
// 展示的tabs
|
65
61
|
const showTabs = computed(() => {
|
66
|
-
|
62
|
+
console.log(props.tabs, 66, 110)
|
67
63
|
if (remoteTabs.value.length) return [{ label: '全部', value: '0' }, ...remoteTabs.value];
|
68
64
|
if (props.tabs.length) return props.tabs
|
69
65
|
return [{ label: '全部', value: '0' }]
|
@@ -87,7 +83,7 @@ watch(() => showTabs.value, () => {
|
|
87
83
|
|
88
84
|
watch(() => props.apiConfig, (nVal) => {
|
89
85
|
if (!nVal?.apiId) return
|
90
|
-
dataService.fetch({
|
86
|
+
dataService.fetch({}, { key: nVal.key, apiId: nVal.apiId, apiType: 'MULTIPLE_DATA_SEARCH' }).then(res => {
|
91
87
|
remoteTabs.value = (res.data ?? []).map(i => ({
|
92
88
|
label: i[props.labelKey],
|
93
89
|
value: i[props.valueKey],
|
@@ -146,4 +142,4 @@ watch(() => props.apiConfig, (nVal) => {
|
|
146
142
|
overflow: hidden;
|
147
143
|
white-space: nowrap;
|
148
144
|
}
|
149
|
-
</style>
|
145
|
+
</style>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<template>
|
2
|
+
<tab-panel
|
3
|
+
:value="value"
|
4
|
+
:label="label"
|
5
|
+
:disabled="disabled"
|
6
|
+
:removable="removable"
|
7
|
+
:destroyOnHide="destroyOnHide"
|
8
|
+
:draggable="draggable"
|
9
|
+
@remove="handleRemove"
|
10
|
+
>
|
11
|
+
<slot></slot>
|
12
|
+
</tab-panel>
|
13
|
+
</template>
|
14
|
+
|
15
|
+
<script>
|
16
|
+
import { TabPanel } from 'tdesign-vue-next';
|
17
|
+
|
18
|
+
export default TabPanel;
|
19
|
+
</script>
|
20
|
+
|
21
|
+
<style lang="less" scoped>
|
22
|
+
/* 自定义样式 */
|
23
|
+
</style>
|