This commit is contained in:
2026-05-28 19:33:15 +03:00
parent 7e3804af72
commit bbdf19bd05
+224 -199
View File
@@ -57,14 +57,29 @@
.full-width { grid-column: 1 / -1; } .full-width { grid-column: 1 / -1; }
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 5px; } .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; } .tag { background: #e2e8f0; padding: 3px 10px; border-radius: 20px; font-size: 0.75rem; color: #334155; }
.links-list { display: flex; flex-wrap: wrap; gap: 8px; } .links-list { display: flex; flex-wrap: wrap; gap: 6px; }
.link-item { background: #e2e8f0; padding: 4px 12px; border-radius: 20px; font-size: 0.8rem; } .link-item { background: #e2e8f0; padding: 4px 12px; border-radius: 20px; font-size: 0.8rem; }
.link-item a { color: #1e3a5f; text-decoration: none; } .link-item a { color: #1e3a5f; text-decoration: none; }
.link-item a:hover { text-decoration: underline; } .link-item a:hover { text-decoration: underline; }
.links-cell { max-width: 250px; }
.resource-link {
display: inline-block;
background: #eef2ff;
color: #1e3a5f;
padding: 3px 8px;
border-radius: 16px;
font-size: 0.7rem;
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 120px;
}
.resource-link:hover { background: #1e3a5f; color: white; }
hr { margin: 1rem 0; border-color: #ecf3f9; } hr { margin: 1rem 0; border-color: #ecf3f9; }
/* Admin Panel */
.admin-panel { .admin-panel {
position: fixed; top: 0; right: -650px; width: 650px; height: 100vh; position: fixed; top: 0; right: -650px; width: 650px; height: 100vh;
background: white; box-shadow: -5px 0 30px rgba(0,0,0,0.2); background: white; box-shadow: -5px 0 30px rgba(0,0,0,0.2);
@@ -85,9 +100,7 @@
.form-group input, .form-group textarea, .form-group select { padding: 8px 12px; border-radius: 10px; border: 1px solid #cbd5e1; font-family: 'Inter', sans-serif; font-size: 0.85rem; } .form-group input, .form-group textarea, .form-group select { padding: 8px 12px; border-radius: 10px; border: 1px solid #cbd5e1; font-family: 'Inter', sans-serif; font-size: 0.85rem; }
.form-group textarea { min-height: 60px; resize: vertical; } .form-group textarea { min-height: 60px; resize: vertical; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; } .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.form-3col { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; }
/* Dynamic links */
.links-container { border: 1px solid #e2e8f0; border-radius: 12px; padding: 0.75rem; background: #fafcff; } .links-container { border: 1px solid #e2e8f0; border-radius: 12px; padding: 0.75rem; background: #fafcff; }
.link-input-group { display: flex; gap: 8px; margin-bottom: 8px; align-items: center; } .link-input-group { display: flex; gap: 8px; margin-bottom: 8px; align-items: center; }
.link-input-group input { flex: 1; } .link-input-group input { flex: 1; }
@@ -137,9 +150,10 @@
@media (max-width: 750px) { @media (max-width: 750px) {
.admin-panel { width: 100%; right: -100%; } .admin-panel { width: 100%; right: -100%; }
.form-row, .form-3col { grid-template-columns: 1fr; } .form-row { grid-template-columns: 1fr; }
.info-grid { grid-template-columns: 1fr; } .info-grid { grid-template-columns: 1fr; }
.action-btns { flex-direction: column; gap: 4px; } .action-btns { flex-direction: column; gap: 4px; }
.links-cell { max-width: 180px; }
} }
</style> </style>
</head> </head>
@@ -163,7 +177,8 @@
<div class="summary-wrapper"> <div class="summary-wrapper">
<table class="summary-table"> <table class="summary-table">
<thead> <thead>
<tr><th>Название</th><th>Тип</th><th>Статус</th><th>Членство</th><th>Приоритет</th><th>Ресурс</th><th style="width: 180px;">Действия</th></thead> <tr><th>Название</th><th>Тип</th><th>Статус</th><th>Членство</th><th>Приоритет</th><th>Ресурсы</th><th style="width: 180px;">Действия</th></tr>
</thead>
<tbody id="summaryTableBody"><tr><td colspan="7" class="loading">Загрузка...</td></tr></tbody> <tbody id="summaryTableBody"><tr><td colspan="7" class="loading">Загрузка...</td></tr></tbody>
</table> </table>
</div> </div>
@@ -171,7 +186,6 @@
<div class="footer-note"> <div class="footer-note">
<i class="fas fa-info-circle"></i> Данные хранятся в файле data.json. Все изменения сохраняются на сервере. <i class="fas fa-info-circle"></i> Данные хранятся в файле data.json. Все изменения сохраняются на сервере.
В админ-панели можно добавить несколько ссылок на ресурсы (соцсети, сайты).
</div> </div>
</div> </div>
@@ -217,13 +231,11 @@
<input type="text" id="orgType" placeholder="Например: Общероссийская ассоциация"> <input type="text" id="orgType" placeholder="Например: Общероссийская ассоциация">
</div> </div>
<!-- Количество членов - отдельное поле -->
<div class="form-group"> <div class="form-group">
<label>Количество членов <span class="hint">(например: 14 человек, 63 подписчика)</span></label> <label>Количество членов <span class="hint">(например: 14 человек, 63 подписчика)</span></label>
<input type="text" id="orgMembersCount" placeholder="Количество членов, состав"> <input type="text" id="orgMembersCount" placeholder="Количество членов, состав">
</div> </div>
<!-- Несколько ссылок на ресурсы -->
<div class="form-group"> <div class="form-group">
<label>Ресурсы организации <span class="hint">(сайты, соцсети, мессенджеры)</span></label> <label>Ресурсы организации <span class="hint">(сайты, соцсети, мессенджеры)</span></label>
<div class="links-container" id="linksContainer"> <div class="links-container" id="linksContainer">
@@ -232,73 +244,30 @@
</div> </div>
</div> </div>
<!-- Расширенные поля для основных организаций -->
<div id="mainOrgFields" style="display: none;"> <div id="mainOrgFields" style="display: none;">
<div class="form-group"> <div class="form-group"><label>Полное наименование</label><input type="text" id="orgFullName" placeholder="Полное официальное наименование"></div>
<label>Полное наименование</label> <div class="form-row">
<input type="text" id="orgFullName" placeholder="Полное официальное наименование"> <div class="form-group"><label>Дата создания</label><input type="text" id="orgCreated" placeholder="Год или дата создания"></div>
<div class="form-group"><label>Юридическая форма</label><input type="text" id="orgLegalForm" placeholder="ОПФ"></div>
</div>
<div class="form-group"><label>Адрес</label><input type="text" id="orgAddress" placeholder="Юридический/фактический адрес"></div>
<div class="form-row">
<div class="form-group"><label>Ключевые лица</label><input type="text" id="orgKeyPeople" placeholder="Заместители, члены правления"></div>
<div class="form-group"><label>Отраслевой состав</label><input type="text" id="orgSectors" placeholder="Отрасли участников (через запятую)"></div>
</div> </div>
<div class="form-row"> <div class="form-row">
<div class="form-group"> <div class="form-group"><label>Критерии вступления</label><input type="text" id="orgCriteria" placeholder="Требования к кандидатам"></div>
<label>Дата создания</label> <div class="form-group"><label>Членские взносы</label><input type="text" id="orgFees" placeholder="Стоимость"></div>
<input type="text" id="orgCreated" placeholder="Год или дата создания">
</div>
<div class="form-group">
<label>Юридическая форма</label>
<input type="text" id="orgLegalForm" placeholder="ОПФ">
</div>
</div>
<div class="form-group">
<label>Адрес</label>
<input type="text" id="orgAddress" placeholder="Юридический/фактический адрес">
</div>
<div class="form-row">
<div class="form-group">
<label>Ключевые лица</label>
<input type="text" id="orgKeyPeople" placeholder="Заместители, члены правления">
</div>
<div class="form-group">
<label>Отраслевой состав</label>
<input type="text" id="orgSectors" placeholder="Отрасли участников (через запятую)">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Критерии вступления</label>
<input type="text" id="orgCriteria" placeholder="Требования к кандидатам">
</div>
<div class="form-group">
<label>Членские взносы</label>
<input type="text" id="orgFees" placeholder="Стоимость">
</div>
</div>
<div class="form-group">
<label>Контактная информация</label>
<input type="text" id="orgContacts" placeholder="Email, телефон для связи">
</div> </div>
<div class="form-group"><label>Контактная информация</label><input type="text" id="orgContacts" placeholder="Email, телефон для связи"></div>
</div> </div>
<div class="form-group"> <div class="form-group"><label>Руководитель</label><input type="text" id="orgHead" placeholder="ФИО руководителя"></div>
<label>Руководитель</label> <div class="form-group"><label>Цели и задачи</label><textarea id="orgGoals" rows="2"></textarea></div>
<input type="text" id="orgHead" placeholder="ФИО руководителя"> <div class="form-group"><label>Основная деятельность</label><textarea id="orgActivity" rows="2"></textarea></div>
</div>
<div class="form-group">
<label>Цели и задачи</label>
<textarea id="orgGoals" rows="2"></textarea>
</div>
<div class="form-group">
<label>Основная деятельность</label>
<textarea id="orgActivity" rows="2"></textarea>
</div>
<div class="form-row"> <div class="form-row">
<div class="form-group"> <div class="form-group"><label>Сильные стороны</label><textarea id="orgStrengths" rows="2"></textarea></div>
<label>Сильные стороны</label> <div class="form-group"><label>Слабые стороны</label><textarea id="orgWeaknesses" rows="2"></textarea></div>
<textarea id="orgStrengths" rows="2"></textarea>
</div>
<div class="form-group">
<label>Слабые стороны</label>
<textarea id="orgWeaknesses" rows="2"></textarea>
</div>
</div> </div>
<div class="btn-group"> <div class="btn-group">
@@ -316,7 +285,7 @@
let currentData = null; let currentData = null;
let currentEditId = null; let currentEditId = null;
let currentEditType = 'main'; let currentEditType = 'main';
let currentLinks = []; // Массив ссылок для текущей организации let currentLinks = [];
function showToast(msg, isError = false) { function showToast(msg, isError = false) {
const toast = document.getElementById('toast'); const toast = document.getElementById('toast');
@@ -376,6 +345,12 @@
return `<div class="links-list">${links.map(link => `<div class="link-item"><a href="${escapeHtml(link)}" target="_blank">${escapeHtml(link)}</a></div>`).join('')}</div>`; return `<div class="links-list">${links.map(link => `<div class="link-item"><a href="${escapeHtml(link)}" target="_blank">${escapeHtml(link)}</a></div>`).join('')}</div>`;
} }
function truncateUrl(url) {
if (!url) return '';
if (url.length <= 40) return url;
return url.substring(0, 37) + '...';
}
function renderDetailed() { function renderDetailed() {
const container = document.getElementById('detailedContainer'); const container = document.getElementById('detailedContainer');
if (!currentData) return; if (!currentData) return;
@@ -386,8 +361,13 @@
const statusClass = org.status === 'active' ? 'status-active' : 'status-warning'; const statusClass = org.status === 'active' ? 'status-active' : 'status-warning';
const statusText = org.status === 'active' ? '✔ Действует' : '⚠️ Требует уточнения'; const statusText = org.status === 'active' ? '✔ Действует' : '⚠️ Требует уточнения';
// Получаем ссылки из org.resources или org.links let allLinks = [];
const links = org.resources?.links || org.links || []; 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 || org.detailed?.membership?.count || '—';
const card = document.createElement('div'); const card = document.createElement('div');
card.className = 'org-card'; card.className = 'org-card';
@@ -408,11 +388,10 @@
<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?.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?.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(d.general?.address || 'Не указан')}</div></div>
<div class="info-card"><div class="label">📊 Статус</div><div class="value">${escapeHtml(d.general?.statusText || 'Действует')}</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">${renderLinks(links)}</div></div> <div class="info-card"><div class="label">🔗 Ресурсы</div><div class="value">${renderLinks(allLinks)}</div></div>
</div> </div>
</div> </div>
<div class="details-section"> <div class="details-section">
<div class="section-title"><i class="fas fa-users"></i> Руководство и структура</div> <div class="section-title"><i class="fas fa-users"></i> Руководство и структура</div>
<div class="info-grid"> <div class="info-grid">
@@ -421,17 +400,14 @@
<div class="info-card"><div class="label">🏢 Отделения</div><div class="value">${escapeHtml(d.leadership?.branches || '—')}</div></div> <div class="info-card"><div class="label">🏢 Отделения</div><div class="value">${escapeHtml(d.leadership?.branches || '—')}</div></div>
</div> </div>
</div> </div>
<div class="details-section"> <div class="details-section">
<div class="section-title"><i class="fas fa-handshake"></i> Членство и состав</div> <div class="section-title"><i class="fas fa-handshake"></i> Членство и состав</div>
<div class="info-grid"> <div class="info-grid">
<div class="info-card"><div class="label">👥 Количество членов</div><div class="value">${escapeHtml(org.membersCount || d.membership?.count || org.summaryMembership || '—')}</div></div>
<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?.criteria || '—')}</div></div>
<div class="info-card"><div class="label">💰 Членские взносы</div><div class="value">${escapeHtml(d.membership?.fees || '—')}</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 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> </div>
<div class="details-section"> <div class="details-section">
<div class="section-title"><i class="fas fa-chart-line"></i> Деятельность и влияние</div> <div class="section-title"><i class="fas fa-chart-line"></i> Деятельность и влияние</div>
<div class="info-grid"> <div class="info-grid">
@@ -440,7 +416,6 @@
<div class="info-card"><div class="label">📧 Контакты</div><div class="value">${escapeHtml(d.resources?.contacts || '—')}</div></div> <div class="info-card"><div class="label">📧 Контакты</div><div class="value">${escapeHtml(d.resources?.contacts || '—')}</div></div>
</div> </div>
</div> </div>
<div class="details-section"> <div class="details-section">
<div class="section-title"><i class="fas fa-chart-simple"></i> SWOT-анализ</div> <div class="section-title"><i class="fas fa-chart-simple"></i> SWOT-анализ</div>
<div class="info-grid"> <div class="info-grid">
@@ -465,7 +440,6 @@
const tbody = document.getElementById('summaryTableBody'); const tbody = document.getElementById('summaryTableBody');
if (!currentData) return; if (!currentData) return;
tbody.innerHTML = ''; tbody.innerHTML = '';
(currentData.organizations || []).forEach(org => { appendSummaryRow(tbody, org, 'main'); }); (currentData.organizations || []).forEach(org => { appendSummaryRow(tbody, org, 'main'); });
(currentData.additionalOrganizations || []).forEach(org => { appendSummaryRow(tbody, org, 'additional'); }); (currentData.additionalOrganizations || []).forEach(org => { appendSummaryRow(tbody, org, 'additional'); });
} }
@@ -475,7 +449,31 @@
const statusText = org.status === 'active' ? 'Действует' : 'Требует уточнения'; const statusText = org.status === 'active' ? 'Действует' : 'Требует уточнения';
const priorityText = org.priority === 'high' ? 'Высокий' : (org.priority === 'medium' ? 'Средний' : 'Низкий'); const priorityText = org.priority === 'high' ? 'Высокий' : (org.priority === 'medium' ? 'Средний' : 'Низкий');
const displayType = type === 'main' ? (org.shortType || 'Основная') : (org.type || 'Дополнительная'); const displayType = type === 'main' ? (org.shortType || 'Основная') : (org.type || 'Дополнительная');
const members = org.membersCount || (type === 'main' ? (org.summaryMembership || '—') : (org.members || '—'));
// Получаем количество членов из всех возможных полей
let members = '—';
if (org.membersCount && org.membersCount !== 'Данные отсутствуют') {
members = org.membersCount;
} else if (type === 'main' && org.summaryMembership && org.summaryMembership !== 'Данные отсутствуют') {
members = org.summaryMembership;
} else if (type === 'additional' && org.members && org.members !== 'Данные отсутствуют') {
members = org.members;
} else if (org.detailed?.membership?.count && org.detailed.membership.count !== 'Нет公开 данных') {
members = org.detailed.membership.count;
}
let allLinks = [];
if (org.resources?.links && Array.isArray(org.resources.links)) allLinks = [...org.resources.links];
if (org.links && Array.isArray(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() !== '' && l !== '—');
let linksHtml = '—';
if (allLinks.length > 0) {
linksHtml = `<div class="links-list">${allLinks.map(link =>
`<a href="${escapeHtml(link)}" target="_blank" class="resource-link" title="${escapeHtml(link)}">${escapeHtml(truncateUrl(link))}</a>`
).join('')}</div>`;
}
const row = document.createElement('tr'); const row = document.createElement('tr');
row.setAttribute('data-id', org.id); row.setAttribute('data-id', org.id);
@@ -486,7 +484,7 @@
<td><span class="status-badge ${statusClass}">${statusText}</span></td> <td><span class="status-badge ${statusClass}">${statusText}</span></td>
<td>${escapeHtml(members)}</td> <td>${escapeHtml(members)}</td>
<td>${priorityText}</td> <td>${priorityText}</td>
<td>${org.link && org.link !== '—' ? `<a href="${escapeHtml(org.link)}" target="_blank">ресурс</a>` : '—'}</td> <td class="links-cell">${linksHtml}</td>
<td class="action-btns"> <td class="action-btns">
<button class="edit-row-btn" onclick="editOrganization('${type}', ${org.id})" title="Редактировать"><i class="fas fa-edit"></i></button> <button class="edit-row-btn" onclick="editOrganization('${type}', ${org.id})" title="Редактировать"><i class="fas fa-edit"></i></button>
${type === 'additional' ? ${type === 'additional' ?
@@ -499,7 +497,6 @@
tbody.appendChild(row); tbody.appendChild(row);
} }
// Функции для работы со ссылками
function renderLinkInputs() { function renderLinkInputs() {
const container = document.getElementById('linksList'); const container = document.getElementById('linksList');
container.innerHTML = ''; container.innerHTML = '';
@@ -513,7 +510,6 @@
container.appendChild(div); container.appendChild(div);
}); });
// Добавляем обработчики удаления
document.querySelectorAll('.remove-link-btn').forEach(btn => { document.querySelectorAll('.remove-link-btn').forEach(btn => {
btn.addEventListener('click', (e) => { btn.addEventListener('click', (e) => {
const idx = parseInt(btn.dataset.index); const idx = parseInt(btn.dataset.index);
@@ -522,7 +518,6 @@
}); });
}); });
// Добавляем обработчики изменения
document.querySelectorAll('.link-input').forEach((input, idx) => { document.querySelectorAll('.link-input').forEach((input, idx) => {
input.addEventListener('change', (e) => { input.addEventListener('change', (e) => {
currentLinks[idx] = e.target.value; currentLinks[idx] = e.target.value;
@@ -559,24 +554,152 @@
fields.style.display = show ? 'block' : 'none'; fields.style.display = show ? 'block' : 'none';
} }
function populateAdminForm() {
let org = null;
if (currentEditType === 'main') {
org = currentData.organizations?.find(o => o.id === currentEditId);
} else {
org = currentData.additionalOrganizations?.find(a => a.id === currentEditId);
}
if (!org) return;
document.getElementById('orgName').value = org.name || '';
document.getElementById('orgPriority').value = org.priority || 'medium';
document.getElementById('orgStatus').value = org.status || 'active';
document.getElementById('orgType').value = currentEditType === 'main' ? (org.shortType || '') : (org.type || '');
// Загружаем количество членов из правильного поля
let membersValue = '';
if (org.membersCount && org.membersCount !== 'Данные отсутствуют') {
membersValue = org.membersCount;
} else if (currentEditType === 'main' && org.summaryMembership && org.summaryMembership !== 'Данные отсутствуют') {
membersValue = org.summaryMembership;
} else if (currentEditType === 'additional' && org.members && org.members !== 'Данные отсутствуют') {
membersValue = org.members;
} else if (org.detailed?.membership?.count) {
membersValue = org.detailed.membership.count;
}
document.getElementById('orgMembersCount').value = membersValue;
// Загружаем ссылки
if (org.resources?.links) currentLinks = [...org.resources.links];
else if (org.links) currentLinks = [...org.links];
else if (org.link && org.link !== '—') currentLinks = [org.link];
else currentLinks = [];
renderLinkInputs();
if (currentEditType === 'main') {
const d = org.detailed || {};
document.getElementById('orgFullName').value = d.general?.fullName || '';
document.getElementById('orgCreated').value = d.general?.created || '';
document.getElementById('orgLegalForm').value = d.general?.legalForm || '';
document.getElementById('orgAddress').value = d.general?.address || '';
document.getElementById('orgKeyPeople').value = d.leadership?.keyPeople || '';
document.getElementById('orgSectors').value = d.membership?.sectors || '';
document.getElementById('orgCriteria').value = d.membership?.criteria || '';
document.getElementById('orgFees').value = d.membership?.fees || '';
document.getElementById('orgContacts').value = d.resources?.contacts || '';
}
document.getElementById('orgHead').value = org.detailed?.leadership?.head || '';
document.getElementById('orgGoals').value = org.detailed?.goals || '';
document.getElementById('orgActivity').value = org.detailed?.activity || '';
document.getElementById('orgStrengths').value = org.detailed?.assessment?.strengths || '';
document.getElementById('orgWeaknesses').value = org.detailed?.assessment?.weaknesses || '';
}
function updateOrgFromForm() {
let org = null;
const collectedLinks = collectLinks();
const membersValue = document.getElementById('orgMembersCount').value;
if (currentEditType === 'main') {
org = currentData.organizations?.find(o => o.id === currentEditId);
if (!org) return;
org.name = document.getElementById('orgName').value;
org.priority = document.getElementById('orgPriority').value;
org.status = document.getElementById('orgStatus').value;
org.shortType = document.getElementById('orgType').value;
org.membersCount = membersValue;
org.summaryMembership = membersValue;
org.resources = org.resources || {};
org.resources.links = collectedLinks;
org.link = collectedLinks[0] || '';
if (!org.detailed) org.detailed = {};
if (!org.detailed.general) org.detailed.general = {};
if (!org.detailed.leadership) org.detailed.leadership = {};
if (!org.detailed.membership) org.detailed.membership = {};
if (!org.detailed.resources) org.detailed.resources = {};
if (!org.detailed.assessment) org.detailed.assessment = {};
org.detailed.membership.count = membersValue;
org.detailed.general.fullName = document.getElementById('orgFullName').value;
org.detailed.general.created = document.getElementById('orgCreated').value;
org.detailed.general.legalForm = document.getElementById('orgLegalForm').value;
org.detailed.general.address = document.getElementById('orgAddress').value;
org.detailed.leadership.keyPeople = document.getElementById('orgKeyPeople').value;
org.detailed.membership.sectors = document.getElementById('orgSectors').value;
org.detailed.membership.criteria = document.getElementById('orgCriteria').value;
org.detailed.membership.fees = document.getElementById('orgFees').value;
org.detailed.resources.contacts = document.getElementById('orgContacts').value;
org.detailed.leadership.head = document.getElementById('orgHead').value;
org.detailed.goals = document.getElementById('orgGoals').value;
org.detailed.activity = document.getElementById('orgActivity').value;
org.detailed.assessment.strengths = document.getElementById('orgStrengths').value;
org.detailed.assessment.weaknesses = document.getElementById('orgWeaknesses').value;
} else {
org = currentData.additionalOrganizations?.find(a => a.id === currentEditId);
if (!org) return;
org.name = document.getElementById('orgName').value;
org.priority = document.getElementById('orgPriority').value;
org.status = document.getElementById('orgStatus').value;
org.type = document.getElementById('orgType').value;
org.members = membersValue;
org.membersCount = membersValue;
org.links = collectedLinks;
org.link = collectedLinks[0] || '';
if (!org.detailed) org.detailed = { leadership: {}, assessment: {} };
org.detailed.leadership.head = document.getElementById('orgHead').value;
org.detailed.goals = document.getElementById('orgGoals').value;
org.detailed.activity = document.getElementById('orgActivity').value;
if (!org.detailed.assessment) org.detailed.assessment = {};
org.detailed.assessment.strengths = document.getElementById('orgStrengths').value;
org.detailed.assessment.weaknesses = document.getElementById('orgWeaknesses').value;
}
saveAndRefresh().then(() => { initAdminSelect(); });
}
window.moveToMain = async function(id) { window.moveToMain = async function(id) {
const org = currentData.additionalOrganizations?.find(a => a.id === id); const org = currentData.additionalOrganizations?.find(a => a.id === id);
if (!org) return; if (!org) return;
let allLinks = [];
if (org.links) allLinks = [...org.links];
else if (org.link && org.link !== '—') allLinks = [org.link];
allLinks = [...new Set(allLinks.filter(l => l && l.trim() !== ''))];
const membersVal = org.membersCount || org.members || 'Данные отсутствуют';
const newMainOrg = { const newMainOrg = {
id: org.id, id: org.id,
name: org.name, name: org.name,
priority: org.priority, priority: org.priority,
status: org.status, status: org.status,
shortType: org.type || 'Организация', shortType: org.type || 'Организация',
membersCount: org.members || org.membersCount || 'Данные отсутствуют', membersCount: membersVal,
link: org.link || '', summaryMembership: membersVal,
sectors: org.sectors || '', link: allLinks[0] || '',
resources: { links: org.links || [] }, resources: { links: allLinks },
detailed: { detailed: {
general: { fullName: org.name, created: '', legalForm: '', address: '', statusText: 'Действует' }, general: { fullName: org.name, created: '', legalForm: '', address: '', statusText: 'Действует' },
leadership: { head: org.detailed?.leadership?.head || '', keyPeople: '', branches: '' }, leadership: { head: org.detailed?.leadership?.head || '', keyPeople: '', branches: '' },
membership: { count: org.members || 'Данные отсутствуют', criteria: '', fees: '', sectors: org.sectors || '' }, membership: { count: membersVal, criteria: '', fees: '', sectors: '' },
goals: org.detailed?.goals || '', goals: org.detailed?.goals || '',
activity: org.detailed?.activity || '', activity: org.detailed?.activity || '',
resources: { contacts: '' }, resources: { contacts: '' },
@@ -594,16 +717,23 @@
const org = currentData.organizations?.find(o => o.id === id); const org = currentData.organizations?.find(o => o.id === id);
if (!org) return; if (!org) return;
let allLinks = [];
if (org.resources?.links) allLinks = [...org.resources.links];
else if (org.link && org.link !== '—') allLinks = [org.link];
allLinks = [...new Set(allLinks.filter(l => l && l.trim() !== ''))];
const membersVal = org.membersCount || org.summaryMembership || 'Данные отсутствуют';
const newAdditionalOrg = { const newAdditionalOrg = {
id: org.id, id: org.id,
name: org.name, name: org.name,
priority: org.priority, priority: org.priority,
status: org.status, status: org.status,
type: org.shortType || 'Основная', type: org.shortType || 'Основная',
members: org.membersCount || org.summaryMembership || 'Данные отсутствуют', members: membersVal,
link: org.link || '', membersCount: membersVal,
sectors: org.sectors || '', link: allLinks[0] || '',
links: org.resources?.links || [], links: allLinks,
detailed: { detailed: {
leadership: { head: org.detailed?.leadership?.head || '' }, leadership: { head: org.detailed?.leadership?.head || '' },
goals: org.detailed?.goals || '', goals: org.detailed?.goals || '',
@@ -657,109 +787,6 @@
}); });
} }
function populateAdminForm() {
let org = null;
if (currentEditType === 'main') {
org = currentData.organizations?.find(o => o.id === currentEditId);
} else {
org = currentData.additionalOrganizations?.find(a => a.id === currentEditId);
}
if (!org) return;
document.getElementById('orgName').value = org.name || '';
document.getElementById('orgPriority').value = org.priority || 'medium';
document.getElementById('orgStatus').value = org.status || 'active';
document.getElementById('orgType').value = currentEditType === 'main' ? (org.shortType || '') : (org.type || '');
// Количество членов
const membersCount = org.membersCount || (currentEditType === 'main' ? org.summaryMembership : org.members) || '';
document.getElementById('orgMembersCount').value = membersCount;
// Ссылки
currentLinks = org.resources?.links || org.links || [];
if (currentLinks.length === 0 && org.link) currentLinks = [org.link];
renderLinkInputs();
if (currentEditType === 'main') {
const d = org.detailed || {};
document.getElementById('orgFullName').value = d.general?.fullName || '';
document.getElementById('orgCreated').value = d.general?.created || '';
document.getElementById('orgLegalForm').value = d.general?.legalForm || '';
document.getElementById('orgAddress').value = d.general?.address || '';
document.getElementById('orgKeyPeople').value = d.leadership?.keyPeople || '';
document.getElementById('orgSectors').value = d.membership?.sectors || org.sectors || '';
document.getElementById('orgCriteria').value = d.membership?.criteria || '';
document.getElementById('orgFees').value = d.membership?.fees || '';
document.getElementById('orgContacts').value = d.resources?.contacts || '';
}
document.getElementById('orgHead').value = org.detailed?.leadership?.head || '';
document.getElementById('orgGoals').value = org.detailed?.goals || '';
document.getElementById('orgActivity').value = org.detailed?.activity || '';
document.getElementById('orgStrengths').value = org.detailed?.assessment?.strengths || '';
document.getElementById('orgWeaknesses').value = org.detailed?.assessment?.weaknesses || '';
}
function updateOrgFromForm() {
let org = null;
if (currentEditType === 'main') {
org = currentData.organizations?.find(o => o.id === currentEditId);
if (!org) return;
org.name = document.getElementById('orgName').value;
org.priority = document.getElementById('orgPriority').value;
org.status = document.getElementById('orgStatus').value;
org.shortType = document.getElementById('orgType').value;
org.membersCount = document.getElementById('orgMembersCount').value;
// Сохраняем ссылки
org.resources = org.resources || {};
org.resources.links = collectLinks();
if (!org.detailed) org.detailed = {};
if (!org.detailed.general) org.detailed.general = {};
if (!org.detailed.leadership) org.detailed.leadership = {};
if (!org.detailed.membership) org.detailed.membership = {};
if (!org.detailed.resources) org.detailed.resources = {};
if (!org.detailed.assessment) org.detailed.assessment = {};
org.detailed.general.fullName = document.getElementById('orgFullName').value;
org.detailed.general.created = document.getElementById('orgCreated').value;
org.detailed.general.legalForm = document.getElementById('orgLegalForm').value;
org.detailed.general.address = document.getElementById('orgAddress').value;
org.detailed.leadership.keyPeople = document.getElementById('orgKeyPeople').value;
org.detailed.membership.sectors = document.getElementById('orgSectors').value;
org.detailed.membership.criteria = document.getElementById('orgCriteria').value;
org.detailed.membership.fees = document.getElementById('orgFees').value;
org.detailed.resources.contacts = document.getElementById('orgContacts').value;
org.detailed.leadership.head = document.getElementById('orgHead').value;
org.detailed.goals = document.getElementById('orgGoals').value;
org.detailed.activity = document.getElementById('orgActivity').value;
org.detailed.assessment.strengths = document.getElementById('orgStrengths').value;
org.detailed.assessment.weaknesses = document.getElementById('orgWeaknesses').value;
} else {
org = currentData.additionalOrganizations?.find(a => a.id === currentEditId);
if (!org) return;
org.name = document.getElementById('orgName').value;
org.priority = document.getElementById('orgPriority').value;
org.status = document.getElementById('orgStatus').value;
org.type = document.getElementById('orgType').value;
org.members = document.getElementById('orgMembersCount').value;
org.links = collectLinks();
if (!org.detailed) org.detailed = { leadership: {}, assessment: {} };
org.detailed.leadership.head = document.getElementById('orgHead').value;
org.detailed.goals = document.getElementById('orgGoals').value;
org.detailed.activity = document.getElementById('orgActivity').value;
if (!org.detailed.assessment) org.detailed.assessment = {};
org.detailed.assessment.strengths = document.getElementById('orgStrengths').value;
org.detailed.assessment.weaknesses = document.getElementById('orgWeaknesses').value;
}
saveAndRefresh().then(() => { initAdminSelect(); });
}
async function addNewOrganization() { async function addNewOrganization() {
const newId = Math.max( const newId = Math.max(
...(currentData.organizations?.map(o => o.id) || [0]), ...(currentData.organizations?.map(o => o.id) || [0]),
@@ -839,7 +866,6 @@
function escapeHtml(str) { if (!str) return ''; return str.replace(/[&<>]/g, m => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[m])); } function escapeHtml(str) { if (!str) return ''; return str.replace(/[&<>]/g, m => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;' }[m])); }
// Admin panel controls
const adminPanel = document.getElementById('adminPanel'); const adminPanel = document.getElementById('adminPanel');
const overlay = document.getElementById('overlay'); const overlay = document.getElementById('overlay');
document.getElementById('adminToggleBtn').addEventListener('click', () => { document.getElementById('adminToggleBtn').addEventListener('click', () => {
@@ -879,7 +905,6 @@
}); });
}); });
// Tabs
const btns = document.querySelectorAll('.tab-btn'); const btns = document.querySelectorAll('.tab-btn');
const panels = { detailed: document.getElementById('detailedPanel'), summary: document.getElementById('summaryPanel') }; const panels = { detailed: document.getElementById('detailedPanel'), summary: document.getElementById('summaryPanel') };
btns.forEach(btn => { btns.forEach(btn => {