sravni-dva-dokumenta-i-sdela/script.js

207 lines
7.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

let data = [];
let currentFilter = 'all';
async function loadData() {
try {
const response = await fetch('data.json');
const json = await response.json();
data = json.zamечания || [];
renderTable();
renderSummary();
} catch (error) {
console.error('Ошибка загрузки данных:', error);
document.getElementById('table-body').innerHTML =
'<tr><td colspan="6" style="text-align:center;padding:40px;color:#dc3545;">Ошибка загрузки данных</td></tr>';
}
}
function compareDecisions(zam, sf) {
if (!zam || !sf) return 'partially';
const zamNorm = zam.toLowerCase().trim();
const sfNorm = sf.toLowerCase().trim();
if (zamNorm === sfNorm) return 'fully';
const zamWords = zamNorm.split(/[\s,;.]+/).filter(w => w.length > 3);
const sfWords = sfNorm.split(/[\s,;.]+/).filter(w => w.length > 3);
const matchCount = zamWords.filter(w => sfWords.includes(w)).length;
const matchPercent = matchCount / Math.max(zamWords.length, sfWords.length);
if (matchPercent >= 0.8) return 'fully';
if (matchPercent >= 0.4) return 'partially';
return 'partially';
}
function findAddedContent(zam, sf) {
if (!zam || !sf) return [];
const zamNorm = zam.toLowerCase();
const sfNorm = sf.toLowerCase();
const zamSentences = zamNorm.split(/[.!?]/).filter(s => s.trim().length > 10);
const sfSentences = sfNorm.split(/[.!?]/).filter(s => s.trim().length > 10);
const added = sfSentences.filter(sfSent =>
!zamSentences.some(zamSent => {
const words1 = sfSent.trim().split(/\s+/).filter(w => w.length > 3);
const words2 = zamSent.trim().split(/\s+/).filter(w => w.length > 3);
const match = words1.filter(w => words2.includes(w)).length;
return match / Math.max(words1.length, words2.length) > 0.6;
})
);
return added.slice(0, 3);
}
function getStatusHtml(status, added) {
const statusLabels = {
'fully': 'Полностью учтено',
'partially': 'Частично учтено',
'added': 'Добавлено'
};
let html = `<span class="status-badge status-${status}">${statusLabels[status]}</span>`;
if (added && added.length > 0) {
html += `<div class="changes-highlight">
<strong>Добавлено в Приложении 1_СФ:</strong>
<ul>${added.map(item => `<li>${item.trim()}.</li>`).join('')}</ul>
</div>`;
}
return html;
}
function renderTable(filter = 'all') {
const tbody = document.getElementById('table-body');
const filtered = filter === 'all'
? data
: data.filter(item => {
const status = compareDecisions(item.decision_zam, item.decision_sf);
const added = findAddedContent(item.decision_zam, item.decision_sf);
if (filter === 'fully') return status === 'fully';
if (filter === 'partially') return status === 'partially';
if (filter === 'added') return added.length > 0;
return true;
});
if (filtered.length === 0) {
tbody.innerHTML = '<tr><td colspan="6" style="text-align:center;padding:40px;">Нет данных для отображения</td></tr>';
return;
}
tbody.innerHTML = filtered.map(item => {
const status = compareDecisions(item.decision_zam, item.decision_sf);
const added = findAddedContent(item.decision_zam, item.decision_sf);
return `
<tr>
<td class="col-id">${item.id}</td>
<td class="col-problem">${item.problem}</td>
<td class="col-recommendation">${item.recommendation}</td>
<td class="col-decision-zam">${item.decision_zam}</td>
<td class="col-decision-sf">${item.decision_sf}</td>
<td class="col-status">${getStatusHtml(status, added)}</td>
</tr>
`;
}).join('');
}
function renderSummary() {
const total = data.length;
let fullyCount = 0;
let partiallyCount = 0;
let addedCount = 0;
const addedItems = [];
data.forEach(item => {
const status = compareDecisions(item.decision_zam, item.decision_sf);
const added = findAddedContent(item.decision_zam, item.decision_sf);
if (status === 'fully') fullyCount++;
else partiallyCount++;
if (added.length > 0) {
addedCount++;
addedItems.push({ id: item.id, added });
}
});
document.getElementById('summary').innerHTML = `
<div class="summary-item">
<strong>${total}</strong>
<span>Всего замечаний</span>
</div>
<div class="summary-item">
<strong style="color:#d4edda">${fullyCount}</strong>
<span>Полностью учтено</span>
</div>
<div class="summary-item">
<strong style="color:#fff3cd">${partiallyCount}</strong>
<span>Частично учтено</span>
</div>
<div class="summary-item">
<strong style="color:#cce5ff">${addedCount}</strong>
<span>С дополнениями</span>
</div>
`;
const summaryDetails = document.getElementById('summary-details');
summaryDetails.innerHTML = `
<div class="summary-card">
<h3>📊 Общая статистика</h3>
<ul>
<li>Всего замечаний проанализировано: <strong>${total}</strong></li>
<li>Полностью учтены в Приложении 1_СФ: <strong>${fullyCount}</strong> (${((fullyCount/total)*100).toFixed(1)}%)</li>
<li>Частично учтены / изменены: <strong>${partiallyCount}</strong> (${((partiallyCount/total)*100).toFixed(1)}%)</li>
<li>Замечаний с новыми дополнениями: <strong>${addedCount}</strong></li>
</ul>
</div>
<div class="summary-card">
<h3>✨ Что добавлено в Приложении 1_СФ</h3>
${addedItems.length > 0 ? `
<ul>
${addedItems.map(item => `
<li>
<strong>Замечание ${item.id}:</strong>
<ul style="margin-top:6px;padding-left:20px;">
${item.added.map(a => `<li>${a.trim()}.</li>`).join('')}
</ul>
</li>
`).join('')}
</ul>
` : '<li>Новых положений не выявлено</li>'}
</div>
<div class="summary-card" style="grid-column:1/-1">
<h3>📋 Ключевые дополнения в Приложении 1_СФ по сравнению с ПКМ замечаниями</h3>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px;">
${addedItems.length > 0 ? addedItems.map(item => `
<div style="background:#f8f9fa;padding:16px;border-radius:8px;border-left:3px solid #3498db;">
<strong style="color:#2c3e50;display:block;margin-bottom:8px;">Замечание ${item.id}</strong>
<ul style="padding-left:20px;">
${item.added.map(a => `<li style="margin:6px 0;font-size:13px;">${a.trim()}.</li>`).join('')}
</ul>
</div>
`).join('') : '<p style="grid-column:1/-1;text-align:center;color:#6c757d;padding:20px;">Все решения полностью соответствуют исходным замечаниям</p>'}
</div>
</div>
`;
}
document.querySelectorAll('.filter-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentFilter = btn.dataset.filter;
renderTable(currentFilter);
});
});
document.addEventListener('DOMContentLoaded', loadData);