// Глобальные переменные
let currentUser = null;
let isAdmin = false;
let currentTab = 'groups';
let groups = [];
let idusers = [];
let allUsers = [];
let currentPage = {
groups: 1,
idusers: 1
};
const itemsPerPage = 20;
let deleteCallback = null;
let deleteParams = null;
// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', function() {
checkAuth();
setupEventListeners();
});
// Проверка аутентификации
async function checkAuth() {
try {
const response = await fetch('/api/user');
if (!response.ok) {
window.location.href = '/';
return;
}
const data = await response.json();
if (data.user) {
currentUser = data.user;
isAdmin = currentUser.role === 'admin';
document.getElementById('userName').textContent = currentUser.name;
document.getElementById('userRole').textContent = `Роль: ${currentUser.role}`;
// Загружаем начальные данные
loadGroups();
loadAllUsers();
loadIdUsers();
//loadStats();
} else {
window.location.href = '/';
}
} catch (error) {
console.error('Ошибка проверки аутентификации:', error);
window.location.href = '/';
}
}
// Настройка обработчиков событий
function setupEventListeners() {
// Переключение вкладок
document.querySelectorAll('.tab').forEach(tab => {
tab.addEventListener('click', function() {
const tabId = this.getAttribute('data-tab');
switchTab(tabId);
});
});
// Поиск в таблице групп
document.getElementById('groupSearch').addEventListener('input', debounce(function() {
filterGroups();
}, 300));
// Фильтры групп
document.getElementById('groupServiceTypeFilter').addEventListener('change', filterGroups);
document.getElementById('groupStatusFilter').addEventListener('change', filterGroups);
// Поиск в таблице идентификаторов
document.getElementById('iduserSearch').addEventListener('input', debounce(function() {
filterIdUsers();
}, 300));
// Фильтры идентификаторов
document.getElementById('iduserServiceTypeFilter').addEventListener('change', filterIdUsers);
document.getElementById('iduserGroupFilter').addEventListener('change', filterIdUsers);
document.getElementById('iduserStatusFilter').addEventListener('change', filterIdUsers);
// Обновление опций групп при изменении типа сервиса в форме
document.getElementById('iduserServiceType').addEventListener('change', function() {
updateGroupOptions();
});
}
// Дебаунс для поиска
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Переключение вкладок
function switchTab(tabId) {
currentTab = tabId;
// Обновляем активные вкладки
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
if (tab.getAttribute('data-tab') === tabId) {
tab.classList.add('active');
}
});
// Показываем активный контент
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
if (content.id === `tab-${tabId}`) {
content.classList.add('active');
}
});
}
// Загрузка всех пользователей
async function loadAllUsers() {
try {
const response = await fetch('/api/users');
if (!response.ok) throw new Error('Ошибка загрузки пользователей');
allUsers = await response.json();
// Заполняем select в форме
const select = document.getElementById('iduserUserId');
select.innerHTML = '';
allUsers.forEach(user => {
const option = document.createElement('option');
option.value = user.id;
option.textContent = `${user.name} (${user.login})`;
select.appendChild(option);
});
} catch (error) {
console.error('Ошибка загрузки пользователей:', error);
}
}
// Загрузка групп
async function loadGroups() {
try {
const tableBody = document.getElementById('groupsTableBody');
tableBody.innerHTML = '
| Загрузка групп... |
';
const response = await fetch('/api2/groups');
if (!response.ok) throw new Error('Ошибка загрузки групп');
groups = await response.json();
// Заполняем фильтр групп для идентификаторов
const groupFilter = document.getElementById('iduserGroupFilter');
const currentValue = groupFilter.value;
groupFilter.innerHTML = '';
groups.forEach(group => {
const option = document.createElement('option');
option.value = group.id;
option.textContent = group.name;
groupFilter.appendChild(option);
});
if (currentValue) {
groupFilter.value = currentValue;
}
renderGroups();
} catch (error) {
console.error('Ошибка загрузки групп:', error);
document.getElementById('groupsTableBody').innerHTML =
'| Ошибка загрузки групп: ' + error.message + ' |
';
}
}
// Отображение групп
function renderGroups(filteredGroups = null) {
const groupsToRender = filteredGroups || groups;
const tableBody = document.getElementById('groupsTableBody');
if (groupsToRender.length === 0) {
tableBody.innerHTML = '| Нет данных для отображения |
';
document.getElementById('groupsPagination').innerHTML = '';
return;
}
// Пагинация
const totalPages = Math.ceil(groupsToRender.length / itemsPerPage);
const startIndex = (currentPage.groups - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const pageGroups = groupsToRender.slice(startIndex, endIndex);
// Очищаем таблицу
tableBody.innerHTML = '';
// Заполняем таблицу
pageGroups.forEach(group => {
const row = document.createElement('tr');
// Бейдж для типа сервиса
let serviceTypeBadge = '';
switch(group.service_type) {
case 'sberbank':
serviceTypeBadge = 'Сбербанк';
break;
case 'yandex':
serviceTypeBadge = 'Яндекс';
break;
case 'ldap':
serviceTypeBadge = 'LDAP';
break;
default:
serviceTypeBadge = 'Прочие';
}
row.innerHTML = `
${group.id} |
${group.name} |
${serviceTypeBadge} |
${group.description || '-'} |
${group.is_active ? 'Активна' : 'Неактивна'} |
${formatDate(group.created_at)} |
${formatDate(group.updated_at)} |
${isAdmin ? `
` : ''}
|
`;
tableBody.appendChild(row);
});
// Пагинация
renderPagination('groups', totalPages);
}
// Фильтрация групп
function filterGroups() {
const searchText = document.getElementById('groupSearch').value.toLowerCase();
const serviceType = document.getElementById('groupServiceTypeFilter').value;
const statusFilter = document.getElementById('groupStatusFilter').value;
const filtered = groups.filter(group => {
// Поиск по тексту
const matchesSearch = !searchText ||
group.name.toLowerCase().includes(searchText) ||
(group.description && group.description.toLowerCase().includes(searchText));
// Фильтр по типу сервиса
const matchesServiceType = !serviceType || group.service_type === serviceType;
// Фильтр по статусу
const matchesStatus = !statusFilter ||
(statusFilter === 'true' ? group.is_active : !group.is_active);
return matchesSearch && matchesServiceType && matchesStatus;
});
currentPage.groups = 1;
renderGroups(filtered);
}
// Загрузка идентификаторов пользователей
async function loadIdUsers() {
try {
const tableBody = document.getElementById('idusersTableBody');
tableBody.innerHTML = '| Загрузка идентификаторов... |
';
const response = await fetch('/api2/idusers');
if (!response.ok) throw new Error('Ошибка загрузки идентификаторов');
idusers = await response.json();
renderIdUsers();
} catch (error) {
console.error('Ошибка загрузки идентификаторов:', error);
document.getElementById('idusersTableBody').innerHTML =
'| Ошибка загрузки идентификаторов: ' + error.message + ' |
';
}
}
// Отображение идентификаторов пользователей
function renderIdUsers(filteredIdUsers = null) {
const idusersToRender = filteredIdUsers || idusers;
const tableBody = document.getElementById('idusersTableBody');
if (idusersToRender.length === 0) {
tableBody.innerHTML = '| Нет данных для отображения |
';
document.getElementById('idusersPagination').innerHTML = '';
return;
}
// Пагинация
const totalPages = Math.ceil(idusersToRender.length / itemsPerPage);
const startIndex = (currentPage.idusers - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const pageIdUsers = idusersToRender.slice(startIndex, endIndex);
// Очищаем таблицу
tableBody.innerHTML = '';
// Заполняем таблицу
pageIdUsers.forEach(iduser => {
const row = document.createElement('tr');
// Бейдж для типа сервиса
let serviceTypeBadge = '';
switch(iduser.service_type) {
case 'sberbank':
serviceTypeBadge = 'Сбербанк';
break;
case 'yandex':
serviceTypeBadge = 'Яндекс';
break;
case 'ldap':
serviceTypeBadge = 'LDAP';
break;
default:
serviceTypeBadge = 'Прочие';
}
// Превью метаданных
let metadataPreview = '-';
if (iduser.metadata && Object.keys(iduser.metadata).length > 0) {
metadataPreview = `
${Object.keys(iduser.metadata).length} поле(й)
`;
}
row.innerHTML = `
${iduser.id} |
${iduser.user_name || 'Неизвестно'}
${iduser.user_login || '-'}
|
${serviceTypeBadge} |
${iduser.external_id || '-'} |
${iduser.login || '-'} |
${iduser.ldap_group || '-'} |
${iduser.group_name || '-'} |
${metadataPreview} |
${iduser.is_active ? 'Активен' : 'Неактивен'} |
${formatDate(iduser.created_at)} |
${isAdmin ? `
` : ''}
|
`;
tableBody.appendChild(row);
});
// Пагинация
renderPagination('idusers', totalPages);
}
// Фильтрация идентификаторов пользователей
function filterIdUsers() {
const searchText = document.getElementById('iduserSearch').value.toLowerCase();
const serviceType = document.getElementById('iduserServiceTypeFilter').value;
const groupId = document.getElementById('iduserGroupFilter').value;
const statusFilter = document.getElementById('iduserStatusFilter').value;
const filtered = idusers.filter(iduser => {
// Поиск по тексту
const matchesSearch = !searchText ||
(iduser.external_id && iduser.external_id.toLowerCase().includes(searchText)) ||
(iduser.login && iduser.login.toLowerCase().includes(searchText)) ||
(iduser.user_name && iduser.user_name.toLowerCase().includes(searchText)) ||
(iduser.user_login && iduser.user_login.toLowerCase().includes(searchText));
// Фильтр по типу сервиса
const matchesServiceType = !serviceType || iduser.service_type === serviceType;
// Фильтр по группе
const matchesGroup = !groupId || iduser.group_id == groupId;
// Фильтр по статусу
const matchesStatus = !statusFilter ||
(statusFilter === 'true' ? iduser.is_active : !iduser.is_active);
return matchesSearch && matchesServiceType && matchesGroup && matchesStatus;
});
currentPage.idusers = 1;
renderIdUsers(filtered);
}
// Загрузка статистики
async function loadStats() {
try {
const statsGrid = document.getElementById('statsGrid');
statsGrid.innerHTML = ' Загрузка статистики...
';
const response = await fetch('/api2/idusers/stats');
if (!response.ok) throw new Error('Ошибка загрузки статистики');
const stats = await response.json();
renderStats(stats);
} catch (error) {
console.error('Ошибка загрузки статистики:', error);
document.getElementById('statsGrid').innerHTML =
'Ошибка загрузки статистики: ' + error.message + '
';
}
}
// Отображение статистики
function renderStats(stats) {
const statsGrid = document.getElementById('statsGrid');
const tableBody = document.getElementById('statsTableBody');
// Статистические карточки
statsGrid.innerHTML = `
Всего идентификаторов
${stats.totals.total_identifiers || 0}
Уникальных пользователей
${stats.totals.total_users || 0}
Активных идентификаторов
${stats.totals.total_active || 0}
Обновлено
${formatDate(stats.timestamp, 'time')}
`;
// Таблица по типам сервисов
tableBody.innerHTML = '';
if (stats.by_service_type && stats.by_service_type.length > 0) {
const total = stats.totals.total_identifiers || 1;
stats.by_service_type.forEach(stat => {
const percentage = Math.round((stat.total_count / total) * 100);
const row = document.createElement('tr');
row.innerHTML = `
${getServiceTypeName(stat.service_type)}
|
${stat.total_count} |
${stat.active_count} |
${stat.unique_users} |
${percentage}%
|
`;
tableBody.appendChild(row);
});
} else {
tableBody.innerHTML = '| Нет данных для отображения |
';
}
}
// Модальное окно для добавления группы
function showAddGroupModal() {
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
document.getElementById('groupModalTitle').textContent = 'Добавить группу';
document.getElementById('groupId').value = '';
document.getElementById('groupForm').reset();
document.getElementById('groupIsActive').checked = true;
document.getElementById('groupMessage').innerHTML = '';
document.getElementById('groupModal').classList.add('active');
}
// Модальное окно для редактирования группы
async function editGroup(id) {
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
try {
const response = await fetch(`/api2/groups/${id}`);
if (!response.ok) throw new Error('Ошибка загрузки группы');
const group = await response.json();
document.getElementById('groupModalTitle').textContent = 'Редактировать группу';
document.getElementById('groupId').value = group.id;
document.getElementById('groupName').value = group.name;
document.getElementById('groupDescription').value = group.description || '';
document.getElementById('groupServiceType').value = group.service_type;
document.getElementById('groupIsActive').checked = group.is_active;
document.getElementById('groupMessage').innerHTML = '';
document.getElementById('groupModal').classList.add('active');
} catch (error) {
console.error('Ошибка загрузки группы:', error);
alert('Ошибка загрузки группы: ' + error.message);
}
}
// Закрытие модального окна группы
function closeGroupModal() {
document.getElementById('groupModal').classList.remove('active');
}
// Сохранение группы
async function saveGroup(event) {
event.preventDefault();
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
const groupId = document.getElementById('groupId').value;
const isEdit = !!groupId;
const groupData = {
name: document.getElementById('groupName').value,
description: document.getElementById('groupDescription').value,
service_type: document.getElementById('groupServiceType').value,
is_active: document.getElementById('groupIsActive').checked
};
try {
const url = isEdit ? `/api2/groups/${groupId}` : '/api2/groups';
const method = isEdit ? 'PUT' : 'POST';
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(groupData)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Ошибка сохранения');
}
const result = await response.json();
// Показываем сообщение об успехе
document.getElementById('groupMessage').innerHTML = `
Группа успешно ${isEdit ? 'обновлена' : 'создана'}!
`;
// Обновляем список групп
setTimeout(() => {
closeGroupModal();
loadGroups();
}, 1500);
} catch (error) {
console.error('Ошибка сохранения группы:', error);
document.getElementById('groupMessage').innerHTML = `
Ошибка: ${error.message}
`;
}
}
// Подтверждение удаления группы
function confirmDeleteGroup(id) {
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
const group = groups.find(g => g.id == id);
if (!group) return;
document.getElementById('confirmModalTitle').textContent = 'Удаление группы';
document.getElementById('confirmMessage').textContent = `Вы уверены, что хотите удалить группу "${group.name}"?`;
deleteCallback = deleteGroup;
deleteParams = { id };
document.getElementById('confirmModal').classList.add('active');
}
// Удаление группы
async function deleteGroup(params) {
try {
const response = await fetch(`/api2/groups/${params.id}`, {
method: 'DELETE'
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Ошибка удаления');
}
const result = await response.json();
if (result.success) {
// Показываем сообщение об успехе
alert('Группа успешно удалена');
// Обновляем список групп
loadGroups();
} else {
throw new Error(result.message || 'Ошибка удаления');
}
} catch (error) {
console.error('Ошибка удаления группы:', error);
alert('Ошибка удаления группы: ' + error.message);
}
}
// Модальное окно для добавления идентификатора
function showAddIdUserModal() {
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
document.getElementById('iduserModalTitle').textContent = 'Добавить идентификатор';
document.getElementById('iduserId').value = '';
document.getElementById('iduserForm').reset();
// Устанавливаем тип сервиса по умолчанию как LDAP
document.getElementById('iduserServiceType').value = 'ldap';
document.getElementById('iduserIsActive').checked = true;
document.getElementById('iduserMessage').innerHTML = '';
// Добавляем обработчик для автозаполнения LDAP полей
const userIdSelect = document.getElementById('iduserUserId');
// Удаляем существующие обработчики чтобы избежать дублирования
const newUserIdSelect = userIdSelect.cloneNode(true);
userIdSelect.parentNode.replaceChild(newUserIdSelect, userIdSelect);
// Добавляем новый обработчик
document.getElementById('iduserUserId').addEventListener('change', function() {
autoFillLdapFields(this.value);
});
// Обновляем опции групп (все группы, независимо от сервиса)
updateGroupOptions();
document.getElementById('iduserModal').classList.add('active');
}
// Модальное окно для редактирования идентификатора
async function editIdUser(id) {
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
try {
const response = await fetch(`/api2/idusers/${id}`);
if (!response.ok) throw new Error('Ошибка загрузки идентификатора');
const iduser = await response.json();
document.getElementById('iduserModalTitle').textContent = 'Редактировать идентификатор';
document.getElementById('iduserId').value = iduser.id;
document.getElementById('iduserUserId').value = iduser.user_id;
document.getElementById('iduserExternalId').value = iduser.external_id || '';
document.getElementById('iduserLogin').value = iduser.login || '';
document.getElementById('iduserLdapGroup').value = iduser.ldap_group || '';
document.getElementById('iduserServiceType').value = iduser.service_type;
document.getElementById('iduserIsActive').checked = iduser.is_active;
// Устанавливаем метаданные
if (iduser.metadata && Object.keys(iduser.metadata).length > 0) {
document.getElementById('iduserMetadata').value = JSON.stringify(iduser.metadata, null, 2);
} else {
document.getElementById('iduserMetadata').value = '';
}
// Обновляем опции групп (все группы) и выбираем текущую
await updateGroupOptions();
document.getElementById('iduserGroupId').value = iduser.group_id || '';
// Добавляем обработчик для автозаполнения LDAP полей
const userIdSelect = document.getElementById('iduserUserId');
// Удаляем существующие обработчики чтобы избежать дублирования
const newUserIdSelect = userIdSelect.cloneNode(true);
userIdSelect.parentNode.replaceChild(newUserIdSelect, userIdSelect);
// Добавляем новый обработчик
document.getElementById('iduserUserId').addEventListener('change', function() {
autoFillLdapFields(this.value);
});
document.getElementById('iduserMessage').innerHTML = '';
document.getElementById('iduserModal').classList.add('active');
} catch (error) {
console.error('Ошибка загрузки идентификатора:', error);
alert('Ошибка загрузки идентификатора: ' + error.message);
}
}
// Автоматическое заполнение полей LDAP на основе выбранного пользователя
function autoFillLdapFields(userId) {
if (!userId) return;
// Находим пользователя в списке всех пользователей
const user = allUsers.find(u => u.id == userId);
if (!user) return;
// Проверяем, является ли пользователь LDAP пользователем
// Предполагаем, что LDAP пользователи имеют логин в определенном формате
// или у них есть специальный атрибут в метаданных
const isLdapUser = user.login && (
user.login.includes('@') || // LDAP логин часто содержит домен
user.service_type === 'ldap' ||
(user.metadata && user.metadata.dn) // Имеет Distinguished Name
);
if (isLdapUser) {
// Автоматически заполняем логин LDAP если поле пустое
if (!document.getElementById('iduserLogin').value.trim()) {
document.getElementById('iduserLogin').value = user.login;
}
// Автоматически заполняем группу LDAP из атрибутов пользователя
if (!document.getElementById('iduserLdapGroup').value.trim()) {
// Можно извлекать из различных мест:
// 1. Из метаданных пользователя
// 2. Из атрибута department или ou
// 3. Из других полей
if (user.metadata && user.metadata.ou) {
document.getElementById('iduserLdapGroup').value = user.metadata.ou;
} else if (user.department) {
document.getElementById('iduserLdapGroup').value = user.department;
} else if (user.metadata && user.metadata.memberOf) {
document.getElementById('iduserLdapGroup').value = user.metadata.memberOf;
}
}
}
}
// Обновление опций групп - теперь показывает все группы независимо от типа сервиса
async function updateGroupOptions() {
const groupSelect = document.getElementById('iduserGroupId');
// Загружаем группы, если еще не загружены
if (groups.length === 0) {
await loadGroups();
}
// Берем все активные группы (без фильтрации по типу сервиса)
const activeGroups = groups.filter(g => g.is_active);
// Сохраняем текущее значение
const currentValue = groupSelect.value;
// Обновляем опции
groupSelect.innerHTML = '';
activeGroups.forEach(group => {
const option = document.createElement('option');
option.value = group.id;
option.textContent = `${group.name} (${getServiceTypeName(group.service_type)})`;
groupSelect.appendChild(option);
});
// Восстанавливаем значение, если оно есть в новых опциях
if (currentValue && activeGroups.some(g => g.id == currentValue)) {
groupSelect.value = currentValue;
}
return Promise.resolve();
}
// Закрытие модального окна идентификатора
function closeIdUserModal() {
document.getElementById('iduserModal').classList.remove('active');
}
// Сохранение идентификатора
async function saveIdUser(event) {
event.preventDefault();
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
const iduserId = document.getElementById('iduserId').value;
const isEdit = !!iduserId;
// Валидация - External ID теперь необязательный
const externalId = document.getElementById('iduserExternalId').value.trim();
// Парсим метаданные
let metadata = null;
const metadataText = document.getElementById('iduserMetadata').value.trim();
if (metadataText) {
try {
metadata = JSON.parse(metadataText);
} catch (error) {
document.getElementById('iduserMessage').innerHTML = `
Ошибка в формате JSON: ${error.message}
`;
return;
}
}
const iduserData = {
user_id: parseInt(document.getElementById('iduserUserId').value),
service_type: document.getElementById('iduserServiceType').value,
external_id: externalId || null, // Разрешаем null для external_id
login: document.getElementById('iduserLogin').value.trim() || null,
ldap_group: document.getElementById('iduserLdapGroup').value.trim() || null,
group_id: document.getElementById('iduserGroupId').value || null,
metadata: metadata,
is_active: document.getElementById('iduserIsActive').checked
};
// Проверяем обязательные поля
if (!iduserData.user_id) {
document.getElementById('iduserMessage').innerHTML = `
Пожалуйста, выберите пользователя
`;
return;
}
if (!iduserData.service_type) {
document.getElementById('iduserMessage').innerHTML = `
Пожалуйста, выберите тип сервиса
`;
return;
}
try {
const url = isEdit ? `/api2/idusers/${iduserId}` : '/api2/idusers';
const method = isEdit ? 'PUT' : 'POST';
const response = await fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(iduserData)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Ошибка сохранения');
}
const result = await response.json();
// Показываем сообщение об успехе
document.getElementById('iduserMessage').innerHTML = `
Идентификатор успешно ${isEdit ? 'обновлен' : 'создан'}!
`;
// Обновляем список идентификаторов
setTimeout(() => {
closeIdUserModal();
loadIdUsers();
}, 1500);
} catch (error) {
console.error('Ошибка сохранения идентификатора:', error);
document.getElementById('iduserMessage').innerHTML = `
Ошибка: ${error.message}
`;
}
}
// Подтверждение удаления идентификатора
function confirmDeleteIdUser(id) {
if (!isAdmin) {
alert('Недостаточно прав');
return;
}
const iduser = idusers.find(i => i.id == id);
if (!iduser) return;
document.getElementById('confirmModalTitle').textContent = 'Удаление идентификатора';
document.getElementById('confirmMessage').textContent = `Вы уверены, что хотите удалить идентификатор "${iduser.external_id || 'без внешнего ID'}" пользователя "${iduser.user_name}"?`;
deleteCallback = deleteIdUser;
deleteParams = { id };
document.getElementById('confirmModal').classList.add('active');
}
// Удаление идентификатора
async function deleteIdUser(params) {
try {
const response = await fetch(`/api2/idusers/${params.id}`, {
method: 'DELETE'
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Ошибка удаления');
}
const result = await response.json();
if (result.success) {
// Показываем сообщение об успехе
alert('Идентификатор успешно удален');
// Обновляем список идентификаторов
loadIdUsers();
} else {
throw new Error(result.message || 'Ошибка удаления');
}
} catch (error) {
console.error('Ошибка удаления идентификатора:', error);
alert('Ошибка удаления идентификатора: ' + error.message);
}
}
// Пагинация
function renderPagination(type, totalPages) {
const paginationDiv = document.getElementById(`${type}Pagination`);
if (totalPages <= 1) {
paginationDiv.innerHTML = '';
return;
}
let html = '';
// Кнопка "Назад"
html += ``;
// Номера страниц
for (let i = 1; i <= totalPages; i++) {
if (i === 1 || i === totalPages || (i >= currentPage[type] - 2 && i <= currentPage[type] + 2)) {
html += ``;
} else if (i === currentPage[type] - 3 || i === currentPage[type] + 3) {
html += `...`;
}
}
// Кнопка "Вперед"
html += ``;
// Информация о странице
html += `
Страница ${currentPage[type]} из ${totalPages}
`;
paginationDiv.innerHTML = html;
}
// Изменение страницы
function changePage(type, page) {
currentPage[type] = page;
if (type === 'groups') {
filterGroups();
} else if (type === 'idusers') {
filterIdUsers();
}
}
// Подтверждение удаления
function confirmDelete() {
if (deleteCallback && deleteParams) {
deleteCallback(deleteParams);
}
closeConfirmModal();
}
// Закрытие модального окна подтверждения
function closeConfirmModal() {
document.getElementById('confirmModal').classList.remove('active');
deleteCallback = null;
deleteParams = null;
}
// Просмотр метаданных
function showMetadata(metadata) {
document.getElementById('metadataContent').textContent = metadata;
document.getElementById('metadataModal').classList.add('active');
}
// Закрытие модального окна метаданных
function closeMetadataModal() {
document.getElementById('metadataModal').classList.remove('active');
}
// Выход из системы
async function logout() {
try {
await fetch('/api/logout', {
method: 'POST'
});
window.location.href = '/';
} catch (error) {
console.error('Ошибка выхода:', error);
window.location.href = '/';
}
}
// Вспомогательные функции
function formatDate(dateString, type = 'date') {
if (!dateString) return '-';
const date = new Date(dateString);
if (type === 'date') {
return date.toLocaleDateString('ru-RU', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
}) + ' ' + date.toLocaleTimeString('ru-RU', {
hour: '2-digit',
minute: '2-digit'
});
} else if (type === 'time') {
return date.toLocaleTimeString('ru-RU', {
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
}
return date.toLocaleString('ru-RU');
}
function getServiceTypeName(type) {
switch(type) {
case 'sberbank': return 'Сбербанк';
case 'yandex': return 'Яндекс';
case 'ldap': return 'LDAP';
default: return 'Прочие';
}
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}