406 lines
26 KiB
HTML
406 lines
26 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: 1400px; 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; }
|
||
|
||
.admin-toggle {
|
||
position: fixed; bottom: 20px; right: 20px; background: #1e3a5f; color: white;
|
||
border: none; border-radius: 50px; padding: 12px 20px; cursor: pointer;
|
||
font-weight: 600; z-index: 1000; box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
||
display: flex; align-items: center; gap: 8px;
|
||
}
|
||
.admin-toggle:hover { background: #0f2b40; transform: scale(1.02); }
|
||
|
||
.tabs { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.75rem; margin-bottom: 2rem; border-bottom: 2px solid #e2e8f0; padding-bottom: 0.75rem; }
|
||
.tab-btn { background: transparent; border: none; font-size: 0.95rem; font-weight: 600; padding: 0.6rem 1.5rem; border-radius: 40px; cursor: pointer; color: #475569; transition: all 0.2s; }
|
||
.tab-btn i { margin-right: 8px; }
|
||
.tab-btn.active { background: #1e3a5f; color: white; }
|
||
.tab-panel { display: none; animation: fadeIn 0.25s ease; }
|
||
.tab-panel.active-panel { display: block; }
|
||
@keyframes fadeIn { from { opacity: 0; transform: translateY(5px);} to { opacity: 1; transform: translateY(0);} }
|
||
|
||
.org-grid { display: flex; flex-direction: column; gap: 1.5rem; }
|
||
.org-card { background: white; border-radius: 24px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); border: 1px solid #eef2f6; overflow: hidden; transition: all 0.2s; }
|
||
.org-card:hover { box-shadow: 0 8px 25px rgba(0,0,0,0.08); }
|
||
.org-header { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; padding: 1.2rem 1.5rem; background: #ffffff; border-bottom: 1px solid #f0f2f5; cursor: pointer; }
|
||
.org-title { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
||
.org-name { font-weight: 700; font-size: 1.2rem; color: #0f172a; }
|
||
.priority-badge { background: #eef2ff; color: #1e40af; border-radius: 40px; padding: 0.25rem 0.8rem; font-size: 0.7rem; font-weight: 600; }
|
||
.status-badge { border-radius: 40px; padding: 0.25rem 0.8rem; font-size: 0.7rem; font-weight: 600; }
|
||
.status-active { background: #dcfce7; color: #15803d; }
|
||
.status-warning { background: #fff3e3; color: #b45309; }
|
||
.toggle-icon { font-size: 1.2rem; color: #64748b; transition: transform 0.2s; }
|
||
.org-details { padding: 1.5rem; background: #fefefe; border-top: 1px solid #f1f5f9; display: none; }
|
||
.org-details.open { display: block; }
|
||
|
||
/* Стили для комитетов */
|
||
.committees-section { margin-top: 1.5rem; }
|
||
.committees-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 1rem; margin-top: 1rem; }
|
||
.committee-card { background: #f8fafc; border-radius: 16px; border: 1px solid #e2e8f0; overflow: hidden; transition: all 0.2s; }
|
||
.committee-card:hover { border-color: #cbd5e1; background: #fefefe; }
|
||
.committee-header { display: flex; justify-content: space-between; align-items: center; padding: 1rem; background: #f1f5f9; cursor: pointer; }
|
||
.committee-name { font-weight: 600; color: #1e3a5f; }
|
||
.committee-status { font-size: 0.7rem; padding: 2px 8px; border-radius: 20px; }
|
||
.status-active { background: #dcfce7; color: #15803d; }
|
||
.status-medium { background: #fef3c7; color: #b45309; }
|
||
.status-inactive { background: #fee2e2; color: #dc2626; }
|
||
.committee-details { padding: 1rem; display: none; border-top: 1px solid #e2e8f0; }
|
||
.committee-details.open { display: block; }
|
||
.leader-info { background: white; border-radius: 12px; padding: 0.75rem; margin-bottom: 0.75rem; border-left: 3px solid #1e3a5f; }
|
||
.leader-label { font-size: 0.7rem; text-transform: uppercase; color: #6c86a3; font-weight: 600; }
|
||
.leader-name { font-weight: 700; color: #0f172a; margin: 4px 0; }
|
||
.leader-contacts { font-size: 0.8rem; color: #475569; }
|
||
.leader-contacts a { color: #1e3a5f; text-decoration: none; }
|
||
.leader-contacts a:hover { text-decoration: underline; }
|
||
.committee-description { font-size: 0.85rem; color: #334155; line-height: 1.5; margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid #e2e8f0; }
|
||
|
||
.details-section { margin-bottom: 1.5rem; }
|
||
.section-title { font-weight: 700; font-size: 0.9rem; text-transform: uppercase; letter-spacing: 0.5px; color: #5b6e8c; margin-bottom: 0.8rem; border-left: 3px solid #1e3a5f; padding-left: 10px; }
|
||
.section-title i { margin-right: 8px; }
|
||
|
||
.info-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; }
|
||
.info-card { background: #f8fafc; border-radius: 16px; padding: 0.8rem 1rem; transition: all 0.2s; }
|
||
.info-card .label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.3px; font-weight: 600; color: #6c86a3; margin-bottom: 0.3rem; }
|
||
.info-card .value { font-size: 0.9rem; font-weight: 500; color: #1e2a44; line-height: 1.4; word-break: break-word; }
|
||
|
||
.full-width { grid-column: 1 / -1; }
|
||
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 5px; }
|
||
.tag { background: #e2e8f0; padding: 3px 10px; border-radius: 20px; font-size: 0.75rem; color: #334155; }
|
||
|
||
.links-list { display: flex; flex-wrap: wrap; gap: 8px; }
|
||
.resource-link { display: inline-block; background: #eef2ff; color: #1e3a5f; padding: 4px 12px; border-radius: 20px; font-size: 0.75rem; text-decoration: none; }
|
||
.resource-link:hover { background: #1e3a5f; color: white; }
|
||
|
||
.summary-wrapper { overflow-x: auto; background: white; border-radius: 24px; }
|
||
.summary-table { width: 100%; border-collapse: collapse; }
|
||
.summary-table th { background: #f1f5f9; padding: 14px; text-align: left; font-weight: 600; font-size: 0.85rem; }
|
||
.summary-table td { padding: 14px; border-bottom: 1px solid #eef2f8; font-size: 0.85rem; vertical-align: middle; }
|
||
.summary-table tr:hover { background: #fafcff; }
|
||
|
||
.footer-note { margin-top: 2rem; text-align: center; font-size: 0.75rem; color: #6c86a3; }
|
||
.loading { text-align: center; padding: 3rem; color: #64748b; }
|
||
|
||
@media (max-width: 750px) {
|
||
.committees-grid { grid-template-columns: 1fr; }
|
||
.info-grid { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="header">
|
||
<h1><i class="fas fa-chart-line"></i> Бизнес-объединения ДНР</h1>
|
||
<p>Аналитический обзор с детальной информацией по комитетам организаций</p>
|
||
</div>
|
||
|
||
<div class="tabs">
|
||
<button class="tab-btn active" data-tab="detailed"><i class="fas fa-chart-simple"></i> Детальный анализ</button>
|
||
<button class="tab-btn" data-tab="summary"><i class="fas fa-table-list"></i> Сводная таблица</button>
|
||
<div>
|
||
<a href="/committees.html" style="display: inline-flex; align-items: center; gap: 8px; background: #1e3a5f; color: white; padding: 8px 20px; border-radius: 40px; text-decoration: none; font-size: 0.9rem;">
|
||
<i class="fas fa-users"></i> Комитеты организаций
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div id="detailedPanel" class="tab-panel active-panel">
|
||
<div id="detailedContainer" class="org-grid"><div class="loading"><i class="fas fa-spinner fa-spin"></i> Загрузка...</div></div>
|
||
</div>
|
||
|
||
<div id="summaryPanel" class="tab-panel">
|
||
<div class="summary-wrapper">
|
||
<table class="summary-table">
|
||
<thead>
|
||
<tr><th>Название</th><th>Тип</th><th>Статус</th><th>Членство</th><th>Приоритет</th><th>Ресурсы</th></thead>
|
||
<tbody id="summaryTableBody"><td><td colspan="6" class="loading">Загрузка...</tr></tr></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer-note">
|
||
<i class="fas fa-info-circle"></i> Данные хранятся в файле data.json. Комитеты организаций загружаются из папки committees/.
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
let currentData = null;
|
||
let committeesData = {};
|
||
|
||
async function loadDataFromServer() {
|
||
try {
|
||
const response = await fetch('/data.json');
|
||
if (!response.ok) throw new Error('Ошибка загрузки');
|
||
currentData = await response.json();
|
||
if (!currentData.organizations) currentData.organizations = [];
|
||
if (!currentData.additionalOrganizations) currentData.additionalOrganizations = [];
|
||
|
||
// Загружаем комитеты для организаций
|
||
await loadCommittees();
|
||
|
||
renderDetailed();
|
||
renderSummaryTable();
|
||
} catch (error) {
|
||
console.error(error);
|
||
document.getElementById('detailedContainer').innerHTML = '<div class="loading" style="color:red;">❌ Ошибка загрузки данных. Убедитесь, что файл data.json существует.</div>';
|
||
}
|
||
}
|
||
|
||
async function loadCommittees() {
|
||
// Загружаем комитеты для ОПОРЫ РОССИИ
|
||
try {
|
||
const response = await fetch('/committees/opora_committees.json');
|
||
if (response.ok) {
|
||
committeesData['opora'] = await response.json();
|
||
}
|
||
} catch (error) {
|
||
console.log('Файл комитетов ОПОРЫ РОССИИ не найден');
|
||
committeesData['opora'] = [];
|
||
}
|
||
|
||
// Здесь можно добавить загрузку комитетов для других организаций
|
||
// Например, для Деловой России, СПП ДНР и т.д.
|
||
}
|
||
|
||
function getCommitteesForOrg(orgName) {
|
||
if (orgName.includes('ОПОРА РОССИИ')) {
|
||
return committeesData['opora'] || [];
|
||
}
|
||
return [];
|
||
}
|
||
|
||
function renderLeaderInfo(leader, title) {
|
||
if (!leader || !leader.name) return '<div class="leader-info"><div class="leader-label">Информация отсутствует</div></div>';
|
||
|
||
const statusMap = {
|
||
'active': 'Активен',
|
||
'medium': 'Средняя активность',
|
||
'inactive': 'Не активен',
|
||
'candidate': 'Кандидат'
|
||
};
|
||
const statusText = statusMap[leader.status] || leader.status || '—';
|
||
|
||
return `
|
||
<div class="leader-info">
|
||
<div class="leader-label">${title}</div>
|
||
<div class="leader-name">${escapeHtml(leader.name)}</div>
|
||
<div class="leader-contacts">
|
||
${leader.contacts?.email ? `<i class="fas fa-envelope"></i> <a href="mailto:${escapeHtml(leader.contacts.email)}">${escapeHtml(leader.contacts.email)}</a><br>` : ''}
|
||
${leader.contacts?.phone ? `<i class="fas fa-phone"></i> <a href="tel:${escapeHtml(leader.contacts.phone)}">${escapeHtml(leader.contacts.phone)}</a><br>` : ''}
|
||
${leader.contacts?.telegram ? `<i class="fab fa-telegram"></i> <a href="https://t.me/${escapeHtml(leader.contacts.telegram.replace('@', ''))}" target="_blank">${escapeHtml(leader.contacts.telegram)}</a><br>` : ''}
|
||
</div>
|
||
<div style="font-size:0.75rem; color:#475569; margin-top:4px;">
|
||
<span class="tag">${escapeHtml(leader.title || '—')}</span>
|
||
<span class="tag">Статус: ${statusText}</span>
|
||
</div>
|
||
${leader.additional_info ? `<div style="font-size:0.75rem; color:#6c86a3; margin-top:6px;">${escapeHtml(leader.additional_info)}</div>` : ''}
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
function renderCommittees(orgName) {
|
||
const committees = getCommitteesForOrg(orgName);
|
||
if (!committees || committees.length === 0) return '';
|
||
|
||
return `
|
||
<div class="committees-section">
|
||
<div class="section-title"><i class="fas fa-users"></i> Комитеты организации</div>
|
||
<div class="committees-grid" id="committees-${orgName.replace(/[^a-zA-Z0-9]/g, '_')}">
|
||
${committees.map((committee, idx) => `
|
||
<div class="committee-card">
|
||
<div class="committee-header" onclick="toggleCommitteeDetails('${orgName.replace(/[^a-zA-Z0-9]/g, '_')}_${idx}')">
|
||
<span class="committee-name"><i class="fas fa-folder"></i> ${escapeHtml(committee.name)}</span>
|
||
<span class="committee-status ${committee.current_leader?.status === 'active' ? 'status-active' : (committee.current_leader?.status === 'medium' ? 'status-medium' : 'status-inactive')}">
|
||
${committee.current_leader?.status === 'active' ? 'Активен' : (committee.current_leader?.status === 'medium' ? 'Средняя активность' : 'Статус не определён')}
|
||
</span>
|
||
</div>
|
||
<div class="committee-details" id="committee-details-${orgName.replace(/[^a-zA-Z0-9]/g, '_')}_${idx}">
|
||
${renderLeaderInfo(committee.current_leader, '👤 Текущий руководитель')}
|
||
${renderLeaderInfo(committee.candidate_for_leader, '👥 Кандидат на должность руководителя')}
|
||
<div class="committee-description">
|
||
<strong>О комитете:</strong><br>
|
||
${escapeHtml(committee.description.substring(0, 300))}${committee.description.length > 300 ? '...' : ''}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`).join('')}
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
function renderDetailed() {
|
||
const container = document.getElementById('detailedContainer');
|
||
if (!currentData) return;
|
||
container.innerHTML = '';
|
||
(currentData.organizations || []).forEach(org => {
|
||
const d = org.detailed || {};
|
||
const priorityText = org.priority === 'high' ? 'Высокий' : (org.priority === 'medium' ? 'Средний' : 'Низкий');
|
||
const statusClass = org.status === 'active' ? 'status-active' : 'status-warning';
|
||
const statusText = org.status === 'active' ? '✔ Действует' : '⚠️ Требует уточнения';
|
||
|
||
let allLinks = [];
|
||
if (org.resources?.links) allLinks = [...org.resources.links];
|
||
if (org.links) allLinks = [...allLinks, ...org.links];
|
||
if (org.link && org.link !== '—' && !allLinks.includes(org.link)) allLinks.push(org.link);
|
||
allLinks = allLinks.filter(l => l && l.trim() !== '');
|
||
|
||
const membersDisplay = org.membersCount || org.summaryMembership || d.membership?.count || '—';
|
||
|
||
const card = document.createElement('div');
|
||
card.className = 'org-card';
|
||
card.innerHTML = `
|
||
<div class="org-header" onclick="toggleDetails(${org.id})">
|
||
<div class="org-title">
|
||
<span class="org-name"><i class="fas fa-building"></i> ${escapeHtml(org.name)}</span>
|
||
<span class="priority-badge">⭐ Приоритет: ${priorityText}</span>
|
||
<span class="status-badge ${statusClass}">${statusText}</span>
|
||
</div>
|
||
<div class="toggle-icon"><i class="fas fa-chevron-down" id="icon-${org.id}"></i></div>
|
||
</div>
|
||
<div class="org-details" id="details-${org.id}">
|
||
<div class="details-section">
|
||
<div class="section-title"><i class="fas fa-info-circle"></i> Общая информация</div>
|
||
<div class="info-grid">
|
||
<div class="info-card"><div class="label">📌 Полное наименование</div><div class="value">${escapeHtml(d.general?.fullName || org.name)}</div></div>
|
||
<div class="info-card"><div class="label">📅 Дата создания</div><div class="value">${escapeHtml(d.general?.created || 'Не указана')}</div></div>
|
||
<div class="info-card"><div class="label">🏛️ Юридическая форма</div><div class="value">${escapeHtml(d.general?.legalForm || 'Не указана')}</div></div>
|
||
<div class="info-card"><div class="label">📍 Адрес</div><div class="value">${escapeHtml(d.general?.address || 'Не указан')}</div></div>
|
||
<div class="info-card"><div class="label">👥 Количество членов</div><div class="value">${escapeHtml(membersDisplay)}</div></div>
|
||
<div class="info-card"><div class="label">🔗 Ресурсы</div><div class="value"><div class="links-list">${allLinks.map(link => `<a href="${escapeHtml(link)}" target="_blank" class="resource-link">${escapeHtml(link.length > 40 ? link.substring(0, 40) + '...' : link)}</a>`).join('') || '—'}</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="details-section">
|
||
<div class="section-title"><i class="fas fa-users"></i> Руководство и структура</div>
|
||
<div class="info-grid">
|
||
<div class="info-card"><div class="label">👤 Руководитель</div><div class="value">${escapeHtml(d.leadership?.head || '—')}</div></div>
|
||
<div class="info-card"><div class="label">👥 Ключевые лица</div><div class="value">${escapeHtml(d.leadership?.keyPeople || '—')}</div></div>
|
||
<div class="info-card"><div class="label">🏢 Отделения</div><div class="value">${escapeHtml(d.leadership?.branches || '—')}</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="details-section">
|
||
<div class="section-title"><i class="fas fa-handshake"></i> Членство и состав</div>
|
||
<div class="info-grid">
|
||
<div class="info-card"><div class="label">📋 Критерии вступления</div><div class="value">${escapeHtml(d.membership?.criteria || '—')}</div></div>
|
||
<div class="info-card"><div class="label">💰 Членские взносы</div><div class="value">${escapeHtml(d.membership?.fees || '—')}</div></div>
|
||
<div class="info-card full-width"><div class="label">🏭 Отраслевой состав</div><div class="value"><div class="tags">${renderTags(d.membership?.sectors || org.sectors || '—')}</div></div></div>
|
||
</div>
|
||
</div>
|
||
<div class="details-section">
|
||
<div class="section-title"><i class="fas fa-chart-line"></i> Деятельность и влияние</div>
|
||
<div class="info-grid">
|
||
<div class="info-card full-width"><div class="label">🎯 Цели и задачи</div><div class="value">${escapeHtml(d.goals || '—')}</div></div>
|
||
<div class="info-card full-width"><div class="label">⚡ Основная деятельность</div><div class="value">${escapeHtml(d.activity || '—')}</div></div>
|
||
<div class="info-card"><div class="label">📧 Контакты</div><div class="value">${escapeHtml(d.resources?.contacts || '—')}</div></div>
|
||
</div>
|
||
</div>
|
||
<div class="details-section">
|
||
<div class="section-title"><i class="fas fa-chart-simple"></i> SWOT-анализ</div>
|
||
<div class="info-grid">
|
||
<div class="info-card"><div class="label">✅ Сильные стороны</div><div class="value">${escapeHtml(d.assessment?.strengths || '—')}</div></div>
|
||
<div class="info-card"><div class="label">⚠️ Слабые стороны</div><div class="value">${escapeHtml(d.assessment?.weaknesses || '—')}</div></div>
|
||
<div class="info-card full-width"><div class="label">🎯 Рекомендации</div><div class="value">${escapeHtml(d.assessment?.priority || '—')}</div></div>
|
||
</div>
|
||
</div>
|
||
${renderCommittees(org.name)}
|
||
</div>
|
||
`;
|
||
container.appendChild(card);
|
||
});
|
||
}
|
||
|
||
function renderTags(tagsStr) {
|
||
if (!tagsStr || tagsStr === '—') return '<span class="tag">—</span>';
|
||
const tags = tagsStr.split(',').map(t => t.trim());
|
||
return tags.map(tag => `<span class="tag">${escapeHtml(tag)}</span>`).join('');
|
||
}
|
||
|
||
function renderSummaryTable() {
|
||
const tbody = document.getElementById('summaryTableBody');
|
||
if (!currentData) return;
|
||
tbody.innerHTML = '';
|
||
(currentData.organizations || []).forEach(org => { appendSummaryRow(tbody, org, 'main'); });
|
||
(currentData.additionalOrganizations || []).forEach(org => { appendSummaryRow(tbody, org, 'additional'); });
|
||
}
|
||
|
||
function appendSummaryRow(tbody, org, type) {
|
||
const statusClass = org.status === 'active' ? 'status-active' : 'status-warning';
|
||
const statusText = org.status === 'active' ? 'Действует' : 'Требует уточнения';
|
||
const priorityText = org.priority === 'high' ? 'Высокий' : (org.priority === 'medium' ? 'Средний' : 'Низкий');
|
||
const displayType = type === 'main' ? (org.shortType || 'Основная') : (org.type || 'Дополнительная');
|
||
const members = org.membersCount || (type === 'main' ? (org.summaryMembership || '—') : (org.members || '—'));
|
||
|
||
let allLinks = [];
|
||
if (org.resources?.links) allLinks = [...org.resources.links];
|
||
if (org.links) allLinks = [...allLinks, ...org.links];
|
||
if (org.link && org.link !== '—') allLinks.push(org.link);
|
||
allLinks = allLinks.filter(l => l && l.trim() !== '');
|
||
|
||
let linksHtml = '—';
|
||
if (allLinks.length > 0) {
|
||
linksHtml = `<div class="links-list">${allLinks.map(link => `<a href="${escapeHtml(link)}" target="_blank" class="resource-link">${escapeHtml(link.length > 40 ? link.substring(0, 40) + '...' : link)}</a>`).join('')}</div>`;
|
||
}
|
||
|
||
const row = document.createElement('tr');
|
||
row.innerHTML = `
|
||
<td style="font-weight:500;">${escapeHtml(org.name)}</td>
|
||
<td>${escapeHtml(displayType)}</td>
|
||
<td><span class="status-badge ${statusClass}">${statusText}</span></td>
|
||
<td>${escapeHtml(members)}</td>
|
||
<td>${priorityText}</td>
|
||
<td class="links-cell">${linksHtml}</td>
|
||
`;
|
||
tbody.appendChild(row);
|
||
}
|
||
|
||
window.toggleDetails = function(id) {
|
||
const el = document.getElementById(`details-${id}`);
|
||
const icon = document.getElementById(`icon-${id}`);
|
||
if (el.classList.contains('open')) {
|
||
el.classList.remove('open');
|
||
icon.className = 'fas fa-chevron-down';
|
||
} else {
|
||
el.classList.add('open');
|
||
icon.className = 'fas fa-chevron-up';
|
||
}
|
||
};
|
||
|
||
window.toggleCommitteeDetails = function(id) {
|
||
const el = document.getElementById(`committee-details-${id}`);
|
||
if (el.classList.contains('open')) {
|
||
el.classList.remove('open');
|
||
} else {
|
||
el.classList.add('open');
|
||
}
|
||
};
|
||
|
||
function escapeHtml(str) { if (!str) return ''; return str.replace(/[&<>]/g, m => ({ '&': '&', '<': '<', '>': '>' }[m])); }
|
||
|
||
const btns = document.querySelectorAll('.tab-btn');
|
||
const panels = { detailed: document.getElementById('detailedPanel'), summary: document.getElementById('summaryPanel') };
|
||
btns.forEach(btn => {
|
||
btn.addEventListener('click', () => {
|
||
btns.forEach(b => b.classList.remove('active'));
|
||
btn.classList.add('active');
|
||
const tabId = btn.getAttribute('data-tab');
|
||
Object.values(panels).forEach(p => p.classList.remove('active-panel'));
|
||
if (tabId === 'detailed') panels.detailed.classList.add('active-panel');
|
||
else panels.summary.classList.add('active-panel');
|
||
});
|
||
});
|
||
|
||
loadDataFromServer();
|
||
</script>
|
||
</body>
|
||
</html> |