@dckj-npm/dc-material 0.1.379 → 0.1.381

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.
Files changed (34) hide show
  1. package/build/docs/colorful-button.html +3 -3
  2. package/build/docs/colorful-input.html +3 -3
  3. package/build/docs/custom-form/requirements.html +3 -3
  4. package/build/docs/custom-form.html +3 -3
  5. package/build/docs/index.html +3 -3
  6. package/build/docs/teletext-list.html +3 -3
  7. package/build/docs/{umi.80bcbda5.js → umi.b55ee37b.js} +1 -1
  8. package/build/docs/~demos/colorful-button-demo.html +3 -3
  9. package/build/docs/~demos/colorful-input-demo.html +3 -3
  10. package/build/docs/~demos/teletext-list-demo-1.html +3 -3
  11. package/build/docs/~demos/teletext-list-demo.html +3 -3
  12. package/build/lowcode/assets-daily.json +13 -13
  13. package/build/lowcode/assets-dev.json +2 -2
  14. package/build/lowcode/assets-prod.json +13 -13
  15. package/build/lowcode/meta.design.js +1 -1
  16. package/build/lowcode/meta.js +1 -1
  17. package/build/lowcode/render/default/view.js +1 -1
  18. package/build/lowcode/view.js +1 -1
  19. package/dist/BizComps.js +2 -2
  20. package/dist/BizComps.js.map +1 -1
  21. package/es/components/custom-form/custom-form.d.ts +13 -0
  22. package/es/components/custom-form/custom-form.js +158 -44
  23. package/es/components/custom-form/schema.json +1373 -1373
  24. package/lib/components/custom-form/custom-form.d.ts +13 -0
  25. package/lib/components/custom-form/custom-form.js +157 -43
  26. package/lib/components/custom-form/schema.json +1373 -1373
  27. package/lowcode/custom-form/meta.ts +55 -26
  28. package/lowcode_es/custom-form/meta.js +279 -241
  29. package/lowcode_es/meta.js +1 -1
  30. package/lowcode_lib/custom-form/meta.js +279 -241
  31. package/lowcode_lib/meta.js +1 -1
  32. package/package.json +3 -3
  33. package/es/components/custom-form/CUSTOM_FORM_OPERATION_MANUAL.md +0 -284
  34. package/lib/components/custom-form/CUSTOM_FORM_OPERATION_MANUAL.md +0 -284
@@ -42,6 +42,19 @@ export interface CustomFormItemSchema {
42
42
  }>;
43
43
  /** 动态选项(绑定变量/数据源后优先使用),仅 Select/RadioGroup/CheckboxGroup 生效 */
44
44
  optionsBind?: any[];
45
+ /**
46
+ * optionsBind 数据源中用作选项显示文字的字段名(当数据源字段名不是 'label' 时填写)。
47
+ * 例如数据源字段为 package_name,则填 "package_name"。
48
+ * 不填则默认使用 'label' 字段。
49
+ */
50
+ optionsLabelKey?: string;
51
+ /**
52
+ * optionsBind 数据源中用作选项存储值的字段名(当数据源字段名不是 'value' 时填写)。
53
+ * 例如数据源字段为 id,则填 "id";字段为 package_name,则填 "package_name"。
54
+ * 不填则默认使用 'value' 字段。
55
+ * 配置后,字段联动的 matchKey 会自动默认使用此字段名,无需在联动规则中重复配置。
56
+ */
57
+ optionsValueKey?: string;
45
58
  /** 该表单项占几列(不超过父级 columns),默认 1 */
46
59
  columnSpan?: number;
47
60
  /** 组件尺寸:small / medium / large,默认继承表单全局 size */
@@ -30,7 +30,7 @@ var _excluded = ["format", "showTime"],
30
30
  * - labelCol / wrapperCol via otherProps 透传,labelAlign=left 时配合使用
31
31
  * - onReset 点击重置按钮后触发的回调事件
32
32
  */
33
- import React, { useCallback, useMemo, useRef, useState } from 'react';
33
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
34
34
  import "./index.scss";
35
35
  // ─── 调试日志工具(阶段一)────────────────────────────────────────────────────
36
36
  var DEBUG_PREFIX = '[CustomForm v0.4]';
