@nokecy/qc-ui 1.1.82 → 1.1.83

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.
@@ -150,6 +150,15 @@ var ArrayTableInner = (0, _react2.observer)(function (props) {
150
150
  return cols;
151
151
  }, [sources, props.onRowDrag]); // 移除 field 依赖,避免数据变化时重新计算
152
152
 
153
+ // 懒挂载的格子不创建 Formily 字段,schema 的 default 不会自己写进值:行出现时补一次(每行只补一次)。@author nokecy
154
+ var lazyDefaults = (0, _react.useMemo)(function () {
155
+ return (0, _utils.collectLazyDefaults)(stableColumnDefs);
156
+ }, [stableColumnDefs]);
157
+ var defaultedRowsRef = (0, _react.useRef)(new WeakSet());
158
+ (0, _react.useEffect)(function () {
159
+ if (lazyDefaults.length > 0) (0, _utils.applyLazyDefaults)(field, lazyDefaults, defaultedRowsRef.current);
160
+ });
161
+
153
162
  // 交给 AgGridReact 的列定义:按 x-component-props.headerGroup 把相邻同组的列合并成列组(多级表头)。
154
163
  // stableColumnDefs 保持扁平,懒列识别、列方案还原等内部逻辑仍用它;只有喂给 AG-Grid 的这一份带分组。@author nokecy
