Несколько условий шага, объединяемых через И/ИЛИ
Раньше шаг маршрута мог нести ровно одно условие (field_name/operation/ value). Теперь условий может быть сколько угодно, а их объединение задаётся явно — ConditionsLogic.And (все условия) или .Or (любое из условий). Бэкенд: - Новая сущность TemplateRouteStepCondition (дочерняя таблица template_route_step_conditions, FK на шаг, cascade delete) вместо трёх колонок на TemplateRouteStep. Миграция AddMultipleStepConditions переносит существующие условия шагов в новую таблицу перед удалением старых колонок, чтобы не потерять уже настроенные в деве/проде условия. - TemplateRouteService.MatchesConditions: несколько условий шага объединяются по ConditionsLogic (Any/All); HasUnevaluatableManagerCondition проверяет условие на IsManager в списке условий, а не единственное поле. - TemplateRouteStepService: дубликаты шагов теперь сравниваются по всему набору условий (без учёта порядка) и, если условий два и более, по логике их объединения — сравнение в памяти, а не в SQL, кандидатов на дубликат в пределах маршрута всегда мало. - Валидация условия: раньше «все три поля или ни одного», теперь — в каждом элементе списка все три поля обязательны. Фронтенд: - RouteStepFormModal: условие — динамический список строк (добавить/удалить), у каждой строки свой набор допустимых операторов по типу колонки; селектор И/ИЛИ появляется, когда условий два и больше. - describeStepCondition в таблице шагов склеивает все условия через « И »/« ИЛИ ». Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { ComparisonOperator, Employee, HeadType, ProjectRole, StepExecutorKind, TemplateRouteStep } from '../models';
|
||||
import { comparisonOperatorSymbols, headTypeLabels, projectRoleLabels, texts } from '../texts';
|
||||
import { ConditionsLogic, Employee, HeadType, ProjectRole, StepExecutorKind, TemplateRouteStep } from '../models';
|
||||
import { comparisonOperatorSymbols, conditionsLogicJoiners, headTypeLabels, projectRoleLabels, texts } from '../texts';
|
||||
import { findEmployeeByEmail } from './employee';
|
||||
|
||||
/** Каким из четырёх взаимоисключающих способов у шага задан исполнитель. */
|
||||
@@ -42,8 +42,11 @@ export function describeStepExecutor(step: TemplateRouteStep, employees: Employe
|
||||
return { primary: texts.common.empty };
|
||||
}
|
||||
|
||||
/** Колонка «Условие» в таблице шагов — undefined, если у шага условия нет. */
|
||||
/** Колонка «Условие» в таблице шагов — undefined, если у шага условий нет. */
|
||||
export function describeStepCondition(step: TemplateRouteStep): string | undefined {
|
||||
if (!step.fieldName || !step.operation || step.operation === ComparisonOperator.None || !step.value) return undefined;
|
||||
return `${step.fieldName} ${comparisonOperatorSymbols[step.operation]} ${step.value}`;
|
||||
if (step.conditions.length === 0) return undefined;
|
||||
const joiner = conditionsLogicJoiners[step.conditionsLogic ?? ConditionsLogic.And];
|
||||
return step.conditions
|
||||
.map(c => `${c.fieldName} ${comparisonOperatorSymbols[c.operation]} ${c.value}`)
|
||||
.join(joiner);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user