Files
b_analysis/committees_editor.html
2026-06-15 21:04:54 +03:00

404 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Редактор комитетов</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300;400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', sans-serif; background: #f8fafc; color: #0f172a; line-height: 1.5; padding: 2rem 1rem; }
.container { max-width: 1200px; margin: 0 auto; }
.header { text-align: center; margin-bottom: 2rem; }
.header h1 { font-size: 2rem; font-weight: 700; background: linear-gradient(135deg, #1e3a5f, #0f2b40); -webkit-background-clip: text; background-clip: text; color: transparent; }
.header p { color: #475569; margin-top: 0.5rem; }
.back-link {
display: inline-block;
margin-bottom: 1.5rem;
color: #1e3a5f;
text-decoration: none;
font-weight: 500;
}
.back-link:hover { text-decoration: underline; }
.committee-selector {
background: white;
border-radius: 16px;
padding: 1rem;
margin-bottom: 1.5rem;
border: 1px solid #eef2f6;
display: flex;
gap: 1rem;
align-items: center;
flex-wrap: wrap;
}
.committee-selector select {
flex: 2;
min-width: 250px;
padding: 10px 14px;
border-radius: 12px;
border: 1px solid #cbd5e1;
font-family: 'Inter', sans-serif;
font-size: 0.9rem;
}
.committee-selector button {
background: #1e3a5f;
color: white;
border: none;
padding: 10px 20px;
border-radius: 12px;
cursor: pointer;
font-weight: 500;
}
.editor-form {
background: white;
border-radius: 24px;
padding: 1.5rem;
border: 1px solid #eef2f6;
}
.form-section {
margin-bottom: 2rem;
padding-bottom: 1rem;
border-bottom: 1px solid #eef2f6;
}
.section-title {
font-weight: 700;
font-size: 1rem;
color: #1e3a5f;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 8px;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
font-weight: 600;
font-size: 0.8rem;
color: #475569;
margin-bottom: 0.3rem;
}
.form-group input, .form-group textarea, .form-group select {
width: 100%;
padding: 10px 12px;
border-radius: 10px;
border: 1px solid #cbd5e1;
font-family: 'Inter', sans-serif;
font-size: 0.85rem;
}
.form-group textarea {
min-height: 100px;
resize: vertical;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
.form-3col {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}
.status-select {
width: auto;
display: inline-block;
}
.save-btn {
background: #10b981;
color: white;
border: none;
padding: 12px 24px;
border-radius: 12px;
font-weight: 600;
cursor: pointer;
margin-top: 1rem;
font-size: 1rem;
}
.save-btn:hover { background: #059669; }
.toast {
position: fixed;
bottom: 30px;
right: 30px;
background: #15803d;
color: white;
padding: 12px 20px;
border-radius: 50px;
z-index: 1000;
display: none;
}
.toast.error { background: #dc2626; }
@media (max-width: 700px) {
.form-row, .form-3col { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<div class="container">
<a href="/committees.html" class="back-link"><i class="fas fa-arrow-left"></i> Назад к списку комитетов</a>
<div class="header">
<h1><i class="fas fa-edit"></i> Редактор комитетов</h1>
<p>Редактирование информации о руководителях и кандидатах комитетов</p>
</div>
<div class="committee-selector">
<select id="committeeSelect">
<option value="">-- Выберите комитет --</option>
</select>
<button id="loadCommitteeBtn"><i class="fas fa-folder-open"></i> Загрузить</button>
</div>
<div id="editorContainer" style="display: none;">
<form id="editorForm" class="editor-form">
<div class="form-section">
<div class="section-title"><i class="fas fa-info-circle"></i> Информация о комитете</div>
<div class="form-group">
<label>Название комитета</label>
<input type="text" id="committeeName" readonly style="background:#f1f5f9;">
</div>
<div class="form-group">
<label>Описание деятельности</label>
<textarea id="committeeDescription" readonly style="background:#f1f5f9;"></textarea>
</div>
</div>
<div class="form-section">
<div class="section-title"><i class="fas fa-user-tie"></i> Текущий руководитель</div>
<div class="form-row">
<div class="form-group">
<label>ФИО руководителя</label>
<input type="text" id="leaderName" placeholder="Иванов Иван Иванович">
</div>
<div class="form-group">
<label>Должность / Регалии</label>
<input type="text" id="leaderTitle" placeholder="Председатель комитета">
</div>
</div>
<div class="form-3col">
<div class="form-group">
<label>Email</label>
<input type="email" id="leaderEmail" placeholder="email@example.com">
</div>
<div class="form-group">
<label>Телефон</label>
<input type="text" id="leaderPhone" placeholder="+7 (xxx) xxx-xx-xx">
</div>
<div class="form-group">
<label>Telegram</label>
<input type="text" id="leaderTelegram" placeholder="@username">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Статус активности</label>
<select id="leaderStatus" class="status-select">
<option value="active">Активен</option>
<option value="medium">Средняя активность</option>
<option value="inactive">Не активен</option>
</select>
</div>
<div class="form-group">
<label>Дополнительная информация</label>
<input type="text" id="leaderAdditional" placeholder="Член правления, эксперт и т.д.">
</div>
</div>
</div>
<div class="form-section">
<div class="section-title"><i class="fas fa-user-plus"></i> Кандидат на должность руководителя</div>
<div class="form-row">
<div class="form-group">
<label>ФИО кандидата</label>
<input type="text" id="candidateName" placeholder="Петров Петр Петрович">
</div>
<div class="form-group">
<label>Должность / Регалии</label>
<input type="text" id="candidateTitle" placeholder="Заместитель председателя">
</div>
</div>
<div class="form-3col">
<div class="form-group">
<label>Email</label>
<input type="email" id="candidateEmail" placeholder="email@example.com">
</div>
<div class="form-group">
<label>Телефон</label>
<input type="text" id="candidatePhone" placeholder="+7 (xxx) xxx-xx-xx">
</div>
<div class="form-group">
<label>Telegram</label>
<input type="text" id="candidateTelegram" placeholder="@username">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Статус кандидата</label>
<select id="candidateStatus" class="status-select">
<option value="candidate">Кандидат</option>
<option value="active">Активен</option>
<option value="medium">Средняя активность</option>
<option value="inactive">Не активен</option>
</select>
</div>
<div class="form-group">
<label>Дополнительная информация</label>
<input type="text" id="candidateAdditional" placeholder="Опыт работы, достижения">
</div>
</div>
</div>
<button type="submit" class="save-btn"><i class="fas fa-save"></i> Сохранить изменения</button>
</form>
</div>
</div>
<div id="toast" class="toast">✅ Данные сохранены</div>
<script>
let committeesData = [];
let currentCommitteeIndex = -1;
let currentFile = 'opora_committees.json';
function showToast(msg, isError = false) {
const toast = document.getElementById('toast');
toast.textContent = msg;
toast.className = isError ? 'toast error' : 'toast';
toast.style.display = 'block';
setTimeout(() => { toast.style.display = 'none'; }, 2500);
}
async function loadCommittees() {
try {
const response = await fetch(`/committees/${currentFile}`);
if (response.ok) {
committeesData = await response.json();
populateSelect();
showToast('Комитеты загружены');
} else {
showToast('Ошибка загрузки файла комитетов', true);
}
} catch (error) {
showToast('Ошибка загрузки: ' + error.message, true);
}
}
function populateSelect() {
const select = document.getElementById('committeeSelect');
select.innerHTML = '<option value="">-- Выберите комитет --</option>';
committeesData.forEach((committee, idx) => {
const option = document.createElement('option');
option.value = idx;
option.textContent = committee.name;
select.appendChild(option);
});
}
function loadCommitteeToForm(index) {
const committee = committeesData[index];
if (!committee) return;
currentCommitteeIndex = index;
document.getElementById('committeeName').value = committee.name;
document.getElementById('committeeDescription').value = committee.description;
// Текущий руководитель
document.getElementById('leaderName').value = committee.current_leader?.name || '';
document.getElementById('leaderTitle').value = committee.current_leader?.title || '';
document.getElementById('leaderEmail').value = committee.current_leader?.contacts?.email || '';
document.getElementById('leaderPhone').value = committee.current_leader?.contacts?.phone || '';
document.getElementById('leaderTelegram').value = committee.current_leader?.contacts?.telegram || '';
document.getElementById('leaderStatus').value = committee.current_leader?.status || 'active';
document.getElementById('leaderAdditional').value = committee.current_leader?.additional_info || '';
// Кандидат
document.getElementById('candidateName').value = committee.candidate_for_leader?.name || '';
document.getElementById('candidateTitle').value = committee.candidate_for_leader?.title || '';
document.getElementById('candidateEmail').value = committee.candidate_for_leader?.contacts?.email || '';
document.getElementById('candidatePhone').value = committee.candidate_for_leader?.contacts?.phone || '';
document.getElementById('candidateTelegram').value = committee.candidate_for_leader?.contacts?.telegram || '';
document.getElementById('candidateStatus').value = committee.candidate_for_leader?.status || 'candidate';
document.getElementById('candidateAdditional').value = committee.candidate_for_leader?.additional_info || '';
document.getElementById('editorContainer').style.display = 'block';
}
function saveCommittee() {
const committee = committeesData[currentCommitteeIndex];
if (!committee) return;
// Сохраняем данные текущего руководителя
committee.current_leader = {
name: document.getElementById('leaderName').value,
contacts: {
email: document.getElementById('leaderEmail').value,
phone: document.getElementById('leaderPhone').value,
telegram: document.getElementById('leaderTelegram').value
},
title: document.getElementById('leaderTitle').value,
status: document.getElementById('leaderStatus').value,
additional_info: document.getElementById('leaderAdditional').value
};
// Сохраняем данные кандидата
committee.candidate_for_leader = {
name: document.getElementById('candidateName').value,
contacts: {
email: document.getElementById('candidateEmail').value,
phone: document.getElementById('candidatePhone').value,
telegram: document.getElementById('candidateTelegram').value
},
title: document.getElementById('candidateTitle').value,
status: document.getElementById('candidateStatus').value,
additional_info: document.getElementById('candidateAdditional').value
};
saveToServer();
}
async function saveToServer() {
try {
const response = await fetch(`/save_committees/${currentFile}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(committeesData)
});
const result = await response.json();
if (result.success) {
showToast('✅ Данные сохранены');
} else {
showToast('❌ Ошибка сохранения: ' + result.message, true);
}
} catch (error) {
showToast('❌ Ошибка соединения: ' + error.message, true);
}
}
document.getElementById('loadCommitteeBtn').addEventListener('click', () => {
const idx = document.getElementById('committeeSelect').value;
if (idx !== '') {
loadCommitteeToForm(parseInt(idx));
} else {
showToast('Выберите комитет', true);
}
});
document.getElementById('editorForm').addEventListener('submit', (e) => {
e.preventDefault();
saveCommittee();
});
// Загрузка данных
loadCommittees();
</script>
</body>
</html>