diff --git a/web/src/api/stages.js b/web/src/api/stages.js
index 8fb0ecd..d680d97 100644
--- a/web/src/api/stages.js
+++ b/web/src/api/stages.js
@@ -5,13 +5,10 @@ export const StagesApi = {
return api.post(`/stages/form/${formId}`, payload).then((r) => r.data);
},
updateStage(payload) {
- const { budget_form_id, sheet, phase_code, opens_at, closes_at } = payload;
+ const { budget_form_id, sheet, phase_code } = payload;
return api
- .patch(`/stages/form/${budget_form_id}/${sheet}/${phase_code}`, {
- opens_at,
- closes_at,
- })
+ .patch(`/stages/form/${budget_form_id}/${sheet}/${phase_code}`, payload)
.then((r) => r.data);
},
deleteStage(formId, sheet, phaseCode) {
diff --git a/web/src/components/Stages/AddStagesModal.jsx b/web/src/components/Stages/AddStagesModal.jsx
index f4ac2ca..4b61bee 100644
--- a/web/src/components/Stages/AddStagesModal.jsx
+++ b/web/src/components/Stages/AddStagesModal.jsx
@@ -55,17 +55,9 @@ export const AddStagesModal = ({
try {
const { config } = await import(`../RealtimeTable/constants/${formType}/${sheetObj.sheet}.js`);
setColumnsConfig(config.config);
-
- // Если есть сохраненные выбранные колонки для этого листа
- if (stage?.column_keys) {
- setSelectedColumns(stage.column_keys);
- } else {
- setSelectedColumns([]);
- }
} catch (error) {
console.error(`Failed to load config for ${formType}/${selectedSheet}:`, error);
setColumnsConfig({ columns: [], colors: {} });
- setSelectedColumns([]);
}
};
@@ -79,10 +71,7 @@ export const AddStagesModal = ({
setStageName(stage.phase_code ?? '');
setSelectedSheet(stage.sheet ?? 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 {
setStartDate(null);
setEndDate(null);
@@ -201,6 +190,7 @@ export const AddStagesModal = ({
placeholder="Введите название этапа"
fullWidth
size="small"
+ disabled={stage !== null}
/>
diff --git a/web/src/components/common/TaskCardComponent.jsx b/web/src/components/common/TaskCardComponent.jsx
index 473a34f..ad629ed 100644
--- a/web/src/components/common/TaskCardComponent.jsx
+++ b/web/src/components/common/TaskCardComponent.jsx
@@ -26,7 +26,7 @@ import { formatDate } from '../../utils/formatDate';
import { IconWithContent } from './IconWithContent';
import { Chip } from '../styles/StyledChip';
import { ExportButton } from '../common/Buttons/ButtonsActions';
-import { FROM_TYPE_TRANSLATE } from '../../constants';
+import { FORM_TYPE_TRANSLATE } from '../../constants';
const TaskCard = styled.div`
width: 26.8rem;
@@ -100,7 +100,7 @@ export const TaskCardComponent = ({
const [isEditModalOpen, setEditModalOpen] = useState(false);
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);
useEffect(() => {
diff --git a/web/src/constants.jsx b/web/src/constants.jsx
index c009ff3..65e8351 100644
--- a/web/src/constants.jsx
+++ b/web/src/constants.jsx
@@ -36,7 +36,7 @@ export const EDIT_ACCESS_RUSSIAN = {
};
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 ORG_UNIT_TYPE_OPTIONS = [
diff --git a/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx b/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx
index ffffcd6..9df17cb 100644
--- a/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx
+++ b/web/src/pages/AdminPanel/AuditLogsPage/AuditLogsPage.jsx
@@ -70,7 +70,7 @@ const AuditLogsPage = () => {
limit: rowsPerPage,
user_id: selectedUser?.id,
org_unit_id: selectedSsp?.id,
- event_type: selectedEventType?.id,
+ event: selectedEventType?.id,
date_from: dateFrom ? dateFrom.toISOString() : undefined,
date_to: dateTo ? dateTo.toISOString() : undefined,
task_id: taskId ? taskId : undefined,
diff --git a/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx b/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx
index 5fd8407..e48d33b 100644
--- a/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx
+++ b/web/src/pages/AdminPanel/AuditLogsPage/components/AuditLogsFilters.jsx
@@ -177,32 +177,6 @@ const AuditLogsFilters = ({
spacing={'1rem'}
sx={{ width: '100%', alignItems: 'end' }}
>
-
- Поиск по контексту (ID задачи)
-
-
-
- Поиск по контексту (ID формы)
-
-
{
@@ -36,6 +36,7 @@ const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
async function extractInfo(data, type) {
data = JSON.parse(data);
const config = EVENT_CONFIGS[type] || {};
+ const configForMultDependents = EVENT_CONFIGS_MULT_DEPENDENTS[type] || {};
const result = {};
// Функция для рекурсивного обхода всех узлов
@@ -46,16 +47,33 @@ const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
const currentPath = path ? `${path}.${key}` : key;
if (config[currentPath] || config[key]) {
- const configKey = config[currentPath] || config[key];
let value = obj[key];
+ const configKey = config[currentPath] || config[key];
// Применяем преобразование, если есть функция для этого ключа
if (VALUE_TRANSFORMERS[configKey] && value) {
- const transformer = VALUE_TRANSFORMERS[configKey];
- if (transformer.constructor.name === 'AsyncFunction') {
- value = await transformer(value);
- } else {
- value = transformer(value);
+ try {
+ // Собираем зависимости для трансформера
+ // По умолчанию передаём только текущее значение
+ const dependents = [value];
+
+ // Если для этого ключа есть дополнительные зависимости (другие поля)
+ if (configForMultDependents[configKey] || configForMultDependents[configKey]) {
+ configForMultDependents[configKey].forEach(d => {
+ // Добавляем значения из зависимых полей (в корне data)
+ dependents.push(data[d]);
+ });
+ }
+
+ const transformer = VALUE_TRANSFORMERS[configKey];
+ if (transformer.constructor.name === 'AsyncFunction') {
+ value = await transformer(...dependents);
+ } else {
+ value = transformer(...dependents);
+ }
+ } catch (error) {
+ console.error(`Ошибка в трансформере для ключа "${configKey}":`, error);
+ value = '—';
}
}
@@ -69,8 +87,11 @@ const JsonViewModal = ({ open, onClose, jsonData, eventType }) => {
}
}
- // Начинаем обход с основного объекта
- await traverseAndExtract(data);
+ try {
+ await traverseAndExtract(data);
+ } catch (error) {
+ return JSON.stringify({ error: 'Ошибка при извлечении данных' }, null, 2);
+ }
return JSON.stringify(result, null, 2);
}
diff --git a/web/src/pages/AdminPanel/AuditLogsPage/constants/auditLogs.jsx b/web/src/pages/AdminPanel/AuditLogsPage/constants/auditLogs.jsx
index a00c098..344a520 100644
--- a/web/src/pages/AdminPanel/AuditLogsPage/constants/auditLogs.jsx
+++ b/web/src/pages/AdminPanel/AuditLogsPage/constants/auditLogs.jsx
@@ -1,16 +1,17 @@
export const DEFAULT_ACTIONS = {
ROW_CREATE: 'Создание строки',
ROW_DELETE: 'Удаление строки',
- ACCESS_EXTEND: 'Расширение доступа',
- ACCESS_WINDOW_CHANGE: 'Изменение окна доступа',
+ ACCESS_EXTEND: 'Продление этапа',
+ ACCESS_WINDOW_CHANGE: 'Изменение этапа',
USER_ROLE_CHANGE: 'Изменение роли пользователя',
CREATE_TASK: 'Создание задачи',
- UPDATE_TASK: 'Обновление задачи',
- DELETE_TASK: 'Удаление задачи',
+ // UPDATE_TASK: 'Обновление задачи', //сейчас нет события
+ // DELETE_TASK: 'Удаление задачи',
USER_CREATE: 'Создание пользователя',
USER_ACCESS_GRANTED: 'Предоставление доступа к ССП/РФ',
USER_ACCESS_REVOKED: 'Отмена доступа к ССП/РФ',
VSP_CREATE: 'Создание ВСП',
+ VSP_UPDATE: 'Обновление ВСП',
};
export const ENTITY_RUSSIAN_NAMES = {
@@ -23,8 +24,8 @@ export const ENTITY_RUSSIAN_NAMES = {
TASK: 'задачи',
USER_ACCESS: 'доступа к ССП/РФ',
USER: 'пользователя',
- ACCESS_WINDOW: 'окна доступа',
- ACCESS: 'окна доступа',
+ ACCESS_WINDOW: 'этапа',
+ ACCESS: 'этапа',
USER_ROLE: 'роли пользователя',
VSP: 'ВСП',
};
@@ -37,7 +38,7 @@ export const ACTION_RUSSIAN_NAMES = {
GET: 'Получение',
GRANTED: 'Предоставление',
REVOKED: 'Отмена',
- EXTEND: 'Расширение',
+ EXTEND: 'Продление',
};
export const getRussianNamesForType = (name) => {
diff --git a/web/src/pages/AdminPanel/AuditLogsPage/constants/configEvent.jsx b/web/src/pages/AdminPanel/AuditLogsPage/constants/configEvent.jsx
index 48b0616..5ded6f4 100644
--- a/web/src/pages/AdminPanel/AuditLogsPage/constants/configEvent.jsx
+++ b/web/src/pages/AdminPanel/AuditLogsPage/constants/configEvent.jsx
@@ -6,12 +6,11 @@ export const EVENT_CONFIGS = {
entity_id: 'Пользователь',
},
VSP_CREATE: {
- ssp_id: 'Региональный филиал',
reg_number: 'Регистрационный номер ВСП',
vsp_type: 'Вид ВСП',
address: 'Адрес ВСП',
- approved_format: 'Утвержденный формат',
- open_date: 'Дата открытия ВСП',
+ format: 'Утвержденный формат',
+ opened_at: 'Дата открытия ВСП',
notes: 'Примечания',
location_form: 'Форма расположения ВСП',
numbers: 'Штатная численность ВСП',
@@ -22,14 +21,16 @@ export const EVENT_CONFIGS = {
branch_name: 'Региональный филиал ',
closed_at: 'Дата закрытия ВСП',
user_email: 'Почта пользователя',
+ staff_count: 'Кол-во работников',
+ placement_type: 'Тип размещение',
+ is_active: 'Активный',
},
VSP_UPDATE: {
- ssp_id: 'Региональный филиал',
reg_number: 'Регистрационный номер ВСП',
vsp_type: 'Вид ВСП',
address: 'Адрес ВСП',
- approved_format: 'Утвержденный формат',
- open_date: 'Дата открытия ВСП',
+ format: 'Утвержденный формат',
+ opened_at: 'Дата открытия ВСП',
notes: 'Примечания',
location_form: 'Форма расположения ВСП',
numbers: 'Штатная численность ВСП',
@@ -37,9 +38,12 @@ export const EVENT_CONFIGS = {
rent_contract_num: 'Номер договора аренды',
rent_end_date: 'Срок окончания договора аренды',
system_code: 'Код РФ',
- branch_name: 'Региональный филиал ',
+ 'changes.branch_name': 'Региональный филиал ',
closed_at: 'Дата закрытия ВСП',
user_email: 'Почта пользователя',
+ staff_count: 'Кол-во работников',
+ placement_type: 'Тип размещение',
+ is_active: 'Активный',
},
USER_ACCESS_GRANTED: {
entity_id: 'Пользователь',
@@ -76,10 +80,26 @@ export const EVENT_CONFIGS = {
"year": "Год",
"org_unit_id": "СПП/РФ",
},
- ACCESS_EXTEND:{
+ ACCESS_EXTEND: {
form_id: 'Информация о задаче',
closes_at_after: 'Дата закрытия',
closes_at_before: 'Дата открытия',
- phase_name: 'Названия этапа'
+ 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']
+ },
+}
\ No newline at end of file
diff --git a/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx b/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx
index e3d123c..ed49884 100644
--- a/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx
+++ b/web/src/pages/AdminPanel/AuditLogsPage/utils/transformers.jsx
@@ -4,7 +4,7 @@ import { FormsApi } from '../../../../api/forms';
import { SspApi } from '../../../../api/ssp';
import { TasksApi } from '../../../../api/tasks';
import { UsersApi } from '../../../../api/users';
-import { DIRECTION_TRANSLATE, FROM_TYPE_TRANSLATE, 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 = {
Роль: transformRole,
@@ -18,12 +18,28 @@ export const VALUE_TRANSFORMERS = {
'СПП/РФ': transformSsp,
'Статья расходов': transformExpense,
'Информация о задаче': transformForm,
- 'Направление': transformDirection
+ 'Направление': transformDirection,
+ 'Для роли': transformRoleChanges,
+ 'Колонки в этапе': transformColumns,
+ 'Форма': transformFormType,
};
export function transformRole(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) {
try {
@@ -105,16 +121,90 @@ export async function transformForm(formId) {
const res = await FormsApi.getForm(formId);
const form = res.result;
const formInfo = {
- 'название': FROM_TYPE_TRANSLATE[form.form_type_code],
+ 'название': FORM_TYPE_TRANSLATE[form.form_type_code],
'ССП/РФ': form.org_unit.title,
'Год': form.year,
}
return formInfo
}
-export function transformDirection(direction){
- if (!direction){
+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 };
}
\ No newline at end of file
diff --git a/web/src/pages/AdminPanel/UsersPage/ModalEditUserSsp.jsx b/web/src/pages/AdminPanel/UsersPage/ModalEditUserSsp.jsx
index 08e2963..1cd01dd 100644
--- a/web/src/pages/AdminPanel/UsersPage/ModalEditUserSsp.jsx
+++ b/web/src/pages/AdminPanel/UsersPage/ModalEditUserSsp.jsx
@@ -20,6 +20,10 @@ export const ModalEditUserSsp = ({
const [selectedType, setSelectedType] = useState('rf'); // 'rf' или 'ssp'
useEffect(() => {
+ if (!open) {
+ setCurUser(null);
+ return;
+ }
setCurUser(user);
try {
if (user && user.role_id == ROLES_NAME_ID.executor_rf) {
@@ -29,7 +33,7 @@ export const ModalEditUserSsp = ({
} catch {
setSelectedType('rf');
}
- }, [user]);
+ }, [user, open]);
useEffect(() => {
if (!deps) return;
@@ -75,14 +79,9 @@ export const ModalEditUserSsp = ({
}, [depsData]);
const sspForDfip = useMemo(() => {
- if (!curUser) return [];
- if (newDepsData.update.length > 0) {
- return newDepsData.update.map(
- (sId) => deps.filter((dep) => dep.id == sId)[0],
- );
- }
+ if (!curUser|| !open) return [];
return curUser.org_units ?? [];
- }, [curUser, deps, newDepsData]);
+ }, [curUser, deps, newDepsData, open]);
const handleTypeChange = (value) => {
setSelectedType(value);
diff --git a/web/src/pages/AdminPanel/UsersPage/UserTable/EditUserModal.jsx b/web/src/pages/AdminPanel/UsersPage/UserTable/EditUserModal.jsx
index ef06a2b..9c32b5c 100644
--- a/web/src/pages/AdminPanel/UsersPage/UserTable/EditUserModal.jsx
+++ b/web/src/pages/AdminPanel/UsersPage/UserTable/EditUserModal.jsx
@@ -359,8 +359,8 @@ export const EditUserModal = ({
customSize={58.13}
>
-
-
+
+
{renderField('ФИО', 'full_name', editUser.full_name)}
{renderField('Почта', 'email', editUser.email, 'email')}
diff --git a/web/src/pages/AdminPanel/components/AutocompleteForChangeOptions.jsx b/web/src/pages/AdminPanel/components/AutocompleteForChangeOptions.jsx
index 217eacc..e9684ff 100644
--- a/web/src/pages/AdminPanel/components/AutocompleteForChangeOptions.jsx
+++ b/web/src/pages/AdminPanel/components/AutocompleteForChangeOptions.jsx
@@ -105,7 +105,7 @@ export const AutocompleteForChangeOptions = ({
if (option.email) {
label += ` (${option.email})`;
}
- return label;
+ return label ?? '-';
}}
onChange={handleSelect}
inputValue={inputValue}
diff --git a/web/src/pages/TaskPage/TaskPage.jsx b/web/src/pages/TaskPage/TaskPage.jsx
index 2993547..ae3fcb7 100644
--- a/web/src/pages/TaskPage/TaskPage.jsx
+++ b/web/src/pages/TaskPage/TaskPage.jsx
@@ -22,13 +22,13 @@ import { ModalCreateProject } from './ModalCreateProject';
import { ExportWithTextButton } from '../../components/common/Buttons/ButtonsActions';
import { exportSingleForm } from '../../utils/exportForm';
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 portalContent = (
- {FROM_TYPE_TRANSLATE[task.form_type_code] || ''}
+ {FORM_TYPE_TRANSLATE[task.form_type_code] || ''}
);
diff --git a/web/src/pages/TasksPage/TasksPage.jsx b/web/src/pages/TasksPage/TasksPage.jsx
index 0a06126..00f8933 100644
--- a/web/src/pages/TasksPage/TasksPage.jsx
+++ b/web/src/pages/TasksPage/TasksPage.jsx
@@ -26,7 +26,7 @@ import {
FORM_TYPE_OPTIONS,
ORG_UNIT_TYPE_OPTIONS,
ROLES_NAME_ID,
- FROM_TYPE_TRANSLATE
+ FORM_TYPE_TRANSLATE
} from '../../constants';
import { useAuth } from '../../app/context/AuthProvider';
import { SspApi } from '../../api/ssp';
@@ -414,7 +414,7 @@ export default function TasksPage() {
onChange={(e) => handleFormChange('formTypeCode', e.target.value)}
renderValue={(selected) =>
selected ? (
- FROM_TYPE_TRANSLATE[selected]
+ FORM_TYPE_TRANSLATE[selected]
) : (
Не выбрана
)
@@ -424,7 +424,7 @@ export default function TasksPage() {
>
{FORM_TYPE_OPTIONS.map((formType) => (
))}