Compare commits
No commits in common. "af112285bcc7d3218354d48545fee960ef6ab593" and "db1df61f3774ba0c69e069b9389cb9acbd156b4a" have entirely different histories.
af112285bc
...
db1df61f37
@ -1,6 +1,9 @@
|
|||||||
import api from './client';
|
import api from './client';
|
||||||
|
|
||||||
export const TasksApi = {
|
export const TasksApi = {
|
||||||
|
getById(taskId) {
|
||||||
|
return api.get(`/form/${taskId}`).then((r) => r.data);
|
||||||
|
},
|
||||||
list(params = {}) {
|
list(params = {}) {
|
||||||
return api.get('/form/', { params }).then((r) => r.data);
|
return api.get('/form/', { params }).then((r) => r.data);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,36 +1,25 @@
|
|||||||
import { Box, Typography } from '@mui/material';
|
import { Box, Typography } from '@mui/material';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState, useCallback } from 'react';
|
||||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { ProjectsApi } from '../../api/projects';
|
import { ProjectsApi } from '../../api/projects';
|
||||||
import { SspApi } from '../../api/ssp';
|
import { SspApi } from '../../api/ssp';
|
||||||
import { useAuth } from '../../app/context/AuthProvider';
|
|
||||||
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
|
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
|
||||||
import { DangerOutlinedButton, PrimaryButton } from '../../components/common/Buttons/Buttons';
|
import { DangerOutlinedButton, PrimaryButton } from '../../components/common/Buttons/Buttons';
|
||||||
import Modal from '../../components/common/Modal/Modal';
|
|
||||||
import { WhitePlus } from '../../components/common/icons/icons';
|
import { WhitePlus } from '../../components/common/icons/icons';
|
||||||
import { ROLES_NAME_ID } from '../../constants/constants';
|
import Modal from '../../components/common/Modal/Modal';
|
||||||
import { DEFAULT_PROJECT_CONFIG } from '../../constants/projectConfig';
|
import { DEFAULT_PROJECT_CONFIG } from '../../constants/projectConfig';
|
||||||
import { ModalCreateProject } from '../ProjectsPage/ModalCreateProject';
|
import { ModalCreateProject } from '../ProjectsPage/ModalCreateProject';
|
||||||
import EditModal from './components/EditModal/EditModal';
|
import EditModal from './components/EditModal/EditModal';
|
||||||
import ProjectSummaryTable from './components/ProjectSummaryTable/ProjectSummaryTable';
|
|
||||||
import ProjectsTable from './components/ProjectsTable/ProjectsTable';
|
import ProjectsTable from './components/ProjectsTable/ProjectsTable';
|
||||||
|
import ProjectSummaryTable from './components/ProjectSummaryTable/ProjectSummaryTable';
|
||||||
import TableFilters from './components/TableFilters/TableFilters'; // Импортируем компонент фильтров
|
import TableFilters from './components/TableFilters/TableFilters'; // Импортируем компонент фильтров
|
||||||
import { handleNavigateClick } from './utils/tableHandlers';
|
import { handleNavigateClick } from './utils/tableHandlers';
|
||||||
|
import { useAuth } from '../../app/context/AuthProvider';
|
||||||
|
import { ROLES_NAME_ID } from '../../constants/constants';
|
||||||
|
|
||||||
const NavigationProjectPage = () => {
|
const NavigationProjectPage = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
const branchIdsParam = searchParams.get('branch_ids') || '';
|
|
||||||
const branchIds = useMemo(
|
|
||||||
() =>
|
|
||||||
branchIdsParam
|
|
||||||
.split(',')
|
|
||||||
.filter(Boolean)
|
|
||||||
.map(Number)
|
|
||||||
.filter((value) => Number.isInteger(value) && value > 0),
|
|
||||||
[branchIdsParam],
|
|
||||||
);
|
|
||||||
|
|
||||||
const [selectedRow, setSelectedRow] = useState(null);
|
const [selectedRow, setSelectedRow] = useState(null);
|
||||||
const [editModalOpen, setEditModalOpen] = useState(false);
|
const [editModalOpen, setEditModalOpen] = useState(false);
|
||||||
@ -51,7 +40,7 @@ const NavigationProjectPage = () => {
|
|||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
// Состояния для фильтров
|
// Состояния для фильтров
|
||||||
const [selectedBranches, setSelectedBranches] = useState([]);
|
const [selectedBranch, setSelectedBranch] = useState('');
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
const [selectedStatus, setSelectedStatus] = useState('');
|
const [selectedStatus, setSelectedStatus] = useState('');
|
||||||
const [archivedData, setArchivedData] = useState([]);
|
const [archivedData, setArchivedData] = useState([]);
|
||||||
@ -70,16 +59,22 @@ const NavigationProjectPage = () => {
|
|||||||
const isAdmin = user.role_id === ROLES_NAME_ID.admin;
|
const isAdmin = user.role_id === ROLES_NAME_ID.admin;
|
||||||
|
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
const sspResponse = await SspApi.getAll({ is_active: true });
|
const sspResponse = await (
|
||||||
|
SspApi.getAll({ is_active: true })
|
||||||
|
);
|
||||||
if (!sspResponse.success) {
|
if (!sspResponse.success) {
|
||||||
toast.error('Ошибка загрузки списка ССП');
|
toast.error('Ошибка загрузки списка ССП');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setOrgUnits(sspResponse.result);
|
setOrgUnits(sspResponse.result);
|
||||||
setOrgUnitNames(Object.fromEntries((sspResponse.result || []).map((orgUnit) => [orgUnit.id, orgUnit.title])));
|
setOrgUnitNames(
|
||||||
|
Object.fromEntries((sspResponse.result || []).map((orgUnit) => [orgUnit.id, orgUnit.title])),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
setOrgUnits(user.org_units ?? []);
|
setOrgUnits(user.org_units ?? []);
|
||||||
setOrgUnitNames(Object.fromEntries((user.org_units || []).map((orgUnit) => [orgUnit.id, orgUnit.title])));
|
setOrgUnitNames(
|
||||||
|
Object.fromEntries((user.org_units || []).map((orgUnit) => [orgUnit.id, orgUnit.title])),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading data:', error);
|
console.error('Error loading data:', error);
|
||||||
@ -93,20 +88,13 @@ const NavigationProjectPage = () => {
|
|||||||
loadData();
|
loadData();
|
||||||
}, [loadData]);
|
}, [loadData]);
|
||||||
|
|
||||||
useEffect(() => {
|
const createProjectConfig = useMemo(() => ({
|
||||||
setSelectedBranches(orgUnits.filter(({ id }) => branchIds.includes(id)));
|
|
||||||
}, [branchIds, orgUnits]);
|
|
||||||
|
|
||||||
const createProjectConfig = useMemo(
|
|
||||||
() => ({
|
|
||||||
...DEFAULT_PROJECT_CONFIG,
|
...DEFAULT_PROJECT_CONFIG,
|
||||||
'ССП/РФ': {
|
'ССП/РФ': {
|
||||||
...DEFAULT_PROJECT_CONFIG['ССП/РФ'],
|
...DEFAULT_PROJECT_CONFIG['ССП/РФ'],
|
||||||
options: orgUnits,
|
options: orgUnits,
|
||||||
},
|
},
|
||||||
}),
|
}), [orgUnits]);
|
||||||
[orgUnits],
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let active = true;
|
let active = true;
|
||||||
@ -115,7 +103,7 @@ const NavigationProjectPage = () => {
|
|||||||
const loadProjects = async () => {
|
const loadProjects = async () => {
|
||||||
setIsProjectsLoading(true);
|
setIsProjectsLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await ProjectsApi.listWithReports();
|
const response = await ProjectsApi.listWithReports({ limit: 1000 });
|
||||||
if (active) setTableData(response.result || []);
|
if (active) setTableData(response.result || []);
|
||||||
} catch (requestError) {
|
} catch (requestError) {
|
||||||
console.error('Error loading projects with reports:', requestError);
|
console.error('Error loading projects with reports:', requestError);
|
||||||
@ -142,7 +130,7 @@ const NavigationProjectPage = () => {
|
|||||||
status_in: 'archived',
|
status_in: 'archived',
|
||||||
offset,
|
offset,
|
||||||
limit: archivedPagination.pageSize,
|
limit: archivedPagination.pageSize,
|
||||||
...(selectedBranches.length ? { branch_ids: selectedBranches.map(({ id }) => id).join(',') } : {}),
|
...(selectedBranch?.id ? { branch_id: selectedBranch.id } : {}),
|
||||||
...(searchQuery.trim() ? { search: searchQuery.trim() } : {}),
|
...(searchQuery.trim() ? { search: searchQuery.trim() } : {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -172,7 +160,7 @@ const NavigationProjectPage = () => {
|
|||||||
user,
|
user,
|
||||||
isLoading,
|
isLoading,
|
||||||
isArchiveMode,
|
isArchiveMode,
|
||||||
selectedBranches,
|
selectedBranch,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
archivedPagination.pageIndex,
|
archivedPagination.pageIndex,
|
||||||
archivedPagination.pageSize,
|
archivedPagination.pageSize,
|
||||||
@ -192,7 +180,7 @@ const NavigationProjectPage = () => {
|
|||||||
setIsSummaryLoading(true);
|
setIsSummaryLoading(true);
|
||||||
try {
|
try {
|
||||||
const response = await ProjectsApi.getSummary(selectedRow.original.id);
|
const response = await ProjectsApi.getSummary(selectedRow.original.id);
|
||||||
if (active) setSummaryData(response.result.filter((v) => v.row_type !== 'PROJECT') || []);
|
if (active) setSummaryData(response.result.filter(v => v.row_type !== 'PROJECT') || []);
|
||||||
} catch (requestError) {
|
} catch (requestError) {
|
||||||
console.error('Error loading project summary:', requestError);
|
console.error('Error loading project summary:', requestError);
|
||||||
if (active) {
|
if (active) {
|
||||||
@ -214,7 +202,7 @@ const NavigationProjectPage = () => {
|
|||||||
return archivedData;
|
return archivedData;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedBranches.length === 0 && !searchQuery && !selectedStatus) {
|
if (!selectedBranch && !searchQuery && !selectedStatus) {
|
||||||
return tableData;
|
return tableData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,8 +214,8 @@ const NavigationProjectPage = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Фильтр по филиалу (только для корневых)
|
// Фильтр по филиалу (только для корневых)
|
||||||
if (selectedBranches.length > 0) {
|
if (selectedBranch) {
|
||||||
return selectedBranches.some(({ id }) => item.org_unit_id === id);
|
return item.org_unit_id === selectedBranch.id;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
@ -255,7 +243,7 @@ const NavigationProjectPage = () => {
|
|||||||
|
|
||||||
return parentMatches || hasMatchingChildren;
|
return parentMatches || hasMatchingChildren;
|
||||||
});
|
});
|
||||||
}, [archivedData, isArchiveMode, searchQuery, selectedBranches, selectedStatus, tableData]);
|
}, [archivedData, isArchiveMode, searchQuery, selectedBranch, selectedStatus, tableData]);
|
||||||
|
|
||||||
const onEdit = useCallback((row) => {
|
const onEdit = useCallback((row) => {
|
||||||
const isSmeta = row.depth > 0;
|
const isSmeta = row.depth > 0;
|
||||||
@ -270,12 +258,9 @@ const NavigationProjectPage = () => {
|
|||||||
setEditModalOpen(true);
|
setEditModalOpen(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onNavigate = useCallback(
|
const onNavigate = useCallback((row) => {
|
||||||
(row) => {
|
|
||||||
handleNavigateClick(row, navigate);
|
handleNavigateClick(row, navigate);
|
||||||
},
|
}, [navigate]);
|
||||||
[navigate],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleDeleteProject = async () => {
|
const handleDeleteProject = async () => {
|
||||||
if (!projectToDelete?.id) return;
|
if (!projectToDelete?.id) return;
|
||||||
@ -301,8 +286,7 @@ const NavigationProjectPage = () => {
|
|||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
try {
|
try {
|
||||||
if (formData._rowType === 'smeta') {
|
if (formData._rowType === 'smeta') {
|
||||||
const { is_in_plan, is_in_plan_q2, is_in_plan_q3, is_in_plan_q4, development_block, reserve_to_prrs_ahr, reserve_to_prrs_kv } =
|
const { is_in_plan, is_in_plan_q2, is_in_plan_q3, is_in_plan_q4, development_block, reserve_to_prrs_ahr, reserve_to_prrs_kv } = formData;
|
||||||
formData;
|
|
||||||
await ProjectsApi.updateSmeta(formData._projectId, formData.year, {
|
await ProjectsApi.updateSmeta(formData._projectId, formData.year, {
|
||||||
is_in_plan,
|
is_in_plan,
|
||||||
is_in_plan_q2,
|
is_in_plan_q2,
|
||||||
@ -313,23 +297,7 @@ const NavigationProjectPage = () => {
|
|||||||
reserve_to_prrs_kv: reserve_to_prrs_kv === '' ? null : reserve_to_prrs_kv,
|
reserve_to_prrs_kv: reserve_to_prrs_kv === '' ? null : reserve_to_prrs_kv,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const {
|
const { name, status, technical_number, project_type, vsp_format, placement_type, object_address, staff_count, total_area, org_unit_id, krf_decision_date, fk_decision_date, board_decision_date, open_relocate_close_date, funding_by_ko_decision } = formData;
|
||||||
name,
|
|
||||||
status,
|
|
||||||
technical_number,
|
|
||||||
project_type,
|
|
||||||
vsp_format,
|
|
||||||
placement_type,
|
|
||||||
object_address,
|
|
||||||
staff_count,
|
|
||||||
total_area,
|
|
||||||
org_unit_id,
|
|
||||||
krf_decision_date,
|
|
||||||
fk_decision_date,
|
|
||||||
board_decision_date,
|
|
||||||
open_relocate_close_date,
|
|
||||||
funding_by_ko_decision,
|
|
||||||
} = formData;
|
|
||||||
await ProjectsApi.update(formData._projectId, {
|
await ProjectsApi.update(formData._projectId, {
|
||||||
name,
|
name,
|
||||||
status: status || null,
|
status: status || null,
|
||||||
@ -362,13 +330,7 @@ const NavigationProjectPage = () => {
|
|||||||
const handleBranchChange = (value) => {
|
const handleBranchChange = (value) => {
|
||||||
setSelectedRow(null);
|
setSelectedRow(null);
|
||||||
setSummaryData([]);
|
setSummaryData([]);
|
||||||
setSelectedBranches(value);
|
setSelectedBranch(value);
|
||||||
setSearchParams((currentParams) => {
|
|
||||||
const nextParams = new URLSearchParams(currentParams);
|
|
||||||
if (value.length > 0) nextParams.set('branch_ids', value.map(({ id }) => id).join(','));
|
|
||||||
else nextParams.delete('branch_ids');
|
|
||||||
return nextParams;
|
|
||||||
});
|
|
||||||
setArchivedPagination((current) => ({ ...current, pageIndex: 0 }));
|
setArchivedPagination((current) => ({ ...current, pageIndex: 0 }));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -417,10 +379,11 @@ const NavigationProjectPage = () => {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
}}>
|
}}>
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
|
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1, }}>
|
||||||
|
|
||||||
{/* Компонент фильтров */}
|
{/* Компонент фильтров */}
|
||||||
<TableFilters
|
<TableFilters
|
||||||
selectedBranches={selectedBranches}
|
selectedBranch={selectedBranch}
|
||||||
onBranchChange={handleBranchChange}
|
onBranchChange={handleBranchChange}
|
||||||
searchQuery={searchQuery}
|
searchQuery={searchQuery}
|
||||||
onSearchChange={handleSearchChange}
|
onSearchChange={handleSearchChange}
|
||||||
@ -447,17 +410,14 @@ const NavigationProjectPage = () => {
|
|||||||
orgUnitNames={orgUnitNames}
|
orgUnitNames={orgUnitNames}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProjectSummaryTable data={summaryData} isLoading={isSummaryLoading} selectedRow={selectedRow} />
|
<ProjectSummaryTable
|
||||||
|
data={summaryData}
|
||||||
|
isLoading={isSummaryLoading}
|
||||||
|
selectedRow={selectedRow}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Модалка редактирования */}
|
{/* Модалка редактирования */}
|
||||||
<EditModal
|
<EditModal open={editModalOpen} onClose={() => setEditModalOpen(false)} rowData={selectedRowData} onSave={onSaveEdit} isSaving={isSaving} orgUnitNames={orgUnitNames} />
|
||||||
open={editModalOpen}
|
|
||||||
onClose={() => setEditModalOpen(false)}
|
|
||||||
rowData={selectedRowData}
|
|
||||||
onSave={onSaveEdit}
|
|
||||||
isSaving={isSaving}
|
|
||||||
orgUnitNames={orgUnitNames}
|
|
||||||
/>
|
|
||||||
<ModalCreateProject
|
<ModalCreateProject
|
||||||
open={createModalOpen}
|
open={createModalOpen}
|
||||||
onClose={() => setCreateModalOpen(false)}
|
onClose={() => setCreateModalOpen(false)}
|
||||||
@ -479,10 +439,13 @@ const NavigationProjectPage = () => {
|
|||||||
</DangerOutlinedButton>
|
</DangerOutlinedButton>
|
||||||
</>
|
</>
|
||||||
}>
|
}>
|
||||||
<Typography>Проект «{projectToDelete?.name}» будет удалён без возможности восстановления.</Typography>
|
<Typography>
|
||||||
|
Проект «{projectToDelete?.name}» будет удалён без возможности восстановления.
|
||||||
|
</Typography>
|
||||||
</Modal>
|
</Modal>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,21 @@
|
|||||||
import { Search } from '@mui/icons-material';
|
import { Search } from '@mui/icons-material';
|
||||||
import { Autocomplete, Box, Chip, CircularProgress, MenuItem, Paper, TextField } from '@mui/material';
|
import { Autocomplete, Box, Chip, CircularProgress, MenuItem, Paper, TextField } from '@mui/material';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useEffect, useState, useCallback } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
|
||||||
import { SspApi } from '../../../../api/ssp';
|
import { SspApi } from '../../../../api/ssp';
|
||||||
import { useAuth } from '../../../../app/context/AuthProvider';
|
import { useAuth } from '../../../../app/context/AuthProvider';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
import { PROJECT_STATUSES, ROLES_NAME_ID } from '../../../../constants/constants';
|
import { PROJECT_STATUSES, ROLES_NAME_ID } from '../../../../constants/constants';
|
||||||
|
|
||||||
const FILTER_PROJECT_STATUSES = ['created', 'agreed', 'archived'];
|
const FILTER_PROJECT_STATUSES = ['created', 'agreed', 'archived'];
|
||||||
|
|
||||||
const TableFilters = ({ onBranchChange, onSearchChange, onStatusChange, selectedBranches, selectedStatus, searchQuery }) => {
|
const TableFilters = ({
|
||||||
|
onBranchChange,
|
||||||
|
onSearchChange,
|
||||||
|
onStatusChange,
|
||||||
|
selectedBranch,
|
||||||
|
selectedStatus,
|
||||||
|
searchQuery,
|
||||||
|
}) => {
|
||||||
const [branches, setBranches] = useState([]);
|
const [branches, setBranches] = useState([]);
|
||||||
const [branchInputValue, setBranchInputValue] = useState('');
|
const [branchInputValue, setBranchInputValue] = useState('');
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
@ -21,14 +28,18 @@ const TableFilters = ({ onBranchChange, onSearchChange, onStatusChange, selected
|
|||||||
const isAdmin = user.role_id === ROLES_NAME_ID.admin;
|
const isAdmin = user.role_id === ROLES_NAME_ID.admin;
|
||||||
|
|
||||||
if (isAdmin) {
|
if (isAdmin) {
|
||||||
const sspResponse = await SspApi.getAll({ is_active: true });
|
const sspResponse = await (
|
||||||
|
SspApi.getAll({ is_active: true })
|
||||||
|
);
|
||||||
if (!sspResponse.success) {
|
if (!sspResponse.success) {
|
||||||
toast.error('Ошибка загрузки списка ССП');
|
toast.error('Ошибка загрузки списка ССП');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setBranches(sspResponse.result);
|
setBranches(sspResponse.result);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
setBranches(user.org_units ?? []);
|
setBranches(user.org_units ?? []);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading data:', error);
|
console.error('Error loading data:', error);
|
||||||
@ -38,10 +49,15 @@ const TableFilters = ({ onBranchChange, onSearchChange, onStatusChange, selected
|
|||||||
}
|
}
|
||||||
}, [user]);
|
}, [user]);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadData();
|
loadData();
|
||||||
}, [loadData]);
|
}, [loadData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setBranchInputValue(selectedBranch?.title || '');
|
||||||
|
}, [selectedBranch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
elevation={0}
|
elevation={0}
|
||||||
@ -58,46 +74,29 @@ const TableFilters = ({ onBranchChange, onSearchChange, onStatusChange, selected
|
|||||||
maxHeight: '4.5vh',
|
maxHeight: '4.5vh',
|
||||||
}}>
|
}}>
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
multiple
|
|
||||||
disableCloseOnSelect
|
|
||||||
size='small'
|
size='small'
|
||||||
sx={{
|
sx={{
|
||||||
minWidth: 420,
|
minWidth: 250,
|
||||||
maxWidth: 520,
|
maxWidth: 300,
|
||||||
flex: '1 1 auto',
|
flex: '1 1 auto',
|
||||||
'& .MuiAutocomplete-inputRoot': {
|
|
||||||
flexWrap: 'nowrap',
|
|
||||||
},
|
|
||||||
'& .MuiAutocomplete-input': {
|
|
||||||
minWidth: '0 !important',
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
options={branches}
|
options={branches}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
getOptionLabel={(option) => option.title || ''}
|
getOptionLabel={(option) => option.title || ''}
|
||||||
getOptionKey={(option) => option.id}
|
getOptionKey={(option) => option.id}
|
||||||
value={selectedBranches}
|
value={selectedBranch || null}
|
||||||
inputValue={branchInputValue}
|
inputValue={branchInputValue}
|
||||||
onInputChange={(_event, newInputValue) => {
|
onInputChange={(event, newInputValue) => {
|
||||||
setBranchInputValue(newInputValue);
|
setBranchInputValue(newInputValue);
|
||||||
}}
|
}}
|
||||||
onChange={(_event, newValue) => {
|
onChange={(event, newValue) => {
|
||||||
onBranchChange(newValue);
|
onBranchChange(newValue || '');
|
||||||
}}
|
}}
|
||||||
renderValue={(value, getItemProps) =>
|
|
||||||
value
|
|
||||||
.slice(0, 2)
|
|
||||||
.map((option, index) => {
|
|
||||||
const { key, ...itemProps } = getItemProps({ index });
|
|
||||||
return <Chip {...itemProps} key={option.id || key} label={option.title} size='small' />;
|
|
||||||
})
|
|
||||||
.concat(value.length > 2 ? [<Chip key='more' label={`+${value.length - 2}`} size='small' />] : [])
|
|
||||||
}
|
|
||||||
renderInput={(params) => {
|
renderInput={(params) => {
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
{...params}
|
{...params}
|
||||||
placeholder={selectedBranches.length ? '' : 'Региональные филиалы'}
|
placeholder='Региональные филиалы'
|
||||||
variant='outlined'
|
variant='outlined'
|
||||||
size='small'
|
size='small'
|
||||||
slotProps={{
|
slotProps={{
|
||||||
@ -169,14 +168,14 @@ const TableFilters = ({ onBranchChange, onSearchChange, onStatusChange, selected
|
|||||||
))}
|
))}
|
||||||
</TextField>
|
</TextField>
|
||||||
|
|
||||||
{(selectedBranches.length > 0 || searchQuery || selectedStatus) && (
|
{(selectedBranch || searchQuery || selectedStatus) && (
|
||||||
<Box sx={{ display: 'flex', gap: 1, ml: 'auto' }}>
|
<Box sx={{ display: 'flex', gap: 1, ml: 'auto' }}>
|
||||||
<Chip
|
<Chip
|
||||||
label='Сбросить фильтры'
|
label='Сбросить фильтры'
|
||||||
size='small'
|
size='small'
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setBranchInputValue('');
|
setBranchInputValue('');
|
||||||
onBranchChange([]);
|
onBranchChange('');
|
||||||
onSearchChange('');
|
onSearchChange('');
|
||||||
onStatusChange('');
|
onStatusChange('');
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';
|
|||||||
import { Alert, Box, Button, Paper, Tab, Tabs, Typography } from '@mui/material';
|
import { Alert, Box, Button, Paper, Tab, Tabs, Typography } from '@mui/material';
|
||||||
import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
|
import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
|
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
|
||||||
import { blueColumn } from '../../components/RealtimeTable/constants/columnColors';
|
import { blueColumn } from '../../components/RealtimeTable/constants/columnColors';
|
||||||
import { sectionCodeColor } from '../../components/RealtimeTable/constants/columnConfig';
|
import { sectionCodeColor } from '../../components/RealtimeTable/constants/columnConfig';
|
||||||
@ -174,7 +173,6 @@ const filterSummaryTree = (tree, query) =>
|
|||||||
const countSummaryTree = (tree) => tree.reduce((count, row) => count + 1 + countSummaryTree(row.subRows), 0);
|
const countSummaryTree = (tree) => tree.reduce((count, row) => count + 1 + countSummaryTree(row.subRows), 0);
|
||||||
|
|
||||||
export default function SvodPage() {
|
export default function SvodPage() {
|
||||||
const navigate = useNavigate();
|
|
||||||
const { getSheetFilters, updateSheetFilters, getSummary, invalidateSummary } = useSvod();
|
const { getSheetFilters, updateSheetFilters, getSummary, invalidateSummary } = useSvod();
|
||||||
const [sheet, setSheet] = useState('MAIN');
|
const [sheet, setSheet] = useState('MAIN');
|
||||||
const [rows, setRows] = useState([]);
|
const [rows, setRows] = useState([]);
|
||||||
@ -227,22 +225,6 @@ export default function SvodPage() {
|
|||||||
loadSummary();
|
loadSummary();
|
||||||
}, [invalidateSummary, loadSummary, selectedOrganizations, sheet, year]);
|
}, [invalidateSummary, loadSummary, selectedOrganizations, sheet, year]);
|
||||||
|
|
||||||
const openFilteredTasks = useCallback(() => {
|
|
||||||
const params = new URLSearchParams({ year: String(year) });
|
|
||||||
const organizationIds = selectedOrganizations.map(({ id }) => id);
|
|
||||||
if (organizationIds.length > 0) params.set('org_units', organizationIds.join(','));
|
|
||||||
if (sheet !== 'MAIN') params.set('form_type', sheet);
|
|
||||||
navigate(`/tasks?${params.toString()}`);
|
|
||||||
}, [navigate, selectedOrganizations, sheet, year]);
|
|
||||||
|
|
||||||
const openFilteredProjects = useCallback(() => {
|
|
||||||
const params = new URLSearchParams();
|
|
||||||
const organizationIds = selectedOrganizations.map(({ id }) => id);
|
|
||||||
if (organizationIds.length > 0) params.set('branch_ids', organizationIds.join(','));
|
|
||||||
const query = params.toString();
|
|
||||||
navigate(query ? `/projects?${query}` : '/projects');
|
|
||||||
}, [navigate, selectedOrganizations]);
|
|
||||||
|
|
||||||
const filteredRows = useMemo(() => {
|
const filteredRows = useMemo(() => {
|
||||||
const normalizedSearch = search.trim().toLowerCase();
|
const normalizedSearch = search.trim().toLowerCase();
|
||||||
const tree = buildSummaryTree(rows);
|
const tree = buildSummaryTree(rows);
|
||||||
@ -374,22 +356,13 @@ export default function SvodPage() {
|
|||||||
{`Найдено ${filteredRowsCount.toLocaleString('ru-RU')} из ${rows.length.toLocaleString('ru-RU')} строк`}
|
{`Найдено ${filteredRowsCount.toLocaleString('ru-RU')} из ${rows.length.toLocaleString('ru-RU')} строк`}
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{sheet === 'FORM_3' ? (
|
|
||||||
<Button variant='contained' onClick={openFilteredProjects} sx={{ ml: 'auto', height: '2.5rem', flexShrink: 0 }}>
|
|
||||||
Перейти к проектам
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button variant='contained' onClick={openFilteredTasks} sx={{ ml: 'auto', height: '2.5rem', flexShrink: 0 }}>
|
|
||||||
Перейти к задачам
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
<Button
|
<Button
|
||||||
variant='outlined'
|
variant='outlined'
|
||||||
color='default'
|
color='default'
|
||||||
startIcon={<RefreshRoundedIcon />}
|
startIcon={<RefreshRoundedIcon />}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={refreshSummary}
|
onClick={refreshSummary}
|
||||||
sx={{ height: '2.5rem', flexShrink: 0 }}>
|
sx={{ ml: 'auto', height: '2.5rem', flexShrink: 0 }}>
|
||||||
Обновить
|
Обновить
|
||||||
</Button>
|
</Button>
|
||||||
</SvodFilters>
|
</SvodFilters>
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { Autocomplete, Box, Button, FormControl, FormLabel, MenuItem, Select, TextField } from '@mui/material';
|
import { Autocomplete, Button, FormControl, FormLabel, MenuItem, Select, TextField } from '@mui/material';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useNavigate } from 'react-router';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { SspApi } from '../../api/ssp';
|
import { SspApi } from '../../api/ssp';
|
||||||
import { TasksApi } from '../../api/tasks';
|
import { TasksApi } from '../../api/tasks';
|
||||||
import { useAuth } from '../../app/context/AuthProvider';
|
import { useAuth } from '../../app/context/AuthProvider';
|
||||||
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
|
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
|
||||||
import { PrimaryButton, PrimaryOutlinedButton } from '../../components/common/Buttons/Buttons';
|
import { PrimaryButton } from '../../components/common/Buttons/Buttons';
|
||||||
import Modal from '../../components/common/Modal/Modal';
|
import Modal from '../../components/common/Modal/Modal';
|
||||||
import { OrgUnitsAutocompletePaper } from '../../components/common/OrgUnitsAutocompletePaper/OrgUnitsAutocompletePaper';
|
import { OrgUnitsAutocompletePaper } from '../../components/common/OrgUnitsAutocompletePaper/OrgUnitsAutocompletePaper';
|
||||||
import { renderOrgUnitValue } from '../../components/common/OrgUnitsAutocompletePaper/renderOrgUnitValue';
|
import { renderOrgUnitValue } from '../../components/common/OrgUnitsAutocompletePaper/renderOrgUnitValue';
|
||||||
@ -14,6 +14,7 @@ import { PaginatedList } from '../../components/common/PaginatedList';
|
|||||||
import { TaskCardComponent } from '../../components/common/TaskCardComponent';
|
import { TaskCardComponent } from '../../components/common/TaskCardComponent';
|
||||||
import { WhitePlus } from '../../components/common/icons/icons';
|
import { WhitePlus } from '../../components/common/icons/icons';
|
||||||
import { FORM_TYPE_OPTIONS, FORM_TYPE_TRANSLATE, ORG_UNIT_TYPE_OPTIONS, ROLES_NAME_ID } from '../../constants/constants';
|
import { FORM_TYPE_OPTIONS, FORM_TYPE_TRANSLATE, ORG_UNIT_TYPE_OPTIONS, ROLES_NAME_ID } from '../../constants/constants';
|
||||||
|
import { exportBulkForms, exportSingleForm } from '../../utils/exportFile';
|
||||||
import { PageContainer } from '../StyledForPage';
|
import { PageContainer } from '../StyledForPage';
|
||||||
|
|
||||||
const modalSelectMenuProps = {
|
const modalSelectMenuProps = {
|
||||||
@ -28,30 +29,19 @@ const modalSelectSx = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function TasksPage() {
|
export default function TasksPage() {
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [items, setItems] = useState([]);
|
const [items, setItems] = useState([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [loadingUpdate, setLoadingUpdate] = useState(false);
|
const [loadingUpdate, setLoadingUpdate] = useState(false);
|
||||||
const [modalOpen, setModalOpen] = useState(false);
|
const [modalOpen, setModalOpen] = useState(false);
|
||||||
|
const [query, setQuery] = useState('');
|
||||||
const yearFilter = searchParams.get('year') || '';
|
|
||||||
const formTypeFilter = searchParams.get('form_type') || '';
|
|
||||||
const orgUnitsFilter = searchParams.get('org_units') || '';
|
|
||||||
const orgUnitIdsFilter = useMemo(
|
|
||||||
() =>
|
|
||||||
orgUnitsFilter
|
|
||||||
.split(',')
|
|
||||||
.filter(Boolean)
|
|
||||||
.map(Number)
|
|
||||||
.filter((value) => Number.isInteger(value) && value > 0),
|
|
||||||
[orgUnitsFilter],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Pagination state
|
// Pagination state
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [limit, setLimit] = useState(20);
|
const [limit, setLimit] = useState(20);
|
||||||
const [totalCount, setTotalCount] = useState(0);
|
const [totalCount, setTotalCount] = useState(0);
|
||||||
|
const [isLoadAll, setisLoadAll] = useState(false);
|
||||||
|
|
||||||
const [sspList, setSspList] = useState([]);
|
const [sspList, setSspList] = useState([]);
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@ -61,13 +51,6 @@ export default function TasksPage() {
|
|||||||
formTypeCode: '',
|
formTypeCode: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const yearOptions = useMemo(() => {
|
|
||||||
const currentYear = new Date().getFullYear();
|
|
||||||
return Array.from({ length: 8 }, (_, index) => currentYear - 5 + index);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const selectedOrgUnits = useMemo(() => sspList.filter((unit) => orgUnitIdsFilter.includes(unit.id)), [sspList, orgUnitIdsFilter]);
|
|
||||||
|
|
||||||
const filteredOrgUnits = useMemo(() => {
|
const filteredOrgUnits = useMemo(() => {
|
||||||
if (!formData.orgUnitType) return [];
|
if (!formData.orgUnitType) return [];
|
||||||
const isSsp = formData.orgUnitType === 'ssp';
|
const isSsp = formData.orgUnitType === 'ssp';
|
||||||
@ -84,18 +67,8 @@ export default function TasksPage() {
|
|||||||
|
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
const updateFilter = (name, value) => {
|
const [exportMode, setExportMode] = useState(false);
|
||||||
setSearchParams((currentParams) => {
|
const [exportList, setExportList] = useState([]);
|
||||||
const nextParams = new URLSearchParams(currentParams);
|
|
||||||
if (value) {
|
|
||||||
nextParams.set(name, value);
|
|
||||||
} else {
|
|
||||||
nextParams.delete(name);
|
|
||||||
}
|
|
||||||
return nextParams;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const openModal = () => {
|
const openModal = () => {
|
||||||
setModalOpen(true);
|
setModalOpen(true);
|
||||||
};
|
};
|
||||||
@ -161,17 +134,14 @@ export default function TasksPage() {
|
|||||||
handleFormChange('org_unit_id', checked ? filteredOrgUnits.map((unit) => unit.id) : []);
|
handleFormChange('org_unit_id', checked ? filteredOrgUnits.map((unit) => unit.id) : []);
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadTasks = useCallback(
|
const loadTasks = async (currentPage = page, currentLimit = limit) => {
|
||||||
async (currentPage, currentLimit) => {
|
if (isLoadAll) return;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const skip = (currentPage - 1) * currentLimit;
|
const skip = (currentPage - 1) * currentLimit;
|
||||||
const params = {
|
const params = {
|
||||||
offset: skip,
|
offset: skip,
|
||||||
limit: currentLimit,
|
limit: currentLimit,
|
||||||
...(yearFilter && { year: Number(yearFilter) }),
|
|
||||||
...(formTypeFilter && { form_type: formTypeFilter }),
|
|
||||||
...(orgUnitIdsFilter.length > 0 && { org_units: orgUnitIdsFilter.join(',') }),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await TasksApi.list(params);
|
const res = await TasksApi.list(params);
|
||||||
@ -179,60 +149,68 @@ export default function TasksPage() {
|
|||||||
|
|
||||||
setItems(data);
|
setItems(data);
|
||||||
setTotalCount(res.count);
|
setTotalCount(res.count);
|
||||||
} catch (_error) {
|
} catch (error) {
|
||||||
toast.error('Ошибка загрузки задач');
|
toast.error('Ошибка загрузки задач');
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
[yearFilter, formTypeFilter, orgUnitIdsFilter],
|
|
||||||
);
|
|
||||||
|
|
||||||
const handlePageChange = (_event, value) => {
|
useEffect(() => {
|
||||||
|
setPage(1);
|
||||||
|
}, [query]);
|
||||||
|
|
||||||
|
const handlePageChange = (event, value) => {
|
||||||
setPage(value);
|
setPage(value);
|
||||||
|
loadTasks(value, limit);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLimitChange = (event) => {
|
const handleLimitChange = (event) => {
|
||||||
const newLimit = event.target.value;
|
const newLimit = event.target.value;
|
||||||
setLimit(newLimit);
|
setLimit(newLimit);
|
||||||
setPage(1);
|
setPage(1);
|
||||||
|
loadTasks(1, newLimit);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!user) return;
|
if (modalOpen) {
|
||||||
if (user.role_id !== ROLES_NAME_ID.admin) {
|
SspApi.getAll({ is_active: true }).then((data) => {
|
||||||
setSspList(user.org_units || []);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SspApi.getAll({ is_active: true })
|
|
||||||
.then((data) => {
|
|
||||||
if (data.result) {
|
if (data.result) {
|
||||||
setSspList(data.result);
|
setSspList(data.result);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.catch(() => toast.error('Ошибка загрузки подразделений'));
|
}
|
||||||
}, [user]);
|
}, [modalOpen]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadTasks(page, limit);
|
loadTasks(page, limit);
|
||||||
}, [page, limit, loadTasks]);
|
}, []);
|
||||||
|
|
||||||
const handleFilterChange = (name, value) => {
|
useEffect(() => {
|
||||||
setPage(1);
|
setExportList([]);
|
||||||
updateFilter(name, value);
|
}, [exportMode]);
|
||||||
|
|
||||||
|
const handleChangeToExportList = (taskId, checked) => {
|
||||||
|
if (checked) {
|
||||||
|
setExportList((prev) => [...prev, taskId]);
|
||||||
|
} else {
|
||||||
|
const newExportList = exportList.filter((t) => t != taskId);
|
||||||
|
setExportList(newExportList);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleClearFilters = () => {
|
const handleBulkExport = async () => {
|
||||||
setPage(1);
|
await exportBulkForms(exportList);
|
||||||
setSearchParams((currentParams) => {
|
setExportMode(false);
|
||||||
const nextParams = new URLSearchParams(currentParams);
|
|
||||||
nextParams.delete('year');
|
|
||||||
nextParams.delete('form_type');
|
|
||||||
nextParams.delete('org_units');
|
|
||||||
return nextParams;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSingleExport = (taskId, taskTitle) => {
|
||||||
|
exportSingleForm(taskId, taskTitle);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate total pages
|
||||||
|
const totalPages = Math.ceil(totalCount / limit);
|
||||||
|
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -264,56 +242,6 @@ export default function TasksPage() {
|
|||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
filterActions={
|
|
||||||
<Box sx={{ display: 'flex', gap: 1.5, flexWrap: 'wrap', alignItems: 'center', minHeight: '2.5rem' }}>
|
|
||||||
<Select
|
|
||||||
size='small'
|
|
||||||
displayEmpty
|
|
||||||
value={yearFilter}
|
|
||||||
onChange={(event) => handleFilterChange('year', event.target.value)}
|
|
||||||
sx={{ width: 130 }}>
|
|
||||||
<MenuItem value=''>Все годы</MenuItem>
|
|
||||||
{yearOptions.map((year) => (
|
|
||||||
<MenuItem key={year} value={year}>
|
|
||||||
{year}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
<Select
|
|
||||||
size='small'
|
|
||||||
displayEmpty
|
|
||||||
value={formTypeFilter}
|
|
||||||
onChange={(event) => handleFilterChange('form_type', event.target.value)}
|
|
||||||
sx={{ width: 210 }}>
|
|
||||||
<MenuItem value=''>Все формы</MenuItem>
|
|
||||||
{FORM_TYPE_OPTIONS.map((formType) => (
|
|
||||||
<MenuItem key={formType} value={formType}>
|
|
||||||
{FORM_TYPE_TRANSLATE[formType]}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
|
|
||||||
<Autocomplete
|
|
||||||
multiple
|
|
||||||
size='small'
|
|
||||||
options={sspList}
|
|
||||||
disableCloseOnSelect
|
|
||||||
noOptionsText='Не найдено'
|
|
||||||
getOptionLabel={(option) => option.title || ''}
|
|
||||||
isOptionEqualToValue={(option, value) => option.id === value.id}
|
|
||||||
value={selectedOrgUnits}
|
|
||||||
onChange={(_event, newValue) => handleFilterChange('org_units', newValue.map((unit) => unit.id).join(','))}
|
|
||||||
renderValue={renderOrgUnitValue}
|
|
||||||
renderInput={(params) => <TextField {...params} placeholder={selectedOrgUnits.length ? '' : 'Все подразделения'} />}
|
|
||||||
sx={{ width: 480, maxWidth: '100%' }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<PrimaryOutlinedButton onClick={handleClearFilters} sx={{ height: '2.5rem' }}>
|
|
||||||
Сбросить
|
|
||||||
</PrimaryOutlinedButton>
|
|
||||||
</Box>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
<Modal
|
<Modal
|
||||||
@ -398,7 +326,7 @@ export default function TasksPage() {
|
|||||||
isOptionEqualToValue={(option, value) => option.id === value.id}
|
isOptionEqualToValue={(option, value) => option.id === value.id}
|
||||||
renderValue={renderOrgUnitValue}
|
renderValue={renderOrgUnitValue}
|
||||||
value={filteredOrgUnits.filter((ssp) => formData.org_unit_id.includes(ssp.id))}
|
value={filteredOrgUnits.filter((ssp) => formData.org_unit_id.includes(ssp.id))}
|
||||||
onChange={(_event, newValue) => {
|
onChange={(event, newValue) => {
|
||||||
handleFormChange(
|
handleFormChange(
|
||||||
'org_unit_id',
|
'org_unit_id',
|
||||||
newValue.map((ssp) => ssp.id),
|
newValue.map((ssp) => ssp.id),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user