вызов метода взятия партиции перед сабмитом
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
StatusBadge,
|
||||
useMatrixEditor,
|
||||
getPlannedMatrix,
|
||||
getCurrentListPartition,
|
||||
notifyActiveStep,
|
||||
useRequestTypeId,
|
||||
REQUEST_STATUS,
|
||||
@@ -189,6 +190,21 @@ const ClearanceForm: React.FC<IRequestFormProps> = ({
|
||||
if (!rtId) {
|
||||
throw new Error('Тип заявки не определён — обновите страницу и повторите.');
|
||||
}
|
||||
// requestId уже задан → редактируем существующую заявку, пишем в ту же
|
||||
// партицию (editListId). Иначе — создаём новую, и партицию для записи
|
||||
// спрашиваем у approval-route ПРЯМО СЕЙЧАС (а не берём из кеша onInit):
|
||||
// это единственный запрос, который проверяет порог элементов текущего
|
||||
// списка и ставит в очередь создание следующей партиции при достижении —
|
||||
// без него архивация никогда не сработает. Сбой запроса не должен
|
||||
// блокировать подачу заявки — откатываемся на список по конвенции имён.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
const { id, code } = await saveClearanceRequest(
|
||||
requestId,
|
||||
rtId,
|
||||
@@ -196,7 +212,7 @@ const ClearanceForm: React.FC<IRequestFormProps> = ({
|
||||
toApprovers(matrix.rows),
|
||||
toApprovers(executors.rows),
|
||||
status,
|
||||
editListId
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(status);
|
||||
@@ -207,13 +223,14 @@ const ClearanceForm: React.FC<IRequestFormProps> = ({
|
||||
onSaved();
|
||||
}
|
||||
// Отправка на согласование — уведомляем первый активный шаг (поток оповещения).
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не текущей:
|
||||
// поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда фактически записали (writeListId),
|
||||
// не обязательно текущей на момент рендера формы: поток ищет строку
|
||||
// маршрута именно в НЕЙ.
|
||||
if (status === REQUEST_STATUS.onApproval) {
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID)
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,10 +94,13 @@ export interface ISaveResult {
|
||||
* existingId задан → обновляем ту же запись (черновик/доработка), иначе создаём новую.
|
||||
* Возвращает Id заявки (+ код при создании).
|
||||
*
|
||||
* listId — партиция ОБНОВЛЯЕМОЙ заявки (см. loadClearanceRequest). Имеет смысл
|
||||
* только вместе с existingId: новая заявка всегда создаётся в ТЕКУЩЕЙ партиции —
|
||||
* писать новые заявки в архив незачем и нельзя (approval-route переключает
|
||||
* текущую партицию сам, по своему порогу элементов).
|
||||
* listId — партиция, в которую фактически пишем: при редактировании — партиция
|
||||
* ОБНОВЛЯЕМОЙ заявки (см. loadClearanceRequest), при создании — партиция,
|
||||
* полученная от approval-route API непосредственно перед вызовом (см.
|
||||
* getCurrentListPartition в ClearanceForm.tsx) — именно этот вызов, а не кеш из
|
||||
* onInit, проверяет порог элементов и запускает архивацию следующей партиции.
|
||||
* Не задан (сбой запроса за текущей партицией) → откат на список по конвенции
|
||||
* имён, как до появления партиционирования.
|
||||
*/
|
||||
export async function saveClearanceRequest(
|
||||
existingId: number | undefined,
|
||||
@@ -108,8 +111,7 @@ export async function saveClearanceRequest(
|
||||
status: string,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const employee = await ensureEmployee(data.Employee);
|
||||
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee);
|
||||
|
||||
@@ -126,6 +128,6 @@ export async function saveClearanceRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(clearanceApprovalService(existingId ? listId : undefined), id, approvers, executors, status);
|
||||
await writeRoute(clearanceApprovalService(listId), id, approvers, executors, status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
StatusBadge,
|
||||
useMatrixEditor,
|
||||
getPlannedMatrix,
|
||||
getCurrentListPartition,
|
||||
notifyActiveStep,
|
||||
useRequestTypeId,
|
||||
REQUEST_STATUS,
|
||||
@@ -186,6 +187,21 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
|
||||
if (!rtId) {
|
||||
throw new Error('Тип заявки не определён — обновите страницу и повторите.');
|
||||
}
|
||||
// requestId уже задан → редактируем существующую заявку, пишем в ту же
|
||||
// партицию (editListId). Иначе — создаём новую, и партицию для записи
|
||||
// спрашиваем у approval-route ПРЯМО СЕЙЧАС (а не берём из кеша onInit):
|
||||
// это единственный запрос, который проверяет порог элементов текущего
|
||||
// списка и ставит в очередь создание следующей партиции при достижении —
|
||||
// без него архивация никогда не сработает. Сбой запроса не должен
|
||||
// блокировать подачу заявки — откатываемся на список по конвенции имён.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
const { id, code } = await saveHireRequest(
|
||||
requestId,
|
||||
rtId,
|
||||
@@ -193,7 +209,7 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
|
||||
toApprovers(matrix.rows),
|
||||
toApprovers(executors.rows),
|
||||
status,
|
||||
editListId
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(status);
|
||||
@@ -201,21 +217,22 @@ const RecruitingHireForm: React.FC<IRequestFormProps> = ({
|
||||
setRequestCode(code);
|
||||
}
|
||||
if (files.length > 0) {
|
||||
await uploadAttachments(editListId || dataListTitle(FORM_ID), id, files); // файлы — после создания элемента
|
||||
await uploadAttachments(writeListId || dataListTitle(FORM_ID), id, files); // файлы — после создания элемента
|
||||
setFiles([]); // выгруженные файлы убираем, чтобы пересохранение не дублировало
|
||||
setExistingAttachments(await getAttachments(editListId || dataListTitle(FORM_ID), id)); // показать добавленные
|
||||
setExistingAttachments(await getAttachments(writeListId || dataListTitle(FORM_ID), id)); // показать добавленные
|
||||
}
|
||||
if (onSaved) {
|
||||
onSaved();
|
||||
}
|
||||
// Отправка на согласование — уведомляем первый активный шаг (поток оповещения).
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не текущей:
|
||||
// поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда фактически записали (writeListId),
|
||||
// не обязательно текущей на момент рендера формы: поток ищет строку
|
||||
// маршрута именно в НЕЙ.
|
||||
if (status === REQUEST_STATUS.onApproval) {
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID),
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,10 +55,13 @@ export interface ISaveResult {
|
||||
* executors может быть пустым — тогда после согласования заявка станет «Согласовано».
|
||||
* Возвращает Id заявки (+ код при создании).
|
||||
*
|
||||
* listId — партиция ОБНОВЛЯЕМОЙ заявки (см. loadHireRequest). Имеет смысл
|
||||
* только вместе с existingId: новая заявка всегда создаётся в ТЕКУЩЕЙ партиции —
|
||||
* писать новые заявки в архив незачем и нельзя (approval-route переключает
|
||||
* текущую партицию сам, по своему порогу элементов).
|
||||
* listId — партиция, в которую фактически пишем: при редактировании — партиция
|
||||
* ОБНОВЛЯЕМОЙ заявки (см. loadHireRequest), при создании — партиция, полученная
|
||||
* от approval-route API непосредственно перед вызовом (см. getCurrentListPartition
|
||||
* в RecruitingHireForm.tsx) — именно этот вызов, а не кеш из onInit, проверяет
|
||||
* порог элементов и запускает архивацию следующей партиции.
|
||||
* Не задан (сбой запроса за текущей партицией) → откат на список по конвенции
|
||||
* имён, как до появления партиционирования.
|
||||
*/
|
||||
export async function saveHireRequest(
|
||||
existingId: number | undefined,
|
||||
@@ -69,8 +72,7 @@ export async function saveHireRequest(
|
||||
status: string,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const item = buildItem(data, status);
|
||||
|
||||
let id: number;
|
||||
@@ -86,6 +88,6 @@ export async function saveHireRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(hireApprovalService(existingId ? listId : undefined), id, approvers, executors, status);
|
||||
await writeRoute(hireApprovalService(listId), id, approvers, executors, status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
StatusBadge,
|
||||
useMatrixEditor,
|
||||
getPlannedMatrix,
|
||||
getCurrentListPartition,
|
||||
notifyActiveStep,
|
||||
useRequestTypeId,
|
||||
REQUEST_STATUS,
|
||||
@@ -160,13 +161,28 @@ const RecruitingSelectionForm: React.FC<IRequestFormProps> = ({
|
||||
if (!rtId) {
|
||||
throw new Error('Тип заявки не определён — обновите страницу и повторите.');
|
||||
}
|
||||
// requestId уже задан → редактируем существующую заявку, пишем в ту же
|
||||
// партицию (editListId). Иначе — создаём новую, и партицию для записи
|
||||
// спрашиваем у approval-route ПРЯМО СЕЙЧАС (а не берём из кеша onInit):
|
||||
// это единственный запрос, который проверяет порог элементов текущего
|
||||
// списка и ставит в очередь создание следующей партиции при достижении —
|
||||
// без него архивация никогда не сработает. Сбой запроса не должен
|
||||
// блокировать подачу заявки — откатываемся на список по конвенции имён.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
const { id, code } = await saveSelectionRequest(
|
||||
requestId,
|
||||
rtId,
|
||||
data,
|
||||
toApprovers(matrix.rows),
|
||||
status,
|
||||
editListId
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(status);
|
||||
@@ -174,21 +190,22 @@ const RecruitingSelectionForm: React.FC<IRequestFormProps> = ({
|
||||
setRequestCode(code);
|
||||
}
|
||||
if (files.length > 0) {
|
||||
await uploadAttachments(editListId || dataListTitle(FORM_ID), id, files); // файлы — после создания элемента
|
||||
await uploadAttachments(writeListId || dataListTitle(FORM_ID), id, files); // файлы — после создания элемента
|
||||
setFiles([]); // выгруженные файлы убираем, чтобы пересохранение не дублировало
|
||||
setExistingAttachments(await getAttachments(editListId || dataListTitle(FORM_ID), id));
|
||||
setExistingAttachments(await getAttachments(writeListId || dataListTitle(FORM_ID), id));
|
||||
}
|
||||
if (onSaved) {
|
||||
onSaved();
|
||||
}
|
||||
// Отправка на согласование — уведомляем первый активный шаг (поток оповещения).
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не текущей:
|
||||
// поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда фактически записали (writeListId),
|
||||
// не обязательно текущей на момент рендера формы: поток ищет строку
|
||||
// маршрута именно в НЕЙ.
|
||||
if (status === REQUEST_STATUS.onApproval) {
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID)
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -98,10 +98,13 @@ export interface ISaveResult {
|
||||
* status = «Черновик» (сохранение) или «На согласовании» (отправка). Фазы исполнения
|
||||
* нет — writeRoute вызывается с пустым списком исполнителей. Возвращает Id (+ код при создании).
|
||||
*
|
||||
* listId — партиция ОБНОВЛЯЕМОЙ заявки (см. loadSelectionRequest). Имеет смысл
|
||||
* только вместе с existingId: новая заявка всегда создаётся в ТЕКУЩЕЙ партиции —
|
||||
* писать новые заявки в архив незачем и нельзя (approval-route переключает
|
||||
* текущую партицию сам, по своему порогу элементов).
|
||||
* listId — партиция, в которую фактически пишем: при редактировании — партиция
|
||||
* ОБНОВЛЯЕМОЙ заявки (см. loadSelectionRequest), при создании — партиция,
|
||||
* полученная от approval-route API непосредственно перед вызовом (см.
|
||||
* getCurrentListPartition в RecruitingSelectionForm.tsx) — именно этот вызов,
|
||||
* а не кеш из onInit, проверяет порог элементов и запускает архивацию
|
||||
* следующей партиции. Не задан (сбой запроса за текущей партицией) → откат
|
||||
* на список по конвенции имён, как до появления партиционирования.
|
||||
*/
|
||||
export async function saveSelectionRequest(
|
||||
existingId: number | undefined,
|
||||
@@ -111,8 +114,7 @@ export async function saveSelectionRequest(
|
||||
status: string,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const item = buildScalarBody(data);
|
||||
item.RequestStatus = status;
|
||||
await applyPeople(item, data);
|
||||
@@ -130,6 +132,6 @@ export async function saveSelectionRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(selectionApprovalService(existingId ? listId : undefined), id, approvers, [], status);
|
||||
await writeRoute(selectionApprovalService(listId), id, approvers, [], status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
StatusBadge,
|
||||
useMatrixEditor,
|
||||
getPlannedMatrix,
|
||||
getCurrentListPartition,
|
||||
notifyActiveStep,
|
||||
useRequestTypeId,
|
||||
REQUEST_STATUS,
|
||||
@@ -225,12 +226,28 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
||||
? REQUEST_STATUS.onApproval
|
||||
: REQUEST_STATUS.approved;
|
||||
|
||||
// requestId уже задан → редактируем существующую заявку, пишем в ту же
|
||||
// партицию (editListId). Иначе — создаём новую, и партицию для записи
|
||||
// спрашиваем у approval-route ПРЯМО СЕЙЧАС (а не берём из кеша onInit):
|
||||
// это единственный запрос, который проверяет порог элементов текущего
|
||||
// списка и ставит в очередь создание следующей партиции при достижении —
|
||||
// без него архивация никогда не сработает. Сбой запроса не должен
|
||||
// блокировать подачу заявки — откатываемся на список по конвенции имён.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
|
||||
const { id, code } = await saveTicketRequest(
|
||||
requestId,
|
||||
data,
|
||||
toApprovers(matrix.rows),
|
||||
finalStatus,
|
||||
editListId
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(finalStatus);
|
||||
@@ -240,9 +257,9 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
||||
|
||||
let attachments = existingAttachments;
|
||||
if (files.length > 0) {
|
||||
await uploadAttachments(editListId || dataListTitle(FORM_ID), id, files);
|
||||
await uploadAttachments(writeListId || dataListTitle(FORM_ID), id, files);
|
||||
setFiles([]);
|
||||
attachments = await getAttachments(editListId || dataListTitle(FORM_ID), id);
|
||||
attachments = await getAttachments(writeListId || dataListTitle(FORM_ID), id);
|
||||
setExistingAttachments(attachments);
|
||||
}
|
||||
|
||||
@@ -251,12 +268,13 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
||||
}
|
||||
|
||||
if (finalStatus === REQUEST_STATUS.onApproval) {
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не
|
||||
// текущей: поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда фактически записали (writeListId),
|
||||
// не обязательно текущей на момент рендера формы: поток ищет строку
|
||||
// маршрута именно в НЕЙ.
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID)
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID)
|
||||
});
|
||||
} else if (finalStatus === REQUEST_STATUS.approved) {
|
||||
// Согласование не требуется для этого вида работ — сразу передаём в отдел 1С.
|
||||
@@ -268,7 +286,7 @@ const Ticket1CForm: React.FC<IRequestFormProps> = ({
|
||||
attachments,
|
||||
webAbsoluteUrl: context.pageContext.web.absoluteUrl
|
||||
});
|
||||
await setPlannerTaskId(id, taskId, editListId);
|
||||
await setPlannerTaskId(id, taskId, writeListId);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -48,10 +48,13 @@ export interface ISaveResult {
|
||||
* Фазы исполнения нет: после согласования заявка уходит в Planner, а не исполнителю
|
||||
* из матрицы. Возвращает Id заявки (+ код при создании).
|
||||
*
|
||||
* listId — партиция ОБНОВЛЯЕМОЙ заявки (см. loadTicketRequest). Имеет смысл
|
||||
* только вместе с existingId: новая заявка всегда создаётся в ТЕКУЩЕЙ партиции —
|
||||
* писать новые заявки в архив незачем и нельзя (approval-route переключает
|
||||
* текущую партицию сам, по своему порогу элементов).
|
||||
* listId — партиция, в которую фактически пишем: при редактировании — партиция
|
||||
* ОБНОВЛЯЕМОЙ заявки (см. loadTicketRequest), при создании — партиция,
|
||||
* полученная от approval-route API непосредственно перед вызовом (см.
|
||||
* getCurrentListPartition в Ticket1CForm.tsx) — именно этот вызов, а не кеш из
|
||||
* onInit, проверяет порог элементов и запускает архивацию следующей партиции.
|
||||
* Не задан (сбой запроса за текущей партицией) → откат на список по конвенции
|
||||
* имён, как до появления партиционирования.
|
||||
*/
|
||||
export async function saveTicketRequest(
|
||||
existingId: number | undefined,
|
||||
@@ -60,8 +63,7 @@ export async function saveTicketRequest(
|
||||
status: string,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const item = buildItem(data, status);
|
||||
|
||||
let id: number;
|
||||
@@ -77,7 +79,7 @@ export async function saveTicketRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(ticket1cApprovalService(existingId ? listId : undefined), id, approvers, [], status);
|
||||
await writeRoute(ticket1cApprovalService(listId), id, approvers, [], status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ import {
|
||||
isEditableStatus,
|
||||
IApproverToWrite,
|
||||
APPROVAL_PHASE,
|
||||
findUnassignedStep
|
||||
findUnassignedStep,
|
||||
getCurrentListPartition
|
||||
} from '../../shared/approval';
|
||||
import {
|
||||
uploadAttachments,
|
||||
@@ -202,6 +203,17 @@ const TmcTransferForm: React.FC<IRequestFormProps> = ({
|
||||
if (!rtId) {
|
||||
throw new Error('Тип заявки не определён — обновите страницу и повторите.');
|
||||
}
|
||||
// Новая заявка — резолвим ТЕКУЩУЮ партицию через approval-route (заодно
|
||||
// выполняется проверка порога и создание следующей архивной партиции при
|
||||
// необходимости); при редактировании остаёмся в партиции самой заявки.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
const { id, code } = await saveTmcTransferRequest(
|
||||
requestId,
|
||||
rtId,
|
||||
@@ -209,7 +221,7 @@ const TmcTransferForm: React.FC<IRequestFormProps> = ({
|
||||
toApprovers(matrix.rows),
|
||||
toApprovers(executors.rows),
|
||||
status,
|
||||
editListId
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(status);
|
||||
@@ -217,21 +229,22 @@ const TmcTransferForm: React.FC<IRequestFormProps> = ({
|
||||
setRequestCode(code);
|
||||
}
|
||||
if (files.length > 0) {
|
||||
await uploadAttachments(editListId || dataListTitle(FORM_ID), id, files);
|
||||
await uploadAttachments(writeListId || dataListTitle(FORM_ID), id, files);
|
||||
setFiles([]);
|
||||
setExistingAttachments(await getAttachments(editListId || dataListTitle(FORM_ID), id));
|
||||
setExistingAttachments(await getAttachments(writeListId || dataListTitle(FORM_ID), id));
|
||||
}
|
||||
if (onSaved) {
|
||||
onSaved();
|
||||
}
|
||||
// Отправка на согласование — уведомляем первый активный шаг (поток оповещения).
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не текущей:
|
||||
// поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда только что записали (writeListId),
|
||||
// а не editListId: для новой заявки это может быть только что созданная
|
||||
// текущая партиция, отличная от editListId (который тут undefined).
|
||||
if (status === REQUEST_STATUS.onApproval) {
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID)
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,10 +54,11 @@ export interface ISaveResult {
|
||||
* existingId задан → обновляем ту же запись (черновик/доработка), иначе создаём новую.
|
||||
* Возвращает Id заявки (+ уникальный код при создании).
|
||||
*
|
||||
* listId — партиция ОБНОВЛЯЕМОЙ заявки (см. loadTmcTransferRequest). Имеет смысл
|
||||
* только вместе с existingId: новая заявка всегда создаётся в ТЕКУЩЕЙ партиции —
|
||||
* писать новые заявки в архив незачем и нельзя (approval-route переключает
|
||||
* текущую партицию сам, по своему порогу элементов).
|
||||
* listId — партиция, в которую пишем: для обновления существующей заявки —
|
||||
* партиция ЭТОЙ заявки (см. loadTmcTransferRequest), для новой — ТЕКУЩАЯ
|
||||
* партиция (см. getCurrentListPartition), которую вызывающая сторона резолвит
|
||||
* заранее и передаёт сюда, а не текущая-по-умолчанию: именно на этом резолве
|
||||
* держится проверка порога и создание следующей архивной партиции.
|
||||
*/
|
||||
export async function saveTmcTransferRequest(
|
||||
existingId: number | undefined,
|
||||
@@ -68,8 +69,7 @@ export async function saveTmcTransferRequest(
|
||||
status: string,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const item = buildItem(data, status);
|
||||
|
||||
let id: number;
|
||||
@@ -85,6 +85,6 @@ export async function saveTmcTransferRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(tmcTransferApprovalService(existingId ? listId : undefined), id, approvers, executors, status);
|
||||
await writeRoute(tmcTransferApprovalService(listId), id, approvers, executors, status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ import {
|
||||
REQUEST_STATUS,
|
||||
isEditableStatus,
|
||||
IApproverToWrite,
|
||||
findUnassignedStep
|
||||
findUnassignedStep,
|
||||
getCurrentListPartition
|
||||
} from '../../shared/approval';
|
||||
import { IRequestFormProps } from '../../models/types';
|
||||
import {
|
||||
@@ -176,13 +177,24 @@ const UnpaidLeaveForm: React.FC<IRequestFormProps> = ({
|
||||
if (!rtId) {
|
||||
throw new Error('Тип заявки не определён — обновите страницу и повторите.');
|
||||
}
|
||||
// Новая заявка пишется в ТЕКУЩУЮ партицию — запрашиваем её у approval-route
|
||||
// API непосредственно перед записью (не кеш из onInit): именно этот вызов
|
||||
// проверяет порог элементов и запускает архивацию следующей партиции.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
const { id, code } = await saveUnpaidLeaveRequest(
|
||||
requestId,
|
||||
rtId,
|
||||
data,
|
||||
toApprovers(matrix.rows),
|
||||
status,
|
||||
editListId
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(status);
|
||||
@@ -193,13 +205,13 @@ const UnpaidLeaveForm: React.FC<IRequestFormProps> = ({
|
||||
onSaved();
|
||||
}
|
||||
// Отправка на согласование — уведомляем первый активный шаг (поток оповещения).
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не текущей:
|
||||
// поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда фактически записана заявка (writeListId),
|
||||
// не текущей: поток ищет строку маршрута именно в НЕЙ.
|
||||
if (status === REQUEST_STATUS.onApproval) {
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID)
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,8 +89,7 @@ export async function saveUnpaidLeaveRequest(
|
||||
status: string,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const employee = await ensureUser(data.Employee);
|
||||
// Замещающий необязателен: резолвим только если выбран.
|
||||
const substituteId = data.Substitute ? (await ensureUser(data.Substitute)).Id : undefined;
|
||||
@@ -109,6 +108,6 @@ export async function saveUnpaidLeaveRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(unpaidLeaveApprovalService(existingId ? listId : undefined), id, approvers, [], status);
|
||||
await writeRoute(unpaidLeaveApprovalService(listId), id, approvers, [], status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
StatusBadge,
|
||||
useMatrixEditor,
|
||||
getPlannedMatrix,
|
||||
getCurrentListPartition,
|
||||
notifyActiveStep,
|
||||
useRequestTypeId,
|
||||
REQUEST_STATUS,
|
||||
@@ -173,7 +174,29 @@ const VacationForm: React.FC<IRequestFormProps> = ({
|
||||
if (!rtId) {
|
||||
throw new Error('Тип заявки не определён — обновите страницу и повторите.');
|
||||
}
|
||||
const { id, code } = await saveVacationRequest(requestId, rtId, data, toApprovers(matrix.rows), status, editListId);
|
||||
// requestId уже задан → редактируем существующую заявку, пишем в ту же
|
||||
// партицию (editListId). Иначе — создаём новую, и партицию для записи
|
||||
// спрашиваем у approval-route ПРЯМО СЕЙЧАС (а не берём из кеша onInit):
|
||||
// это единственный запрос, который проверяет порог элементов текущего
|
||||
// списка и ставит в очередь создание следующей партиции при достижении —
|
||||
// без него архивация никогда не сработает. Сбой запроса не должен
|
||||
// блокировать подачу заявки — откатываемся на список по конвенции имён.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
const { id, code } = await saveVacationRequest(
|
||||
requestId,
|
||||
rtId,
|
||||
data,
|
||||
toApprovers(matrix.rows),
|
||||
status,
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(status);
|
||||
if (code) {
|
||||
@@ -183,13 +206,14 @@ const VacationForm: React.FC<IRequestFormProps> = ({
|
||||
onSaved();
|
||||
}
|
||||
// Отправка на согласование — уведомляем первый активный шаг (поток оповещения).
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не текущей:
|
||||
// поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда фактически записали (writeListId),
|
||||
// не обязательно текущей на момент рендера формы: поток ищет строку
|
||||
// маршрута именно в НЕЙ.
|
||||
if (status === REQUEST_STATUS.onApproval) {
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID)
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,10 +67,13 @@ export interface ISaveResult {
|
||||
* Фазы исполнения у отпуска нет — writeRoute вызывается с пустым списком исполнителей.
|
||||
* Возвращает Id заявки (+ код при создании).
|
||||
*
|
||||
* listId — партиция ОБНОВЛЯЕМОЙ заявки (см. loadVacationRequest). Имеет смысл
|
||||
* только вместе с existingId: новая заявка всегда создаётся в ТЕКУЩЕЙ партиции —
|
||||
* писать новые заявки в архив незачем и нельзя (approval-route переключает
|
||||
* текущую партицию сам, по своему порогу элементов).
|
||||
* listId — партиция, в которую фактически пишем: при редактировании — партиция
|
||||
* ОБНОВЛЯЕМОЙ заявки (см. loadVacationRequest), при создании — партиция,
|
||||
* полученная от approval-route API непосредственно перед вызовом (см.
|
||||
* getCurrentListPartition в VacationForm.tsx) — именно этот вызов, а не кеш из
|
||||
* onInit, проверяет порог элементов и запускает архивацию следующей партиции.
|
||||
* Не задан (сбой запроса за текущей партицией) → откат на список по конвенции
|
||||
* имён, как до появления партиционирования.
|
||||
*/
|
||||
export async function saveVacationRequest(
|
||||
existingId: number | undefined,
|
||||
@@ -80,8 +83,7 @@ export async function saveVacationRequest(
|
||||
status: string,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const employee = await ensureEmployee(data.Employee);
|
||||
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee);
|
||||
|
||||
@@ -98,6 +100,6 @@ export async function saveVacationRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(vacationApprovalService(existingId ? listId : undefined), id, approvers, [], status);
|
||||
await writeRoute(vacationApprovalService(listId), id, approvers, [], status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
StatusBadge,
|
||||
useMatrixEditor,
|
||||
getPlannedMatrix,
|
||||
getCurrentListPartition,
|
||||
notifyActiveStep,
|
||||
useRequestTypeId,
|
||||
REQUEST_STATUS,
|
||||
@@ -210,6 +211,21 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
||||
if (!rtId) {
|
||||
throw new Error('Тип заявки не определён — обновите страницу и повторите.');
|
||||
}
|
||||
// requestId уже задан → редактируем существующую заявку, пишем в ту же
|
||||
// партицию (editListId). Иначе — создаём новую, и партицию для записи
|
||||
// спрашиваем у approval-route ПРЯМО СЕЙЧАС (а не берём из кеша onInit):
|
||||
// это единственный запрос, который проверяет порог элементов текущего
|
||||
// списка и ставит в очередь создание следующей партиции при достижении —
|
||||
// без него архивация никогда не сработает. Сбой запроса не должен
|
||||
// блокировать подачу заявки — откатываемся на список по конвенции имён.
|
||||
let writeListId = editListId;
|
||||
if (!requestId) {
|
||||
try {
|
||||
writeListId = (await getCurrentListPartition(context, rtId)).listId;
|
||||
} catch (e) {
|
||||
console.error('Не удалось получить текущую партицию списка — используется список по конвенции имён', e);
|
||||
}
|
||||
}
|
||||
const { id, code } = await saveWorkplaceRequest(
|
||||
requestId,
|
||||
rtId,
|
||||
@@ -218,7 +234,7 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
||||
toApprovers(executors.rows),
|
||||
status,
|
||||
sourceId,
|
||||
editListId
|
||||
writeListId
|
||||
);
|
||||
setRequestId(id);
|
||||
setRequestStatus(status);
|
||||
@@ -226,21 +242,22 @@ const WorkplaceSetupForm: React.FC<IRequestFormProps> = ({
|
||||
setRequestCode(code);
|
||||
}
|
||||
if (files.length > 0) {
|
||||
await uploadAttachments(editListId || dataListTitle(FORM_ID), id, files);
|
||||
await uploadAttachments(writeListId || dataListTitle(FORM_ID), id, files);
|
||||
setFiles([]); // выгруженные файлы убираем, чтобы пересохранение не дублировало
|
||||
setExistingAttachments(await getAttachments(editListId || dataListTitle(FORM_ID), id)); // показать добавленные
|
||||
setExistingAttachments(await getAttachments(writeListId || dataListTitle(FORM_ID), id)); // показать добавленные
|
||||
}
|
||||
if (onSaved) {
|
||||
onSaved();
|
||||
}
|
||||
// Отправка на согласование — уведомляем первый активный шаг (поток оповещения).
|
||||
// Имена списков — той же партиции, что и сама заявка (editListId), не текущей:
|
||||
// поток ищет строку маршрута именно в НЕЙ.
|
||||
// Имена списков — той же партиции, куда фактически записали (writeListId),
|
||||
// не обязательно текущей на момент рендера формы: поток ищет строку
|
||||
// маршрута именно в НЕЙ.
|
||||
if (status === REQUEST_STATUS.onApproval) {
|
||||
await notifyActiveStep(context, approval, id, {
|
||||
requestTypeId: rtId,
|
||||
dataListName: editListId ? dataListTitleForListId(FORM_ID, editListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: editListId ? approvalListTitleForListId(FORM_ID, editListId) : approvalListTitle(FORM_ID),
|
||||
dataListName: writeListId ? dataListTitleForListId(FORM_ID, writeListId) : dataListTitle(FORM_ID),
|
||||
approvalListName: writeListId ? approvalListTitleForListId(FORM_ID, writeListId) : approvalListTitle(FORM_ID),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,10 +74,13 @@ export interface ISaveResult {
|
||||
* Исполнители пишутся сразу — фаза исполнения стартует автоматически после согласования.
|
||||
* sourceHireId — если заявка создана на основе «прием». Возвращает Id заявки (+ код при создании).
|
||||
*
|
||||
* listId — партиция ОБНОВЛЯЕМОЙ заявки (см. loadWorkplaceRequest). Имеет смысл
|
||||
* только вместе с existingId: новая заявка всегда создаётся в ТЕКУЩЕЙ партиции —
|
||||
* писать новые заявки в архив незачем и нельзя (approval-route переключает
|
||||
* текущую партицию сам, по своему порогу элементов).
|
||||
* listId — партиция, в которую фактически пишем: при редактировании — партиция
|
||||
* ОБНОВЛЯЕМОЙ заявки (см. loadWorkplaceRequest), при создании — партиция,
|
||||
* полученная от approval-route API непосредственно перед вызовом (см.
|
||||
* getCurrentListPartition в WorkplaceSetupForm.tsx) — именно этот вызов, а не
|
||||
* кеш из onInit, проверяет порог элементов и запускает архивацию следующей
|
||||
* партиции. Не задан (сбой запроса за текущей партицией) → откат на список по
|
||||
* конвенции имён, как до появления партиционирования.
|
||||
*/
|
||||
export async function saveWorkplaceRequest(
|
||||
existingId: number | undefined,
|
||||
@@ -89,8 +92,7 @@ export async function saveWorkplaceRequest(
|
||||
sourceHireId?: number,
|
||||
listId?: string
|
||||
): Promise<ISaveResult> {
|
||||
const list =
|
||||
existingId && listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
||||
const item = buildItem(data, status, sourceHireId);
|
||||
|
||||
let id: number;
|
||||
@@ -106,6 +108,6 @@ export async function saveWorkplaceRequest(
|
||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||
}
|
||||
|
||||
await writeRoute(workplaceApprovalService(existingId ? listId : undefined), id, approvers, executors, status);
|
||||
await writeRoute(workplaceApprovalService(listId), id, approvers, executors, status);
|
||||
return { id, code };
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { APPROVAL_API_CLIENT_ID, getApprovalApiBaseUrl } from '../config';
|
||||
import {
|
||||
ApprovalStatus,
|
||||
ICurrentListPartition,
|
||||
IApiResponse,
|
||||
IRequestType,
|
||||
IRequestTypeListSeries,
|
||||
@@ -54,6 +55,30 @@ export async function getListPartitions(context: WebPartContext): Promise<IReque
|
||||
return body.data ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/request-types/{id}/lists/current — партиция, в которую нужно писать
|
||||
* НОВУЮ заявку этого типа. Вызывать перед КАЖДЫМ созданием, не кешировать: этот
|
||||
* запрос заодно проверяет порог элементов на бэкенде и ставит в очередь
|
||||
* создание следующей партиции при достижении — без него архивация никогда не
|
||||
* запустится, сколько бы заявок ни создали (bulk-эндпоинт lists, который
|
||||
* портал и так грузит при onInit, только читает реестр и порог не проверяет).
|
||||
*/
|
||||
export async function getCurrentListPartition(
|
||||
context: WebPartContext,
|
||||
requestTypeId: number
|
||||
): Promise<ICurrentListPartition> {
|
||||
const c = await client(context);
|
||||
const response: HttpClientResponse = await c.get(
|
||||
`${getApprovalApiBaseUrl()}/api/request-types/${requestTypeId}/lists/current`,
|
||||
AadHttpClient.configurations.v1
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`request-types/${requestTypeId}/lists/current: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const body: IApiResponse<ICurrentListPartition> = await response.json();
|
||||
return body.data;
|
||||
}
|
||||
|
||||
// Кеш на уровне МОДУЛЯ (не useRef/useState) — список типов заявок админ меняет
|
||||
// редко, а без кеша каждая форма и каждый переход в режим согласующего дёргали
|
||||
// бы /api/request-types заново. Живёт до перезагрузки страницы — тот же принцип,
|
||||
|
||||
@@ -14,6 +14,7 @@ export type { IApprovalRow } from './models/IApprovalRow';
|
||||
export type {
|
||||
ApprovalStatus,
|
||||
IListPartition,
|
||||
ICurrentListPartition,
|
||||
IRequestType,
|
||||
IRequestTypeListSeries,
|
||||
IResolvedRoute,
|
||||
@@ -21,7 +22,13 @@ export type {
|
||||
IResolveFieldValue,
|
||||
} from './models/IApprovalRouteApi';
|
||||
|
||||
export { getRequestTypes, getRequestTypeIdByPageUrl, getListPartitions, resolveRoute } from './approvalRoute.service';
|
||||
export {
|
||||
getRequestTypes,
|
||||
getRequestTypeIdByPageUrl,
|
||||
getListPartitions,
|
||||
getCurrentListPartition,
|
||||
resolveRoute
|
||||
} from './approvalRoute.service';
|
||||
export {
|
||||
initListPartitions,
|
||||
listPartitionsLoaded,
|
||||
|
||||
@@ -50,6 +50,23 @@ export interface IRequestTypeListSeries {
|
||||
partitions: IListPartition[];
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/request-types/{id}/lists/current → { data: ICurrentListPartition }
|
||||
*
|
||||
* Партиция, в которую нужно писать НОВУЮ заявку. Не чистый GET на бэкенде —
|
||||
* этот же запрос проверяет порог элементов и при необходимости ставит в
|
||||
* очередь создание следующей партиции, поэтому его нужно звать перед КАЖДЫМ
|
||||
* созданием заявки, а не читать из кеша (см. shared/approval/listPartitions.ts,
|
||||
* который для этого не подходит — грузится один раз при onInit).
|
||||
*/
|
||||
export interface ICurrentListPartition {
|
||||
requestTypeId: number;
|
||||
number: number;
|
||||
siteUrl: string;
|
||||
listId: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
// Условие видимости шага маршрута (настраивается в админке маршрутов —
|
||||
// «Показывать шаг только при выполнении условия», сравнение «Поле списка»/
|
||||
// «Оператор»/«Значение»). fieldName — внутреннее имя колонки списка (напр.
|
||||
|
||||
Reference in New Issue
Block a user