feat: переделана страница профиля на AJAX загрузку

- Создан новый JS модуль employeeProfile.js
- Аватар сотрудника загружается через API с глобальными URL
- Посты сотрудника загружаются через FeedList с правильными URL медиа
- Добавлены ID контейнеров для динамической загрузки (#employeeAvatar, #employeeName, #employeePosts)
- Подключены скрипты для лайков, комментариев и модала деталей
- Добавлен emoji-picker для форм комментариев
- Добавлен модал для просмотра публикаций
- Исправлена проблема с localhost URL в аватарах и медиа постов
This commit is contained in:
admin i 2025-12-05 12:21:30 +03:00
parent 6ae6516db7
commit 5d65b71c21
3 changed files with 162 additions and 3 deletions

View File

@ -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 `
<img src="${employee.avatar}"
alt="Аватар ${employee.last_name} ${employee.first_name}"
class="ios-ava" style="object-fit:cover;">
`;
} else {
const initial = (employee.first_name || employee.last_name || '?').charAt(0).toUpperCase();
return `
<div class="ios-ava--ph">
${initial}
</div>
`;
}
}
/**
* Рендеринг имени (опционально, если нужно обновить)
*/
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 = '<div class="text-secondary small">Публикаций пока нет.</div>';
}
} catch (error) {
console.error('Failed to load employee posts:', error);
container.innerHTML = '<div class="text-danger small">Не удалось загрузить публикации.</div>';
}
}
}
/**
* Инициализация профиля сотрудника
*/
export function initEmployeeProfile(employeeId, options) {
const profile = new EmployeeProfile(employeeId, options);
profile.init();
return profile;
}

View File

@ -1,13 +1,28 @@
{% load static %}
{# === JavaScript для страницы детального просмотра сотрудника === #}
<script src="{% static 'js/components/postDetailModal.js' %}"></script>
<script src="{% static 'js/components/feedLikes.js' %}"></script>
<script src="{% static 'js/components/feedComments.js' %}"></script>
<script type="module">
import { initSkillsManager } from '{% static "js/components/skillsManager.js" %}';
import { initDeptRoleEditor } from '{% static "js/components/deptRoleEditor.js" %}';
import { initEmployeeForm } from '{% static "js/components/employeeFormHandler.js" %}';
import { smoothScrollTo } from '{% static "js/utils/scroll.js" %}';
import { initEmployeeProfile } from '{% static "js/components/employeeProfile.js" %}';
document.addEventListener('DOMContentLoaded', () => {
// 0. Загрузка данных профиля через AJAX (аватар и посты с правильными URL)
const employeeId = '{{ emp.id }}';
if (employeeId) {
initEmployeeProfile(employeeId, {
avatarContainer: '#employeeAvatar',
nameContainer: '#employeeName',
postsContainer: '#employeePosts'
});
}
// 1. Обработчик формы редактирования профиля
const employeeForm = initEmployeeForm();
console.log('[employee_detail_scripts] employeeForm initialized:', employeeForm);

View File

@ -28,7 +28,7 @@
<div class="p-3 text-center">
<!-- Avatar -->
<div class="ava-wrap mb-3">
<div class="ava-wrap mb-3" id="employeeAvatar">
{% if emp.avatar %}
<img src="{{ emp.avatar }}"
alt="Аватар {{ emp.last_name }} {{ emp.first_name }}"
@ -43,7 +43,7 @@
<!-- Name + edit button -->
<div class="d-flex align-items-center justify-content-center gap-2 mb-1">
<div class="ios-name">
<div class="ios-name" id="employeeName">
{{ emp.last_name }} {{ emp.first_name }}{% if emp.patronymic %} {{ emp.patronymic }}{% endif %}
</div>
{% if can_edit %}
@ -412,7 +412,8 @@
<i class="bi-activity"></i>
<div class="ios-section-title mb-0">Активность</div>
</div>
<div>
<div id="employeePosts">
{# Посты загружаются через JavaScript из employeeProfile.js #}
{% if posts %}
{% include "feed/_feed_cards.html" with items=posts %}
{% else %}
@ -424,9 +425,16 @@
</div>
</div>
</div>
<!-- Модальное окно для просмотра публикации -->
{% include "feed/components/modal_post_detail.html" %}
{% endblock %}
{% block extra_js %}
{# === JavaScript логика === #}
{% include "employees/components/employee_detail_scripts.html" %}
<!-- Emoji Picker Library -->
<script type="module" src="https://cdn.jsdelivr.net/npm/emoji-picker-element@^1/index.js"></script>
{% endblock %}