doc
This commit is contained in:
856
public/admin-doc.html
Normal file
856
public/admin-doc.html
Normal file
@@ -0,0 +1,856 @@
|
||||
<!-- public/admin-doc.html -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Управление группами пользователей | CRM</title>
|
||||
<link rel="stylesheet" href="/styles.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
:root {
|
||||
--admin-color: #e74c3c;
|
||||
--secretary-color: #3498db;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
margin: 0;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
margin-bottom: 20px;
|
||||
background: white;
|
||||
padding: 5px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 12px 24px;
|
||||
border: none;
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
background: #3498db;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
display: none;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.content-section.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.group-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.group-color {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.group-color.admin {
|
||||
background: var(--admin-color);
|
||||
}
|
||||
|
||||
.group-color.secretary {
|
||||
background: var(--secretary-color);
|
||||
}
|
||||
|
||||
.users-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.user-card {
|
||||
background: white;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.user-card:hover {
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.user-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #3498db;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.group-badges {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.group-badge {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.group-badge.admin {
|
||||
background: var(--admin-color);
|
||||
}
|
||||
|
||||
.group-badge.secretary {
|
||||
background: var(--secretary-color);
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #3498db;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-danger:hover {
|
||||
background: #c0392b;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: #27ae60;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-success:hover {
|
||||
background: #229954;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.loading i {
|
||||
font-size: 24px;
|
||||
margin-bottom: 10px;
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding: 10px 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.stats {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
background: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #3498db;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.no-users {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.users-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.stats {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1><i class="fas fa-users-cog"></i> Управление группами пользователей</h1>
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-primary" onclick="refreshAllData()">
|
||||
<i class="fas fa-sync-alt"></i> Обновить
|
||||
</button>
|
||||
<button class="btn btn-success" onclick="goBack()">
|
||||
<i class="fas fa-arrow-left"></i> Назад в CRM
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab active" onclick="showTab('secretary')">
|
||||
<i class="fas fa-file-signature"></i> Секретари
|
||||
</button>
|
||||
<button class="tab" onclick="showTab('administration')">
|
||||
<i class="fas fa-user-shield"></i> Администрация
|
||||
</button>
|
||||
<button class="tab" onclick="showTab('all-users')">
|
||||
<i class="fas fa-users"></i> Все пользователи
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Секретари -->
|
||||
<div id="secretary-section" class="content-section active">
|
||||
<div class="group-info">
|
||||
<div class="group-color secretary"></div>
|
||||
<div>
|
||||
<h3>Группа "Секретарь"</h3>
|
||||
<p>Пользователи этой группы могут согласовывать документы в системе</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
<input type="text" id="secretary-search" class="search-input"
|
||||
placeholder="Поиск пользователей..." onkeyup="filterUsers('secretary')">
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number" id="secretary-count">0</div>
|
||||
<div class="stat-label">Всего пользователей</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number" id="secretary-in-group">0</div>
|
||||
<div class="stat-label">В группе "Секретарь"</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="secretary-users" class="users-container">
|
||||
<div class="loading">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<p>Загрузка пользователей...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Администрация -->
|
||||
<div id="administration-section" class="content-section">
|
||||
<div class="group-info">
|
||||
<div class="group-color admin"></div>
|
||||
<div>
|
||||
<h3>Группа "Администрация"</h3>
|
||||
<p>Пользователи этой группы имеют права администратора в системе</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="search-box">
|
||||
<input type="text" id="admin-search" class="search-input"
|
||||
placeholder="Поиск пользователей..." onkeyup="filterUsers('admin')">
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number" id="admin-count">0</div>
|
||||
<div class="stat-label">Всего пользователей</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number" id="admin-in-group">0</div>
|
||||
<div class="stat-label">В группе "Администрация"</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="admin-users" class="users-container">
|
||||
<div class="loading">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<p>Загрузка пользователей...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Все пользователи -->
|
||||
<div id="all-users-section" class="content-section">
|
||||
<div class="search-box">
|
||||
<input type="text" id="all-search" class="search-input"
|
||||
placeholder="Поиск пользователей..." onkeyup="filterUsers('all')">
|
||||
</div>
|
||||
|
||||
<div class="stats">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number" id="total-users">0</div>
|
||||
<div class="stat-label">Всего пользователей</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number" id="admins-count">0</div>
|
||||
<div class="stat-label">Администраторы</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number" id="secretaries-count">0</div>
|
||||
<div class="stat-label">Секретари</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="all-users" class="users-container">
|
||||
<div class="loading">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
<p>Загрузка пользователей...</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let currentTab = 'secretary';
|
||||
let allUsers = [];
|
||||
let secretaryGroupId = null;
|
||||
let adminGroupId = null;
|
||||
|
||||
// Проверка авторизации
|
||||
async function checkAuth() {
|
||||
try {
|
||||
const response = await fetch('/api/user');
|
||||
if (response.status === 401) {
|
||||
window.location.href = '/';
|
||||
return false;
|
||||
}
|
||||
const data = await response.json();
|
||||
if (data.user.role !== 'admin') {
|
||||
alert('Доступ запрещен. Требуются права администратора.');
|
||||
window.location.href = '/';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Ошибка проверки авторизации:', error);
|
||||
window.location.href = '/';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Загрузка данных
|
||||
async function loadData() {
|
||||
if (!await checkAuth()) return;
|
||||
|
||||
try {
|
||||
// Загружаем группы
|
||||
const groupsResponse = await fetch('/api/groups');
|
||||
const groups = await groupsResponse.json();
|
||||
|
||||
// Находим ID групп
|
||||
secretaryGroupId = groups.find(g => g.name === 'Секретарь')?.id;
|
||||
adminGroupId = groups.find(g => g.name === 'Администрация')?.id;
|
||||
|
||||
if (!secretaryGroupId) {
|
||||
console.warn('Группа "Секретарь" не найдена');
|
||||
}
|
||||
|
||||
if (!adminGroupId) {
|
||||
console.warn('Группа "Администрация" не найдена');
|
||||
}
|
||||
|
||||
// Загружаем всех пользователей
|
||||
const usersResponse = await fetch('/api/users/all');
|
||||
const users = await usersResponse.json();
|
||||
|
||||
allUsers = users;
|
||||
|
||||
// Обновляем статистику
|
||||
updateStats();
|
||||
|
||||
// Отображаем пользователей
|
||||
renderUsers();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Ошибка загрузки данных:', error);
|
||||
showError('Не удалось загрузить данные');
|
||||
}
|
||||
}
|
||||
|
||||
// Обновление статистики
|
||||
function updateStats() {
|
||||
// Статистика для секретарей
|
||||
const secretaryUsers = allUsers.filter(u => u.groups?.some(g => g.group_name === 'Секретарь'));
|
||||
document.getElementById('secretary-count').textContent = allUsers.length;
|
||||
document.getElementById('secretary-in-group').textContent = secretaryUsers.length;
|
||||
|
||||
// Статистика для администрации
|
||||
const adminUsers = allUsers.filter(u => u.groups?.some(g => g.group_name === 'Администрация'));
|
||||
document.getElementById('admin-count').textContent = allUsers.length;
|
||||
document.getElementById('admin-in-group').textContent = adminUsers.length;
|
||||
|
||||
// Общая статистика
|
||||
document.getElementById('total-users').textContent = allUsers.length;
|
||||
document.getElementById('admins-count').textContent = adminUsers.length;
|
||||
document.getElementById('secretaries-count').textContent = secretaryUsers.length;
|
||||
}
|
||||
|
||||
// Отображение пользователей
|
||||
function renderUsers() {
|
||||
renderSecretaryUsers();
|
||||
renderAdminUsers();
|
||||
renderAllUsers();
|
||||
}
|
||||
|
||||
// Отображение пользователей для секретарей
|
||||
function renderSecretaryUsers() {
|
||||
const container = document.getElementById('secretary-users');
|
||||
const searchTerm = document.getElementById('secretary-search').value.toLowerCase();
|
||||
|
||||
const filteredUsers = allUsers.filter(user =>
|
||||
user.name.toLowerCase().includes(searchTerm) ||
|
||||
user.login.toLowerCase().includes(searchTerm) ||
|
||||
user.email.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
|
||||
if (filteredUsers.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="no-users">
|
||||
<i class="fas fa-users-slash" style="font-size: 48px; color: #ccc; margin-bottom: 15px;"></i>
|
||||
<p>Пользователи не найдены</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = filteredUsers.map(user => {
|
||||
const isSecretary = user.groups?.some(g => g.group_name === 'Секретарь');
|
||||
const isAdmin = user.groups?.some(g => g.group_name === 'Администрация');
|
||||
|
||||
return `
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-avatar">${user.name.charAt(0).toUpperCase()}</div>
|
||||
<div>
|
||||
<div class="user-name">${user.name}</div>
|
||||
<div class="user-role">${user.role === 'admin' ? 'Администратор' : 'Учитель'}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-details">
|
||||
<div><i class="fas fa-user"></i> ${user.login}</div>
|
||||
<div><i class="fas fa-envelope"></i> ${user.email}</div>
|
||||
</div>
|
||||
|
||||
<div class="group-badges">
|
||||
${isSecretary ? '<span class="group-badge secretary"><i class="fas fa-file-signature"></i> Секретарь</span>' : ''}
|
||||
${isAdmin ? '<span class="group-badge admin"><i class="fas fa-user-shield"></i> Администрация</span>' : ''}
|
||||
</div>
|
||||
|
||||
<div class="user-actions">
|
||||
${isSecretary ?
|
||||
`<button class="btn btn-danger" onclick="removeFromGroup(${user.id}, 'secretary')">
|
||||
<i class="fas fa-user-minus"></i> Убрать из секретарей
|
||||
</button>` :
|
||||
`<button class="btn btn-success" onclick="addToGroup(${user.id}, 'secretary')">
|
||||
<i class="fas fa-user-plus"></i> Добавить в секретари
|
||||
</button>`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// Отображение пользователей для администрации
|
||||
function renderAdminUsers() {
|
||||
const container = document.getElementById('admin-users');
|
||||
const searchTerm = document.getElementById('admin-search').value.toLowerCase();
|
||||
|
||||
const filteredUsers = allUsers.filter(user =>
|
||||
user.name.toLowerCase().includes(searchTerm) ||
|
||||
user.login.toLowerCase().includes(searchTerm) ||
|
||||
user.email.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
|
||||
if (filteredUsers.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="no-users">
|
||||
<i class="fas fa-users-slash" style="font-size: 48px; color: #ccc; margin-bottom: 15px;"></i>
|
||||
<p>Пользователи не найдены</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = filteredUsers.map(user => {
|
||||
const isSecretary = user.groups?.some(g => g.group_name === 'Секретарь');
|
||||
const isAdmin = user.groups?.some(g => g.group_name === 'Администрация');
|
||||
|
||||
return `
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-avatar">${user.name.charAt(0).toUpperCase()}</div>
|
||||
<div>
|
||||
<div class="user-name">${user.name}</div>
|
||||
<div class="user-role">${user.role === 'admin' ? 'Администратор' : 'Учитель'}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-details">
|
||||
<div><i class="fas fa-user"></i> ${user.login}</div>
|
||||
<div><i class="fas fa-envelope"></i> ${user.email}</div>
|
||||
</div>
|
||||
|
||||
<div class="group-badges">
|
||||
${isSecretary ? '<span class="group-badge secretary"><i class="fas fa-file-signature"></i> Секретарь</span>' : ''}
|
||||
${isAdmin ? '<span class="group-badge admin"><i class="fas fa-user-shield"></i> Администрация</span>' : ''}
|
||||
</div>
|
||||
|
||||
<div class="user-actions">
|
||||
${isAdmin ?
|
||||
`<button class="btn btn-danger" onclick="removeFromGroup(${user.id}, 'admin')">
|
||||
<i class="fas fa-user-minus"></i> Убрать из администрации
|
||||
</button>` :
|
||||
`<button class="btn btn-success" onclick="addToGroup(${user.id}, 'admin')">
|
||||
<i class="fas fa-user-plus"></i> Добавить в администрацию
|
||||
</button>`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// Отображение всех пользователей
|
||||
function renderAllUsers() {
|
||||
const container = document.getElementById('all-users');
|
||||
const searchTerm = document.getElementById('all-search').value.toLowerCase();
|
||||
|
||||
const filteredUsers = allUsers.filter(user =>
|
||||
user.name.toLowerCase().includes(searchTerm) ||
|
||||
user.login.toLowerCase().includes(searchTerm) ||
|
||||
user.email.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
|
||||
if (filteredUsers.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="no-users">
|
||||
<i class="fas fa-users-slash" style="font-size: 48px; color: #ccc; margin-bottom: 15px;"></i>
|
||||
<p>Пользователи не найдены</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = filteredUsers.map(user => {
|
||||
const isSecretary = user.groups?.some(g => g.group_name === 'Секретарь');
|
||||
const isAdmin = user.groups?.some(g => g.group_name === 'Администрация');
|
||||
|
||||
return `
|
||||
<div class="user-card">
|
||||
<div class="user-header">
|
||||
<div class="user-avatar">${user.name.charAt(0).toUpperCase()}</div>
|
||||
<div>
|
||||
<div class="user-name">${user.name}</div>
|
||||
<div class="user-role">${user.role === 'admin' ? 'Администратор' : 'Учитель'}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-details">
|
||||
<div><i class="fas fa-user"></i> ${user.login}</div>
|
||||
<div><i class="fas fa-envelope"></i> ${user.email}</div>
|
||||
</div>
|
||||
|
||||
<div class="group-badges">
|
||||
${isSecretary ? '<span class="group-badge secretary"><i class="fas fa-file-signature"></i> Секретарь</span>' : ''}
|
||||
${isAdmin ? '<span class="group-badge admin"><i class="fas fa-user-shield"></i> Администрация</span>' : ''}
|
||||
</div>
|
||||
|
||||
<div class="user-actions">
|
||||
${isSecretary ?
|
||||
`<button class="btn btn-danger" onclick="removeFromGroup(${user.id}, 'secretary')">
|
||||
<i class="fas fa-user-minus"></i> Убрать из секретарей
|
||||
</button>` :
|
||||
`<button class="btn btn-success" onclick="addToGroup(${user.id}, 'secretary')">
|
||||
<i class="fas fa-user-plus"></i> В секретари
|
||||
</button>`
|
||||
}
|
||||
${isAdmin ?
|
||||
`<button class="btn btn-danger" onclick="removeFromGroup(${user.id}, 'admin')">
|
||||
<i class="fas fa-user-minus"></i> Убрать из администрации
|
||||
</button>` :
|
||||
`<button class="btn btn-primary" onclick="addToGroup(${user.id}, 'admin')">
|
||||
<i class="fas fa-user-plus"></i> В администрацию
|
||||
</button>`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
// Фильтрация пользователей
|
||||
function filterUsers(section) {
|
||||
switch(section) {
|
||||
case 'secretary':
|
||||
renderSecretaryUsers();
|
||||
break;
|
||||
case 'admin':
|
||||
renderAdminUsers();
|
||||
break;
|
||||
case 'all':
|
||||
renderAllUsers();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Показать вкладку
|
||||
function showTab(tabName) {
|
||||
currentTab = tabName;
|
||||
|
||||
// Обновляем активные вкладки
|
||||
document.querySelectorAll('.tab').forEach(tab => {
|
||||
tab.classList.remove('active');
|
||||
});
|
||||
document.querySelectorAll('.tab').forEach(tab => {
|
||||
if (tab.onclick.toString().includes(tabName)) {
|
||||
tab.classList.add('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Обновляем активные секции
|
||||
document.querySelectorAll('.content-section').forEach(section => {
|
||||
section.classList.remove('active');
|
||||
});
|
||||
|
||||
switch(tabName) {
|
||||
case 'secretary':
|
||||
document.getElementById('secretary-section').classList.add('active');
|
||||
break;
|
||||
case 'administration':
|
||||
document.getElementById('administration-section').classList.add('active');
|
||||
break;
|
||||
case 'all-users':
|
||||
document.getElementById('all-users-section').classList.add('active');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Добавить пользователя в группу
|
||||
async function addToGroup(userId, groupType) {
|
||||
if (!await checkAuth()) return;
|
||||
|
||||
const groupName = groupType === 'secretary' ? 'Секретарь' : 'Администрация';
|
||||
const groupId = groupType === 'secretary' ? secretaryGroupId : adminGroupId;
|
||||
|
||||
if (!groupId) {
|
||||
showError(`Группа "${groupName}" не найдена`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm(`Добавить пользователя в группу "${groupName}"?`)) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/groups/${groupId}/users/${userId}`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showSuccess(`Пользователь добавлен в группу "${groupName}"`);
|
||||
await refreshAllData();
|
||||
} else {
|
||||
const error = await response.text();
|
||||
showError(error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка добавления в группу:', error);
|
||||
showError('Не удалось добавить пользователя в группу');
|
||||
}
|
||||
}
|
||||
|
||||
// Удалить пользователя из группы
|
||||
async function removeFromGroup(userId, groupType) {
|
||||
if (!await checkAuth()) return;
|
||||
|
||||
const groupName = groupType === 'secretary' ? 'Секретарь' : 'Администрация';
|
||||
const groupId = groupType === 'secretary' ? secretaryGroupId : adminGroupId;
|
||||
|
||||
if (!groupId) {
|
||||
showError(`Группа "${groupName}" не найдена`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm(`Убрать пользователя из группы "${groupName}"?`)) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/groups/${groupId}/users/${userId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
showSuccess(`Пользователь убран из группы "${groupName}"`);
|
||||
await refreshAllData();
|
||||
} else {
|
||||
const error = await response.text();
|
||||
showError(error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка удаления из группы:', error);
|
||||
showError('Не удалось убрать пользователя из группы');
|
||||
}
|
||||
}
|
||||
|
||||
// Обновить все данные
|
||||
async function refreshAllData() {
|
||||
await loadData();
|
||||
showSuccess('Данные обновлены');
|
||||
}
|
||||
|
||||
// Показать сообщение об ошибке
|
||||
function showError(message) {
|
||||
alert('Ошибка: ' + message);
|
||||
}
|
||||
|
||||
// Показать сообщение об успехе
|
||||
function showSuccess(message) {
|
||||
// Можно заменить на более красивый toast
|
||||
alert('Успех: ' + message);
|
||||
}
|
||||
|
||||
// Вернуться в CRM
|
||||
function goBack() {
|
||||
window.location.href = '/admin';
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
if (await checkAuth()) {
|
||||
await loadData();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user