Compare commits
No commits in common. "8a280781bb421f6a6215b456ac0fc4c0b392b387" and "bdb4c389ce6044f772ddee3d4078751c2da67cbc" have entirely different histories.
8a280781bb
...
bdb4c389ce
@ -2,11 +2,8 @@
|
||||
import { useEffect, useRef, useLayoutEffect, useState } from 'react';
|
||||
import { isFormula, extractFormula, calculateFormula, formatNumber } from '../../utils/formulaUtils';
|
||||
import { saveToStorage, loadFromStorage } from '../../utils/localStorageUtils';
|
||||
import { useRealtime } from '../../contexts/RealtimeContext';
|
||||
|
||||
const EditCell = ({ refCell, onChange, disabled, value, tableId, cellId, table }) => {
|
||||
const { endEditing: contextEndEditing } = useRealtime();
|
||||
|
||||
const EditCell = ({ refCell, onChange, disabled, value, tableId, cellId }) => {
|
||||
const [curValue, setCurValue] = useState(value);
|
||||
const [displayValue, setDisplayValue] = useState(value);
|
||||
const [isFormulaMode, setIsFormulaMode] = useState(false);
|
||||
@ -72,6 +69,7 @@ const EditCell = ({ refCell, onChange, disabled, value, tableId, cellId, table }
|
||||
if (isFormula(curValue)) {
|
||||
// Сохраняем формулу в localStorage
|
||||
saveToStorage(storageKey, curValue);
|
||||
|
||||
// Вычисляем и сохраняем результат
|
||||
try {
|
||||
const formula = extractFormula(curValue);
|
||||
@ -110,32 +108,6 @@ const EditCell = ({ refCell, onChange, disabled, value, tableId, cellId, table }
|
||||
return displayValue;
|
||||
};
|
||||
|
||||
const finishEditing = () => {
|
||||
if (!disabled) {
|
||||
handleSave();
|
||||
}
|
||||
const editingCell = table.getState().editingCell || null;
|
||||
if (editingCell) {
|
||||
contextEndEditing?.(editingCell.row, editingCell.column);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
// Проверяем, был ли клик внутри элемента редактирования
|
||||
const editElement = ref.current;
|
||||
if (editElement && !editElement.contains(event.target)) {
|
||||
finishEditing();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, [ref, finishEditing]);
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
@ -178,10 +150,16 @@ const EditCell = ({ refCell, onChange, disabled, value, tableId, cellId, table }
|
||||
}}
|
||||
onChange={handleChangeValue}
|
||||
value={curValue}
|
||||
onBlur={handleSave}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
finishEditing();
|
||||
handleSave();
|
||||
// Закрываем редактирование
|
||||
if (onChange) {
|
||||
// Симулируем завершение редактирования
|
||||
document.activeElement?.blur();
|
||||
}
|
||||
}
|
||||
}}
|
||||
placeholder={isFormulaMode ? 'Введите формулу (начинается с =)' : ''}
|
||||
|
||||
@ -63,6 +63,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
addRow: contextAddRow,
|
||||
deleteRow: contextDeleteRow,
|
||||
startEditing: contextStartEditing,
|
||||
endEditing: contextEndEditing,
|
||||
} = useRealtime();
|
||||
|
||||
const {
|
||||
@ -179,6 +180,8 @@ const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
|
||||
if (cell) {
|
||||
if (editingCell) return;
|
||||
contextStartEditing?.(cell.row, cell.column);
|
||||
} else {
|
||||
contextEndEditing?.(editingCell.row, editingCell.column);
|
||||
}
|
||||
},
|
||||
columnVirtualizerOptions: ({ table }) => ({
|
||||
|
||||
@ -126,7 +126,8 @@ const SettingPanel = ({
|
||||
</Tooltip>
|
||||
</GroupByObject>
|
||||
|
||||
{!isProject &&
|
||||
|
||||
{!isProject ??
|
||||
<>
|
||||
<Divider orientation="vertical" flexItem />
|
||||
<GroupByObject title="Строки">
|
||||
|
||||
@ -3,7 +3,6 @@ import { createPortal } from 'react-dom';
|
||||
import { columns as mockColumns } from '../../mocks/mockTable';
|
||||
import { config } from './constants/FORM_2/AHR';
|
||||
import { useParams } from 'react-router';
|
||||
import { useRealtime } from './contexts/RealtimeContext';
|
||||
|
||||
function EditCellPortal({
|
||||
cell,
|
||||
@ -21,8 +20,6 @@ function EditCellPortal({
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const isDisabled = false;
|
||||
|
||||
const { endEditing: contextEndEditing } = useRealtime();
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current) {
|
||||
const tbodyRef = ref.current.offsetParent?.offsetParent?.offsetParent;
|
||||
@ -71,7 +68,6 @@ function EditCellPortal({
|
||||
disabled={!isEditable}
|
||||
onChange={handleChange}
|
||||
tableId={tableKey}
|
||||
table={table}
|
||||
cellId={cell.row.id + '_' + cell.column.id}
|
||||
/>,
|
||||
refTbody,
|
||||
|
||||
@ -12,7 +12,7 @@ export const DEFAULT_PROJECT_CONFIG = {
|
||||
defaultValue: null,
|
||||
min: 0,
|
||||
step: 1,
|
||||
required_field: false,
|
||||
required_field: true,
|
||||
},
|
||||
'Тип проекта развития': {
|
||||
type: 'multiselect',
|
||||
|
||||
@ -12,8 +12,8 @@ export const EVENT_CONFIGS = {
|
||||
format: 'Утвержденный формат',
|
||||
opened_at: 'Дата открытия ВСП',
|
||||
notes: 'Примечания',
|
||||
placement_type: 'Форма расположения ВСП',
|
||||
staff_count: 'Штатная численность ВСП',
|
||||
location_form: 'Форма расположения ВСП',
|
||||
numbers: 'Штатная численность ВСП',
|
||||
total_area: 'Площадь помещений ВСП',
|
||||
rent_contract_num: 'Номер договора аренды',
|
||||
rent_end_date: 'Срок окончания договора аренды',
|
||||
@ -21,6 +21,8 @@ export const EVENT_CONFIGS = {
|
||||
branch_name: 'Региональный филиал ',
|
||||
closed_at: 'Дата закрытия ВСП',
|
||||
user_email: 'Почта пользователя',
|
||||
staff_count: 'Кол-во работников',
|
||||
placement_type: 'Тип размещение',
|
||||
is_active: 'Активный',
|
||||
},
|
||||
VSP_UPDATE: {
|
||||
@ -30,8 +32,8 @@ export const EVENT_CONFIGS = {
|
||||
format: 'Утвержденный формат',
|
||||
opened_at: 'Дата открытия ВСП',
|
||||
notes: 'Примечания',
|
||||
placement_type: 'Форма расположения ВСП',
|
||||
staff_count: 'Штатная численность ВСП',
|
||||
location_form: 'Форма расположения ВСП',
|
||||
numbers: 'Штатная численность ВСП',
|
||||
total_area: 'Площадь помещений ВСП',
|
||||
rent_contract_num: 'Номер договора аренды',
|
||||
rent_end_date: 'Срок окончания договора аренды',
|
||||
@ -39,6 +41,8 @@ export const EVENT_CONFIGS = {
|
||||
'changes.branch_name': 'Региональный филиал ',
|
||||
closed_at: 'Дата закрытия ВСП',
|
||||
user_email: 'Почта пользователя',
|
||||
staff_count: 'Кол-во работников',
|
||||
placement_type: 'Тип размещение',
|
||||
is_active: 'Активный',
|
||||
},
|
||||
USER_ACCESS_GRANTED: {
|
||||
|
||||
@ -43,8 +43,8 @@ const ModalEditAddVsp = ({
|
||||
open_date: null,
|
||||
close_date: null,
|
||||
notes: '',
|
||||
placement_type: '',
|
||||
staff_count: '',
|
||||
location_form: '',
|
||||
numbers: '',
|
||||
area: null,
|
||||
rent_contract_num: '',
|
||||
rent_end_date: null,
|
||||
@ -94,8 +94,8 @@ const ModalEditAddVsp = ({
|
||||
? new Date(initialData.close_date)
|
||||
: null,
|
||||
notes: initialData.notes || '',
|
||||
placement_type: initialData.placement_type || '',
|
||||
staff_count: initialData.staff_count?.toString() || '',
|
||||
location_form: initialData.location_form || '',
|
||||
numbers: initialData.staff_count?.toString() || '',
|
||||
area: initialData.area || null,
|
||||
rent_contract_num: initialData.rent_contract_num || '',
|
||||
rent_end_date: initialData.rent_end_date
|
||||
@ -114,8 +114,8 @@ const ModalEditAddVsp = ({
|
||||
open_date: null,
|
||||
close_date: null,
|
||||
notes: '',
|
||||
placement_type: '',
|
||||
staff_count: '',
|
||||
location_form: '',
|
||||
numbers: '',
|
||||
area: null,
|
||||
rent_contract_num: '',
|
||||
rent_end_date: null,
|
||||
@ -215,7 +215,7 @@ const ModalEditAddVsp = ({
|
||||
|
||||
const submitData = {
|
||||
...formData,
|
||||
staff_count: formData.staff_count ? parseInt(formData.staff_count, 10) : null,
|
||||
numbers: formData.staff_count ? parseInt(formData.staff_count, 10) : null,
|
||||
area: formData.area ? parseFloat(formData.area) : null,
|
||||
open_date: formData.open_date
|
||||
? formData.open_date.toLocaleDateString('en-CA')
|
||||
@ -255,8 +255,8 @@ const ModalEditAddVsp = ({
|
||||
open_date: null,
|
||||
close_date: null,
|
||||
notes: '',
|
||||
placement_type: '',
|
||||
staff_count: '',
|
||||
location_form: '',
|
||||
numbers: '',
|
||||
area: '',
|
||||
rent_contract_num: '',
|
||||
rent_end_date: null,
|
||||
@ -461,11 +461,11 @@ const ModalEditAddVsp = ({
|
||||
<FieldLabel>Форма расположения ВСП</FieldLabel>
|
||||
<StyledTextField
|
||||
select
|
||||
value={formData.placement_type}
|
||||
onChange={handleChange('placement_type')}
|
||||
value={formData.location_form}
|
||||
onChange={handleChange('location_form')}
|
||||
placeholder="Выберите форму расположения"
|
||||
error={!!errors.placement_type}
|
||||
helperText={errors.placement_type}
|
||||
error={!!errors.location_form}
|
||||
helperText={errors.location_form}
|
||||
disabled={loading}
|
||||
slotProps={{
|
||||
select: {
|
||||
@ -496,7 +496,7 @@ const ModalEditAddVsp = ({
|
||||
<StyledTextField
|
||||
type="text"
|
||||
value={formData.staff_count}
|
||||
onChange={handleNumberChange('staff_count')}
|
||||
onChange={handleNumberChange('numbers')}
|
||||
placeholder="Введите численность"
|
||||
error={!!errors.staff_count}
|
||||
helperText={errors.staff_count}
|
||||
|
||||
@ -192,7 +192,7 @@ const TableDictVsp = ({
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
accessorKey: 'placement_type',
|
||||
accessorKey: 'location_form',
|
||||
header: 'Форма расположения ВСП',
|
||||
size: 170,
|
||||
minSize: 140,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
// src/components/common/ProjectCardComponent/ModalCreateProject.jsx
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Box, Button, Divider, TextField, Typography } from '@mui/material';
|
||||
import SelectWithOptions from '../AdminPanel/components/SelectWithOptions';
|
||||
@ -10,41 +11,43 @@ export const ModalCreateProject = ({
|
||||
onCreate,
|
||||
config = {},
|
||||
initialData = null,
|
||||
title = 'Создание проекта',
|
||||
buttonText = 'Создать',
|
||||
isEdit = false,
|
||||
projectId = null,
|
||||
}) => {
|
||||
const [projectData, setProjectData] = useState(() => {
|
||||
// Если есть initialData, используем её, иначе создаем из конфига
|
||||
if (initialData) {
|
||||
return { ...initialData };
|
||||
}
|
||||
// Иначе создаем из конфига
|
||||
const data = {};
|
||||
const initial = {};
|
||||
Object.keys(config).forEach((key) => {
|
||||
data[key] = config[key].defaultValue;
|
||||
initial[key] = config[key].defaultValue;
|
||||
});
|
||||
return data;
|
||||
return initial;
|
||||
});
|
||||
|
||||
const [errors, setErrors] = useState({});
|
||||
|
||||
// Обновляем данные при изменении initialData
|
||||
useEffect(() => {
|
||||
if (initialData) {
|
||||
setProjectData({ ...initialData });
|
||||
} else {
|
||||
const data = {};
|
||||
const initial = {};
|
||||
Object.keys(config).forEach((key) => {
|
||||
data[key] = config[key].defaultValue;
|
||||
initial[key] = config[key].defaultValue;
|
||||
});
|
||||
setProjectData(data);
|
||||
setProjectData(initial);
|
||||
}
|
||||
setErrors({});
|
||||
}, [initialData, config, open]);
|
||||
}, [initialData, config]);
|
||||
|
||||
const handleChange = (field, value) => {
|
||||
setProjectData((prev) => ({
|
||||
...prev,
|
||||
[field]: value,
|
||||
}));
|
||||
// Очищаем ошибку для поля при изменении
|
||||
if (errors[field]) {
|
||||
setErrors((prev) => ({
|
||||
...prev,
|
||||
@ -57,6 +60,7 @@ export const ModalCreateProject = ({
|
||||
if (config.required_field) {
|
||||
const value = projectData[fieldName];
|
||||
|
||||
// Проверка для разных типов полей
|
||||
if (config.type === 'multiselect') {
|
||||
if (!value || (Array.isArray(value) && value.length === 0) || value === '') {
|
||||
return `Поле "${fieldName}" обязательно для заполнения`;
|
||||
@ -69,9 +73,11 @@ export const ModalCreateProject = ({
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return `Поле "${fieldName}" обязательно для заполнения`;
|
||||
}
|
||||
// Проверка на минимальное значение
|
||||
if (config.min !== undefined && Number(value) < config.min) {
|
||||
return `Значение должно быть не меньше ${config.min}`;
|
||||
}
|
||||
// Проверка на максимальное значение
|
||||
if (config.max !== undefined && Number(value) > config.max) {
|
||||
return `Значение должно быть не больше ${config.max}`;
|
||||
}
|
||||
@ -99,7 +105,7 @@ export const ModalCreateProject = ({
|
||||
const handleClickCreate = () => {
|
||||
if (validateAllFields()) {
|
||||
onCreate(projectData);
|
||||
onClose();
|
||||
// Не закрываем модалку здесь, пусть это делает родительский компонент
|
||||
}
|
||||
};
|
||||
|
||||
@ -219,6 +225,7 @@ export const ModalCreateProject = ({
|
||||
value={projectData[fieldName] || ''}
|
||||
onChange={(e) => {
|
||||
const inputValue = e.target.value;
|
||||
//только числа
|
||||
const isValidInput =
|
||||
/^\d*\.?\d*$/.test(inputValue) || inputValue === '';
|
||||
if (isValidInput) {
|
||||
@ -253,7 +260,7 @@ export const ModalCreateProject = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={title}
|
||||
title={isEdit ? 'Редактирование проекта' : 'Создание проекта'}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
customSize={'43.75'}
|
||||
@ -271,7 +278,7 @@ export const ModalCreateProject = ({
|
||||
onClick={handleClickCreate}
|
||||
style={{ height: '2.5rem' }}
|
||||
>
|
||||
{buttonText}
|
||||
{isEdit ? 'Сохранить' : 'Создать'}
|
||||
</PrimaryButton>
|
||||
</>
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ export const ProjectCardComponent = ({
|
||||
id,
|
||||
name,
|
||||
org_unit_name,
|
||||
years,
|
||||
year,
|
||||
status,
|
||||
level,
|
||||
project_type,
|
||||
@ -180,7 +180,7 @@ export const ProjectCardComponent = ({
|
||||
const prepareProjectDataForEdit = () => {
|
||||
return {
|
||||
'ССП/РФ': project.org_unit_id || null,
|
||||
'Год': years || null,
|
||||
'Год': year || null,
|
||||
'Тип проекта развития': project_type || null,
|
||||
'Название проекта': currentName,
|
||||
'Формат ВСП': vsp_format || null,
|
||||
@ -316,7 +316,7 @@ export const ProjectCardComponent = ({
|
||||
>
|
||||
<CardBody>
|
||||
<IconWithContent icon={<DateIcon />}>
|
||||
{years.join(', ') || 'Год не указан'}
|
||||
{year || 'Год не указан'}
|
||||
</IconWithContent>
|
||||
<IconWithContent icon={<UserIcon />}>
|
||||
{org_unit_name || 'Организация не указана'}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user