Corp/backend/static/js/components/newEmployeesScroller.js
Игорь Надеин fcc52317cd fix: добавлен cache-busting для динамического импорта autoScrollerHandler
- Добавлен timestamp параметр в URL импорта
- Браузер будет загружать свежую версию вместо кешированной
- Исправлена проблема с устаревшими скриптами
2025-12-05 11:10:02 +03:00

179 lines
5.2 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.

/**
* Модуль для загрузки и отображения новых сотрудников
* Использует API для получения данных с корректными глобальными URL
*/
export class NewEmployeesScroller {
constructor(containerId = 'newEmployeesContainer') {
this.container = document.getElementById(containerId);
if (!this.container) {
console.warn(`Container #${containerId} not found`);
return;
}
this.apiUrl = '/api/v1/employees/';
}
/**
* Инициализация - загрузка и рендеринг
*/
async init() {
try {
const employees = await this.fetchNewEmployees();
if (employees && employees.length > 0) {
this.render(employees);
} else {
this.container.style.display = 'none';
}
} catch (error) {
console.error('Failed to load new employees:', error);
this.container.style.display = 'none';
}
}
/**
* Загрузка новых сотрудников через API
*/
async fetchNewEmployees() {
// Дата 14 дней назад
const since = new Date();
since.setDate(since.getDate() - 14);
const sinceISO = since.toISOString();
const params = new URLSearchParams({
active: 'true',
created_at__gte: sinceISO,
ordering: '-created_at',
page_size: '10'
});
const response = await fetch(`${this.apiUrl}?${params}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data.results || data;
}
/**
* Рендеринг списка сотрудников
*/
render(employees) {
const scrollerHtml = this.createScrollerHtml(employees);
this.container.innerHTML = scrollerHtml;
this.container.style.display = 'block';
// Инициализируем автоскролл после рендеринга
this.initAutoScroll();
}
/**
* Инициализация автоскролла для созданного скроллера
*/
async initAutoScroll() {
try {
// Динамический импорт модуля автоскролла
// Добавляем timestamp для обхода кеша браузера
const timestamp = Date.now();
const { initAutoScroller } = await import(`/static/js/components/autoScrollerHandler.js?v=${timestamp}`);
// Небольшая задержка для гарантии, что DOM обновился
setTimeout(() => {
initAutoScroller({
selector: '.js-join-scroller',
speed: 0.5
});
}, 100);
} catch (error) {
console.warn('Failed to initialize auto-scroller:', error);
}
}
/**
* Создание HTML разметки скроллера
*/
createScrollerHtml(employees) {
const items = employees.map(emp => this.createEmployeeItem(emp)).join('');
return `
<div>
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0 text-secondary"></h6>
</div>
<div class="join-scroller js-join-scroller" aria-label="Новые сотрудники">
<div class="join-rail">
${items}
</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0 text-secondary"></h6>
</div>
</div>
`;
}
/**
* Создание элемента сотрудника
*/
createEmployeeItem(emp) {
const empId = emp.id || emp.pk;
const empName = emp.short_name || emp.full_name || emp.email || 'Сотрудник';
const deptName = emp.department?.name || emp.department_name || '';
const avatar = emp.avatar;
// Аватар или иконка
let avatarHtml;
if (avatar) {
avatarHtml = `<img src="${avatar}" alt="" loading="lazy">`;
} else {
avatarHtml = `
<i class="bi-person" aria-hidden="true"></i>
<span class="visually-hidden">${this.escapeHtml(empName)}</span>
`;
}
// Навыки
let skillsHtml = '';
if (emp.skills && emp.skills.length > 0) {
const skillsList = emp.skills.map(s => this.escapeHtml(s.name)).join(', ');
skillsHtml = `<div class="skills-line"><b>Навыки:</b> ${skillsList}</div>`;
}
return `
<div class="join-item">
<a href="/employees/${empId}/"
class="join-ava text-decoration-none"
title="${this.escapeHtml(empName)}">
${avatarHtml}
</a>
<div class="join-info">
<div class="name">${this.escapeHtml(empName)}</div>
${deptName ? `<div class="sub">${this.escapeHtml(deptName)}</div>` : ''}
${skillsHtml}
</div>
</div>
`;
}
/**
* Экранирование HTML
*/
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
}
/**
* Инициализация при загрузке DOM
*/
export function initNewEmployeesScroller(containerId) {
const scroller = new NewEmployeesScroller(containerId);
scroller.init();
return scroller;
}