Много разных изменений
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
import { api } from '../api.js';
|
||||
import { escapeHtml, showAlert, hideAlert } from '../utils.js';
|
||||
import { confirmAction } from '../dialog.js';
|
||||
import { renderPagination } from '../pagination.js';
|
||||
import { debounce, readUrlState, writeUrlState } from '../url-state.js';
|
||||
import { markTableReady, renderTableEmpty, renderTableError, renderTableLoading } from '../view-state.js';
|
||||
import { trackUxEvent } from '../../../telemetry.js';
|
||||
|
||||
const ROLE_LABELS = {
|
||||
ADMIN: 'Администратор',
|
||||
@@ -21,21 +26,53 @@ const ROLE_BADGE = {
|
||||
export async function initUsers() {
|
||||
const usersTbody = document.getElementById('users-tbody');
|
||||
const createForm = document.getElementById('create-form');
|
||||
const searchInput = document.getElementById('users-search');
|
||||
const roleFilter = document.getElementById('users-role-filter');
|
||||
const sortSelect = document.getElementById('users-sort');
|
||||
const pagination = document.getElementById('users-pagination');
|
||||
const restored = readUrlState({ userQuery: '', userRole: '', userPage: '0', userSize: '25', userSort: 'fullName,asc' });
|
||||
const state = {
|
||||
query: restored.userQuery,
|
||||
role: restored.userRole,
|
||||
page: Math.max(Number(restored.userPage) || 0, 0),
|
||||
size: [25, 50, 100].includes(Number(restored.userSize)) ? Number(restored.userSize) : 25,
|
||||
sort: restored.userSort
|
||||
};
|
||||
searchInput.value = state.query;
|
||||
roleFilter.value = state.role;
|
||||
sortSelect.value = state.sort;
|
||||
|
||||
async function loadUsers() {
|
||||
renderTableLoading(usersTbody, 7, 'Загрузка пользователей...');
|
||||
hideAlert('users-alert');
|
||||
try {
|
||||
const users = await api.get('/api/users?includeArchived=true');
|
||||
renderUsers(users);
|
||||
const [sort, direction] = state.sort.split(',');
|
||||
const params = new URLSearchParams({
|
||||
query: state.query,
|
||||
page: String(state.page),
|
||||
size: String(state.size),
|
||||
sort,
|
||||
direction,
|
||||
includeArchived: 'true'
|
||||
});
|
||||
if (state.role) params.set('role', state.role);
|
||||
const result = await api.get(`/api/users/page?${params}`);
|
||||
renderUsers(result.items || []);
|
||||
renderPagination(pagination, result, {
|
||||
label: 'пользователей',
|
||||
onPage: page => { state.page = page; loadUsers(); },
|
||||
onSize: size => { state.size = size; state.page = 0; loadUsers(); }
|
||||
});
|
||||
persistState();
|
||||
trackUxEvent('реестр_пользователей_загружен', { total: Number(result.totalItems || 0), page: state.page });
|
||||
} catch (e) {
|
||||
usersTbody.innerHTML =
|
||||
'<tr><td colspan="7" class="loading-row">Ошибка загрузки: ' +
|
||||
escapeHtml(e.message) + '</td></tr>';
|
||||
renderTableError(usersTbody, 7, e.message || 'Не удалось загрузить пользователей', loadUsers);
|
||||
}
|
||||
}
|
||||
|
||||
function renderUsers(users) {
|
||||
if (!users || !users.length) {
|
||||
usersTbody.innerHTML = '<tr><td colspan="7" class="loading-row">Нет пользователей</td></tr>';
|
||||
renderTableEmpty(usersTbody, 7, state.query || state.role ? 'Пользователи не найдены' : 'Пользователей пока нет');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,8 +91,25 @@ export async function initUsers() {
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
markTableReady(usersTbody);
|
||||
}
|
||||
|
||||
searchInput.addEventListener('input', debounce(() => {
|
||||
state.query = searchInput.value.trim();
|
||||
state.page = 0;
|
||||
loadUsers();
|
||||
}));
|
||||
roleFilter.addEventListener('change', () => {
|
||||
state.role = roleFilter.value;
|
||||
state.page = 0;
|
||||
loadUsers();
|
||||
});
|
||||
sortSelect.addEventListener('change', () => {
|
||||
state.sort = sortSelect.value;
|
||||
state.page = 0;
|
||||
loadUsers();
|
||||
});
|
||||
|
||||
createForm.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
hideAlert('create-alert');
|
||||
@@ -97,12 +151,17 @@ export async function initUsers() {
|
||||
const deleteBtn = e.target.closest('.btn-archive-user');
|
||||
if (!deleteBtn) return;
|
||||
|
||||
if (!confirm('Архивировать пользователя? История расписания и связей сохранится.')) return;
|
||||
if (!await confirmAction({
|
||||
title: 'Архивировать пользователя?',
|
||||
message: 'Доступ будет отключён, а история расписания и связей сохранится.',
|
||||
confirmLabel: 'Архивировать',
|
||||
danger: true
|
||||
})) return;
|
||||
try {
|
||||
await api.delete('/api/users/' + deleteBtn.dataset.id);
|
||||
loadUsers();
|
||||
} catch (err) {
|
||||
alert(err.message || 'Ошибка архивирования');
|
||||
showAlert('users-alert', err.message || 'Ошибка архивирования', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -114,9 +173,19 @@ export async function initUsers() {
|
||||
await api.post('/api/users/' + restoreBtn.dataset.id + '/restore', {});
|
||||
loadUsers();
|
||||
} catch (err) {
|
||||
alert(err.message || 'Ошибка восстановления');
|
||||
showAlert('users-alert', err.message || 'Ошибка восстановления', 'error');
|
||||
}
|
||||
});
|
||||
|
||||
function persistState() {
|
||||
writeUrlState({
|
||||
userQuery: state.query,
|
||||
userRole: state.role,
|
||||
userPage: state.page || '',
|
||||
userSize: state.size === 25 ? '' : state.size,
|
||||
userSort: state.sort === 'fullName,asc' ? '' : state.sort
|
||||
});
|
||||
}
|
||||
|
||||
await loadUsers();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user