diff --git a/src/webparts/requestPortal/features/myRequests/MyRequestsPanel.tsx b/src/webparts/requestPortal/features/myRequests/MyRequestsPanel.tsx
index a70a910..0d278d2 100644
--- a/src/webparts/requestPortal/features/myRequests/MyRequestsPanel.tsx
+++ b/src/webparts/requestPortal/features/myRequests/MyRequestsPanel.tsx
@@ -4,6 +4,7 @@ import { getMyRequests } from './myRequests.service';
import { IMyRequest } from './models/IMyRequest';
import { REQUEST_STATUS } from '../../shared/approval';
import { navigate, routeUrl } from '../../shared/routing';
+import { onRequestsChanged } from '../../shared/requestEvents';
import styles from './MyRequestsPanel.module.scss';
export interface IMyRequestsPanelProps {
@@ -53,7 +54,10 @@ function statusClass(status: string): string {
}
}
-const RequestItem: React.FC<{ r: IMyRequest }> = ({ r }) => (
+// «Ждёt вашего решения»: автор здесь — не вы, поэтому важны email + имя,
+// а статус не нужен (в этой секции все заявки по определению «на согласовании»).
+// «Созданы вами»: автор — всегда вы, строку с ним не показываем, зато нужен статус.
+const RequestItem: React.FC<{ r: IMyRequest; variant: 'own' | 'approval' }> = ({ r, variant }) => (
= ({ r }) => (
>
{r.title || `#${r.id}`}
-
- {r.authorEmail || r.authorName || '— автор не определён —'}
-
+ {variant === 'approval' && (
+
+ {[r.authorName, r.authorEmail].filter(Boolean).join(' · ') || '— автор не определён —'}
+
+ )}
{r.created && {formatDate(r.created)}}
- {r.status || '—'}
+ {variant === 'own' && (
+ {r.status || '—'}
+ )}
);
-const RequestGroups: React.FC<{ rows: IMyRequest[] }> = ({ rows }) => (
+const RequestGroups: React.FC<{ rows: IMyRequest[]; variant: 'own' | 'approval' }> = ({
+ rows,
+ variant,
+}) => (
<>
{groupByType(rows).map((group) => (
{group.requestTypeName}
{group.rows.map((r) => (
-
+
))}
@@ -102,6 +113,11 @@ const RequestGroups: React.FC<{ rows: IMyRequest[] }> = ({ rows }) => (
// Владелец: второй разработчик. Вся логика/данные — внутри этой папки.
// Общий UI-кит (shared/ui), pnpjs и config можно импортировать, но НЕ менять.
//
+// Перечитывает данные по событию rp-requests-changed (shared/requestEvents) —
+// оно шлётся после сохранения формы (SubmitFeature) и после решения
+// согласующего (ApproverService.decide), так что панель обновляется сама,
+// без перезагрузки страницы.
+//
// Диагностика по типам заявок (listId/siteUrl/rowCount/error) в UI не выводится —
// см. console.table в devtools при загрузке панели.
const MyRequestsPanel: React.FC = ({ context }) => {
@@ -110,17 +126,25 @@ const MyRequestsPanel: React.FC = ({ context }) => {
React.useEffect(() => {
let cancelled = false;
- getMyRequests(context)
- .then((result) => {
- if (cancelled) return;
- setRows(result.rows);
- console.table(result.debug);
- })
- .catch((e) => {
- if (!cancelled) setError((e as Error).message);
- });
+
+ const load = (): void => {
+ getMyRequests(context)
+ .then((result) => {
+ if (cancelled) return;
+ setRows(result.rows);
+ setError('');
+ console.table(result.debug);
+ })
+ .catch((e) => {
+ if (!cancelled) setError((e as Error).message);
+ });
+ };
+
+ load();
+ const unsubscribe = onRequestsChanged(load);
return () => {
cancelled = true;
+ unsubscribe();
};
}, [context]);
@@ -142,14 +166,14 @@ const MyRequestsPanel: React.FC = ({ context }) => {
{pendingApproval.length > 0 && (
)}
{own.length > 0 && (
)}
diff --git a/src/webparts/requestPortal/features/submit/SubmitFeature.tsx b/src/webparts/requestPortal/features/submit/SubmitFeature.tsx
index 62ae41c..a43881e 100644
--- a/src/webparts/requestPortal/features/submit/SubmitFeature.tsx
+++ b/src/webparts/requestPortal/features/submit/SubmitFeature.tsx
@@ -7,6 +7,7 @@ import { RequestGrid } from '../../components/RequestGrid/RequestGrid';
import { getRequestsByCategory, REQUEST_TYPES } from '../../data/requests';
import { getFormComponent } from '../../forms/registry';
import { IRequestType } from '../../models/types';
+import { emitRequestsChanged } from '../../shared/requestEvents';
export interface ISubmitFeatureProps {
context: WebPartContext;
@@ -60,7 +61,13 @@ const SubmitFeature: React.FC = ({ context, activeCategoryI
// Ленивый рендер формы: её код подтягивается только сейчас, при открытии.
return (
Загрузка формы…}>
-
+
);
};
diff --git a/src/webparts/requestPortal/shared/approval/approverDecision.service.ts b/src/webparts/requestPortal/shared/approval/approverDecision.service.ts
index 2b5f91e..2f0f22b 100644
--- a/src/webparts/requestPortal/shared/approval/approverDecision.service.ts
+++ b/src/webparts/requestPortal/shared/approval/approverDecision.service.ts
@@ -6,6 +6,7 @@ import { ApprovalListService } from './approvalList.service';
import { REQUEST_STATUS, APPROVAL_PHASE } from './models/statuses';
import { IApprovalRow } from './models/IApprovalRow';
import { ISiteUser } from './models/ISiteUser';
+import { emitRequestsChanged } from '../requestEvents';
export type ApproverDecision = 'approve' | 'return' | 'reject';
@@ -74,6 +75,7 @@ export class ApproverService {
const rows = await this.approval.getForRequest(requestId);
const requestStatus = this.computeRequestStatus(rows);
await this.updateRequestStatus(requestId, requestStatus);
+ emitRequestsChanged();
return requestStatus;
}
diff --git a/src/webparts/requestPortal/shared/requestEvents.ts b/src/webparts/requestPortal/shared/requestEvents.ts
new file mode 100644
index 0000000..80ee54a
--- /dev/null
+++ b/src/webparts/requestPortal/shared/requestEvents.ts
@@ -0,0 +1,15 @@
+// Общее событие «список заявок изменился»: создана новая заявка или принято
+// решение согласующего. Панель «Текущие заявки» (features/myRequests) подписана
+// и перечитывает данные. Через window.dispatchEvent — проще шины состояния,
+// достаточно для нечастых событий (сохранение формы, решение согласующего).
+const EVENT_NAME = 'rp-requests-changed';
+
+export function emitRequestsChanged(): void {
+ window.dispatchEvent(new Event(EVENT_NAME));
+}
+
+/** Подписка на изменения. Возвращает функцию отписки (вызвать в cleanup эффекта). */
+export function onRequestsChanged(handler: () => void): () => void {
+ window.addEventListener(EVENT_NAME, handler);
+ return () => window.removeEventListener(EVENT_NAME, handler);
+}