@ebiz/designer-components 0.0.30 → 0.0.32
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 -1
- package/dist/index.mjs +21039 -20619
- package/package.json +1 -1
- package/src/components/EbizMap.vue +542 -0
- package/src/components/EbizTableSort.vue +2 -3
- package/src/components/EbizTdesignButtonDialog.vue +12 -30
- package/src/components/TdesignButton.vue +6 -0
- package/src/components/senior/EbizSData/index.vue +228 -0
- package/src/components/senior/EbizSForm/index.vue +385 -0
- package/src/components/senior/EbizSForm/item.vue +478 -0
- package/src/components/senior/EbizSForm/mItems/DateTimePicker.vue +52 -0
- package/src/components/senior/EbizSForm/mItems/Picker.vue +64 -0
- package/src/index.js +10 -3
- package/src/router/index.js +12 -0
- package/src/views/EbizMap.vue +202 -0
- package/src/views/EbizSDataDemo.vue +137 -0
- package/src/views/Home.vue +3 -1
- package/src/components/EbizSForm.vue +0 -398
- package/src/components/EbizSFormItem.vue +0 -587
@@ -0,0 +1,228 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<div>
|
4
|
+
<EbizTdesignCard :bordered="false">
|
5
|
+
<EbizPageHeader></EbizPageHeader>
|
6
|
+
<EbizDivider></EbizDivider>
|
7
|
+
<!-- 表单区域 -->
|
8
|
+
<ebiz-s-form v-model="formDataValue" ref="formRef" layout="inline" labelAlign="top"
|
9
|
+
@submit="handleSearch" @reset="handleReset">
|
10
|
+
<slot name="form"></slot>
|
11
|
+
<template #buttons>
|
12
|
+
<t-space>
|
13
|
+
<EbizTdesignButton theme="primary" type="submit">搜索</EbizTdesignButton>
|
14
|
+
<EbizTdesignButton theme="default" type="reset">重置</EbizTdesignButton>
|
15
|
+
</t-space>
|
16
|
+
</template>
|
17
|
+
</ebiz-s-form>
|
18
|
+
</EbizTdesignCard>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<EbizTdesignCard :bordered="false" style="margin-top: 16px;">
|
22
|
+
<div>
|
23
|
+
<!-- 表格区域 -->
|
24
|
+
<div style="display: flex; justify-content: space-between; align-items: center;">
|
25
|
+
<div style="display: flex; align-items: center;">
|
26
|
+
<slot name="left"></slot>
|
27
|
+
<slot name="search">
|
28
|
+
<div v-if="defaultSearch" style="margin-left: 10px;">
|
29
|
+
<t-input v-model="searchValue" placeholder="请输入搜索内容" @change="handleSearch"></t-input>
|
30
|
+
</div>
|
31
|
+
</slot>
|
32
|
+
</div>
|
33
|
+
<div style="display: flex; align-items: center; justify-content: flex-end;">
|
34
|
+
<slot name="right"></slot>
|
35
|
+
<t-space size="10px">
|
36
|
+
<EbizTdesignButton theme="info" variant="outline" @click="handleSearch">
|
37
|
+
<t-icon name="refresh" />
|
38
|
+
</EbizTdesignButton>
|
39
|
+
<EbizTableSort></EbizTableSort>
|
40
|
+
</t-space>
|
41
|
+
</div>
|
42
|
+
</div>
|
43
|
+
<div style="margin-top: 8px;">
|
44
|
+
<slot :data="data"></slot>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
|
48
|
+
<div v-if="pageEnable" style="margin-top: 16px;">
|
49
|
+
<!-- 分页区域 -->
|
50
|
+
<t-pagination v-model:current="currentPage" v-model:page-size="pageSize" :total="total"
|
51
|
+
:page-size-options="pageSizeOptions" @change="onPageChange" />
|
52
|
+
</div>
|
53
|
+
</EbizTdesignCard>
|
54
|
+
</div>
|
55
|
+
</template>
|
56
|
+
|
57
|
+
<script>
|
58
|
+
/**
|
59
|
+
* @displayName 数据组件
|
60
|
+
* @description 数据组件,用于获取和展示数据列表
|
61
|
+
* @category 数据展示
|
62
|
+
* @name EbizSData
|
63
|
+
*/
|
64
|
+
export default {
|
65
|
+
name: "EbizSData"
|
66
|
+
}
|
67
|
+
</script>
|
68
|
+
|
69
|
+
<script setup>
|
70
|
+
import { defineProps, defineEmits, ref, onMounted, computed } from 'vue';
|
71
|
+
import { dataService, EbizSFormItem, EbizTableSort, EbizTdesignButton, EbizTdesignCard, EbizPageHeader } from "../../../index"
|
72
|
+
import { Button as TButton, Space as TSpace } from 'tdesign-vue-next';
|
73
|
+
|
74
|
+
const currentPage = ref(1)
|
75
|
+
const pageSize = ref(10)
|
76
|
+
const hasMore = ref(true)
|
77
|
+
const refreshing = ref(false)
|
78
|
+
const total = ref(0)
|
79
|
+
const pageSizeOptions = ref([10, 20, 50, 100])
|
80
|
+
|
81
|
+
const data = ref([]);
|
82
|
+
|
83
|
+
const props = defineProps({
|
84
|
+
showPageHeader: {
|
85
|
+
type: Boolean,
|
86
|
+
default: true
|
87
|
+
},
|
88
|
+
defaultSearch: {
|
89
|
+
type: Boolean,
|
90
|
+
default: false
|
91
|
+
},
|
92
|
+
showDivider: {
|
93
|
+
type: Boolean,
|
94
|
+
default: false
|
95
|
+
},
|
96
|
+
pageEnable: {
|
97
|
+
type: Boolean,
|
98
|
+
default: true
|
99
|
+
},
|
100
|
+
defaultParams: {},
|
101
|
+
// 接口配置
|
102
|
+
apiConfig: {
|
103
|
+
type: Object,
|
104
|
+
default: () => ({})
|
105
|
+
},
|
106
|
+
formData: {
|
107
|
+
type: Object,
|
108
|
+
default: () => ({})
|
109
|
+
},
|
110
|
+
labelKey: {
|
111
|
+
type: String,
|
112
|
+
default: 'name'
|
113
|
+
},
|
114
|
+
// 分页大小
|
115
|
+
size: {
|
116
|
+
type: Number,
|
117
|
+
default: 10
|
118
|
+
},
|
119
|
+
/**
|
120
|
+
* 头部内容
|
121
|
+
*/
|
122
|
+
header: {
|
123
|
+
type: String,
|
124
|
+
default: undefined
|
125
|
+
},
|
126
|
+
/**
|
127
|
+
* 底部内容
|
128
|
+
*/
|
129
|
+
footer: {
|
130
|
+
type: String,
|
131
|
+
default: undefined
|
132
|
+
},
|
133
|
+
/**
|
134
|
+
* 是否展示分割线
|
135
|
+
*/
|
136
|
+
split: {
|
137
|
+
type: Boolean,
|
138
|
+
default: true
|
139
|
+
},
|
140
|
+
/**
|
141
|
+
* 是否展示斑马纹
|
142
|
+
*/
|
143
|
+
stripe: {
|
144
|
+
type: Boolean,
|
145
|
+
default: false
|
146
|
+
},
|
147
|
+
/**
|
148
|
+
* 是否开启虚拟滚动
|
149
|
+
*/
|
150
|
+
async: {
|
151
|
+
type: Boolean,
|
152
|
+
default: false
|
153
|
+
},
|
154
|
+
fetchUrl: {
|
155
|
+
type: String,
|
156
|
+
default: undefined
|
157
|
+
}
|
158
|
+
});
|
159
|
+
|
160
|
+
const defaultFormData = ref({ ...props.formData })
|
161
|
+
const searchValue = ref('')
|
162
|
+
|
163
|
+
const loadData = async () => {
|
164
|
+
|
165
|
+
let params = {
|
166
|
+
keyword: searchValue.value
|
167
|
+
}
|
168
|
+
if (props.pageEnable) {
|
169
|
+
params = {
|
170
|
+
page: currentPage.value,
|
171
|
+
pagesize: pageSize.value,
|
172
|
+
}
|
173
|
+
}
|
174
|
+
const res = await dataService.fetch({ ...params, ...props.defaultParams, ...props.formData }, props.apiConfig, props.fetchUrl)
|
175
|
+
|
176
|
+
data.value = res.data || []
|
177
|
+
total.value = res.total || 0
|
178
|
+
|
179
|
+
// 判断是否还有更多数据
|
180
|
+
hasMore.value = (res.data || []).length === pageSize.value
|
181
|
+
refreshing.value = false
|
182
|
+
}
|
183
|
+
|
184
|
+
const emit = defineEmits(['scroll', 'load-more', 'update:formData']);
|
185
|
+
|
186
|
+
// 组件挂载时加载数据
|
187
|
+
onMounted(() => {
|
188
|
+
currentPage.value = 1
|
189
|
+
pageSize.value = props.size
|
190
|
+
loadData()
|
191
|
+
})
|
192
|
+
|
193
|
+
// 搜索
|
194
|
+
const handleSearch = (context) => {
|
195
|
+
const result = emit('search', context)
|
196
|
+
if (result === false) {
|
197
|
+
return
|
198
|
+
}
|
199
|
+
currentPage.value = 1
|
200
|
+
loadData()
|
201
|
+
}
|
202
|
+
|
203
|
+
// 重置
|
204
|
+
const handleReset = (context) => {
|
205
|
+
const result = emit('reset', context)
|
206
|
+
if (result === false) {
|
207
|
+
return
|
208
|
+
}
|
209
|
+
emit('update:formData', { ...defaultFormData.value })
|
210
|
+
currentPage.value = 1
|
211
|
+
loadData()
|
212
|
+
}
|
213
|
+
|
214
|
+
|
215
|
+
const onPageChange = () => {
|
216
|
+
loadData()
|
217
|
+
}
|
218
|
+
|
219
|
+
const formDataValue = computed({
|
220
|
+
get: () => props.formData,
|
221
|
+
set: (value) => {
|
222
|
+
emit('update:formData', value)
|
223
|
+
}
|
224
|
+
})
|
225
|
+
|
226
|
+
</script>
|
227
|
+
|
228
|
+
<style></style>
|
@@ -0,0 +1,385 @@
|
|
1
|
+
<template>
|
2
|
+
<t-form ref="formRef" :class="['ebiz-s-form', className]" :colon="colon" :data="data" :disabled="disabled"
|
3
|
+
:label-align="labelAlign" :label-width="labelWidth" :layout="layout" :reset-type="resetType"
|
4
|
+
:reset-on-semi-controlled="resetOnSemiControlled" :rules="rules" :scroll-to-first-error="scrollToFirstError"
|
5
|
+
:show-error-message="showErrorMessage" :status-icon="statusIcon" :style="customStyle" @reset="handleReset"
|
6
|
+
@submit="handleSubmit" @validate="handleValidate">
|
7
|
+
|
8
|
+
<slot></slot>
|
9
|
+
|
10
|
+
<ebiz-s-form-item label=" ">
|
11
|
+
<slot name="buttons">
|
12
|
+
<t-space>
|
13
|
+
<t-button v-if="showCancelButton" :theme="cancelButtonTheme" type="reset">{{
|
14
|
+
cancelButtonText
|
15
|
+
}}</t-button>
|
16
|
+
<t-button v-if="showSubmitButton" theme="primary" :loading="loading" type="submit">{{
|
17
|
+
submitButtonText }}</t-button>
|
18
|
+
</t-space>
|
19
|
+
</slot>
|
20
|
+
</ebiz-s-form-item>
|
21
|
+
</t-form>
|
22
|
+
</template>
|
23
|
+
|
24
|
+
<script>
|
25
|
+
/**
|
26
|
+
* @displayName PC端表单
|
27
|
+
* @description PC端表单组件,基于TDesign Form封装,支持表单验证、API提交等功能
|
28
|
+
* @category 表单组件
|
29
|
+
* @name EbizSForm
|
30
|
+
*/
|
31
|
+
export default {
|
32
|
+
name: "EbizSForm"
|
33
|
+
}
|
34
|
+
</script>
|
35
|
+
|
36
|
+
<script setup>
|
37
|
+
import { defineProps, defineEmits, ref, reactive, computed } from 'vue';
|
38
|
+
import { Form as TForm, Button as TButton, Space as TSpace, MessagePlugin } from 'tdesign-vue-next';
|
39
|
+
import dataService from "../../../apiService/simpleDataService";
|
40
|
+
import EbizSFormItem from './item.vue';
|
41
|
+
|
42
|
+
const props = defineProps({
|
43
|
+
/**
|
44
|
+
* 表单数据对象
|
45
|
+
*/
|
46
|
+
data: {
|
47
|
+
type: Object,
|
48
|
+
default: () => ({})
|
49
|
+
},
|
50
|
+
/**
|
51
|
+
* 表单域标签的位置
|
52
|
+
* @options left|right|top
|
53
|
+
*/
|
54
|
+
labelAlign: {
|
55
|
+
type: String,
|
56
|
+
default: 'right',
|
57
|
+
validator: (val) => ['left', 'right', 'top'].includes(val)
|
58
|
+
},
|
59
|
+
/**
|
60
|
+
* 表单布局
|
61
|
+
* @options vertical|inline
|
62
|
+
*/
|
63
|
+
layout: {
|
64
|
+
type: String,
|
65
|
+
default: 'vertical',
|
66
|
+
validator: (val) => ['vertical', 'inline'].includes(val)
|
67
|
+
},
|
68
|
+
/**
|
69
|
+
* 是否显示必填标记
|
70
|
+
*/
|
71
|
+
colon: {
|
72
|
+
type: Boolean,
|
73
|
+
default: false
|
74
|
+
},
|
75
|
+
/**
|
76
|
+
* 是否禁用整个表单
|
77
|
+
*/
|
78
|
+
disabled: {
|
79
|
+
type: Boolean,
|
80
|
+
default: false
|
81
|
+
},
|
82
|
+
/**
|
83
|
+
* 表单域标签的宽度
|
84
|
+
*/
|
85
|
+
labelWidth: {
|
86
|
+
type: [String, Number],
|
87
|
+
default: '100px'
|
88
|
+
},
|
89
|
+
/**
|
90
|
+
* 表单校验规则
|
91
|
+
*/
|
92
|
+
rules: {
|
93
|
+
type: Object,
|
94
|
+
default: () => ({})
|
95
|
+
},
|
96
|
+
/**
|
97
|
+
* 是否显示校验错误信息
|
98
|
+
*/
|
99
|
+
showErrorMessage: {
|
100
|
+
type: Boolean,
|
101
|
+
default: true
|
102
|
+
},
|
103
|
+
/**
|
104
|
+
* 是否显示校验图标
|
105
|
+
*/
|
106
|
+
statusIcon: {
|
107
|
+
type: Boolean,
|
108
|
+
default: false
|
109
|
+
},
|
110
|
+
/**
|
111
|
+
* 表单重置时的方式
|
112
|
+
* @options empty|initial
|
113
|
+
*/
|
114
|
+
resetType: {
|
115
|
+
type: String,
|
116
|
+
default: 'empty',
|
117
|
+
validator: (val) => ['empty', 'initial'].includes(val)
|
118
|
+
},
|
119
|
+
/**
|
120
|
+
* 重置时是否清空所有非受控字段
|
121
|
+
*/
|
122
|
+
resetOnSemiControlled: {
|
123
|
+
type: Boolean,
|
124
|
+
default: false
|
125
|
+
},
|
126
|
+
/**
|
127
|
+
* 表单校验不通过时,是否自动定位到第一个错误字段
|
128
|
+
*/
|
129
|
+
scrollToFirstError: {
|
130
|
+
type: Boolean,
|
131
|
+
default: true
|
132
|
+
},
|
133
|
+
/**
|
134
|
+
* 自定义样式
|
135
|
+
*/
|
136
|
+
customStyle: {
|
137
|
+
type: [String, Object],
|
138
|
+
default: ''
|
139
|
+
},
|
140
|
+
/**
|
141
|
+
* 自定义类名
|
142
|
+
*/
|
143
|
+
className: {
|
144
|
+
type: String,
|
145
|
+
default: ''
|
146
|
+
},
|
147
|
+
/**
|
148
|
+
* 是否显示表单按钮(提交和取消)
|
149
|
+
*/
|
150
|
+
showButtons: {
|
151
|
+
type: Boolean,
|
152
|
+
default: true
|
153
|
+
},
|
154
|
+
/**
|
155
|
+
* 是否显示提交按钮
|
156
|
+
*/
|
157
|
+
showSubmitButton: {
|
158
|
+
type: Boolean,
|
159
|
+
default: true
|
160
|
+
},
|
161
|
+
/**
|
162
|
+
* 提交按钮文字
|
163
|
+
*/
|
164
|
+
submitButtonText: {
|
165
|
+
type: String,
|
166
|
+
default: '提交'
|
167
|
+
},
|
168
|
+
/**
|
169
|
+
* 是否显示取消按钮
|
170
|
+
*/
|
171
|
+
showCancelButton: {
|
172
|
+
type: Boolean,
|
173
|
+
default: true
|
174
|
+
},
|
175
|
+
/**
|
176
|
+
* 取消按钮文字
|
177
|
+
*/
|
178
|
+
cancelButtonText: {
|
179
|
+
type: String,
|
180
|
+
default: '取消'
|
181
|
+
},
|
182
|
+
/**
|
183
|
+
* 取消按钮主题
|
184
|
+
*/
|
185
|
+
cancelButtonTheme: {
|
186
|
+
type: String,
|
187
|
+
default: 'default'
|
188
|
+
},
|
189
|
+
/**
|
190
|
+
* API配置,用于表单提交
|
191
|
+
*/
|
192
|
+
apiConfig: {
|
193
|
+
type: Object,
|
194
|
+
default: () => null
|
195
|
+
},
|
196
|
+
/**
|
197
|
+
* 是否在提交成功后重置表单
|
198
|
+
*/
|
199
|
+
resetOnSuccess: {
|
200
|
+
type: Boolean,
|
201
|
+
default: false
|
202
|
+
},
|
203
|
+
/**
|
204
|
+
* 提交成功后的消息提示
|
205
|
+
*/
|
206
|
+
successMessage: {
|
207
|
+
type: String,
|
208
|
+
default: '提交成功'
|
209
|
+
},
|
210
|
+
/**
|
211
|
+
* 提交失败后的消息提示
|
212
|
+
*/
|
213
|
+
errorMessage: {
|
214
|
+
type: String,
|
215
|
+
default: '提交失败'
|
216
|
+
},
|
217
|
+
/**
|
218
|
+
* 是否显示提交结果消息
|
219
|
+
*/
|
220
|
+
showResultMessage: {
|
221
|
+
type: Boolean,
|
222
|
+
default: true
|
223
|
+
}
|
224
|
+
});
|
225
|
+
|
226
|
+
const emit = defineEmits([
|
227
|
+
'reset',
|
228
|
+
'submit',
|
229
|
+
'validate',
|
230
|
+
'success',
|
231
|
+
'error',
|
232
|
+
'cancel'
|
233
|
+
]);
|
234
|
+
|
235
|
+
const formRef = ref(null);
|
236
|
+
const loading = ref(false);
|
237
|
+
|
238
|
+
/**
|
239
|
+
* 提交表单
|
240
|
+
*/
|
241
|
+
const handleFormSubmit = async () => {
|
242
|
+
if (!formRef.value) return;
|
243
|
+
|
244
|
+
const validateResult = await formRef.value.validate();
|
245
|
+
if (validateResult !== true) {
|
246
|
+
return;
|
247
|
+
}
|
248
|
+
|
249
|
+
emit('submit', props.data);
|
250
|
+
|
251
|
+
if (props.apiConfig) {
|
252
|
+
await submitFormData();
|
253
|
+
}
|
254
|
+
};
|
255
|
+
|
256
|
+
/**
|
257
|
+
* 调用API提交表单数据
|
258
|
+
*/
|
259
|
+
const submitFormData = async () => {
|
260
|
+
try {
|
261
|
+
loading.value = true;
|
262
|
+
|
263
|
+
const { url, method, headers, params } = props.apiConfig;
|
264
|
+
const response = await dataService.request({
|
265
|
+
url,
|
266
|
+
method: method || 'post',
|
267
|
+
data: props.data,
|
268
|
+
params,
|
269
|
+
headers
|
270
|
+
});
|
271
|
+
|
272
|
+
if (props.showResultMessage) {
|
273
|
+
MessagePlugin.success(props.successMessage);
|
274
|
+
}
|
275
|
+
|
276
|
+
emit('success', response);
|
277
|
+
|
278
|
+
if (props.resetOnSuccess && formRef.value) {
|
279
|
+
formRef.value.reset();
|
280
|
+
}
|
281
|
+
|
282
|
+
return response;
|
283
|
+
} catch (error) {
|
284
|
+
if (props.showResultMessage) {
|
285
|
+
MessagePlugin.error(props.errorMessage || error.message || '提交失败');
|
286
|
+
}
|
287
|
+
|
288
|
+
emit('error', error);
|
289
|
+
return null;
|
290
|
+
} finally {
|
291
|
+
loading.value = false;
|
292
|
+
}
|
293
|
+
};
|
294
|
+
|
295
|
+
/**
|
296
|
+
* 表单重置
|
297
|
+
* @param {Object} context 表单上下文
|
298
|
+
*/
|
299
|
+
const handleReset = (context) => {
|
300
|
+
console.log('handleReset', context);
|
301
|
+
emit('reset', context);
|
302
|
+
};
|
303
|
+
|
304
|
+
/**
|
305
|
+
* 表单验证
|
306
|
+
* @param {Object} result 表单验证结果
|
307
|
+
*/
|
308
|
+
const handleValidate = (result) => {
|
309
|
+
emit('validate', result);
|
310
|
+
};
|
311
|
+
|
312
|
+
|
313
|
+
/**
|
314
|
+
* 表单提交事件,由内置的HTML表单submit事件触发
|
315
|
+
*/
|
316
|
+
const handleSubmit = (context) => {
|
317
|
+
console.log('handleSubmit', context);
|
318
|
+
|
319
|
+
// 这里只做转发,实际提交逻辑在handleFormSubmit中
|
320
|
+
emit('submit', context);
|
321
|
+
};
|
322
|
+
|
323
|
+
// 暴露方法给父组件
|
324
|
+
defineExpose({
|
325
|
+
/**
|
326
|
+
* 提交表单方法
|
327
|
+
*/
|
328
|
+
submit: handleFormSubmit,
|
329
|
+
/**
|
330
|
+
* 重置表单方法
|
331
|
+
*/
|
332
|
+
reset: () => {
|
333
|
+
if (formRef.value) {
|
334
|
+
formRef.value.reset();
|
335
|
+
}
|
336
|
+
},
|
337
|
+
/**
|
338
|
+
* 校验表单方法
|
339
|
+
* @returns {Promise} 校验结果Promise
|
340
|
+
*/
|
341
|
+
validate: async () => {
|
342
|
+
if (formRef.value) {
|
343
|
+
return await formRef.value.validate();
|
344
|
+
}
|
345
|
+
return false;
|
346
|
+
},
|
347
|
+
/**
|
348
|
+
* 校验特定字段
|
349
|
+
* @param {Array|String} fields 字段名称或字段名称数组
|
350
|
+
* @returns {Promise} 校验结果Promise
|
351
|
+
*/
|
352
|
+
validateFields: async (fields) => {
|
353
|
+
if (formRef.value) {
|
354
|
+
return await formRef.value.validateFields(fields);
|
355
|
+
}
|
356
|
+
return false;
|
357
|
+
},
|
358
|
+
/**
|
359
|
+
* 清除校验结果
|
360
|
+
* @param {Array|String} fields 字段名称或字段名称数组,不传则清除所有
|
361
|
+
*/
|
362
|
+
clearValidate: (fields) => {
|
363
|
+
if (formRef.value) {
|
364
|
+
formRef.value.clearValidate(fields);
|
365
|
+
}
|
366
|
+
},
|
367
|
+
/**
|
368
|
+
* 获取表单DOM元素
|
369
|
+
*/
|
370
|
+
getFormElement: () => formRef.value
|
371
|
+
});
|
372
|
+
</script>
|
373
|
+
|
374
|
+
<style scoped>
|
375
|
+
.ebiz-s-form {
|
376
|
+
width: 100%;
|
377
|
+
}
|
378
|
+
|
379
|
+
.form-buttons {
|
380
|
+
margin-top: 24px;
|
381
|
+
padding: 8px 0;
|
382
|
+
display: flex;
|
383
|
+
justify-content: center;
|
384
|
+
}
|
385
|
+
</style>
|