125 lines
4.8 KiB
JavaScript
125 lines
4.8 KiB
JavaScript
const ROW_TYPE_LEVELS = {
|
||
ROOT: 0,
|
||
GROUP: 1,
|
||
ITEM: 2,
|
||
SUB_ITEM: 3,
|
||
INPUT: 4,
|
||
};
|
||
|
||
export function buildRowHierarchy(items, mapItem = (item) => item) {
|
||
const result = [];
|
||
const stack = [];
|
||
|
||
for (const [index, item] of items.entries()) {
|
||
const currentLevel = ROW_TYPE_LEVELS[item.row_type] ?? 999;
|
||
|
||
while (stack.length > 0 && (ROW_TYPE_LEVELS[stack.at(-1).row_type] ?? 999) >= currentLevel) {
|
||
stack.pop();
|
||
}
|
||
|
||
const parent = stack.at(-1);
|
||
const newNode = { ...mapItem(item, index), subRows: [] };
|
||
|
||
if (parent) parent.subRows.push(newNode);
|
||
else result.push(newNode);
|
||
|
||
if (item.row_type !== 'INPUT') stack.push(newNode);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
export function getDataRowId(data) {
|
||
return data?.id || data?.line_id || null;
|
||
}
|
||
|
||
export function getRowId(row) {
|
||
return getDataRowId(row.original.data);
|
||
}
|
||
|
||
// AURORA-1978: что удаляет кнопка «Удалить строку» для выделенной строки.
|
||
// На форме 4 у строк программы (GROUP) и проекта (ITEM) нет line_id — их
|
||
// удаляют отдельные события program_deleted / project_deleted по id из header.
|
||
// Непустые программу/проект сервер не удалит (v3.del_form4_program /
|
||
// v3.del_form4_project), поэтому причину показываем сразу, без запроса.
|
||
// rowData — row.original (row_type, data, subRows).
|
||
export function getDeleteTarget(rowData, { isForm4 = false } = {}) {
|
||
if (!rowData) return null;
|
||
const header = rowData.data?.header;
|
||
const hasChildren = Array.isArray(rowData.subRows) && rowData.subRows.length > 0;
|
||
|
||
if (isForm4 && rowData.row_type === 'GROUP' && header?.program_id != null) {
|
||
return {
|
||
kind: 'program',
|
||
id: header.program_id,
|
||
name: header.name ?? '',
|
||
blockedReason: hasChildren ? 'Нельзя удалить программу: в ней есть проекты или расходы' : null,
|
||
};
|
||
}
|
||
if (isForm4 && rowData.row_type === 'ITEM' && header?.project_id != null) {
|
||
return {
|
||
kind: 'project',
|
||
id: header.project_id,
|
||
name: header.name ?? '',
|
||
blockedReason: hasChildren ? 'Нельзя удалить проект: в нём есть расходы' : null,
|
||
};
|
||
}
|
||
|
||
const id = getDataRowId(rowData.data);
|
||
return id == null ? null : { kind: 'row', id };
|
||
}
|
||
|
||
// AURORA-1984: цель добавления проекта по выделенной строке. Программа задана
|
||
// только если у GROUP/ITEM/INPUT header.program_id != null; иначе проект
|
||
// самостоятельный. rowData — row.original.
|
||
export function getProjectAddTarget(rowData) {
|
||
const programId = rowData?.data?.header?.program_id;
|
||
const typed = ['GROUP', 'ITEM', 'INPUT'].includes(rowData?.row_type);
|
||
return typed && programId != null ? { program_id: programId } : {};
|
||
}
|
||
|
||
export function isVspRow(row) {
|
||
if (row?.original?.data?.id) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
export function isVspNewRow(rowData) {
|
||
if (!rowData) return false;
|
||
const newRow = rowData[3];
|
||
return !!newRow.id;
|
||
}
|
||
|
||
export function getParentId(data) {
|
||
return data?.project_id || data?.expense_item_id || null;
|
||
}
|
||
|
||
// AURORA-1887: лист AHR отдаёт header.can_add_row=false для статей
|
||
// аренды/коммуналки/охраны (у записи сателлита нет понятия "сверх лимита" —
|
||
// ручная строка там не имеет смысла). На остальных листах и для остальных
|
||
// статей (включая лимитные — AURORA-1907 "сверх лимита" не трогаем) поле
|
||
// либо true, либо вовсе отсутствует/null — по умолчанию добавление строки
|
||
// разрешено.
|
||
export function canAddRowForHeader(header) {
|
||
return header?.can_add_row !== false;
|
||
}
|
||
|
||
// AURORA-1980: что переименовывает кнопка панели — программу (GROUP) или проект (ITEM) формы 4.
|
||
export function getRenameTarget(rowData) {
|
||
const header = rowData?.data?.header;
|
||
if (rowData?.row_type === 'GROUP' && header?.program_id != null) {
|
||
return { kind: 'program', id: header.program_id, name: header.name ?? '' };
|
||
}
|
||
if (rowData?.row_type === 'ITEM' && header?.project_id != null) {
|
||
return { kind: 'project', id: header.project_id, name: header.name ?? '' };
|
||
}
|
||
return null;
|
||
}
|
||
|
||
// AURORA-1980: WS без идентификатора запроса — свой ответ на своё переименование
|
||
// узнаём по is_self, событию и id узла (чужое переименование окно не закрывает).
|
||
export function isRenameResponse(msg, target) {
|
||
if (!msg || !target || msg.is_self !== true) return false;
|
||
return msg.event === `${target.kind}_updated` && msg.data?.[`${target.kind}_id`] === target.id;
|
||
}
|