433 lines
17 KiB
JavaScript
433 lines
17 KiB
JavaScript
// JavaScript для страницы профиля пользователя
|
||
|
||
class ProfileManager {
|
||
constructor() {
|
||
this.warehouse = new WarehouseManager();
|
||
this.currentUser = null;
|
||
this.userOperations = [];
|
||
|
||
this.init();
|
||
}
|
||
|
||
init() {
|
||
$(document).ready(() => {
|
||
this.loadProfile();
|
||
this.bindEvents();
|
||
});
|
||
}
|
||
|
||
bindEvents() {
|
||
// Обработчики для настроек
|
||
$('#saveSettingsBtn').on('click', () => this.saveSettings());
|
||
|
||
// Обработчики для форм
|
||
$('#changePasswordForm').on('submit', (e) => {
|
||
e.preventDefault();
|
||
this.savePassword();
|
||
});
|
||
|
||
$('#editProfileForm').on('submit', (e) => {
|
||
e.preventDefault();
|
||
this.saveProfile();
|
||
});
|
||
}
|
||
|
||
// Загрузка профиля
|
||
async loadProfile() {
|
||
try {
|
||
this.currentUser = auth.getCurrentUser();
|
||
if (!this.currentUser) {
|
||
window.location.href = 'login.html';
|
||
return;
|
||
}
|
||
|
||
this.displayUserInfo();
|
||
await this.loadUserStatistics();
|
||
await this.loadUserOperations();
|
||
this.loadSettings();
|
||
|
||
} catch (error) {
|
||
console.error('Ошибка при загрузке профиля:', error);
|
||
auth.showNotification('Ошибка при загрузке профиля', 'danger');
|
||
}
|
||
}
|
||
|
||
// Отображение информации о пользователе
|
||
displayUserInfo() {
|
||
// Основная информация
|
||
$('#userName').text(this.currentUser.name);
|
||
$('#userPosition').text(this.currentUser.position);
|
||
$('#userDepartment').text(this.currentUser.department);
|
||
$('#userEmail').text(this.currentUser.email);
|
||
|
||
// Роли
|
||
const roles = this.currentUser.roles.map(role => this.getRoleDisplayName(role)).join(', ');
|
||
$('#userRoles').html(`<span class="badge bg-primary me-1">${roles}</span>`);
|
||
|
||
// Разрешения
|
||
const permissions = this.currentUser.permissions.map(perm => this.getPermissionDisplayName(perm)).join(', ');
|
||
$('#userPermissions').html(`<span class="badge bg-secondary me-1">${permissions}</span>`);
|
||
|
||
// Дата регистрации (имитация)
|
||
const registrationDate = new Date();
|
||
registrationDate.setMonth(registrationDate.getMonth() - 3); // 3 месяца назад
|
||
$('#userRegistrationDate').text(registrationDate.toLocaleDateString('ru-RU'));
|
||
|
||
// Последний вход
|
||
const lastLogin = new Date();
|
||
lastLogin.setHours(lastLogin.getHours() - 2); // 2 часа назад
|
||
$('#lastLogin').text(lastLogin.toLocaleDateString('ru-RU') + ' ' + lastLogin.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }));
|
||
}
|
||
|
||
// Получение отображаемого названия роли
|
||
getRoleDisplayName(role) {
|
||
const roleNames = {
|
||
'admin': 'Администратор',
|
||
'manager': 'Менеджер',
|
||
'operator': 'Оператор',
|
||
'viewer': 'Наблюдатель'
|
||
};
|
||
return roleNames[role] || role;
|
||
}
|
||
|
||
// Получение отображаемого названия разрешения
|
||
getPermissionDisplayName(permission) {
|
||
const permissionNames = {
|
||
'read': 'Чтение',
|
||
'write': 'Запись',
|
||
'delete': 'Удаление',
|
||
'admin': 'Администрирование'
|
||
};
|
||
return permissionNames[permission] || permission;
|
||
}
|
||
|
||
// Загрузка статистики пользователя
|
||
async loadUserStatistics() {
|
||
try {
|
||
const operations = await this.warehouse.getOperations();
|
||
const userOperations = operations.filter(op => op.employeeId === this.currentUser.id);
|
||
|
||
// Общее количество операций
|
||
$('#totalOperations').text(userOperations.length);
|
||
|
||
// Операции в этом месяце
|
||
const thisMonth = new Date().getMonth();
|
||
const thisYear = new Date().getFullYear();
|
||
const thisMonthOperations = userOperations.filter(op => {
|
||
const opDate = new Date(op.date);
|
||
return opDate.getMonth() === thisMonth && opDate.getFullYear() === thisYear;
|
||
});
|
||
$('#thisMonthOperations').text(thisMonthOperations.length);
|
||
|
||
// Операции сегодня
|
||
const today = new Date().toISOString().split('T')[0];
|
||
const todayOperations = userOperations.filter(op => op.date.startsWith(today));
|
||
$('#todayOperations').text(todayOperations.length);
|
||
|
||
} catch (error) {
|
||
console.error('Ошибка при загрузке статистики:', error);
|
||
}
|
||
}
|
||
|
||
// Загрузка операций пользователя
|
||
async loadUserOperations() {
|
||
try {
|
||
const operations = await this.warehouse.getOperations();
|
||
this.userOperations = operations
|
||
.filter(op => op.employeeId === this.currentUser.id)
|
||
.sort((a, b) => new Date(b.date) - new Date(a.date))
|
||
.slice(0, 10); // Последние 10 операций
|
||
|
||
this.renderUserOperations();
|
||
|
||
} catch (error) {
|
||
console.error('Ошибка при загрузке операций:', error);
|
||
}
|
||
}
|
||
|
||
// Рендеринг операций пользователя
|
||
renderUserOperations() {
|
||
const tbody = $('#userOperationsTable tbody');
|
||
tbody.empty();
|
||
|
||
if (this.userOperations.length === 0) {
|
||
tbody.html(`
|
||
<tr>
|
||
<td colspan="5" class="text-center text-muted py-4">
|
||
<i class="fas fa-inbox fa-2x mb-3"></i>
|
||
<br>У вас пока нет операций
|
||
</td>
|
||
</tr>
|
||
`);
|
||
return;
|
||
}
|
||
|
||
this.userOperations.forEach(operation => {
|
||
const row = this.createOperationRow(operation);
|
||
tbody.append(row);
|
||
});
|
||
}
|
||
|
||
// Создание строки операции
|
||
createOperationRow(operation) {
|
||
const typeIcon = operation.type === 'incoming' ? 'fa-box-open text-success' : 'fa-truck text-warning';
|
||
const typeText = operation.type === 'incoming' ? 'Приход' : 'Расход';
|
||
const statusClass = this.getStatusClass(operation.status);
|
||
const statusText = this.getStatusText(operation.status);
|
||
|
||
return `
|
||
<tr>
|
||
<td>${this.formatDate(operation.date)}</td>
|
||
<td>
|
||
<i class="fas ${typeIcon} me-1"></i>
|
||
${typeText}
|
||
</td>
|
||
<td>${operation.itemName}</td>
|
||
<td>${operation.quantity}</td>
|
||
<td>
|
||
<span class="status-badge ${statusClass}">${statusText}</span>
|
||
</td>
|
||
</tr>
|
||
`;
|
||
}
|
||
|
||
// Получение класса статуса
|
||
getStatusClass(status) {
|
||
switch (status) {
|
||
case 'completed': return 'status-completed';
|
||
case 'pending': return 'status-pending';
|
||
case 'cancelled': return 'status-cancelled';
|
||
default: return 'status-pending';
|
||
}
|
||
}
|
||
|
||
// Получение текста статуса
|
||
getStatusText(status) {
|
||
switch (status) {
|
||
case 'completed': return 'Завершено';
|
||
case 'pending': return 'В обработке';
|
||
case 'cancelled': return 'Отменено';
|
||
default: return 'Неизвестно';
|
||
}
|
||
}
|
||
|
||
// Форматирование даты
|
||
formatDate(dateString) {
|
||
const date = new Date(dateString);
|
||
return date.toLocaleDateString('ru-RU', {
|
||
day: '2-digit',
|
||
month: '2-digit',
|
||
year: 'numeric',
|
||
hour: '2-digit',
|
||
minute: '2-digit'
|
||
});
|
||
}
|
||
|
||
// Загрузка настроек
|
||
loadSettings() {
|
||
// Загружаем настройки из localStorage
|
||
const settings = JSON.parse(localStorage.getItem('user_settings') || '{}');
|
||
|
||
$('#emailNotifications').prop('checked', settings.emailNotifications !== false);
|
||
$('#lowStockAlerts').prop('checked', settings.lowStockAlerts !== false);
|
||
$('#operationReports').prop('checked', settings.operationReports || false);
|
||
|
||
$('#themeSelect').val(settings.theme || 'light');
|
||
$('#languageSelect').val(settings.language || 'ru');
|
||
}
|
||
|
||
// Сохранение настроек
|
||
saveSettings() {
|
||
const settings = {
|
||
emailNotifications: $('#emailNotifications').is(':checked'),
|
||
lowStockAlerts: $('#lowStockAlerts').is(':checked'),
|
||
operationReports: $('#operationReports').is(':checked'),
|
||
theme: $('#themeSelect').val(),
|
||
language: $('#languageSelect').val()
|
||
};
|
||
|
||
localStorage.setItem('user_settings', JSON.stringify(settings));
|
||
auth.showNotification('Настройки сохранены', 'success');
|
||
}
|
||
|
||
// Смена пароля
|
||
changePassword() {
|
||
$('#changePasswordForm')[0].reset();
|
||
$('#changePasswordModal').modal('show');
|
||
}
|
||
|
||
// Сохранение пароля
|
||
savePassword() {
|
||
const currentPassword = $('#currentPassword').val();
|
||
const newPassword = $('#newPassword').val();
|
||
const confirmPassword = $('#confirmPassword').val();
|
||
|
||
// Валидация
|
||
if (!currentPassword || !newPassword || !confirmPassword) {
|
||
auth.showNotification('Пожалуйста, заполните все поля', 'warning');
|
||
return;
|
||
}
|
||
|
||
if (newPassword !== confirmPassword) {
|
||
auth.showNotification('Новые пароли не совпадают', 'warning');
|
||
return;
|
||
}
|
||
|
||
if (newPassword.length < 6) {
|
||
auth.showNotification('Новый пароль должен содержать минимум 6 символов', 'warning');
|
||
return;
|
||
}
|
||
|
||
// В реальном приложении здесь был бы запрос к серверу
|
||
// Для демонстрации просто показываем уведомление
|
||
auth.showNotification('Пароль успешно изменен', 'success');
|
||
$('#changePasswordModal').modal('hide');
|
||
$('#changePasswordForm')[0].reset();
|
||
}
|
||
|
||
// Редактирование профиля
|
||
editProfile() {
|
||
// Заполняем форму текущими данными
|
||
$('#editName').val(this.currentUser.name);
|
||
$('#editEmail').val(this.currentUser.email);
|
||
$('#editDepartment').val(this.currentUser.department);
|
||
$('#editPosition').val(this.currentUser.position);
|
||
$('#editPhone').val(this.currentUser.phone || '');
|
||
|
||
$('#editProfileModal').modal('show');
|
||
}
|
||
|
||
// Сохранение профиля
|
||
saveProfile() {
|
||
const formData = {
|
||
name: $('#editName').val(),
|
||
email: $('#editEmail').val(),
|
||
department: $('#editDepartment').val(),
|
||
position: $('#editPosition').val(),
|
||
phone: $('#editPhone').val()
|
||
};
|
||
|
||
// Валидация
|
||
if (!formData.name || !formData.email) {
|
||
auth.showNotification('Пожалуйста, заполните обязательные поля', 'warning');
|
||
return;
|
||
}
|
||
|
||
if (!this.isValidEmail(formData.email)) {
|
||
auth.showNotification('Пожалуйста, введите корректный email', 'warning');
|
||
return;
|
||
}
|
||
|
||
// В реальном приложении здесь был бы запрос к серверу
|
||
// Для демонстрации обновляем локальные данные
|
||
Object.assign(this.currentUser, formData);
|
||
localStorage.setItem('warehouse_user', JSON.stringify(this.currentUser));
|
||
|
||
// Обновляем отображение
|
||
this.displayUserInfo();
|
||
|
||
auth.showNotification('Профиль успешно обновлен', 'success');
|
||
$('#editProfileModal').modal('hide');
|
||
}
|
||
|
||
// Просмотр активности
|
||
viewActivity() {
|
||
// В реальном приложении здесь можно открыть страницу с детальной статистикой
|
||
auth.showNotification('Функция просмотра активности находится в разработке', 'info');
|
||
}
|
||
|
||
// Валидация email
|
||
isValidEmail(email) {
|
||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
return emailRegex.test(email);
|
||
}
|
||
|
||
// Получение статистики активности
|
||
getActivityStats() {
|
||
const now = new Date();
|
||
const stats = {
|
||
today: 0,
|
||
thisWeek: 0,
|
||
thisMonth: 0,
|
||
total: this.userOperations.length
|
||
};
|
||
|
||
this.userOperations.forEach(operation => {
|
||
const opDate = new Date(operation.date);
|
||
const diffTime = now - opDate;
|
||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||
|
||
if (diffDays === 0) stats.today++;
|
||
if (diffDays <= 7) stats.thisWeek++;
|
||
if (diffDays <= 30) stats.thisMonth++;
|
||
});
|
||
|
||
return stats;
|
||
}
|
||
|
||
// Экспорт данных пользователя
|
||
exportUserData() {
|
||
try {
|
||
const userData = {
|
||
profile: this.currentUser,
|
||
operations: this.userOperations,
|
||
statistics: this.getActivityStats(),
|
||
settings: JSON.parse(localStorage.getItem('user_settings') || '{}')
|
||
};
|
||
|
||
const dataStr = JSON.stringify(userData, null, 2);
|
||
const blob = new Blob([dataStr], { type: 'application/json' });
|
||
const link = document.createElement('a');
|
||
const url = URL.createObjectURL(blob);
|
||
link.setAttribute('href', url);
|
||
link.setAttribute('download', `profile_${this.currentUser.username}_${new Date().toISOString().split('T')[0]}.json`);
|
||
link.style.visibility = 'hidden';
|
||
document.body.appendChild(link);
|
||
link.click();
|
||
document.body.removeChild(link);
|
||
|
||
auth.showNotification('Данные профиля экспортированы', 'success');
|
||
|
||
} catch (error) {
|
||
console.error('Ошибка при экспорте:', error);
|
||
auth.showNotification('Ошибка при экспорте данных', 'danger');
|
||
}
|
||
}
|
||
|
||
// Получение рекомендаций
|
||
getRecommendations() {
|
||
const recommendations = [];
|
||
|
||
// Рекомендации на основе роли
|
||
if (this.currentUser.roles.includes('admin')) {
|
||
recommendations.push({
|
||
type: 'info',
|
||
title: 'Административные функции',
|
||
message: 'У вас есть доступ ко всем функциям системы. Не забудьте регулярно проверять отчеты и управлять пользователями.'
|
||
});
|
||
}
|
||
|
||
if (this.currentUser.roles.includes('manager')) {
|
||
recommendations.push({
|
||
type: 'warning',
|
||
title: 'Управление складом',
|
||
message: 'Следите за товарами с низким запасом и контролируйте операции операторов.'
|
||
});
|
||
}
|
||
|
||
// Рекомендации на основе активности
|
||
const stats = this.getActivityStats();
|
||
if (stats.today === 0) {
|
||
recommendations.push({
|
||
type: 'success',
|
||
title: 'Добро пожаловать!',
|
||
message: 'Сегодня у вас пока нет операций. Начните работу с добавления товаров или оформления операций.'
|
||
});
|
||
}
|
||
|
||
return recommendations;
|
||
}
|
||
}
|
||
|
||
// Инициализация менеджера профиля
|
||
const profileManager = new ProfileManager();
|