Files
magistr/frontend/react/admin/users-service.js
dipatrik10 97bf3cc50a feat: завершить миграцию фронтенда на React (этапы 1-5)
Админка, настройки, логин, кабинеты преподавателя и студента
полностью переведены на React 19 (модель strangler, docs/REACT_MIGRATION.md).

- 15 вкладок админки: lazy-загрузка, общий error boundary, сервисный слой
- Удалены legacy-views и переходный слой LegacyTabView (45 файлов)
- Сборка esbuild (frontend/scripts/build-react.mjs) с бюджетами gzip на чанки
- CSP-хэши, кэширование: chunk'и immutable, CSS/HTML no-cache (react-cache.conf)
- Фиксы: lazy-импорт именованных экспортов (краш после авторизации),
  растяжение #admin-root/#settings-root на всю ширину,
  возврат subjects/lessonTypes из справочников (краш просмотра расписаний),
  отказ от заведомо широкого поиска расписания без выбранной цели,
  центрирование карточки логина
- Тесты: 237/237 (npm run check), регрессионные на lazy-вкладки и ширину
- Документация: REACT_MIGRATION.md, REACT_MIGRATION_RESULT.md, FRONTEND.md
2026-09-28 23:15:04 +03:00

113 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { apiClient } from '../shared/api-client.js';
export const USER_TABLE_COLUMNS = 7;
export const USER_PAGE_SIZES = [25, 50, 100];
export const USER_SORT_OPTIONS = Object.freeze([
{ value: 'fullName,asc', label: 'По ФИО А–Я' },
{ value: 'fullName,desc', label: 'По ФИО Я–А' },
{ value: 'username,asc', label: 'По логину' },
{ value: 'role,asc', label: 'По роли' },
{ value: 'status,asc', label: 'По статусу' }
]);
export const ROLE_LABELS = Object.freeze({
ADMIN: 'Администратор',
EDUCATION_OFFICE: 'Учебный отдел',
DEPARTMENT: 'Кафедра',
SCHEDULE_VIEWER: 'Просмотр расписаний',
TEACHER: 'Преподаватель',
STUDENT: 'Студент'
});
export const ROLE_BADGE = Object.freeze({
ADMIN: 'badge-admin',
EDUCATION_OFFICE: 'badge-admin',
DEPARTMENT: 'badge-teacher',
SCHEDULE_VIEWER: 'badge-student',
TEACHER: 'badge-teacher',
STUDENT: 'badge-student'
});
export const ROLE_FILTER_OPTIONS = Object.freeze([
{ value: 'ADMIN', label: 'Администратор' },
{ value: 'EDUCATION_OFFICE', label: 'Учебный отдел' },
{ value: 'DEPARTMENT', label: 'Кафедра' },
{ value: 'SCHEDULE_VIEWER', label: 'Просмотр расписаний' },
{ value: 'TEACHER', label: 'Преподаватель' },
{ value: 'STUDENT', label: 'Студент' }
]);
export function normalizeUsersState(restored = {}) {
const size = Number(restored.userSize);
return {
query: restored.userQuery || '',
role: restored.userRole || '',
page: Math.max(Number(restored.userPage) || 0, 0),
size: USER_PAGE_SIZES.includes(size) ? size : 25,
sort: USER_SORT_OPTIONS.some(option => option.value === restored.userSort)
? restored.userSort
: 'fullName,asc'
};
}
export function initialUsersState(restored = {}) {
return normalizeUsersState(restored);
}
export function usersQueryParams(state) {
const [sort, direction] = String(state.sort || 'fullName,asc').split(',');
const params = new URLSearchParams({
query: state.query || '',
page: String(state.page || 0),
size: String(state.size || 25),
sort,
direction,
includeArchived: 'true'
});
if (state.role) params.set('role', state.role);
return `/api/users/page?${params}`;
}
export function usersUrlState(state) {
return {
userQuery: state.query || '',
userRole: state.role || '',
userPage: state.page || '',
userSize: state.size === 25 ? '' : state.size,
userSort: state.sort === 'fullName,asc' ? '' : state.sort
};
}
export function fetchUsersPage(state, client = apiClient) {
return client.get(usersQueryParams(state), { errorMessage: 'Не удалось загрузить пользователей' });
}
export function createUser({ username, password, role, fullName, jobTitle, departmentId }, client = apiClient) {
return client.post(
'/api/users',
{ username, password, role, fullName, jobTitle, departmentId: Number(departmentId) },
{ errorMessage: 'Ошибка соединения' }
);
}
export function archiveUser(id, client = apiClient) {
return client.delete(`/api/users/${id}`, { errorMessage: 'Ошибка архивирования' });
}
export function restoreUser(id, client = apiClient) {
return client.post(`/api/users/${id}/restore`, {}, { errorMessage: 'Ошибка восстановления' });
}
export function roleLabel(role) {
return ROLE_LABELS[role] || role;
}
export function roleBadgeClass(role) {
return ROLE_BADGE[role] || '';
}
export function usersEmptyMessage(state) {
return state.query || state.role ? 'Пользователи не найдены' : 'Пользователей пока нет';
}