@myrtex-org/form 1.1.26 → 1.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, Component, ChangeDetectionStrategy, EventEmitter, Directive, Input, Output, ChangeDetectorRef, Inject, ViewChild, NgModule } from '@angular/core';
2
+ import { Injectable, inject, ChangeDetectionStrategy, Component, EventEmitter, Output, Input, Directive, ChangeDetectorRef, Inject, ViewChild, NgModule } from '@angular/core';
3
3
  import * as i1$3 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i1$1 from '@angular/router';
@@ -863,6 +863,184 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
863
863
  type: Injectable
864
864
  }] });
865
865
 
866
+ class FormulaCalculateService {
867
+ constructor() {
868
+ this._operatorPrecedence = {
869
+ '+': 1,
870
+ '-': 1,
871
+ '*': 2,
872
+ '/': 2,
873
+ };
874
+ this._operators = ['+', '-', '*', '/'];
875
+ }
876
+ calculateMathExpression(expression, values) {
877
+ try {
878
+ return this._calculateMathExpression(expression, values);
879
+ }
880
+ catch {
881
+ return 0;
882
+ }
883
+ }
884
+ calculateStringConcatenation(expression, values) {
885
+ return expression.replace(/{(?<systemName>\w+)(?::(?<format>[^}]+))?}/g, (_match, systemName) => {
886
+ const value = values.find(x => x.sysName === systemName);
887
+ return value?.value?.toString?.() ?? '';
888
+ });
889
+ }
890
+ _calculateMathExpression(expression, values) {
891
+ const operatorStack = [];
892
+ const operandStack = [];
893
+ for (let i = 0; i < expression.length; i++) {
894
+ const charValue = expression[i];
895
+ if (/\s/.test(charValue)) {
896
+ continue;
897
+ }
898
+ if (charValue === '{') {
899
+ let sysNameOperand = '';
900
+ while (i < expression.length && expression[i] !== '}') {
901
+ sysNameOperand += expression[i];
902
+ i++;
903
+ }
904
+ sysNameOperand += expression[i] ?? '';
905
+ const value = this._getNumberValue(values, sysNameOperand);
906
+ if (value === null) {
907
+ return 0;
908
+ }
909
+ operandStack.push(value);
910
+ continue;
911
+ }
912
+ if (charValue === '(') {
913
+ const nestedExpression = this._getExpressionBetweenParentheses(expression, i);
914
+ operandStack.push(this._calculateMathExpression(nestedExpression, values));
915
+ i += nestedExpression.length + 1;
916
+ continue;
917
+ }
918
+ if (this._isOperator(charValue)) {
919
+ this._addOperator(operatorStack, operandStack, charValue);
920
+ continue;
921
+ }
922
+ if (/\d/.test(charValue)) {
923
+ let number = '';
924
+ while (i < expression.length && (/[\d.]/.test(expression[i]))) {
925
+ number += expression[i];
926
+ i++;
927
+ }
928
+ i--;
929
+ const value = this._getNumberValue(values, number);
930
+ if (value === null) {
931
+ return 0;
932
+ }
933
+ operandStack.push(value);
934
+ continue;
935
+ }
936
+ if (/[a-zA-Z]/.test(charValue)) {
937
+ i += this._addFunctionResult(operandStack, values, expression, i);
938
+ }
939
+ }
940
+ this._calculateAll(operandStack, operatorStack);
941
+ return operandStack.pop() ?? 0;
942
+ }
943
+ _addFunctionResult(operandStack, values, expression, startIndex) {
944
+ const idxEof = expression.indexOf(')', startIndex);
945
+ const operand = expression.substring(startIndex, idxEof - startIndex + 1);
946
+ const lowerOperand = operand.toLowerCase();
947
+ if (lowerOperand.startsWith('pow(') && lowerOperand.endsWith(')')) {
948
+ const innerExpression = operand.substring(4, operand.length - 1);
949
+ const innerOperands = innerExpression.split(',').map(x => x.trim());
950
+ const baseValue = this._getNumberValue(values, innerOperands[0]);
951
+ const exponent = this._getNumberValue(values, innerOperands[1]);
952
+ if (baseValue === null || exponent === null) {
953
+ operandStack.push(0);
954
+ }
955
+ else {
956
+ operandStack.push(Math.pow(baseValue, exponent));
957
+ }
958
+ return operand.length - 1;
959
+ }
960
+ if (lowerOperand.startsWith('sqrt(') && lowerOperand.endsWith(')')) {
961
+ const innerExpression = operand.substring(5, operand.length - 1);
962
+ const value = this._getNumberValue(values, innerExpression);
963
+ operandStack.push(value === null ? 0 : Math.sqrt(value));
964
+ return operand.length - 1;
965
+ }
966
+ throw new Error('Invalid function operand');
967
+ }
968
+ _addOperator(operatorStack, operandStack, operatorToken) {
969
+ while (operatorStack.length > 0 &&
970
+ this._getOperatorPrecedence(operatorToken) <= this._getOperatorPrecedence(operatorStack[operatorStack.length - 1])) {
971
+ const operand2 = operandStack.pop() ?? 0;
972
+ const operand1 = operandStack.pop() ?? 0;
973
+ const operatorTokenToApply = operatorStack.pop();
974
+ operandStack.push(this._calculate(operand1, operand2, operatorTokenToApply));
975
+ }
976
+ operatorStack.push(operatorToken);
977
+ }
978
+ _calculateAll(operandStack, operatorStack) {
979
+ while (operatorStack.length > 0) {
980
+ const operatorToken = operatorStack.pop();
981
+ const operand2 = operandStack.pop() ?? 0;
982
+ const operand1 = operandStack.pop() ?? 0;
983
+ operandStack.push(this._calculate(operand1, operand2, operatorToken));
984
+ }
985
+ }
986
+ _getOperatorPrecedence(operatorToken) {
987
+ return this._operatorPrecedence[operatorToken];
988
+ }
989
+ _getExpressionBetweenParentheses(expression, startIndex) {
990
+ let level = 0;
991
+ for (let i = startIndex; i < expression.length; i++) {
992
+ if (expression[i] === '(') {
993
+ level++;
994
+ }
995
+ else if (expression[i] === ')') {
996
+ level--;
997
+ if (level === 0) {
998
+ return expression.substring(startIndex + 1, i);
999
+ }
1000
+ }
1001
+ }
1002
+ throw new Error('Unbalanced parentheses');
1003
+ }
1004
+ _getNumberValue(values, operand) {
1005
+ const cleanOperand = operand.trim().replace(',', '.').replace(/^\{|\}$/g, '');
1006
+ const val = values.find(x => x.sysName === cleanOperand);
1007
+ if (val) {
1008
+ if (val.value === null || val.value === undefined || val.value === '') {
1009
+ return null;
1010
+ }
1011
+ const parsed = Number(String(val.value).replace(',', '.'));
1012
+ return Number.isFinite(parsed) ? parsed : null;
1013
+ }
1014
+ const asNumber = Number(cleanOperand);
1015
+ if (Number.isFinite(asNumber)) {
1016
+ return asNumber;
1017
+ }
1018
+ throw new Error(`Invalid operand ${operand}`);
1019
+ }
1020
+ _calculate(operand1, operand2, operatorToken) {
1021
+ switch (operatorToken) {
1022
+ case '+':
1023
+ return operand1 + operand2;
1024
+ case '-':
1025
+ return operand1 - operand2;
1026
+ case '*':
1027
+ return operand1 * operand2;
1028
+ case '/':
1029
+ return operand1 / operand2;
1030
+ default:
1031
+ throw new Error(`Invalid operator ${operatorToken}`);
1032
+ }
1033
+ }
1034
+ _isOperator(token) {
1035
+ return this._operators.includes(token);
1036
+ }
1037
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FormulaCalculateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1038
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FormulaCalculateService }); }
1039
+ }
1040
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FormulaCalculateService, decorators: [{
1041
+ type: Injectable
1042
+ }] });
1043
+
866
1044
  class ObjectFormEffects {
867
1045
  constructor(_actions$, _store, _router, _applicationService, _toasterService) {
868
1046
  this._actions$ = _actions$;
@@ -1041,48 +1219,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1041
1219
  }], ctorParameters: () => [{ type: i1$1.Router }] });
