теперь можно пройти по заявку в мои заявки
This commit is contained in:
@@ -70,6 +70,13 @@
|
||||
border: 1px solid $gray-200;
|
||||
border-radius: $r-sm;
|
||||
background: $gray-50;
|
||||
text-decoration: none;
|
||||
transition: .16s;
|
||||
|
||||
&:hover {
|
||||
border-color: $gold-400;
|
||||
background: $gold-50;
|
||||
}
|
||||
}
|
||||
|
||||
.itemMain {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { getMyRequests } from './myRequests.service';
|
||||
import { IMyRequest } from './models/IMyRequest';
|
||||
import { REQUEST_STATUS } from '../../shared/approval';
|
||||
import { navigate, routeUrl } from '../../shared/routing';
|
||||
import styles from './MyRequestsPanel.module.scss';
|
||||
|
||||
export interface IMyRequestsPanelProps {
|
||||
@@ -97,17 +98,32 @@ const MyRequestsPanel: React.FC<IMyRequestsPanelProps> = ({ context }) => {
|
||||
<div className={styles.groupTitle}>{group.requestTypeName}</div>
|
||||
<ul className={styles.list}>
|
||||
{group.rows.map((r) => (
|
||||
<li className={styles.item} key={`${r.requestTypeId}-${r.id}`}>
|
||||
<div className={styles.itemMain}>
|
||||
<span className={styles.itemTitle}>{r.title || `#${r.id}`}</span>
|
||||
<span className={styles.itemAuthor}>
|
||||
{r.authorEmail || r.authorName || '— автор не определён —'}
|
||||
<li key={`${r.requestTypeId}-${r.id}`}>
|
||||
<a
|
||||
className={styles.item}
|
||||
href={routeUrl({ mode: 'approve', formKey: r.formKey, itemId: r.id })}
|
||||
onClick={(e) => {
|
||||
// Обычный левый клик — SPA-переход (без перезагрузки страницы).
|
||||
// Ctrl/Cmd/Shift/среднюю кнопку — не трогаем, пусть браузер сам
|
||||
// откроет в новой вкладке по href.
|
||||
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
navigate({ mode: 'approve', formKey: r.formKey, itemId: r.id });
|
||||
}}
|
||||
>
|
||||
<div className={styles.itemMain}>
|
||||
<span className={styles.itemTitle}>{r.title || `#${r.id}`}</span>
|
||||
<span className={styles.itemAuthor}>
|
||||
{r.authorEmail || r.authorName || '— автор не определён —'}
|
||||
</span>
|
||||
{r.created && <span className={styles.itemDate}>{formatDate(r.created)}</span>}
|
||||
</div>
|
||||
<span className={`${styles.status} ${statusClass(r.status)}`}>
|
||||
{r.status || '—'}
|
||||
</span>
|
||||
{r.created && <span className={styles.itemDate}>{formatDate(r.created)}</span>}
|
||||
</div>
|
||||
<span className={`${styles.status} ${statusClass(r.status)}`}>
|
||||
{r.status || '—'}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -11,4 +11,6 @@ export interface IMyRequest {
|
||||
requestTypeId: number;
|
||||
requestTypeName: string;
|
||||
section: string;
|
||||
/** Ключ формы (rptype в URL режима согласования) — поле pageUrl из approval-route API. */
|
||||
formKey: string;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ async function getMyRequestsForType(
|
||||
requestTypeId: type.id,
|
||||
requestTypeName: type.name,
|
||||
section: type.section,
|
||||
formKey: type.pageUrl,
|
||||
};
|
||||
})
|
||||
.filter((r) => !!tokenEmail && r.authorEmail.toLowerCase() === tokenEmail);
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
// ── Заглушка формы (до появления реальных форм) ──
|
||||
.formPlaceholder {
|
||||
margin-top: $sp-6;
|
||||
padding: $sp-8;
|
||||
background: $white;
|
||||
border: 1px solid $gray-200;
|
||||
@@ -44,7 +43,6 @@
|
||||
}
|
||||
|
||||
.loading {
|
||||
margin-top: $sp-6;
|
||||
padding: $sp-8;
|
||||
color: $gray-500;
|
||||
font-size: $fs-sm;
|
||||
|
||||
@@ -1,41 +1,39 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import type { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import styles from './SubmitFeature.module.scss';
|
||||
import { Icon } from '../../shared/ui/Icon/Icon';
|
||||
import { CategoryTabs } from '../../components/CategoryTabs/CategoryTabs';
|
||||
import { RequestGrid } from '../../components/RequestGrid/RequestGrid';
|
||||
import { CATEGORIES, DEFAULT_CATEGORY_ID } from '../../data/categories';
|
||||
import { getRequestsByCategory, REQUEST_TYPES } from '../../data/requests';
|
||||
import { getFormComponent } from '../../forms/registry';
|
||||
import { IRequestType } from '../../models/types';
|
||||
|
||||
export interface ISubmitFeatureProps {
|
||||
context: WebPartContext;
|
||||
/** Активная категория. Вкладки теперь рендерятся на уровне портала (RequestPortal),
|
||||
* чтобы оставаться на экране и в режиме согласования — эта фича их только слушает. */
|
||||
activeCategoryId: string;
|
||||
/** Открыть сразу форму с предзаполнением (производная заявка), минуя плитки. */
|
||||
initialForm?: { formKey: string; sourceId: number };
|
||||
}
|
||||
|
||||
// Фича «Подать заявку»: категории → плитки → беспоук-форма.
|
||||
// Фича «Подать заявку»: плитки → беспоук-форма (категории/вкладки — в RequestPortal).
|
||||
// Владелец: автор портала. Живёт целиком в features/submit/**.
|
||||
const SubmitFeature: React.FC<ISubmitFeatureProps> = ({ context, initialForm }) => {
|
||||
const SubmitFeature: React.FC<ISubmitFeatureProps> = ({ context, activeCategoryId, initialForm }) => {
|
||||
// Если пришли по ссылке «создать на основе» — сразу открываем нужную форму.
|
||||
const initialSelected = useMemo(
|
||||
() => (initialForm ? REQUEST_TYPES.filter((r) => r.id === initialForm.formKey)[0] ?? null : null),
|
||||
[initialForm]
|
||||
);
|
||||
|
||||
const [activeCategoryId, setActiveCategoryId] = useState<string>(
|
||||
initialSelected ? initialSelected.categoryId : DEFAULT_CATEGORY_ID
|
||||
);
|
||||
const [selectedRequest, setSelectedRequest] = useState<IRequestType | null>(initialSelected);
|
||||
|
||||
const requests = getRequestsByCategory(activeCategoryId);
|
||||
// Смена категории (вкладка сверху) — возвращаемся к списку плиток.
|
||||
useEffect(() => {
|
||||
setSelectedRequest((prev) => (prev && prev.categoryId !== activeCategoryId ? null : prev));
|
||||
}, [activeCategoryId]);
|
||||
|
||||
const handleCategoryChange = (categoryId: string): void => {
|
||||
setActiveCategoryId(categoryId);
|
||||
setSelectedRequest(null); // при смене категории возвращаемся к списку плиток
|
||||
};
|
||||
const requests = getRequestsByCategory(activeCategoryId);
|
||||
|
||||
const handleBack = (): void => setSelectedRequest(null);
|
||||
|
||||
@@ -69,12 +67,6 @@ const SubmitFeature: React.FC<ISubmitFeatureProps> = ({ context, initialForm })
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<CategoryTabs
|
||||
categories={CATEGORIES}
|
||||
activeId={activeCategoryId}
|
||||
onChange={handleCategoryChange}
|
||||
/>
|
||||
|
||||
{selectedRequest ? (
|
||||
renderSelected(selectedRequest)
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user