@@ -203,22 +203,36 @@ var renderFormItemComponent = function renderFormItemComponent(item) {
203
203
  var _item$optionsBind;
204
204
  var componentProps = item.componentProps || {};
205
205
  // optionsBind(动态绑定)优先级 > componentProps.dataSource > options(静态)
206
- var dataSource = (_item$optionsBind = item.optionsBind) !== null && _item$optionsBind !== void 0 && _item$optionsBind.length ? item.optionsBind : componentProps.dataSource || item.options || [];
206
+ var rawDataSource = (_item$optionsBind = item.optionsBind) !== null && _item$optionsBind !== void 0 && _item$optionsBind.length ? item.optionsBind : componentProps.dataSource || item.options || [];
207
+
208
+ // 若配置了 optionsLabelKey / optionsValueKey,将原始数据字段映射到 label / value 字段
209
+ // 这使得 API 返回的任意格式(如 {package_name, id, package_price})均可直接用作选项数据源
210
+ var labelKey = item.optionsLabelKey;
211
+ var valueKey = item.optionsValueKey;
212
+ var dataSource = (labelKey || valueKey) && Array.isArray(rawDataSource) ? rawDataSource.map(function (opt) {
213
+ var _opt$labelKey, _opt$valueKey;
214
+ return _extends({}, opt, labelKey ? {
215
+ label: (_opt$labelKey = opt[labelKey]) !== null && _opt$labelKey !== void 0 ? _opt$labelKey : opt.label
216
+ } : {}, valueKey ? {
217
+ value: (_opt$valueKey = opt[valueKey]) !== null && _opt$valueKey !== void 0 ? _opt$valueKey : opt.value
218
+ } : {});
219
+ }) : rawDataSource;
207
220
  switch (item.componentType) {
208
221
  case 'TextArea':
209
222
  return /*#__PURE__*/React.createElement(TextAreaAny, componentProps);
210
223
  case 'Select':
211
- return /*#__PURE__*/React.createElement(SelectAny, _extends({
224
+ // dataSource 放在末尾以确保 optionsBind 优先级高于 componentProps.dataSource
225
+ return /*#__PURE__*/React.createElement(SelectAny, _extends({}, componentProps, {
212
226
  dataSource: dataSource
213
- }, componentProps));
227
+ }));
214
228
  case 'RadioGroup':
215
- return /*#__PURE__*/React.createElement(RadioGroupAny, _extends({
229
+ return /*#__PURE__*/React.createElement(RadioGroupAny, _extends({}, componentProps, {
216
230
  dataSource: dataSource
217
- }, componentProps));
231
+ }));
218
232
  case 'CheckboxGroup':
219
- return /*#__PURE__*/React.createElement(CheckboxGroupAny, _extends({
233
+ return /*#__PURE__*/React.createElement(CheckboxGroupAny, _extends({}, componentProps, {
220
234
  dataSource: dataSource
221
- }, componentProps));
235
+ }));
222
236
  case 'NumberPicker':
223
237
  return /*#__PURE__*/React.createElement(NumberPickerAny, componentProps);
224
238
  case 'DatePicker':
@@ -315,6 +329,12 @@ var CustomForm = function CustomForm(_ref) {
315
329
  // 初始化时直接合并 resolvedInitialValues,避免 useEffect 延迟问题
316
330
  var valuesRef = useRef(resolvedInitialValues ? _extends({}, resolvedInitialValues) : {});
317
331
 
332
+ // ─── 缓存最新的 formItems,避免 handleFieldChange 闭包访问过期值 ─────────
333
+ var formItemsRef = useRef(formItems);
334
+ useEffect(function () {
335
+ formItemsRef.current = formItems;
336
+ }, [formItems]);
337
+
318
338
  // ─── 联动回填触发器:用 state 驱动组件重渲染以更新受控字段 ───────────────
319
339
  // 注意:不预填 resolvedInitialValues,初始值通过 defaultValue(非受控)处理
320
340
  // 预填会导致所有有初始值的字段变为受控组件,用户改值后因 linkageValues 未更新而回显旧值
@@ -322,6 +342,19 @@ var CustomForm = function CustomForm(_ref) {
322
342
  linkageValues = _useState[0],
323
343
  setLinkageValues = _useState[1];
324
344
 
345
+ // ─── Bug Fix: initialValues 变化时同步 valuesRef(编辑模式异步加载场景)──────
346
+ // 用 JSON.stringify 做深比较,避免父组件每次重渲染都因内联对象引用变化触发重置
347
+ var lastInitSerialRef = useRef('');
348
+ useEffect(function () {
349
+ var serial = JSON.stringify(resolvedInitialValues);
350
+ if (serial !== lastInitSerialRef.current) {
351
+ lastInitSerialRef.current = serial;
352
+ valuesRef.current = resolvedInitialValues ? _extends({}, resolvedInitialValues) : {};
353
+ setLinkageValues({});
354
+ cfLog('initialValues', 'initialValues 已变更,重新初始化 valuesRef', resolvedInitialValues);
355
+ }
356
+ }, [resolvedInitialValues]);
357
+
325
358
  // ─── 统一 onChange 处理器(阶段一 + 阶段二核心)─────────────────────────────
326
359
  var handleFieldChange = useCallback(function (field, value) {
327
360
  var _extends2;
@@ -332,9 +365,29 @@ var CustomForm = function CustomForm(_ref) {
332
365
  allValues: valuesRef.current
333
366
  });
334
367
 
335
- // 2. 字段联动(阶段二):检查是否有对应的联动规则
336
- var linkagePatched = null;
368
+ // 2. 字段联动(阶段二)
337
369
  if (fieldLinkage && fieldLinkage.length > 0) {
370
+ // ── 第一步:收集当前 watchField 所有规则"可能影响"到的字段(预清除范围)──────
371
+ // 目的:当用户把 watchField 改为不匹配任何规则的值时,
372
+ // 把上一次联动写入的字段清回初始值,而不是永久保留旧的联动值。
373
+ var clearableFields = new Set();
374
+ fieldLinkage.forEach(function (rule) {
375
+ if (rule.watchField !== field) return;
376
+ if (rule.fillField) clearableFields.add(rule.fillField);
377
+ if (rule.fillFields) Object.keys(rule.fillFields).forEach(function (f) {
378
+ return clearableFields.add(f);
379
+ });
380
+ if (rule.staticRules) {
381
+ Object.values(rule.staticRules).forEach(function (ruleMap) {
382
+ return Object.keys(ruleMap).forEach(function (f) {
383
+ return clearableFields.add(f);
384
+ });
385
+ });
386
+ }
387
+ });
388
+
389
+ // ── 第二步:按规则计算本次实际要写入的值 ────────────────────────────────────
390
+ var fills = {};
338
391
  fieldLinkage.forEach(function (rule) {
339
392
  if (rule.watchField !== field) return;
340
393
 
@@ -342,28 +395,54 @@ var CustomForm = function CustomForm(_ref) {
342
395
  if (rule.staticRules) {
343
396
  var staticFill = rule.staticRules[String(value)];
344
397
  if (staticFill) {
345
- linkagePatched = _extends({}, linkagePatched || {}, staticFill);
346
- Object.assign(valuesRef.current, staticFill);
398
+ Object.assign(fills, staticFill);
347
399
  cfLog('linkage', "\u9759\u6001\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", staticFill);
348
400
  }
349
401
  }
350
402
 
351
403
  // 2b. 数据源动态联动(高级格式)
352
404
  if (rule.dataSource && rule.fillFields) {
353
- var matchKey = rule.matchKey || 'value';
354
- var matched = rule.dataSource.find(function (item) {
355
- return item[matchKey] === value;
356
- });
357
- if (matched) {
358
- var fill = {};
359
- Object.entries(rule.fillFields).forEach(function (_ref2) {
360
- var formField = _ref2[0],
361
- dsKey = _ref2[1];
362
- fill[formField] = matched[dsKey];
405
+ // ─── 防御:dataSource 必须是数组 ───────────────────────────────────────
406
+ // 若属性面板 dataSource 字段未通过「变量绑定」控件正确绑定,
407
+ // 而是直接输入了文本(如 "this.state.xxx"),则 rule.dataSource 为字符串而非数组。
408
+ // 在非数组上调用 .find() 会抛 TypeError,该错误会在 Fusion Field 的 onChange 包装
409
+ // 器中向上传播,阻断 _reRender(即 instance.forceUpdate())的调用,导致:
410
+ // 1. Form 不重新渲染 → 下拉选中值消失(Select 回显空白)
411
+ // 2. setLinkageValues 未执行 → 联动回填字段不更新
412
+ // 因此必须先做类型守卫,跳过非数组情况并给出明确提示。
413
+ if (!Array.isArray(rule.dataSource)) {
414
+ cfWarn('linkage', "\u52A8\u6001\u8054\u52A8\uFF08watchField=\"" + rule.watchField + "\"\uFF09\u7684 dataSource \u4E0D\u662F\u6570\u7EC4" + ("\uFF08\u5B9E\u9645\u7C7B\u578B\uFF1A" + typeof rule.dataSource + "\uFF0C\u503C\uFF1A" + JSON.stringify(rule.dataSource) + "\uFF09\u3002") + "\u8BF7\u5728\u5C5E\u6027\u9762\u677F\u4E2D\u901A\u8FC7\u300C\u53D8\u91CF\u7ED1\u5B9A\u300D\u63A7\u4EF6\u9009\u62E9\u6570\u636E\u6E90\u53D8\u91CF\uFF0C\u4E0D\u8981\u76F4\u63A5\u8F93\u5165\u6587\u5B57\u8DEF\u5F84\u3002");
415
+ } else {
416
+ var _formItemsRef$current;
417
+ var matchKey = rule.matchKey || ((_formItemsRef$current = formItemsRef.current.find(function (i) {
418
+ return i.field === rule.watchField;
419
+ })) === null || _formItemsRef$current === void 0 ? void 0 : _formItemsRef$current.optionsValueKey) || 'value';
420
+ // 同时支持严格相等和字符串化比较,兼容 id 字段类型不一致(数字 vs 字符串)的场景
421
+ var matched = rule.dataSource.find(function (item) {
422
+ return item[matchKey] === value || item[matchKey] !== undefined && value !== undefined && String(item[matchKey]) === String(value);
363
423
  });
364
- linkagePatched = _extends({}, linkagePatched || {}, fill);
365
- Object.assign(valuesRef.current, fill);
366
- cfLog('linkage', "\u52A8\u6001\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", fill);
424
+ if (matched) {
425
+ var fill = {};
426
+ Object.entries(rule.fillFields).forEach(function (_ref2) {
427
+ var formField = _ref2[0],
428
+ dsKey = _ref2[1];
429
+ // 防止把 watchField 误填进 fillFields,否则会用 undefined 覆盖用户的选择值
430
+ if (formField === field) {
431
+ cfWarn('linkage', "fillFields \u4E2D\u7684 key \"" + formField + "\" \u4E0E\u76D1\u542C\u5B57\u6BB5 watchField \u76F8\u540C\uFF0C\u5DF2\u8DF3\u8FC7\u3002" + "fillFields \u683C\u5F0F\u4E3A {\"\u76EE\u6807\u8868\u5355\u5B57\u6BB5\":\"\u6570\u636E\u6E90\u5B57\u6BB5\u540D\"}\uFF0C\u8BF7\u68C0\u67E5 key/value \u662F\u5426\u5199\u53CD\u3002");
432
+ return;
433
+ }
434
+ // 数据源字段名不存在时提示可用字段,避免静默填入 undefined
435
+ if (!(dsKey in matched)) {
436
+ cfWarn('linkage', "fillFields \u4E2D\u6570\u636E\u6E90\u5B57\u6BB5\u540D \"" + dsKey + "\" \u5728\u5339\u914D\u9879\u4E2D\u4E0D\u5B58\u5728\uFF0C\u5DF2\u8DF3\u8FC7\u3002" + ("\u5339\u914D\u9879\u53EF\u7528\u5B57\u6BB5\uFF1A" + Object.keys(matched).join(', ')));
437
+ return;
438
+ }
439
+ fill[formField] = matched[dsKey];
440
+ });
441
+ Object.assign(fills, fill);
442
+ cfLog('linkage', "\u52A8\u6001\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", fill);
443
+ } else {
444
+ cfWarn('linkage', "\u52A8\u6001\u8054\u52A8\uFF1A\u5728 dataSource \u4E2D\u672A\u627E\u5230 matchKey=\"" + matchKey + "\" \u7B49\u4E8E \"" + value + "\" \u7684\u8BB0\u5F55\u3002" + "\u8BF7\u786E\u8BA4 matchKey \u4E0E optionsBind \u5B58\u50A8\u503C\u5B57\u6BB5\u540D\u4E00\u81F4\uFF08\u914D\u7F6E\u4E86 optionsValueKey \u65F6\u4F1A\u81EA\u52A8\u4F7F\u7528\u8BE5\u5B57\u6BB5\u540D\uFF09\uFF0C\u4E14 dataSource \u4E0E optionsBind \u540C\u6E90\u3002");
445
+ }
367
446
  }
368
447
  }
369
448
 
@@ -372,20 +451,42 @@ var CustomForm = function CustomForm(_ref) {
372
451
  var noConstraint = rule.matchValue === undefined || rule.matchValue === '';
373
452
  var _matched = noConstraint || String(value) === String(rule.matchValue);
374
453
  if (_matched) {
375
- var _fill2;
376
- var _fill = (_fill2 = {}, _fill2[rule.fillField] = rule.fillValue, _fill2);
377
- linkagePatched = _extends({}, linkagePatched || {}, _fill);
378
- Object.assign(valuesRef.current, _fill);
379
- cfLog('linkage', "\u7B80\u5355\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", _fill);
454
+ var _cfLog;
455
+ fills[rule.fillField] = rule.fillValue;
456
+ cfLog('linkage', "\u7B80\u5355\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", (_cfLog = {}, _cfLog[rule.fillField] = rule.fillValue, _cfLog));
380
457
  }
381
458
  }
382
459
  });
383
- }
384
- // 有联动回填时,更新 linkageValues 触发重渲染
385
- if (linkagePatched) {
386
- setLinkageValues(function (prev) {
387
- return _extends({}, prev, linkagePatched);
388
- });
460
+
461
+ // ── 第三步:同步更新 valuesRef 和 linkageValues ──────────────────────────────
462
+ // 先把 clearableFields 回退为初始值(无论本次有无匹配)
463
+ // 再把 fills 叠加进来(覆盖刚刚的回退值)
464
+ // 结果:本次有匹配 字段显示新的联动值;本次无匹配 → 字段回退为初始值或空
465
+ if (clearableFields.size > 0) {
466
+ clearableFields.forEach(function (f) {
467
+ var initVal = resolvedInitialValues === null || resolvedInitialValues === void 0 ? void 0 : resolvedInitialValues[f];
468
+ if (initVal !== undefined) {
469
+ valuesRef.current[f] = initVal;
470
+ } else {
471
+ delete valuesRef.current[f];
472
+ }
473
+ });
474
+ Object.assign(valuesRef.current, fills);
475
+ setLinkageValues(function (prev) {
476
+ var next = _extends({}, prev);
477
+ // 删除"可被清除"但本次未填入的字段,使其退出受控状态
478
+ clearableFields.forEach(function (f) {
479
+ if (!(f in fills)) delete next[f];
480
+ });
481
+ return _extends({}, next, fills);
482
+ });
483
+ } else if (Object.keys(fills).length > 0) {
484
+ // 保底路径:clearableFields 为空但仍有 fills(理论上不会出现)
485
+ Object.assign(valuesRef.current, fills);
486
+ setLinkageValues(function (prev) {
487
+ return _extends({}, prev, fills);
488
+ });
489
+ }
389
490
  }
390
491
 
391
492
  // 3. 计算 computedFields,得到包含衍生字段的完整值
@@ -395,7 +496,7 @@ var CustomForm = function CustomForm(_ref) {
395
496
  if (onChange) {
396
497
  onChange(field, value, allValues);
397
498
  }
398
- }, [resolvedComputedFields, fieldLinkage, onChange]);
499
+ }, [resolvedComputedFields, resolvedInitialValues, fieldLinkage, onChange]);
399
500
 
400
501
  // ─── 提交处理 ───────────────────────────────────────────────────────────────
401
502
  // ─── 对齐方式映射 ───────────────────────────────────────────────────────────
@@ -425,8 +526,11 @@ var CustomForm = function CustomForm(_ref) {
425
526
  return ops;
426
527
  }, [operations, showSubmit, submitText, submitValidate, showReset, resetText]);
427
528
  var handleSubmit = useCallback(function (values, errors, field, buttonDataSource) {
428
- // Form 收集的 values 与 ref 缓存合并(兼容 initialValues 未经 onChange 的字段)
429
- var mergedValues = _extends({}, valuesRef.current, values);
529
+ // 合并原则:valuesRef.current 优先级最高,因为它是所有变化(用户输入 + 联动回填)的唯一可信来源。
530
+ // Form.Submit 返回的 values 中,联动回填字段没有经过 onChange,Form 内部 store
531
+ // 可能保留初始 undefined/"",若让 values 覆盖 valuesRef 会丢失联动写入的正确值。
532
+ // { ...values, ...valuesRef.current }:valuesRef 覆盖 Form stale 值,确保联动回填生效。
533
+ var mergedValues = _extends({}, values, valuesRef.current);
430
534
  // 追加 computedFields 衍生字段
431
535
  var finalValues = applyComputedFields(mergedValues, resolvedComputedFields);
432
536
 
@@ -491,7 +595,15 @@ var CustomForm = function CustomForm(_ref) {
491
595
  // buttonDataSource:单个按钮绑定的数据源(优先);未绑定时回退到组件级 submitDataSource
492
596
  var effectiveDS = buttonDataSource !== null && buttonDataSource !== void 0 ? buttonDataSource : submitDataSource;
493
597
  runSubmitDataSource(effectiveDS, finalValues, errors, field);
494
- }, [computedFields, submitMapping, onSubmit, onSubmitFailed, submitDataSource]);
598
+ }, [resolvedComputedFields, submitMapping, onSubmit, onSubmitFailed, submitDataSource]);
599
+
600
+ // ─── 重置处理:同时清除 linkageValues 和 valuesRef ────────────────────────────
601
+ var handleReset = useCallback(function () {
602
+ setLinkageValues({});
603
+ valuesRef.current = resolvedInitialValues ? _extends({}, resolvedInitialValues) : {};
604
+ cfLog('reset', '表单已重置,linkageValues 和 valuesRef 已恢复初始状态');
605
+ onReset === null || onReset === void 0 ? void 0 : onReset();
606
+ }, [resolvedInitialValues, onReset]);
495
607
 
496
608
  // ─── 渲染表单项,绑定统一 onChange ──────────────────────────────────────────
497
609
  var formItemNodes = formItems.map(function (item, index) {
@@ -579,10 +691,12 @@ var CustomForm = function CustomForm(_ref) {
579
691
  var hasContent = formItemNodes.length > 0 || childrenNodes.length > 0;
580
692
 
581
693
  // initialValues 通过 defaultValue 传入 Form(非受控初始化),避免覆盖联动回填的受控值
694
+ // 注意:必须使用 resolvedInitialValues(已标准化为对象格式),而非原始 initialValues
695
+ // 原始值在设计器中为数组格式 [{field, valueType, value}],直接传给 NextForm.defaultValue 无效
582
696
  var formInitialProps = {};
583
- if (initialValues && Object.keys(initialValues).length > 0) {
584
- formInitialProps.defaultValue = initialValues;
585
- cfLog('render', '表单携带 initialValues 渲染', initialValues);
697
+ if (resolvedInitialValues && Object.keys(resolvedInitialValues).length > 0) {
698
+ formInitialProps.defaultValue = resolvedInitialValues;
699
+ cfLog('render', '表单携带 initialValues 渲染', resolvedInitialValues);
586
700
  }
587
701
  return /*#__PURE__*/React.createElement(NextFormAny, _extends({
588
702
  className: "custom-form"
@@ -610,7 +724,7 @@ var CustomForm = function CustomForm(_ref) {
610
724
  return /*#__PURE__*/React.createElement(NextFormAny.Reset, _extends({
611
725
  key: opIndex,
612
726
  type: op.type || 'normal',
613
- onClick: onReset
727
+ onClick: handleReset
614
728
  }, op.buttonProps || {}), op.text);
615
729
  }
616
730
  // ── 提交按钮 ─────────────────────────────────────────────────────