@dckj-npm/dc-material 0.1.377 → 0.1.379

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 (43) 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 +48 -0
  4. package/build/docs/custom-form.html +48 -0
  5. package/build/docs/index.html +3 -3
  6. package/build/docs/teletext-list.html +3 -3
  7. package/build/docs/umi.80bcbda5.js +1 -0
  8. package/build/docs/{umi.9770df27.css → umi.b31e14a3.css} +1 -1
  9. package/build/docs/~demos/colorful-button-demo.html +3 -3
  10. package/build/docs/~demos/colorful-input-demo.html +3 -3
  11. package/build/docs/~demos/teletext-list-demo-1.html +3 -3
  12. package/build/docs/~demos/teletext-list-demo.html +3 -3
  13. package/build/lowcode/assets-daily.json +13 -13
  14. package/build/lowcode/assets-dev.json +2 -2
  15. package/build/lowcode/assets-prod.json +13 -13
  16. package/build/lowcode/meta.design.js +1 -1
  17. package/build/lowcode/meta.js +1 -1
  18. package/build/lowcode/render/default/view.css +1 -1
  19. package/build/lowcode/render/default/view.js +1 -1
  20. package/build/lowcode/view.css +1 -1
  21. package/build/lowcode/view.js +1 -1
  22. package/dist/BizComps.css +1 -1
  23. package/dist/BizComps.js +2 -2
  24. package/dist/BizComps.js.map +1 -1
  25. package/es/components/custom-form/CUSTOM_FORM_OPERATION_MANUAL.md +284 -0
  26. package/es/components/custom-form/custom-form.d.ts +188 -2
  27. package/es/components/custom-form/custom-form.js +506 -26
  28. package/es/components/custom-form/index.d.ts +1 -1
  29. package/es/components/custom-form/index.scss +1 -1
  30. package/es/components/custom-form/schema.json +1374 -0
  31. package/lib/components/custom-form/CUSTOM_FORM_OPERATION_MANUAL.md +284 -0
  32. package/lib/components/custom-form/custom-form.d.ts +188 -2
  33. package/lib/components/custom-form/custom-form.js +511 -31
  34. package/lib/components/custom-form/index.d.ts +1 -1
  35. package/lib/components/custom-form/index.scss +1 -1
  36. package/lib/components/custom-form/schema.json +1374 -0
  37. package/lowcode/custom-form/meta.ts +1675 -116
  38. package/lowcode_es/custom-form/meta.js +2116 -141
  39. package/lowcode_es/meta.js +1 -1
  40. package/lowcode_lib/custom-form/meta.js +2116 -141
  41. package/lowcode_lib/meta.js +1 -1
  42. package/package.json +3 -3
  43. package/build/docs/umi.6f6bf535.js +0 -1
@@ -4,20 +4,60 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  exports.__esModule = true;
5
5
  exports["default"] = void 0;
6
6
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
7
- var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
7
+ var _extends4 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
8
8
  var _upload = _interopRequireDefault(require("@alifd/next/lib/upload"));
9
9
  var _numberPicker = _interopRequireDefault(require("@alifd/next/lib/number-picker"));
10
10
  var _datePicker = _interopRequireDefault(require("@alifd/next/lib/date-picker"));
11
11
  var _checkbox = _interopRequireDefault(require("@alifd/next/lib/checkbox"));
12
12
  var _radio = _interopRequireDefault(require("@alifd/next/lib/radio"));
13
+ var _button = _interopRequireDefault(require("@alifd/next/lib/button"));
13
14
  var _select = _interopRequireDefault(require("@alifd/next/lib/select"));
14
15
  var _input = _interopRequireDefault(require("@alifd/next/lib/input"));
15
16
  var _responsiveGrid = _interopRequireDefault(require("@alifd/next/lib/responsive-grid"));
16
17
  var _form = _interopRequireDefault(require("@alifd/next/lib/form"));
17
18
  var _react = _interopRequireWildcard(require("react"));
18
19
  require("./index.scss");
