@nokecy/qc-ui 1.1.47 → 1.1.49

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 (32) hide show
  1. package/dist/cjs/RuleBuilder/RuleBuilderContainer.js +2 -1
  2. package/dist/cjs/RuleBuilder/RuleCard.d.ts +2 -0
  3. package/dist/cjs/RuleBuilder/RuleCard.js +27 -3
  4. package/dist/cjs/RuleBuilder/RuleGroupEditor.d.ts +2 -0
  5. package/dist/cjs/RuleBuilder/RuleGroupEditor.js +5 -1
  6. package/dist/cjs/RuleBuilder/constants/operators.d.ts +5 -0
  7. package/dist/cjs/RuleBuilder/constants/operators.js +9 -1
  8. package/dist/cjs/RuleBuilder/index.d.ts +1 -1
  9. package/dist/cjs/RuleBuilder/index.js +6 -0
  10. package/dist/cjs/RuleBuilder/inputs/ValueInput.d.ts +10 -2
  11. package/dist/cjs/RuleBuilder/inputs/ValueInput.js +56 -5
  12. package/dist/cjs/RuleBuilder/types/index.d.ts +13 -1
  13. package/dist/cjs/RuleBuilder/types/index.js +1 -1
  14. package/dist/cjs/RuleBuilder/utils/validation.js +38 -0
  15. package/dist/cjs/array-table/utils.js +36 -0
  16. package/dist/esm/RuleBuilder/RuleBuilderContainer.js +2 -1
  17. package/dist/esm/RuleBuilder/RuleCard.d.ts +2 -0
  18. package/dist/esm/RuleBuilder/RuleCard.js +28 -4
  19. package/dist/esm/RuleBuilder/RuleGroupEditor.d.ts +2 -0
  20. package/dist/esm/RuleBuilder/RuleGroupEditor.js +5 -1
  21. package/dist/esm/RuleBuilder/constants/operators.d.ts +5 -0
  22. package/dist/esm/RuleBuilder/constants/operators.js +8 -0
  23. package/dist/esm/RuleBuilder/index.d.ts +1 -1
  24. package/dist/esm/RuleBuilder/index.js +1 -1
  25. package/dist/esm/RuleBuilder/inputs/ValueInput.d.ts +10 -2
  26. package/dist/esm/RuleBuilder/inputs/ValueInput.js +57 -6
  27. package/dist/esm/RuleBuilder/types/index.d.ts +13 -1
  28. package/dist/esm/RuleBuilder/types/index.js +1 -1
  29. package/dist/esm/RuleBuilder/utils/validation.js +39 -1
  30. package/dist/esm/array-table/utils.js +36 -0
  31. package/dist/umd/qc-ui.min.js +1 -1
  32. package/package.json +1 -1
@@ -62,7 +62,8 @@ var RuleBuilderInner = function RuleBuilderInner(_ref) {
62
62
  path: [],
63
63
  level: 0,
64
64
  maxLevel: (config === null || config === void 0 ? void 0 : config.maxNestingLevel) || 5,
65
- readonly: readonly
65
+ readonly: readonly,
66
+ allowFieldComparison: config === null || config === void 0 ? void 0 : config.allowFieldComparison
66
67
  }));
67
68
  };
68
69
 
@@ -11,6 +11,8 @@ export interface RuleCardProps {
11
11
  path: RulePath;
12
12
  /** 是否只读模式 */
13
13
  readonly?: boolean;
14
+ /** 是否允许与另一个字段比较 @author nokecy */
15
+ allowFieldComparison?: boolean;
14
16
  }