155
164
  var gridColumnDefs = (0, _react.useMemo)(function () {
@@ -4,6 +4,11 @@ export type ReadOnlyFormatterCtx = {
4
4
  columnProps: any;
5
5
  /** 内层数据字段的 schema(可读 enum / x-component-props) */
6
6
  fieldSchema: any;
7
+ /**
8
+ * 运行时才确定的选项(field.setDataSource / setFieldState 写入的 dataSource)。
9
+ * 懒挂载格子没有自己的 Formily 字段时,由调用方取同列已创建字段的选项带进来;有值时优先于 schema 静态选项。
10
+ */
11
+ dataSource?: any[];
7
12
  };
8
13
  export type ReadOnlyFormatter = (value: any, ctx: ReadOnlyFormatterCtx) => string;
9
14
  /**
@@ -32,6 +32,7 @@ var resolveOptions = function resolveOptions(ctx) {
32
32
  var _ref, _ref2, _ref3, _fieldSchema$enum, _fieldSchema$xCompon, _fieldSchema$xCompon2;
33
33
  var columnProps = ctx.columnProps,
34
34
  fieldSchema = ctx.fieldSchema;
35
+ if (Array.isArray(ctx.dataSource) && ctx.dataSource.length > 0) return ctx.dataSource;
35
36
  var candidate = (_ref = (_ref2 = (_ref3 = (_fieldSchema$enum = fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema.enum) !== null && _fieldSchema$enum !== void 0 ? _fieldSchema$enum : fieldSchema === null || fieldSchema === void 0 || (_fieldSchema$xCompon = fieldSchema['x-component-props']) === null || _fieldSchema$xCompon === void 0 ? void 0 : _fieldSchema$xCompon.options) !== null && _ref3 !== void 0 ? _ref3 : fieldSchema === null || fieldSchema === void 0 || (_fieldSchema$xCompon2 = fieldSchema['x-component-props']) === null || _fieldSchema$xCompon2 === void 0 ? void 0 : _fieldSchema$xCompon2.dataSource) !== null && _ref2 !== void 0 ? _ref2 : columnProps === null || columnProps === void 0 ? void 0 : columnProps.options) !== null && _ref !== void 0 ? _ref : columnProps === null || columnProps === void 0 ? void 0 : columnProps.dataSource;
36
37
  return Array.isArray(candidate) ? candidate : [];
37
38
  };
@@ -64,20 +65,63 @@ var selectFormatter = function selectFormatter(value, ctx) {
64
65
  }
65
66
  return mapOptionLabel(value, options);
66
67
  };
68
+
69
+ /**
70
+ * 日期/时间控件没写 format 时的默认显示格式,与 antd 控件自己的默认一致:
71
+ * TimePicker 只显示时间;showTime 带到秒;按月/按年选择器只显示到月/年。
72
+ * 文本态与点开后的控件看到同一个格式,不然 showTime 的列平时只见日期、点开才见时间。
73
+ */
74
+ var defaultDateFormat = function defaultDateFormat(component, props) {
75
+ if (component === 'TimePicker') return props !== null && props !== void 0 && props.use12Hours ? 'hh:mm:ss a' : 'HH:mm:ss';
76
+ if ((props === null || props === void 0 ? void 0 : props.picker) === 'month') return 'YYYY-MM';
77
+ if ((props === null || props === void 0 ? void 0 : props.picker) === 'year') return 'YYYY';
78
+ if (props !== null && props !== void 0 && props.showTime) return 'YYYY-MM-DD HH:mm:ss';
79
+ return 'YYYY-MM-DD';
80
+ };
67
81
  var dateFormatter = function dateFormatter(value, ctx) {
68
- var _ref6, _ctx$columnProps$form, _ctx$columnProps, _ctx$fieldSchema;
82
+ var _ctx$fieldSchema, _ctx$columnProps, _ctx$fieldSchema2;
69
83
  if (value == null || value === '') return '';
70
- var fmt = (_ref6 = (_ctx$columnProps$form = (_ctx$columnProps = ctx.columnProps) === null || _ctx$columnProps === void 0 ? void 0 : _ctx$columnProps.format) !== null && _ctx$columnProps$form !== void 0 ? _ctx$columnProps$form : (_ctx$fieldSchema = ctx.fieldSchema) === null || _ctx$fieldSchema === void 0 || (_ctx$fieldSchema = _ctx$fieldSchema['x-component-props']) === null || _ctx$fieldSchema === void 0 ? void 0 : _ctx$fieldSchema.format) !== null && _ref6 !== void 0 ? _ref6 : 'YYYY-MM-DD';
84
+ var props = (_ctx$fieldSchema = ctx.fieldSchema) === null || _ctx$fieldSchema === void 0 ? void 0 : _ctx$fieldSchema['x-component-props'];
85
+ // antd 的 format 还可以是数组/函数,文本态只认字符串,其余回到默认
86
+ var configured = [(_ctx$columnProps = ctx.columnProps) === null || _ctx$columnProps === void 0 ? void 0 : _ctx$columnProps.format, props === null || props === void 0 ? void 0 : props.format].find(function (f) {
87
+ return typeof f === 'string' && f;
88
+ });
89
+ var fmt = configured !== null && configured !== void 0 ? configured : defaultDateFormat((_ctx$fieldSchema2 = ctx.fieldSchema) === null || _ctx$fieldSchema2 === void 0 ? void 0 : _ctx$fieldSchema2['x-component'], props);
71
90
  if (typeof value.format === 'function') return value.format(fmt);
72
91
  // 后端回来的多是 ISO 串(2024-10-19T00:00:00)或时间戳:与 Formily readPretty 一致,按 dayjs(value).format(fmt) 显示;
73
- // 解析不了的文本(如「待定」)原样显示,不吞掉。dayjs 随 antd 传递依赖引入,本库其他模块已直接使用。
92
+ // 解析不了的文本(如「待定」、纯时间 08:30:00)原样显示,不吞掉。dayjs 随 antd 传递依赖引入,本库其他模块已直接使用。
74
93
  var parsed = (0, _dayjs.default)(value);
75
94
  return parsed.isValid() ? parsed.format(fmt) : String(value);
76
95
  };
96
+
97
+ /**
98
+ * 数字格:按控件的 precision 补齐小数位、按 formatter 属性(千分位、百分号等)显示,
99
+ * 与点开后的 InputNumber 一致;没配这两项时与原样输出相同。
100
+ */
101
+ var numberFormatter = function numberFormatter(value, ctx) {
102
+ var _ctx$fieldSchema$xCo, _ctx$fieldSchema3, _ctx$columnProps$prec, _ctx$columnProps2, _ctx$columnProps$form, _ctx$columnProps3;
103
+ if (value == null || value === '') return '';
104
+ var props = (_ctx$fieldSchema$xCo = (_ctx$fieldSchema3 = ctx.fieldSchema) === null || _ctx$fieldSchema3 === void 0 ? void 0 : _ctx$fieldSchema3['x-component-props']) !== null && _ctx$fieldSchema$xCo !== void 0 ? _ctx$fieldSchema$xCo : {};
105
+ var precision = (_ctx$columnProps$prec = (_ctx$columnProps2 = ctx.columnProps) === null || _ctx$columnProps2 === void 0 ? void 0 : _ctx$columnProps2.precision) !== null && _ctx$columnProps$prec !== void 0 ? _ctx$columnProps$prec : props.precision;
106
+ var num = Number(value);
107
+ var base = typeof precision === 'number' && precision >= 0 && Number.isFinite(num) ? num.toFixed(precision) : String(value);
108
+ var formatter = (_ctx$columnProps$form = (_ctx$columnProps3 = ctx.columnProps) === null || _ctx$columnProps3 === void 0 ? void 0 : _ctx$columnProps3.formatter) !== null && _ctx$columnProps$form !== void 0 ? _ctx$columnProps$form : props.formatter;
109
+ if (typeof formatter === 'function') {
110
+ try {
111
+ return String(formatter(base, {
112
+ userTyping: false,
113
+ input: ''
114
+ }));
115
+ } catch (_unused) {
116
+ return base;
117
+ }
118
+ }
119
+ return base;
120
+ };
77
121
  var booleanFormatter = function booleanFormatter(value, ctx) {
78
- var _ctx$fieldSchema$xCo, _ctx$fieldSchema2, _props$checkedChildre, _props$unCheckedChild;
122
+ var _ctx$fieldSchema$xCo2, _ctx$fieldSchema4, _props$checkedChildre, _props$unCheckedChild;
79
123
  if (value == null || value === '') return '';
80
- var props = (_ctx$fieldSchema$xCo = (_ctx$fieldSchema2 = ctx.fieldSchema) === null || _ctx$fieldSchema2 === void 0 ? void 0 : _ctx$fieldSchema2['x-component-props']) !== null && _ctx$fieldSchema$xCo !== void 0 ? _ctx$fieldSchema$xCo : {};
124
+ var props = (_ctx$fieldSchema$xCo2 = (_ctx$fieldSchema4 = ctx.fieldSchema) === null || _ctx$fieldSchema4 === void 0 ? void 0 : _ctx$fieldSchema4['x-component-props']) !== null && _ctx$fieldSchema$xCo2 !== void 0 ? _ctx$fieldSchema$xCo2 : {};
81
125
  var truthy = (_props$checkedChildre = props.checkedChildren) !== null && _props$checkedChildre !== void 0 ? _props$checkedChildre : '是';
82
126
  var falsy = (_props$unCheckedChild = props.unCheckedChildren) !== null && _props$unCheckedChild !== void 0 ? _props$unCheckedChild : '否';
83
127
  return value ? String(truthy) : String(falsy);
@@ -93,8 +137,8 @@ var registry = {
93
137
  Password: textFormatter,
94
138
  Text: textFormatter,
95
139
  Preview: textFormatter,
96
- NumberPicker: textFormatter,
97
- InputNumber: textFormatter,
140
+ NumberPicker: numberFormatter,
141
+ InputNumber: numberFormatter,
98
142
  Select: selectFormatter,
99
143
  TreeSelect: selectFormatter,
100
144
  Cascader: selectFormatter,
@@ -152,17 +196,17 @@ var registerReadOnlyLabels = exports.registerReadOnlyLabels = function registerR
152
196
  if (o && o.value != null) map.set(String(o.value), String((_o$label = o.label) !== null && _o$label !== void 0 ? _o$label : o.value));
153
197
  });
154
198
  } else {
155
- Object.entries(labels !== null && labels !== void 0 ? labels : {}).forEach(function (_ref7) {
156
- var _ref8 = _slicedToArray(_ref7, 2),
157
- k = _ref8[0],
158
- v = _ref8[1];
199
+ Object.entries(labels !== null && labels !== void 0 ? labels : {}).forEach(function (_ref6) {
200
+ var _ref7 = _slicedToArray(_ref6, 2),
201
+ k = _ref7[0],
202
+ v = _ref7[1];
159
203
  return map.set(String(k), String(v));
160
204
  });
161
205
  }
162
206
  var toText = function toText(v) {
163
- var _ref9, _v$label, _map$get;
207
+ var _ref8, _v$label, _map$get;
164
208
  if (v == null || v === '') return '';
165
- if (_typeof(v) === 'object') return String((_ref9 = (_v$label = v.label) !== null && _v$label !== void 0 ? _v$label : v.value) !== null && _ref9 !== void 0 ? _ref9 : '');
209
+ if (_typeof(v) === 'object') return String((_ref8 = (_v$label = v.label) !== null && _v$label !== void 0 ? _v$label : v.value) !== null && _ref8 !== void 0 ? _ref8 : '');
166
210
  return (_map$get = map.get(String(v))) !== null && _map$get !== void 0 ? _map$get : String(v);
167
211
  };
168
212
  var formatter = function formatter(value) {
@@ -41,3 +41,20 @@ declare const LazyReadOnlyText: (params: any) => React.JSX.Element;
41
41
  declare const buildArrayTableColumns: (dataSource: any[], field: ArrayField, sources: ObservableColumnSource[]) => AgGridReactProps['columnDefs'];
42
42
  declare const useAddition: () => React.JSX.Element | null;
43
43
  export { isColumnComponent, useArrayTableSources, useArrayTableActions, buildArrayTableColumns, useAddition, LazyAgField, LazyReadOnlyText };
44
+ export type LazyColumnDefault = {
45
+ key: string;
46
+ value: any;
47
+ };
48
+ /**
49
+ * 收集懒挂载列上声明了 default 的字段。
50
+ *
51
+ * Formily 在字段创建时把 schema 的 default 写进值(值为空时)。懒挂载的格子不创建字段,
52
+ * 老记录里缺的列、代码直接 push 的行就拿不到默认值,保存时是 null。
53
+ * 表达式形态的默认值({{...}})要求值上下文,这里不处理。@author nokecy
54
+ */
55
+ export declare const collectLazyDefaults: (columns: any[]) => LazyColumnDefault[];
56
+ /**
57
+ * 给还没处理过的新增行补默认值:值为空(null/undefined)才写,每行只补一次——
58
+ * 用户之后把格子清空是有意的,不能再被填回去。已落库的行(带 id)不动。@author nokecy
59
+ */
60
+ export declare const applyLazyDefaults: (arrayField: any, defaults: LazyColumnDefault[], handled: WeakSet<object>) => void;
@@ -3,10 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.useArrayTableSources = exports.useArrayTableActions = exports.useAddition = exports.isColumnComponent = exports.buildArrayTableColumns = exports.LazyReadOnlyText = exports.LazyAgField = void 0;
6
+ exports.useArrayTableSources = exports.useArrayTableActions = exports.useAddition = exports.isColumnComponent = exports.collectLazyDefaults = exports.buildArrayTableColumns = exports.applyLazyDefaults = exports.LazyReadOnlyText = exports.LazyAgField = void 0;
7
7
  var _react = _interopRequireWildcard(require("react"));
8
8
  var _antd = require("antd");
9
9
  var _react2 = require("@formily/react");
10
+ var _reactive = require("@formily/reactive");
10
11
  var _shared = require("@formily/shared");
11
12
  var _jsonSchema = require("@formily/json-schema");
12
13
  var _arrayBase = _interopRequireDefault(require("./arrayBase"));
@@ -306,6 +307,20 @@ var hasRequiredRule = function hasRequiredRule(rule) {
306
307
  return false;
307
308
  };
308
309
 
310
+ /**
311
+ * 数据字段是否挂了任何校验规则。
312
+ *
313
+ * 懒挂载的格子没有 Formily 字段,提交时 form.validate 碰不到它。必填规则能静态识别,
314
+ * 但「自定义 validator 函数里判空」「必填写在校验规则的其他形态里」识别不了——
315
+ * 这类列的空格子若不挂真控件,空值会绕过校验直接提交。故有校验规则的列,空格子按必填一样挂真控件。
316
+ * 有值的格子里不合格式的内容不在此列(要挂全部校验过的格子等于取消懒挂载)。@author nokecy
317
+ */
318
+ var hasValidatorRule = function hasValidatorRule(fieldSchema) {
319
+ var validator = fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema['x-validator'];
320
+ if (validator == null || validator === '') return false;
321
+ return Array.isArray(validator) ? validator.length > 0 : true;
322
+ };
323
+
309
324
  /**
310
325
  * 数据字段是否必填(静态判定):字段上写了 required,或 x-validator 里带 required 规则。
311
326
  *
@@ -420,6 +435,28 @@ var LazyAgField = exports.LazyAgField = function LazyAgField(params) {
420
435
  };
421
436
  }();
422
437
 
438
+ /**
439
+ * 运行时设置的选项(field.setDataSource / setFieldState dataSource)。
440
+ *
441
+ * 只取本格自己的字段:点开过的格子字段还在,失焦卸回文本后仍按名称显示。
442
+ * 不借同列其他格的选项——选项常常按行不同(如标签类型跟随同行的打印功能),借来的选项会把值映射成别的名称,
443
+ * 比显示原编码更糟。从未点开过的格子没有字段,要显示名称请把选项写进 Schema(x-component-props.options)。
444
+ * 仅选项类组件且有值时才查;按精确地址取、放在 untracked 里,不让每个格子都订阅整张字段表。@author nokecy
445
+ */
446
+ var liveDataSource = function liveDataSource(liveValue) {
447
+ var _field$value$indexOf4, _field$value4, _field$value4$indexOf;
448
+ var form = field === null || field === void 0 ? void 0 : field.form;
449
+ // 只有用「选项映射」格式化器的列(Select 一族,或登记为同一格式化器的组件)才需要运行时选项
450
+ if (!form || !dataKey || isBlank(liveValue) || formatter !== (0, _readOnlyFormatters.getReadOnlyFormatter)('Select')) return undefined;
451
+ var index = (_field$value$indexOf4 = field === null || field === void 0 || (_field$value4 = field.value) === null || _field$value4 === void 0 || (_field$value4$indexOf = _field$value4.indexOf) === null || _field$value4$indexOf === void 0 ? void 0 : _field$value4$indexOf.call(_field$value4, record)) !== null && _field$value$indexOf4 !== void 0 ? _field$value$indexOf4 : -1;
452
+ if (index < 0) return undefined;
453
+ var own = (0, _reactive.untracked)(function () {
454
+ return form.query(field.path.concat(index).concat(dataKey)).take();
455
+ });
456
+ var source = own === null || own === void 0 ? void 0 : own.dataSource;
457
+ return Array.isArray(source) && source.length > 0 ? source : undefined;
458
+ };
459
+
423
460
  // Observer 让本格反应式跟随内层 Formily 字段值。
424
461
  // record 即 field.value[index] 的可观察对象;在 Observer 里按内层字段名直接读 record[dataKey]
425
462
  // (而非 AG-Grid 渲染时快照的 params.value)建立依赖后,onFieldValueChange/setValuesIn 程序化原地
@@ -452,10 +489,12 @@ var LazyAgField = exports.LazyAgField = function LazyAgField(params) {
452
489
  node: node
453
490
  }));
454
491
  }
455
- var text = formatter ? formatter(liveValue, {
492
+ var ctx = {
456
493
  columnProps: columnProps,
457
- fieldSchema: fieldSchema
458
- }) : liveValue == null ? '' : String(liveValue);
494
+ fieldSchema: fieldSchema,
495
+ dataSource: activated ? undefined : liveDataSource(liveValue)
496
+ };
497
+ var text = formatter ? formatter(liveValue, ctx) : liveValue == null ? '' : String(liveValue);
459
498
  // 纯文本占满单元格,点击交给 AG-Grid onCellClicked 激活;样式尽量贴近 Editable 只读态避免点开跳动
460
499
  // 只读态(readPretty/disabled/readOnly)的空格不出编辑提示,留空与只读快路径一致
461
500
  var pattern = text === '' ? resolveLazyCellPattern(field, record, dataKey, fieldSchema, scope) : undefined;
@@ -472,10 +511,7 @@ var LazyAgField = exports.LazyAgField = function LazyAgField(params) {
472
511
  }, resolveEmptyPlaceholder(fieldSchema));
