@ebiz/designer-components 0.0.37 → 0.0.39

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.
@@ -1,7 +1,8 @@
1
1
  <template>
2
- <t-form ref="formRef" :class="['ebiz-s-form', className]" :colon="colon" :data="data" :disabled="disabled"
2
+ <t-form ref="formRef" :class="['ebiz-s-form', className]" :colon="colon" :data="localFormData" :disabled="disabled"
3
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"
4
+ :reset-on-semi-controlled="resetOnSemiControlled" :rules="formRules"
5
+ :scroll-to-first-error="scrollToFirstError"
5
6
  :show-error-message="showErrorMessage" :status-icon="statusIcon" :style="customStyle" @reset="handleReset"
6
7
  @submit="handleSubmit" @validate="handleValidate">
7
8
 
@@ -10,10 +11,12 @@
10
11
  <ebiz-s-form-item label=" ">
11
12
  <slot name="buttons">
12
13
  <t-space>
13
- <t-button v-if="showCancelButton" :theme="cancelButtonTheme" type="reset">{{
14
- cancelButtonText
14
+ <t-button v-if="showCancelButton" :theme="cancelButtonTheme" type="reset" :loading="loading"
15
+ :disabled="loading || disabled">{{
16
+ cancelButtonText
15
17
  }}</t-button>
16
- <t-button v-if="showSubmitButton" theme="primary" :loading="loading" type="submit">{{
18
+ <t-button v-if="showSubmitButton" theme="primary" :loading="loading"
19
+ :disabled="loading || disabled" type="submit">{{
17
20
  submitButtonText }}</t-button>
18
21
  </t-space>
19
22
  </slot>
@@ -34,7 +37,7 @@ export default {
34
37
  </script>
35
38
 
36
39
  <script setup>
37
- import { defineProps, defineEmits, ref } from 'vue';
40
+ import { defineProps, defineEmits, ref, watch, computed } from 'vue';
38
41
  import { Form as TForm, Button as TButton, Space as TSpace, MessagePlugin } from 'tdesign-vue-next';
39
42
  import dataService from "../../../apiService/simpleDataService";
40
43
  import EbizSFormItem from './item.vue';
@@ -193,6 +196,13 @@ const props = defineProps({
193
196
  type: Object,
194
197
  default: () => null
195
198
  },
199
+ /**
200
+ * 详情API配置,用于加载表单数据
201
+ */
202
+ detailApiConfig: {
203
+ type: Object,
204
+ default: () => null
205
+ },
196
206
  /**
197
207
  * 是否在提交成功后重置表单
198
208
  */
@@ -229,13 +239,61 @@ const emit = defineEmits([
229
239
  'validate',
230
240
  'success',
231
241
  'error',
232
- 'cancel'
242
+ 'cancel',
243
+ 'detail-loaded',
244
+ 'detail-error'
233
245
  ]);
234
246
 
235
247
  const formRef = ref(null);
236
248
  const loading = ref(false);
249
+ const currentId = ref(null);
250
+ const currentParams = ref({});
251
+ const localFormData = ref({...props.data});
237
252
 
253
+ // 合并rules并监听变化
254
+ const formRules = computed(() => props.rules);
238
255
 
256
+ // 监听props的data变化,同步到localFormData
257
+ watch(() => props.data, (newData) => {
258
+ // 如果外部传入的数据变化,同步更新本地数据
259
+ if (newData && typeof newData === 'object') {
260
+ // 清空现有数据
261
+ Object.keys(localFormData.value).forEach(key => {
262
+ delete localFormData.value[key];
263
+ });
264
+
265
+ // 写入新数据
266
+ Object.keys(newData).forEach(key => {
267
+ localFormData.value[key] = newData[key];
268
+ });
269
+ }
270
+ }, { deep: true });
271
+
272
+ /**
273
+ * 获取错误消息
274
+ * @param {Error} error 错误对象
275
+ * @param {string} prefix 错误消息前缀
276
+ * @returns {string} 格式化后的错误消息
277
+ */
278
+ const getErrorMessage = (error, prefix = '提交失败') => {
279
+ if (!error) return `${prefix}: 未知错误`;
280
+
281
+ // 处理不同类型的错误
282
+ if (error.response && error.response.data) {
283
+ // API返回的详细错误信息
284
+ const { message, msg, error: errMsg } = error.response.data;
285
+ return `${prefix}: ${message || msg || errMsg || error.message || '服务器返回错误'}`;
286
+ } else if (error.message) {
287
+ // 标准错误对象
288
+ return `${prefix}: ${error.message}`;
289
+ } else if (typeof error === 'string') {
290
+ // 字符串错误
291
+ return `${prefix}: ${error}`;
292
+ } else {
293
+ // 未知错误
294
+ return `${prefix}: 未知错误`;
295
+ }
296
+ };
239
297
 
240
298
  /**
241
299
  * 调用API提交表单数据
@@ -243,30 +301,42 @@ const loading = ref(false);
243
301
  const submitFormData = async () => {
244
302
  try {
245
303
  loading.value = true;
304
+
305
+ // 准备请求参数
306
+ const fetchParams = { ...localFormData.value };
307
+
308
+ // 如果有ID,添加到请求参数中
309
+ if (currentId.value) {
310
+ fetchParams.id = currentId.value;
311
+ }
312
+
313
+ // 合并当前参数到请求参数
314
+ if (currentParams.value && Object.keys(currentParams.value).length > 0) {
315
+ Object.keys(currentParams.value).forEach(key => {
316
+ fetchParams[key] = currentParams.value[key];
317
+ });
318
+ }
246
319
 
247
- const { url, method, headers, params } = props.apiConfig;
248
- const response = await dataService.request({
249
- url,
250
- method: method || 'post',
251
- data: props.data,
252
- params,
253
- headers
254
- });
320
+ // 直接使用 apiConfig,不做任何处理
321
+ const response = await dataService.fetch(fetchParams, props.apiConfig);
255
322
 
323
+ // 直接使用响应数据
324
+ const transformedResponse = response;
256
325
  if (props.showResultMessage) {
257
326
  MessagePlugin.success(props.successMessage);
258
327
  }
259
328
 
260
- emit('success', response);
329
+ emit('success', transformedResponse);
261
330
 
262
331
  if (props.resetOnSuccess && formRef.value) {
263
332
  formRef.value.reset();
264
333
  }
265
334
 
266
- return response;
335
+ return transformedResponse;
267
336
  } catch (error) {
268
337
  if (props.showResultMessage) {
269
- MessagePlugin.error(props.errorMessage || error.message || '提交失败');
338
+ const errorMsg = getErrorMessage(error, props.errorMessage);
339
+ MessagePlugin.error(errorMsg);
270
340
  }
271
341
 
272
342
  emit('error', error);
@@ -277,46 +347,225 @@ const submitFormData = async () => {
277
347
  };
278
348
 
279
349
  /**
280
- * 提交表单
350
+ * 表单重置
351
+ * @param {Object} context 表单上下文
281
352
  */
282
- const handleFormSubmit = async () => {
283
- if (!formRef.value) return;
353
+ const handleReset = (context) => {
354
+ emit('reset', context);
355
+ };
284
356
 
285
- const validateResult = await formRef.value.validate();
286
- if (validateResult !== true) {
287
- return;
357
+ /**
358
+ * 表单验证
359
+ * @param {Object} result 表单验证结果
360
+ */
361
+ const handleValidate = (result) => {
362
+ emit('validate', result);
363
+ };
364
+
365
+ /**
366
+ * 表单提交事件,由内置的HTML表单submit事件触发
367
+ */
368
+ const handleSubmit = async (_context) => {
369
+ try {
370
+ if (!formRef.value) return;
371
+
372
+ const validateResult = await formRef.value.validate();
373
+
374
+ if (validateResult !== true) {
375
+ // 获取第一个错误信息
376
+ const firstKey = Object.keys(validateResult)[0];
377
+ const firstError = validateResult[firstKey]?.[0]?.message || '表单验证失败';
378
+
379
+ if (props.showResultMessage) {
380
+ MessagePlugin.error(firstError);
381
+ }
382
+
383
+ emit('error', { validateResult, firstError });
384
+ return;
385
+ }
386
+
387
+ emit('submit', localFormData.value);
388
+
389
+ if (props.apiConfig) {
390
+ await submitFormData();
391
+ }
392
+ } catch (error) {
393
+ if (props.showResultMessage) {
394
+ MessagePlugin.error(getErrorMessage(error));
395
+ }
396
+
397
+ emit('error', error);
288
398
  }
399
+ };
289
400
 
290
- emit('submit', props.data);
401
+ /**
402
+ * 加载详情数据
403
+ * @param {string|number} id 记录ID
404
+ */
405
+ const loadDetailData = async (id) => {
406
+ if (!props.detailApiConfig || !id) return null;
407
+
408
+ try {
409
+ loading.value = true;
410
+
411
+ // 准备请求参数
412
+ const fetchParams = { id };
413
+
414
+ // 合并当前参数到请求参数
415
+ if (currentParams.value && Object.keys(currentParams.value).length > 0) {
416
+ Object.keys(currentParams.value).forEach(key => {
417
+ fetchParams[key] = currentParams.value[key];
418
+ });
419
+ }
420
+
421
+ // 调用dataService进行API请求,直接使用detailApiConfig
422
+ const response = await dataService.fetch(fetchParams, props.detailApiConfig);
423
+
424
+ // 获取详情数据
425
+ const detailData = response.data || response;
426
+
427
+ // 更新本地表单数据
428
+ if (detailData) {
429
+ // 清空现有数据
430
+ Object.keys(localFormData.value).forEach(key => {
431
+ delete localFormData.value[key];
432
+ });
433
+
434
+ // 写入新数据
435
+ Object.keys(detailData).forEach(key => {
436
+ localFormData.value[key] = detailData[key];
437
+ });
438
+ }
439
+
440
+ // 触发加载成功事件
441
+ emit('detail-loaded', detailData);
442
+ return detailData;
443
+ } catch (error) {
444
+ // 显示错误消息
445
+ if (props.showResultMessage) {
446
+ MessagePlugin.error(`加载详情失败: ${error.message || '未知错误'}`);
447
+ }
448
+
449
+ // 触发错误事件
450
+ emit('detail-error', error);
451
+ return null;
452
+ } finally {
453
+ loading.value = false;
454
+ }
455
+ };
291
456
 
292
- if (props.apiConfig) {
293
- await submitFormData();
457
+ /**
458
+ * 打开表单并设置参数
459
+ * @param {Object} params 表单参数
460
+ */
461
+ const openForm = (params = {}) => {
462
+ // 处理传入的表单数据
463
+ if (params.formData) {
464
+ // 清空现有数据
465
+ Object.keys(localFormData.value).forEach(key => {
466
+ delete localFormData.value[key];
467
+ });
468
+
469
+ // 写入新数据
470
+ Object.keys(params.formData).forEach(key => {
471
+ localFormData.value[key] = params.formData[key];
472
+ });
473
+ } else if (params.clearData) {
474
+ // 如果要求清空数据
475
+ Object.keys(localFormData.value).forEach(key => {
476
+ delete localFormData.value[key];
477
+ });
478
+ }
479
+
480
+ // 存储ID
481
+ if (params.id) {
482
+ currentId.value = params.id;
483
+
484
+ // 如果有detailApiConfig,加载详情数据
485
+ if (props.detailApiConfig) {
486
+ loadDetailData(params.id);
487
+ }
488
+ } else {
489
+ currentId.value = null;
294
490
  }
491
+
492
+ // 存储其他自定义参数
493
+ currentParams.value = params;
494
+
495
+ return { success: true, message: '表单已准备就绪' };
295
496
  };
296
497
 
297
498
  /**
298
- * 表单重置
299
- * @param {Object} context 表单上下文
499
+ * 设置表单数据
500
+ * @param {Object} data 要设置的数据
300
501
  */
301
- const handleReset = (context) => {
302
- emit('reset', context);
502
+ const setFormData = (data) => {
503
+ if (!data || typeof data !== 'object') {
504
+ return { success: false, message: '数据必须是一个对象' };
505
+ }
506
+
507
+ // 清空现有数据
508
+ Object.keys(localFormData.value).forEach(key => {
509
+ delete localFormData.value[key];
510
+ });
511
+
512
+ // 写入新数据
513
+ Object.keys(data).forEach(key => {
514
+ localFormData.value[key] = data[key];
515
+ });
516
+
517
+ return { success: true, message: '表单数据已设置' };
303
518
  };
304
519
 
305
520
  /**
306
- * 表单验证
307
- * @param {Object} result 表单验证结果
521
+ * 获取表单数据
308
522
  */
309
- const handleValidate = (result) => {
310
- emit('validate', result);
523
+ const getFormData = () => {
524
+ return { ...localFormData.value };
311
525
  };
312
526
 
527
+ /**
528
+ * 清空表单数据
529
+ */
530
+ const clearFormData = () => {
531
+ // 清空表单数据
532
+ Object.keys(localFormData.value).forEach(key => {
533
+ delete localFormData.value[key];
534
+ });
535
+
536
+ emit('reset', { type: 'clear' });
537
+ return { success: true, message: '表单数据已清空' };
538
+ };
313
539
 
314
540
  /**
315
- * 表单提交事件,由内置的HTML表单submit事件触发
541
+ * 提交表单
316
542
  */
317
- const handleSubmit = (context) => {
318
- // 这里只做转发,实际提交逻辑在handleFormSubmit中
319
- emit('submit', context);
543
+ const submitForm = async () => {
544
+ try {
545
+ if (!formRef.value) {
546
+ return { success: false, message: '表单引用不存在' };
547
+ }
548
+
549
+ const validateResult = await formRef.value.validate();
550
+
551
+ if (validateResult === true) {
552
+ emit('submit', localFormData.value);
553
+
554
+ if (props.apiConfig) {
555
+ const response = await submitFormData();
556
+ return { success: true, message: '提交成功', data: response };
557
+ }
558
+
559
+ return { success: true, message: '表单验证通过', data: { ...localFormData.value } };
560
+ } else {
561
+ const firstKey = Object.keys(validateResult)[0];
562
+ const firstError = validateResult[firstKey]?.[0]?.message || '表单验证失败';
563
+
564
+ return { success: false, message: firstError, errors: validateResult };
565
+ }
566
+ } catch (error) {
567
+ return { success: false, message: error.message || '提交过程中发生错误' };
568
+ }
320
569
  };
321
570
 
322
571
  // 暴露方法给父组件
@@ -324,7 +573,7 @@ defineExpose({
324
573
  /**
325
574
  * 提交表单方法
326
575
  */
327
- submit: handleFormSubmit,
576
+ submit: submitForm,
328
577
  /**
329
578
  * 重置表单方法
330
579
  */
@@ -366,7 +615,43 @@ defineExpose({
366
615
  /**
367
616
  * 获取表单DOM元素
368
617
  */
369
- getFormElement: () => formRef.value
618
+ getFormElement: () => formRef.value,
619
+ /**
620
+ * 打开表单并设置参数
621
+ */
622
+ openForm,
623
+ /**
624
+ * 加载详情数据
625
+ */
626
+ loadDetailData,
627
+ /**
628
+ * 清空表单数据
629
+ */
630
+ clearFormData,
631
+ /**
632
+ * 设置表单数据
633
+ */
634
+ setFormData,
635
+ /**
636
+ * 获取表单数据
637
+ */
638
+ getFormData,
639
+ /**
640
+ * 表单引用
641
+ */
642
+ formRef,
643
+ /**
644
+ * 当前ID
645
+ */
646
+ currentId,
647
+ /**
648
+ * 当前参数
649
+ */
650
+ currentParams,
651
+ /**
652
+ * 本地表单数据
653
+ */
654
+ localFormData
370
655
  });
371
656
  </script>
372
657
 
package/src/index.js CHANGED
@@ -85,8 +85,8 @@ import { LoadingPlugin as EbizLoading } from 'tdesign-vue-next';
85
85
  import EbizMap from './components/EbizMap.vue';
86
86
 
87
87
  import EbizSData from './components/senior/EbizSData/index.vue';
88
- import EbizSForm from "./components/senior/EbizSForm/index.vue";
89
- import EbizSFormItem from "./components/senior/EbizSForm/item.vue";
88
+ import EbizSForm from './components/senior/EbizSForm/index.vue';
89
+ import EbizSFormItem from './components/senior/EbizSForm/item.vue';
90
90
  import EbizSDialog from "./components/senior/EbizSDialog/index.vue";
91
91
 
92
92
  // 导出组件
@@ -3,6 +3,7 @@ import Home from '../views/Home.vue'
3
3
  import ButtonView from '../views/Button.vue'
4
4
  import TableView from '../views/TableView.vue'
5
5
  import TdesignDescriptions from '../views/TdesignDescriptions.vue'
6
+ import EbizSForm from '../views/EbizSForm/index.vue'
6
7
 
7
8
  const routes = [
8
9
  {
@@ -320,8 +321,7 @@ const routes = [
320
321
  {
321
322
  path: '/ebiz-s-form',
322
323
  name: 'EbizSForm',
323
- component: () => import('../views/EbizSFormDemo.vue'),
324
- meta: { title: 'PC端表单组件示例' }
324
+ component: EbizSForm
325
325
  },
326
326
  {
327
327
  path: '/ebiz-map',