Новые условия (#15)
Tests / frontend-test (push) Successful in 46s
Tests / backend-test (push) Successful in 1m48s

Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/gorbenko.pavel/tnsu-approval-route/pulls/15
This commit was merged in pull request #15.
This commit is contained in:
2026-08-24 12:27:25 +00:00
parent a1fa862ed4
commit e4a6cb8167
12 changed files with 137 additions and 31 deletions
@@ -86,6 +86,12 @@ const OPERATION_OPTIONS = Object.values(ComparisonOperator)
.filter(v => v !== ComparisonOperator.None)
.map(v => ({ value: v, label: comparisonOperatorLabels[v] }));
/** «Больше»/«меньше» сравнивают числа — для текстовой колонки они бессмысленны. */
const NUMERIC_ONLY_OPERATIONS: ComparisonOperator[] = [ComparisonOperator.GreaterThan, ComparisonOperator.LessThan];
/** «Содержит»/«Не содержит» — поиск подстроки, только для текстовых колонок. */
const TEXT_ONLY_OPERATIONS: ComparisonOperator[] = [ComparisonOperator.Contains, ComparisonOperator.NotContains];
/**
* Служебное поле условия, не привязанное к списку SharePoint — вычисляется на бэкенде
* (см. TemplateRouteService.ResolveAsync) по значению поля Position В САМОЙ ЗАЯВКЕ
@@ -173,20 +179,33 @@ export const RouteStepFormModal: React.FC<IRouteStepFormModalProps> = ({
// IsManager — служебное булево поле, а не колонка списка, поэтому для него
// числовые ограничения не действуют в любом случае.
const selectedField = sharePointFields.items.find(f => f.internalName === form.fieldName);
const isNumericField = isManagerField ? false : selectedField ? isNumericFieldType(selectedField.typeAsString) : true;
const fieldKind: 'bool' | 'numeric' | 'text' | 'unknown' = isManagerField
? 'bool'
: !selectedField
? 'unknown'
: isNumericFieldType(selectedField.typeAsString)
? 'numeric'
: 'text';
const isNumericField = fieldKind === 'numeric' || fieldKind === 'unknown';
const operationOptions = isNumericField
? OPERATION_OPTIONS
: OPERATION_OPTIONS.filter(o => o.value === ComparisonOperator.Equal);
// Числовая колонка: всё, кроме «содержит»/«не содержит». Текстовая: всё, кроме «больше»/«меньше».
// Булев IsManager: только «равно»/«не равно». Неизвестный тип — не ограничиваем.
const operationOptions = React.useMemo(() => OPERATION_OPTIONS.filter(o => {
if (fieldKind === 'bool') return o.value === ComparisonOperator.Equal || o.value === ComparisonOperator.NotEqual;
if (fieldKind === 'numeric') return TEXT_ONLY_OPERATIONS.indexOf(o.value) < 0;
if (fieldKind === 'text') return NUMERIC_ONLY_OPERATIONS.indexOf(o.value) < 0;
return true;
}), [fieldKind]);
// Строковая колонка допускает только «равно» — если пользователь сменил
// field_name на нечисловую колонку, а раньше был выбран «больше»/«меньше», сбрасываем.
// Оператор, недопустимый для выбранной колонки (например, «больше» после смены
// field_name на текстовую), сбрасываем на «равно» — оно допустимо всегда.
const isOperationAllowed = operationOptions.some(o => o.value === form.operation);
React.useEffect(() => {
if (!isNumericField && form.operation !== ComparisonOperator.Equal) {
if (!isOperationAllowed) {
setForm(f => ({ ...f, operation: ComparisonOperator.Equal }));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isNumericField]);
}, [isOperationAllowed]);
// IsManager — булево поле: значение должно быть одним из IS_MANAGER_VALUE_OPTIONS,
// а не произвольным текстом, который пользователь мог набрать для другого field_name.