1042
1220
 
1043
1221
  class ComponentFactoryDirective {
1044
- constructor(viewContainer, cdr) {
1222
+ constructor(viewContainer) {
1045
1223
  this.viewContainer = viewContainer;
1046
- this.cdr = cdr;
1047
1224
  this.values = [];
1048
1225
  this.changed = new EventEmitter();
1049
1226
  }
1050
1227
  ngOnChanges(changes) {
1051
- // 1. Сначала инициализируем виджет, если сменился тип
1052
- if ('type' in changes && this.type) {
1228
+ if ('type' in changes && this.type && changes['type'].previousValue !== changes['type'].currentValue) {
1053
1229
  this.initWidget(this.type);
1054
1230
  }
1055
- // 2. Если компонент уже есть (или только что создался), обновляем все свойства
1056
- if (this.dynamicComponent) {
1057
- if ('data' in changes && this.data) {
1058
- this.dynamicComponent.instance.data = this.data;
1059
- }
1060
- if ('valueMode' in changes && this.valueMode) {
1061
- this.dynamicComponent.instance.valueMode = this.valueMode;
1062
- }
1063
- // Используем currentValue из changes, чтобы быть уверенными в свежести данных
1064
- if ('values' in changes) {
1065
- this.dynamicComponent.instance.values = changes['values'].currentValue;
1066
- }
1067
- // КРИТИЧНО: уведомляем Angular, что в динамическом компоненте обновились данные
1068
- this.dynamicComponent.changeDetectorRef.detectChanges();
1231
+ if ('data' in changes && this.data) {
1232
+ this.applyData(this.data);
1233
+ }
1234
+ if ('valueMode' in changes && this.data && this.valueMode) {
1235
+ this.applyValueMode(this.valueMode);
1236
+ }
1237
+ if ('values' in changes && this.data) {
1238
+ this.applyValues(this.values);
1069
1239
  }
1070
1240
  }
1071
1241
  initWidget(type) {
1072
1242
  const componentType = this.map[type];
1073
- if (!componentType)
1243
+ if (!componentType) {
1074
1244
  return;
1075
- this.viewContainer.clear();
1245
+ }
1246
+ if (this.dynamicComponent) {
1247
+ this.viewContainer.clear();
1248
+ this.dynamicComponent = undefined;
1249
+ }
1076
1250
  this.dynamicComponent = this.viewContainer.createComponent(componentType);
1077
- // Сразу передаем всё, что есть на момент создания
1078
- const instance = this.dynamicComponent.instance;
1079
- if (this.data)
1080
- instance.data = this.data;
1081
- if (this.values)
1082
- instance.values = this.values;
1083
- if (this.valueMode)
1084
- instance.valueMode = this.valueMode;
1085
- if (this.dynamicComponent && this.dynamicComponent.instance.changed) {
1251
+ if (this.data) {
1252
+ this.dynamicComponent.instance.data = this.data;
1253
+ }
1254
+ if (this.dynamicComponent.instance.changed) {
1086
1255
  this.dynamicComponent.instance.changed.subscribe((res) => {
1087
1256
  this.changed.emit(res);
1088
1257
  });
@@ -1103,7 +1272,7 @@ class ComponentFactoryDirective {
1103
1272
  this.dynamicComponent.instance.valueMode = valueMode;
1104
1273
  }
1105
1274
  }
1106
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentFactoryDirective, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1275
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentFactoryDirective, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1107
1276
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.3.12", type: ComponentFactoryDirective, isStandalone: true, selector: "[appComponentFactory]", inputs: { type: "type", data: "data", values: "values", valueMode: "valueMode", map: "map" }, outputs: { changed: "changed" }, usesOnChanges: true, ngImport: i0 }); }
1108
1277
  }
1109
1278
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ComponentFactoryDirective, decorators: [{
@@ -1112,7 +1281,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1112
1281
  selector: '[appComponentFactory]',
1113
1282
  standalone: true
1114
1283
  }]
1115
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }], propDecorators: { type: [{
1284
+ }], ctorParameters: () => [{ type: i0.ViewContainerRef }], propDecorators: { type: [{
1116
1285
  type: Input
1117
1286
  }], data: [{
1118
1287
  type: Input
@@ -1172,6 +1341,12 @@ class BaseFieldComponent {
1172
1341
  set values(value) {
1173
1342
  if (this.valueMode === 'manual') {
1174
1343
  this.manualValues = value;
1344
+ const isFormulaInputNumber = this.settings?.type === ComponentType.InputNumber &&
1345
+ this.settings?.options?.inputState === InputState.Formula;
1346
+ if (isFormulaInputNumber && this.model) {
1347
+ this.model.value = getValueModel(this.settings, this.manualValues)?.value;
1348
+ this._detector.detectChanges();
1349
+ }
1175
1350
  }
1176
1351
  }
1177
1352
  set data(settings) {
@@ -1403,6 +1578,12 @@ class InputNumberComponent extends BaseFieldComponent {
1403
1578
  this.validateValue = 0;
1404
1579
  }
1405
1580
  get isReadonly() {
1581
+ return this.hasFormula;
1582
+ }
1583
+ get isInputDisabled() {
1584
+ return this.disabled || this.hasFormula;
1585
+ }
1586
+ get hasFormula() {
1406
1587
  return this.settings.options.inputState === InputState.Formula;
1407
1588
  }
1408
1589
  onChangeInput() {
@@ -1415,11 +1596,11 @@ class InputNumberComponent extends BaseFieldComponent {
1415
1596
  this.settings.options.maxValue && model.value && this.settings.options.maxValue < model.value);
1416
1597
  }
1417
1598
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputNumberComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1418
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: InputNumberComponent, selector: "app-input-number", usesInheritance: true, ngImport: i0, template: "@if (settings) {\r\n <div class=\"input-number-content\">\r\n @if (settings.options.label) {\r\n <mrx-label\r\n [required]=\"settings.options.required\"\r\n [tooltip]=\"settings.options.tooltip || ''\"\r\n >\r\n {{ settings.options.label }}\r\n </mrx-label>\r\n }\r\n\r\n <mrx-input-number\r\n [(ngModel)]=\"model.value\"\r\n [fields]=\"autosaveFields\"\r\n [readonly]=\"isReadonly\"\r\n [allowNegative]=\"true\"\r\n [numberType]=\"isReadonly || settings.options.decimals ? 'float' : 'int'\"\r\n [decimalSeparator]=\"settings.options.decimalSeparator\"\r\n [decimals]=\"isReadonly ? (settings.options.decimals || 2) : settings.options.decimals\"\r\n [placeholder]=\"settings.options.placeholder\"\r\n [disabled]=\"disabled\"\r\n [invalid]=\"getInvalid\"\r\n [invalidMessage]=\"getInvalidMessage\"\r\n (modelChange)=\"dispatchModify($event)\"\r\n (change)=\"onChangeInput()\"\r\n ></mrx-input-number>\r\n\r\n @if (settings.options.minValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.minValue }}\"\r\n [value]=\"validateValue\"\r\n [minValue]=\"settings.options.minValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n @if (settings.options.maxValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.maxValue }}\"\r\n [value]=\"validateValue\"\r\n [maxValue]=\"settings.options.maxValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n </div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: i1$2.LabelComponent, selector: "mrx-label", inputs: ["requiredHidden", "required", "boldLabel", "disabled", "placeholder", "label", "customClasses", "triggerTextPosition", "isPublicInfo", "publicInfoTooltip", "isSwitch", "switchLabel", "switchValue", "switchSize", "isCheckbox", "checkboxLabel", "checkboxValue", "counter", "linkText", "linkPrevent", "linkType", "linkMonochrome", "href", "triggerType", "tooltip", "tooltipInitialVisible", "isSaveToStorage"], outputs: ["changeSwitchValue", "changeCheckboxValue", "clickedLink"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1$2.InputNumberComponent, selector: "mrx-input-number", inputs: ["fields", "placeholder", "innerClass", "customClasses", "required", "allowNegative", "size", "separator", "decimalSeparator", "decimals", "isNullableValue", "isAutoCorrectingValue", "invalid", "checkInvalid", "numberType", "invalidMessage", "disabled", "readonly", "minValue", "maxValue"], outputs: ["modelChange", "modelChangeBlur"] }, { kind: "component", type: i1$2.HintErrorMessageComponent, selector: "mrx-hint-error-message", inputs: ["message", "value", "maxValue", "minValue", "minLength", "maxLength", "checkInvalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1599
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: InputNumberComponent, selector: "app-input-number", usesInheritance: true, ngImport: i0, template: "@if (settings) {\r\n <div class=\"input-number-content\">\r\n @if (settings.options.label) {\r\n <mrx-label\r\n [required]=\"settings.options.required\"\r\n [tooltip]=\"settings.options.tooltip || ''\"\r\n >\r\n {{ settings.options.label }}\r\n </mrx-label>\r\n }\r\n\r\n <mrx-input-number\r\n [(ngModel)]=\"model.value\"\r\n [fields]=\"autosaveFields\"\r\n [readonly]=\"isReadonly\"\r\n [allowNegative]=\"true\"\r\n [numberType]=\"isReadonly || settings.options.decimals ? 'float' : 'int'\"\r\n [decimalSeparator]=\"settings.options.decimalSeparator\"\r\n [decimals]=\"isReadonly ? (settings.options.decimals || 2) : settings.options.decimals\"\r\n [placeholder]=\"settings.options.placeholder\"\r\n [disabled]=\"isInputDisabled\"\r\n [invalid]=\"getInvalid\"\r\n [invalidMessage]=\"getInvalidMessage\"\r\n (modelChange)=\"dispatchModify($event)\"\r\n (change)=\"onChangeInput()\"\r\n ></mrx-input-number>\r\n\r\n @if (settings.options.minValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.minValue }}\"\r\n [value]=\"validateValue\"\r\n [minValue]=\"settings.options.minValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n @if (settings.options.maxValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.maxValue }}\"\r\n [value]=\"validateValue\"\r\n [maxValue]=\"settings.options.maxValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n </div>\r\n}\r\n", styles: [""], dependencies: [{ kind: "component", type: i1$2.LabelComponent, selector: "mrx-label", inputs: ["requiredHidden", "required", "boldLabel", "disabled", "placeholder", "label", "customClasses", "triggerTextPosition", "isPublicInfo", "publicInfoTooltip", "isSwitch", "switchLabel", "switchValue", "switchSize", "isCheckbox", "checkboxLabel", "checkboxValue", "counter", "linkText", "linkPrevent", "linkType", "linkMonochrome", "href", "triggerType", "tooltip", "tooltipInitialVisible", "isSaveToStorage"], outputs: ["changeSwitchValue", "changeCheckboxValue", "clickedLink"] }, { kind: "directive", type: i2$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i1$2.InputNumberComponent, selector: "mrx-input-number", inputs: ["fields", "placeholder", "innerClass", "customClasses", "required", "allowNegative", "size", "separator", "decimalSeparator", "decimals", "isNullableValue", "isAutoCorrectingValue", "invalid", "checkInvalid", "numberType", "invalidMessage", "disabled", "readonly", "minValue", "maxValue"], outputs: ["modelChange", "modelChangeBlur"] }, { kind: "component", type: i1$2.HintErrorMessageComponent, selector: "mrx-hint-error-message", inputs: ["message", "value", "maxValue", "minValue", "minLength", "maxLength", "checkInvalid"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1419
1600
  }
1420
1601
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputNumberComponent, decorators: [{
1421
1602
  type: Component,
1422
- args: [{ selector: 'app-input-number', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (settings) {\r\n <div class=\"input-number-content\">\r\n @if (settings.options.label) {\r\n <mrx-label\r\n [required]=\"settings.options.required\"\r\n [tooltip]=\"settings.options.tooltip || ''\"\r\n >\r\n {{ settings.options.label }}\r\n </mrx-label>\r\n }\r\n\r\n <mrx-input-number\r\n [(ngModel)]=\"model.value\"\r\n [fields]=\"autosaveFields\"\r\n [readonly]=\"isReadonly\"\r\n [allowNegative]=\"true\"\r\n [numberType]=\"isReadonly || settings.options.decimals ? 'float' : 'int'\"\r\n [decimalSeparator]=\"settings.options.decimalSeparator\"\r\n [decimals]=\"isReadonly ? (settings.options.decimals || 2) : settings.options.decimals\"\r\n [placeholder]=\"settings.options.placeholder\"\r\n [disabled]=\"disabled\"\r\n [invalid]=\"getInvalid\"\r\n [invalidMessage]=\"getInvalidMessage\"\r\n (modelChange)=\"dispatchModify($event)\"\r\n (change)=\"onChangeInput()\"\r\n ></mrx-input-number>\r\n\r\n @if (settings.options.minValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.minValue }}\"\r\n [value]=\"validateValue\"\r\n [minValue]=\"settings.options.minValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n @if (settings.options.maxValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.maxValue }}\"\r\n [value]=\"validateValue\"\r\n [maxValue]=\"settings.options.maxValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n </div>\r\n}\r\n" }]
1603
+ args: [{ selector: 'app-input-number', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (settings) {\r\n <div class=\"input-number-content\">\r\n @if (settings.options.label) {\r\n <mrx-label\r\n [required]=\"settings.options.required\"\r\n [tooltip]=\"settings.options.tooltip || ''\"\r\n >\r\n {{ settings.options.label }}\r\n </mrx-label>\r\n }\r\n\r\n <mrx-input-number\r\n [(ngModel)]=\"model.value\"\r\n [fields]=\"autosaveFields\"\r\n [readonly]=\"isReadonly\"\r\n [allowNegative]=\"true\"\r\n [numberType]=\"isReadonly || settings.options.decimals ? 'float' : 'int'\"\r\n [decimalSeparator]=\"settings.options.decimalSeparator\"\r\n [decimals]=\"isReadonly ? (settings.options.decimals || 2) : settings.options.decimals\"\r\n [placeholder]=\"settings.options.placeholder\"\r\n [disabled]=\"isInputDisabled\"\r\n [invalid]=\"getInvalid\"\r\n [invalidMessage]=\"getInvalidMessage\"\r\n (modelChange)=\"dispatchModify($event)\"\r\n (change)=\"onChangeInput()\"\r\n ></mrx-input-number>\r\n\r\n @if (settings.options.minValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.minValue }}\"\r\n [value]=\"validateValue\"\r\n [minValue]=\"settings.options.minValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n @if (settings.options.maxValue) {\r\n <mrx-hint-error-message\r\n message=\"\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 {{ settings.options.maxValue }}\"\r\n [value]=\"validateValue\"\r\n [maxValue]=\"settings.options.maxValue\"\r\n ></mrx-hint-error-message>\r\n }\r\n </div>\r\n}\r\n" }]
1423
1604
  }] });
1424
1605
 
1425
1606
  class InputSelectComponent extends BaseFieldComponent {
@@ -1994,10 +2175,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1994
2175
  }] } });
1995
2176
 
1996
2177
  class InputTableModalComponent extends ModalServiceComponent {
1997
- constructor(dialogRef, store, data) {
2178
+ constructor(dialogRef, store, formulaCalculateService, data) {
1998
2179
  super();
1999
2180
  this.dialogRef = dialogRef;
2000
2181
  this.store = store;
2182
+ this.formulaCalculateService = formulaCalculateService;
2001
2183
  this.emptyRow = true;
2002
2184
  this.title = data.title;
2003
2185
  this.okText = data.okText;
@@ -2015,6 +2197,7 @@ class InputTableModalComponent extends ModalServiceComponent {
2015
2197
  else {
2016
2198
  this._transformValues(valueModel);
2017
2199
  }
2200
+ this._recalculateFormulaFields();
2018
2201
  this.emptyRow = this.rowModel.data.every(x => this.isEmpty(x.value, x.valueType));
2019
2202
  }
2020
2203
  ok() {
@@ -2042,6 +2225,46 @@ class InputTableModalComponent extends ModalServiceComponent {
2042
2225
  }
2043
2226
  this.rowModel = cloneRowModel;
2044
2227
  }
2228
+ _recalculateFormulaFields() {
2229
+ const formulaComponents = this._getFormulaNumberComponents(this.settings.components);
2230
+ if (!formulaComponents.length) {
2231
+ return;
2232
+ }
2233
+ const cloneRowModel = structuredClone(this.rowModel);
2234
+ for (let i = 0; i < formulaComponents.length; i++) {
2235
+ let hasUpdates = false;
2236
+ for (const component of formulaComponents) {
2237
+ const formula = component.options?.formula?.trim();
2238
+ if (!formula) {
2239
+ continue;
2240
+ }
2241
+ const result = this.formulaCalculateService.calculateMathExpression(formula, cloneRowModel.data);
2242
+ const targetValue = cloneRowModel.data.find(x => x.sysName === component.sysName);
2243
+ if (!targetValue || targetValue.value === result) {
2244
+ continue;
2245
+ }
2246
+ targetValue.value = result;
2247
+ hasUpdates = true;
2248
+ }
2249
+ if (!hasUpdates) {
2250
+ break;
2251
+ }
2252
+ }
2253
+ this.rowModel = cloneRowModel;
2254
+ }
2255
+ _getFormulaNumberComponents(components) {
2256
+ const result = [];
2257
+ for (const component of components) {
2258
+ if (component.type === ComponentType.InputNumber &&
2259
+ component.options?.inputState === InputState.Formula) {
2260
+ result.push(component);
2261
+ }
2262
+ if (component.components?.length) {
2263
+ result.push(...this._getFormulaNumberComponents(component.components));
2264
+ }
2265
+ }
2266
+ return result;
2267
+ }
2045
2268
  _isValid() {
2046
2269
  var hasError = false;
2047
2270
  var requiredComponents = this._getRequiredComponents(this.settings.components);
@@ -2073,9 +2296,10 @@ class InputTableModalComponent extends ModalServiceComponent {
2073
2296
  return value.length === 0;
2074
2297
  return false;
2075
2298
  }
2076
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputTableModalComponent, deps: [{ token: i1$2.ModalRef }, { token: i2.Store }, { token: MODAL_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
2299
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: InputTableModalComponent, deps: [{ token: i1$2.ModalRef }, { token: i2.Store }, { token: FormulaCalculateService }, { token: MODAL_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
2077
2300
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: InputTableModalComponent, isStandalone: true, selector: "app-input-table-modal", providers: [
2078
2301
  provideNgxMask(),
2302
+ FormulaCalculateService,
2079
2303
  ReferenceService // для компонента список
2080
2304
  ], usesInheritance: true, ngImport: i0, template: "<mrx-modal\r\n [title]=\"title\"\r\n size=\"large\"\r\n (close)=\"close()\"\r\n (ok)=\"ok()\"\r\n>\r\n <app-form-dispenser-modal\r\n [sectionSettings]=\"settings\"\r\n [values]=\"rowModel.data\"\r\n [valueMode]=\"'manual'\"\r\n (changed)=\"componentValueChanged($event)\"\r\n ></app-form-dispenser-modal>\r\n\r\n <ng-template #footerContent>\r\n <mrx-button\r\n [customClasses]=\"'mr-3'\"\r\n [type]=\"'secondary'\"\r\n [size]=\"'medium'\"\r\n (click)=\"close()\"\r\n >\u041E\u0442\u043C\u0435\u043D\u0430\r\n </mrx-button>\r\n <mrx-button\r\n [type]=\"'primary'\"\r\n [size]=\"'medium'\"\r\n [disabled]=\"emptyRow\"\r\n (click)=\"ok()\"\r\n >{{ okText }}\r\n </mrx-button>\r\n </ng-template>\r\n</mrx-modal>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: ModalModule }, { kind: "component", type: i1$2.ModalComponent, selector: "mrx-modal", inputs: ["title", "message", "alert", "okText", "closeText", "size", "color", "customClasses", "expandable", "isEmbed", "isClose", "isBack", "backText", "enableFooter", "alignButtons", "isLoading", "iconPosition"], outputs: ["ok", "close", "back", "expand"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i1$2.ButtonComponent, selector: "mrx-button", inputs: ["size", "type", "color", "iconPosition", "active", "disabled", "isLoading", "iconOnly", "customClasses", "label", "icon", "iconClass", "buttonType", "href", "target", "routerLink", "queryParams"], outputs: ["mrxClick"] }, { kind: "component", type: FormDispenserModal, selector: "app-form-dispenser-modal", inputs: ["sectionSettings", "values", "valueMode"], outputs: ["changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2081
2305
  }
@@ -2087,9 +2311,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2087
2311
  FormDispenserModal,
2088
2312
  ], providers: [
2089
2313
  provideNgxMask(),
2314
+ FormulaCalculateService,
2090
2315
  ReferenceService // для компонента список
2091
2316
  ], template: "<mrx-modal\r\n [title]=\"title\"\r\n size=\"large\"\r\n (close)=\"close()\"\r\n (ok)=\"ok()\"\r\n>\r\n <app-form-dispenser-modal\r\n [sectionSettings]=\"settings\"\r\n [values]=\"rowModel.data\"\r\n [valueMode]=\"'manual'\"\r\n (changed)=\"componentValueChanged($event)\"\r\n ></app-form-dispenser-modal>\r\n\r\n <ng-template #footerContent>\r\n <mrx-button\r\n [customClasses]=\"'mr-3'\"\r\n [type]=\"'secondary'\"\r\n [size]=\"'medium'\"\r\n (click)=\"close()\"\r\n >\u041E\u0442\u043C\u0435\u043D\u0430\r\n </mrx-button>\r\n <mrx-button\r\n [type]=\"'primary'\"\r\n [size]=\"'medium'\"\r\n [disabled]=\"emptyRow\"\r\n (click)=\"ok()\"\r\n >{{ okText }}\r\n </mrx-button>\r\n </ng-template>\r\n</mrx-modal>\r\n" }]
2092
- }], ctorParameters: () => [{ type: i1$2.ModalRef }, { type: i2.Store }, { type: undefined, decorators: [{
2317
+ }], ctorParameters: () => [{ type: i1$2.ModalRef }, { type: i2.Store }, { type: FormulaCalculateService }, { type: undefined, decorators: [{
2093
2318
  type: Inject,
2094
2319
  args: [MODAL_DATA]
2095
2320
  }] }] });
@@ -2190,7 +2415,7 @@ class InputTableComponent {
2190
2415
  });
2191
2416
  }
2192
2417
  deleteRow(event) {
2193
- const findRow = structuredClone(this.model.data.find(item => item.id === event.row.data.id));
2418
+ const findRow = this.model.data.find(item => item.id === event.row.data.id);
2194
2419
  if (findRow) {
2195
2420
  this.model.data = this.model.data.filter(item => item.id !== event.row.data.id);
2196
2421
  this._initDataSource(this.model.data);
@@ -2238,8 +2463,6 @@ class InputTableComponent {
2238
2463
  switch (component.type) {
2239
2464
  case ComponentType.InputDate:
2240
2465
  return 'date';
2241
- case ComponentType.InputSwitch:
2242
- return 'boolean';
2243
2466
  default:
2244
2467
  return 'string';
2245
2468
  }
@@ -2296,7 +2519,6 @@ class InputTableComponent {
2296
2519
  this._detector.detectChanges();
2297
2520
  }
2298
2521
  _transformColumn(component) {
2299
- const dataType = this.getDataType(component);
2300
2522
  const column = {
2301
2523
  caption: component.options.label || '',
2302
2524
  columns: component.components.map(c => this._transformColumn(structuredClone(c))),
@@ -2305,21 +2527,6 @@ class InputTableComponent {
2305
2527
  format: this.getFormat(component),
2306
2528
  minWidth: 160
2307
2529
  };
2308
- if (dataType === 'boolean') {
2309
- column.calculateCellValue = (rowData) => {
2310
- const value = rowData[component.sysName];
2311
- // Если true — Да, если false, "" или null — Нет
2312
- return !!value;
2313
- };
2314
- column.lookup = {
2315
- dataSource: [
2316
- { value: true, displayValue: 'Да' },
2317
- { value: false, displayValue: 'Нет' }
2318
- ],
2319
- valueExpr: 'value',
2320
- displayExpr: 'displayValue'
2321
- };
2322
- }
2323
2530
  if (this.settings.options.groups.length) {
2324
2531
  const findIdx = this.settings.options.groups.findIndex(x => x === component.sysName);
2325
2532
  if (findIdx !== -1) {