куча правок
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
// Общая механика «шагов, которые могут идти параллельно» — 1:1 повторяет
|
||||
// request-portal/src/webparts/requestPortal/shared/approval/useMatrixEditor.ts
|
||||
// (blockRanges/swapBlocks/withOrders/markParallel), только обобщена под
|
||||
// generic-тип с полями order/parallelWithPrev, чтобы работать и с
|
||||
// ManagedApprovalRow здесь, и не тащить зависимость на request-portal.
|
||||
//
|
||||
// Параллельность кодируется ЧЕРЕЗ РАВНЫЙ order у соседних строк — отдельного
|
||||
// флага в SharePoint нет (см. FIELDS в requestManageService.ts: там только
|
||||
// StepOrder). parallelWithPrev — это производное поле, вычисляемое на клиенте
|
||||
// из совпадения order с предыдущей строкой (см. markParallel), а не то, что
|
||||
// хранится в списке.
|
||||
export interface IOrderedItem {
|
||||
order: number;
|
||||
parallelWithPrev?: boolean;
|
||||
}
|
||||
|
||||
export interface IBlockRange {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
|
||||
/** Разбивает строки (уже отсортированные по order) на шаги — блоки с общим order. */
|
||||
export function blockRanges<T extends IOrderedItem>(rows: T[]): IBlockRange[] {
|
||||
const ranges: IBlockRange[] = [];
|
||||
rows.forEach((r, i) => {
|
||||
if (i === 0 || !r.parallelWithPrev) ranges.push({ start: i, end: i });
|
||||
else ranges[ranges.length - 1].end = i;
|
||||
});
|
||||
return ranges;
|
||||
}
|
||||
|
||||
export function blockIndexOf(ranges: IBlockRange[], row: number): number {
|
||||
for (let i = 0; i < ranges.length; i += 1) {
|
||||
if (row >= ranges[i].start && row <= ranges[i].end) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Меняет местами два блока (диапазона индексов), не трогая порядок строк внутри них. */
|
||||
export function swapBlocks<T>(rows: T[], a: IBlockRange, b: IBlockRange): T[] {
|
||||
return [
|
||||
...rows.slice(0, a.start),
|
||||
...rows.slice(b.start, b.end + 1),
|
||||
...rows.slice(a.start, a.end + 1),
|
||||
...rows.slice(b.end + 1)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Пересчитывает order начиная с floor+1: у параллельных строк (parallelWithPrev)
|
||||
* order общий с предыдущей, у остальных — на единицу больше. Вызывается после
|
||||
* КАЖДОГО перемещения/переключения параллельности, иначе order разъедется с тем,
|
||||
* что показано на экране. floor — order последней ЗАБЛОКИРОВАННОЙ (уже решённой)
|
||||
* строки фазы; строки после неё не могут получить order <= floor — это и есть
|
||||
* гарантия «нельзя поставить согласующего выше того, кто уже одобрил».
|
||||
*/
|
||||
export function withOrdersFrom<T extends IOrderedItem>(rows: T[], floor: number): T[] {
|
||||
let order = floor;
|
||||
return rows.map((r, i) => {
|
||||
const parallel = i > 0 && !!r.parallelWithPrev;
|
||||
if (!parallel) order += 1;
|
||||
return { ...r, order, parallelWithPrev: parallel };
|
||||
});
|
||||
}
|
||||
|
||||
/** Заполняет parallelWithPrev по факту совпадения order с предыдущей строкой (строки уже отсортированы по order). */
|
||||
export function markParallel<T extends IOrderedItem>(rows: T[]): T[] {
|
||||
return rows.map((r, i) => ({ ...r, parallelWithPrev: i > 0 && r.order === rows[i - 1].order }));
|
||||
}
|
||||
Reference in New Issue
Block a user