19
- var _excluded = ["columns", "spacing", "emptyContent", "formItems", "showSubmit", "submitText", "submitValidate", "submitDataSource", "submitButtonProps", "showReset", "resetText", "resetButtonProps", "onSubmit", "onSubmitFailed", "children"];
20
+ var _excluded = ["format", "showTime"],
21
+ _excluded2 = ["columns", "spacing", "emptyContent", "formItems", "initialValues", "computedFields", "fieldLinkage", "submitMapping", "fullWidth", "showSubmit", "submitText", "submitValidate", "submitDataSource", "submitButtonProps", "showReset", "resetText", "resetButtonProps", "operations", "operationAlign", "onSubmit", "onSubmitFailed", "onChange", "onReset", "children", "labelAlign", "labelCol", "size"];
22
+ /**
23
+ * CustomForm v0.5
24
+ * 阶段一新增能力:
25
+ * - onChange(field, value, allValues) 统一字段变化事件,消灭所有 onXxxChange 样板函数
26
+ * - initialValues 属性面板直接配置字段初始值,无需在页面 state 手写
27
+ * - computedFields 声明式模板字符串计算衍生字段,提交时自动合并
28
+ * 阶段二新增能力:
29
+ * - DateTimePicker 日期时间组件,格式化为 YYYY-MM-DD HH:mm
30
+ * - optionsBind 下拉/单选/复选选项支持变量绑定(动态数据源)
31
+ * - fieldLinkage 字段联动:选 A → 自动填 B/C(从数据源查找匹配项)
32
+ * - submitMapping 提交映射:自动组装 itemList 格式,消灭手写 onSubmitClick
33
+ * 阶段三新增能力:
34
+ * - labelAlign 全局标签位置(top/left/inset),对齐 Fusion Form 标准
35
+ * - fullWidth(全局) 全局控制所有表单项组件是否 100% 宽,可被单项覆盖
36
+ * - isPreview 全局预览/只读态(依赖 Fusion Form isPreview 广播)
37
+ * - labelCol / wrapperCol via otherProps 透传,labelAlign=left 时配合使用
38
+ * - onReset 点击重置按钮后触发的回调事件
39
+ */
20
40
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
41
+ // ─── 调试日志工具(阶段一)────────────────────────────────────────────────────
42
+ var DEBUG_PREFIX = '[CustomForm v0.4]';
43
+ var cfLog = function cfLog(tag) {
44
+ var _console;
45
+ // 生产环境可通过 window.__CUSTOM_FORM_DEBUG__ = false 关闭
46
+ if (typeof window !== 'undefined' && window.__CUSTOM_FORM_DEBUG__ === false) return;
47
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
48
+ args[_key - 1] = arguments[_key];
49
+ }
50
+ (_console = console).log.apply(_console, [DEBUG_PREFIX + " [" + tag + "]"].concat(args));
51
+ };
52
+ var cfWarn = function cfWarn(tag) {
53
+ var _console2;
54
+ for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
55
+ args[_key2 - 1] = arguments[_key2];
56
+ }
57
+ (_console2 = console).warn.apply(_console2, [DEBUG_PREFIX + " [" + tag + "]"].concat(args));
58
+ };
59
+ // ─────────────────────────────────────────────────────────────────────────────
60
+
21
61
  var NextFormAny = _form["default"];
22
62
  var ResponsiveGridAny = _responsiveGrid["default"];
23
63
  var ResponsiveGridCell = _responsiveGrid["default"].Cell;
@@ -25,17 +65,130 @@ var FormItemAny = _form["default"].Item;
25
65
  var InputAny = _input["default"];
26
66
  var TextAreaAny = _input["default"].TextArea;
27
67
  var SelectAny = _select["default"];
68
+ var ButtonAny = _button["default"];
28
69
  var RadioGroupAny = _radio["default"].Group;
29
70
  var CheckboxGroupAny = _checkbox["default"].Group;
30
71
  var DatePickerAny = _datePicker["default"];
31
72
  var NumberPickerAny = _numberPicker["default"];
32
73
  var UploadAny = _upload["default"];
