Сортировка в таблицах и попытка приструнить генерацию превьюшек
All checks were successful
Deploy MES Core / deploy (push) Successful in 13s

This commit is contained in:
2026-04-03 01:10:05 +03:00
parent cddbfeadde
commit b76ce4913f
16 changed files with 722 additions and 34 deletions

View File

@@ -38,10 +38,114 @@
localStorage.setItem('theme', newTheme);
updateThemeIcon(newTheme);
}
function sfParseDate(text) {
const s = (text || '').trim();
if (!s) return null;
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) {
const d = new Date(s + 'T00:00:00');
return isNaN(d.getTime()) ? null : d;
}
const m = s.match(/^(\d{1,2})\.(\d{1,2})\.(\d{2}|\d{4})$/);
if (m) {
const dd = parseInt(m[1], 10);
const mm = parseInt(m[2], 10) - 1;
let yy = parseInt(m[3], 10);
if (yy < 100) yy += 2000;
const d = new Date(yy, mm, dd);
return isNaN(d.getTime()) ? null : d;
}
return null;
}
function sfParseNumber(text) {
const s = (text || '').toString().trim();
if (!s) return null;
const cleaned = s
.replace(/\s+/g, '')
.replace(/,/g, '.')
.replace(/[^0-9.\-]/g, '');
if (!cleaned || cleaned === '-' || cleaned === '.') return null;
const n = parseFloat(cleaned);
return isNaN(n) ? null : n;
}
function sfMakeSortable(table) {
const thead = table.querySelector('thead');
const tbody = table.querySelector('tbody');
if (!thead || !tbody) return;
const ths = Array.from(thead.querySelectorAll('th'));
ths.forEach((th, idx) => {
if ((th.getAttribute('data-sort') || '').toLowerCase() === 'false') return;
th.style.cursor = 'pointer';
th.addEventListener('click', () => {
const cur = table.getAttribute('data-sort-col');
const sameCol = cur !== null && String(idx) === String(cur);
const dir = sameCol && table.getAttribute('data-sort-dir') === 'asc' ? 'desc' : 'asc';
table.setAttribute('data-sort-col', String(idx));
table.setAttribute('data-sort-dir', dir);
const rows = Array.from(tbody.querySelectorAll('tr'));
// Комментарий: сортировка делается на клиенте. Мы просто переупорядочиваем строки в tbody.
// Это работает для всех таблиц, где разметка уже готова, без переписывания вьюх.
rows.sort((a, b) => {
const aCell = a.children[idx];
const bCell = b.children[idx];
const aText = (aCell ? aCell.textContent : '').trim();
const bText = (bCell ? bCell.textContent : '').trim();
const type = (th.getAttribute('data-sort-type') || '').toLowerCase();
if (type === 'number') {
const an = sfParseNumber(aText);
const bn = sfParseNumber(bText);
if (an === null && bn === null) return 0;
if (an === null) return dir === 'asc' ? 1 : -1;
if (bn === null) return dir === 'asc' ? -1 : 1;
return dir === 'asc' ? (an - bn) : (bn - an);
}
if (type === 'date') {
const ad = sfParseDate(aText);
const bd = sfParseDate(bText);
const at = ad ? ad.getTime() : null;
const bt = bd ? bd.getTime() : null;
if (at === null && bt === null) return 0;
if (at === null) return dir === 'asc' ? 1 : -1;
if (bt === null) return dir === 'asc' ? -1 : 1;
return dir === 'asc' ? (at - bt) : (bt - at);
}
// Попытка автоматически понять тип
const an = sfParseNumber(aText);
const bn = sfParseNumber(bText);
if (an !== null && bn !== null) return dir === 'asc' ? (an - bn) : (bn - an);
const ad = sfParseDate(aText);
const bd = sfParseDate(bText);
if (ad && bd) return dir === 'asc' ? (ad.getTime() - bd.getTime()) : (bd.getTime() - ad.getTime());
const cmp = aText.localeCompare(bText, 'ru', { numeric: true, sensitivity: 'base' });
return dir === 'asc' ? cmp : -cmp;
});
const frag = document.createDocumentFragment();
rows.forEach(r => frag.appendChild(r));
tbody.appendChild(frag);
});
});
}
document.addEventListener('DOMContentLoaded', () => {
const savedTheme = localStorage.getItem('theme') || 'dark';
document.documentElement.setAttribute('data-bs-theme', savedTheme);
updateThemeIcon(savedTheme);
// Включаем сортировку для таблиц, которые явно помечены data-sortable="1".
document.querySelectorAll('table[data-sortable="1"]').forEach(sfMakeSortable);
});
</script>
</body>