1001 lines
45 KiB
JavaScript
1001 lines
45 KiB
JavaScript
// Глобальные переменные
|
||
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);
|
||
}
|
||
|
||
// Дебаунс для поиска
|
||
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 = '<option value="">Выберите пользователя</option>';
|
||
|
||
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 = '<tr><td colspan="8" class="loading"><i class="fas fa-spinner fa-spin"></i> Загрузка групп...</td></tr>';
|
||
|
||
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 = '<option value="">Все группы</option>';
|
||
|
||
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 =
|
||
'<tr><td colspan="8" class="error">Ошибка загрузки групп: ' + error.message + '</td></tr>';
|
||
}
|
||
}
|
||
|
||
// Отображение групп
|
||
function renderGroups(filteredGroups = null) {
|
||
const groupsToRender = filteredGroups || groups;
|
||
const tableBody = document.getElementById('groupsTableBody');
|
||
|
||
if (groupsToRender.length === 0) {
|
||
tableBody.innerHTML = '<tr><td colspan="8" class="no-data">Нет данных для отображения</td></tr>';
|
||
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 = '<span class="badge badge-sberbank">Сбербанк</span>';
|
||
break;
|
||
case 'yandex':
|
||
serviceTypeBadge = '<span class="badge badge-yandex">Яндекс</span>';
|
||
break;
|
||
case 'ldap':
|
||
serviceTypeBadge = '<span class="badge badge-ldap">LDAP</span>';
|
||
break;
|
||
default:
|
||
serviceTypeBadge = '<span class="badge badge-other">Прочие</span>';
|
||
}
|
||
|
||
row.innerHTML = `
|
||
<td>${group.id}</td>
|
||
<td><strong>${group.name}</strong></td>
|
||
<td>${serviceTypeBadge}</td>
|
||
<td>${group.description || '-'}</td>
|
||
<td>${group.is_active ? '<span class="status-active">Активна</span>' : '<span class="status-inactive">Неактивна</span>'}</td>
|
||
<td>${formatDate(group.created_at)}</td>
|
||
<td>${formatDate(group.updated_at)}</td>
|
||
<td class="actions">
|
||
${isAdmin ? `
|
||
<button class="btn btn-primary btn-small" onclick="editGroup(${group.id})">
|
||
<i class="fas fa-edit"></i>
|
||
</button>
|
||
<button class="btn btn-danger btn-small" onclick="confirmDeleteGroup(${group.id})">
|
||
<i class="fas fa-trash"></i>
|
||
</button>
|
||
` : ''}
|
||
</td>
|
||
`;
|
||
|
||
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 = '<tr><td colspan="11" class="loading"><i class="fas fa-spinner fa-spin"></i> Загрузка идентификаторов...</td></tr>';
|
||
|
||
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 =
|
||
'<tr><td colspan="11" class="error">Ошибка загрузки идентификаторов: ' + error.message + '</td></tr>';
|
||
}
|
||
}
|
||
|
||
// Отображение идентификаторов пользователей
|
||
function renderIdUsers(filteredIdUsers = null) {
|
||
const idusersToRender = filteredIdUsers || idusers;
|
||
const tableBody = document.getElementById('idusersTableBody');
|
||
|
||
if (idusersToRender.length === 0) {
|
||
tableBody.innerHTML = '<tr><td colspan="11" class="no-data">Нет данных для отображения</td></tr>';
|
||
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 = '<span class="badge badge-sberbank">Сбербанк</span>';
|
||
break;
|
||
case 'yandex':
|
||
serviceTypeBadge = '<span class="badge badge-yandex">Яндекс</span>';
|
||
break;
|
||
case 'ldap':
|
||
serviceTypeBadge = '<span class="badge badge-ldap">LDAP</span>';
|
||
break;
|
||
default:
|
||
serviceTypeBadge = '<span class="badge badge-other">Прочие</span>';
|
||
}
|
||
|
||
// Превью метаданных
|
||
let metadataPreview = '-';
|
||
if (iduser.metadata && Object.keys(iduser.metadata).length > 0) {
|
||
metadataPreview = `<div class="metadata-preview" title="Нажмите для просмотра" onclick="showMetadata('${escapeHtml(JSON.stringify(iduser.metadata, null, 2))}')">
|
||
${Object.keys(iduser.metadata).length} поле(й)
|
||
</div>`;
|
||
}
|
||
|
||
row.innerHTML = `
|
||
<td>${iduser.id}</td>
|
||
<td>
|
||
<strong>${iduser.user_name || 'Неизвестно'}</strong><br>
|
||
<small>${iduser.user_login || '-'}</small>
|
||
</td>
|
||
<td>${serviceTypeBadge}</td>
|
||
<td><strong>${iduser.external_id}</strong></td>
|
||
<td>${iduser.login || '-'}</td>
|
||
<td>${iduser.ldap_group || '-'}</td>
|
||
<td>${iduser.group_name || '-'}</td>
|
||
<td>${metadataPreview}</td>
|
||
<td>${iduser.is_active ? '<span class="status-active">Активен</span>' : '<span class="status-inactive">Неактивен</span>'}</td>
|
||
<td>${formatDate(iduser.created_at)}</td>
|
||
<td class="actions">
|
||
${isAdmin ? `
|
||
<button class="btn btn-primary btn-small" onclick="editIdUser(${iduser.id})">
|
||
<i class="fas fa-edit"></i>
|
||
</button>
|
||
<button class="btn btn-danger btn-small" onclick="confirmDeleteIdUser(${iduser.id})">
|
||
<i class="fas fa-trash"></i>
|
||
</button>
|
||
` : ''}
|
||
</td>
|
||
`;
|
||
|
||
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.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 = '<div class="loading"><i class="fas fa-spinner fa-spin"></i> Загрузка статистики...</div>';
|
||
|
||
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 =
|
||
'<div class="error">Ошибка загрузки статистики: ' + error.message + '</div>';
|
||
}
|
||
}
|
||
|
||
// Отображение статистики
|
||
function renderStats(stats) {
|
||
const statsGrid = document.getElementById('statsGrid');
|
||
const tableBody = document.getElementById('statsTableBody');
|
||
|
||
// Статистические карточки
|
||
statsGrid.innerHTML = `
|
||
<div class="stat-card">
|
||
<div class="stat-label">Всего идентификаторов</div>
|
||
<div class="stat-value">${stats.totals.total_identifiers || 0}</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-label">Уникальных пользователей</div>
|
||
<div class="stat-value">${stats.totals.total_users || 0}</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-label">Активных идентификаторов</div>
|
||
<div class="stat-value">${stats.totals.total_active || 0}</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-label">Обновлено</div>
|
||
<div class="stat-value">${formatDate(stats.timestamp, 'time')}</div>
|
||
</div>
|
||
`;
|
||
|
||
// Таблица по типам сервисов
|
||
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 = `
|
||
<td>
|
||
<span class="badge badge-${stat.service_type}">
|
||
${getServiceTypeName(stat.service_type)}
|
||
</span>
|
||
</td>
|
||
<td>${stat.total_count}</td>
|
||
<td>${stat.active_count}</td>
|
||
<td>${stat.unique_users}</td>
|
||
<td>
|
||
<div style="background: #e2e8f0; height: 10px; border-radius: 5px; margin-top: 5px;">
|
||
<div style="width: ${percentage}%; background: #667eea; height: 100%; border-radius: 5px;"></div>
|
||
</div>
|
||
${percentage}%
|
||
</td>
|
||
`;
|
||
tableBody.appendChild(row);
|
||
});
|
||
} else {
|
||
tableBody.innerHTML = '<tr><td colspan="5" class="no-data">Нет данных для отображения</td></tr>';
|
||
}
|
||
}
|
||
|
||
// Модальное окно для добавления группы
|
||
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 = `
|
||
<div class="success">
|
||
<i class="fas fa-check-circle"></i>
|
||
Группа успешно ${isEdit ? 'обновлена' : 'создана'}!
|
||
</div>
|
||
`;
|
||
|
||
// Обновляем список групп
|
||
setTimeout(() => {
|
||
closeGroupModal();
|
||
loadGroups();
|
||
}, 1500);
|
||
|
||
} catch (error) {
|
||
console.error('Ошибка сохранения группы:', error);
|
||
document.getElementById('groupMessage').innerHTML = `
|
||
<div class="error">
|
||
<i class="fas fa-exclamation-circle"></i>
|
||
Ошибка: ${error.message}
|
||
</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// Подтверждение удаления группы
|
||
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();
|
||
document.getElementById('iduserIsActive').checked = true;
|
||
document.getElementById('iduserMessage').innerHTML = '';
|
||
|
||
// Обновляем опции групп
|
||
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 = '';
|
||
}
|
||
|
||
// Обновляем опции групп и выбираем текущую
|
||
updateGroupOptions().then(() => {
|
||
document.getElementById('iduserGroupId').value = iduser.group_id || '';
|
||
});
|
||
|
||
document.getElementById('iduserMessage').innerHTML = '';
|
||
|
||
document.getElementById('iduserModal').classList.add('active');
|
||
} catch (error) {
|
||
console.error('Ошибка загрузки идентификатора:', error);
|
||
alert('Ошибка загрузки идентификатора: ' + error.message);
|
||
}
|
||
}
|
||
|
||
// Обновление опций групп в зависимости от типа сервиса
|
||
async function updateGroupOptions() {
|
||
const serviceType = document.getElementById('iduserServiceType').value;
|
||
const groupSelect = document.getElementById('iduserGroupId');
|
||
|
||
// Загружаем группы, если еще не загружены
|
||
if (groups.length === 0) {
|
||
await loadGroups();
|
||
}
|
||
|
||
// Фильтруем группы по типу сервиса
|
||
const filteredGroups = serviceType ?
|
||
groups.filter(g => g.service_type === serviceType && g.is_active) :
|
||
groups.filter(g => g.is_active);
|
||
|
||
// Сохраняем текущее значение
|
||
const currentValue = groupSelect.value;
|
||
|
||
// Обновляем опции
|
||
groupSelect.innerHTML = '<option value="">Без группы</option>';
|
||
filteredGroups.forEach(group => {
|
||
const option = document.createElement('option');
|
||
option.value = group.id;
|
||
option.textContent = group.name;
|
||
groupSelect.appendChild(option);
|
||
});
|
||
|
||
// Восстанавливаем значение, если оно есть в новых опциях
|
||
if (currentValue && filteredGroups.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;
|
||
|
||
// Парсим метаданные
|
||
let metadata = null;
|
||
const metadataText = document.getElementById('iduserMetadata').value.trim();
|
||
if (metadataText) {
|
||
try {
|
||
metadata = JSON.parse(metadataText);
|
||
} catch (error) {
|
||
document.getElementById('iduserMessage').innerHTML = `
|
||
<div class="error">
|
||
<i class="fas fa-exclamation-circle"></i>
|
||
Ошибка в формате JSON: ${error.message}
|
||
</div>
|
||
`;
|
||
return;
|
||
}
|
||
}
|
||
|
||
const iduserData = {
|
||
user_id: parseInt(document.getElementById('iduserUserId').value),
|
||
service_type: document.getElementById('iduserServiceType').value,
|
||
external_id: document.getElementById('iduserExternalId').value,
|
||
login: document.getElementById('iduserLogin').value || undefined,
|
||
ldap_group: document.getElementById('iduserLdapGroup').value || undefined,
|
||
group_id: document.getElementById('iduserGroupId').value || undefined,
|
||
metadata: metadata,
|
||
is_active: document.getElementById('iduserIsActive').checked
|
||
};
|
||
|
||
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 = `
|
||
<div class="success">
|
||
<i class="fas fa-check-circle"></i>
|
||
Идентификатор успешно ${isEdit ? 'обновлен' : 'создан'}!
|
||
</div>
|
||
`;
|
||
|
||
// Обновляем список идентификаторов
|
||
setTimeout(() => {
|
||
closeIdUserModal();
|
||
loadIdUsers();
|
||
}, 1500);
|
||
|
||
} catch (error) {
|
||
console.error('Ошибка сохранения идентификатора:', error);
|
||
document.getElementById('iduserMessage').innerHTML = `
|
||
<div class="error">
|
||
<i class="fas fa-exclamation-circle"></i>
|
||
Ошибка: ${error.message}
|
||
</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// Подтверждение удаления идентификатора
|
||
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}" пользователя "${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 += `<button class="page-btn" ${currentPage[type] === 1 ? 'disabled' : ''} onclick="changePage('${type}', ${currentPage[type] - 1})">
|
||
<i class="fas fa-chevron-left"></i>
|
||
</button>`;
|
||
|
||
// Номера страниц
|
||
for (let i = 1; i <= totalPages; i++) {
|
||
if (i === 1 || i === totalPages || (i >= currentPage[type] - 2 && i <= currentPage[type] + 2)) {
|
||
html += `<button class="page-btn ${currentPage[type] === i ? 'active' : ''}" onclick="changePage('${type}', ${i})">
|
||
${i}
|
||
</button>`;
|
||
} else if (i === currentPage[type] - 3 || i === currentPage[type] + 3) {
|
||
html += `<span class="page-btn" style="border: none; background: none;">...</span>`;
|
||
}
|
||
}
|
||
|
||
// Кнопка "Вперед"
|
||
html += `<button class="page-btn" ${currentPage[type] === totalPages ? 'disabled' : ''} onclick="changePage('${type}', ${currentPage[type] + 1})">
|
||
<i class="fas fa-chevron-right"></i>
|
||
</button>`;
|
||
|
||
// Информация о странице
|
||
html += `<span style="margin-left: 20px; color: #718096;">
|
||
Страница ${currentPage[type]} из ${totalPages}
|
||
</span>`;
|
||
|
||
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;
|
||
}
|