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
@@ -50,6 +50,13 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
);
// Матрица маршрута из фактических строк заявки (read-only), разбитая по фазам.
//
// decisionSeq входит в reloadKey: после решения согласующего строки маршрута
// меняются на сервере (своя — на «Согласовано», следующая — на «На
// согласовании»), поэтому счётчик инкрементируется и useMatrixEditor
// перечитывает матрицу. Иначе на экране остались бы данные, загруженные при
// открытии формы, и пользователь видел бы свой шаг всё ещё «На согласовании».
const [decisionSeq, setDecisionSeq] = useState<number>(0);
const approval = useMemo(() => hireApprovalService(), []);
const loadApprovers = useCallback(
() =>
@@ -58,7 +65,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
.then((rows) => rows.filter((r) => r.phase !== APPROVAL_PHASE.execution)),
[approval, itemId]
);
const approvers = useMatrixEditor(loadApprovers, `a-${itemId}`, false, true, (l) =>
const approvers = useMatrixEditor(loadApprovers, `a-${itemId}-${decisionSeq}`, false, true, (l) =>
approval.getJobTitle(l)
);
const loadExecutors = useCallback(
@@ -68,7 +75,7 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
.then((rows) => rows.filter((r) => r.phase === APPROVAL_PHASE.execution)),
[approval, itemId]
);
const executors = useMatrixEditor(loadExecutors, `e-${itemId}`, false, true, (l) =>
const executors = useMatrixEditor(loadExecutors, `e-${itemId}-${decisionSeq}`, false, true, (l) =>
approval.getJobTitle(l)
);
@@ -161,7 +168,14 @@ const RecruitingHireView: React.FC<IRecruitingHireViewProps> = ({ context, itemI
{/* Панель решения — ВНЕ печати и FormModeProvider (комментарий редактируемый). */}
<div className="rp-no-print">
<DecisionPanel service={approverService} requestId={itemId} />
<DecisionPanel
service={approverService}
requestId={itemId}
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
}}
/>
</div>
</div>
);
@@ -1,8 +1,8 @@
{
"dataListTitle": "Прием на работу — согласование",
"columns": [
{ "internalName": "Approver", "title": "Согласующий", "type": "User", "userSelectionMode": "PeopleOnly" },
{ "internalName": "Status", "title": "Статус", "type": "Choice", "choices": ["Черновик", "На согласовании", "Согласовано", "Отклонено", "Возвращена на доработку", "Ждёт очереди", "На исполнении", "Выполнено", "Выполнение", "Закрыта"] },
{ "internalName": "TansuSiteApprover", "title": "Согласующий", "type": "User", "userSelectionMode": "PeopleOnly" },
{ "internalName": "RequestStatus", "title": "Статус", "type": "Choice", "choices": ["Черновик", "Ждёт очереди", "На согласовании", "На исполнении", "Согласовано", "Выполнено", "Отклонено", "Возвращена на доработку"] },
{ "internalName": "Ticket", "title": "Заявка", "type": "Lookup", "lookupList": "Прием на работу — данные", "lookupShowField": "Title" },
{ "internalName": "Date", "title": "Дата", "type": "DateTime" },
{ "internalName": "Comment", "title": "Комментарий", "type": "Note" },
@@ -39,6 +39,13 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
);
// Матрица маршрута из фактических строк заявки (read-only), разбитая по фазам.
//
// decisionSeq входит в reloadKey: после решения согласующего строки маршрута
// меняются на сервере (своя — на «Согласовано», следующая — на «На
// согласовании»), поэтому счётчик инкрементируется и useMatrixEditor
// перечитывает матрицу. Иначе на экране остались бы данные, загруженные при
// открытии формы, и пользователь видел бы свой шаг всё ещё «На согласовании».
const [decisionSeq, setDecisionSeq] = useState<number>(0);
const approval = useMemo(() => workplaceApprovalService(), []);
const loadApprovers = useCallback(
() =>
@@ -47,7 +54,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
.then((rows) => rows.filter((r) => r.phase !== APPROVAL_PHASE.execution)),
[approval, itemId]
);
const approvers = useMatrixEditor(loadApprovers, `a-${itemId}`, false, true, (l) =>
const approvers = useMatrixEditor(loadApprovers, `a-${itemId}-${decisionSeq}`, false, true, (l) =>
approval.getJobTitle(l)
);
const loadExecutors = useCallback(
@@ -57,7 +64,7 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
.then((rows) => rows.filter((r) => r.phase === APPROVAL_PHASE.execution)),
[approval, itemId]
);
const executors = useMatrixEditor(loadExecutors, `e-${itemId}`, false, true, (l) =>
const executors = useMatrixEditor(loadExecutors, `e-${itemId}-${decisionSeq}`, false, true, (l) =>
approval.getJobTitle(l)
);
@@ -138,7 +145,14 @@ const WorkplaceSetupView: React.FC<IWorkplaceSetupViewProps> = ({ context, itemI
</div>
<div className="rp-no-print">
<DecisionPanel service={approverService} requestId={itemId} />
<DecisionPanel
service={approverService}
requestId={itemId}
onDecided={(newStatus) => {
setStatus(newStatus);
setDecisionSeq((n) => n + 1);
}}
/>
</div>
</div>
);
@@ -1,8 +1,8 @@
{
"dataListTitle": "Организация рабочего места — согласование",
"columns": [
{ "internalName": "Approver", "title": "Согласующий", "type": "User", "userSelectionMode": "PeopleOnly" },
{ "internalName": "Status", "title": "Статус", "type": "Choice", "choices": ["Черновик", "На согласовании", "Согласовано", "Отклонено", "Возвращена на доработку", "Ждёт очереди", "На исполнении", "Выполнено", "Выполнение", "Закрыта"] },
{ "internalName": "TansuSiteApprover", "title": "Согласующий", "type": "User", "userSelectionMode": "PeopleOnly" },
{ "internalName": "RequestStatus", "title": "Статус", "type": "Choice", "choices": ["Черновик", "Ждёт очереди", "На согласовании", "На исполнении", "Согласовано", "Выполнено", "Отклонено", "Возвращена на доработку"] },
{ "internalName": "Ticket", "title": "Заявка", "type": "Lookup", "lookupList": "Организация рабочего места — данные", "lookupShowField": "Title" },
{ "internalName": "Date", "title": "Дата", "type": "DateTime" },
{ "internalName": "Comment", "title": "Комментарий", "type": "Note" },