From d749bfae26186ccb732a2f92d2a15ec4b71ddfd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B8=D0=BC=D1=83=D1=80=20=D0=93=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D1=86=D0=BA=D0=B8=D0=B9?= Date: Mon, 28 Sep 2026 14:45:02 +0500 Subject: [PATCH] =?UTF-8?q?feat:=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82=D1=80?= =?UTF-8?q?=D1=8B=20=D0=B8=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0=20=D0=B2=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D1=86=D0=B0=D1=85=20=D0=B7=D0=B0=D1=8F=D0=B2=D0=BE=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Во всех разделах со списками заявок (На согласовании, На исполнении, Доработка, Мои заявки, Все заявки): - фильтры по типу, статусу и периоду даты создания, кнопка «Сбросить»; - сортировка по клику на заголовок: номер (по числам), тип, дата, статус. Без фильтров загрузка прежняя, постраничная. При активном фильтре или сортировке загружается полный список раздела и обрабатывается в памяти, иначе отсортировалась бы только текущая страница. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../myRequests/RequestsFilterBar.module.scss | 82 ++++++++ .../features/myRequests/RequestsFilterBar.tsx | 115 +++++++++++ .../myRequests/RequestsTableView.module.scss | 42 ---- .../features/myRequests/RequestsTableView.tsx | 179 ++++++++++++------ .../myRequests/SortableHeader.module.scss | 39 ++++ .../features/myRequests/SortableHeader.tsx | 38 ++++ .../features/myRequests/myRequests.service.ts | 76 +++++++- .../myRequests/requestsTableFilters.test.ts | 126 ++++++++++++ .../myRequests/requestsTableFilters.ts | 126 ++++++++++++ .../features/myRequests/useTableRefinement.ts | 99 ++++++++++ 10 files changed, 814 insertions(+), 108 deletions(-) create mode 100644 src/webparts/requestPortal/features/myRequests/RequestsFilterBar.module.scss create mode 100644 src/webparts/requestPortal/features/myRequests/RequestsFilterBar.tsx create mode 100644 src/webparts/requestPortal/features/myRequests/SortableHeader.module.scss create mode 100644 src/webparts/requestPortal/features/myRequests/SortableHeader.tsx create mode 100644 src/webparts/requestPortal/features/myRequests/requestsTableFilters.test.ts create mode 100644 src/webparts/requestPortal/features/myRequests/requestsTableFilters.ts create mode 100644 src/webparts/requestPortal/features/myRequests/useTableRefinement.ts diff --git a/src/webparts/requestPortal/features/myRequests/RequestsFilterBar.module.scss b/src/webparts/requestPortal/features/myRequests/RequestsFilterBar.module.scss new file mode 100644 index 0000000..d5c525d --- /dev/null +++ b/src/webparts/requestPortal/features/myRequests/RequestsFilterBar.module.scss @@ -0,0 +1,82 @@ +@import '../../../../styles/design-tokens'; + +// Ниже этой ширины контролы встают в колонку во всю ширину — в строку они +// на телефоне не помещаются даже с переносом. +$bar-stack-breakpoint: 640px; + +.bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: $sp-3; + margin-bottom: $sp-4; + + @media (max-width: $bar-stack-breakpoint) { + flex-direction: column; + align-items: stretch; + } +} + +// Общий вид полей — как у поиска в шапке таблицы (см. RequestsTableView.module.scss). +@mixin field { + padding: 9px 13px; + border: 1px solid $gray-300; + border-radius: $r-sm; + background-color: $white; + font-family: $font-sans; + font-size: $fs-sm; + color: $gray-900; + transition: .18s; + + @include input-focus-gold; +} + +.select { + @include field; + + // appearance: none + своя SVG-галочка — как в shared/ui/Select. Нативная + // стрелка ОС рисуется своим шрифтом и рядом с остальными полями портала + // выглядит чужеродно (и по-разному в разных браузерах). + appearance: none; + padding-right: 34px; + background-image: url("data:image/svg+xml,%3Csvg width='12' height='8' viewBox='0 0 12 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%236B7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 12px center; + cursor: pointer; +} + +.period { + display: flex; + align-items: center; + gap: $sp-2; + + @media (max-width: $bar-stack-breakpoint) { + flex-wrap: wrap; + } +} + +.periodLabel { + font-size: $fs-sm; + color: $gray-500; + white-space: nowrap; +} + +.date { + @include field; + // Нативный date-инпут на iOS без явного размера схлопывается в ноль. + min-width: 140px; + + @media (max-width: $bar-stack-breakpoint) { + flex: 1; + } +} + +// Цвета пунктов списка статусов — те же, что у StatusBadge. Только color: +// background-color нативный