473
512
  }
474
513
  // 登记了只读渲染器的组件(如带颜色的 Tag)按渲染器出内容,与组件自己的阅读态一致
475
- var shown = renderer && text !== '' ? renderer(liveValue, {
476
- columnProps: columnProps,
477
- fieldSchema: fieldSchema
478
- }) : text;
514
+ var shown = renderer && text !== '' ? renderer(liveValue, ctx) : text;
479
515
  return /*#__PURE__*/_react.default.createElement("span", {
480
516
  className: "ag-array-table-lazy-text",
481
517
  style: {
@@ -737,7 +773,8 @@ var buildArrayTableColumns = exports.buildArrayTableColumns = function buildArra
737
773
  fieldSchema: dataField,
738
774
  lazyEditable: true,
739
775
  // 供 index.tsx 识别懒列(激活/导航用)
740
- required: isRequiredSchema(dataField) // 必填且为空的格必须挂真控件,见 LazyAgField
776
+ // 必填、或带校验规则且为空的格必须挂真控件,否则没有字段节点,提交时没人校验它,见 LazyAgField
777
+ required: isRequiredSchema(dataField) || hasValidatorRule(dataField)
741
778
  }
742
779
  }));
743
780
  }
@@ -764,4 +801,54 @@ var useAddition = exports.useAddition = function useAddition() {
764
801
  }