15
17
  /**
16
18
  * 规则卡片组件 - 紧凑版
@@ -32,7 +32,9 @@ var RuleCard = exports.RuleCard = function RuleCard(_ref) {
32
32
  var rule = _ref.rule,
33
33
  path = _ref.path,
34
34
  _ref$readonly = _ref.readonly,
35
- readonly = _ref$readonly === void 0 ? false : _ref$readonly;
35
+ readonly = _ref$readonly === void 0 ? false : _ref$readonly,
36
+ _ref$allowFieldCompar = _ref.allowFieldComparison,
37
+ allowFieldComparison = _ref$allowFieldCompar === void 0 ? false : _ref$allowFieldCompar;
36
38
  var _useRuleBuilderContex = (0, _RuleBuilderContext.useRuleBuilderContext)(),
37
39
  state = _useRuleBuilderContex.state,
38
40
  dispatch = _useRuleBuilderContex.dispatch;
@@ -62,7 +64,9 @@ var RuleCard = exports.RuleCard = function RuleCard(_ref) {
62
64
  rule: _objectSpread(_objectSpread({}, rule), {}, {
63
65
  fieldName: fieldName,
64
66
  value: undefined,
65
- value2: undefined
67
+ value2: undefined,
68
+ // 可比较的字段随数据类型变化,保留字段模式但清空已选字段。@author nokecy
69
+ valueField: rule.valueField !== undefined ? '' : undefined
66
70
  })
67
71
  }
68
72
  });
@@ -81,7 +85,8 @@ var RuleCard = exports.RuleCard = function RuleCard(_ref) {
81
85
  rule: _objectSpread(_objectSpread({}, rule), {}, {
82
86
  operator: operator,
83
87
  value: needsValue || needsValue2 || needsMultiValue ? rule.value : undefined,
84
- value2: needsValue2 ? rule.value2 : undefined
88
+ value2: needsValue2 ? rule.value2 : undefined,
89
+ valueField: (0, _operators.operatorSupportsValueField)(operator) ? rule.valueField : undefined
85
90
  })
86
91
  }
87
92
  });
@@ -101,6 +106,21 @@ var RuleCard = exports.RuleCard = function RuleCard(_ref) {
101
106
  });
102
107
  };
103
108
 
109
+ // 比较字段改变处理:切换模式或选择字段时清空固定值,undefined 表示回到固定值模式。@author nokecy
110
+ var handleValueFieldChange = function handleValueFieldChange(valueField) {
111
+ dispatch({
112
+ type: 'UPDATE_RULE',
113
+ payload: {
114
+ path: path,
115
+ rule: _objectSpread(_objectSpread({}, rule), {}, {
116
+ value: undefined,
117
+ value2: undefined,
118
+ valueField: valueField
119
+ })
120
+ }
121
+ });
122
+ };
123
+
104
124
  // 删除规则处理
105
125
  var handleDelete = function handleDelete() {
106
126
  dispatch({
@@ -159,6 +179,10 @@ var RuleCard = exports.RuleCard = function RuleCard(_ref) {
159
179
  value: rule.value,
160
180
  value2: rule.value2,
161
181
  onChange: handleValueChange,
182
+ valueField: rule.valueField,
183
+ onValueFieldChange: allowFieldComparison ? handleValueFieldChange : undefined,
184
+ fields: state.fields,
185
+ fieldName: rule.fieldName,
162
186
  disabled: readonly,
163
187
  size: "small"
164
188
  }), ruleErrors.some(function (e) {
@@ -14,6 +14,8 @@ export interface RuleGroupEditorProps {
14
14
  maxLevel: number;
15
15
  /** 是否只读模式 */
16
16
  readonly?: boolean;
17
+ /** 是否允许与另一个字段比较 @author nokecy */
18
+ allowFieldComparison?: boolean;
17
19
  /** 规则组变更回调(可选) */
18
20
  onChange?: (group: RuleGroupDto) => void;
19
21
  }
@@ -42,6 +42,8 @@ var RuleGroupEditor = exports.RuleGroupEditor = function RuleGroupEditor(_ref) {
42
42
  maxLevel = _ref.maxLevel,
43
43
  _ref$readonly = _ref.readonly,
44
44
  readonly = _ref$readonly === void 0 ? false : _ref$readonly,
45
+ _ref$allowFieldCompar = _ref.allowFieldComparison,
46
+ allowFieldComparison = _ref$allowFieldCompar === void 0 ? false : _ref$allowFieldCompar,
45
47
  onChange = _ref.onChange;
46
48
  var _useRuleBuilderContex = (0, _RuleBuilderContext.useRuleBuilderContext)(),
47
49
  state = _useRuleBuilderContex.state,
@@ -154,7 +156,8 @@ var RuleGroupEditor = exports.RuleGroupEditor = function RuleGroupEditor(_ref) {
154
156
  key: ruleIndex,
155
157
  rule: rule,
156
158
  path: rulePath,
157
- readonly: readonly
159
+ readonly: readonly,
160
+ allowFieldComparison: allowFieldComparison
158
161
  });
