diff --git a/web/src/pages/DictVspPage/DictVspPage.jsx b/web/src/pages/DictVspPage/DictVspPage.jsx index c6f6e0d..b502414 100644 --- a/web/src/pages/DictVspPage/DictVspPage.jsx +++ b/web/src/pages/DictVspPage/DictVspPage.jsx @@ -13,7 +13,7 @@ import { PageContainer } from '../../components/common/PageContainer'; import DictVspFilters from './components/DictVspFilters'; import DictVspModals from './components/DictVspModals'; import TableDictVsp from './components/TableDictVsp'; -import { buildVspListParams, vspMatchesStatus } from './utils/vspListParams'; +import { buildVspListParams, sspsForStatus, vspMatchesStatus } from './utils/vspListParams'; const DictVspInfo = () => { const portalContent = ( @@ -40,6 +40,16 @@ function DictVspPage() { const modalsRef = useRef(null); const listFilter = useMemo(() => ({ status, ...closeDates }), [status, closeDates]); + const visibleSsps = useMemo(() => sspsForStatus(ssps, status), [ssps, status]); + // Создание и правка ВСП — только на активном ССП (бэк отклоняет архивный). + const activeSsps = useMemo(() => sspsForStatus(ssps, 'active'), [ssps]); + + // Выбранный архивный ССП исчезает из фильтра при возврате в «Действующие» — сбрасываем выбор. + useEffect(() => { + if (selectedSsp && !visibleSsps.some((ssp) => ssp.id === selectedSsp.id)) { + setSelectedSsp(null); + } + }, [selectedSsp, visibleSsps]); const loadVspList = useCallback(async () => { if (!user) return; @@ -70,7 +80,8 @@ function DictVspPage() { setIsLoading(true); try { const isAdmin = user.role_id === ROLES_NAME_ID.admin; - const sspResponse = isAdmin ? await SspApi.getAll({ is_active: true }) : null; + // AURORA-1883: все ССП, включая архивные, — для закрытых ВСП; в «Действующих» архивные скрываются (sspsForStatus). + const sspResponse = isAdmin ? await SspApi.getAll() : null; if (isAdmin) { if (!sspResponse.success) { @@ -176,7 +187,7 @@ function DictVspPage() { { +const DictVspModals = forwardRef(({ onAdd, onEdit, onDelete, ssps, exportSsps, listFilter }, ref) => { const [modalOpen, setModalOpen] = useState(false); const [modalExportOpen, setModalExportOpen] = useState(false); const [editingItem, setEditingItem] = useState(null); @@ -55,7 +55,7 @@ const DictVspModals = forwardRef(({ onAdd, onEdit, onDelete, ssps, listFilter }, loading={saveLoading} ssps={ssps} /> - + ); }); diff --git a/web/src/pages/DictVspPage/utils/vspListParams.js b/web/src/pages/DictVspPage/utils/vspListParams.js index fcbc40c..4f22a21 100644 --- a/web/src/pages/DictVspPage/utils/vspListParams.js +++ b/web/src/pages/DictVspPage/utils/vspListParams.js @@ -21,3 +21,9 @@ export function vspMatchesStatus(vsp, status) { if (status === 'closed') return vsp.is_active === false; return true; } + +/** ССП для фильтра и выгрузки: архивные — только при «Закрытые»/«Все» (закрытые ВСП бывают на архивных ССП). */ +export function sspsForStatus(ssps, status) { + const list = ssps || []; + return status === 'active' ? list.filter((ssp) => ssp.is_active !== false) : list; +} diff --git a/web/src/pages/DictVspPage/utils/vspListParams.test.js b/web/src/pages/DictVspPage/utils/vspListParams.test.js index 330bba3..af3db31 100644 --- a/web/src/pages/DictVspPage/utils/vspListParams.test.js +++ b/web/src/pages/DictVspPage/utils/vspListParams.test.js @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { buildVspListParams, vspMatchesStatus } from './vspListParams.js'; +import { buildVspListParams, sspsForStatus, vspMatchesStatus } from './vspListParams.js'; // AURORA-1883: параметры запроса справочника ВСП по статусу и периоду закрытия. test('active status sends no close period', () => { @@ -31,3 +31,24 @@ test('vspMatchesStatus follows is_active', () => { assert.equal(vspMatchesStatus({ is_active: true }, 'closed'), false); assert.equal(vspMatchesStatus({ is_active: false }, 'all'), true); }); + +// AURORA-1883, финальное ревью I-1: закрытые ВСП архивного ССП должны фильтроваться и выгружаться. +test('sspsForStatus hides archived SSPs only for active VSPs', () => { + const ssps = [ + { id: 1, is_active: true }, + { id: 2, is_active: false }, + ]; + assert.deepEqual( + sspsForStatus(ssps, 'active').map((s) => s.id), + [1], + ); + assert.deepEqual( + sspsForStatus(ssps, 'closed').map((s) => s.id), + [1, 2], + ); + assert.deepEqual( + sspsForStatus(ssps, 'all').map((s) => s.id), + [1, 2], + ); + assert.deepEqual(sspsForStatus(undefined, 'active'), []); +});