@ebiz/designer-components 0.0.25 → 0.0.27

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.
@@ -0,0 +1,360 @@
1
+ <template>
2
+ <div class="ebiz-tdesign-button-dialog">
3
+ <t-button
4
+ :theme="buttonTheme"
5
+ :variant="buttonVariant"
6
+ :size="buttonSize"
7
+ :block="buttonBlock"
8
+ :shape="buttonShape"
9
+ :disabled="buttonDisabled"
10
+ :loading="buttonLoading"
11
+ :icon="buttonIcon"
12
+ @click="handleButtonClick"
13
+ >
14
+ <template v-if="$slots.buttonContent">
15
+ <slot name="buttonContent"></slot>
16
+ </template>
17
+ <template v-else>
18
+ {{ buttonText }}
19
+ </template>
20
+ </t-button>
21
+
22
+ <t-dialog
23
+ v-model:visible="dialogVisible"
24
+ :header="title || computedTitle"
25
+ :width="dialogWidth"
26
+ :top="dialogTop"
27
+ :attach="dialogAttach"
28
+ :destroy-on-close="dialogDestroyOnClose"
29
+ :mode="dialogMode"
30
+ :placement="dialogPlacement"
31
+ :show-overlay="dialogShowOverlay"
32
+ :close-on-esc-keydown="dialogCloseOnEscKeydown"
33
+ :close-on-overlay-click="dialogCloseOnOverlayClick"
34
+ :show-footer="dialogShowFooter"
35
+ @close="handleDialogClose"
36
+ @confirm="handleDialogConfirm"
37
+ @cancel="handleDialogCancel"
38
+ >
39
+ <template #header>
40
+ <slot name="header">
41
+ <div :class="['dialog-header', dialogType === 'delete' ? 'dialog-header-delete' : '']">
42
+ {{ title || computedTitle }}
43
+ </div>
44
+ </slot>
45
+ </template>
46
+
47
+ <template #body>
48
+ <slot name="body">
49
+ <div v-if="dialogType === 'delete'" class="delete-confirm-content">
50
+ <t-icon name="error-circle" size="large" class="delete-icon" />
51
+ <p class="delete-message">{{ deleteConfirmMessage }}</p>
52
+ </div>
53
+ </slot>
54
+ </template>
55
+
56
+ <template #footer>
57
+ <slot name="footer">
58
+ <t-space>
59
+ <t-button v-if="cancelText" theme="default" @click="handleDialogCancel">{{ cancelText }}</t-button>
60
+ <t-button v-if="confirmText" theme="primary" :loading="apiLoading" @click="handleDialogConfirm">{{ confirmText }}</t-button>
61
+ </t-space>
62
+ </slot>
63
+ </template>
64
+ </t-dialog>
65
+ </div>
66
+ </template>
67
+
68
+ <script setup>
69
+ import { ref, computed, watch } from 'vue'
70
+ import { Button as TButton, Dialog as TDialog, Space as TSpace, MessagePlugin, Icon as TIcon } from 'tdesign-vue-next'
71
+ import dataService from '../apiService/simpleDataService'
72
+
73
+ const props = defineProps({
74
+ // 弹窗类型
75
+ dialogType: {
76
+ type: String,
77
+ default: 'normal', // 'normal', 'add', 'delete'
78
+ validator: (value) => ['normal', 'add', 'delete'].includes(value)
79
+ },
80
+
81
+ // 删除确认消息
82
+ deleteConfirmMessage: {
83
+ type: String,
84
+ default: '确定要删除该数据吗?此操作不可逆,请谨慎操作。'
85
+ },
86
+
87
+ // 按钮基础属性
88
+ buttonText: {
89
+ type: String,
90
+ default: ''
91
+ },
92
+ // 按钮样式属性
93
+ buttonTheme: {
94
+ type: String,
95
+ default: ''
96
+ },
97
+ buttonVariant: {
98
+ type: String,
99
+ default: 'base'
100
+ },
101
+ buttonSize: {
102
+ type: String,
103
+ default: 'medium'
104
+ },
105
+ buttonBlock: {
106
+ type: Boolean,
107
+ default: false
108
+ },
109
+ buttonShape: {
110
+ type: String,
111
+ default: 'rectangle'
112
+ },
113
+ buttonDisabled: {
114
+ type: Boolean,
115
+ default: false
116
+ },
117
+ buttonLoading: {
118
+ type: Boolean,
119
+ default: false
120
+ },
121
+ buttonIcon: {
122
+ type: String,
123
+ default: ''
124
+ },
125
+
126
+ // 弹窗基础属性
127
+ title: {
128
+ type: String,
129
+ default: ''
130
+ },
131
+ visible: {
132
+ type: Boolean,
133
+ default: false
134
+ },
135
+ confirmText: {
136
+ type: String,
137
+ default: undefined
138
+ },
139
+ cancelText: {
140
+ type: String,
141
+ default: undefined
142
+ },
143
+
144
+ // 弹窗样式和行为属性
145
+ dialogWidth: {
146
+ type: [String, Number],
147
+ default: '500px'
148
+ },
149
+ dialogTop: {
150
+ type: [String, Number],
151
+ default: '15vh'
152
+ },
153
+ dialogAttach: {
154
+ type: [String, Function],
155
+ default: 'body'
156
+ },
157
+ dialogDestroyOnClose: {
158
+ type: Boolean,
159
+ default: false
160
+ },
161
+ dialogMode: {
162
+ type: String,
163
+ default: 'modal'
164
+ },
165
+ dialogPlacement: {
166
+ type: String,
167
+ default: 'top'
168
+ },
169
+ dialogShowOverlay: {
170
+ type: Boolean,
171
+ default: true
172
+ },
173
+ dialogCloseOnEscKeydown: {
174
+ type: Boolean,
175
+ default: true
176
+ },
177
+ dialogCloseOnOverlayClick: {
178
+ type: Boolean,
179
+ default: true
180
+ },
181
+ dialogShowFooter: {
182
+ type: Boolean,
183
+ default: true
184
+ },
185
+
186
+ // API配置
187
+ apiConfig: {
188
+ type: Object,
189
+ default: () => null
190
+ },
191
+ // 是否在API调用成功后自动关闭弹窗
192
+ closeOnSuccess: {
193
+ type: Boolean,
194
+ default: true
195
+ },
196
+ // 是否显示API调用的结果消息
197
+ showResultMessage: {
198
+ type: Boolean,
199
+ default: true
200
+ }
201
+ })
202
+
203
+ const emit = defineEmits([
204
+ 'update:modelValue',
205
+ 'button-click',
206
+ 'dialog-close',
207
+ 'dialog-confirm',
208
+ 'dialog-cancel',
209
+ 'api-success',
210
+ 'api-error'
211
+ ])
212
+
213
+ const computedTitle = computed(() => {
214
+ switch (props.dialogType) {
215
+ case 'add': return '添加数据';
216
+ case 'delete': return '删除确认';
217
+ default: return '标题';
218
+ }
219
+ })
220
+
221
+ // 初始化dialogVisible
222
+ const dialogVisible = ref(props.visible)
223
+ const apiLoading = ref(false)
224
+
225
+ // 监听props的visible变化
226
+ watch(() => props.visible, (newVal) => {
227
+ dialogVisible.value = newVal
228
+ })
229
+
230
+ // 监听dialogVisible变化,同步更新modelValue
231
+ watch(dialogVisible, (newVal) => {
232
+ emit('update:modelValue', newVal)
233
+ })
234
+
235
+ // 按钮点击事件
236
+ const handleButtonClick = (e) => {
237
+ dialogVisible.value = true
238
+ emit('button-click', e)
239
+ }
240
+
241
+ // 弹窗关闭事件
242
+ const handleDialogClose = (e) => {
243
+ dialogVisible.value = false
244
+ emit('dialog-close', e)
245
+ }
246
+
247
+ // API调用方法
248
+ const callApi = async () => {
249
+ if (!props.apiConfig) return null
250
+
251
+ try {
252
+ apiLoading.value = true
253
+ const { url, method, data, params, headers } = props.apiConfig
254
+
255
+ // 构建请求配置
256
+ const requestConfig = {
257
+ url,
258
+ method: method || (props.dialogType === 'delete' ? 'delete' : props.dialogType === 'add' ? 'post' : 'get'),
259
+ data,
260
+ params,
261
+ headers
262
+ }
263
+
264
+ // 调用dataService进行API请求
265
+ const response = await dataService.request(requestConfig)
266
+
267
+ // 显示成功消息
268
+ if (props.showResultMessage) {
269
+ const successMessage = props.dialogType === 'delete'
270
+ ? '删除成功'
271
+ : props.dialogType === 'add'
272
+ ? '添加成功'
273
+ : '操作成功'
274
+ MessagePlugin.success(successMessage)
275
+ }
276
+
277
+ // 触发成功事件
278
+ emit('api-success', response)
279
+
280
+ // 如果设置了成功后关闭,则关闭弹窗
281
+ if (props.closeOnSuccess) {
282
+ dialogVisible.value = false
283
+ }
284
+
285
+ return response
286
+ } catch (error) {
287
+ // 显示错误消息
288
+ if (props.showResultMessage) {
289
+ const errorPrefix = props.dialogType === 'delete'
290
+ ? '删除失败'
291
+ : props.dialogType === 'add'
292
+ ? '添加失败'
293
+ : '操作失败'
294
+ MessagePlugin.error(`${errorPrefix}: ${error.message || '未知错误'}`)
295
+ }
296
+
297
+ // 触发错误事件
298
+ emit('api-error', error)
299
+ return null
300
+ } finally {
301
+ apiLoading.value = false
302
+ }
303
+ }
304
+
305
+ // 弹窗确认事件
306
+ const handleDialogConfirm = async (e) => {
307
+ emit('dialog-confirm', e)
308
+
309
+ // 对于非普通类型的弹窗,总是尝试调用API
310
+ if (props.dialogType !== 'normal') {
311
+ if (props.apiConfig) {
312
+ await callApi()
313
+ } else {
314
+ console.warn(`${props.dialogType} 类型的弹窗没有配置 apiConfig`)
315
+ dialogVisible.value = false
316
+ }
317
+ } else {
318
+ // 普通弹窗的行为
319
+ if (props.apiConfig) {
320
+ await callApi()
321
+ } else {
322
+ dialogVisible.value = false
323
+ }
324
+ }
325
+ }
326
+
327
+ // 弹窗取消事件
328
+ const handleDialogCancel = (e) => {
329
+ dialogVisible.value = false
330
+ emit('dialog-cancel', e)
331
+ }
332
+ </script>
333
+
334
+ <style scoped>
335
+ .ebiz-tdesign-button-dialog {
336
+ display: inline-block;
337
+ }
338
+
339
+ .dialog-header-delete {
340
+ color: var(--td-error-color, #e34d59);
341
+ }
342
+
343
+ .delete-confirm-content {
344
+ display: flex;
345
+ align-items: center;
346
+ padding: 16px;
347
+ }
348
+
349
+ .delete-icon {
350
+ font-size: 24px;
351
+ color: var(--td-error-color, #e34d59);
352
+ margin-right: 12px;
353
+ }
354
+
355
+ .delete-message {
356
+ margin: 0;
357
+ font-size: 14px;
358
+ line-height: 22px;
359
+ }
360
+ </style>
package/src/index.js CHANGED
@@ -60,6 +60,9 @@ import EbizTreeMergeTable from './components/EbizTreeMergeTable.vue';
60
60
  import EbizTdesignLoading from './components/EbizTdesignLoading.vue';
61
61
  import EbizAutoForm from './components/EbizAutoForm.vue';
62
62
  import EbizDepartmentSelector from './components/EbizDepartmentSelector.vue';
63
+ import EbizTdesignButtonDialog from './components/EbizTdesignButtonDialog.vue';
64
+ import EbizSForm from './components/EbizSForm.vue';
65
+ import EbizSFormItem from './components/EbizSFormItem.vue';
63
66
  import { MessagePlugin as EbizMessage } from 'tdesign-vue-next';
64
67
 
65
68
  // import EbizDescriptions from './components/EbizDescriptions.vue';
@@ -191,5 +194,10 @@ export {
191
194
  EbizDescriptionsItem,
192
195
  TDescriptionsItem,
193
196
  EbizTdesignLoading,
194
- EbizLoading
197
+ EbizLoading,
198
+ // 弹窗按钮组件
199
+ EbizTdesignButtonDialog,
200
+ // PC端表单组件
201
+ EbizSForm,
202
+ EbizSFormItem
195
203
  };
@@ -310,6 +310,18 @@ const routes = [
310
310
  name: 'EbizDepartmentSelector',
311
311
  component: () => import('../views/EbizDepartmentSelectorDemo.vue'),
312
312
  meta: { title: 'Ebiz部门选择器组件示例' }
313
+ },
314
+ {
315
+ path: '/ebiz-tdesign-button-dialog',
316
+ name: 'EbizTdesignButtonDialog',
317
+ component: () => import('../views/EbizTdesignButtonDialogExample.vue'),
318
+ meta: { title: '弹窗按钮组件示例' }
319
+ },
320
+ {
321
+ path: '/ebiz-s-form',
322
+ name: 'EbizSForm',
323
+ component: () => import('../views/EbizSFormDemo.vue'),
324
+ meta: { title: 'PC端表单组件示例' }
313
325
  }
314
326
  ]
315
327