Compare commits

..

No commits in common. "36a534f06fd1ac7b8313b365908d37d28f6360df" and "6e2ba371fe4d01313fc2144204ad0d60bac0157b" have entirely different histories.

7 changed files with 18 additions and 68 deletions

View File

@ -12,14 +12,14 @@ export const DEFAULT_PROJECT_CONFIG = {
defaultValue: null,
min: 0,
step: 1,
required_field: true,
required_field: false,
},
'Тип проекта развития': {
type: 'multiselect',
options: ['Открытие ВСП', 'Закрытие ВСП', 'Переезд ВСП', 'Реновация РФ', 'Открытие УРМ'],
placeholder: 'Выберите тип проекта',
defaultValue: null,
required_field: true,
required_field: false,
},
'Название проекта': {
type: 'text',
@ -29,17 +29,16 @@ export const DEFAULT_PROJECT_CONFIG = {
},
'Формат ВСП': {
type: 'multiselect',
options: ['Флагманский', 'Типовой', 'Розничный', 'МСБ', 'Лёгкий', 'Мини', 'Розничный-киоск', 'МБО', 'Офис самообслуживания', 'Другое'],
options: ['Фланговый', 'Типовой', 'Розничный', 'МСБ', 'Лёгкий', 'Мини', 'Розничный-киоск', 'МБО', 'Офис самообслуживания', 'Другое'],
placeholder: 'Выберите формат ВСП',
defaultValue: null,
required_field: true,
required_field: false,
},
'Адрес объекта': {
type: 'text',
placeholder: 'Введите адрес объекта',
defaultValue: '',
required_field: true,
required_field: false,
},
'Целевая численность, чел.': {
type: 'number',
@ -54,8 +53,7 @@ export const DEFAULT_PROJECT_CONFIG = {
options: ['Собственность', 'Аренда', 'Субаренда'],
placeholder: 'Выберите тип размещения',
defaultValue: null,
required_field: true,
required_field: false,
},
'Площадь размещения, м2': {
type: 'number',

View File

@ -135,7 +135,7 @@ export default function FormPage() {
'Формат ВСП': {
type: 'multiselect',
options: [
'Флагманский',
'Фланговый',
'Типовой',
'Розничный',
'МСБ',

View File

@ -202,13 +202,11 @@ const SummaryPage = () => {
const onEdit = (row) => {
const isSmeta = row.depth > 0;
const parentProject = isSmeta ? row.getParentRow()?.original : row.original;
const projectId = parentProject?.id;
const projectId = isSmeta ? row.getParentRow()?.original?.id : row.original.id;
setSelectedRowData({
...row.original,
_rowType: isSmeta ? 'smeta' : 'project',
_projectId: projectId,
_projectFundingByKoDecision: parentProject?.funding_by_ko_decision,
});
setEditModalOpen(true);
};

View File

@ -1,5 +1,4 @@
import { Box, IconButton, Tooltip } from '@mui/material';
import { differenceInMonths, isValid, parseISO } from 'date-fns';
import { Back, EditPenSvg, TrashSvg } from '../../components/common/icons/icons';
import StatusBadge from './components/StatusBadge/StatusBadge';
import { DEVELOMENT_BLOCK, FUNDING_BY_DECISION } from './constants';
@ -64,19 +63,6 @@ export const createFirstColumns = (handlers) => {
header: 'Дата открытия / переезда / закрытия',
size: 160,
},
{
id: 'project_implementation_months',
accessorFn: (row) => {
if (!Array.isArray(row.sub_rows) || !row.board_decision_date) return null;
const boardDecisionDate = parseISO(row.board_decision_date);
if (!isValid(boardDecisionDate)) return null;
return differenceInMonths(new Date(), boardDecisionDate);
},
header: 'Время реализации проекта в месяцах',
size: 180,
},
{
accessorKey: 'project_type',
header: 'Тип проекта',

View File

@ -4,7 +4,7 @@ import React from 'react';
import { useAuth } from '../../../../app/context/AuthProvider';
import { DangerOutlinedButton, PrimaryButton } from '../../../../components/common/Buttons/Buttons';
import { DEVELOMENT_BLOCK, FUNDING_BY_DECISION } from '../../constants';
import { canEditFirstTableField, hasReserveValuesInChildSmetas, isFirstTableFieldDependencySatisfied } from '../../constants/fieldAccess';
import { canEditFirstTableField, isFirstTableFieldDependencySatisfied } from '../../constants/fieldAccess';
const EditModal = ({ open, onClose, rowData, onSave, isSaving = false, orgUnitNames = {} }) => {
const { user } = useAuth();
@ -80,10 +80,8 @@ const EditModal = ({ open, onClose, rowData, onSave, isSaving = false, orgUnitNa
// Компонент для поля ввода
const renderField = (field) => {
const rawValue = formData[field.key];
const isFundingByDecisionLocked = field.key === 'funding_by_ko_decision' && hasReserveValuesInChildSmetas(formData);
const isFieldDisabled =
field.disabled ||
isFundingByDecisionLocked ||
!canEditFirstTableField(field.key, user?.role_id) ||
!isFirstTableFieldDependencySatisfied(field.key, formData);
const fieldValue = field.valueType === 'boolean' && rawValue !== null && rawValue !== undefined
@ -145,11 +143,6 @@ const EditModal = ({ open, onClose, rowData, onSave, isSaving = false, orgUnitNa
return <MenuItem key={value} value={value}>{label}</MenuItem>;
})]}
</TextField>
{isFundingByDecisionLocked && (
<Typography sx={{ mt: 0.5, color: 'warning.main', fontSize: '0.75rem', lineHeight: 1.4 }}>
Поле нельзя изменить: в одной из дочерних смет заполнено значение «Из резерва Банка в смету ПРРС АХР» или «Из резерва Банка в смету ПРРС КВ».
</Typography>
)}
</Box>
);
};

View File

@ -11,14 +11,14 @@ const ALL_ROLES = [
// Матрица доступа к полям первой таблицы.
export const FIRST_TABLE_FIELD_ACCESS = {
name: ADMIN_ROLES,
org_unit_id: ALL_ROLES,
org_unit_id: ADMIN_ROLES,
status: DFIP_ROLES,
technical_number: [],
object_address: ALL_ROLES,
vsp_format: ALL_ROLES,
placement_type: ALL_ROLES,
staff_count: ALL_ROLES,
total_area: ALL_ROLES,
placement_type: ADMIN_ROLES,
staff_count: ADMIN_ROLES,
total_area: ADMIN_ROLES,
project_type: ALL_ROLES,
krf_decision_date: ALL_ROLES,
fk_decision_date: ALL_ROLES,
@ -41,33 +41,10 @@ export const FIRST_TABLE_FIELD_DEPENDENCIES = {
board_decision_date: "fk_decision_date",
};
export const FIRST_TABLE_FIELD_VALUE_REQUIREMENTS = {
reserve_to_prrs_ahr: {
fieldKey: "_projectFundingByKoDecision",
value: "bank_reserve",
},
reserve_to_prrs_kv: {
fieldKey: "_projectFundingByKoDecision",
value: "bank_reserve",
},
};
export const canEditFirstTableField = (fieldKey, roleId) =>
FIRST_TABLE_FIELD_ACCESS[fieldKey]?.includes(roleId) ?? false;
const isFilled = (value) => value !== null && value !== undefined && value !== "";
export const hasReserveValuesInChildSmetas = (project) =>
(project?.sub_rows || []).some(
(smeta) => isFilled(smeta.reserve_to_prrs_ahr) || isFilled(smeta.reserve_to_prrs_kv),
);
export const isFirstTableFieldDependencySatisfied = (fieldKey, rowData) => {
const dependencyKey = FIRST_TABLE_FIELD_DEPENDENCIES[fieldKey];
if (dependencyKey && !rowData?.[dependencyKey]) return false;
const valueRequirement = FIRST_TABLE_FIELD_VALUE_REQUIREMENTS[fieldKey];
if (valueRequirement && rowData?.[valueRequirement.fieldKey] !== valueRequirement.value) return false;
return true;
return !dependencyKey || Boolean(rowData?.[dependencyKey]);
};

View File

@ -120,7 +120,7 @@ export const ModalCreateProject = ({
switch (config.type) {
case 'multiselect':
return (
<Box key={fieldName} sx={{ mb: hasError ? '0.5rem' : 0 }}>
<Box key={fieldName}>
<Typography
className='gray-color'
sx={{
@ -159,7 +159,7 @@ export const ModalCreateProject = ({
case 'text':
return (
<Box key={fieldName} sx={{ mb: hasError ? '0.5rem' : 0 }}>
<Box key={fieldName}>
<Typography
className='gray-color'
sx={{
@ -191,7 +191,7 @@ export const ModalCreateProject = ({
case 'number':
return (
<Box key={fieldName} sx={{ mb: hasError ? '0.5rem' : 0 }}>
<Box key={fieldName}>
<Typography
className='gray-color'
sx={{
@ -264,10 +264,8 @@ export const ModalCreateProject = ({
flexDirection: 'column',
gap: '1.25rem',
'& .sameSize': {
minWidth: '39.75rem',
},
'& .sameSize.MuiInputBase-root, & .sameSize .MuiInputBase-root': {
height: '2.69rem',
minWidth: '39.75rem',
},
'& .gray-color': { color: '#4A5565' },
}}>