feat: auto-load default xlsx on page open
Dashboard fetches "Функции и вес рекрутинг 2026 (2).xlsx" from the same directory on load, so opening the page renders the MVP immediately without requiring a manual upload. Manual upload still works as override. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f97af2b749
commit
da623a388c
33
app.js
33
app.js
@ -22,6 +22,8 @@ const state = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// === Init ===
|
// === Init ===
|
||||||
|
const DEFAULT_XLSX = './Функции и вес рекрутинг 2026 (2).xlsx';
|
||||||
|
|
||||||
addEventListener('DOMContentLoaded', () => {
|
addEventListener('DOMContentLoaded', () => {
|
||||||
$('file-input').onchange = onFile;
|
$('file-input').onchange = onFile;
|
||||||
$('group-filter').onchange = e => { state.groupFilter = [...e.target.selectedOptions].map(o => o.value); render(); };
|
$('group-filter').onchange = e => { state.groupFilter = [...e.target.selectedOptions].map(o => o.value); render(); };
|
||||||
@ -29,22 +31,37 @@ addEventListener('DOMContentLoaded', () => {
|
|||||||
$('theme-toggle').onclick = toggleTheme;
|
$('theme-toggle').onclick = toggleTheme;
|
||||||
$('inp-vacancies').oninput = e => { state.vacancies = +e.target.value || 0; render(); };
|
$('inp-vacancies').oninput = e => { state.vacancies = +e.target.value || 0; render(); };
|
||||||
$('inp-salary').oninput = e => { state.salary = +e.target.value || 0; render(); };
|
$('inp-salary').oninput = e => { state.salary = +e.target.value || 0; render(); };
|
||||||
|
autoLoad();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function autoLoad() {
|
||||||
|
try {
|
||||||
|
const res = await fetch(DEFAULT_XLSX);
|
||||||
|
if (!res.ok) return;
|
||||||
|
const buf = await res.arrayBuffer();
|
||||||
|
loadWorkbook(buf);
|
||||||
|
} catch (_) { /* fallback: ручная загрузка */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadWorkbook(buf) {
|
||||||
|
const wb = XLSX.read(buf, { type: 'array' });
|
||||||
|
const sheet = wb.SheetNames.find(n => n.toLowerCase().includes('функ')) || wb.SheetNames[0];
|
||||||
|
const rows = XLSX.utils.sheet_to_json(wb.Sheets[sheet], { header: 1, defval: null });
|
||||||
|
state.items = parseRows(rows);
|
||||||
|
if (!state.items.length) return;
|
||||||
|
populateGroups();
|
||||||
|
showDashboard();
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
// === Excel ===
|
// === Excel ===
|
||||||
async function onFile(e) {
|
async function onFile(e) {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
try {
|
try {
|
||||||
const buf = await file.arrayBuffer();
|
const buf = await file.arrayBuffer();
|
||||||
const wb = XLSX.read(buf, { type: 'array' });
|
loadWorkbook(buf);
|
||||||
const sheet = wb.SheetNames.find(n => n.toLowerCase().includes('функ')) || wb.SheetNames[0];
|
if (!state.items.length) alert('В файле не найдено функций. Проверьте формат (лист «функции»).');
|
||||||
const rows = XLSX.utils.sheet_to_json(wb.Sheets[sheet], { header: 1, defval: null });
|
|
||||||
state.items = parseRows(rows);
|
|
||||||
if (!state.items.length) return alert('В файле не найдено функций. Проверьте формат (лист «функции»).');
|
|
||||||
populateGroups();
|
|
||||||
showDashboard();
|
|
||||||
render();
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(`Ошибка чтения файла: ${err.message}`);
|
alert(`Ошибка чтения файла: ${err.message}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<p id="placeholder">Загрузите Excel-файл — дашборд построится автоматически.</p>
|
<p id="placeholder">Загрузка данных… Если дашборд не появился — нажмите «📁 Загрузить .xlsx».</p>
|
||||||
|
|
||||||
<script src="./app.js"></script>
|
<script src="./app.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Reference in New Issue
Block a user