diff --git a/src/webparts/requestPortal/features/myRequests/RequestsTableView.tsx b/src/webparts/requestPortal/features/myRequests/RequestsTableView.tsx
index 776fd37..16566f7 100644
--- a/src/webparts/requestPortal/features/myRequests/RequestsTableView.tsx
+++ b/src/webparts/requestPortal/features/myRequests/RequestsTableView.tsx
@@ -17,12 +17,14 @@ import {
hydratePendingAuthors,
searchOwnRequests,
} from './myRequests.service';
+import { hydrateStartDates } from './startDates.service';
import { IMyRequest } from './models/IMyRequest';
import { DataTable, IDataTableColumn, IconButton } from '@tnsu/ui-kit';
import { REQUEST_STATUS, IRequestType, StatusBadge } from '../../shared/approval';
import { confirmAndDeleteDraft, isDeletableStatus } from '../../shared/draftDeletion';
import { friendlyErrorMessage } from '../../shared/diagnostics';
import { getFormComponent } from '../../forms/registry';
+import { FORM_ID as WORKPLACE_SETUP_FORM_ID } from '../../forms/WorkplaceSetup/model';
import { onRequestsChanged } from '../../shared/requestEvents';
import { perfScope } from '../../shared/perfTrace';
import { useRoutedQuery } from '../../shared/usePersistedQuery';
@@ -135,6 +137,8 @@ interface ITableColumns {
status: boolean;
/** Колонка «Исполнитель» — у кого заявка сейчас (см. showsAssignee). */
assignee: boolean;
+ /** Колонка «Дата выхода» — только «Все заявки» по организации рабочего места. */
+ startDate?: boolean;
/** Заголовок колонки с комментарием; undefined — колонки нет. */
commentLabel?: string;
}
@@ -157,7 +161,12 @@ function showsAssignee(view: ListView, statusFilter: string): boolean {
return true;
}
-function columnsFor(view: ListView, statusFilter: string): ITableColumns {
+/** Дата выхода сотрудника есть только у заявки на организацию рабочего места, и показываем её во «Все заявки». */
+function showsStartDate(view: ListView, type: IRequestType | undefined): boolean {
+ return view === 'all' && type?.pageUrl === WORKPLACE_SETUP_FORM_ID;
+}
+
+function columnsFor(view: ListView, statusFilter: string, startDate = false): ITableColumns {
const assignee = showsAssignee(view, statusFilter);
const decisionStatus = decisionStatusFor(view, statusFilter);
const commentLabel =
@@ -171,7 +180,7 @@ function columnsFor(view: ListView, statusFilter: string): ITableColumns {
if (view === 'rework') return { author: false, status: false, assignee, commentLabel };
if (view === 'own:created') return { author: false, status: !statusFilter, assignee, commentLabel };
// 'all' — заявки всех авторов вперемешку, поэтому нужны и автор, и статус.
- if (view === 'all') return { author: true, status: true, assignee };
+ if (view === 'all') return { author: true, status: true, assignee, startDate };
// История решений: заявка чужая, поэтому нужен автор. Статус — только если он
// не предопределён самой вкладкой («Отклонённые мной» — это всегда «Отклонено»,
// а вот у согласованных/выполненных заявка могла уйти дальше по маршруту).
@@ -235,6 +244,8 @@ const Table: React.FC<{
rows: IMyRequest[];
view: ListView;
statusFilter: string;
+ /** Показывать колонку «Дата выхода» (см. showsStartDate). */
+ withStartDate: boolean;
sort: ISortState;
onSort: (key: SortKey) => void;
onOpen: (request: IMyRequest) => void;
@@ -242,8 +253,8 @@ const Table: React.FC<{
onShowHistory: (request: IMyRequest) => void;
/** Удалить черновик; задан только там, где в таблице бывают свои черновики. */
onDelete?: (request: IMyRequest) => void;
-}> = ({ rows, view, statusFilter, sort, onSort, onOpen, onShowHistory, onDelete }) => {
- const cols = columnsFor(view, statusFilter);
+}> = ({ rows, view, statusFilter, withStartDate, sort, onSort, onOpen, onShowHistory, onDelete }) => {
+ const cols = columnsFor(view, statusFilter, withStartDate);
const sortable = (label: string, key: SortKey): React.ReactNode => (
);
@@ -261,6 +272,14 @@ const Table: React.FC<{
{ key: 'title', title: 'Название', render: (r) => r.title || r.code || `#${r.id}` },
{ key: 'date', title: sortable('Дата', 'date'), width: '110px', render: (r) => formatDate(r.created) }
];
+ if (cols.startDate) {
+ columns.push({
+ key: 'startDate',
+ title: 'Дата выхода',
+ width: '120px',
+ render: (r) => formatDate(r.startDate ?? '') || '—'
+ });
+ }
if (cols.author) {
columns.push({
key: 'author',
@@ -588,6 +607,7 @@ export const RequestsTableView: React.FC = ({
await Promise.all([
decisionStatus ? hydrateDecisionComments(context, types, result.rows, decisionStatus) : undefined,
showsAssignee(view, statusFilter) ? hydrateCurrentAssignees(context, types, result.rows) : undefined,
+ showsStartDate(view, allRequestsType) ? hydrateStartDates(context, result.rows) : undefined,
]);
return result;
};
@@ -745,6 +765,7 @@ export const RequestsTableView: React.FC = ({
rows={visible}
view={view}
statusFilter={statusFilter}
+ withStartDate={showsStartDate(view, allRequestsType)}
sort={sort}
onSort={refinement.onSort}
onOpen={onOpen}
diff --git a/src/webparts/requestPortal/features/myRequests/models/IMyRequest.ts b/src/webparts/requestPortal/features/myRequests/models/IMyRequest.ts
index 80bef3e..38a740b 100644
--- a/src/webparts/requestPortal/features/myRequests/models/IMyRequest.ts
+++ b/src/webparts/requestPortal/features/myRequests/models/IMyRequest.ts
@@ -76,4 +76,12 @@ export interface IMyRequest {
* hydrateCurrentAssignees).
*/
currentAssignees?: IAssignee[];
+ /**
+ * Дата выхода сотрудника на работу (колонка StartDate) — только у заявок на
+ * организацию рабочего места, колонка «Дата выхода» во «Все заявки». Как и
+ * decisionComment, живёт в списке данных и дочитывается только для видимой
+ * страницы (см. hydrateStartDates). ISO-строка; '' — не заполнена,
+ * undefined — не дочитывалось.
+ */
+ startDate?: string;
}
diff --git a/src/webparts/requestPortal/features/myRequests/pageCache.ts b/src/webparts/requestPortal/features/myRequests/pageCache.ts
index f3f6da8..37285dd 100644
--- a/src/webparts/requestPortal/features/myRequests/pageCache.ts
+++ b/src/webparts/requestPortal/features/myRequests/pageCache.ts
@@ -53,6 +53,7 @@ export function pageSignature(page: IPage): string {
r.created,
r.authorName,
r.decisionComment ?? '',
+ r.startDate ?? '',
(r.currentAssignees ?? []).map((a) => `${a.name}/${a.email}`).join(','),
].join('~')
)
diff --git a/src/webparts/requestPortal/features/myRequests/startDates.service.ts b/src/webparts/requestPortal/features/myRequests/startDates.service.ts
new file mode 100644
index 0000000..dfb6749
--- /dev/null
+++ b/src/webparts/requestPortal/features/myRequests/startDates.service.ts
@@ -0,0 +1,55 @@
+import { WebPartContext } from '@microsoft/sp-webpart-base';
+import '@pnp/sp/webs';
+import '@pnp/sp/lists';
+import '@pnp/sp/items';
+import { spForSite } from '../../shared/pnp/pnpjs';
+import { traced } from '../../shared/perfTrace';
+import { IMyRequest } from './models/IMyRequest';
+
+/**
+ * Проставляет startDate — дату выхода сотрудника (колонка StartDate списка
+ * данных). Только для видимой страницы; группировка по партиции строки, как в
+ * hydrateAuthors: в другой партиции тот же Id — чужая заявка. Мутирует строки.
+ */
+export async function hydrateStartDates(context: WebPartContext, rows: IMyRequest[]): Promise {
+ if (rows.length === 0) return;
+ return traced('дата выхода (REST)', () => hydrateStartDatesInner(context, rows));
+}
+
+async function hydrateStartDatesInner(context: WebPartContext, rows: IMyRequest[]): Promise {
+ const byPartition = new Map();
+ rows.forEach((r) => {
+ const bucket = byPartition.get(r.listId.toLowerCase()) || {
+ siteUrl: r.siteUrl,
+ listId: r.listId,
+ typeName: r.requestTypeName,
+ ids: [],
+ };
+ bucket.ids.push(r.id);
+ byPartition.set(r.listId.toLowerCase(), bucket);
+ });
+
+ const byKey = new Map();
+ await Promise.all(
+ Array.from(byPartition.values()).map(async ({ siteUrl, listId, typeName, ids }) => {
+ try {
+ const sp = spForSite(siteUrl, context);
+ const dataRows = (await sp.web
+ .getList(listId)
+ .items.filter(ids.map((id) => `Id eq ${id}`).join(' or '))
+ .select('Id', 'StartDate')
+ .top(ids.length)()) as Array>;
+ dataRows.forEach((r) => byKey.set(`${listId.toLowerCase()}-${r.Id as number}`, (r.StartDate as string) || ''));
+ } catch (e) {
+ console.error(
+ `[Все заявки] Не удалось дочитать дату выхода для «${typeName}» (${listId}):`,
+ (e as Error).message
+ );
+ }
+ })
+ );
+
+ rows.forEach((r) => {
+ r.startDate = byKey.get(`${r.listId.toLowerCase()}-${r.id}`) ?? '';
+ });
+}