765
802
  return addition;
766
803
  }, null);
804
+ };
805
+ /** 简单字段名(非路径、非解构),默认值回填只处理这一种 */
806
+ var SIMPLE_FIELD_NAME = /^[A-Za-z_$][\w$]*$/;
807
+ /**
808
+ * 收集懒挂载列上声明了 default 的字段。
809
+ *
810
+ * Formily 在字段创建时把 schema 的 default 写进值(值为空时)。懒挂载的格子不创建字段,
811
+ * 老记录里缺的列、代码直接 push 的行就拿不到默认值,保存时是 null。
812
+ * 表达式形态的默认值({{...}})要求值上下文,这里不处理。@author nokecy
813
+ */
814
+ var collectLazyDefaults = exports.collectLazyDefaults = function collectLazyDefaults(columns) {
815
+ return (columns !== null && columns !== void 0 ? columns : []).filter(function (col) {
816
+ var _col$cellRendererPara;
817
+ return col === null || col === void 0 || (_col$cellRendererPara = col.cellRendererParams) === null || _col$cellRendererPara === void 0 ? void 0 : _col$cellRendererPara.lazyEditable;
818
+ }).map(function (col) {
819
+ var _fieldSchema$name3;
820
+ var fieldSchema = col.cellRendererParams.fieldSchema;
821
+ return {
822
+ key: String((_fieldSchema$name3 = fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema.name) !== null && _fieldSchema$name3 !== void 0 ? _fieldSchema$name3 : col.field),
823
+ value: fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema.default
824
+ };
825
+ }).filter(function (_ref7) {
826
+ var key = _ref7.key,
827
+ value = _ref7.value;
828
+ return SIMPLE_FIELD_NAME.test(key) && value !== undefined && value !== null && !(typeof value === 'string' && value.includes('{{'));
829
+ });
830
+ };
831
+
832
+ /**
833
+ * 给还没处理过的新增行补默认值:值为空(null/undefined)才写,每行只补一次——
834
+ * 用户之后把格子清空是有意的,不能再被填回去。已落库的行(带 id)不动。@author nokecy
835
+ */
836
+ var applyLazyDefaults = exports.applyLazyDefaults = function applyLazyDefaults(arrayField, defaults, handled) {
837
+ var rows = arrayField === null || arrayField === void 0 ? void 0 : arrayField.value;
838
+ var form = arrayField === null || arrayField === void 0 ? void 0 : arrayField.form;
839
+ if (!Array.isArray(rows) || !form || defaults.length === 0) return;
840
+ rows.forEach(function (row, index) {
841
+ if (row == null || _typeof(row) !== 'object' || handled.has(row)) return;
842
+ handled.add(row);
843
+ // 已落库的行(带 id)保持库里的样子:补默认值会让受控字段凭空出现「变更」,
844
+ // 已审批的数据保存时还会被要求填变更原因。只补新增行(按钮之外的途径推进来的行)。
845
+ if (row.id != null || row._id != null) return;
846
+ defaults.forEach(function (_ref8) {
847
+ var key = _ref8.key,
848
+ value = _ref8.value;
849
+ if (row[key] == null) {
850
+ form.setValuesIn(arrayField.path.concat(index).concat(key), _typeof(value) === 'object' ? JSON.parse(JSON.stringify(value)) : value);
851
+ }
852
+ });
853
+ });
767
854
  };