159
162
  }), currentGroup.groups.length > 0 && /*#__PURE__*/_react.default.createElement("div", {
160
163
  className: _indexModule.default.nestedGroups
@@ -166,6 +169,7 @@ var RuleGroupEditor = exports.RuleGroupEditor = function RuleGroupEditor(_ref) {
166
169
  level: level + 1,
167
170
  maxLevel: maxLevel,
168
171
  readonly: readonly,
172
+ allowFieldComparison: allowFieldComparison,
169
173
  onChange: onChange
170
174
  });
171
175
  })), currentGroup.rules.length === 0 && currentGroup.groups.length === 0 && /*#__PURE__*/_react.default.createElement("div", {
@@ -41,6 +41,11 @@ export declare const operatorRequiresValue2: (operator: MatchOperator) => boolea
41
41
  * 检查操作符是否需要多个值(In/NotIn)
42
42
  */
43
43
  export declare const operatorRequiresMultiValue: (operator: MatchOperator) => boolean;
44
+ /**
45
+ * 检查操作符是否支持与另一个字段比较(与后端 RuleGroupValidator 一致:等于、不等于及 4 个大小比较)
46
+ * @author nokecy
47
+ */
48
+ export declare const operatorSupportsValueField: (operator: MatchOperator) => boolean;
44
49
  /**
45
50
  * 最大嵌套层级
46
51
  */
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.operatorRequiresValue2 = exports.operatorRequiresValue = exports.operatorRequiresMultiValue = exports.getOperatorsByDataType = exports.getOperatorInfo = exports.OPERATOR_INFO_MAP = exports.MAX_NESTING_LEVEL = void 0;
6
+ exports.operatorSupportsValueField = exports.operatorRequiresValue2 = exports.operatorRequiresValue = exports.operatorRequiresMultiValue = exports.getOperatorsByDataType = exports.getOperatorInfo = exports.OPERATOR_INFO_MAP = exports.MAX_NESTING_LEVEL = void 0;
7
7
  var _types = require("../types");
8
8
  var _OPERATOR_INFO_MAP;
9
9
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
@@ -166,6 +166,14 @@ var operatorRequiresMultiValue = exports.operatorRequiresMultiValue = function o
166
166
  return ((_OPERATOR_INFO_MAP$op3 = OPERATOR_INFO_MAP[operator]) === null || _OPERATOR_INFO_MAP$op3 === void 0 ? void 0 : _OPERATOR_INFO_MAP$op3.requiresMultiValue) || false;
167
167
  };
168
168
 
169
+ /**
170
+ * 检查操作符是否支持与另一个字段比较(与后端 RuleGroupValidator 一致:等于、不等于及 4 个大小比较)
171
+ * @author nokecy
172
+ */
173
+ var operatorSupportsValueField = exports.operatorSupportsValueField = function operatorSupportsValueField(operator) {
174
+ return [_types.MatchOperator.Equals, _types.MatchOperator.NotEquals, _types.MatchOperator.GreaterThan, _types.MatchOperator.GreaterThanOrEqual, _types.MatchOperator.LessThan, _types.MatchOperator.LessThanOrEqual].includes(operator);
175
+ };
176
+
169
177
  /**
170
178
  * 最大嵌套层级
171
179
  */
@@ -20,6 +20,6 @@ export { RuleBuilderProvider, useRuleBuilderContext, useRuleBuilderState, useRul
20
20
  export { createEmptyRule, createEmptyRuleGroup, generateRuleDescription, cloneRuleGroup, isRuleGroupEmpty, countRules, getMaxDepth, } from './utils/ruleHelpers';
21
21
  export { getRuleGroupByPath, getRuleByPath, updateRuleAtPath, deleteRuleAtPath, addRuleAtPath, updateRuleGroupAtPath, deleteRuleGroupAtPath, addRuleGroupAtPath, } from './utils/pathHelpers';
22
22
  export { validateRuleGroup, validateRule, isRuleGroupValid, } from './utils/validation';
23
- export { OPERATOR_INFO_MAP, getOperatorInfo, operatorRequiresValue, operatorRequiresValue2, operatorRequiresMultiValue, getOperatorsByDataType, MAX_NESTING_LEVEL, } from './constants/operators';
23
+ export { OPERATOR_INFO_MAP, getOperatorInfo, operatorRequiresValue, operatorRequiresValue2, operatorRequiresMultiValue, operatorSupportsValueField, getOperatorsByDataType, MAX_NESTING_LEVEL, } from './constants/operators';
24
24
  export type { MatchOperator, MatchLogic, FieldDataType, RuleDto, RuleGroupDto, FieldDefinition, ValidationResult, ValidationError, RuleBuilderProps, RuleBuilderConfig, RulePath, RuleBuilderState, RuleBuilderAction, OperatorInfo, } from './types';
25
25
  export { RuleBuilderContainer as default } from './RuleBuilderContainer';
@@ -207,6 +207,12 @@ Object.defineProperty(exports, "operatorRequiresValue2", {
207
207
  return _operators.operatorRequiresValue2;
208
208
  }
209
209
  });
210
+ Object.defineProperty(exports, "operatorSupportsValueField", {
211
+ enumerable: true,
212
+ get: function get() {
213
+ return _operators.operatorSupportsValueField;
214
+ }
215
+ });
210
216
  Object.defineProperty(exports, "updateRuleAtPath", {
211
217
  enumerable: true,
212
218
  get: function get() {
@@ -5,10 +5,10 @@
5
5
  * - IsNull/IsNotNull: 不渲染任何输入
6
6
  * - Between: 渲染 BetweenValueInput
7
7
  * - In/NotIn: 渲染 MultiValueInput
8
- * - 其他: 渲染 SingleValueInput
8
+ * - 其他: 渲染 SingleValueInput;允许比较字段时前置「固定值 / 字段」切换
9
9
  */
10
10
  import React from 'react';
11
- import type { MatchOperator, FieldDataType } from '../types';
11
+ import type { MatchOperator, FieldDataType, FieldDefinition } from '../types';
12
12
  export interface ValueInputProps {
13
13
  /** 操作符 */
14
14
  operator: MatchOperator;
@@ -24,6 +24,14 @@ export interface ValueInputProps {
24
24
  disabled?: boolean;
25
25
  /** 尺寸 */
26
26
  size?: 'small' | 'middle' | 'large';
27
+ /** 比较字段(undefined 为固定值模式) @author nokecy */
28
+ valueField?: string;
29
+ /** 比较字段变更回调;不传则不提供「字段」模式 @author nokecy */
30
+ onValueFieldChange?: (valueField: string | undefined) => void;
31
+ /** 可供比较的字段列表 @author nokecy */
32
+ fields?: FieldDefinition[];
33
+ /** 当前规则的字段名(比较字段中排除自身) @author nokecy */
34
+ fieldName?: string;
27
35
  }
28
36
  export declare const ValueInput: React.FC<ValueInputProps>;
29
37
  export default ValueInput;
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = exports.ValueInput = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
+ var _antd = require("antd");
8
9
  var _operators = require("../constants/operators");
9
10
  var _SingleValueInput = _interopRequireDefault(require("./SingleValueInput"));
10
11
  var _BetweenValueInput = _interopRequireDefault(require("./BetweenValueInput"));
@@ -17,7 +18,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
17
18
  * - IsNull/IsNotNull: 不渲染任何输入
18
19
  * - Between: 渲染 BetweenValueInput
19
20
  * - In/NotIn: 渲染 MultiValueInput
20
- * - 其他: 渲染 SingleValueInput
21
+ * - 其他: 渲染 SingleValueInput;允许比较字段时前置「固定值 / 字段」切换
21
22
  */
22
23
 
23
24
  var ValueInput = exports.ValueInput = function ValueInput(_ref) {
@@ -29,7 +30,12 @@ var ValueInput = exports.ValueInput = function ValueInput(_ref) {
29
30
  _ref$disabled = _ref.disabled,
30
31
  disabled = _ref$disabled === void 0 ? false : _ref$disabled,
31
32
  _ref$size = _ref.size,
32
- size = _ref$size === void 0 ? 'middle' : _ref$size;
33
+ size = _ref$size === void 0 ? 'middle' : _ref$size,
34
+ valueField = _ref.valueField,
35
+ onValueFieldChange = _ref.onValueFieldChange,
36
+ _ref$fields = _ref.fields,
37
+ fields = _ref$fields === void 0 ? [] : _ref$fields,
38
+ fieldName = _ref.fieldName;
33
39
  // 不需要值输入的操作符(IsNull/IsNotNull)
34
40
  if (!(0, _operators.operatorRequiresValue)(operator) && !(0, _operators.operatorRequiresValue2)(operator) && !(0, _operators.operatorRequiresMultiValue)(operator)) {
35
41
  return null;
@@ -65,9 +71,7 @@ var ValueInput = exports.ValueInput = function ValueInput(_ref) {
65
71
  size: size
66
72
  });
67
73
  }
68
-
69
- // 其他操作符:渲染单值输入
70
- return /*#__PURE__*/_react.default.createElement(_SingleValueInput.default, {
74
+ var singleValueInput = /*#__PURE__*/_react.default.createElement(_SingleValueInput.default, {
71
75
  value: value,
72
76
  onChange: function onChange(val) {
73
77
  return _onChange(val);
@@ -76,5 +80,52 @@ var ValueInput = exports.ValueInput = function ValueInput(_ref) {
76
80
  disabled: disabled,
77
81
  size: size
78
82
  });
83
+
84
+ // 其他操作符:渲染单值输入
85
+ if (!onValueFieldChange || !(0, _operators.operatorSupportsValueField)(operator)) {
86
+ return singleValueInput;
87
+ }
88
+
89
+ // 比较类操作符:可切换为与同类型的另一个字段比较。@author nokecy
90
+ var isFieldMode = valueField !== undefined;
91
+ return /*#__PURE__*/_react.default.createElement(_antd.Space, {
92
+ size: 4
93
+ }, /*#__PURE__*/_react.default.createElement(_antd.Segmented, {
94
+ size: size,
95
+ value: isFieldMode ? 'field' : 'value',
96
+ disabled: disabled,
97
+ options: [{
98
+ label: '固定值',
99
+ value: 'value'
100
+ }, {
101
+ label: '字段',
102
+ value: 'field'
103
+ }],
104
+ onChange: function onChange(mode) {
105
+ return onValueFieldChange(mode === 'field' ? '' : undefined);
106
+ }
107
+ }), isFieldMode ? /*#__PURE__*/_react.default.createElement(_antd.Select, {
108
+ value: valueField || undefined,
109
+ onChange: function onChange(name) {
110
+ return onValueFieldChange(name);
111
+ },
112
+ placeholder: "\u8BF7\u9009\u62E9\u6BD4\u8F83\u5B57\u6BB5",
113
+ disabled: disabled,
114
+ size: size,
115
+ showSearch: true,
116
+ optionFilterProp: "label",
117
+ style: {
118
+ width: 200
119
+ },
120
+ options: fields.filter(function (field) {
121
+ return field.dataType === dataType && field.name !== fieldName;
122
+ }).map(function (field) {
123
+ return {
124
+ value: field.name,
125
+ label: field.displayName,
126
+ title: field.description
127
+ };
128
+ })
129
+ }) : singleValueInput);
79
130
  };
80
131
  var _default = exports.default = ValueInput;
@@ -8,7 +8,7 @@
8
8
  * JSON 序列化属性名:
9
9
  * - fieldName (不是 FieldName)
10
10
  * - operator (不是 Operator)
11
- * - value, value2
11
+ * - value, value2, valueField
12
12
  * - logic, rules, groups
13
13
  */
14
14
  /**
@@ -78,6 +78,12 @@ export interface RuleDto {
78
78
  value?: any;
79
79
  /** 第二个值(用于 Between 操作符) */
80
80
  value2?: any;
81
+ /**
82
+ * 比较字段:与另一个字段的值比较,与 value 互斥,仅 6 个比较操作符可用。
83
+ * undefined 为固定值模式;空字符串表示已切到字段模式但尚未选择。
84
+ * @author nokecy
85
+ */
86
+ valueField?: string;
81
87
  }
82
88
  /**
83
89
  * 规则组 DTO(与后端保持一致)
@@ -143,6 +149,12 @@ export interface RuleBuilderConfig {
143
149
  maxNestingLevel?: number;
144
150
  /** 是否显示 JSON 预览 */
145
151
  showJsonPreview?: boolean;
152
+ /**
153
+ * 是否允许规则与另一个字段比较(valueField)。
154
+ * 需要后端规则引擎与调用方的格式转换都支持 valueField 才能开启,默认关闭。
155
+ * @author nokecy
156
+ */
157
+ allowFieldComparison?: boolean;
146
158
  /** 自定义验证器 */
147
159
  validator?: (rule: RuleGroupDto) => ValidationResult;
148
160
  }
@@ -14,7 +14,7 @@ exports.MatchOperator = exports.MatchLogic = void 0;
14
14
  * JSON 序列化属性名:
15
15
  * - fieldName (不是 FieldName)
16
16
  * - operator (不是 Operator)
17
- * - value, value2
17
+ * - value, value2, valueField
18
18
  * - logic, rules, groups
19
19
  */
20
20
  /**
@@ -112,6 +112,12 @@ function validateRule(rule, fields) {
112
112
  });
113
113
  }
114
114
 
115
+ // 比较字段模式:值来自另一个字段,不再校验固定值。@author nokecy
116
+ if (rule.valueField !== undefined) {
117
+ errors.push.apply(errors, _toConsumableArray(validateValueField(rule, fields)));
118
+ return errors;
119
+ }
120
+
115
121
  // 4. 检查值是否为空(对于需要值的操作符)
116
122
  if ((0, _operators.operatorRequiresValue)(rule.operator)) {
117
123
  if (rule.value === undefined || rule.value === null || rule.value === '') {
@@ -194,6 +200,38 @@ function validateRule(rule, fields) {
194
200
  return errors;
195
201
  }
196
202
 
203
+ /**
204
+ * 验证比较字段模式的规则
205
+ * @param rule 规则(valueField 已设置)
206
+ * @param fields 字段定义列表
207
+ * @returns 错误列表
208
+ * @author nokecy
209
+ */
210
+ function validateValueField(rule, fields) {
211
+ var errors = [];
212
+ var addError = function addError(message) {
213
+ return errors.push({
214
+ path: [],
215
+ message: message,
216
+ field: rule.fieldName
217
+ });
218
+ };
219
+ if (!(0, _operators.operatorSupportsValueField)(rule.operator)) {
220
+ addError('当前操作符不支持比较字段');
221
+ }
222
+ if (rule.value !== undefined && rule.value !== null && rule.value !== '') {
223
+ addError('固定值和比较字段只能设置一个');
224
+ }
225
+ if (!rule.valueField) {
226
+ addError('请选择比较字段');
227
+ } else if (!fields.some(function (f) {
228
+ return f.name === rule.valueField;
229
+ })) {
230
+ addError("\u6BD4\u8F83\u5B57\u6BB5 \"".concat(rule.valueField, "\" \u4E0D\u5B58\u5728"));
231
+ }
232
+ return errors;
233
+ }
234
+
197
235
  /**
198
236
  * 验证值的类型是否匹配
199
237
  * @param value 值
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  });
7
7
  exports.useArrayTableSources = exports.useArrayTableActions = exports.useAddition = exports.isColumnComponent = exports.buildArrayTableColumns = exports.LazyReadOnlyText = exports.LazyAgField = void 0;
8
8
  var _react = _interopRequireDefault(require("react"));
9
+ var _antd = require("antd");
9
10
  var _react2 = require("@formily/react");
10
11
  var _shared = require("@formily/shared");
11
12
  var _arrayBase = _interopRequireDefault(require("./arrayBase"));
@@ -169,6 +170,26 @@ var readByFieldPath = function readByFieldPath(record, path) {
169
170
  }, record);
170
171
  };
171
172
 
173
+ /** 「选一个」型组件:空值占位说「请选择」,其余说「请输入」 */
174
+ var SELECT_LIKE = new Set(['Select', 'TreeSelect', 'Cascader', 'DatePicker', 'TimePicker', 'Radio.Group', 'Checkbox.Group', 'Transfer']);
175
+
176
+ /**
177
+ * 懒挂载空值格显示什么。
178
+ *
179
+ * 懒挂载把未激活的可编辑格降成纯文本,值为空时整格一片空白——连输入框边框都没有,
180
+ * 用户看不出这里能填,以为功能坏了。故空值时按真控件的 placeholder 出淡灰占位,
181
+ * 点开前后看到同一句话,观感连续。
182
+ *
183
+ * 同样的理由 Switch/Checkbox 早就强制 eager 了(见 buildArrayTableColumns 的
184
+ * isInlineToggle),这里是把那条理由推广到其余可编辑列。@author nokecy
185
+ */
186
+ var resolveEmptyPlaceholder = function resolveEmptyPlaceholder(fieldSchema) {
187
+ var _fieldSchema$xCompon;
188
+ var configured = fieldSchema === null || fieldSchema === void 0 || (_fieldSchema$xCompon = fieldSchema['x-component-props']) === null || _fieldSchema$xCompon === void 0 ? void 0 : _fieldSchema$xCompon.placeholder;
189
+ if (typeof configured === 'string' && configured) return configured;
190
+ return SELECT_LIKE.has(fieldSchema === null || fieldSchema === void 0 ? void 0 : fieldSchema['x-component']) ? '请选择' : '请输入';
191
+ };
192
+
172
193
  /**
173
194
  * 懒挂载单元格渲染器(可编辑列)。
174
195
  *
@@ -195,6 +216,9 @@ var LazyAgField = exports.LazyAgField = function LazyAgField(params) {
195
216
  formatter = params.formatter,
196
217
  columnProps = params.columnProps,
197
218
  fieldSchema = params.fieldSchema;
219
+ // hook 必须在下面的条件 return 之前调用
220
+ var _theme$useToken = _antd.theme.useToken(),
221
+ token = _theme$useToken.token;
198
222
  var key = "".concat(node === null || node === void 0 ? void 0 : node.id, ":").concat(colDef === null || colDef === void 0 ? void 0 : colDef.field);
199
223
  var activated = (record === null || record === void 0 ? void 0 : record._isNew) === true || (context === null || context === void 0 || (_context$activeCells = context.activeCells) === null || _context$activeCells === void 0 || (_context$activeCells$ = _context$activeCells.has) === null || _context$activeCells$ === void 0 ? void 0 : _context$activeCells$.call(_context$activeCells, key)) === true;
200
224
  if (activated) {
@@ -221,6 +245,18 @@ var LazyAgField = exports.LazyAgField = function LazyAgField(params) {
221
245
  fieldSchema: fieldSchema
222
246
  }) : liveValue == null ? '' : String(liveValue);
223
247
  // 纯文本占满单元格,点击交给 AG-Grid onCellClicked 激活;样式尽量贴近 Editable 只读态避免点开跳动
248
+ if (text === '') {
249
+ // 空值:出淡灰 placeholder,让用户看得出这格能填(颜色取 antd 输入框 placeholder 的 token,自动跟随暗色主题)
250
+ return /*#__PURE__*/_react.default.createElement("span", {
251
+ className: "ag-array-table-lazy-placeholder",
252
+ style: {
253
+ display: 'inline-block',
254
+ width: '100%',
255
+ cursor: 'text',
256
+ color: token.colorTextPlaceholder
257
+ }
258
+ }, resolveEmptyPlaceholder(fieldSchema));
259
+ }
224
260
  return /*#__PURE__*/_react.default.createElement("span", {
225
261
  className: "ag-array-table-lazy-text",
226
262
  style: {
@@ -56,7 +56,8 @@ var RuleBuilderInner = function RuleBuilderInner(_ref) {
56
56
  path: [],
57
57
  level: 0,
58
58
  maxLevel: (config === null || config === void 0 ? void 0 : config.maxNestingLevel) || 5,
59
- readonly: readonly
59
+ readonly: readonly,
60
+ allowFieldComparison: config === null || config === void 0 ? void 0 : config.allowFieldComparison
60
61
  }));
61
62
  };
62
63
 
@@ -11,6 +11,8 @@ export interface RuleCardProps {
11
11
  path: RulePath;
12
12
  /** 是否只读模式 */
13
13
  readonly?: boolean;
14
+ /** 是否允许与另一个字段比较 @author nokecy */
15
+ allowFieldComparison?: boolean;
14
16
  }
15
17
  /**
16
18
  * 规则卡片组件 - 紧凑版
@@ -16,7 +16,7 @@ import { FieldSelector } from "./selectors/FieldSelector";
16
16
  import { OperatorSelector } from "./selectors/OperatorSelector";
17
17
  import ValueInput from "./inputs/ValueInput";
18
18
  import { useRuleBuilderContext } from "./context/RuleBuilderContext";
19
- import { getOperatorInfo } from "./constants/operators";
19
+ import { getOperatorInfo, operatorSupportsValueField } from "./constants/operators";
20
20
  import styles from "./styles/index.module.less";
21
21
  /**
22
22
  * 规则卡片组件 - 紧凑版
@@ -27,7 +27,9 @@ export var RuleCard = function RuleCard(_ref) {
27
27
  var rule = _ref.rule,
28
28
  path = _ref.path,
29
29
  _ref$readonly = _ref.readonly,
30
- readonly = _ref$readonly === void 0 ? false : _ref$readonly;
30
+ readonly = _ref$readonly === void 0 ? false : _ref$readonly,
31
+ _ref$allowFieldCompar = _ref.allowFieldComparison,
32
+ allowFieldComparison = _ref$allowFieldCompar === void 0 ? false : _ref$allowFieldCompar;
31
33
  var _useRuleBuilderContex = useRuleBuilderContext(),
32
34
  state = _useRuleBuilderContex.state,
33
35
  dispatch = _useRuleBuilderContex.dispatch;
@@ -57,7 +59,9 @@ export var RuleCard = function RuleCard(_ref) {
57
59
  rule: _objectSpread(_objectSpread({}, rule), {}, {
58
60
  fieldName: fieldName,
59
61
  value: undefined,
60
- value2: undefined
62
+ value2: undefined,
63
+ // 可比较的字段随数据类型变化,保留字段模式但清空已选字段。@author nokecy
64
+ valueField: rule.valueField !== undefined ? '' : undefined
61
65
  })
62
66
  }
63
67
  });
@@ -76,7 +80,8 @@ export var RuleCard = function RuleCard(_ref) {
76
80
  rule: _objectSpread(_objectSpread({}, rule), {}, {
77
81
  operator: operator,
78
82
  value: needsValue || needsValue2 || needsMultiValue ? rule.value : undefined,
79
- value2: needsValue2 ? rule.value2 : undefined
83
+ value2: needsValue2 ? rule.value2 : undefined,
84
+ valueField: operatorSupportsValueField(operator) ? rule.valueField : undefined
80
85
  })
81
86
  }
82
87
  });
@@ -96,6 +101,21 @@ export var RuleCard = function RuleCard(_ref) {
96
101
  });
97
102
  };
98
103
 
104
+ // 比较字段改变处理:切换模式或选择字段时清空固定值,undefined 表示回到固定值模式。@author nokecy
105
+ var handleValueFieldChange = function handleValueFieldChange(valueField) {
106
+ dispatch({
107
+ type: 'UPDATE_RULE',
108
+ payload: {
109
+ path: path,
110
+ rule: _objectSpread(_objectSpread({}, rule), {}, {
111
+ value: undefined,
112
+ value2: undefined,
113
+ valueField: valueField
114
+ })
115
+ }
116
+ });
117
+ };
118
+
99
119
  // 删除规则处理
100
120
  var handleDelete = function handleDelete() {
101
121
  dispatch({
@@ -154,6 +174,10 @@ export var RuleCard = function RuleCard(_ref) {
154
174
  value: rule.value,
155
175
  value2: rule.value2,
156
176
  onChange: handleValueChange,
177
+ valueField: rule.valueField,
178
+ onValueFieldChange: allowFieldComparison ? handleValueFieldChange : undefined,
179
+ fields: state.fields,
180
+ fieldName: rule.fieldName,
157
181
  disabled: readonly,
158
182
  size: "small"
159
183
  }), ruleErrors.some(function (e) {
@@ -14,6 +14,8 @@ export interface RuleGroupEditorProps {
14
14
  maxLevel: number;
15
15
  /** 是否只读模式 */
16
16
  readonly?: boolean;
17
+ /** 是否允许与另一个字段比较 @author nokecy */
18
+ allowFieldComparison?: boolean;
17
19
  /** 规则组变更回调(可选) */
18
20
  onChange?: (group: RuleGroupDto) => void;
19
21
  }
@@ -35,6 +35,8 @@ export var RuleGroupEditor = function RuleGroupEditor(_ref) {
35
35
  maxLevel = _ref.maxLevel,
36
36
  _ref$readonly = _ref.readonly,
37
37
  readonly = _ref$readonly === void 0 ? false : _ref$readonly,
38
+ _ref$allowFieldCompar = _ref.allowFieldComparison,
39
+ allowFieldComparison = _ref$allowFieldCompar === void 0 ? false : _ref$allowFieldCompar,
38
40
  onChange = _ref.onChange;
39
41
  var _useRuleBuilderContex = useRuleBuilderContext(),
40
42
  state = _useRuleBuilderContex.state,
@@ -147,7 +149,8 @@ export var RuleGroupEditor = function RuleGroupEditor(_ref) {
147
149
  key: ruleIndex,
148
150
  rule: rule,
149
151
  path: rulePath,
150
- readonly: readonly
152
+ readonly: readonly,
153
+ allowFieldComparison: allowFieldComparison
151
154
  });
152
155
  }), currentGroup.groups.length > 0 && /*#__PURE__*/React.createElement("div", {
153
156
  className: styles.nestedGroups
@@ -159,6 +162,7 @@ export var RuleGroupEditor = function RuleGroupEditor(_ref) {
159
162
  level: level + 1,
160
163
  maxLevel: maxLevel,
161
164
  readonly: readonly,
165
+ allowFieldComparison: allowFieldComparison,
162
166
  onChange: onChange
163
167
  });
164
168
  })), currentGroup.rules.length === 0 && currentGroup.groups.length === 0 && /*#__PURE__*/React.createElement("div", {
@@ -41,6 +41,11 @@ export declare const operatorRequiresValue2: (operator: MatchOperator) => boolea
41
41
  * 检查操作符是否需要多个值(In/NotIn)
42
42
  */
43
43
  export declare const operatorRequiresMultiValue: (operator: MatchOperator) => boolean;
44
+ /**
45
+ * 检查操作符是否支持与另一个字段比较(与后端 RuleGroupValidator 一致:等于、不等于及 4 个大小比较)
46
+ * @author nokecy
47
+ */
48
+ export declare const operatorSupportsValueField: (operator: MatchOperator) => boolean;
44
49
  /**
45
50
  * 最大嵌套层级
46
51
  */
@@ -163,6 +163,14 @@ export var operatorRequiresMultiValue = function operatorRequiresMultiValue(oper
163
163
  return ((_OPERATOR_INFO_MAP$op3 = OPERATOR_INFO_MAP[operator]) === null || _OPERATOR_INFO_MAP$op3 === void 0 ? void 0 : _OPERATOR_INFO_MAP$op3.requiresMultiValue) || false;
164
164
  };
165
165
 
166
+ /**
167
+ * 检查操作符是否支持与另一个字段比较(与后端 RuleGroupValidator 一致:等于、不等于及 4 个大小比较)
168
+ * @author nokecy
169
+ */
170
+ export var operatorSupportsValueField = function operatorSupportsValueField(operator) {
171
+ return [MatchOperator.Equals, MatchOperator.NotEquals, MatchOperator.GreaterThan, MatchOperator.GreaterThanOrEqual, MatchOperator.LessThan, MatchOperator.LessThanOrEqual].includes(operator);
172
+ };
173
+
166
174
  /**
167
175
  * 最大嵌套层级
168
176
  */
@@ -20,6 +20,6 @@ export { RuleBuilderProvider, useRuleBuilderContext, useRuleBuilderState, useRul
20
20
  export { createEmptyRule, createEmptyRuleGroup, generateRuleDescription, cloneRuleGroup, isRuleGroupEmpty, countRules, getMaxDepth, } from './utils/ruleHelpers';
21
21
  export { getRuleGroupByPath, getRuleByPath, updateRuleAtPath, deleteRuleAtPath, addRuleAtPath, updateRuleGroupAtPath, deleteRuleGroupAtPath, addRuleGroupAtPath, } from './utils/pathHelpers';
22
22
  export { validateRuleGroup, validateRule, isRuleGroupValid, } from './utils/validation';
23
- export { OPERATOR_INFO_MAP, getOperatorInfo, operatorRequiresValue, operatorRequiresValue2, operatorRequiresMultiValue, getOperatorsByDataType, MAX_NESTING_LEVEL, } from './constants/operators';
23
+ export { OPERATOR_INFO_MAP, getOperatorInfo, operatorRequiresValue, operatorRequiresValue2, operatorRequiresMultiValue, operatorSupportsValueField, getOperatorsByDataType, MAX_NESTING_LEVEL, } from './constants/operators';
24
24
  export type { MatchOperator, MatchLogic, FieldDataType, RuleDto, RuleGroupDto, FieldDefinition, ValidationResult, ValidationError, RuleBuilderProps, RuleBuilderConfig, RulePath, RuleBuilderState, RuleBuilderAction, OperatorInfo, } from './types';
25
25
  export { RuleBuilderContainer as default } from './RuleBuilderContainer';
@@ -34,7 +34,7 @@ export { getRuleGroupByPath, getRuleByPath, updateRuleAtPath, deleteRuleAtPath,
34
34
  export { validateRuleGroup, validateRule, isRuleGroupValid } from "./utils/validation";
35
35
 
36
36
  // ============ 常量 ============
37
- export { OPERATOR_INFO_MAP, getOperatorInfo, operatorRequiresValue, operatorRequiresValue2, operatorRequiresMultiValue, getOperatorsByDataType, MAX_NESTING_LEVEL } from "./constants/operators";
37
+ export { OPERATOR_INFO_MAP, getOperatorInfo, operatorRequiresValue, operatorRequiresValue2, operatorRequiresMultiValue, operatorSupportsValueField, getOperatorsByDataType, MAX_NESTING_LEVEL } from "./constants/operators";
38
38
 
39
39
  // ============ 类型定义 ============
40
40