fix: ограничить управление строками и этапами по правам доступа
This commit is contained in:
parent
d66e4fe375
commit
ee3b87c69a
@ -8,7 +8,6 @@ import DictsNavigatorPage from '../pages/DictsNavigatorPage/DictsNavigatorPage.j
|
||||
import FormsPage from '../pages/FormsPage';
|
||||
import LoginPage from '../pages/LoginPage';
|
||||
import NewFormTablePage from '../pages/NewFormTablePage.jsx';
|
||||
import NewTablePage from '../pages/NewTablePage.jsx';
|
||||
import NavigationProjectPage from '../pages/ProjectPages/NavigationProjectPage.jsx';
|
||||
import Svod2Page from '../pages/Svod2Page/Svod2Page.jsx';
|
||||
import { SvodProvider } from '../pages/SvodPage/SvodContext.jsx';
|
||||
@ -52,7 +51,6 @@ export const AppRoutes = () => {
|
||||
<Route path='/admin_panel/audit-log' element={<AuditLogsPage />} />
|
||||
<Route path='/dicts/dict-vsp' element={<DictVspPage />} />
|
||||
<Route path='/dicts-navigator' element={<DictsNavigatorPage />} />
|
||||
<Route path='/new-table' element={<NewTablePage />} />
|
||||
<Route path='/tables-new' element={<TablesTest />} />
|
||||
<Route path='/tables/:form/:sheetName' element={<NewFormTablePage />} />
|
||||
<Route path='/table/form/:formId/form-type/:formType/:sheetName/:direction/:year' element={<NewFormTablePage />} />
|
||||
|
||||
@ -26,6 +26,7 @@ import { getRowId } from './utils/rowUtils';
|
||||
|
||||
import { DictVspApi } from '../../api/dict-vsp';
|
||||
import { useAuth } from '../../app/context/AuthProvider';
|
||||
import { ROLES_NAME_ID } from '../../constants/constants';
|
||||
import { FormsNoCanAddRow } from './constants/formConfig';
|
||||
|
||||
const CONFIG_CACHE = new Map();
|
||||
@ -121,6 +122,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
const [createModalType, setCreateModalType] = useState(null);
|
||||
|
||||
const isFormNoCanAddRow = useMemo(() => FormsNoCanAddRow[formType]?.includes(sheetName) ?? false, [formType, sheetName]);
|
||||
const canModifyRows = userRoleId === ROLES_NAME_ID.admin || columnsCurStage.length > 0;
|
||||
|
||||
const isVspAdditionRow = useMemo(() => {
|
||||
if (!formType || !sheetName) return false;
|
||||
@ -664,6 +666,10 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
}, [getSelectedRow]);
|
||||
|
||||
const handleDeleteRow = useCallback(() => {
|
||||
if (!canModifyRows) {
|
||||
toast.error('Удаление строк недоступно: нет доступных для редактирования столбцов');
|
||||
return;
|
||||
}
|
||||
const row = getSelectedRow();
|
||||
if (!row) {
|
||||
toast.error('Выделите строку для удаления');
|
||||
@ -671,9 +677,13 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
}
|
||||
contextDeleteRow(getRowId(row));
|
||||
setRowSelection({});
|
||||
}, [contextDeleteRow, getSelectedRow]);
|
||||
}, [canModifyRows, contextDeleteRow, getSelectedRow]);
|
||||
|
||||
const addRow = useCallback(() => {
|
||||
if (!canModifyRows) {
|
||||
toast.error('Добавление строк недоступно: нет доступных для редактирования столбцов');
|
||||
return;
|
||||
}
|
||||
if (isVspAdditionRow) {
|
||||
return handleOpenModalSelectVsp();
|
||||
}
|
||||
@ -681,13 +691,21 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
return handleOpenModalSelectExpenseItem();
|
||||
}
|
||||
return handleAddRow();
|
||||
}, [isVspAdditionRow, isAdditionExpenseItem, handleOpenModalSelectVsp, handleAddRow, handleOpenModalSelectExpenseItem]);
|
||||
}, [canModifyRows, isVspAdditionRow, isAdditionExpenseItem, handleOpenModalSelectVsp, handleAddRow, handleOpenModalSelectExpenseItem]);
|
||||
|
||||
const addProgram = useCallback(() => {
|
||||
if (!canModifyRows) {
|
||||
toast.error('Добавление строк недоступно: нет доступных для редактирования столбцов');
|
||||
return;
|
||||
}
|
||||
setCreateModalType('program');
|
||||
}, []);
|
||||
}, [canModifyRows]);
|
||||
|
||||
const addProject = useCallback(() => {
|
||||
if (!canModifyRows) {
|
||||
toast.error('Добавление строк недоступно: нет доступных для редактирования столбцов');
|
||||
return;
|
||||
}
|
||||
const row = getSelectedRow();
|
||||
if (!row) {
|
||||
toast.error('Выделите строку для вставки');
|
||||
@ -698,7 +716,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
return;
|
||||
}
|
||||
setCreateModalType('project');
|
||||
}, [getSelectedRow]);
|
||||
}, [canModifyRows, getSelectedRow]);
|
||||
|
||||
const closeSelectVspModal = useCallback(() => setIsOpenModalSelectVsp(false), []);
|
||||
const closeSelectExpenseItemModal = useCallback(() => setIsOpenModalSelectExpenseItem(false), []);
|
||||
@ -777,6 +795,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
direction={direction}
|
||||
year={year}
|
||||
isFormNoCanAddRow={isFormNoCanAddRow}
|
||||
canModifyRows={canModifyRows}
|
||||
formType={formType}
|
||||
validationErrors={validationErrors}
|
||||
onNavigateToColumn={handleNavigateToColumn}
|
||||
|
||||
@ -90,6 +90,7 @@ const SettingPanel = ({
|
||||
direction,
|
||||
year,
|
||||
isFormNoCanAddRow,
|
||||
canModifyRows,
|
||||
formType,
|
||||
validationErrors = [],
|
||||
onNavigateToColumn,
|
||||
@ -178,7 +179,7 @@ const SettingPanel = ({
|
||||
|
||||
<Divider orientation='vertical' flexItem />
|
||||
<GroupByObject title='Строки'>
|
||||
{!isFormNoCanAddRow && (
|
||||
{!isFormNoCanAddRow && canModifyRows && (
|
||||
<>
|
||||
<Tooltip title='Добавить строку'>
|
||||
<IconButton onClick={onAddRow} variant='outlined' sx={controlSx}>
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import { Box, CircularProgress, Stack } from '@mui/material';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAuth } from '../../app/context/AuthProvider';
|
||||
import { useTaskStages } from '../../hooks/useTaskStages';
|
||||
import { useProjectStages } from '../../hooks/useProjectStages';
|
||||
import { SHEET_NAME } from '../../constants/constants';
|
||||
import { ROLES_NAME_ID, SHEET_NAME } from '../../constants/constants';
|
||||
import { PrimaryButton } from '../common/Buttons/Buttons';
|
||||
import Modal from '../common/Modal/Modal';
|
||||
import { EditContainer } from '../common/Modal/ModalStyled';
|
||||
@ -23,6 +24,8 @@ export const SettingModal = ({
|
||||
formTypeCode = '',
|
||||
sheets,
|
||||
}) => {
|
||||
const { user } = useAuth();
|
||||
const isAdmin = user?.role_id === ROLES_NAME_ID.admin;
|
||||
const taskStages = useTaskStages(taskId);
|
||||
const projectStages = useProjectStages(projectId, year, reportType);
|
||||
const stages = mode === 'project' ? projectStages : taskStages;
|
||||
@ -137,11 +140,13 @@ export const SettingModal = ({
|
||||
<>
|
||||
<Modal open={isOpen} onClose={onClose} title={modalTitle} customSize={50}>
|
||||
<EditContainer style={{ margin: 0 }}>
|
||||
<Stack direction='row' sx={{ width: '100%', justifyContent: 'flex-end' }}>
|
||||
<PrimaryButton onClick={handleAddStage} startIcon={<WhitePlus />}>
|
||||
Добавить этап
|
||||
</PrimaryButton>
|
||||
</Stack>
|
||||
{isAdmin && (
|
||||
<Stack direction='row' sx={{ width: '100%', justifyContent: 'flex-end' }}>
|
||||
<PrimaryButton onClick={handleAddStage} startIcon={<WhitePlus />}>
|
||||
Добавить этап
|
||||
</PrimaryButton>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{stagesInfo.isLoading ? (
|
||||
<Box
|
||||
@ -159,20 +164,22 @@ export const SettingModal = ({
|
||||
onDelete={!isTaskMode ? handleDeleteStage : undefined}
|
||||
/>
|
||||
)}
|
||||
<AddStagesModal
|
||||
isOpen={isAddEditModalOpen}
|
||||
onClose={() => {
|
||||
setIsAddEditModalOpen(false);
|
||||
}}
|
||||
stage={stageForEdit}
|
||||
createStage={createStage}
|
||||
updateStage={updateStage}
|
||||
isTaskMode={isTaskMode}
|
||||
isSaving={isSaving}
|
||||
sheetOptions={sheetOptions}
|
||||
formType={formTypeCode}
|
||||
defaultSheet={mode === 'project' ? reportType : ''}
|
||||
/>
|
||||
{isAdmin && (
|
||||
<AddStagesModal
|
||||
isOpen={isAddEditModalOpen}
|
||||
onClose={() => {
|
||||
setIsAddEditModalOpen(false);
|
||||
}}
|
||||
stage={stageForEdit}
|
||||
createStage={createStage}
|
||||
updateStage={updateStage}
|
||||
isTaskMode={isTaskMode}
|
||||
isSaving={isSaving}
|
||||
sheetOptions={sheetOptions}
|
||||
formType={formTypeCode}
|
||||
defaultSheet={mode === 'project' ? reportType : ''}
|
||||
/>
|
||||
)}
|
||||
{!isTaskMode && (
|
||||
<DeleteStageModal
|
||||
isOpen={isDeleteModalOpen}
|
||||
|
||||
@ -17,7 +17,7 @@ const TableCard = ({ table, onNavigate, action }) => {
|
||||
</div>
|
||||
<SectionTitle>
|
||||
<h2>{table.name}</h2>
|
||||
<h2>{DIRECTION_TRANSLATE[table?.direction]}</h2>
|
||||
<h2>{DIRECTION_TRANSLATE[table?.direction] || ''}</h2>
|
||||
{/* <UsersList>
|
||||
<div className="img-user"></div>
|
||||
</UsersList> */}
|
||||
|
||||
@ -167,14 +167,16 @@ export const EditUserModal = ({ isOpen, onClose, onConfirm, user, onEditSsp }) =
|
||||
variant='outlined'
|
||||
size='small'
|
||||
autoFocus
|
||||
InputProps={{
|
||||
endAdornment: (
|
||||
<InputAdornment position='end'>
|
||||
<IconButton edge='end' onClick={() => toggleEdit(field)} size='small' sx={{ padding: '4px' }}>
|
||||
<EditOutlinedIcon fontSize='small' />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
slotProps={{
|
||||
input: {
|
||||
endAdornment: (
|
||||
<InputAdornment position='end'>
|
||||
<IconButton edge='end' onClick={() => toggleEdit(field)} size='small' sx={{ padding: '4px' }}>
|
||||
<EditOutlinedIcon fontSize='small' />
|
||||
</IconButton>
|
||||
</InputAdornment>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@ -10,7 +10,7 @@ import { DIRECTION_TRANSLATE, SHEET_NAME } from '../constants/constants';
|
||||
const TableInfo = ({ formId, sheetName, direction, isProject = false }) => {
|
||||
const path = (isProject ? '/project/' : '/task/') + formId;
|
||||
const tableName = SHEET_NAME[sheetName] || sheetName;
|
||||
const directionName = DIRECTION_TRANSLATE[direction] || direction;
|
||||
const directionName = DIRECTION_TRANSLATE[direction] || '';
|
||||
const portalContent = (
|
||||
<TaskInfoContainer>
|
||||
<BackButton to={path} />
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
import { createPortal } from 'react-dom';
|
||||
import { TaskInfoContainer } from '../components/common/SwitchFormTask/SwitchFormTask.style';
|
||||
|
||||
import RealtimeTable from '../components/RealtimeTable';
|
||||
|
||||
const TableInfo = () => {
|
||||
const portalContent = (
|
||||
<TaskInfoContainer>
|
||||
{/* <BackButton to={`/task/${table.task_id}`} />
|
||||
<NameTask>{table.name}</NameTask> */}
|
||||
</TaskInfoContainer>
|
||||
);
|
||||
|
||||
const targetElement = document.getElementById('TableInfo');
|
||||
|
||||
if (targetElement) {
|
||||
return createPortal(portalContent, targetElement);
|
||||
}
|
||||
};
|
||||
|
||||
export default function NewTablePage() {
|
||||
return (
|
||||
<>
|
||||
<RealtimeTable />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@ -93,21 +93,23 @@ const TableFilters = ({
|
||||
onBranchChange(newValue || '');
|
||||
}}
|
||||
renderInput={(params) => {
|
||||
const { InputProps, ...rest } = params;
|
||||
return (
|
||||
<TextField
|
||||
{...rest}
|
||||
{...params}
|
||||
placeholder='Региональные филиалы'
|
||||
variant='outlined'
|
||||
size='small'
|
||||
InputProps={{
|
||||
...InputProps,
|
||||
endAdornment: (
|
||||
<>
|
||||
{isLoading && <CircularProgress color='inherit' size={20} />}
|
||||
{InputProps?.endAdornment}
|
||||
</>
|
||||
),
|
||||
slotProps={{
|
||||
...params.slotProps,
|
||||
input: {
|
||||
...params.slotProps.input,
|
||||
endAdornment: (
|
||||
<>
|
||||
{isLoading && <CircularProgress color='inherit' size={20} />}
|
||||
{params.slotProps.input.endAdornment}
|
||||
</>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -85,12 +85,12 @@ export function SvodFilters({
|
||||
onChange({ selectedOrganizations: selectedAll ? [SELECT_ALL_OPTION] : value });
|
||||
}}
|
||||
sx={{ minWidth: '18.75rem', flex: '1 1 22.5rem', maxWidth: '32.5rem' }}
|
||||
renderTags={(value, getTagProps) =>
|
||||
renderValue={(value, getItemProps) =>
|
||||
value
|
||||
.slice(0, 2)
|
||||
.map((option, index) => {
|
||||
const tagProps = getTagProps({ index });
|
||||
return <Chip {...tagProps} key={option.id} label={option.title} size='small' />;
|
||||
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' />] : [])
|
||||
}
|
||||
@ -99,14 +99,17 @@ export function SvodFilters({
|
||||
{...params}
|
||||
label='ССП/РФ'
|
||||
placeholder={selectedOrganizations.length ? '' : emptyOrganizationsPlaceholder}
|
||||
InputProps={{
|
||||
...(params.InputProps || {}),
|
||||
endAdornment: (
|
||||
<>
|
||||
{organizationsLoading && <CircularProgress size='1.125rem' />}
|
||||
{params.InputProps?.endAdornment}
|
||||
</>
|
||||
),
|
||||
slotProps={{
|
||||
...params.slotProps,
|
||||
input: {
|
||||
...params.slotProps.input,
|
||||
endAdornment: (
|
||||
<>
|
||||
{organizationsLoading && <CircularProgress size='1.125rem' />}
|
||||
{params.slotProps.input.endAdornment}
|
||||
</>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@ -117,12 +120,14 @@ export function SvodFilters({
|
||||
onChange={(event) => onChange({ search: event.target.value })}
|
||||
placeholder={searchPlaceholder}
|
||||
sx={{ minWidth: '16.25rem', flex: '1 1 17.5rem', maxWidth: '23.75rem' }}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position='start'>
|
||||
<SearchRoundedIcon sx={{ color: '#99a1af' }} />
|
||||
</InputAdornment>
|
||||
),
|
||||
slotProps={{
|
||||
input: {
|
||||
startAdornment: (
|
||||
<InputAdornment position='start'>
|
||||
<SearchRoundedIcon sx={{ color: '#99a1af' }} />
|
||||
</InputAdornment>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{children}
|
||||
|
||||
@ -44,7 +44,7 @@ const formatValue = (value) => {
|
||||
|
||||
const getShapeForSheet = (sheet) => {
|
||||
const directionShape = { q1: 0, q2: 0, q3: 0, q4: 0, year: 0 };
|
||||
const correctedShape = sheet === 'FORM_4' ? directionShape : { q2: 0, q3: 0, q4: 0 };
|
||||
const correctedShape = { q2: 0, q3: 0, q4: 0 };
|
||||
return {
|
||||
plan: { support: directionShape, development: directionShape, ...(['FORM_1', 'MAIN'].includes(sheet) ? { total_year: 0 } : {}) },
|
||||
approved: { support: directionShape, development: directionShape, ...(['FORM_1', 'MAIN'].includes(sheet) ? { total_year: 0 } : {}) },
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user