diff --git a/backend/static/js/components/employeeProfile.js b/backend/static/js/components/employeeProfile.js new file mode 100644 index 00000000..fe49e92c --- /dev/null +++ b/backend/static/js/components/employeeProfile.js @@ -0,0 +1,136 @@ +/** + * Модуль для загрузки и отображения профиля сотрудника + * Использует API для получения данных с корректными глобальными URL + */ + +export class EmployeeProfile { + constructor(employeeId, options = {}) { + this.employeeId = employeeId; + this.apiUrl = `/api/v1/employees/${employeeId}/`; + this.postsApiUrl = '/api/v1/posts/'; + + // Селекторы контейнеров + this.avatarContainer = options.avatarContainer || '#employeeAvatar'; + this.nameContainer = options.nameContainer || '#employeeName'; + this.postsContainer = options.postsContainer || '#employeePosts'; + } + + /** + * Инициализация - загрузка и рендеринг + */ + async init() { + try { + // Загружаем данные сотрудника + const employee = await this.fetchEmployee(); + if (employee) { + this.renderAvatar(employee); + this.renderName(employee); + } + + // Загружаем посты сотрудника + await this.loadPosts(); + } catch (error) { + console.error('Failed to load employee profile:', error); + } + } + + /** + * Загрузка данных сотрудника через API + */ + async fetchEmployee() { + const response = await fetch(this.apiUrl); + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return await response.json(); + } + + /** + * Рендеринг аватара + */ + renderAvatar(employee) { + const container = document.querySelector(this.avatarContainer); + if (!container) return; + + const avatarHtml = this.createAvatarHtml(employee); + container.innerHTML = avatarHtml; + } + + /** + * Создание HTML аватара + */ + createAvatarHtml(employee) { + if (employee.avatar) { + return ` + Аватар ${employee.last_name} ${employee.first_name} + `; + } else { + const initial = (employee.first_name || employee.last_name || '?').charAt(0).toUpperCase(); + return ` +
+ ${initial} +
+ `; + } + } + + /** + * Рендеринг имени (опционально, если нужно обновить) + */ + renderName(employee) { + const container = document.querySelector(this.nameContainer); + if (!container) return; + + let fullName = `${employee.last_name} ${employee.first_name}`; + if (employee.patronymic) { + fullName += ` ${employee.patronymic}`; + } + container.textContent = fullName; + } + + /** + * Загрузка постов сотрудника + */ + async loadPosts() { + const container = document.querySelector(this.postsContainer); + if (!container) return; + + try { + // Динамический импорт FeedList + const { FeedList } = await import('/static/js/components/feedList.js'); + + // Создаем экземпляр FeedList для постов сотрудника + const feedList = new FeedList({ + containerId: this.postsContainer.replace('#', ''), + apiUrl: this.postsApiUrl, + params: { + author: this.employeeId, + ordering: '-created_at' + }, + showLoadMore: false, // Не показываем кнопку "загрузить еще" + postsPerPage: 10 + }); + + await feedList.init(); + + // Если постов нет, показываем сообщение + if (feedList.posts.length === 0) { + container.innerHTML = '
Публикаций пока нет.
'; + } + } catch (error) { + console.error('Failed to load employee posts:', error); + container.innerHTML = '
Не удалось загрузить публикации.
'; + } + } +} + +/** + * Инициализация профиля сотрудника + */ +export function initEmployeeProfile(employeeId, options) { + const profile = new EmployeeProfile(employeeId, options); + profile.init(); + return profile; +} diff --git a/backend/templates/employees/components/employee_detail_scripts.html b/backend/templates/employees/components/employee_detail_scripts.html index 310a3d14..13c7d4f3 100644 --- a/backend/templates/employees/components/employee_detail_scripts.html +++ b/backend/templates/employees/components/employee_detail_scripts.html @@ -1,13 +1,28 @@ {% load static %} {# === JavaScript для страницы детального просмотра сотрудника === #} + + + + {% endblock %} +