Compare commits

..

2 Commits

Author SHA1 Message Date
PotapovaA
761a435b98 AURORA-1134 2026-06-25 18:54:32 +03:00
PotapovaA
3f9595928e этапы 2026-06-25 11:20:29 +03:00
21 changed files with 250 additions and 105 deletions

View File

@ -1,4 +1,4 @@
import api from './client'; import api from "./client";
export const FormsSheetApi = { export const FormsSheetApi = {
get(formId, sheetName, params) { get(formId, sheetName, params) {
@ -9,7 +9,10 @@ export const FormsSheetApi = {
export(formId, sheetName, params = {}) { export(formId, sheetName, params = {}) {
return api.get(`export/form/${formId}/sheet/${sheetName}`, { return api.get(`export/form/${formId}/sheet/${sheetName}`, {
params, params,
responseType: 'blob', responseType: "blob",
}); });
}, },
getExpenseItem(itemId) {
return api.get(`/expense-item/${itemId}`).then((r) => r.data);
},
}; };

View File

@ -5,13 +5,10 @@ export const StagesApi = {
return api.post(`/stages/form/${formId}`, payload).then((r) => r.data); return api.post(`/stages/form/${formId}`, payload).then((r) => r.data);
}, },
updateStage(payload) { updateStage(payload) {
const { budget_form_id, sheet, phase_code, opens_at, closes_at } = payload; const { budget_form_id, sheet, phase_code } = payload;
return api return api
.patch(`/stages/form/${budget_form_id}/${sheet}/${phase_code}`, { .patch(`/stages/form/${budget_form_id}/${sheet}/${phase_code}`, payload)
opens_at,
closes_at,
})
.then((r) => r.data); .then((r) => r.data);
}, },
deleteStage(formId, sheet, phaseCode) { deleteStage(formId, sheet, phaseCode) {

View File

@ -151,7 +151,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
if (isPinned) { if (isPinned) {
const colId = table.getState().columnPinning.left[index]; const colId = table.getState().columnPinning.left[index];
const column = table.getColumn(colId); const column = table.getColumn(colId);
return column.columnDef.size; return column?.getSize() ?? 150;
} }
const allCols = [...table.getLeftVisibleLeafColumns(), ...table.getCenterVisibleLeafColumns()] const allCols = [...table.getLeftVisibleLeafColumns(), ...table.getCenterVisibleLeafColumns()]
return allCols[index]?.getSize() ?? 150; return allCols[index]?.getSize() ?? 150;
@ -243,7 +243,6 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
toast.error('Ошибка редактирования ячейки'); toast.error('Ошибка редактирования ячейки');
} }
}, [dataEditingCells, editingCell]); }, [dataEditingCells, editingCell]);
console.log(editingCell)
useEffect(() => { useEffect(() => {
if (table && data && columns.length !== 0) { if (table && data && columns.length !== 0) {

View File

@ -55,17 +55,9 @@ export const AddStagesModal = ({
try { try {
const { config } = await import(`../RealtimeTable/constants/${formType}/${sheetObj.sheet}.js`); const { config } = await import(`../RealtimeTable/constants/${formType}/${sheetObj.sheet}.js`);
setColumnsConfig(config.config); setColumnsConfig(config.config);
// Если есть сохраненные выбранные колонки для этого листа
if (stage?.column_keys) {
setSelectedColumns(stage.column_keys);
} else {
setSelectedColumns([]);
}
} catch (error) { } catch (error) {
console.error(`Failed to load config for ${formType}/${selectedSheet}:`, error); console.error(`Failed to load config for ${formType}/${selectedSheet}:`, error);
setColumnsConfig({ columns: [], colors: {} }); setColumnsConfig({ columns: [], colors: {} });
setSelectedColumns([]);
} }
}; };
@ -79,10 +71,7 @@ export const AddStagesModal = ({
setStageName(stage.phase_code ?? ''); setStageName(stage.phase_code ?? '');
setSelectedSheet(stage.sheet ?? null); setSelectedSheet(stage.sheet ?? null);
setSelectedRole(stage.role ?? null); setSelectedRole(stage.role ?? null);
if (stage.column_keys) {
setSelectedColumns(stage.column_keys.map(c => 'data.' + c)); setSelectedColumns(stage.column_keys.map(c => 'data.' + c));
}
} else { } else {
setStartDate(null); setStartDate(null);
setEndDate(null); setEndDate(null);
@ -201,6 +190,7 @@ export const AddStagesModal = ({
placeholder="Введите название этапа" placeholder="Введите название этапа"
fullWidth fullWidth
size="small" size="small"
disabled={stage !== null}
/> />
</FormControl> </FormControl>
</Stack> </Stack>

View File

@ -26,7 +26,7 @@ import { formatDate } from '../../utils/formatDate';
import { IconWithContent } from './IconWithContent'; import { IconWithContent } from './IconWithContent';
import { Chip } from '../styles/StyledChip'; import { Chip } from '../styles/StyledChip';
import { ExportButton } from '../common/Buttons/ButtonsActions'; import { ExportButton } from '../common/Buttons/ButtonsActions';
import { FROM_TYPE_TRANSLATE } from '../../constants'; import { FORM_TYPE_TRANSLATE } from '../../constants';
const TaskCard = styled.div` const TaskCard = styled.div`
width: 26.8rem; width: 26.8rem;
@ -100,7 +100,7 @@ export const TaskCardComponent = ({
const [isEditModalOpen, setEditModalOpen] = useState(false); const [isEditModalOpen, setEditModalOpen] = useState(false);
const [editedTitle, setEditedTitle] = useState(''); const [editedTitle, setEditedTitle] = useState('');
const [currentTitle, setCurrentTitle] = useState(FROM_TYPE_TRANSLATE[form_type_code] ||''); const [currentTitle, setCurrentTitle] = useState(FORM_TYPE_TRANSLATE[form_type_code] ||'');
const [isChecked, setIsChecked] = useState(false); const [isChecked, setIsChecked] = useState(false);
useEffect(() => { useEffect(() => {

View File

@ -36,7 +36,7 @@ export const EDIT_ACCESS_RUSSIAN = {
}; };
export const FORM_TYPE_OPTIONS = ['FORM_1', 'FORM_2', 'FORM_3', 'FORM_4']; export const FORM_TYPE_OPTIONS = ['FORM_1', 'FORM_2', 'FORM_3', 'FORM_4'];
export const FROM_TYPE_TRANSLATE = { 'FORM_1': 'Смета ССП', 'FORM_2': 'Смета РФ', 'FORM_3': 'Программа развитие ПРРС', 'FORM_4': 'Проектная деятельность' }; export const FORM_TYPE_TRANSLATE = { 'FORM_1': 'Смета ССП', 'FORM_2': 'Смета РФ', 'FORM_3': 'Программа развитие ПРРС', 'FORM_4': 'Проектная деятельность' };
export const DIRECTION_TRANSLATE = { 'Support': 'Поддержка', 'Development': 'Развитие' }; export const DIRECTION_TRANSLATE = { 'Support': 'Поддержка', 'Development': 'Развитие' };
export const ORG_UNIT_TYPE_OPTIONS = [ export const ORG_UNIT_TYPE_OPTIONS = [

View File

@ -70,7 +70,7 @@ const AuditLogsPage = () => {
limit: rowsPerPage, limit: rowsPerPage,
user_id: selectedUser?.id, user_id: selectedUser?.id,
org_unit_id: selectedSsp?.id, org_unit_id: selectedSsp?.id,
event_type: selectedEventType?.id, event: selectedEventType?.id,
date_from: dateFrom ? dateFrom.toISOString() : undefined, date_from: dateFrom ? dateFrom.toISOString() : undefined,
date_to: dateTo ? dateTo.toISOString() : undefined, date_to: dateTo ? dateTo.toISOString() : undefined,
task_id: taskId ? taskId : undefined, task_id: taskId ? taskId : undefined,
@ -137,7 +137,9 @@ const AuditLogsPage = () => {
return ( return (
<PageContainer> <PageContainer>
<HeaderSwitch /> <HeaderSwitch />
<Box display="flex" justifyContent="space-between"> <Box sx={{
display: "flex", justifyContent: "space-between"
}} >
<SwitchUserSsp /> <SwitchUserSsp />
</Box> </Box>

View File

@ -177,32 +177,6 @@ const AuditLogsFilters = ({
spacing={'1rem'} spacing={'1rem'}
sx={{ width: '100%', alignItems: 'end' }} sx={{ width: '100%', alignItems: 'end' }}
> >
<FilterFieldWrapper>
<FormLabelStyled>Поиск по контексту (ID задачи)</FormLabelStyled>
<SearchComponent
style={{
width: '100%',
}}
height={'2.56rem'}
placeholder="Например: #1234"
debounceMs={400}
onChange={onTaskIdChange}
value={taskId}
/>
</FilterFieldWrapper>
<FilterFieldWrapper>
<FormLabelStyled>Поиск по контексту (ID формы)</FormLabelStyled>
<SearchComponent
style={{
width: '100%',
}}
height={'2.56rem'}
placeholder="Например: #1234"
debounceMs={400}
onChange={onFormIdChange}
value={formId}
/>
</FilterFieldWrapper>
<DefaultOutlinedButton <DefaultOutlinedButton
onClick={onResetFilters} onClick={onResetFilters}

View File

@ -118,8 +118,7 @@ const AuditLogsTable = ({
size: 250, size: 250,
Cell: ({ row }) => ( Cell: ({ row }) => (
<Typography> <Typography>
{getRussianNamesForType(row.original.action) || {getRussianNamesForType(row.original.action) }
row.original.event_type}
</Typography> </Typography>
), ),
enableColumnActions: false, enableColumnActions: false,

View File

@ -7,7 +7,7 @@ import {
CircularProgress, CircularProgress,
} from '@mui/material'; } from '@mui/material';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { EVENT_CONFIGS } from '../constants/configEvent'; import { EVENT_CONFIGS, EVENT_CONFIGS_MULT_DEPENDENTS } from '../constants/configEvent';
import { VALUE_TRANSFORMERS } from '../utils/transformers'; import { VALUE_TRANSFORMERS } from '../utils/transformers';
const JsonViewModal = ({ open, onClose, jsonData, eventType }) => { const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
@ -36,6 +36,7 @@ const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
async function extractInfo(data, type) { async function extractInfo(data, type) {
data = JSON.parse(data); data = JSON.parse(data);
const config = EVENT_CONFIGS[type] || {}; const config = EVENT_CONFIGS[type] || {};
const configForMultDependents = EVENT_CONFIGS_MULT_DEPENDENTS[type] || {};
const result = {}; const result = {};
// Функция для рекурсивного обхода всех узлов // Функция для рекурсивного обхода всех узлов
@ -46,16 +47,33 @@ const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
const currentPath = path ? `${path}.${key}` : key; const currentPath = path ? `${path}.${key}` : key;
if (config[currentPath] || config[key]) { if (config[currentPath] || config[key]) {
const configKey = config[currentPath] || config[key];
let value = obj[key]; let value = obj[key];
const configKey = config[currentPath] || config[key];
// Применяем преобразование, если есть функция для этого ключа // Применяем преобразование, если есть функция для этого ключа
if (VALUE_TRANSFORMERS[configKey] && value) { if (VALUE_TRANSFORMERS[configKey] && value) {
try {
// Собираем зависимости для трансформера
// По умолчанию передаём только текущее значение
const dependents = [value];
// Если для этого ключа есть дополнительные зависимости (другие поля)
if (configForMultDependents[configKey] || configForMultDependents[configKey]) {
configForMultDependents[configKey].forEach(d => {
// Добавляем значения из зависимых полей (в корне data)
dependents.push(data[d]);
});
}
const transformer = VALUE_TRANSFORMERS[configKey]; const transformer = VALUE_TRANSFORMERS[configKey];
if (transformer.constructor.name === 'AsyncFunction') { if (transformer.constructor.name === 'AsyncFunction') {
value = await transformer(value); value = await transformer(...dependents);
} else { } else {
value = transformer(value); value = transformer(...dependents);
}
} catch (error) {
console.error(`Ошибка в трансформере для ключа "${configKey}":`, error);
value = '—';
} }
} }
@ -69,8 +87,11 @@ const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
} }
} }
// Начинаем обход с основного объекта try {
await traverseAndExtract(data); await traverseAndExtract(data);
} catch (error) {
return JSON.stringify({ error: 'Ошибка при извлечении данных' }, null, 2);
}
return JSON.stringify(result, null, 2); return JSON.stringify(result, null, 2);
} }

View File

@ -1,21 +1,20 @@
export const DEFAULT_ACTIONS = { export const DEFAULT_ACTIONS = {
ROW_CREATE: 'Создание строки', ROW_CREATE: 'Создание строки',
ROW_DELETE: 'Удаление строки', ROW_DELETE: 'Удаление строки',
ACCESS_WINDOW_CHANGE: 'Изменение окна доступа', ACCESS_EXTEND: 'Продление этапа',
ACCESS_EXTEND: 'Расширение доступа', ACCESS_WINDOW_CHANGE: 'Изменение этапа',
USER_ROLE_CHANGE: 'Изменение роли пользователя', USER_ROLE_CHANGE: 'Изменение роли пользователя',
CREATE_TASK: 'Создание задачи', CREATE_TASK: 'Создание задачи',
UPDATE_TASK: 'Обновление задачи', // UPDATE_TASK: 'Обновление задачи', //сейчас нет события
DELETE_TASK: 'Удаление задачи', // DELETE_TASK: 'Удаление задачи',
USER_CREATE: 'Создание пользователя', USER_CREATE: 'Создание пользователя',
LOGIN: 'Вход в систему',
USER_ACCESS_GRANTED: 'Предоставление доступа к ССП/РФ', USER_ACCESS_GRANTED: 'Предоставление доступа к ССП/РФ',
USER_ACCESS_REVOKED: 'Отмена доступа к ССП/РФ', USER_ACCESS_REVOKED: 'Отмена доступа к ССП/РФ',
VSP_CREATE: 'Создание ВСП', VSP_CREATE: 'Создание ВСП',
VSP_UPDATE: 'Обновление ВСП',
}; };
export const ENTITY_RUSSIAN_NAMES = { export const ENTITY_RUSSIAN_NAMES = {
LOGIN: 'Вход в систему',
ROW: 'строки', ROW: 'строки',
PROJECT: 'проекта', PROJECT: 'проекта',
TABLE: 'таблицы', TABLE: 'таблицы',
@ -25,7 +24,8 @@ export const ENTITY_RUSSIAN_NAMES = {
TASK: 'задачи', TASK: 'задачи',
USER_ACCESS: 'доступа к ССП/РФ', USER_ACCESS: 'доступа к ССП/РФ',
USER: 'пользователя', USER: 'пользователя',
ACCESS_WINDOW: 'окна доступа', ACCESS_WINDOW: 'этапа',
ACCESS: 'этапа',
USER_ROLE: 'роли пользователя', USER_ROLE: 'роли пользователя',
VSP: 'ВСП', VSP: 'ВСП',
}; };
@ -38,6 +38,7 @@ export const ACTION_RUSSIAN_NAMES = {
GET: 'Получение', GET: 'Получение',
GRANTED: 'Предоставление', GRANTED: 'Предоставление',
REVOKED: 'Отмена', REVOKED: 'Отмена',
EXTEND: 'Продление',
}; };
export const getRussianNamesForType = (name) => { export const getRussianNamesForType = (name) => {

View File

@ -6,12 +6,11 @@ export const EVENT_CONFIGS = {
entity_id: 'Пользователь', entity_id: 'Пользователь',
}, },
VSP_CREATE: { VSP_CREATE: {
ssp_id: 'Региональный филиал',
reg_number: 'Регистрационный номер ВСП', reg_number: 'Регистрационный номер ВСП',
vsp_type: 'Вид ВСП', vsp_type: 'Вид ВСП',
address: 'Адрес ВСП', address: 'Адрес ВСП',
approved_format: 'Утвержденный формат', format: 'Утвержденный формат',
open_date: 'Дата открытия ВСП', opened_at: 'Дата открытия ВСП',
notes: 'Примечания', notes: 'Примечания',
location_form: 'Форма расположения ВСП', location_form: 'Форма расположения ВСП',
numbers: 'Штатная численность ВСП', numbers: 'Штатная численность ВСП',
@ -22,14 +21,16 @@ export const EVENT_CONFIGS = {
branch_name: 'Региональный филиал ', branch_name: 'Региональный филиал ',
closed_at: 'Дата закрытия ВСП', closed_at: 'Дата закрытия ВСП',
user_email: 'Почта пользователя', user_email: 'Почта пользователя',
staff_count: 'Кол-во работников',
placement_type: 'Тип размещение',
is_active: 'Активный',
}, },
VSP_UPDATE: { VSP_UPDATE: {
ssp_id: 'Региональный филиал',
reg_number: 'Регистрационный номер ВСП', reg_number: 'Регистрационный номер ВСП',
vsp_type: 'Вид ВСП', vsp_type: 'Вид ВСП',
address: 'Адрес ВСП', address: 'Адрес ВСП',
approved_format: 'Утвержденный формат', format: 'Утвержденный формат',
open_date: 'Дата открытия ВСП', opened_at: 'Дата открытия ВСП',
notes: 'Примечания', notes: 'Примечания',
location_form: 'Форма расположения ВСП', location_form: 'Форма расположения ВСП',
numbers: 'Штатная численность ВСП', numbers: 'Штатная численность ВСП',
@ -37,9 +38,12 @@ export const EVENT_CONFIGS = {
rent_contract_num: 'Номер договора аренды', rent_contract_num: 'Номер договора аренды',
rent_end_date: 'Срок окончания договора аренды', rent_end_date: 'Срок окончания договора аренды',
system_code: 'Код РФ', system_code: 'Код РФ',
branch_name: 'Региональный филиал ', 'changes.branch_name': 'Региональный филиал ',
closed_at: 'Дата закрытия ВСП', closed_at: 'Дата закрытия ВСП',
user_email: 'Почта пользователя', user_email: 'Почта пользователя',
staff_count: 'Кол-во работников',
placement_type: 'Тип размещение',
is_active: 'Активный',
}, },
USER_ACCESS_GRANTED: { USER_ACCESS_GRANTED: {
entity_id: 'Пользователь', entity_id: 'Пользователь',
@ -56,11 +60,15 @@ export const EVENT_CONFIGS = {
}, },
ROW_CREATE: { ROW_CREATE: {
sheet: "Лист", sheet: "Лист",
expense_item_id: 'Статья расходов' expense_item_id: 'Статья расходов',
form_id: 'Информация о задаче',
direction: 'Направление',
}, },
ROW_DELETE: { ROW_DELETE: {
sheet: "Лист", sheet: "Лист",
expense_item_id: 'Статья расходов' expense_item_id: 'Статья расходов',
form_id: 'Информация о задаче',
direction: 'Направление',
}, },
PROJECT_CREATE: { PROJECT_CREATE: {
"name": "Название", "name": "Название",
@ -71,5 +79,27 @@ export const EVENT_CONFIGS = {
"name": "Название", "name": "Название",
"year": "Год", "year": "Год",
"org_unit_id": "СПП/РФ", "org_unit_id": "СПП/РФ",
} },
ACCESS_EXTEND: {
form_id: 'Информация о задаче',
closes_at_after: 'Дата закрытия',
closes_at_before: 'Дата открытия',
phase_name: 'Названия этапа',
sheet: "Лист",
},
ACCESS_WINDOW_CHANGE: {
form_id: 'Информация о задаче',
closes_at: 'Дата закрытия',
open_at: 'Дата открытия',
phase_name: 'Названия этапа',
role: 'Для роли',
column_keys: 'Колонки в этапе',
action: 'Действие',
sheet: "Лист",
},
}; };
export const EVENT_CONFIGS_MULT_DEPENDENTS = {
ACCESS_WINDOW_CHANGE: {
'Колонки в этапе': ['form_id', 'sheet']
},
}

View File

@ -1,8 +1,10 @@
import { DictVspApi } from '../../../../api/dict-vsp'; import { DictVspApi } from '../../../../api/dict-vsp';
import { FormsSheetApi } from '../../../../api/form_sheet';
import { FormsApi } from '../../../../api/forms';
import { SspApi } from '../../../../api/ssp'; import { SspApi } from '../../../../api/ssp';
import { TasksApi } from '../../../../api/tasks'; import { TasksApi } from '../../../../api/tasks';
import { UsersApi } from '../../../../api/users'; import { UsersApi } from '../../../../api/users';
import { ROLES_ID_RUSSIAN_NAME, SHEET_NAME } from '../../../../constants'; import { DIRECTION_TRANSLATE, FORM_TYPE_TRANSLATE, ROLES_ID_RUSSIAN_NAME, SHEET_NAME, STAGE_ROLE_RUSSIAN_NAME } from '../../../../constants';
export const VALUE_TRANSFORMERS = { export const VALUE_TRANSFORMERS = {
Роль: transformRole, Роль: transformRole,
@ -14,11 +16,30 @@ export const VALUE_TRANSFORMERS = {
'Создана для СПП/РФ': transformSspsDict, 'Создана для СПП/РФ': transformSspsDict,
'Лист': transformSheet, 'Лист': transformSheet,
'СПП/РФ': transformSsp, 'СПП/РФ': transformSsp,
'Статья расходов': transformExpense,
'Информация о задаче': transformForm,
'Направление': transformDirection,
'Для роли': transformRoleChanges,
'Колонки в этапе': transformColumns,
'Форма': transformFormType,
}; };
export function transformRole(value) { export function transformRole(value) {
return ROLES_ID_RUSSIAN_NAME[value] || 'Роль не найдена'; return ROLES_ID_RUSSIAN_NAME[value] || 'Роль не найдена';
} }
export function transformFormType(value) {
return FORM_TYPE_TRANSLATE[value] || 'Форма не найдена';
}
export function transformRoleChanges(value) {
if (typeof value === 'string') {
return STAGE_ROLE_RUSSIAN_NAME[value]
}
return {
before: STAGE_ROLE_RUSSIAN_NAME[value.before],
after: STAGE_ROLE_RUSSIAN_NAME[value.after],
}
}
export async function transformUser(userId) { export async function transformUser(userId) {
try { try {
@ -83,3 +104,107 @@ export async function transformSspsDict(ssps) {
export function transformSheet(value) { export function transformSheet(value) {
return SHEET_NAME[value] || 'Лист не найден'; return SHEET_NAME[value] || 'Лист не найден';
} }
export async function transformExpense(itemId) {
if (!itemId) {
return 'нет информации'
}
const res = await FormsSheetApi.getExpenseItem(itemId);
const expense = res.result;
return expense.name;
}
export async function transformForm(formId) {
if (!formId) {
return 'нет информации'
}
const res = await FormsApi.getForm(formId);
const form = res.result;
const formInfo = {
'название': FORM_TYPE_TRANSLATE[form.form_type_code],
'ССП/РФ': form.org_unit.title,
'Год': form.year,
}
return formInfo
}
export function transformDirection(direction) {
if (!direction) {
return '-';
}
return DIRECTION_TRANSLATE[direction];
}
export async function transformColumns(cols, formId, sheet) {
if (!formId || !sheet) return cols;
const res = await FormsApi.getForm(formId);
const form = res.result;
const formType = form.form_type_code;
const { config } = await import(`../../../../components/RealtimeTable/constants/${formType}/${sheet}.js`);
const columns = config.config.columns;
function findColumnAndHeaders(columns, targetAccessorKey) {
// Рекурсивная функция для поиска колонки и сбора родителей
function searchRecursively(columnsArray, path = []) {
for (let column of columnsArray) {
// Проверяем текущую колонку
if (column.accessorKey === targetAccessorKey) {
// Нашли целевую колонку, возвращаем путь с заголовками
return {
found: true,
headers: [...path, column.header],
column: column
};
}
// Если у колонки есть вложенные колонки, ищем в них
if (column.columns && Array.isArray(column.columns)) {
const result = searchRecursively(column.columns, [...path, column.header]);
if (result.found) {
return result;
}
}
}
return { found: false };
}
const result = searchRecursively(columns);
if (result.found) {
return {
headers: result.headers,
column: result.column,
path: result.headers.join(' → ')
};
} else {
return {
headers: [],
column: null,
path: null,
error: `Колонка с accessorKey "${targetAccessorKey}" не найдена`
};
}
}
if (Array.isArray(cols)) {
const res = [];
cols.forEach(c => {
res.push(findColumnAndHeaders(columns, "data." + c).path || '');
})
return res;
}
const translateColsAfter = [];
const translateColsBefore = [];
cols.after.forEach(c => {
translateColsAfter.push(findColumnAndHeaders(columns, "data." + c).path || '');
})
cols.before.forEach(c => {
translateColsBefore.push(findColumnAndHeaders(columns, "data." + c).path || '');
})
// Пример использования:
return { after: translateColsAfter, before: translateColsBefore };
}

View File

@ -20,6 +20,10 @@ export const ModalEditUserSsp = ({
const [selectedType, setSelectedType] = useState('rf'); // 'rf' или 'ssp' const [selectedType, setSelectedType] = useState('rf'); // 'rf' или 'ssp'
useEffect(() => { useEffect(() => {
if (!open) {
setCurUser(null);
return;
}
setCurUser(user); setCurUser(user);
try { try {
if (user && user.role_id == ROLES_NAME_ID.executor_rf) { if (user && user.role_id == ROLES_NAME_ID.executor_rf) {
@ -29,7 +33,7 @@ export const ModalEditUserSsp = ({
} catch { } catch {
setSelectedType('rf'); setSelectedType('rf');
} }
}, [user]); }, [user, open]);
useEffect(() => { useEffect(() => {
if (!deps) return; if (!deps) return;
@ -75,14 +79,9 @@ export const ModalEditUserSsp = ({
}, [depsData]); }, [depsData]);
const sspForDfip = useMemo(() => { const sspForDfip = useMemo(() => {
if (!curUser) return []; if (!curUser|| !open) return [];
if (newDepsData.update.length > 0) {
return newDepsData.update.map(
(sId) => deps.filter((dep) => dep.id == sId)[0],
);
}
return curUser.org_units ?? []; return curUser.org_units ?? [];
}, [curUser, deps, newDepsData]); }, [curUser, deps, newDepsData, open]);
const handleTypeChange = (value) => { const handleTypeChange = (value) => {
setSelectedType(value); setSelectedType(value);

View File

@ -359,8 +359,8 @@ export const EditUserModal = ({
customSize={58.13} customSize={58.13}
> >
<FormStack> <FormStack>
<Box display={'flex'} gap={'1.5rem'} flexDirection={'column'}> <Box sx={{ display: 'flex', gap: '1.5rem', flexDirection: 'column' }} >
<Box display={'flex'} gap={'.5rem'} flexDirection={'column'}> <Box sx={{ display: 'flex', gap: '.5rem', flexDirection: 'column' }} >
{renderField('ФИО', 'full_name', editUser.full_name)} {renderField('ФИО', 'full_name', editUser.full_name)}
{renderField('Почта', 'email', editUser.email, 'email')} {renderField('Почта', 'email', editUser.email, 'email')}
</Box> </Box>

View File

@ -105,7 +105,7 @@ export const AutocompleteForChangeOptions = ({
if (option.email) { if (option.email) {
label += ` (${option.email})`; label += ` (${option.email})`;
} }
return label; return label ?? '-';
}} }}
onChange={handleSelect} onChange={handleSelect}
inputValue={inputValue} inputValue={inputValue}

View File

@ -95,7 +95,9 @@ const TableFooter = ({
</FormControl> </FormControl>
</Box> </Box>
<Stack direction="row" spacing={2} alignItems="center"> <Stack sx={{
direction: "row", spacing: 2, alignItems: "center"
}}>
<Pagination <Pagination
count={Math.max(1, totalPages)} count={Math.max(1, totalPages)}
page={page + 1} page={page + 1}

View File

@ -142,7 +142,7 @@ function DictVspPage() {
<DictVspInfo /> <DictVspInfo />
{/* <HeaderSwitch /> */} {/* <HeaderSwitch /> */}
<PageContainer> <PageContainer>
<Stack alignItems={'stretch'} width="100%"> <Stack sx={{ alignItems: 'stretch' }} width="100%">
<Box width="100%"> <Box width="100%">
{user.role_id !== ROLES_NAME_ID.executor_rf && ( {user.role_id !== ROLES_NAME_ID.executor_rf && (
<DictVspFilters <DictVspFilters

View File

@ -106,9 +106,12 @@ function DictsNavigatorPage() {
</FeatureList> </FeatureList>
<PrimaryButton height={'2.75rem'} onClick={handleNavigateToVSP}> <PrimaryButton height={'2.75rem'} onClick={handleNavigateToVSP}>
<Stack <Stack
spacing={'.25rem'} sx={{
direction={'row'} spacing: '.25rem',
alignItems={'center'} direction: 'row',
alignItems: 'center',
}}
> >
<TransitionSvg /> <TransitionSvg />
<p>Открыть справочник объектов</p> <p>Открыть справочник объектов</p>

View File

@ -22,13 +22,13 @@ import { ModalCreateProject } from './ModalCreateProject';
import { ExportWithTextButton } from '../../components/common/Buttons/ButtonsActions'; import { ExportWithTextButton } from '../../components/common/Buttons/ButtonsActions';
import { exportSingleForm } from '../../utils/exportForm'; import { exportSingleForm } from '../../utils/exportForm';
import TablesList from '../../components/common/TableList/TableList'; import TablesList from '../../components/common/TableList/TableList';
import { DIRECTION_TRANSLATE, FROM_TYPE_TRANSLATE, SHEET_NAME } from '../../constants'; import { DIRECTION_TRANSLATE, FORM_TYPE_TRANSLATE, SHEET_NAME } from '../../constants';
const TaskInfo = ({ task }) => { const TaskInfo = ({ task }) => {
const portalContent = ( const portalContent = (
<TaskInfoContainer> <TaskInfoContainer>
<BackButton to="/tasks" /> <BackButton to="/tasks" />
<NameTask>{FROM_TYPE_TRANSLATE[task.form_type_code] || ''}</NameTask> <NameTask>{FORM_TYPE_TRANSLATE[task.form_type_code] || ''}</NameTask>
</TaskInfoContainer> </TaskInfoContainer>
); );

View File

@ -26,7 +26,7 @@ import {
FORM_TYPE_OPTIONS, FORM_TYPE_OPTIONS,
ORG_UNIT_TYPE_OPTIONS, ORG_UNIT_TYPE_OPTIONS,
ROLES_NAME_ID, ROLES_NAME_ID,
FROM_TYPE_TRANSLATE FORM_TYPE_TRANSLATE
} from '../../constants'; } from '../../constants';
import { useAuth } from '../../app/context/AuthProvider'; import { useAuth } from '../../app/context/AuthProvider';
import { SspApi } from '../../api/ssp'; import { SspApi } from '../../api/ssp';
@ -414,7 +414,7 @@ export default function TasksPage() {
onChange={(e) => handleFormChange('formTypeCode', e.target.value)} onChange={(e) => handleFormChange('formTypeCode', e.target.value)}
renderValue={(selected) => renderValue={(selected) =>
selected ? ( selected ? (
FROM_TYPE_TRANSLATE[selected] FORM_TYPE_TRANSLATE[selected]
) : ( ) : (
<span style={{ color: 'rgba(0,0,0,0.6)' }}>Не выбрана</span> <span style={{ color: 'rgba(0,0,0,0.6)' }}>Не выбрана</span>
) )
@ -424,7 +424,7 @@ export default function TasksPage() {
> >
{FORM_TYPE_OPTIONS.map((formType) => ( {FORM_TYPE_OPTIONS.map((formType) => (
<MenuItem key={formType} value={formType}> <MenuItem key={formType} value={formType}>
{FROM_TYPE_TRANSLATE[formType]} {FORM_TYPE_TRANSLATE[formType]}
</MenuItem> </MenuItem>
))} ))}
</Select> </Select>