diff --git a/src/webparts/requestPortal/forms/Clearance/README.md b/src/webparts/requestPortal/forms/Clearance/README.md index 818e830..23e6407 100644 --- a/src/webparts/requestPortal/forms/Clearance/README.md +++ b/src/webparts/requestPortal/forms/Clearance/README.md @@ -49,8 +49,10 @@ RequestTypeId» в `docs/forms.md`). Тип уже зарегистрирова заявления в портале. Пара связана колонками-гиперссылками: `DismissalUrl` здесь → на заявление, -`ClearanceUrl` в заявлении → на лист. Форма их не показывает и не пишет — их -заполняет автосоздание (или вручную в SharePoint). +`ClearanceUrl` в заявлении → на лист. Форма их не пишет (заполняет автосоздание либо +вручную в SharePoint), но **показывает**: поле «Заявление на увольнение» — +`LinkField` из `shared/ui`, read-only, открывается в новой вкладке; у листов, +заведённых руками, ссылки нет и поле не рендерится. ## Секции формы RequestSection (сотрудник · должность · подразделение · дата расторжения · сумма обучения · парковочная карта · карта СКУД) diff --git a/src/webparts/requestPortal/forms/Clearance/load.ts b/src/webparts/requestPortal/forms/Clearance/load.ts index 01e3276..197fadc 100644 --- a/src/webparts/requestPortal/forms/Clearance/load.ts +++ b/src/webparts/requestPortal/forms/Clearance/load.ts @@ -32,6 +32,7 @@ export async function loadClearanceRequest(itemId: number, listId?: string): Pro 'AccessCard', 'TrainingAmount', 'Organization', + 'DismissalUrl', 'RequestStatus', 'RequestUniqueCode', 'Employee/Title', @@ -52,7 +53,9 @@ export async function loadClearanceRequest(itemId: number, listId?: string): Pro ParkingCard: !!item.ParkingCard, AccessCard: !!item.AccessCard, TrainingAmount: amount === null || amount === undefined ? '' : String(amount), - Organization: (item.Organization as string) || '' + Organization: (item.Organization as string) || '', + // Гиперссылка приходит объектом {Url, Description} — модели нужен только адрес. + DismissalUrl: (item.DismissalUrl as { Url?: string } | undefined)?.Url || '' }; return { diff --git a/src/webparts/requestPortal/forms/Clearance/model.ts b/src/webparts/requestPortal/forms/Clearance/model.ts index 217e533..359bd65 100644 --- a/src/webparts/requestPortal/forms/Clearance/model.ts +++ b/src/webparts/requestPortal/forms/Clearance/model.ts @@ -31,6 +31,12 @@ export interface IFormData { * read-only (см. shared/ui/OrganizationField). */ Organization: string; + /** + * Ссылка на заявление на увольнение, по которому создан этот лист — колонка- + * гиперссылка `DismissalUrl`. Форма её не пишет (заполняет автосоздание, см. + * forms/Dismissal/createClearance.ts) и не даёт править — только показывает. + */ + DismissalUrl: string; } /** Обновление одного поля формы с сохранением типа значения. */ @@ -56,7 +62,8 @@ export const EMPTY_DATA: IFormData = { ParkingCard: false, AccessCard: false, TrainingAmount: '', - Organization: '' + Organization: '', + DismissalUrl: '' }; /** Плейсхолдер для поля выбора сотрудника. */ diff --git a/src/webparts/requestPortal/forms/Clearance/sections/RequestSection.tsx b/src/webparts/requestPortal/forms/Clearance/sections/RequestSection.tsx index 79fd408..a37caf9 100644 --- a/src/webparts/requestPortal/forms/Clearance/sections/RequestSection.tsx +++ b/src/webparts/requestPortal/forms/Clearance/sections/RequestSection.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { CollapseSection, FormField, TextInput, MoneyInput, Toggle, PeopleField, OrganizationField } from '../../../shared/ui'; +import { CollapseSection, FormField, TextInput, MoneyInput, Toggle, PeopleField, OrganizationField, LinkField } from '../../../shared/ui'; import { ISectionProps, EMPLOYEE_PLACEHOLDER } from '../model'; // Подразделение подтягивается автоматически при выборе сотрудника (см. @@ -89,5 +89,12 @@ export const RequestSection: React.FC = ({ readOnly={hrRecordsEditable ? false : undefined} /> + {/* Есть только у листов, созданных автоматически по согласованному заявлению + на увольнение (см. forms/Dismissal/createClearance.ts). */} + ); diff --git a/src/webparts/requestPortal/forms/Dismissal/DismissalView.tsx b/src/webparts/requestPortal/forms/Dismissal/DismissalView.tsx index ec8d621..976cc51 100644 --- a/src/webparts/requestPortal/forms/Dismissal/DismissalView.tsx +++ b/src/webparts/requestPortal/forms/Dismissal/DismissalView.tsx @@ -124,13 +124,17 @@ const DismissalView: React.FC = ({ context, itemId, formKey const createClearance = (): void => { setClearanceError(''); ensureClearanceForDismissal(context, itemId, listId) - .then((result) => + .then((result) => { setClearance( result.existing ? 'Обходной лист по этому заявлению уже был создан.' : `Обходной лист создан автоматически${result.code ? ` — №${result.code}` : ''} и отправлен на согласование.` - ) - ) + ); + // Поле-ссылка в секции заполняется из данных заявки, а они прочитаны ДО + // создания листа — дописываем адрес в модель, иначе ссылка появилась бы + // только после перезагрузки страницы. + setData((prev) => ({ ...prev, ClearanceUrl: result.url })); + }) .catch((e) => setClearanceError( `Заявление согласовано, но обходной лист создать не удалось: ${friendlyErrorMessage(e)} — заведите его вручную.` diff --git a/src/webparts/requestPortal/forms/Dismissal/README.md b/src/webparts/requestPortal/forms/Dismissal/README.md index 858fe0f..fecf596 100644 --- a/src/webparts/requestPortal/forms/Dismissal/README.md +++ b/src/webparts/requestPortal/forms/Dismissal/README.md @@ -61,6 +61,11 @@ approval-route (`getPlannedMatrix` для фаз «Согласование» и (`…?rpmode=approve&rptype=…&rpid=…&rplist=…`, см. `docs/routing.md`), а не на элемент списка, и не ломается, когда парная заявка уезжает в другую партицию. +Ссылки **видны на обеих формах** и кликабельны: поле «Обходной лист» в заявлении и +«Заявление на увольнение» в обходном листе (`LinkField`, `shared/ui`) — read-only, +открываются в новой вкладке и появляются только когда связь есть. У согласующего, +только что одобрившего заявление, ссылка появляется сразу, без перезагрузки. + Что важно знать про это поведение: - **Идемпотентность — по непустой `ClearanceUrl`.** Заявление можно согласовать повторно (возврат на доработку → отправка → согласование), и без этой проверки diff --git a/src/webparts/requestPortal/forms/Dismissal/load.ts b/src/webparts/requestPortal/forms/Dismissal/load.ts index 512438a..79abe79 100644 --- a/src/webparts/requestPortal/forms/Dismissal/load.ts +++ b/src/webparts/requestPortal/forms/Dismissal/load.ts @@ -32,6 +32,7 @@ export async function loadDismissalRequest(itemId: number, listId?: string): Pro 'Phone', 'Comment', 'Organization', + 'ClearanceUrl', 'RequestStatus', 'RequestUniqueCode', 'Employee/Title', @@ -51,7 +52,9 @@ export async function loadDismissalRequest(itemId: number, listId?: string): Pro LastWorkingDay: lastDay.slice(0, 10), // ISO → YYYY-MM-DD для input type=date Phone: (item.Phone as string) || '', Comment: (item.Comment as string) || '', - Organization: (item.Organization as string) || '' + Organization: (item.Organization as string) || '', + // Гиперссылка приходит объектом {Url, Description} — модели нужен только адрес. + ClearanceUrl: (item.ClearanceUrl as { Url?: string } | undefined)?.Url || '' }; return { diff --git a/src/webparts/requestPortal/forms/Dismissal/model.ts b/src/webparts/requestPortal/forms/Dismissal/model.ts index 1530ddf..00ff560 100644 --- a/src/webparts/requestPortal/forms/Dismissal/model.ts +++ b/src/webparts/requestPortal/forms/Dismissal/model.ts @@ -38,6 +38,12 @@ export interface IFormData { * read-only (см. shared/ui/OrganizationField). */ Organization: string; + /** + * Ссылка на обходной лист, созданный по этому заявлению — колонка-гиперссылка + * `ClearanceUrl`. Форма её не пишет (заполняет автосоздание, см. + * createClearance.ts) и не даёт править — только показывает переходом. + */ + ClearanceUrl: string; } /** Обновление одного поля формы с сохранением типа значения. */ @@ -64,7 +70,8 @@ export const EMPTY_DATA: IFormData = { LastWorkingDay: '', Phone: '', Comment: '', - Organization: '' + Organization: '', + ClearanceUrl: '' }; /** Плейсхолдер для поля выбора сотрудника. */ diff --git a/src/webparts/requestPortal/forms/Dismissal/sections/RequestSection.tsx b/src/webparts/requestPortal/forms/Dismissal/sections/RequestSection.tsx index 68277c7..a4b886a 100644 --- a/src/webparts/requestPortal/forms/Dismissal/sections/RequestSection.tsx +++ b/src/webparts/requestPortal/forms/Dismissal/sections/RequestSection.tsx @@ -6,7 +6,8 @@ import { TextArea, PhoneInput, PeopleField, - OrganizationField + OrganizationField, + LinkField } from '../../../shared/ui'; import { ISectionProps, EMPLOYEE_PLACEHOLDER } from '../model'; import { isoDatePlusDays } from '../../../shared/dateUtils'; @@ -76,5 +77,12 @@ export const RequestSection: React.FC = ({ data, set, context, on