From 8966829ad9b28b0d4f99aa524332ac1429f2d9a1 Mon Sep 17 00:00:00 2001 From: Veronika Tsygankova Date: Thu, 4 Jun 2026 12:04:22 +0300 Subject: [PATCH] =?UTF-8?q?[AURORA-1061]=20-=20=D0=9F=D0=BE=D0=B4=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B8=D1=82=D1=8C=20=D0=B0=D0=B4=D0=BC=D0=B8?= =?UTF-8?q?=D0=BD=D0=BA=D1=83=20=D0=BA=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=BC?= =?UTF-8?q?=D1=83=20=D0=B1=D1=8D=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/api/ssp.js | 21 +-- web/src/api/users.js | 6 +- web/src/components/common/SearchComponent.jsx | 36 +++- web/src/index.jsx | 37 ++-- .../AuditLogsPage/AuditLogsPage.jsx | 97 ++++++----- .../components/AuditLogsFilters.jsx | 8 +- .../components/AuditLogsTable.jsx | 3 +- .../AuditLogsPage/components/TableFooter.jsx | 164 ------------------ .../AuditLogsPage/utils/transformers.jsx | 4 +- .../pages/AdminPanel/SppsPage/ModalAddSsp.jsx | 10 +- .../SppsPage/ModalChangeUsersInSsp.jsx | 65 +++++-- .../SppsPage/ModalConfirmArchiveSsp.jsx | 2 +- .../AdminPanel/SppsPage/ModalEditSsp.jsx | 7 +- .../pages/AdminPanel/SppsPage/SppsPage.jsx | 138 ++++++++------- .../pages/AdminPanel/SppsPage/SspTable.jsx | 11 +- .../AdminPanel/UsersPage/ModalAddUsers.jsx | 2 +- .../AdminPanel/UsersPage/ModalEditUserSsp.jsx | 14 +- .../UsersPage/UserTable/DepartmentCell.jsx | 2 +- .../UsersPage/UserTable/EditUserModal.jsx | 2 +- .../UsersPage/UserTable/UserTable.jsx | 10 +- .../pages/AdminPanel/UsersPage/UsersPage.jsx | 99 ++++------- .../components/StyledTable/StyledTable.jsx | 4 + .../components/StyledTable/TableFooter.jsx | 103 ++++------- web/src/pages/AdminPanel/utils/filters.js | 8 +- web/src/pages/DictVspPage/DictVspPage.jsx | 2 +- .../components/Modals/Modal.style.jsx | 51 +++--- 26 files changed, 390 insertions(+), 516 deletions(-) delete mode 100644 web/src/pages/AdminPanel/AuditLogsPage/components/TableFooter.jsx diff --git a/web/src/api/ssp.js b/web/src/api/ssp.js index 77bc44a..29d8de0 100644 --- a/web/src/api/ssp.js +++ b/web/src/api/ssp.js @@ -1,23 +1,20 @@ import api from './client'; export const SspApi = { - get(sspId) { - return api.get(`/ssp/${sspId}`).then((r) => r.data); + getSsp(sspId, params = {}) { + return api.get(`/org-unit/${sspId}`, { params }).then((r) => r.data); }, getAll(params = {}) { - return api.get(`/ssp/`, { params }).then((r) => r.data); + return api.get(`/org-unit/`, { params }).then((r) => r.data); }, - getCountUsers() { - return api.get(`/ssp/count-users/`).then((r) => r.data); + updateSsp(sspId, ssp) { + return api.patch(`/org-unit/${sspId}`, ssp).then((r) => r.data); }, - getUsersById(sspId) { - return api.get(`/ssp/get-users/${sspId}`).then((r) => r.data); + createSsp(ssp) { + return api.post(`/org-unit/`, ssp).then((r) => r.data); }, - update(sspId, ssp) { - return api.patch(`/ssp/${sspId}`, ssp).then((r) => r.data); - }, - create(ssp) { - return api.put(`/ssp/`, ssp).then((r) => r.data); + deleteSsp(sspId) { + return api.delete(`/org-unit/${sspId}`).then((r) => r.data); }, getManySsp(userId) { return api diff --git a/web/src/api/users.js b/web/src/api/users.js index 73c2824..9ee1126 100644 --- a/web/src/api/users.js +++ b/web/src/api/users.js @@ -9,7 +9,7 @@ export const UsersApi = { }, getAll() { return api - .get("/users/", { params: { limit: 1000, skip: 0 } }) + .get("/users/", { params: { limit: 1000, skip: 0, load_orgs: true } }) .then((r) => r.data); }, update(idUser, data) { @@ -18,8 +18,8 @@ export const UsersApi = { getAllRoles() { return api.get(`/users/roles/`).then((r) => r.data); }, - add(payload) { - return api.put(`/users/`, payload).then((r) => r.data); + createUser(payload) { + return api.post(`/users/`, payload).then((r) => r.data); }, delete(userId) { return api.delete(`/users/${userId}`).then((r) => r.data); diff --git a/web/src/components/common/SearchComponent.jsx b/web/src/components/common/SearchComponent.jsx index f2814b4..f141967 100644 --- a/web/src/components/common/SearchComponent.jsx +++ b/web/src/components/common/SearchComponent.jsx @@ -1,28 +1,58 @@ +import { useEffect, useRef, useState } from 'react'; import { TextField, InputAdornment } from '@mui/material'; import { Search } from './icons/icons'; function SearchComponent({ placeholder = 'Поиск...', - value, + value = '', onChange, + debounceMs = 0, height = '2rem', + sx: sxProp, ...rest }) { + const [inputValue, setInputValue] = useState(value); + const onChangeRef = useRef(onChange); + + useEffect(() => { + onChangeRef.current = onChange; + }, [onChange]); + + useEffect(() => { + setInputValue(value); + }, [value]); + + useEffect(() => { + if (!debounceMs) return; + const timer = setTimeout(() => { + if (inputValue !== value) { + onChangeRef.current(inputValue); + } + }, debounceMs); + return () => clearTimeout(timer); + }, [inputValue, debounceMs, value]); + const handleChange = (e) => { - onChange(e.target.value); + const next = e.target.value; + setInputValue(next); + if (!debounceMs) { + onChange(next); + } }; + return ( - - - - - - + + + + + + + + , ); diff --git a/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx b/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx index fe57739..e8fe696 100644 --- a/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx +++ b/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx @@ -1,12 +1,10 @@ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { PageContainer } from '../../StyledForPage'; import { HeaderSwitch } from '../../../components/HeaderMenu/HeaderSwitch.jsx'; import { SwitchUserSsp } from '../../../components/AdminPanel/SwitchUserSsp'; import { ROLES_NAME_ID } from '../../../constants'; import { useAuth } from '../../../app/context/AuthProvider'; import { Box } from '@mui/material'; -import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; -import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { toast } from 'react-toastify'; import { AuditLogsApi } from '../../../api/audit-logs'; import { SspApi } from '../../../api/ssp'; @@ -71,7 +69,7 @@ const AuditLogsPage = () => { page: page + 1, limit: rowsPerPage, user_id: selectedUser?.id, - ssp_id: selectedSsp?.id, + org_unit_id: selectedSsp?.id, event_type: selectedEventType?.id, date_from: dateFrom ? dateFrom.toISOString() : undefined, date_to: dateTo ? dateTo.toISOString() : undefined, @@ -80,13 +78,8 @@ const AuditLogsPage = () => { }; const data = await AuditLogsApi.getAll(params); - setLogs(data.result); - setTotalCount((prev) => { - if (data.result.length == rowsPerPage) { - return data.result.length + rowsPerPage * (page + 1); - } - return prev - rowsPerPage + data.result.length; - }); + setLogs(data.result ?? []); + setTotalCount(data.count ?? 0); } catch (error) { toast.error('Ошибка получения журнала аудита'); console.error(error); @@ -118,6 +111,16 @@ const AuditLogsPage = () => { setPage(0); }; + const handleTaskIdChange = useCallback((value) => { + setTaskId(value); + setPage(0); + }, []); + + const handleFormIdChange = useCallback((value) => { + setFormId(value); + setPage(0); + }, []); + const handleResetFilters = () => { setSelectedUser(null); setSelectedSsp(null); @@ -132,45 +135,43 @@ const AuditLogsPage = () => { if (!user || user.role_id !== ROLES_NAME_ID.admin) return null; return ( - - - - - - + + + + + - + - - - + + ); }; diff --git a/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx b/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx index 1bde8d0..5fd8407 100644 --- a/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx +++ b/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx @@ -148,10 +148,11 @@ const AuditLogsFilters = ({ Дата начала onDateFromChange(newValue)} slotProps={{ + field: { clearable: true }, textField: { size: 'small', sx: { width: '100%' } }, }} /> @@ -160,10 +161,11 @@ const AuditLogsFilters = ({ Дата окончания onDateToChange(newValue)} slotProps={{ + field: { clearable: true }, textField: { size: 'small', sx: { width: '100%' } }, }} /> @@ -183,6 +185,7 @@ const AuditLogsFilters = ({ }} height={'2.56rem'} placeholder="Например: #1234" + debounceMs={400} onChange={onTaskIdChange} value={taskId} /> @@ -195,6 +198,7 @@ const AuditLogsFilters = ({ }} height={'2.56rem'} placeholder="Например: #1234" + debounceMs={400} onChange={onFormIdChange} value={formId} /> diff --git a/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsTable.jsx b/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsTable.jsx index cbf0882..5e1c533 100644 --- a/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsTable.jsx +++ b/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsTable.jsx @@ -184,8 +184,7 @@ const AuditLogsTable = ({ onPageChange={onPageChange} onRowsPerPageChange={onRowsPerPageChange} // Опции высоты - containerHeight="calc(100vh - 450px)" - minHeight="400px" + minHeight='calc(100vh - 29rem)' // Состояние загрузки loading={loading} // Отключаем ненужные функции diff --git a/web/src/pages/AdminPanel/AuditLogsPage/components/TableFooter.jsx b/web/src/pages/AdminPanel/AuditLogsPage/components/TableFooter.jsx deleted file mode 100644 index 1a3692f..0000000 --- a/web/src/pages/AdminPanel/AuditLogsPage/components/TableFooter.jsx +++ /dev/null @@ -1,164 +0,0 @@ -import { - Box, - Typography, - Select, - MenuItem, - FormControl, - Button, - Stack, - Paper, -} from '@mui/material'; -import { styled } from '@mui/material/styles'; -import { DefaultOutlinedButton } from '../../../../components/common/Buttons/Buttons'; - -// Стилизованные кнопки для страниц -const StyledPageButton = styled(Button)(({ active }) => ({ - minWidth: '2.5rem', - height: '2.56rem', - padding: '0', - fontSize: '0.875rem', - fontWeight: 500, - transition: 'all 0.2s ease', - ...(active === 'true' - ? { - background: 'linear-gradient(172deg, #7abc51 0%, #46881c 100%)', - color: 'white', - '&:hover': { - transform: 'translateY(-1px)', - }, - } - : { - border: '1px solid #d1d5dc', - color: '#374151', - '&:hover': { - borderColor: '#5FAC43', - backgroundColor: 'rgba(95, 172, 67, 0.04)', - transform: 'translateY(-1px)', - }, - }), - '&:active': { - transform: 'translateY(0)', - }, -})); - -const TableFooter = ({ - totalCount, - page, - rowsPerPage, - onPageChange, - onRowsPerPageChange, - rowsPerPageOptions = [10, 20, 50, 100], -}) => { - const totalPages = Math.ceil(totalCount / rowsPerPage); - - const handlePreviousPage = () => { - if (page > 0) { - onPageChange(page - 1); - } - }; - - const handleNextPage = () => { - if (page < totalPages - 1) { - onPageChange(page + 1); - } - }; - - const handleRowsPerPageChange = (event) => { - onRowsPerPageChange(parseInt(event.target.value, 10)); - }; - - const from = page * rowsPerPage + 1; - const to = Math.min((page + 1) * rowsPerPage, totalCount); - - return ( - - - {/* Левая часть - информация о строках */} - - - {`Показано ${from}-${to}`} - - - - - - - - {/* Правая часть - навигация */} - - - Предыдущая - - - - {/* Текущая страница */} - {page + 1} - - {/* Следующая страница (если есть) */} - {page + 1 < totalPages && ( - onPageChange(page + 1)} - > - {page + 2} - - )} - - - - Следующая - - - - - ); -}; - -export default TableFooter; diff --git a/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx b/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx index 87bc363..df4917a 100644 --- a/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx +++ b/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx @@ -32,7 +32,7 @@ export async function transformUser(userId) { export async function transformSsp(sspId) { try { - const ssp = await SspApi.get(sspId); + const ssp = await SspApi.getSsp(sspId); if (ssp?.result?.title) { return ssp.result.title; } @@ -50,7 +50,7 @@ export async function transformSsps(sspIds) { const res = []; for (const sspId of sspIds) { try { - const ssp = await SspApi.get(sspId); + const ssp = await SspApi.getSsp(sspId); res.push(ssp?.result?.title || 'РФ/ССП не найден'); } catch (error) { res.push('РФ/ССП не найден'); diff --git a/web/src/pages/AdminPanel/SppsPage/ModalAddSsp.jsx b/web/src/pages/AdminPanel/SppsPage/ModalAddSsp.jsx index 5d0ae1e..863bcab 100644 --- a/web/src/pages/AdminPanel/SppsPage/ModalAddSsp.jsx +++ b/web/src/pages/AdminPanel/SppsPage/ModalAddSsp.jsx @@ -20,6 +20,14 @@ export const ModalAddSsp = ({ open, onClose, onSave }) => { const [usersData, setUsersData] = useState({ update: [], delete: [] }); const [allUsers, setAllUsers] = useState([]); + useEffect(() => { + if (!open) { + setTitle(''); + setType('ssp'); + setUsersData({ update: [], delete: [] }); + } + }, [open]); + useEffect(() => { UsersApi.getAll() .then((data) => { @@ -37,7 +45,7 @@ export const ModalAddSsp = ({ open, onClose, onSave }) => { const handleClickSave = () => { const saveSsp = { title: title, - is_ssp: type === 'ssp' ? 1 : 0, + is_ssp: type === 'ssp', }; onSave?.(saveSsp, usersData); diff --git a/web/src/pages/AdminPanel/SppsPage/ModalChangeUsersInSsp.jsx b/web/src/pages/AdminPanel/SppsPage/ModalChangeUsersInSsp.jsx index 9272c67..8845a9e 100644 --- a/web/src/pages/AdminPanel/SppsPage/ModalChangeUsersInSsp.jsx +++ b/web/src/pages/AdminPanel/SppsPage/ModalChangeUsersInSsp.jsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import Modal from '../../../components/common/Modal/Modal'; -import { Box, Button } from '@mui/material'; +import { Box, Button, CircularProgress } from '@mui/material'; import { SspApi } from '../../../api/ssp'; import { UsersApi } from '../../../api/users'; import { toast } from 'react-toastify'; @@ -14,6 +14,7 @@ export const ModalChangeUsersInSsp = ({ open, onClose, ssp, onEdit }) => { }); const [allUsers, setAllUsers] = useState([]); + const [loadingUsers, setLoadingUsers] = useState(false); useEffect(() => { UsersApi.getAll() .then((data) => { @@ -29,15 +30,33 @@ export const ModalChangeUsersInSsp = ({ open, onClose, ssp, onEdit }) => { }, []); useEffect(() => { + if (!open) { + setUsers([]); + setUsersDataForUpdate({ update: [], delete: [] }); + setLoadingUsers(false); + return; + } if (!ssp) return; - SspApi.getUsersById(ssp.id).then((data) => { - if (data.success) { - setUsers(data.result); - return; - } - toast.error('Ошибка получания пользователей ' + data.message); - }); - }, [ssp]); + + setLoadingUsers(true); + setUsers([]); + setUsersDataForUpdate({ update: [], delete: [] }); + + SspApi.getSsp(ssp.id, { load_users: true }) + .then((data) => { + if (data.success) { + setUsers(data.result?.users ?? []); + return; + } + toast.error('Ошибка получания пользователей ' + data.message); + }) + .catch(() => { + toast.error('Ошибка получания пользователей'); + }) + .finally(() => { + setLoadingUsers(false); + }); + }, [open, ssp]); const handleClickSave = () => { onEdit?.(ssp, usersDataForUpdate); @@ -62,6 +81,7 @@ export const ModalChangeUsersInSsp = ({ open, onClose, ssp, onEdit }) => {