@@ -17,7 +17,7 @@ import { useField, observer, RecursionField } from "@formily/react";
17
17
  import { useFieldSchema } from "@formily/react";
18
18
  import { connect, mapProps, mapReadPretty } from "@formily/react";
19
19
  import uniqueId from "lodash/uniqueId";
20
- import { useAddition, buildArrayTableColumns, useArrayTableSources, useArrayTableActions, isColumnComponent } from "./utils";
20
+ import { useAddition, buildArrayTableColumns, useArrayTableSources, useArrayTableActions, isColumnComponent, collectLazyDefaults, applyLazyDefaults } from "./utils";
21
21
  import { groupColumnDefs } from "./columnGroup";
22
22
  import { ARRAY_TABLE_INDEX_FIELD, hasOwnIndexColumn, makeIndexColumn } from "./indexColumn";
23
23
  import { useCellFocus, useKeyboardNavigation, useRowDrag, suppressNativeInputKeys } from "./hooks";
@@ -146,6 +146,15 @@ var ArrayTableInner = observer(function (props) {
146
146
  return cols;
147
147
  }, [sources, props.onRowDrag]); // 移除 field 依赖,避免数据变化时重新计算
148
148
 
149
+ // 懒挂载的格子不创建 Formily 字段,schema 的 default 不会自己写进值:行出现时补一次(每行只补一次)。@author nokecy
150
+ var lazyDefaults = useMemo(function () {
151
+ return collectLazyDefaults(stableColumnDefs);
152
+ }, [stableColumnDefs]);
153
+ var defaultedRowsRef = useRef(new WeakSet());
154
+ useEffect(function () {
155
+ if (lazyDefaults.length > 0) applyLazyDefaults(field, lazyDefaults, defaultedRowsRef.current);
156
+ });
157
+
149
158
  // 交给 AgGridReact 的列定义:按 x-component-props.headerGroup 把相邻同组的列合并成列组(多级表头)。
