feat: инициатор заменяет согласующих в заявке на рабочее место до отправки
Если согласующий из маршрута недоступен (отпуск и т.п.), инициатор может поставить на его шаг другого человека, пока заявка не отправлена. Шаг целиком (порядок, роль, SLA) сохраняется, удалить его по-прежнему нельзя — состав маршрута из админки остаётся гарантированным. Замена — общая операция useMatrixEditor.replace, кнопка подключена только в этой форме. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -414,6 +414,11 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
||||
editor={matrix}
|
||||
search={(q) => approval.searchUsers(q)}
|
||||
canRemoveRow={composeRemoveRowRule(effectiveUserEmail(context))}
|
||||
// Пока заявка не отправлена, любой инициатор может поставить на шаг
|
||||
// другого человека (напр. согласующий в отпуске), но не убрать шаг:
|
||||
// состав маршрута из админки остаётся гарантированным.
|
||||
canReplaceRow={readOnly ? undefined : () => true}
|
||||
onReplaceRow={matrix.replace}
|
||||
/>
|
||||
|
||||
{!executors.loading && (executors.editable || executors.rows.length > 0) && (
|
||||
|
||||
@@ -17,6 +17,12 @@ export interface IUseMatrixEditor {
|
||||
moveBlockUp: (index: number) => void;
|
||||
moveBlockDown: (index: number) => void;
|
||||
remove: (index: number) => void;
|
||||
/**
|
||||
* Поставить в строку другого человека. Шаг (порядок, роль, SLA и прочие
|
||||
* настройки из админки) остаётся прежним — меняется только исполнитель шага.
|
||||
* Человек, уже стоящий в маршруте, не подставляется (дубль шага).
|
||||
*/
|
||||
replace: (row: IMatrixRow, user: ISiteUser) => void;
|
||||
/** Переключить «идёт параллельно с предыдущим шагом». Для первой строки — no-op. */
|
||||
toggleParallel: (index: number) => void;
|
||||
/** Границы шагов: индексы строк, объединённых общим order. */
|
||||
@@ -285,6 +291,13 @@ export function useMatrixEditor(
|
||||
const remove = (i: number): void =>
|
||||
setRows((prev) => withOrders(prev.filter((_, idx) => idx !== i)));
|
||||
|
||||
const replace = (row: IMatrixRow, user: ISiteUser): void =>
|
||||
setRows((prev) => {
|
||||
if (user.email && prev.some((r) => r !== row && r.email === user.email)) return prev;
|
||||
// warning убираем: он был про незаполненную роль шага, а теперь человек выбран вручную.
|
||||
return prev.map((r) => (r === row ? { ...r, who: user.name, email: user.email, warning: null } : r));
|
||||
});
|
||||
|
||||
const toggleParallel = (i: number): void =>
|
||||
setRows((prev) =>
|
||||
i <= 0
|
||||
@@ -302,6 +315,7 @@ export function useMatrixEditor(
|
||||
moveBlockUp,
|
||||
moveBlockDown,
|
||||
remove,
|
||||
replace,
|
||||
toggleParallel,
|
||||
blocks: blockRanges(rows),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user