Search requests (#2)

Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz>
Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/2
Co-authored-by: timur.gorodetskiy <timur.gorodetskiy@tnsu.kz>
Co-committed-by: timur.gorodetskiy <timur.gorodetskiy@tnsu.kz>
This commit was merged in pull request #2.
This commit is contained in:
2026-08-06 09:59:07 +00:00
committed by gorbenko.pavel
parent 571614c031
commit 6acb22dd95
23 changed files with 1622 additions and 459 deletions
@@ -32,17 +32,20 @@ export class ApproverService {
) {}
// Ожидающая строка текущего пользователя, если сейчас его очередь; иначе undefined.
// Последовательное согласование: активна первая строка со статусом «На согласовании».
// Очередь уже проставлена на запись (см. createSteps/advanceQueue) — активна
// ровно одна строка со статусом «На согласовании» на фазу, искать «первую по
// порядку» не нужно.
public async getPendingRowForCurrentUser(requestId: number): Promise<IApprovalRow | undefined> {
const rows = await this.approval.getForRequest(requestId);
const userId = await this.approval.getCurrentUserId();
// Активна первая незакрытая строка по очереди: согласующий («На согласовании»)
// или, когда согласование пройдено, исполнитель («На исполнении»).
const firstPending = rows.filter(
// Активные строки текущего шага: согласующий («На согласовании») или, когда
// согласование пройдено, исполнитель («На исполнении»). При параллельном шаге
// (одинаковый StepOrder) активных строк может быть несколько сразу — ищем
// среди ВСЕХ активных, а не только среди первой по порядку.
const active = rows.filter(
(r) => r.status === REQUEST_STATUS.onApproval || r.status === REQUEST_STATUS.onExecution
)[0];
if (firstPending && firstPending.approverId === userId) return firstPending;
return undefined;
);
return active.filter((r) => r.approverId === userId)[0];
}
// Делегирование: согласующий добавляет делеганта ПЕРЕД собой (Order — между
@@ -59,22 +62,24 @@ export class ApproverService {
const prevOrder = before.length > 0 ? before[before.length - 1].order : current.order - 1;
const newOrder = (prevOrder + current.order) / 2;
const position = await this.approval.getJobTitle(user.loginName);
// Делегат наследует фазу той строки, вместо которой действует, и её статус
// ожидания (согласование → «На согласовании», исполнение → «На исполнении»).
const pendingStatus =
current.phase === APPROVAL_PHASE.execution
? REQUEST_STATUS.onExecution
: REQUEST_STATUS.onApproval;
// Делегат наследует фазу той строки, вместо которой согласует (согласование/исполнение).
// Обе строки — делегат и прежний согласующий — уходят в «Ждёт очереди»,
// activateNextQueued затем активирует делегата (у него меньший order).
await this.approval.addApproverRow(
requestId,
{ email: user.email, position, allowReassign: false },
newOrder,
pendingStatus,
REQUEST_STATUS.queued,
current.phase
);
await this.approval.setStatus(current.id, REQUEST_STATUS.queued);
await this.approval.activateNextQueued(requestId);
emitRequestsChanged();
}
// Применяет решение: обновляет строку и пересчитывает статус заявки.
// Применяет решение: обновляет строку, продвигает очередь (на следующего
// согласующего внутри фазы либо на первого исполнителя, если фаза согласования
// только что завершилась целиком) и пересчитывает статус заявки.
// Возвращает новый статус заявки.
public async decide(
requestId: number,