150
159
  // stableColumnDefs 保持扁平,懒列识别、列方案还原等内部逻辑仍用它;只有喂给 AG-Grid 的这一份带分组。@author nokecy
151
160
  var gridColumnDefs = useMemo(function () {
@@ -4,6 +4,11 @@ export type ReadOnlyFormatterCtx = {
4
4
  columnProps: any;
5
5
  /** 内层数据字段的 schema(可读 enum / x-component-props) */
6
6
  fieldSchema: any;
7
+ /**
8
+ * 运行时才确定的选项(field.setDataSource / setFieldState 写入的 dataSource)。
9
+ * 懒挂载格子没有自己的 Formily 字段时,由调用方取同列已创建字段的选项带进来;有值时优先于 schema 静态选项。
10
+ */
11
+ dataSource?: any[];
7
12
  };
8
13
  export type ReadOnlyFormatter = (value: any, ctx: ReadOnlyFormatterCtx) => string;
9
14
  /**
@@ -26,6 +26,7 @@ var resolveOptions = function resolveOptions(ctx) {
26
26
  var _ref, _ref2, _ref3, _fieldSchema$enum, _fieldSchema$xCompon, _fieldSchema$xCompon2;
27
27
  var columnProps = ctx.columnProps,
28
28
  fieldSchema = ctx.fieldSchema;
29
+ if (Array.isArray(ctx.dataSource) && ctx.dataSource.length > 0) return ctx.dataSource;
29
30
  var candidate = (_ref = (_ref2 = (_ref3 = (_fieldSchema$enum = fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema.enum) !== null && _fieldSchema$enum !== void 0 ? _fieldSchema$enum : fieldSchema === null || fieldSchema === void 0 || (_fieldSchema$xCompon = fieldSchema['x-component-props']) === null || _fieldSchema$xCompon === void 0 ? void 0 : _fieldSchema$xCompon.options) !== null && _ref3 !== void 0 ? _ref3 : fieldSchema === null || fieldSchema === void 0 || (_fieldSchema$xCompon2 = fieldSchema['x-component-props']) === null || _fieldSchema$xCompon2 === void 0 ? void 0 : _fieldSchema$xCompon2.dataSource) !== null && _ref2 !== void 0 ? _ref2 : columnProps === null || columnProps === void 0 ? void 0 : columnProps.options) !== null && _ref !== void 0 ? _ref : columnProps === null || columnProps === void 0 ? void 0 : columnProps.dataSource;
30
31
  return Array.isArray(candidate) ? candidate : [];
31
32
  };
@@ -58,20 +59,63 @@ var selectFormatter = function selectFormatter(value, ctx) {
58
59
  }
59
60
  return mapOptionLabel(value, options);
60
61
  };
62
+
63
+ /**
64
+ * 日期/时间控件没写 format 时的默认显示格式,与 antd 控件自己的默认一致:
65
+ * TimePicker 只显示时间;showTime 带到秒;按月/按年选择器只显示到月/年。
66
+ * 文本态与点开后的控件看到同一个格式,不然 showTime 的列平时只见日期、点开才见时间。
67
+ */
68
+ var defaultDateFormat = function defaultDateFormat(component, props) {
69
+ if (component === 'TimePicker') return props !== null && props !== void 0 && props.use12Hours ? 'hh:mm:ss a' : 'HH:mm:ss';
70
+ if ((props === null || props === void 0 ? void 0 : props.picker) === 'month') return 'YYYY-MM';
71
+ if ((props === null || props === void 0 ? void 0 : props.picker) === 'year') return 'YYYY';
72
+ if (props !== null && props !== void 0 && props.showTime) return 'YYYY-MM-DD HH:mm:ss';
73
+ return 'YYYY-MM-DD';
74
+ };
61
75
  var dateFormatter = function dateFormatter(value, ctx) {
62
- var _ref6, _ctx$columnProps$form, _ctx$columnProps, _ctx$fieldSchema;
76
+ var _ctx$fieldSchema, _ctx$columnProps, _ctx$fieldSchema2;
63
77
  if (value == null || value === '') return '';
64
- var fmt = (_ref6 = (_ctx$columnProps$form = (_ctx$columnProps = ctx.columnProps) === null || _ctx$columnProps === void 0 ? void 0 : _ctx$columnProps.format) !== null && _ctx$columnProps$form !== void 0 ? _ctx$columnProps$form : (_ctx$fieldSchema = ctx.fieldSchema) === null || _ctx$fieldSchema === void 0 || (_ctx$fieldSchema = _ctx$fieldSchema['x-component-props']) === null || _ctx$fieldSchema === void 0 ? void 0 : _ctx$fieldSchema.format) !== null && _ref6 !== void 0 ? _ref6 : 'YYYY-MM-DD';
78
+ var props = (_ctx$fieldSchema = ctx.fieldSchema) === null || _ctx$fieldSchema === void 0 ? void 0 : _ctx$fieldSchema['x-component-props'];
79
+ // antd 的 format 还可以是数组/函数,文本态只认字符串,其余回到默认
80
+ var configured = [(_ctx$columnProps = ctx.columnProps) === null || _ctx$columnProps === void 0 ? void 0 : _ctx$columnProps.format, props === null || props === void 0 ? void 0 : props.format].find(function (f) {
81
+ return typeof f === 'string' && f;
82
+ });
83
+ var fmt = configured !== null && configured !== void 0 ? configured : defaultDateFormat((_ctx$fieldSchema2 = ctx.fieldSchema) === null || _ctx$fieldSchema2 === void 0 ? void 0 : _ctx$fieldSchema2['x-component'], props);
65
84
  if (typeof value.format === 'function') return value.format(fmt);
66
85
  // 后端回来的多是 ISO 串(2024-10-19T00:00:00)或时间戳:与 Formily readPretty 一致,按 dayjs(value).format(fmt) 显示;
67
- // 解析不了的文本(如「待定」)原样显示,不吞掉。dayjs 随 antd 传递依赖引入,本库其他模块已直接使用。
86
+ // 解析不了的文本(如「待定」、纯时间 08:30:00)原样显示,不吞掉。dayjs 随 antd 传递依赖引入,本库其他模块已直接使用。
68
87
  var parsed = dayjs(value);
69
88
  return parsed.isValid() ? parsed.format(fmt) : String(value);
70
89
  };
90
+
91
+ /**
92
+ * 数字格:按控件的 precision 补齐小数位、按 formatter 属性(千分位、百分号等)显示,
93
+ * 与点开后的 InputNumber 一致;没配这两项时与原样输出相同。
94
+ */
95
+ var numberFormatter = function numberFormatter(value, ctx) {
96
+ var _ctx$fieldSchema$xCo, _ctx$fieldSchema3, _ctx$columnProps$prec, _ctx$columnProps2, _ctx$columnProps$form, _ctx$columnProps3;
97
+ if (value == null || value === '') return '';
98
+ var props = (_ctx$fieldSchema$xCo = (_ctx$fieldSchema3 = ctx.fieldSchema) === null || _ctx$fieldSchema3 === void 0 ? void 0 : _ctx$fieldSchema3['x-component-props']) !== null && _ctx$fieldSchema$xCo !== void 0 ? _ctx$fieldSchema$xCo : {};
99
+ var precision = (_ctx$columnProps$prec = (_ctx$columnProps2 = ctx.columnProps) === null || _ctx$columnProps2 === void 0 ? void 0 : _ctx$columnProps2.precision) !== null && _ctx$columnProps$prec !== void 0 ? _ctx$columnProps$prec : props.precision;
100
+ var num = Number(value);
101
+ var base = typeof precision === 'number' && precision >= 0 && Number.isFinite(num) ? num.toFixed(precision) : String(value);
102
+ var formatter = (_ctx$columnProps$form = (_ctx$columnProps3 = ctx.columnProps) === null || _ctx$columnProps3 === void 0 ? void 0 : _ctx$columnProps3.formatter) !== null && _ctx$columnProps$form !== void 0 ? _ctx$columnProps$form : props.formatter;
103
+ if (typeof formatter === 'function') {
104
+ try {
105
+ return String(formatter(base, {
106
+ userTyping: false,
107
+ input: ''
108
+ }));
109
+ } catch (_unused) {
110
+ return base;
111
+ }
112
+ }
113
+ return base;
114
+ };
71
115
  var booleanFormatter = function booleanFormatter(value, ctx) {
72
- var _ctx$fieldSchema$xCo, _ctx$fieldSchema2, _props$checkedChildre, _props$unCheckedChild;
116
+ var _ctx$fieldSchema$xCo2, _ctx$fieldSchema4, _props$checkedChildre, _props$unCheckedChild;
73
117
  if (value == null || value === '') return '';
74
- var props = (_ctx$fieldSchema$xCo = (_ctx$fieldSchema2 = ctx.fieldSchema) === null || _ctx$fieldSchema2 === void 0 ? void 0 : _ctx$fieldSchema2['x-component-props']) !== null && _ctx$fieldSchema$xCo !== void 0 ? _ctx$fieldSchema$xCo : {};
118
+ var props = (_ctx$fieldSchema$xCo2 = (_ctx$fieldSchema4 = ctx.fieldSchema) === null || _ctx$fieldSchema4 === void 0 ? void 0 : _ctx$fieldSchema4['x-component-props']) !== null && _ctx$fieldSchema$xCo2 !== void 0 ? _ctx$fieldSchema$xCo2 : {};
75
119
  var truthy = (_props$checkedChildre = props.checkedChildren) !== null && _props$checkedChildre !== void 0 ? _props$checkedChildre : '是';
76
120
  var falsy = (_props$unCheckedChild = props.unCheckedChildren) !== null && _props$unCheckedChild !== void 0 ? _props$unCheckedChild : '否';
77
121
  return value ? String(truthy) : String(falsy);
@@ -87,8 +131,8 @@ var registry = {
87
131
  Password: textFormatter,
88
132
  Text: textFormatter,
89
133
  Preview: textFormatter,
90
- NumberPicker: textFormatter,
91
- InputNumber: textFormatter,
134
+ NumberPicker: numberFormatter,
135
+ InputNumber: numberFormatter,
92
136
  Select: selectFormatter,
93
137
  TreeSelect: selectFormatter,
94
138
  Cascader: selectFormatter,
@@ -146,17 +190,17 @@ export var registerReadOnlyLabels = function registerReadOnlyLabels(component, l
146
190
  if (o && o.value != null) map.set(String(o.value), String((_o$label = o.label) !== null && _o$label !== void 0 ? _o$label : o.value));
147
191
  });
148
192
  } else {
149
- Object.entries(labels !== null && labels !== void 0 ? labels : {}).forEach(function (_ref7) {
150
- var _ref8 = _slicedToArray(_ref7, 2),
151
- k = _ref8[0],
152
- v = _ref8[1];
193
+ Object.entries(labels !== null && labels !== void 0 ? labels : {}).forEach(function (_ref6) {
194
+ var _ref7 = _slicedToArray(_ref6, 2),
195
+ k = _ref7[0],
196
+ v = _ref7[1];
153
197
  return map.set(String(k), String(v));
154
198
  });
155
199
  }
156
200
  var toText = function toText(v) {
157
- var _ref9, _v$label, _map$get;
201
+ var _ref8, _v$label, _map$get;
158
202
  if (v == null || v === '') return '';
159
- if (_typeof(v) === 'object') return String((_ref9 = (_v$label = v.label) !== null && _v$label !== void 0 ? _v$label : v.value) !== null && _ref9 !== void 0 ? _ref9 : '');
203
+ if (_typeof(v) === 'object') return String((_ref8 = (_v$label = v.label) !== null && _v$label !== void 0 ? _v$label : v.value) !== null && _ref8 !== void 0 ? _ref8 : '');
160
204
  return (_map$get = map.get(String(v))) !== null && _map$get !== void 0 ? _map$get : String(v);
161
205
  };
162
206
  var formatter = function formatter(value) {
@@ -41,3 +41,20 @@ declare const LazyReadOnlyText: (params: any) => React.JSX.Element;
41
41
  declare const buildArrayTableColumns: (dataSource: any[], field: ArrayField, sources: ObservableColumnSource[]) => AgGridReactProps['columnDefs'];
42
42
  declare const useAddition: () => React.JSX.Element | null;
43
43
  export { isColumnComponent, useArrayTableSources, useArrayTableActions, buildArrayTableColumns, useAddition, LazyAgField, LazyReadOnlyText };
44
+ export type LazyColumnDefault = {
45
+ key: string;
46
+ value: any;
47
+ };
48
+ /**
49
+ * 收集懒挂载列上声明了 default 的字段。
50
+ *
51
+ * Formily 在字段创建时把 schema 的 default 写进值(值为空时)。懒挂载的格子不创建字段,
52
+ * 老记录里缺的列、代码直接 push 的行就拿不到默认值,保存时是 null。
53
+ * 表达式形态的默认值({{...}})要求值上下文,这里不处理。@author nokecy
54
+ */
55
+ export declare const collectLazyDefaults: (columns: any[]) => LazyColumnDefault[];
56
+ /**
57
+ * 给还没处理过的新增行补默认值:值为空(null/undefined)才写,每行只补一次——
58
+ * 用户之后把格子清空是有意的,不能再被填回去。已落库的行(带 id)不动。@author nokecy
59
+ */
60
+ export declare const applyLazyDefaults: (arrayField: any, defaults: LazyColumnDefault[], handled: WeakSet<object>) => void;