let currentEntries = [];
let seenEntryIds = new Set();
let highlightNewIds = new Set();
let highlightClearTimer = null;
let editId = null;
let editGroups = [];
let groupsLoaded = false;
let studentsLoaded = false;
const PAGE_SIZE = 20;
let page = 1;
let totalEntries = 0;
let searchTimer = null;
let view = localStorage.getItem('journalView') === 'cards' ? 'cards' : 'list';
let aiCorrecting = false;
let editDeletePhoto = false;
let linkSettings = null;
async function loadLinkSettings() {
if (!linkSettings) {
const res = await fetch(`${API}/api/settings`, { headers: hdr() });
linkSettings = await res.json().catch(() => ({}));
}
return linkSettings;
}
function isImageFile(name) {
return /\.(jpe?g|jfif|png|gif|webp|bmp|avif|svg|ico)$/i.test(name || '');
}
function mainPhotoPath(e) {
if (e.photo_path) return e.photo_path;
if (e.photos && e.photos.length) return e.photos[0].photo_path;
return null;
}
function filesHTML(files) {
if (!files || !files.length) return '';
return `
${files.map(f => {
const link = isImageFile(f.name)
? `
${esc(f.name)} `
: `
${esc(f.name)} `;
return `
${link}✕ `;
}).join('')}
`;
}
const AI_STATUS_LABELS = {
pending: 'ИИ: в очереди',
processing: 'ИИ: проверяет…',
done: 'ИИ: проверено',
skipped: 'ИИ: пропущено',
error: 'ИИ: ошибка',
reverted: 'ИИ: возвращён оригинал',
};
const AI_STATUS_ICONS = {
pending: 'clock',
processing: 'loader',
done: 'circle-check',
skipped: 'skip-forward',
error: 'circle-alert',
reverted: 'undo',
};
function aiBadge(e) {
if (!e || !e.ai_status) return '';
const st = e.ai_status;
const label = AI_STATUS_LABELS[st] || `ИИ: ${st}`;
const icon = AI_STATUS_ICONS[st] || 'sparkles';
return `
${mp ? `
` : ''}
${esc(e.student_name)}
${esc(e.group_name)}
${esc(e.description)}${aiBadge(e)}
${filesHTML(e.files)}
${new Date(e.created_at).toLocaleString('ru')}
✎
${mp ? `
✦ ` : ''}
×
`;
}
function cardEntryHTML(e) {
const mp = mainPhotoPath(e);
return `
${mp
? `
`
: `
`}
${e.group_name ? `
${esc(e.group_name)} ` : ''}
${esc(e.student_name)}
${esc(e.description)}${aiBadge(e)}
${filesHTML(e.files)}
`;
}
function renderGrid() {
const grid = document.getElementById('grid');
if (!currentEntries.length) {
const fmt = d => d ? d.split('-').reverse().join('.') : '';
const from = fmt(document.getElementById('dateFrom').value);
const to = fmt(document.getElementById('dateTo').value);
let range = '';
if (from && to) range = ` за ${from} – ${to}`;
else if (from) range = ` с ${from}`;
else if (to) range = ` по ${to}`;
grid.className = 'grid';
grid.innerHTML = `Загрузка...
';
try {
const res = await fetch(`${API}/api/entries/${enhanceEntryId}/photo/jobs`, { headers: hdr() });
if (!res.ok) throw new Error('Ошибка загрузки истории');
const rows = await res.json();
if (!rows.length) {
list.innerHTML = 'Изменений фотографии пока не было.
';
return;
}
list.innerHTML = rows.map(r => {
const before = r.before_path ? `