74
+
75
+ /**
76
+ * computedFields:计算字段映射表
77
+ * key = 要写入 values 的字段名
78
+ * value = 模板字符串,用 {fieldName} 引用其他字段值
79
+ * 示例:{ "order_desc": "{package_name},{package_price},日期:{banquet_date}" }
80
+ */
81
+
82
+ /**
83
+ * 字段联动规则(阶段二 + 阶段四 UX 简化)
84
+ *
85
+ * 【简单格式(推荐)】— 属性面板 ArraySetter 可视化编辑,每条规则对应一行:
86
+ * { watchField, matchValue?, fillField, fillValue }
87
+ * watchField = 监听哪个字段变化
88
+ * matchValue = 匹配值(留空 = 任何变化都触发)
89
+ * fillField = 要回填的目标字段名
90
+ * fillValue = 回填的具体值
91
+ *
92
+ * 【高级格式(兼容旧配置)】— 支持动态数据源查找 + staticRules 嵌套格式:
93
+ * { watchField, dataSource?, matchKey?, fillFields?, staticRules? }
94
+ */
95
+
96
+ /** 提交映射 item(阶段二) */
97
+
98
+ /** rename 模式:单条字段重命名规则 */
99
+
100
+ /**
101
+ * 操作按钮配置项(阶段四新增)
102
+ * 表单底部可配置多个按钮,每个按钮均可独立设置操作类型与数据源。
103
+ */
104
+
105
+ /**
106
+ * 提交参数配置(阶段五扩展)
107
+ *
108
+ * 三种工作模式(mode):
109
+ * - 'passthrough':直接将 finalValues 作为请求参数,无需任何配置(字段名与 API 参数名相同时使用)。
110
+ * - 'rename':按 fieldRenameMap 规则重命名指定字段,未列出的字段保持原名透传;
111
+ * 适合字段名与 API 参数名不一致的标准 REST 接口。
112
+ * - 'itemList':将字段转换为动态表单格式 [{columnName, columnValue}],
113
+ * 适合 /source/api/dynamicFormTableRecord/ 等动态表单接口。
114
+ *
115
+ * 向后兼容:未设置 mode 时,若 items 不为空则自动识别为 'itemList' 模式,否则等同于 'passthrough'。
116
+ */
117
+
118
+ // ─── 工具:模板字符串渲染 ─────────────────────────────────────────────────────
119
+ /**
120
+ * 将 "{fieldA},{fieldB}" 中的占位符替换为 values 对应的真实值
121
+ */
122
+ var renderTemplate = function renderTemplate(template, values) {
123
+ return template.replace(/\{(\w+)\}/g, function (_, key) {
124
+ var val = values[key];
125
+ return val !== undefined && val !== null ? String(val) : '';
126
+ });
127
+ };
128
+
129
+ /**
130
+ * 将 initialValues 从数组格式标准化为对象格式(向后兼容)。
131
+ * 数组格式由低代码设计器属性面板存储:[{field, valueType, value}, ...]
132
+ * 对象格式为运行时使用:{ fieldName: value, ... }
133
+ */
134
+ var normalizeInitialValues = function normalizeInitialValues(raw) {
135
+ if (!raw) return {};
136
+ if (Array.isArray(raw)) {
137
+ return raw.reduce(function (acc, item) {
138
+ if (item && item.field) {
139
+ acc[item.field] = item.value !== undefined ? item.value : '';
140
+ }
141
+ return acc;
142
+ }, {});
143
+ }
144
+ return raw;
145
+ };
146
+
147
+ /**
148
+ * 将 computedFields 从数组格式标准化为对象格式(向后兼容)。
149
+ * 数组格式:[{targetField, template}, ...]
150
+ * 对象格式:{ targetField: template, ... }
151
+ */
152
+ var normalizeComputedFields = function normalizeComputedFields(raw) {
153
+ if (!raw) return {};
154
+ if (Array.isArray(raw)) {
155
+ return raw.reduce(function (acc, item) {
156
+ if (item && item.targetField) {
157
+ acc[item.targetField] = item.template || '';
158
+ }
159
+ return acc;
160
+ }, {});
161
+ }
162
+ return raw;
163
+ };
164
+
165
+ /**
166
+ * 将 computedFields 的所有模板计算后合并进 values,返回新对象(不修改原值)
167
+ */
168
+ var applyComputedFields = function applyComputedFields(values, computedFields) {
169
+ if (!computedFields || Object.keys(computedFields).length === 0) return values;
170
+ var result = (0, _extends4["default"])({}, values);
171
+ Object.keys(computedFields).forEach(function (key) {
172
+ result[key] = renderTemplate(computedFields[key], result);
173
+ });
174
+ cfLog('computedFields', '计算字段结果', result);
175
+ return result;
176
+ };
177
+ // ─────────────────────────────────────────────────────────────────────────────
178
+
33
179
  var runSubmitDataSource = function runSubmitDataSource(submitDataSource, values, errors, field) {
34
180
  if (!submitDataSource) return;
35
181
  if (typeof submitDataSource === 'function') {
36
182
  submitDataSource(values, errors, field);
37
183
  return;
38
184
  }
185
+ // lowcode-engine 数据源对象(this.dataSourceMap.xxx)使用 .load(params) 触发请求。
186
+ // params 会与数据源静态 options.params 合并覆盖;
187
+ // 若 submitMapping 已配置,values 中包含 itemList,可直接覆盖接口默认参数。
188
+ if (typeof (submitDataSource === null || submitDataSource === void 0 ? void 0 : submitDataSource.load) === 'function') {
189
+ submitDataSource.load(values);
190
+ return;
191
+ }
39
192
  if (typeof (submitDataSource === null || submitDataSource === void 0 ? void 0 : submitDataSource.run) === 'function') {
40
193
  submitDataSource.run(values, errors, field);
41
194
  return;
@@ -53,27 +206,51 @@ var runSubmitDataSource = function runSubmitDataSource(submitDataSource, values,
53
206
  }
54
207
  };
55
208
  var renderFormItemComponent = function renderFormItemComponent(item) {
209
+ var _item$optionsBind;
56
210
  var componentProps = item.componentProps || {};
57
- var dataSource = componentProps.dataSource || item.options || [];
211
+ // optionsBind(动态绑定)优先级 > componentProps.dataSource > options(静态)
212
+ var dataSource = (_item$optionsBind = item.optionsBind) !== null && _item$optionsBind !== void 0 && _item$optionsBind.length ? item.optionsBind : componentProps.dataSource || item.options || [];
58
213
  switch (item.componentType) {
59
214
  case 'TextArea':
60
215
  return /*#__PURE__*/_react["default"].createElement(TextAreaAny, componentProps);
61
216
  case 'Select':
62
- return /*#__PURE__*/_react["default"].createElement(SelectAny, (0, _extends2["default"])({
217
+ return /*#__PURE__*/_react["default"].createElement(SelectAny, (0, _extends4["default"])({
63
218
  dataSource: dataSource
64
219
  }, componentProps));
65
220
  case 'RadioGroup':
66
- return /*#__PURE__*/_react["default"].createElement(RadioGroupAny, (0, _extends2["default"])({
221
+ return /*#__PURE__*/_react["default"].createElement(RadioGroupAny, (0, _extends4["default"])({
67
222
  dataSource: dataSource
68
223
  }, componentProps));
69
224
  case 'CheckboxGroup':
70
- return /*#__PURE__*/_react["default"].createElement(CheckboxGroupAny, (0, _extends2["default"])({
225
+ return /*#__PURE__*/_react["default"].createElement(CheckboxGroupAny, (0, _extends4["default"])({
71
226
  dataSource: dataSource
72
227
  }, componentProps));
73
228
  case 'NumberPicker':
74
229
  return /*#__PURE__*/_react["default"].createElement(NumberPickerAny, componentProps);
75
230
  case 'DatePicker':
76
- return /*#__PURE__*/_react["default"].createElement(DatePickerAny, componentProps);
231
+ return /*#__PURE__*/_react["default"].createElement(DatePickerAny, (0, _extends4["default"])({
232
+ format: "YYYY-MM-DD"
233
+ }, componentProps));
234
+ case 'DateTimePicker':
235
+ {
236
+ // 将 format / showTime 从 componentProps 中单独析构,防止 spread 覆盖我们的计算值
237
+ var cpFormat = componentProps.format,
238
+ _ignoredShowTime = componentProps.showTime,
239
+ restCp = (0, _objectWithoutPropertiesLoose2["default"])(componentProps, _excluded);
240
+ var dtFmt = cpFormat || 'YYYY-MM-DD HH:mm:ss';
241
+ // 提取日期部分(空格前)和时间部分(空格后)
242
+ // @alifd/next DatePicker 会将 format(日期)与 showTime.format(时间)拼接显示
243
+ // 若把含时间的完整格式传给 format,再传 showTime.format,会导致时间重复显示
244
+ var spaceIdx = dtFmt.indexOf(' ');
245
+ var dateFmt = spaceIdx !== -1 ? dtFmt.slice(0, spaceIdx) : dtFmt;
246
+ var timeFmt = spaceIdx !== -1 ? dtFmt.slice(spaceIdx + 1) : 'HH:mm:ss';
247
+ return /*#__PURE__*/_react["default"].createElement(DatePickerAny, (0, _extends4["default"])({}, restCp, {
248
+ format: dateFmt,
249
+ showTime: {
250
+ format: timeFmt
251
+ }
252
+ }));
253
+ }
77
254
  case 'Upload':
78
255
  return /*#__PURE__*/_react["default"].createElement(UploadAny, componentProps);
79
256
  case 'Input':
@@ -85,11 +262,16 @@ var CustomForm = function CustomForm(_ref) {
85
262
  var _ref$columns = _ref.columns,
86
263
  columns = _ref$columns === void 0 ? 1 : _ref$columns,
87
264
  _ref$spacing = _ref.spacing,
88
- spacing = _ref$spacing === void 0 ? [0, 16, 16, 0] : _ref$spacing,
265
+ spacing = _ref$spacing === void 0 ? [0, 16] : _ref$spacing,
89
266
  _ref$emptyContent = _ref.emptyContent,
90
267
  emptyContent = _ref$emptyContent === void 0 ? '添加表单项' : _ref$emptyContent,
91
268
  _ref$formItems = _ref.formItems,
92
269
  formItems = _ref$formItems === void 0 ? [] : _ref$formItems,
270
+ initialValues = _ref.initialValues,
271
+ computedFields = _ref.computedFields,
272
+ fieldLinkage = _ref.fieldLinkage,
273
+ submitMapping = _ref.submitMapping,
274
+ globalFullWidth = _ref.fullWidth,
93
275
  _ref$showSubmit = _ref.showSubmit,
94
276
  showSubmit = _ref$showSubmit === void 0 ? true : _ref$showSubmit,
95
277
  _ref$submitText = _ref.submitText,
@@ -103,33 +285,293 @@ var CustomForm = function CustomForm(_ref) {
103
285
  _ref$resetText = _ref.resetText,
104
286
  resetText = _ref$resetText === void 0 ? '重置' : _ref$resetText,
105
287
  resetButtonProps = _ref.resetButtonProps,
288
+ operations = _ref.operations,
289
+ _ref$operationAlign = _ref.operationAlign,
290
+ operationAlign = _ref$operationAlign === void 0 ? 'center' : _ref$operationAlign,
106
291
  onSubmit = _ref.onSubmit,
107
292
  onSubmitFailed = _ref.onSubmitFailed,
293
+ onChange = _ref.onChange,
294
+ onReset = _ref.onReset,
108
295
  children = _ref.children,
109
- otherProps = (0, _objectWithoutPropertiesLoose2["default"])(_ref, _excluded);
110
- var handleSubmit = (0, _react.useCallback)(function (values, errors, field) {
296
+ labelAlign = _ref.labelAlign,
297
+ labelCol = _ref.labelCol,
298
+ globalSize = _ref.size,
299
+ otherProps = (0, _objectWithoutPropertiesLoose2["default"])(_ref, _excluded2);
300
+ // ─── 直接传递列数,通过 device="desktop" 锁定成桌面模式,防止 ResponsiveGrid 根据视口自动缩列
301
+ // ResponsiveGrid columns 只接受 number/string,不接受 breakpoint 对象
302
+ var fixedColumns = columns;
303
+
304
+ // ─── 兼容旧版 4-value spacing → 标准化为 [rowGap, colGap] ─────────────────
305
+ var normalizedGap = (0, _react.useMemo)(function () {
306
+ var _spacing$, _spacing$2;
307
+ if (!Array.isArray(spacing)) return spacing;
308
+ if (spacing.length >= 2) return [spacing[0], spacing[1]];
309
+ return [(_spacing$ = spacing[0]) !== null && _spacing$ !== void 0 ? _spacing$ : 0, (_spacing$2 = spacing[0]) !== null && _spacing$2 !== void 0 ? _spacing$2 : 16];
310
+ }, [spacing]);
311
+
312
+ // ─── 标准化 initialValues / computedFields(支持设计器生成的数组格式与运行时对象格式)
313
+ var resolvedInitialValues = (0, _react.useMemo)(function () {
314
+ return normalizeInitialValues(initialValues);
315
+ }, [initialValues]);
316
+ var resolvedComputedFields = (0, _react.useMemo)(function () {
317
+ return normalizeComputedFields(computedFields);
318
+ }, [computedFields]);
319
+
320
+ // ─── 用 ref 缓存所有字段的当前值,避免 onChange 闭包过期 ──────────────────
321
+ // 初始化时直接合并 resolvedInitialValues,避免 useEffect 延迟问题
322
+ var valuesRef = (0, _react.useRef)(resolvedInitialValues ? (0, _extends4["default"])({}, resolvedInitialValues) : {});
323
+
324
+ // ─── 联动回填触发器:用 state 驱动组件重渲染以更新受控字段 ───────────────
325
+ // 注意:不预填 resolvedInitialValues,初始值通过 defaultValue(非受控)处理
326
+ // 预填会导致所有有初始值的字段变为受控组件,用户改值后因 linkageValues 未更新而回显旧值
327
+ var _useState = (0, _react.useState)({}),
328
+ linkageValues = _useState[0],
329
+ setLinkageValues = _useState[1];
330
+
331
+ // ─── 统一 onChange 处理器(阶段一 + 阶段二核心)─────────────────────────────
332
+ var handleFieldChange = (0, _react.useCallback)(function (field, value) {
333
+ var _extends2;
334
+ // 1. 更新本地 values 缓存
335
+ valuesRef.current = (0, _extends4["default"])({}, valuesRef.current, (_extends2 = {}, _extends2[field] = value, _extends2));
336
+ cfLog('onChange', "\u5B57\u6BB5 \"" + field + "\" \u53D8\u5316", {
337
+ value: value,
338
+ allValues: valuesRef.current
339
+ });
340
+
341
+ // 2. 字段联动(阶段二):检查是否有对应的联动规则
342
+ var linkagePatched = null;
343
+ if (fieldLinkage && fieldLinkage.length > 0) {
344
+ fieldLinkage.forEach(function (rule) {
345
+ if (rule.watchField !== field) return;
346
+
347
+ // 2a. 静态联动规则(高级格式)
348
+ if (rule.staticRules) {
349
+ var staticFill = rule.staticRules[String(value)];
350
+ if (staticFill) {
351
+ linkagePatched = (0, _extends4["default"])({}, linkagePatched || {}, staticFill);
352
+ Object.assign(valuesRef.current, staticFill);
353
+ cfLog('linkage', "\u9759\u6001\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", staticFill);
354
+ }
355
+ }
356
+
357
+ // 2b. 数据源动态联动(高级格式)
358
+ if (rule.dataSource && rule.fillFields) {
359
+ var matchKey = rule.matchKey || 'value';
360
+ var matched = rule.dataSource.find(function (item) {
361
+ return item[matchKey] === value;
362
+ });
363
+ if (matched) {
364
+ var fill = {};
365
+ Object.entries(rule.fillFields).forEach(function (_ref2) {
366
+ var formField = _ref2[0],
367
+ dsKey = _ref2[1];
368
+ fill[formField] = matched[dsKey];
369
+ });
370
+ linkagePatched = (0, _extends4["default"])({}, linkagePatched || {}, fill);
371
+ Object.assign(valuesRef.current, fill);
372
+ cfLog('linkage', "\u52A8\u6001\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", fill);
373
+ }
374
+ }
375
+
376
+ // 2c. 简单联动格式(新格式,属性面板可视化编辑生成)
377
+ if (rule.fillField !== undefined && rule.fillValue !== undefined) {
378
+ var noConstraint = rule.matchValue === undefined || rule.matchValue === '';
379
+ var _matched = noConstraint || String(value) === String(rule.matchValue);
380
+ if (_matched) {
381
+ var _fill2;
382
+ var _fill = (_fill2 = {}, _fill2[rule.fillField] = rule.fillValue, _fill2);
383
+ linkagePatched = (0, _extends4["default"])({}, linkagePatched || {}, _fill);
384
+ Object.assign(valuesRef.current, _fill);
385
+ cfLog('linkage', "\u7B80\u5355\u8054\u52A8 \"" + field + "\" = " + value + "\uFF0C\u56DE\u586B", _fill);
386
+ }
387
+ }
388
+ });
389
+ }
390
+ // 有联动回填时,更新 linkageValues 触发重渲染
391
+ if (linkagePatched) {
392
+ setLinkageValues(function (prev) {
393
+ return (0, _extends4["default"])({}, prev, linkagePatched);
394
+ });
395
+ }
396
+
397
+ // 3. 计算 computedFields,得到包含衍生字段的完整值
398
+ var allValues = applyComputedFields(valuesRef.current, resolvedComputedFields);
399
+
400
+ // 4. 触发外部 onChange 事件(低代码侧可绑定 updateVariable)
401
+ if (onChange) {
402
+ onChange(field, value, allValues);
403
+ }
404
+ }, [resolvedComputedFields, fieldLinkage, onChange]);
405
+
406
+ // ─── 提交处理 ───────────────────────────────────────────────────────────────
407
+ // ─── 对齐方式映射 ───────────────────────────────────────────────────────────
408
+ var alignJustifyMap = {
409
+ left: 'flex-start',
410
+ center: 'center',
411
+ right: 'flex-end'
412
+ };
413
+
414
+ // ─── 有效操作按钮列表 ────────────────────────────────────────────────────────
415
+ // operations prop 存在(哪怕是空数组)时:以 operations 为准,完全忽略旧版 showSubmit/showReset
416
+ // operations prop 为 undefined 时:回退到旧版双按钮模式(向后兼容)
417
+ var effectiveOperations = (0, _react.useMemo)(function () {
418
+ if (operations !== undefined) return operations;
419
+ var ops = [];
420
+ if (showReset) ops.push({
421
+ text: resetText || '重置',
422
+ action: 'reset',
423
+ type: 'normal'
424
+ });
425
+ if (showSubmit) ops.push({
426
+ text: submitText || '提交',
427
+ action: 'submit',
428
+ type: 'primary',
429
+ submitValidate: submitValidate
430
+ });
431
+ return ops;
432
+ }, [operations, showSubmit, submitText, submitValidate, showReset, resetText]);
433
+ var handleSubmit = (0, _react.useCallback)(function (values, errors, field, buttonDataSource) {
434
+ // 将 Form 收集的 values 与 ref 缓存合并(兼容 initialValues 未经 onChange 的字段)
435
+ var mergedValues = (0, _extends4["default"])({}, valuesRef.current, values);
436
+ // 追加 computedFields 衍生字段
437
+ var finalValues = applyComputedFields(mergedValues, resolvedComputedFields);
438
+
439
+ // submitMapping:按 mode 构建请求参数(阶段五)
440
+ if (submitMapping) {
441
+ var _submitMapping$mode, _submitMapping$items, _submitMapping$fieldR, _submitMapping$items2;
442
+ // 向后兼容:未设置 mode 时,有 items 数组则默认 itemList,否则 passthrough
443
+ var mode = (_submitMapping$mode = submitMapping.mode) !== null && _submitMapping$mode !== void 0 ? _submitMapping$mode : (_submitMapping$items = submitMapping.items) !== null && _submitMapping$items !== void 0 && _submitMapping$items.length ? 'itemList' : 'passthrough';
444
+ if (mode === 'rename' && (_submitMapping$fieldR = submitMapping.fieldRenameMap) !== null && _submitMapping$fieldR !== void 0 && _submitMapping$fieldR.length) {
445
+ // ── rename:重命名指定字段,其余字段按原名透传
446
+ var renamed = (0, _extends4["default"])({}, finalValues);
447
+ submitMapping.fieldRenameMap.forEach(function (_ref3) {
448
+ var fromField = _ref3.fromField,
449
+ toField = _ref3.toField;
450
+ if (fromField && toField && fromField in renamed) {
451
+ renamed[toField] = renamed[fromField];
452
+ if (fromField !== toField) delete renamed[fromField];
453
+ }
454
+ });
455
+ finalValues = renamed;
456
+ cfLog('submitMapping', 'rename 模式字段重命名完成', finalValues);
457
+ } else if (mode === 'itemList' && (_submitMapping$items2 = submitMapping.items) !== null && _submitMapping$items2 !== void 0 && _submitMapping$items2.length) {
458
+ var _extends3;
459
+ // ── itemList:转换为动态表单格式 [{columnName, columnValue}]
460
+ var targetField = submitMapping.targetField || 'itemList';
461
+ var itemList = submitMapping.items.map(function (mappingItem) {
462
+ var columnValue;
463
+ if (mappingItem.field) {
464
+ var _finalValues$mappingI;
465
+ columnValue = (_finalValues$mappingI = finalValues[mappingItem.field]) !== null && _finalValues$mappingI !== void 0 ? _finalValues$mappingI : '';
466
+ } else if (mappingItem.template) {
467
+ columnValue = renderTemplate(mappingItem.template, finalValues);
468
+ } else {
469
+ columnValue = '';
470
+ }
471
+ return {
472
+ columnName: mappingItem.columnName,
473
+ columnValue: columnValue
474
+ };
475
+ });
476
+ finalValues = (0, _extends4["default"])({}, finalValues, (_extends3 = {}, _extends3[targetField] = itemList, _extends3));
477
+ cfLog('submitMapping', "itemList \u6A21\u5F0F\u5DF2\u751F\u6210 " + targetField, itemList);
478
+ }
479
+ // passthrough: finalValues 直接作为请求参数,无需处理
480
+ }
481
+ cfLog('submit', '提交触发', {
482
+ rawValues: values,
483
+ errors: errors,
484
+ finalValues: finalValues
485
+ });
111
486
  if (errors && Object.keys(errors).length) {
487
+ cfWarn('submit', '校验失败', errors);
112
488
  if (onSubmitFailed) {
113
- onSubmitFailed(values, errors, field);
489
+ onSubmitFailed(finalValues, errors, field);
114
490
  }
115
491
  return;
116
492
  }
493
+ cfLog('submit', '校验通过,准备提交', finalValues);
117
494
  if (onSubmit) {
118
- onSubmit(values, errors, field);
495
+ onSubmit(finalValues, errors, field);
119
496
  }
120
- runSubmitDataSource(submitDataSource, values, errors, field);
121
- }, [onSubmit, onSubmitFailed, submitDataSource]);
497
+ // buttonDataSource:单个按钮绑定的数据源(优先);未绑定时回退到组件级 submitDataSource
498
+ var effectiveDS = buttonDataSource !== null && buttonDataSource !== void 0 ? buttonDataSource : submitDataSource;
499
+ runSubmitDataSource(effectiveDS, finalValues, errors, field);
500
+ }, [computedFields, submitMapping, onSubmit, onSubmitFailed, submitDataSource]);
501
+
502
+ // ─── 渲染表单项,绑定统一 onChange ──────────────────────────────────────────
122
503
  var formItemNodes = formItems.map(function (item, index) {
504
+ var _linkageValues$item$f, _item$componentProps;
123
505
  var colSpan = Math.min(columns, Math.max(1, item.columnSpan || 1));
124
- var formItemProps = item.formItemProps || {};
506
+
507
+ // 初始值优先级:item.initialValue > linkageValues[field](含联动回填)> initialValues[field]
508
+ var fieldInitialValue = item.initialValue !== undefined ? item.initialValue : (_linkageValues$item$f = linkageValues[item.field]) !== null && _linkageValues$item$f !== void 0 ? _linkageValues$item$f : resolvedInitialValues === null || resolvedInitialValues === void 0 ? void 0 : resolvedInitialValues[item.field];
509
+
510
+ // 包装组件的 onChange,注入 field 信息
511
+ // fullWidth 优先级:item.fullWidth(单项)> globalFullWidth(全局)> undefined(不限制)
512
+ var effectiveFullWidth = item.fullWidth !== undefined ? item.fullWidth : globalFullWidth;
513
+ // 有效尺寸:单项 > 全局 > undefined(继承 Form 默认)
514
+ var effectiveSize = item.size || globalSize;
515
+ var componentPropsWithChange = (0, _extends4["default"])({}, item.placeholder ? {
516
+ placeholder: item.placeholder
517
+ } : {}, effectiveSize ? {
518
+ size: effectiveSize
519
+ } : {}, effectiveFullWidth !== undefined ? {
520
+ style: (0, _extends4["default"])({
521
+ width: effectiveFullWidth ? '100%' : undefined
522
+ }, ((_item$componentProps = item.componentProps) === null || _item$componentProps === void 0 ? void 0 : _item$componentProps.style) || {})
523
+ } : {}, item.componentProps || {}, {
524
+ onChange: function onChange(value) {
525
+ var _item$componentProps2;
526
+ if (typeof ((_item$componentProps2 = item.componentProps) === null || _item$componentProps2 === void 0 ? void 0 : _item$componentProps2.onChange) === 'function') {
527
+ item.componentProps.onChange(value);
528
+ }
529
+ // DatePicker / DateTimePicker 的 onChange 返回 Moment 对象,需格式化为字符串后再存储
530
+ var storedValue = value;
531
+ if (['DatePicker', 'DateTimePicker'].includes(item.componentType) && value && typeof value.format === 'function') {
532
+ var _item$componentProps3;
533
+ var fmt = ((_item$componentProps3 = item.componentProps) === null || _item$componentProps3 === void 0 ? void 0 : _item$componentProps3.format) || (item.componentType === 'DateTimePicker' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD');
534
+ storedValue = value.format(fmt);
535
+ }
536
+ handleFieldChange(item.field, storedValue);
537
+ }
538
+ });
539
+
540
+ // 联动回填时,通过 value(受控)覆盖字段值;否则只用 defaultValue
541
+ var isLinkageControlled = linkageValues[item.field] !== undefined && item.initialValue === undefined;
542
+ if (isLinkageControlled) {
543
+ componentPropsWithChange.value = linkageValues[item.field];
544
+ } else if (fieldInitialValue !== undefined && componentPropsWithChange.value === undefined) {
545
+ componentPropsWithChange.defaultValue = fieldInitialValue;
546
+ cfLog('renderItem', "\u5B57\u6BB5 \"" + item.field + "\" \u6CE8\u5165\u521D\u59CB\u503C", fieldInitialValue);
547
+ }
548
+ if (!item.field) {
549
+ cfWarn('renderItem', "\u7B2C " + (index + 1) + " \u4E2A\u8868\u5355\u9879\u7F3A\u5C11 field \u5B57\u6BB5\uFF0ConChange \u5C06\u65E0\u6CD5\u7ED1\u5B9A");
550
+ }
551
+
552
+ // 合并 Form.Item 属性:通用属性 < 快捷字段 < formItemProps(最高优先级)
553
+ // labelAlign / labelCol 显式传入,确保设计器中不依赖 Form context 也能生效
554
+ var mergedFormItemProps = (0, _extends4["default"])({}, labelAlign ? {
555
+ labelAlign: labelAlign
556
+ } : {}, labelCol ? {
557
+ labelCol: labelCol
558
+ } : {}, effectiveSize ? {
559
+ size: effectiveSize
560
+ } : {}, item.help ? {
561
+ help: item.help
562
+ } : {}, item.extra ? {
563
+ extra: item.extra
564
+ } : {}, item.formItemProps || {});
125
565
  return /*#__PURE__*/_react["default"].createElement(ResponsiveGridCell, {
126
566
  colSpan: colSpan,
127
567
  key: (item.field || index) + "-form-item"
128
- }, /*#__PURE__*/_react["default"].createElement(FormItemAny, (0, _extends2["default"])({
568
+ }, /*#__PURE__*/_react["default"].createElement(FormItemAny, (0, _extends4["default"])({
129
569
  label: item.label,
130
570
  name: item.field,
131
571
  required: item.required
132
- }, formItemProps), renderFormItemComponent(item)));
572
+ }, mergedFormItemProps), renderFormItemComponent((0, _extends4["default"])({}, item, {
573
+ componentProps: componentPropsWithChange
574
+ }))));
133
575
  });
134
576
  var childrenNodes = _react["default"].Children.toArray(children).map(function (child, index) {
135
577
  if (/*#__PURE__*/_react["default"].isValidElement(child) && child.type === ResponsiveGridCell) {
@@ -141,24 +583,62 @@ var CustomForm = function CustomForm(_ref) {
141
583
  }, child);
142
584
  });
143
585
  var hasContent = formItemNodes.length > 0 || childrenNodes.length > 0;
144
- return /*#__PURE__*/_react["default"].createElement(NextFormAny, (0, _extends2["default"])({
586
+
587
+ // initialValues 通过 defaultValue 传入 Form(非受控初始化),避免覆盖联动回填的受控值
588
+ var formInitialProps = {};
589
+ if (initialValues && Object.keys(initialValues).length > 0) {
590
+ formInitialProps.defaultValue = initialValues;
591
+ cfLog('render', '表单携带 initialValues 渲染', initialValues);
592
+ }
593
+ return /*#__PURE__*/_react["default"].createElement(NextFormAny, (0, _extends4["default"])({
145
594
  className: "custom-form"
146
- }, otherProps), hasContent ? /*#__PURE__*/_react["default"].createElement(ResponsiveGridAny, {
595
+ }, labelAlign ? {
596
+ labelAlign: labelAlign
597
+ } : {}, labelCol ? {
598
+ labelCol: labelCol
599
+ } : {}, globalSize ? {
600
+ size: globalSize
601
+ } : {}, formInitialProps, otherProps), hasContent ? /*#__PURE__*/_react["default"].createElement(ResponsiveGridAny, {
147
602
  className: "custom-form__grid",
148
- gap: spacing,
149
- columns: columns
603
+ device: "desktop",
604
+ gap: normalizedGap,
605
+ columns: fixedColumns
150
606
  }, formItemNodes, childrenNodes) : /*#__PURE__*/_react["default"].createElement("div", {
151
607
  className: "custom-form__empty"
152
- }, emptyContent), showSubmit || showReset ? /*#__PURE__*/_react["default"].createElement("div", {
153
- className: "custom-form__actions"
154
- }, showReset ? /*#__PURE__*/_react["default"].createElement(NextFormAny.Reset, (0, _extends2["default"])({
155
- className: "custom-form__reset"
156
- }, resetButtonProps), resetText) : null, showSubmit ? /*#__PURE__*/_react["default"].createElement(NextFormAny.Submit, (0, _extends2["default"])({
157
- className: "custom-form__submit",
158
- type: "primary",
159
- validate: submitValidate,
160
- onClick: handleSubmit
161
- }, submitButtonProps), submitText) : null) : null);
608
+ }, emptyContent), effectiveOperations.length > 0 ? /*#__PURE__*/_react["default"].createElement("div", {
609
+ className: "custom-form__actions",
610
+ style: {
611
+ justifyContent: alignJustifyMap[operationAlign] || 'center'
612
+ }
613
+ }, effectiveOperations.map(function (op, opIndex) {
614
+ // ── 重置按钮 ─────────────────────────────────────────────────────
615
+ if (op.action === 'reset') {
616
+ return /*#__PURE__*/_react["default"].createElement(NextFormAny.Reset, (0, _extends4["default"])({
617
+ key: opIndex,
618
+ type: op.type || 'normal',
619
+ onClick: onReset
620
+ }, op.buttonProps || {}), op.text);
621
+ }
622
+ // ── 提交按钮 ─────────────────────────────────────────────────────
623
+ if (op.action === 'submit') {
624
+ // 每个提交按钮独立决定是否校验:per-button > 全局 submitValidate
625
+ var btnValidate = op.submitValidate !== undefined ? op.submitValidate : submitValidate;
626
+ return /*#__PURE__*/_react["default"].createElement(NextFormAny.Submit, (0, _extends4["default"])({
627
+ key: opIndex,
628
+ type: op.type || 'primary',
629
+ validate: btnValidate,
630
+ onClick: function onClick(values, errors, field) {
631
+ return handleSubmit(values, errors, field, op.dataSource);
632
+ }
633
+ }, op.buttonProps || {}), op.text);
634
+ }
635
+ // ── 自定义按钮 ───────────────────────────────────────────────────
636
+ return /*#__PURE__*/_react["default"].createElement(ButtonAny, (0, _extends4["default"])({
637
+ key: opIndex,
638
+ type: op.type || 'normal',
639
+ onClick: op.onClick
640
+ }, op.buttonProps || {}), op.text);
641
+ })) : null);
162
642
  };
163
643
  CustomForm.displayName = 'CustomForm';
164
644
  var _default = exports["default"] = CustomForm;
@@ -2,5 +2,5 @@
2
2
  * 自定义表单
3
3
  */
4
4
  import CustomForm from './custom-form';
5
- export type { CustomFormProps, CustomFormItemSchema, CustomFormItemType } from './custom-form';
5
+ export type { CustomFormProps, CustomFormItemSchema, CustomFormItemType, ComputedFields } from './custom-form';
6
6
  export { CustomForm };